From ba5e06f5b4629b10e94240e97d785a1e9c313204 Mon Sep 17 00:00:00 2001 From: Samir Date: Thu, 13 May 2021 15:32:25 +0600 Subject: [PATCH] readme file updated --- README.md | 1 + dist/jmuxer.js | 95 +- dist/jmuxer.min.js | 2734 +---------------------------------------- example/jmuxer.min.js | 2734 +---------------------------------------- 4 files changed, 58 insertions(+), 5506 deletions(-) diff --git a/README.md b/README.md index 1e1619e..113164f 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,7 @@ h264_feeder.pipe(jmuxer.createStream()).pipe(http_or_ws_or_any); | ------------- |:-------------:| -----:| | feed | data object | object properites may have audio, video and duration. At least one media property i.e audio or video must be provided. If no duration is provided, it will calculate duration based on fps value | | createStream | - | Get a writeable stream to feed buffer. Available on NodeJS only | +| reset | - | Reset the jmuxer and start over | | destroy | - | Destroy the jmuxer instance and release the resources | **Typescript definition** diff --git a/dist/jmuxer.js b/dist/jmuxer.js index 5fd3630..c3513a7 100644 --- a/dist/jmuxer.js +++ b/dist/jmuxer.js @@ -870,7 +870,6 @@ this.remuxer = remuxer; this.track = remuxer.mp4track; - this.isSafari = remuxer.env == 'browser' && /Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor); } _createClass(H264Parser, [{ @@ -931,10 +930,7 @@ } } - if (!this.isSafari) { - push = true; - } - + push = true; break; case NALU.AUD: @@ -1651,7 +1647,7 @@ var _super = _createSuper(AACRemuxer); - function AACRemuxer(timescale, env) { + function AACRemuxer(timescale) { var _this; _classCallCheck(this, AACRemuxer); @@ -1660,7 +1656,6 @@ _this.readyToDecode = false; _this.nextDts = 0; _this.dts = 0; - _this.env = env; _this.mp4track = { id: BaseRemuxer.getTrackID(), type: 'audio', @@ -1686,6 +1681,8 @@ this.mp4track.channelCount = ''; this.mp4track.config = ''; this.mp4track.timescale = this.timescale; + this.nextDts = 0; + this.dts = 0; } }, { key: "remux", @@ -1763,7 +1760,7 @@ var _super = _createSuper(H264Remuxer); - function H264Remuxer(timescale, env) { + function H264Remuxer(timescale) { var _this; _classCallCheck(this, H264Remuxer); @@ -1772,7 +1769,6 @@ _this.readyToDecode = false; _this.nextDts = 0; _this.dts = 0; - _this.env = env; _this.mp4track = { id: BaseRemuxer.getTrackID(), type: 'video', @@ -1797,6 +1793,8 @@ this.readyToDecode = false; this.mp4track.sps = ''; this.mp4track.pps = ''; + this.nextDts = 0; + this.dts = 0; } }, { key: "remux", @@ -1934,12 +1932,12 @@ key: "addTrack", value: function addTrack(type) { if (type === 'video' || type === 'both') { - this.tracks.video = new H264Remuxer(this.timescale, this.env); + this.tracks.video = new H264Remuxer(this.timescale); this.trackTypes.push('video'); } if (type === 'audio' || type === 'both') { - this.tracks.audio = new AACRemuxer(this.timescale, this.env); + this.tracks.audio = new AACRemuxer(this.timescale); this.trackTypes.push('audio'); } } @@ -2308,7 +2306,6 @@ this.node = typeof this.options.node === 'string' ? document.getElementById(this.options.node) : this.options.node; this.mseReady = false; this.setupMSE(); - this.sourceBuffers = {}; } }, { key: "createStream", @@ -2340,12 +2337,26 @@ this.isMSESupported = !!window.MediaSource; this.mediaSource = new MediaSource(); - this.node.src = URL.createObjectURL(this.mediaSource); + this.url = URL.createObjectURL(this.mediaSource); + this.node.src = this.url; + this.mseEnded = false; this.mediaSource.addEventListener('sourceopen', this.onMSEOpen.bind(this)); this.mediaSource.addEventListener('sourceclose', this.onMSEClose.bind(this)); this.mediaSource.addEventListener('webkitsourceopen', this.onMSEOpen.bind(this)); this.mediaSource.addEventListener('webkitsourceclose', this.onMSEClose.bind(this)); } + }, { + key: "endMSE", + value: function endMSE() { + if (!this.mseEnded) { + try { + this.mseEnded = true; + this.mediaSource.endOfStream(); + } catch (e) { + error('mediasource is not available to end'); + } + } + } }, { key: "feed", value: function feed(data) { @@ -2523,18 +2534,6 @@ value: function destroy() { this.stopInterval(); - if (this.mediaSource) { - try { - if (this.bufferControllers) { - this.mediaSource.endOfStream(); - } - } catch (e) { - error("mediasource is not available to end ".concat(e.message)); - } - - this.mediaSource = null; - } - if (this.stream) { this.remuxController.flush(); this.stream.push(null); @@ -2552,11 +2551,37 @@ } this.bufferControllers = null; + this.endMSE(); } this.node = false; this.mseReady = false; this.videoStarted = false; + this.mediaSource = null; + } + }, { + key: "reset", + value: function reset() { + this.node.pause(); + + if (this.remuxController) { + this.remuxController.reset(); + } + + if (this.bufferControllers) { + for (var type in this.bufferControllers) { + this.bufferControllers[type].destroy(); + } + + this.bufferControllers = null; + this.endMSE(); + } + + if (this.env == 'browser') { + this.initBrowser(); + } + + log('JMuxer was reset'); } }, { key: "createBuffer", @@ -2574,7 +2599,6 @@ var sb = this.mediaSource.addSourceBuffer("".concat(type, "/mp4; codecs=\"").concat(track.mp4track.codec, "\"")); this.bufferControllers[type] = new BufferController(sb, type); - this.sourceBuffers[type] = sb; this.bufferControllers[type].on('error', this.onBufferError.bind(this)); } } @@ -2665,6 +2689,7 @@ this.options.onReady.call(null); } + URL.revokeObjectURL(this.url); this.createBuffer(); } }, { @@ -2676,25 +2701,15 @@ }, { key: "onBufferError", value: function onBufferError(data) { - if (typeof this.options.onError === 'function') { - this.options.onError.call(null, data); - } - if (data.name == 'QuotaExceeded') { this.bufferControllers[data.type].initCleanup(this.node.currentTime); return; + } else { + this.endMSE(); } - if (this.mediaSource.sourceBuffers.length > 0 && this.sourceBuffers[data.type]) { - this.mediaSource.removeSourceBuffer(this.sourceBuffers[data.type]); - } - - if (this.mediaSource.sourceBuffers.length == 0) { - try { - this.mediaSource.endOfStream(); - } catch (e) { - error('mediasource is not available to end'); - } + if (typeof this.options.onError === 'function') { + this.options.onError.call(null, data); } } }]); diff --git a/dist/jmuxer.min.js b/dist/jmuxer.min.js index 3e6d156..eeff9e4 100644 --- a/dist/jmuxer.min.js +++ b/dist/jmuxer.min.js @@ -1,2733 +1 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('stream')) : - typeof define === 'function' && define.amd ? define(['stream'], factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.JMuxer = factory(global.stream)); -}(this, (function (stream) { 'use strict'; - - function _typeof(obj) { - "@babel/helpers - typeof"; - - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); - } - - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - } - - 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, descriptor.key, descriptor); - } - } - - function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; - } - - function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; - } - - function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - writable: true, - configurable: true - } - }); - if (superClass) _setPrototypeOf(subClass, superClass); - } - - function _getPrototypeOf(o) { - _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { - return o.__proto__ || Object.getPrototypeOf(o); - }; - return _getPrototypeOf(o); - } - - function _setPrototypeOf(o, p) { - _setPrototypeOf = Object.setPrototypeOf || 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 { - Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); - return true; - } catch (e) { - return false; - } - } - - function _assertThisInitialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return self; - } - - function _possibleConstructorReturn(self, call) { - if (call && (typeof call === "object" || typeof call === "function")) { - return call; - } - - return _assertThisInitialized(self); - } - - function _createSuper(Derived) { - var hasNativeReflectConstruct = _isNativeReflectConstruct(); - - return function _createSuperInternal() { - var Super = _getPrototypeOf(Derived), - result; - - if (hasNativeReflectConstruct) { - var NewTarget = _getPrototypeOf(this).constructor; - - result = Reflect.construct(Super, arguments, NewTarget); - } else { - result = Super.apply(this, arguments); - } - - return _possibleConstructorReturn(this, result); - }; - } - - function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); - } - - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; - } - - function _iterableToArrayLimit(arr, i) { - if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - function _unsupportedIterableToArray(o, minLen) { - if (!o) return; - if (typeof o === "string") return _arrayLikeToArray(o, minLen); - var n = Object.prototype.toString.call(o).slice(8, -1); - if (n === "Object" && o.constructor) n = o.constructor.name; - if (n === "Map" || n === "Set") return Array.from(o); - if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); - } - - function _arrayLikeToArray(arr, len) { - if (len == null || len > arr.length) len = arr.length; - - for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; - - return arr2; - } - - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); - } - - function _createForOfIteratorHelper(o, allowArrayLike) { - var it; - - if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { - if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { - if (it) o = it; - var i = 0; - - var F = function () {}; - - return { - s: F, - n: function () { - if (i >= o.length) return { - done: true - }; - return { - done: false, - value: o[i++] - }; - }, - e: function (e) { - throw e; - }, - f: F - }; - } - - throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); - } - - var normalCompletion = true, - didErr = false, - err; - return { - s: function () { - it = o[Symbol.iterator](); - }, - n: function () { - var step = it.next(); - normalCompletion = step.done; - return step; - }, - e: function (e) { - didErr = true; - err = e; - }, - f: function () { - try { - if (!normalCompletion && it.return != null) it.return(); - } finally { - if (didErr) throw err; - } - } - }; - } - - var logger; - var errorLogger; - function setLogger() { - /*eslint-disable */ - logger = console.log; - errorLogger = console.error; - /*eslint-enable */ - } - function log(message) { - if (logger) { - for (var _len = arguments.length, optionalParams = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - optionalParams[_key - 1] = arguments[_key]; - } - - logger.apply(void 0, [message].concat(optionalParams)); - } - } - function error(message) { - if (errorLogger) { - for (var _len2 = arguments.length, optionalParams = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { - optionalParams[_key2 - 1] = arguments[_key2]; - } - - errorLogger.apply(void 0, [message].concat(optionalParams)); - } - } - - var NALU = /*#__PURE__*/function () { - _createClass(NALU, null, [{ - key: "type", - value: function type(nalu) { - if (nalu.ntype in NALU.TYPES) { - return NALU.TYPES[nalu.ntype]; - } else { - return 'UNKNOWN'; - } - } - }, { - key: "NDR", - get: function get() { - return 1; - } - }, { - key: "IDR", - get: function get() { - return 5; - } - }, { - key: "SEI", - get: function get() { - return 6; - } - }, { - key: "SPS", - get: function get() { - return 7; - } - }, { - key: "PPS", - get: function get() { - return 8; - } - }, { - key: "AUD", - get: function get() { - return 9; - } - }, { - key: "TYPES", - get: function get() { - var _ref; - - return _ref = {}, _defineProperty(_ref, NALU.IDR, 'IDR'), _defineProperty(_ref, NALU.SEI, 'SEI'), _defineProperty(_ref, NALU.SPS, 'SPS'), _defineProperty(_ref, NALU.PPS, 'PPS'), _defineProperty(_ref, NALU.NDR, 'NDR'), _defineProperty(_ref, NALU.AUD, 'AUD'), _ref; - } - }]); - - function NALU(data) { - _classCallCheck(this, NALU); - - this.payload = data; - this.nri = (this.payload[0] & 0x60) >> 5; // nal_ref_idc - - this.ntype = this.payload[0] & 0x1f; - this.isvcl = this.ntype == 1 || this.ntype == 5; - this.stype = ''; // slice_type - - this.isfmb = false; // first_mb_in_slice - } - - _createClass(NALU, [{ - key: "toString", - value: function toString() { - return "".concat(NALU.type(this), ": NRI: ").concat(this.getNri()); - } - }, { - key: "getNri", - value: function getNri() { - return this.nri; - } - }, { - key: "type", - value: function type() { - return this.ntype; - } - }, { - key: "isKeyframe", - value: function isKeyframe() { - return this.ntype === NALU.IDR; - } - }, { - key: "getPayload", - value: function getPayload() { - return this.payload; - } - }, { - key: "getPayloadSize", - value: function getPayloadSize() { - return this.payload.byteLength; - } - }, { - key: "getSize", - value: function getSize() { - return 4 + this.getPayloadSize(); - } - }, { - key: "getData", - value: function getData() { - var result = new Uint8Array(this.getSize()); - var view = new DataView(result.buffer); - view.setUint32(0, this.getSize() - 4); - result.set(this.getPayload(), 4); - return result; - } - }]); - - return NALU; - }(); - - function appendByteArray(buffer1, buffer2) { - var tmp = new Uint8Array((buffer1.byteLength | 0) + (buffer2.byteLength | 0)); - tmp.set(buffer1, 0); - tmp.set(buffer2, buffer1.byteLength | 0); - return tmp; - } - function secToTime(sec) { - var seconds, - hours, - minutes, - result = ''; - seconds = Math.floor(sec); - hours = parseInt(seconds / 3600, 10) % 24; - minutes = parseInt(seconds / 60, 10) % 60; - seconds = seconds < 0 ? 0 : seconds % 60; - - if (hours > 0) { - result += (hours < 10 ? '0' + hours : hours) + ':'; - } - - result += (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds); - return result; - } - - /** - * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264. - */ - var ExpGolomb = /*#__PURE__*/function () { - function ExpGolomb(data) { - _classCallCheck(this, ExpGolomb); - - this.data = data; - this.index = 0; - this.bitLength = data.byteLength * 8; - } - - _createClass(ExpGolomb, [{ - key: "skipBits", - value: function skipBits(size) { - // console.log(` skip bits: size=${size}, ${this.index}.`); - if (this.bitsAvailable < size) { - //throw new Error('no bytes available'); - return false; - } - - this.index += size; - } - }, { - key: "readBits", - value: function readBits(size) { - var moveIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - // console.log(` read bits: size=${size}, ${this.index}.`); - var result = this.getBits(size, this.index, moveIndex); // console.log(` read bits: result=${result}`); - - return result; - } - }, { - key: "getBits", - value: function getBits(size, offsetBits) { - var moveIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; - - if (this.bitsAvailable < size) { - //throw new Error('no bytes available'); - return 0; - } - - var offset = offsetBits % 8; - - var _byte = this.data[offsetBits / 8 | 0] & 0xff >>> offset; - - var bits = 8 - offset; - - if (bits >= size) { - if (moveIndex) { - this.index += size; - } - - return _byte >> bits - size; - } else { - if (moveIndex) { - this.index += bits; - } - - var nextSize = size - bits; - return _byte << nextSize | this.getBits(nextSize, offsetBits + bits, moveIndex); - } - } - }, { - key: "skipLZ", - value: function skipLZ() { - var leadingZeroCount; - - for (leadingZeroCount = 0; leadingZeroCount < this.bitLength - this.index; ++leadingZeroCount) { - if (this.getBits(1, this.index + leadingZeroCount, false) !== 0) { - // console.log(` skip LZ : size=${leadingZeroCount}, ${this.index}.`); - this.index += leadingZeroCount; - return leadingZeroCount; - } - } - - return leadingZeroCount; - } - }, { - key: "skipUEG", - value: function skipUEG() { - this.skipBits(1 + this.skipLZ()); - } - }, { - key: "skipEG", - value: function skipEG() { - this.skipBits(1 + this.skipLZ()); - } - }, { - key: "readUEG", - value: function readUEG() { - var prefix = this.skipLZ(); - return this.readBits(prefix + 1) - 1; - } - }, { - key: "readEG", - value: function readEG() { - var value = this.readUEG(); - - if (0x01 & value) { - // the number is odd if the low order bit is set - return 1 + value >>> 1; // add 1 to make it even, and divide by 2 - } else { - return -1 * (value >>> 1); // divide by two then make it negative - } - } - }, { - key: "readBoolean", - value: function readBoolean() { - return this.readBits(1) === 1; - } - }, { - key: "readUByte", - value: function readUByte() { - var numberOfBytes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; - return this.readBits(numberOfBytes * 8); - } - }, { - key: "readUShort", - value: function readUShort() { - return this.readBits(16); - } - }, { - key: "readUInt", - value: function readUInt() { - return this.readBits(32); - } - }, { - key: "bitsAvailable", - get: function get() { - return this.bitLength - this.index; - } - }]); - - return ExpGolomb; - }(); - - var H264Parser = /*#__PURE__*/function () { - _createClass(H264Parser, null, [{ - key: "extractNALu", - value: function extractNALu(buffer) { - var i = 0, - length = buffer.byteLength, - value, - state = 0, - result = [], - left, - lastIndex = 0; - - while (i < length) { - value = buffer[i++]; // finding 3 or 4-byte start codes (00 00 01 OR 00 00 00 01) - - switch (state) { - case 0: - if (value === 0) { - state = 1; - } - - break; - - case 1: - if (value === 0) { - state = 2; - } else { - state = 0; - } - - break; - - case 2: - case 3: - if (value === 0) { - state = 3; - } else if (value === 1 && i < length) { - if (lastIndex != i - state - 1) { - result.push(buffer.subarray(lastIndex, i - state - 1)); - } - - lastIndex = i; - state = 0; - } else { - state = 0; - } - - break; - } - } - - if (lastIndex < length) { - left = buffer.subarray(lastIndex, length); - } - - return [result, left]; - } - /** - * 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 decoder {ExpGolomb} exp golomb decoder - * @param count {number} the number of entries in this scaling list - * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1 - */ - - }, { - key: "skipScalingList", - value: function skipScalingList(decoder, count) { - var lastScale = 8, - nextScale = 8, - deltaScale; - - for (var j = 0; j < count; j++) { - if (nextScale !== 0) { - deltaScale = decoder.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. - */ - - }, { - key: "readSPS", - value: function readSPS(data) { - var decoder = new ExpGolomb(data); - var frameCropLeftOffset = 0, - frameCropRightOffset = 0, - frameCropTopOffset = 0, - frameCropBottomOffset = 0, - sarScale = 1, - profileIdc, - profileCompat, - levelIdc, - numRefFramesInPicOrderCntCycle, - picWidthInMbsMinus1, - picHeightInMapUnitsMinus1, - frameMbsOnlyFlag, - scalingListCount; - decoder.readUByte(); - profileIdc = decoder.readUByte(); // profile_idc - - profileCompat = decoder.readBits(5); // constraint_set[0-4]_flag, u(5) - - decoder.skipBits(3); // reserved_zero_3bits u(3), - - levelIdc = decoder.readUByte(); // level_idc u(8) - - decoder.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 = decoder.readUEG(); - - if (chromaFormatIdc === 3) { - decoder.skipBits(1); // separate_colour_plane_flag - } - - decoder.skipUEG(); // bit_depth_luma_minus8 - - decoder.skipUEG(); // bit_depth_chroma_minus8 - - decoder.skipBits(1); // qpprime_y_zero_transform_bypass_flag - - if (decoder.readBoolean()) { - // seq_scaling_matrix_present_flag - scalingListCount = chromaFormatIdc !== 3 ? 8 : 12; - - for (var i = 0; i < scalingListCount; ++i) { - if (decoder.readBoolean()) { - // seq_scaling_list_present_flag[ i ] - if (i < 6) { - H264Parser.skipScalingList(decoder, 16); - } else { - H264Parser.skipScalingList(decoder, 64); - } - } - } - } - } - - decoder.skipUEG(); // log2_max_frame_num_minus4 - - var picOrderCntType = decoder.readUEG(); - - if (picOrderCntType === 0) { - decoder.readUEG(); // log2_max_pic_order_cnt_lsb_minus4 - } else if (picOrderCntType === 1) { - decoder.skipBits(1); // delta_pic_order_always_zero_flag - - decoder.skipEG(); // offset_for_non_ref_pic - - decoder.skipEG(); // offset_for_top_to_bottom_field - - numRefFramesInPicOrderCntCycle = decoder.readUEG(); - - for (var _i = 0; _i < numRefFramesInPicOrderCntCycle; ++_i) { - decoder.skipEG(); // offset_for_ref_frame[ i ] - } - } - - decoder.skipUEG(); // max_num_ref_frames - - decoder.skipBits(1); // gaps_in_frame_num_value_allowed_flag - - picWidthInMbsMinus1 = decoder.readUEG(); - picHeightInMapUnitsMinus1 = decoder.readUEG(); - frameMbsOnlyFlag = decoder.readBits(1); - - if (frameMbsOnlyFlag === 0) { - decoder.skipBits(1); // mb_adaptive_frame_field_flag - } - - decoder.skipBits(1); // direct_8x8_inference_flag - - if (decoder.readBoolean()) { - // frame_cropping_flag - frameCropLeftOffset = decoder.readUEG(); - frameCropRightOffset = decoder.readUEG(); - frameCropTopOffset = decoder.readUEG(); - frameCropBottomOffset = decoder.readUEG(); - } - - if (decoder.readBoolean()) { - // vui_parameters_present_flag - if (decoder.readBoolean()) { - // aspect_ratio_info_present_flag - var sarRatio; - var aspectRatioIdc = decoder.readUByte(); - - switch (aspectRatioIdc) { - case 1: - sarRatio = [1, 1]; - break; - - case 2: - sarRatio = [12, 11]; - break; - - case 3: - sarRatio = [10, 11]; - break; - - case 4: - sarRatio = [16, 11]; - break; - - case 5: - sarRatio = [40, 33]; - break; - - case 6: - sarRatio = [24, 11]; - break; - - case 7: - sarRatio = [20, 11]; - break; - - case 8: - sarRatio = [32, 11]; - break; - - case 9: - sarRatio = [80, 33]; - break; - - case 10: - sarRatio = [18, 11]; - break; - - case 11: - sarRatio = [15, 11]; - break; - - case 12: - sarRatio = [64, 33]; - break; - - case 13: - sarRatio = [160, 99]; - break; - - case 14: - sarRatio = [4, 3]; - break; - - case 15: - sarRatio = [3, 2]; - break; - - case 16: - sarRatio = [2, 1]; - break; - - case 255: - { - sarRatio = [decoder.readUByte() << 8 | decoder.readUByte(), decoder.readUByte() << 8 | decoder.readUByte()]; - break; - } - } - - if (sarRatio) { - sarScale = sarRatio[0] / sarRatio[1]; - } - } - - if (decoder.readBoolean()) { - decoder.skipBits(1); - } - - if (decoder.readBoolean()) { - decoder.skipBits(4); - - if (decoder.readBoolean()) { - decoder.skipBits(24); - } - } - - if (decoder.readBoolean()) { - decoder.skipUEG(); - decoder.skipUEG(); - } - - if (decoder.readBoolean()) { - var unitsInTick = decoder.readUInt(); - var timeScale = decoder.readUInt(); - var fixedFrameRate = decoder.readBoolean(); - } - } - - return { - width: Math.ceil(((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale), - height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset) - }; - } - }, { - key: "parseHeader", - value: function parseHeader(unit) { - var decoder = new ExpGolomb(unit.getPayload()); // skip NALu type - - decoder.readUByte(); - unit.isfmb = decoder.readUEG() === 0; - unit.stype = decoder.readUEG(); - } - }]); - - function H264Parser(remuxer) { - _classCallCheck(this, H264Parser); - - this.remuxer = remuxer; - this.track = remuxer.mp4track; - } - - _createClass(H264Parser, [{ - key: "parseSPS", - value: function parseSPS(sps) { - var config = H264Parser.readSPS(new Uint8Array(sps)); - this.track.width = config.width; - this.track.height = config.height; - this.track.sps = [new Uint8Array(sps)]; - this.track.codec = 'avc1.'; - var codecarray = new DataView(sps.buffer, sps.byteOffset + 1, 4); - - for (var i = 0; i < 3; ++i) { - var h = codecarray.getUint8(i).toString(16); - - if (h.length < 2) { - h = '0' + h; - } - - this.track.codec += h; - } - } - }, { - key: "parsePPS", - value: function parsePPS(pps) { - this.track.pps = [new Uint8Array(pps)]; - } - }, { - key: "parseNAL", - value: function parseNAL(unit) { - if (!unit) return false; - var push = false; - - switch (unit.type()) { - case NALU.IDR: - case NALU.NDR: - push = true; - break; - - case NALU.PPS: - if (!this.track.pps) { - this.parsePPS(unit.getPayload()); - - if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) { - this.remuxer.readyToDecode = true; - } - } - - push = true; - break; - - case NALU.SPS: - if (!this.track.sps) { - this.parseSPS(unit.getPayload()); - - if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) { - this.remuxer.readyToDecode = true; - } - } - - push = true; - break; - - case NALU.AUD: - log('AUD - ignoing'); - break; - - case NALU.SEI: - log('SEI - ignoing'); - break; - } - - return push; - } - }]); - - return H264Parser; - }(); - - var aacHeader; - var AACParser = /*#__PURE__*/function () { - _createClass(AACParser, null, [{ - key: "getHeaderLength", - value: function getHeaderLength(data) { - return data[1] & 0x01 ? 7 : 9; // without CRC 7 and with CRC 9 Refs: https://wiki.multimedia.cx/index.php?title=ADTS - } - }, { - key: "getFrameLength", - value: function getFrameLength(data) { - return (data[3] & 0x03) << 11 | data[4] << 3 | (data[5] & 0xE0) >>> 5; // 13 bits length ref: https://wiki.multimedia.cx/index.php?title=ADTS - } - }, { - key: "isAACPattern", - value: function isAACPattern(data) { - return data[0] === 0xff && (data[1] & 0xf0) === 0xf0 && (data[1] & 0x06) === 0x00; - } - }, { - key: "extractAAC", - value: function extractAAC(buffer) { - var i = 0, - length = buffer.byteLength, - result = [], - headerLength, - frameLength; - - if (!AACParser.isAACPattern(buffer)) { - error('Invalid ADTS audio format'); - return result; - } - - headerLength = AACParser.getHeaderLength(buffer); - - if (!aacHeader) { - aacHeader = buffer.subarray(0, headerLength); - } - - while (i < length) { - frameLength = AACParser.getFrameLength(buffer); - result.push(buffer.subarray(headerLength, frameLength)); - buffer = buffer.slice(frameLength); - i += frameLength; - } - - return result; - } - }, { - key: "samplingRateMap", - get: function get() { - return [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350]; - } - }, { - key: "getAACHeaderData", - get: function get() { - return aacHeader; - } - }]); - - function AACParser(remuxer) { - _classCallCheck(this, AACParser); - - this.remuxer = remuxer; - this.track = remuxer.mp4track; - } - - _createClass(AACParser, [{ - key: "setAACConfig", - value: function setAACConfig() { - var objectType, - sampleIndex, - channelCount, - config = new Uint8Array(2), - headerData = AACParser.getAACHeaderData; - if (!headerData) return; - objectType = ((headerData[2] & 0xC0) >>> 6) + 1; - sampleIndex = (headerData[2] & 0x3C) >>> 2; - channelCount = (headerData[2] & 0x01) << 2; - channelCount |= (headerData[3] & 0xC0) >>> 6; - /* refer to http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config */ - - config[0] = objectType << 3; - config[0] |= (sampleIndex & 0x0E) >> 1; - config[1] |= (sampleIndex & 0x01) << 7; - config[1] |= channelCount << 3; - this.track.codec = 'mp4a.40.' + objectType; - this.track.channelCount = channelCount; - this.track.config = config; - this.remuxer.readyToDecode = true; - } - }]); - - return AACParser; - }(); - - var Event = /*#__PURE__*/function () { - function Event(type) { - _classCallCheck(this, Event); - - this.listener = {}; - this.type = type | ''; - } - - _createClass(Event, [{ - key: "on", - value: function on(event, fn) { - if (!this.listener[event]) { - this.listener[event] = []; - } - - this.listener[event].push(fn); - return true; - } - }, { - key: "off", - value: function off(event, fn) { - if (this.listener[event]) { - var index = this.listener[event].indexOf(fn); - - if (index > -1) { - this.listener[event].splice(index, 1); - } - - return true; - } - - return false; - } - }, { - key: "offAll", - value: function offAll() { - this.listener = {}; - } - }, { - key: "dispatch", - value: function dispatch(event, data) { - if (this.listener[event]) { - this.listener[event].map(function (each) { - each.apply(null, [data]); - }); - return true; - } - - return false; - } - }]); - - return Event; - }(); - - /** - * Generate MP4 Box - * taken from: https://github.com/dailymotion/hls.js - */ - var MP4 = /*#__PURE__*/function () { - function MP4() { - _classCallCheck(this, MP4); - } - - _createClass(MP4, null, [{ - key: "init", - value: function init() { - MP4.types = { - avc1: [], - // codingname - avcC: [], - btrt: [], - dinf: [], - dref: [], - esds: [], - ftyp: [], - hdlr: [], - mdat: [], - mdhd: [], - mdia: [], - mfhd: [], - minf: [], - moof: [], - moov: [], - mp4a: [], - mvex: [], - mvhd: [], - sdtp: [], - stbl: [], - stco: [], - stsc: [], - stsd: [], - stsz: [], - stts: [], - tfdt: [], - tfhd: [], - traf: [], - trak: [], - trun: [], - trex: [], - tkhd: [], - vmhd: [], - smhd: [] - }; - var i; - - for (i in MP4.types) { - if (MP4.types.hasOwnProperty(i)) { - MP4.types[i] = [i.charCodeAt(0), i.charCodeAt(1), i.charCodeAt(2), i.charCodeAt(3)]; - } - } - - var videoHdlr = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00, // pre_defined - 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide' - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler' - ]); - var audioHdlr = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00, // pre_defined - 0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun' - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler' - ]); - MP4.HDLR_TYPES = { - video: videoHdlr, - audio: audioHdlr - }; - var dref = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x01, // entry_count - 0x00, 0x00, 0x00, 0x0c, // entry_size - 0x75, 0x72, 0x6c, 0x20, // 'url' type - 0x00, // version 0 - 0x00, 0x00, 0x01 // entry_flags - ]); - var stco = new Uint8Array([0x00, // version - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00 // entry_count - ]); - MP4.STTS = MP4.STSC = MP4.STCO = stco; - MP4.STSZ = new Uint8Array([0x00, // version - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00, // sample_size - 0x00, 0x00, 0x00, 0x00 // sample_count - ]); - MP4.VMHD = new Uint8Array([0x00, // version - 0x00, 0x00, 0x01, // flags - 0x00, 0x00, // graphicsmode - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // opcolor - ]); - MP4.SMHD = new Uint8Array([0x00, // version - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, // balance - 0x00, 0x00 // reserved - ]); - MP4.STSD = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x01]); // entry_count - - var majorBrand = new Uint8Array([105, 115, 111, 109]); // isom - - var avc1Brand = new Uint8Array([97, 118, 99, 49]); // avc1 - - var minorVersion = new Uint8Array([0, 0, 0, 1]); - MP4.FTYP = MP4.box(MP4.types.ftyp, majorBrand, minorVersion, majorBrand, avc1Brand); - MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref)); - } - }, { - key: "box", - value: function box(type) { - for (var _len = arguments.length, payload = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - payload[_key - 1] = arguments[_key]; - } - - var size = 8, - i = payload.length, - len = i, - result; // calculate the total size we need to allocate - - while (i--) { - size += payload[i].byteLength; - } - - result = new Uint8Array(size); - result[0] = size >> 24 & 0xff; - result[1] = size >> 16 & 0xff; - result[2] = size >> 8 & 0xff; - result[3] = size & 0xff; - result.set(type, 4); // copy the payload into the result - - for (i = 0, size = 8; i < len; ++i) { - // copy payload[i] array @ offset size - result.set(payload[i], size); - size += payload[i].byteLength; - } - - return result; - } - }, { - key: "hdlr", - value: function hdlr(type) { - return MP4.box(MP4.types.hdlr, MP4.HDLR_TYPES[type]); - } - }, { - key: "mdat", - value: function mdat(data) { - return MP4.box(MP4.types.mdat, data); - } - }, { - key: "mdhd", - value: function mdhd(timescale, duration) { - return MP4.box(MP4.types.mdhd, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x02, // creation_time - 0x00, 0x00, 0x00, 0x03, // modification_time - timescale >> 24 & 0xFF, timescale >> 16 & 0xFF, timescale >> 8 & 0xFF, timescale & 0xFF, // timescale - duration >> 24, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration - 0x55, 0xc4, // 'und' language (undetermined) - 0x00, 0x00])); - } - }, { - key: "mdia", - value: function mdia(track) { - return MP4.box(MP4.types.mdia, MP4.mdhd(track.timescale, track.duration), MP4.hdlr(track.type), MP4.minf(track)); - } - }, { - key: "mfhd", - value: function mfhd(sequenceNumber) { - return MP4.box(MP4.types.mfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // flags - sequenceNumber >> 24, sequenceNumber >> 16 & 0xFF, sequenceNumber >> 8 & 0xFF, sequenceNumber & 0xFF // sequence_number - ])); - } - }, { - key: "minf", - value: function minf(track) { - if (track.type === 'audio') { - return MP4.box(MP4.types.minf, MP4.box(MP4.types.smhd, MP4.SMHD), MP4.DINF, MP4.stbl(track)); - } else { - return MP4.box(MP4.types.minf, MP4.box(MP4.types.vmhd, MP4.VMHD), MP4.DINF, MP4.stbl(track)); - } - } - }, { - key: "moof", - value: function moof(sn, baseMediaDecodeTime, track) { - return MP4.box(MP4.types.moof, MP4.mfhd(sn), MP4.traf(track, baseMediaDecodeTime)); - } - /** - * @param tracks... (optional) {array} the tracks associated with this movie - */ - - }, { - key: "moov", - value: function moov(tracks, duration, timescale) { - var i = tracks.length, - boxes = []; - - while (i--) { - boxes[i] = MP4.trak(tracks[i]); - } - - return MP4.box.apply(null, [MP4.types.moov, MP4.mvhd(timescale, duration)].concat(boxes).concat(MP4.mvex(tracks))); - } - }, { - key: "mvex", - value: function mvex(tracks) { - var i = tracks.length, - boxes = []; - - while (i--) { - boxes[i] = MP4.trex(tracks[i]); - } - - return MP4.box.apply(null, [MP4.types.mvex].concat(boxes)); - } - }, { - key: "mvhd", - value: function mvhd(timescale, duration) { - var bytes = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x01, // creation_time - 0x00, 0x00, 0x00, 0x02, // modification_time - timescale >> 24 & 0xFF, timescale >> 16 & 0xFF, timescale >> 8 & 0xFF, timescale & 0xFF, // timescale - duration >> 24 & 0xFF, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration - 0x00, 0x01, 0x00, 0x00, // 1.0 rate - 0x01, 0x00, // 1.0 volume - 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined - 0xff, 0xff, 0xff, 0xff // next_track_ID - ]); - return MP4.box(MP4.types.mvhd, bytes); - } - }, { - key: "sdtp", - value: function sdtp(track) { - var samples = track.samples || [], - bytes = new Uint8Array(4 + samples.length), - flags, - i; // leave the full box header (4 bytes) all zero - // write the sample table - - for (i = 0; i < samples.length; i++) { - flags = samples[i].flags; - bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy; - } - - return MP4.box(MP4.types.sdtp, bytes); - } - }, { - key: "stbl", - value: function stbl(track) { - return MP4.box(MP4.types.stbl, MP4.stsd(track), MP4.box(MP4.types.stts, MP4.STTS), MP4.box(MP4.types.stsc, MP4.STSC), MP4.box(MP4.types.stsz, MP4.STSZ), MP4.box(MP4.types.stco, MP4.STCO)); - } - }, { - key: "avc1", - value: function avc1(track) { - var sps = [], - pps = [], - i, - data, - len; // assemble the SPSs - - for (i = 0; i < track.sps.length; i++) { - data = track.sps[i]; - len = data.byteLength; - sps.push(len >>> 8 & 0xFF); - sps.push(len & 0xFF); - sps = sps.concat(Array.prototype.slice.call(data)); // SPS - } // assemble the PPSs - - - for (i = 0; i < track.pps.length; i++) { - data = track.pps[i]; - len = data.byteLength; - pps.push(len >>> 8 & 0xFF); - pps.push(len & 0xFF); - pps = pps.concat(Array.prototype.slice.call(data)); - } - - var avcc = MP4.box(MP4.types.avcC, new Uint8Array([0x01, // version - sps[3], // profile - sps[4], // profile compat - sps[5], // level - 0xfc | 3, // lengthSizeMinusOne, hard-coded to 4 bytes - 0xE0 | track.sps.length // 3bit reserved (111) + numOfSequenceParameterSets - ].concat(sps).concat([track.pps.length // numOfPictureParameterSets - ]).concat(pps))), - // "PPS" - width = track.width, - height = track.height; // console.log('avcc:' + Hex.hexDump(avcc)); - - return MP4.box(MP4.types.avc1, new Uint8Array([0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, // data_reference_index - 0x00, 0x00, // pre_defined - 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined - width >> 8 & 0xFF, width & 0xff, // width - height >> 8 & 0xFF, height & 0xff, // height - 0x00, 0x48, 0x00, 0x00, // horizresolution - 0x00, 0x48, 0x00, 0x00, // vertresolution - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, // frame_count - 0x12, 0x62, 0x69, 0x6E, 0x65, // binelpro.ru - 0x6C, 0x70, 0x72, 0x6F, 0x2E, 0x72, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compressorname - 0x00, 0x18, // depth = 24 - 0x11, 0x11]), // pre_defined = -1 - avcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB - 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate - 0x00, 0x2d, 0xc6, 0xc0])) // avgBitrate - ); - } - }, { - key: "esds", - value: function esds(track) { - var configlen = track.config.byteLength; - var data = new Uint8Array(26 + configlen + 3); - data.set([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x03, // descriptor_type - 0x17 + configlen, // length - 0x00, 0x01, // es_id - 0x00, // stream_priority - 0x04, // descriptor_type - 0x0f + configlen, // length - 0x40, // codec : mpeg4_audio - 0x15, // stream_type - 0x00, 0x00, 0x00, // buffer_size - 0x00, 0x00, 0x00, 0x00, // maxBitrate - 0x00, 0x00, 0x00, 0x00, // avgBitrate - 0x05, // descriptor_type - configlen]); - data.set(track.config, 26); - data.set([0x06, 0x01, 0x02], 26 + configlen); // return new Uint8Array([ - // 0x00, // version 0 - // 0x00, 0x00, 0x00, // flags - // - // 0x03, // descriptor_type - // 0x17+configlen, // length - // 0x00, 0x01, //es_id - // 0x00, // stream_priority - // - // 0x04, // descriptor_type - // 0x0f+configlen, // length - // 0x40, //codec : mpeg4_audio - // 0x15, // stream_type - // 0x00, 0x00, 0x00, // buffer_size - // 0x00, 0x00, 0x00, 0x00, // maxBitrate - // 0x00, 0x00, 0x00, 0x00, // avgBitrate - // - // 0x05 // descriptor_type - // ].concat([configlen]).concat(track.config).concat([0x06, 0x01, 0x02])); // GASpecificConfig)); // length + audio config descriptor - - return data; - } - }, { - key: "mp4a", - value: function mp4a(track) { - var audiosamplerate = track.audiosamplerate; - return MP4.box(MP4.types.mp4a, new Uint8Array([0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, // data_reference_index - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, track.channelCount, // channelcount - 0x00, 0x10, // sampleSize:16bits - 0x00, 0x00, // pre_defined - 0x00, 0x00, // reserved2 - audiosamplerate >> 8 & 0xFF, audiosamplerate & 0xff, // - 0x00, 0x00]), MP4.box(MP4.types.esds, MP4.esds(track))); - } - }, { - key: "stsd", - value: function stsd(track) { - if (track.type === 'audio') { - return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track)); - } else { - return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track)); - } - } - }, { - key: "tkhd", - value: function tkhd(track) { - var id = track.id, - duration = track.duration, - width = track.width, - height = track.height, - volume = track.volume; - return MP4.box(MP4.types.tkhd, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x07, // flags - 0x00, 0x00, 0x00, 0x00, // creation_time - 0x00, 0x00, 0x00, 0x00, // modification_time - id >> 24 & 0xFF, id >> 16 & 0xFF, id >> 8 & 0xFF, id & 0xFF, // track_ID - 0x00, 0x00, 0x00, 0x00, // reserved - duration >> 24, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, // layer - 0x00, 0x00, // alternate_group - volume >> 0 & 0xff, volume % 1 * 10 >> 0 & 0xff, // track volume // FIXME - 0x00, 0x00, // reserved - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix - width >> 8 & 0xFF, width & 0xFF, 0x00, 0x00, // width - height >> 8 & 0xFF, height & 0xFF, 0x00, 0x00 // height - ])); - } - }, { - key: "traf", - value: function traf(track, baseMediaDecodeTime) { - var sampleDependencyTable = MP4.sdtp(track), - id = track.id; - return MP4.box(MP4.types.traf, MP4.box(MP4.types.tfhd, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - id >> 24, id >> 16 & 0XFF, id >> 8 & 0XFF, id & 0xFF // track_ID - ])), MP4.box(MP4.types.tfdt, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - baseMediaDecodeTime >> 24, baseMediaDecodeTime >> 16 & 0XFF, baseMediaDecodeTime >> 8 & 0XFF, baseMediaDecodeTime & 0xFF // baseMediaDecodeTime - ])), MP4.trun(track, sampleDependencyTable.length + 16 + // tfhd - 16 + // tfdt - 8 + // traf header - 16 + // mfhd - 8 + // moof header - 8), // mdat header - sampleDependencyTable); - } - /** - * Generate a track box. - * @param track {object} a track definition - * @return {Uint8Array} the track box - */ - - }, { - key: "trak", - value: function trak(track) { - track.duration = track.duration || 0xffffffff; - return MP4.box(MP4.types.trak, MP4.tkhd(track), MP4.mdia(track)); - } - }, { - key: "trex", - value: function trex(track) { - var id = track.id; - return MP4.box(MP4.types.trex, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - id >> 24, id >> 16 & 0XFF, id >> 8 & 0XFF, id & 0xFF, // track_ID - 0x00, 0x00, 0x00, 0x01, // default_sample_description_index - 0x00, 0x00, 0x00, 0x00, // default_sample_duration - 0x00, 0x00, 0x00, 0x00, // default_sample_size - 0x00, 0x01, 0x00, 0x01 // default_sample_flags - ])); - } - }, { - key: "trun", - value: function trun(track, offset) { - var samples = track.samples || [], - len = samples.length, - arraylen = 12 + 16 * len, - array = new Uint8Array(arraylen), - i, - sample, - duration, - size, - flags, - cts; - offset += 8 + arraylen; - array.set([0x00, // version 0 - 0x00, 0x0f, 0x01, // flags - len >>> 24 & 0xFF, len >>> 16 & 0xFF, len >>> 8 & 0xFF, len & 0xFF, // sample_count - offset >>> 24 & 0xFF, offset >>> 16 & 0xFF, offset >>> 8 & 0xFF, offset & 0xFF // data_offset - ], 0); - - for (i = 0; i < len; i++) { - sample = samples[i]; - duration = sample.duration; - size = sample.size; - flags = sample.flags; - cts = sample.cts; - array.set([duration >>> 24 & 0xFF, duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, // sample_duration - size >>> 24 & 0xFF, size >>> 16 & 0xFF, size >>> 8 & 0xFF, size & 0xFF, // sample_size - flags.isLeading << 2 | flags.dependsOn, flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.paddingValue << 1 | flags.isNonSync, flags.degradPrio & 0xF0 << 8, flags.degradPrio & 0x0F, // sample_flags - cts >>> 24 & 0xFF, cts >>> 16 & 0xFF, cts >>> 8 & 0xFF, cts & 0xFF // sample_composition_time_offset - ], 12 + 16 * i); - } - - return MP4.box(MP4.types.trun, array); - } - }, { - key: "initSegment", - value: function initSegment(tracks, duration, timescale) { - if (!MP4.types) { - MP4.init(); - } - - var movie = MP4.moov(tracks, duration, timescale), - result; - result = new Uint8Array(MP4.FTYP.byteLength + movie.byteLength); - result.set(MP4.FTYP); - result.set(movie, MP4.FTYP.byteLength); - return result; - } - }]); - - return MP4; - }(); - - var track_id = 1; - var BaseRemuxer = /*#__PURE__*/function () { - function BaseRemuxer() { - _classCallCheck(this, BaseRemuxer); - } - - _createClass(BaseRemuxer, [{ - key: "flush", - value: function flush() { - this.mp4track.len = 0; - this.mp4track.samples = []; - } - }, { - key: "isReady", - value: function isReady() { - if (!this.readyToDecode || !this.samples.length) return null; - return true; - } - }], [{ - key: "getTrackID", - value: function getTrackID() { - return track_id++; - } - }]); - - return BaseRemuxer; - }(); - - var AACRemuxer = /*#__PURE__*/function (_BaseRemuxer) { - _inherits(AACRemuxer, _BaseRemuxer); - - var _super = _createSuper(AACRemuxer); - - function AACRemuxer(timescale) { - var _this; - - _classCallCheck(this, AACRemuxer); - - _this = _super.call(this); - _this.readyToDecode = false; - _this.nextDts = 0; - _this.dts = 0; - _this.mp4track = { - id: BaseRemuxer.getTrackID(), - type: 'audio', - channelCount: 0, - len: 0, - fragmented: true, - timescale: timescale, - duration: timescale, - samples: [], - config: '', - codec: '' - }; - _this.samples = []; - _this.aac = new AACParser(_assertThisInitialized(_this)); - return _this; - } - - _createClass(AACRemuxer, [{ - key: "resetTrack", - value: function resetTrack() { - this.readyToDecode = false; - this.mp4track.codec = ''; - this.mp4track.channelCount = ''; - this.mp4track.config = ''; - this.mp4track.timescale = this.timescale; - this.nextDts = 0; - this.dts = 0; - } - }, { - key: "remux", - value: function remux(frames) { - if (frames.length > 0) { - for (var i = 0; i < frames.length; i++) { - var frame = frames[i]; - var payload = frame.units; - var size = payload.byteLength; - this.samples.push({ - units: payload, - size: size, - duration: frame.duration - }); - this.mp4track.len += size; - - if (!this.readyToDecode) { - this.aac.setAACConfig(); - } - } - } - } - }, { - key: "getPayload", - value: function getPayload() { - if (!this.isReady()) { - return null; - } - - var payload = new Uint8Array(this.mp4track.len); - var offset = 0; - var samples = this.mp4track.samples; - var mp4Sample, duration; - this.dts = this.nextDts; - - while (this.samples.length) { - var sample = this.samples.shift(), - units = sample.units; - duration = sample.duration; - - if (duration <= 0) { - log("remuxer: invalid sample duration at DTS: ".concat(this.nextDts, " :").concat(duration)); - this.mp4track.len -= sample.size; - continue; - } - - this.nextDts += duration; - mp4Sample = { - size: sample.size, - duration: duration, - cts: 0, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - dependsOn: 1 - } - }; - payload.set(sample.units, offset); - offset += sample.size; - samples.push(mp4Sample); - } - - if (!samples.length) return null; - return new Uint8Array(payload.buffer, 0, this.mp4track.len); - } - }]); - - return AACRemuxer; - }(BaseRemuxer); - - var H264Remuxer = /*#__PURE__*/function (_BaseRemuxer) { - _inherits(H264Remuxer, _BaseRemuxer); - - var _super = _createSuper(H264Remuxer); - - function H264Remuxer(timescale) { - var _this; - - _classCallCheck(this, H264Remuxer); - - _this = _super.call(this); - _this.readyToDecode = false; - _this.nextDts = 0; - _this.dts = 0; - _this.mp4track = { - id: BaseRemuxer.getTrackID(), - type: 'video', - len: 0, - fragmented: true, - sps: '', - pps: '', - width: 0, - height: 0, - timescale: timescale, - duration: timescale, - samples: [] - }; - _this.samples = []; - _this.h264 = new H264Parser(_assertThisInitialized(_this)); - return _this; - } - - _createClass(H264Remuxer, [{ - key: "resetTrack", - value: function resetTrack() { - this.readyToDecode = false; - this.mp4track.sps = ''; - this.mp4track.pps = ''; - this.nextDts = 0; - this.dts = 0; - } - }, { - key: "remux", - value: function remux(frames) { - var _iterator = _createForOfIteratorHelper(frames), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var frame = _step.value; - var units = []; - var size = 0; - - var _iterator2 = _createForOfIteratorHelper(frame.units), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var unit = _step2.value; - - if (this.h264.parseNAL(unit)) { - units.push(unit); - size += unit.getSize(); - } - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - - if (units.length > 0 && this.readyToDecode) { - this.mp4track.len += size; - this.samples.push({ - units: units, - size: size, - keyFrame: frame.keyFrame, - duration: frame.duration - }); - } - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - } - }, { - key: "getPayload", - value: function getPayload() { - if (!this.isReady()) { - return null; - } - - var payload = new Uint8Array(this.mp4track.len); - var offset = 0; - var samples = this.mp4track.samples; - var mp4Sample, duration; - this.dts = this.nextDts; - - while (this.samples.length) { - var sample = this.samples.shift(), - units = sample.units; - duration = sample.duration; - - if (duration <= 0) { - log("remuxer: invalid sample duration at DTS: ".concat(this.nextDts, " :").concat(duration)); - this.mp4track.len -= sample.size; - continue; - } - - this.nextDts += duration; - mp4Sample = { - size: sample.size, - duration: duration, - cts: 0, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - isNonSync: sample.keyFrame ? 0 : 1, - dependsOn: sample.keyFrame ? 2 : 1 - } - }; - - var _iterator3 = _createForOfIteratorHelper(units), - _step3; - - try { - for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { - var unit = _step3.value; - payload.set(unit.getData(), offset); - offset += unit.getSize(); - } - } catch (err) { - _iterator3.e(err); - } finally { - _iterator3.f(); - } - - samples.push(mp4Sample); - } - - if (!samples.length) return null; - return new Uint8Array(payload.buffer, 0, this.mp4track.len); - } - }]); - - return H264Remuxer; - }(BaseRemuxer); - - var RemuxController = /*#__PURE__*/function (_Event) { - _inherits(RemuxController, _Event); - - var _super = _createSuper(RemuxController); - - function RemuxController(env) { - var _this; - - _classCallCheck(this, RemuxController); - - _this = _super.call(this, 'remuxer'); - _this.initialized = false; - _this.trackTypes = []; - _this.tracks = {}; - _this.seq = 1; - _this.env = env; - _this.timescale = 1000; - _this.mediaDuration = 0; - return _this; - } - - _createClass(RemuxController, [{ - key: "addTrack", - value: function addTrack(type) { - if (type === 'video' || type === 'both') { - this.tracks.video = new H264Remuxer(this.timescale); - this.trackTypes.push('video'); - } - - if (type === 'audio' || type === 'both') { - this.tracks.audio = new AACRemuxer(this.timescale); - this.trackTypes.push('audio'); - } - } - }, { - key: "reset", - value: function reset() { - var _iterator = _createForOfIteratorHelper(this.trackTypes), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var type = _step.value; - this.tracks[type].resetTrack(); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - - this.initialized = false; - } - }, { - key: "destroy", - value: function destroy() { - this.tracks = {}; - this.offAll(); - } - }, { - key: "flush", - value: function flush() { - if (!this.initialized) { - if (this.isReady()) { - this.dispatch('ready'); - this.initSegment(); - this.initialized = true; - this.flush(); - } - } else { - var _iterator2 = _createForOfIteratorHelper(this.trackTypes), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var type = _step2.value; - var track = this.tracks[type]; - var pay = track.getPayload(); - - if (pay && pay.byteLength) { - var moof = MP4.moof(this.seq, track.dts, track.mp4track); - var mdat = MP4.mdat(pay); - var payload = appendByteArray(moof, mdat); - var data = { - type: type, - payload: payload, - dts: track.dts - }; - this.dispatch('buffer', data); - var duration = secToTime(track.dts / this.timescale); - log("put segment (".concat(type, "): dts: ").concat(track.dts, " frames: ").concat(track.mp4track.samples.length, " second: ").concat(duration)); - track.flush(); - this.seq++; - } - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - } - } - }, { - key: "initSegment", - value: function initSegment() { - var tracks = []; - - var _iterator3 = _createForOfIteratorHelper(this.trackTypes), - _step3; - - try { - for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { - var type = _step3.value; - var track = this.tracks[type]; - - if (this.env == 'browser') { - var _data = { - type: type, - payload: MP4.initSegment([track.mp4track], this.mediaDuration, this.timescale) - }; - this.dispatch('buffer', _data); - } else { - tracks.push(track.mp4track); - } - } - } catch (err) { - _iterator3.e(err); - } finally { - _iterator3.f(); - } - - if (this.env == 'node') { - var data = { - type: 'all', - payload: MP4.initSegment(tracks, this.mediaDuration, this.timescale) - }; - this.dispatch('buffer', data); - } - - log('Initial segment generated.'); - } - }, { - key: "isReady", - value: function isReady() { - var _iterator4 = _createForOfIteratorHelper(this.trackTypes), - _step4; - - try { - for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { - var type = _step4.value; - if (!this.tracks[type].readyToDecode || !this.tracks[type].samples.length) return false; - } - } catch (err) { - _iterator4.e(err); - } finally { - _iterator4.f(); - } - - return true; - } - }, { - key: "remux", - value: function remux(data) { - var _iterator5 = _createForOfIteratorHelper(this.trackTypes), - _step5; - - try { - for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { - var type = _step5.value; - var frames = data[type]; - if (type === 'audio' && this.tracks.video && !this.tracks.video.readyToDecode) continue; - /* if video is present, don't add audio until video get ready */ - - if (frames.length > 0) { - this.tracks[type].remux(frames); - } - } - } catch (err) { - _iterator5.e(err); - } finally { - _iterator5.f(); - } - - this.flush(); - } - }]); - - return RemuxController; - }(Event); - - var BufferController = /*#__PURE__*/function (_Event) { - _inherits(BufferController, _Event); - - var _super = _createSuper(BufferController); - - function BufferController(sourceBuffer, type) { - var _this; - - _classCallCheck(this, BufferController); - - _this = _super.call(this, 'buffer'); - _this.type = type; - _this.queue = new Uint8Array(); - _this.cleaning = false; - _this.pendingCleaning = 0; - _this.cleanOffset = 30; - _this.cleanRanges = []; - _this.sourceBuffer = sourceBuffer; - - _this.sourceBuffer.addEventListener('updateend', function () { - if (_this.pendingCleaning > 0) { - _this.initCleanup(_this.pendingCleaning); - - _this.pendingCleaning = 0; - } - - _this.cleaning = false; - - if (_this.cleanRanges.length) { - _this.doCleanup(); - - return; - } - }); - - _this.sourceBuffer.addEventListener('error', function () { - _this.dispatch('error', { - type: _this.type, - name: 'buffer', - error: 'buffer error' - }); - }); - - return _this; - } - - _createClass(BufferController, [{ - key: "destroy", - value: function destroy() { - this.queue = null; - this.sourceBuffer = null; - this.offAll(); - } - }, { - key: "doCleanup", - value: function doCleanup() { - if (!this.cleanRanges.length) { - this.cleaning = false; - return; - } - - var range = this.cleanRanges.shift(); - log("".concat(this.type, " remove range [").concat(range[0], " - ").concat(range[1], ")")); - this.cleaning = true; - this.sourceBuffer.remove(range[0], range[1]); - } - }, { - key: "initCleanup", - value: function initCleanup(cleanMaxLimit) { - if (this.sourceBuffer.updating) { - this.pendingCleaning = cleanMaxLimit; - return; - } - - if (this.sourceBuffer.buffered && this.sourceBuffer.buffered.length && !this.cleaning) { - for (var i = 0; i < this.sourceBuffer.buffered.length; ++i) { - var start = this.sourceBuffer.buffered.start(i); - var end = this.sourceBuffer.buffered.end(i); - - if (cleanMaxLimit - start > this.cleanOffset) { - end = cleanMaxLimit - this.cleanOffset; - - if (start < end) { - this.cleanRanges.push([start, end]); - } - } - } - - this.doCleanup(); - } - } - }, { - key: "doAppend", - value: function doAppend() { - if (!this.queue.length) return; - - if (this.sourceBuffer.updating) { - return; - } - - try { - this.sourceBuffer.appendBuffer(this.queue); - this.queue = new Uint8Array(); - } catch (e) { - if (e.name === 'QuotaExceededError') { - log("".concat(this.type, " buffer quota full")); - this.dispatch('error', { - type: this.type, - name: 'QuotaExceeded', - error: 'buffer error' - }); - return; - } - - error("Error occured while appending ".concat(this.type, " buffer - ").concat(e.name, ": ").concat(e.message)); - this.dispatch('error', { - type: this.type, - name: 'unexpectedError', - error: 'buffer error' - }); - } - } - }, { - key: "feed", - value: function feed(data) { - this.queue = appendByteArray(this.queue, data); - } - }]); - - return BufferController; - }(Event); - - var JMuxer = /*#__PURE__*/function (_Event) { - _inherits(JMuxer, _Event); - - var _super = _createSuper(JMuxer); - - _createClass(JMuxer, null, [{ - key: "isSupported", - value: function isSupported(codec) { - return window.MediaSource && window.MediaSource.isTypeSupported(codec); - } - }]); - - function JMuxer(options) { - var _this; - - _classCallCheck(this, JMuxer); - - _this = _super.call(this, 'jmuxer'); - var defaults = { - node: '', - mode: 'both', - // both, audio, video - flushingTime: 1500, - clearBuffer: true, - fps: 30, - debug: false, - onReady: function onReady() {}, - // function called when MSE is ready to accept frames - onError: function onError() {} // function called when jmuxer encounters any buffer related error - - }; - _this.options = Object.assign({}, defaults, options); - _this.env = (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && typeof window === 'undefined' ? 'node' : 'browser'; - - if (_this.options.debug) { - setLogger(); - } - - if (!_this.options.fps) { - _this.options.fps = 30; - } - - _this.frameDuration = 1000 / _this.options.fps | 0; - _this.remuxController = new RemuxController(_this.env); - - _this.remuxController.addTrack(_this.options.mode); - - _this.lastCleaningTime = Date.now(); - _this.kfPosition = []; - _this.kfCounter = 0; - _this.pendingUnits = {}; - _this.remainingData = new Uint8Array(); - /* events callback */ - - _this.remuxController.on('buffer', _this.onBuffer.bind(_assertThisInitialized(_this))); - - if (_this.env == 'browser') { - _this.remuxController.on('ready', _this.createBuffer.bind(_assertThisInitialized(_this))); - - _this.initBrowser(); - } - - _this.startInterval(); - - return _this; - } - - _createClass(JMuxer, [{ - key: "initBrowser", - value: function initBrowser() { - if (typeof this.options.node === 'string' && this.options.node == '') { - error('no video element were found to render, provide a valid video element'); - } - - this.node = typeof this.options.node === 'string' ? document.getElementById(this.options.node) : this.options.node; - this.mseReady = false; - this.setupMSE(); //this.sourceBuffers = {}; - } - }, { - key: "createStream", - value: function createStream() { - var feed = this.feed.bind(this); - var destroy = this.destroy.bind(this); - this.stream = new stream.Duplex({ - writableObjectMode: true, - read: function read(size) {}, - write: function write(data, encoding, callback) { - feed(data); - callback(); - }, - "final": function final(callback) { - destroy(); - callback(); - } - }); - return this.stream; - } - }, { - key: "setupMSE", - value: function setupMSE() { - window.MediaSource = window.MediaSource || window.WebKitMediaSource; - - if (!window.MediaSource) { - throw 'Oops! Browser does not support media source extension.'; - } - - this.isMSESupported = !!window.MediaSource; - this.mediaSource = new MediaSource(); - this.url = URL.createObjectURL(this.mediaSource); - this.node.src = this.url; - this.mseEnded = false; - this.mediaSource.addEventListener('sourceopen', this.onMSEOpen.bind(this)); - this.mediaSource.addEventListener('sourceclose', this.onMSEClose.bind(this)); - this.mediaSource.addEventListener('webkitsourceopen', this.onMSEOpen.bind(this)); - this.mediaSource.addEventListener('webkitsourceclose', this.onMSEClose.bind(this)); - } - }, { - key: "endMSE", - value: function endMSE() { - if (!this.mseEnded) { - try { - this.mseEnded = true; - this.mediaSource.endOfStream(); - } catch (e) { - error('mediasource is not available to end'); - } - } - } - }, { - key: "feed", - value: function feed(data) { - var remux = false, - slices, - left, - duration, - chunks = { - video: [], - audio: [] - }; - if (!data || !this.remuxController) return; - duration = data.duration ? parseInt(data.duration) : 0; - - if (data.video) { - data.video = appendByteArray(this.remainingData, data.video); - - var _H264Parser$extractNA = H264Parser.extractNALu(data.video); - - var _H264Parser$extractNA2 = _slicedToArray(_H264Parser$extractNA, 2); - - slices = _H264Parser$extractNA2[0]; - left = _H264Parser$extractNA2[1]; - - if (slices.length > 0) { - chunks.video = this.getVideoFrames(slices, duration); - remux = true; - } - - this.remainingData = left || new Uint8Array(); - } - - if (data.audio) { - slices = AACParser.extractAAC(data.audio); - - if (slices.length > 0) { - chunks.audio = this.getAudioFrames(slices, duration); - remux = true; - } - } - - if (!remux) { - error('Input object must have video and/or audio property. Make sure it is a valid typed array'); - return; - } - - this.remuxController.remux(chunks); - } - }, { - key: "getVideoFrames", - value: function getVideoFrames(nalus, duration) { - var _this2 = this; - - var units = [], - frames = [], - fd = 0, - tt = 0, - keyFrame = false, - vcl = false; - - if (this.pendingUnits.units) { - units = this.pendingUnits.units; - vcl = this.pendingUnits.vcl; - keyFrame = this.pendingUnits.keyFrame; - this.pendingUnits = {}; - } - - var _iterator = _createForOfIteratorHelper(nalus), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var nalu = _step.value; - var unit = new NALU(nalu); - - if (unit.type() === NALU.IDR || unit.type() === NALU.NDR) { - H264Parser.parseHeader(unit); - } - - if (units.length && vcl && (unit.isfmb || !unit.isvcl)) { - frames.push({ - units: units, - keyFrame: keyFrame - }); - units = []; - keyFrame = false; - vcl = false; - } - - units.push(unit); - keyFrame = keyFrame || unit.isKeyframe(); - vcl = vcl || unit.isvcl; - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - - if (units.length) { - // lets keep indecisive nalus as pending in case of fixed fps - if (!duration) { - this.pendingUnits = { - units: units, - keyFrame: keyFrame, - vcl: vcl - }; - } else if (vcl) { - frames.push({ - units: units, - keyFrame: keyFrame - }); - } else { - var last = frames.length - 1; - frames[last].units = frames[last].units.concat(units); - } - } - - fd = duration ? duration / frames.length | 0 : this.frameDuration; - tt = duration ? duration - fd * frames.length : 0; - frames.map(function (frame) { - frame.duration = fd; - - if (tt > 0) { - frame.duration++; - tt--; - } - - _this2.kfCounter++; - - if (frame.keyFrame && _this2.options.clearBuffer) { - _this2.kfPosition.push(_this2.kfCounter * fd / 1000); - } - }); - log("jmuxer: No. of frames of the last chunk: ".concat(frames.length)); - return frames; - } - }, { - key: "getAudioFrames", - value: function getAudioFrames(aacFrames, duration) { - var frames = [], - fd = 0, - tt = 0; - - var _iterator2 = _createForOfIteratorHelper(aacFrames), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var units = _step2.value; - frames.push({ - units: units - }); - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - - fd = duration ? duration / frames.length | 0 : this.frameDuration; - tt = duration ? duration - fd * frames.length : 0; - frames.map(function (frame) { - frame.duration = fd; - - if (tt > 0) { - frame.duration++; - tt--; - } - }); - return frames; - } - }, { - key: "destroy", - value: function destroy() { - this.stopInterval(); - - if (this.stream) { - this.remuxController.flush(); - this.stream.push(null); - this.stream = null; - } - - if (this.remuxController) { - this.remuxController.destroy(); - this.remuxController = null; - } - - if (this.bufferControllers) { - for (var type in this.bufferControllers) { - this.bufferControllers[type].destroy(); - } - - this.bufferControllers = null; - this.endMSE(); - } - - this.node = false; - this.mseReady = false; - this.videoStarted = false; - this.mediaSource = null; - } - }, { - key: "reset", - value: function reset() { - this.node.pause(); - - if (this.remuxController) { - this.remuxController.reset(); - } - - if (this.bufferControllers) { - for (var type in this.bufferControllers) { - this.bufferControllers[type].destroy(); - } - - this.bufferControllers = null; - this.endMSE(); - } //this.lastCleaningTime = Date.now(); - //this.kfPosition = []; - //this.kfCounter = 0; - //this.pendingUnits = {}; - //this.remainingData = new Uint8Array(); - - - if (this.env == 'browser') { - this.initBrowser(); - } - - log('JMuxer was reset'); - } - }, { - key: "createBuffer", - value: function createBuffer() { - if (!this.mseReady || !this.remuxController || !this.remuxController.isReady() || this.bufferControllers) return; - this.bufferControllers = {}; - - for (var type in this.remuxController.tracks) { - var track = this.remuxController.tracks[type]; - - if (!JMuxer.isSupported("".concat(type, "/mp4; codecs=\"").concat(track.mp4track.codec, "\""))) { - error('Browser does not support codec'); - return false; - } - - var sb = this.mediaSource.addSourceBuffer("".concat(type, "/mp4; codecs=\"").concat(track.mp4track.codec, "\"")); - this.bufferControllers[type] = new BufferController(sb, type); //this.sourceBuffers[type] = sb; - - this.bufferControllers[type].on('error', this.onBufferError.bind(this)); - } - } - }, { - key: "startInterval", - value: function startInterval() { - var _this3 = this; - - this.interval = setInterval(function () { - if (_this3.bufferControllers) { - _this3.releaseBuffer(); - - _this3.clearBuffer(); - } - }, this.options.flushingTime); - } - }, { - key: "stopInterval", - value: function stopInterval() { - if (this.interval) { - clearInterval(this.interval); - } - } - }, { - key: "releaseBuffer", - value: function releaseBuffer() { - for (var type in this.bufferControllers) { - this.bufferControllers[type].doAppend(); - } - } - }, { - key: "getSafeClearOffsetOfBuffer", - value: function getSafeClearOffsetOfBuffer(offset) { - var maxLimit = this.options.mode === 'audio' && offset || 0, - adjacentOffset; - - for (var i = 0; i < this.kfPosition.length; i++) { - if (this.kfPosition[i] >= offset) { - break; - } - - adjacentOffset = this.kfPosition[i]; - } - - if (adjacentOffset) { - this.kfPosition = this.kfPosition.filter(function (kfDelimiter) { - if (kfDelimiter < adjacentOffset) { - maxLimit = kfDelimiter; - } - - return kfDelimiter >= adjacentOffset; - }); - } - - return maxLimit; - } - }, { - key: "clearBuffer", - value: function clearBuffer() { - if (this.options.clearBuffer && Date.now() - this.lastCleaningTime > 10000) { - for (var type in this.bufferControllers) { - var cleanMaxLimit = this.getSafeClearOffsetOfBuffer(this.node.currentTime); - this.bufferControllers[type].initCleanup(cleanMaxLimit); - } - - this.lastCleaningTime = Date.now(); - } - } - }, { - key: "onBuffer", - value: function onBuffer(data) { - if (this.env == 'browser') { - if (this.bufferControllers && this.bufferControllers[data.type]) { - this.bufferControllers[data.type].feed(data.payload); - } - } else if (this.stream) { - this.stream.push(data.payload); - } - } - /* Events on MSE */ - - }, { - key: "onMSEOpen", - value: function onMSEOpen() { - this.mseReady = true; - - if (typeof this.options.onReady === 'function') { - this.options.onReady.call(null); - } - - URL.revokeObjectURL(this.url); - this.createBuffer(); - } - }, { - key: "onMSEClose", - value: function onMSEClose() { - this.mseReady = false; - this.videoStarted = false; - } - }, { - key: "onBufferError", - value: function onBufferError(data) { - if (data.name == 'QuotaExceeded') { - this.bufferControllers[data.type].initCleanup(this.node.currentTime); - return; - } else { - /* - if (this.mediaSource.sourceBuffers.length > 0 && this.sourceBuffers[data.type]) { - this.mediaSource.removeSourceBuffer(this.sourceBuffers[data.type]); - } */ - //if (this.mediaSource.sourceBuffers.length == 0) { - this.endMSE(); //} - } - - if (typeof this.options.onError === 'function') { - this.options.onError.call(null, data); - } - } - }]); - - return JMuxer; - }(Event); - - return JMuxer; - -}))); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("stream")):"function"==typeof define&&define.amd?define(["stream"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).JMuxer=t(e.stream)}(this,(function(e){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,s=!0,o=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return s=e.done,e},e:function(e){o=!0,a=e},f:function(){try{s||null==n.return||n.return()}finally{if(o)throw a}}}}var v,m;function k(e){if(v){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r1?t-1:0),r=1;r>5,this.ntype=31&this.payload[0],this.isvcl=1==this.ntype||5==this.ntype,this.stype="",this.isfmb=!1}return i(e,null,[{key:"type",value:function(t){return t.ntype in e.TYPES?e.TYPES[t.ntype]:"UNKNOWN"}},{key:"NDR",get:function(){return 1}},{key:"IDR",get:function(){return 5}},{key:"SEI",get:function(){return 6}},{key:"SPS",get:function(){return 7}},{key:"PPS",get:function(){return 8}},{key:"AUD",get:function(){return 9}},{key:"TYPES",get:function(){var t;return a(t={},e.IDR,"IDR"),a(t,e.SEI,"SEI"),a(t,e.SPS,"SPS"),a(t,e.PPS,"PPS"),a(t,e.NDR,"NDR"),a(t,e.AUD,"AUD"),t}}]),i(e,[{key:"toString",value:function(){return"".concat(e.type(this),": NRI: ").concat(this.getNri())}},{key:"getNri",value:function(){return this.nri}},{key:"type",value:function(){return this.ntype}},{key:"isKeyframe",value:function(){return this.ntype===e.IDR}},{key:"getPayload",value:function(){return this.payload}},{key:"getPayloadSize",value:function(){return this.payload.byteLength}},{key:"getSize",value:function(){return 4+this.getPayloadSize()}},{key:"getData",value:function(){var e=new Uint8Array(this.getSize());return new DataView(e.buffer).setUint32(0,this.getSize()-4),e.set(this.getPayload(),4),e}}]),e}();function S(e,t){var n=new Uint8Array((0|e.byteLength)+(0|t.byteLength));return n.set(e,0),n.set(t,0|e.byteLength),n}var w,x=function(){function e(t){n(this,e),this.data=t,this.index=0,this.bitLength=8*t.byteLength}return i(e,[{key:"skipBits",value:function(e){if(this.bitsAvailable1&&void 0!==arguments[1])||arguments[1],n=this.getBits(e,this.index,t);return n}},{key:"getBits",value:function(e,t){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if(this.bitsAvailable>>r,a=8-r;if(a>=e)return n&&(this.index+=e),i>>a-e;n&&(this.index+=a);var s=e-a;return i<>>1:-1*(e>>>1)}},{key:"readBoolean",value:function(){return 1===this.readBits(1)}},{key:"readUByte",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return this.readBits(8*e)}},{key:"readUShort",value:function(){return this.readBits(16)}},{key:"readUInt",value:function(){return this.readBits(32)}},{key:"bitsAvailable",get:function(){return this.bitLength-this.index}}]),e}(),U=function(){function e(t){n(this,e),this.remuxer=t,this.track=t.mp4track}return i(e,null,[{key:"extractNALu",value:function(e){for(var t,n,r=0,i=e.byteLength,a=0,s=[],o=0;r>>5}},{key:"isAACPattern",value:function(e){return 255===e[0]&&240==(240&e[1])&&0==(6&e[1])}},{key:"extractAAC",value:function(t){var n,r,i=0,a=t.byteLength,s=[];if(!e.isAACPattern(t))return g("Invalid ADTS audio format"),s;for(n=e.getHeaderLength(t),w||(w=t.subarray(0,n));i>>6),n=(60&a[2])>>>2,r=(1&a[2])<<2,r|=(192&a[3])>>>6,i[0]=t<<3,i[0]|=(14&n)>>1,i[1]|=(1&n)<<7,i[1]|=r<<3,this.track.codec="mp4a.40."+t,this.track.channelCount=r,this.track.config=i,this.remuxer.readyToDecode=!0)}}]),e}(),C=function(){function e(t){n(this,e),this.listener={},this.type=""|t}return i(e,[{key:"on",value:function(e,t){return this.listener[e]||(this.listener[e]=[]),this.listener[e].push(t),!0}},{key:"off",value:function(e,t){if(this.listener[e]){var n=this.listener[e].indexOf(t);return n>-1&&this.listener[e].splice(n,1),!0}return!1}},{key:"offAll",value:function(){this.listener={}}},{key:"dispatch",value:function(e,t){return!!this.listener[e]&&(this.listener[e].map((function(e){e.apply(null,[t])})),!0)}}]),e}(),B=function(){function e(){n(this,e)}return i(e,null,[{key:"init",value:function(){var t;for(t in e.types={avc1:[],avcC:[],btrt:[],dinf:[],dref:[],esds:[],ftyp:[],hdlr:[],mdat:[],mdhd:[],mdia:[],mfhd:[],minf:[],moof:[],moov:[],mp4a:[],mvex:[],mvhd:[],sdtp:[],stbl:[],stco:[],stsc:[],stsd:[],stsz:[],stts:[],tfdt:[],tfhd:[],traf:[],trak:[],trun:[],trex:[],tkhd:[],vmhd:[],smhd:[]},e.types)e.types.hasOwnProperty(t)&&(e.types[t]=[t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2),t.charCodeAt(3)]);var n=new Uint8Array([0,0,0,0,0,0,0,0,118,105,100,101,0,0,0,0,0,0,0,0,0,0,0,0,86,105,100,101,111,72,97,110,100,108,101,114,0]),r=new Uint8Array([0,0,0,0,0,0,0,0,115,111,117,110,0,0,0,0,0,0,0,0,0,0,0,0,83,111,117,110,100,72,97,110,100,108,101,114,0]);e.HDLR_TYPES={video:n,audio:r};var i=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,12,117,114,108,32,0,0,0,1]),a=new Uint8Array([0,0,0,0,0,0,0,0]);e.STTS=e.STSC=e.STCO=a,e.STSZ=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0]),e.VMHD=new Uint8Array([0,0,0,1,0,0,0,0,0,0,0,0]),e.SMHD=new Uint8Array([0,0,0,0,0,0,0,0]),e.STSD=new Uint8Array([0,0,0,0,0,0,0,1]);var s=new Uint8Array([105,115,111,109]),o=new Uint8Array([97,118,99,49]),u=new Uint8Array([0,0,0,1]);e.FTYP=e.box(e.types.ftyp,s,u,s,o),e.DINF=e.box(e.types.dinf,e.box(e.types.dref,i))}},{key:"box",value:function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r>24&255,i[1]=a>>16&255,i[2]=a>>8&255,i[3]=255&a,i.set(e,4),s=0,a=8;s>24&255,t>>16&255,t>>8&255,255&t,n>>24,n>>16&255,n>>8&255,255&n,85,196,0,0]))}},{key:"mdia",value:function(t){return e.box(e.types.mdia,e.mdhd(t.timescale,t.duration),e.hdlr(t.type),e.minf(t))}},{key:"mfhd",value:function(t){return e.box(e.types.mfhd,new Uint8Array([0,0,0,0,t>>24,t>>16&255,t>>8&255,255&t]))}},{key:"minf",value:function(t){return"audio"===t.type?e.box(e.types.minf,e.box(e.types.smhd,e.SMHD),e.DINF,e.stbl(t)):e.box(e.types.minf,e.box(e.types.vmhd,e.VMHD),e.DINF,e.stbl(t))}},{key:"moof",value:function(t,n,r){return e.box(e.types.moof,e.mfhd(t),e.traf(r,n))}},{key:"moov",value:function(t,n,r){for(var i=t.length,a=[];i--;)a[i]=e.trak(t[i]);return e.box.apply(null,[e.types.moov,e.mvhd(r,n)].concat(a).concat(e.mvex(t)))}},{key:"mvex",value:function(t){for(var n=t.length,r=[];n--;)r[n]=e.trex(t[n]);return e.box.apply(null,[e.types.mvex].concat(r))}},{key:"mvhd",value:function(t,n){var r=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,2,t>>24&255,t>>16&255,t>>8&255,255&t,n>>24&255,n>>16&255,n>>8&255,255&n,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return e.box(e.types.mvhd,r)}},{key:"sdtp",value:function(t){var n,r,i=t.samples||[],a=new Uint8Array(4+i.length);for(r=0;r>>8&255),a.push(255&i),a=a.concat(Array.prototype.slice.call(r));for(n=0;n>>8&255),s.push(255&i),s=s.concat(Array.prototype.slice.call(r));var o=e.box(e.types.avcC,new Uint8Array([1,a[3],a[4],a[5],255,224|t.sps.length].concat(a).concat([t.pps.length]).concat(s))),u=t.width,c=t.height;return e.box(e.types.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,u>>8&255,255&u,c>>8&255,255&c,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,98,105,110,101,108,112,114,111,46,114,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),o,e.box(e.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])))}},{key:"esds",value:function(e){var t=e.config.byteLength,n=new Uint8Array(26+t+3);return n.set([0,0,0,0,3,23+t,0,1,0,4,15+t,64,21,0,0,0,0,0,0,0,0,0,0,0,5,t]),n.set(e.config,26),n.set([6,1,2],26+t),n}},{key:"mp4a",value:function(t){var n=t.audiosamplerate;return e.box(e.types.mp4a,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,t.channelCount,0,16,0,0,0,0,n>>8&255,255&n,0,0]),e.box(e.types.esds,e.esds(t)))}},{key:"stsd",value:function(t){return"audio"===t.type?e.box(e.types.stsd,e.STSD,e.mp4a(t)):e.box(e.types.stsd,e.STSD,e.avc1(t))}},{key:"tkhd",value:function(t){var n=t.id,r=t.duration,i=t.width,a=t.height,s=t.volume;return e.box(e.types.tkhd,new Uint8Array([0,0,0,7,0,0,0,0,0,0,0,0,n>>24&255,n>>16&255,n>>8&255,255&n,0,0,0,0,r>>24,r>>16&255,r>>8&255,255&r,0,0,0,0,0,0,0,0,0,0,0,0,s>>0&255,s%1*10>>0&255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,i>>8&255,255&i,0,0,a>>8&255,255&a,0,0]))}},{key:"traf",value:function(t,n){var r=e.sdtp(t),i=t.id;return e.box(e.types.traf,e.box(e.types.tfhd,new Uint8Array([0,0,0,0,i>>24,i>>16&255,i>>8&255,255&i])),e.box(e.types.tfdt,new Uint8Array([0,0,0,0,n>>24,n>>16&255,n>>8&255,255&n])),e.trun(t,r.length+16+16+8+16+8+8),r)}},{key:"trak",value:function(t){return t.duration=t.duration||4294967295,e.box(e.types.trak,e.tkhd(t),e.mdia(t))}},{key:"trex",value:function(t){var n=t.id;return e.box(e.types.trex,new Uint8Array([0,0,0,0,n>>24,n>>16&255,n>>8&255,255&n,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]))}},{key:"trun",value:function(t,n){var r,i,a,s,o,u,c=t.samples||[],l=c.length,f=12+16*l,h=new Uint8Array(f);for(n+=8+f,h.set([0,0,15,1,l>>>24&255,l>>>16&255,l>>>8&255,255&l,n>>>24&255,n>>>16&255,n>>>8&255,255&n],0),r=0;r>>24&255,a>>>16&255,a>>>8&255,255&a,s>>>24&255,s>>>16&255,s>>>8&255,255&s,o.isLeading<<2|o.dependsOn,o.isDependedOn<<6|o.hasRedundancy<<4|o.paddingValue<<1|o.isNonSync,61440&o.degradPrio,15&o.degradPrio,u>>>24&255,u>>>16&255,u>>>8&255,255&u],12+16*r);return e.box(e.types.trun,h)}},{key:"initSegment",value:function(t,n,r){e.types||e.init();var i,a=e.moov(t,n,r);return(i=new Uint8Array(e.FTYP.byteLength+a.byteLength)).set(e.FTYP),i.set(a,e.FTYP.byteLength),i}}]),e}(),D=1,E=function(){function e(){n(this,e)}return i(e,[{key:"flush",value:function(){this.mp4track.len=0,this.mp4track.samples=[]}},{key:"isReady",value:function(){return!(!this.readyToDecode||!this.samples.length)||null}}],[{key:"getTrackID",value:function(){return D++}}]),e}(),T=function(e){s(r,e);var t=f(r);function r(e){var i;return n(this,r),(i=t.call(this)).readyToDecode=!1,i.nextDts=0,i.dts=0,i.mp4track={id:E.getTrackID(),type:"audio",channelCount:0,len:0,fragmented:!0,timescale:e,duration:e,samples:[],config:"",codec:""},i.samples=[],i.aac=new A(c(i)),i}return i(r,[{key:"resetTrack",value:function(){this.readyToDecode=!1,this.mp4track.codec="",this.mp4track.channelCount="",this.mp4track.config="",this.mp4track.timescale=this.timescale,this.nextDts=0,this.dts=0}},{key:"remux",value:function(e){if(e.length>0)for(var t=0;t0&&this.readyToDecode&&(this.mp4track.len+=s,this.samples.push({units:a,size:s,keyFrame:i.keyFrame,duration:i.duration}))}}catch(e){n.e(e)}finally{n.f()}}},{key:"getPayload",value:function(){if(!this.isReady())return null;var e,t,n=new Uint8Array(this.mp4track.len),r=0,i=this.mp4track.samples;for(this.dts=this.nextDts;this.samples.length;){var a=this.samples.shift(),s=a.units;if((t=a.duration)<=0)k("remuxer: invalid sample duration at DTS: ".concat(this.nextDts," :").concat(t)),this.mp4track.len-=a.size;else{this.nextDts+=t,e={size:a.size,duration:t,cts:0,flags:{isLeading:0,isDependedOn:0,hasRedundancy:0,degradPrio:0,isNonSync:a.keyFrame?0:1,dependsOn:a.keyFrame?2:1}};var o,u=p(s);try{for(u.s();!(o=u.n()).done;){var c=o.value;n.set(c.getData(),r),r+=c.getSize()}}catch(e){u.e(e)}finally{u.f()}i.push(e)}}return i.length?new Uint8Array(n.buffer,0,this.mp4track.len):null}}]),r}(E),L=function(e){s(r,e);var t=f(r);function r(e){var i;return n(this,r),(i=t.call(this,"remuxer")).initialized=!1,i.trackTypes=[],i.tracks={},i.seq=1,i.env=e,i.timescale=1e3,i.mediaDuration=0,i}return i(r,[{key:"addTrack",value:function(e){"video"!==e&&"both"!==e||(this.tracks.video=new P(this.timescale),this.trackTypes.push("video")),"audio"!==e&&"both"!==e||(this.tracks.audio=new T(this.timescale),this.trackTypes.push("audio"))}},{key:"reset",value:function(){var e,t=p(this.trackTypes);try{for(t.s();!(e=t.n()).done;){var n=e.value;this.tracks[n].resetTrack()}}catch(e){t.e(e)}finally{t.f()}this.initialized=!1}},{key:"destroy",value:function(){this.tracks={},this.offAll()}},{key:"flush",value:function(){if(this.initialized){var e,t=p(this.trackTypes);try{for(t.s();!(e=t.n()).done;){var n=e.value,r=this.tracks[n],i=r.getPayload();if(i&&i.byteLength){var a={type:n,payload:S(B.moof(this.seq,r.dts,r.mp4track),B.mdat(i)),dts:r.dts};this.dispatch("buffer",a);var s=(o=r.dts/this.timescale,u=void 0,c=void 0,l=void 0,f=void 0,f="",u=Math.floor(o),(c=parseInt(u/3600,10)%24)>0&&(f+=(c<10?"0"+c:c)+":"),f+=((l=parseInt(u/60,10)%60)<10?"0"+l:l)+":"+((u=u<0?0:u%60)<10?"0"+u:u));k("put segment (".concat(n,"): dts: ").concat(r.dts," frames: ").concat(r.mp4track.samples.length," second: ").concat(s)),r.flush(),this.seq++}}}catch(e){t.e(e)}finally{t.f()}}else this.isReady()&&(this.dispatch("ready"),this.initSegment(),this.initialized=!0,this.flush());var o,u,c,l,f}},{key:"initSegment",value:function(){var e,t=[],n=p(this.trackTypes);try{for(n.s();!(e=n.n()).done;){var r=e.value,i=this.tracks[r];if("browser"==this.env){var a={type:r,payload:B.initSegment([i.mp4track],this.mediaDuration,this.timescale)};this.dispatch("buffer",a)}else t.push(i.mp4track)}}catch(e){n.e(e)}finally{n.f()}if("node"==this.env){var s={type:"all",payload:B.initSegment(t,this.mediaDuration,this.timescale)};this.dispatch("buffer",s)}k("Initial segment generated.")}},{key:"isReady",value:function(){var e,t=p(this.trackTypes);try{for(t.s();!(e=t.n()).done;){var n=e.value;if(!this.tracks[n].readyToDecode||!this.tracks[n].samples.length)return!1}}catch(e){t.e(e)}finally{t.f()}return!0}},{key:"remux",value:function(e){var t,n=p(this.trackTypes);try{for(n.s();!(t=n.n()).done;){var r=t.value,i=e[r];"audio"===r&&this.tracks.video&&!this.tracks.video.readyToDecode||i.length>0&&this.tracks[r].remux(i)}}catch(e){n.e(e)}finally{n.f()}this.flush()}}]),r}(C),R=function(e){s(r,e);var t=f(r);function r(e,i){var a;return n(this,r),(a=t.call(this,"buffer")).type=i,a.queue=new Uint8Array,a.cleaning=!1,a.pendingCleaning=0,a.cleanOffset=30,a.cleanRanges=[],a.sourceBuffer=e,a.sourceBuffer.addEventListener("updateend",(function(){a.pendingCleaning>0&&(a.initCleanup(a.pendingCleaning),a.pendingCleaning=0),a.cleaning=!1,a.cleanRanges.length&&a.doCleanup()})),a.sourceBuffer.addEventListener("error",(function(){a.dispatch("error",{type:a.type,name:"buffer",error:"buffer error"})})),a}return i(r,[{key:"destroy",value:function(){this.queue=null,this.sourceBuffer=null,this.offAll()}},{key:"doCleanup",value:function(){if(this.cleanRanges.length){var e=this.cleanRanges.shift();k("".concat(this.type," remove range [").concat(e[0]," - ").concat(e[1],")")),this.cleaning=!0,this.sourceBuffer.remove(e[0],e[1])}else this.cleaning=!1}},{key:"initCleanup",value:function(e){if(this.sourceBuffer.updating)this.pendingCleaning=e;else if(this.sourceBuffer.buffered&&this.sourceBuffer.buffered.length&&!this.cleaning){for(var t=0;tthis.cleanOffset&&n<(r=e-this.cleanOffset)&&this.cleanRanges.push([n,r])}this.doCleanup()}}},{key:"doAppend",value:function(){if(this.queue.length&&!this.sourceBuffer.updating)try{this.sourceBuffer.appendBuffer(this.queue),this.queue=new Uint8Array}catch(e){if("QuotaExceededError"===e.name)return k("".concat(this.type," buffer quota full")),void this.dispatch("error",{type:this.type,name:"QuotaExceeded",error:"buffer error"});g("Error occured while appending ".concat(this.type," buffer - ").concat(e.name,": ").concat(e.message)),this.dispatch("error",{type:this.type,name:"unexpectedError",error:"buffer error"})}}},{key:"feed",value:function(e){this.queue=S(this.queue,e)}}]),r}(C);return function(r){s(o,r);var a=f(o);function o(e){var r;n(this,o);return(r=a.call(this,"jmuxer")).options=Object.assign({},{node:"",mode:"both",flushingTime:1500,clearBuffer:!0,fps:30,debug:!1,onReady:function(){},onError:function(){}},e),r.env="object"===("undefined"==typeof process?"undefined":t(process))&&"undefined"==typeof window?"node":"browser",r.options.debug&&(v=console.log,m=console.error),r.options.fps||(r.options.fps=30),r.frameDuration=1e3/r.options.fps|0,r.remuxController=new L(r.env),r.remuxController.addTrack(r.options.mode),r.lastCleaningTime=Date.now(),r.kfPosition=[],r.kfCounter=0,r.pendingUnits={},r.remainingData=new Uint8Array,r.remuxController.on("buffer",r.onBuffer.bind(c(r))),"browser"==r.env&&(r.remuxController.on("ready",r.createBuffer.bind(c(r))),r.initBrowser()),r.startInterval(),r}return i(o,null,[{key:"isSupported",value:function(e){return window.MediaSource&&window.MediaSource.isTypeSupported(e)}}]),i(o,[{key:"initBrowser",value:function(){"string"==typeof this.options.node&&""==this.options.node&&g("no video element were found to render, provide a valid video element"),this.node="string"==typeof this.options.node?document.getElementById(this.options.node):this.options.node,this.mseReady=!1,this.setupMSE()}},{key:"createStream",value:function(){var t=this.feed.bind(this),n=this.destroy.bind(this);return this.stream=new e.Duplex({writableObjectMode:!0,read:function(e){},write:function(e,n,r){t(e),r()},final:function(e){n(),e()}}),this.stream}},{key:"setupMSE",value:function(){if(window.MediaSource=window.MediaSource||window.WebKitMediaSource,!window.MediaSource)throw"Oops! Browser does not support media source extension.";this.isMSESupported=!!window.MediaSource,this.mediaSource=new MediaSource,this.url=URL.createObjectURL(this.mediaSource),this.node.src=this.url,this.mseEnded=!1,this.mediaSource.addEventListener("sourceopen",this.onMSEOpen.bind(this)),this.mediaSource.addEventListener("sourceclose",this.onMSEClose.bind(this)),this.mediaSource.addEventListener("webkitsourceopen",this.onMSEOpen.bind(this)),this.mediaSource.addEventListener("webkitsourceclose",this.onMSEClose.bind(this))}},{key:"endMSE",value:function(){if(!this.mseEnded)try{this.mseEnded=!0,this.mediaSource.endOfStream()}catch(e){g("mediasource is not available to end")}}},{key:"feed",value:function(e){var t,n,r,i=!1,a={video:[],audio:[]};if(e&&this.remuxController){if(r=e.duration?parseInt(e.duration):0,e.video){e.video=S(this.remainingData,e.video);var s=h(U.extractNALu(e.video),2);t=s[0],n=s[1],t.length>0&&(a.video=this.getVideoFrames(t,r),i=!0),this.remainingData=n||new Uint8Array}e.audio&&(t=A.extractAAC(e.audio)).length>0&&(a.audio=this.getAudioFrames(t,r),i=!0),i?this.remuxController.remux(a):g("Input object must have video and/or audio property. Make sure it is a valid typed array")}}},{key:"getVideoFrames",value:function(e,t){var n,r=this,i=[],a=[],s=0,o=!1,u=!1;this.pendingUnits.units&&(i=this.pendingUnits.units,u=this.pendingUnits.vcl,o=this.pendingUnits.keyFrame,this.pendingUnits={});var c,l=p(e);try{for(l.s();!(c=l.n()).done;){var f=c.value,h=new b(f);h.type()!==b.IDR&&h.type()!==b.NDR||U.parseHeader(h),i.length&&u&&(h.isfmb||!h.isvcl)&&(a.push({units:i,keyFrame:o}),i=[],o=!1,u=!1),i.push(h),o=o||h.isKeyframe(),u=u||h.isvcl}}catch(e){l.e(e)}finally{l.f()}if(i.length)if(t)if(u)a.push({units:i,keyFrame:o});else{var d=a.length-1;a[d].units=a[d].units.concat(i)}else this.pendingUnits={units:i,keyFrame:o,vcl:u};return n=t?t/a.length|0:this.frameDuration,s=t?t-n*a.length:0,a.map((function(e){e.duration=n,s>0&&(e.duration++,s--),r.kfCounter++,e.keyFrame&&r.options.clearBuffer&&r.kfPosition.push(r.kfCounter*n/1e3)})),k("jmuxer: No. of frames of the last chunk: ".concat(a.length)),a}},{key:"getAudioFrames",value:function(e,t){var n,r,i=[],a=0,s=p(e);try{for(s.s();!(r=s.n()).done;){var o=r.value;i.push({units:o})}}catch(e){s.e(e)}finally{s.f()}return n=t?t/i.length|0:this.frameDuration,a=t?t-n*i.length:0,i.map((function(e){e.duration=n,a>0&&(e.duration++,a--)})),i}},{key:"destroy",value:function(){if(this.stopInterval(),this.stream&&(this.remuxController.flush(),this.stream.push(null),this.stream=null),this.remuxController&&(this.remuxController.destroy(),this.remuxController=null),this.bufferControllers){for(var e in this.bufferControllers)this.bufferControllers[e].destroy();this.bufferControllers=null,this.endMSE()}this.node=!1,this.mseReady=!1,this.videoStarted=!1,this.mediaSource=null}},{key:"reset",value:function(){if(this.node.pause(),this.remuxController&&this.remuxController.reset(),this.bufferControllers){for(var e in this.bufferControllers)this.bufferControllers[e].destroy();this.bufferControllers=null,this.endMSE()}"browser"==this.env&&this.initBrowser(),k("JMuxer was reset")}},{key:"createBuffer",value:function(){if(this.mseReady&&this.remuxController&&this.remuxController.isReady()&&!this.bufferControllers)for(var e in this.bufferControllers={},this.remuxController.tracks){var t=this.remuxController.tracks[e];if(!o.isSupported("".concat(e,'/mp4; codecs="').concat(t.mp4track.codec,'"')))return g("Browser does not support codec"),!1;var n=this.mediaSource.addSourceBuffer("".concat(e,'/mp4; codecs="').concat(t.mp4track.codec,'"'));this.bufferControllers[e]=new R(n,e),this.bufferControllers[e].on("error",this.onBufferError.bind(this))}}},{key:"startInterval",value:function(){var e=this;this.interval=setInterval((function(){e.bufferControllers&&(e.releaseBuffer(),e.clearBuffer())}),this.options.flushingTime)}},{key:"stopInterval",value:function(){this.interval&&clearInterval(this.interval)}},{key:"releaseBuffer",value:function(){for(var e in this.bufferControllers)this.bufferControllers[e].doAppend()}},{key:"getSafeClearOffsetOfBuffer",value:function(e){for(var t,n="audio"===this.options.mode&&e||0,r=0;r=e);r++)t=this.kfPosition[r];return t&&(this.kfPosition=this.kfPosition.filter((function(e){return e=t}))),n}},{key:"clearBuffer",value:function(){if(this.options.clearBuffer&&Date.now()-this.lastCleaningTime>1e4){for(var e in this.bufferControllers){var t=this.getSafeClearOffsetOfBuffer(this.node.currentTime);this.bufferControllers[e].initCleanup(t)}this.lastCleaningTime=Date.now()}}},{key:"onBuffer",value:function(e){"browser"==this.env?this.bufferControllers&&this.bufferControllers[e.type]&&this.bufferControllers[e.type].feed(e.payload):this.stream&&this.stream.push(e.payload)}},{key:"onMSEOpen",value:function(){this.mseReady=!0,"function"==typeof this.options.onReady&&this.options.onReady.call(null),URL.revokeObjectURL(this.url),this.createBuffer()}},{key:"onMSEClose",value:function(){this.mseReady=!1,this.videoStarted=!1}},{key:"onBufferError",value:function(e){"QuotaExceeded"!=e.name?(this.endMSE(),"function"==typeof this.options.onError&&this.options.onError.call(null,e)):this.bufferControllers[e.type].initCleanup(this.node.currentTime)}}]),o}(C)})); diff --git a/example/jmuxer.min.js b/example/jmuxer.min.js index 3e6d156..eeff9e4 100644 --- a/example/jmuxer.min.js +++ b/example/jmuxer.min.js @@ -1,2733 +1 @@ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('stream')) : - typeof define === 'function' && define.amd ? define(['stream'], factory) : - (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.JMuxer = factory(global.stream)); -}(this, (function (stream) { 'use strict'; - - function _typeof(obj) { - "@babel/helpers - typeof"; - - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); - } - - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - } - - 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, descriptor.key, descriptor); - } - } - - function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; - } - - function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } - - return obj; - } - - function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - writable: true, - configurable: true - } - }); - if (superClass) _setPrototypeOf(subClass, superClass); - } - - function _getPrototypeOf(o) { - _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { - return o.__proto__ || Object.getPrototypeOf(o); - }; - return _getPrototypeOf(o); - } - - function _setPrototypeOf(o, p) { - _setPrototypeOf = Object.setPrototypeOf || 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 { - Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); - return true; - } catch (e) { - return false; - } - } - - function _assertThisInitialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return self; - } - - function _possibleConstructorReturn(self, call) { - if (call && (typeof call === "object" || typeof call === "function")) { - return call; - } - - return _assertThisInitialized(self); - } - - function _createSuper(Derived) { - var hasNativeReflectConstruct = _isNativeReflectConstruct(); - - return function _createSuperInternal() { - var Super = _getPrototypeOf(Derived), - result; - - if (hasNativeReflectConstruct) { - var NewTarget = _getPrototypeOf(this).constructor; - - result = Reflect.construct(Super, arguments, NewTarget); - } else { - result = Super.apply(this, arguments); - } - - return _possibleConstructorReturn(this, result); - }; - } - - function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); - } - - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; - } - - function _iterableToArrayLimit(arr, i) { - if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; - var _arr = []; - var _n = true; - var _d = false; - var _e = undefined; - - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - - if (i && _arr.length === i) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - function _unsupportedIterableToArray(o, minLen) { - if (!o) return; - if (typeof o === "string") return _arrayLikeToArray(o, minLen); - var n = Object.prototype.toString.call(o).slice(8, -1); - if (n === "Object" && o.constructor) n = o.constructor.name; - if (n === "Map" || n === "Set") return Array.from(o); - if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); - } - - function _arrayLikeToArray(arr, len) { - if (len == null || len > arr.length) len = arr.length; - - for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; - - return arr2; - } - - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); - } - - function _createForOfIteratorHelper(o, allowArrayLike) { - var it; - - if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { - if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { - if (it) o = it; - var i = 0; - - var F = function () {}; - - return { - s: F, - n: function () { - if (i >= o.length) return { - done: true - }; - return { - done: false, - value: o[i++] - }; - }, - e: function (e) { - throw e; - }, - f: F - }; - } - - throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); - } - - var normalCompletion = true, - didErr = false, - err; - return { - s: function () { - it = o[Symbol.iterator](); - }, - n: function () { - var step = it.next(); - normalCompletion = step.done; - return step; - }, - e: function (e) { - didErr = true; - err = e; - }, - f: function () { - try { - if (!normalCompletion && it.return != null) it.return(); - } finally { - if (didErr) throw err; - } - } - }; - } - - var logger; - var errorLogger; - function setLogger() { - /*eslint-disable */ - logger = console.log; - errorLogger = console.error; - /*eslint-enable */ - } - function log(message) { - if (logger) { - for (var _len = arguments.length, optionalParams = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - optionalParams[_key - 1] = arguments[_key]; - } - - logger.apply(void 0, [message].concat(optionalParams)); - } - } - function error(message) { - if (errorLogger) { - for (var _len2 = arguments.length, optionalParams = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { - optionalParams[_key2 - 1] = arguments[_key2]; - } - - errorLogger.apply(void 0, [message].concat(optionalParams)); - } - } - - var NALU = /*#__PURE__*/function () { - _createClass(NALU, null, [{ - key: "type", - value: function type(nalu) { - if (nalu.ntype in NALU.TYPES) { - return NALU.TYPES[nalu.ntype]; - } else { - return 'UNKNOWN'; - } - } - }, { - key: "NDR", - get: function get() { - return 1; - } - }, { - key: "IDR", - get: function get() { - return 5; - } - }, { - key: "SEI", - get: function get() { - return 6; - } - }, { - key: "SPS", - get: function get() { - return 7; - } - }, { - key: "PPS", - get: function get() { - return 8; - } - }, { - key: "AUD", - get: function get() { - return 9; - } - }, { - key: "TYPES", - get: function get() { - var _ref; - - return _ref = {}, _defineProperty(_ref, NALU.IDR, 'IDR'), _defineProperty(_ref, NALU.SEI, 'SEI'), _defineProperty(_ref, NALU.SPS, 'SPS'), _defineProperty(_ref, NALU.PPS, 'PPS'), _defineProperty(_ref, NALU.NDR, 'NDR'), _defineProperty(_ref, NALU.AUD, 'AUD'), _ref; - } - }]); - - function NALU(data) { - _classCallCheck(this, NALU); - - this.payload = data; - this.nri = (this.payload[0] & 0x60) >> 5; // nal_ref_idc - - this.ntype = this.payload[0] & 0x1f; - this.isvcl = this.ntype == 1 || this.ntype == 5; - this.stype = ''; // slice_type - - this.isfmb = false; // first_mb_in_slice - } - - _createClass(NALU, [{ - key: "toString", - value: function toString() { - return "".concat(NALU.type(this), ": NRI: ").concat(this.getNri()); - } - }, { - key: "getNri", - value: function getNri() { - return this.nri; - } - }, { - key: "type", - value: function type() { - return this.ntype; - } - }, { - key: "isKeyframe", - value: function isKeyframe() { - return this.ntype === NALU.IDR; - } - }, { - key: "getPayload", - value: function getPayload() { - return this.payload; - } - }, { - key: "getPayloadSize", - value: function getPayloadSize() { - return this.payload.byteLength; - } - }, { - key: "getSize", - value: function getSize() { - return 4 + this.getPayloadSize(); - } - }, { - key: "getData", - value: function getData() { - var result = new Uint8Array(this.getSize()); - var view = new DataView(result.buffer); - view.setUint32(0, this.getSize() - 4); - result.set(this.getPayload(), 4); - return result; - } - }]); - - return NALU; - }(); - - function appendByteArray(buffer1, buffer2) { - var tmp = new Uint8Array((buffer1.byteLength | 0) + (buffer2.byteLength | 0)); - tmp.set(buffer1, 0); - tmp.set(buffer2, buffer1.byteLength | 0); - return tmp; - } - function secToTime(sec) { - var seconds, - hours, - minutes, - result = ''; - seconds = Math.floor(sec); - hours = parseInt(seconds / 3600, 10) % 24; - minutes = parseInt(seconds / 60, 10) % 60; - seconds = seconds < 0 ? 0 : seconds % 60; - - if (hours > 0) { - result += (hours < 10 ? '0' + hours : hours) + ':'; - } - - result += (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds); - return result; - } - - /** - * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264. - */ - var ExpGolomb = /*#__PURE__*/function () { - function ExpGolomb(data) { - _classCallCheck(this, ExpGolomb); - - this.data = data; - this.index = 0; - this.bitLength = data.byteLength * 8; - } - - _createClass(ExpGolomb, [{ - key: "skipBits", - value: function skipBits(size) { - // console.log(` skip bits: size=${size}, ${this.index}.`); - if (this.bitsAvailable < size) { - //throw new Error('no bytes available'); - return false; - } - - this.index += size; - } - }, { - key: "readBits", - value: function readBits(size) { - var moveIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; - // console.log(` read bits: size=${size}, ${this.index}.`); - var result = this.getBits(size, this.index, moveIndex); // console.log(` read bits: result=${result}`); - - return result; - } - }, { - key: "getBits", - value: function getBits(size, offsetBits) { - var moveIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; - - if (this.bitsAvailable < size) { - //throw new Error('no bytes available'); - return 0; - } - - var offset = offsetBits % 8; - - var _byte = this.data[offsetBits / 8 | 0] & 0xff >>> offset; - - var bits = 8 - offset; - - if (bits >= size) { - if (moveIndex) { - this.index += size; - } - - return _byte >> bits - size; - } else { - if (moveIndex) { - this.index += bits; - } - - var nextSize = size - bits; - return _byte << nextSize | this.getBits(nextSize, offsetBits + bits, moveIndex); - } - } - }, { - key: "skipLZ", - value: function skipLZ() { - var leadingZeroCount; - - for (leadingZeroCount = 0; leadingZeroCount < this.bitLength - this.index; ++leadingZeroCount) { - if (this.getBits(1, this.index + leadingZeroCount, false) !== 0) { - // console.log(` skip LZ : size=${leadingZeroCount}, ${this.index}.`); - this.index += leadingZeroCount; - return leadingZeroCount; - } - } - - return leadingZeroCount; - } - }, { - key: "skipUEG", - value: function skipUEG() { - this.skipBits(1 + this.skipLZ()); - } - }, { - key: "skipEG", - value: function skipEG() { - this.skipBits(1 + this.skipLZ()); - } - }, { - key: "readUEG", - value: function readUEG() { - var prefix = this.skipLZ(); - return this.readBits(prefix + 1) - 1; - } - }, { - key: "readEG", - value: function readEG() { - var value = this.readUEG(); - - if (0x01 & value) { - // the number is odd if the low order bit is set - return 1 + value >>> 1; // add 1 to make it even, and divide by 2 - } else { - return -1 * (value >>> 1); // divide by two then make it negative - } - } - }, { - key: "readBoolean", - value: function readBoolean() { - return this.readBits(1) === 1; - } - }, { - key: "readUByte", - value: function readUByte() { - var numberOfBytes = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; - return this.readBits(numberOfBytes * 8); - } - }, { - key: "readUShort", - value: function readUShort() { - return this.readBits(16); - } - }, { - key: "readUInt", - value: function readUInt() { - return this.readBits(32); - } - }, { - key: "bitsAvailable", - get: function get() { - return this.bitLength - this.index; - } - }]); - - return ExpGolomb; - }(); - - var H264Parser = /*#__PURE__*/function () { - _createClass(H264Parser, null, [{ - key: "extractNALu", - value: function extractNALu(buffer) { - var i = 0, - length = buffer.byteLength, - value, - state = 0, - result = [], - left, - lastIndex = 0; - - while (i < length) { - value = buffer[i++]; // finding 3 or 4-byte start codes (00 00 01 OR 00 00 00 01) - - switch (state) { - case 0: - if (value === 0) { - state = 1; - } - - break; - - case 1: - if (value === 0) { - state = 2; - } else { - state = 0; - } - - break; - - case 2: - case 3: - if (value === 0) { - state = 3; - } else if (value === 1 && i < length) { - if (lastIndex != i - state - 1) { - result.push(buffer.subarray(lastIndex, i - state - 1)); - } - - lastIndex = i; - state = 0; - } else { - state = 0; - } - - break; - } - } - - if (lastIndex < length) { - left = buffer.subarray(lastIndex, length); - } - - return [result, left]; - } - /** - * 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 decoder {ExpGolomb} exp golomb decoder - * @param count {number} the number of entries in this scaling list - * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1 - */ - - }, { - key: "skipScalingList", - value: function skipScalingList(decoder, count) { - var lastScale = 8, - nextScale = 8, - deltaScale; - - for (var j = 0; j < count; j++) { - if (nextScale !== 0) { - deltaScale = decoder.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. - */ - - }, { - key: "readSPS", - value: function readSPS(data) { - var decoder = new ExpGolomb(data); - var frameCropLeftOffset = 0, - frameCropRightOffset = 0, - frameCropTopOffset = 0, - frameCropBottomOffset = 0, - sarScale = 1, - profileIdc, - profileCompat, - levelIdc, - numRefFramesInPicOrderCntCycle, - picWidthInMbsMinus1, - picHeightInMapUnitsMinus1, - frameMbsOnlyFlag, - scalingListCount; - decoder.readUByte(); - profileIdc = decoder.readUByte(); // profile_idc - - profileCompat = decoder.readBits(5); // constraint_set[0-4]_flag, u(5) - - decoder.skipBits(3); // reserved_zero_3bits u(3), - - levelIdc = decoder.readUByte(); // level_idc u(8) - - decoder.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 = decoder.readUEG(); - - if (chromaFormatIdc === 3) { - decoder.skipBits(1); // separate_colour_plane_flag - } - - decoder.skipUEG(); // bit_depth_luma_minus8 - - decoder.skipUEG(); // bit_depth_chroma_minus8 - - decoder.skipBits(1); // qpprime_y_zero_transform_bypass_flag - - if (decoder.readBoolean()) { - // seq_scaling_matrix_present_flag - scalingListCount = chromaFormatIdc !== 3 ? 8 : 12; - - for (var i = 0; i < scalingListCount; ++i) { - if (decoder.readBoolean()) { - // seq_scaling_list_present_flag[ i ] - if (i < 6) { - H264Parser.skipScalingList(decoder, 16); - } else { - H264Parser.skipScalingList(decoder, 64); - } - } - } - } - } - - decoder.skipUEG(); // log2_max_frame_num_minus4 - - var picOrderCntType = decoder.readUEG(); - - if (picOrderCntType === 0) { - decoder.readUEG(); // log2_max_pic_order_cnt_lsb_minus4 - } else if (picOrderCntType === 1) { - decoder.skipBits(1); // delta_pic_order_always_zero_flag - - decoder.skipEG(); // offset_for_non_ref_pic - - decoder.skipEG(); // offset_for_top_to_bottom_field - - numRefFramesInPicOrderCntCycle = decoder.readUEG(); - - for (var _i = 0; _i < numRefFramesInPicOrderCntCycle; ++_i) { - decoder.skipEG(); // offset_for_ref_frame[ i ] - } - } - - decoder.skipUEG(); // max_num_ref_frames - - decoder.skipBits(1); // gaps_in_frame_num_value_allowed_flag - - picWidthInMbsMinus1 = decoder.readUEG(); - picHeightInMapUnitsMinus1 = decoder.readUEG(); - frameMbsOnlyFlag = decoder.readBits(1); - - if (frameMbsOnlyFlag === 0) { - decoder.skipBits(1); // mb_adaptive_frame_field_flag - } - - decoder.skipBits(1); // direct_8x8_inference_flag - - if (decoder.readBoolean()) { - // frame_cropping_flag - frameCropLeftOffset = decoder.readUEG(); - frameCropRightOffset = decoder.readUEG(); - frameCropTopOffset = decoder.readUEG(); - frameCropBottomOffset = decoder.readUEG(); - } - - if (decoder.readBoolean()) { - // vui_parameters_present_flag - if (decoder.readBoolean()) { - // aspect_ratio_info_present_flag - var sarRatio; - var aspectRatioIdc = decoder.readUByte(); - - switch (aspectRatioIdc) { - case 1: - sarRatio = [1, 1]; - break; - - case 2: - sarRatio = [12, 11]; - break; - - case 3: - sarRatio = [10, 11]; - break; - - case 4: - sarRatio = [16, 11]; - break; - - case 5: - sarRatio = [40, 33]; - break; - - case 6: - sarRatio = [24, 11]; - break; - - case 7: - sarRatio = [20, 11]; - break; - - case 8: - sarRatio = [32, 11]; - break; - - case 9: - sarRatio = [80, 33]; - break; - - case 10: - sarRatio = [18, 11]; - break; - - case 11: - sarRatio = [15, 11]; - break; - - case 12: - sarRatio = [64, 33]; - break; - - case 13: - sarRatio = [160, 99]; - break; - - case 14: - sarRatio = [4, 3]; - break; - - case 15: - sarRatio = [3, 2]; - break; - - case 16: - sarRatio = [2, 1]; - break; - - case 255: - { - sarRatio = [decoder.readUByte() << 8 | decoder.readUByte(), decoder.readUByte() << 8 | decoder.readUByte()]; - break; - } - } - - if (sarRatio) { - sarScale = sarRatio[0] / sarRatio[1]; - } - } - - if (decoder.readBoolean()) { - decoder.skipBits(1); - } - - if (decoder.readBoolean()) { - decoder.skipBits(4); - - if (decoder.readBoolean()) { - decoder.skipBits(24); - } - } - - if (decoder.readBoolean()) { - decoder.skipUEG(); - decoder.skipUEG(); - } - - if (decoder.readBoolean()) { - var unitsInTick = decoder.readUInt(); - var timeScale = decoder.readUInt(); - var fixedFrameRate = decoder.readBoolean(); - } - } - - return { - width: Math.ceil(((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale), - height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset) - }; - } - }, { - key: "parseHeader", - value: function parseHeader(unit) { - var decoder = new ExpGolomb(unit.getPayload()); // skip NALu type - - decoder.readUByte(); - unit.isfmb = decoder.readUEG() === 0; - unit.stype = decoder.readUEG(); - } - }]); - - function H264Parser(remuxer) { - _classCallCheck(this, H264Parser); - - this.remuxer = remuxer; - this.track = remuxer.mp4track; - } - - _createClass(H264Parser, [{ - key: "parseSPS", - value: function parseSPS(sps) { - var config = H264Parser.readSPS(new Uint8Array(sps)); - this.track.width = config.width; - this.track.height = config.height; - this.track.sps = [new Uint8Array(sps)]; - this.track.codec = 'avc1.'; - var codecarray = new DataView(sps.buffer, sps.byteOffset + 1, 4); - - for (var i = 0; i < 3; ++i) { - var h = codecarray.getUint8(i).toString(16); - - if (h.length < 2) { - h = '0' + h; - } - - this.track.codec += h; - } - } - }, { - key: "parsePPS", - value: function parsePPS(pps) { - this.track.pps = [new Uint8Array(pps)]; - } - }, { - key: "parseNAL", - value: function parseNAL(unit) { - if (!unit) return false; - var push = false; - - switch (unit.type()) { - case NALU.IDR: - case NALU.NDR: - push = true; - break; - - case NALU.PPS: - if (!this.track.pps) { - this.parsePPS(unit.getPayload()); - - if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) { - this.remuxer.readyToDecode = true; - } - } - - push = true; - break; - - case NALU.SPS: - if (!this.track.sps) { - this.parseSPS(unit.getPayload()); - - if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) { - this.remuxer.readyToDecode = true; - } - } - - push = true; - break; - - case NALU.AUD: - log('AUD - ignoing'); - break; - - case NALU.SEI: - log('SEI - ignoing'); - break; - } - - return push; - } - }]); - - return H264Parser; - }(); - - var aacHeader; - var AACParser = /*#__PURE__*/function () { - _createClass(AACParser, null, [{ - key: "getHeaderLength", - value: function getHeaderLength(data) { - return data[1] & 0x01 ? 7 : 9; // without CRC 7 and with CRC 9 Refs: https://wiki.multimedia.cx/index.php?title=ADTS - } - }, { - key: "getFrameLength", - value: function getFrameLength(data) { - return (data[3] & 0x03) << 11 | data[4] << 3 | (data[5] & 0xE0) >>> 5; // 13 bits length ref: https://wiki.multimedia.cx/index.php?title=ADTS - } - }, { - key: "isAACPattern", - value: function isAACPattern(data) { - return data[0] === 0xff && (data[1] & 0xf0) === 0xf0 && (data[1] & 0x06) === 0x00; - } - }, { - key: "extractAAC", - value: function extractAAC(buffer) { - var i = 0, - length = buffer.byteLength, - result = [], - headerLength, - frameLength; - - if (!AACParser.isAACPattern(buffer)) { - error('Invalid ADTS audio format'); - return result; - } - - headerLength = AACParser.getHeaderLength(buffer); - - if (!aacHeader) { - aacHeader = buffer.subarray(0, headerLength); - } - - while (i < length) { - frameLength = AACParser.getFrameLength(buffer); - result.push(buffer.subarray(headerLength, frameLength)); - buffer = buffer.slice(frameLength); - i += frameLength; - } - - return result; - } - }, { - key: "samplingRateMap", - get: function get() { - return [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350]; - } - }, { - key: "getAACHeaderData", - get: function get() { - return aacHeader; - } - }]); - - function AACParser(remuxer) { - _classCallCheck(this, AACParser); - - this.remuxer = remuxer; - this.track = remuxer.mp4track; - } - - _createClass(AACParser, [{ - key: "setAACConfig", - value: function setAACConfig() { - var objectType, - sampleIndex, - channelCount, - config = new Uint8Array(2), - headerData = AACParser.getAACHeaderData; - if (!headerData) return; - objectType = ((headerData[2] & 0xC0) >>> 6) + 1; - sampleIndex = (headerData[2] & 0x3C) >>> 2; - channelCount = (headerData[2] & 0x01) << 2; - channelCount |= (headerData[3] & 0xC0) >>> 6; - /* refer to http://wiki.multimedia.cx/index.php?title=MPEG-4_Audio#Audio_Specific_Config */ - - config[0] = objectType << 3; - config[0] |= (sampleIndex & 0x0E) >> 1; - config[1] |= (sampleIndex & 0x01) << 7; - config[1] |= channelCount << 3; - this.track.codec = 'mp4a.40.' + objectType; - this.track.channelCount = channelCount; - this.track.config = config; - this.remuxer.readyToDecode = true; - } - }]); - - return AACParser; - }(); - - var Event = /*#__PURE__*/function () { - function Event(type) { - _classCallCheck(this, Event); - - this.listener = {}; - this.type = type | ''; - } - - _createClass(Event, [{ - key: "on", - value: function on(event, fn) { - if (!this.listener[event]) { - this.listener[event] = []; - } - - this.listener[event].push(fn); - return true; - } - }, { - key: "off", - value: function off(event, fn) { - if (this.listener[event]) { - var index = this.listener[event].indexOf(fn); - - if (index > -1) { - this.listener[event].splice(index, 1); - } - - return true; - } - - return false; - } - }, { - key: "offAll", - value: function offAll() { - this.listener = {}; - } - }, { - key: "dispatch", - value: function dispatch(event, data) { - if (this.listener[event]) { - this.listener[event].map(function (each) { - each.apply(null, [data]); - }); - return true; - } - - return false; - } - }]); - - return Event; - }(); - - /** - * Generate MP4 Box - * taken from: https://github.com/dailymotion/hls.js - */ - var MP4 = /*#__PURE__*/function () { - function MP4() { - _classCallCheck(this, MP4); - } - - _createClass(MP4, null, [{ - key: "init", - value: function init() { - MP4.types = { - avc1: [], - // codingname - avcC: [], - btrt: [], - dinf: [], - dref: [], - esds: [], - ftyp: [], - hdlr: [], - mdat: [], - mdhd: [], - mdia: [], - mfhd: [], - minf: [], - moof: [], - moov: [], - mp4a: [], - mvex: [], - mvhd: [], - sdtp: [], - stbl: [], - stco: [], - stsc: [], - stsd: [], - stsz: [], - stts: [], - tfdt: [], - tfhd: [], - traf: [], - trak: [], - trun: [], - trex: [], - tkhd: [], - vmhd: [], - smhd: [] - }; - var i; - - for (i in MP4.types) { - if (MP4.types.hasOwnProperty(i)) { - MP4.types[i] = [i.charCodeAt(0), i.charCodeAt(1), i.charCodeAt(2), i.charCodeAt(3)]; - } - } - - var videoHdlr = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00, // pre_defined - 0x76, 0x69, 0x64, 0x65, // handler_type: 'vide' - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x56, 0x69, 0x64, 0x65, 0x6f, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'VideoHandler' - ]); - var audioHdlr = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00, // pre_defined - 0x73, 0x6f, 0x75, 0x6e, // handler_type: 'soun' - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x53, 0x6f, 0x75, 0x6e, 0x64, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x00 // name: 'SoundHandler' - ]); - MP4.HDLR_TYPES = { - video: videoHdlr, - audio: audioHdlr - }; - var dref = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x01, // entry_count - 0x00, 0x00, 0x00, 0x0c, // entry_size - 0x75, 0x72, 0x6c, 0x20, // 'url' type - 0x00, // version 0 - 0x00, 0x00, 0x01 // entry_flags - ]); - var stco = new Uint8Array([0x00, // version - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00 // entry_count - ]); - MP4.STTS = MP4.STSC = MP4.STCO = stco; - MP4.STSZ = new Uint8Array([0x00, // version - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x00, // sample_size - 0x00, 0x00, 0x00, 0x00 // sample_count - ]); - MP4.VMHD = new Uint8Array([0x00, // version - 0x00, 0x00, 0x01, // flags - 0x00, 0x00, // graphicsmode - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // opcolor - ]); - MP4.SMHD = new Uint8Array([0x00, // version - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, // balance - 0x00, 0x00 // reserved - ]); - MP4.STSD = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x01]); // entry_count - - var majorBrand = new Uint8Array([105, 115, 111, 109]); // isom - - var avc1Brand = new Uint8Array([97, 118, 99, 49]); // avc1 - - var minorVersion = new Uint8Array([0, 0, 0, 1]); - MP4.FTYP = MP4.box(MP4.types.ftyp, majorBrand, minorVersion, majorBrand, avc1Brand); - MP4.DINF = MP4.box(MP4.types.dinf, MP4.box(MP4.types.dref, dref)); - } - }, { - key: "box", - value: function box(type) { - for (var _len = arguments.length, payload = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { - payload[_key - 1] = arguments[_key]; - } - - var size = 8, - i = payload.length, - len = i, - result; // calculate the total size we need to allocate - - while (i--) { - size += payload[i].byteLength; - } - - result = new Uint8Array(size); - result[0] = size >> 24 & 0xff; - result[1] = size >> 16 & 0xff; - result[2] = size >> 8 & 0xff; - result[3] = size & 0xff; - result.set(type, 4); // copy the payload into the result - - for (i = 0, size = 8; i < len; ++i) { - // copy payload[i] array @ offset size - result.set(payload[i], size); - size += payload[i].byteLength; - } - - return result; - } - }, { - key: "hdlr", - value: function hdlr(type) { - return MP4.box(MP4.types.hdlr, MP4.HDLR_TYPES[type]); - } - }, { - key: "mdat", - value: function mdat(data) { - return MP4.box(MP4.types.mdat, data); - } - }, { - key: "mdhd", - value: function mdhd(timescale, duration) { - return MP4.box(MP4.types.mdhd, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x02, // creation_time - 0x00, 0x00, 0x00, 0x03, // modification_time - timescale >> 24 & 0xFF, timescale >> 16 & 0xFF, timescale >> 8 & 0xFF, timescale & 0xFF, // timescale - duration >> 24, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration - 0x55, 0xc4, // 'und' language (undetermined) - 0x00, 0x00])); - } - }, { - key: "mdia", - value: function mdia(track) { - return MP4.box(MP4.types.mdia, MP4.mdhd(track.timescale, track.duration), MP4.hdlr(track.type), MP4.minf(track)); - } - }, { - key: "mfhd", - value: function mfhd(sequenceNumber) { - return MP4.box(MP4.types.mfhd, new Uint8Array([0x00, 0x00, 0x00, 0x00, // flags - sequenceNumber >> 24, sequenceNumber >> 16 & 0xFF, sequenceNumber >> 8 & 0xFF, sequenceNumber & 0xFF // sequence_number - ])); - } - }, { - key: "minf", - value: function minf(track) { - if (track.type === 'audio') { - return MP4.box(MP4.types.minf, MP4.box(MP4.types.smhd, MP4.SMHD), MP4.DINF, MP4.stbl(track)); - } else { - return MP4.box(MP4.types.minf, MP4.box(MP4.types.vmhd, MP4.VMHD), MP4.DINF, MP4.stbl(track)); - } - } - }, { - key: "moof", - value: function moof(sn, baseMediaDecodeTime, track) { - return MP4.box(MP4.types.moof, MP4.mfhd(sn), MP4.traf(track, baseMediaDecodeTime)); - } - /** - * @param tracks... (optional) {array} the tracks associated with this movie - */ - - }, { - key: "moov", - value: function moov(tracks, duration, timescale) { - var i = tracks.length, - boxes = []; - - while (i--) { - boxes[i] = MP4.trak(tracks[i]); - } - - return MP4.box.apply(null, [MP4.types.moov, MP4.mvhd(timescale, duration)].concat(boxes).concat(MP4.mvex(tracks))); - } - }, { - key: "mvex", - value: function mvex(tracks) { - var i = tracks.length, - boxes = []; - - while (i--) { - boxes[i] = MP4.trex(tracks[i]); - } - - return MP4.box.apply(null, [MP4.types.mvex].concat(boxes)); - } - }, { - key: "mvhd", - value: function mvhd(timescale, duration) { - var bytes = new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x00, 0x00, 0x00, 0x01, // creation_time - 0x00, 0x00, 0x00, 0x02, // modification_time - timescale >> 24 & 0xFF, timescale >> 16 & 0xFF, timescale >> 8 & 0xFF, timescale & 0xFF, // timescale - duration >> 24 & 0xFF, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration - 0x00, 0x01, 0x00, 0x00, // 1.0 rate - 0x01, 0x00, // 1.0 volume - 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined - 0xff, 0xff, 0xff, 0xff // next_track_ID - ]); - return MP4.box(MP4.types.mvhd, bytes); - } - }, { - key: "sdtp", - value: function sdtp(track) { - var samples = track.samples || [], - bytes = new Uint8Array(4 + samples.length), - flags, - i; // leave the full box header (4 bytes) all zero - // write the sample table - - for (i = 0; i < samples.length; i++) { - flags = samples[i].flags; - bytes[i + 4] = flags.dependsOn << 4 | flags.isDependedOn << 2 | flags.hasRedundancy; - } - - return MP4.box(MP4.types.sdtp, bytes); - } - }, { - key: "stbl", - value: function stbl(track) { - return MP4.box(MP4.types.stbl, MP4.stsd(track), MP4.box(MP4.types.stts, MP4.STTS), MP4.box(MP4.types.stsc, MP4.STSC), MP4.box(MP4.types.stsz, MP4.STSZ), MP4.box(MP4.types.stco, MP4.STCO)); - } - }, { - key: "avc1", - value: function avc1(track) { - var sps = [], - pps = [], - i, - data, - len; // assemble the SPSs - - for (i = 0; i < track.sps.length; i++) { - data = track.sps[i]; - len = data.byteLength; - sps.push(len >>> 8 & 0xFF); - sps.push(len & 0xFF); - sps = sps.concat(Array.prototype.slice.call(data)); // SPS - } // assemble the PPSs - - - for (i = 0; i < track.pps.length; i++) { - data = track.pps[i]; - len = data.byteLength; - pps.push(len >>> 8 & 0xFF); - pps.push(len & 0xFF); - pps = pps.concat(Array.prototype.slice.call(data)); - } - - var avcc = MP4.box(MP4.types.avcC, new Uint8Array([0x01, // version - sps[3], // profile - sps[4], // profile compat - sps[5], // level - 0xfc | 3, // lengthSizeMinusOne, hard-coded to 4 bytes - 0xE0 | track.sps.length // 3bit reserved (111) + numOfSequenceParameterSets - ].concat(sps).concat([track.pps.length // numOfPictureParameterSets - ]).concat(pps))), - // "PPS" - width = track.width, - height = track.height; // console.log('avcc:' + Hex.hexDump(avcc)); - - return MP4.box(MP4.types.avc1, new Uint8Array([0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, // data_reference_index - 0x00, 0x00, // pre_defined - 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pre_defined - width >> 8 & 0xFF, width & 0xff, // width - height >> 8 & 0xFF, height & 0xff, // height - 0x00, 0x48, 0x00, 0x00, // horizresolution - 0x00, 0x48, 0x00, 0x00, // vertresolution - 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, // frame_count - 0x12, 0x62, 0x69, 0x6E, 0x65, // binelpro.ru - 0x6C, 0x70, 0x72, 0x6F, 0x2E, 0x72, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // compressorname - 0x00, 0x18, // depth = 24 - 0x11, 0x11]), // pre_defined = -1 - avcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80, // bufferSizeDB - 0x00, 0x2d, 0xc6, 0xc0, // maxBitrate - 0x00, 0x2d, 0xc6, 0xc0])) // avgBitrate - ); - } - }, { - key: "esds", - value: function esds(track) { - var configlen = track.config.byteLength; - var data = new Uint8Array(26 + configlen + 3); - data.set([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - 0x03, // descriptor_type - 0x17 + configlen, // length - 0x00, 0x01, // es_id - 0x00, // stream_priority - 0x04, // descriptor_type - 0x0f + configlen, // length - 0x40, // codec : mpeg4_audio - 0x15, // stream_type - 0x00, 0x00, 0x00, // buffer_size - 0x00, 0x00, 0x00, 0x00, // maxBitrate - 0x00, 0x00, 0x00, 0x00, // avgBitrate - 0x05, // descriptor_type - configlen]); - data.set(track.config, 26); - data.set([0x06, 0x01, 0x02], 26 + configlen); // return new Uint8Array([ - // 0x00, // version 0 - // 0x00, 0x00, 0x00, // flags - // - // 0x03, // descriptor_type - // 0x17+configlen, // length - // 0x00, 0x01, //es_id - // 0x00, // stream_priority - // - // 0x04, // descriptor_type - // 0x0f+configlen, // length - // 0x40, //codec : mpeg4_audio - // 0x15, // stream_type - // 0x00, 0x00, 0x00, // buffer_size - // 0x00, 0x00, 0x00, 0x00, // maxBitrate - // 0x00, 0x00, 0x00, 0x00, // avgBitrate - // - // 0x05 // descriptor_type - // ].concat([configlen]).concat(track.config).concat([0x06, 0x01, 0x02])); // GASpecificConfig)); // length + audio config descriptor - - return data; - } - }, { - key: "mp4a", - value: function mp4a(track) { - var audiosamplerate = track.audiosamplerate; - return MP4.box(MP4.types.mp4a, new Uint8Array([0x00, 0x00, 0x00, // reserved - 0x00, 0x00, 0x00, // reserved - 0x00, 0x01, // data_reference_index - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, track.channelCount, // channelcount - 0x00, 0x10, // sampleSize:16bits - 0x00, 0x00, // pre_defined - 0x00, 0x00, // reserved2 - audiosamplerate >> 8 & 0xFF, audiosamplerate & 0xff, // - 0x00, 0x00]), MP4.box(MP4.types.esds, MP4.esds(track))); - } - }, { - key: "stsd", - value: function stsd(track) { - if (track.type === 'audio') { - return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track)); - } else { - return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track)); - } - } - }, { - key: "tkhd", - value: function tkhd(track) { - var id = track.id, - duration = track.duration, - width = track.width, - height = track.height, - volume = track.volume; - return MP4.box(MP4.types.tkhd, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x07, // flags - 0x00, 0x00, 0x00, 0x00, // creation_time - 0x00, 0x00, 0x00, 0x00, // modification_time - id >> 24 & 0xFF, id >> 16 & 0xFF, id >> 8 & 0xFF, id & 0xFF, // track_ID - 0x00, 0x00, 0x00, 0x00, // reserved - duration >> 24, duration >> 16 & 0xFF, duration >> 8 & 0xFF, duration & 0xFF, // duration - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // reserved - 0x00, 0x00, // layer - 0x00, 0x00, // alternate_group - volume >> 0 & 0xff, volume % 1 * 10 >> 0 & 0xff, // track volume // FIXME - 0x00, 0x00, // reserved - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, // transformation: unity matrix - width >> 8 & 0xFF, width & 0xFF, 0x00, 0x00, // width - height >> 8 & 0xFF, height & 0xFF, 0x00, 0x00 // height - ])); - } - }, { - key: "traf", - value: function traf(track, baseMediaDecodeTime) { - var sampleDependencyTable = MP4.sdtp(track), - id = track.id; - return MP4.box(MP4.types.traf, MP4.box(MP4.types.tfhd, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - id >> 24, id >> 16 & 0XFF, id >> 8 & 0XFF, id & 0xFF // track_ID - ])), MP4.box(MP4.types.tfdt, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - baseMediaDecodeTime >> 24, baseMediaDecodeTime >> 16 & 0XFF, baseMediaDecodeTime >> 8 & 0XFF, baseMediaDecodeTime & 0xFF // baseMediaDecodeTime - ])), MP4.trun(track, sampleDependencyTable.length + 16 + // tfhd - 16 + // tfdt - 8 + // traf header - 16 + // mfhd - 8 + // moof header - 8), // mdat header - sampleDependencyTable); - } - /** - * Generate a track box. - * @param track {object} a track definition - * @return {Uint8Array} the track box - */ - - }, { - key: "trak", - value: function trak(track) { - track.duration = track.duration || 0xffffffff; - return MP4.box(MP4.types.trak, MP4.tkhd(track), MP4.mdia(track)); - } - }, { - key: "trex", - value: function trex(track) { - var id = track.id; - return MP4.box(MP4.types.trex, new Uint8Array([0x00, // version 0 - 0x00, 0x00, 0x00, // flags - id >> 24, id >> 16 & 0XFF, id >> 8 & 0XFF, id & 0xFF, // track_ID - 0x00, 0x00, 0x00, 0x01, // default_sample_description_index - 0x00, 0x00, 0x00, 0x00, // default_sample_duration - 0x00, 0x00, 0x00, 0x00, // default_sample_size - 0x00, 0x01, 0x00, 0x01 // default_sample_flags - ])); - } - }, { - key: "trun", - value: function trun(track, offset) { - var samples = track.samples || [], - len = samples.length, - arraylen = 12 + 16 * len, - array = new Uint8Array(arraylen), - i, - sample, - duration, - size, - flags, - cts; - offset += 8 + arraylen; - array.set([0x00, // version 0 - 0x00, 0x0f, 0x01, // flags - len >>> 24 & 0xFF, len >>> 16 & 0xFF, len >>> 8 & 0xFF, len & 0xFF, // sample_count - offset >>> 24 & 0xFF, offset >>> 16 & 0xFF, offset >>> 8 & 0xFF, offset & 0xFF // data_offset - ], 0); - - for (i = 0; i < len; i++) { - sample = samples[i]; - duration = sample.duration; - size = sample.size; - flags = sample.flags; - cts = sample.cts; - array.set([duration >>> 24 & 0xFF, duration >>> 16 & 0xFF, duration >>> 8 & 0xFF, duration & 0xFF, // sample_duration - size >>> 24 & 0xFF, size >>> 16 & 0xFF, size >>> 8 & 0xFF, size & 0xFF, // sample_size - flags.isLeading << 2 | flags.dependsOn, flags.isDependedOn << 6 | flags.hasRedundancy << 4 | flags.paddingValue << 1 | flags.isNonSync, flags.degradPrio & 0xF0 << 8, flags.degradPrio & 0x0F, // sample_flags - cts >>> 24 & 0xFF, cts >>> 16 & 0xFF, cts >>> 8 & 0xFF, cts & 0xFF // sample_composition_time_offset - ], 12 + 16 * i); - } - - return MP4.box(MP4.types.trun, array); - } - }, { - key: "initSegment", - value: function initSegment(tracks, duration, timescale) { - if (!MP4.types) { - MP4.init(); - } - - var movie = MP4.moov(tracks, duration, timescale), - result; - result = new Uint8Array(MP4.FTYP.byteLength + movie.byteLength); - result.set(MP4.FTYP); - result.set(movie, MP4.FTYP.byteLength); - return result; - } - }]); - - return MP4; - }(); - - var track_id = 1; - var BaseRemuxer = /*#__PURE__*/function () { - function BaseRemuxer() { - _classCallCheck(this, BaseRemuxer); - } - - _createClass(BaseRemuxer, [{ - key: "flush", - value: function flush() { - this.mp4track.len = 0; - this.mp4track.samples = []; - } - }, { - key: "isReady", - value: function isReady() { - if (!this.readyToDecode || !this.samples.length) return null; - return true; - } - }], [{ - key: "getTrackID", - value: function getTrackID() { - return track_id++; - } - }]); - - return BaseRemuxer; - }(); - - var AACRemuxer = /*#__PURE__*/function (_BaseRemuxer) { - _inherits(AACRemuxer, _BaseRemuxer); - - var _super = _createSuper(AACRemuxer); - - function AACRemuxer(timescale) { - var _this; - - _classCallCheck(this, AACRemuxer); - - _this = _super.call(this); - _this.readyToDecode = false; - _this.nextDts = 0; - _this.dts = 0; - _this.mp4track = { - id: BaseRemuxer.getTrackID(), - type: 'audio', - channelCount: 0, - len: 0, - fragmented: true, - timescale: timescale, - duration: timescale, - samples: [], - config: '', - codec: '' - }; - _this.samples = []; - _this.aac = new AACParser(_assertThisInitialized(_this)); - return _this; - } - - _createClass(AACRemuxer, [{ - key: "resetTrack", - value: function resetTrack() { - this.readyToDecode = false; - this.mp4track.codec = ''; - this.mp4track.channelCount = ''; - this.mp4track.config = ''; - this.mp4track.timescale = this.timescale; - this.nextDts = 0; - this.dts = 0; - } - }, { - key: "remux", - value: function remux(frames) { - if (frames.length > 0) { - for (var i = 0; i < frames.length; i++) { - var frame = frames[i]; - var payload = frame.units; - var size = payload.byteLength; - this.samples.push({ - units: payload, - size: size, - duration: frame.duration - }); - this.mp4track.len += size; - - if (!this.readyToDecode) { - this.aac.setAACConfig(); - } - } - } - } - }, { - key: "getPayload", - value: function getPayload() { - if (!this.isReady()) { - return null; - } - - var payload = new Uint8Array(this.mp4track.len); - var offset = 0; - var samples = this.mp4track.samples; - var mp4Sample, duration; - this.dts = this.nextDts; - - while (this.samples.length) { - var sample = this.samples.shift(), - units = sample.units; - duration = sample.duration; - - if (duration <= 0) { - log("remuxer: invalid sample duration at DTS: ".concat(this.nextDts, " :").concat(duration)); - this.mp4track.len -= sample.size; - continue; - } - - this.nextDts += duration; - mp4Sample = { - size: sample.size, - duration: duration, - cts: 0, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - dependsOn: 1 - } - }; - payload.set(sample.units, offset); - offset += sample.size; - samples.push(mp4Sample); - } - - if (!samples.length) return null; - return new Uint8Array(payload.buffer, 0, this.mp4track.len); - } - }]); - - return AACRemuxer; - }(BaseRemuxer); - - var H264Remuxer = /*#__PURE__*/function (_BaseRemuxer) { - _inherits(H264Remuxer, _BaseRemuxer); - - var _super = _createSuper(H264Remuxer); - - function H264Remuxer(timescale) { - var _this; - - _classCallCheck(this, H264Remuxer); - - _this = _super.call(this); - _this.readyToDecode = false; - _this.nextDts = 0; - _this.dts = 0; - _this.mp4track = { - id: BaseRemuxer.getTrackID(), - type: 'video', - len: 0, - fragmented: true, - sps: '', - pps: '', - width: 0, - height: 0, - timescale: timescale, - duration: timescale, - samples: [] - }; - _this.samples = []; - _this.h264 = new H264Parser(_assertThisInitialized(_this)); - return _this; - } - - _createClass(H264Remuxer, [{ - key: "resetTrack", - value: function resetTrack() { - this.readyToDecode = false; - this.mp4track.sps = ''; - this.mp4track.pps = ''; - this.nextDts = 0; - this.dts = 0; - } - }, { - key: "remux", - value: function remux(frames) { - var _iterator = _createForOfIteratorHelper(frames), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var frame = _step.value; - var units = []; - var size = 0; - - var _iterator2 = _createForOfIteratorHelper(frame.units), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var unit = _step2.value; - - if (this.h264.parseNAL(unit)) { - units.push(unit); - size += unit.getSize(); - } - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - - if (units.length > 0 && this.readyToDecode) { - this.mp4track.len += size; - this.samples.push({ - units: units, - size: size, - keyFrame: frame.keyFrame, - duration: frame.duration - }); - } - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - } - }, { - key: "getPayload", - value: function getPayload() { - if (!this.isReady()) { - return null; - } - - var payload = new Uint8Array(this.mp4track.len); - var offset = 0; - var samples = this.mp4track.samples; - var mp4Sample, duration; - this.dts = this.nextDts; - - while (this.samples.length) { - var sample = this.samples.shift(), - units = sample.units; - duration = sample.duration; - - if (duration <= 0) { - log("remuxer: invalid sample duration at DTS: ".concat(this.nextDts, " :").concat(duration)); - this.mp4track.len -= sample.size; - continue; - } - - this.nextDts += duration; - mp4Sample = { - size: sample.size, - duration: duration, - cts: 0, - flags: { - isLeading: 0, - isDependedOn: 0, - hasRedundancy: 0, - degradPrio: 0, - isNonSync: sample.keyFrame ? 0 : 1, - dependsOn: sample.keyFrame ? 2 : 1 - } - }; - - var _iterator3 = _createForOfIteratorHelper(units), - _step3; - - try { - for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { - var unit = _step3.value; - payload.set(unit.getData(), offset); - offset += unit.getSize(); - } - } catch (err) { - _iterator3.e(err); - } finally { - _iterator3.f(); - } - - samples.push(mp4Sample); - } - - if (!samples.length) return null; - return new Uint8Array(payload.buffer, 0, this.mp4track.len); - } - }]); - - return H264Remuxer; - }(BaseRemuxer); - - var RemuxController = /*#__PURE__*/function (_Event) { - _inherits(RemuxController, _Event); - - var _super = _createSuper(RemuxController); - - function RemuxController(env) { - var _this; - - _classCallCheck(this, RemuxController); - - _this = _super.call(this, 'remuxer'); - _this.initialized = false; - _this.trackTypes = []; - _this.tracks = {}; - _this.seq = 1; - _this.env = env; - _this.timescale = 1000; - _this.mediaDuration = 0; - return _this; - } - - _createClass(RemuxController, [{ - key: "addTrack", - value: function addTrack(type) { - if (type === 'video' || type === 'both') { - this.tracks.video = new H264Remuxer(this.timescale); - this.trackTypes.push('video'); - } - - if (type === 'audio' || type === 'both') { - this.tracks.audio = new AACRemuxer(this.timescale); - this.trackTypes.push('audio'); - } - } - }, { - key: "reset", - value: function reset() { - var _iterator = _createForOfIteratorHelper(this.trackTypes), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var type = _step.value; - this.tracks[type].resetTrack(); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - - this.initialized = false; - } - }, { - key: "destroy", - value: function destroy() { - this.tracks = {}; - this.offAll(); - } - }, { - key: "flush", - value: function flush() { - if (!this.initialized) { - if (this.isReady()) { - this.dispatch('ready'); - this.initSegment(); - this.initialized = true; - this.flush(); - } - } else { - var _iterator2 = _createForOfIteratorHelper(this.trackTypes), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var type = _step2.value; - var track = this.tracks[type]; - var pay = track.getPayload(); - - if (pay && pay.byteLength) { - var moof = MP4.moof(this.seq, track.dts, track.mp4track); - var mdat = MP4.mdat(pay); - var payload = appendByteArray(moof, mdat); - var data = { - type: type, - payload: payload, - dts: track.dts - }; - this.dispatch('buffer', data); - var duration = secToTime(track.dts / this.timescale); - log("put segment (".concat(type, "): dts: ").concat(track.dts, " frames: ").concat(track.mp4track.samples.length, " second: ").concat(duration)); - track.flush(); - this.seq++; - } - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - } - } - }, { - key: "initSegment", - value: function initSegment() { - var tracks = []; - - var _iterator3 = _createForOfIteratorHelper(this.trackTypes), - _step3; - - try { - for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { - var type = _step3.value; - var track = this.tracks[type]; - - if (this.env == 'browser') { - var _data = { - type: type, - payload: MP4.initSegment([track.mp4track], this.mediaDuration, this.timescale) - }; - this.dispatch('buffer', _data); - } else { - tracks.push(track.mp4track); - } - } - } catch (err) { - _iterator3.e(err); - } finally { - _iterator3.f(); - } - - if (this.env == 'node') { - var data = { - type: 'all', - payload: MP4.initSegment(tracks, this.mediaDuration, this.timescale) - }; - this.dispatch('buffer', data); - } - - log('Initial segment generated.'); - } - }, { - key: "isReady", - value: function isReady() { - var _iterator4 = _createForOfIteratorHelper(this.trackTypes), - _step4; - - try { - for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { - var type = _step4.value; - if (!this.tracks[type].readyToDecode || !this.tracks[type].samples.length) return false; - } - } catch (err) { - _iterator4.e(err); - } finally { - _iterator4.f(); - } - - return true; - } - }, { - key: "remux", - value: function remux(data) { - var _iterator5 = _createForOfIteratorHelper(this.trackTypes), - _step5; - - try { - for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { - var type = _step5.value; - var frames = data[type]; - if (type === 'audio' && this.tracks.video && !this.tracks.video.readyToDecode) continue; - /* if video is present, don't add audio until video get ready */ - - if (frames.length > 0) { - this.tracks[type].remux(frames); - } - } - } catch (err) { - _iterator5.e(err); - } finally { - _iterator5.f(); - } - - this.flush(); - } - }]); - - return RemuxController; - }(Event); - - var BufferController = /*#__PURE__*/function (_Event) { - _inherits(BufferController, _Event); - - var _super = _createSuper(BufferController); - - function BufferController(sourceBuffer, type) { - var _this; - - _classCallCheck(this, BufferController); - - _this = _super.call(this, 'buffer'); - _this.type = type; - _this.queue = new Uint8Array(); - _this.cleaning = false; - _this.pendingCleaning = 0; - _this.cleanOffset = 30; - _this.cleanRanges = []; - _this.sourceBuffer = sourceBuffer; - - _this.sourceBuffer.addEventListener('updateend', function () { - if (_this.pendingCleaning > 0) { - _this.initCleanup(_this.pendingCleaning); - - _this.pendingCleaning = 0; - } - - _this.cleaning = false; - - if (_this.cleanRanges.length) { - _this.doCleanup(); - - return; - } - }); - - _this.sourceBuffer.addEventListener('error', function () { - _this.dispatch('error', { - type: _this.type, - name: 'buffer', - error: 'buffer error' - }); - }); - - return _this; - } - - _createClass(BufferController, [{ - key: "destroy", - value: function destroy() { - this.queue = null; - this.sourceBuffer = null; - this.offAll(); - } - }, { - key: "doCleanup", - value: function doCleanup() { - if (!this.cleanRanges.length) { - this.cleaning = false; - return; - } - - var range = this.cleanRanges.shift(); - log("".concat(this.type, " remove range [").concat(range[0], " - ").concat(range[1], ")")); - this.cleaning = true; - this.sourceBuffer.remove(range[0], range[1]); - } - }, { - key: "initCleanup", - value: function initCleanup(cleanMaxLimit) { - if (this.sourceBuffer.updating) { - this.pendingCleaning = cleanMaxLimit; - return; - } - - if (this.sourceBuffer.buffered && this.sourceBuffer.buffered.length && !this.cleaning) { - for (var i = 0; i < this.sourceBuffer.buffered.length; ++i) { - var start = this.sourceBuffer.buffered.start(i); - var end = this.sourceBuffer.buffered.end(i); - - if (cleanMaxLimit - start > this.cleanOffset) { - end = cleanMaxLimit - this.cleanOffset; - - if (start < end) { - this.cleanRanges.push([start, end]); - } - } - } - - this.doCleanup(); - } - } - }, { - key: "doAppend", - value: function doAppend() { - if (!this.queue.length) return; - - if (this.sourceBuffer.updating) { - return; - } - - try { - this.sourceBuffer.appendBuffer(this.queue); - this.queue = new Uint8Array(); - } catch (e) { - if (e.name === 'QuotaExceededError') { - log("".concat(this.type, " buffer quota full")); - this.dispatch('error', { - type: this.type, - name: 'QuotaExceeded', - error: 'buffer error' - }); - return; - } - - error("Error occured while appending ".concat(this.type, " buffer - ").concat(e.name, ": ").concat(e.message)); - this.dispatch('error', { - type: this.type, - name: 'unexpectedError', - error: 'buffer error' - }); - } - } - }, { - key: "feed", - value: function feed(data) { - this.queue = appendByteArray(this.queue, data); - } - }]); - - return BufferController; - }(Event); - - var JMuxer = /*#__PURE__*/function (_Event) { - _inherits(JMuxer, _Event); - - var _super = _createSuper(JMuxer); - - _createClass(JMuxer, null, [{ - key: "isSupported", - value: function isSupported(codec) { - return window.MediaSource && window.MediaSource.isTypeSupported(codec); - } - }]); - - function JMuxer(options) { - var _this; - - _classCallCheck(this, JMuxer); - - _this = _super.call(this, 'jmuxer'); - var defaults = { - node: '', - mode: 'both', - // both, audio, video - flushingTime: 1500, - clearBuffer: true, - fps: 30, - debug: false, - onReady: function onReady() {}, - // function called when MSE is ready to accept frames - onError: function onError() {} // function called when jmuxer encounters any buffer related error - - }; - _this.options = Object.assign({}, defaults, options); - _this.env = (typeof process === "undefined" ? "undefined" : _typeof(process)) === 'object' && typeof window === 'undefined' ? 'node' : 'browser'; - - if (_this.options.debug) { - setLogger(); - } - - if (!_this.options.fps) { - _this.options.fps = 30; - } - - _this.frameDuration = 1000 / _this.options.fps | 0; - _this.remuxController = new RemuxController(_this.env); - - _this.remuxController.addTrack(_this.options.mode); - - _this.lastCleaningTime = Date.now(); - _this.kfPosition = []; - _this.kfCounter = 0; - _this.pendingUnits = {}; - _this.remainingData = new Uint8Array(); - /* events callback */ - - _this.remuxController.on('buffer', _this.onBuffer.bind(_assertThisInitialized(_this))); - - if (_this.env == 'browser') { - _this.remuxController.on('ready', _this.createBuffer.bind(_assertThisInitialized(_this))); - - _this.initBrowser(); - } - - _this.startInterval(); - - return _this; - } - - _createClass(JMuxer, [{ - key: "initBrowser", - value: function initBrowser() { - if (typeof this.options.node === 'string' && this.options.node == '') { - error('no video element were found to render, provide a valid video element'); - } - - this.node = typeof this.options.node === 'string' ? document.getElementById(this.options.node) : this.options.node; - this.mseReady = false; - this.setupMSE(); //this.sourceBuffers = {}; - } - }, { - key: "createStream", - value: function createStream() { - var feed = this.feed.bind(this); - var destroy = this.destroy.bind(this); - this.stream = new stream.Duplex({ - writableObjectMode: true, - read: function read(size) {}, - write: function write(data, encoding, callback) { - feed(data); - callback(); - }, - "final": function final(callback) { - destroy(); - callback(); - } - }); - return this.stream; - } - }, { - key: "setupMSE", - value: function setupMSE() { - window.MediaSource = window.MediaSource || window.WebKitMediaSource; - - if (!window.MediaSource) { - throw 'Oops! Browser does not support media source extension.'; - } - - this.isMSESupported = !!window.MediaSource; - this.mediaSource = new MediaSource(); - this.url = URL.createObjectURL(this.mediaSource); - this.node.src = this.url; - this.mseEnded = false; - this.mediaSource.addEventListener('sourceopen', this.onMSEOpen.bind(this)); - this.mediaSource.addEventListener('sourceclose', this.onMSEClose.bind(this)); - this.mediaSource.addEventListener('webkitsourceopen', this.onMSEOpen.bind(this)); - this.mediaSource.addEventListener('webkitsourceclose', this.onMSEClose.bind(this)); - } - }, { - key: "endMSE", - value: function endMSE() { - if (!this.mseEnded) { - try { - this.mseEnded = true; - this.mediaSource.endOfStream(); - } catch (e) { - error('mediasource is not available to end'); - } - } - } - }, { - key: "feed", - value: function feed(data) { - var remux = false, - slices, - left, - duration, - chunks = { - video: [], - audio: [] - }; - if (!data || !this.remuxController) return; - duration = data.duration ? parseInt(data.duration) : 0; - - if (data.video) { - data.video = appendByteArray(this.remainingData, data.video); - - var _H264Parser$extractNA = H264Parser.extractNALu(data.video); - - var _H264Parser$extractNA2 = _slicedToArray(_H264Parser$extractNA, 2); - - slices = _H264Parser$extractNA2[0]; - left = _H264Parser$extractNA2[1]; - - if (slices.length > 0) { - chunks.video = this.getVideoFrames(slices, duration); - remux = true; - } - - this.remainingData = left || new Uint8Array(); - } - - if (data.audio) { - slices = AACParser.extractAAC(data.audio); - - if (slices.length > 0) { - chunks.audio = this.getAudioFrames(slices, duration); - remux = true; - } - } - - if (!remux) { - error('Input object must have video and/or audio property. Make sure it is a valid typed array'); - return; - } - - this.remuxController.remux(chunks); - } - }, { - key: "getVideoFrames", - value: function getVideoFrames(nalus, duration) { - var _this2 = this; - - var units = [], - frames = [], - fd = 0, - tt = 0, - keyFrame = false, - vcl = false; - - if (this.pendingUnits.units) { - units = this.pendingUnits.units; - vcl = this.pendingUnits.vcl; - keyFrame = this.pendingUnits.keyFrame; - this.pendingUnits = {}; - } - - var _iterator = _createForOfIteratorHelper(nalus), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var nalu = _step.value; - var unit = new NALU(nalu); - - if (unit.type() === NALU.IDR || unit.type() === NALU.NDR) { - H264Parser.parseHeader(unit); - } - - if (units.length && vcl && (unit.isfmb || !unit.isvcl)) { - frames.push({ - units: units, - keyFrame: keyFrame - }); - units = []; - keyFrame = false; - vcl = false; - } - - units.push(unit); - keyFrame = keyFrame || unit.isKeyframe(); - vcl = vcl || unit.isvcl; - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - - if (units.length) { - // lets keep indecisive nalus as pending in case of fixed fps - if (!duration) { - this.pendingUnits = { - units: units, - keyFrame: keyFrame, - vcl: vcl - }; - } else if (vcl) { - frames.push({ - units: units, - keyFrame: keyFrame - }); - } else { - var last = frames.length - 1; - frames[last].units = frames[last].units.concat(units); - } - } - - fd = duration ? duration / frames.length | 0 : this.frameDuration; - tt = duration ? duration - fd * frames.length : 0; - frames.map(function (frame) { - frame.duration = fd; - - if (tt > 0) { - frame.duration++; - tt--; - } - - _this2.kfCounter++; - - if (frame.keyFrame && _this2.options.clearBuffer) { - _this2.kfPosition.push(_this2.kfCounter * fd / 1000); - } - }); - log("jmuxer: No. of frames of the last chunk: ".concat(frames.length)); - return frames; - } - }, { - key: "getAudioFrames", - value: function getAudioFrames(aacFrames, duration) { - var frames = [], - fd = 0, - tt = 0; - - var _iterator2 = _createForOfIteratorHelper(aacFrames), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var units = _step2.value; - frames.push({ - units: units - }); - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - - fd = duration ? duration / frames.length | 0 : this.frameDuration; - tt = duration ? duration - fd * frames.length : 0; - frames.map(function (frame) { - frame.duration = fd; - - if (tt > 0) { - frame.duration++; - tt--; - } - }); - return frames; - } - }, { - key: "destroy", - value: function destroy() { - this.stopInterval(); - - if (this.stream) { - this.remuxController.flush(); - this.stream.push(null); - this.stream = null; - } - - if (this.remuxController) { - this.remuxController.destroy(); - this.remuxController = null; - } - - if (this.bufferControllers) { - for (var type in this.bufferControllers) { - this.bufferControllers[type].destroy(); - } - - this.bufferControllers = null; - this.endMSE(); - } - - this.node = false; - this.mseReady = false; - this.videoStarted = false; - this.mediaSource = null; - } - }, { - key: "reset", - value: function reset() { - this.node.pause(); - - if (this.remuxController) { - this.remuxController.reset(); - } - - if (this.bufferControllers) { - for (var type in this.bufferControllers) { - this.bufferControllers[type].destroy(); - } - - this.bufferControllers = null; - this.endMSE(); - } //this.lastCleaningTime = Date.now(); - //this.kfPosition = []; - //this.kfCounter = 0; - //this.pendingUnits = {}; - //this.remainingData = new Uint8Array(); - - - if (this.env == 'browser') { - this.initBrowser(); - } - - log('JMuxer was reset'); - } - }, { - key: "createBuffer", - value: function createBuffer() { - if (!this.mseReady || !this.remuxController || !this.remuxController.isReady() || this.bufferControllers) return; - this.bufferControllers = {}; - - for (var type in this.remuxController.tracks) { - var track = this.remuxController.tracks[type]; - - if (!JMuxer.isSupported("".concat(type, "/mp4; codecs=\"").concat(track.mp4track.codec, "\""))) { - error('Browser does not support codec'); - return false; - } - - var sb = this.mediaSource.addSourceBuffer("".concat(type, "/mp4; codecs=\"").concat(track.mp4track.codec, "\"")); - this.bufferControllers[type] = new BufferController(sb, type); //this.sourceBuffers[type] = sb; - - this.bufferControllers[type].on('error', this.onBufferError.bind(this)); - } - } - }, { - key: "startInterval", - value: function startInterval() { - var _this3 = this; - - this.interval = setInterval(function () { - if (_this3.bufferControllers) { - _this3.releaseBuffer(); - - _this3.clearBuffer(); - } - }, this.options.flushingTime); - } - }, { - key: "stopInterval", - value: function stopInterval() { - if (this.interval) { - clearInterval(this.interval); - } - } - }, { - key: "releaseBuffer", - value: function releaseBuffer() { - for (var type in this.bufferControllers) { - this.bufferControllers[type].doAppend(); - } - } - }, { - key: "getSafeClearOffsetOfBuffer", - value: function getSafeClearOffsetOfBuffer(offset) { - var maxLimit = this.options.mode === 'audio' && offset || 0, - adjacentOffset; - - for (var i = 0; i < this.kfPosition.length; i++) { - if (this.kfPosition[i] >= offset) { - break; - } - - adjacentOffset = this.kfPosition[i]; - } - - if (adjacentOffset) { - this.kfPosition = this.kfPosition.filter(function (kfDelimiter) { - if (kfDelimiter < adjacentOffset) { - maxLimit = kfDelimiter; - } - - return kfDelimiter >= adjacentOffset; - }); - } - - return maxLimit; - } - }, { - key: "clearBuffer", - value: function clearBuffer() { - if (this.options.clearBuffer && Date.now() - this.lastCleaningTime > 10000) { - for (var type in this.bufferControllers) { - var cleanMaxLimit = this.getSafeClearOffsetOfBuffer(this.node.currentTime); - this.bufferControllers[type].initCleanup(cleanMaxLimit); - } - - this.lastCleaningTime = Date.now(); - } - } - }, { - key: "onBuffer", - value: function onBuffer(data) { - if (this.env == 'browser') { - if (this.bufferControllers && this.bufferControllers[data.type]) { - this.bufferControllers[data.type].feed(data.payload); - } - } else if (this.stream) { - this.stream.push(data.payload); - } - } - /* Events on MSE */ - - }, { - key: "onMSEOpen", - value: function onMSEOpen() { - this.mseReady = true; - - if (typeof this.options.onReady === 'function') { - this.options.onReady.call(null); - } - - URL.revokeObjectURL(this.url); - this.createBuffer(); - } - }, { - key: "onMSEClose", - value: function onMSEClose() { - this.mseReady = false; - this.videoStarted = false; - } - }, { - key: "onBufferError", - value: function onBufferError(data) { - if (data.name == 'QuotaExceeded') { - this.bufferControllers[data.type].initCleanup(this.node.currentTime); - return; - } else { - /* - if (this.mediaSource.sourceBuffers.length > 0 && this.sourceBuffers[data.type]) { - this.mediaSource.removeSourceBuffer(this.sourceBuffers[data.type]); - } */ - //if (this.mediaSource.sourceBuffers.length == 0) { - this.endMSE(); //} - } - - if (typeof this.options.onError === 'function') { - this.options.onError.call(null, data); - } - } - }]); - - return JMuxer; - }(Event); - - return JMuxer; - -}))); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("stream")):"function"==typeof define&&define.amd?define(["stream"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).JMuxer=t(e.stream)}(this,(function(e){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){for(var n=0;ne.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,s=!0,o=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return s=e.done,e},e:function(e){o=!0,a=e},f:function(){try{s||null==n.return||n.return()}finally{if(o)throw a}}}}var v,m;function k(e){if(v){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r1?t-1:0),r=1;r>5,this.ntype=31&this.payload[0],this.isvcl=1==this.ntype||5==this.ntype,this.stype="",this.isfmb=!1}return i(e,null,[{key:"type",value:function(t){return t.ntype in e.TYPES?e.TYPES[t.ntype]:"UNKNOWN"}},{key:"NDR",get:function(){return 1}},{key:"IDR",get:function(){return 5}},{key:"SEI",get:function(){return 6}},{key:"SPS",get:function(){return 7}},{key:"PPS",get:function(){return 8}},{key:"AUD",get:function(){return 9}},{key:"TYPES",get:function(){var t;return a(t={},e.IDR,"IDR"),a(t,e.SEI,"SEI"),a(t,e.SPS,"SPS"),a(t,e.PPS,"PPS"),a(t,e.NDR,"NDR"),a(t,e.AUD,"AUD"),t}}]),i(e,[{key:"toString",value:function(){return"".concat(e.type(this),": NRI: ").concat(this.getNri())}},{key:"getNri",value:function(){return this.nri}},{key:"type",value:function(){return this.ntype}},{key:"isKeyframe",value:function(){return this.ntype===e.IDR}},{key:"getPayload",value:function(){return this.payload}},{key:"getPayloadSize",value:function(){return this.payload.byteLength}},{key:"getSize",value:function(){return 4+this.getPayloadSize()}},{key:"getData",value:function(){var e=new Uint8Array(this.getSize());return new DataView(e.buffer).setUint32(0,this.getSize()-4),e.set(this.getPayload(),4),e}}]),e}();function S(e,t){var n=new Uint8Array((0|e.byteLength)+(0|t.byteLength));return n.set(e,0),n.set(t,0|e.byteLength),n}var w,x=function(){function e(t){n(this,e),this.data=t,this.index=0,this.bitLength=8*t.byteLength}return i(e,[{key:"skipBits",value:function(e){if(this.bitsAvailable1&&void 0!==arguments[1])||arguments[1],n=this.getBits(e,this.index,t);return n}},{key:"getBits",value:function(e,t){var n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if(this.bitsAvailable>>r,a=8-r;if(a>=e)return n&&(this.index+=e),i>>a-e;n&&(this.index+=a);var s=e-a;return i<>>1:-1*(e>>>1)}},{key:"readBoolean",value:function(){return 1===this.readBits(1)}},{key:"readUByte",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1;return this.readBits(8*e)}},{key:"readUShort",value:function(){return this.readBits(16)}},{key:"readUInt",value:function(){return this.readBits(32)}},{key:"bitsAvailable",get:function(){return this.bitLength-this.index}}]),e}(),U=function(){function e(t){n(this,e),this.remuxer=t,this.track=t.mp4track}return i(e,null,[{key:"extractNALu",value:function(e){for(var t,n,r=0,i=e.byteLength,a=0,s=[],o=0;r>>5}},{key:"isAACPattern",value:function(e){return 255===e[0]&&240==(240&e[1])&&0==(6&e[1])}},{key:"extractAAC",value:function(t){var n,r,i=0,a=t.byteLength,s=[];if(!e.isAACPattern(t))return g("Invalid ADTS audio format"),s;for(n=e.getHeaderLength(t),w||(w=t.subarray(0,n));i>>6),n=(60&a[2])>>>2,r=(1&a[2])<<2,r|=(192&a[3])>>>6,i[0]=t<<3,i[0]|=(14&n)>>1,i[1]|=(1&n)<<7,i[1]|=r<<3,this.track.codec="mp4a.40."+t,this.track.channelCount=r,this.track.config=i,this.remuxer.readyToDecode=!0)}}]),e}(),C=function(){function e(t){n(this,e),this.listener={},this.type=""|t}return i(e,[{key:"on",value:function(e,t){return this.listener[e]||(this.listener[e]=[]),this.listener[e].push(t),!0}},{key:"off",value:function(e,t){if(this.listener[e]){var n=this.listener[e].indexOf(t);return n>-1&&this.listener[e].splice(n,1),!0}return!1}},{key:"offAll",value:function(){this.listener={}}},{key:"dispatch",value:function(e,t){return!!this.listener[e]&&(this.listener[e].map((function(e){e.apply(null,[t])})),!0)}}]),e}(),B=function(){function e(){n(this,e)}return i(e,null,[{key:"init",value:function(){var t;for(t in e.types={avc1:[],avcC:[],btrt:[],dinf:[],dref:[],esds:[],ftyp:[],hdlr:[],mdat:[],mdhd:[],mdia:[],mfhd:[],minf:[],moof:[],moov:[],mp4a:[],mvex:[],mvhd:[],sdtp:[],stbl:[],stco:[],stsc:[],stsd:[],stsz:[],stts:[],tfdt:[],tfhd:[],traf:[],trak:[],trun:[],trex:[],tkhd:[],vmhd:[],smhd:[]},e.types)e.types.hasOwnProperty(t)&&(e.types[t]=[t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2),t.charCodeAt(3)]);var n=new Uint8Array([0,0,0,0,0,0,0,0,118,105,100,101,0,0,0,0,0,0,0,0,0,0,0,0,86,105,100,101,111,72,97,110,100,108,101,114,0]),r=new Uint8Array([0,0,0,0,0,0,0,0,115,111,117,110,0,0,0,0,0,0,0,0,0,0,0,0,83,111,117,110,100,72,97,110,100,108,101,114,0]);e.HDLR_TYPES={video:n,audio:r};var i=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,12,117,114,108,32,0,0,0,1]),a=new Uint8Array([0,0,0,0,0,0,0,0]);e.STTS=e.STSC=e.STCO=a,e.STSZ=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0]),e.VMHD=new Uint8Array([0,0,0,1,0,0,0,0,0,0,0,0]),e.SMHD=new Uint8Array([0,0,0,0,0,0,0,0]),e.STSD=new Uint8Array([0,0,0,0,0,0,0,1]);var s=new Uint8Array([105,115,111,109]),o=new Uint8Array([97,118,99,49]),u=new Uint8Array([0,0,0,1]);e.FTYP=e.box(e.types.ftyp,s,u,s,o),e.DINF=e.box(e.types.dinf,e.box(e.types.dref,i))}},{key:"box",value:function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r>24&255,i[1]=a>>16&255,i[2]=a>>8&255,i[3]=255&a,i.set(e,4),s=0,a=8;s>24&255,t>>16&255,t>>8&255,255&t,n>>24,n>>16&255,n>>8&255,255&n,85,196,0,0]))}},{key:"mdia",value:function(t){return e.box(e.types.mdia,e.mdhd(t.timescale,t.duration),e.hdlr(t.type),e.minf(t))}},{key:"mfhd",value:function(t){return e.box(e.types.mfhd,new Uint8Array([0,0,0,0,t>>24,t>>16&255,t>>8&255,255&t]))}},{key:"minf",value:function(t){return"audio"===t.type?e.box(e.types.minf,e.box(e.types.smhd,e.SMHD),e.DINF,e.stbl(t)):e.box(e.types.minf,e.box(e.types.vmhd,e.VMHD),e.DINF,e.stbl(t))}},{key:"moof",value:function(t,n,r){return e.box(e.types.moof,e.mfhd(t),e.traf(r,n))}},{key:"moov",value:function(t,n,r){for(var i=t.length,a=[];i--;)a[i]=e.trak(t[i]);return e.box.apply(null,[e.types.moov,e.mvhd(r,n)].concat(a).concat(e.mvex(t)))}},{key:"mvex",value:function(t){for(var n=t.length,r=[];n--;)r[n]=e.trex(t[n]);return e.box.apply(null,[e.types.mvex].concat(r))}},{key:"mvhd",value:function(t,n){var r=new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,2,t>>24&255,t>>16&255,t>>8&255,255&t,n>>24&255,n>>16&255,n>>8&255,255&n,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return e.box(e.types.mvhd,r)}},{key:"sdtp",value:function(t){var n,r,i=t.samples||[],a=new Uint8Array(4+i.length);for(r=0;r>>8&255),a.push(255&i),a=a.concat(Array.prototype.slice.call(r));for(n=0;n>>8&255),s.push(255&i),s=s.concat(Array.prototype.slice.call(r));var o=e.box(e.types.avcC,new Uint8Array([1,a[3],a[4],a[5],255,224|t.sps.length].concat(a).concat([t.pps.length]).concat(s))),u=t.width,c=t.height;return e.box(e.types.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,u>>8&255,255&u,c>>8&255,255&c,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,98,105,110,101,108,112,114,111,46,114,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),o,e.box(e.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])))}},{key:"esds",value:function(e){var t=e.config.byteLength,n=new Uint8Array(26+t+3);return n.set([0,0,0,0,3,23+t,0,1,0,4,15+t,64,21,0,0,0,0,0,0,0,0,0,0,0,5,t]),n.set(e.config,26),n.set([6,1,2],26+t),n}},{key:"mp4a",value:function(t){var n=t.audiosamplerate;return e.box(e.types.mp4a,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,t.channelCount,0,16,0,0,0,0,n>>8&255,255&n,0,0]),e.box(e.types.esds,e.esds(t)))}},{key:"stsd",value:function(t){return"audio"===t.type?e.box(e.types.stsd,e.STSD,e.mp4a(t)):e.box(e.types.stsd,e.STSD,e.avc1(t))}},{key:"tkhd",value:function(t){var n=t.id,r=t.duration,i=t.width,a=t.height,s=t.volume;return e.box(e.types.tkhd,new Uint8Array([0,0,0,7,0,0,0,0,0,0,0,0,n>>24&255,n>>16&255,n>>8&255,255&n,0,0,0,0,r>>24,r>>16&255,r>>8&255,255&r,0,0,0,0,0,0,0,0,0,0,0,0,s>>0&255,s%1*10>>0&255,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,i>>8&255,255&i,0,0,a>>8&255,255&a,0,0]))}},{key:"traf",value:function(t,n){var r=e.sdtp(t),i=t.id;return e.box(e.types.traf,e.box(e.types.tfhd,new Uint8Array([0,0,0,0,i>>24,i>>16&255,i>>8&255,255&i])),e.box(e.types.tfdt,new Uint8Array([0,0,0,0,n>>24,n>>16&255,n>>8&255,255&n])),e.trun(t,r.length+16+16+8+16+8+8),r)}},{key:"trak",value:function(t){return t.duration=t.duration||4294967295,e.box(e.types.trak,e.tkhd(t),e.mdia(t))}},{key:"trex",value:function(t){var n=t.id;return e.box(e.types.trex,new Uint8Array([0,0,0,0,n>>24,n>>16&255,n>>8&255,255&n,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]))}},{key:"trun",value:function(t,n){var r,i,a,s,o,u,c=t.samples||[],l=c.length,f=12+16*l,h=new Uint8Array(f);for(n+=8+f,h.set([0,0,15,1,l>>>24&255,l>>>16&255,l>>>8&255,255&l,n>>>24&255,n>>>16&255,n>>>8&255,255&n],0),r=0;r>>24&255,a>>>16&255,a>>>8&255,255&a,s>>>24&255,s>>>16&255,s>>>8&255,255&s,o.isLeading<<2|o.dependsOn,o.isDependedOn<<6|o.hasRedundancy<<4|o.paddingValue<<1|o.isNonSync,61440&o.degradPrio,15&o.degradPrio,u>>>24&255,u>>>16&255,u>>>8&255,255&u],12+16*r);return e.box(e.types.trun,h)}},{key:"initSegment",value:function(t,n,r){e.types||e.init();var i,a=e.moov(t,n,r);return(i=new Uint8Array(e.FTYP.byteLength+a.byteLength)).set(e.FTYP),i.set(a,e.FTYP.byteLength),i}}]),e}(),D=1,E=function(){function e(){n(this,e)}return i(e,[{key:"flush",value:function(){this.mp4track.len=0,this.mp4track.samples=[]}},{key:"isReady",value:function(){return!(!this.readyToDecode||!this.samples.length)||null}}],[{key:"getTrackID",value:function(){return D++}}]),e}(),T=function(e){s(r,e);var t=f(r);function r(e){var i;return n(this,r),(i=t.call(this)).readyToDecode=!1,i.nextDts=0,i.dts=0,i.mp4track={id:E.getTrackID(),type:"audio",channelCount:0,len:0,fragmented:!0,timescale:e,duration:e,samples:[],config:"",codec:""},i.samples=[],i.aac=new A(c(i)),i}return i(r,[{key:"resetTrack",value:function(){this.readyToDecode=!1,this.mp4track.codec="",this.mp4track.channelCount="",this.mp4track.config="",this.mp4track.timescale=this.timescale,this.nextDts=0,this.dts=0}},{key:"remux",value:function(e){if(e.length>0)for(var t=0;t0&&this.readyToDecode&&(this.mp4track.len+=s,this.samples.push({units:a,size:s,keyFrame:i.keyFrame,duration:i.duration}))}}catch(e){n.e(e)}finally{n.f()}}},{key:"getPayload",value:function(){if(!this.isReady())return null;var e,t,n=new Uint8Array(this.mp4track.len),r=0,i=this.mp4track.samples;for(this.dts=this.nextDts;this.samples.length;){var a=this.samples.shift(),s=a.units;if((t=a.duration)<=0)k("remuxer: invalid sample duration at DTS: ".concat(this.nextDts," :").concat(t)),this.mp4track.len-=a.size;else{this.nextDts+=t,e={size:a.size,duration:t,cts:0,flags:{isLeading:0,isDependedOn:0,hasRedundancy:0,degradPrio:0,isNonSync:a.keyFrame?0:1,dependsOn:a.keyFrame?2:1}};var o,u=p(s);try{for(u.s();!(o=u.n()).done;){var c=o.value;n.set(c.getData(),r),r+=c.getSize()}}catch(e){u.e(e)}finally{u.f()}i.push(e)}}return i.length?new Uint8Array(n.buffer,0,this.mp4track.len):null}}]),r}(E),L=function(e){s(r,e);var t=f(r);function r(e){var i;return n(this,r),(i=t.call(this,"remuxer")).initialized=!1,i.trackTypes=[],i.tracks={},i.seq=1,i.env=e,i.timescale=1e3,i.mediaDuration=0,i}return i(r,[{key:"addTrack",value:function(e){"video"!==e&&"both"!==e||(this.tracks.video=new P(this.timescale),this.trackTypes.push("video")),"audio"!==e&&"both"!==e||(this.tracks.audio=new T(this.timescale),this.trackTypes.push("audio"))}},{key:"reset",value:function(){var e,t=p(this.trackTypes);try{for(t.s();!(e=t.n()).done;){var n=e.value;this.tracks[n].resetTrack()}}catch(e){t.e(e)}finally{t.f()}this.initialized=!1}},{key:"destroy",value:function(){this.tracks={},this.offAll()}},{key:"flush",value:function(){if(this.initialized){var e,t=p(this.trackTypes);try{for(t.s();!(e=t.n()).done;){var n=e.value,r=this.tracks[n],i=r.getPayload();if(i&&i.byteLength){var a={type:n,payload:S(B.moof(this.seq,r.dts,r.mp4track),B.mdat(i)),dts:r.dts};this.dispatch("buffer",a);var s=(o=r.dts/this.timescale,u=void 0,c=void 0,l=void 0,f=void 0,f="",u=Math.floor(o),(c=parseInt(u/3600,10)%24)>0&&(f+=(c<10?"0"+c:c)+":"),f+=((l=parseInt(u/60,10)%60)<10?"0"+l:l)+":"+((u=u<0?0:u%60)<10?"0"+u:u));k("put segment (".concat(n,"): dts: ").concat(r.dts," frames: ").concat(r.mp4track.samples.length," second: ").concat(s)),r.flush(),this.seq++}}}catch(e){t.e(e)}finally{t.f()}}else this.isReady()&&(this.dispatch("ready"),this.initSegment(),this.initialized=!0,this.flush());var o,u,c,l,f}},{key:"initSegment",value:function(){var e,t=[],n=p(this.trackTypes);try{for(n.s();!(e=n.n()).done;){var r=e.value,i=this.tracks[r];if("browser"==this.env){var a={type:r,payload:B.initSegment([i.mp4track],this.mediaDuration,this.timescale)};this.dispatch("buffer",a)}else t.push(i.mp4track)}}catch(e){n.e(e)}finally{n.f()}if("node"==this.env){var s={type:"all",payload:B.initSegment(t,this.mediaDuration,this.timescale)};this.dispatch("buffer",s)}k("Initial segment generated.")}},{key:"isReady",value:function(){var e,t=p(this.trackTypes);try{for(t.s();!(e=t.n()).done;){var n=e.value;if(!this.tracks[n].readyToDecode||!this.tracks[n].samples.length)return!1}}catch(e){t.e(e)}finally{t.f()}return!0}},{key:"remux",value:function(e){var t,n=p(this.trackTypes);try{for(n.s();!(t=n.n()).done;){var r=t.value,i=e[r];"audio"===r&&this.tracks.video&&!this.tracks.video.readyToDecode||i.length>0&&this.tracks[r].remux(i)}}catch(e){n.e(e)}finally{n.f()}this.flush()}}]),r}(C),R=function(e){s(r,e);var t=f(r);function r(e,i){var a;return n(this,r),(a=t.call(this,"buffer")).type=i,a.queue=new Uint8Array,a.cleaning=!1,a.pendingCleaning=0,a.cleanOffset=30,a.cleanRanges=[],a.sourceBuffer=e,a.sourceBuffer.addEventListener("updateend",(function(){a.pendingCleaning>0&&(a.initCleanup(a.pendingCleaning),a.pendingCleaning=0),a.cleaning=!1,a.cleanRanges.length&&a.doCleanup()})),a.sourceBuffer.addEventListener("error",(function(){a.dispatch("error",{type:a.type,name:"buffer",error:"buffer error"})})),a}return i(r,[{key:"destroy",value:function(){this.queue=null,this.sourceBuffer=null,this.offAll()}},{key:"doCleanup",value:function(){if(this.cleanRanges.length){var e=this.cleanRanges.shift();k("".concat(this.type," remove range [").concat(e[0]," - ").concat(e[1],")")),this.cleaning=!0,this.sourceBuffer.remove(e[0],e[1])}else this.cleaning=!1}},{key:"initCleanup",value:function(e){if(this.sourceBuffer.updating)this.pendingCleaning=e;else if(this.sourceBuffer.buffered&&this.sourceBuffer.buffered.length&&!this.cleaning){for(var t=0;tthis.cleanOffset&&n<(r=e-this.cleanOffset)&&this.cleanRanges.push([n,r])}this.doCleanup()}}},{key:"doAppend",value:function(){if(this.queue.length&&!this.sourceBuffer.updating)try{this.sourceBuffer.appendBuffer(this.queue),this.queue=new Uint8Array}catch(e){if("QuotaExceededError"===e.name)return k("".concat(this.type," buffer quota full")),void this.dispatch("error",{type:this.type,name:"QuotaExceeded",error:"buffer error"});g("Error occured while appending ".concat(this.type," buffer - ").concat(e.name,": ").concat(e.message)),this.dispatch("error",{type:this.type,name:"unexpectedError",error:"buffer error"})}}},{key:"feed",value:function(e){this.queue=S(this.queue,e)}}]),r}(C);return function(r){s(o,r);var a=f(o);function o(e){var r;n(this,o);return(r=a.call(this,"jmuxer")).options=Object.assign({},{node:"",mode:"both",flushingTime:1500,clearBuffer:!0,fps:30,debug:!1,onReady:function(){},onError:function(){}},e),r.env="object"===("undefined"==typeof process?"undefined":t(process))&&"undefined"==typeof window?"node":"browser",r.options.debug&&(v=console.log,m=console.error),r.options.fps||(r.options.fps=30),r.frameDuration=1e3/r.options.fps|0,r.remuxController=new L(r.env),r.remuxController.addTrack(r.options.mode),r.lastCleaningTime=Date.now(),r.kfPosition=[],r.kfCounter=0,r.pendingUnits={},r.remainingData=new Uint8Array,r.remuxController.on("buffer",r.onBuffer.bind(c(r))),"browser"==r.env&&(r.remuxController.on("ready",r.createBuffer.bind(c(r))),r.initBrowser()),r.startInterval(),r}return i(o,null,[{key:"isSupported",value:function(e){return window.MediaSource&&window.MediaSource.isTypeSupported(e)}}]),i(o,[{key:"initBrowser",value:function(){"string"==typeof this.options.node&&""==this.options.node&&g("no video element were found to render, provide a valid video element"),this.node="string"==typeof this.options.node?document.getElementById(this.options.node):this.options.node,this.mseReady=!1,this.setupMSE()}},{key:"createStream",value:function(){var t=this.feed.bind(this),n=this.destroy.bind(this);return this.stream=new e.Duplex({writableObjectMode:!0,read:function(e){},write:function(e,n,r){t(e),r()},final:function(e){n(),e()}}),this.stream}},{key:"setupMSE",value:function(){if(window.MediaSource=window.MediaSource||window.WebKitMediaSource,!window.MediaSource)throw"Oops! Browser does not support media source extension.";this.isMSESupported=!!window.MediaSource,this.mediaSource=new MediaSource,this.url=URL.createObjectURL(this.mediaSource),this.node.src=this.url,this.mseEnded=!1,this.mediaSource.addEventListener("sourceopen",this.onMSEOpen.bind(this)),this.mediaSource.addEventListener("sourceclose",this.onMSEClose.bind(this)),this.mediaSource.addEventListener("webkitsourceopen",this.onMSEOpen.bind(this)),this.mediaSource.addEventListener("webkitsourceclose",this.onMSEClose.bind(this))}},{key:"endMSE",value:function(){if(!this.mseEnded)try{this.mseEnded=!0,this.mediaSource.endOfStream()}catch(e){g("mediasource is not available to end")}}},{key:"feed",value:function(e){var t,n,r,i=!1,a={video:[],audio:[]};if(e&&this.remuxController){if(r=e.duration?parseInt(e.duration):0,e.video){e.video=S(this.remainingData,e.video);var s=h(U.extractNALu(e.video),2);t=s[0],n=s[1],t.length>0&&(a.video=this.getVideoFrames(t,r),i=!0),this.remainingData=n||new Uint8Array}e.audio&&(t=A.extractAAC(e.audio)).length>0&&(a.audio=this.getAudioFrames(t,r),i=!0),i?this.remuxController.remux(a):g("Input object must have video and/or audio property. Make sure it is a valid typed array")}}},{key:"getVideoFrames",value:function(e,t){var n,r=this,i=[],a=[],s=0,o=!1,u=!1;this.pendingUnits.units&&(i=this.pendingUnits.units,u=this.pendingUnits.vcl,o=this.pendingUnits.keyFrame,this.pendingUnits={});var c,l=p(e);try{for(l.s();!(c=l.n()).done;){var f=c.value,h=new b(f);h.type()!==b.IDR&&h.type()!==b.NDR||U.parseHeader(h),i.length&&u&&(h.isfmb||!h.isvcl)&&(a.push({units:i,keyFrame:o}),i=[],o=!1,u=!1),i.push(h),o=o||h.isKeyframe(),u=u||h.isvcl}}catch(e){l.e(e)}finally{l.f()}if(i.length)if(t)if(u)a.push({units:i,keyFrame:o});else{var d=a.length-1;a[d].units=a[d].units.concat(i)}else this.pendingUnits={units:i,keyFrame:o,vcl:u};return n=t?t/a.length|0:this.frameDuration,s=t?t-n*a.length:0,a.map((function(e){e.duration=n,s>0&&(e.duration++,s--),r.kfCounter++,e.keyFrame&&r.options.clearBuffer&&r.kfPosition.push(r.kfCounter*n/1e3)})),k("jmuxer: No. of frames of the last chunk: ".concat(a.length)),a}},{key:"getAudioFrames",value:function(e,t){var n,r,i=[],a=0,s=p(e);try{for(s.s();!(r=s.n()).done;){var o=r.value;i.push({units:o})}}catch(e){s.e(e)}finally{s.f()}return n=t?t/i.length|0:this.frameDuration,a=t?t-n*i.length:0,i.map((function(e){e.duration=n,a>0&&(e.duration++,a--)})),i}},{key:"destroy",value:function(){if(this.stopInterval(),this.stream&&(this.remuxController.flush(),this.stream.push(null),this.stream=null),this.remuxController&&(this.remuxController.destroy(),this.remuxController=null),this.bufferControllers){for(var e in this.bufferControllers)this.bufferControllers[e].destroy();this.bufferControllers=null,this.endMSE()}this.node=!1,this.mseReady=!1,this.videoStarted=!1,this.mediaSource=null}},{key:"reset",value:function(){if(this.node.pause(),this.remuxController&&this.remuxController.reset(),this.bufferControllers){for(var e in this.bufferControllers)this.bufferControllers[e].destroy();this.bufferControllers=null,this.endMSE()}"browser"==this.env&&this.initBrowser(),k("JMuxer was reset")}},{key:"createBuffer",value:function(){if(this.mseReady&&this.remuxController&&this.remuxController.isReady()&&!this.bufferControllers)for(var e in this.bufferControllers={},this.remuxController.tracks){var t=this.remuxController.tracks[e];if(!o.isSupported("".concat(e,'/mp4; codecs="').concat(t.mp4track.codec,'"')))return g("Browser does not support codec"),!1;var n=this.mediaSource.addSourceBuffer("".concat(e,'/mp4; codecs="').concat(t.mp4track.codec,'"'));this.bufferControllers[e]=new R(n,e),this.bufferControllers[e].on("error",this.onBufferError.bind(this))}}},{key:"startInterval",value:function(){var e=this;this.interval=setInterval((function(){e.bufferControllers&&(e.releaseBuffer(),e.clearBuffer())}),this.options.flushingTime)}},{key:"stopInterval",value:function(){this.interval&&clearInterval(this.interval)}},{key:"releaseBuffer",value:function(){for(var e in this.bufferControllers)this.bufferControllers[e].doAppend()}},{key:"getSafeClearOffsetOfBuffer",value:function(e){for(var t,n="audio"===this.options.mode&&e||0,r=0;r=e);r++)t=this.kfPosition[r];return t&&(this.kfPosition=this.kfPosition.filter((function(e){return e=t}))),n}},{key:"clearBuffer",value:function(){if(this.options.clearBuffer&&Date.now()-this.lastCleaningTime>1e4){for(var e in this.bufferControllers){var t=this.getSafeClearOffsetOfBuffer(this.node.currentTime);this.bufferControllers[e].initCleanup(t)}this.lastCleaningTime=Date.now()}}},{key:"onBuffer",value:function(e){"browser"==this.env?this.bufferControllers&&this.bufferControllers[e.type]&&this.bufferControllers[e.type].feed(e.payload):this.stream&&this.stream.push(e.payload)}},{key:"onMSEOpen",value:function(){this.mseReady=!0,"function"==typeof this.options.onReady&&this.options.onReady.call(null),URL.revokeObjectURL(this.url),this.createBuffer()}},{key:"onMSEClose",value:function(){this.mseReady=!1,this.videoStarted=!1}},{key:"onBufferError",value:function(e){"QuotaExceeded"!=e.name?(this.endMSE(),"function"==typeof this.options.onError&&this.options.onError.call(null,e)):this.bufferControllers[e.type].initCleanup(this.node.currentTime)}}]),o}(C)}));