Skip to content

Commit

Permalink
feat: Update usage of minBufferTime according to the DASH spec
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed Nov 18, 2024
1 parent d8a14b0 commit 8603c8a
Show file tree
Hide file tree
Showing 19 changed files with 10 additions and 127 deletions.
13 changes: 0 additions & 13 deletions docs/tutorials/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,19 +191,6 @@ the ad blocker in compiled mode as well.

<hr>

**Q:** Why does some DASH content take a long time to start playback?

**A:** Shaka Player honors the `minBufferTime` field in DASH. If this field is
set to a large value, Shaka Player will buffer that much content before
beginning playback. To override this behavior and ignore the `minBufferTime`
field, we offer the following configuration:

```js
player.configure('manifest.dash.ignoreMinBufferTime', true);
```

<hr>

**Q:** My HLS stream is failing on Chrome, with a chunk demuxer append failed
error.

Expand Down
1 change: 0 additions & 1 deletion docs/tutorials/manifest-parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ MyManifestParser.prototype.loadManifest_ = function(data) {

return {
presentationTimeline: timeline,
minBufferTime: 5, // seconds
offlineSessionIds: [],
variants: [
this.loadVariant_(true, true),
Expand Down
7 changes: 0 additions & 7 deletions docs/tutorials/network-and-buffering-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,6 @@ content will be removed from the start of the buffer to save memory.
This is a minimum; if the stream's max segment size is longer than the
'bufferBehind', then that will be used instead.


*NOTES:*
- *`rebufferingGoal` should always be less than `bufferingGoal`.*
- *A DASH manifest's `minBufferTime`, if greater, overrides `rebufferingGoal`.*
- *You can ignore `minBufferTime` by setting the
`manifest.dash.ignoreMinBufferTime` configuration to true.*

All of these settings should be customized for your application. The default
values are very conservative.

Expand Down
6 changes: 0 additions & 6 deletions externs/shaka/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* textStreams: !Array.<shaka.extern.Stream>,
* imageStreams: !Array.<shaka.extern.Stream>,
* offlineSessionIds: !Array.<string>,
* minBufferTime: number,
* sequenceMode: boolean,
* ignoreManifestTimestampsInSegmentsMode: boolean,
* type: string,
Expand Down Expand Up @@ -76,11 +75,6 @@
* @property {!Array.<string>} offlineSessionIds
* <i>Defaults to [].</i> <br>
* An array of EME sessions to load for offline playback.
* @property {number} minBufferTime
* <i>Defaults to 0.</i> <br>
* The minimum number of seconds of content that must be buffered before
* playback can begin. Can be overridden by a higher value from the Player
* configuration.
* @property {boolean} sequenceMode
* If true, we will append the media segments using sequence mode; that is to
* say, ignoring any timestamps inside the media files.
Expand Down
3 changes: 1 addition & 2 deletions externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -1104,8 +1104,7 @@ shaka.extern.xml.Node;
* Defaults to <code>false</code>.
* @property {boolean} ignoreMinBufferTime
* If true will cause DASH parser to ignore <code>minBufferTime</code> from
* manifest. It allows player config to take precedence over manifest for
* <code>rebufferingGoal</code>.
* manifest.
* <br>
* Defaults to <code>false</code>.
* @property {boolean} autoCorrectDrift
Expand Down
4 changes: 0 additions & 4 deletions lib/dash/dash_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -799,10 +799,7 @@ shaka.dash.DashParser = class {

await contentSteeringPromise;

// Set minBufferTime to 0 for low-latency DASH live stream to achieve the
// best latency
if (this.lowLatencyMode_) {
minBufferTime = 0;
const presentationDelay = suggestedPresentationDelay != null ?
suggestedPresentationDelay : this.config_.defaultPresentationDelay;
presentationTimeline.setDelay(presentationDelay);
Expand All @@ -818,7 +815,6 @@ shaka.dash.DashParser = class {
textStreams: this.periodCombiner_.getTextStreams(),
imageStreams: this.periodCombiner_.getImageStreams(),
offlineSessionIds: [],
minBufferTime: minBufferTime || 0,
sequenceMode: this.config_.dash.sequenceMode,
ignoreManifestTimestampsInSegmentsMode: false,
type: shaka.media.ManifestParser.DASH,
Expand Down
1 change: 0 additions & 1 deletion lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,6 @@ shaka.hls.HlsParser = class {
textStreams,
imageStreams,
offlineSessionIds: [],
minBufferTime: 0,
sequenceMode: this.config_.hls.sequenceMode,
ignoreManifestTimestampsInSegmentsMode:
this.config_.hls.ignoreManifestTimestampsInSegmentsMode,
Expand Down
8 changes: 1 addition & 7 deletions lib/media/playhead.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,6 @@ shaka.media.MediaSourcePlayhead = class {
/** @private {shaka.media.PresentationTimeline} */
this.timeline_ = manifest.presentationTimeline;

/** @private {number} */
this.minBufferTime_ = manifest.minBufferTime || 0;

/** @private {?shaka.extern.StreamingConfiguration} */
this.config_ = config;

Expand Down Expand Up @@ -482,10 +479,7 @@ shaka.media.MediaSourcePlayhead = class {
const isBuffered = (playheadTime) => shaka.media.TimeRangesUtils.isBuffered(
this.mediaElement_.buffered, playheadTime);

const rebufferingGoal = Math.max(
this.minBufferTime_,
this.config_.rebufferingGoal);

const rebufferingGoal = this.config_.rebufferingGoal;
const safeSeekOffset = this.config_.safeSeekOffset;

let start = this.timeline_.getSeekRangeStart();
Expand Down
8 changes: 2 additions & 6 deletions lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -779,9 +779,7 @@ shaka.media.StreamingEngine = class {
// If the new segment can be finished in time without risking a buffer
// underflow, we should abort the old one and switch.
const bufferedAhead = (bufferEnd || 0) - presentationTime;
const safetyBuffer = Math.max(
this.manifest_.minBufferTime || 0,
this.config_.rebufferingGoal);
const safetyBuffer = this.config_.rebufferingGoal;
const safeBufferedAhead = bufferedAhead - safetyBuffer;
if (timeToFetchNewSegment < safeBufferedAhead) {
return true;
Expand Down Expand Up @@ -1366,9 +1364,7 @@ shaka.media.StreamingEngine = class {
'bufferedAhead=' + bufferedAhead);

const unscaledBufferingGoal = Math.max(
this.manifest_.minBufferTime || 0,
this.config_.rebufferingGoal,
this.config_.bufferingGoal);
this.config_.rebufferingGoal, this.config_.bufferingGoal);

const scaledBufferingGoal = Math.max(1,
unscaledBufferingGoal * this.bufferingScale_);
Expand Down
1 change: 0 additions & 1 deletion lib/mss/mss_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,6 @@ shaka.mss.MssParser = class {
textStreams: context.textStreams,
imageStreams: [],
offlineSessionIds: [],
minBufferTime: 0,
sequenceMode: this.config_.mss.sequenceMode,
ignoreManifestTimestampsInSegmentsMode: false,
type: shaka.media.ManifestParser.MSS,
Expand Down
1 change: 0 additions & 1 deletion lib/offline/manifest_converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ shaka.offline.ManifestConverter = class {

return {
presentationTimeline: timeline,
minBufferTime: 2,
offlineSessionIds: manifestDB.sessionIds,
variants: Array.from(variants.values()),
textStreams: textStreams,
Expand Down
16 changes: 3 additions & 13 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -2638,13 +2638,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
this.playheadObservers_ =
this.createPlayheadObserversForMSE_(startTime);

// We need to start the buffer management code near the end because it
// will set the initial buffering state and that depends on other
// components being initialized.
const rebufferThreshold = Math.max(
this.manifest_.minBufferTime,
this.config_.streaming.rebufferingGoal);
this.startBufferManagement_(mediaElement, rebufferThreshold);
this.startBufferManagement_(
mediaElement, this.config_.streaming.rebufferingGoal);
};

if (!this.config_.streaming.startAtSegmentBoundary) {
Expand Down Expand Up @@ -4187,12 +4182,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
this.onAbrStatusChanged_();
}
if (this.bufferObserver_) {
let rebufferThreshold = this.config_.streaming.rebufferingGoal;
if (this.manifest_) {
rebufferThreshold =
Math.max(rebufferThreshold, this.manifest_.minBufferTime);
}
this.updateBufferingSettings_(rebufferThreshold);
this.updateBufferingSettings_(this.config_.streaming.rebufferingGoal);
}

if (this.manifest_) {
Expand Down
54 changes: 1 addition & 53 deletions test/dash/dash_parser_manifest_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ describe('DashParser Manifest', () => {
manifest.sequenceMode = true;
manifest.type = shaka.media.ManifestParser.DASH;
manifest.anyTimeline();
manifest.minBufferTime = 75;
manifest.addPartialVariant((variant) => {
variant.language = 'en';
variant.bandwidth = 200;
Expand Down Expand Up @@ -256,7 +255,6 @@ describe('DashParser Manifest', () => {
manifest.sequenceMode = false;
manifest.type = shaka.media.ManifestParser.DASH;
manifest.anyTimeline();
manifest.minBufferTime = 75;
manifest.addPartialVariant((variant) => {
variant.language = 'en';
variant.bandwidth = 200;
Expand Down Expand Up @@ -1759,56 +1757,6 @@ describe('DashParser Manifest', () => {
expect(stream).toBeUndefined();
});

it('override manifest value if ignoreMinBufferTime is true', async () => {
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="1" mimeType="video/mp4">',
' <Representation id="video-sd" width="640" height="480">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' </Period>',
'</MPD>',
].join('\n');

fakeNetEngine.setResponseText('dummy://foo', manifestText);
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
config.dash.ignoreMinBufferTime = true;
parser.configure(config);

/** @type {shaka.extern.Manifest} */
const manifest = await parser.start('dummy://foo', playerInterface);
const minBufferTime = manifest.minBufferTime;
expect(minBufferTime).toBe(0);
});

it('get manifest value if ignoreMinBufferTime is false', async () => {
const manifestText = [
'<MPD minBufferTime="PT75S">',
' <Period id="1" duration="PT30S">',
' <AdaptationSet id="1" mimeType="video/mp4">',
' <Representation id="video-sd" width="640" height="480">',
' <BaseURL>v-sd.mp4</BaseURL>',
' <SegmentBase indexRange="100-200" />',
' </Representation>',
' </AdaptationSet>',
' </Period>',
'</MPD>',
].join('\n');

fakeNetEngine.setResponseText('dummy://foo', manifestText);
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
config.dash.ignoreMinBufferTime = false;
parser.configure(config);

/** @type {shaka.extern.Manifest} */
const manifest = await parser.start('dummy://foo', playerInterface);
const minBufferTime = manifest.minBufferTime;
expect(minBufferTime).toBe(75);
});

it('honors the ignoreMaxSegmentDuration config', async () => {
const manifestText = [
'<MPD maxSegmentDuration="PT5S">',
Expand Down Expand Up @@ -1944,7 +1892,7 @@ describe('DashParser Manifest', () => {
const manifest = await parser.start('dummy://foo', playerInterface);
const presentationTimeline = manifest.presentationTimeline;
const presentationDelay = presentationTimeline.getDelay();
expect(presentationDelay).toBe(1.5*manifest.minBufferTime);
expect(presentationDelay).toBe(3);
});

it('Honors the ignoreEmptyAdaptationSet config', async () => {
Expand Down
3 changes: 2 additions & 1 deletion test/media/playhead_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ describe('Playhead', () => {
textStreams: [],
imageStreams: [],
presentationTimeline: timeline,
minBufferTime: 10,
offlineSessionIds: [],
sequenceMode: false,
ignoreManifestTimestampsInSegmentsMode: false,
Expand Down Expand Up @@ -405,6 +404,8 @@ describe('Playhead', () => {
timeline.getSeekRangeStart.and.returnValue(5);
timeline.getSeekRangeEnd.and.returnValue(60);

config.rebufferingGoal = 10;

playhead = new shaka.media.MediaSourcePlayhead(
video,
manifest,
Expand Down
1 change: 0 additions & 1 deletion test/media/streaming_engine_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,6 @@ describe('StreamingEngine', () => {
return {
presentationTimeline: timeline,
offlineSessionIds: [],
minBufferTime: 2,
textStreams: [],
imageStreams: [],
sequenceMode: false,
Expand Down
6 changes: 0 additions & 6 deletions test/media/streaming_engine_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2641,8 +2641,6 @@ describe('StreamingEngine', () => {
beforeEach(() => {
setupVod();

manifest.minBufferTime = 1;

config = shaka.util.PlayerConfiguration.createDefault().streaming;
config.rebufferingGoal = 1;
config.bufferingGoal = 1;
Expand Down Expand Up @@ -2752,8 +2750,6 @@ describe('StreamingEngine', () => {
it('does not fail immediately', async () => {
setupVod();

manifest.minBufferTime = 1;

// Create StreamingEngine.
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
config.rebufferingGoal = 1;
Expand Down Expand Up @@ -2816,8 +2812,6 @@ describe('StreamingEngine', () => {
it('fails after multiple QuotaExceededError', async () => {
setupVod();

manifest.minBufferTime = 1;

// Create StreamingEngine.
const config = shaka.util.PlayerConfiguration.createDefault().streaming;
config.rebufferingGoal = 1;
Expand Down
1 change: 0 additions & 1 deletion test/offline/storage_compatibility_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ filterDescribe('Storage Compatibility', offlineSupported, () => {

const expected = shaka.test.ManifestGenerator.generate((manifest) => {
manifest.anyTimeline();
manifest.minBufferTime = 2;

manifest.addPartialVariant((variant) => {
variant.addPartialStream(ContentType.VIDEO, (stream) => {
Expand Down
2 changes: 0 additions & 2 deletions test/test/util/manifest_generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ shaka.test.ManifestGenerator.Manifest = class {
this.presentationTimeline = timeline;
/** @type {!Array.<string>} */
this.offlineSessionIds = [];
/** @type {number} */
this.minBufferTime = 0;
/** @type {boolean} */
this.sequenceMode = false;
/** @type {boolean} */
Expand Down
1 change: 0 additions & 1 deletion test/test/util/streaming_engine_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,6 @@ shaka.test.StreamingEngineUtil = class {
/** @type {shaka.extern.Manifest} */
const manifest = {
presentationTimeline,
minBufferTime: 2,
offlineSessionIds: [],
variants: [],
textStreams: [],
Expand Down

0 comments on commit 8603c8a

Please sign in to comment.