jmuxer 2.0.2 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/jmuxer.js CHANGED
@@ -2,7 +2,7 @@
2
2
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('stream')) :
3
3
  typeof define === 'function' && define.amd ? define(['stream'], factory) :
4
4
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.JMuxer = factory(global.stream));
5
- }(this, (function (stream) { 'use strict';
5
+ })(this, (function (stream) { 'use strict';
6
6
 
7
7
  function _typeof(obj) {
8
8
  "@babel/helpers - typeof";
@@ -94,7 +94,7 @@
94
94
  if (typeof Proxy === "function") return true;
95
95
 
96
96
  try {
97
- Date.prototype.toString.call(Reflect.construct(Date, [], function () {}));
97
+ Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
98
98
  return true;
99
99
  } catch (e) {
100
100
  return false;
@@ -112,6 +112,8 @@
112
112
  function _possibleConstructorReturn(self, call) {
113
113
  if (call && (typeof call === "object" || typeof call === "function")) {
114
114
  return call;
115
+ } else if (call !== void 0) {
116
+ throw new TypeError("Derived constructors may only return object or undefined");
115
117
  }
116
118
 
117
119
  return _assertThisInitialized(self);
@@ -145,14 +147,17 @@
145
147
  }
146
148
 
147
149
  function _iterableToArrayLimit(arr, i) {
148
- if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
150
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
151
+
152
+ if (_i == null) return;
149
153
  var _arr = [];
150
154
  var _n = true;
151
155
  var _d = false;
152
- var _e = undefined;
156
+
157
+ var _s, _e;
153
158
 
154
159
  try {
155
- for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
160
+ for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
156
161
  _arr.push(_s.value);
157
162
 
158
163
  if (i && _arr.length === i) break;
@@ -193,9 +198,9 @@
193
198
  }
194
199
 
195
200
  function _createForOfIteratorHelper(o, allowArrayLike) {
196
- var it;
201
+ var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
197
202
 
198
- if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) {
203
+ if (!it) {
199
204
  if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
200
205
  if (it) o = it;
201
206
  var i = 0;
@@ -228,7 +233,7 @@
228
233
  err;
229
234
  return {
230
235
  s: function () {
231
- it = o[Symbol.iterator]();
236
+ it = it.call(o);
232
237
  },
233
238
  n: function () {
234
239
  var step = it.next();
@@ -277,54 +282,6 @@
277
282
  }
278
283
 
279
284
  var NALU = /*#__PURE__*/function () {
280
- _createClass(NALU, null, [{
281
- key: "type",
282
- value: function type(nalu) {
283
- if (nalu.ntype in NALU.TYPES) {
284
- return NALU.TYPES[nalu.ntype];
285
- } else {
286
- return 'UNKNOWN';
287
- }
288
- }
289
- }, {
290
- key: "NDR",
291
- get: function get() {
292
- return 1;
293
- }
294
- }, {
295
- key: "IDR",
296
- get: function get() {
297
- return 5;
298
- }
299
- }, {
300
- key: "SEI",
301
- get: function get() {
302
- return 6;
303
- }
304
- }, {
305
- key: "SPS",
306
- get: function get() {
307
- return 7;
308
- }
309
- }, {
310
- key: "PPS",
311
- get: function get() {
312
- return 8;
313
- }
314
- }, {
315
- key: "AUD",
316
- get: function get() {
317
- return 9;
318
- }
319
- }, {
320
- key: "TYPES",
321
- get: function get() {
322
- var _ref;
323
-
324
- 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;
325
- }
326
- }]);
327
-
328
285
  function NALU(data) {
329
286
  _classCallCheck(this, NALU);
330
287
 
@@ -382,6 +339,52 @@
382
339
  result.set(this.getPayload(), 4);
383
340
  return result;
384
341
  }
342
+ }], [{
343
+ key: "NDR",
344
+ get: function get() {
345
+ return 1;
346
+ }
347
+ }, {
348
+ key: "IDR",
349
+ get: function get() {
350
+ return 5;
351
+ }
352
+ }, {
353
+ key: "SEI",
354
+ get: function get() {
355
+ return 6;
356
+ }
357
+ }, {
358
+ key: "SPS",
359
+ get: function get() {
360
+ return 7;
361
+ }
362
+ }, {
363
+ key: "PPS",
364
+ get: function get() {
365
+ return 8;
366
+ }
367
+ }, {
368
+ key: "AUD",
369
+ get: function get() {
370
+ return 9;
371
+ }
372
+ }, {
373
+ key: "TYPES",
374
+ get: function get() {
375
+ var _ref;
376
+
377
+ 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;
378
+ }
379
+ }, {
380
+ key: "type",
381
+ value: function type(nalu) {
382
+ if (nalu.ntype in NALU.TYPES) {
383
+ return NALU.TYPES[nalu.ntype];
384
+ } else {
385
+ return 'UNKNOWN';
386
+ }
387
+ }
385
388
  }]);
386
389
 
387
390
  return NALU;
@@ -424,6 +427,18 @@
424
427
  }
425
428
 
426
429
  _createClass(ExpGolomb, [{
430
+ key: "setData",
431
+ value: function setData(data) {
432
+ this.data = data;
433
+ this.index = 0;
434
+ this.bitLength = data.byteLength * 8;
435
+ }
436
+ }, {
437
+ key: "bitsAvailable",
438
+ get: function get() {
439
+ return this.bitLength - this.index;
440
+ }
441
+ }, {
427
442
  key: "skipBits",
428
443
  value: function skipBits(size) {
429
444
  // console.log(` skip bits: size=${size}, ${this.index}.`);
@@ -538,18 +553,93 @@
538
553
  value: function readUInt() {
539
554
  return this.readBits(32);
540
555
  }
541
- }, {
542
- key: "bitsAvailable",
543
- get: function get() {
544
- return this.bitLength - this.index;
545
- }
546
556
  }]);
547
557
 
548
558
  return ExpGolomb;
549
559
  }();
550
560
 
551
561
  var H264Parser = /*#__PURE__*/function () {
552
- _createClass(H264Parser, null, [{
562
+ function H264Parser(remuxer) {
563
+ _classCallCheck(this, H264Parser);
564
+
565
+ this.remuxer = remuxer;
566
+ this.track = remuxer.mp4track;
567
+ }
568
+
569
+ _createClass(H264Parser, [{
570
+ key: "parseSPS",
571
+ value: function parseSPS(sps) {
572
+ var config = H264Parser.readSPS(new Uint8Array(sps));
573
+ this.track.fps = config.fps;
574
+ this.track.width = config.width;
575
+ this.track.height = config.height;
576
+ this.track.sps = [new Uint8Array(sps)];
577
+ this.track.codec = 'avc1.';
578
+ var codecarray = new DataView(sps.buffer, sps.byteOffset + 1, 4);
579
+
580
+ for (var i = 0; i < 3; ++i) {
581
+ var h = codecarray.getUint8(i).toString(16);
582
+
583
+ if (h.length < 2) {
584
+ h = '0' + h;
585
+ }
586
+
587
+ this.track.codec += h;
588
+ }
589
+ }
590
+ }, {
591
+ key: "parsePPS",
592
+ value: function parsePPS(pps) {
593
+ this.track.pps = [new Uint8Array(pps)];
594
+ }
595
+ }, {
596
+ key: "parseNAL",
597
+ value: function parseNAL(unit) {
598
+ if (!unit) return false;
599
+ var push = false;
600
+
601
+ switch (unit.type()) {
602
+ case NALU.IDR:
603
+ case NALU.NDR:
604
+ push = true;
605
+ break;
606
+
607
+ case NALU.PPS:
608
+ if (!this.track.pps) {
609
+ this.parsePPS(unit.getPayload());
610
+
611
+ if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) {
612
+ this.remuxer.readyToDecode = true;
613
+ }
614
+ }
615
+
616
+ push = true;
617
+ break;
618
+
619
+ case NALU.SPS:
620
+ if (!this.track.sps) {
621
+ this.parseSPS(unit.getPayload());
622
+
623
+ if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) {
624
+ this.remuxer.readyToDecode = true;
625
+ }
626
+ }
627
+
628
+ push = true;
629
+ break;
630
+
631
+ case NALU.AUD:
632
+ log('AUD - ignoing');
633
+ break;
634
+
635
+ case NALU.SEI:
636
+ log('SEI - ignoing');
637
+ break;
638
+ }
639
+
640
+ return push;
641
+ }
642
+ }], [{
553
643
  key: "extractNALu",
554
644
  value: function extractNALu(buffer) {
555
645
  var i = 0,
@@ -650,21 +740,40 @@
650
740
  frameCropBottomOffset = 0,
651
741
  sarScale = 1,
652
742
  profileIdc,
653
- profileCompat,
654
- levelIdc,
655
743
  numRefFramesInPicOrderCntCycle,
656
744
  picWidthInMbsMinus1,
657
745
  picHeightInMapUnitsMinus1,
658
746
  frameMbsOnlyFlag,
659
- scalingListCount;
660
- decoder.readUByte();
747
+ scalingListCount,
748
+ fps = 0;
749
+ decoder.readUByte(); // skip NAL header
750
+ // rewrite NAL
751
+
752
+ var rbsp = [],
753
+ hdr_bytes = 1,
754
+ nal_bytes = data.byteLength;
755
+
756
+ for (var i = hdr_bytes; i < nal_bytes; i++) {
757
+ if (i + 2 < nal_bytes && decoder.readBits(24, false) === 0x000003) {
758
+ rbsp.push(decoder.readBits(8));
759
+ rbsp.push(decoder.readBits(8));
760
+ i += 2; // emulation_prevention_three_byte
761
+
762
+ decoder.readBits(8);
763
+ } else {
764
+ rbsp.push(decoder.readBits(8));
765
+ }
766
+ }
767
+
768
+ decoder.setData(new Uint8Array(rbsp)); // end of rewrite data
769
+
661
770
  profileIdc = decoder.readUByte(); // profile_idc
662
771
 
663
- profileCompat = decoder.readBits(5); // constraint_set[0-4]_flag, u(5)
772
+ decoder.readBits(5); // constraint_set[0-4]_flag, u(5)
664
773
 
665
774
  decoder.skipBits(3); // reserved_zero_3bits u(3),
666
775
 
667
- levelIdc = decoder.readUByte(); // level_idc u(8)
776
+ decoder.readUByte(); // level_idc u(8)
668
777
 
669
778
  decoder.skipUEG(); // seq_parameter_set_id
670
779
  // some profiles have more optional data we don't need
@@ -686,10 +795,10 @@
686
795
  // seq_scaling_matrix_present_flag
687
796
  scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
688
797
 
689
- for (var i = 0; i < scalingListCount; ++i) {
798
+ for (var _i = 0; _i < scalingListCount; ++_i) {
690
799
  if (decoder.readBoolean()) {
691
800
  // seq_scaling_list_present_flag[ i ]
692
- if (i < 6) {
801
+ if (_i < 6) {
693
802
  H264Parser.skipScalingList(decoder, 16);
694
803
  } else {
695
804
  H264Parser.skipScalingList(decoder, 64);
@@ -714,7 +823,7 @@
714
823
 
715
824
  numRefFramesInPicOrderCntCycle = decoder.readUEG();
716
825
 
717
- for (var _i = 0; _i < numRefFramesInPicOrderCntCycle; ++_i) {
826
+ for (var _i2 = 0; _i2 < numRefFramesInPicOrderCntCycle; ++_i2) {
718
827
  decoder.skipEG(); // offset_for_ref_frame[ i ]
719
828
  }
720
829
  }
@@ -820,7 +929,7 @@
820
929
  }
821
930
  }
822
931
 
823
- if (sarRatio) {
932
+ if (sarRatio && sarRatio[0] > 0 && sarRatio[1] > 0) {
824
933
  sarScale = sarRatio[0] / sarRatio[1];
825
934
  }
826
935
  }
@@ -846,10 +955,16 @@
846
955
  var unitsInTick = decoder.readUInt();
847
956
  var timeScale = decoder.readUInt();
848
957
  var fixedFrameRate = decoder.readBoolean();
958
+ var frameDuration = timeScale / (2 * unitsInTick);
959
+
960
+ if (fixedFrameRate) {
961
+ fps = frameDuration;
962
+ }
849
963
  }
850
964
  }
851
965
 
852
966
  return {
967
+ fps: fps > 0 ? fps : undefined,
853
968
  width: Math.ceil(((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale),
854
969
  height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset)
855
970
  };
@@ -865,108 +980,18 @@
865
980
  }
866
981
  }]);
867
982
 
868
- function H264Parser(remuxer) {
869
- _classCallCheck(this, H264Parser);
983
+ return H264Parser;
984
+ }();
985
+
986
+ var AACParser = /*#__PURE__*/function () {
987
+ function AACParser(remuxer) {
988
+ _classCallCheck(this, AACParser);
870
989
 
871
990
  this.remuxer = remuxer;
872
991
  this.track = remuxer.mp4track;
873
992
  }
874
993
 
875
- _createClass(H264Parser, [{
876
- key: "parseSPS",
877
- value: function parseSPS(sps) {
878
- var config = H264Parser.readSPS(new Uint8Array(sps));
879
- this.track.width = config.width;
880
- this.track.height = config.height;
881
- this.track.sps = [new Uint8Array(sps)];
882
- this.track.codec = 'avc1.';
883
- var codecarray = new DataView(sps.buffer, sps.byteOffset + 1, 4);
884
-
885
- for (var i = 0; i < 3; ++i) {
886
- var h = codecarray.getUint8(i).toString(16);
887
-
888
- if (h.length < 2) {
889
- h = '0' + h;
890
- }
891
-
892
- this.track.codec += h;
893
- }
894
- }
895
- }, {
896
- key: "parsePPS",
897
- value: function parsePPS(pps) {
898
- this.track.pps = [new Uint8Array(pps)];
899
- }
900
- }, {
901
- key: "parseNAL",
902
- value: function parseNAL(unit) {
903
- if (!unit) return false;
904
- var push = false;
905
-
906
- switch (unit.type()) {
907
- case NALU.IDR:
908
- case NALU.NDR:
909
- push = true;
910
- break;
911
-
912
- case NALU.PPS:
913
- if (!this.track.pps) {
914
- this.parsePPS(unit.getPayload());
915
-
916
- if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) {
917
- this.remuxer.readyToDecode = true;
918
- }
919
- }
920
-
921
- push = true;
922
- break;
923
-
924
- case NALU.SPS:
925
- if (!this.track.sps) {
926
- this.parseSPS(unit.getPayload());
927
-
928
- if (!this.remuxer.readyToDecode && this.track.pps && this.track.sps) {
929
- this.remuxer.readyToDecode = true;
930
- }
931
- }
932
-
933
- push = true;
934
- break;
935
-
936
- case NALU.AUD:
937
- log('AUD - ignoing');
938
- break;
939
-
940
- case NALU.SEI:
941
- log('SEI - ignoing');
942
- break;
943
- }
944
-
945
- return push;
946
- }
947
- }]);
948
-
949
- return H264Parser;
950
- }();
951
-
952
- var aacHeader;
953
- var AACParser = /*#__PURE__*/function () {
954
- _createClass(AACParser, null, [{
955
- key: "getHeaderLength",
956
- value: function getHeaderLength(data) {
957
- return data[1] & 0x01 ? 7 : 9; // without CRC 7 and with CRC 9 Refs: https://wiki.multimedia.cx/index.php?title=ADTS
958
- }
959
- }, {
960
- key: "getFrameLength",
961
- value: function getFrameLength(data) {
962
- return (data[3] & 0x03) << 11 | data[4] << 3 | (data[5] & 0xE0) >>> 5; // 13 bits length ref: https://wiki.multimedia.cx/index.php?title=ADTS
963
- }
964
- }, {
965
- key: "isAACPattern",
966
- value: function isAACPattern(data) {
967
- return data[0] === 0xff && (data[1] & 0xf0) === 0xf0 && (data[1] & 0x06) === 0x00;
968
- }
969
- }, {
994
+ _createClass(AACParser, [{
970
995
  key: "extractAAC",
971
996
  value: function extractAAC(buffer) {
972
997
  var i = 0,
@@ -982,8 +1007,8 @@
982
1007
 
983
1008
  headerLength = AACParser.getHeaderLength(buffer);
984
1009
 
985
- if (!aacHeader) {
986
- aacHeader = buffer.subarray(0, headerLength);
1010
+ if (!this.aacHeader) {
1011
+ this.aacHeader = buffer.subarray(0, headerLength);
987
1012
  }
988
1013
 
989
1014
  while (i < length) {
@@ -996,32 +1021,13 @@
996
1021
  return result;
997
1022
  }
998
1023
  }, {
999
- key: "samplingRateMap",
1000
- get: function get() {
1001
- return [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
1002
- }
1003
- }, {
1004
- key: "getAACHeaderData",
1005
- get: function get() {
1006
- return aacHeader;
1007
- }
1008
- }]);
1009
-
1010
- function AACParser(remuxer) {
1011
- _classCallCheck(this, AACParser);
1012
-
1013
- this.remuxer = remuxer;
1014
- this.track = remuxer.mp4track;
1015
- }
1016
-
1017
- _createClass(AACParser, [{
1018
1024
  key: "setAACConfig",
1019
1025
  value: function setAACConfig() {
1020
1026
  var objectType,
1021
1027
  sampleIndex,
1022
1028
  channelCount,
1023
1029
  config = new Uint8Array(2),
1024
- headerData = AACParser.getAACHeaderData;
1030
+ headerData = this.aacHeader;
1025
1031
  if (!headerData) return;
1026
1032
  objectType = ((headerData[2] & 0xC0) >>> 6) + 1;
1027
1033
  sampleIndex = (headerData[2] & 0x3C) >>> 2;
@@ -1038,6 +1044,26 @@
1038
1044
  this.track.config = config;
1039
1045
  this.remuxer.readyToDecode = true;
1040
1046
  }
1047
+ }], [{
1048
+ key: "samplingRateMap",
1049
+ get: function get() {
1050
+ return [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
1051
+ }
1052
+ }, {
1053
+ key: "getHeaderLength",
1054
+ value: function getHeaderLength(data) {
1055
+ return data[1] & 0x01 ? 7 : 9; // without CRC 7 and with CRC 9 Refs: https://wiki.multimedia.cx/index.php?title=ADTS
1056
+ }
1057
+ }, {
1058
+ key: "getFrameLength",
1059
+ value: function getFrameLength(data) {
1060
+ return (data[3] & 0x03) << 11 | data[4] << 3 | (data[5] & 0xE0) >>> 5; // 13 bits length ref: https://wiki.multimedia.cx/index.php?title=ADTS
1061
+ }
1062
+ }, {
1063
+ key: "isAACPattern",
1064
+ value: function isAACPattern(data) {
1065
+ return data[0] === 0xff && (data[1] & 0xf0) === 0xf0 && (data[1] & 0x06) === 0x00;
1066
+ }
1041
1067
  }]);
1042
1068
 
1043
1069
  return AACParser;
@@ -1719,8 +1745,8 @@
1719
1745
  this.dts = this.nextDts;
1720
1746
 
1721
1747
  while (this.samples.length) {
1722
- var sample = this.samples.shift(),
1723
- units = sample.units;
1748
+ var sample = this.samples.shift();
1749
+ sample.units;
1724
1750
  duration = sample.duration;
1725
1751
 
1726
1752
  if (duration <= 0) {
@@ -1750,6 +1776,11 @@
1750
1776
  if (!samples.length) return null;
1751
1777
  return new Uint8Array(payload.buffer, 0, this.mp4track.len);
1752
1778
  }
1779
+ }, {
1780
+ key: "getAacParser",
1781
+ value: function getAacParser() {
1782
+ return this.aac;
1783
+ }
1753
1784
  }]);
1754
1785
 
1755
1786
  return AACRemuxer;
@@ -1776,6 +1807,7 @@
1776
1807
  fragmented: true,
1777
1808
  sps: '',
1778
1809
  pps: '',
1810
+ fps: 30,
1779
1811
  width: 0,
1780
1812
  height: 0,
1781
1813
  timescale: timescale,
@@ -1832,7 +1864,8 @@
1832
1864
  units: units,
1833
1865
  size: size,
1834
1866
  keyFrame: frame.keyFrame,
1835
- duration: frame.duration
1867
+ duration: frame.duration,
1868
+ compositionTimeOffset: frame.compositionTimeOffset
1836
1869
  });
1837
1870
  }
1838
1871
  }
@@ -1870,7 +1903,7 @@
1870
1903
  mp4Sample = {
1871
1904
  size: sample.size,
1872
1905
  duration: duration,
1873
- cts: 0,
1906
+ cts: sample.compositionTimeOffset || 0,
1874
1907
  flags: {
1875
1908
  isLeading: 0,
1876
1909
  isDependedOn: 0,
@@ -1925,6 +1958,7 @@
1925
1958
  _this.env = env;
1926
1959
  _this.timescale = 1000;
1927
1960
  _this.mediaDuration = 0;
1961
+ _this.aacParser = null;
1928
1962
  return _this;
1929
1963
  }
1930
1964
 
@@ -1937,7 +1971,9 @@
1937
1971
  }
1938
1972
 
1939
1973
  if (type === 'audio' || type === 'both') {
1940
- this.tracks.audio = new AACRemuxer(this.timescale);
1974
+ var aacRemuxer = new AACRemuxer(this.timescale);
1975
+ this.aacParser = aacRemuxer.getAacParser();
1976
+ this.tracks.audio = aacRemuxer;
1941
1977
  this.trackTypes.push('audio');
1942
1978
  }
1943
1979
  }
@@ -1995,6 +2031,11 @@
1995
2031
  payload: payload,
1996
2032
  dts: track.dts
1997
2033
  };
2034
+
2035
+ if (type === 'video') {
2036
+ data.fps = track.mp4track.fps;
2037
+ }
2038
+
1998
2039
  this.dispatch('buffer', data);
1999
2040
  var duration = secToTime(track.dts / this.timescale);
2000
2041
  log("put segment (".concat(type, "): dts: ").concat(track.dts, " frames: ").concat(track.mp4track.samples.length, " second: ").concat(duration));
@@ -2166,55 +2207,55 @@
2166
2207
  }, {
2167
2208
  key: "initCleanup",
2168
2209
  value: function initCleanup(cleanMaxLimit) {
2169
- if (this.sourceBuffer.updating) {
2170
- this.pendingCleaning = cleanMaxLimit;
2171
- return;
2172
- }
2210
+ try {
2211
+ if (this.sourceBuffer.updating) {
2212
+ this.pendingCleaning = cleanMaxLimit;
2213
+ return;
2214
+ }
2173
2215
 
2174
- if (this.sourceBuffer.buffered && this.sourceBuffer.buffered.length && !this.cleaning) {
2175
- for (var i = 0; i < this.sourceBuffer.buffered.length; ++i) {
2176
- var start = this.sourceBuffer.buffered.start(i);
2177
- var end = this.sourceBuffer.buffered.end(i);
2216
+ if (this.sourceBuffer.buffered && this.sourceBuffer.buffered.length && !this.cleaning) {
2217
+ for (var i = 0; i < this.sourceBuffer.buffered.length; ++i) {
2218
+ var start = this.sourceBuffer.buffered.start(i);
2219
+ var end = this.sourceBuffer.buffered.end(i);
2178
2220
 
2179
- if (cleanMaxLimit - start > this.cleanOffset) {
2180
- end = cleanMaxLimit - this.cleanOffset;
2221
+ if (cleanMaxLimit - start > this.cleanOffset) {
2222
+ end = cleanMaxLimit - this.cleanOffset;
2181
2223
 
2182
- if (start < end) {
2183
- this.cleanRanges.push([start, end]);
2224
+ if (start < end) {
2225
+ this.cleanRanges.push([start, end]);
2226
+ }
2184
2227
  }
2185
2228
  }
2186
- }
2187
2229
 
2188
- this.doCleanup();
2230
+ this.doCleanup();
2231
+ }
2232
+ } catch (e) {
2233
+ error("Error occured while cleaning ".concat(this.type, " buffer - ").concat(e.name, ": ").concat(e.message));
2189
2234
  }
2190
2235
  }
2191
2236
  }, {
2192
2237
  key: "doAppend",
2193
2238
  value: function doAppend() {
2194
2239
  if (!this.queue.length) return;
2195
-
2196
- if (this.sourceBuffer.updating) {
2197
- return;
2198
- }
2240
+ if (!this.sourceBuffer || this.sourceBuffer.updating) return;
2199
2241
 
2200
2242
  try {
2201
2243
  this.sourceBuffer.appendBuffer(this.queue);
2202
2244
  this.queue = new Uint8Array();
2203
2245
  } catch (e) {
2246
+ var name = 'unexpectedError';
2247
+
2204
2248
  if (e.name === 'QuotaExceededError') {
2205
2249
  log("".concat(this.type, " buffer quota full"));
2206
- this.dispatch('error', {
2207
- type: this.type,
2208
- name: 'QuotaExceeded',
2209
- error: 'buffer error'
2210
- });
2211
- return;
2250
+ name = 'QuotaExceeded';
2251
+ } else {
2252
+ error("Error occured while appending ".concat(this.type, " buffer - ").concat(e.name, ": ").concat(e.message));
2253
+ name = 'InvalidStateError';
2212
2254
  }
2213
2255
 
2214
- error("Error occured while appending ".concat(this.type, " buffer - ").concat(e.name, ": ").concat(e.message));
2215
2256
  this.dispatch('error', {
2216
2257
  type: this.type,
2217
- name: 'unexpectedError',
2258
+ name: name,
2218
2259
  error: 'buffer error'
2219
2260
  });
2220
2261
  }
@@ -2234,26 +2275,23 @@
2234
2275
 
2235
2276
  var _super = _createSuper(JMuxer);
2236
2277
 
2237
- _createClass(JMuxer, null, [{
2238
- key: "isSupported",
2239
- value: function isSupported(codec) {
2240
- return window.MediaSource && window.MediaSource.isTypeSupported(codec);
2241
- }
2242
- }]);
2243
-
2244
2278
  function JMuxer(options) {
2245
2279
  var _this;
2246
2280
 
2247
2281
  _classCallCheck(this, JMuxer);
2248
2282
 
2249
2283
  _this = _super.call(this, 'jmuxer');
2284
+ _this.isReset = false;
2250
2285
  var defaults = {
2251
2286
  node: '',
2252
2287
  mode: 'both',
2253
2288
  // both, audio, video
2254
- flushingTime: 1500,
2289
+ flushingTime: 500,
2290
+ maxDelay: 500,
2255
2291
  clearBuffer: true,
2256
2292
  fps: 30,
2293
+ readFpsFromTrack: false,
2294
+ // set true to fetch fps value from NALu
2257
2295
  debug: false,
2258
2296
  onReady: function onReady() {},
2259
2297
  // function called when MSE is ready to accept frames
@@ -2276,13 +2314,10 @@
2276
2314
 
2277
2315
  _this.remuxController.addTrack(_this.options.mode);
2278
2316
 
2279
- _this.lastCleaningTime = Date.now();
2280
- _this.kfPosition = [];
2281
- _this.kfCounter = 0;
2282
- _this.pendingUnits = {};
2283
- _this.remainingData = new Uint8Array();
2317
+ _this.initData();
2284
2318
  /* events callback */
2285
2319
 
2320
+
2286
2321
  _this.remuxController.on('buffer', _this.onBuffer.bind(_assertThisInitialized(_this)));
2287
2322
 
2288
2323
  if (_this.env == 'browser') {
@@ -2291,12 +2326,20 @@
2291
2326
  _this.initBrowser();
2292
2327
  }
2293
2328
 
2294
- _this.startInterval();
2295
-
2296
2329
  return _this;
2297
2330
  }
2298
2331
 
2299
2332
  _createClass(JMuxer, [{
2333
+ key: "initData",
2334
+ value: function initData() {
2335
+ this.lastCleaningTime = Date.now();
2336
+ this.kfPosition = [];
2337
+ this.kfCounter = 0;
2338
+ this.pendingUnits = {};
2339
+ this.remainingData = new Uint8Array();
2340
+ this.startInterval();
2341
+ }
2342
+ }, {
2300
2343
  key: "initBrowser",
2301
2344
  value: function initBrowser() {
2302
2345
  if (typeof this.options.node === 'string' && this.options.node == '') {
@@ -2380,21 +2423,26 @@
2380
2423
 
2381
2424
  slices = _H264Parser$extractNA2[0];
2382
2425
  left = _H264Parser$extractNA2[1];
2426
+ this.remainingData = left || new Uint8Array();
2383
2427
 
2384
2428
  if (slices.length > 0) {
2385
- chunks.video = this.getVideoFrames(slices, duration);
2429
+ chunks.video = this.getVideoFrames(slices, duration, data.compositionTimeOffset);
2386
2430
  remux = true;
2431
+ } else {
2432
+ error('Failed to extract any NAL units from video data:', left);
2433
+ return;
2387
2434
  }
2388
-
2389
- this.remainingData = left || new Uint8Array();
2390
2435
  }
2391
2436
 
2392
2437
  if (data.audio) {
2393
- slices = AACParser.extractAAC(data.audio);
2438
+ slices = this.remuxController.aacParser.extractAAC(data.audio);
2394
2439
 
2395
2440
  if (slices.length > 0) {
2396
2441
  chunks.audio = this.getAudioFrames(slices, duration);
2397
2442
  remux = true;
2443
+ } else {
2444
+ error('Failed to extract audio data from:', data.audio);
2445
+ return;
2398
2446
  }
2399
2447
  }
2400
2448
 
@@ -2407,7 +2455,7 @@
2407
2455
  }
2408
2456
  }, {
2409
2457
  key: "getVideoFrames",
2410
- value: function getVideoFrames(nalus, duration) {
2458
+ value: function getVideoFrames(nalus, duration, compositionTimeOffset) {
2411
2459
  var _this2 = this;
2412
2460
 
2413
2461
  var units = [],
@@ -2471,7 +2519,10 @@
2471
2519
  });
2472
2520
  } else {
2473
2521
  var last = frames.length - 1;
2474
- frames[last].units = frames[last].units.concat(units);
2522
+
2523
+ if (last >= 0) {
2524
+ frames[last].units = frames[last].units.concat(units);
2525
+ }
2475
2526
  }
2476
2527
  }
2477
2528
 
@@ -2479,6 +2530,7 @@
2479
2530
  tt = duration ? duration - fd * frames.length : 0;
2480
2531
  frames.map(function (frame) {
2481
2532
  frame.duration = fd;
2533
+ frame.compositionTimeOffset = compositionTimeOffset;
2482
2534
 
2483
2535
  if (tt > 0) {
2484
2536
  frame.duration++;
@@ -2562,6 +2614,8 @@
2562
2614
  }, {
2563
2615
  key: "reset",
2564
2616
  value: function reset() {
2617
+ this.stopInterval();
2618
+ this.isReset = true;
2565
2619
  this.node.pause();
2566
2620
 
2567
2621
  if (this.remuxController) {
@@ -2577,6 +2631,8 @@
2577
2631
  this.endMSE();
2578
2632
  }
2579
2633
 
2634
+ this.initData();
2635
+
2580
2636
  if (this.env == 'browser') {
2581
2637
  this.initBrowser();
2582
2638
  }
@@ -2608,12 +2664,12 @@
2608
2664
  var _this3 = this;
2609
2665
 
2610
2666
  this.interval = setInterval(function () {
2611
- if (_this3.bufferControllers) {
2612
- _this3.releaseBuffer();
2613
-
2614
- _this3.clearBuffer();
2667
+ if (_this3.options.flushingTime) {
2668
+ _this3.applyAndClearBuffer();
2669
+ } else if (_this3.bufferControllers) {
2670
+ _this3.cancelDelay();
2615
2671
  }
2616
- }, this.options.flushingTime);
2672
+ }, this.options.flushingTime || 1000);
2617
2673
  }
2618
2674
  }, {
2619
2675
  key: "stopInterval",
@@ -2622,6 +2678,18 @@
2622
2678
  clearInterval(this.interval);
2623
2679
  }
2624
2680
  }
2681
+ }, {
2682
+ key: "cancelDelay",
2683
+ value: function cancelDelay() {
2684
+ if (this.node.buffered && this.node.buffered.length > 0 && !this.node.seeking) {
2685
+ var end = this.node.buffered.end(0);
2686
+
2687
+ if (end - this.node.currentTime > this.options.maxDelay / 1000) {
2688
+ console.log('delay');
2689
+ this.node.currentTime = end - 0.001;
2690
+ }
2691
+ }
2692
+ }
2625
2693
  }, {
2626
2694
  key: "releaseBuffer",
2627
2695
  value: function releaseBuffer() {
@@ -2629,6 +2697,14 @@
2629
2697
  this.bufferControllers[type].doAppend();
2630
2698
  }
2631
2699
  }
2700
+ }, {
2701
+ key: "applyAndClearBuffer",
2702
+ value: function applyAndClearBuffer() {
2703
+ if (this.bufferControllers) {
2704
+ this.releaseBuffer();
2705
+ this.clearBuffer();
2706
+ }
2707
+ }
2632
2708
  }, {
2633
2709
  key: "getSafeClearOffsetOfBuffer",
2634
2710
  value: function getSafeClearOffsetOfBuffer(offset) {
@@ -2670,6 +2746,12 @@
2670
2746
  }, {
2671
2747
  key: "onBuffer",
2672
2748
  value: function onBuffer(data) {
2749
+ if (this.options.readFpsFromTrack && typeof data.fps !== 'undefined' && this.options.fps != data.fps) {
2750
+ this.options.fps = data.fps;
2751
+ this.frameDuration = Math.ceil(1000 / data.fps);
2752
+ log("JMuxer changed FPS to ".concat(data.fps, " from track data"));
2753
+ }
2754
+
2673
2755
  if (this.env == 'browser') {
2674
2756
  if (this.bufferControllers && this.bufferControllers[data.type]) {
2675
2757
  this.bufferControllers[data.type].feed(data.payload);
@@ -2677,6 +2759,10 @@
2677
2759
  } else if (this.stream) {
2678
2760
  this.stream.push(data.payload);
2679
2761
  }
2762
+
2763
+ if (this.options.flushingTime === 0) {
2764
+ this.applyAndClearBuffer();
2765
+ }
2680
2766
  }
2681
2767
  /* Events on MSE */
2682
2768
 
@@ -2684,13 +2770,11 @@
2684
2770
  key: "onMSEOpen",
2685
2771
  value: function onMSEOpen() {
2686
2772
  this.mseReady = true;
2773
+ URL.revokeObjectURL(this.url); // this.createBuffer();
2687
2774
 
2688
2775
  if (typeof this.options.onReady === 'function') {
2689
- this.options.onReady.call(null);
2776
+ this.options.onReady.call(null, this.isReset);
2690
2777
  }
2691
-
2692
- URL.revokeObjectURL(this.url);
2693
- this.createBuffer();
2694
2778
  }
2695
2779
  }, {
2696
2780
  key: "onMSEClose",
@@ -2702,8 +2786,12 @@
2702
2786
  key: "onBufferError",
2703
2787
  value: function onBufferError(data) {
2704
2788
  if (data.name == 'QuotaExceeded') {
2789
+ log("JMuxer cleaning ".concat(data.type, " buffer due to QuotaExceeded error"));
2705
2790
  this.bufferControllers[data.type].initCleanup(this.node.currentTime);
2706
2791
  return;
2792
+ } else if (data.name == 'InvalidStateError') {
2793
+ log('JMuxer is reseting due to InvalidStateError');
2794
+ this.reset();
2707
2795
  } else {
2708
2796
  this.endMSE();
2709
2797
  }
@@ -2712,6 +2800,11 @@
2712
2800
  this.options.onError.call(null, data);
2713
2801
  }
2714
2802
  }
2803
+ }], [{
2804
+ key: "isSupported",
2805
+ value: function isSupported(codec) {
2806
+ return window.MediaSource && window.MediaSource.isTypeSupported(codec);
2807
+ }
2715
2808
  }]);
2716
2809
 
2717
2810
  return JMuxer;
@@ -2719,4 +2812,4 @@
2719
2812
 
2720
2813
  return JMuxer;
2721
2814
 
2722
- })));
2815
+ }));