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,