Skip to content

Commit

Permalink
Added partial support to specify negative r values in SegmentTimeline
Browse files Browse the repository at this point in the history
Can now specify negative values for the r attribute in SegmentTimeline.
Not supported with live when used on the last element.

Issue #162

Change-Id: I7206e02f7af469a7daf1e4710befb2d102f4f979
  • Loading branch information
TheModMaker authored and Gerrit Code Review committed Aug 25, 2015
1 parent dc008cc commit fdcee73
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 27 deletions.
3 changes: 2 additions & 1 deletion lib/dash/list_segment_index_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ shaka.dash.ListSegmentIndexSource.prototype.create = function() {
var timeline = [];
if (segmentList.timeline) {
timeline = shaka.dash.MpdUtils.createTimeline(
segmentList.timeline, segmentList.timescale || 1);
segmentList.timeline, segmentList.timescale || 1,
this.period_.duration || 0);
}

// Calculate a value to be used as an initial start value.
Expand Down
14 changes: 13 additions & 1 deletion lib/dash/mpd_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1442,7 +1442,7 @@ shaka.dash.mpd.SegmentTimePoint.prototype.parse = function(parent, elem) {
// Parse attributes.
this.startTime = mpd.parseAttr_(elem, 't', mpd.parseNonNegativeInt_);
this.duration = mpd.parseAttr_(elem, 'd', mpd.parseNonNegativeInt_);
this.repeat = mpd.parseAttr_(elem, 'r', mpd.parseNonNegativeInt_);
this.repeat = mpd.parseAttr_(elem, 'r', mpd.parseInt_);
};


Expand Down Expand Up @@ -1775,6 +1775,18 @@ shaka.dash.mpd.parseRange_ = function(rangeString) {
};


/**
* Parses an integer.
* @param {string} intString The integer string.
* @return {?number} The parsed integer on success; otherwise, return null.
* @private
*/
shaka.dash.mpd.parseInt_ = function(intString) {
var result = window.parseInt(intString, 10);
return (!isNaN(result) ? result : null);
};


/**
* Parses a positive integer.
* @param {string} intString The integer string.
Expand Down
61 changes: 37 additions & 24 deletions lib/dash/mpd_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,15 @@ shaka.dash.MpdUtils.fillUrlTemplate = function(
*
* @param {shaka.dash.mpd.SegmentTimeline} segmentTimeline
* @param {number} timescale
* @param {number} durationSeconds The duration of the period (in seconds).
* @return {!Array.<{start: number, end: number}>}
*/
shaka.dash.MpdUtils.createTimeline = function(segmentTimeline, timescale) {
shaka.dash.MpdUtils.createTimeline = function(
segmentTimeline, timescale, durationSeconds) {
shaka.asserts.assert(segmentTimeline);

var lastEndTime = 0;
var duration = durationSeconds * timescale;
var timePoints = segmentTimeline.timePoints;

/** @type {!Array.<{start: number, end: number}>} */
Expand All @@ -247,36 +250,46 @@ shaka.dash.MpdUtils.createTimeline = function(segmentTimeline, timescale) {
var startTime = tpStart != null ? tpStart : lastEndTime;

var repeat = timePoints[i].repeat || 0;
for (var j = 0; j <= repeat; ++j) {
var endTime = startTime + timePoints[i].duration;
if (repeat < 0) {
var d = timePoints[i].duration;
if (i + 1 === timePoints.length) {
var delta = timePoints[0].startTime + duration - startTime;
repeat = Math.ceil(delta / d) - 1;
} else {
var next = timePoints[i + 1].startTime;
repeat = Math.ceil((next - startTime) / d) - 1;
}
}

// The end of the last segment may end before the start of the current
// segment (a gap) or may end after the start of the current segment (an
// overlap). If there is a gap/overlap then stretch/compress the end of
// the last segment to the start of the current segment.
//
// Note: it is possible to move the start of the current segment to the
// end of the last segment, but this would complicate the computation of
// the $Time$ placeholder.
if ((timeline.length > 0) && (startTime != lastEndTime)) {
var delta = startTime - lastEndTime;

if (Math.abs(delta / timescale) >=
shaka.dash.MpdUtils.GAP_OVERLAP_WARN_THRESHOLD) {
shaka.log.warning(
'SegmentTimeline contains a large gap/overlap.',
'The content may have errors in it.',
timePoints[i]);
}

timeline[timeline.length - 1].end = startTime;
// The end of the last segment may end before the start of the current
// segment (a gap) or may end after the start of the current segment (an
// overlap). If there is a gap/overlap then stretch/compress the end of
// the last segment to the start of the current segment.
//
// Note: it is possible to move the start of the current segment to the
// end of the last segment, but this would complicate the computation of
// the $Time$ placeholder.
if ((timeline.length > 0) && (startTime != lastEndTime)) {
var delta = startTime - lastEndTime;

if (Math.abs(delta / timescale) >=
shaka.dash.MpdUtils.GAP_OVERLAP_WARN_THRESHOLD) {
shaka.log.warning(
'SegmentTimeline contains a large gap/overlap.',
'The content may have errors in it.',
timePoints[i]);
}

timeline[timeline.length - 1].end = startTime;
}

for (var j = 0; j <= repeat; ++j) {
var endTime = startTime + timePoints[i].duration;
timeline.push({start: startTime, end: endTime});

startTime = endTime;
lastEndTime = endTime;
} // for j
}
}

return timeline;
Expand Down
3 changes: 2 additions & 1 deletion lib/dash/timeline_segment_index_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ shaka.dash.TimelineSegmentIndexSource.prototype.create = function() {

var segmentTemplate = this.representation_.segmentTemplate;
var timeline = shaka.dash.MpdUtils.createTimeline(
segmentTemplate.timeline, segmentTemplate.timescale || 1);
segmentTemplate.timeline, segmentTemplate.timescale || 1,
this.period_.duration || 0);

/** @type {!Array.<!shaka.media.SegmentReference>} */
var references = [];
Expand Down
87 changes: 87 additions & 0 deletions spec/mpd_utils_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,5 +167,92 @@ describe('MpdUtils', function() {
1, 2, 3, 4)).toBeNull();
});
});

