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

Seekable differs from non-MSE behavior #5

Closed
dmlap opened this issue Jul 10, 2015 · 37 comments
Closed

Seekable differs from non-MSE behavior #5

dmlap opened this issue Jul 10, 2015 · 37 comments

Comments

@dmlap
Copy link

dmlap commented Jul 10, 2015

The MSE spec seems to indicate that the highest end time for seekable should never exceed the highest buffered time when the duration is set to Infinity. The HTML standard indicates that duration should be Infinity for unbounded or live media and that user agents should be very liberal determining seekable ranges for media.

Safari on iOS and OSX seems to have interpreted this as meaning that the seekable range should include the time ranges covered by all segments in the current "sliding window" of content in a live HLS video. That definition is convenient because it makes seeking to the live point or building a DVR interface a simple operation for downstream developers, and seems in keeping with the spirit of the HTML standard. It does not seem possible to configure Source Buffers or a Media Source to achieve the same effect. Is there a mechanism to override seekable with out-of-band info like you might get from an M3U8?

@dmlap
Copy link
Author

dmlap commented Aug 18, 2015

As a consequence of the current seekable definition and step 8 of the video seeking algorithm, I believe out-of-buffer seeking is not possible for live streams. MSE specifies the seekable ranges to be the union of the current buffered regions and the video spec constrains seeking to time positions within the seekable range.

To make things a bit more concrete, imagine you have a sliding-window style live stream manifest with five video segments currently available. After a bit of buffering, your player has downloaded one segment. In Safari and iOS devices, you would be allowed to set the current time to any position that is greater than three segment durations from the latest available position. With Media Source Extensions, you would only be able to seek within the segment you currently have buffered:

Manifest:
     0            1          2           3           4
| -------- |  -------- |  -------- |  -------- |  -------- |

Buffered:
     0
| -------- |

MSE Seekable:
     0
| -------- |

"Native" HTML5 Seekable:
     0            1          2
| -------- |  -------- |  -------- |

@jdsmith3000
Copy link
Contributor

The issue in this bug seems to involve consistency of behavior, but not interoperability, assuming I understand it correctly. The impact seems to limit how close to real-time a user can seek on live streams. Moving beyond the limits of buffered data should temporarily stall playback until buffering is restored, while limiting the seek to within the buffered range would minimize the risk of that.

@dmlap
Copy link
Author

dmlap commented Aug 25, 2015

Yes, the issue is about consistency with the HTML spec's guidelines for live playback behavior.

I may be missing something in your point about real-time playback. It seems to me that the stream can be joined arbitrarily close to real-time by adjusting where to begin appending data into a Source Buffer. What you can't do (I think) is instruct the video element to seek back two minutes if you only have one currently appended in your Source Buffer, unlike media with a known duration or non-MSE live implementations.

@heff
Copy link

heff commented Aug 25, 2015

It sounds like we need a mechanism similar to mediaSource.duration, but for live content where duration must be Infinity.

With non-live content the app can set mediaSource.duration, which informs the MediaSource what video data (outside of buffered) is available to the app. The MediaSource assumes the start time is zero and that we can seek anywhere up to duration, despite having none of it buffered.

With live content the MediaSource can't look at duration because it must be Infinity, and can't assume the start time is zero. So it currently only relies on buffered, which is a very limited view point. If the UI were to respect seekable (blocking seeks outside of the buffered range) but display the actual content length that's available to the app, it would be a frustrating experience for the viewer. Expanding seekable to represent the full length of the content available to the app would be no less safe than the non-live use case, there just isn't a way to do that.

So it seems like it would helpful if the MediaSource provided more control over defining the start time and end time of the available media timeline. What if it were direct control over what seekable returns?

mediaSource.seekableStart = ...
mediaSource.seekableEnd = ...

Changes to those properties could reuse the durationchange event.

@dmlap
Copy link
Author

dmlap commented Aug 25, 2015

@heff that's a great summary of the problem, thanks. Something like your proposal does seem like it would address the issue. One minor suggestion: Time Ranges support non-contiguous regions. I don't know of a streaming format that makes use of that feature but it could be added without complicating the API too much since Time Ranges are normalized:

mediaSource.addSeekableRange(240, 360);
mediaSource.removeSeekableRange(260, 280);

@wolenetz
Copy link
Member

