forked from shaka-project/shaka-player
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch reworks SegmentIndexes so that any SegmentReference they contain is guaranteed to be available. This makes SegmentIndexes work consistently between static content and live content (specifically content specified using SegmentTemplate with @duration). * Rework StreamInfo to use a ISegmentIndexSource and a ISegmentInitSource, which construct a SegmentIndex and an intiailization segment respectively. * Make ManifestInfo destructible and various async operations in StreamVideoSource safer. * Introduce LiveSegmentIndex, which manages SegmentReference eviction. * Introduce DynamicLiveSegmentIndex, which manages SegmentReference eviction and generation. * Implement improved segment availability logic for segment eviction. * Move SegmentIndex construction from MpdProcessor to several ISegmentIndexSource implementations. * Use a SegmentIndex to represent subtitles to simplify Stream creation in StreamVideoSource. * Move manifest update code from StreamVideoSource to ManifestUpdater. * Move PeriodInfo.duration determination in MpdProcessor to StreamVideoSource. * Since "forced" manifest updates are no longer required for content specified using SegmentTemplate with @duration, simplify manifest update code in DashVideoSource. * Make Stream continue to update even if it runs out of SegmentReferences, this simplifies previous resync logic and makes DynamicLiveSegmentIndex work seamlessly. * Refactor SegmentIndex and initialization fetch code in ContentDatabase. * Download all SegmentIndexes in the background after the initial streams have started. Follow up work is required to remove seek range logic from DashVideoSource. Change-Id: I4a908195aba632a911a6e55213fc41d41428162b
- Loading branch information
Timothy Drews
committed
Jun 9, 2015
1 parent
6d08f0b
commit 22c57e9
Showing
42 changed files
with
4,528 additions
and
3,363 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
/** | ||
* Copyright 2015 Google Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* @fileoverview Implements a SegmentIndexSource that constructs a SegmentIndex | ||
* from an MP4 or WebM container. | ||
*/ | ||
|
||
goog.provide('shaka.dash.ContainerSegmentIndexSource'); | ||
|
||
goog.require('shaka.asserts'); | ||
goog.require('shaka.dash.LiveSegmentIndex'); | ||
goog.require('shaka.log'); | ||
goog.require('shaka.media.ISegmentIndexSource'); | ||
goog.require('shaka.media.Mp4SegmentIndexParser'); | ||
goog.require('shaka.media.SegmentIndex'); | ||
goog.require('shaka.media.SegmentMetadata'); | ||
goog.require('shaka.media.SegmentReference'); | ||
goog.require('shaka.media.WebmSegmentIndexParser'); | ||
goog.require('shaka.util.TypedBind'); | ||
|
||
|
||
|
||
/** | ||
* Creates a ContainerSegmentIndexSource. | ||
* | ||
* @param {!shaka.dash.mpd.Mpd} mpd | ||
* @param {!shaka.dash.mpd.Period} period | ||
* @param {string} containerType The container type, which must be either | ||
* 'mp4' or 'webm'. | ||
* @param {!shaka.media.SegmentMetadata} indexMetadata Metadata info for the | ||
* container's index metadata. | ||
* @param {shaka.media.SegmentMetadata} initMetadata Metadata info for the | ||
* container's headers, which is required for WebM containers and ignored | ||
* for MP4 containers. | ||
* @param {number} manifestCreationTime The time, in seconds, when the manifest | ||
* was created. | ||
* @constructor | ||
* @struct | ||
* @implements {shaka.media.ISegmentIndexSource} | ||
*/ | ||
shaka.dash.ContainerSegmentIndexSource = function( | ||
mpd, period, containerType, indexMetadata, initMetadata, | ||
manifestCreationTime) { | ||
shaka.asserts.assert(containerType != 'webm' || initMetadata); | ||
|
||
/** @private {!shaka.dash.mpd.Mpd} */ | ||
this.mpd_ = mpd; | ||
|
||
/** @private {!shaka.dash.mpd.Period} */ | ||
this.period_ = period; | ||
|
||
/** @private {string} */ | ||
this.containerType_ = containerType; | ||
|
||
/** @private {!shaka.media.SegmentMetadata} */ | ||
this.indexMetadata_ = indexMetadata; | ||
|
||
/** @private {shaka.media.SegmentMetadata} */ | ||
this.initMetadata_ = initMetadata; | ||
|
||
/** @private {number} */ | ||
this.manifestCreationTime_ = manifestCreationTime; | ||
|
||
/** @private {Promise.<!shaka.media.SegmentIndex>} */ | ||
this.promise_ = null; | ||
|
||
/** @private {shaka.media.SegmentIndex} */ | ||
this.segmentIndex_ = null; | ||
}; | ||
|
||
|
||
/** | ||
* @override | ||
* @suppress {checkTypes} to set otherwise non-nullable types to null. | ||
*/ | ||
shaka.dash.ContainerSegmentIndexSource.prototype.destroy = function() { | ||
this.mpd_ = null; | ||
this.period_ = null; | ||
|
||
this.indexMetadata_.abortFetch(); | ||
this.indexMetadata_ = null; | ||
|
||
if (this.initMetadata_) { | ||
this.initMetadata_.abortFetch(); | ||
this.initMetadata_ = null; | ||
} | ||
|
||
if (this.segmentIndex_) { | ||
this.segmentIndex_.destroy(); | ||
this.segmentIndex_ = null; | ||
} | ||
|
||
this.promise_ = null; | ||
}; | ||
|
||
|
||
/** @override */ | ||
shaka.dash.ContainerSegmentIndexSource.prototype.create = function() { | ||
if (this.promise_) { | ||
return this.promise_; | ||
} | ||
|
||
var async = [this.indexMetadata_.fetch()]; | ||
if (this.containerType_ == 'webm') { | ||
async.push(this.initMetadata_.fetch()); | ||
} | ||
|
||
this.promise_ = Promise.all(async).then(shaka.util.TypedBind(this, | ||
/** @param {!Array} results */ | ||
function(results) { | ||
var indexData = results[0]; | ||
var initData = results[1] || null; | ||
|
||
var references = null; | ||
if (this.containerType_ == 'mp4') { | ||
var parser = new shaka.media.Mp4SegmentIndexParser(); | ||
references = parser.parse(new DataView(indexData), | ||
this.indexMetadata_.startByte, | ||
this.indexMetadata_.url); | ||
} else if (this.containerType_ == 'webm') { | ||
shaka.asserts.assert(initData); | ||
var parser = new shaka.media.WebmSegmentIndexParser(); | ||
references = parser.parse(new DataView(indexData), | ||
new DataView(initData), | ||
this.indexMetadata_.url); | ||
} else { | ||
shaka.asserts.unreachable(); | ||
} | ||
|
||
if (!references) { | ||
var error = new Error('Failed to parse segment references from', | ||
this.containerType_, | ||
'container.'); | ||
error.type = 'stream'; | ||
return Promise.reject(error); | ||
} | ||
|
||
var segmentIndex = this.mpd_.type == 'dynamic' ? | ||
new shaka.dash.LiveSegmentIndex( | ||
references, | ||
this.mpd_, | ||
this.period_, | ||
this.manifestCreationTime_) : | ||
new shaka.media.SegmentIndex(references); | ||
return Promise.resolve(segmentIndex); | ||
})); | ||
|
||
return this.promise_; | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/** | ||
* Copyright 2015 Google Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
* @fileoverview Implements an ISegmentIndexSource that constructs a | ||
* SegmentIndex from a SegmentTemplate with a segment duration. | ||
*/ | ||
|
||
goog.provide('shaka.dash.DurationSegmentIndexSource'); | ||
|
||
goog.require('shaka.asserts'); | ||
goog.require('shaka.dash.DynamicLiveSegmentIndex'); | ||
goog.require('shaka.log'); | ||
goog.require('shaka.media.ISegmentIndexSource'); | ||
goog.require('shaka.media.SegmentIndex'); | ||
goog.require('shaka.media.SegmentReference'); | ||
goog.require('shaka.util.Clock'); | ||
goog.require('shaka.util.TypedBind'); | ||
|
||
|
||
|
||
/** | ||
* Creates a DurationSegmentIndexSource. | ||
* | ||
* @param {!shaka.dash.mpd.Mpd} mpd | ||
* @param {!shaka.dash.mpd.Period} period | ||
* @param {!shaka.dash.mpd.Representation} representation | ||
* @param {number} manifestCreationTime The time, in seconds, when the manifest | ||
* was created. | ||
* @constructor | ||
* @struct | ||
* @implements {shaka.media.ISegmentIndexSource} | ||
*/ | ||
shaka.dash.DurationSegmentIndexSource = function( | ||
mpd, period, representation, manifestCreationTime) { | ||
shaka.asserts.assert(period.start != null); | ||
shaka.asserts.assert((mpd.type == 'dynamic') || (period.duration != null)); | ||
shaka.asserts.assert(representation.segmentTemplate); | ||
shaka.asserts.assert(representation.segmentTemplate.timescale > 0); | ||
shaka.asserts.assert(representation.segmentTemplate.segmentDuration); | ||
|
||
/** @private {!shaka.dash.mpd.Mpd} */ | ||
this.mpd_ = mpd; | ||
|
||
/** @private {!shaka.dash.mpd.Period} */ | ||
this.period_ = period; | ||
|
||
/** @private {!shaka.dash.mpd.Representation} */ | ||
this.representation_ = representation; | ||
|
||
/** @private {number} */ | ||
this.manifestCreationTime_ = manifestCreationTime; | ||
|
||
/** @private {shaka.media.SegmentIndex} */ | ||
this.segmentIndex_ = null; | ||
}; | ||
|
||
|
||
/** | ||
* @override | ||
* @suppress {checkTypes} to set otherwise non-nullable types to null. | ||
*/ | ||
shaka.dash.DurationSegmentIndexSource.prototype.destroy = function() { | ||
this.mpd_ = null; | ||
this.period_ = null; | ||
this.representation_ = null; | ||
|
||
if (this.segmentIndex_) { | ||
this.segmentIndex_.destroy(); | ||
this.segmentIndex_ = null; | ||
} | ||
}; | ||
|
||
|
||
/** @override */ | ||
shaka.dash.DurationSegmentIndexSource.prototype.create = function() { | ||
if (this.segmentIndex_) { | ||
return Promise.resolve(this.segmentIndex_); | ||
} | ||
|
||
if (this.mpd_.type == 'dynamic') { | ||
try { | ||
this.segmentIndex_ = new shaka.dash.DynamicLiveSegmentIndex( | ||
this.mpd_, this.period_, this.representation_, | ||
this.manifestCreationTime_); | ||
} catch (exception) { | ||
return Promise.reject(exception); | ||
} | ||
} else { | ||
var segmentTemplate = this.representation_.segmentTemplate; | ||
var scaledSegmentDuration = | ||
segmentTemplate.segmentDuration / segmentTemplate.timescale; | ||
var numSegments = Math.ceil(this.period_.duration / scaledSegmentDuration); | ||
var references = shaka.dash.MpdUtils.generateSegmentReferences( | ||
this.representation_, 1, numSegments); | ||
if (!references) { | ||
var error = new Error('Failed to generate SegmentReferences'); | ||
error.type = 'stream'; | ||
return Promise.reject(error); | ||
} | ||
this.segmentIndex_ = new shaka.media.SegmentIndex(references); | ||
} | ||
|
||
return Promise.resolve(this.segmentIndex_); | ||
}; | ||
|
Oops, something went wrong.