-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
fix: media buffer is not empty but video element buffer is empty #6571
fix: media buffer is not empty but video element buffer is empty #6571
Conversation
If the audio and video buffer are not aligned then there is a problem with the HLS source. Can you file an issue that with steps to reproduce? I'd like to understand the root cause before accepting a fix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please define two consts, one for media and one for mediaBuffer, then replace media where necessary.
Yeah the resource is correct. We cannot reproduce the issue in a stable way because the video position is not always accurate. Here is a reproducing step:
My config in your demo page is here: A video snapshot is here: https://drive.google.com/file/d/1grpQx0ROHjxV0K6DfpX-90tdA_Kp_vD4/view?usp=drive_link Why this happenI found the issue is imported by this PR: #5084 It will make an audio fragment and a video fragment check differently sometimes. My example shows it requests audio with the audio fragments: [0-2].... ,[5730.04, 5732.309], [5732.309, 5734.2]...
The requested position is 5732.1
But the maxFragLookUpTolerance(0.25) will make the request to the next fragment [5732.309, 5734.2] not [5730.04, 5732.309] But the video buffer request didn't use So it request the fragment So the buffer in two tracks will be the audio buffer [5732.309, 5734.2]
the video buffer [5729.650, 5732.277]
the video element buffer [] So I think we would better use the media element buffer to check. |
The asset has segments which do not start with a key frame. That explains why initial audio and video segment selection and buffered ranges do not align. hls.js backtracks or requests earlier video segments so that it can buffer video starting from a time earlier than the target start/seek position. |
Hi @JackPu, Have you been able to reproduce this issue in dev (https://hlsjs-dev.video-dev.org/demo/)? I cannot. The issue is really that the audio segment needed is not loaded and that has been fixed. If you are looking for a fix in v1.5.x then we need a change made against the "patch/v1.5.x" branch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A change is needed to ensure seekToStartPos
happens only once there is combined buffer with adjustment if needed. The thing that is missing from this PR is coordination of audio-stream-controller and subtitle-stream-controller:
hls.js/src/controller/audio-stream-controller.ts
Lines 676 to 684 in cedf96d
onFragBuffered(event: Events.FRAG_BUFFERED, data: FragBufferedData) { | |
const { frag, part } = data; | |
if (frag.type !== PlaylistLevelType.AUDIO) { | |
if (!this.loadedmetadata && frag.type === PlaylistLevelType.MAIN) { | |
const bufferable = this.videoBuffer || this.media; | |
if (bufferable) { | |
const bufferedTimeRanges = BufferHelper.getBuffered(bufferable); | |
if (bufferedTimeRanges.length) { | |
this.loadedmetadata = true; |
hls.js/src/controller/subtitle-stream-controller.ts
Lines 194 to 197 in cedf96d
onFragBuffered(event: Events.FRAG_BUFFERED, data: FragBufferedData) { | |
if (!this.loadedmetadata && data.frag.type === PlaylistLevelType.MAIN) { | |
if (this.media?.buffered.length) { | |
this.loadedmetadata = true; |
If we only gate where setting of loadedmetadata
in stream-controller to delay seek to start, audio and subtitles may set theirloadedmetadata
to true first and on next tick load fragments at currentTime which is still set to 0:
hls.js/src/controller/base-stream-controller.ts
Lines 1482 to 1492 in cedf96d
protected getLoadPosition(): number { | |
const { media } = this; | |
// if we have not yet loaded any fragment, start loading from start position | |
let pos = 0; | |
if (this.loadedmetadata && media) { | |
pos = media.currentTime; | |
} else if (this.nextLoadPosition) { | |
pos = this.nextLoadPosition; | |
} | |
return pos; |
There's a few other places where loadedmetadata
is read so this is a risky change to make. It's adding a dependency that the combined buffer be populated after appending a 'main' fragment when that could also happen when appending audio (if main is already buffered). This could delay start times or lock up seek to start entirely - which is what we want to fix, but I cannot reproduce in dev.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix for this in patch/v1.5.x would be to add || !this.startFragRequested
to to this conditional so that on start the audio and main stream controllers use strict tolerance (0) for initial fragment selection independent of loadedmetadata
:
hls.js/src/controller/base-stream-controller.ts
Lines 1304 to 1305 in cedf96d
const lookupTolerance = | |
bufferEnd > end - maxFragLookUpTolerance ? 0 : maxFragLookUpTolerance; |
Same here for dev where there is already an additional check for paused
added in #6524. I cannot reproduce this issue in dev because media is a paused at start prior to seeking to the start position (but you could break that by calling play() successfully before reaching this point):
hls.js/src/controller/base-stream-controller.ts
Lines 1439 to 1444 in b472831
const lookupTolerance = | |
backwardSeek || | |
bufferEnd > end - maxFragLookUpTolerance || | |
this.media?.paused | |
? 0 | |
: maxFragLookUpTolerance; |
Hi @JackPu, I've incorporated v1.6.0 fixes for this issue in #6591. It addresses the fragment selection that misses the audio needed on startup, and also delays seek to start until both audio and video source buffers are provisioned ( Please try the branch build here https://feature-interstitials.hls-js-4zn.pages.dev/ |
Thank you so much. It works for me. And it did solve my problems. And my PR is not good enough. It will increase the join time(loadStart -> loadeddata). And I have patched your PR now #6524 |
I have another issue. But I cannot find the reason. Maybe it could be about the level switch. I have upgraded the branch in our own repo from 1.2.7 -> 1.5.7. We use the |
Yes. Please file an issue. |
Closing as this is being addressed in #6591. |
This PR will
It will solve one edge case: the
mediaBuffer
is not empty, but the video elementbuffered
is empty, so theseekToStartPosition
can be executed.Why is this Pull Request needed?
The video will freeze if we can not seek the correct position in the special case:
Then it will not increase the gap delta position because the
bufferStart
is 0.Are there any points in the code the reviewer needs to double check?
Resolves issues:
Checklist