If I understand correctly, there are two live-stream seeking problems related to MSE described so far in this issue:

  1. MSE assumes live (infinite duration) streams start at time 0. It assumes the same for non-live streams, too.
  2. MSE disallows seeking beyond the end of currently buffered media for live (infinite duration) streams.

Both of these could lead to non-ideal default UI controls and behavior, especially when combined.
My understanding is that both of these could be alleviated by apps overriding default UI controls to adapt to the live streaming case (though not ideal, since a standardized expectation of better behavior consistency is the request in this issue).

@dmlap I am confused, though, by "What you can't do (I think) is instruct the video element to seek back two minutes if you only have one currently appended in your Source Buffer, unlike media with a known duration or non-MSE live implementations."
In MSE, seekable (when duration equals positive Infinity, and there is a non-empty HTMLMediaElement.buffered TimeRanges), is a range [0, highest_end_time_of_buffered]. So you, could indeed seek back two minutes if you only have one currently appended, so long as there is sufficient room in the timeline prior to the currently appended media. Note that the currently appended media need not have a buffered start at time 0. Am I misunderstanding something?

@dmlap
Copy link
Author

dmlap commented Aug 26, 2015

@wolenetz I'd agree with your formulation of the issues. I didn't realize the start point of seekable was pegged to zero for live media. In that case, I believe you're correct and my example was a bad one (and clarifies @jdsmith3000's original comment for me, thanks!). The issue would be restricted to seeking forward in live streams.

One follow-up question on the start point of seekable: pegging the start point to zero seems like it could be a problem for long-running live streams. The SourceBuffer is eventually going to run out of space and the live window will march on. How should applications handle seeks to timeline positions that were evicted from the buffer and are no longer available to be downloaded?

@wolenetz
Copy link
Member

The issue of SourceBuffer running out of space is orhogonal, IMHO, and handled separately by the user agent's implementation of the coded frame eviction algorithm (http://www.w3.org/TR/media-source/#sourcebuffer-coded-frame-eviction). In appendBuffer() usage, this algorithm is run prior to parsing newly appended media into the timeline (and throws a QuotaExceededErr if not enough space was freed). In appendStream() usage, the same behavior occurs synchronously during the call of appendStream(); the eviction algorithm also runs during each iteration of the stream append loop, though no QuotaExceededErr is thrown from there, but there is an error transition by which an app can discover the problem. Regardless, if the user-agent's choice of removal ranges within its coded frame eviction algorithm was insufficient to free enough space, the app is given notification and can explicitly Remove() buffered ranges.