// TODO: Create more unit tests for this.
describe('createTimeline', function() {
it('supports negative repetitions', function() {
var timepoints = [
createTimepoint(0, 10, 0),
createTimepoint(10, 10, -1),
createTimepoint(40, 10, 0)
];
var result = [
{ start: 0, end: 10 },
{ start: 10, end: 20 },
{ start: 20, end: 30 },
{ start: 30, end: 40 },
{ start: 40, end: 50 }
];
checkTimepoints(timepoints, result, 1, 0);
});

it('supports negative repetitions with uneven border', function() {
var timepoints = [
createTimepoint(0, 10, 0),
createTimepoint(10, 10, -1),
createTimepoint(45, 5, 0)
];
var result = [
{ start: 0, end: 10 },
{ start: 10, end: 20 },
{ start: 20, end: 30 },
{ start: 30, end: 40 },
{ start: 40, end: 45 },
{ start: 45, end: 50 }
];
checkTimepoints(timepoints, result, 1, 0);
});

it('supports negative repetitions at end', function() {
var timepoints = [
createTimepoint(0, 10, 0),
createTimepoint(10, 5, -1)
];
var result = [
{ start: 0, end: 10 },
{ start: 10, end: 15 },
{ start: 15, end: 20 },
{ start: 20, end: 25 }
];
checkTimepoints(timepoints, result, 1, 25);
});

/**
* Creates a new timepoint.
*
* @param {number} start
* @param {number} dur
* @param {number} rep
*/
function createTimepoint(start, dur, rep) {
var ret = new shaka.dash.mpd.SegmentTimePoint();
ret.startTime = start;
ret.duration = dur;
ret.repeat = rep;
return ret;
}

/**
* Checks that the createTimeline works with the given timepoints and the
* given expected results.
*
* @param {!Array.<!shaka.dash.mpd.TimePoint>} points
* @param {!Array.<{start: number, end: number}} expected
* @param {number} scale
* @param {number} duration
*/
function checkTimepoints(points, expected, scale, duration) {
var timeline = new shaka.dash.mpd.SegmentTimeline();
timeline.timePoints = points;

var data = MpdUtils.createTimeline(timeline, scale, duration);
expect(data).toBeTruthy();
expect(data.length).toBe(expected.length);
for (var i = 0; i < expected.length; i++) {
expect(data[i].start).toBe(expected[i].start);
expect(data[i].end).toBe(expected[i].end);
}
}
});
});

0 comments on commit fdcee73

Please sign in to comment.