rx-player icon indicating copy to clipboard operation
rx-player copied to clipboard

Duration is not correct after live ended

Open KunXi-Fox opened this issue 7 months ago • 8 comments

Hi there,

I've noticed that we're having issue with calculate the correct duration for live stream with DVR window after live ended.

I'll trying to explain the issue with example below, let's say:

  • We have a live stream with DVR window, start at 10000
  • User is watching at 10050
  • User has 20 seconds buffered
  • Live stream ended at 10600

Based all those things, while right before live ended, the status should be:

  • videoElement.duration: math.pow(2,32)
  • minimumPosition: 10000
  • maximumPosition: 10600
  • position: 10050

In our codebase, we're calculate the current time and duration as:

currentTime: (position - minimumPosition) = 50 duration: (maximumPosition - minimumPosition) = 600

which is correct.

While live ended, we get:

  • videoElement.duration: 10070 (10050 + 20 which is maxBufferedEnd)
  • minimumPosition: 0
  • maximumPosition: 10070 (which is equal to videoElement.duration)
  • position: 10050

currentTime: (position - minimumPosition) = 10050 duration: (maximumPosition - minimumPosition) = 10070

All those value are totally incorrect, the expected value should be:

currentTime: 50 duration: 600

I've found a way to make current time to correct one, which is after live ended, I call videoElement.current = 50.1 to adjust the current time to correct one. But I can not do anything correct to make duration works fine unless I cache the last dynamic duration (I don't think it's a correct way)

From read code, I found the reason why duration is not correct:

We're change the duration to maxBufferredEnd here:

https://github.com/canalplus/rx-player/blob/766e4467e8e9a47fe13ee446f8b92cec5bbb0881/src/mse/utils/media_source_duration_updater.ts#L183-L193

and after live ended, we're return duration (wrong value) directly:

https://github.com/canalplus/rx-player/blob/766e4467e8e9a47fe13ee446f8b92cec5bbb0881/src/main_thread/api/public_api.ts#L2646-L2650

Is there any other way to get it works? Thanks

KunXi-Fox avatar Aug 06 '25 03:08 KunXi-Fox

Hi,

For the API properties duration and currentTime, those are basically the media time derived from the content and they are not always forced to be starting from a 0 position.

I guess an ending live content would be one of the scenario: there was content before the current available minimum position potentially but it is not available anymore.

To me duration and currentTime should not change suddenly during playback as a live content ends, but what I find strange/not right here is that minimumPosition is updated to 0. It should not, unless the new MPD now provides data dating back to the 0 position... Is that the case? Or maybe it is just unclear for the player in that new "ended live" MPD what the starting position is and thus it just defaults to 0?

peaBerberian avatar Aug 08 '25 15:08 peaBerberian

Yeah, you're correct, from what I observe, the manifest type=static one remove all the DVR window and make the assets starts from 0.

sample mpd:

<?xml version="1.0" encoding="UTF-8"?>
<MPD id="201" mediaPresentationDuration="PT3H30M16.36S" minBufferTime="PT2S" profiles="urn:mpeg:dash:profile:isoff-live:2011" type="static" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:scte35="urn:scte:scte35:2013:xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd">
    <Period duration="PT8.720S" id="27815511" start="PT0S">
    </Period>
    ...
</MPD>

I compared with dashjs as well, for same assets, after live ended, when I access videoElement.duration, it changes to 0 based value as well as videoElement.currentTime.

KunXi-Fox avatar Aug 12 '25 02:08 KunXi-Fox

Also add last-dynamic one for comparison:

<?xml version="1.0" encoding="UTF-8"?>
<MPD availabilityStartTime="2024-07-03T05:21:49.519000+00:00" id="201" minBufferTime="PT2S" minimumUpdatePeriod="PT6S" profiles="urn:mpeg:dash:profile:isoff-live:2011" publishTime="2025-08-01T03:30:43+00:00" suggestedPresentationDelay="PT12.000S" timeShiftBufferDepth="PT12626.880S" type="dynamic" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:scte35="urn:scte:scte35:2013:xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd">
    <Period duration="PT12.840S" id="27815511" start="PT9450H38M29.986S">
    </Period>
    <UTCTiming schemeIdUri="urn:mpeg:dash:utc:http-iso:2014" value="https://time.akamai.com/?iso"/>
</MPD>

KunXi-Fox avatar Aug 12 '25 02:08 KunXi-Fox

If I understand correctly, the MPD completely changes after a refresh when it's ended?

I assumed it only updated things like MPD@type, MPD@mediaPresentationDuration and Period@duration, not also moved the already-declared segments' time.

Is there a presentationTimeOffset attribute also appearing in the MPD once it becomes static (this attribute allows to remove the "live offset" from segment).

I would guess that dash.js reload when it refreshes on the new MPD? (I don't understand how it would align dynamically the currentTime attibute there otherwise). And if it does refresh, does it keep track of the same frame, just at a different currentTime?

peaBerberian avatar Aug 12 '25 10:08 peaBerberian

If I understand correctly, the MPD completely changes after a refresh when it's ended?

From what I compared, the changes is mainly for:

  • MPD tag: availabilityStartTime been removed and mediaPresentationDuration been added, type changes to static
  • Period tag: duration and start been aligned
  • SegmentTemplate tag: presentationTimeOffset value been changed (see image below)
Image

The others are exactly same as dynamic one.

Is there a presentationTimeOffset attribute also appearing in the MPD once it becomes static (this attribute allows to remove the "live offset" from segment).

Yeah, presentationTimeOffset has been defined on SegmentTemplate on static manifest.

I would guess that dash.js reload when it refreshes on the new MPD?

I haven't notice any refresh/interruptions during dynamic transition to static, so I guess the answer is NO.

Although I haven't check the implementation from code level on dashjs.

KunXi-Fox avatar Aug 13 '25 07:08 KunXi-Fox

I would like to take time to deep dive into dashjs code while I get some time.

Duration changes to 0 based seems more straightforward. Dashjs always set mediaSource.duration from the parsed manifest. So once it's became to static, duration actually didn't changes much. And some how the current time been aligned, so the previously buffered segment is been marked as deprecated and been garbage collected in a short time, and then duration can be updated to a correct value.

KunXi-Fox avatar Aug 13 '25 07:08 KunXi-Fox

Updates:

I read this from dash.js: https://github.com/Dash-Industry-Forum/dash.js/issues/4291#issuecomment-1808293039

This is probably because we ignore the last MPD update in the current dynamic to static transition workflow.

Which means dashjs do nothing for last static mpd. I need to test with it again to see why I saw duration and currentTime changes after live ended from dashjs

KunXi-Fox avatar Aug 28 '25 01:08 KunXi-Fox

I'm unsure of what a DASH client need to do if the MPD changes some important information (like the presentationTimeOffset for the same segment) after an MPD update, nor if its authorized.

It seems difficult to handle right all cases. I would have expected just dynamic -> static with segments at the same position than before, which is much easier to manage.

peaBerberian avatar Aug 28 '25 12:08 peaBerberian