diff --git a/lib/dash/segment_base.js b/lib/dash/segment_base.js index e354a98a63..5bbf09868a 100644 --- a/lib/dash/segment_base.js +++ b/lib/dash/segment_base.js @@ -105,7 +105,7 @@ shaka.dash.SegmentBase.createStream = function(context, requestInitSegment) { var init = SegmentBase.createInitSegment(context, SegmentBase.fromInheritance_); var index = SegmentBase.createSegmentIndex_( - context, requestInitSegment, init, unscaledPresentationTimeOffset); + context, requestInitSegment, init, scaledPresentationTimeOffset); return { createSegmentIndex: index.createSegmentIndex, @@ -127,12 +127,12 @@ shaka.dash.SegmentBase.createStream = function(context, requestInitSegment) { * @param {number} startByte * @param {?number} endByte * @param {string} containerType - * @param {number} unscaledPresentationTimeOffset + * @param {number} scaledPresentationTimeOffset * @return {shaka.dash.DashParser.SegmentIndexFunctions} */ shaka.dash.SegmentBase.createSegmentIndexFromUris = function( context, requestInitSegment, init, uris, - startByte, endByte, containerType, unscaledPresentationTimeOffset) { + startByte, endByte, containerType, scaledPresentationTimeOffset) { var presentationTimeline = context.presentationTimeline; var fitLast = !context.dynamic || !context.periodInfo.isLastPeriod; var periodStartTime = context.periodInfo.start; @@ -157,12 +157,12 @@ shaka.dash.SegmentBase.createSegmentIndexFromUris = function( if (containerType == 'mp4') { references = shaka.media.Mp4SegmentIndexParser( - indexData, startByte, uris, unscaledPresentationTimeOffset); + indexData, startByte, uris, scaledPresentationTimeOffset); } else { goog.asserts.assert(initData, 'WebM requires init data'); var parser = new shaka.media.WebmSegmentIndexParser(); references = parser.parse(indexData, initData, uris, - unscaledPresentationTimeOffset); + scaledPresentationTimeOffset); } presentationTimeline.notifySegments(periodStartTime, references); @@ -210,13 +210,13 @@ shaka.dash.SegmentBase.fromInheritance_ = function(frame) { * @param {shaka.dash.DashParser.Context} context * @param {shaka.dash.DashParser.RequestInitSegmentCallback} requestInitSegment * @param {shaka.media.InitSegmentReference} init - * @param {number} unscaledPresentationTimeOffset + * @param {number} scaledPresentationTimeOffset * @return {shaka.dash.DashParser.SegmentIndexFunctions} * @throws shaka.util.Error When there is a parsing error. * @private */ shaka.dash.SegmentBase.createSegmentIndex_ = function( - context, requestInitSegment, init, unscaledPresentationTimeOffset) { + context, requestInitSegment, init, scaledPresentationTimeOffset) { var MpdUtils = shaka.dash.MpdUtils; var SegmentBase = shaka.dash.SegmentBase; var XmlUtils = shaka.util.XmlUtils; @@ -280,5 +280,5 @@ shaka.dash.SegmentBase.createSegmentIndex_ = function( return shaka.dash.SegmentBase.createSegmentIndexFromUris( context, requestInitSegment, init, indexUris, indexRange.start, - indexRange.end, containerType, unscaledPresentationTimeOffset); + indexRange.end, containerType, scaledPresentationTimeOffset); }; diff --git a/lib/media/mp4_segment_index_parser.js b/lib/media/mp4_segment_index_parser.js index a2258c4add..f675a727c8 100644 --- a/lib/media/mp4_segment_index_parser.js +++ b/lib/media/mp4_segment_index_parser.js @@ -31,12 +31,12 @@ goog.require('shaka.util.Mp4Parser'); * the MP4 container. * @param {!Array.} uris The possible locations of the MP4 file that * contains the segments. - * @param {number} unscaledPresentationTimeOffset + * @param {number} scaledPresentationTimeOffset * @return {!Array.} * @throws {shaka.util.Error} */ shaka.media.Mp4SegmentIndexParser = function( - sidxData, sidxOffset, uris, unscaledPresentationTimeOffset) { + sidxData, sidxOffset, uris, scaledPresentationTimeOffset) { var Mp4SegmentIndexParser = shaka.media.Mp4SegmentIndexParser; @@ -46,7 +46,7 @@ shaka.media.Mp4SegmentIndexParser = function( .fullBox('sidx', function(box) { references = Mp4SegmentIndexParser.parseSIDX_( sidxOffset, - unscaledPresentationTimeOffset, + scaledPresentationTimeOffset, uris, box); }); @@ -71,7 +71,7 @@ shaka.media.Mp4SegmentIndexParser = function( * Parse a SIDX box from the given reader. * * @param {number} sidxOffset - * @param {number} unscaledPresentationTimeOffset + * @param {number} scaledPresentationTimeOffset * @param {!Array.} uris The possible locations of the MP4 file that * contains the segments. * @param {!shaka.util.Mp4Parser.ParsedBox} box @@ -80,7 +80,7 @@ shaka.media.Mp4SegmentIndexParser = function( */ shaka.media.Mp4SegmentIndexParser.parseSIDX_ = function( sidxOffset, - unscaledPresentationTimeOffset, + scaledPresentationTimeOffset, uris, box) { @@ -122,8 +122,7 @@ shaka.media.Mp4SegmentIndexParser.parseSIDX_ = function( var referenceCount = box.reader.readUint16(); // Substract the presentation time offset - var unscaledStartTime = - earliestPresentationTime - unscaledPresentationTimeOffset; + var unscaledStartTime = earliestPresentationTime; var startByte = sidxOffset + box.size + firstOffset; for (var i = 0; i < referenceCount; i++) { @@ -151,8 +150,10 @@ shaka.media.Mp4SegmentIndexParser.parseSIDX_ = function( references.push( new shaka.media.SegmentReference( references.length, - unscaledStartTime / timescale, - (unscaledStartTime + subsegmentDuration) / timescale, + (unscaledStartTime / timescale) - + scaledPresentationTimeOffset, + ((unscaledStartTime + subsegmentDuration) / timescale) - + scaledPresentationTimeOffset, function() { return uris; }, startByte, startByte + referenceSize - 1)); diff --git a/lib/media/webm_segment_index_parser.js b/lib/media/webm_segment_index_parser.js index 4a3ac0a1ba..375d11fe08 100644 --- a/lib/media/webm_segment_index_parser.js +++ b/lib/media/webm_segment_index_parser.js @@ -81,7 +81,7 @@ shaka.media.WebmSegmentIndexParser.CUE_CLUSTER_POSITION = 0xf1; * @param {!ArrayBuffer} initData The WebM container's headers. * @param {!Array.} uris The possible locations of the WebM file that * contains the segments. - * @param {number} unscaledPresentationTimeOffset + * @param {number} scaledPresentationTimeOffset * @return {!Array.} * @throws {shaka.util.Error} @@ -89,7 +89,7 @@ shaka.media.WebmSegmentIndexParser.CUE_CLUSTER_POSITION = 0xf1; * @see http://www.webmproject.org/docs/container/ */ shaka.media.WebmSegmentIndexParser.prototype.parse = function( - cuesData, initData, uris, unscaledPresentationTimeOffset) { + cuesData, initData, uris, scaledPresentationTimeOffset) { var tuple = this.parseWebmContainer_(initData); var parser = new shaka.util.EbmlParser(new DataView(cuesData)); var cuesElement = parser.parseElement(); @@ -103,7 +103,7 @@ shaka.media.WebmSegmentIndexParser.prototype.parse = function( return this.parseCues_( cuesElement, tuple.segmentOffset, tuple.timecodeScale, tuple.duration, - uris, unscaledPresentationTimeOffset); + uris, scaledPresentationTimeOffset); }; @@ -242,21 +242,21 @@ shaka.media.WebmSegmentIndexParser.prototype.parseInfo_ = function( * @param {number} timecodeScale * @param {number} duration * @param {!Array.} uris - * @param {number} unscaledPresentationTimeOffset + * @param {number} scaledPresentationTimeOffset * @return {!Array.} * @throws {shaka.util.Error} * @private */ shaka.media.WebmSegmentIndexParser.prototype.parseCues_ = function( cuesElement, segmentOffset, timecodeScale, duration, uris, - unscaledPresentationTimeOffset) { + scaledPresentationTimeOffset) { var references = []; var getUris = function() { return uris; }; var parser = cuesElement.createParser(); - var lastTime = -1; - var lastOffset = -1; + var lastTime = null; + var lastOffset = null; while (parser.hasMoreData()) { var elem = parser.parseElement(); @@ -270,17 +270,17 @@ shaka.media.WebmSegmentIndexParser.prototype.parseCues_ = function( } // Substract presentation time offset from unscaled time - var currentTime = timecodeScale * - (tuple.unscaledTime - unscaledPresentationTimeOffset); + var currentTime = timecodeScale * tuple.unscaledTime; var currentOffset = segmentOffset + tuple.relativeOffset; - if (lastTime >= 0) { - goog.asserts.assert(lastOffset >= 0, 'last offset cannot be 0'); + if (lastTime != null) { + goog.asserts.assert(lastOffset != null, 'last offset cannot be null'); references.push( new shaka.media.SegmentReference( references.length, - lastTime, currentTime, + lastTime - scaledPresentationTimeOffset, + currentTime - scaledPresentationTimeOffset, getUris, lastOffset, currentOffset - 1)); } @@ -289,12 +289,16 @@ shaka.media.WebmSegmentIndexParser.prototype.parseCues_ = function( lastOffset = currentOffset; } - if (lastTime >= 0) { - goog.asserts.assert(lastOffset >= 0, 'last offset cannot be 0'); + if (lastTime != null) { + goog.asserts.assert(lastOffset != null, 'last offset cannot be null'); references.push( new shaka.media.SegmentReference( - references.length, lastTime, duration, getUris, lastOffset, null)); + references.length, + lastTime - scaledPresentationTimeOffset, + duration - scaledPresentationTimeOffset, + getUris, + lastOffset, null)); } return references; diff --git a/test/dash/dash_parser_segment_base_unit.js b/test/dash/dash_parser_segment_base_unit.js index 8b71584620..e04b291252 100644 --- a/test/dash/dash_parser_segment_base_unit.js +++ b/test/dash/dash_parser_segment_base_unit.js @@ -25,6 +25,16 @@ describe('DashParser SegmentBase', function() { var parser; /** @type {shakaExtern.ManifestParser.PlayerInterface} */ var playerInterface; + /** @const {string} */ + var indexSegmentUri = '/base/test/test/assets/index-segment.mp4'; + /** @type {ArrayBuffer} */ + var indexSegment; + + beforeAll(function(done) { + shaka.test.Util.fetch(indexSegmentUri).then(function(data) { + indexSegment = data; + }).catch(fail).then(done); + }); beforeEach(function() { fakeNetEngine = new shaka.test.FakeNetworkingEngine(); @@ -252,6 +262,41 @@ describe('DashParser SegmentBase', function() { .then(done); }); + it('does not assume the same timescale as media', function(done) { + var source = [ + '', + ' ', + ' ', + ' ', + ' http://example.com/index.mp4', + ' ', + ' ', + ' ', + ' ', + ''].join('\n'); + + fakeNetEngine.setResponseMap({ + 'dummy://foo': shaka.util.StringUtils.toUTF8(source), + 'http://example.com/index.mp4': indexSegment + }); + + var video; + parser.start('dummy://foo', playerInterface) + .then(function(manifest) { + video = manifest.periods[0].variants[0].video; + return video.createSegmentIndex(); // real data, should succeed + }) + .then(function() { + var reference = video.getSegmentReference(0); + expect(reference.startTime).toEqual(-2); + expect(reference.endTime).toEqual(10); + }) + .catch(fail) + .then(done); + }); + describe('fails for', function() { it('unsupported container', function(done) { var source = [ diff --git a/test/media/mp4_segment_index_parser_unit.js b/test/media/mp4_segment_index_parser_unit.js index 2a5ce78c31..b10c9b13f8 100644 --- a/test/media/mp4_segment_index_parser_unit.js +++ b/test/media/mp4_segment_index_parser_unit.js @@ -68,4 +68,24 @@ describe('Mp4SegmentIndexParser', function() { expect(result[i].endByte).toBe(references[i].endByte); } }); + + it('takes a scaled presentationTimeOffset in seconds', function() { + var result = shaka.media.Mp4SegmentIndexParser(indexSegment, 0, [], 2); + var references = + [ + {startTime: -2, endTime: 10}, + {startTime: 10, endTime: 22}, + {startTime: 22, endTime: 34}, + {startTime: 34, endTime: 46}, + {startTime: 46, endTime: 58} + ]; + + expect(result).toBeTruthy(); + expect(result.length).toBe(references.length); + for (var i = 0; i < result.length; i++) { + expect(result[i].position).toBe(i); + expect(result[i].startTime).toBe(references[i].startTime); + expect(result[i].endTime).toBe(references[i].endTime); + } + }); }); diff --git a/test/media/webm_segment_index_parser_unit.js b/test/media/webm_segment_index_parser_unit.js index 6f3da487c2..058c808048 100644 --- a/test/media/webm_segment_index_parser_unit.js +++ b/test/media/webm_segment_index_parser_unit.js @@ -82,4 +82,24 @@ describe('WebmSegmentIndexParser', function() { expect(result[i].endByte).toBe(references[i].endByte); } }); + + it('takes a scaled presentationTimeOffset in seconds', function() { + var result = parser.parse(indexSegment, initSegment, [], 2); + var references = + [ + {startTime: -2, endTime: 10}, + {startTime: 10, endTime: 22}, + {startTime: 22, endTime: 34}, + {startTime: 34, endTime: 46}, + {startTime: 46, endTime: 58} + ]; + + expect(result).toBeTruthy(); + expect(result.length).toBe(references.length); + for (var i = 0; i < result.length; i++) { + expect(result[i].position).toBe(i); + expect(result[i].startTime).toBe(references[i].startTime); + expect(result[i].endTime).toBe(references[i].endTime); + } + }); });