Skip to content

Commit

Permalink
feat: Add TextDisplayer config (#6477)
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed Apr 24, 2024
1 parent 4302a6b commit de2a2d8
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 14 deletions.
10 changes: 10 additions & 0 deletions demo/config.js
Expand Up @@ -93,6 +93,7 @@ shakaDemo.Config = class {
this.addMssManifestSection_();
this.addRetrySection_('manifest', 'Manifest Retry Parameters');
this.addRetrictionsSection_('', 'Restrictions');
this.addTextDisplayerSection_();
this.addCmcdSection_();
this.addCmsdSection_();
this.addLcevcSection_();
Expand Down Expand Up @@ -306,6 +307,15 @@ shakaDemo.Config = class {
this.addRetrictionsSection_('abr', 'Adaptation Restrictions');
}

/** @private */
addTextDisplayerSection_() {
const docLink = this.resolveExternLink_('.TextDisplayerConfiguration');
this.addSection_('Text displayer', docLink)
.addNumberInput_('Captions update period',
'textDisplayer.captionsUpdatePeriod',
/* canBeDecimal= */ true);
}

/** @private */
addCmcdSection_() {
const docLink = this.resolveExternLink_('.CmcdConfiguration');
Expand Down
2 changes: 2 additions & 0 deletions docs/tutorials/upgrade.md
Expand Up @@ -106,6 +106,8 @@ application:
- `mediaSource.sourceBufferExtraFeatures` has been replaced with `mediaSource.addExtraFeaturesToSourceBuffer` callback.

- Plugin changes:
- `TextDisplayer` plugins must implement the `configure()` method.
- `TextParser` plugins must implement the `setManifestType()` and `setSequenceMode()` methods.
- `Transmuxer` plugins now has three new parameters in `transmux()` method.

- Player API Changes:
Expand Down
20 changes: 20 additions & 0 deletions externs/shaka/player.js
Expand Up @@ -1753,6 +1753,23 @@ shaka.extern.LcevcConfiguration;
shaka.extern.OfflineConfiguration;


/**
* @typedef {{
* captionsUpdatePeriod: number
* }}
*
* @description
* Text displayer configuration.
*
* @property {number} captionsUpdatePeriod
* The number of seconds to see if the captions should be updated.
* Defaults to <code>0.25</code>.
*
* @exportDoc
*/
shaka.extern.TextDisplayerConfiguration;


/**
* @typedef {{
* ads: shaka.extern.AdsConfiguration,
Expand Down Expand Up @@ -1784,6 +1801,7 @@ shaka.extern.OfflineConfiguration;
* restrictions: shaka.extern.Restrictions,
* playRangeStart: number,
* playRangeEnd: number,
* textDisplayer: shaka.extern.TextDisplayerConfiguration,
* textDisplayFactory: shaka.extern.TextDisplayer.Factory
* }}
*
Expand Down Expand Up @@ -1870,6 +1888,8 @@ shaka.extern.OfflineConfiguration;
* @property {number} playRangeEnd
* Optional playback and seek end time in seconds. Defaults to the end of
* the presentation if not provided.
* @property {shaka.extern.TextDisplayerConfiguration} textDisplayer
* Text displayer configuration and settings.
* @property {shaka.extern.TextDisplayer.Factory} textDisplayFactory
* A factory to construct a text displayer. Note that, if this is changed
* during playback, it will cause the text tracks to be reloaded.
Expand Down
7 changes: 7 additions & 0 deletions externs/shaka/text.js
Expand Up @@ -132,6 +132,13 @@ shaka.extern.TextDisplayer = class {
*/
destroy() {}

/**
* Sets the TextDisplayer configuration.
*
* @param {shaka.extern.TextDisplayerConfiguration} config
*/
configure(config) {}

/**
* Append given text cues to the list of cues to be displayed.
*
Expand Down
22 changes: 21 additions & 1 deletion lib/player.js
Expand Up @@ -2088,6 +2088,13 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
// until they are both initialized before setting the initial value.
const textDisplayerFactory = this.config_.textDisplayFactory;
const textDisplayer = textDisplayerFactory();
if (textDisplayer.configure) {
textDisplayer.configure(this.config_.textDisplayer);
} else {
shaka.Deprecate.deprecateFeature(5,
'Text displayer w/ configure',
'Text displayer should have a "configure" method!');
}
this.lastTextFactory_ = textDisplayerFactory;

const mediaSourceEngine = this.createMediaSourceEngine(
Expand Down Expand Up @@ -3436,13 +3443,25 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
const textDisplayerFactory = this.config_.textDisplayFactory;
if (this.lastTextFactory_ != textDisplayerFactory) {
const displayer = textDisplayerFactory();
if (displayer.configure) {
displayer.configure(this.config_.textDisplayer);
} else {
shaka.Deprecate.deprecateFeature(5,
'Text displayer w/ configure',
'Text displayer should have a "configure" method!');
}
this.mediaSourceEngine_.setTextDisplayer(displayer);
this.lastTextFactory_ = textDisplayerFactory;

if (this.streamingEngine_) {
// Reload the text stream, so the cues will load again.
this.streamingEngine_.reloadTextStream();
}
} else {
const displayer = this.mediaSourceEngine_.getTextDisplayer();
if (displayer.configure) {
displayer.configure(this.config_.textDisplayer);
}
}
}
if (this.abrManager_) {
Expand Down Expand Up @@ -5590,8 +5609,9 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
// TextDisplay factory must capture a reference to "this".
config.textDisplayFactory = () => {
if (this.videoContainer_) {
const latestConfig = this.getConfiguration();
return new shaka.text.UITextDisplayer(
this.video_, this.videoContainer_);
this.video_, this.videoContainer_, latestConfig.textDisplayer);
} else {
// eslint-disable-next-line no-restricted-syntax
if (HTMLMediaElement.prototype.addTextTrack) {
Expand Down
9 changes: 9 additions & 0 deletions lib/text/simple_text_displayer.js
Expand Up @@ -56,6 +56,15 @@ shaka.text.SimpleTextDisplayer = class {
this.textTrack_.mode = 'hidden';
}


/**
* @override
* @export
*/
configure(config) {
// Unused.
}

/**
* @override
* @export
Expand Down
7 changes: 7 additions & 0 deletions lib/text/stub_text_displayer.js
Expand Up @@ -13,6 +13,13 @@ goog.provide('shaka.text.StubTextDisplayer');
* @export
*/
shaka.text.StubTextDisplayer = class {
/**
* @override
* @export
*/
configure(config) {
}

/**
* @override
* @export
Expand Down
8 changes: 5 additions & 3 deletions lib/text/text_engine.js
Expand Up @@ -7,7 +7,7 @@
goog.provide('shaka.text.TextEngine');

goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.Deprecate');
goog.require('shaka.media.ClosedCaptionParser');
goog.require('shaka.text.Cue');
goog.require('shaka.util.BufferUtils');
Expand Down Expand Up @@ -153,13 +153,15 @@ shaka.text.TextEngine = class {
if (this.parser_.setSequenceMode) {
this.parser_.setSequenceMode(sequenceMode);
} else {
shaka.log.alwaysWarn(
shaka.Deprecate.deprecateFeature(5,
'Text parsers w/ setSequenceMode',
'Text parsers should have a "setSequenceMode" method!');
}
if (this.parser_.setManifestType) {
this.parser_.setManifestType(manifestType);
} else {
shaka.log.alwaysWarn(
shaka.Deprecate.deprecateFeature(5,
'Text parsers w/ setManifestType',
'Text parsers should have a "setManifestType" method!');
}
this.segmentRelativeVttTiming_ = segmentRelativeVttTiming;
Expand Down
22 changes: 14 additions & 8 deletions lib/text/ui_text_displayer.js
Expand Up @@ -28,8 +28,9 @@ shaka.text.UITextDisplayer = class {
* Constructor.
* @param {HTMLMediaElement} video
* @param {HTMLElement} videoContainer
* @param {shaka.extern.TextDisplayerConfiguration} config
*/
constructor(video, videoContainer) {
constructor(video, videoContainer, config) {
goog.asserts.assert(videoContainer, 'videoContainer should be valid.');

/** @private {boolean} */
Expand Down Expand Up @@ -64,18 +65,12 @@ shaka.text.UITextDisplayer = class {

this.videoContainer_.appendChild(this.textContainer_);

/**
* The captions' update period in seconds.
* @private {number}
*/
const updatePeriod = 0.25;

/** @private {shaka.util.Timer} */
this.captionsTimer_ = new shaka.util.Timer(() => {
if (!this.video_.paused) {
this.updateCaptions_();
}
}).tickEvery(updatePeriod);
}).tickEvery(config.captionsUpdatePeriod);

/**
* Maps cues to cue elements. Specifically points out the wrapper element of
Expand Down Expand Up @@ -130,6 +125,17 @@ shaka.text.UITextDisplayer = class {
}


/**
* @override
* @export
*/
configure(config) {
if (this.captionsTimer_) {
this.captionsTimer_.tickEvery(config.captionsUpdatePeriod);
}
}


/**
* @override
* @export
Expand Down
5 changes: 5 additions & 0 deletions lib/util/player_configuration.js
Expand Up @@ -396,6 +396,10 @@ shaka.util.PlayerConfiguration = class {
skipPlayDetection,
};

const textDisplayer = {
captionsUpdatePeriod: 0.25,
};

const AutoShowText = shaka.config.AutoShowText;

/** @type {shaka.extern.PlayerConfiguration} */
Expand Down Expand Up @@ -436,6 +440,7 @@ shaka.util.PlayerConfiguration = class {
},
playRangeStart: 0,
playRangeEnd: Infinity,
textDisplayer: textDisplayer,
textDisplayFactory: () => null,
cmcd: cmcd,
cmsd: cmsd,
Expand Down
3 changes: 3 additions & 0 deletions test/test/util/fake_text_displayer.js
Expand Up @@ -34,6 +34,9 @@ shaka.test.FakeTextDisplayer = class {
return func();
}

/** @override */
configure(config) {}

/** @override */
append(cues) {
const func = shaka.test.Util.spyFunc(this.appendSpy);
Expand Down
3 changes: 2 additions & 1 deletion test/test/util/layout_tests.js
Expand Up @@ -291,7 +291,8 @@ shaka.test.DomTextLayoutTests = class extends shaka.test.TextLayoutTests {
recreateTextDisplayer() {
this.textDisplayer = new shaka.text.UITextDisplayer(
/** @type {!HTMLMediaElement} */(this.mockVideo),
this.videoContainer);
this.videoContainer,
{captionsUpdatePeriod: 0.25});
this.textDisplayer.setTextVisibility(true);
}

Expand Down
3 changes: 2 additions & 1 deletion test/text/ui_text_displayer_unit.js
Expand Up @@ -51,7 +51,8 @@ describe('UITextDisplayer', () => {

beforeEach(() => {
video.currentTime = 0;
textDisplayer = new shaka.text.UITextDisplayer(video, videoContainer);
textDisplayer = new shaka.text.UITextDisplayer(
video, videoContainer, {captionsUpdatePeriod: 0.25});
});

afterEach(async () => {
Expand Down

0 comments on commit de2a2d8

Please sign in to comment.