Skip to content

Instantly share code, notes, and snippets.

@Xe

Xe/gruvbox.css Secret

Last active January 14, 2020 02:13
Show Gist options
  • Save Xe/fadf1100a8152a3f328fc07522cf8176 to your computer and use it in GitHub Desktop.
Save Xe/fadf1100a8152a3f328fc07522cf8176 to your computer and use it in GitHub Desktop.
stream.html
main {
font-family: monospace, monospace;
max-width: 600px;
margin: auto;
}
@media only screen and (max-device-width: 736px) {
main {
padding: 0rem;
}
video {
max-width: 100%;
max-height: 240px;
}
}
::selection {
background: #d3869b;
}
body {
background: #282828;
color: #ebdbb2;
}
pre {
background-color: #3c3836;
padding: 1em;
border: 0;
}
a,
a:active,
a:visited {
color: #b16286;
background-color: #1d2021;
}
h1,
h2,
h3,
h4,
h5 {
margin-bottom: .1rem;
}
blockquote {
border-left: 1px solid #bdae93;
margin: 0.5em 10px;
padding: 0.5em 10px;
}
footer {
align: center;
}
@media (prefers-color-scheme: light) {
body {
background: #fbf1c7;
color: #3c3836;
}
pre {
background-color: #ebdbb2;
padding: 1em;
border: 0;
}
a,
a:active,
a:visited {
color: #b16286;
background-color: #f9f5d7;
}
h1,
h2,
h3,
h4,
h5 {
margin-bottom: .1rem;
}
blockquote {
border-left: 1px solid #655c54;
margin: 0.5em 10px;
padding: 0.5em 10px;
}
}
<html>
<head>
<title>Streams from Within</title>
<link rel="stylesheet" href="/gruvbox.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<main>
<script src="stream_hls.js"></script>
<h1>Streams from Within</h1>
<p><a href="https://discord.gg/xqz2Eb8">For chat click here</a></p>
</main>
<center>
<video height="600" id="video" controls></video>
</center>
<script>
var video = document.getElementById('video');
if (screen.width <= 736) {
video.src = "/live/cadey.m3u8";
}
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource('/hls/cadey.m3u8');
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function() {
video.play();
console.log("hls");
});
}
// hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled.
// When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element throught the `src` property.
// This is using the built-in support of the plain video element, without using hls.js.
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
console.log("live");
video.src = '/live/cadey.m3u8';
video.addEventListener('canplay', function() {
video.play();
});
}
</script>
</body>
</html>
typeof window !== "undefined" &&
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Hls"] = factory();
else
root["Hls"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ // create a fake namespace object
/******/ // mode & 1: value is a module id, require it
/******/ // mode & 2: merge all properties of value into the ns
/******/ // mode & 4: return value when already ns object
/******/ // mode & 8|1: behave like require
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/dist/";
/******/
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = "./src/hls.ts");
/******/ })
/************************************************************************/
/******/ ({
/***/ "./node_modules/eventemitter3/index.js":
/*!*********************************************!*\
!*** ./node_modules/eventemitter3/index.js ***!
\*********************************************/
/*! no static exports found */
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var has = Object.prototype.hasOwnProperty
, prefix = '~';
/**
* Constructor to create a storage for our `EE` objects.
* An `Events` instance is a plain object whose properties are event names.
*
* @constructor
* @private
*/
function Events() {}
//
// We try to not inherit from `Object.prototype`. In some engines creating an
// instance in this way is faster than calling `Object.create(null)` directly.
// If `Object.create(null)` is not supported we prefix the event names with a
// character to make sure that the built-in object properties are not
// overridden or used as an attack vector.
//
if (Object.create) {
Events.prototype = Object.create(null);
//
// This hack is needed because the `__proto__` property is still inherited in
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
//
if (!new Events().__proto__) prefix = false;
}
/**
* Representation of a single event listener.
*
* @param {Function} fn The listener function.
* @param {*} context The context to invoke the listener with.
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
* @constructor
* @private
*/
function EE(fn, context, once) {
this.fn = fn;
this.context = context;
this.once = once || false;
}
/**
* Add a listener for a given event.
*
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} context The context to invoke the listener with.
* @param {Boolean} once Specify if the listener is a one-time listener.
* @returns {EventEmitter}
* @private
*/
function addListener(emitter, event, fn, context, once) {
if (typeof fn !== 'function') {
throw new TypeError('The listener must be a function');
}
var listener = new EE(fn, context || emitter, once)
, evt = prefix ? prefix + event : event;
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
else emitter._events[evt] = [emitter._events[evt], listener];
return emitter;
}
/**
* Clear event by name.
*
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
* @param {(String|Symbol)} evt The Event name.
* @private
*/
function clearEvent(emitter, evt) {
if (--emitter._eventsCount === 0) emitter._events = new Events();
else delete emitter._events[evt];
}
/**
* Minimal `EventEmitter` interface that is molded against the Node.js
* `EventEmitter` interface.
*
* @constructor
* @public
*/
function EventEmitter() {
this._events = new Events();
this._eventsCount = 0;
}
/**
* Return an array listing the events for which the emitter has registered
* listeners.
*
* @returns {Array}
* @public
*/
EventEmitter.prototype.eventNames = function eventNames() {
var names = []
, events
, name;
if (this._eventsCount === 0) return names;
for (name in (events = this._events)) {
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
}
if (Object.getOwnPropertySymbols) {
return names.concat(Object.getOwnPropertySymbols(events));
}
return names;
};
/**
* Return the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Array} The registered listeners.
* @public
*/
EventEmitter.prototype.listeners = function listeners(event) {
var evt = prefix ? prefix + event : event
, handlers = this._events[evt];
if (!handlers) return [];
if (handlers.fn) return [handlers.fn];
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
ee[i] = handlers[i].fn;
}
return ee;
};
/**
* Return the number of listeners listening to a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Number} The number of listeners.
* @public
*/
EventEmitter.prototype.listenerCount = function listenerCount(event) {
var evt = prefix ? prefix + event : event
, listeners = this._events[evt];
if (!listeners) return 0;
if (listeners.fn) return 1;
return listeners.length;
};
/**
* Calls each of the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Boolean} `true` if the event had listeners, else `false`.
* @public
*/
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return false;
var listeners = this._events[evt]
, len = arguments.length
, args
, i;
if (listeners.fn) {
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
switch (len) {
case 1: return listeners.fn.call(listeners.context), true;
case 2: return listeners.fn.call(listeners.context, a1), true;
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
}
for (i = 1, args = new Array(len -1); i < len; i++) {
args[i - 1] = arguments[i];
}
listeners.fn.apply(listeners.context, args);
} else {
var length = listeners.length
, j;
for (i = 0; i < length; i++) {
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
switch (len) {
case 1: listeners[i].fn.call(listeners[i].context); break;
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
default:
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
args[j - 1] = arguments[j];
}
listeners[i].fn.apply(listeners[i].context, args);
}
}
}
return true;
};
/**
* Add a listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.on = function on(event, fn, context) {
return addListener(this, event, fn, context, false);
};
/**
* Add a one-time listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.once = function once(event, fn, context) {
return addListener(this, event, fn, context, true);
};
/**
* Remove the listeners of a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn Only remove the listeners that match this function.
* @param {*} context Only remove the listeners that have this context.
* @param {Boolean} once Only remove one-time listeners.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return this;
if (!fn) {
clearEvent(this, evt);
return this;
}
var listeners = this._events[evt];
if (listeners.fn) {
if (
listeners.fn === fn &&
(!once || listeners.once) &&
(!context || listeners.context === context)
) {
clearEvent(this, evt);
}
} else {
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
if (
listeners[i].fn !== fn ||
(once && !listeners[i].once) ||
(context && listeners[i].context !== context)
) {
events.push(listeners[i]);
}
}
//
// Reset the array, or remove it completely if we have no more listeners.
//
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
else clearEvent(this, evt);
}
return this;
};
/**
* Remove all listeners, or those of the specified event.
*
* @param {(String|Symbol)} [event] The event name.
* @returns {EventEmitter} `this`.
* @public
*/
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
var evt;
if (event) {
evt = prefix ? prefix + event : event;
if (this._events[evt]) clearEvent(this, evt);
} else {
this._events = new Events();
this._eventsCount = 0;
}
return this;
};
//
// Alias methods names because people roll like that.
//
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
//
// Expose the prefix.
//
EventEmitter.prefixed = prefix;
//
// Allow `EventEmitter` to be imported as module namespace.
//
EventEmitter.EventEmitter = EventEmitter;
//
// Expose the module.
//
if (true) {
module.exports = EventEmitter;
}
/***/ }),
/***/ "./node_modules/url-toolkit/src/url-toolkit.js":
/*!*****************************************************!*\
!*** ./node_modules/url-toolkit/src/url-toolkit.js ***!
\*****************************************************/
/*! no static exports found */
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
/***/ (function(module, exports, __webpack_require__) {
// see https://tools.ietf.org/html/rfc1808
/* jshint ignore:start */
(function(root) {
/* jshint ignore:end */
var URL_REGEX = /^((?:[a-zA-Z0-9+\-.]+:)?)(\/\/[^\/?#]*)?((?:[^\/\?#]*\/)*.*?)??(;.*?)?(\?.*?)?(#.*?)?$/;
var FIRST_SEGMENT_REGEX = /^([^\/?#]*)(.*)$/;
var SLASH_DOT_REGEX = /(?:\/|^)\.(?=\/)/g;
var SLASH_DOT_DOT_REGEX = /(?:\/|^)\.\.\/(?!\.\.\/).*?(?=\/)/g;
var URLToolkit = { // jshint ignore:line
// 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) {} // jshint ignore:line
return path.split('').reverse().join('');
},
buildURLFromParts: function(parts) {
return parts.scheme + parts.netLoc + parts.path + parts.params + parts.query + parts.fragment;
}
};
/* jshint ignore:start */
if(true)
module.exports = URLToolkit;
else {}
})(this);
/* jshint ignore:end */
/***/ }),
/***/ "./node_modules/webworkify-webpack/index.js":
/*!**************************************************!*\
!*** ./node_modules/webworkify-webpack/index.js ***!
\**************************************************/
/*! no static exports found */
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
/***/ (function(module, exports, __webpack_require__) {
function webpackBootstrapFunc (modules) {
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
/******/ // on error function for async loading
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
var f = __webpack_require__(__webpack_require__.s = ENTRY_MODULE)
return f.default || f // try to call default if defined to also support babel esmodule exports
}
var moduleNameReqExp = '[\\.|\\-|\\+|\\w|\/|@]+'
var dependencyRegExp = '\\(\\s*(\/\\*.*?\\*\/)?\\s*.*?(' + moduleNameReqExp + ').*?\\)' // additional chars when output.pathinfo is true
// http://stackoverflow.com/a/2593661/130442
function quoteRegExp (str) {
return (str + '').replace(/[.?*+^$[\]\\(){}|-]/g, '\\$&')
}
function isNumeric(n) {
return !isNaN(1 * n); // 1 * n converts integers, integers as string ("123"), 1e3 and "1e3" to integers and strings to NaN
}
function getModuleDependencies (sources, module, queueName) {
var retval = {}
retval[queueName] = []
var fnString = module.toString()
var wrapperSignature = fnString.match(/^function\s?\w*\(\w+,\s*\w+,\s*(\w+)\)/)
if (!wrapperSignature) return retval
var webpackRequireName = wrapperSignature[1]
// main bundle deps
var re = new RegExp('(\\\\n|\\W)' + quoteRegExp(webpackRequireName) + dependencyRegExp, 'g')
var match
while ((match = re.exec(fnString))) {
if (match[3] === 'dll-reference') continue
retval[queueName].push(match[3])
}
// dll deps
re = new RegExp('\\(' + quoteRegExp(webpackRequireName) + '\\("(dll-reference\\s(' + moduleNameReqExp + '))"\\)\\)' + dependencyRegExp, 'g')
while ((match = re.exec(fnString))) {
if (!sources[match[2]]) {
retval[queueName].push(match[1])
sources[match[2]] = __webpack_require__(match[1]).m
}
retval[match[2]] = retval[match[2]] || []
retval[match[2]].push(match[4])
}
// convert 1e3 back to 1000 - this can be important after uglify-js converted 1000 to 1e3
var keys = Object.keys(retval);
for (var i = 0; i < keys.length; i++) {
for (var j = 0; j < retval[keys[i]].length; j++) {
if (isNumeric(retval[keys[i]][j])) {
retval[keys[i]][j] = 1 * retval[keys[i]][j];
}
}
}
return retval
}
function hasValuesInQueues (queues) {
var keys = Object.keys(queues)
return keys.reduce(function (hasValues, key) {
return hasValues || queues[key].length > 0
}, false)
}
function getRequiredModules (sources, moduleId) {
var modulesQueue = {
main: [moduleId]
}
var requiredModules = {
main: []
}
var seenModules = {
main: {}
}
while (hasValuesInQueues(modulesQueue)) {
var queues = Object.keys(modulesQueue)
for (var i = 0; i < queues.length; i++) {
var queueName = queues[i]
var queue = modulesQueue[queueName]
var moduleToCheck = queue.pop()
seenModules[queueName] = seenModules[queueName] || {}
if (seenModules[queueName][moduleToCheck] || !sources[queueName][moduleToCheck]) continue
seenModules[queueName][moduleToCheck] = true
requiredModules[queueName] = requiredModules[queueName] || []
requiredModules[queueName].push(moduleToCheck)
var newModules = getModuleDependencies(sources, sources[queueName][moduleToCheck], queueName)
var newModulesKeys = Object.keys(newModules)
for (var j = 0; j < newModulesKeys.length; j++) {
modulesQueue[newModulesKeys[j]] = modulesQueue[newModulesKeys[j]] || []
modulesQueue[newModulesKeys[j]] = modulesQueue[newModulesKeys[j]].concat(newModules[newModulesKeys[j]])
}
}
}
return requiredModules
}
module.exports = function (moduleId, options) {
options = options || {}
var sources = {
main: __webpack_require__.m
}
var requiredModules = options.all ? { main: Object.keys(sources.main) } : getRequiredModules(sources, moduleId)
var src = ''
Object.keys(requiredModules).filter(function (m) { return m !== 'main' }).forEach(function (module) {
var entryModule = 0
while (requiredModules[module][entryModule]) {
entryModule++
}
requiredModules[module].push(entryModule)
sources[module][entryModule] = '(function(module, exports, __webpack_require__) { module.exports = __webpack_require__; })'
src = src + 'var ' + module + ' = (' + webpackBootstrapFunc.toString().replace('ENTRY_MODULE', JSON.stringify(entryModule)) + ')({' + requiredModules[module].map(function (id) { return '' + JSON.stringify(id) + ': ' + sources[module][id].toString() }).join(',') + '});\n'
})
src = src + 'new ((' + webpackBootstrapFunc.toString().replace('ENTRY_MODULE', JSON.stringify(moduleId)) + ')({' + requiredModules.main.map(function (id) { return '' + JSON.stringify(id) + ': ' + sources.main[id].toString() }).join(',') + '}))(self);'
var blob = new window.Blob([src], { type: 'text/javascript' })
if (options.bare) { return blob }
var URL = window.URL || window.webkitURL || window.mozURL || window.msURL
var workerUrl = URL.createObjectURL(blob)
var worker = new window.Worker(workerUrl)
worker.objectURL = workerUrl
return worker
}
/***/ }),
/***/ "./src/crypt/decrypter.js":
/*!********************************************!*\
!*** ./src/crypt/decrypter.js + 3 modules ***!
\********************************************/
/*! exports provided: default */
/*! ModuleConcatenation bailout: Cannot concat with ./src/errors.ts because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/events.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/utils/get-self-scope.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/utils/logger.js because of ./src/hls.ts */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// CONCATENATED MODULE: ./src/crypt/aes-crypto.js
var AESCrypto =
/*#__PURE__*/
function () {
function AESCrypto(subtle, iv) {
this.subtle = subtle;
this.aesIV = iv;
}
var _proto = AESCrypto.prototype;
_proto.decrypt = function decrypt(data, key) {
return this.subtle.decrypt({
name: 'AES-CBC',
iv: this.aesIV
}, key, data);
};
return AESCrypto;
}();
// CONCATENATED MODULE: ./src/crypt/fast-aes-key.js
var FastAESKey =
/*#__PURE__*/
function () {
function FastAESKey(subtle, key) {
this.subtle = subtle;
this.key = key;
}
var _proto = FastAESKey.prototype;
_proto.expandKey = function expandKey() {
return this.subtle.importKey('raw', this.key, {
name: 'AES-CBC'
}, false, ['encrypt', 'decrypt']);
};
return FastAESKey;
}();
/* harmony default export */ var fast_aes_key = (FastAESKey);
// CONCATENATED MODULE: ./src/crypt/aes-decryptor.js
// PKCS7
function removePadding(buffer) {
var outputBytes = buffer.byteLength;
var paddingBytes = outputBytes && new DataView(buffer).getUint8(outputBytes - 1);
if (paddingBytes) {
return buffer.slice(0, outputBytes - paddingBytes);
} else {
return buffer;
}
}
var AESDecryptor =
/*#__PURE__*/
function () {
function AESDecryptor() {
// Static after running initTable
this.rcon = [0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
this.subMix = [new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256)];
this.invSubMix = [new Uint32Array(256), new Uint32Array(256), new Uint32Array(256), new Uint32Array(256)];
this.sBox = new Uint32Array(256);
this.invSBox = new Uint32Array(256); // Changes during runtime
this.key = new Uint32Array(0);
this.initTable();
} // Using view.getUint32() also swaps the byte order.
var _proto = AESDecryptor.prototype;
_proto.uint8ArrayToUint32Array_ = function uint8ArrayToUint32Array_(arrayBuffer) {
var view = new DataView(arrayBuffer);
var newArray = new Uint32Array(4);
for (var i = 0; i < 4; i++) {
newArray[i] = view.getUint32(i * 4);
}
return newArray;
};
_proto.initTable = function initTable() {
var sBox = this.sBox;
var invSBox = this.invSBox;
var subMix = this.subMix;
var subMix0 = subMix[0];
var subMix1 = subMix[1];
var subMix2 = subMix[2];
var subMix3 = subMix[3];
var invSubMix = this.invSubMix;
var invSubMix0 = invSubMix[0];
var invSubMix1 = invSubMix[1];
var invSubMix2 = invSubMix[2];
var invSubMix3 = invSubMix[3];
var d = new Uint32Array(256);
var x = 0;
var xi = 0;
var i = 0;
for (i = 0; i < 256; i++) {
if (i < 128) {
d[i] = i << 1;
} else {
d[i] = i << 1 ^ 0x11b;
}
}
for (i = 0; i < 256; i++) {
var sx = xi ^ xi << 1 ^ xi << 2 ^ xi << 3 ^ xi << 4;
sx = sx >>> 8 ^ sx & 0xff ^ 0x63;
sBox[x] = sx;
invSBox[sx] = x; // Compute multiplication
var x2 = d[x];
var x4 = d[x2];
var x8 = d[x4]; // Compute sub/invSub bytes, mix columns tables
var t = d[sx] * 0x101 ^ sx * 0x1010100;
subMix0[x] = t << 24 | t >>> 8;
subMix1[x] = t << 16 | t >>> 16;
subMix2[x] = t << 8 | t >>> 24;
subMix3[x] = t; // Compute inv sub bytes, inv mix columns tables
t = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
invSubMix0[sx] = t << 24 | t >>> 8;
invSubMix1[sx] = t << 16 | t >>> 16;
invSubMix2[sx] = t << 8 | t >>> 24;
invSubMix3[sx] = t; // Compute next counter
if (!x) {
x = xi = 1;
} else {
x = x2 ^ d[d[d[x8 ^ x2]]];
xi ^= d[d[xi]];
}
}
};
_proto.expandKey = function expandKey(keyBuffer) {
// convert keyBuffer to Uint32Array
var key = this.uint8ArrayToUint32Array_(keyBuffer);
var sameKey = true;
var offset = 0;
while (offset < key.length && sameKey) {
sameKey = key[offset] === this.key[offset];
offset++;
}
if (sameKey) {
return;
}
this.key = key;
var keySize = this.keySize = key.length;
if (keySize !== 4 && keySize !== 6 && keySize !== 8) {
throw new Error('Invalid aes key size=' + keySize);
}
var ksRows = this.ksRows = (keySize + 6 + 1) * 4;
var ksRow;
var invKsRow;
var keySchedule = this.keySchedule = new Uint32Array(ksRows);
var invKeySchedule = this.invKeySchedule = new Uint32Array(ksRows);
var sbox = this.sBox;
var rcon = this.rcon;
var invSubMix = this.invSubMix;
var invSubMix0 = invSubMix[0];
var invSubMix1 = invSubMix[1];
var invSubMix2 = invSubMix[2];
var invSubMix3 = invSubMix[3];
var prev;
var t;
for (ksRow = 0; ksRow < ksRows; ksRow++) {
if (ksRow < keySize) {
prev = keySchedule[ksRow] = key[ksRow];
continue;
}
t = prev;
if (ksRow % keySize === 0) {
// Rot word
t = t << 8 | t >>> 24; // Sub word
t = sbox[t >>> 24] << 24 | sbox[t >>> 16 & 0xff] << 16 | sbox[t >>> 8 & 0xff] << 8 | sbox[t & 0xff]; // Mix Rcon
t ^= rcon[ksRow / keySize | 0] << 24;
} else if (keySize > 6 && ksRow % keySize === 4) {
// Sub word
t = sbox[t >>> 24] << 24 | sbox[t >>> 16 & 0xff] << 16 | sbox[t >>> 8 & 0xff] << 8 | sbox[t & 0xff];
}
keySchedule[ksRow] = prev = (keySchedule[ksRow - keySize] ^ t) >>> 0;
}
for (invKsRow = 0; invKsRow < ksRows; invKsRow++) {
ksRow = ksRows - invKsRow;
if (invKsRow & 3) {
t = keySchedule[ksRow];
} else {
t = keySchedule[ksRow - 4];
}
if (invKsRow < 4 || ksRow <= 4) {
invKeySchedule[invKsRow] = t;
} else {
invKeySchedule[invKsRow] = invSubMix0[sbox[t >>> 24]] ^ invSubMix1[sbox[t >>> 16 & 0xff]] ^ invSubMix2[sbox[t >>> 8 & 0xff]] ^ invSubMix3[sbox[t & 0xff]];
}
invKeySchedule[invKsRow] = invKeySchedule[invKsRow] >>> 0;
}
} // Adding this as a method greatly improves performance.
;
_proto.networkToHostOrderSwap = function networkToHostOrderSwap(word) {
return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;
};
_proto.decrypt = function decrypt(inputArrayBuffer, offset, aesIV, removePKCS7Padding) {
var nRounds = this.keySize + 6;
var invKeySchedule = this.invKeySchedule;
var invSBOX = this.invSBox;
var invSubMix = this.invSubMix;
var invSubMix0 = invSubMix[0];
var invSubMix1 = invSubMix[1];
var invSubMix2 = invSubMix[2];
var invSubMix3 = invSubMix[3];
var initVector = this.uint8ArrayToUint32Array_(aesIV);
var initVector0 = initVector[0];
var initVector1 = initVector[1];
var initVector2 = initVector[2];
var initVector3 = initVector[3];
var inputInt32 = new Int32Array(inputArrayBuffer);
var outputInt32 = new Int32Array(inputInt32.length);
var t0, t1, t2, t3;
var s0, s1, s2, s3;
var inputWords0, inputWords1, inputWords2, inputWords3;
var ksRow, i;
var swapWord = this.networkToHostOrderSwap;
while (offset < inputInt32.length) {
inputWords0 = swapWord(inputInt32[offset]);
inputWords1 = swapWord(inputInt32[offset + 1]);
inputWords2 = swapWord(inputInt32[offset + 2]);
inputWords3 = swapWord(inputInt32[offset + 3]);
s0 = inputWords0 ^ invKeySchedule[0];
s1 = inputWords3 ^ invKeySchedule[1];
s2 = inputWords2 ^ invKeySchedule[2];
s3 = inputWords1 ^ invKeySchedule[3];
ksRow = 4; // Iterate through the rounds of decryption
for (i = 1; i < nRounds; i++) {
t0 = invSubMix0[s0 >>> 24] ^ invSubMix1[s1 >> 16 & 0xff] ^ invSubMix2[s2 >> 8 & 0xff] ^ invSubMix3[s3 & 0xff] ^ invKeySchedule[ksRow];
t1 = invSubMix0[s1 >>> 24] ^ invSubMix1[s2 >> 16 & 0xff] ^ invSubMix2[s3 >> 8 & 0xff] ^ invSubMix3[s0 & 0xff] ^ invKeySchedule[ksRow + 1];
t2 = invSubMix0[s2 >>> 24] ^ invSubMix1[s3 >> 16 & 0xff] ^ invSubMix2[s0 >> 8 & 0xff] ^ invSubMix3[s1 & 0xff] ^ invKeySchedule[ksRow + 2];
t3 = invSubMix0[s3 >>> 24] ^ invSubMix1[s0 >> 16 & 0xff] ^ invSubMix2[s1 >> 8 & 0xff] ^ invSubMix3[s2 & 0xff] ^ invKeySchedule[ksRow + 3]; // Update state
s0 = t0;
s1 = t1;
s2 = t2;
s3 = t3;
ksRow = ksRow + 4;
} // Shift rows, sub bytes, add round key
t0 = invSBOX[s0 >>> 24] << 24 ^ invSBOX[s1 >> 16 & 0xff] << 16 ^ invSBOX[s2 >> 8 & 0xff] << 8 ^ invSBOX[s3 & 0xff] ^ invKeySchedule[ksRow];
t1 = invSBOX[s1 >>> 24] << 24 ^ invSBOX[s2 >> 16 & 0xff] << 16 ^ invSBOX[s3 >> 8 & 0xff] << 8 ^ invSBOX[s0 & 0xff] ^ invKeySchedule[ksRow + 1];
t2 = invSBOX[s2 >>> 24] << 24 ^ invSBOX[s3 >> 16 & 0xff] << 16 ^ invSBOX[s0 >> 8 & 0xff] << 8 ^ invSBOX[s1 & 0xff] ^ invKeySchedule[ksRow + 2];
t3 = invSBOX[s3 >>> 24] << 24 ^ invSBOX[s0 >> 16 & 0xff] << 16 ^ invSBOX[s1 >> 8 & 0xff] << 8 ^ invSBOX[s2 & 0xff] ^ invKeySchedule[ksRow + 3];
ksRow = ksRow + 3; // Write
outputInt32[offset] = swapWord(t0 ^ initVector0);
outputInt32[offset + 1] = swapWord(t3 ^ initVector1);
outputInt32[offset + 2] = swapWord(t2 ^ initVector2);
outputInt32[offset + 3] = swapWord(t1 ^ initVector3); // reset initVector to last 4 unsigned int
initVector0 = inputWords0;
initVector1 = inputWords1;
initVector2 = inputWords2;
initVector3 = inputWords3;
offset = offset + 4;
}
return removePKCS7Padding ? removePadding(outputInt32.buffer) : outputInt32.buffer;
};
_proto.destroy = function destroy() {
this.key = undefined;
this.keySize = undefined;
this.ksRows = undefined;
this.sBox = undefined;
this.invSBox = undefined;
this.subMix = undefined;
this.invSubMix = undefined;
this.keySchedule = undefined;
this.invKeySchedule = undefined;
this.rcon = undefined;
};
return AESDecryptor;
}();
/* harmony default export */ var aes_decryptor = (AESDecryptor);
// EXTERNAL MODULE: ./src/errors.ts
var errors = __webpack_require__("./src/errors.ts");
// EXTERNAL MODULE: ./src/utils/logger.js
var logger = __webpack_require__("./src/utils/logger.js");
// EXTERNAL MODULE: ./src/events.js
var events = __webpack_require__("./src/events.js");
// EXTERNAL MODULE: ./src/utils/get-self-scope.js
var get_self_scope = __webpack_require__("./src/utils/get-self-scope.js");
// CONCATENATED MODULE: ./src/crypt/decrypter.js
// see https://stackoverflow.com/a/11237259/589493
var global = Object(get_self_scope["getSelfScope"])(); // safeguard for code that might run both on worker and main thread
var decrypter_Decrypter =
/*#__PURE__*/
function () {
function Decrypter(observer, config, _temp) {
var _ref = _temp === void 0 ? {} : _temp,
_ref$removePKCS7Paddi = _ref.removePKCS7Padding,
removePKCS7Padding = _ref$removePKCS7Paddi === void 0 ? true : _ref$removePKCS7Paddi;
this.logEnabled = true;
this.observer = observer;
this.config = config;
this.removePKCS7Padding = removePKCS7Padding; // built in decryptor expects PKCS7 padding
if (removePKCS7Padding) {
try {
var browserCrypto = global.crypto;
if (browserCrypto) {
this.subtle = browserCrypto.subtle || browserCrypto.webkitSubtle;
}
} catch (e) {}
}
this.disableWebCrypto = !this.subtle;
}
var _proto = Decrypter.prototype;
_proto.isSync = function isSync() {
return this.disableWebCrypto && this.config.enableSoftwareAES;
};
_proto.decrypt = function decrypt(data, key, iv, callback) {
var _this = this;
if (this.disableWebCrypto && this.config.enableSoftwareAES) {
if (this.logEnabled) {
logger["logger"].log('JS AES decrypt');
this.logEnabled = false;
}
var decryptor = this.decryptor;
if (!decryptor) {
this.decryptor = decryptor = new aes_decryptor();
}
decryptor.expandKey(key);
callback(decryptor.decrypt(data, 0, iv, this.removePKCS7Padding));
} else {
if (this.logEnabled) {
logger["logger"].log('WebCrypto AES decrypt');
this.logEnabled = false;
}
var subtle = this.subtle;
if (this.key !== key) {
this.key = key;
this.fastAesKey = new fast_aes_key(subtle, key);
}
this.fastAesKey.expandKey().then(function (aesKey) {
// decrypt using web crypto
var crypto = new AESCrypto(subtle, iv);
crypto.decrypt(data, aesKey).catch(function (err) {
_this.onWebCryptoError(err, data, key, iv, callback);
}).then(function (result) {
callback(result);
});
}).catch(function (err) {
_this.onWebCryptoError(err, data, key, iv, callback);
});
}
};
_proto.onWebCryptoError = function onWebCryptoError(err, data, key, iv, callback) {
if (this.config.enableSoftwareAES) {
logger["logger"].log('WebCrypto Error, disable WebCrypto API');
this.disableWebCrypto = true;
this.logEnabled = true;
this.decrypt(data, key, iv, callback);
} else {
logger["logger"].error("decrypting error : " + err.message);
this.observer.trigger(events["default"].ERROR, {
type: errors["ErrorTypes"].MEDIA_ERROR,
details: errors["ErrorDetails"].FRAG_DECRYPT_ERROR,
fatal: true,
reason: err.message
});
}
};
_proto.destroy = function destroy() {
var decryptor = this.decryptor;
if (decryptor) {
decryptor.destroy();
this.decryptor = undefined;
}
};
return Decrypter;
}();
/* harmony default export */ var decrypter = __webpack_exports__["default"] = (decrypter_Decrypter);
/***/ }),
/***/ "./src/demux/demuxer-inline.js":
/*!**************************************************!*\
!*** ./src/demux/demuxer-inline.js + 12 modules ***!
\**************************************************/
/*! exports provided: default */
/*! ModuleConcatenation bailout: Cannot concat with ./src/crypt/decrypter.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/demux/id3.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/demux/mp4demuxer.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/errors.ts because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/events.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/polyfills/number-isFinite.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/utils/get-self-scope.js because of ./src/hls.ts */
/*! ModuleConcatenation bailout: Cannot concat with ./src/utils/logger.js because of ./src/hls.ts */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
// EXTERNAL MODULE: ./src/events.js
var events = __webpack_require__("./src/events.js");
// EXTERNAL MODULE: ./src/errors.ts
var errors = __webpack_require__("./src/errors.ts");
// EXTERNAL MODULE: ./src/crypt/decrypter.js + 3 modules
var crypt_decrypter = __webpack_require__("./src/crypt/decrypter.js");
// EXTERNAL MODULE: ./src/polyfills/number-isFinite.js
var number_isFinite = __webpack_require__("./src/polyfills/number-isFinite.js");
// EXTERNAL MODULE: ./src/utils/logger.js
var logger = __webpack_require__("./src/utils/logger.js");
// EXTERNAL MODULE: ./src/utils/get-self-scope.js
var get_self_scope = __webpack_require__("./src/utils/get-self-scope.js");
// CONCATENATED MODULE: ./src/demux/adts.js
/**
* ADTS parser helper
* @link https://wiki.multimedia.cx/index.php?title=ADTS
*/
function getAudioConfig(observer, data, offset, audioCodec) {
var adtsObjectType,
// :int
adtsSampleingIndex,
// :int
adtsExtensionSampleingIndex,
// :int
adtsChanelConfig,
// :int
config,
userAgent = navigator.userAgent.toLowerCase(),
manifestCodec = audioCodec,
adtsSampleingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350]; // byte 2
adtsObjectType = ((data[offset + 2] & 0xC0) >>> 6) + 1;
adtsSampleingIndex = (data[offset + 2] & 0x3C) >>> 2;
if (adtsSampleingIndex > adtsSampleingRates.length - 1) {
observer.trigger(events["default"].ERROR, {
type: errors["ErrorTypes"].MEDIA_ERROR,
details: errors["ErrorDetails"].FRAG_PARSING_ERROR,
fatal: true,
reason: "invalid ADTS sampling index:" + adtsSampleingIndex
});
return;
}
adtsChanelConfig = (data[offset + 2] & 0x01) << 2; // byte 3
adtsChanelConfig |= (data[offset + 3] & 0xC0) >>> 6;
logger["logger"].log("manifest codec:" + audioCodec + ",ADTS data:type:" + adtsObjectType + ",sampleingIndex:" + adtsSampleingIndex + "[" + adtsSampleingRates[adtsSampleingIndex] + "Hz],channelConfig:" + adtsChanelConfig); // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
if (/firefox/i.test(userAgent)) {
if (adtsSampleingIndex >= 6) {
adtsObjectType = 5;
config = new Array(4); // HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
// there is a factor 2 between frame sample rate and output sample rate
// multiply frequency by 2 (see table below, equivalent to substract 3)
adtsExtensionSampleingIndex = adtsSampleingIndex - 3;
} else {
adtsObjectType = 2;
config = new Array(2);
adtsExtensionSampleingIndex = adtsSampleingIndex;
} // Android : always use AAC
} else if (userAgent.indexOf('android') !== -1) {
adtsObjectType = 2;
config = new Array(2);
adtsExtensionSampleingIndex = adtsSampleingIndex;
} else {
/* for other browsers (Chrome/Vivaldi/Opera ...)
always force audio type to be HE-AAC SBR, as some browsers do not support audio codec switch properly (like Chrome ...)
*/
adtsObjectType = 5;
config = new Array(4); // if (manifest codec is HE-AAC or HE-AACv2) OR (manifest codec not specified AND frequency less than 24kHz)
if (audioCodec && (audioCodec.indexOf('mp4a.40.29') !== -1 || audioCodec.indexOf('mp4a.40.5') !== -1) || !audioCodec && adtsSampleingIndex >= 6) {
// HE-AAC uses SBR (Spectral Band Replication) , high frequencies are constructed from low frequencies
// there is a factor 2 between frame sample rate and output sample rate
// multiply frequency by 2 (see table below, equivalent to substract 3)
adtsExtensionSampleingIndex = adtsSampleingIndex - 3;
} else {
// if (manifest codec is AAC) AND (frequency less than 24kHz AND nb channel is 1) OR (manifest codec not specified and mono audio)
// Chrome fails to play back with low frequency AAC LC mono when initialized with HE-AAC. This is not a problem with stereo.
if (audioCodec && audioCodec.indexOf('mp4a.40.2') !== -1 && (adtsSampleingIndex >= 6 && adtsChanelConfig === 1 || /vivaldi/i.test(userAgent)) || !audioCodec && adtsChanelConfig === 1) {
adtsObjectType = 2;
config = new Array(2);
}
adtsExtensionSampleingIndex = adtsSampleingIndex;
}
}
/* refer to http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config
ISO 14496-3 (AAC).pdf - Table 1.13 — Syntax of AudioSpecificConfig()
Audio Profile / Audio Object Type
0: Null
1: AAC Main
2: AAC LC (Low Complexity)
3: AAC SSR (Scalable Sample Rate)
4: AAC LTP (Long Term Prediction)
5: SBR (Spectral Band Replication)
6: AAC Scalable
sampling freq
0: 96000 Hz
1: 88200 Hz
2: 64000 Hz
3: 48000 Hz
4: 44100 Hz
5: 32000 Hz
6: 24000 Hz
7: 22050 Hz
8: 16000 Hz
9: 12000 Hz
10: 11025 Hz
11: 8000 Hz
12: 7350 Hz
13: Reserved
14: Reserved
15: frequency is written explictly
Channel Configurations
These are the channel configurations:
0: Defined in AOT Specifc Config
1: 1 channel: front-center
2: 2 channels: front-left, front-right
*/
// audioObjectType = profile => profile, the MPEG-4 Audio Object Type minus 1
config[0] = adtsObjectType << 3; // samplingFrequencyIndex
config[0] |= (adtsSampleingIndex & 0x0E) >> 1;
config[1] |= (adtsSampleingIndex & 0x01) << 7; // channelConfiguration
config[1] |= adtsChanelConfig << 3;
if (adtsObjectType === 5) {
// adtsExtensionSampleingIndex
config[1] |= (adtsExtensionSampleingIndex & 0x0E) >> 1;
config[2] = (adtsExtensionSampleingIndex & 0x01) << 7; // adtsObjectType (force to 2, chrome is checking that object type is less than 5 ???
// https://chromium.googlesource.com/chromium/src.git/+/master/media/formats/mp4/aac.cc
config[2] |= 2 << 2;
config[3] = 0;
}
return {
config: config,
samplerate: adtsSampleingRates[adtsSampleingIndex],
channelCount: adtsChanelConfig,
codec: 'mp4a.40.' + adtsObjectType,
manifestCodec: manifestCodec
};
}
function isHeaderPattern(data, offset) {
return data[offset] === 0xff && (data[offset + 1] & 0xf6) === 0xf0;
}
function getHeaderLength(data, offset) {
return data[offset + 1] & 0x01 ? 7 : 9;
}
function getFullFrameLength(data, offset) {
return (data[offset + 3] & 0x03) << 11 | data[offset + 4] << 3 | (data[offset + 5] & 0xE0) >>> 5;
}
function isHeader(data, offset) {
// Look for ADTS header | 1111 1111 | 1111 X00X | where X can be either 0 or 1
// Layer bits (position 14 and 15) in header should be always 0 for ADTS
// More info https://wiki.multimedia.cx/index.php?title=ADTS
if (offset + 1 < data.length && isHeaderPattern(data, offset)) {
return true;
}
return false;
}
function adts_probe(data, offset) {
// same as isHeader but we also check that ADTS frame follows last ADTS frame
// or end of data is reached
if (isHeader(data, offset)) {
// ADTS header Length
var headerLength = getHeaderLength(data, offset); // ADTS frame Length
var frameLength = headerLength;
if (offset + 5 < data.length) {
frameLength = getFullFrameLength(data, offset);
}
var newOffset = offset + frameLength;
if (newOffset === data.length || newOffset + 1 < data.length && isHeaderPattern(data, newOffset)) {
return true;
}
}
return false;
}
function initTrackConfig(track, observer, data, offset, audioCodec) {
if (!track.samplerate) {
var config = getAudioConfig(observer, data, offset, audioCodec);
track.config = config.config;
track.samplerate = config.samplerate;
track.channelCount = config.channelCount;
track.codec = config.codec;
track.manifestCodec = config.manifestCodec;
logger["logger"].log("parsed codec:" + track.codec + ",rate:" + config.samplerate + ",nb channel:" + config.channelCount);
}
}
function getFrameDuration(samplerate) {
return 1024 * 90000 / samplerate;
}
function parseFrameHeader(data, offset, pts, frameIndex, frameDuration) {
var headerLength, frameLength, stamp;
var length = data.length; // The protection skip bit tells us if we have 2 bytes of CRC data at the end of the ADTS header
headerLength = getHeaderLength(data, offset); // retrieve frame size
frameLength = getFullFrameLength(data, offset);
frameLength -= headerLength;
if (frameLength > 0 && offset + headerLength + frameLength <= length) {
stamp = pts + frameIndex * frameDuration; // logger.log(`AAC frame, offset/length/total/pts:${offset+headerLength}/${frameLength}/${data.byteLength}/${(stamp/90).toFixed(0)}`);
return {
headerLength: headerLength,
frameLength: frameLength,
stamp: stamp
};
}
return undefined;
}
function appendFrame(track, data, offset, pts, frameIndex) {
var frameDuration = getFrameDuration(track.samplerate);
var header = parseFrameHeader(data, offset, pts, frameIndex, frameDuration);
if (header) {
var stamp = header.stamp;
var headerLength = header.headerLength;
var frameLength = header.frameLength; // logger.log(`AAC frame, offset/length/total/pts:${offset+headerLength}/${frameLength}/${data.byteLength}/${(stamp/90).toFixed(0)}`);
var aacSample = {
unit: data.subarray(offset + headerLength, offset + headerLength + frameLength),
pts: stamp,
dts: stamp
};
track.samples.push(aacSample);
return {
sample: aacSample,
length: frameLength + headerLength
};
}
return undefined;
}
// EXTERNAL MODULE: ./src/demux/id3.js
var id3 = __webpack_require__("./src/demux/id3.js");
// CONCATENATED MODULE: ./src/demux/aacdemuxer.js
/**
* AAC demuxer
*/
var aacdemuxer_AACDemuxer =
/*#__PURE__*/
function () {
function AACDemuxer(observer, remuxer, config) {
this.observer = observer;
this.config = config;
this.remuxer = remuxer;
}
var _proto = AACDemuxer.prototype;
_proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, duration) {
this._audioTrack = {
container: 'audio/adts',
type: 'audio',
id: 0,
sequenceNumber: 0,
isAAC: true,
samples: [],
len: 0,
manifestCodec: audioCodec,
duration: duration,
inputTimeScale: 90000
};
};
_proto.resetTimeStamp = function resetTimeStamp() {};
AACDemuxer.probe = function probe(data) {
if (!data) {
return false;
} // Check for the ADTS sync word
// Look for ADTS header | 1111 1111 | 1111 X00X | where X can be either 0 or 1
// Layer bits (position 14 and 15) in header should be always 0 for ADTS
// More info https://wiki.multimedia.cx/index.php?title=ADTS
var id3Data = id3["default"].getID3Data(data, 0) || [];
var offset = id3Data.length;
for (var length = data.length; offset < length; offset++) {
if (adts_probe(data, offset)) {
logger["logger"].log('ADTS sync word found !');
return true;
}
}
return false;
} // feed incoming data to the front of the parsing pipeline
;
_proto.append = function append(data, timeOffset, contiguous, accurateTimeOffset) {
var track = this._audioTrack;
var id3Data = id3["default"].getID3Data(data, 0) || [];
var timestamp = id3["default"].getTimeStamp(id3Data);
var pts = Object(number_isFinite["isFiniteNumber"])(timestamp) ? timestamp * 90 : timeOffset * 90000;
var frameIndex = 0;
var stamp = pts;
var length = data.length;
var offset = id3Data.length;
var id3Samples = [{
pts: stamp,
dts: stamp,
data: id3Data
}];
while (offset < length - 1) {
if (isHeader(data, offset) && offset + 5 < length) {
initTrackConfig(track, this.observer, data, offset, track.manifestCodec);
var frame = appendFrame(track, data, offset, pts, frameIndex);
if (frame) {
offset += frame.length;
stamp = frame.sample.pts;
frameIndex++;
} else {
logger["logger"].log('Unable to parse AAC frame');
break;
}
} else if (id3["default"].isHeader(data, offset)) {
id3Data = id3["default"].getID3Data(data, offset);
id3Samples.push({
pts: stamp,
dts: stamp,
data: id3Data
});
offset += id3Data.length;
} else {
// nothing found, keep looking
offset++;
}
}
this.remuxer.remux(track, {
samples: []
}, {
samples: id3Samples,
inputTimeScale: 90000
}, {
samples: []
}, timeOffset, contiguous, accurateTimeOffset);
};
_proto.destroy = function destroy() {};
return AACDemuxer;
}();
/* harmony default export */ var aacdemuxer = (aacdemuxer_AACDemuxer);
// EXTERNAL MODULE: ./src/demux/mp4demuxer.js
var mp4demuxer = __webpack_require__("./src/demux/mp4demuxer.js");
// CONCATENATED MODULE: ./src/demux/mpegaudio.js
/**
* MPEG parser helper
*/
var MpegAudio = {
BitratesMap: [32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160],
SamplingRateMap: [44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000],
SamplesCoefficients: [// MPEG 2.5
[0, // Reserved
72, // Layer3
144, // Layer2
12 // Layer1
], // Reserved
[0, // Reserved
0, // Layer3
0, // Layer2
0 // Layer1
], // MPEG 2
[0, // Reserved
72, // Layer3
144, // Layer2
12 // Layer1
], // MPEG 1
[0, // Reserved
144, // Layer3
144, // Layer2
12 // Layer1
]],
BytesInSlot: [0, // Reserved
1, // Layer3
1, // Layer2
4 // Layer1
],
appendFrame: function appendFrame(track, data, offset, pts, frameIndex) {
// Using http://www.datavoyage.com/mpgscript/mpeghdr.htm as a reference
if (offset + 24 > data.length) {
return undefined;
}
var header = this.parseHeader(data, offset);
if (header && offset + header.frameLength <= data.length) {
var frameDuration = header.samplesPerFrame * 90000 / header.sampleRate;
var stamp = pts + frameIndex * frameDuration;
var sample = {
unit: data.subarray(offset, offset + header.frameLength),
pts: stamp,
dts: stamp
};
track.config = [];
track.channelCount = header.channelCount;
track.samplerate = header.sampleRate;
track.samples.push(sample);
return {
sample: sample,
length: header.frameLength
};
}
return undefined;
},
parseHeader: function parseHeader(data, offset) {
var headerB = data[offset + 1] >> 3 & 3;
var headerC = data[offset + 1] >> 1 & 3;
var headerE = data[offset + 2] >> 4 & 15;
var headerF = data[offset + 2] >> 2 & 3;
var headerG = data[offset + 2] >> 1 & 1;
if (headerB !== 1 && headerE !== 0 && headerE !== 15 && headerF !== 3) {
var columnInBitrates = headerB === 3 ? 3 - headerC : headerC === 3 ? 3 : 4;
var bitRate = MpegAudio.BitratesMap[columnInBitrates * 14 + headerE - 1] * 1000;
var columnInSampleRates = headerB === 3 ? 0 : headerB === 2 ? 1 : 2;
var sampleRate = MpegAudio.SamplingRateMap[columnInSampleRates * 3 + headerF];
var channelCount = data[offset + 3] >> 6 === 3 ? 1 : 2; // If bits of channel mode are `11` then it is a single channel (Mono)
var sampleCoefficient = MpegAudio.SamplesCoefficients[headerB][headerC];
var bytesInSlot = MpegAudio.BytesInSlot[headerC];
var samplesPerFrame = sampleCoefficient * 8 * bytesInSlot;
var frameLength = parseInt(sampleCoefficient * bitRate / sampleRate + headerG, 10) * bytesInSlot;
return {
sampleRate: sampleRate,
channelCount: channelCount,
frameLength: frameLength,
samplesPerFrame: samplesPerFrame
};
}
return undefined;
},
isHeaderPattern: function isHeaderPattern(data, offset) {
return data[offset] === 0xff && (data[offset + 1] & 0xe0) === 0xe0 && (data[offset + 1] & 0x06) !== 0x00;
},
isHeader: function isHeader(data, offset) {
// Look for MPEG header | 1111 1111 | 111X XYZX | where X can be either 0 or 1 and Y or Z should be 1
// Layer bits (position 14 and 15) in header should be always different from 0 (Layer I or Layer II or Layer III)
// More info http://www.mp3-tech.org/programmer/frame_header.html
if (offset + 1 < data.length && this.isHeaderPattern(data, offset)) {
return true;
}
return false;
},
probe: function probe(data, offset) {
// same as isHeader but we also check that MPEG frame follows last MPEG frame
// or end of data is reached
if (offset + 1 < data.length && this.isHeaderPattern(data, offset)) {
// MPEG header Length
var headerLength = 4; // MPEG frame Length
var header = this.parseHeader(data, offset);
var frameLength = headerLength;
if (header && header.frameLength) {
frameLength = header.frameLength;
}
var newOffset = offset + frameLength;
if (newOffset === data.length || newOffset + 1 < data.length && this.isHeaderPattern(data, newOffset)) {
return true;
}
}
return false;
}
};
/* harmony default export */ var mpegaudio = (MpegAudio);
// CONCATENATED MODULE: ./src/demux/exp-golomb.js
/**
* Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
*/
var exp_golomb_ExpGolomb =
/*#__PURE__*/
function () {
function ExpGolomb(data) {
this.data = data; // the number of bytes left to examine in this.data
this.bytesAvailable = data.byteLength; // the current word being examined
this.word = 0; // :uint
// the number of bits left to examine in the current word
this.bitsAvailable = 0; // :uint
} // ():void
var _proto = ExpGolomb.prototype;
_proto.loadWord = function loadWord() {
var data = this.data,
bytesAvailable = this.bytesAvailable,
position = data.byteLength - bytesAvailable,
workingBytes = new Uint8Array(4),
availableBytes = Math.min(4, bytesAvailable);
if (availableBytes === 0) {
throw new Error('no bytes available');
}
workingBytes.set(data.subarray(position, position + availableBytes));
this.word = new DataView(workingBytes.buffer).getUint32(0); // track the amount of this.data that has been processed
this.bitsAvailable = availableBytes * 8;
this.bytesAvailable -= availableBytes;
} // (count:int):void
;
_proto.skipBits = function skipBits(count) {
var skipBytes; // :int
if (this.bitsAvailable > count) {
this.word <<= count;
this.bitsAvailable -= count;
} else {
count -= this.bitsAvailable;
skipBytes = count >> 3;
count -= skipBytes >> 3;
this.bytesAvailable -= skipBytes;
this.loadWord();
this.word <<= count;
this.bitsAvailable -= count;
}
} // (size:int):uint
;
_proto.readBits = function readBits(size) {
var bits = Math.min(this.bitsAvailable, size),
// :uint
valu = this.word >>> 32 - bits; // :uint
if (size > 32) {
logger["logger"].error('Cannot read more than 32 bits at a time');
}
this.bitsAvailable -= bits;
if (this.bitsAvailable > 0) {
this.word <<= bits;
} else if (this.bytesAvailable > 0) {
this.loadWord();
}
bits = size - bits;
if (bits > 0 && this.bitsAvailable) {
return valu << bits | this.readBits(bits);
} else {
return valu;
}
} // ():uint
;
_proto.skipLZ = function skipLZ() {
var leadingZeroCount; // :uint
for (leadingZeroCount = 0; leadingZeroCount < this.bitsAvailable; ++leadingZeroCount) {
if ((this.word & 0x80000000 >>> leadingZeroCount) !== 0) {
// the first bit of working word is 1
this.word <<= leadingZeroCount;
this.bitsAvailable -= leadingZeroCount;
return leadingZeroCount;
}
} // we exhausted word and still have not found a 1
this.loadWord();
return leadingZeroCount + this.skipLZ();
} // ():void
;
_proto.skipUEG = function skipUEG() {
this.skipBits(1 + this.skipLZ());
} // ():void
;
_proto.skipEG = function skipEG() {
this.skipBits(1 + this.skipLZ());
} // ():uint
;
_proto.readUEG = function readUEG() {
var clz = this.skipLZ(); // :uint
return this.readBits(clz + 1) - 1;
} // ():int
;
_proto.readEG = function readEG() {
var valu = this.readUEG(); // :int
if (0x01 & valu) {
// the number is odd if the low order bit is set
return 1 + valu >>> 1; // add 1 to make it even, and divide by 2
} else {
return -1 * (valu >>> 1); // divide by two then make it negative
}
} // Some convenience functions
// :Boolean
;
_proto.readBoolean = function readBoolean() {
return this.readBits(1) === 1;
} // ():int
;
_proto.readUByte = function readUByte() {
return this.readBits(8);
} // ():int
;
_proto.readUShort = function readUShort() {
return this.readBits(16);
} // ():int
;
_proto.readUInt = function readUInt() {
return this.readBits(32);
}
/**
* Advance the ExpGolomb decoder past a scaling list. The scaling
* list is optionally transmitted as part of a sequence parameter
* set and is not relevant to transmuxing.
* @param count {number} the number of entries in this scaling list
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
*/
;
_proto.skipScalingList = function skipScalingList(count) {
var lastScale = 8,
nextScale = 8,
j,
deltaScale;
for (j = 0; j < count; j++) {
if (nextScale !== 0) {
deltaScale = this.readEG();
nextScale = (lastScale + deltaScale + 256) % 256;
}
lastScale = nextScale === 0 ? lastScale : nextScale;
}
}
/**
* Read a sequence parameter set and return some interesting video
* properties. A sequence parameter set is the H264 metadata that
* describes the properties of upcoming video frames.
* @param data {Uint8Array} the bytes of a sequence parameter set
* @return {object} an object with configuration parsed from the
* sequence parameter set, including the dimensions of the
* associated video frames.
*/
;
_proto.readSPS = function readSPS() {
var frameCropLeftOffset = 0,
frameCropRightOffset = 0,
frameCropTopOffset = 0,
frameCropBottomOffset = 0,
profileIdc,
profileCompat,
levelIdc,
numRefFramesInPicOrderCntCycle,
picWidthInMbsMinus1,
picHeightInMapUnitsMinus1,
frameMbsOnlyFlag,
scalingListCount,
i,
readUByte = this.readUByte.bind(this),
readBits = this.readBits.bind(this),
readUEG = this.readUEG.bind(this),
readBoolean = this.readBoolean.bind(this),
skipBits = this.skipBits.bind(this),
skipEG = this.skipEG.bind(this),
skipUEG = this.skipUEG.bind(this),
skipScalingList = this.skipScalingList.bind(this);
readUByte();
profileIdc = readUByte(); // profile_idc
profileCompat = readBits(5); // constraint_set[0-4]_flag, u(5)
skipBits(3); // reserved_zero_3bits u(3),
levelIdc = readUByte(); // level_idc u(8)
skipUEG(); // seq_parameter_set_id
// some profiles have more optional data we don't need
if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
var chromaFormatIdc = readUEG();
if (chromaFormatIdc === 3) {
skipBits(1);
} // separate_colour_plane_flag
skipUEG(); // bit_depth_luma_minus8
skipUEG(); // bit_depth_chroma_minus8
skipBits(1); // qpprime_y_zero_transform_bypass_flag
if (readBoolean()) {
// seq_scaling_matrix_present_flag
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
for (i = 0; i < scalingListCount; i++) {
if (readBoolean()) {
// seq_scaling_list_present_flag[ i ]
if (i < 6) {
skipScalingList(16);
} else {
skipScalingList(64);
}
}
}
}
}
skipUEG(); // log2_max_frame_num_minus4
var picOrderCntType = readUEG();
if (picOrderCntType === 0) {
readUEG(); // log2_max_pic_order_cnt_lsb_minus4
} else if (picOrderCntType === 1) {
skipBits(1); // delta_pic_order_always_zero_flag
skipEG(); // offset_for_non_ref_pic
skipEG(); // offset_for_top_to_bottom_field
numRefFramesInPicOrderCntCycle = readUEG();
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
skipEG();
} // offset_for_ref_frame[ i ]
}
skipUEG(); // max_num_ref_frames
skipBits(1); // gaps_in_frame_num_value_allowed_flag
picWidthInMbsMinus1 = readUEG();
picHeightInMapUnitsMinus1 = readUEG();
frameMbsOnlyFlag = readBits(1);
if (frameMbsOnlyFlag === 0) {
skipBits(1);
} // mb_adaptive_frame_field_flag
skipBits(1); // direct_8x8_inference_flag
if (readBoolean()) {
// frame_cropping_flag
frameCropLeftOffset = readUEG();
frameCropRightOffset = readUEG();
frameCropTopOffset = readUEG();
frameCropBottomOffset = readUEG();
}
var pixelRatio = [1, 1];
if (readBoolean()) {
// vui_parameters_present_flag
if (readBoolean()) {
// aspect_ratio_info_present_flag
var aspectRatioIdc = readUByte();
switch (aspectRatioIdc) {
case 1:
pixelRatio = [1, 1];
break;
case 2:
pixelRatio = [12, 11];
break;
case 3:
pixelRatio = [10, 11];
break;
case 4:
pixelRatio = [16, 11];
break;
case 5:
pixelRatio = [40, 33];
break;
case 6:
pixelRatio = [24, 11];
break;
case 7:
pixelRatio = [20, 11];
break;
case 8:
pixelRatio = [32, 11];
break;
case 9:
pixelRatio = [80, 33];
break;
case 10:
pixelRatio = [18, 11];
break;
case 11:
pixelRatio = [15, 11];
break;
case 12:
pixelRatio = [64, 33];
break;
case 13:
pixelRatio = [160, 99];
break;
case 14:
pixelRatio = [4, 3];
break;
case 15:
pixelRatio = [3, 2];
break;
case 16:
pixelRatio = [2, 1];
break;
case 255:
{
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
break;
}
}
}
}
return {
width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
pixelRatio: pixelRatio
};
};
_proto.readSliceType = function readSliceType() {
// skip NALu type
this.readUByte(); // discard first_mb_in_slice
this.readUEG(); // return slice_type
return this.readUEG();
};
return ExpGolomb;
}();
/* harmony default export */ var exp_golomb = (exp_golomb_ExpGolomb);
// CONCATENATED MODULE: ./src/demux/sample-aes.js
/**
* SAMPLE-AES decrypter
*/
var sample_aes_SampleAesDecrypter =
/*#__PURE__*/
function () {
function SampleAesDecrypter(observer, config, decryptdata, discardEPB) {
this.decryptdata = decryptdata;
this.discardEPB = discardEPB;
this.decrypter = new crypt_decrypter["default"](observer, config, {
removePKCS7Padding: false
});
}
var _proto = SampleAesDecrypter.prototype;
_proto.decryptBuffer = function decryptBuffer(encryptedData, callback) {
this.decrypter.decrypt(encryptedData, this.decryptdata.key.buffer, this.decryptdata.iv.buffer, callback);
} // AAC - encrypt all full 16 bytes blocks starting from offset 16
;
_proto.decryptAacSample = function decryptAacSample(samples, sampleIndex, callback, sync) {
var curUnit = samples[sampleIndex].unit;
var encryptedData = curUnit.subarray(16, curUnit.length - curUnit.length % 16);
var encryptedBuffer = encryptedData.buffer.slice(encryptedData.byteOffset, encryptedData.byteOffset + encryptedData.length);
var localthis = this;
this.decryptBuffer(encryptedBuffer, function (decryptedData) {
decryptedData = new Uint8Array(decryptedData);
curUnit.set(decryptedData, 16);
if (!sync) {
localthis.decryptAacSamples(samples, sampleIndex + 1, callback);
}
});
};
_proto.decryptAacSamples = function decryptAacSamples(samples, sampleIndex, callback) {
for (;; sampleIndex++) {
if (sampleIndex >= samples.length) {
callback();
return;
}
if (samples[sampleIndex].unit.length < 32) {
continue;
}
var sync = this.decrypter.isSync();
this.decryptAacSample(samples, sampleIndex, callback, sync);
if (!sync) {
return;
}
}
} // AVC - encrypt one 16 bytes block out of ten, starting from offset 32
;
_proto.getAvcEncryptedData = function getAvcEncryptedData(decodedData) {
var encryptedDataLen = Math.floor((decodedData.length - 48) / 160) * 16 + 16;
var encryptedData = new Int8Array(encryptedDataLen);
var outputPos = 0;
for (var inputPos = 32; inputPos <= decodedData.length - 16; inputPos += 160, outputPos += 16) {
encryptedData.set(decodedData.subarray(inputPos, inputPos + 16), outputPos);
}
return encryptedData;
};
_proto.getAvcDecryptedUnit = function getAvcDecryptedUnit(decodedData, decryptedData) {
decryptedData = new Uint8Array(decryptedData);
var inputPos = 0;
for (var outputPos = 32; outputPos <= decodedData.length - 16; outputPos += 160, inputPos += 16) {
decodedData.set(decryptedData.subarray(inputPos, inputPos + 16), outputPos);
}
return decodedData;
};
_proto.decryptAvcSample = function decryptAvcSample(samples, sampleIndex, unitIndex, callback, curUnit, sync) {
var decodedData = this.discardEPB(curUnit.data);
var encryptedData = this.getAvcEncryptedData(decodedData);
var localthis = this;
this.decryptBuffer(encryptedData.buffer, function (decryptedData) {
curUnit.data = localthis.getAvcDecryptedUnit(decodedData, decryptedData);
if (!sync) {
localthis.decryptAvcSamples(samples, sampleIndex, unitIndex + 1, callback);
}
});
};
_proto.decryptAvcSamples = function decryptAvcSamples(samples, sampleIndex, unitIndex, callback) {
for (;; sampleIndex++, unitIndex = 0) {
if (sampleIndex >= samples.length) {
callback();
return;
}
var curUnits = samples[sampleIndex].units;
for (;; unitIndex++) {
if (unitIndex >= curUnits.length) {
break;
}
var curUnit = curUnits[unitIndex];
if (curUnit.length <= 48 || curUnit.type !== 1 && curUnit.type !== 5) {
continue;
}
var sync = this.decrypter.isSync();
this.decryptAvcSample(samples, sampleIndex, unitIndex, callback, curUnit, sync);
if (!sync) {
return;
}
}
}
};
return SampleAesDecrypter;
}();
/* harmony default export */ var sample_aes = (sample_aes_SampleAesDecrypter);
// CONCATENATED MODULE: ./src/demux/tsdemuxer.js
/**
* highly optimized TS demuxer:
* parse PAT, PMT
* extract PES packet from audio and video PIDs
* extract AVC/H264 NAL units and AAC/ADTS samples from PES packet
* trigger the remuxer upon parsing completion
* it also tries to workaround as best as it can audio codec switch (HE-AAC to AAC and vice versa), without having to restart the MediaSource.
* it also controls the remuxing process :
* upon discontinuity or level switch detection, it will also notifies the remuxer so that it can reset its state.
*/
// import Hex from '../utils/hex';
// We are using fixed track IDs for driving the MP4 remuxer
// instead of following the TS PIDs.
// There is no reason not to do this and some browsers/SourceBuffer-demuxers
// may not like if there are TrackID "switches"
// See https://github.com/video-dev/hls.js/issues/1331
// Here we are mapping our internal track types to constant MP4 track IDs
// With MSE currently one can only have one track of each, and we are muxing
// whatever video/audio rendition in them.
var RemuxerTrackIdConfig = {
video: 1,
audio: 2,
id3: 3,
text: 4
};
var tsdemuxer_TSDemuxer =
/*#__PURE__*/
function () {
function TSDemuxer(observer, remuxer, config, typeSupported) {
this.observer = observer;
this.config = config;
this.typeSupported = typeSupported;
this.remuxer = remuxer;
this.sampleAes = null;
}
var _proto = TSDemuxer.prototype;
_proto.setDecryptData = function setDecryptData(decryptdata) {
if (decryptdata != null && decryptdata.key != null && decryptdata.method === 'SAMPLE-AES') {
this.sampleAes = new sample_aes(this.observer, this.config, decryptdata, this.discardEPB);
} else {
this.sampleAes = null;
}
};
TSDemuxer.probe = function probe(data) {
var syncOffset = TSDemuxer._syncOffset(data);
if (syncOffset < 0) {
return false;
} else {
if (syncOffset) {
logger["logger"].warn("MPEG2-TS detected but first sync word found @ offset " + syncOffset + ", junk ahead ?");
}
return true;
}
};
TSDemuxer._syncOffset = function _syncOffset(data) {
// scan 1000 first bytes
var scanwindow = Math.min(1000, data.length - 3 * 188);
var i = 0;
while (i < scanwindow) {
// a TS fragment should contain at least 3 TS packets, a PAT, a PMT, and one PID, each starting with 0x47
if (data[i] === 0x47 && data[i + 188] === 0x47 && data[i + 2 * 188] === 0x47) {
return i;
} else {
i++;
}
}
return -1;
}
/**
* Creates a track model internal to demuxer used to drive remuxing input
*
* @param {string} type 'audio' | 'video' | 'id3' | 'text'
* @param {number} duration
* @return {object} TSDemuxer's internal track model
*/
;
TSDemuxer.createTrack = function createTrack(type, duration) {
return {
container: type === 'video' || type === 'audio' ? 'video/mp2t' : undefined,
type: type,
id: RemuxerTrackIdConfig[type],
pid: -1,
inputTimeScale: 90000,
sequenceNumber: 0,
samples: [],
dropped: type === 'video' ? 0 : undefined,
isAAC: type === 'audio' ? true : undefined,
duration: type === 'audio' ? duration : undefined
};
}
/**
* Initializes a new init segment on the demuxer/remuxer interface. Needed for discontinuities/track-switches (or at stream start)
* Resets all internal track instances of the demuxer.
*
* @override Implements generic demuxing/remuxing interface (see DemuxerInline)
* @param {object} initSegment
* @param {string} audioCodec
* @param {string} videoCodec
* @param {number} duration (in TS timescale = 90kHz)
*/
;
_proto.resetInitSegment = function resetInitSegment(initSegment, audioCodec, videoCodec, duration) {
this.pmtParsed = false;
this._pmtId = -1;
this._avcTrack = TSDemuxer.createTrack('video', duration);
this._audioTrack = TSDemuxer.createTrack('audio', duration);
this._id3Track = TSDemuxer.createTrack('id3', duration);
this._txtTrack = TSDemuxer.createTrack('text', duration); // flush any partial content
this.aacOverFlow = null;
this.aacLastPTS = null;
this.avcSample = null;
this.audioCodec = audioCodec;
this.videoCodec = videoCodec;
this._duration = duration;
}
/**
*
* @override
*/
;
_proto.resetTimeStamp = function resetTimeStamp() {} // feed incoming data to the front of the parsing pipeline
;
_proto.append = function append(data, timeOffset, contiguous, accurateTimeOffset) {
var start,
len = data.length,
stt,
pid,
atf,
offset,
pes,
unknownPIDs = false;
this.contiguous = contiguous;
var pmtParsed = this.pmtParsed,
avcTrack = this._avcTrack,
audioTrack = this._audioTrack,
id3Track = this._id3Track,
avcId = avcTrack.pid,
audioId = audioTrack.pid,
id3Id = id3Track.pid,
pmtId = this._pmtId,
avcData = avcTrack.pesData,
audioData = audioTrack.pesData,
id3Data = id3Track.pesData,
parsePAT = this._parsePAT,
parsePMT = this._parsePMT,
parsePES = this._parsePES,
parseAVCPES = this._parseAVCPES.bind(this),
parseAACPES = this._parseAACPES.bind(this),
parseMPEGPES = this._parseMPEGPES.bind(this),
parseID3PES = this._parseID3PES.bind(this);
var syncOffset = TSDemuxer._syncOffset(data); // don't parse last TS packet if incomplete
len -= (len + syncOffset) % 188; // loop through TS packets
for (start = syncOffset; start < len; start += 188) {
if (data[start] === 0x47) {
stt = !!(data[start + 1] & 0x40); // pid is a 13-bit field starting at the last bit of TS[1]
pid = ((data[start + 1] & 0x1f) << 8) + data[start + 2];
atf = (data[start + 3] & 0x30) >> 4; // if an adaption field is present, its length is specified by the fifth byte of the TS packet header.
if (atf > 1) {
offset = start + 5 + data[start + 4]; // continue if there is only adaptation field
if (offset === start + 188) {
continue;
}
} else {
offset = start + 4;
}
switch (pid) {
case avcId:
if (stt) {
if (avcData && (pes = parsePES(avcData)) && pes.pts !== undefined) {
parseAVCPES(pes, false);
}
avcData = {
data: [],
size: 0
};
}
if (avcData) {
avcData.data.push(data.subarray(offset, start + 188));
avcData.size += start + 188 - offset;
}
break;
case audioId:
if (stt) {
if (audioData && (pes = parsePES(audioData)) && pes.pts !== undefined) {
if (audioTrack.isAAC) {
parseAACPES(pes);
} else {
parseMPEGPES(pes);
}
}
audioData = {
data: [],
size: 0
};
}
if (audioData) {
audioData.data.push(data.subarray(offset, start + 188));
audioData.size += start + 188 - offset;
}
break;
case id3Id:
if (stt) {
if (id3Data && (pes = parsePES(id3Data)) && pes.pts !== undefined) {
parseID3PES(pes);
}
id3Data = {
data: [],
size: 0
};
}
if (id3Data) {
id3Data.data.push(data.subarray(offset, start + 188));
id3Data.size += start + 188 - offset;
}
break;
case 0:
if (stt) {
offset += data[offset] + 1;
}
pmtId = this._pmtId = parsePAT(data, offset);
break;
case pmtId:
if (stt) {
offset += data[offset] + 1;
}
var parsedPIDs = parsePMT(data, offset, this.typeSupported.mpeg === true || this.typeSupported.mp3 === true, this.sampleAes != null); // only update track id if track PID found while parsing PMT
// this is to avoid resetting the PID to -1 in case
// track PID transiently disappears from the stream
// this could happen in case of transient missing audio samples for example
// NOTE this is only the PID of the track as found in TS,
// but we are not using this for MP4 track IDs.
avcId = parsedPIDs.avc;
if (avcId > 0) {
avcTrack.pid = avcId;
}
audioId = parsedPIDs.audio;
if (audioId > 0) {
audioTrack.pid = audioId;
audioTrack.isAAC = parsedPIDs.isAAC;
}
id3Id = parsedPIDs.id3;
if (id3Id > 0) {
id3Track.pid = id3Id;
}
if (unknownPIDs && !pmtParsed) {
logger["logger"].log('reparse from beginning');
unknownPIDs = false; // we set it to -188, the += 188 in the for loop will reset start to 0
start = syncOffset - 188;
}
pmtParsed = this.pmtParsed = true;
break;
case 17:
case 0x1fff:
break;
default:
unknownPIDs = true;
break;
}
} else {
this.observer.trigger(events["default"].ERROR, {
type: errors["ErrorTypes"].MEDIA_ERROR,
details: errors["ErrorDetails"].FRAG_PARSING_ERROR,
fatal: false,
reason: 'TS packet did not start with 0x47'
});
}
} // try to parse last PES packets
if (avcData && (pes = parsePES(avcData)) && pes.pts !== undefined) {
parseAVCPES(pes, true);
avcTrack.pesData = null;
} else {
// either avcData null or PES truncated, keep it for next frag parsing
avcTrack.pesData = avcData;
}
if (audioData && (pes = parsePES(audioData)) && pes.pts !== undefined) {
if (audioTrack.isAAC) {
parseAACPES(pes);
} else {
parseMPEGPES(pes);
}
audioTrack.pesData = null;
} else {
if (audioData && audioData.size) {
logger["logger"].log('last AAC PES packet truncated,might overlap between fragments');
} // either audioData null or PES truncated, keep it for next frag parsing
audioTrack.pesData = audioData;
}
if (id3Data && (pes = parsePES(id3Data)) && pes.pts !== undefined) {
parseID3PES(pes);
id3Track.pesData = null;
} else {
// either id3Data null or PES truncated, keep it for next frag parsing
id3Track.pesData = id3Data;
}
if (this.sampleAes == null) {
this.remuxer.remux(audioTrack, avcTrack, id3Track, this._txtTrack, timeOffset, contiguous, accurateTimeOffset);
} else {
this.decryptAndRemux(audioTrack, avcTrack, id3Track, this._txtTrack, timeOffset, contiguous, accurateTimeOffset);
}
};
_proto.decryptAndRemux = function decryptAndRemux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, contiguous, accurateTimeOffset) {
if (audioTrack.samples && audioTrack.isAAC) {
var localthis = this;
this.sampleAes.decryptAacSamples(audioTrack.samples, 0, function () {
localthis.decryptAndRemuxAvc(audioTrack, videoTrack, id3Track, textTrack, timeOffset, contiguous, accurateTimeOffset);
});
} else {
this.decryptAndRemuxAvc(audioTrack, videoTrack, id3Track, textTrack, timeOffset, contiguous, accurateTimeOffset);
}
};
_proto.decryptAndRemuxAvc = function decryptAndRemuxAvc(audioTrack, videoTrack, id3Track, textTrack, timeOffset, contiguous, accurateTimeOffset) {
if (videoTrack.samples) {
var localthis = this;
this.sampleAes.decryptAvcSamples(videoTrack.samples, 0, 0, function () {
localthis.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, contiguous, accurateTimeOffset);
});
} else {
this.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, contiguous, accurateTimeOffset);
}
};
_proto.destroy = function destroy() {
this._initPTS = this._initDTS = undefined;
this._duration = 0;
};
_proto._parsePAT = function _parsePAT(data, offset) {
// skip the PSI header and parse the first PMT entry
return (data[offset + 10] & 0x1F) << 8 | data[offset + 11]; // logger.log('PMT PID:' + this._pmtId);
};
_proto._parsePMT = function _parsePMT(data, offset, mpegSupported, isSampleAes) {
var sectionLength,
tableEnd,
programInfoLength,
pid,
result = {
audio: -1,
avc: -1,
id3: -1,
isAAC: true
};
sectionLength = (data[offset + 1] & 0x0f) << 8 | data[offset + 2];
tableEnd = offset + 3 + sectionLength - 4; // to determine where the table is, we have to figure out how
// long the program info descriptors are
programInfoLength = (data[offset + 10] & 0x0f) << 8 | data[offset + 11]; // advance the offset to the first entry in the mapping table
offset += 12 + programInfoLength;
while (offset < tableEnd) {
pid = (data[offset + 1] & 0x1F) << 8 | data[offset + 2];
switch (data[offset]) {
case 0xcf:
// SAMPLE-AES AAC
if (!isSampleAes) {
logger["logger"].log('unknown stream type:' + data[offset]);
break;
}
/* falls through */
// ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio)
case 0x0f:
// logger.log('AAC PID:' + pid);
if (result.audio === -1) {
result.audio = pid;
}
break;
// Packetized metadata (ID3)
case 0x15:
// logger.log('ID3 PID:' + pid);
if (result.id3 === -1) {
result.id3 = pid;
}
break;
case 0xdb:
// SAMPLE-AES AVC
if (!isSampleAes) {
logger["logger"].log('unknown stream type:' + data[offset]);
break;
}
/* falls through */
// ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video)
case 0x1b:
// logger.log('AVC PID:' + pid);
if (result.avc === -1) {
result.avc = pid;
}
break;
// ISO/IEC 11172-3 (MPEG-1 audio)
// or ISO/IEC 13818-3 (MPEG-2 halved sample rate audio)
case 0x03:
case 0x04:
// logger.log('MPEG PID:' + pid);
if (!mpegSupported) {
logger["logger"].log('MPEG audio found, not supported in this browser for now');
} else if (result.audio === -1) {
result.audio = pid;
result.isAAC = false;
}
break;
case 0x24:
logger["logger"].warn('HEVC stream type found, not supported for now');
break;
default:
logger["logger"].log('unknown stream type:' + data[offset]);
break;
} // move to the next table entry
// skip past the elementary stream descriptors, if present
offset += ((data[offset + 3] & 0x0F) << 8 | data[offset + 4]) + 5;
}
return result;
};
_proto._parsePES = function _parsePES(stream) {
var i = 0,
frag,
pesFlags,
pesPrefix,
pesLen,
pesHdrLen,
pesData,
pesPts,
pesDts,
payloadStartOffset,
data = stream.data; // safety check
if (!stream || stream.size === 0) {
return null;
} // we might need up to 19 bytes to read PES header
// if first chunk of data is less than 19 bytes, let's merge it with following ones until we get 19 bytes
// usually only one merge is needed (and this is rare ...)
while (data[0].length < 19 && data.length > 1) {
var newData = new Uint8Array(data[0].length + data[1].length);
newData.set(data[0]);
newData.set(data[1], data[0].length);
data[0] = newData;
data.splice(1, 1);
} // retrieve PTS/DTS from first fragment
frag = data[0];
pesPrefix = (frag[0] << 16) + (frag[1] << 8) + frag[2];
if (pesPrefix === 1) {
pesLen = (frag[4] << 8) + frag[5]; // if PES parsed length is not zero and greater than total received length, stop parsing. PES might be truncated
// minus 6 : PES header size
if (pesLen && pesLen > stream.size - 6) {
return null;
}
pesFlags = frag[7];
if (pesFlags & 0xC0) {
/* PES header described here : http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
as PTS / DTS is 33 bit we cannot use bitwise operator in JS,
as Bitwise operators treat their operands as a sequence of 32 bits */
pesPts = (frag[9] & 0x0E) * 536870912 + // 1 << 29
(frag[10] & 0xFF) * 4194304 + // 1 << 22
(frag[11] & 0xFE) * 16384 + // 1 << 14
(frag[12] & 0xFF) * 128 + // 1 << 7
(frag[13] & 0xFE) / 2; // check if greater than 2^32 -1
if (pesPts > 4294967295) {
// decrement 2^33
pesPts -= 8589934592;
}
if (pesFlags & 0x40) {
pesDts = (frag[14] & 0x0E) * 536870912 + // 1 << 29
(frag[15] & 0xFF) * 4194304 + // 1 << 22
(frag[16] & 0xFE) * 16384 + // 1 << 14
(frag[17] & 0xFF) * 128 + // 1 << 7
(frag[18] & 0xFE) / 2; // check if greater than 2^32 -1
if (pesDts > 4294967295) {
// decrement 2^33
pesDts -= 8589934592;
}
if (pesPts - pesDts > 60 * 90000) {
logger["logger"].warn(Math.round((pesPts - pesDts) / 90000) + "s delta between PTS and DTS, align them");
pesPts = pesDts;
}
} else {
pesDts = pesPts;
}
}
pesHdrLen = frag[8]; // 9 bytes : 6 bytes for PES header + 3 bytes for PES extension
payloadStartOffset = pesHdrLen + 9;
if (stream.size <= payloadStartOffset) {
return null;
}
stream.size -= payloadStartOffset; // reassemble PES packet
pesData = new Uint8Array(stream.size);
for (var j = 0, dataLen = data.length; j < dataLen; j++) {
frag = data[j];
var len = frag.byteLength;
if (payloadStartOffset) {
if (payloadStartOffset > len) {
// trim full frag if PES header bigger than frag
payloadStartOffset -= len;
continue;
} else {
// trim partial frag if PES header smaller than frag
frag = frag.subarray(payloadStartOffset);
len -= payloadStartOffset;
payloadStartOffset = 0;
}
}
pesData.set(frag, i);
i += len;
}
if (pesLen) {
// payload size : remove PES header + PES extension
pesLen -= pesHdrLen + 3;
}
return {
data: pesData,
pts: pesPts,
dts: pesDts,
len: pesLen
};
} else {
return null;
}
};
_proto.pushAccesUnit = function pushAccesUnit(avcSample, avcTrack) {
if (avcSample.units.length && avcSample.frame) {
var samples = avcTrack.samples;
var nbSamples = samples.length; // only push AVC sample if starting with a keyframe is not mandatory OR
// if keyframe already found in this fragment OR
// keyframe found in last fragment (track.sps) AND
// samples already appended (we already found a keyframe in this fragment) OR fragment is contiguous
if (!this.config.forceKeyFrameOnDiscontinuity || avcSample.key === true || avcTrack.sps && (nbSamples || this.contiguous)) {
avcSample.id = nbSamples;
samples.push(avcSample);
} else {
// dropped samples, track it
avcTrack.dropped++;
}
}
if (avcSample.debug.length) {
logger["logger"].log(avcSample.pts + '/' + avcSample.dts + ':' + avcSample.debug);
}
};
_proto._parseAVCPES = function _parseAVCPES(pes, last) {
var _this = this;
// logger.log('parse new PES');
var track = this._avcTrack,
units = this._parseAVCNALu(pes.data),
debug = false,
expGolombDecoder,
avcSample = this.avcSample,
push,
spsfound = false,
i,
pushAccesUnit = this.pushAccesUnit.bind(this),
createAVCSample = function createAVCSample(key, pts, dts, debug) {
return {
key: key,
pts: pts,
dts: dts,
units: [],
debug: debug
};
}; // free pes.data to save up some memory
pes.data = null; // if new NAL units found and last sample still there, let's push ...
// this helps parsing streams with missing AUD (only do this if AUD never found)
if (avcSample && units.length && !track.audFound) {
pushAccesUnit(avcSample, track);
avcSample = this.avcSample = createAVCSample(false, pes.pts, pes.dts, '');
}
units.forEach(function (unit) {
switch (unit.type) {
// NDR
case 1:
push = true;
if (!avcSample) {
avcSample = _this.avcSample = createAVCSample(true, pes.pts, pes.dts, '');
}
if (debug) {
avcSample.debug += 'NDR ';
}
avcSample.frame = true;
var data = unit.data; // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
if (spsfound && data.length > 4) {
// retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
var sliceType = new exp_golomb(data).readSliceType(); // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
// SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
// An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
// I slice: A slice that is not an SI slice that is decoded using intra prediction only.
// if (sliceType === 2 || sliceType === 7) {
if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
avcSample.key = true;
}
}
break;
// IDR
case 5: