Skip to content

Commit

Permalink
Fix-up startNumber behavior.
Browse files Browse the repository at this point in the history
* Revert 5c7fca9, which intended
  to allow startNumber to be 0, and maintain the previous behavior,
  which requires startNumber to begin at 1 (this appears to be in-line
  with the MPD spec).
* Correctly compute the $Time$ placeholder.
* Rename firstSegmentNumber to startNumber to clarify code.

Closes #10

Change-Id: I9b565edc9e23b9ad7c6bc62829d6b0ab565008a4
  • Loading branch information
Timothy Drews authored and Gerrit Code Review committed Feb 13, 2015
1 parent d797c70 commit b244def
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 30 deletions.
11 changes: 5 additions & 6 deletions lib/dash/mpd_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ shaka.dash.mpd.SegmentList = function() {
this.segmentDuration = null;

/** @type {number} */
this.firstSegmentNumber = 1;
this.startNumber = 1;

/** @type {shaka.dash.mpd.Initialization} */
this.initialization = null;
Expand Down Expand Up @@ -475,7 +475,7 @@ shaka.dash.mpd.SegmentTemplate = function() {
this.segmentDuration = null;

/** @type {number} */
this.firstSegmentNumber = 1;
this.startNumber = 1;

/** @type {?string} */
this.mediaUrlTemplate = null;
Expand Down Expand Up @@ -957,7 +957,7 @@ shaka.dash.mpd.SegmentList.prototype.parse = function(parent, elem) {
this.segmentDuration =
mpd.parseAttr_(elem, 'duration', mpd.parseNonNegativeInt_);

this.firstSegmentNumber =
this.startNumber =
mpd.parseAttr_(elem, 'startNumber', mpd.parsePositiveInt_) || 1;

// Parse simple children
Expand Down Expand Up @@ -1000,9 +1000,8 @@ shaka.dash.mpd.SegmentTemplate.prototype.parse = function(parent, elem) {
this.segmentDuration =
mpd.parseAttr_(elem, 'duration', mpd.parseNonNegativeInt_);

// The startNumber attribute defaults to 1 but may be set to 0 explicitly.
this.firstSegmentNumber =
mpd.parseAttr_(elem, 'startNumber', mpd.parseNonNegativeInt_) || 1;
this.startNumber =
mpd.parseAttr_(elem, 'startNumber', mpd.parsePositiveInt_) || 1;

this.mediaUrlTemplate = mpd.parseAttr_(elem, 'media', mpd.parseString_);
this.indexUrlTemplate = mpd.parseAttr_(elem, 'index', mpd.parseString_);
Expand Down
38 changes: 19 additions & 19 deletions lib/dash/mpd_processor.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ shaka.dash.MpdProcessor.prototype.calculateDurations_ = function(mpd) {
* @private
*/
shaka.dash.MpdProcessor.prototype.calculatePeriodDuration_ = function(period) {
if (period.duration) {
if (period.duration != null) {
return;
}

Expand Down Expand Up @@ -322,7 +322,7 @@ shaka.dash.MpdProcessor.prototype.processSegmentTemplates_ = function(mpd) {
'Ignoring segment timeline because an explicit segment index ' +
'URL was provided for the SegmentTemplate.');
}
if (segmentTemplate.duration) {
if (segmentTemplate.segmentDuration) {
shaka.log.warning(
'Ignoring segment duration because an explicit segment index ' +
'URL was provided for the SegmentTemplate.');
Expand All @@ -346,7 +346,7 @@ shaka.dash.MpdProcessor.prototype.processSegmentTemplates_ = function(mpd) {
--k;
}
} else if (segmentTemplate.segmentDuration) {
if (period.duration) {
if (period.duration != null) {
this.generateSegmentListFromDuration_(
representation,
period.duration);
Expand Down Expand Up @@ -456,7 +456,7 @@ shaka.dash.MpdProcessor.prototype.generateSegmentListFromTimeline_ = function(
// lengths.
segmentList.timescale = segmentTemplate.timescale;
segmentList.presentationTimeOffset = segmentTemplate.presentationTimeOffset;
segmentList.firstSegmentNumber = segmentTemplate.firstSegmentNumber;
segmentList.startNumber = segmentTemplate.startNumber;
segmentList.initialization = this.generateInitialization_(representation);
segmentList.segmentUrls = [];

Expand Down Expand Up @@ -509,7 +509,7 @@ shaka.dash.MpdProcessor.prototype.generateSegmentListFromTimeline_ = function(
var filledUrlTemplate = this.fillUrlTemplate_(
segmentTemplate.mediaUrlTemplate,
representation.id,
segmentNumber - 1 + segmentTemplate.firstSegmentNumber,
(segmentNumber - 1) + segmentTemplate.startNumber,
representation.bandwidth,
startTime);

Expand Down Expand Up @@ -561,27 +561,29 @@ shaka.dash.MpdProcessor.prototype.generateSegmentListFromDuration_ = function(

var segmentList = new shaka.dash.mpd.SegmentList();

// Note: do not copy |segmentDuration| since the segments may have different
// lengths.
segmentList.timescale = segmentTemplate.timescale;
segmentList.presentationTimeOffset = segmentTemplate.presentationTimeOffset;
segmentList.firstSegmentNumber = segmentTemplate.firstSegmentNumber;
segmentList.segmentDuration = segmentTemplate.segmentDuration;
segmentList.startNumber = segmentTemplate.startNumber;
segmentList.initialization = this.generateInitialization_(representation);
segmentList.segmentUrls = [];

// The current segment number.
var segmentNumber = 1;
var startTime = 0;
var numSegments =
Math.floor(periodDuration / segmentTemplate.segmentDuration);

for (var segmentNumber = 1; segmentNumber <= numSegments; ++segmentNumber) {
var time =
((segmentNumber - 1) + (segmentTemplate.startNumber - 1)) *
segmentTemplate.segmentDuration;

while ((startTime / segmentList.timescale) < periodDuration) {
// Generate the media URL.
shaka.asserts.assert(segmentTemplate.mediaUrlTemplate);
var filledUrlTemplate = this.fillUrlTemplate_(
segmentTemplate.mediaUrlTemplate,
representation.id,
segmentNumber - 1 + segmentTemplate.firstSegmentNumber,
segmentNumber - 1 + segmentTemplate.startNumber,
representation.bandwidth,
startTime);
time);

if (!filledUrlTemplate) {
// An error has already been logged.
Expand All @@ -595,13 +597,10 @@ shaka.dash.MpdProcessor.prototype.generateSegmentListFromDuration_ = function(
// Create the SegmentUrl.
var segmentUrl = new shaka.dash.mpd.SegmentUrl();
segmentUrl.mediaUrl = mediaUrl;
segmentUrl.startTime = startTime;
segmentUrl.startTime = time;
segmentUrl.duration = segmentTemplate.segmentDuration;

segmentList.segmentUrls.push(segmentUrl);

++segmentNumber;
startTime += segmentTemplate.segmentDuration;
}

representation.segmentList = segmentList;
Expand Down Expand Up @@ -1017,7 +1016,8 @@ shaka.dash.MpdProcessor.prototype.createSegmentMetadataInfo_ = function(
*/
shaka.dash.MpdProcessor.prototype.createSegmentIndex_ = function(segmentList) {
var timescale = segmentList.timescale;
var firstSegmentNumber = segmentList.firstSegmentNumber;
var presentationTimeOffset = segmentList.presentationTimeOffset;
var startNumber = segmentList.startNumber;
var segmentDuration = segmentList.segmentDuration;

/** @type {!Array.<!shaka.media.SegmentReference>} */
Expand Down
105 changes: 100 additions & 5 deletions spec/mpd_processor_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ describe('MpdProcessor', function() {
m.periods.push(p);
});

it('generates a SegmentBase from a SegmentTemplate', function() {
it('creates SegmentBase from SegmentTemplate', function() {
st.mediaUrlTemplate = 'http://example.com/$Bandwidth$-media.mp4';
st.indexUrlTemplate = 'http://example.com/$Bandwidth$-index.sidx';
st.initializationUrlTemplate = 'http://example.com/$Bandwidth$-init.mp4';
Expand Down Expand Up @@ -243,7 +243,7 @@ describe('MpdProcessor', function() {
expect(i2.range).toBeNull();
});

it('generates a SegmentList from a SegmentTemplate', function() {
it('creates SegmentList from SegmentTemplate+SegmentTimeline', function() {
var tp1 = new mpd.SegmentTimePoint();
tp1.duration = 10;
tp1.repeat = 1;
Expand All @@ -259,7 +259,7 @@ describe('MpdProcessor', function() {
st.timescale = 9000;
st.presentationTimeOffset = 0;
st.segmentDuration = null;
st.firstSegmentNumber = 1;
st.startNumber = 1;
st.mediaUrlTemplate = '$Number$-$Time$-$Bandwidth$-media.mp4';
st.initializationUrlTemplate = '$Bandwidth$-init.mp4';

Expand All @@ -281,7 +281,7 @@ describe('MpdProcessor', function() {
expect(sl1.timescale).toBe(9000);
expect(sl1.presentationTimeOffset).toBe(0);
expect(sl1.segmentDuration).toBe(null);
expect(sl1.firstSegmentNumber).toBe(1);
expect(sl1.startNumber).toBe(1);

expect(sl1.initialization).toBeTruthy();
expect(sl1.initialization.url).toBeTruthy();
Expand Down Expand Up @@ -319,7 +319,7 @@ describe('MpdProcessor', function() {
expect(sl2.timescale).toBe(9000);
expect(sl2.presentationTimeOffset).toBe(0);
expect(sl2.segmentDuration).toBe(null);
expect(sl2.firstSegmentNumber).toBe(1);
expect(sl2.startNumber).toBe(1);

expect(sl2.initialization).toBeTruthy();
expect(sl2.initialization.url).toBeTruthy();
Expand Down Expand Up @@ -349,6 +349,101 @@ describe('MpdProcessor', function() {
expect(sl2.segmentUrls[2].startTime).toBe(20);
expect(sl2.segmentUrls[2].duration).toBe(20);
});

it('creates SegmentList from SegmentTemplate+segmentDuration', function() {
p.duration = 30;

st.timescale = 9000;
st.presentationTimeOffset = 0;
st.segmentDuration = 10;
st.startNumber = 5; // Ensure startNumber > 1 works.
st.mediaUrlTemplate = '$Number$-$Time$-$Bandwidth$-media.mp4';
st.initializationUrlTemplate = '$Bandwidth$-init.mp4';

r1.bandwidth = 250000;
r1.baseUrl = new goog.Uri('http://example.com/');

r2.bandwidth = 500000;
r2.baseUrl = new goog.Uri('http://example.com/');

processor.processSegmentTemplates_(m);

// Check |r1|.
expect(r1.segmentBase).toBeNull();
expect(r1.segmentList).toBeTruthy();

var sl1 = r1.segmentList;
expect(sl1.timescale).toBe(9000);
expect(sl1.presentationTimeOffset).toBe(0);
expect(sl1.segmentDuration).toBe(10);
expect(sl1.startNumber).toBe(5);

expect(sl1.initialization).toBeTruthy();
expect(sl1.initialization.url).toBeTruthy();
expect(sl1.initialization.url.toString())
.toBe('http://example.com/250000-init.mp4');

expect(sl1.segmentUrls.length).toBe(3);

expect(sl1.segmentUrls[0].mediaUrl).toBeTruthy();
expect(sl1.segmentUrls[0].mediaUrl.toString())
.toBe('http://example.com/5-40-250000-media.mp4');
expect(sl1.segmentUrls[0].mediaRange).toBeNull();
expect(sl1.segmentUrls[0].startTime).toBe(40);
expect(sl1.segmentUrls[0].duration).toBe(10);

expect(sl1.segmentUrls[1].mediaUrl).toBeTruthy();
expect(sl1.segmentUrls[1].mediaUrl.toString())
.toBe('http://example.com/6-50-250000-media.mp4');
expect(sl1.segmentUrls[1].mediaRange).toBeNull();
expect(sl1.segmentUrls[1].startTime).toBe(50);
expect(sl1.segmentUrls[1].duration).toBe(10);

expect(sl1.segmentUrls[2].mediaUrl).toBeTruthy();
expect(sl1.segmentUrls[2].mediaUrl.toString())
.toBe('http://example.com/7-60-250000-media.mp4');
expect(sl1.segmentUrls[2].mediaRange).toBeNull();
expect(sl1.segmentUrls[2].startTime).toBe(60);
expect(sl1.segmentUrls[2].duration).toBe(10);

// Check |r2|.
expect(r2.segmentBase).toBeNull();
expect(r2.segmentList).toBeTruthy();

var sl2 = r2.segmentList;
expect(sl2.timescale).toBe(9000);
expect(sl2.presentationTimeOffset).toBe(0);
expect(sl2.segmentDuration).toBe(10);
expect(sl2.startNumber).toBe(5);

expect(sl2.initialization).toBeTruthy();
expect(sl2.initialization.url).toBeTruthy();
expect(sl2.initialization.url.toString())
.toBe('http://example.com/500000-init.mp4');

expect(sl2.segmentUrls.length).toBe(3);

expect(sl2.segmentUrls[0].mediaUrl).toBeTruthy();
expect(sl2.segmentUrls[0].mediaUrl.toString())
.toBe('http://example.com/5-40-500000-media.mp4');
expect(sl2.segmentUrls[0].mediaRange).toBeNull();
expect(sl2.segmentUrls[0].startTime).toBe(40);
expect(sl2.segmentUrls[0].duration).toBe(10);

expect(sl2.segmentUrls[1].mediaUrl).toBeTruthy();
expect(sl2.segmentUrls[1].mediaUrl.toString())
.toBe('http://example.com/6-50-500000-media.mp4');
expect(sl2.segmentUrls[1].mediaRange).toBeNull();
expect(sl2.segmentUrls[1].startTime).toBe(50);
expect(sl2.segmentUrls[1].duration).toBe(10);

expect(sl2.segmentUrls[2].mediaUrl).toBeTruthy();
expect(sl2.segmentUrls[2].mediaUrl.toString())
.toBe('http://example.com/7-60-500000-media.mp4');
expect(sl2.segmentUrls[2].mediaRange).toBeNull();
expect(sl2.segmentUrls[2].startTime).toBe(60);
expect(sl2.segmentUrls[2].duration).toBe(10);
});
});

describe('fillUrlTemplate_', function() {
Expand Down
17 changes: 17 additions & 0 deletions spec/mpd_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -785,5 +785,22 @@ describe('mpd', function() {
var mpd = shaka.dash.mpd.parseMpd(source, '');
expect(mpd).toBeTruthy();
});

it('defaults startNumber to 1', function() {
var source = [
'<MPD>',
' <Period id="1" duration="PT0H1M0.00S">',
' <AdaptationSet id="1" lang="en" contentType="audio">',
' <SegmentTemplate startNumber="0" />',
' </AdaptationSet>',
' </Period>',
'</MPD>'].join('\n');

var mpd = shaka.dash.mpd.parseMpd(source, '');
var period = mpd.periods[0];
var adaptationSet = period.adaptationSets[0];
var segmentTemplate = adaptationSet.segmentTemplate;
expect(segmentTemplate.startNumber).toBe(1);
});
});

0 comments on commit b244def

Please sign in to comment.