diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index f2a2b8d30b..8b5afd90d5 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -32,6 +32,7 @@ import { getIncludeCorsCredentials } from '../../scripts/settings/webSettings'; import { setBackdropTransparency, TRANSPARENCY_LEVEL } from '../../components/backdrop/backdrop'; import Events from '../../utils/events.ts'; import { includesAny } from '../../utils/container.ts'; +import debounce from 'lodash-es/debounce'; /** * Returns resolved URL. @@ -571,7 +572,12 @@ function tryRemoveElement(elem) { } } - setSubtitleOffset(offset) { + setSubtitleOffset = debounce(this._setSubtitleOffset, 100); + + /** + * @private + */ + _setSubtitleOffset(offset) { const offsetValue = parseFloat(offset); // if .ass currently rendering @@ -620,6 +626,41 @@ function tryRemoveElement(elem) { return relativeOffset; } + /** + * @private + * These browsers will not clear the existing active cue when setting an offset + * for native TextTracks. + * Any previous text tracks that are on the screen when the offset changes will remain next + * to the new tracks until they reach the end time of the new offset's instance of the track. + */ + requiresHidingActiveCuesOnOffsetChange() { + return !!browser.firefox; + } + + /** + * @private + */ + hideTextTrackWithActiveCues(currentTrack) { + if (currentTrack.activeCues) { + currentTrack.mode = 'hidden'; + } + } + + /** + * Forces the active cue to clear by disabling then re-enabling the track. + * The track mode is reverted inside of a 0ms timeout to free up the track + * and allow it to disable and clear the active cue. + * @private + */ + forceClearTextTrackActiveCues(currentTrack) { + if (currentTrack.activeCues) { + currentTrack.mode = 'disabled'; + setTimeout(() => { + currentTrack.mode = 'showing'; + }, 0); + } + } + /** * @private */ @@ -629,11 +670,21 @@ function tryRemoveElement(elem) { if (offsetValue === 0) { return; } + + const shouldClearActiveCues = this.requiresHidingActiveCuesOnOffsetChange(); + if (shouldClearActiveCues) { + this.hideTextTrackWithActiveCues(currentTrack); + } + Array.from(currentTrack.cues) .forEach(function (cue) { cue.startTime -= offsetValue; cue.endTime -= offsetValue; }); + + if (shouldClearActiveCues) { + this.forceClearTextTrackActiveCues(currentTrack); + } } } @@ -771,6 +822,8 @@ function tryRemoveElement(elem) { } destroy() { + this.setSubtitleOffset.cancel(); + destroyHlsPlayer(this); destroyFlvPlayer(this);