Skip to content

Commit

Permalink
Do not prematurely evict segments from multi-period manifests
Browse files Browse the repository at this point in the history
presentationTimeline.getSegmentAvailabilityStart() yields a start time
relative to the AST, but all of the reference start/end times are relative
to their PTO. We need to normalize the start time to the period before
we evict any segments.
  • Loading branch information
baconz committed Aug 16, 2016
1 parent 2ee7eec commit 8892233
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 15 deletions.
9 changes: 4 additions & 5 deletions lib/dash/segment_list.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ shaka.dash.SegmentList.createStream = function(context, segmentIndexMap) {
}

var references = SegmentList.createSegmentReferences_(
context.periodInfo.start, context.periodInfo.duration, info.startNumber,
context.periodInfo.duration, info.startNumber,
context.representation.baseUris, info);
shaka.dash.MpdUtils.fitSegmentReferences(
context.periodInfo.duration, references);
if (segmentIndex) {
segmentIndex.merge(references);
segmentIndex.evict(
context.presentationTimeline.getSegmentAvailabilityStart());
var start = context.presentationTimeline.getSegmentAvailabilityStart();
segmentIndex.evict(start - context.periodInfo.start);
} else {
context.presentationTimeline.notifySegments(
context.periodInfo.start, references);
Expand Down Expand Up @@ -236,7 +236,6 @@ shaka.dash.SegmentList.checkSegmentListInfo_ = function(context, info) {
/**
* Creates an array of segment references for the given data.
*
* @param {number} periodStart in seconds.
* @param {?number} periodDuration in seconds.
* @param {number} startNumber
* @param {!Array.<string>} baseUris
Expand All @@ -245,7 +244,7 @@ shaka.dash.SegmentList.checkSegmentListInfo_ = function(context, info) {
* @private
*/
shaka.dash.SegmentList.createSegmentReferences_ = function(
periodStart, periodDuration, startNumber, baseUris, info) {
periodDuration, startNumber, baseUris, info) {
var MpdUtils = shaka.dash.MpdUtils;

var max = info.mediaSegments.length;
Expand Down
4 changes: 2 additions & 2 deletions lib/dash/segment_template.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ shaka.dash.SegmentTemplate.createStream = function(
context.periodInfo.duration, references);
if (segmentIndex) {
segmentIndex.merge(references);
segmentIndex.evict(
context.presentationTimeline.getSegmentAvailabilityStart());
var start = context.presentationTimeline.getSegmentAvailabilityStart();
segmentIndex.evict(start - context.periodInfo.start);
} else {
context.presentationTimeline.notifySegments(
context.periodInfo.start, references);
Expand Down
70 changes: 65 additions & 5 deletions test/dash/dash_parser_live_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,11 @@ describe('DashParser.Live', function() {
fakeNetEngine.setResponseMapAsText({'dummy://foo': firstManifest});
parser.start('dummy://foo', fakeNetEngine, newPeriod, errorCallback)
.then(function(manifest) {
Dash.verifySegmentIndex(manifest, firstReferences);
Dash.verifySegmentIndex(manifest, firstReferences, 0);

fakeNetEngine.setResponseMapAsText({'dummy://foo': secondManifest});
return delayForUpdatePeriod().then(function() {
Dash.verifySegmentIndex(manifest, secondReferences);
Dash.verifySegmentIndex(manifest, secondReferences, 0);
});
})
.catch(fail)
Expand All @@ -155,7 +155,7 @@ describe('DashParser.Live', function() {
done, basicLines, basicRefs, partialUpdateLines, updateRefs);
});

it('evicts old references', function(done) {
it('evicts old references for single-period live stream', function(done) {
var template = [
'<MPD type="dynamic" minimumUpdatePeriod="PT%(updateTime)dS"',
' timeShiftBufferDepth="PT1S"',
Expand Down Expand Up @@ -183,15 +183,75 @@ describe('DashParser.Live', function() {

expect(stream.findSegmentPosition).toBeTruthy();
expect(stream.findSegmentPosition(0)).not.toBe(null);
Dash.verifySegmentIndex(manifest, basicRefs);
Dash.verifySegmentIndex(manifest, basicRefs, 0);

// 15 seconds for @timeShiftBufferDepth, the first segment duration,
// and the @suggestedPresentationDuration.
Date.now = function() { return (2 * 15 + 5) * 1000; };
return delayForUpdatePeriod().then(function() {
// The first reference should have been evicted.
expect(stream.findSegmentPosition(0)).toBe(null);
Dash.verifySegmentIndex(manifest, basicRefs.slice(1));
Dash.verifySegmentIndex(manifest, basicRefs.slice(1), 0);
});
})
.catch(fail)
.then(done);
});

it('evicts old references for multi-period live stream', function(done) {
var template = [
'<MPD type="dynamic" minimumUpdatePeriod="PT%(updateTime)dS"',
' timeShiftBufferDepth="PT1S"',
' availabilityStartTime="1970-01-01T00:00:00Z">',
' <Period id="1">',
' <AdaptationSet mimeType="video/mp4">',
' <Representation id="3" bandwidth="500">',
' <BaseURL>http://example.com</BaseURL>',
'%(contents)s',
' </Representation>',
' </AdaptationSet>',
' </Period>',
' <Period id="2" start="PT%(pStart)dS">',
' <AdaptationSet mimeType="video/mp4">',
' <Representation id="4" bandwidth="500">',
' <BaseURL>http://example.com</BaseURL>',
'%(contents)s',
' </Representation>',
' </AdaptationSet>',
' </Period>',
'</MPD>'
].join('\n');
// Set the period start to the sum of the durations of the references
// in the previous period.
var durs = basicRefs.map(function(r) { return r.endTime - r.startTime });
var pStart = durs.reduce(function(p, d) { return p + d}, 0);
var args = {
updateTime: updateTime,
pStart: pStart,
contents: basicLines.join('\n')
};
var text = sprintf(template, args);

fakeNetEngine.setResponseMapAsText({'dummy://foo': text});
Date.now = function() { return 0; };
parser.start('dummy://foo', fakeNetEngine, newPeriod, errorCallback)
.then(function(manifest) {
Dash.verifySegmentIndex(manifest, basicRefs, 0);
Dash.verifySegmentIndex(manifest, basicRefs, 1);

// 15 seconds for @timeShiftBufferDepth, the first segment duration,
// and the @suggestedPresentationDuration.
Date.now = function() { return (2 * 15 + 5) * 1000; };
return delayForUpdatePeriod().then(function() {
// The first reference should have been evicted.
Dash.verifySegmentIndex(manifest, basicRefs.slice(1), 0);
Dash.verifySegmentIndex(manifest, basicRefs, 1);
// Same as above, but 1 period length later
Date.now = function() { return (2 * 15 + 5 + pStart) * 1000; };
return delayForUpdatePeriod();
}).then(function() {
Dash.verifySegmentIndex(manifest, [], 0);
Dash.verifySegmentIndex(manifest, basicRefs.slice(1), 1);
});
})
.catch(fail)
Expand Down
13 changes: 10 additions & 3 deletions test/test/util/dash_parser_util.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,21 @@ shaka.test.Dash.makeDashParser = function() {
*
* @param {shakaExtern.Manifest} manifest
* @param {!Array.<shaka.media.SegmentReference>} references
* @param {number} periodIndex
*/
shaka.test.Dash.verifySegmentIndex = function(manifest, references) {
shaka.test.Dash.verifySegmentIndex = function(
manifest, references, periodIndex) {
expect(manifest).toBeTruthy();
var stream = manifest.periods[0].streamSets[0].streams[0];
var stream = manifest.periods[periodIndex].streamSets[0].streams[0];
expect(stream).toBeTruthy();
expect(stream.findSegmentPosition).toBeTruthy();
expect(stream.getSegmentReference).toBeTruthy();

if (references.length == 0) {
expect(stream.findSegmentPosition(0)).toBe(null);
return;
}

var positionBeforeFirst =
stream.findSegmentPosition(references[0].startTime - 1);
expect(positionBeforeFirst).toBe(null);
Expand Down Expand Up @@ -84,7 +91,7 @@ shaka.test.Dash.testSegmentIndex = function(done, manifestText, references) {
var filterPeriod = function() {};
dashParser.start('dummy://foo', fakeNetEngine, filterPeriod, fail, fail)
.then(function(manifest) {
shaka.test.Dash.verifySegmentIndex(manifest, references);
shaka.test.Dash.verifySegmentIndex(manifest, references, 0);
})
.catch(fail)
.then(done);
Expand Down

0 comments on commit 8892233

Please sign in to comment.