Skip to content

Commit

Permalink
Change startNumber interpretation
Browse files Browse the repository at this point in the history
Based on feedback from @tobbee on github, we are changing the
interpretation of startNumber for SegmentTemplate.  This will allow
for live streams with startNumber > 1 as served by the DASH-IF's live
simulator.

Closes #237

Change-Id: I0a8a6cae069cfd558a085452db9a871c3220784e
  • Loading branch information
joeyparrish committed Dec 14, 2015
1 parent ef3e38a commit 4584b0f
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 124 deletions.
14 changes: 2 additions & 12 deletions lib/dash/duration_segment_index_source.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,24 +130,14 @@ shaka.dash.DurationSegmentIndexSource.prototype.createStaticSegmentIndex_ =
var scaledSegmentDuration =
segmentTemplate.segmentDuration / segmentTemplate.timescale;

// SegmentTemplate with @duration implicitly lists all segments in the
// Period. So, @startNumber effectively indicates the number of segments
// which are absent from the start of the Period.
// (See section 5.3.9.5.3 of the DASH spec.)
var numSegmentsInPeriod =
Math.ceil(this.period_.duration / scaledSegmentDuration);
if (segmentTemplate.startNumber > numSegmentsInPeriod) {
shaka.log.error(
'The first segment starts after the end of the Period',
'(because @startNumber > 1). @startNumber seems to be incorrect.');
return null;
}

var references = shaka.dash.MpdUtils.generateSegmentReferences(
this.networkCallback_,
this.representation_,
segmentTemplate.startNumber,
numSegmentsInPeriod - (segmentTemplate.startNumber - 1));
1,
numSegmentsInPeriod);
if (!references) {
return null;
}
Expand Down
23 changes: 0 additions & 23 deletions lib/dash/dynamic_live_segment_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,40 +276,17 @@ shaka.dash.DynamicLiveSegmentIndex.computeAvailableSegmentRange_ =
}

// Now compute the segment numbers.
//
// SegmentTemplate with @duration implicitly lists all segments in the
// Period. So, @startNumber effectively indicates the number of segments
// which are absent from the start of the Period.
// (See section 5.3.9.5.3 of the DASH spec.)
var earliestSegmentNumber =
(earliestAvailableSegmentStartTime / scaledSegmentDuration) + 1;
shaka.asserts.assert(
earliestSegmentNumber == Math.round(earliestSegmentNumber),
'earliestSegmentNumber should be an integer.');
if (earliestSegmentNumber < segmentTemplate.startNumber) {
shaka.log.warning(
'The earliest available segment may not be available yet',
'(because @startNumber > 1).',
'@startNumber may be incorrect.',
representation);
// Don't return; the manifest is probably incorrect but the content may
// still be playable.
}

var currentSegmentNumber =
(currentSegmentStartTime / scaledSegmentDuration) + 1;
shaka.asserts.assert(
currentSegmentNumber == Math.round(currentSegmentNumber),
'currentSegmentNumber should be an integer.');
if (currentSegmentNumber < segmentTemplate.startNumber) {
shaka.log.warning(
'The current segment may not be available yet',
'(because @startNumber > 1).',
'@startNumber may be incorrect.',
representation);
// Don't return; the manifest is probably incorrect but the content may
// still be playable.
}

