@tianfeng98/hls.js
Version:
HLS.js is a JavaScript library that supports playing MPEG-TS and HEVC encoded HLS streams in browsers with support for MSE.
1,343 lines (1,305 loc) • 831 kB
JavaScript
(function __HLS_WORKER_BUNDLE__(__IN_WORKER__){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Hls = factory());
})(this, (function () { 'use strict';
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter(function (r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
})), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
_defineProperty(e, r, t[r]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
});
}
return e;
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
Object.defineProperty(Constructor, "prototype", {
writable: false
});
return Constructor;
}
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _getPrototypeOf(o) {
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
return o.__proto__ || Object.getPrototypeOf(o);
};
return _getPrototypeOf(o);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _isNativeReflectConstruct() {
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy === "function") return true;
try {
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
return true;
} catch (e) {
return false;
}
}
function _construct(Parent, args, Class) {
if (_isNativeReflectConstruct()) {
_construct = Reflect.construct.bind();
} else {
_construct = function _construct(Parent, args, Class) {
var a = [null];
a.push.apply(a, args);
var Constructor = Function.bind.apply(Parent, a);
var instance = new Constructor();
if (Class) _setPrototypeOf(instance, Class.prototype);
return instance;
};
}
return _construct.apply(null, arguments);
}
function _isNativeFunction(fn) {
return Function.toString.call(fn).indexOf("[native code]") !== -1;
}
function _wrapNativeSuper(Class) {
var _cache = typeof Map === "function" ? new Map() : undefined;
_wrapNativeSuper = function _wrapNativeSuper(Class) {
if (Class === null || !_isNativeFunction(Class)) return Class;
if (typeof Class !== "function") {
throw new TypeError("Super expression must either be null or a function");
}
if (typeof _cache !== "undefined") {
if (_cache.has(Class)) return _cache.get(Class);
_cache.set(Class, Wrapper);
}
function Wrapper() {
return _construct(Class, arguments, _getPrototypeOf(this).constructor);
}
Wrapper.prototype = Object.create(Class.prototype, {
constructor: {
value: Wrapper,
enumerable: false,
writable: true,
configurable: true
}
});
return _setPrototypeOf(Wrapper, Class);
};
return _wrapNativeSuper(Class);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _toPrimitive(input, hint) {
if (typeof input !== "object" || input === null) return input;
var prim = input[Symbol.toPrimitive];
if (prim !== undefined) {
var res = prim.call(input, hint || "default");
if (typeof res !== "object") return res;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return (hint === "string" ? String : Number)(input);
}
function _toPropertyKey(arg) {
var key = _toPrimitive(arg, "string");
return typeof key === "symbol" ? key : String(key);
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var urlToolkit = {exports: {}};
(function (module, exports) {
// see https://tools.ietf.org/html/rfc1808
(function (root) {
var URL_REGEX =
/^(?=((?:[a-zA-Z0-9+\-.]+:)?))\1(?=((?:\/\/[^\/?#]*)?))\2(?=((?:(?:[^?#\/]*\/)*[^;?#\/]*)?))\3((?:;[^?#]*)?)(\?[^#]*)?(#[^]*)?$/;
var FIRST_SEGMENT_REGEX = /^(?=([^\/?#]*))\1([^]*)$/;
var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g;
var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g;
var URLToolkit = {
// If opts.alwaysNormalize is true then the path will always be normalized even when it starts with / or //
// E.g
// With opts.alwaysNormalize = false (default, spec compliant)
// http://a.com/b/cd + /e/f/../g => http://a.com/e/f/../g
// With opts.alwaysNormalize = true (not spec compliant)
// http://a.com/b/cd + /e/f/../g => http://a.com/e/g
buildAbsoluteURL: function (baseURL, relativeURL, opts) {
opts = opts || {};
// remove any remaining space and CRLF
baseURL = baseURL.trim();
relativeURL = relativeURL.trim();
if (!relativeURL) {
// 2a) If the embedded URL is entirely empty, it inherits the
// entire base URL (i.e., is set equal to the base URL)
// and we are done.
if (!opts.alwaysNormalize) {
return baseURL;
}
var basePartsForNormalise = URLToolkit.parseURL(baseURL);
if (!basePartsForNormalise) {
throw new Error('Error trying to parse base URL.');
}
basePartsForNormalise.path = URLToolkit.normalizePath(
basePartsForNormalise.path
);
return URLToolkit.buildURLFromParts(basePartsForNormalise);
}
var relativeParts = URLToolkit.parseURL(relativeURL);
if (!relativeParts) {
throw new Error('Error trying to parse relative URL.');
}
if (relativeParts.scheme) {
// 2b) If the embedded URL starts with a scheme name, it is
// interpreted as an absolute URL and we are done.
if (!opts.alwaysNormalize) {
return relativeURL;
}
relativeParts.path = URLToolkit.normalizePath(relativeParts.path);
return URLToolkit.buildURLFromParts(relativeParts);
}
var baseParts = URLToolkit.parseURL(baseURL);
if (!baseParts) {
throw new Error('Error trying to parse base URL.');
}
if (!baseParts.netLoc && baseParts.path && baseParts.path[0] !== '/') {
// If netLoc missing and path doesn't start with '/', assume everthing before the first '/' is the netLoc
// This causes 'example.com/a' to be handled as '//example.com/a' instead of '/example.com/a'
var pathParts = FIRST_SEGMENT_REGEX.exec(baseParts.path);
baseParts.netLoc = pathParts[1];
baseParts.path = pathParts[2];
}
if (baseParts.netLoc && !baseParts.path) {
baseParts.path = '/';
}
var builtParts = {
// 2c) Otherwise, the embedded URL inherits the scheme of
// the base URL.
scheme: baseParts.scheme,
netLoc: relativeParts.netLoc,
path: null,
params: relativeParts.params,
query: relativeParts.query,
fragment: relativeParts.fragment,
};
if (!relativeParts.netLoc) {
// 3) If the embedded URL's <net_loc> is non-empty, we skip to
// Step 7. Otherwise, the embedded URL inherits the <net_loc>
// (if any) of the base URL.
builtParts.netLoc = baseParts.netLoc;
// 4) If the embedded URL path is preceded by a slash "/", the
// path is not relative and we skip to Step 7.
if (relativeParts.path[0] !== '/') {
if (!relativeParts.path) {
// 5) If the embedded URL path is empty (and not preceded by a
// slash), then the embedded URL inherits the base URL path
builtParts.path = baseParts.path;
// 5a) if the embedded URL's <params> is non-empty, we skip to
// step 7; otherwise, it inherits the <params> of the base
// URL (if any) and
if (!relativeParts.params) {
builtParts.params = baseParts.params;
// 5b) if the embedded URL's <query> is non-empty, we skip to
// step 7; otherwise, it inherits the <query> of the base
// URL (if any) and we skip to step 7.
if (!relativeParts.query) {
builtParts.query = baseParts.query;
}
}
} else {
// 6) The last segment of the base URL's path (anything
// following the rightmost slash "/", or the entire path if no
// slash is present) is removed and the embedded URL's path is
// appended in its place.
var baseURLPath = baseParts.path;
var newPath =
baseURLPath.substring(0, baseURLPath.lastIndexOf('/') + 1) +
relativeParts.path;
builtParts.path = URLToolkit.normalizePath(newPath);
}
}
}
if (builtParts.path === null) {
builtParts.path = opts.alwaysNormalize
? URLToolkit.normalizePath(relativeParts.path)
: relativeParts.path;
}
return URLToolkit.buildURLFromParts(builtParts);
},
parseURL: function (url) {
var parts = URL_REGEX.exec(url);
if (!parts) {
return null;
}
return {
scheme: parts[1] || '',
netLoc: parts[2] || '',
path: parts[3] || '',
params: parts[4] || '',
query: parts[5] || '',
fragment: parts[6] || '',
};
},
normalizePath: function (path) {
// The following operations are
// then applied, in order, to the new path:
// 6a) All occurrences of "./", where "." is a complete path
// segment, are removed.
// 6b) If the path ends with "." as a complete path segment,
// that "." is removed.
path = path.split('').reverse().join('').replace(SLASH_DOT_REGEX, '');
// 6c) All occurrences of "<segment>/../", where <segment> is a
// complete path segment not equal to "..", are removed.
// Removal of these path segments is performed iteratively,
// removing the leftmost matching pattern on each iteration,
// until no matching pattern remains.
// 6d) If the path ends with "<segment>/..", where <segment> is a
// complete path segment not equal to "..", that
// "<segment>/.." is removed.
while (
path.length !== (path = path.replace(SLASH_DOT_DOT_REGEX, '')).length
) {}
return path.split('').reverse().join('');
},
buildURLFromParts: function (parts) {
return (
parts.scheme +
parts.netLoc +
parts.path +
parts.params +
parts.query +
parts.fragment
);
},
};
module.exports = URLToolkit;
})();
} (urlToolkit));
var urlToolkitExports = urlToolkit.exports;
var isFiniteNumber = Number.isFinite || function (value) {
return typeof value === 'number' && isFinite(value);
};
var Events = /*#__PURE__*/function (Events) {
Events["MEDIA_ATTACHING"] = "hlsMediaAttaching";
Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
Events["MEDIA_DETACHED"] = "hlsMediaDetached";
Events["BUFFER_RESET"] = "hlsBufferReset";
Events["BUFFER_CODECS"] = "hlsBufferCodecs";
Events["BUFFER_CREATED"] = "hlsBufferCreated";
Events["BUFFER_APPENDING"] = "hlsBufferAppending";
Events["BUFFER_APPENDED"] = "hlsBufferAppended";
Events["BUFFER_EOS"] = "hlsBufferEos";
Events["BUFFER_FLUSHING"] = "hlsBufferFlushing";
Events["BUFFER_FLUSHED"] = "hlsBufferFlushed";
Events["MANIFEST_LOADING"] = "hlsManifestLoading";
Events["MANIFEST_LOADED"] = "hlsManifestLoaded";
Events["MANIFEST_PARSED"] = "hlsManifestParsed";
Events["LEVEL_SWITCHING"] = "hlsLevelSwitching";
Events["LEVEL_SWITCHED"] = "hlsLevelSwitched";
Events["LEVEL_LOADING"] = "hlsLevelLoading";
Events["LEVEL_LOADED"] = "hlsLevelLoaded";
Events["LEVEL_UPDATED"] = "hlsLevelUpdated";
Events["LEVEL_PTS_UPDATED"] = "hlsLevelPtsUpdated";
Events["LEVELS_UPDATED"] = "hlsLevelsUpdated";
Events["AUDIO_TRACKS_UPDATED"] = "hlsAudioTracksUpdated";
Events["AUDIO_TRACK_SWITCHING"] = "hlsAudioTrackSwitching";
Events["AUDIO_TRACK_SWITCHED"] = "hlsAudioTrackSwitched";
Events["AUDIO_TRACK_LOADING"] = "hlsAudioTrackLoading";
Events["AUDIO_TRACK_LOADED"] = "hlsAudioTrackLoaded";
Events["SUBTITLE_TRACKS_UPDATED"] = "hlsSubtitleTracksUpdated";
Events["SUBTITLE_TRACKS_CLEARED"] = "hlsSubtitleTracksCleared";
Events["SUBTITLE_TRACK_SWITCH"] = "hlsSubtitleTrackSwitch";
Events["SUBTITLE_TRACK_LOADING"] = "hlsSubtitleTrackLoading";
Events["SUBTITLE_TRACK_LOADED"] = "hlsSubtitleTrackLoaded";
Events["SUBTITLE_FRAG_PROCESSED"] = "hlsSubtitleFragProcessed";
Events["CUES_PARSED"] = "hlsCuesParsed";
Events["NON_NATIVE_TEXT_TRACKS_FOUND"] = "hlsNonNativeTextTracksFound";
Events["INIT_PTS_FOUND"] = "hlsInitPtsFound";
Events["FRAG_LOADING"] = "hlsFragLoading";
Events["FRAG_LOAD_EMERGENCY_ABORTED"] = "hlsFragLoadEmergencyAborted";
Events["FRAG_LOADED"] = "hlsFragLoaded";
Events["FRAG_DECRYPTED"] = "hlsFragDecrypted";
Events["FRAG_PARSING_INIT_SEGMENT"] = "hlsFragParsingInitSegment";
Events["FRAG_PARSING_USERDATA"] = "hlsFragParsingUserdata";
Events["FRAG_PARSING_METADATA"] = "hlsFragParsingMetadata";
Events["FRAG_PARSED"] = "hlsFragParsed";
Events["FRAG_BUFFERED"] = "hlsFragBuffered";
Events["FRAG_CHANGED"] = "hlsFragChanged";
Events["FPS_DROP"] = "hlsFpsDrop";
Events["FPS_DROP_LEVEL_CAPPING"] = "hlsFpsDropLevelCapping";
Events["MAX_AUTO_LEVEL_UPDATED"] = "hlsMaxAutoLevelUpdated";
Events["ERROR"] = "hlsError";
Events["DESTROYING"] = "hlsDestroying";
Events["KEY_LOADING"] = "hlsKeyLoading";
Events["KEY_LOADED"] = "hlsKeyLoaded";
Events["LIVE_BACK_BUFFER_REACHED"] = "hlsLiveBackBufferReached";
Events["BACK_BUFFER_REACHED"] = "hlsBackBufferReached";
Events["STEERING_MANIFEST_LOADED"] = "hlsSteeringManifestLoaded";
return Events;
}({});
/**
* Defines each Event type and payload by Event name. Used in {@link hls.js#HlsEventEmitter} to strongly type the event listener API.
*/
var ErrorTypes = /*#__PURE__*/function (ErrorTypes) {
ErrorTypes["NETWORK_ERROR"] = "networkError";
ErrorTypes["MEDIA_ERROR"] = "mediaError";
ErrorTypes["KEY_SYSTEM_ERROR"] = "keySystemError";
ErrorTypes["MUX_ERROR"] = "muxError";
ErrorTypes["OTHER_ERROR"] = "otherError";
return ErrorTypes;
}({});
var ErrorDetails = /*#__PURE__*/function (ErrorDetails) {
ErrorDetails["KEY_SYSTEM_NO_KEYS"] = "keySystemNoKeys";
ErrorDetails["KEY_SYSTEM_NO_ACCESS"] = "keySystemNoAccess";
ErrorDetails["KEY_SYSTEM_NO_SESSION"] = "keySystemNoSession";
ErrorDetails["KEY_SYSTEM_NO_CONFIGURED_LICENSE"] = "keySystemNoConfiguredLicense";
ErrorDetails["KEY_SYSTEM_LICENSE_REQUEST_FAILED"] = "keySystemLicenseRequestFailed";
ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_REQUEST_FAILED"] = "keySystemServerCertificateRequestFailed";
ErrorDetails["KEY_SYSTEM_SERVER_CERTIFICATE_UPDATE_FAILED"] = "keySystemServerCertificateUpdateFailed";
ErrorDetails["KEY_SYSTEM_SESSION_UPDATE_FAILED"] = "keySystemSessionUpdateFailed";
ErrorDetails["KEY_SYSTEM_STATUS_OUTPUT_RESTRICTED"] = "keySystemStatusOutputRestricted";
ErrorDetails["KEY_SYSTEM_STATUS_INTERNAL_ERROR"] = "keySystemStatusInternalError";
ErrorDetails["MANIFEST_LOAD_ERROR"] = "manifestLoadError";
ErrorDetails["MANIFEST_LOAD_TIMEOUT"] = "manifestLoadTimeOut";
ErrorDetails["MANIFEST_PARSING_ERROR"] = "manifestParsingError";
ErrorDetails["MANIFEST_INCOMPATIBLE_CODECS_ERROR"] = "manifestIncompatibleCodecsError";
ErrorDetails["LEVEL_EMPTY_ERROR"] = "levelEmptyError";
ErrorDetails["LEVEL_LOAD_ERROR"] = "levelLoadError";
ErrorDetails["LEVEL_LOAD_TIMEOUT"] = "levelLoadTimeOut";
ErrorDetails["LEVEL_PARSING_ERROR"] = "levelParsingError";
ErrorDetails["LEVEL_SWITCH_ERROR"] = "levelSwitchError";
ErrorDetails["AUDIO_TRACK_LOAD_ERROR"] = "audioTrackLoadError";
ErrorDetails["AUDIO_TRACK_LOAD_TIMEOUT"] = "audioTrackLoadTimeOut";
ErrorDetails["SUBTITLE_LOAD_ERROR"] = "subtitleTrackLoadError";
ErrorDetails["SUBTITLE_TRACK_LOAD_TIMEOUT"] = "subtitleTrackLoadTimeOut";
ErrorDetails["FRAG_LOAD_ERROR"] = "fragLoadError";
ErrorDetails["FRAG_LOAD_TIMEOUT"] = "fragLoadTimeOut";
ErrorDetails["FRAG_DECRYPT_ERROR"] = "fragDecryptError";
ErrorDetails["FRAG_PARSING_ERROR"] = "fragParsingError";
ErrorDetails["FRAG_GAP"] = "fragGap";
ErrorDetails["REMUX_ALLOC_ERROR"] = "remuxAllocError";
ErrorDetails["KEY_LOAD_ERROR"] = "keyLoadError";
ErrorDetails["KEY_LOAD_TIMEOUT"] = "keyLoadTimeOut";
ErrorDetails["BUFFER_ADD_CODEC_ERROR"] = "bufferAddCodecError";
ErrorDetails["BUFFER_INCOMPATIBLE_CODECS_ERROR"] = "bufferIncompatibleCodecsError";
ErrorDetails["BUFFER_APPEND_ERROR"] = "bufferAppendError";
ErrorDetails["BUFFER_APPENDING_ERROR"] = "bufferAppendingError";
ErrorDetails["BUFFER_STALLED_ERROR"] = "bufferStalledError";
ErrorDetails["BUFFER_FULL_ERROR"] = "bufferFullError";
ErrorDetails["BUFFER_SEEK_OVER_HOLE"] = "bufferSeekOverHole";
ErrorDetails["BUFFER_NUDGE_ON_STALL"] = "bufferNudgeOnStall";
ErrorDetails["INTERNAL_EXCEPTION"] = "internalException";
ErrorDetails["INTERNAL_ABORTED"] = "aborted";
ErrorDetails["UNKNOWN"] = "unknown";
return ErrorDetails;
}({});
var noop = function noop() {};
var fakeLogger = {
trace: noop,
debug: noop,
log: noop,
warn: noop,
info: noop,
error: noop
};
var exportedLogger = fakeLogger;
// let lastCallTime;
// function formatMsgWithTimeInfo(type, msg) {
// const now = Date.now();
// const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
// lastCallTime = now;
// msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
// return msg;
// }
function consolePrintFn(type) {
var func = self.console[type];
if (func) {
return func.bind(self.console, "[" + type + "] >");
}
return noop;
}
function exportLoggerFunctions(debugConfig) {
for (var _len = arguments.length, functions = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
functions[_key - 1] = arguments[_key];
}
functions.forEach(function (type) {
exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
});
}
function enableLogs(debugConfig, id) {
// check that console is available
if (self.console && debugConfig === true || typeof debugConfig === 'object') {
exportLoggerFunctions(debugConfig,
// Remove out from list here to hard-disable a log-level
// 'trace',
'debug', 'log', 'info', 'warn', 'error');
// Some browsers don't allow to use bind on console object anyway
// fallback to default if needed
try {
exportedLogger.log("Debug logs enabled for \"" + id + "\" in hls.js version " + "1.0.1");
} catch (e) {
exportedLogger = fakeLogger;
}
} else {
exportedLogger = fakeLogger;
}
}
var logger = exportedLogger;
var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/;
var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g;
// adapted from https://github.com/kanongil/node-m3u8parse/blob/master/attrlist.js
var AttrList = /*#__PURE__*/function () {
function AttrList(attrs) {
if (typeof attrs === 'string') {
attrs = AttrList.parseAttrList(attrs);
}
_extends(this, attrs);
}
var _proto = AttrList.prototype;
_proto.decimalInteger = function decimalInteger(attrName) {
var intValue = parseInt(this[attrName], 10);
if (intValue > Number.MAX_SAFE_INTEGER) {
return Infinity;
}
return intValue;
};
_proto.hexadecimalInteger = function hexadecimalInteger(attrName) {
if (this[attrName]) {
var stringValue = (this[attrName] || '0x').slice(2);
stringValue = (stringValue.length & 1 ? '0' : '') + stringValue;
var value = new Uint8Array(stringValue.length / 2);
for (var i = 0; i < stringValue.length / 2; i++) {
value[i] = parseInt(stringValue.slice(i * 2, i * 2 + 2), 16);
}
return value;
} else {
return null;
}
};
_proto.hexadecimalIntegerAsNumber = function hexadecimalIntegerAsNumber(attrName) {
var intValue = parseInt(this[attrName], 16);
if (intValue > Number.MAX_SAFE_INTEGER) {
return Infinity;
}
return intValue;
};
_proto.decimalFloatingPoint = function decimalFloatingPoint(attrName) {
return parseFloat(this[attrName]);
};
_proto.optionalFloat = function optionalFloat(attrName, defaultValue) {
var value = this[attrName];
return value ? parseFloat(value) : defaultValue;
};
_proto.enumeratedString = function enumeratedString(attrName) {
return this[attrName];
};
_proto.bool = function bool(attrName) {
return this[attrName] === 'YES';
};
_proto.decimalResolution = function decimalResolution(attrName) {
var res = DECIMAL_RESOLUTION_REGEX.exec(this[attrName]);
if (res === null) {
return undefined;
}
return {
width: parseInt(res[1], 10),
height: parseInt(res[2], 10)
};
};
AttrList.parseAttrList = function parseAttrList(input) {
var match;
var attrs = {};
var quote = '"';
ATTR_LIST_REGEX.lastIndex = 0;
while ((match = ATTR_LIST_REGEX.exec(input)) !== null) {
var value = match[2];
if (value.indexOf(quote) === 0 && value.lastIndexOf(quote) === value.length - 1) {
value = value.slice(1, -1);
}
var name = match[1].trim();
attrs[name] = value;
}
return attrs;
};
_createClass(AttrList, [{
key: "clientAttrs",
get: function get() {
return Object.keys(this).filter(function (attr) {
return attr.substring(0, 2) === 'X-';
});
}
}]);
return AttrList;
}();
// Avoid exporting const enum so that these values can be inlined
function isDateRangeCueAttribute(attrName) {
return attrName !== "ID" && attrName !== "CLASS" && attrName !== "START-DATE" && attrName !== "DURATION" && attrName !== "END-DATE" && attrName !== "END-ON-NEXT";
}
function isSCTE35Attribute(attrName) {
return attrName === "SCTE35-OUT" || attrName === "SCTE35-IN";
}
var DateRange = /*#__PURE__*/function () {
function DateRange(dateRangeAttr, dateRangeWithSameId) {
this.attr = void 0;
this._startDate = void 0;
this._endDate = void 0;
this._badValueForSameId = void 0;
if (dateRangeWithSameId) {
var previousAttr = dateRangeWithSameId.attr;
for (var key in previousAttr) {
if (Object.prototype.hasOwnProperty.call(dateRangeAttr, key) && dateRangeAttr[key] !== previousAttr[key]) {
logger.warn("DATERANGE tag attribute: \"" + key + "\" does not match for tags with ID: \"" + dateRangeAttr.ID + "\"");
this._badValueForSameId = key;
break;
}
}
// Merge DateRange tags with the same ID
dateRangeAttr = _extends(new AttrList({}), previousAttr, dateRangeAttr);
}
this.attr = dateRangeAttr;
this._startDate = new Date(dateRangeAttr["START-DATE"]);
if ("END-DATE" in this.attr) {
var endDate = new Date(this.attr["END-DATE"]);
if (isFiniteNumber(endDate.getTime())) {
this._endDate = endDate;
}
}
}
_createClass(DateRange, [{
key: "id",
get: function get() {
return this.attr.ID;
}
}, {
key: "class",
get: function get() {
return this.attr.CLASS;
}
}, {
key: "startDate",
get: function get() {
return this._startDate;
}
}, {
key: "endDate",
get: function get() {
if (this._endDate) {
return this._endDate;
}
var duration = this.duration;
if (duration !== null) {
return new Date(this._startDate.getTime() + duration * 1000);
}
return null;
}
}, {
key: "duration",
get: function get() {
if ("DURATION" in this.attr) {
var duration = this.attr.decimalFloatingPoint("DURATION");
if (isFiniteNumber(duration)) {
return duration;
}
} else if (this._endDate) {
return (this._endDate.getTime() - this._startDate.getTime()) / 1000;
}
return null;
}
}, {
key: "plannedDuration",
get: function get() {
if ("PLANNED-DURATION" in this.attr) {
return this.attr.decimalFloatingPoint("PLANNED-DURATION");
}
return null;
}
}, {
key: "endOnNext",
get: function get() {
return this.attr.bool("END-ON-NEXT");
}
}, {
key: "isValid",
get: function get() {
return !!this.id && !this._badValueForSameId && isFiniteNumber(this.startDate.getTime()) && (this.duration === null || this.duration >= 0) && (!this.endOnNext || !!this.class);
}
}]);
return DateRange;
}();
var LoadStats = function LoadStats() {
this.aborted = false;
this.loaded = 0;
this.retry = 0;
this.total = 0;
this.chunkCount = 0;
this.bwEstimate = 0;
this.loading = {
start: 0,
first: 0,
end: 0
};
this.parsing = {
start: 0,
end: 0
};
this.buffering = {
start: 0,
first: 0,
end: 0
};
};
var ElementaryStreamTypes = {
AUDIO: "audio",
VIDEO: "video",
AUDIOVIDEO: "audiovideo"
};
var BaseSegment = /*#__PURE__*/function () {
function BaseSegment(baseurl) {
var _this$elementaryStrea;
this._byteRange = null;
this._url = null;
// baseurl is the URL to the playlist
this.baseurl = void 0;
// relurl is the portion of the URL that comes from inside the playlist.
this.relurl = void 0;
// Holds the types of data this fragment supports
this.elementaryStreams = (_this$elementaryStrea = {}, _this$elementaryStrea[ElementaryStreamTypes.AUDIO] = null, _this$elementaryStrea[ElementaryStreamTypes.VIDEO] = null, _this$elementaryStrea[ElementaryStreamTypes.AUDIOVIDEO] = null, _this$elementaryStrea);
this.baseurl = baseurl;
}
// setByteRange converts a EXT-X-BYTERANGE attribute into a two element array
var _proto = BaseSegment.prototype;
_proto.setByteRange = function setByteRange(value, previous) {
var params = value.split('@', 2);
var start;
if (params.length === 1) {
start = (previous == null ? void 0 : previous.byteRangeEndOffset) || 0;
} else {
start = parseInt(params[1]);
}
this._byteRange = [start, parseInt(params[0]) + start];
};
_createClass(BaseSegment, [{
key: "byteRange",
get: function get() {
if (!this._byteRange) {
return [];
}
return this._byteRange;
}
}, {
key: "byteRangeStartOffset",
get: function get() {
return this.byteRange[0];
}
}, {
key: "byteRangeEndOffset",
get: function get() {
return this.byteRange[1];
}
}, {
key: "url",
get: function get() {
if (!this._url && this.baseurl && this.relurl) {
this._url = urlToolkitExports.buildAbsoluteURL(this.baseurl, this.relurl, {
alwaysNormalize: true
});
}
return this._url || '';
},
set: function set(value) {
this._url = value;
}
}]);
return BaseSegment;
}();
/**
* Object representing parsed data from an HLS Segment. Found in {@link hls.js#LevelDetails.fragments}.
*/
var Fragment = /*#__PURE__*/function (_BaseSegment) {
_inheritsLoose(Fragment, _BaseSegment);
function Fragment(type, baseurl) {
var _this;
_this = _BaseSegment.call(this, baseurl) || this;
_this._decryptdata = null;
_this.rawProgramDateTime = null;
_this.programDateTime = null;
_this.tagList = [];
// EXTINF has to be present for a m3u8 to be considered valid
_this.duration = 0;
// sn notates the sequence number for a segment, and if set to a string can be 'initSegment'
_this.sn = 0;
// levelkeys are the EXT-X-KEY tags that apply to this segment for decryption
// core difference from the private field _decryptdata is the lack of the initialized IV
// _decryptdata will set the IV for this segment based on the segment number in the fragment
_this.levelkeys = void 0;
// A string representing the fragment type
_this.type = void 0;
// A reference to the loader. Set while the fragment is loading, and removed afterwards. Used to abort fragment loading
_this.loader = null;
// A reference to the key loader. Set while the key is loading, and removed afterwards. Used to abort key loading
_this.keyLoader = null;
// The level/track index to which the fragment belongs
_this.level = -1;
// The continuity counter of the fragment
_this.cc = 0;
// The starting Presentation Time Stamp (PTS) of the fragment. Set after transmux complete.
_this.startPTS = void 0;
// The ending Presentation Time Stamp (PTS) of the fragment. Set after transmux complete.
_this.endPTS = void 0;
// The starting Decode Time Stamp (DTS) of the fragment. Set after transmux complete.
_this.startDTS = void 0;
// The ending Decode Time Stamp (DTS) of the fragment. Set after transmux complete.
_this.endDTS = void 0;
// The start time of the fragment, as listed in the manifest. Updated after transmux complete.
_this.start = 0;
// Set by `updateFragPTSDTS` in level-helper
_this.deltaPTS = void 0;
// The maximum starting Presentation Time Stamp (audio/video PTS) of the fragment. Set after transmux complete.
_this.maxStartPTS = void 0;
// The minimum ending Presentation Time Stamp (audio/video PTS) of the fragment. Set after transmux complete.
_this.minEndPTS = void 0;
// Load/parse timing information
_this.stats = new LoadStats();
_this.urlId = 0;
_this.data = void 0;
// A flag indicating whether the segment was downloaded in order to test bitrate, and was not buffered
_this.bitrateTest = false;
// #EXTINF segment title
_this.title = null;
// The Media Initialization Section for this segment
_this.initSegment = null;
// Fragment is the last fragment in the media playlist
_this.endList = void 0;
// Fragment is marked by an EXT-X-GAP tag indicating that it does not contain media data and should not be loaded
_this.gap = void 0;
_this.type = type;
return _this;
}
var _proto2 = Fragment.prototype;
_proto2.setKeyFormat = function setKeyFormat(keyFormat) {
if (this.levelkeys) {
var _key = this.levelkeys[keyFormat];
if (_key && !this._decryptdata) {
this._decryptdata = _key.getDecryptData(this.sn);
}
}
};
_proto2.abortRequests = function abortRequests() {
var _this$loader, _this$keyLoader;
(_this$loader = this.loader) == null ? void 0 : _this$loader.abort();
(_this$keyLoader = this.keyLoader) == null ? void 0 : _this$keyLoader.abort();
};
_proto2.setElementaryStreamInfo = function setElementaryStreamInfo(type, startPTS, endPTS, startDTS, endDTS, partial) {
if (partial === void 0) {
partial = false;
}
var elementaryStreams = this.elementaryStreams;
var info = elementaryStreams[type];
if (!info) {
elementaryStreams[type] = {
startPTS: startPTS,
endPTS: endPTS,
startDTS: startDTS,
endDTS: endDTS,
partial: partial
};
return;
}
info.startPTS = Math.min(info.startPTS, startPTS);
info.endPTS = Math.max(info.endPTS, endPTS);
info.startDTS = Math.min(info.startDTS, startDTS);
info.endDTS = Math.max(info.endDTS, endDTS);
};
_proto2.clearElementaryStreamInfo = function clearElementaryStreamInfo() {
var elementaryStreams = this.elementaryStreams;
elementaryStreams[ElementaryStreamTypes.AUDIO] = null;
elementaryStreams[ElementaryStreamTypes.VIDEO] = null;
elementaryStreams[ElementaryStreamTypes.AUDIOVIDEO] = null;
};
_createClass(Fragment, [{
key: "decryptdata",
get: function get() {
var levelkeys = this.levelkeys;
if (!levelkeys && !this._decryptdata) {
return null;
}
if (!this._decryptdata && this.levelkeys && !this.levelkeys.NONE) {
var _key2 = this.levelkeys.identity;
if (_key2) {
this._decryptdata = _key2.getDecryptData(this.sn);
} else {
var keyFormats = Object.keys(this.levelkeys);
if (keyFormats.length === 1) {
return this._decryptdata = this.levelkeys[keyFormats[0]].getDecryptData(this.sn);
}
}
}
return this._decryptdata;
}
}, {
key: "end",
get: function get() {
return this.start + this.duration;
}
}, {
key: "endProgramDateTime",
get: function get() {
if (this.programDateTime === null) {
return null;
}
if (!isFiniteNumber(this.programDateTime)) {
return null;
}
var duration = !isFiniteNumber(this.duration) ? 0 : this.duration;
return this.programDateTime + duration * 1000;
}
}, {
key: "encrypted",
get: function get() {
var _this$_decryptdata;
// At the m3u8-parser level we need to add support for manifest signalled keyformats
// when we want the fragment to start reporting that it is encrypted.
// Currently, keyFormat will only be set for identity keys
if ((_this$_decryptdata = this._decryptdata) != null && _this$_decryptdata.encrypted) {
return true;
} else if (this.levelkeys) {
var keyFormats = Object.keys(this.levelkeys);
var len = keyFormats.length;
if (len > 1 || len === 1 && this.levelkeys[keyFormats[0]].encrypted) {
return true;
}
}
return false;
}
}]);
return Fragment;
}(BaseSegment);
/**
* Object representing parsed data from an HLS Partial Segment. Found in {@link hls.js#LevelDetails.partList}.
*/
var Part = /*#__PURE__*/function (_BaseSegment2) {
_inheritsLoose(Part, _BaseSegment2);
function Part(partAttrs, frag, baseurl, index, previous) {
var _this2;
_this2 = _BaseSegment2.call(this, baseurl) || this;
_this2.fragOffset = 0;
_this2.duration = 0;
_this2.gap = false;
_this2.independent = false;
_this2.relurl = void 0;
_this2.fragment = void 0;
_this2.index = void 0;
_this2.stats = new LoadStats();
_this2.duration = partAttrs.decimalFloatingPoint('DURATION');
_this2.gap = partAttrs.bool('GAP');
_this2.independent = partAttrs.bool('INDEPENDENT');
_this2.relurl = partAttrs.enumeratedString('URI');
_this2.fragment = frag;
_this2.index = index;
var byteRange = partAttrs.enumeratedString('BYTERANGE');
if (byteRange) {
_this2.setByteRange(byteRange, previous);
}
if (previous) {
_this2.fragOffset = previous.fragOffset + previous.duration;
}
return _this2;
}
_createClass(Part, [{
key: "start",
get: function get() {
return this.fragment.start + this.fragOffset;
}
}, {
key: "end",
get: function get() {
return this.start + this.duration;
}
}, {
key: "loaded",
get: function get() {
var elementaryStreams = this.elementaryStreams;
return !!(elementaryStreams.audio || elementaryStreams.video || elementaryStreams.audiovideo);
}
}]);
return Part;
}(BaseSegment);
var DEFAULT_TARGET_DURATION = 10;
/**
* Object representing parsed data from an HLS Media Playlist. Found in {@link hls.js#Level.details}.
*/
var LevelDetails = /*#__PURE__*/function () {
function LevelDetails(baseUrl) {
this.PTSKnown = false;
this.alignedSliding = false;
this.averagetargetduration = void 0;
this.endCC = 0;
this.endSN = 0;
this.fragments = void 0;
this.fragmentHint = void 0;
this.partList = null;
this.dateRanges = void 0;
this.live = true;
this.ageHeader = 0;
this.advancedDateTime = void 0;
this.updated = true;
this.advanced = true;
this.availabilityDelay = void 0;
// Manifest reload synchronization
this.misses = 0;
this.startCC = 0;
this.startSN = 0;
this.startTimeOffset = null;
this.targetduration = 0;
this.totalduration = 0;
this.type = null;
this.url = void 0;
this.m3u8 = '';
this.version = null;
this.canBlockReload = false;
this.canSkipUntil = 0;
this.canSkipDateRanges = false;
this.skippedSegments = 0;
this.recentlyRemovedDateranges = void 0;
this.partHoldBack = 0;
this.holdBack = 0;
this.partTarget = 0;
this.preloadHint = void 0;
this.renditionReports = void 0;
this.tuneInGoal = 0;
this.deltaUpdateFailed = void 0;
this.driftStartTime = 0;
this.driftEndTime = 0;
this.driftStart = 0;
this.driftEnd = 0;
this.encryptedFragments = void 0;
this.playlistParsingError = null;
this.variableList = null;
this.hasVariableRefs = false;
this.fragments = [];
this.encryptedFragments = [];
this.dateRanges = {};
this.url = baseUrl;
}
var _proto = LevelDetails.prototype;
_proto.reloaded = function reloaded(previous) {
if (!previous) {
this.advanced = true;
this.updated = true;
return;
}
var partSnDiff = this.lastPartSn - previous.lastPartSn;
var partIndexDiff = this.lastPartIndex - previous.lastPartIndex;
this.updated = this.endSN !== previous.endSN || !!partIndexDiff || !!partSnDiff || !this.live;
this.advanced = this.endSN > previous.endSN || partSnDiff > 0 || partSnDiff === 0 && partIndexDiff > 0;
if (this.updated || this.advanced) {
this.misses = Math.floor(previous.misses * 0.6);
} else {
this.misses = previous.misses + 1;
}
this.availabilityDelay = previous.availabilityDelay;
};
_createClass(LevelDetails, [{
key: "hasProgramDateTime",
get: function get() {
if (this.fragments.length) {
return isFiniteNumber(this.fragments[this.fragments.length - 1].programDateTime);
}
return false;
}
}, {
key: "levelTargetDuration",
get: function get() {
return this.averagetargetduration || this.targetduration || DEFAULT_TARGET_DURATION;
}
}, {
key: "drift",
get: function get() {
var runTime = this.driftEndTime - this.driftStartTime;
if (runTime > 0) {
var runDuration = this.driftEnd - this.driftStart;
return runDuration * 1000 / runTime;
}
return 1;
}
}, {
key: "edge",
get: function get() {
return this.partEnd || this.fragmentEnd;
}
}, {
key: "partEnd",
get: function get() {
var _this$partList;
if ((_this$partList = this.partList) != null && _this$partList.length) {
return this.partList[this.partList.length - 1].end;
}
return this.fragmentEnd;
}
}, {
key: "fragmentEnd",
get: function get() {
var _this$fragments;
if ((_this$fragments = this.fragments) != null && _this$fragments.length) {
return this.fragments[this.fragments.length - 1].end;
}
return 0;
}
}, {
key: "age",
get: function get() {
if (this.advancedDateTime) {
return Math.max(Date.now() - this.advancedDateTime, 0) / 1000;
}
return 0;
}
}, {
key: "lastPartIndex",
get: function get() {
var _this$partList2;
if ((_this$partList2 = this.partList) != null && _this$partList2.length) {
return this.partList[this.partList.length - 1].index;
}
return -1;
}
}, {
key: "lastPartSn",
get: function get() {
var _this$partList3;
if ((_this$partList3 = this.partList) != null && _this$partList3.length) {
return this.partList[this.partList.length - 1].fragment.sn;
}
return this.endSN;
}
}]);
return LevelDetails;
}();
// This file is inserted as a shim for modules which we do not want to include into the distro.
// This replacement is done in the "alias" plugin of the rollup config.
var empty = undefined;
var Cues = /*@__PURE__*/getDefaultExportFromCjs(empty);
function sliceUint8(array, start, end) {
// @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
// It always exists in the TypeScript definition so fails, but it fails at runtime on IE11.
return Uint8Array.prototype.slice ? array.slice(start, end) : new Uint8Array(Array.prototype.slice.call(array, start, end));
}
// breaking up those two types in order to clarify what is happening in the decoding path.
/**
* Returns true if an ID3 header can be found at offset in data
* @param data - The data to search
* @param offset - The offset at which to start searching
*/
var isHeader$2 = function isHeader(data, offset) {
/*
* http://id3.org/id3v2.3.0
* [0] = 'I'
* [1] = 'D'
* [2] = '3'
* [3,4] = {Version}
* [5] = {Flags}
* [6-9] = {ID3 Size}
*
* An ID3v2 tag can be detected with the following pattern:
* $49 44 33 yy yy xx zz zz zz zz
* Where yy is less than $FF, xx is the 'flags' byte and zz is less than $80
*/
if (offset + 10 <= data.length) {
// look for 'ID3' identifier
if (data[offset] === 0x49 && data[offset + 1] === 0x44 && data[offset + 2] === 0x33) {
// check version is within range
if (data[offset + 3] < 0xff && data[offset + 4] < 0xff) {
// check size is within range
if (data[offset + 6] < 0x80 && data[offset + 7] < 0x80 && data[offset + 8] < 0x80 && data[offset + 9] < 0x80) {
return true;
}
}
}
}
return false;
};
/**
* Returns true if an ID3 footer can be found at offset in data
* @param data - The data to search
* @param offset - The offset at which to start searching
*/
var isFooter = function isFooter(data, offset) {
/*
* The footer is a copy of the header, but with a different identifier
*/
if (offset + 10 <= data.length) {
// look for '3DI' identifier
if (data[offset] === 0x33 && data[offset + 1] === 0x44 && data[offset + 2] === 0x49) {
// check version is within range
if (data[offset + 3] < 0xff && data[offset + 4] < 0xff) {
// check size is within range
if (data[offset + 6] < 0x80 && data[offset + 7] < 0x80 && data[offset + 8] < 0x80 && data[offset + 9] < 0x80) {
return true;
}
}
}
}
return false;
};
/**
* Returns any adjacent ID3 tags found in data starting at offset, as one block of data
* @param data - The data to search in
* @param offset - The offset at which to start searching
* @returns the block of data containing any ID3 tags found
* or *undefined* if no header is found at the starting offset
*/
var getID3Data = function getID3Data(data, offset) {
var front = offset;
var length = 0;
while (isHeader$2(data, offset)) {
// ID3 header is 10 bytes
length += 10;
var size = readSize(data, offset + 6);
length += size;
if (isFooter(data, offset + 10)) {
// ID3 footer is 10 bytes
length += 10;
}
offset += length;
}
if (length > 0) {
return data.subarray(front, front + length);
}
return undefined;
};
var readSize = function readSize(data, offset) {
var size = 0;
size = (data[offset] & 0x7f) << 21;
size |= (data[offset + 1] & 0x7f) << 14;
size |= (data[offset + 2] & 0x7f) << 7;
size |= data[offset + 3] & 0x7f;
return size;
};
var canParse$2 = function canParse(data, offset) {
return isHeader$2(data, offset) && readSize(data, offset + 6) + 10 <= data.length - offset;
};
/**
* Searches for the Elementary Stream timestamp found in the ID3 data chunk
* @param data - Block of data containing one or more ID3 tags
*/
var getTimeStamp = function getTimeStamp(data) {
var frames = getID3Frames(data);
for (var i = 0; i < frames.length; i++) {
var frame = frames[i];
if (isTimeStampFrame(frame)) {
return readTimeStamp(frame);
}
}
return undefined;
};
/**
* Returns true if the ID3 frame is an Elementary Stream timestamp frame
*/
var isTimeStampFrame = function isTimeStampFrame(frame) {
return frame && frame.key === 'PRIV' && frame.info === 'com.apple.streaming.transportStreamTimestamp';
};
var getFrameData = function getFrameData(data) {
/*
Frame ID $xx xx xx xx (four characters)
Size $xx xx xx xx
Flags $xx xx
*/
var type = String.fromCharCode(data[0], data[1], data[2], data[3]);
var size = readSize(data, 4);
// skip frame id, size, and flags
var offset = 10;
return {
type: type,
size: size,
data: data.subarray(offset, offset + size)
};
};
/**
* Returns an array of ID3 frames found in all the ID3 tags in the id3Data
* @param id3Data - The ID3 data containing one or more ID3 tags
*/
var getID3Frames = function getID3Frames(id3Data) {
var offset = 0;
var frames = [];
while (isHeader$2(id3Data, offset)) {
var size = readSize(id3Data, offset + 6);
// skip past ID3 header
offset += 10;
var end = offset + size;
// loop through frames in the ID3 tag
while (offset + 8 < end) {
var frameData = getFrameData(id3Data.subarray(offset));
var frame = decodeFrame(frameData);
if (frame) {
frames.push(frame);
}
// skip frame header and frame data
offset += frameData.size + 10;
}
if (isFooter(id3Data, offset)) {
offset += 10;
}
}
return frames;
};
var decodeFrame = function decodeFrame(frame) {
if (frame.type === 'PRIV') {
return decodePrivFrame(frame);