From ad58e80bd5dc21098a22fab23655aeb9865d6753 Mon Sep 17 00:00:00 2001 From: Philippe Elsass Date: Wed, 30 Mar 2022 16:28:05 +0200 Subject: [PATCH] feat: add segmentRelativeVttTiming option --- externs/shaka/player.js | 5 ++ externs/shaka/text.js | 6 +- lib/media/media_source_engine.js | 13 +++- lib/player.js | 7 ++ lib/text/text_engine.js | 11 ++- lib/text/vtt_text_parser.js | 6 +- lib/util/player_configuration.js | 1 + test/text/text_engine_unit.js | 8 +-- test/text/vtt_text_parser_unit.js | 111 +++++++++++++++--------------- 9 files changed, 104 insertions(+), 64 deletions(-) diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 87abd72a266..cd0d4fce329 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -782,6 +782,7 @@ shaka.extern.HlsManifestConfiguration; * disableText: boolean, * disableThumbnails: boolean, * defaultPresentationDelay: number, + * segmentRelativeVttTiming: boolean, * dash: shaka.extern.DashManifestConfiguration, * hls: shaka.extern.HlsManifestConfiguration * }} @@ -813,6 +814,10 @@ shaka.extern.HlsManifestConfiguration; * configured or set as 0. * For HLS, the default value is 3 segments duration if not configured or * set as 0. + * @property {boolean} segmentRelativeVttTiming + * Option to calculate VTT text timings relatively to the segment start + * instead of relative to the period start (which is the default). + * Defaults to false. * @property {shaka.extern.DashManifestConfiguration} dash * Advanced parameters used by the DASH manifest parser. * @property {shaka.extern.HlsManifestConfiguration} hls diff --git a/externs/shaka/text.js b/externs/shaka/text.js index 6403664c6e5..d50d2c2b33c 100644 --- a/externs/shaka/text.js +++ b/externs/shaka/text.js @@ -442,7 +442,8 @@ shaka.extern.TextParser = class { * @typedef {{ * periodStart: number, * segmentStart: number, - * segmentEnd: number + * segmentEnd: number, + * vttOffset: number * }} * * @property {number} periodStart @@ -451,6 +452,9 @@ shaka.extern.TextParser = class { * The absolute start time of the segment in seconds. * @property {number} segmentEnd * The absolute end time of the segment in seconds. + * @property {number} vttOffset + * The start time relative to either segment or period start depending + * on segmentRelativeVttTiming configuration. * * @exportDoc */ diff --git a/lib/media/media_source_engine.js b/lib/media/media_source_engine.js index 3f5fe6be23a..8fd1931161e 100644 --- a/lib/media/media_source_engine.js +++ b/lib/media/media_source_engine.js @@ -66,6 +66,9 @@ shaka.media.MediaSourceEngine = class { /** @private {shaka.text.TextEngine} */ this.textEngine_ = null; + /** @private {boolean} */ + this.segmentRelativeVttTiming_ = false; + const onMetadataNoOp = (metadata, timestampOffset, segmentEnd) => {}; /** @private {!function(!Array., @@ -367,7 +370,8 @@ shaka.media.MediaSourceEngine = class { if (!this.textEngine_) { this.textEngine_ = new shaka.text.TextEngine(this.textDisplayer_); } - this.textEngine_.initParser(mimeType, sequenceMode); + this.textEngine_.initParser(mimeType, sequenceMode, + this.segmentRelativeVttTiming_); } /** @@ -1113,6 +1117,13 @@ shaka.media.MediaSourceEngine = class { } } + /** + * @param {boolean} segmentRelativeVttTiming + */ + setSegmentRelativeVttTiming(segmentRelativeVttTiming) { + this.segmentRelativeVttTiming_ = segmentRelativeVttTiming; + } + /** * Apply platform-specific transformations to this segment to work around * issues in the platform. diff --git a/lib/player.js b/lib/player.js index b22b5023720..1f15811f5d3 100644 --- a/lib/player.js +++ b/lib/player.js @@ -1571,6 +1571,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget { (metadata, offset, endTime) => { this.processTimedMetadataMediaSrc_(metadata, offset, endTime); }); + const {segmentRelativeVttTiming} = this.config_.manifest; + mediaSourceEngine.setSegmentRelativeVttTiming(segmentRelativeVttTiming); // Wait for media source engine to finish opening. This promise should // NEVER be rejected as per the media source engine implementation. @@ -3005,6 +3007,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } if (this.mediaSourceEngine_) { + const {segmentRelativeVttTiming} = this.config_.manifest; + this.mediaSourceEngine_.setSegmentRelativeVttTiming( + segmentRelativeVttTiming); + const textDisplayerFactory = this.config_.textDisplayFactory; if (this.lastTextFactory_ != textDisplayerFactory) { const displayer = @@ -4849,6 +4855,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { periodStart: 0, segmentStart: 0, segmentEnd: this.video_.duration, + vttOffset: 0, }; const data = shaka.util.BufferUtils.toUint8(buffer); const cues = obj.parseMedia(data, time); diff --git a/lib/text/text_engine.js b/lib/text/text_engine.js index 151ff0898d2..c9685425725 100644 --- a/lib/text/text_engine.js +++ b/lib/text/text_engine.js @@ -31,6 +31,9 @@ shaka.text.TextEngine = class { /** @private {shaka.extern.TextDisplayer} */ this.displayer_ = displayer; + /** @private {boolean} */ + this.segmentRelativeVttTiming_ = false; + /** @private {number} */ this.timestampOffset_ = 0; @@ -130,8 +133,9 @@ shaka.text.TextEngine = class { * * @param {string} mimeType * @param {boolean} sequenceMode + * @param {boolean} segmentRelativeVttTiming */ - initParser(mimeType, sequenceMode) { + initParser(mimeType, sequenceMode, segmentRelativeVttTiming) { // No parser for CEA, which is extracted from video and side-loaded // into TextEngine and TextDisplayer. if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE || @@ -149,6 +153,7 @@ shaka.text.TextEngine = class { shaka.log.alwaysWarn( 'Text parsers should have a "setSequenceMode" method!'); } + this.segmentRelativeVttTiming_ = segmentRelativeVttTiming; } /** @@ -174,11 +179,15 @@ shaka.text.TextEngine = class { return; } + const vttOffset = this.segmentRelativeVttTiming_ ? + startTime : this.timestampOffset_; + /** @type {shaka.extern.TextParser.TimeContext} **/ const time = { periodStart: this.timestampOffset_, segmentStart: startTime, segmentEnd: endTime, + vttOffset: vttOffset, }; // Parse the buffer and add the new cues. diff --git a/lib/text/vtt_text_parser.js b/lib/text/vtt_text_parser.js index 73334e545f4..51bd1ad02a5 100644 --- a/lib/text/vtt_text_parser.js +++ b/lib/text/vtt_text_parser.js @@ -62,9 +62,13 @@ shaka.text.VttTextParser = class { shaka.util.Error.Code.INVALID_TEXT_HEADER); } + // Depending on "segmentRelativeVttTiming" configuration, + // "vttOffset" will correspond to either "periodStart" (default) + // or "segmentStart", for segmented VTT where timings are relative + // to the beginning of each segment. // NOTE: "periodStart" is the timestamp offset applied via TextEngine. // It is no longer closely tied to periods, but the name stuck around. - let offset = time.periodStart; + let offset = time.vttOffset; // Do not honor the 'X-TIMESTAMP-MAP' value when in sequence mode. // That is because it is used mainly (solely?) to account for the timestamp diff --git a/lib/util/player_configuration.js b/lib/util/player_configuration.js index fe4f5d27e9f..8b58de2eac0 100644 --- a/lib/util/player_configuration.js +++ b/lib/util/player_configuration.js @@ -86,6 +86,7 @@ shaka.util.PlayerConfiguration = class { disableText: false, disableThumbnails: false, defaultPresentationDelay: 0, + segmentRelativeVttTiming: false, dash: { clockSyncUri: '', ignoreDrmInfo: false, diff --git a/test/text/text_engine_unit.js b/test/text/text_engine_unit.js index 46c6606de14..37626426fec 100644 --- a/test/text/text_engine_unit.js +++ b/test/text/text_engine_unit.js @@ -96,7 +96,7 @@ describe('TextEngine', () => { await textEngine.appendBuffer(dummyData, 0, 3); expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([ dummyData, - {periodStart: 0, segmentStart: 0, segmentEnd: 3}, + {periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0}, ]); expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([ @@ -111,7 +111,7 @@ describe('TextEngine', () => { expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([ dummyData, - {periodStart: 0, segmentStart: 3, segmentEnd: 5}, + {periodStart: 0, segmentStart: 3, segmentEnd: 5, vttOffset: 0}, ]); expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([ @@ -263,7 +263,7 @@ describe('TextEngine', () => { expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([ dummyData, - {periodStart: 0, segmentStart: 0, segmentEnd: 3}, + {periodStart: 0, segmentStart: 0, segmentEnd: 3, vttOffset: 0}, ]); expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([ [ @@ -277,7 +277,7 @@ describe('TextEngine', () => { expect(mockParseMedia).toHaveBeenCalledOnceMoreWith([ dummyData, - {periodStart: 4, segmentStart: 4, segmentEnd: 7}, + {periodStart: 4, segmentStart: 4, segmentEnd: 7, vttOffset: 4}, ]); expect(mockDisplayer.appendSpy).toHaveBeenCalledOnceMoreWith([ [ diff --git a/test/text/vtt_text_parser_unit.js b/test/text/vtt_text_parser_unit.js index f2b1b51bf8b..ec0ccb8ecf3 100644 --- a/test/text/vtt_text_parser_unit.js +++ b/test/text/vtt_text_parser_unit.js @@ -34,13 +34,13 @@ describe('VttTextParser', () => { it('supports no cues', () => { verifyHelper([], 'WEBVTT', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports initial comments', () => { verifyHelper([], 'WEBVTT - Comments', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports comment blocks', () => { @@ -48,7 +48,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + 'NOTE\n' + 'This is a comment block', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports comment blocks with inital comment', () => { @@ -56,7 +56,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + 'NOTE - A header comment\n' + 'This is a comment block', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('handles a blank line at the end of the file', () => { @@ -67,7 +67,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('handles no blank line at the end of the file', () => { @@ -78,7 +78,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000\n' + 'Test\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0, }); }); @@ -90,7 +90,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports cues with no settings', () => { @@ -106,7 +106,7 @@ describe('VttTextParser', () => { '2\n' + '00:00:40.000 --> 00:00:50.000\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports cues with no ID', () => { @@ -120,7 +120,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:40.000 --> 00:00:50.000\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports comments within cues', () => { @@ -136,7 +136,7 @@ describe('VttTextParser', () => { 'This is a note\n\n' + '00:00:40.000 --> 00:00:50.000\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports non-integer timecodes', () => { @@ -147,7 +147,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.100 --> 00:00:40.505\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports large timecodes', () => { @@ -158,50 +158,50 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 30:00:00.000\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('requires header', () => { errorHelper(shaka.util.Error.Code.INVALID_TEXT_HEADER, '', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); errorHelper(shaka.util.Error.Code.INVALID_TEXT_HEADER, '00:00:00.000 --> 00:00:00.020\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('rejects invalid time values', () => { errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n0:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n00:00.20 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n00:100.20 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n00:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n00:00:00:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n00:61.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); errorHelper(shaka.util.Error.Code.INVALID_TEXT_CUE, 'WEBVTT\n\n61:00.020 --> 0:00.040\nTest', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}, + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}, anyString); }); @@ -226,7 +226,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:40.000 --> 00:00:50.000 vertical:lr\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports line setting', () => { @@ -258,7 +258,7 @@ describe('VttTextParser', () => { 'Test3\n\n' + '00:00:55.000 --> 00:01:05.000 line:12.3%\n' + 'Test4\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports line setting with optional part', () => { @@ -280,7 +280,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:40.000 --> 00:00:50.000 line:-1,center\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports position setting', () => { @@ -294,7 +294,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:25.000 --> 00:00:45.000 position:12.3%\n' + 'Test2\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports position setting with optional part', () => { @@ -314,7 +314,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:20.000 --> 00:00:40.000 position:45%,start\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports size setting', () => { @@ -328,7 +328,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:25.000 --> 00:00:45.000 size:12.3%\n' + 'Test2\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports align setting', () => { @@ -339,7 +339,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 align:center\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports multiple settings', () => { @@ -357,7 +357,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 align:center size:56% vertical:lr\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports timestamps with one-digit hour at start time', () => { @@ -375,7 +375,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '0:00:20.000 --> 00:00:40.000 align:center size:56% vertical:lr\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports timestamps with one-digit hour at end time', () => { @@ -393,7 +393,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 0:00:40.000 align:center size:56% vertical:lr\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports stamps with one-digit hours at start & end time', () => { @@ -411,15 +411,15 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '0:00:20.000 --> 0:00:40.000 align:center size:56% vertical:lr\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); - it('uses time offset from periodStart, not segmentStart', () => { + it('uses time offset from vttOffset, not periodStart or segmentStart', () => { verifyHelper( [ { - startTime: 70, - endTime: 80, + startTime: 50, + endTime: 60, payload: 'Test', textAlign: 'center', size: 56, @@ -429,10 +429,9 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '0:00:10.000 --> 0:00:20.000 align:center size:56% vertical:lr\n' + 'Test', - {periodStart: 60, segmentStart: 80, segmentEnd: 100}); + {periodStart: 60, segmentStart: 80, segmentEnd: 100, vttOffset: 40}); }); - it('parses VTTRegions', () => { verifyHelper( [ @@ -460,7 +459,7 @@ describe('VttTextParser', () => { 'viewportanchor=10%,90% scroll=up\n\n' + '0:00:20.000 --> 0:00:40.000 region:reg1\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('ignores and logs invalid settings', () => { @@ -473,7 +472,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 vertical:es\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); verifyHelper( [ @@ -482,7 +481,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 vertical:\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); verifyHelper( [ @@ -491,7 +490,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 vertical\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); verifyHelper( [ @@ -500,7 +499,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 line:-3%\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); verifyHelper( [ @@ -509,7 +508,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 line:45%%\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); verifyHelper( [ @@ -518,7 +517,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 align:10\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); verifyHelper( [ @@ -527,7 +526,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.000 --> 00:00:40.000 align:foo\n' + 'Test\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); expect(logWarningSpy).toHaveBeenCalledTimes(7); }); @@ -546,7 +545,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:40.000 --> 00:00:50.000 line:-1\n' + 'Test2', - {periodStart: 0, segmentStart: 25, segmentEnd: 65}); + {periodStart: 0, segmentStart: 25, segmentEnd: 65, vttOffset: 0}); }); it('handles timestamp rollover with X-TIMESTAMP-MAP header', () => { @@ -562,7 +561,7 @@ describe('VttTextParser', () => { 'Test', // Non-null segmentStart takes precedence over X-TIMESTAMP-MAP. // This protects us from rollover in the MPEGTS field. - {periodStart: 0, segmentStart: 95440, segmentEnd: 95550}); + {periodStart: 0, segmentStart: 95440, segmentEnd: 95550, vttOffset: 0}); verifyHelper( [ @@ -575,7 +574,7 @@ describe('VttTextParser', () => { 'X-TIMESTAMP-MAP=MPEGTS:9745408,LOCAL:00:00:00.000\n\n' + '00:00:00.000 --> 00:00:02.000 line:0\n' + 'Test2', - {periodStart: 0, segmentStart: 95550, segmentEnd: 95560}); + {periodStart: 0, segmentStart: 95550, segmentEnd: 95560, vttOffset: 0}); }); it('supports global style blocks', () => { @@ -606,7 +605,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:40.000 --> 00:00:50.000\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports global style blocks without blank lines', () => { @@ -634,7 +633,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:40.000 --> 00:00:50.000\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports payload stylized', () => { @@ -775,7 +774,7 @@ describe('VttTextParser', () => { 'Test 7\n\n' + '00:01:30.000 --> 00:01:40.000\n' + 'Test8', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports specific style blocks', () => { @@ -803,7 +802,7 @@ describe('VttTextParser', () => { 'Test\n\n' + '00:00:40.000 --> 00:00:50.000\n' + 'Test2', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports only two digits in the timestamp', () => { @@ -814,7 +813,7 @@ describe('VttTextParser', () => { 'WEBVTT\n\n' + '00:00:20.00 --> 00:00:40.00\n' + 'Test', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports class with default color', () => { @@ -956,7 +955,7 @@ describe('VttTextParser', () => { 'forward slash 1/2 in text\n\n' + '00:01:50.000 --> 00:02:00.000\n' + 'less or more < > in text', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); it('supports default color overriding', () => { @@ -982,7 +981,7 @@ describe('VttTextParser', () => { '::cue(bg_blue) { font-size: 10px; background-color: #FF0 }\n\n' + '00:00:10.000 --> 00:00:20.000\n' + 'Example 1\n\n', - {periodStart: 0, segmentStart: 0, segmentEnd: 0}); + {periodStart: 0, segmentStart: 0, segmentEnd: 0, vttOffset: 0}); }); /**