Skip to content

Commit

Permalink
Account for overlapping sidx subsegment durations by parsing earliers…
Browse files Browse the repository at this point in the history
…tPresentationTime

Fixes #6191
  • Loading branch information
robwalch committed Feb 7, 2024
1 parent 88d54a9 commit aadb239
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions src/utils/mp4-tools.ts
Expand Up @@ -38,6 +38,13 @@ export function readUint32(buffer: Uint8Array, offset: number): number {
return val < 0 ? 4294967296 + val : val;
}

export function readUint64(buffer: Uint8Array, offset: number) {
let result = readUint32(buffer, offset);
result *= Math.pow(2, 32);
result += readUint32(buffer, offset + 4);
return result;
}

export function readSint32(buffer: Uint8Array, offset: number): number {
return (
(buffer[offset] << 24) |
Expand Down Expand Up @@ -125,15 +132,15 @@ export function parseSegmentIndex(sidx: Uint8Array): SidxInfo | null {
const timescale = readUint32(sidx, index);
index += 4;

// TODO: parse earliestPresentationTime and firstOffset
// usually zero in our case
const earliestPresentationTime = 0;
const firstOffset = 0;
let earliestPresentationTime = 0;
let firstOffset = 0;

if (version === 0) {
index += 8;
earliestPresentationTime = readUint32(sidx, (index += 4));
firstOffset = readUint32(sidx, (index += 4));
} else {
index += 16;
earliestPresentationTime = readUint64(sidx, (index += 8));
firstOffset = readUint64(sidx, (index += 8));
}

// skip reserved
Expand Down Expand Up @@ -677,19 +684,31 @@ export function getDuration(data: Uint8Array, initData: InitData) {
}
if (videoDuration === 0 && audioDuration === 0) {
// If duration samples are not available in the traf use sidx subsegment_duration
let sidxMinStart = Infinity;
let sidxMaxEnd = 0;
let sidxDuration = 0;
const sidxs = findBox(data, ['sidx']);
for (let i = 0; i < sidxs.length; i++) {
const sidx = parseSegmentIndex(sidxs[i]);
if (sidx?.references) {
sidxDuration += sidx.references.reduce(
sidxMinStart = Math.min(
sidxMinStart,
sidx.earliestPresentationTime / sidx.timescale,
);
const subSegmentDuration = sidx.references.reduce(
(dur, ref) => dur + ref.info.duration || 0,
0,
);
sidxMaxEnd = Math.max(
sidxMaxEnd,
subSegmentDuration + sidx.earliestPresentationTime / sidx.timescale,
);
sidxDuration = sidxMaxEnd - sidxMinStart;
}
}

return sidxDuration;
if (sidxDuration && Number.isFinite(sidxDuration)) {
return sidxDuration;
}
}
if (videoDuration) {
return videoDuration;
Expand Down

0 comments on commit aadb239

Please sign in to comment.