shaka.log.v1('earliestSegmentNumber', earliestSegmentNumber);
shaka.log.v1('currentSegmentNumber', currentSegmentNumber);
Expand Down
51 changes: 6 additions & 45 deletions lib/dash/mpd_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -562,9 +562,6 @@ shaka.dash.mpd.SegmentList = function() {
* SegmentList's corresponding Representation, relative to the start of the
* Representation's Period.
*
* Please see shaka.dash.mpd.SegmentTemplate.zeroBasedSegmentNumbers for
* additional information.
*
* @type {number}
*/
this.startNumber = 1;
Expand Down Expand Up @@ -658,28 +655,6 @@ shaka.dash.mpd.SegmentTemplate = function() {
*/
this.startNumber = 1;

/**
* True if the manifest uses zero-based segment numbers; false if the
* manifest uses one-based segment numbers.
*
* The DASH spec. does not explicitly indicate if manifests should use
* zero-based segment numbers or one-based segment numbers; however, the
* spec. seems to prefer one-based segment numbers. We assume manifests use
* one-based segment numbers unless the manifest specifies startNumber == 0.
*
* So, manifests which use zero-based segment numbers and specify
* startNumber > 0 will cause the player to interpret the first segment
* listed in a Representation as the startNumber'th segment relative to the
* start of the Representation's Period, instead of the (startNumber - 1)'th
* segment. So, we encourage manifests to use one-based segment numbers.
*
* We only need this property so we can compute $Number$ for manifests that
* use zero-based segment numbers instead of one-based segment numbers.
*
* @type {boolean}
*/
this.zeroBasedSegmentNumbers = false;

/** @type {?string} */
this.mediaUrlTemplate = null;

Expand Down Expand Up @@ -707,7 +682,6 @@ shaka.dash.mpd.SegmentTemplate.prototype.clone = function() {
clone.presentationTimeOffset = this.presentationTimeOffset;
clone.segmentDuration = this.segmentDuration;
clone.startNumber = this.startNumber;
clone.zeroBasedSegmentNumbers = this.zeroBasedSegmentNumbers;
clone.mediaUrlTemplate = this.mediaUrlTemplate;
clone.indexUrlTemplate = this.indexUrlTemplate;
clone.initializationUrlTemplate = this.initializationUrlTemplate;
Expand Down Expand Up @@ -1349,17 +1323,11 @@ shaka.dash.mpd.SegmentList.prototype.parse = function(parent, elem) {
this.segmentDuration = mpd.parseAttr_(
elem, 'duration', mpd.parsePositiveInt_, this.segmentDuration);

// May not be zero, because that would lead to a negative start time.
var startNumber = mpd.parseAttr_(
elem, 'startNumber', mpd.parseNonNegativeInt_, this.startNumber);
elem, 'startNumber', mpd.parsePositiveInt_);
if (startNumber != null) {
if (startNumber > 0) {
this.startNumber = startNumber;
} else {
shaka.log.warning(
'SegmentList specifies @startNumber=0.',
'Please consider using one-based segment numbers.');
this.startNumber = 1;
}
this.startNumber = startNumber;
}

// Parse simple children
Expand Down Expand Up @@ -1414,18 +1382,11 @@ shaka.dash.mpd.SegmentTemplate.prototype.parse = function(parent, elem) {
this.segmentDuration = mpd.parseAttr_(
elem, 'duration', mpd.parsePositiveInt_, this.segmentDuration);

// May be zero. It's questionable, but it does happen.
var startNumber = mpd.parseAttr_(
elem, 'startNumber', mpd.parseNonNegativeInt_, this.startNumber);
elem, 'startNumber', mpd.parseNonNegativeInt_);
if (startNumber != null) {
if (startNumber > 0) {
this.startNumber = startNumber;
} else {
shaka.log.warning(
'SegmentTemplate specifies @startNumber=0.',
'Please consider using one-based segment numbers.');
this.startNumber = 1;
this.zeroBasedSegmentNumbers = true;
}
this.startNumber = startNumber;
}

this.mediaUrlTemplate = mpd.parseAttr_(
Expand Down
8 changes: 1 addition & 7 deletions lib/dash/mpd_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,7 @@ shaka.dash.MpdUtils.generateSegmentReferences = function(
var scaledEndTime = endTime / segmentTemplate.timescale;

// Compute the media URL template placeholder replacements.
//
// To compute $Number$ we must subtract 1 for manifests that use
// zero-based segment numbers, see
// shaka.dash.mpd.SegmentTemplate.zeroBasedSegmentNumbers.
var segmentReplacement = segmentTemplate.zeroBasedSegmentNumbers ?
segmentNumber - 1 :
segmentNumber;
var segmentReplacement = segmentTemplate.startNumber + segmentNumber - 1;
var timeReplacement = startTime;

// Generate the media URL.
Expand Down
98 changes: 65 additions & 33 deletions spec/mpd_processor_segment_template_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,17 +372,37 @@ describe('MpdProcessor.SegmentTemplate', function() {
},
'references': [
{
'url': 'http://example.com/5-360000-250000-media.mp4',
'url': 'http://example.com/5-0-250000-media.mp4',
'start': 0,
'end': 10
},
{
'url': 'http://example.com/6-90000-250000-media.mp4',
'start': 10,
'end': 20
},
{
'url': 'http://example.com/7-180000-250000-media.mp4',
'start': 20,
'end': 30
},
{
'url': 'http://example.com/8-270000-250000-media.mp4',
'start': 30,
'end': 40
},
{
'url': 'http://example.com/9-360000-250000-media.mp4',
'start': 40,
'end': 50
},
{
'url': 'http://example.com/6-450000-250000-media.mp4',
'url': 'http://example.com/10-450000-250000-media.mp4',
'start': 50,
'end': 60
},
{
'url': 'http://example.com/7-540000-250000-media.mp4',
'url': 'http://example.com/11-540000-250000-media.mp4',
'start': 60,
'end': 70
}
Expand All @@ -397,17 +417,37 @@ describe('MpdProcessor.SegmentTemplate', function() {
},
'references': [
{
'url': 'http://example.com/5-360000-500000-media.mp4',
'url': 'http://example.com/5-0-500000-media.mp4',
'start': 0,
'end': 10
},
{
'url': 'http://example.com/6-90000-500000-media.mp4',
'start': 10,
'end': 20
},
{
'url': 'http://example.com/7-180000-500000-media.mp4',
'start': 20,
'end': 30
},
{
'url': 'http://example.com/8-270000-500000-media.mp4',
'start': 30,
'end': 40
},
{
'url': 'http://example.com/9-360000-500000-media.mp4',
'start': 40,
'end': 50
},
{
'url': 'http://example.com/6-450000-500000-media.mp4',
'url': 'http://example.com/10-450000-500000-media.mp4',
'start': 50,
'end': 60
},
{
'url': 'http://example.com/7-540000-500000-media.mp4',
'url': 'http://example.com/11-540000-500000-media.mp4',
'start': 60,
'end': 70
}
Expand All @@ -417,10 +457,7 @@ describe('MpdProcessor.SegmentTemplate', function() {
});

it('and w/ @startNumber == 0', function(done) {
// The parser converts @startNumber=0 to startNumber=1 and
// zeroBasedSegmentNumbers=true.
st.startNumber = 1;
st.zeroBasedSegmentNumbers = true;
st.startNumber = 0;

// If the MPD is static and uses segment duration then there must be
// an explicit Period duration.
Expand Down Expand Up @@ -547,7 +584,7 @@ describe('MpdProcessor.SegmentTemplate', function() {
// = 3579
//
// The segment index of this segment is
// I1 = FLOOR(T1 / SegmentDuration) =
// I1 = FLOOR(T1 / SegmentDuration)
// = FLOOR(3589 / 10)
// = 357
//
Expand Down Expand Up @@ -615,15 +652,14 @@ describe('MpdProcessor.SegmentTemplate', function() {
// = 3520 (or 31680000 unscaled)
//
// The segment index of this segment is
// I0 = CEIL(T0 / SegmentDuration) - (StartNumber - 1)
// = CEIL(3520 / 10) - (5 - 1)
// = 352 - 4
// = 348
// I0 = CEIL(T0 / SegmentDuration)
// = CEIL(3520 / 10)
// = 352
//
// so $Number$ is thus
// N0 = I0 + StartNumber
// = 348 + 5
// = 353
// = 352 + 5
// = 357
//
// The start time of the latest available segment is given by
// T1 = CurrentPresentationTime - SegmentDuration -
Expand All @@ -632,15 +668,14 @@ describe('MpdProcessor.SegmentTemplate', function() {
// = 3579
//
// The segment index of this segment is
// I1 = FLOOR(T1 / SegmentDuration) - (StartNumber - 1) =
// = FLOOR(3589 / 10) - (5 - 1)
// = 357 - 4
// = 353
// I1 = FLOOR(T1 / SegmentDuration)
// = FLOOR(3589 / 10)
// = 357
//
// so $Number$ is thus
// N1 = I1 + StartNumber
// = 353 + 5
// = 358
// = 357 + 5
// = 362

var manifestInfo =
processor.createManifestInfo_(m, manifestCreationTime);
Expand All @@ -654,32 +689,32 @@ describe('MpdProcessor.SegmentTemplate', function() {
},
'references': [
{
'url': 'http://example.com/353-31680000-250000-media.mp4',
'url': 'http://example.com/357-31680000-250000-media.mp4',
'start': 3520,
'end': 3530
},
{
'url': 'http://example.com/354-31770000-250000-media.mp4',
'url': 'http://example.com/358-31770000-250000-media.mp4',
'start': 3530,
'end': 3540
},
{
'url': 'http://example.com/355-31860000-250000-media.mp4',
'url': 'http://example.com/359-31860000-250000-media.mp4',
'start': 3540,
'end': 3550
},
{
'url': 'http://example.com/356-31950000-250000-media.mp4',
'url': 'http://example.com/360-31950000-250000-media.mp4',
'start': 3550,
'end': 3560
},
{
'url': 'http://example.com/357-32040000-250000-media.mp4',
'url': 'http://example.com/361-32040000-250000-media.mp4',
'start': 3560,
'end': 3570
},
{
'url': 'http://example.com/358-32130000-250000-media.mp4',
'url': 'http://example.com/362-32130000-250000-media.mp4',
'start': 3570,
'end': 3580
}
Expand All @@ -689,10 +724,7 @@ describe('MpdProcessor.SegmentTemplate', function() {
});

it('and w/ @startNumber == 0', function(done) {
// The parser converts @startNumber=0 to startNumber=1 and
// zeroBasedSegmentNumbers=true.
st.startNumber = 1;
st.zeroBasedSegmentNumbers = true;
st.startNumber = 0;

var manifestInfo =
processor.createManifestInfo_(m, manifestCreationTime);
Expand Down
5 changes: 1 addition & 4 deletions spec/mpd_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,6 @@ describe('mpd', function() {
var adaptationSet = period.adaptationSets[0];
var segmentTemplate = adaptationSet.segmentTemplate;
expect(segmentTemplate.startNumber).toBe(1);
expect(segmentTemplate.zeroBasedSegmentNumbers).toBe(false);
});

it('defaults startNumber to 1 when invalid', function() {
Expand All @@ -504,7 +503,6 @@ describe('mpd', function() {
var adaptationSet = period.adaptationSets[0];
var segmentTemplate = adaptationSet.segmentTemplate;
expect(segmentTemplate.startNumber).toBe(1);
expect(segmentTemplate.zeroBasedSegmentNumbers).toBe(false);
});

it('allows startNumber to be 0', function() {
Expand All @@ -521,8 +519,7 @@ describe('mpd', function() {
var period = mpd.periods[0];
var adaptationSet = period.adaptationSets[0];
var segmentTemplate = adaptationSet.segmentTemplate;
expect(segmentTemplate.startNumber).toBe(1);
expect(segmentTemplate.zeroBasedSegmentNumbers).toBe(true);
expect(segmentTemplate.startNumber).toBe(0);
});

it('does not override valid zeros with defaults', function() {
Expand Down

0 comments on commit 4584b0f

Please sign in to comment.