diff --git a/externs/shaka/player.js b/externs/shaka/player.js index 87abd72a266..17a681fa64e 100644 --- a/externs/shaka/player.js +++ b/externs/shaka/player.js @@ -782,6 +782,7 @@ shaka.extern.HlsManifestConfiguration; * disableText: boolean, * disableThumbnails: boolean, * defaultPresentationDelay: number, + * textOffsetMode: boolean, * dash: shaka.extern.DashManifestConfiguration, * hls: shaka.extern.HlsManifestConfiguration * }} @@ -813,6 +814,11 @@ 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} textOffsetMode + * Option to use alternative text timings calculation. Currently allows + * to change VTT text timings to be relative to segment start instead of + * being absolute (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..eb7a64e1935 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, + * offsetStart: 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} offsetStart + * The start time relative to either segment or period start + * depending on textOffsetMode configuration. * * @exportDoc */ diff --git a/lib/media/media_source_engine.js b/lib/media/media_source_engine.js index 3f5fe6be23a..69bae448b2b 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.textOffsetMode_ = false; + const onMetadataNoOp = (metadata, timestampOffset, segmentEnd) => {}; /** @private {!function(!Array., @@ -367,7 +370,7 @@ 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.textOffsetMode_); } /** @@ -1113,6 +1116,13 @@ shaka.media.MediaSourceEngine = class { } } + /** + * @param {boolean} textOffsetMode + */ + setTextOffsetMode(textOffsetMode) { + this.textOffsetMode_ = textOffsetMode; + } + /** * 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..f855a3dfbfc 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 {textOffsetMode} = this.config_.manifest; + mediaSourceEngine.setTextOffsetMode(textOffsetMode); // Wait for media source engine to finish opening. This promise should // NEVER be rejected as per the media source engine implementation. @@ -3005,6 +3007,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget { } if (this.mediaSourceEngine_) { + const {textOffsetMode} = this.config_.manifest; + this.mediaSourceEngine_.setTextOffsetMode(textOffsetMode); + const textDisplayerFactory = this.config_.textDisplayFactory; if (this.lastTextFactory_ != textDisplayerFactory) { const displayer = @@ -4849,6 +4854,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget { periodStart: 0, segmentStart: 0, segmentEnd: this.video_.duration, + offsetStart: 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..2ef055e200c 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.textOffsetMode_ = false; + /** @private {number} */ this.timestampOffset_ = 0; @@ -130,8 +133,9 @@ shaka.text.TextEngine = class { * * @param {string} mimeType * @param {boolean} sequenceMode + * @param {boolean} textOffsetMode */ - initParser(mimeType, sequenceMode) { + initParser(mimeType, sequenceMode, textOffsetMode) { // 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.textOffsetMode_ = textOffsetMode; } /** @@ -179,6 +184,7 @@ shaka.text.TextEngine = class { periodStart: this.timestampOffset_, segmentStart: startTime, segmentEnd: endTime, + offsetStart: this.textOffsetMode_ ? startTime : this.timestampOffset_, }; // 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..ea905b60649 100644 --- a/lib/text/vtt_text_parser.js +++ b/lib/text/vtt_text_parser.js @@ -62,9 +62,12 @@ shaka.text.VttTextParser = class { shaka.util.Error.Code.INVALID_TEXT_HEADER); } + // Depending on configuration, "offsetStart" 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.offsetStart; // 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..38a80596408 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, + textOffsetMode: false, dash: { clockSyncUri: '', ignoreDrmInfo: false,