From c4c95eda197138ac6188543b26b7a55e8dd7fd39 Mon Sep 17 00:00:00 2001 From: Theodore Abshire Date: Fri, 20 Jul 2018 14:25:21 -0700 Subject: [PATCH] Notify segments on HLS manifests Beforehand, we would call presentationTimeline.notifyMaxSegmentDuration, which effectively does half of what presentationTimeline.notifySegments does. At the time, we only thought that that was only what we had to do. However, it did mean that we were never setting the maxFirstSegmentStartTime_, which was causing HLS livestreams with overridden segment availability times to have incorrect seek ranges. Closes #1307 Change-Id: I3a9385eb522579156e088f298e404063bf9542dd --- lib/hls/hls_parser.js | 23 ++++++++++++++++++- test/hls/hls_parser_unit.js | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index d69c58dced..75dfaaa52d 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -123,6 +123,9 @@ shaka.hls.HlsParser = function() { /** @private {!shaka.util.OperationManager} */ this.operationManager_ = new shaka.util.OperationManager(); + + /** @private {!Array.>} */ + this.segmentsToNotifyByStream_ = []; }; @@ -1117,7 +1120,7 @@ shaka.hls.HlsParser.prototype.createPresentationTimeline_ = this.presentationTimeline_ = new shaka.media.PresentationTimeline( presentationStartTime, delay); this.presentationTimeline_.setStatic(!this.isLive_()); - this.presentationTimeline_.notifyMaxSegmentDuration(this.maxTargetDuration_); + this.notifySegments_(); }; @@ -1215,6 +1218,21 @@ shaka.hls.HlsParser.prototype.createSegmentReference_ = }; +/** @private */ +shaka.hls.HlsParser.prototype.notifySegments_ = function() { + // The presentation timeline may or may not be set yet. + // If it does not yet exist, hold onto the segments until it does. + if (!this.presentationTimeline_) { + return; + } + this.segmentsToNotifyByStream_.forEach((segments) => { + // HLS doesn't have separate periods, so it's always "the first period". + this.presentationTimeline_.notifySegments(segments, true); + }); + this.segmentsToNotifyByStream_ = []; +}; + + /** * Parses shaka.hls.Segment objects into shaka.media.SegmentReferences. * @@ -1265,6 +1283,9 @@ shaka.hls.HlsParser.prototype.createSegments_ = references.push(reference); } + this.segmentsToNotifyByStream_.push(references); + this.notifySegments_(); + return references; }.bind(this)); }; diff --git a/test/hls/hls_parser_unit.js b/test/hls/hls_parser_unit.js index d420ae608a..9dc15aeaa0 100644 --- a/test/hls/hls_parser_unit.js +++ b/test/hls/hls_parser_unit.js @@ -313,6 +313,51 @@ describe('HlsParser', function() { testHlsParser(master, media, manifest, done); }); + it('sets maxFirstSegmentStartTime', async () => { + const master = [ + '#EXTM3U\n', + '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",', + 'RESOLUTION=960x540,FRAME-RATE=60\n', + 'test:/video', + ].join(''); + + const media = [ + '#EXTM3U\n', + '#EXT-X-PLAYLIST-TYPE:VOD\n', + '#EXT-X-MEDIA-SEQUENCE:131\n', + '#EXT-X-MAP:URI="test:/init.mp4",BYTERANGE="616@0"\n', + '#EXTINF:5,\n', + '#EXT-X-BYTERANGE:121090@616\n', + 'test:/main.mp4', + ].join(''); + + segmentData = new Uint8Array([ + 0x00, 0x00, 0x00, 0x24, // size (36) + 0x6D, 0x6F, 0x6F, 0x66, // type (moof) + 0x00, 0x00, 0x00, 0x1C, // traf size (28) + 0x74, 0x72, 0x61, 0x66, // type (traf) + + 0x00, 0x00, 0x00, 0x14, // tfdt size (20) + 0x74, 0x66, 0x64, 0x74, // type (tfdt) + 0x01, 0x00, 0x00, 0x00, // version and flags + + 0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes (0) + 0x00, 0x0A, 0x00, 0x00, // baseMediaDecodeTime last 4 bytes (655360) + ]).buffer; + + fakeNetEngine.setResponseMap({ + 'test:/master': toUTF8(master), + 'test:/video': toUTF8(media), + 'test:/init.mp4': initSegmentData, + 'test:/main.mp4': segmentData, + }); + + let manifest = await parser.start('test:/master', playerInterface); + let presentationTimeline = manifest.presentationTimeline; + // baseMediaDecodeTime (655360) / timescale (1000) + expect(presentationTimeline.getSeekRangeStart()).toBe(655.36); + }); + it('parses multiplexed variant', function(done) { const master = [ '#EXTM3U\n',