mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-15 16:06:41 +03:00
Added partial support to specify negative r values in SegmentTimeline
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
This commit is contained in:
committed by
Gerrit Code Review
parent
dc008cc6cf
commit
fdcee73fb4
@@ -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.
|
||||
|
||||
+13
-1
@@ -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_);
|
||||
};
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
+36
-23
@@ -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}>} */
|
||||
@@ -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;
|
||||
// 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;
|
||||
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;
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user