The problem really is two-fold:

  1. How can an app or user seek forward beyond end of currently buffered in an MSE live-stream (that has Infinite duration)?

  2. There's some interop issues already between Chrome's strict compliance and other's less compliance around disallowing unrestricted doubles in TimeRanges. This causes different results across various user agents in MSE when the HTMLMediaElement has reached HAVE_METADATA, but otherwise has nothing buffered. In Chrome MSE, an app couldn't seek before anything is buffered; in others, the seekable range (and allowance for seeking) is less strict (because they allow unrestricted double of +Infinity in seekable range: see also https://code.google.com/p/chromium/issues/detail?id=461733#c23).

I believe an API like MediaSource.setSeekableRange([start,end]) could satisfy both problems (in #2, an app could achieve more interoperable behavior by explicitly setting a non-finite seekable range that overrides the default logic in existing MSE spec.

jdsmith@, is this new API suggestion acceptable? I think it solves at least one real problem users of MSE are having, which is "how can apps reliably control the MSE seekable range in live (infinite duration) streams?"

@dmlap
Copy link
Author

dmlap commented Sep 25, 2015

@jdsmith3000 have you been able to give this issue some thought? I'd be happy to attempt a PR against the spec with @wolenetz's suggestion if that would help move things along.

@jdsmith3000
Copy link
Contributor

Would this API then alter the response from mediaSource.seekable? And would the effects persist as streaming continued?

@wolenetz: Given the double limitation you site on the seekable TimeRange, what does Chrome return for a live stream with duration = infinity? To me, it makes sense to return the full range, and have the app then limit the forward seeking to current real time.

@dmlap
Copy link
Author

dmlap commented Sep 29, 2015

For consistency with the video element's seekable attribute, I think the API should override the response of mediaSource.seekable and be persistent. The current behavior of mediaSource.seekable for live streams doesn't actually provide any information that isn't available to the application developer through other mechanisms in MSE and responding with different values than the media element itself would confuse me, at least.

@jdsmith3000
Copy link
Contributor

I've had some discussions here, but haven't closed. We aren't convinced that having the app set a seekable range is the right solution. It seems instead that we might want a concept where apps can jump to the live edge. Some formats might also have problems with zero based timestamps (e.g. MPEG-2 TS timestamps roll over every 26 ½ hours, so it’s not as simple as taking the timestamp for a segment and mapping it into a simple zero based timestamp).

@dmlap
Copy link
Author

dmlap commented Oct 13, 2015

Could you elaborate on what sort of concept you had in mind to allow an app to jump to the live edge? The only ideas I can come up with seem to require info from the app about where the live edge is, which devolves into a seekable setter of some flavor.

@wolenetz
Copy link
Member

+interop label to follow-up on the TimeRanges discrepancy in Edge vs others (also, need to confirm if unrestricted double TimeRanges are being done in Edge)

@jdsmith3000 jdsmith3000 added this to the V1 milestone Oct 15, 2015
@foolip
Copy link
Member

foolip commented Oct 23, 2015

To me, it makes sense to return the full range, and have the app then limit the forward seeking to current real time.

@jdsmith3000, assuming that by this you mean that end times in TimeRanges should be allowed to be Infinity, this doesn't sound great from the PoV of HTMLMediaElement, to me:
https://code.google.com/p/chromium/issues/detail?id=461733#c27

The per-spec model for seeking media elements is that the requested time is clamped to seekable ranges, and then normally that's precisely where you'll end up. If at all possible, I think MSE should behave the same way.

Simply allowing the seekable ranges to be set sounds pretty good to me. If you'd like a constructor for TimeRanges so that you can add a settable SourceBuffer.seekable attribute that might work. A setSeekable() that takes and array or array-of-arrays would also do the trick.

@jdsmith3000
Copy link
Contributor

I'm aware of live streaming players built on the current API that accomplish seekable ranges by implementing custom controls and their own time ranges. These span from the live edge back through a DVR window maintained by the server. The current API isn't specifically aware of either limit, and knows only that duration is +infinity.

Allowing apps to set a seekable range for this case could approximate both limits and enable live seeking using either the standard controls or custom ones that still use the seekable range from the API. Presumably the seekable range would be set at least with each append of new sourceBuffer data. That append contains the most current live data, and the app can extrapolate the DVR limit using window data from the manifest or some other source.

We previously talked about these times persisting once set. That makes seekeable limits in this case the responsibility of the app, and that's probably fine. We would likely want to somehow limit apps from using this on VoD content, where valid time ranges exist. This might be done by allowing seekable ranges to be set only on duration +infinity content, or where the API itelf cannot supply valid time ranges.

Assuming we can agree on this limitation, I'd support going ahead with implementing something like this approach:

mediaSource.addSeekableRange(240, 360);

I'm less clear on the proposed

@jdsmith3000
Copy link
Contributor

Completing my previous statement: I'm less clear about the proposed

@jdsmith3000
Copy link
Contributor

mediaSource.removeSeekableRange(260, 280);

For seekable ranges with gaps in them, and would like to discuss this at the TPAC session.

@jdsmith3000
Copy link
Contributor

I don't recall the TPAC discussions for sure, but believe that there was some concern about letting a custom range clip the buffered one. I think your suggestion of using the union of the custom range and the buffered one addresses this, and means that custom ranges are primarily for expanding seekable ranges, likely into live DVR time ranges.

Is it your intent that setting custom ranges can be done multiple times, and individual ranges are stored for use in calculating the union with buffered data? I've been thinking we want a single custom range to for DVR type uses, and this would need to be updated frequently to insure the oldest DVR time is accurate.

On naming, I think shorter is better, and prefer setSeekableRange despite the union operation with buffered data.

@dmlap
Copy link
Author

dmlap commented Jan 28, 2016

@wolenetz @jdsmith3000 anything I can do to help resolve this issue? Sounds like the preference is for a seekable range setter instead of get/remove. #42 doesn't fit that bill but if it's roughly the sort of contribution you'd expect, I'd be happy to trying a new patch for setSeekableRange.

@wolenetz
Copy link
Member

@dmlap, your PR is currently pending on:

  1. fixing the failed IPR check (w3c folks are aware), and
  2. ensuring it covers the approach outlined in @jdsmith3000 's most recent response, above.
    If (1) is delayed much longer, either @jdsmith3000 or I will move forward with a separate PR to fix this.

@dmlap
Copy link
Author

dmlap commented Mar 30, 2016

@wolenetz thanks for the update. I don't know if or when I'll be able to resolve (1). If my PR is making this issue harder to address, please don't hesitate to close it. I'll be happy knowing this live streaming use-case is supported by MSE v1-- it doesn't matter to me if my wording is used or not.

@wolenetz
Copy link
Member

OK, it looks like we need to make progress on this. I'll compose a PR soon to attempt to fix this.

@paulbrucecotton
Copy link

@wolenetz: When is your proposed PR going to be ready for review?

@wolenetz
Copy link
Member

We synced on this during today's editors' sync. @jdsmith3000 and I are on the same page and I will proceed with a PR. The naming of the new method is still something we'd like to simplify, and we also think just a single range (if any) for the custom_seekable_range is necessary (we don't have any other use cases identified which need multiple disjoint custom_seekable_ranges, and the existing spec behavior for seekable with finite duration is a single range [0,duration).

@wolenetz
Copy link
Member

wolenetz commented Jun 8, 2016

fyi - this is a test message, since I'm suddenly getting a warning on all my github pages:
"One of our mostly harmless robots seems to think you are not a human.
Because of that, it’s hidden your profile from the public. If you really are human, please contact support to have your profile reinstated. We promise we won’t require DNA proof of your humanity."

I've contacted their support. Hopefully this won't impact my immediate work.

@wolenetz wolenetz removed their assignment Jun 8, 2016
@wolenetz
Copy link
Member

wolenetz commented Jun 8, 2016

I didn't unassign myself. Looks like GH's "mostly harmless robot" did that and I can't reassign myself. I'll continue until blocked...

@wolenetz
Copy link
Member

wolenetz commented Jun 8, 2016

It looks like GH has now just fixed my profile problem. That outage happened at a bad time, to say the least.

@wolenetz wolenetz self-assigned this Jun 8, 2016
wolenetz added a commit that referenced this issue Jun 9, 2016
Fix #5: Add support for customizing seekable on live MSE streams
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Jul 17, 2016
…gerald

See w3c/media-source#5

MozReview-Commit-ID: EP37gRmUAXF

--HG--
extra : rebase_source : cd134517a3f1d50bce2f17a82acabe0f2bb042cb
lissyx pushed a commit to mozilla-b2g/gecko-tablet that referenced this issue Jul 17, 2016
jryans pushed a commit to jryans/gecko-dev that referenced this issue Jul 20, 2016
janekptacijarabaci pushed a commit to janekptacijarabaci/Pale-Moon that referenced this issue Jul 30, 2017
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this issue Sep 30, 2019
…gerald

See w3c/media-source#5

MozReview-Commit-ID: EP37gRmUAXF

UltraBlame original commit: fcb130529e8206fb65ed0bff9837762d29cd7a1a
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this issue Sep 30, 2019
…gerald

See w3c/media-source#5

MozReview-Commit-ID: EP37gRmUAXF

UltraBlame original commit: fcb130529e8206fb65ed0bff9837762d29cd7a1a
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this issue Sep 30, 2019
…gerald

See w3c/media-source#5

MozReview-Commit-ID: EP37gRmUAXF

UltraBlame original commit: fcb130529e8206fb65ed0bff9837762d29cd7a1a
@falk-stefan
Copy link

I am not sure if this is a 100% related but how are we seeking when we load audio files in chunks or segments? The issue I am having is that if I want to play an mp3 from the middle, currentTime will be set to an arbitrary value and increase from there instead of going from where I would like it to.

See my stackoverflow question for details. Any help on this would be awesome!

@wolenetz
Copy link
Member

@falk-stefan, I've responded to your stackoverflow question today. Also, in addition to duration, you'll probably want to inspect in your repro what your media element reports as its buffered ranges when the seek is issued. (e.g. element.buffered).

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

No branches or pull requests

7 participants