123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577 |
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.JMuxer = factory());
- }(this, (function () { 'use strict';
- 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 _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 _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 || this.stype === 7;
- }
- }, {
- 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;
- }();
- /**
- * 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 = [],
- lastIndex;
- 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) {
- result.push(buffer.subarray(lastIndex, i - state - 1));
- }
- lastIndex = i;
- state = 0;
- } else {
- state = 0;
- }
- break;
- }
- }
- if (lastIndex) {
- result.push(buffer.subarray(lastIndex, length));
- }
- return result;
- }
- /**
- * 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 () {
- _createClass(BaseRemuxer, null, [{
- key: "getTrackID",
- value: function getTrackID() {
- return track_id++;
- }
- }]);
- function BaseRemuxer() {
- _classCallCheck(this, BaseRemuxer);
- this.seq = 1;
- }
- _createClass(BaseRemuxer, [{
- key: "flush",
- value: function flush() {
- this.seq++;
- this.mp4track.len = 0;
- this.mp4track.samples = [];
- }
- }, {
- key: "isReady",
- value: function isReady() {
- if (!this.readyToDecode || !this.samples.length) return null;
- return true;
- }
- }]);
- return BaseRemuxer;
- }();
- var AACRemuxer = /*#__PURE__*/function (_BaseRemuxer) {
- _inherits(AACRemuxer, _BaseRemuxer);
- var _super = _createSuper(AACRemuxer);
- function AACRemuxer() {
- var _this;
- _classCallCheck(this, AACRemuxer);
- _this = _super.call(this);
- _this.readyToDecode = false;
- _this.nextDts = 0;
- _this.dts = 0;
- _this.timescale = 1000;
- _this.mp4track = {
- id: BaseRemuxer.getTrackID(),
- type: 'audio',
- channelCount: 0,
- len: 0,
- fragmented: true,
- timescale: _this.timescale,
- duration: _this.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;
- }
- }, {
- 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() {
- var _this;
- _classCallCheck(this, H264Remuxer);
- _this = _super.call(this);
- _this.readyToDecode = false;
- _this.nextDts = 0;
- _this.dts = 0;
- _this.timescale = 1000;
- _this.mp4track = {
- id: BaseRemuxer.getTrackID(),
- type: 'video',
- len: 0,
- fragmented: true,
- sps: '',
- pps: '',
- width: 0,
- height: 0,
- timescale: _this.timescale,
- duration: _this.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 = '';
- }
- }, {
- 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);
- 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;
- }
- var RemuxController = /*#__PURE__*/function (_Event) {
- _inherits(RemuxController, _Event);
- var _super = _createSuper(RemuxController);
- function RemuxController(streaming) {
- var _this;
- _classCallCheck(this, RemuxController);
- _this = _super.call(this, 'remuxer');
- _this.initialized = false;
- _this.trackTypes = [];
- _this.tracks = {};
- _this.mediaDuration = streaming ? Infinity : 1000;
- return _this;
- }
- _createClass(RemuxController, [{
- key: "addTrack",
- value: function addTrack(type) {
- if (type === 'video' || type === 'both') {
- this.tracks.video = new H264Remuxer();
- this.trackTypes.push('video');
- }
- if (type === 'audio' || type === 'both') {
- this.tracks.audio = new AACRemuxer();
- 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');
- var _iterator2 = _createForOfIteratorHelper(this.trackTypes),
- _step2;
- try {
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
- var type = _step2.value;
- var track = this.tracks[type];
- var data = {
- type: type,
- payload: MP4.initSegment([track.mp4track], this.mediaDuration, track.mp4track.timescale)
- };
- this.dispatch('buffer', data);
- }
- } catch (err) {
- _iterator2.e(err);
- } finally {
- _iterator2.f();
- }
- log('Initial segment generated.');
- this.initialized = true;
- this.flush();
- }
- } else {
- var _iterator3 = _createForOfIteratorHelper(this.trackTypes),
- _step3;
- try {
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
- var _type = _step3.value;
- var _track = this.tracks[_type];
- var pay = _track.getPayload();
- if (pay && pay.byteLength) {
- var moof = MP4.moof(_track.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 / 1000);
- log("put segment (".concat(_type, "): ").concat(_track.seq, " dts: ").concat(_track.dts, " gop: ").concat(_track.mp4track.samples.length, " second: ").concat(duration));
- _track.flush();
- }
- }
- } catch (err) {
- _iterator3.e(err);
- } finally {
- _iterator3.f();
- }
- }
- }
- }, {
- 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 () {
- console.log("sourceBuffer解码错误");
- _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();
- //range[0] = 0;
- //range[1] = 5000;
- //console.log("起始%d:%d,终止 %d:%d", range[0]/60, range[0]%60, range[1]/60, range[1]%60);
- //log("".concat(this.type, " remove range [").concat(range[0], " - ").concat(range[1], ")"));
- this.cleaning = true;
- //暂时移除
- //console.log("10s清理缓存");
- 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);
- window.MediaSource = window.MediaSource || window.WebKitMediaSource;
- var JMuxmer = /*#__PURE__*/function (_Event) {
- _inherits(JMuxmer, _Event);
- var _super = _createSuper(JMuxmer);
- _createClass(JMuxmer, null, [{
- key: "isSupported",
- value: function isSupported(codec) {
- return window.MediaSource && window.MediaSource.isTypeSupported(codec);
- }
- }]);
- function JMuxmer(options) {
- var _this;
- _classCallCheck(this, JMuxmer);
- _this = _super.call(this, 'jmuxer');
- window.MediaSource = window.MediaSource || window.WebKitMediaSource;
- var defaults = {
- node: '',
- mode: 'both',
- // both, audio, video
- flushingTime: 1500,
- clearBuffer: true,
- onReady: null,
- // function called when MSE is ready to accept frames
- fps: 30,
- debug: false
- };
- _this.options = Object.assign({}, defaults, options);
- if (_this.options.debug) {
- setLogger();
- }
- if (typeof _this.options.node === 'string' && _this.options.node == '') {
- error('no video element were found to render, provide a valid video element');
- }
- if (!_this.options.fps) {
- _this.options.fps = 30;
- }
- _this.frameDuration = 1000 / _this.options.fps | 0; // todo remove
- _this.node = typeof _this.options.node === 'string' ? document.getElementById(_this.options.node) : _this.options.node;
- _this.sourceBuffers = {};
- _this.isMSESupported = !!window.MediaSource;
- if (!_this.isMSESupported) {
- throw 'Oops! Browser does not support media source extension.';
- }
- _this.setupMSE();
- _this.remuxController = new RemuxController(_this.options.clearBuffer);
- _this.remuxController.addTrack(_this.options.mode);
- _this.mseReady = false;
- _this.lastCleaningTime = Date.now();
- _this.kfPosition = [];
- _this.kfCounter = 0;
- /* events callback */
- _this.remuxController.on('buffer', _this.onBuffer.bind(_assertThisInitialized(_this)));
- _this.remuxController.on('ready', _this.createBuffer.bind(_assertThisInitialized(_this)));
- _this.startInterval();
- return _this;
- }
- _createClass(JMuxmer, [{
- key: "setupMSE",
- value: function setupMSE() {
- this.mediaSource = new MediaSource();
- this.node.src = URL.createObjectURL(this.mediaSource);
- 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: "feed",
- value: function feed(data) {
- var remux = false,
- slices,
- duration,
- chunks = {
- video: [],
- audio: []
- };
- if (!data || !this.remuxController) return;
- duration = data.duration ? parseInt(data.duration) : 0;
- if (data.video) {
- slices = H264Parser.extractNALu(data.video);
- if (slices.length > 0) {
- chunks.video = this.getVideoFrames(slices, duration);
- remux = true;
- }
- }
- 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;
- 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) {
- if (vcl || !frames.length) {
- 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.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.remuxController) {
- this.remuxController.destroy();
- this.remuxController = null;
- }
- if (this.bufferControllers) {
- for (var type in this.bufferControllers) {
- this.bufferControllers[type].destroy();
- }
- this.bufferControllers = null;
- }
- this.node = false;
- this.mseReady = false;
- this.videoStarted = false;
- }
- }, {
- 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 (!JMuxmer.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 > 5000)
- {
- for (var type in this.bufferControllers)
- {
- var cleanMaxLimit = this.getSafeClearOffsetOfBuffer(this.node.currentTime);
- //console.log(type + ",时间" + this.node.currentTime);
- this.bufferControllers[type].initCleanup(cleanMaxLimit);
- }
- this.lastCleaningTime = Date.now();
- }
- }
- }, {
- key: "onBuffer",
- value: function onBuffer(data) {
- if (this.bufferControllers && this.bufferControllers[data.type]) {
- this.bufferControllers[data.type].feed(data.payload);
- }
- }
- /* Events on MSE */
- }, {
- key: "onMSEOpen",
- value: function onMSEOpen() {
- this.mseReady = true;
- if (typeof this.options.onReady === 'function') {
- this.options.onReady();
- this.options.onReady = null;
- }
- 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;
- }
- 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');
- }
- }
- }
- }]);
- return JMuxmer;
- }(Event);
- return JMuxmer;
- })));
|