Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hls.Events.ERROR is never received unless HTMLVideoElement is attached to the DOM #5759

Closed
5 tasks done
bes opened this issue Aug 22, 2023 · 30 comments · Fixed by #5805
Closed
5 tasks done

Hls.Events.ERROR is never received unless HTMLVideoElement is attached to the DOM #5759

bes opened this issue Aug 22, 2023 · 30 comments · Fixed by #5805

Comments

@bes
Copy link

bes commented Aug 22, 2023

What version of Hls.js are you using?

1.4.10

What browser (including version) are you using?

Chrome 116.0.5845.96 (Official Build) (arm64)

What OS (including version) are you using?

macOS 13.5.1 (22G90)

Test stream

No response

Configuration

{} (irrelevant AFAIK)

Additional player setup steps

Standard setup, but the HTMLVideoElement is never attached to the DOM

Checklist

Steps to reproduce

  1. Create HTMLVideoElement manually: document.createElement("video")
  2. Standard HLS.js setup, use element from previous step
  3. Register hlsJs.on(Hls.Events.ERROR, ...
  4. Have a HLS stream with a stall in it
  5. Play the video, wait for it to stall

Expected behaviour

Hls.Events.ERROR to be received.

See previous discussion: #5758

What actually happened?

  • Hls.Events.ERROR is never received
  • audio keeps playing as usual, but video is frozen/does not produce new frames.
  • If I "nudge" the video it starts producing frames again

If I attach the HTMLVideoElement to the DOM, it will throw an Hls.Events.ERROR after a few seconds.

Console output

hls.mjs:405 [log] > Debug logs enabled for "Hls instance" in hls.js version 1.4.10
hls.mjs:25314 [log] > stopLoad
hls.mjs:25285 [log] > loadSource:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
hls.mjs:15295 [log] > [stream-controller]: Trigger BUFFER_RESET
hls.mjs:25259 [log] > attachMedia
hls.mjs:18413 [log] > [buffer-controller]: Media source opened
hls.mjs:9538 [log] > [subtitle-stream-controller]: STOPPED->IDLE
hls.mjs:6119 [log] > [level-controller]: manifest loaded, 1 level(s) found, first bitrate: 10171552
hls.mjs:18512 [log] > 2 bufferCodec event(s) expected
hls.mjs:25304 [log] > startLoad(1.5202)
hls.mjs:6188 [log] > [level-controller]: Switching to level 0 from level -1
hls.mjs:17420 [log] > [audio-track-controller]: Updating audio tracks, 1 track(s) found in group:audio
hls.mjs:17466 [log] > [audio-track-controller]: Switching to audio-track 0 "Audio" lang:en group:audio
hls.mjs:9423 [log] > [audio-stream-controller]: Reset loading state
hls.mjs:9538 [log] > [audio-stream-controller]: STOPPED->IDLE
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->WAITING_TRACK
hls.mjs:6329 [log] > [level-controller]: Loading level index 0 with URI 1/1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
hls.mjs:9538 [log] > [stream-controller]: STOPPED->IDLE
hls.mjs:17524 [log] > [audio-track-controller]: loading audio-track playlist 0 "Audio" lang:en group:audio
hls.mjs:9538 [log] > [audio-stream-controller]: WAITING_TRACK->STOPPED
hls.mjs:9538 [log] > [audio-stream-controller]: STOPPED->WAITING_TRACK
hls.mjs:9538 [log] > [subtitle-stream-controller]: IDLE->STOPPED
hls.mjs:9538 [log] > [subtitle-stream-controller]: STOPPED->IDLE
hls.mjs:15350 [log] > [stream-controller]: Level 0 loaded [0,1876][part-1876--1], cc [0, 0] duration:7505.149
hls.mjs:18980 [log] > [buffer-controller]: Updating Media Source duration to 7505.149
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 0 cc: 0 of [0-1876] level: 0, target: 1.52
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:17391 [log] > [audio-track-controller]: audio-track 0 "Audio" lang:en group:audio loaded [0-1861]
hls.mjs:16970 [log] > [audio-stream-controller]: Track 0 loaded [0,1861][part-1861--1],duration:7505.166000000191
hls.mjs:9538 [log] > [audio-stream-controller]: WAITING_TRACK->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 0 cc: 0 of [0-1861] track: 0, target: 1.52
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:14402 [log] > [transmuxer-interface, main]: Starting new transmux session for sn: 0 p: -1 level: 0 id: 1
        discontinuity: true
        trackSwitch: true
        contiguous: false
        accurateTimeOffset: true
        timeOffset: 0
        initSegmentChange: true
hls.mjs:12544 [log] > [mp4-remuxer]: ISGenerated flag reset
hls.mjs:12535 [log] > [mp4-remuxer]: initPTS & initDTS reset
hls.mjs:12539 [log] > [mp4-remuxer]: reset next timestamp
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:15885 [log] > [stream-controller]: Init video buffer, container:video/mp4, codecs[level/parsed]=[/avc1.640034]
hls.mjs:16657 [log] > [audio-stream-controller]: InitPTS for cc: 0 found from main: 31860
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 0 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 0 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:14402 [log] > [transmuxer-interface, audio]: Starting new transmux session for sn: 0 p: -1 level: 0 id: 1
        discontinuity: true
        trackSwitch: true
        contiguous: false
        accurateTimeOffset: false
        timeOffset: 0
        initSegmentChange: true
hls.mjs:10042 [log] > ADTS sync word found !
hls.mjs:12544 [log] > [mp4-remuxer]: ISGenerated flag reset
hls.mjs:12535 [log] > [mp4-remuxer]: initPTS & initDTS reset
hls.mjs:12539 [log] > [mp4-remuxer]: reset next timestamp
hls.mjs:9782 [log] > manifest codec:mp4a.40.2, ADTS type:2, samplingIndex:3
hls.mjs:9932 [log] > parsed codec:mp4a.40.5, rate:48000, channels:2
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:17271 [log] > [audio-stream-controller]: Init audio buffer, container:audio/mp4, codecs[parsed]=[mp4a.40.5]
hls.mjs:19048 [log] > [buffer-controller]: creating sourceBuffer(video/mp4;codecs=avc1.640034)
hls.mjs:19048 [log] > [buffer-controller]: creating sourceBuffer(audio/mp4;codecs=mp4a.40.5)
hls.mjs:15505 [log] > [stream-controller]: Alternate track found, use video.buffered to schedule main fragment loading
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 0 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 0 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 0 of track 0 (frag:[0.000-4.032] > buffer:[0.000-4.032])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 1 cc: 0 of [0-1861] track: 0, target: 4.032
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 0 of level 0 (frag:[0.000-4.017] > buffer:[0.000-4.017])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:15642 [log] > [stream-controller]: seek to target start position 1.5202 from current time 0
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 1 cc: 0 of [0-1876] level: 0, target: 4.017
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:8436 [log] > [stream-controller]: media seeking to 1.520, state: FRAG_LOADING
hls.mjs:8436 [log] > [audio-stream-controller]: media seeking to 1.520, state: FRAG_LOADING
hls.mjs:8436 [log] > [subtitle-stream-controller]: media seeking to 1.520, state: IDLE
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 1 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 1 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 1 of track 0 (frag:[4.032-8.064] > buffer:[0.000-8.064])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:12831 [warn] > AVC: 17 ms (-1500dts) overlapping between fragments detected
overrideMethod @ console.js:213
remuxVideo @ hls.mjs:12831
remux @ hls.mjs:12642
transmuxUnencrypted @ hls.mjs:13801
transmux @ hls.mjs:13790
push @ hls.mjs:13664
push @ hls.mjs:14426
_handleFragmentLoadProgress @ hls.mjs:15428
progressCallback @ hls.mjs:8509
(anonymous) @ hls.mjs:8791
Promise.then (async)
_doFragLoad @ hls.mjs:8789
_loadFragForPlayback @ hls.mjs:8511
loadFragment @ hls.mjs:8499
loadFragment @ hls.mjs:15137
doTickIdle @ hls.mjs:15123
doTick @ hls.mjs:15009
tick @ hls.mjs:7479
fragBufferedComplete @ hls.mjs:8678
onFragBuffered @ hls.mjs:15533
emit @ hls.mjs:14109
emit @ hls.mjs:25209
trigger @ hls.mjs:25213
onUnblocked @ hls.mjs:18832
(anonymous) @ hls.mjs:19170
Promise.then (async)
blockBuffers @ hls.mjs:19168
onFragParsed @ hls.mjs:18842
emit @ hls.mjs:14088
emit @ hls.mjs:25209
trigger @ hls.mjs:25213
updateLevelTiming @ hls.mjs:9514
_handleTransmuxerFlush @ hls.mjs:8867
handleFlushResult @ hls.mjs:14486
flush @ hls.mjs:14463
_handleFragmentLoadComplete @ hls.mjs:8696
(anonymous) @ hls.mjs:8530
Promise.then (async)
_loadFragForPlayback @ hls.mjs:8511
loadFragment @ hls.mjs:8499
loadFragment @ hls.mjs:15137
doTickIdle @ hls.mjs:15123
doTick @ hls.mjs:15009
tick @ hls.mjs:7479
onLevelLoaded @ hls.mjs:15391
emit @ hls.mjs:14109
emit @ hls.mjs:25209
trigger @ hls.mjs:25213
handlePlaylistLoaded @ hls.mjs:3933
handleTrackOrLevelPlaylist @ hls.mjs:3801
onSuccess @ hls.mjs:3678
readystatechange @ hls.mjs:24288
XMLHttpRequest.send (async)
openAndSendXhr @ hls.mjs:24230
loadInternal @ hls.mjs:24203
load @ hls.mjs:24168
load @ hls.mjs:3693
onLevelLoading @ hls.mjs:3559
emit @ hls.mjs:14109
emit @ hls.mjs:25209
trigger @ hls.mjs:25213
loadPlaylist @ hls.mjs:6334
set level @ hls.mjs:6206
set nextLoadLevel @ hls.mjs:6350
set nextLoadLevel @ hls.mjs:25420
startLoad @ hls.mjs:14953
(anonymous) @ hls.mjs:25306
startLoad @ hls.mjs:25305
filterAndSortMediaOptions @ hls.mjs:6143
onManifestLoaded @ hls.mjs:6023
emit @ hls.mjs:14109
emit @ hls.mjs:25209
trigger @ hls.mjs:25213
handleMasterPlaylist @ hls.mjs:3742
onSuccess @ hls.mjs:3680
readystatechange @ hls.mjs:24288
XMLHttpRequest.send (async)
openAndSendXhr @ hls.mjs:24230
loadInternal @ hls.mjs:24203
load @ hls.mjs:24168
load @ hls.mjs:3693
onManifestLoading @ hls.mjs:3543
emit @ hls.mjs:14109
emit @ hls.mjs:25209
trigger @ hls.mjs:25213
loadSource @ hls.mjs:25291
MediaPlayer.loadVideo @ media-player.tsx:864
load @ media-instance.ts:58
MediaInstance @ media-instance.ts:42
(anonymous) @ projection-viewpoint-instance.ts:129
(anonymous) @ map.ts:58
OperatorSubscriber._this._next @ OperatorSubscriber.ts:70
Subscriber.next @ Subscriber.ts:75
(anonymous) @ Subject.ts:68
errorContext @ errorContext.ts:29
Subject.next @ Subject.ts:61
BehaviorSubject.next @ BehaviorSubject.ts:37
(anonymous) @ projection-viewpoint-instance.ts:109
ConsumerObserver.next @ Subscriber.ts:161
Subscriber._next @ Subscriber.ts:119
Subscriber.next @ Subscriber.ts:75
(anonymous) @ combineLatest.ts:272
OperatorSubscriber._this._next @ OperatorSubscriber.ts:70
Subscriber.next @ Subscriber.ts:75
(anonymous) @ Subject.ts:68
errorContext @ errorContext.ts:29
Subject.next @ Subject.ts:61
BehaviorSubject.next @ BehaviorSubject.ts:37
(anonymous) @ projection-viewpoint-instance.ts:208
Promise.then (async)
(anonymous) @ projection-viewpoint-instance.ts:206
Promise.then (async)
load @ projection-viewpoint-instance.ts:201
ProjectionViewpointInstance @ projection-viewpoint-instance.ts:159
createViewpointInstance @ game-media-conductor.ts:194
replaceOnlyViewpointInstance @ game-media-conductor.ts:179
goToViewpoint @ video-camera-settings.tsx:59
onClick @ video-camera-settings.tsx:145
callCallback @ react-dom.development.js:188
invokeGuardedCallbackDev @ react-dom.development.js:237
invokeGuardedCallback @ react-dom.development.js:292
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:306
executeDispatch @ react-dom.development.js:389
executeDispatchesInOrder @ react-dom.development.js:414
executeDispatchesAndRelease @ react-dom.development.js:3278
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:3287
forEachAccumulated @ react-dom.development.js:3259
runEventsInBatch @ react-dom.development.js:3304
runExtractedPluginEventsInBatch @ react-dom.development.js:3514
handleTopLevel @ react-dom.development.js:3558
batchedEventUpdates$1 @ react-dom.development.js:21871
batchedEventUpdates @ react-dom.development.js:795
dispatchEventForLegacyPluginEventSystem @ react-dom.development.js:3568
attemptToDispatchEvent @ react-dom.development.js:4267
dispatchEvent @ react-dom.development.js:4189
unstable_runWithPriority @ scheduler.development.js:653
runWithPriority$1 @ react-dom.development.js:11039
discreteUpdates$1 @ react-dom.development.js:21887
discreteUpdates @ react-dom.development.js:806
dispatchDiscreteEvent @ react-dom.development.js:4168
Show 1 more frame
Show less
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 1 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 1 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 1 of level 0 (frag:[4.000-8.000] > buffer:[0.000-3.950][4.000-8.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 2 cc: 0 of [0-1876] level: 0, target: 8
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 2 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 2 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 2 cc: 0 of [0-1861] track: 0, target: 8.064
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 2 of level 0 (frag:[8.000-12.000] > buffer:[0.000-3.950][4.000-12.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 2 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 2 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 2 of track 0 (frag:[8.064-12.096] > buffer:[0.000-12.096])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:15280 [log] > [stream-controller]: Media seeked to 1.520
hls.mjs:25238 [log] > destroy
hls.mjs:25270 [log] > detachMedia
hls.mjs:18536 [log] > [buffer-controller]: media source detaching
hls.mjs:9538 [log] > [stream-controller]: IDLE->STOPPED
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->STOPPED
hls.mjs:9538 [log] > [subtitle-stream-controller]: IDLE->STOPPED
hls.mjs:8436 [log] > [stream-controller]: media seeking to 1.020, state: IDLE
hls.mjs:8436 [log] > [audio-stream-controller]: media seeking to 1.020, state: IDLE
hls.mjs:8436 [log] > [subtitle-stream-controller]: media seeking to 1.020, state: IDLE
hls.mjs:15280 [log] > [stream-controller]: Media seeked to 1.020
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 3 cc: 0 of [0-1876] level: 0, target: 12
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 3 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 3 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 3 of level 0 (frag:[12.000-16.000] > buffer:[0.000-3.950][4.000-16.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 3 cc: 0 of [0-1861] track: 0, target: 12.096
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 3 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 3 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 3 of track 0 (frag:[12.096-16.128] > buffer:[0.000-16.128])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 4 cc: 0 of [0-1876] level: 0, target: 16
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 4 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 4 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 4 of level 0 (frag:[16.000-20.000] > buffer:[0.000-3.950][4.000-20.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 4 cc: 0 of [0-1861] track: 0, target: 16.128
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 4 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 4 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 4 of track 0 (frag:[16.128-20.160] > buffer:[0.000-20.160])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 5 cc: 0 of [0-1876] level: 0, target: 20
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 5 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 5 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 5 of level 0 (frag:[20.000-24.000] > buffer:[0.000-3.950][4.000-24.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 5 cc: 0 of [0-1861] track: 0, target: 20.16
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 5 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 5 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 5 of track 0 (frag:[20.160-24.192] > buffer:[0.000-24.192])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 6 cc: 0 of [0-1876] level: 0, target: 24
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 6 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 6 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 6 of level 0 (frag:[24.000-28.000] > buffer:[0.000-3.950][4.000-28.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 6 cc: 0 of [0-1861] track: 0, target: 24.192
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 6 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 6 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 6 of track 0 (frag:[24.192-28.224] > buffer:[0.000-28.224])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 7 cc: 0 of [0-1876] level: 0, target: 28
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 7 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 7 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 7 of level 0 (frag:[28.000-32.000] > buffer:[0.000-3.950][4.000-32.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 7 cc: 0 of [0-1861] track: 0, target: 28.224
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 7 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 7 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 7 of track 0 (frag:[28.224-32.256] > buffer:[0.000-32.256])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 8 cc: 0 of [0-1876] level: 0, target: 32
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 8 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 8 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 8 of level 0 (frag:[32.000-36.000] > buffer:[0.000-3.950][4.000-36.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 8 cc: 0 of [0-1861] track: 0, target: 32.256
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 8 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 8 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 8 of track 0 (frag:[32.256-36.288] > buffer:[0.000-36.288])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 9 cc: 0 of [0-1876] level: 0, target: 36
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 9 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 9 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 9 of level 0 (frag:[36.000-40.000] > buffer:[0.000-3.950][4.000-40.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 9 cc: 0 of [0-1861] track: 0, target: 36.288
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 9 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 9 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 9 of track 0 (frag:[36.288-40.320] > buffer:[0.000-40.320])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 10 cc: 0 of [0-1876] level: 0, target: 40
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 10 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 10 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 10 of level 0 (frag:[40.000-44.000] > buffer:[0.000-3.950][4.000-44.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 10 cc: 0 of [0-1861] track: 0, target: 40.32
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 10 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 10 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 10 of track 0 (frag:[40.320-44.352] > buffer:[0.000-44.352])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 11 cc: 0 of [0-1876] level: 0, target: 44
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 11 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 11 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 11 of level 0 (frag:[44.000-48.000] > buffer:[0.000-3.950][4.000-48.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 11 cc: 0 of [0-1861] track: 0, target: 44.352
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 11 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 11 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 11 of track 0 (frag:[44.352-48.384] > buffer:[0.000-48.384])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 12 cc: 0 of [0-1876] level: 0, target: 48
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 12 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 12 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 12 of level 0 (frag:[48.000-52.000] > buffer:[0.000-3.950][4.000-52.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 12 cc: 0 of [0-1861] track: 0, target: 48.384
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 12 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 12 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 12 of track 0 (frag:[48.384-52.416] > buffer:[0.000-52.416])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 13 cc: 0 of [0-1876] level: 0, target: 52
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 13 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 13 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 13 of level 0 (frag:[52.000-56.000] > buffer:[0.000-3.950][4.000-56.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 13 cc: 0 of [0-1861] track: 0, target: 52.416
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 13 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 13 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 13 of track 0 (frag:[52.416-56.448] > buffer:[0.000-56.448])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 14 cc: 0 of [0-1876] level: 0, target: 56
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 14 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 14 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 14 of level 0 (frag:[56.000-60.000] > buffer:[0.000-3.950][4.000-60.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 14 cc: 0 of [0-1861] track: 0, target: 56.448
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 14 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 14 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 14 of track 0 (frag:[56.448-60.480] > buffer:[0.000-60.480])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [stream-controller]: Loading fragment 15 cc: 0 of [0-1876] level: 0, target: 60
hls.mjs:9538 [log] > [stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [stream-controller]: Loaded fragment 15 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 15 of level 0
hls.mjs:9538 [log] > [stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [stream-controller]: Buffered main sn: 15 of level 0 (frag:[60.000-64.000] > buffer:[0.000-3.950][4.000-64.000])
hls.mjs:9538 [log] > [stream-controller]: PARSED->IDLE
hls.mjs:8769 [log] > [audio-stream-controller]: Loading fragment 15 cc: 0 of [0-1861] track: 0, target: 60.48
hls.mjs:9538 [log] > [audio-stream-controller]: IDLE->FRAG_LOADING
hls.mjs:9538 [log] > [audio-stream-controller]: FRAG_LOADING->PARSING
hls.mjs:8525 [log] > [audio-stream-controller]: Loaded fragment 15 of level 0
hls.mjs:13734 [log] > [transmuxer.ts]: Flushed fragment 15 of level 0
hls.mjs:9538 [log] > [audio-stream-controller]: PARSING->PARSED
hls.mjs:8669 [log] > [audio-stream-controller]: Buffered audio sn: 15 of track 0 (frag:[60.480-64.512] > buffer:[0.000-64.512])
hls.mjs:9538 [log] > [audio-stream-controller]: PARSED->IDLE

Chrome media internals output

No response

@bes bes added Bug Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. labels Aug 22, 2023
@bes
Copy link
Author

bes commented Aug 22, 2023

Unfortunately I can't share the stream.

@robwalch
Copy link
Collaborator

So the element is attached to the player, but not the DOM?

Have you looked for an escape in gap-controller poll()?

@bes
Copy link
Author

bes commented Aug 22, 2023

Thanks, I will try GapController. Is an unattached video element otherwise unsupported?

@robwalch
Copy link
Collaborator

robwalch commented Aug 22, 2023

I was able to play from a disconnected media element and throttle the network to produce a stall that triggered:

this._reportStall(bufferInfo);

@bes
Copy link
Author

bes commented Aug 22, 2023

Is there some way to share the stream privately with you?

EDIT: GitHub app didn't show your above message until it was too late. Sorry.

@robwalch
Copy link
Collaborator

Is there some way to share the stream privately with you?

video-dev Slack https://www.video-dev.org

@bes
Copy link
Author

bes commented Aug 28, 2023

@robwalch maybe I was too slow to click the link? When I click "Join the Slack community" it says

"This link is no longer active To join this workspace, you’ll need to ask the person who originally invited you for a new link."

@robwalch
Copy link
Collaborator

@bes - Please give it another try now. Thanks.

@robwalch
Copy link
Collaborator

Hls.Events.ERROR is never received
audio keeps playing as usual, but video is frozen/does not produce new frames.

I'm a little confused by the description. If the HTMLVideoElement is not in the DOM, how is it that any video or frames would be visible?

As far as I can tell this issue (not reporting stall errors) is a result of the stall check exiting early here:

const bufferInfo = BufferHelper.bufferInfo(media, currentTime, 0);
const isBuffered = bufferInfo.len > 0;
const nextStart = bufferInfo.nextStart || 0;
// There is no playable buffer (seeked, waiting for buffer)
if (!isBuffered && !nextStart) {
return;

This may be easier to reproduce with the element removed from the DOM as the video buffer is likely ignored and stalls only occur when reaching the end of the audio buffer which is more than not ahead of the video buffer.

@robwalch
Copy link
Collaborator

robwalch commented Aug 30, 2023

Ah I see you are copying the video to a texture with OpenGL... Unfortunately it looks like the browser will ignore the video buffer and continue playing through audio when the element is not attached to the DOM. You might want to try attaching the element to the DOM but hiding it with CSS in one of several ways (display: none might have the same effect so absolute positioning offscreen might do the trick).

There is still an issue with stall check exiting early when (audio) playback actually does stall. I have a fix for that (#5779).

For detecting playback getting ahead of the video buffer without playback stalling (currentTime advances normally but frames are likely dropped), keep an eye on #3596 (the work-in-progress for that is up at https://github.com/video-dev/hls.js/compare/feature/video-buffer-starved).

@bes
Copy link
Author

bes commented Aug 30, 2023

Thanks @robwalch

I tried attaching the video element both with display: none, which didn't work, and without it, which didn't work either.

It only starts working once I scroll the video element into view 😭 (Chrome)

So I guess this is a browser issue. Do you think it would be worth it to report this to Chrome? It doesn't stall at all in Firefox or Safari. My thinking is that Chrome should treat copying of video frames to OpenGL in the same way as an attached and visible video element.

@robwalch
Copy link
Collaborator

robwalch commented Aug 30, 2023

You should file an issue, but for now I suggest you implement you own tracking of currentTime in the buffered ranges. The branch I shared may help. You can do this using only video.currentTime, video.buffered.end(n), and the timeupdate event.

@bes
Copy link
Author

bes commented Aug 30, 2023

So I did like this to nudge the videoElement forward after 2 seconds of the video buffer stalling.

    private lastSmallestEnd = 0;

    private checkVideoBufferedRanges = () => {
        if (this.videoElement === null) {
            return;
        }
        if (this.hlsJs === undefined) {
            return;
        }
        const currentTime = this.videoElement.currentTime;
        let smallestEnd = Number.MAX_SAFE_INTEGER;
        try {
            // This is an array of the buffered ranges of all sources [video, audio].
            // This call can throw
            const timeRanges = this.videoElement.buffered;
            if (timeRanges.length > 0) {
                for (let i = 0; i < timeRanges.length; i++) {
                    const end = timeRanges.end(i);
                    console.log("Index and end", { i, end });
                    if (end < smallestEnd) {
                        smallestEnd = end;
                    }
                }
            }
        } catch {
            // Noop
        }

        if (this.lastSmallestEnd !== smallestEnd && this.lastSmallestEnd !== 0) {
            this.lastSmallestEnd = 0;
        }

        if (currentTime > smallestEnd + 2) {
            if (this.lastSmallestEnd !== smallestEnd) {
                console.log("Nudging!");
                this.setTime(currentTime);
                this.lastSmallestEnd = smallestEnd;
            }
        }
    };

But I am surprised that after nudging, and seeing the video start moving again, the smallestEnd variable doesn't change! It's stuck at the old value!

Log:

Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 11.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 11.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 11.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}
Nudging!
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 19.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 23.999999}

@robwalch
Copy link
Collaborator

robwalch commented Aug 30, 2023

Not a Contribution

I thought the issue was that playback was advancing past the end of the video buffer like this:

image

So why do you want to nudge playback?

I would either pause playback so that audio stops until video frames are available (the user experience will be audio and video stalling together), or let audio playback continue as it does now, but track that video is stalled and frames are being dropped, and not copy from the video element since there is nothing new to copy.

@bes
Copy link
Author

bes commented Aug 31, 2023

I can't tell you what is happening, I can only see the symptoms:

  • videoElement.buffered[0] seems to stall at 3.949999
  • If i nudge videoElement.currentTime forward, it starts playing, but buffered[0] does not change
  • I see video moving on screen after nudging

The graphs available at https://hlsjs.video-dev.org/demo/ are they available in the HLS.js package somewhere, so that I can just use them to get a feeling for what is happening?

@bes
Copy link
Author

bes commented Aug 31, 2023

Also, if I add a 1x1px video on the screen, visible, everything "just works", which is irritating, but will probably have to do.

EDIT: This adds about 10% percentage points of load to the page when running.

@robwalch
Copy link
Collaborator

videoElement.buffered[0] seems to stall at 3.949999

There is a video buffer gap between the first and second segment. Related issues:

The graphs available at https://hlsjs.video-dev.org/demo/ are they available in the HLS.js package somewhere, so that I can just use them to get a feeling for what is happening?

https://github.com/video-dev/hls.js/tree/master/demo/chart

@bes
Copy link
Author

bes commented Sep 1, 2023

@robwalch Do you have any publicly available examples of stalling video (but audio continues), that I can use when creating a proof-of-concept bug report for Chrome?

I want to illustrate the difference between using a video element & using opengl canvas, but I don't have any public videos available for that.

@bes
Copy link
Author

bes commented Sep 4, 2023

Wrote an issue directed at Chrome https://bugs.chromium.org/p/chromium/issues/detail?id=1478681

@bes
Copy link
Author

bes commented Sep 6, 2023

Update: I got an answer from a Chromium developer here: https://bugs.chromium.org/p/chromium/issues/detail?id=1478681#c6
In short, they basically recommend the same thing as you did above (I think?)

Would there be a chance of HLS.js getting the option of enabling such a buffer checking, so that everyone doesn't have to reimplement it?

And the follow-up question being; why isn't the .end attribute making progress after nudging the video?

@robwalch
Copy link
Collaborator

robwalch commented Sep 6, 2023

why isn't the .end attribute making progress after nudging the video?

The buffered TimeRange end advances only after audio and video are loaded and appended to the MediaSource audio and video SourceBuffers. If you have a gap in either buffer, you have more than one time range, and it is the last time range which is extended after each append.

Would there be a chance of HLS.js getting the option of enabling such a buffer checking, so that everyone doesn't have to reimplement it?

Some players accept a "min buffer time" or "buffering goal" and stop playback (set rate to 0 or pause) when reaching the buffered end, and only resume when buffer "has enough" or reaches the min/goal.

A feature request and PR contributing this functionality would be accepted as long as it is optional, not on by default (for backwards compatibility), well documented, and aligns with existing player API (HLS.js and similar libraries).

@bes
Copy link
Author

bes commented Sep 6, 2023

Thanks, I'll see what I can manage.

You say:

The buffered TimeRange end advances only after audio and video are loaded and appended to the MediaSource audio and video SourceBuffers. If you have a gap in either buffer, you have more than one time range, and it is the last time range which is extended after each append.

But as I wrote in #5759 (comment) -

  • The (video) buffer seems to stop at 3.949999
  • I nudge the currentTime to somewhere after that, let's say 5s, video + audio are playing
  • Only two buffers are printed in the log, but only the audio buffer is making progress, just like before.

This is extremely surprising to me, super counter-intuitive. If possible, can you explain why am I seeing that behavior?

Like, I can't build anything that "gets me out of that situation" if the buffer information can't be relied on.

I'm at a loss.

@robwalch
Copy link
Collaborator

robwalch commented Sep 6, 2023

Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 11.999999}
Index and end {i: 0, end: 3.949999}
Index and end {i: 1, end: 15.999999}

It's buffering at 11.9 -> 15.9. There is a gap in the buffer starting at 3.9 which will always be reproduced when loading and appending the same video.

Why? Likely an issue with misaligned or overlapping video. See related issue #5743.

To continue playback, you need to seek over (or nudge past) the gap.

@bes
Copy link
Author

bes commented Sep 6, 2023

Yes, and when I do that, buffer[0].end is still stuck at 3.949999.

Maybe we're saying the same thing, but I don't get why buffer[0] (which I assume is video) is stuck at 3.949999 even though I see video moving (after nudging).

Are we saying the same thing? Am I being thick?

@bes
Copy link
Author

bes commented Sep 6, 2023

Thank you for our slack chat @robwalch , it was very helpful.

I just wanted to update my latest understanding here: The different indexes of buffered are not different streams, but rather the available buffered intervals of the audio+video.

It doesn't seem that I can detect this stall using buffered alone. The Chrome person suggested using VideoFrame or requestVideoFrameCallback, but those aren't sufficiently available cross-browser for my needs.

@robwalch
Copy link
Collaborator

robwalch commented Sep 6, 2023

With the video removed from the DOM or display: none, Chrome does not pick up the second video TimeRange after the gap for decoding, unless a seek is performed. There are two video TimeRanges because of a gap in the video buffer between the first and second segment append.

When attached to the DOM and displayed, currentTime advances past the gap while audio is played but video is frozen for 1-2 seconds. Eventually currentTime stalls and audio stops waiting for that gap to filled (this shows up as {video_buffering_state: {reason: "DEMUXER_UNDERFLOW", state: "BUFFERING_HAVE_NOTHING"}}
in the media dev-tools panel Events tab). This stall and associated media element "waiting" event never occur when video is not displayed.

As we have three issues with similar gap issues I'd like to find a solution that removes the gap altogether, but I don't see a path forward when we are passing media to MSE as provided by the source asset. I event tried putting the video SourceBuffer in "sequence" mode and still got a gap, so I'm inclined to think this is unavoidable with certain segments, but I can't tell you why. The media panel offers no clues why an append produces a gap (removing frames?) when it was made at the end of last append.

I can look into having the gap-controller proactively step over video gaps. My concern is that could produce skips in audio and introduces seek operations on platforms perfectly capable of transitioning over these gaps without the same late demuxer underflow that only Chrome seems to exhibit.

@robwalch robwalch added browser: Chrome Stream Issue and removed Needs Triage If there is a suspected stream issue, apply this label to triage if it is something we should fix. cannot reproduce labels Sep 7, 2023
@robwalch robwalch added this to the 1.5.0 milestone Sep 7, 2023
@robwalch
Copy link
Collaborator

robwalch commented Sep 7, 2023

The cause of the video buffer gap is overlapping decode timestamps between the first and second segments:

hls.mjs:12831 [warn] > AVC: 17 ms (-1500dts) overlapping between fragments detected

HLS.js does not shift the samples to prevent overlapping appends when the next segments presentation time is greater than the expected start decode time. If we make an exception for chrome the gap goes away. Here's the code in question:

} else {
logger.warn(
`AVC: ${toMsFromMpegTsClock(
-delta,
true,
)} ms (${delta}dts) overlapping between fragments detected`,
);
}
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts) {
firstDTS = nextAvcDts;
const firstPTS = inputSamples[0].pts - delta;
inputSamples[0].dts = firstDTS;
inputSamples[0].pts = firstPTS;
logger.log(
`Video: First PTS/DTS adjusted: ${toMsFromMpegTsClock(

@robwalch robwalch removed this from the 1.5.0 milestone Sep 7, 2023
@robwalch
Copy link
Collaborator

robwalch commented Sep 7, 2023

Unfortunately, adjusting the first sample of the second segment doesn't work for all related issues. It prevented media from being appended in one, so this is not a fix I think we should make. These gaps are caused by samples at the end of the first segment overlapping with the start of the first.

@robwalch
Copy link
Collaborator

robwalch commented Sep 7, 2023

Hi @bes,

Let me know if #5805 resolves this issue for you. If should prevent the gap at 4s in Chrome without introducing new regressions in buffering.

https://bugfix-chrome-avc-overlap-m2.hls-js-4zn.pages.dev/

@bes
Copy link
Author

bes commented Sep 8, 2023

@robwalch I tried it in my WebGL setup (pulled & built your branch locally), and it works! Big thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants