Skip to content

Commit

Permalink
Add configurations for gap jumping.
Browse files Browse the repository at this point in the history
This adds the new configuration options that will be used in gap
jumping.  This also changes Playhead to accept the config over the
rebuffing goal directly.

Issue #555

Change-Id: I467690ad1f417e69634087e04e0b44c98e1c9b81
  • Loading branch information
TheModMaker committed Apr 3, 2017
1 parent b4d0fa4 commit d4d4347
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 66 deletions.
13 changes: 12 additions & 1 deletion externs/shaka/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,9 @@ shakaExtern.ManifestConfiguration;
* bufferBehind: number,
* ignoreTextStreamFailures: boolean,
* useRelativeCueTimestamps: boolean,
* startAtSegmentBoundary: boolean
* startAtSegmentBoundary: boolean,
* smallGapLimit: number,
* jumpLargeGaps: boolean
* }}
*
* @description
Expand Down Expand Up @@ -503,6 +505,15 @@ shakaExtern.ManifestConfiguration;
* segment. This affects both explicit start times and calculated start time
* for live streams. This can put us further from the live edge. Defaults to
* false.
* @property {number} smallGapLimit
* The limit (in seconds) for a gap in the media to be considered "small".
* Small gaps are jumped automatically without events. Large gaps result
* in a Player event and can be jumped.
* @property {boolean} jumpLargeGaps
* If true, jump large gaps in addition to small gaps. The event will be
* raised first. Then, if the app doesn't call preventDefault() on the event,
* the Player will jump the gap. If false, then the event will be raised,
* but the gap will not be jumped.
* @exportDoc
*/
shakaExtern.StreamingConfiguration;
Expand Down
48 changes: 24 additions & 24 deletions lib/media/playhead.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ goog.provide('shaka.media.Playhead');

goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.media.PresentationTimeline');
goog.require('shaka.media.TimeRangesUtils');
goog.require('shaka.util.EventManager');
goog.require('shaka.util.IDestroyable');
goog.require('shaka.util.StreamUtils');



Expand All @@ -35,7 +35,7 @@ goog.require('shaka.util.IDestroyable');
*
* @param {HTMLMediaElement} video
* @param {shakaExtern.Manifest} manifest
* @param {number} rebufferingGoal
* @param {shakaExtern.StreamingConfiguration} config
* @param {?number} startTime The playhead's initial position in seconds. If
* null, defaults to the start of the presentation for VOD and the live-edge
* for live.
Expand All @@ -47,15 +47,15 @@ goog.require('shaka.util.IDestroyable');
* @implements {shaka.util.IDestroyable}
*/
shaka.media.Playhead = function(
video, manifest, rebufferingGoal, startTime, onSeek) {
video, manifest, config, startTime, onSeek) {
/** @private {HTMLMediaElement} */
this.video_ = video;

/** @private {shaka.media.PresentationTimeline} */
this.timeline_ = manifest.presentationTimeline;
/** @private {?shakaExtern.Manifest} */
this.manifest_ = manifest;

/** @private {number} */
this.rebufferingGoal_ = rebufferingGoal;
/** @private {?shakaExtern.StreamingConfiguration} */
this.config_ = config;

/**
* The playhead's initial position in seconds, or null if it should
Expand Down Expand Up @@ -102,19 +102,14 @@ shaka.media.Playhead.prototype.destroy = function() {
}

this.video_ = null;
this.timeline_ = null;
this.manifest_ = null;
this.config_ = null;
this.onSeek_ = null;

return p;
};


/** @param {number} rebufferingGoal */
shaka.media.Playhead.prototype.setRebufferingGoal = function(rebufferingGoal) {
this.rebufferingGoal_ = rebufferingGoal;
};


/** @param {number} startTime */
shaka.media.Playhead.prototype.setStartTime = function(startTime) {
if (this.video_.readyState > 0)
Expand Down Expand Up @@ -154,16 +149,16 @@ shaka.media.Playhead.prototype.getStartTime_ = function() {
}

var startTime;
if (this.timeline_.getDuration() < Infinity) {
var timeline = this.manifest_.presentationTimeline;
if (timeline.getDuration() < Infinity) {
// If the presentation is VOD, or if the presentation is live but has
// finished broadcasting, then start from the beginning.
startTime = this.timeline_.getEarliestStart();
startTime = timeline.getEarliestStart();
} else {
// Otherwise, start near the live-edge, but ensure that the startup
// buffering goal can be met
startTime = Math.max(
this.timeline_.getSeekRangeEnd(),
this.timeline_.getEarliestStart());
startTime =
Math.max(timeline.getSeekRangeEnd(), timeline.getEarliestStart());
}
return startTime;
};
Expand Down Expand Up @@ -317,12 +312,17 @@ shaka.media.Playhead.prototype.onPlaying_ = function() {
* @private
*/
shaka.media.Playhead.prototype.reposition_ = function(currentTime) {
goog.asserts.assert(this.manifest_ && this.config_, 'Must not be destroyed');

var isBuffered = (function(time) {
return shaka.media.TimeRangesUtils.bufferedAheadOf(
this.video_.buffered, time) > 0;
}.bind(this));

var timeline = this.timeline_;
var rebufferingGoal = shaka.util.StreamUtils.getRebufferingGoal(
this.manifest_, this.config_, 1 /* scaleFactor */);

var timeline = this.manifest_.presentationTimeline;
// TODO(modmaker): |start| uses getEarliestStart to support gaps at the
// beginning of the media. Once gap jumping is added, this should be:
// var start = timeline.getSafeAvailabilityStart(0);
Expand All @@ -333,14 +333,14 @@ shaka.media.Playhead.prototype.reposition_ = function(currentTime) {
// forward. This means we cannot seek to it since we will "fall" outside the
// window while we buffer. So we define a "safe" region that is far enough
// away. For VOD, |safe == start|.
var safe = timeline.getSafeAvailabilityStart(this.rebufferingGoal_);
var safe = timeline.getSafeAvailabilityStart(rebufferingGoal);

// These are the times to seek to rather than the exact destinations. When
// we seek, we will get another event (after a slight delay) and these steps
// will run again. So if we seeked directly to |start|, |start| would move
// on the next call and we would loop forever.
var seekStart = timeline.getSafeAvailabilityStart(1);
var seekSafe = timeline.getSafeAvailabilityStart(this.rebufferingGoal_ + 1);
var seekSafe = timeline.getSafeAvailabilityStart(rebufferingGoal + 1);


if (currentTime > end) {
Expand Down Expand Up @@ -417,10 +417,10 @@ shaka.media.Playhead.prototype.movePlayhead_ = function(
* @private
*/
shaka.media.Playhead.prototype.clampTime_ = function(time) {
var start = this.timeline_.getEarliestStart();
var start = this.manifest_.presentationTimeline.getEarliestStart();
if (time < start) return start;

var end = this.timeline_.getSegmentAvailabilityEnd();
var end = this.manifest_.presentationTimeline.getSegmentAvailabilityEnd();
if (time > end) return end;

return time;
Expand Down
21 changes: 2 additions & 19 deletions lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,22 +265,6 @@ shaka.media.StreamingEngine.MediaState_;
shaka.media.StreamingEngine.prototype.MIN_BUFFER_LENGTH = 2;


/**
* Gets the StreamingEngine's rebuffering goal.
*
* @param {shakaExtern.Manifest} manifest
* @param {shakaExtern.StreamingConfiguration} config
* @param {number} scaleFactor
*
* @return {number}
*/
shaka.media.StreamingEngine.getRebufferingGoal = function(
manifest, config, scaleFactor) {
return scaleFactor *
Math.max(manifest.minBufferTime || 0, config.rebufferingGoal);
};


/** @override */
shaka.media.StreamingEngine.prototype.destroy = function() {
for (var type in this.mediaStates_) {
Expand Down Expand Up @@ -311,9 +295,8 @@ shaka.media.StreamingEngine.prototype.configure = function(config) {
this.config_ = config;

goog.asserts.assert(this.manifest_, 'manifest_ should not be null');
var rebufferingGoal = shaka.media.StreamingEngine.getRebufferingGoal(
var rebufferingGoal = shaka.util.StreamUtils.getRebufferingGoal(
this.manifest_, this.config_, this.bufferingGoalScale_);
this.playerInterface_.playhead.setRebufferingGoal(rebufferingGoal);
this.playerInterface_.playheadObserver.setRebufferingGoal(rebufferingGoal);
};

Expand Down Expand Up @@ -984,7 +967,7 @@ shaka.media.StreamingEngine.prototype.getBufferingGoal_ = function() {
goog.asserts.assert(this.manifest_, 'manifest_ should not be null');
goog.asserts.assert(this.config_, 'config_ should not be null');

var rebufferingGoal = shaka.media.StreamingEngine.getRebufferingGoal(
var rebufferingGoal = shaka.util.StreamUtils.getRebufferingGoal(
this.manifest_, this.config_, this.bufferingGoalScale_);

return Math.max(
Expand Down
12 changes: 6 additions & 6 deletions lib/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,11 +637,9 @@ shaka.Player.prototype.createNetworkingEngine = function() {
*/
shaka.Player.prototype.createPlayhead = function(opt_startTime) {
goog.asserts.assert(this.manifest_, 'Must have manifest');
var rebufferingGoal = shaka.media.StreamingEngine.getRebufferingGoal(
this.manifest_, this.config_.streaming, 1 /* scaleFactor */);
return new shaka.media.Playhead(
this.video_, this.manifest_, rebufferingGoal, opt_startTime || null,
this.onSeek_.bind(this));
this.video_, this.manifest_, this.config_.streaming,
opt_startTime || null, this.onSeek_.bind(this));
};


Expand All @@ -653,7 +651,7 @@ shaka.Player.prototype.createPlayhead = function(opt_startTime) {
*/
shaka.Player.prototype.createPlayheadObserver = function() {
goog.asserts.assert(this.manifest_, 'Must have manifest');
var rebufferingGoal = shaka.media.StreamingEngine.getRebufferingGoal(
var rebufferingGoal = shaka.util.StreamUtils.getRebufferingGoal(
this.manifest_, this.config_.streaming, 1 /* scaleFactor */);
return new shaka.media.PlayheadObserver(
this.video_, this.manifest_, rebufferingGoal,
Expand Down Expand Up @@ -1708,7 +1706,9 @@ shaka.Player.prototype.defaultConfig_ = function() {
bufferBehind: 30,
ignoreTextStreamFailures: false,
useRelativeCueTimestamps: false,
startAtSegmentBoundary: false
startAtSegmentBoundary: false,
smallGapLimit: 0.5,
jumpLargeGaps: false
},
abr: {
manager: this.defaultAbrManager_,
Expand Down
16 changes: 16 additions & 0 deletions lib/util/stream_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -559,3 +559,19 @@ shaka.util.StreamUtils.findPeriodContainingStream = function(manifest, stream) {
}
return -1;
};


/**
* Gets the rebuffering goal from the manifest and configuration.
*
* @param {shakaExtern.Manifest} manifest
* @param {shakaExtern.StreamingConfiguration} config
* @param {number} scaleFactor
*
* @return {number}
*/
shaka.util.StreamUtils.getRebufferingGoal = function(
manifest, config, scaleFactor) {
return scaleFactor *
Math.max(manifest.minBufferTime || 0, config.rebufferingGoal);
};
35 changes: 26 additions & 9 deletions test/media/playhead_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ describe('Playhead', function() {
var timeline;
var manifest;
var playhead;
var config;

// Callback to us from Playhead when a valid 'seeking' event occurs.
var onSeek;
Expand All @@ -40,10 +41,26 @@ describe('Playhead', function() {
timeline.getDuration.and.throwError(new Error());
timeline.setDuration.and.throwError(new Error());

manifest = /** @type {shakaExtern.Manifest} */ ({
// shakaExtern.Manifest
manifest = {
periods: [],
presentationTimeline: timeline
});
presentationTimeline: timeline,
minBufferTime: 10,
offlineSessionIds: []
};

// shakaExtern.StreamingConfiguration
config = {
rebufferingGoal: 10,
bufferingGoal: 5,
retryParameters: shaka.net.NetworkingEngine.defaultRetryParameters(),
bufferBehind: 15,
ignoreTextStreamFailures: false,
useRelativeCueTimestamps: false,
startAtSegmentBoundary: false,
smallGapLimit: 0.5,
jumpLargeGaps: false
};
});

afterEach(function(done) {
Expand All @@ -56,7 +73,7 @@ describe('Playhead', function() {
playhead = new shaka.media.Playhead(
video,
manifest,
10 /* minBufferTime */,
config,
5 /* startTime */,
onSeek);

Expand Down Expand Up @@ -95,7 +112,7 @@ describe('Playhead', function() {
playhead = new shaka.media.Playhead(
video,
manifest,
10 /* minBufferTime */,
config,
5 /* startTime */,
onSeek);

Expand All @@ -121,7 +138,7 @@ describe('Playhead', function() {
playhead = new shaka.media.Playhead(
video,
manifest,
10 /* rebufferingGoal */,
config,
5 /* startTime */,
onSeek);

Expand Down Expand Up @@ -259,7 +276,7 @@ describe('Playhead', function() {
playhead = new shaka.media.Playhead(
video,
manifest,
10 /* rebufferingGoal */,
config,
5 /* startTime */,
onSeek);

Expand Down Expand Up @@ -305,7 +322,7 @@ describe('Playhead', function() {
playhead = new shaka.media.Playhead(
video,
manifest,
10 /* rebufferingGoal */,
config,
5 /* startTime */,
onSeek);

Expand Down Expand Up @@ -339,7 +356,7 @@ describe('Playhead', function() {
playhead = new shaka.media.Playhead(
video,
manifest,
10 /* rebufferingGoal */,
config,
5 /* startTime */,
onSeek);

Expand Down
19 changes: 17 additions & 2 deletions test/media/streaming_engine_integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,12 +217,25 @@ describe('StreamingEngine', function() {
}

function setupPlayhead() {
/** @type {shakaExtern.StreamingConfiguration} */
var config = {
rebufferingGoal: 2,
bufferingGoal: 5,
retryParameters: shaka.net.NetworkingEngine.defaultRetryParameters(),
bufferBehind: 15,
ignoreTextStreamFailures: false,
useRelativeCueTimestamps: false,
startAtSegmentBoundary: false,
smallGapLimit: 0.5,
jumpLargeGaps: false
};

onBuffering = jasmine.createSpy('onBuffering');
var onSeek = function() { streamingEngine.seeked(); };
playhead = new shaka.media.Playhead(
/** @type {!HTMLVideoElement} */(video),
/** @type {shakaExtern.Manifest} */ (manifest),
2 /* rebufferingGoal */,
config,
null /* startTime */,
onSeek);
playheadObserver = new shaka.media.PlayheadObserver(
Expand Down Expand Up @@ -278,7 +291,9 @@ describe('StreamingEngine', function() {
bufferBehind: 15,
ignoreTextStreamFailures: false,
useRelativeCueTimestamps: false,
startAtSegmentBoundary: false
startAtSegmentBoundary: false,
smallGapLimit: 0.5,
jumpLargeGaps: false
};
var playerInterface = {
playhead: playhead,
Expand Down
Loading

0 comments on commit d4d4347

Please sign in to comment.