Skip to content

Commit 1cd6912

Browse files
authored
Handle invalid signed "tfdt" decode time values (video-dev#5333)
* Handle invalid signed "tfdt" decode time values Resolves video-dev#5303 * Return latest result (falls back to playlist time) * Safe check for value over 2^63
1 parent 46a7daf commit 1cd6912

File tree

2 files changed

+22
-8
lines changed

2 files changed

+22
-8
lines changed

src/remux/passthrough-remuxer.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,12 @@ class PassThroughRemuxer implements Remuxer {
168168
}
169169

170170
const startDTS = getStartDTS(initData, data);
171+
const decodeTime = startDTS === null ? timeOffset : startDTS;
171172
if (
172-
isInvalidInitPts(initPTS, startDTS, timeOffset) ||
173+
isInvalidInitPts(initPTS, decodeTime, timeOffset) ||
173174
(initSegment.timescale !== initPTS.timescale && accurateTimeOffset)
174175
) {
175-
initSegment.initPTS = startDTS - timeOffset;
176+
initSegment.initPTS = decodeTime - timeOffset;
176177
this.initPTS = initPTS = {
177178
baseTime: initSegment.initPTS,
178179
timescale: 1,
@@ -181,7 +182,7 @@ class PassThroughRemuxer implements Remuxer {
181182

182183
const duration = getDuration(data, initData);
183184
const startTime = audioTrack
184-
? startDTS - initPTS.baseTime / initPTS.timescale
185+
? decodeTime - initPTS.baseTime / initPTS.timescale
185186
: (lastEndTime as number);
186187
const endTime = startTime + duration;
187188
offsetStartDTS(initData, data, initPTS.baseTime / initPTS.timescale);

src/utils/mp4-tools.ts

+18-5
Original file line numberDiff line numberDiff line change
@@ -350,10 +350,13 @@ export function parseSinf(sinf: Uint8Array): Uint8Array | null {
350350
* @returns the earliest base media decode start time for the
351351
* fragment, in seconds
352352
*/
353-
export function getStartDTS(initData: InitData, fmp4: Uint8Array): number {
353+
export function getStartDTS(
354+
initData: InitData,
355+
fmp4: Uint8Array
356+
): number | null {
354357
// we need info from two children of each track fragment box
355-
return (
356-
findBox(fmp4, ['moof', 'traf']).reduce((result: number | null, traf) => {
358+
return findBox(fmp4, ['moof', 'traf']).reduce(
359+
(result: number | null, traf) => {
357360
const tfdt = findBox(traf, ['tfdt'])[0];
358361
const version = tfdt[0];
359362
const start = findBox(traf, ['tfhd']).reduce(
@@ -364,7 +367,16 @@ export function getStartDTS(initData: InitData, fmp4: Uint8Array): number {
364367
if (track) {
365368
let baseTime = readUint32(tfdt, 4);
366369
if (version === 1) {
367-
baseTime *= Math.pow(2, 32);
370+
// If value is too large, assume signed 64-bit. Negative track fragment decode times are invalid, but they exist in the wild.
371+
// This prevents large values from being used for initPTS, which can cause playlist sync issues.
372+
// https://github.com/video-dev/hls.js/issues/5303
373+
if (baseTime === UINT32_MAX) {
374+
logger.warn(
375+
`[mp4-demuxer]: Ignoring assumed invalid signed 64-bit track fragment decode time`
376+
);
377+
return result;
378+
}
379+
baseTime *= UINT32_MAX + 1;
368380
baseTime += readUint32(tfdt, 8);
369381
}
370382
// assume a 90kHz clock if no timescale was specified
@@ -390,7 +402,8 @@ export function getStartDTS(initData: InitData, fmp4: Uint8Array): number {
390402
return start;
391403
}
392404
return result;
393-
}, null) || 0
405+
},
406+
null
394407
);
395408
}
396409

0 commit comments

Comments
 (0)