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

Does an MPD with SegmentTimeline necessarily need to use wallclock? #1233

Closed
leandromoreira opened this issue Jan 19, 2018 · 18 comments
Closed
Assignees
Labels
status: archived Archived and locked; will not be updated type: docs Improvements or fixes to documentation
Milestone

Comments

@leandromoreira
Copy link
Contributor

Have you read the FAQ and checked for duplicate issues: Yes

What version of Shaka Player are you using: v2.3.0-uncompiled

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: Demo

If custom app, can you reproduce the issue using our demo app:

What browser and OS are you using: MacOS 10.13 Firefox 57.0.4

What are the manifest and license server URIs:

<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:ns1="http://www.w3.org/2001/XMLSchema-instance" availabilityStartTime="2017-10-18T16:23:54Z" minBufferTime="PT2S" minimumUpdatePeriod="PT0S" publishTime="2017-12-06T13:41:34Z" timeShiftBufferDepth="PT120S" type="dynamic" ns1:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash-if-simple">
  <Period start="PT0S" id="0">
    <AdaptationSet id="1990" mimeType="audio/mp4" contentType="audio" lang="por" segmentAlignment="true" startWithSAP="1" audioSamplingRate="48000">
      <Representation id="1988" bandwidth="96000" codecs="mp4a.40.5">
        <SegmentTemplate timescale="1" media="116_audio-$Time$.mp4" initialization="data:video/mp4;base64,CAFE">
          <SegmentTimeline>
            <S t="5263668" d="10" r="12"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
    <AdaptationSet id="1989" mimeType="video/mp4" contentType="video" frameRate="30/1" segmentAlignment="true" startWithSAP="1" par="16:9" maxWidth="768" maxHeight="432">
      <Representation id="1986" bandwidth="626000" codecs="avc1.64001F" sar="1:1" width="512" height="288">
        <SegmentTemplate timescale="1" media="116_626-$Time$.mp4" initialization="data:video/mp4;base64,CAFE">
          <SegmentTimeline>
            <S t="5263668" d="10" r="12"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
      <Representation id="1987" bandwidth="1485000" codecs="avc1.64001F" sar="1:1" width="768" height="432">
        <SegmentTemplate timescale="1" media="116_1485-$Time$.mp4" initialization="data:video/mp4;base64,CAFE">
          <SegmentTimeline>
            <S t="5263668" d="10" r="12"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

What did you do?

Try to play a live streaming, that I already played using DASHjs reference player.

What did you expect to happen?

The player to use solely the SegmentTimeline values to retrieve the live edge segment.

What actually happened?

It did not. It seems that it uses the now() - (AST + Period.start) - delay as the base to calculate the edge segment Time. I came to this conclusion by debuging this live stream.

Long Story;

While reading some docs on that I was under the impression that the player could find the first segment (most recent) by itself with no dependency on any clock at all.

(current wall clock time according to player - time at which first segment became available according to manifest) / (duration / timescale) + 1 = number of most recent segment

The problem with this formula is that the calculation will only be accurate if both the player and the origin use the exact same timing, which is far from obvious. Even the official DASH specification acknowledges this as it lists a variety of reasons why a player and origin would use conflicting time sources.

For instance, let's take this SegmentTemplate:

        <SegmentTemplate timescale="1" media="116_audio-$Time$.mp4" initialization="data:video/mp4;base64,CAFE">
          <SegmentTimeline>
            <S t="5263668" d="10" r="12"/>
          </SegmentTimeline>
        </SegmentTemplate>

The way I know which segment is the edge of this live streaming is:

"take the last time the 't'-element was specified and add the total duration of all of the following segments to it, except for the last segment signaled in the manifest and there you have it: the timestamp of this last segment without the need to know the current wall clock time."

t=5263668+12*10*1

