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

Smooth period transition #2580

Merged

Conversation

aescarcha
Copy link
Contributor

This PR introduces buffer reuse for compatible codecs and preload of next periods to avoid jumps and freezes when switching periods.

It also introduces some changes to the SourceBufferSink to handle the appends and removes with a queue.

It's the same as #2575 but with clearer commit history.
Closes #1708

@robertbryer
Copy link
Contributor

Good stuff!

Trying to seek to the next period doesn't work when you have already preloaded into the period. I get:

"This SourceBuffer has been removed from the parent media source."

So I think a normal buffer reset is being called after the preload when you seek like this.

@@ -644,6 +702,80 @@ function Stream(config) {
checkIfInitializationCompleted();
}

function isCompatibleWithStream(stream) {
return compareCodecs(stream, Constants.VIDEO) && compareCodecs(stream, Constants.AUDIO);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will return false for audio-only (and video-only streams), which is incorrect.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires a few changes like checking if the previous / next period has audio and video to avoid saving the non-needed buffer or recreating it, will add it last.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added commit d7f4b8f to allow preload of audio-only or video-only periods, but won't work when switching from a video/audio period to a video-only one

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following that commit, this works great for multiperiod audio-only services 🍾

@davemevans
Copy link
Contributor

Streams signalling InbandEvent throw the following error on Period transition, and playback stops:

Uncaught TypeError: Cannot read property 'addInbandEvents' of undefined
    at Object.onMediaFragmentLoaded (streaming\controllers\BufferController.js:227)
    at core\EventBus.js:88
    at Array.forEach (<anonymous>)
    at Object.trigger (core\EventBus.js:88)
    at Object.onFragmentLoadingCompleted (streaming\controllers\FragmentController.js:138)
    at core\EventBus.js:88
    at Array.forEach (<anonymous>)
    at Object.trigger (core\EventBus.js:88)
    at Object.onLoadingCompleted (streaming\models\FragmentModel.js:310)
    at core\EventBus.js:88

Example manifest:

<?xml version="1.0" encoding="UTF-8"?>
<MPD type="static" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:dvb="urn:dvb:dash-extensions:2014-1" profiles="urn:dvb:dash:profile:dvb-dash:2014,urn:dvb:dash:profile:dvb-dash:isoff-ext-live:2014" minBufferTime="PT2.049S" maxSegmentDuration="PT3.84S" mediaPresentationDuration="PT38.40S">
	<BaseURL serviceLocation="A" dvb:priority="1" dvb:weight="1">http://rdmedia.bbc.co.uk/dash/ondemand/testcard/1/</BaseURL>
	<Period duration="PT19.2S" start="PT0S">
		<AdaptationSet startWithSAP="2" segmentAlignment="true" id="1" sar="1:1" mimeType="video/mp4" >
			<InbandEventStream schemeIdUri="tag:rdmedia.bbc.co.uk,2014:events/ballposition" value="1"/>
			<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
			<BaseURL>avc3-events/</BaseURL>
			<SegmentTemplate startNumber="1" timescale="1000" duration="3840" media="$RepresentationID$/$Number%06d$.m4s" initialization="$RepresentationID$/IS.mp4" />
			<Representation id="1920x1080i25" codecs="avc3.640028" height="1080" width="1920" frameRate="25" scanType="interlaced" bandwidth="8060152" />
		</AdaptationSet>
		<AdaptationSet startWithSAP="2" segmentAlignment="true" id="2" codecs="mp4a.40.5" audioSamplingRate="48000" lang="eng" mimeType="audio/mp4" >
			<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
			<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
			<BaseURL>audio/</BaseURL>
			<SegmentTemplate startNumber="1" timescale="1000" duration="3840" media="$RepresentationID$/$Number%06d$.m4s" initialization="$RepresentationID$/IS.mp4" />
			<Representation id="96kbps" bandwidth="96000" />
		</AdaptationSet>
	</Period>
	<Period start="PT19.2S" duration="PT19.2S">
		<AdaptationSet startWithSAP="2" segmentAlignment="true" id="1" sar="1:1" mimeType="video/mp4" >
			<InbandEventStream schemeIdUri="tag:rdmedia.bbc.co.uk,2014:events/ballposition" value="1"/>
			<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
			<BaseURL>avc3-events/</BaseURL>
			<SegmentTemplate startNumber="6" presentationTimeOffset="19200" timescale="1000" duration="3840" media="$RepresentationID$/$Number%06d$.m4s" initialization="$RepresentationID$/IS.mp4" />
			<Representation id="1920x1080i25" codecs="avc3.640028" height="1080" width="1920" frameRate="25" scanType="interlaced" bandwidth="8060152" />
		</AdaptationSet>
		<AdaptationSet startWithSAP="2" segmentAlignment="true" id="2" codecs="mp4a.40.5" audioSamplingRate="48000" lang="eng" mimeType="audio/mp4" >
			<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
			<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
			<BaseURL>audio/</BaseURL>
			<SegmentTemplate startNumber="6" presentationTimeOffset="19200" timescale="1000" duration="3840" media="$RepresentationID$/$Number%06d$.m4s" initialization="$RepresentationID$/IS.mp4" />
			<Representation id="96kbps" bandwidth="96000" />
		</AdaptationSet>
    </Period>
</MPD>

@davemevans
Copy link
Contributor

Overall, this is great stuff. The performance is significantly better than without this patch, but I see some strange behaviour (differing between browsers) happening and the result is not completely seamless. I believe the content is correct and should be seamlessly playable.

In Chrome (66, Windows 7), the video always pauses on the frame displaying timecode 00:00:18:18. The audio sounds like it is seamless but it's hard to tell without a continuous tone.

In Firefox (61, Windows 7), the video and audio glitch on the frame displaying timecode 00:00:19:04 (which is the final frame of the first Period).

Example MPD:

Same as in #2580 (comment), but with InbandEventStreams removed.

return buffer.buffered;
} catch (e) {
log('getAllBufferRanges exception: ' + e.message);
return [];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm expecting this function to either return something null-like, or an object implementing the timeranges interface: .start(n) .end(n) .length. Array here works, because the empty array returns length 0 and then nobody calls start or end in that case, but it seems initially confusing reading this to be returning an array. Maybe add an explainer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Null it is then

@aescarcha
Copy link
Contributor Author

aescarcha commented May 23, 2018

I added 2 commits to fix @robertbryer issues.

@bbcrddave I can reproduce the InbandEvent issue, but if I remove the <InbandEventStream tag from the mpd it works flawlessly in Chrome 66, and have a small audio glitch in Firefox 60 (both in MacOS).

EDIT: Fixed the InbandEvent issue, I also tested on Windows 10 and saw some frames are dropped while transitioning on Firefox if using old hardware ( i5-540M, RAM 4GB ) but Chrome and Edge worked like a charm. I tested it in a newer laptop and every browser worked fine.

@epiclabsDASH
Copy link
Contributor

Thanks for all the great feedback! Given the importance of the changes of this PR and the need of testing it exhaustively, I am going to keep this out of dash.js v2.7.0 (code freeze today). Let's continue testing this and I will do the merge once we feel comfortable with this PR and after releasing dash.js v2.7.0.

@davemevans
Copy link
Contributor

I updated Chrome to the latest patch level and it now appears to play smoothly through the transition 👍
I still get an audible glitch and momentary paused frame in Firefox, in all versions (Beta, Nightly etc).

@davemevans
Copy link
Contributor

Something weird is happening which, in the worst case, is occasionally causing playback to stop and, in the best case, causing segments to be redownloaded. Given the manifest below, at the period transition, a portion of the buffered but as-yet-unplayed range is removed. Sometimes the segments are redownloaded and appended again, sometimes playback stalls. The buffered range removed is always the same.

Log highlights:

[119488] Requesting seek to time: 19.2
[119501] Seeking to: 19.2
[119503] Removing video buffer from: 0 to 18.7
[119513] Removing video buffer from: 27.38 to 35.06

Sample manifest:

<?xml version="1.0" encoding="UTF-8"?>
<MPD type="static" xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:dvb="urn:dvb:dash-extensions:2014-1" profiles="urn:dvb:dash:profile:dvb-dash:2014,urn:dvb:dash:profile:dvb-dash:isoff-ext-live:2014" minBufferTime="PT2.049S" maxSegmentDuration="PT3.84S" mediaPresentationDuration="PT38.40S">
	<BaseURL serviceLocation="A" dvb:priority="1" dvb:weight="1">http://rdmedia.bbc.co.uk/dash/ondemand/testcard/1/</BaseURL>
	<Period duration="PT19.2S" start="PT0S">
		<AdaptationSet startWithSAP="2" segmentAlignment="true" id="1" sar="1:1" mimeType="video/mp4" >
			<InbandEventStream schemeIdUri="tag:rdmedia.bbc.co.uk,2014:events/ballposition" value="1"/>
			<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
			<BaseURL>avc3-events/</BaseURL>
			<SegmentTemplate startNumber="1" timescale="1000" duration="3840" media="$RepresentationID$/$Number%06d$.m4s" initialization="$RepresentationID$/IS.mp4" />
			<Representation id="1920x1080i25" codecs="avc3.640028" height="1080" width="1920" frameRate="25" scanType="interlaced" bandwidth="8060152" />
		</AdaptationSet>
	</Period>
	<Period start="PT19.2S" duration="PT19.2S">
		<AdaptationSet startWithSAP="2" segmentAlignment="true" id="1" sar="1:1" mimeType="video/mp4" >
			<InbandEventStream schemeIdUri="tag:rdmedia.bbc.co.uk,2014:events/ballposition" value="1"/>
			<Role schemeIdUri="urn:mpeg:dash:role:2011" value="main"/>
			<BaseURL>avc3-events/</BaseURL>
			<SegmentTemplate startNumber="6" presentationTimeOffset="19200" timescale="1000" duration="3840" media="$RepresentationID$/$Number%06d$.m4s" initialization="$RepresentationID$/IS.mp4" />
			<Representation id="1920x1080i25" codecs="avc3.640028" height="1080" width="1920" frameRate="25" scanType="interlaced" bandwidth="8060152" />
		</AdaptationSet>
    </Period>
</MPD>

@aescarcha
Copy link
Contributor Author

@bbcrddave fixed in ea21de8 , seek was called if track was only audio or only video, it's weird that it only caused troubled with some streams...

@epiclabsDASH epiclabsDASH added this to the 2.8 milestone May 25, 2018
@epiclabsDASH epiclabsDASH merged commit 6565361 into Dash-Industry-Forum:development Jun 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants