Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add TextDisplayer config #6477

Merged
merged 3 commits into from Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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