rx-player
Version:
Canal+ HTML5 Video Player
229 lines (228 loc) • 9.59 kB
JavaScript
"use strict";
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
var add_text_track_1 = require("../../../compat/add_text_track");
var remove_cue_1 = require("../../../compat/remove_cue");
var log_1 = require("../../../log");
var ranges_1 = require("../../../utils/ranges");
var manual_time_ranges_1 = require("../manual_time_ranges");
var native_parsers_1 = require("./native_parsers");
/**
* Implementation of an `ITextDisplayer` for "native" text tracks.
* "Native" text tracks rely on a `<track>` HTMLElement and its associated
* expected behavior to display subtitles synchronized to the video.
* @class NativeTextDisplayer
*/
var NativeTextDisplayer = /** @class */ (function () {
/**
* @param {HTMLMediaElement} videoElement
*/
function NativeTextDisplayer(videoElement) {
log_1.default.debug("NTD: Creating NativeTextDisplayer");
var _a = (0, add_text_track_1.default)(videoElement), track = _a.track, trackElement = _a.trackElement;
this._buffered = new manual_time_ranges_1.default();
this._videoElement = videoElement;
this._track = track;
this._trackElement = trackElement;
}
/**
* Push text segment to the NativeTextDisplayer.
* @param {Object} infos
* @returns {Object}
*/
NativeTextDisplayer.prototype.pushTextData = function (infos) {
var e_1, _a;
var _b, _c;
log_1.default.debug("NTD: Appending new native text tracks");
if (infos.chunk === null) {
return (0, ranges_1.convertToRanges)(this._buffered);
}
var timestampOffset = infos.timestampOffset, appendWindow = infos.appendWindow, chunk = infos.chunk;
var startTime = chunk.start, endTime = chunk.end, dataString = chunk.data, type = chunk.type, language = chunk.language;
var appendWindowStart = (_b = appendWindow[0]) !== null && _b !== void 0 ? _b : 0;
var appendWindowEnd = (_c = appendWindow[1]) !== null && _c !== void 0 ? _c : Infinity;
var cues = (0, native_parsers_1.default)(type, dataString, timestampOffset, language);
if (appendWindowStart !== 0 && appendWindowEnd !== Infinity) {
// Removing before window start
var i = 0;
while (i < cues.length && cues[i].endTime <= appendWindowStart) {
i++;
}
cues.splice(0, i);
i = 0;
while (i < cues.length && cues[i].startTime < appendWindowStart) {
cues[i].startTime = appendWindowStart;
i++;
}
// Removing after window end
i = cues.length - 1;
while (i >= 0 && cues[i].startTime >= appendWindowEnd) {
i--;
}
cues.splice(i, cues.length);
i = cues.length - 1;
while (i >= 0 && cues[i].endTime > appendWindowEnd) {
cues[i].endTime = appendWindowEnd;
i--;
}
}
var start;
if (startTime !== undefined) {
start = Math.max(appendWindowStart, startTime);
}
else {
if (cues.length <= 0) {
log_1.default.warn("NTD: Current text tracks have no cues nor start time. Aborting");
return (0, ranges_1.convertToRanges)(this._buffered);
}
log_1.default.warn("NTD: No start time given. Guessing from cues.");
start = cues[0].startTime;
}
var end;
if (endTime !== undefined) {
end = Math.min(appendWindowEnd, endTime);
}
else {
if (cues.length <= 0) {
log_1.default.warn("NTD: Current text tracks have no cues nor end time. Aborting");
return (0, ranges_1.convertToRanges)(this._buffered);
}
log_1.default.warn("NTD: No end time given. Guessing from cues.");
end = cues[cues.length - 1].endTime;
}
if (end <= start) {
log_1.default.warn("NTD: Invalid text track appended: ", "the start time is inferior or equal to the end time.");
return (0, ranges_1.convertToRanges)(this._buffered);
}
if (cues.length > 0) {
var firstCue = cues[0];
// NOTE(compat): cleanup all current cues if the newly added
// ones are in the past. this is supposed to fix an issue on
// IE/Edge.
// TODO Move to compat
var currentCues = this._track.cues;
if (currentCues !== null && currentCues.length > 0) {
if (firstCue.startTime < currentCues[currentCues.length - 1].startTime) {
this._removeData(firstCue.startTime, +Infinity);
}
}
try {
for (var cues_1 = __values(cues), cues_1_1 = cues_1.next(); !cues_1_1.done; cues_1_1 = cues_1.next()) {
var cue = cues_1_1.value;
this._track.addCue(cue);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (cues_1_1 && !cues_1_1.done && (_a = cues_1.return)) _a.call(cues_1);
}
finally { if (e_1) throw e_1.error; }
}
}
this._buffered.insert(start, end);
return (0, ranges_1.convertToRanges)(this._buffered);
};
/**
* Remove buffered data.
* @param {number} start - start position, in seconds
* @param {number} end - end position, in seconds
* @returns {Object}
*/
NativeTextDisplayer.prototype.removeBuffer = function (start, end) {
this._removeData(start, end);
return (0, ranges_1.convertToRanges)(this._buffered);
};
/**
* Returns the currently buffered data, in a TimeRanges object.
* @returns {Array.<Object>}
*/
NativeTextDisplayer.prototype.getBufferedRanges = function () {
return (0, ranges_1.convertToRanges)(this._buffered);
};
NativeTextDisplayer.prototype.reset = function () {
log_1.default.debug("NTD: Aborting NativeTextDisplayer");
this._removeData(0, Infinity);
this._clearTrackElement();
};
NativeTextDisplayer.prototype.stop = function () {
log_1.default.debug("NTD: Aborting NativeTextDisplayer");
this._removeData(0, Infinity);
var _a = this, _trackElement = _a._trackElement, _videoElement = _a._videoElement;
if (_trackElement !== undefined && _videoElement.hasChildNodes()) {
try {
_videoElement.removeChild(_trackElement);
}
catch (_e) {
log_1.default.warn("NTD: Can't remove track element from the video");
}
}
this._track.mode = "disabled";
if (this._trackElement !== undefined) {
this._trackElement.innerHTML = "";
}
};
NativeTextDisplayer.prototype._removeData = function (start, end) {
log_1.default.debug("NTD: Removing native text track data", start, end);
var track = this._track;
var cues = track.cues;
if (cues !== null) {
for (var i = cues.length - 1; i >= 0; i--) {
var cue = cues[i];
var startTime = cue.startTime, endTime = cue.endTime;
if (startTime >= start && startTime <= end && endTime <= end) {
(0, remove_cue_1.default)(track, cue);
}
}
}
this._buffered.remove(start, end);
};
NativeTextDisplayer.prototype._clearTrackElement = function () {
var _a = this, _trackElement = _a._trackElement, _videoElement = _a._videoElement;
if (_trackElement !== undefined && _videoElement.hasChildNodes()) {
try {
_videoElement.removeChild(_trackElement);
}
catch (_e) {
log_1.default.warn("NTD: Can't remove track element from the video");
}
}
// Ugly trick to work-around browser bugs by refreshing its mode
var oldMode = this._track.mode;
this._track.mode = "disabled";
this._track.mode = oldMode;
if (this._trackElement !== undefined) {
this._trackElement.innerHTML = "";
}
};
return NativeTextDisplayer;
}());
exports.default = NativeTextDisplayer;
/*
* The following ugly code is here to provide a compile-time check that an
* `INativeTextTracksBufferSegmentData` (type of data pushed to a
* `NativeTextDisplayer`) can be derived from a `ITextTrackSegmentData`
* (text track data parsed from a segment).
*
* It doesn't correspond at all to real code that will be called. This is just
* a hack to tell TypeScript to perform that check.
*/
if (0 /* __ENVIRONMENT__.CURRENT_ENV */ === 1 /* __ENVIRONMENT__.DEV */) {
// @ts-expect-error: uncalled function just for type checking
function _checkType(input) {
function checkEqual(_arg) {
/* nothing */
}
checkEqual(input);
}
}