Is this assumption backed by the DASH specs? (since I couldn't find on the guidelines but at the same time the DASHjs is able to play it)

@leandromoreira
Copy link
Contributor Author

I read some closed issues:

And all of them stick with this notion of wallclock, I'll set the right AST but I still would like to know if this clock sync is required for all live streaming and why on earth dashjs support this.

@sandersaares
Copy link
Contributor

sandersaares commented Jan 19, 2018

I am quite sure the answer is "yes, it must be in wall clock time and any dash.js behavior to the contrary is an accident" but I will leave it to player authors to go in depth about that. I just wanted to mention that clock-sync is solved by the UTCTiming element in DASH (defined in 2014 amd 1), which provides an authoritative time source to the client and thus defines "wall clock time" unambiguously.

Edit: this is if you want to be IOP-conforming. Non-IOP-conforming behavior can be far more flexible, of course.

@leandromoreira
Copy link
Contributor Author

Thank you @sandersaares 😄

@joeyparrish
Copy link
Member

We currently take a strict view of this and require the presentation timeline (derived from AST) to be correct. In future, we may be more flexible, to better tolerate drift in live streams. See #999 for details.

@leandromoreira
Copy link
Contributor Author

leandromoreira commented Feb 9, 2018

Hi nice people,

I changed my server-side implementation to rely on the sequential scheme ($Number) to avoid this AST timing but the player still shows, seemingly timing errors about cannot find segment t=500002.838.
(v2.3.0-uncompiled, demo app running locally, MacOS 10.13, Firefox 58.0.1)

Please noticed that I didn't update my availabilityStartTime.

Should I remove the t from <S>? Also, shouldn't Shaka discard any attempt to get timing in this scheme?

<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:ns1="http://www.w3.org/2001/XMLSchema-instance" availabilityStartTime="2017-10-18T16:23:54Z" minBufferTime="PT2S" minimumUpdatePeriod="PT0S" publishTime="2017-12-06T13:41:34Z" timeShiftBufferDepth="PT120S" type="dynamic" ns1:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" profiles="urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash-if-simple">
  <Period start="PT0S" id="0">
    <AdaptationSet id="1990" mimeType="audio/mp4" contentType="audio" lang="por" segmentAlignment="true" startWithSAP="1" audioSamplingRate="48000">
      <Representation id="1988" bandwidth="96000" codecs="mp4a.40.5">
        <SegmentTemplate timescale="1" media="116_audio-$Number$.mp4" startNumber="4463029" initialization="data:video/mp4;base64,CAFE">
          <SegmentTimeline>
            <S t="5263668" d="10" r="12"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
    <AdaptationSet id="1989" mimeType="video/mp4" contentType="video" frameRate="30/1" segmentAlignment="true" startWithSAP="1" par="16:9" maxWidth="768" maxHeight="432">
      <Representation id="1986" bandwidth="626000" codecs="avc1.64001F" sar="1:1" width="512" height="288">
        <SegmentTemplate timescale="1" media="116_626-$Number$.mp4" startNumber="4463029" initialization="data:video/mp4;base64,CAFE">
          <SegmentTimeline>
            <S t="5263668" d="10" r="12"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
      <Representation id="1987" bandwidth="1485000" codecs="avc1.64001F" sar="1:1" width="768" height="432">
        <SegmentTemplate timescale="1" media="116_1485-$Number$.mp4" startNumber="4463029" initialization="data:video/mp4;base64,CAFE">
          <SegmentTimeline>
            <S t="5263668" d="10" r="12"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

@leandromoreira
Copy link
Contributor Author

I also tried to use the Elemental Delta segmenter to generate DASH but it doesn't play as well. Here's their generated MDP.

<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd" id="110" type="dynamic" publishTime="2018-02-09T12:26:44" minimumUpdatePeriod="PT15S" availabilityStartTime="2017-11-19T17:41:42.573000+00:00" minBufferTime="PT15S" suggestedPresentationDelay="PT30.00S" timeShiftBufferDepth="PT59.50S" profiles="urn:hbbtv:dash:profile:isoff-live:2012,urn:mpeg:dash:profile:isoff-live:2011">
  <Period start="PT0.00S" id="1">
    <AdaptationSet mimeType="video/mp4" scanType="progressive" segmentAlignment="true" subsegmentAlignment="true" startWithSAP="1" subsegmentStartsWithSAP="1" bitstreamSwitching="true">
      <Representation id="1" width="768" height="432" frameRate="30/1" bandwidth="1485000" codecs="avc1.64001F">
        <SegmentTemplate timescale="30" media="coelhao_video_1_2_$Number$.mp4?m=1516907594" initialization="coelhao_video_1_2_init.mp4?m=1516907594" startNumber="4467355">
          <SegmentTimeline>
            <S t="211975782" d="300" r="4"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
      <Representation id="2" width="512" height="288" frameRate="30/1" bandwidth="626000" codecs="avc1.64001F">
        <SegmentTemplate timescale="30" media="coelhao_video_1_3_$Number$.mp4?m=1516907594" initialization="coelhao_video_1_3_init.mp4?m=1516907594" startNumber="4467355">
          <SegmentTimeline>
            <S t="211975782" d="300" r="4"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
    <AdaptationSet mimeType="audio/mp4" segmentAlignment="0" lang="eng">
      <Representation id="3" bandwidth="96000" audioSamplingRate="48000" codecs="mp4a.40.5">
        <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"></AudioChannelConfiguration>
        <SegmentTemplate timescale="48000" media="coelhao_audio_1_1_$Number$.mp4?m=1516907594" initialization="coelhao_audio_1_1_init.mp4?m=1516907594" startNumber="4467355">
          <SegmentTimeline>
            <S t="339161257599" d="479232"/>
            <S t="339161736831" d="481280"/>
            <S t="339162218111" d="479232"/>
            <S t="339162697343" d="481280"/>
            <S t="339163178623" d="479232"/>
          </SegmentTimeline>
        </SegmentTemplate>
      </Representation>
    </AdaptationSet>
  </Period>
</MPD>

@leandromoreira
Copy link
Contributor Author

I'm planning to find a way to expose these resource so you can test it.

@TheModMaker
Copy link
Contributor

Every live manifest type requires clock sync. Changing from duration to SegmentTimeline only changes how the segments are represented, it doesn't change the timeline. We still require accurate clock sync to determine where to start playing. When we start playing a live stream, we calculate now and use that to determine the live edge, which is at now - AST.

Looking at the Elemental manifest, if we fetched your manifest at 2018-02-09T12:26:44 (the publishTime), then the live edge is at 7094701 seconds. The last audio segment in your manifest starts at 7065899 seconds or close to 8 hours off. My guess is that this is a timezone problem.

@leandromoreira
Copy link
Contributor Author

leandromoreira commented Feb 9, 2018

thanks, @TheModMaker I'll take a closer look at it ;D

@leandromoreira
Copy link
Contributor Author

I was trying to understand what you've described and I'm still wondering how this information is used to determine the segment that Shaka needs to request.

For instance, I ran a ruby program here to understand the relation between these variables (mostly availabilityStartTime, SegmentTemplate@timescale and S@t )

AST_UTC=1511113302
#=> 1511113302
NOW=Time.now.to_i
#=> 1518199697
LIVE_EDGE=NOW - AST_UTC
#=> 7086395 (is this the wallclock?)
t_x=339163178623
#=> 339163178623 (last S@t for audio)
timescale=48000
#=> 48000 (ts for audio)
STARTS_AT=t_x/timescale
#=> 7065899
LIVE_EDGE
#=> 7086395
STARTS_AT
#=> 7065899
(LIVE_EDGE-STARTS_AT)
#=> 20496
(LIVE_EDGE-STARTS_AT)/60/60
# => 5 (in hours)

At the end how does shaka uses the S@t to determine the Segment to request?

@TheModMaker
Copy link
Contributor

You can look at #1265 for an in-depth description of how segment times work. It deals with multi-Period live, but the basic concepts are the same.

Basically there is a concept of a "presentation time". This represents the time that a segment will be played. For our case, this also maps to the <video> current time. Presentation times start at 0. For live content, the wall-clock time of availabilityStartTime represents 0. So when you specify that a segment starts at S@t of 339163178623 (in timescale units), then that is the presentation time that it will be played at (presentationTimeOffset and Period@start can change this, but you don't use it).

When we start streaming, we need to determine what presentation time to start playing at. We use now - AST to determine the presentation time to play at. So in your ruby code, we start playing at presentation time 7086395 seconds.

Note that you can't change the S@t times because they need to match the values in the media segments. If you change the manifest, when we append the segment to the <video> element, it will appear at the wrong time in the video timeline.

@leandromoreira
Copy link
Contributor Author

Thank you very much @TheModMaker I learned more here and I'll read the docs again =D but if I have any relevant doubt I'll post it here.

@leandromoreira
Copy link
Contributor Author

leandromoreira commented Feb 12, 2018

Hi @TheModMaker @sandersaares and @joeyparrish thank you again for the attention and help,

I read the guideline and ISO again (at least the sections on the timeline) and I'm still with some doubts, but first, let's see if I really understood it right.

Let's continue with this pseudo code scenario, after that I'll post my question:

AST = 1000
PUBLISH = 1900
UTC_TAG = 1900
PERIOD_START = 0
PTO = 0

SEGMENTS = [ 
  {SEQ: 0, DURATION: 10, T: 1880}, 
  {SEQ: 1, DURATION: 10, T: 1890}, 
  {SEQ: 2, DURATION: 10, T: 1900}
]

CLIENT_NOW = UTC_TAG

START_PRESENTATION_TIME = CLIENT_NOW - AST # or live edge

# 900

dash timeline example

  1. Given that the START_PRESENTATION_TIME is 900 what a dash client (shaka) does is it to search the segment list for a S@t equals to AST + START_PRESENTATION_TIME?

  2. Given that AST is 0 (in wall clock) does this mean that shaka should use the segment SEQ=2 to start playing?

  3. Once Shaka knows which Segment to start, does it drops the timing logic and follows the SEQ + 1 to deal with segment availability?

  4. If I want to reduce latency (by the cost of shorter segments and probably more rebuffers) how can I instruct a dash client (shaka) to start at my last segment ($Number)?

  5. In case of $Number templating, do we only check timing to determine the live edge? (this one I'll try to read the code too)

Some random thoughts

I think that we should offer or be by default less strict with timing but I know that deep inside this is mostly an MPEG dash spec "problem", it'd be pretty good if there was a simple MPEG dash spec for live streaming.

I really loved what US proposed (although I thought it was on specs ¬¬), basically a dash client should rely only on S@t to determine the availability so we could use t as PTS or other info we have in the encoder (in @timescale units) and it could be more precise than clock time.

@joeyparrish joeyparrish added the type: question A question from the community label Feb 12, 2018
@joeyparrish joeyparrish reopened this Feb 12, 2018
@TheModMaker
Copy link
Contributor

See #999 for ignoring availabilityStartTime and just using segment times for determining start time.

I will write up a doc describing this is much more detail since there has been a lot of confusion about how live works in Dash.

It is important to note: segment times are in presentation time, not wall clock time. Please ignore wall clock time since it is ONLY used to determine where we start playing. We only use it to determine where to set video.currentTime initially. Once we have it set, we ignore any wall clock time. (There is one exception when we calculate availability, but that is entirely separate from this discussion)

So you start streaming, what presentation time do we start at? It is now - AST, which is 1900 - 1000 or 900. So we set video.currentTime to 900 and start streaming.

From this point forward, we only deal with presentation times. These times start at 0 and go forward (think like a VOD stream). While we are streaming, we look at video.currentTime to determine which segment we should download next. We determine each segment's presentation time and use that to pick the right segment.

So lets convert the three segments you listed to their presentation times. A segment has a presentation time of: (@t - @presentationTimeOffset) / @timescale + Period@start

Segment 0 will have a presentation time of: (1880 - 0) / 1 + 0 or 1880. Similarly segment 1 will have 1890, and segment 2 will have 1900. So your segments are 1000 seconds in the future.


I think that we should offer or be by default less strict with timing but I know that deep inside this is mostly an MPEG dash spec "problem", it'd be pretty good if there was a simple MPEG dash spec for live streaming.

This exists, it is called the IOP Guidelines. This is much more realistic and restrictive than the DASH spec itself. But even that is a bit permissive on what is allowed.

Given that the START_PRESENTATION_TIME is 900 what a dash client (shaka) does is to search the segment list for a S@t equals to AST + START_PRESENTATION_TIME?

The segment times are in presentation time, so this doesn't use AST. Once we have 900, we look up a segment with a presentation time of 900.

Given that AST is 0 (in wall clock) does this mean that shaka should use the segment SEQ=2 to start playing?

That is not correct. AST is equivalent to 0 in presentation time. So if AST is 1000 in wall clock time, then that is equivalent to 0 in presentation time. But again, this only means that if we start playing at 1900 wall clock time (e.g. using Date.now), then we are at 900 in presentation time.

Once Shaka know which Segment to start does it drops the timing logic and follows the SEQ + 1 to deal with segment availability?

Yes and no. Once we start streaming we will just pick the next segment. But if we seek, we need to look up which segment to start at. But again, we are using video.currentTime to lookup the presentation time of the segments.

If I want to reduce latency (by the cost of shorter segments and probably more rebuffers) how can I instruct a dash client (shaka) to start at my last segment ($Number)?

You can't. After #999 we will do it by default, but there is no way to do it now.

In case of $Number templating, do we only check timing to determine the live edge? (this one I'll try to read the code too)

There is NO difference between different kinds of manifests. You can use $Time$ or $Number$, you can use SegmentTemplate or SegmentList, it makes no difference. The only difference is how you represent the segments. SegmentList uses an explicit list of URLs, SegmentTemplate uses a format template. $Time$ and $Number$ is just a format specifier (like %s in printf), it doesn't affect timings in any way.

So this:

<SegmentTemplate timescale="1" media="Foo-$Number$.mp4" initialization="init.mp4">
  <SegmentTimeline>
    <S t="0" d="10"/>
    <S d="10"/>
    <S d="10"/>
    <S d="10"/>
    <S d="10"/>
  </SegmentTimeline>
</SegmentTemplate>

Is exactly the same as:

<SegmentTemplate timescale="1" media="Foo-$Number$.mp4" initialization="init.mp4" 
    duration="10" />

@TheModMaker TheModMaker self-assigned this Feb 12, 2018
@leandromoreira
Copy link
Contributor Author

leandromoreira commented Feb 12, 2018

I will write up a doc describing this is much more detail since there has been a lot of confusion about how live works in Dash.

First, sorry to make you go again and again in your explanation. It'd be very helpful to have such doc! A sample code (with controlled Presentation and Wall Clock timing) and diagrams can help.

Please ignore wall clock time since it is ONLY used to determine where we start playing. We only use it to determine where to set video.currentTime initially.

Redoing my example in pseudo code:

# -------------------------|AST|------|NOW|->
AST = 100 

# at AST=100 my encoder started to split segments of 10 seconds
# starting with S[0]@t=0 then ten seconds later S[1]@t=10 and so on..

PUBLISH = 130
UTC_TAG = 130
# thirty seconds after I publish an (new) mpd
PERIOD_START = 0
PTO = 0

# it has some previous segments
SEGMENTS = [ 
  {SEQ: 0, DURATION: 10, T: 10}, 
  {SEQ: 1, DURATION: 10, T: 20}, 
  {SEQ: 2, DURATION: 10, T: 30}
]

CLIENT_NOW = UTC_TAG

START_PRESENTATION_TIME = CLIENT_NOW - AST
# video.currentTime=30
# from this point and beyond it'll rely mostly on S[x]@t
  1. With this example, does it means that shake will play the segment (number 2 ) as the live edge?
  2. Does TSB change anything in here?

It seems to me that the AST marks the starting of the presentation timeline (t=0) and then the encoder must increase its S[x]@t each segment (S[x]@r) following the SegmentTimeline@timescale and S[x]@d.

@TheModMaker
Copy link
Contributor

First, sorry to make you go again and again in your explanation. It'd be very helpful to have such doc! A sample code (with controlled Presentation and Wall Clock timing) and diagrams can help.

No problem. I'm happy to help.

  1. With this example, does it means that shake will play the segment (number 2) as the live edge?

Actually we will be playing at segment 1. I forgot we need to offset by the segment duration. So "right now" is 30, but that time is still being recorded on the server. We need to wait for the whole segment to be recorded, so we will be playing at least 10 seconds in the past. So the real live edge will be 20.

  1. Does TSB change anything in here?

TSB only changes whether a segment is "available". This can be thought of as a DVR window, you can play the last TSB seconds of a live stream. Anything older than that isn't available, so you can't seek to it. For example, if the TSB was 15, then in your example, we'll allow seeking in the range [5, 20]. But this moves as time goes on with the live edge, so one second later it will be [6, 21], then after one second, [7, 22].

@leandromoreira
Copy link
Contributor Author

leandromoreira commented Feb 14, 2018

Thank you very much @TheModMaker I think I finally understood and I'll adapt my server-side code to be compliant with Dash.

I'll be happy to help or give feedback or read the doc you're going to do.

cheers.

@joeyparrish joeyparrish added type: docs Improvements or fixes to documentation and removed type: question A question from the community labels Feb 26, 2018
@joeyparrish joeyparrish added this to the Backlog milestone Feb 26, 2018
@joeyparrish joeyparrish modified the milestones: Backlog, v2.4.0 Mar 2, 2018
joeyparrish pushed a commit that referenced this issue Mar 21, 2018
Closes #1233
Issue #1265

Change-Id: I3f207bedd4a943ca49ddc580f152e92e33d7e89a
@joeyparrish
Copy link
Member

New doc cherry-picked for v2.3.4.

@shaka-project shaka-project locked and limited conversation to collaborators Apr 30, 2018
@shaka-bot shaka-bot added the status: archived Archived and locked; will not be updated label Apr 15, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: archived Archived and locked; will not be updated type: docs Improvements or fixes to documentation
Projects
None yet
Development

No branches or pull requests

5 participants