Skip to content

Commit

Permalink
fix(DASH): Live to vod transition (#7404)
Browse files Browse the repository at this point in the history
The PR is solving playback error in a Multi period manifest when the
start time is not 0.
Additionally, solving the error code 3015 due to the clear of the buffer
during the playback.
Fixes #7401
  • Loading branch information
Iragne authored Oct 15, 2024
1 parent 051a8c5 commit 2d14dd5
Show file tree
Hide file tree
Showing 15 changed files with 232 additions and 2 deletions.
1 change: 1 addition & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ module.exports = (config) => {
{pattern: 'test/test/assets/dash-multi-codec/*', included: false},
{pattern: 'test/test/assets/dash-multi-codec-ec3/*', included: false},
{pattern: 'test/test/assets/3675/*', included: false},
{pattern: 'test/test/assets/7401/*', included: false},
{pattern: 'test/test/assets/6339/*', included: false},
{pattern: 'test/test/assets/dash-aes-128/*', included: false},
{pattern: 'test/test/assets/dash-clearkey/*', included: false},
Expand Down
6 changes: 4 additions & 2 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1341,11 +1341,13 @@ shaka.dash.DashParser = class {
for (let i = 0; i < periodNodes.length; i++) {
const elem = periodNodes[i];
const next = periodNodes[i + 1];
const start = /** @type {number} */ (
let start = /** @type {number} */ (
TXml.parseAttr(elem, 'start', TXml.parseDuration, prevEnd));
const periodId = elem.attributes['id'];
const givenDuration =
TXml.parseAttr(elem, 'duration', TXml.parseDuration);
start = (i == 0 && start == 0 && this.isTransitionFromDynamicToStatic_) ?
seekRangeStart : start;

let periodDuration = null;
if (next) {
Expand All @@ -1355,7 +1357,7 @@ shaka.dash.DashParser = class {
const nextStart =
TXml.parseAttr(next, 'start', TXml.parseDuration);
if (nextStart != null) {
periodDuration = nextStart - start;
periodDuration = nextStart - start + seekRangeStart;
}
} else if (presentationDuration != null) {
// "The Period extends until the Period.start of the next Period, or
Expand Down
40 changes: 40 additions & 0 deletions test/player_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,46 @@ describe('Player', () => {
expect(seekRange.start).toBeCloseTo(start);
});
});
describe('Live to VOD', () => {
it('playback transition when current time is in the past', async () => {
const netEngine = player.getNetworkingEngine();
const startTime = Date.now();
netEngine.registerRequestFilter((type, request) => {
if (type != shaka.net.NetworkingEngine.RequestType.MANIFEST) {
return;
}
// Simulate a live stream by providing different manifests over time.
const time = (Date.now() - startTime) / 1000;
const manifestNumber = Math.min(5, Math.floor(0.5 + time / 2));
request.uris = [
'/base/test/test/assets/7401/dash_' + manifestNumber + '.mpd',
];
console.log('getting manifest', request.uris);
});
player.configure('streaming.bufferBehind', 1);
player.configure('streaming.evictionGoal', 1);
// Play the stream .
await player.load('/base/test/test/assets/7401/dash_0.mpd', 1020);
await video.play();
video.pause();
// Wait for the stream to be over.
eventManager.listen(player, 'error', Util.spyFunc(onErrorSpy));
/** @type {shaka.test.Waiter} */
const waiter = new shaka.test.Waiter(eventManager)
.setPlayer(player)
.timeoutAfter(40)
.failOnTimeout(true);
// wait for Dynamic to static
await waiter.waitUntilVodTransition(video);
expect(player.isLive()).toBe(false);
// set the playback to 1020 in middle of the second period
video.currentTime = 1020;
await video.play();
await waiter.waitForEnd(video);
// The stream should have transitioned to VOD by now.
expect(player.isLive()).toBe(false);
});
});

describe('attach', () => {
beforeEach(async () => {
Expand Down
Binary file added test/test/assets/7401/chunk-stream0-00001.m4s
Binary file not shown.
Binary file added test/test/assets/7401/chunk-stream0-00002.m4s
Binary file not shown.
Binary file added test/test/assets/7401/chunk-stream0-00003.m4s
Binary file not shown.
Binary file added test/test/assets/7401/chunk-stream0-00004.m4s
Binary file not shown.
Binary file added test/test/assets/7401/chunk-stream0-00005.m4s
Binary file not shown.
Binary file added test/test/assets/7401/chunk-stream0-00006.m4s
Binary file not shown.
Binary file added test/test/assets/7401/chunk-stream0-00007.m4s
Binary file not shown.
52 changes: 52 additions & 0 deletions test/test/assets/7401/dash_0.mpd
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:mpeg:dash:schema:mpd:2011"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
profiles="urn:mpeg:dash:profile:isoff-live:2011"
type="dynamic"
minimumUpdatePeriod="PT2S"
suggestedPresentationDelay="PT2S"
availabilityStartTime="2021-10-28T07:35:57.755Z"
publishTime="2021-10-28T07:36:29.744Z"
timeShiftBufferDepth="PT42.0S"
maxSegmentDuration="PT2.0S"
minBufferTime="PT4.0S">
<ProgramInformation>
</ProgramInformation>
<ServiceDescription id="0">
</ServiceDescription>
<Period id="0" start="PT1000.0S" duration="PT14.0S">
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="6" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
<Period id="1" start="PT1014.0S" duration="PT14.0S">
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="6" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
<Period id="2" start="PT1028.0S" >
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="1" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
</MPD>
52 changes: 52 additions & 0 deletions test/test/assets/7401/dash_1.mpd
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:mpeg:dash:schema:mpd:2011"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
profiles="urn:mpeg:dash:profile:isoff-live:2011"
type="dynamic"
minimumUpdatePeriod="PT2S"
suggestedPresentationDelay="PT2S"
availabilityStartTime="2021-10-28T07:35:57.755Z"
publishTime="2021-10-28T07:36:31.750Z"
timeShiftBufferDepth="PT42.0S"
maxSegmentDuration="PT2.0S"
minBufferTime="PT4.0S">
<ProgramInformation>
</ProgramInformation>
<ServiceDescription id="0">
</ServiceDescription>
<Period id="0" start="PT1000.0S" duration="PT14.0S">
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="6" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
<Period id="1" start="PT1014.0S" duration="PT14.0S">
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="6" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
<Period id="2" start="PT1028.0S" >
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="2" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
</MPD>
48 changes: 48 additions & 0 deletions test/test/assets/7401/dash_2.mpd
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:mpeg:dash:schema:mpd:2011"
xmlns:xlink="http://www.w3.org/1999/xlink"
xsi:schemaLocation="urn:mpeg:DASH:schema:MPD:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
profiles="urn:mpeg:dash:profile:isoff-live:2011"
type="static"
mediaPresentationDuration="PT42.0S"
maxSegmentDuration="PT2.0S"
minBufferTime="PT4.0S">
<ProgramInformation>
</ProgramInformation>
<ServiceDescription id="0">
</ServiceDescription>
<Period id="0" start="PT0.0S" duration="PT14.0S">
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="6" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
<Period id="1" start="PT14.0S" duration="PT14.0S">
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="6" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
<Period id="2" start="PT28.0S" duration="PT14.0S">
<AdaptationSet id="0" contentType="video" startWithSAP="1" segmentAlignment="true" bitstreamSwitching="true" frameRate="30/1" maxWidth="1280" maxHeight="720" par="16:9">
<Representation id="0" mimeType="video/mp4" codecs="avc1.64001f" bandwidth="122012" width="1280" height="720" sar="1:1">
<SegmentTemplate timescale="15360" initialization="init-stream$RepresentationID$.m4s" media="chunk-stream$RepresentationID$-$Number%05d$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30720" r="6" />
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
</MPD>
Binary file added test/test/assets/7401/init-stream0.m4s
Binary file not shown.
35 changes: 35 additions & 0 deletions test/test/util/waiter.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,41 @@ shaka.test.Waiter = class {
return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
}

/**
* Wait for the video player to fetch the static manifest.
* Promise is resolved player.isLive is false.
*
* @param {!HTMLMediaElement} mediaElement
* @return {!Promise}
*/
waitUntilVodTransition(mediaElement) {
// The name of what we're waiting for
const goalName = 'manifest to be static';

// The cleanup on timeout
let timer = null;
const cleanup = () => {
if (timer) {
timer.stop();
}
};

// The conditions for success
const p = new Promise((resolve) => {
const check = () => {
if (!this.player_.isLive()) {
cleanup();
resolve();
}
};

timer = new shaka.util.Timer(check);
timer.tickEvery(/* seconds= */ 1);
});

return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
}

/**
* Wait for the video playhead to reach a certain target time.
* If the playhead reaches |timeGoal| or the video ends before |timeout|
Expand Down

0 comments on commit 2d14dd5

Please sign in to comment.