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

Seeking during initial update_ fetches all segments from 0 seconds to the seek location #3299

Closed
naktinis opened this issue Mar 31, 2021 · 5 comments · Fixed by #3795 or #4009
Closed
Labels
priority: P2 Smaller impact or easy workaround status: archived Archived and locked; will not be updated type: bug Something isn't working correctly
Milestone

Comments

@naktinis
Copy link

Have you read the FAQ and checked for duplicate open issues?
Yes.

What version of Shaka Player are you using?
v3.0.10.

Can you reproduce the issue with our latest release version?
Yes.

Can you reproduce the issue with the latest code from master?
Yes.

Are you using the demo app or your own custom app?
Custom app.

If custom app, can you reproduce the issue using our demo app?
Not sure.

What browser and OS are you using?
MacOS 11.2.2, Firefox 87.

For embedded devices (smart TVs, etc.), what model and firmware version are you using?
N/A

What are the manifest and license server URIs?
N/A

What configuration are you using? What is the output of player.getConfiguration()?
N/A

What did you do?
Seek soon after "loadedmetadata". For example:

video.addEventListener('loadedmetadata', function() {
    setTimeout(() => video.currentTime = 165, 1);
});

What did you expect to happen?
Video should stop buffering at current playhead (t=0), then seek to the requested time (t=165), and from there buffer bufferingGoal (30 s, in this case) of data.

What actually happened?
It started downloading segments from t=0 to t=165+bufferingGoal. So it downloaded 195 seconds of data instead of downloading 30 seconds (bufferingGoal) of data.

It does appear that calling this.forceClearBuffer_(mediaState) in seeked() (streaming_engine.js) solves the problem. Note that it's not deterministic, but I think with the current test setup I can reproduce it ~9/10 times (so I still may be missing something).

My current interpretation of v2 logs is that something like this is happening:

  • manifest is loaded
  • update_() is called for the first time and starts to download data
  • seek is initiated
  • appendBuffer is not yet called (still processing XHR) so in seeked() somethingBuffered returns false
  • as a result of somethingBuffered being false forceClearBuffer is not called
  • since forceClearBuffer is not called, the original update_ is not interrupted
  • however presentationTime is updated to the new seek time and somehow that makes update_ download all this unnecessary data between 0 and 195 seconds.

Part of the log when this happens:

