@@ -4,7 +4,10 @@ import { ErrorDetails, ErrorTypes } from '../errors';
44import { Events } from '../events' ;
55import { PlaylistLevelType } from '../types/loader' ;
66import { type ILogger , Logger } from '../utils/logger' ;
7- import { toMsFromMpegTsClock } from '../utils/timescale-conversion' ;
7+ import {
8+ timestampToString ,
9+ toMsFromMpegTsClock ,
10+ } from '../utils/timescale-conversion' ;
811import type { HlsConfig } from '../config' ;
912import type { HlsEventEmitter } from '../events' ;
1013import type { SourceBufferName } from '../types/buffer' ;
@@ -107,7 +110,19 @@ export default class MP4Remuxer extends Logger implements Remuxer {
107110 }
108111
109112 resetTimeStamp ( defaultTimeStamp : TimestampOffset | null ) {
110- this . log ( 'initPTS & initDTS reset' ) ;
113+ const initPTS = this . _initPTS ;
114+ if (
115+ ! initPTS ||
116+ ! defaultTimeStamp ||
117+ defaultTimeStamp . trackId !== initPTS . trackId ||
118+ defaultTimeStamp . baseTime !== initPTS . baseTime ||
119+ defaultTimeStamp . timescale !== initPTS . timescale
120+ ) {
121+ this . log (
122+ `Reset initPTS: ${ initPTS ? timestampToString ( initPTS ) : initPTS } > ${ defaultTimeStamp ? timestampToString ( defaultTimeStamp ) : defaultTimeStamp } ` ,
123+ ) ;
124+ }
125+
111126 this . _initPTS = this . _initDTS = defaultTimeStamp ;
112127 }
113128
@@ -334,6 +349,25 @@ export default class MP4Remuxer extends Logger implements Remuxer {
334349 } ;
335350 }
336351
352+ computeInitPts (
353+ basetime : number ,
354+ timescale : number ,
355+ presentationTime : number ,
356+ type : 'audio' | 'video' ,
357+ ) : number {
358+ const offset = Math . round ( presentationTime * timescale ) ;
359+ let timestamp = normalizePts ( basetime , offset ) ;
360+ if ( timestamp < offset + timescale ) {
361+ this . log (
362+ `Adjusting PTS for rollover in timeline near ${ ( offset - timestamp ) / timescale } ${ type } ` ,
363+ ) ;
364+ while ( timestamp < offset + timescale ) {
365+ timestamp += 8589934592 ;
366+ }
367+ }
368+ return timestamp - offset ;
369+ }
370+
337371 generateIS (
338372 audioTrack : DemuxedAudioTrack ,
339373 videoTrack : DemuxedVideoTrack ,
@@ -395,8 +429,12 @@ export default class MP4Remuxer extends Logger implements Remuxer {
395429 timescale = audioTrack . inputTimeScale ;
396430 if ( ! _initPTS || timescale !== _initPTS . timescale ) {
397431 // remember first PTS of this demuxing context. for audio, PTS = DTS
398- initPTS = initDTS =
399- audioSamples [ 0 ] . pts - Math . round ( timescale * timeOffset ) ;
432+ initPTS = initDTS = this . computeInitPts (
433+ audioSamples [ 0 ] . pts ,
434+ timescale ,
435+ timeOffset ,
436+ 'audio' ,
437+ ) ;
400438 } else {
401439 computePTSDTS = false ;
402440 }
@@ -421,13 +459,22 @@ export default class MP4Remuxer extends Logger implements Remuxer {
421459 trackId = videoTrack . id ;
422460 timescale = videoTrack . inputTimeScale ;
423461 if ( ! _initPTS || timescale !== _initPTS . timescale ) {
424- const startPTS = this . getVideoStartPts ( videoSamples ) ;
425- const startOffset = Math . round ( timescale * timeOffset ) ;
426- initDTS = Math . min (
427- initDTS as number ,
428- normalizePts ( videoSamples [ 0 ] . dts , startPTS ) - startOffset ,
462+ const basePTS = this . getVideoStartPts ( videoSamples ) ;
463+ const baseDTS = normalizePts ( videoSamples [ 0 ] . dts , basePTS ) ;
464+ const videoInitDTS = this . computeInitPts (
465+ baseDTS ,
466+ timescale ,
467+ timeOffset ,
468+ 'video' ,
469+ ) ;
470+ const videoInitPTS = this . computeInitPts (
471+ basePTS ,
472+ timescale ,
473+ timeOffset ,
474+ 'video' ,
429475 ) ;
430- initPTS = Math . min ( initPTS as number , startPTS - startOffset ) ;
476+ initDTS = Math . min ( initDTS as number , videoInitDTS ) ;
477+ initPTS = Math . min ( initPTS as number , videoInitPTS ) ;
431478 } else {
432479 computePTSDTS = false ;
433480 }
@@ -897,11 +944,18 @@ export default class MP4Remuxer extends Logger implements Remuxer {
897944 } ) ;
898945
899946 if ( ! contiguous || nextAudioTs < 0 ) {
947+ const sampleCount = inputSamples . length ;
900948 // filter out sample with negative PTS that are not playable anyway
901949 // if we don't remove these negative samples, they will shift all audio samples forward.
902950 // leading to audio overlap between current / next fragment
903951 inputSamples = inputSamples . filter ( ( sample ) => sample . pts >= 0 ) ;
904952
953+ if ( sampleCount !== inputSamples . length ) {
954+ this . warn (
955+ `Removed ${ inputSamples . length - sampleCount } of ${ sampleCount } samples (initPTS ${ initTime } / ${ inputTimeScale } )` ,
956+ ) ;
957+ }
958+
905959 // in case all samples have negative PTS, and have been filtered out, return now
906960 if ( ! inputSamples . length ) {
907961 return ;
0 commit comments