(video:4) update_: presentationTime=0 bufferedAhead=0
...
(video:4) fetching segment
...
Seek to 165   <- I think at this point appendBuffer may be working, but not done yet
...
(all): seeked: buffered seek: presentationTime=165   <- inaccurate log message, buffer.length is 0 here
...
(video:4) fetchAndAppend_: presentationTime=165 reference.startTime=5 reference.endTime=10
(video:4) fetching segment
fetching: reference= Object { startTime: 5, endTime: 10... <- fetching segment 5..10 sec (should fetch ~165..170 sec)
...   <- keeps fetching 10..15, 15..20, 20..25... until over 165 sec (the seek location)

Is it possible that something like this is happening?

@OrenMe
Copy link
Contributor

OrenMe commented Apr 21, 2021

You can pass initial start time via config and then shaka optimizes loading from that point.

@naktinis
Copy link
Author

naktinis commented Apr 21, 2021

@OrenMe thanks for the suggestion, but during the load() call the seek time is not yet known. First, I want to load the video as soon as possible (the critical part), and then in the background find the appropriate seek time that depends on some conditions (needs an HTTP request; this is a "slow" and non-critical part).

This ticket is about making seeking more predictable, intuitive, and well-defined. It does look like a bug at the first glance.

@TheModMaker
Copy link
Contributor

I was able to reproduce on Firefox, but not Chrome for some reason. I was also able to reproduce on the nightly site.

@TheModMaker TheModMaker added type: bug Something isn't working correctly priority: P3 Useful but not urgent and removed needs triage labels Apr 26, 2021
@TheModMaker TheModMaker added this to the v3.2 milestone Apr 26, 2021
@joeyparrish joeyparrish added priority: P2 Smaller impact or easy workaround and removed priority: P3 Useful but not urgent labels May 5, 2021
@joeyparrish joeyparrish modified the milestones: v3.2, v3.3 Jul 7, 2021
@pcruiksh
Copy link
Contributor

I have just observed similar behaviour with 3.1.0 on Chrome, seeking HLS content. However this doesn't just occur during initial update_().

After several arbitrary seeks, the streaming engine gets stuck buffering segments to catch up with the new playback position, instead of buffering from the seek target. Playback resumes when segments are finally buffered beyond the presentation time. Here is an example seeking to presentation time 5734:

image

image

@pcruiksh
Copy link
Contributor

pcruiksh commented Dec 6, 2021

This seems to be resolved by also clearing the buffer under the condition mediaState.performingUpdate, as this gets set prior to initializing the source buffer, so there is a window where you could seek while waiting for the source buffer to initialize, and before the initial fetch operation is created, so the buffer is not cleared, and the upcoming operation is not aborted, so one media state continues to fetch and update, effectively ignoring the seek.

I can reproduce this fairly reliably with two unbuffered seeks in close succession (takes a bit of trial and error to get the interval timing just right), but not at all with the above change.

theodab pushed a commit that referenced this issue Jan 14, 2022
Previously, we only cleared the buffer if the media state had
something buffered. This ensured that we did not pointlessly clear the
buffer when nothing was there.
However, this lead to problems if a seek was performed early during the
loading process, before the source buffer is initialized. During that
time, nothing is buffered, so we would not clear the buffer on a seek.
This lead to us accidentally fetching content from the beginning of the
presentation, rather than starting from the new clock time.
This changes the streaming engine to also clear the buffer if
mediaState.performingUpdate is true, to avoid that situation.

Closes #3299
joeyparrish pushed a commit that referenced this issue Jan 28, 2022
Previously, we only cleared the buffer if the media state had
something buffered. This ensured that we did not pointlessly clear the
buffer when nothing was there.
However, this lead to problems if a seek was performed early during the
loading process, before the source buffer is initialized. During that
time, nothing is buffered, so we would not clear the buffer on a seek.
This lead to us accidentally fetching content from the beginning of the
presentation, rather than starting from the new clock time.
This changes the streaming engine to also clear the buffer if
mediaState.performingUpdate is true, to avoid that situation.

Closes #3299
joeyparrish pushed a commit that referenced this issue Jan 28, 2022
Previously, we only cleared the buffer if the media state had
something buffered. This ensured that we did not pointlessly clear the
buffer when nothing was there.
However, this lead to problems if a seek was performed early during the
loading process, before the source buffer is initialized. During that
time, nothing is buffered, so we would not clear the buffer on a seek.
This lead to us accidentally fetching content from the beginning of the
presentation, rather than starting from the new clock time.
This changes the streaming engine to also clear the buffer if
mediaState.performingUpdate is true, to avoid that situation.

Closes #3299
joeyparrish pushed a commit that referenced this issue Jan 28, 2022
Previously, we only cleared the buffer if the media state had
something buffered. This ensured that we did not pointlessly clear the
buffer when nothing was there.
However, this lead to problems if a seek was performed early during the
loading process, before the source buffer is initialized. During that
time, nothing is buffered, so we would not clear the buffer on a seek.
This lead to us accidentally fetching content from the beginning of the
presentation, rather than starting from the new clock time.
This changes the streaming engine to also clear the buffer if
mediaState.performingUpdate is true, to avoid that situation.

Closes #3299
@github-actions github-actions bot added the status: archived Archived and locked; will not be updated label Mar 15, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2022
@avelad avelad modified the milestones: v3.3, v4.0 May 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
priority: P2 Smaller impact or easy workaround status: archived Archived and locked; will not be updated type: bug Something isn't working correctly
Projects
None yet
7 participants