hls.js 1.5.3 → 1.5.5-0.canary.9977

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.
Files changed (68) hide show
  1. package/README.md +1 -0
  2. package/dist/hls-demo.js +10 -0
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1954 -1103
  5. package/dist/hls.js.d.ts +63 -50
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1631 -784
  8. package/dist/hls.light.js.map +1 -1
  9. package/dist/hls.light.min.js +1 -1
  10. package/dist/hls.light.min.js.map +1 -1
  11. package/dist/hls.light.mjs +1428 -590
  12. package/dist/hls.light.mjs.map +1 -1
  13. package/dist/hls.min.js +1 -1
  14. package/dist/hls.min.js.map +1 -1
  15. package/dist/hls.mjs +1703 -866
  16. package/dist/hls.mjs.map +1 -1
  17. package/dist/hls.worker.js +1 -1
  18. package/dist/hls.worker.js.map +1 -1
  19. package/package.json +18 -18
  20. package/src/config.ts +3 -2
  21. package/src/controller/abr-controller.ts +24 -22
  22. package/src/controller/audio-stream-controller.ts +16 -17
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +7 -7
  25. package/src/controller/base-stream-controller.ts +56 -29
  26. package/src/controller/buffer-controller.ts +11 -11
  27. package/src/controller/cap-level-controller.ts +1 -2
  28. package/src/controller/cmcd-controller.ts +25 -3
  29. package/src/controller/content-steering-controller.ts +8 -6
  30. package/src/controller/eme-controller.ts +9 -22
  31. package/src/controller/error-controller.ts +6 -8
  32. package/src/controller/fps-controller.ts +2 -3
  33. package/src/controller/gap-controller.ts +43 -16
  34. package/src/controller/latency-controller.ts +9 -11
  35. package/src/controller/level-controller.ts +5 -17
  36. package/src/controller/stream-controller.ts +27 -33
  37. package/src/controller/subtitle-stream-controller.ts +14 -15
  38. package/src/controller/subtitle-track-controller.ts +5 -3
  39. package/src/controller/timeline-controller.ts +23 -30
  40. package/src/crypt/aes-crypto.ts +21 -2
  41. package/src/crypt/decrypter-aes-mode.ts +4 -0
  42. package/src/crypt/decrypter.ts +32 -18
  43. package/src/crypt/fast-aes-key.ts +24 -5
  44. package/src/demux/audio/adts.ts +9 -4
  45. package/src/demux/sample-aes.ts +2 -0
  46. package/src/demux/transmuxer-interface.ts +4 -12
  47. package/src/demux/transmuxer-worker.ts +4 -4
  48. package/src/demux/transmuxer.ts +16 -3
  49. package/src/demux/tsdemuxer.ts +63 -37
  50. package/src/demux/video/avc-video-parser.ts +208 -119
  51. package/src/demux/video/base-video-parser.ts +134 -2
  52. package/src/demux/video/exp-golomb.ts +0 -208
  53. package/src/demux/video/hevc-video-parser.ts +746 -0
  54. package/src/events.ts +7 -0
  55. package/src/hls.ts +42 -34
  56. package/src/loader/fragment-loader.ts +9 -2
  57. package/src/loader/key-loader.ts +2 -0
  58. package/src/loader/level-key.ts +10 -9
  59. package/src/remux/mp4-generator.ts +196 -1
  60. package/src/remux/mp4-remuxer.ts +23 -7
  61. package/src/task-loop.ts +5 -2
  62. package/src/types/component-api.ts +2 -0
  63. package/src/types/demuxer.ts +3 -0
  64. package/src/types/events.ts +4 -0
  65. package/src/utils/codecs.ts +33 -4
  66. package/src/utils/encryption-methods-util.ts +21 -0
  67. package/src/utils/logger.ts +53 -24
  68. package/src/utils/mp4-tools.ts +28 -9
package/dist/hls.light.js CHANGED
@@ -5,6 +5,21 @@
5
5
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Hls = factory());
6
6
  })(this, (function () { 'use strict';
7
7
 
8
+ function _construct(t, e, r) {
9
+ if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
10
+ var o = [null];
11
+ o.push.apply(o, e);
12
+ var p = new (t.bind.apply(t, o))();
13
+ return r && _setPrototypeOf(p, r.prototype), p;
14
+ }
15
+ function _isNativeReflectConstruct() {
16
+ try {
17
+ var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
18
+ } catch (t) {}
19
+ return (_isNativeReflectConstruct = function () {
20
+ return !!t;
21
+ })();
22
+ }
8
23
  function ownKeys(e, r) {
9
24
  var t = Object.keys(e);
10
25
  if (Object.getOwnPropertySymbols) {
@@ -103,32 +118,6 @@
103
118
  };
104
119
  return _setPrototypeOf(o, p);
105
120
  }
106
- function _isNativeReflectConstruct() {
107
- if (typeof Reflect === "undefined" || !Reflect.construct) return false;
108
- if (Reflect.construct.sham) return false;
109
- if (typeof Proxy === "function") return true;
110
- try {
111
- Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
112
- return true;
113
- } catch (e) {
114
- return false;
115
- }
116
- }
117
- function _construct(Parent, args, Class) {
118
- if (_isNativeReflectConstruct()) {
119
- _construct = Reflect.construct.bind();
120
- } else {
121
- _construct = function _construct(Parent, args, Class) {
122
- var a = [null];
123
- a.push.apply(a, args);
124
- var Constructor = Function.bind.apply(Parent, a);
125
- var instance = new Constructor();
126
- if (Class) _setPrototypeOf(instance, Class.prototype);
127
- return instance;
128
- };
129
- }
130
- return _construct.apply(null, arguments);
131
- }
132
121
  function _isNativeFunction(fn) {
133
122
  try {
134
123
  return Function.toString.call(fn).indexOf("[native code]") !== -1;
@@ -363,6 +352,7 @@
363
352
  Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
364
353
  Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
365
354
  Events["MEDIA_DETACHED"] = "hlsMediaDetached";
355
+ Events["MEDIA_ENDED"] = "hlsMediaEnded";
366
356
  Events["BUFFER_RESET"] = "hlsBufferReset";
367
357
  Events["BUFFER_CODECS"] = "hlsBufferCodecs";
368
358
  Events["BUFFER_CREATED"] = "hlsBufferCreated";
@@ -476,6 +466,21 @@
476
466
  return ErrorDetails;
477
467
  }({});
478
468
 
469
+ var Logger = function Logger(label, logger) {
470
+ this.trace = void 0;
471
+ this.debug = void 0;
472
+ this.log = void 0;
473
+ this.warn = void 0;
474
+ this.info = void 0;
475
+ this.error = void 0;
476
+ var lb = "[" + label + "]:";
477
+ this.trace = noop;
478
+ this.debug = logger.debug.bind(null, lb);
479
+ this.log = logger.log.bind(null, lb);
480
+ this.warn = logger.warn.bind(null, lb);
481
+ this.info = logger.info.bind(null, lb);
482
+ this.error = logger.error.bind(null, lb);
483
+ };
479
484
  var noop = function noop() {};
480
485
  var fakeLogger = {
481
486
  trace: noop,
@@ -485,7 +490,9 @@
485
490
  info: noop,
486
491
  error: noop
487
492
  };
488
- var exportedLogger = fakeLogger;
493
+ function createLogger() {
494
+ return _extends({}, fakeLogger);
495
+ }
489
496
 
490
497
  // let lastCallTime;
491
498
  // function formatMsgWithTimeInfo(type, msg) {
@@ -496,38 +503,36 @@
496
503
  // return msg;
497
504
  // }
498
505
 
499
- function consolePrintFn(type) {
506
+ function consolePrintFn(type, id) {
500
507
  var func = self.console[type];
501
- if (func) {
502
- return func.bind(self.console, "[" + type + "] >");
503
- }
504
- return noop;
508
+ return func ? func.bind(self.console, (id ? '[' + id + '] ' : '') + "[" + type + "] >") : noop;
505
509
  }
506
- function exportLoggerFunctions(debugConfig) {
507
- for (var _len = arguments.length, functions = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
508
- functions[_key - 1] = arguments[_key];
509
- }
510
- functions.forEach(function (type) {
511
- exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
512
- });
510
+ function getLoggerFn(key, debugConfig, id) {
511
+ return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
513
512
  }
514
- function enableLogs(debugConfig, id) {
513
+ var exportedLogger = createLogger();
514
+ function enableLogs(debugConfig, context, id) {
515
515
  // check that console is available
516
+ var newLogger = createLogger();
516
517
  if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
517
- exportLoggerFunctions(debugConfig,
518
+ var keys = [
518
519
  // Remove out from list here to hard-disable a log-level
519
520
  // 'trace',
520
- 'debug', 'log', 'info', 'warn', 'error');
521
+ 'debug', 'log', 'info', 'warn', 'error'];
522
+ keys.forEach(function (key) {
523
+ newLogger[key] = getLoggerFn(key, debugConfig, id);
524
+ });
521
525
  // Some browsers don't allow to use bind on console object anyway
522
526
  // fallback to default if needed
523
527
  try {
524
- exportedLogger.log("Debug logs enabled for \"" + id + "\" in hls.js version " + "1.5.3");
528
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.5-0.canary.9977");
525
529
  } catch (e) {
526
- exportedLogger = fakeLogger;
530
+ /* log fn threw an exception. All logger methods are no-ops. */
531
+ return createLogger();
527
532
  }
528
- } else {
529
- exportedLogger = fakeLogger;
530
533
  }
534
+ exportedLogger = newLogger;
535
+ return newLogger;
531
536
  }
532
537
  var logger = exportedLogger;
533
538
 
@@ -1173,6 +1178,26 @@
1173
1178
  return LevelDetails;
1174
1179
  }();
1175
1180
 
1181
+ var DecrypterAesMode = {
1182
+ cbc: 0,
1183
+ ctr: 1
1184
+ };
1185
+
1186
+ function isFullSegmentEncryption(method) {
1187
+ return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
1188
+ }
1189
+ function getAesModeFromFullSegmentMethod(method) {
1190
+ switch (method) {
1191
+ case 'AES-128':
1192
+ case 'AES-256':
1193
+ return DecrypterAesMode.cbc;
1194
+ case 'AES-256-CTR':
1195
+ return DecrypterAesMode.ctr;
1196
+ default:
1197
+ throw new Error("invalid full segment method " + method);
1198
+ }
1199
+ }
1200
+
1176
1201
  // This file is inserted as a shim for modules which we do not want to include into the distro.
1177
1202
  // This replacement is done in the "alias" plugin of the rollup config.
1178
1203
  var empty = undefined;
@@ -1577,6 +1602,12 @@
1577
1602
  var val = readSint32(buffer, offset);
1578
1603
  return val < 0 ? 4294967296 + val : val;
1579
1604
  }
1605
+ function readUint64(buffer, offset) {
1606
+ var result = readUint32(buffer, offset);
1607
+ result *= Math.pow(2, 32);
1608
+ result += readUint32(buffer, offset + 4);
1609
+ return result;
1610
+ }
1580
1611
  function readSint32(buffer, offset) {
1581
1612
  return buffer[offset] << 24 | buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3];
1582
1613
  }
@@ -1639,15 +1670,14 @@
1639
1670
  var index = 8;
1640
1671
  var timescale = readUint32(sidx, index);
1641
1672
  index += 4;
1642
-
1643
- // TODO: parse earliestPresentationTime and firstOffset
1644
- // usually zero in our case
1645
1673
  var earliestPresentationTime = 0;
1646
1674
  var firstOffset = 0;
1647
1675
  if (version === 0) {
1648
- index += 8;
1676
+ earliestPresentationTime = readUint32(sidx, index += 4);
1677
+ firstOffset = readUint32(sidx, index += 4);
1649
1678
  } else {
1650
- index += 16;
1679
+ earliestPresentationTime = readUint64(sidx, index += 8);
1680
+ firstOffset = readUint64(sidx, index += 8);
1651
1681
  }
1652
1682
 
1653
1683
  // skip reserved
@@ -2097,17 +2127,24 @@
2097
2127
  }
2098
2128
  if (videoDuration === 0 && audioDuration === 0) {
2099
2129
  // If duration samples are not available in the traf use sidx subsegment_duration
2130
+ var sidxMinStart = Infinity;
2131
+ var sidxMaxEnd = 0;
2100
2132
  var sidxDuration = 0;
2101
2133
  var sidxs = findBox(data, ['sidx']);
2102
2134
  for (var _i2 = 0; _i2 < sidxs.length; _i2++) {
2103
2135
  var sidx = parseSegmentIndex(sidxs[_i2]);
2104
2136
  if (sidx != null && sidx.references) {
2105
- sidxDuration += sidx.references.reduce(function (dur, ref) {
2137
+ sidxMinStart = Math.min(sidxMinStart, sidx.earliestPresentationTime / sidx.timescale);
2138
+ var subSegmentDuration = sidx.references.reduce(function (dur, ref) {
2106
2139
  return dur + ref.info.duration || 0;
2107
2140
  }, 0);
2141
+ sidxMaxEnd = Math.max(sidxMaxEnd, subSegmentDuration + sidx.earliestPresentationTime / sidx.timescale);
2142
+ sidxDuration = sidxMaxEnd - sidxMinStart;
2108
2143
  }
2109
2144
  }
2110
- return sidxDuration;
2145
+ if (sidxDuration && isFiniteNumber(sidxDuration)) {
2146
+ return sidxDuration;
2147
+ }
2111
2148
  }
2112
2149
  if (videoDuration) {
2113
2150
  return videoDuration;
@@ -2614,13 +2651,13 @@
2614
2651
  this.keyFormatVersions = formatversions;
2615
2652
  this.iv = iv;
2616
2653
  this.encrypted = method ? method !== 'NONE' : false;
2617
- this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2654
+ this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2618
2655
  }
2619
2656
  var _proto = LevelKey.prototype;
2620
2657
  _proto.isSupported = function isSupported() {
2621
2658
  // If it's Segment encryption or No encryption, just select that key system
2622
2659
  if (this.method) {
2623
- if (this.method === 'AES-128' || this.method === 'NONE') {
2660
+ if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2624
2661
  return true;
2625
2662
  }
2626
2663
  if (this.keyFormat === 'identity') {
@@ -2634,14 +2671,13 @@
2634
2671
  if (!this.encrypted || !this.uri) {
2635
2672
  return null;
2636
2673
  }
2637
- if (this.method === 'AES-128' && this.uri && !this.iv) {
2674
+ if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2638
2675
  if (typeof sn !== 'number') {
2639
2676
  // We are fetching decryption data for a initialization segment
2640
- // If the segment was encrypted with AES-128
2677
+ // If the segment was encrypted with AES-128/256
2641
2678
  // It must have an IV defined. We cannot substitute the Segment Number in.
2642
- if (this.method === 'AES-128' && !this.iv) {
2643
- logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2644
- }
2679
+ logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2680
+
2645
2681
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2646
2682
  sn = 0;
2647
2683
  }
@@ -2803,23 +2839,28 @@
2803
2839
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2804
2840
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2805
2841
  }
2806
-
2807
- // Idealy fLaC and Opus would be first (spec-compliant) but
2808
- // some browsers will report that fLaC is supported then fail.
2809
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2810
2842
  var codecsToCheck = {
2843
+ // Idealy fLaC and Opus would be first (spec-compliant) but
2844
+ // some browsers will report that fLaC is supported then fail.
2845
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2811
2846
  flac: ['flac', 'fLaC', 'FLAC'],
2812
- opus: ['opus', 'Opus']
2847
+ opus: ['opus', 'Opus'],
2848
+ // Replace audio codec info if browser does not support mp4a.40.34,
2849
+ // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
2850
+ 'mp4a.40.34': ['mp3']
2813
2851
  }[lowerCaseCodec];
2814
2852
  for (var i = 0; i < codecsToCheck.length; i++) {
2853
+ var _getMediaSource;
2815
2854
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2816
2855
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2817
2856
  return codecsToCheck[i];
2857
+ } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2858
+ return '';
2818
2859
  }
2819
2860
  }
2820
2861
  return lowerCaseCodec;
2821
2862
  }
2822
- var AUDIO_CODEC_REGEXP = /flac|opus/i;
2863
+ var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2823
2864
  function getCodecCompatibleName(codec, preferManagedMediaSource) {
2824
2865
  if (preferManagedMediaSource === void 0) {
2825
2866
  preferManagedMediaSource = true;
@@ -2847,6 +2888,18 @@
2847
2888
  }
2848
2889
  return codec;
2849
2890
  }
2891
+ function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
2892
+ var MediaSource = getMediaSource(preferManagedMediaSource) || {
2893
+ isTypeSupported: function isTypeSupported() {
2894
+ return false;
2895
+ }
2896
+ };
2897
+ return {
2898
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
2899
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
2900
+ ac3: false
2901
+ };
2902
+ }
2850
2903
 
2851
2904
  var MASTER_PLAYLIST_REGEX = /#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-(SESSION-DATA|SESSION-KEY|DEFINE|CONTENT-STEERING|START):([^\r\n]*)[\r\n]+/g;
2852
2905
  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -4421,8 +4474,43 @@
4421
4474
  this.currentTime = 0;
4422
4475
  this.stallCount = 0;
4423
4476
  this._latency = null;
4424
- this.timeupdateHandler = function () {
4425
- return _this.timeupdate();
4477
+ this.onTimeupdate = function () {
4478
+ var media = _this.media,
4479
+ levelDetails = _this.levelDetails;
4480
+ if (!media || !levelDetails) {
4481
+ return;
4482
+ }
4483
+ _this.currentTime = media.currentTime;
4484
+ var latency = _this.computeLatency();
4485
+ if (latency === null) {
4486
+ return;
4487
+ }
4488
+ _this._latency = latency;
4489
+
4490
+ // Adapt playbackRate to meet target latency in low-latency mode
4491
+ var _this$config = _this.config,
4492
+ lowLatencyMode = _this$config.lowLatencyMode,
4493
+ maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4494
+ if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4495
+ return;
4496
+ }
4497
+ var targetLatency = _this.targetLatency;
4498
+ if (targetLatency === null) {
4499
+ return;
4500
+ }
4501
+ var distanceFromTarget = latency - targetLatency;
4502
+ // Only adjust playbackRate when within one target duration of targetLatency
4503
+ // and more than one second from under-buffering.
4504
+ // Playback further than one target duration from target can be considered DVR playback.
4505
+ var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
4506
+ var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4507
+ if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
4508
+ var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4509
+ var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
4510
+ media.playbackRate = Math.min(max, Math.max(1, rate));
4511
+ } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4512
+ media.playbackRate = 1;
4513
+ }
4426
4514
  };
4427
4515
  this.hls = hls;
4428
4516
  this.config = hls.config;
@@ -4434,7 +4522,7 @@
4434
4522
  this.onMediaDetaching();
4435
4523
  this.levelDetails = null;
4436
4524
  // @ts-ignore
4437
- this.hls = this.timeupdateHandler = null;
4525
+ this.hls = null;
4438
4526
  };
4439
4527
  _proto.registerListeners = function registerListeners() {
4440
4528
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4452,11 +4540,11 @@
4452
4540
  };
4453
4541
  _proto.onMediaAttached = function onMediaAttached(event, data) {
4454
4542
  this.media = data.media;
4455
- this.media.addEventListener('timeupdate', this.timeupdateHandler);
4543
+ this.media.addEventListener('timeupdate', this.onTimeupdate);
4456
4544
  };
4457
4545
  _proto.onMediaDetaching = function onMediaDetaching() {
4458
4546
  if (this.media) {
4459
- this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4547
+ this.media.removeEventListener('timeupdate', this.onTimeupdate);
4460
4548
  this.media = null;
4461
4549
  }
4462
4550
  };
@@ -4469,10 +4557,10 @@
4469
4557
  var details = _ref.details;
4470
4558
  this.levelDetails = details;
4471
4559
  if (details.advanced) {
4472
- this.timeupdate();
4560
+ this.onTimeupdate();
4473
4561
  }
4474
4562
  if (!details.live && this.media) {
4475
- this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4563
+ this.media.removeEventListener('timeupdate', this.onTimeupdate);
4476
4564
  }
4477
4565
  };
4478
4566
  _proto.onError = function onError(event, data) {
@@ -4482,45 +4570,7 @@
4482
4570
  }
4483
4571
  this.stallCount++;
4484
4572
  if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
4485
- logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
4486
- }
4487
- };
4488
- _proto.timeupdate = function timeupdate() {
4489
- var media = this.media,
4490
- levelDetails = this.levelDetails;
4491
- if (!media || !levelDetails) {
4492
- return;
4493
- }
4494
- this.currentTime = media.currentTime;
4495
- var latency = this.computeLatency();
4496
- if (latency === null) {
4497
- return;
4498
- }
4499
- this._latency = latency;
4500
-
4501
- // Adapt playbackRate to meet target latency in low-latency mode
4502
- var _this$config = this.config,
4503
- lowLatencyMode = _this$config.lowLatencyMode,
4504
- maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4505
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4506
- return;
4507
- }
4508
- var targetLatency = this.targetLatency;
4509
- if (targetLatency === null) {
4510
- return;
4511
- }
4512
- var distanceFromTarget = latency - targetLatency;
4513
- // Only adjust playbackRate when within one target duration of targetLatency
4514
- // and more than one second from under-buffering.
4515
- // Playback further than one target duration from target can be considered DVR playback.
4516
- var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4517
- var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4518
- if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4519
- var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4520
- var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4521
- media.playbackRate = Math.min(max, Math.max(1, rate));
4522
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4523
- media.playbackRate = 1;
4573
+ this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
4524
4574
  }
4525
4575
  };
4526
4576
  _proto.estimateLiveEdge = function estimateLiveEdge() {
@@ -5428,19 +5478,17 @@
5428
5478
  MoveAllAlternatesMatchingHDCP: 2,
5429
5479
  SwitchToSDR: 4
5430
5480
  }; // Reserved for future use
5431
- var ErrorController = /*#__PURE__*/function () {
5481
+ var ErrorController = /*#__PURE__*/function (_Logger) {
5482
+ _inheritsLoose(ErrorController, _Logger);
5432
5483
  function ErrorController(hls) {
5433
- this.hls = void 0;
5434
- this.playlistError = 0;
5435
- this.penalizedRenditions = {};
5436
- this.log = void 0;
5437
- this.warn = void 0;
5438
- this.error = void 0;
5439
- this.hls = hls;
5440
- this.log = logger.log.bind(logger, "[info]:");
5441
- this.warn = logger.warn.bind(logger, "[warning]:");
5442
- this.error = logger.error.bind(logger, "[error]:");
5443
- this.registerListeners();
5484
+ var _this;
5485
+ _this = _Logger.call(this, 'error-controller', hls.logger) || this;
5486
+ _this.hls = void 0;
5487
+ _this.playlistError = 0;
5488
+ _this.penalizedRenditions = {};
5489
+ _this.hls = hls;
5490
+ _this.registerListeners();
5491
+ return _this;
5444
5492
  }
5445
5493
  var _proto = ErrorController.prototype;
5446
5494
  _proto.registerListeners = function registerListeners() {
@@ -5796,19 +5844,19 @@
5796
5844
  }
5797
5845
  };
5798
5846
  return ErrorController;
5799
- }();
5847
+ }(Logger);
5800
5848
 
5801
- var BasePlaylistController = /*#__PURE__*/function () {
5849
+ var BasePlaylistController = /*#__PURE__*/function (_Logger) {
5850
+ _inheritsLoose(BasePlaylistController, _Logger);
5802
5851
  function BasePlaylistController(hls, logPrefix) {
5803
- this.hls = void 0;
5804
- this.timer = -1;
5805
- this.requestScheduled = -1;
5806
- this.canLoad = false;
5807
- this.log = void 0;
5808
- this.warn = void 0;
5809
- this.log = logger.log.bind(logger, logPrefix + ":");
5810
- this.warn = logger.warn.bind(logger, logPrefix + ":");
5811
- this.hls = hls;
5852
+ var _this;
5853
+ _this = _Logger.call(this, logPrefix, hls.logger) || this;
5854
+ _this.hls = void 0;
5855
+ _this.timer = -1;
5856
+ _this.requestScheduled = -1;
5857
+ _this.canLoad = false;
5858
+ _this.hls = hls;
5859
+ return _this;
5812
5860
  }
5813
5861
  var _proto = BasePlaylistController.prototype;
5814
5862
  _proto.destroy = function destroy() {
@@ -5841,7 +5889,7 @@
5841
5889
  try {
5842
5890
  uri = new self.URL(attr.URI, previous.url).href;
5843
5891
  } catch (error) {
5844
- logger.warn("Could not construct new URL for Rendition Report: " + error);
5892
+ this.warn("Could not construct new URL for Rendition Report: " + error);
5845
5893
  uri = attr.URI || '';
5846
5894
  }
5847
5895
  // Use exact match. Otherwise, the last partial match, if any, will be used
@@ -5880,7 +5928,7 @@
5880
5928
  return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
5881
5929
  };
5882
5930
  _proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
5883
- var _this = this;
5931
+ var _this2 = this;
5884
5932
  var details = data.details,
5885
5933
  stats = data.stats;
5886
5934
 
@@ -5985,7 +6033,7 @@
5985
6033
  // );
5986
6034
 
5987
6035
  this.timer = self.setTimeout(function () {
5988
- return _this.loadPlaylist(deliveryDirectives);
6036
+ return _this2.loadPlaylist(deliveryDirectives);
5989
6037
  }, estimatedTimeUntilUpdate);
5990
6038
  } else {
5991
6039
  this.clearTimer();
@@ -6001,7 +6049,7 @@
6001
6049
  return new HlsUrlParameters(msn, part, skip);
6002
6050
  };
6003
6051
  _proto.checkRetry = function checkRetry(errorEvent) {
6004
- var _this2 = this;
6052
+ var _this3 = this;
6005
6053
  var errorDetails = errorEvent.details;
6006
6054
  var isTimeout = isTimeoutError(errorEvent);
6007
6055
  var errorAction = errorEvent.errorAction;
@@ -6025,7 +6073,7 @@
6025
6073
  var delay = getRetryDelay(retryConfig, retryCount);
6026
6074
  // Schedule level/track reload
6027
6075
  this.timer = self.setTimeout(function () {
6028
- return _this2.loadPlaylist();
6076
+ return _this3.loadPlaylist();
6029
6077
  }, delay);
6030
6078
  this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
6031
6079
  }
@@ -6036,7 +6084,7 @@
6036
6084
  return retry;
6037
6085
  };
6038
6086
  return BasePlaylistController;
6039
- }();
6087
+ }(Logger);
6040
6088
 
6041
6089
  /*
6042
6090
  * compute an Exponential Weighted moving average
@@ -6410,30 +6458,33 @@
6410
6458
  }, {});
6411
6459
  }
6412
6460
 
6413
- var AbrController = /*#__PURE__*/function () {
6461
+ var AbrController = /*#__PURE__*/function (_Logger) {
6462
+ _inheritsLoose(AbrController, _Logger);
6414
6463
  function AbrController(_hls) {
6415
- var _this = this;
6416
- this.hls = void 0;
6417
- this.lastLevelLoadSec = 0;
6418
- this.lastLoadedFragLevel = -1;
6419
- this.firstSelection = -1;
6420
- this._nextAutoLevel = -1;
6421
- this.nextAutoLevelKey = '';
6422
- this.audioTracksByGroup = null;
6423
- this.codecTiers = null;
6424
- this.timer = -1;
6425
- this.fragCurrent = null;
6426
- this.partCurrent = null;
6427
- this.bitrateTestDelay = 0;
6428
- this.bwEstimator = void 0;
6464
+ var _this;
6465
+ _this = _Logger.call(this, 'abr', _hls.logger) || this;
6466
+ _this.hls = void 0;
6467
+ _this.lastLevelLoadSec = 0;
6468
+ _this.lastLoadedFragLevel = -1;
6469
+ _this.firstSelection = -1;
6470
+ _this._nextAutoLevel = -1;
6471
+ _this.nextAutoLevelKey = '';
6472
+ _this.audioTracksByGroup = null;
6473
+ _this.codecTiers = null;
6474
+ _this.timer = -1;
6475
+ _this.fragCurrent = null;
6476
+ _this.partCurrent = null;
6477
+ _this.bitrateTestDelay = 0;
6478
+ _this.bwEstimator = void 0;
6429
6479
  /*
6430
6480
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
6431
6481
  quickly enough to prevent underbuffering
6432
6482
  */
6433
- this._abandonRulesCheck = function () {
6434
- var frag = _this.fragCurrent,
6435
- part = _this.partCurrent,
6436
- hls = _this.hls;
6483
+ _this._abandonRulesCheck = function () {
6484
+ var _assertThisInitialize = _assertThisInitialized(_this),
6485
+ frag = _assertThisInitialize.fragCurrent,
6486
+ part = _assertThisInitialize.partCurrent,
6487
+ hls = _assertThisInitialize.hls;
6437
6488
  var autoLevelEnabled = hls.autoLevelEnabled,
6438
6489
  media = hls.media;
6439
6490
  if (!frag || !media) {
@@ -6522,21 +6573,22 @@
6522
6573
  _this.resetEstimator(nextLoadLevelBitrate);
6523
6574
  }
6524
6575
  _this.clearTimer();
6525
- logger.warn("[abr] Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
6576
+ _this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
6526
6577
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
6527
6578
  frag: frag,
6528
6579
  part: part,
6529
6580
  stats: stats
6530
6581
  });
6531
6582
  };
6532
- this.hls = _hls;
6533
- this.bwEstimator = this.initEstimator();
6534
- this.registerListeners();
6583
+ _this.hls = _hls;
6584
+ _this.bwEstimator = _this.initEstimator();
6585
+ _this.registerListeners();
6586
+ return _this;
6535
6587
  }
6536
6588
  var _proto = AbrController.prototype;
6537
6589
  _proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
6538
6590
  if (abrEwmaDefaultEstimate) {
6539
- logger.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6591
+ this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6540
6592
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
6541
6593
  }
6542
6594
  this.firstSelection = -1;
@@ -6788,13 +6840,13 @@
6788
6840
  // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
6789
6841
  var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
6790
6842
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
6791
- logger.info("[abr] bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
6843
+ this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
6792
6844
  // don't use conservative factor on bitrate test
6793
6845
  bwFactor = bwUpFactor = 1;
6794
6846
  }
6795
6847
  }
6796
6848
  var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
6797
- logger.info("[abr] " + (bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6849
+ this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
6798
6850
  if (bestLevel > -1) {
6799
6851
  return bestLevel;
6800
6852
  }
@@ -6850,7 +6902,7 @@
6850
6902
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
6851
6903
  currentFrameRate = minFramerate;
6852
6904
  currentBw = Math.max(currentBw, minBitrate);
6853
- logger.log("[abr] picked start tier " + JSON.stringify(startTier));
6905
+ this.log("picked start tier " + JSON.stringify(startTier));
6854
6906
  } else {
6855
6907
  currentCodecSet = level == null ? void 0 : level.codecSet;
6856
6908
  currentVideoRange = level == null ? void 0 : level.videoRange;
@@ -6903,9 +6955,9 @@
6903
6955
  var forcedAutoLevel = _this2.forcedAutoLevel;
6904
6956
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
6905
6957
  if (levelsSkipped.length) {
6906
- logger.trace("[abr] Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
6958
+ _this2.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
6907
6959
  }
6908
- logger.info("[abr] switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
6960
+ _this2.info("switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
6909
6961
  }
6910
6962
  if (firstSelection) {
6911
6963
  _this2.firstSelection = i;
@@ -6939,7 +6991,7 @@
6939
6991
  }
6940
6992
  var firstLevel = this.hls.firstLevel;
6941
6993
  var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
6942
- logger.warn("[abr] Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
6994
+ this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
6943
6995
  return clamped;
6944
6996
  }
6945
6997
  }, {
@@ -6981,15 +7033,18 @@
6981
7033
  return nextABRAutoLevel;
6982
7034
  },
6983
7035
  set: function set(nextLevel) {
6984
- var value = Math.max(this.hls.minAutoLevel, nextLevel);
6985
- if (this._nextAutoLevel != value) {
7036
+ var _this$hls3 = this.hls,
7037
+ maxAutoLevel = _this$hls3.maxAutoLevel,
7038
+ minAutoLevel = _this$hls3.minAutoLevel;
7039
+ var value = Math.min(Math.max(nextLevel, minAutoLevel), maxAutoLevel);
7040
+ if (this._nextAutoLevel !== value) {
6986
7041
  this.nextAutoLevelKey = '';
6987
7042
  this._nextAutoLevel = value;
6988
7043
  }
6989
7044
  }
6990
7045
  }]);
6991
7046
  return AbrController;
6992
- }();
7047
+ }(Logger);
6993
7048
 
6994
7049
  /**
6995
7050
  * Provides methods dealing with buffer length retrieval for example.
@@ -7210,57 +7265,57 @@
7210
7265
  }();
7211
7266
 
7212
7267
  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
7213
- var BufferController = /*#__PURE__*/function () {
7268
+ var BufferController = /*#__PURE__*/function (_Logger) {
7269
+ _inheritsLoose(BufferController, _Logger);
7214
7270
  function BufferController(hls) {
7215
- var _this = this;
7271
+ var _this;
7272
+ _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
7216
7273
  // The level details used to determine duration, target-duration and live
7217
- this.details = null;
7274
+ _this.details = null;
7218
7275
  // cache the self generated object url to detect hijack of video tag
7219
- this._objectUrl = null;
7276
+ _this._objectUrl = null;
7220
7277
  // A queue of buffer operations which require the SourceBuffer to not be updating upon execution
7221
- this.operationQueue = void 0;
7278
+ _this.operationQueue = void 0;
7222
7279
  // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
7223
- this.listeners = void 0;
7224
- this.hls = void 0;
7280
+ _this.listeners = void 0;
7281
+ _this.hls = void 0;
7225
7282
  // The number of BUFFER_CODEC events received before any sourceBuffers are created
7226
- this.bufferCodecEventsExpected = 0;
7283
+ _this.bufferCodecEventsExpected = 0;
7227
7284
  // The total number of BUFFER_CODEC events received
7228
- this._bufferCodecEventsTotal = 0;
7285
+ _this._bufferCodecEventsTotal = 0;
7229
7286
  // A reference to the attached media element
7230
- this.media = null;
7287
+ _this.media = null;
7231
7288
  // A reference to the active media source
7232
- this.mediaSource = null;
7289
+ _this.mediaSource = null;
7233
7290
  // Last MP3 audio chunk appended
7234
- this.lastMpegAudioChunk = null;
7235
- this.appendSource = void 0;
7291
+ _this.lastMpegAudioChunk = null;
7292
+ _this.appendSource = void 0;
7236
7293
  // counters
7237
- this.appendErrors = {
7294
+ _this.appendErrors = {
7238
7295
  audio: 0,
7239
7296
  video: 0,
7240
7297
  audiovideo: 0
7241
7298
  };
7242
- this.tracks = {};
7243
- this.pendingTracks = {};
7244
- this.sourceBuffer = void 0;
7245
- this.log = void 0;
7246
- this.warn = void 0;
7247
- this.error = void 0;
7248
- this._onEndStreaming = function (event) {
7299
+ _this.tracks = {};
7300
+ _this.pendingTracks = {};
7301
+ _this.sourceBuffer = void 0;
7302
+ _this._onEndStreaming = function (event) {
7249
7303
  if (!_this.hls) {
7250
7304
  return;
7251
7305
  }
7252
7306
  _this.hls.pauseBuffering();
7253
7307
  };
7254
- this._onStartStreaming = function (event) {
7308
+ _this._onStartStreaming = function (event) {
7255
7309
  if (!_this.hls) {
7256
7310
  return;
7257
7311
  }
7258
7312
  _this.hls.resumeBuffering();
7259
7313
  };
7260
7314
  // Keep as arrow functions so that we can directly reference these functions directly as event listeners
7261
- this._onMediaSourceOpen = function () {
7262
- var media = _this.media,
7263
- mediaSource = _this.mediaSource;
7315
+ _this._onMediaSourceOpen = function () {
7316
+ var _assertThisInitialize = _assertThisInitialized(_this),
7317
+ media = _assertThisInitialize.media,
7318
+ mediaSource = _assertThisInitialize.mediaSource;
7264
7319
  _this.log('Media source opened');
7265
7320
  if (media) {
7266
7321
  media.removeEventListener('emptied', _this._onMediaEmptied);
@@ -7276,27 +7331,25 @@
7276
7331
  }
7277
7332
  _this.checkPendingTracks();
7278
7333
  };
7279
- this._onMediaSourceClose = function () {
7334
+ _this._onMediaSourceClose = function () {
7280
7335
  _this.log('Media source closed');
7281
7336
  };
7282
- this._onMediaSourceEnded = function () {
7337
+ _this._onMediaSourceEnded = function () {
7283
7338
  _this.log('Media source ended');
7284
7339
  };
7285
- this._onMediaEmptied = function () {
7286
- var mediaSrc = _this.mediaSrc,
7287
- _objectUrl = _this._objectUrl;
7340
+ _this._onMediaEmptied = function () {
7341
+ var _assertThisInitialize2 = _assertThisInitialized(_this),
7342
+ mediaSrc = _assertThisInitialize2.mediaSrc,
7343
+ _objectUrl = _assertThisInitialize2._objectUrl;
7288
7344
  if (mediaSrc !== _objectUrl) {
7289
- logger.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7345
+ _this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
7290
7346
  }
7291
7347
  };
7292
- this.hls = hls;
7293
- var logPrefix = '[buffer-controller]';
7294
- this.appendSource = hls.config.preferManagedMediaSource;
7295
- this.log = logger.log.bind(logger, logPrefix);
7296
- this.warn = logger.warn.bind(logger, logPrefix);
7297
- this.error = logger.error.bind(logger, logPrefix);
7298
- this._initSourceBuffer();
7299
- this.registerListeners();
7348
+ _this.hls = hls;
7349
+ _this.appendSource = hls.config.preferManagedMediaSource;
7350
+ _this._initSourceBuffer();
7351
+ _this.registerListeners();
7352
+ return _this;
7300
7353
  }
7301
7354
  var _proto = BufferController.prototype;
7302
7355
  _proto.hasSourceTypes = function hasSourceTypes() {
@@ -7308,6 +7361,12 @@
7308
7361
  this.lastMpegAudioChunk = null;
7309
7362
  // @ts-ignore
7310
7363
  this.hls = null;
7364
+ // @ts-ignore
7365
+ this._onMediaSourceOpen = this._onMediaSourceClose = null;
7366
+ // @ts-ignore
7367
+ this._onMediaSourceEnded = null;
7368
+ // @ts-ignore
7369
+ this._onStartStreaming = this._onEndStreaming = null;
7311
7370
  };
7312
7371
  _proto.registerListeners = function registerListeners() {
7313
7372
  var hls = this.hls;
@@ -7465,6 +7524,7 @@
7465
7524
  _this2.resetBuffer(type);
7466
7525
  });
7467
7526
  this._initSourceBuffer();
7527
+ this.hls.resumeBuffering();
7468
7528
  };
7469
7529
  _proto.resetBuffer = function resetBuffer(type) {
7470
7530
  var sb = this.sourceBuffer[type];
@@ -8168,7 +8228,7 @@
8168
8228
  }
8169
8229
  }]);
8170
8230
  return BufferController;
8171
- }();
8231
+ }(Logger);
8172
8232
  function removeSourceChildren(node) {
8173
8233
  var sourceChildren = node.querySelectorAll('source');
8174
8234
  [].slice.call(sourceChildren).forEach(function (source) {
@@ -8292,7 +8352,7 @@
8292
8352
  var hls = this.hls;
8293
8353
  var maxLevel = this.getMaxLevel(levels.length - 1);
8294
8354
  if (maxLevel !== this.autoLevelCapping) {
8295
- logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8355
+ hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
8296
8356
  }
8297
8357
  hls.autoLevelCapping = maxLevel;
8298
8358
  if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
@@ -8482,10 +8542,10 @@
8482
8542
  totalDroppedFrames: droppedFrames
8483
8543
  });
8484
8544
  if (droppedFPS > 0) {
8485
- // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8545
+ // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8486
8546
  if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
8487
8547
  var currentLevel = hls.currentLevel;
8488
- logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8548
+ hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
8489
8549
  if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
8490
8550
  currentLevel = currentLevel - 1;
8491
8551
  hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
@@ -8519,26 +8579,28 @@
8519
8579
  }();
8520
8580
 
8521
8581
  var PATHWAY_PENALTY_DURATION_MS = 300000;
8522
- var ContentSteeringController = /*#__PURE__*/function () {
8582
+ var ContentSteeringController = /*#__PURE__*/function (_Logger) {
8583
+ _inheritsLoose(ContentSteeringController, _Logger);
8523
8584
  function ContentSteeringController(hls) {
8524
- this.hls = void 0;
8525
- this.log = void 0;
8526
- this.loader = null;
8527
- this.uri = null;
8528
- this.pathwayId = '.';
8529
- this.pathwayPriority = null;
8530
- this.timeToLoad = 300;
8531
- this.reloadTimer = -1;
8532
- this.updated = 0;
8533
- this.started = false;
8534
- this.enabled = true;
8535
- this.levels = null;
8536
- this.audioTracks = null;
8537
- this.subtitleTracks = null;
8538
- this.penalizedPathways = {};
8539
- this.hls = hls;
8540
- this.log = logger.log.bind(logger, "[content-steering]:");
8541
- this.registerListeners();
8585
+ var _this;
8586
+ _this = _Logger.call(this, 'content-steering', hls.logger) || this;
8587
+ _this.hls = void 0;
8588
+ _this.loader = null;
8589
+ _this.uri = null;
8590
+ _this.pathwayId = '.';
8591
+ _this.pathwayPriority = null;
8592
+ _this.timeToLoad = 300;
8593
+ _this.reloadTimer = -1;
8594
+ _this.updated = 0;
8595
+ _this.started = false;
8596
+ _this.enabled = true;
8597
+ _this.levels = null;
8598
+ _this.audioTracks = null;
8599
+ _this.subtitleTracks = null;
8600
+ _this.penalizedPathways = {};
8601
+ _this.hls = hls;
8602
+ _this.registerListeners();
8603
+ return _this;
8542
8604
  }
8543
8605
  var _proto = ContentSteeringController.prototype;
8544
8606
  _proto.registerListeners = function registerListeners() {
@@ -8659,7 +8721,7 @@
8659
8721
  errorAction.resolved = this.pathwayId !== errorPathway;
8660
8722
  }
8661
8723
  if (!errorAction.resolved) {
8662
- logger.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
8724
+ this.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
8663
8725
  }
8664
8726
  }
8665
8727
  };
@@ -8739,7 +8801,7 @@
8739
8801
  return defaultPathway;
8740
8802
  };
8741
8803
  _proto.clonePathways = function clonePathways(pathwayClones) {
8742
- var _this = this;
8804
+ var _this2 = this;
8743
8805
  var levels = this.levels;
8744
8806
  if (!levels) {
8745
8807
  return;
@@ -8755,7 +8817,7 @@
8755
8817
  })) {
8756
8818
  return;
8757
8819
  }
8758
- var clonedVariants = _this.getLevelsForPathway(baseId).map(function (baseLevel) {
8820
+ var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
8759
8821
  var attributes = new AttrList(baseLevel.attrs);
8760
8822
  attributes['PATHWAY-ID'] = cloneId;
8761
8823
  var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
@@ -8792,12 +8854,12 @@
8792
8854
  return clonedLevel;
8793
8855
  });
8794
8856
  levels.push.apply(levels, clonedVariants);
8795
- cloneRenditionGroups(_this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8796
- cloneRenditionGroups(_this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8857
+ cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8858
+ cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8797
8859
  });
8798
8860
  };
8799
8861
  _proto.loadSteeringManifest = function loadSteeringManifest(uri) {
8800
- var _this2 = this;
8862
+ var _this3 = this;
8801
8863
  var config = this.hls.config;
8802
8864
  var Loader = config.loader;
8803
8865
  if (this.loader) {
@@ -8832,87 +8894,87 @@
8832
8894
  };
8833
8895
  var callbacks = {
8834
8896
  onSuccess: function onSuccess(response, stats, context, networkDetails) {
8835
- _this2.log("Loaded steering manifest: \"" + url + "\"");
8897
+ _this3.log("Loaded steering manifest: \"" + url + "\"");
8836
8898
  var steeringData = response.data;
8837
- if (steeringData.VERSION !== 1) {
8838
- _this2.log("Steering VERSION " + steeringData.VERSION + " not supported!");
8899
+ if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
8900
+ _this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
8839
8901
  return;
8840
8902
  }
8841
- _this2.updated = performance.now();
8842
- _this2.timeToLoad = steeringData.TTL;
8903
+ _this3.updated = performance.now();
8904
+ _this3.timeToLoad = steeringData.TTL;
8843
8905
  var reloadUri = steeringData['RELOAD-URI'],
8844
8906
  pathwayClones = steeringData['PATHWAY-CLONES'],
8845
8907
  pathwayPriority = steeringData['PATHWAY-PRIORITY'];
8846
8908
  if (reloadUri) {
8847
8909
  try {
8848
- _this2.uri = new self.URL(reloadUri, url).href;
8910
+ _this3.uri = new self.URL(reloadUri, url).href;
8849
8911
  } catch (error) {
8850
- _this2.enabled = false;
8851
- _this2.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
8912
+ _this3.enabled = false;
8913
+ _this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
8852
8914
  return;
8853
8915
  }
8854
8916
  }
8855
- _this2.scheduleRefresh(_this2.uri || context.url);
8917
+ _this3.scheduleRefresh(_this3.uri || context.url);
8856
8918
  if (pathwayClones) {
8857
- _this2.clonePathways(pathwayClones);
8919
+ _this3.clonePathways(pathwayClones);
8858
8920
  }
8859
8921
  var loadedSteeringData = {
8860
8922
  steeringManifest: steeringData,
8861
8923
  url: url.toString()
8862
8924
  };
8863
- _this2.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8925
+ _this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8864
8926
  if (pathwayPriority) {
8865
- _this2.updatePathwayPriority(pathwayPriority);
8927
+ _this3.updatePathwayPriority(pathwayPriority);
8866
8928
  }
8867
8929
  },
8868
8930
  onError: function onError(error, context, networkDetails, stats) {
8869
- _this2.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8870
- _this2.stopLoad();
8931
+ _this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8932
+ _this3.stopLoad();
8871
8933
  if (error.code === 410) {
8872
- _this2.enabled = false;
8873
- _this2.log("Steering manifest " + context.url + " no longer available");
8934
+ _this3.enabled = false;
8935
+ _this3.log("Steering manifest " + context.url + " no longer available");
8874
8936
  return;
8875
8937
  }
8876
- var ttl = _this2.timeToLoad * 1000;
8938
+ var ttl = _this3.timeToLoad * 1000;
8877
8939
  if (error.code === 429) {
8878
- var loader = _this2.loader;
8940
+ var loader = _this3.loader;
8879
8941
  if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
8880
8942
  var retryAfter = loader.getResponseHeader('Retry-After');
8881
8943
  if (retryAfter) {
8882
8944
  ttl = parseFloat(retryAfter) * 1000;
8883
8945
  }
8884
8946
  }
8885
- _this2.log("Steering manifest " + context.url + " rate limited");
8947
+ _this3.log("Steering manifest " + context.url + " rate limited");
8886
8948
  return;
8887
8949
  }
8888
- _this2.scheduleRefresh(_this2.uri || context.url, ttl);
8950
+ _this3.scheduleRefresh(_this3.uri || context.url, ttl);
8889
8951
  },
8890
8952
  onTimeout: function onTimeout(stats, context, networkDetails) {
8891
- _this2.log("Timeout loading steering manifest (" + context.url + ")");
8892
- _this2.scheduleRefresh(_this2.uri || context.url);
8953
+ _this3.log("Timeout loading steering manifest (" + context.url + ")");
8954
+ _this3.scheduleRefresh(_this3.uri || context.url);
8893
8955
  }
8894
8956
  };
8895
8957
  this.log("Requesting steering manifest: " + url);
8896
8958
  this.loader.load(context, loaderConfig, callbacks);
8897
8959
  };
8898
8960
  _proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
8899
- var _this3 = this;
8961
+ var _this4 = this;
8900
8962
  if (ttlMs === void 0) {
8901
8963
  ttlMs = this.timeToLoad * 1000;
8902
8964
  }
8903
8965
  this.clearTimeout();
8904
8966
  this.reloadTimer = self.setTimeout(function () {
8905
- var _this3$hls;
8906
- var media = (_this3$hls = _this3.hls) == null ? void 0 : _this3$hls.media;
8967
+ var _this4$hls;
8968
+ var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
8907
8969
  if (media && !media.ended) {
8908
- _this3.loadSteeringManifest(uri);
8970
+ _this4.loadSteeringManifest(uri);
8909
8971
  return;
8910
8972
  }
8911
- _this3.scheduleRefresh(uri, _this3.timeToLoad * 1000);
8973
+ _this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
8912
8974
  }, ttlMs);
8913
8975
  };
8914
8976
  return ContentSteeringController;
8915
- }();
8977
+ }(Logger);
8916
8978
  function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
8917
8979
  if (!tracks) {
8918
8980
  return;
@@ -9779,7 +9841,7 @@
9779
9841
  /**
9780
9842
  * @ignore
9781
9843
  */
9782
- function mergeConfig(defaultConfig, userConfig) {
9844
+ function mergeConfig(defaultConfig, userConfig, logger) {
9783
9845
  if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
9784
9846
  throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
9785
9847
  }
@@ -9849,7 +9911,7 @@
9849
9911
  /**
9850
9912
  * @ignore
9851
9913
  */
9852
- function enableStreamingMode(config) {
9914
+ function enableStreamingMode(config, logger) {
9853
9915
  var currentLoader = config.loader;
9854
9916
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
9855
9917
  // If a developer has configured their own loader, respect that choice
@@ -9866,12 +9928,11 @@
9866
9928
  }
9867
9929
  }
9868
9930
 
9869
- var chromeOrFirefox;
9870
9931
  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
9871
9932
  _inheritsLoose(LevelController, _BasePlaylistControll);
9872
9933
  function LevelController(hls, contentSteeringController) {
9873
9934
  var _this;
9874
- _this = _BasePlaylistControll.call(this, hls, '[level-controller]') || this;
9935
+ _this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
9875
9936
  _this._levels = [];
9876
9937
  _this._firstLevel = -1;
9877
9938
  _this._maxAutoLevel = -1;
@@ -9940,21 +10001,13 @@
9940
10001
  var videoCodecFound = false;
9941
10002
  var audioCodecFound = false;
9942
10003
  data.levels.forEach(function (levelParsed) {
9943
- var _audioCodec, _videoCodec;
10004
+ var _videoCodec;
9944
10005
  var attributes = levelParsed.attrs;
9945
-
9946
- // erase audio codec info if browser does not support mp4a.40.34.
9947
- // demuxer will autodetect codec and fallback to mpeg/audio
9948
10006
  var audioCodec = levelParsed.audioCodec,
9949
10007
  videoCodec = levelParsed.videoCodec;
9950
- if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
9951
- chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
9952
- if (chromeOrFirefox) {
9953
- levelParsed.audioCodec = audioCodec = undefined;
9954
- }
9955
- }
9956
10008
  if (audioCodec) {
9957
- levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
10009
+ // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
10010
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
9958
10011
  }
9959
10012
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
9960
10013
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -11101,8 +11154,8 @@
11101
11154
  var _frag$decryptdata;
11102
11155
  var byteRangeStart = start;
11103
11156
  var byteRangeEnd = end;
11104
- if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
11105
- // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
11157
+ if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
11158
+ // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
11106
11159
  // has the unencrypted size specified in the range.
11107
11160
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
11108
11161
  var fragmentLen = end - start;
@@ -11135,6 +11188,9 @@
11135
11188
  (part ? part : frag).stats.aborted = true;
11136
11189
  return new LoadError(errorData);
11137
11190
  }
11191
+ function isMethodFullSegmentAesCbc(method) {
11192
+ return method === 'AES-128' || method === 'AES-256';
11193
+ }
11138
11194
  var LoadError = /*#__PURE__*/function (_Error) {
11139
11195
  _inheritsLoose(LoadError, _Error);
11140
11196
  function LoadError(data) {
@@ -11291,6 +11347,8 @@
11291
11347
  }
11292
11348
  return this.loadKeyEME(keyInfo, frag);
11293
11349
  case 'AES-128':
11350
+ case 'AES-256':
11351
+ case 'AES-256-CTR':
11294
11352
  return this.loadKeyHTTP(keyInfo, frag);
11295
11353
  default:
11296
11354
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
@@ -11424,13 +11482,17 @@
11424
11482
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
11425
11483
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
11426
11484
  */
11427
- var TaskLoop = /*#__PURE__*/function () {
11428
- function TaskLoop() {
11429
- this._boundTick = void 0;
11430
- this._tickTimer = null;
11431
- this._tickInterval = null;
11432
- this._tickCallCount = 0;
11433
- this._boundTick = this.tick.bind(this);
11485
+ var TaskLoop = /*#__PURE__*/function (_Logger) {
11486
+ _inheritsLoose(TaskLoop, _Logger);
11487
+ function TaskLoop(label, logger) {
11488
+ var _this;
11489
+ _this = _Logger.call(this, label, logger) || this;
11490
+ _this._boundTick = void 0;
11491
+ _this._tickTimer = null;
11492
+ _this._tickInterval = null;
11493
+ _this._tickCallCount = 0;
11494
+ _this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
11495
+ return _this;
11434
11496
  }
11435
11497
  var _proto = TaskLoop.prototype;
11436
11498
  _proto.destroy = function destroy() {
@@ -11516,7 +11578,7 @@
11516
11578
  */;
11517
11579
  _proto.doTick = function doTick() {};
11518
11580
  return TaskLoop;
11519
- }();
11581
+ }(Logger);
11520
11582
 
11521
11583
  var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
11522
11584
  if (size === void 0) {
@@ -11702,37 +11764,65 @@
11702
11764
  }
11703
11765
 
11704
11766
  var AESCrypto = /*#__PURE__*/function () {
11705
- function AESCrypto(subtle, iv) {
11767
+ function AESCrypto(subtle, iv, aesMode) {
11706
11768
  this.subtle = void 0;
11707
11769
  this.aesIV = void 0;
11770
+ this.aesMode = void 0;
11708
11771
  this.subtle = subtle;
11709
11772
  this.aesIV = iv;
11773
+ this.aesMode = aesMode;
11710
11774
  }
11711
11775
  var _proto = AESCrypto.prototype;
11712
11776
  _proto.decrypt = function decrypt(data, key) {
11713
- return this.subtle.decrypt({
11714
- name: 'AES-CBC',
11715
- iv: this.aesIV
11716
- }, key, data);
11777
+ switch (this.aesMode) {
11778
+ case DecrypterAesMode.cbc:
11779
+ return this.subtle.decrypt({
11780
+ name: 'AES-CBC',
11781
+ iv: this.aesIV
11782
+ }, key, data);
11783
+ case DecrypterAesMode.ctr:
11784
+ return this.subtle.decrypt({
11785
+ name: 'AES-CTR',
11786
+ counter: this.aesIV,
11787
+ length: 64
11788
+ },
11789
+ //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
11790
+ key, data);
11791
+ default:
11792
+ throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
11793
+ }
11717
11794
  };
11718
11795
  return AESCrypto;
11719
11796
  }();
11720
11797
 
11721
11798
  var FastAESKey = /*#__PURE__*/function () {
11722
- function FastAESKey(subtle, key) {
11799
+ function FastAESKey(subtle, key, aesMode) {
11723
11800
  this.subtle = void 0;
11724
11801
  this.key = void 0;
11802
+ this.aesMode = void 0;
11725
11803
  this.subtle = subtle;
11726
11804
  this.key = key;
11805
+ this.aesMode = aesMode;
11727
11806
  }
11728
11807
  var _proto = FastAESKey.prototype;
11729
11808
  _proto.expandKey = function expandKey() {
11809
+ var subtleAlgoName = getSubtleAlgoName(this.aesMode);
11730
11810
  return this.subtle.importKey('raw', this.key, {
11731
- name: 'AES-CBC'
11811
+ name: subtleAlgoName
11732
11812
  }, false, ['encrypt', 'decrypt']);
11733
11813
  };
11734
11814
  return FastAESKey;
11735
11815
  }();
11816
+ function getSubtleAlgoName(aesMode) {
11817
+ switch (aesMode) {
11818
+ case DecrypterAesMode.cbc:
11819
+ return 'AES-CBC';
11820
+ case DecrypterAesMode.ctr:
11821
+ return 'AES-CTR';
11822
+ default:
11823
+ throw new Error("[FastAESKey] invalid aes mode " + aesMode);
11824
+ }
11825
+ }
11736
11826
 
11737
11827
  // PKCS7
11738
11828
  function removePadding(array) {
@@ -11985,7 +12075,8 @@
11985
12075
  this.currentIV = null;
11986
12076
  this.currentResult = null;
11987
12077
  this.useSoftware = void 0;
11988
- this.useSoftware = config.enableSoftwareAES;
12078
+ this.enableSoftwareAES = void 0;
12079
+ this.enableSoftwareAES = config.enableSoftwareAES;
11989
12080
  this.removePKCS7Padding = removePKCS7Padding;
11990
12081
  // built in decryptor expects PKCS7 padding
11991
12082
  if (removePKCS7Padding) {
@@ -11998,9 +12089,7 @@
11998
12089
  /* no-op */
11999
12090
  }
12000
12091
  }
12001
- if (this.subtle === null) {
12002
- this.useSoftware = true;
12003
- }
12092
+ this.useSoftware = this.subtle === null;
12004
12093
  }
12005
12094
  var _proto = Decrypter.prototype;
12006
12095
  _proto.destroy = function destroy() {
@@ -12037,11 +12126,11 @@
12037
12126
  this.softwareDecrypter = null;
12038
12127
  }
12039
12128
  };
12040
- _proto.decrypt = function decrypt(data, key, iv) {
12129
+ _proto.decrypt = function decrypt(data, key, iv, aesMode) {
12041
12130
  var _this = this;
12042
12131
  if (this.useSoftware) {
12043
12132
  return new Promise(function (resolve, reject) {
12044
- _this.softwareDecrypt(new Uint8Array(data), key, iv);
12133
+ _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
12045
12134
  var decryptResult = _this.flush();
12046
12135
  if (decryptResult) {
12047
12136
  resolve(decryptResult.buffer);
@@ -12050,16 +12139,20 @@
12050
12139
  }
12051
12140
  });
12052
12141
  }
12053
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
12142
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
12054
12143
  }
12055
12144
 
12056
12145
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
12057
12146
  // data is handled in the flush() call
12058
12147
  ;
12059
- _proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
12148
+ _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
12060
12149
  var currentIV = this.currentIV,
12061
12150
  currentResult = this.currentResult,
12062
12151
  remainderData = this.remainderData;
12152
+ if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
12153
+ logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
12154
+ return null;
12155
+ }
12063
12156
  this.logOnce('JS AES decrypt');
12064
12157
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
12065
12158
  // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
@@ -12092,12 +12185,12 @@
12092
12185
  }
12093
12186
  return result;
12094
12187
  };
12095
- _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
12188
+ _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
12096
12189
  var _this2 = this;
12097
12190
  var subtle = this.subtle;
12098
12191
  if (this.key !== key || !this.fastAesKey) {
12099
12192
  this.key = key;
12100
- this.fastAesKey = new FastAESKey(subtle, key);
12193
+ this.fastAesKey = new FastAESKey(subtle, key, aesMode);
12101
12194
  }
12102
12195
  return this.fastAesKey.expandKey().then(function (aesKey) {
12103
12196
  // decrypt using web crypto
@@ -12105,22 +12198,25 @@
12105
12198
  return Promise.reject(new Error('web crypto not initialized'));
12106
12199
  }
12107
12200
  _this2.logOnce('WebCrypto AES decrypt');
12108
- var crypto = new AESCrypto(subtle, new Uint8Array(iv));
12201
+ var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
12109
12202
  return crypto.decrypt(data.buffer, aesKey);
12110
12203
  }).catch(function (err) {
12111
12204
  logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
12112
- return _this2.onWebCryptoError(data, key, iv);
12205
+ return _this2.onWebCryptoError(data, key, iv, aesMode);
12113
12206
  });
12114
12207
  };
12115
- _proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
12116
- this.useSoftware = true;
12117
- this.logEnabled = true;
12118
- this.softwareDecrypt(data, key, iv);
12119
- var decryptResult = this.flush();
12120
- if (decryptResult) {
12121
- return decryptResult.buffer;
12208
+ _proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
12209
+ var enableSoftwareAES = this.enableSoftwareAES;
12210
+ if (enableSoftwareAES) {
12211
+ this.useSoftware = true;
12212
+ this.logEnabled = true;
12213
+ this.softwareDecrypt(data, key, iv, aesMode);
12214
+ var decryptResult = this.flush();
12215
+ if (decryptResult) {
12216
+ return decryptResult.buffer;
12217
+ }
12122
12218
  }
12123
- throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
12219
+ throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
12124
12220
  };
12125
12221
  _proto.getValidChunk = function getValidChunk(data) {
12126
12222
  var currentChunk = data;
@@ -12174,7 +12270,7 @@
12174
12270
  _inheritsLoose(BaseStreamController, _TaskLoop);
12175
12271
  function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
12176
12272
  var _this;
12177
- _this = _TaskLoop.call(this) || this;
12273
+ _this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
12178
12274
  _this.hls = void 0;
12179
12275
  _this.fragPrevious = null;
12180
12276
  _this.fragCurrent = null;
@@ -12199,25 +12295,87 @@
12199
12295
  _this.startFragRequested = false;
12200
12296
  _this.decrypter = void 0;
12201
12297
  _this.initPTS = [];
12202
- _this.onvseeking = null;
12203
- _this.onvended = null;
12204
- _this.logPrefix = '';
12205
- _this.log = void 0;
12206
- _this.warn = void 0;
12298
+ _this.buffering = true;
12299
+ _this.onMediaSeeking = function () {
12300
+ var _assertThisInitialize = _assertThisInitialized(_this),
12301
+ config = _assertThisInitialize.config,
12302
+ fragCurrent = _assertThisInitialize.fragCurrent,
12303
+ media = _assertThisInitialize.media,
12304
+ mediaBuffer = _assertThisInitialize.mediaBuffer,
12305
+ state = _assertThisInitialize.state;
12306
+ var currentTime = media ? media.currentTime : 0;
12307
+ var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12308
+ _this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12309
+ if (_this.state === State.ENDED) {
12310
+ _this.resetLoadingState();
12311
+ } else if (fragCurrent) {
12312
+ // Seeking while frag load is in progress
12313
+ var tolerance = config.maxFragLookUpTolerance;
12314
+ var fragStartOffset = fragCurrent.start - tolerance;
12315
+ var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12316
+ // if seeking out of buffered range or into new one
12317
+ if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12318
+ var pastFragment = currentTime > fragEndOffset;
12319
+ // if the seek position is outside the current fragment range
12320
+ if (currentTime < fragStartOffset || pastFragment) {
12321
+ if (pastFragment && fragCurrent.loader) {
12322
+ _this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12323
+ fragCurrent.abortRequests();
12324
+ _this.resetLoadingState();
12325
+ }
12326
+ _this.fragPrevious = null;
12327
+ }
12328
+ }
12329
+ }
12330
+ if (media) {
12331
+ // Remove gap fragments
12332
+ _this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
12333
+ _this.lastCurrentTime = currentTime;
12334
+ }
12335
+
12336
+ // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12337
+ if (!_this.loadedmetadata && !bufferInfo.len) {
12338
+ _this.nextLoadPosition = _this.startPosition = currentTime;
12339
+ }
12340
+
12341
+ // Async tick to speed up processing
12342
+ _this.tickImmediate();
12343
+ };
12344
+ _this.onMediaEnded = function () {
12345
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12346
+ _this.startPosition = _this.lastCurrentTime = 0;
12347
+ if (_this.playlistType === PlaylistLevelType.MAIN) {
12348
+ _this.hls.trigger(Events.MEDIA_ENDED, {
12349
+ stalled: false
12350
+ });
12351
+ }
12352
+ };
12207
12353
  _this.playlistType = playlistType;
12208
- _this.logPrefix = logPrefix;
12209
- _this.log = logger.log.bind(logger, logPrefix + ":");
12210
- _this.warn = logger.warn.bind(logger, logPrefix + ":");
12211
12354
  _this.hls = hls;
12212
12355
  _this.fragmentLoader = new FragmentLoader(hls.config);
12213
12356
  _this.keyLoader = keyLoader;
12214
12357
  _this.fragmentTracker = fragmentTracker;
12215
12358
  _this.config = hls.config;
12216
12359
  _this.decrypter = new Decrypter(hls.config);
12217
- hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
12218
12360
  return _this;
12219
12361
  }
12220
12362
  var _proto = BaseStreamController.prototype;
12363
+ _proto.registerListeners = function registerListeners() {
12364
+ var hls = this.hls;
12365
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12366
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12367
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12368
+ hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12369
+ hls.on(Events.ERROR, this.onError, this);
12370
+ };
12371
+ _proto.unregisterListeners = function unregisterListeners() {
12372
+ var hls = this.hls;
12373
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
12374
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
12375
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
12376
+ hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
12377
+ hls.off(Events.ERROR, this.onError, this);
12378
+ };
12221
12379
  _proto.doTick = function doTick() {
12222
12380
  this.onTickEnd();
12223
12381
  };
@@ -12241,6 +12399,12 @@
12241
12399
  this.clearNextTick();
12242
12400
  this.state = State.STOPPED;
12243
12401
  };
12402
+ _proto.pauseBuffering = function pauseBuffering() {
12403
+ this.buffering = false;
12404
+ };
12405
+ _proto.resumeBuffering = function resumeBuffering() {
12406
+ this.buffering = true;
12407
+ };
12244
12408
  _proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
12245
12409
  // If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
12246
12410
  // of nothing loading/loaded return false
@@ -12271,10 +12435,8 @@
12271
12435
  };
12272
12436
  _proto.onMediaAttached = function onMediaAttached(event, data) {
12273
12437
  var media = this.media = this.mediaBuffer = data.media;
12274
- this.onvseeking = this.onMediaSeeking.bind(this);
12275
- this.onvended = this.onMediaEnded.bind(this);
12276
- media.addEventListener('seeking', this.onvseeking);
12277
- media.addEventListener('ended', this.onvended);
12438
+ media.addEventListener('seeking', this.onMediaSeeking);
12439
+ media.addEventListener('ended', this.onMediaEnded);
12278
12440
  var config = this.config;
12279
12441
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12280
12442
  this.startLoad(config.startPosition);
@@ -12288,10 +12450,9 @@
12288
12450
  }
12289
12451
 
12290
12452
  // remove video listeners
12291
- if (media && this.onvseeking && this.onvended) {
12292
- media.removeEventListener('seeking', this.onvseeking);
12293
- media.removeEventListener('ended', this.onvended);
12294
- this.onvseeking = this.onvended = null;
12453
+ if (media) {
12454
+ media.removeEventListener('seeking', this.onMediaSeeking);
12455
+ media.removeEventListener('ended', this.onMediaEnded);
12295
12456
  }
12296
12457
  if (this.keyLoader) {
12297
12458
  this.keyLoader.detach();
@@ -12301,54 +12462,8 @@
12301
12462
  this.fragmentTracker.removeAllFragments();
12302
12463
  this.stopLoad();
12303
12464
  };
12304
- _proto.onMediaSeeking = function onMediaSeeking() {
12305
- var config = this.config,
12306
- fragCurrent = this.fragCurrent,
12307
- media = this.media,
12308
- mediaBuffer = this.mediaBuffer,
12309
- state = this.state;
12310
- var currentTime = media ? media.currentTime : 0;
12311
- var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12312
- this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12313
- if (this.state === State.ENDED) {
12314
- this.resetLoadingState();
12315
- } else if (fragCurrent) {
12316
- // Seeking while frag load is in progress
12317
- var tolerance = config.maxFragLookUpTolerance;
12318
- var fragStartOffset = fragCurrent.start - tolerance;
12319
- var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12320
- // if seeking out of buffered range or into new one
12321
- if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12322
- var pastFragment = currentTime > fragEndOffset;
12323
- // if the seek position is outside the current fragment range
12324
- if (currentTime < fragStartOffset || pastFragment) {
12325
- if (pastFragment && fragCurrent.loader) {
12326
- this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12327
- fragCurrent.abortRequests();
12328
- this.resetLoadingState();
12329
- }
12330
- this.fragPrevious = null;
12331
- }
12332
- }
12333
- }
12334
- if (media) {
12335
- // Remove gap fragments
12336
- this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
12337
- this.lastCurrentTime = currentTime;
12338
- }
12339
-
12340
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12341
- if (!this.loadedmetadata && !bufferInfo.len) {
12342
- this.nextLoadPosition = this.startPosition = currentTime;
12343
- }
12344
-
12345
- // Async tick to speed up processing
12346
- this.tickImmediate();
12347
- };
12348
- _proto.onMediaEnded = function onMediaEnded() {
12349
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12350
- this.startPosition = this.lastCurrentTime = 0;
12351
- };
12465
+ _proto.onManifestLoading = function onManifestLoading() {};
12466
+ _proto.onError = function onError(event, data) {};
12352
12467
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
12353
12468
  this.startTimeOffset = data.startTimeOffset;
12354
12469
  this.initPTS = [];
@@ -12358,7 +12473,7 @@
12358
12473
  this.stopLoad();
12359
12474
  _TaskLoop.prototype.onHandlerDestroying.call(this);
12360
12475
  // @ts-ignore
12361
- this.hls = null;
12476
+ this.hls = this.onMediaSeeking = this.onMediaEnded = null;
12362
12477
  };
12363
12478
  _proto.onHandlerDestroyed = function onHandlerDestroyed() {
12364
12479
  this.state = State.STOPPED;
@@ -12488,10 +12603,10 @@
12488
12603
  var decryptData = frag.decryptdata;
12489
12604
 
12490
12605
  // check to see if the payload needs to be decrypted
12491
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
12606
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
12492
12607
  var startTime = self.performance.now();
12493
12608
  // decrypt init segment data
12494
- return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
12609
+ return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
12495
12610
  hls.trigger(Events.ERROR, {
12496
12611
  type: ErrorTypes.MEDIA_ERROR,
12497
12612
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -12604,7 +12719,7 @@
12604
12719
  }
12605
12720
  var keyLoadingPromise = null;
12606
12721
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
12607
- this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + " " + frag.level);
12722
+ this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
12608
12723
  this.state = State.KEY_LOADING;
12609
12724
  this.fragCurrent = frag;
12610
12725
  keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
@@ -12635,7 +12750,7 @@
12635
12750
  var partIndex = this.getNextPart(partList, frag, targetBufferTime);
12636
12751
  if (partIndex > -1) {
12637
12752
  var part = partList[partIndex];
12638
- this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12753
+ this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12639
12754
  this.nextLoadPosition = part.start + part.duration;
12640
12755
  this.state = State.FRAG_LOADING;
12641
12756
  var _result;
@@ -12668,7 +12783,7 @@
12668
12783
  }
12669
12784
  }
12670
12785
  }
12671
- this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12786
+ this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
12672
12787
  // Don't update nextLoadPosition for fragments which are not buffered
12673
12788
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
12674
12789
  this.nextLoadPosition = frag.start + frag.duration;
@@ -13229,7 +13344,7 @@
13229
13344
  errorAction.resolved = true;
13230
13345
  }
13231
13346
  } else {
13232
- logger.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13347
+ this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13233
13348
  return;
13234
13349
  }
13235
13350
  } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
@@ -13619,6 +13734,7 @@
13619
13734
  */
13620
13735
  function getAudioConfig(observer, data, offset, audioCodec) {
13621
13736
  var adtsObjectType;
13737
+ var originalAdtsObjectType;
13622
13738
  var adtsExtensionSamplingIndex;
13623
13739
  var adtsChannelConfig;
13624
13740
  var config;
@@ -13626,7 +13742,7 @@
13626
13742
  var manifestCodec = audioCodec;
13627
13743
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
13628
13744
  // byte 2
13629
- adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13745
+ adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13630
13746
  var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
13631
13747
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
13632
13748
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
@@ -13643,8 +13759,8 @@
13643
13759
  // byte 3
13644
13760
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
13645
13761
  logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
13646
- // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
13647
- if (/firefox/i.test(userAgent)) {
13762
+ // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
13763
+ if (/firefox|palemoon/i.test(userAgent)) {
13648
13764
  if (adtsSamplingIndex >= 6) {
13649
13765
  adtsObjectType = 5;
13650
13766
  config = new Array(4);
@@ -13738,6 +13854,7 @@
13738
13854
  samplerate: adtsSamplingRates[adtsSamplingIndex],
13739
13855
  channelCount: adtsChannelConfig,
13740
13856
  codec: 'mp4a.40.' + adtsObjectType,
13857
+ parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
13741
13858
  manifestCodec: manifestCodec
13742
13859
  };
13743
13860
  }
@@ -13792,7 +13909,8 @@
13792
13909
  track.channelCount = config.channelCount;
13793
13910
  track.codec = config.codec;
13794
13911
  track.manifestCodec = config.manifestCodec;
13795
- logger.log("parsed codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13912
+ track.parsedCodec = config.parsedCodec;
13913
+ logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
13796
13914
  }
13797
13915
  }
13798
13916
  function getFrameDuration(samplerate) {
@@ -14272,32 +14390,136 @@
14272
14390
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
14273
14391
  }
14274
14392
  };
14275
- return BaseVideoParser;
14276
- }();
14277
-
14278
- /**
14279
- * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
14280
- */
14281
-
14282
- var ExpGolomb = /*#__PURE__*/function () {
14283
- function ExpGolomb(data) {
14284
- this.data = void 0;
14285
- this.bytesAvailable = void 0;
14286
- this.word = void 0;
14287
- this.bitsAvailable = void 0;
14288
- this.data = data;
14289
- // the number of bytes left to examine in this.data
14290
- this.bytesAvailable = data.byteLength;
14291
- // the current word being examined
14292
- this.word = 0; // :uint
14293
- // the number of bits left to examine in the current word
14294
- this.bitsAvailable = 0; // :uint
14295
- }
14393
+ _proto.parseNALu = function parseNALu(track, array) {
14394
+ var len = array.byteLength;
14395
+ var state = track.naluState || 0;
14396
+ var lastState = state;
14397
+ var units = [];
14398
+ var i = 0;
14399
+ var value;
14400
+ var overflow;
14401
+ var unitType;
14402
+ var lastUnitStart = -1;
14403
+ var lastUnitType = 0;
14404
+ // logger.log('PES:' + Hex.hexDump(array));
14296
14405
 
14297
- // ():void
14298
- var _proto = ExpGolomb.prototype;
14299
- _proto.loadWord = function loadWord() {
14300
- var data = this.data;
14406
+ if (state === -1) {
14407
+ // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14408
+ lastUnitStart = 0;
14409
+ // NALu type is value read from offset 0
14410
+ lastUnitType = this.getNALuType(array, 0);
14411
+ state = 0;
14412
+ i = 1;
14413
+ }
14414
+ while (i < len) {
14415
+ value = array[i++];
14416
+ // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14417
+ if (!state) {
14418
+ state = value ? 0 : 1;
14419
+ continue;
14420
+ }
14421
+ if (state === 1) {
14422
+ state = value ? 0 : 2;
14423
+ continue;
14424
+ }
14425
+ // here we have state either equal to 2 or 3
14426
+ if (!value) {
14427
+ state = 3;
14428
+ } else if (value === 1) {
14429
+ overflow = i - state - 1;
14430
+ if (lastUnitStart >= 0) {
14431
+ var unit = {
14432
+ data: array.subarray(lastUnitStart, overflow),
14433
+ type: lastUnitType
14434
+ };
14435
+ // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14436
+ units.push(unit);
14437
+ } else {
14438
+ // lastUnitStart is undefined => this is the first start code found in this PES packet
14439
+ // first check if start code delimiter is overlapping between 2 PES packets,
14440
+ // ie it started in last packet (lastState not zero)
14441
+ // and ended at the beginning of this PES packet (i <= 4 - lastState)
14442
+ var lastUnit = this.getLastNalUnit(track.samples);
14443
+ if (lastUnit) {
14444
+ if (lastState && i <= 4 - lastState) {
14445
+ // start delimiter overlapping between PES packets
14446
+ // strip start delimiter bytes from the end of last NAL unit
14447
+ // check if lastUnit had a state different from zero
14448
+ if (lastUnit.state) {
14449
+ // strip last bytes
14450
+ lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
14451
+ }
14452
+ }
14453
+ // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
14454
+
14455
+ if (overflow > 0) {
14456
+ // logger.log('first NALU found with overflow:' + overflow);
14457
+ lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14458
+ lastUnit.state = 0;
14459
+ }
14460
+ }
14461
+ }
14462
+ // check if we can read unit type
14463
+ if (i < len) {
14464
+ unitType = this.getNALuType(array, i);
14465
+ // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14466
+ lastUnitStart = i;
14467
+ lastUnitType = unitType;
14468
+ state = 0;
14469
+ } else {
14470
+ // not enough byte to read unit type. let's read it on next PES parsing
14471
+ state = -1;
14472
+ }
14473
+ } else {
14474
+ state = 0;
14475
+ }
14476
+ }
14477
+ if (lastUnitStart >= 0 && state >= 0) {
14478
+ var _unit = {
14479
+ data: array.subarray(lastUnitStart, len),
14480
+ type: lastUnitType,
14481
+ state: state
14482
+ };
14483
+ units.push(_unit);
14484
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
14485
+ }
14486
+ // no NALu found
14487
+ if (units.length === 0) {
14488
+ // append pes.data to previous NAL unit
14489
+ var _lastUnit = this.getLastNalUnit(track.samples);
14490
+ if (_lastUnit) {
14491
+ _lastUnit.data = appendUint8Array(_lastUnit.data, array);
14492
+ }
14493
+ }
14494
+ track.naluState = state;
14495
+ return units;
14496
+ };
14497
+ return BaseVideoParser;
14498
+ }();
14499
+
14500
+ /**
14501
+ * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
14502
+ */
14503
+
14504
+ var ExpGolomb = /*#__PURE__*/function () {
14505
+ function ExpGolomb(data) {
14506
+ this.data = void 0;
14507
+ this.bytesAvailable = void 0;
14508
+ this.word = void 0;
14509
+ this.bitsAvailable = void 0;
14510
+ this.data = data;
14511
+ // the number of bytes left to examine in this.data
14512
+ this.bytesAvailable = data.byteLength;
14513
+ // the current word being examined
14514
+ this.word = 0; // :uint
14515
+ // the number of bits left to examine in the current word
14516
+ this.bitsAvailable = 0; // :uint
14517
+ }
14518
+
14519
+ // ():void
14520
+ var _proto = ExpGolomb.prototype;
14521
+ _proto.loadWord = function loadWord() {
14522
+ var data = this.data;
14301
14523
  var bytesAvailable = this.bytesAvailable;
14302
14524
  var position = data.byteLength - bytesAvailable;
14303
14525
  var workingBytes = new Uint8Array(4);
@@ -14426,22 +14648,179 @@
14426
14648
  ;
14427
14649
  _proto.readUInt = function readUInt() {
14428
14650
  return this.readBits(32);
14651
+ };
14652
+ return ExpGolomb;
14653
+ }();
14654
+
14655
+ var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
14656
+ _inheritsLoose(AvcVideoParser, _BaseVideoParser);
14657
+ function AvcVideoParser() {
14658
+ return _BaseVideoParser.apply(this, arguments) || this;
14659
+ }
14660
+ var _proto = AvcVideoParser.prototype;
14661
+ _proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
14662
+ var _this = this;
14663
+ var units = this.parseNALu(track, pes.data);
14664
+ var VideoSample = this.VideoSample;
14665
+ var push;
14666
+ var spsfound = false;
14667
+ // free pes.data to save up some memory
14668
+ pes.data = null;
14669
+
14670
+ // if new NAL units found and last sample still there, let's push ...
14671
+ // this helps parsing streams with missing AUD (only do this if AUD never found)
14672
+ if (VideoSample && units.length && !track.audFound) {
14673
+ this.pushAccessUnit(VideoSample, track);
14674
+ VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts, '');
14675
+ }
14676
+ units.forEach(function (unit) {
14677
+ var _VideoSample2;
14678
+ switch (unit.type) {
14679
+ // NDR
14680
+ case 1:
14681
+ {
14682
+ var iskey = false;
14683
+ push = true;
14684
+ var data = unit.data;
14685
+ // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
14686
+ if (spsfound && data.length > 4) {
14687
+ // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
14688
+ var sliceType = _this.readSliceType(data);
14689
+ // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
14690
+ // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
14691
+ // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
14692
+ // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
14693
+ // if (sliceType === 2 || sliceType === 7) {
14694
+ if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
14695
+ iskey = true;
14696
+ }
14697
+ }
14698
+ if (iskey) {
14699
+ var _VideoSample;
14700
+ // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
14701
+ if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
14702
+ _this.pushAccessUnit(VideoSample, track);
14703
+ VideoSample = _this.VideoSample = null;
14704
+ }
14705
+ }
14706
+ if (!VideoSample) {
14707
+ VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
14708
+ }
14709
+ VideoSample.frame = true;
14710
+ VideoSample.key = iskey;
14711
+ break;
14712
+ // IDR
14713
+ }
14714
+ case 5:
14715
+ push = true;
14716
+ // handle PES not starting with AUD
14717
+ // if we have frame data already, that cannot belong to the same frame, so force a push
14718
+ if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
14719
+ _this.pushAccessUnit(VideoSample, track);
14720
+ VideoSample = _this.VideoSample = null;
14721
+ }
14722
+ if (!VideoSample) {
14723
+ VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
14724
+ }
14725
+ VideoSample.key = true;
14726
+ VideoSample.frame = true;
14727
+ break;
14728
+ // SEI
14729
+ case 6:
14730
+ {
14731
+ push = true;
14732
+ parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
14733
+ break;
14734
+ // SPS
14735
+ }
14736
+ case 7:
14737
+ {
14738
+ var _track$pixelRatio, _track$pixelRatio2;
14739
+ push = true;
14740
+ spsfound = true;
14741
+ var sps = unit.data;
14742
+ var config = _this.readSPS(sps);
14743
+ if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) {
14744
+ track.width = config.width;
14745
+ track.height = config.height;
14746
+ track.pixelRatio = config.pixelRatio;
14747
+ track.sps = [sps];
14748
+ track.duration = duration;
14749
+ var codecarray = sps.subarray(1, 4);
14750
+ var codecstring = 'avc1.';
14751
+ for (var i = 0; i < 3; i++) {
14752
+ var h = codecarray[i].toString(16);
14753
+ if (h.length < 2) {
14754
+ h = '0' + h;
14755
+ }
14756
+ codecstring += h;
14757
+ }
14758
+ track.codec = codecstring;
14759
+ }
14760
+ break;
14761
+ }
14762
+ // PPS
14763
+ case 8:
14764
+ push = true;
14765
+ track.pps = [unit.data];
14766
+ break;
14767
+ // AUD
14768
+ case 9:
14769
+ push = true;
14770
+ track.audFound = true;
14771
+ if (VideoSample) {
14772
+ _this.pushAccessUnit(VideoSample, track);
14773
+ }
14774
+ VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
14775
+ break;
14776
+ // Filler Data
14777
+ case 12:
14778
+ push = true;
14779
+ break;
14780
+ default:
14781
+ push = false;
14782
+ if (VideoSample) {
14783
+ VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
14784
+ }
14785
+ break;
14786
+ }
14787
+ if (VideoSample && push) {
14788
+ var _units = VideoSample.units;
14789
+ _units.push(unit);
14790
+ }
14791
+ });
14792
+ // if last PES packet, push samples
14793
+ if (last && VideoSample) {
14794
+ this.pushAccessUnit(VideoSample, track);
14795
+ this.VideoSample = null;
14796
+ }
14797
+ };
14798
+ _proto.getNALuType = function getNALuType(data, offset) {
14799
+ return data[offset] & 0x1f;
14800
+ };
14801
+ _proto.readSliceType = function readSliceType(data) {
14802
+ var eg = new ExpGolomb(data);
14803
+ // skip NALu type
14804
+ eg.readUByte();
14805
+ // discard first_mb_in_slice
14806
+ eg.readUEG();
14807
+ // return slice_type
14808
+ return eg.readUEG();
14429
14809
  }
14430
14810
 
14431
14811
  /**
14432
- * Advance the ExpGolomb decoder past a scaling list. The scaling
14433
- * list is optionally transmitted as part of a sequence parameter
14812
+ * The scaling list is optionally transmitted as part of a sequence parameter
14434
14813
  * set and is not relevant to transmuxing.
14435
14814
  * @param count the number of entries in this scaling list
14436
14815
  * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
14437
14816
  */;
14438
- _proto.skipScalingList = function skipScalingList(count) {
14817
+ _proto.skipScalingList = function skipScalingList(count, reader) {
14439
14818
  var lastScale = 8;
14440
14819
  var nextScale = 8;
14441
14820
  var deltaScale;
14442
14821
  for (var j = 0; j < count; j++) {
14443
14822
  if (nextScale !== 0) {
14444
- deltaScale = this.readEG();
14823
+ deltaScale = reader.readEG();
14445
14824
  nextScale = (lastScale + deltaScale + 256) % 256;
14446
14825
  }
14447
14826
  lastScale = nextScale === 0 ? lastScale : nextScale;
@@ -14456,7 +14835,8 @@
14456
14835
  * sequence parameter set, including the dimensions of the
14457
14836
  * associated video frames.
14458
14837
  */;
14459
- _proto.readSPS = function readSPS() {
14838
+ _proto.readSPS = function readSPS(sps) {
14839
+ var eg = new ExpGolomb(sps);
14460
14840
  var frameCropLeftOffset = 0;
14461
14841
  var frameCropRightOffset = 0;
14462
14842
  var frameCropTopOffset = 0;
@@ -14464,13 +14844,13 @@
14464
14844
  var numRefFramesInPicOrderCntCycle;
14465
14845
  var scalingListCount;
14466
14846
  var i;
14467
- var readUByte = this.readUByte.bind(this);
14468
- var readBits = this.readBits.bind(this);
14469
- var readUEG = this.readUEG.bind(this);
14470
- var readBoolean = this.readBoolean.bind(this);
14471
- var skipBits = this.skipBits.bind(this);
14472
- var skipEG = this.skipEG.bind(this);
14473
- var skipUEG = this.skipUEG.bind(this);
14847
+ var readUByte = eg.readUByte.bind(eg);
14848
+ var readBits = eg.readBits.bind(eg);
14849
+ var readUEG = eg.readUEG.bind(eg);
14850
+ var readBoolean = eg.readBoolean.bind(eg);
14851
+ var skipBits = eg.skipBits.bind(eg);
14852
+ var skipEG = eg.skipEG.bind(eg);
14853
+ var skipUEG = eg.skipUEG.bind(eg);
14474
14854
  var skipScalingList = this.skipScalingList.bind(this);
14475
14855
  readUByte();
14476
14856
  var profileIdc = readUByte(); // profile_idc
@@ -14495,9 +14875,9 @@
14495
14875
  if (readBoolean()) {
14496
14876
  // seq_scaling_list_present_flag[ i ]
14497
14877
  if (i < 6) {
14498
- skipScalingList(16);
14878
+ skipScalingList(16, eg);
14499
14879
  } else {
14500
- skipScalingList(64);
14880
+ skipScalingList(64, eg);
14501
14881
  }
14502
14882
  }
14503
14883
  }
@@ -14602,26 +14982,24 @@
14602
14982
  pixelRatio: pixelRatio
14603
14983
  };
14604
14984
  };
14605
- _proto.readSliceType = function readSliceType() {
14606
- // skip NALu type
14607
- this.readUByte();
14608
- // discard first_mb_in_slice
14609
- this.readUEG();
14610
- // return slice_type
14611
- return this.readUEG();
14612
- };
14613
- return ExpGolomb;
14614
- }();
14985
+ return AvcVideoParser;
14986
+ }(BaseVideoParser);
14615
14987
 
14616
- var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
14617
- _inheritsLoose(AvcVideoParser, _BaseVideoParser);
14618
- function AvcVideoParser() {
14619
- return _BaseVideoParser.apply(this, arguments) || this;
14988
+ var HevcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
14989
+ _inheritsLoose(HevcVideoParser, _BaseVideoParser);
14990
+ function HevcVideoParser() {
14991
+ var _this;
14992
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
14993
+ args[_key] = arguments[_key];
14994
+ }
14995
+ _this = _BaseVideoParser.call.apply(_BaseVideoParser, [this].concat(args)) || this;
14996
+ _this.initVPS = null;
14997
+ return _this;
14620
14998
  }
14621
- var _proto = AvcVideoParser.prototype;
14622
- _proto.parseAVCPES = function parseAVCPES(track, textTrack, pes, last, duration) {
14623
- var _this = this;
14624
- var units = this.parseAVCNALu(track, pes.data);
14999
+ var _proto = HevcVideoParser.prototype;
15000
+ _proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
15001
+ var _this2 = this;
15002
+ var units = this.parseNALu(track, pes.data);
14625
15003
  var VideoSample = this.VideoSample;
14626
15004
  var push;
14627
15005
  var spsfound = false;
@@ -14637,231 +15015,576 @@
14637
15015
  units.forEach(function (unit) {
14638
15016
  var _VideoSample2;
14639
15017
  switch (unit.type) {
14640
- // NDR
15018
+ // NON-IDR, NON RANDOM ACCESS SLICE
15019
+ case 0:
14641
15020
  case 1:
14642
- {
14643
- var iskey = false;
14644
- push = true;
14645
- var data = unit.data;
14646
- // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
14647
- if (spsfound && data.length > 4) {
14648
- // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
14649
- var sliceType = new ExpGolomb(data).readSliceType();
14650
- // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
14651
- // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
14652
- // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
14653
- // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
14654
- // if (sliceType === 2 || sliceType === 7) {
14655
- if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
14656
- iskey = true;
14657
- }
14658
- }
14659
- if (iskey) {
14660
- var _VideoSample;
14661
- // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
14662
- if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
14663
- _this.pushAccessUnit(VideoSample, track);
14664
- VideoSample = _this.VideoSample = null;
14665
- }
14666
- }
14667
- if (!VideoSample) {
14668
- VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
15021
+ case 2:
15022
+ case 3:
15023
+ case 4:
15024
+ case 5:
15025
+ case 6:
15026
+ case 7:
15027
+ case 8:
15028
+ case 9:
15029
+ if (!VideoSample) {
15030
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(false, pes.pts, pes.dts, '');
15031
+ }
15032
+ VideoSample.frame = true;
15033
+ push = true;
15034
+ break;
15035
+
15036
+ // CRA, BLA (random access picture)
15037
+ case 16:
15038
+ case 17:
15039
+ case 18:
15040
+ case 21:
15041
+ push = true;
15042
+ if (spsfound) {
15043
+ var _VideoSample;
15044
+ // handle PES not starting with AUD
15045
+ // if we have frame data already, that cannot belong to the same frame, so force a push
15046
+ if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
15047
+ _this2.pushAccessUnit(VideoSample, track);
15048
+ VideoSample = _this2.VideoSample = null;
14669
15049
  }
14670
- VideoSample.frame = true;
14671
- VideoSample.key = iskey;
14672
- break;
14673
- // IDR
14674
15050
  }
14675
- case 5:
15051
+ if (!VideoSample) {
15052
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
15053
+ }
15054
+ VideoSample.key = true;
15055
+ VideoSample.frame = true;
15056
+ break;
15057
+
15058
+ // IDR
15059
+ case 19:
15060
+ case 20:
14676
15061
  push = true;
14677
15062
  // handle PES not starting with AUD
14678
15063
  // if we have frame data already, that cannot belong to the same frame, so force a push
14679
15064
  if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
14680
- _this.pushAccessUnit(VideoSample, track);
14681
- VideoSample = _this.VideoSample = null;
15065
+ _this2.pushAccessUnit(VideoSample, track);
15066
+ VideoSample = _this2.VideoSample = null;
14682
15067
  }
14683
15068
  if (!VideoSample) {
14684
- VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
15069
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
14685
15070
  }
14686
15071
  VideoSample.key = true;
14687
15072
  VideoSample.frame = true;
14688
15073
  break;
15074
+
14689
15075
  // SEI
14690
- case 6:
14691
- {
14692
- push = true;
14693
- parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
14694
- break;
14695
- // SPS
14696
- }
14697
- case 7:
14698
- {
14699
- var _track$pixelRatio, _track$pixelRatio2;
14700
- push = true;
14701
- spsfound = true;
14702
- var sps = unit.data;
14703
- var expGolombDecoder = new ExpGolomb(sps);
14704
- var config = expGolombDecoder.readSPS();
14705
- if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) {
14706
- track.width = config.width;
14707
- track.height = config.height;
14708
- track.pixelRatio = config.pixelRatio;
14709
- track.sps = [sps];
14710
- track.duration = duration;
14711
- var codecarray = sps.subarray(1, 4);
14712
- var codecstring = 'avc1.';
14713
- for (var i = 0; i < 3; i++) {
14714
- var h = codecarray[i].toString(16);
14715
- if (h.length < 2) {
14716
- h = '0' + h;
14717
- }
14718
- codecstring += h;
14719
- }
14720
- track.codec = codecstring;
14721
- }
14722
- break;
14723
- }
14724
- // PPS
14725
- case 8:
15076
+ case 39:
14726
15077
  push = true;
14727
- track.pps = [unit.data];
15078
+ parseSEIMessageFromNALu(unit.data, 2,
15079
+ // NALu header size
15080
+ pes.pts, textTrack.samples);
14728
15081
  break;
14729
- // AUD
14730
- case 9:
14731
- push = true;
14732
- track.audFound = true;
14733
- if (VideoSample) {
14734
- _this.pushAccessUnit(VideoSample, track);
14735
- }
14736
- VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
14737
- break;
14738
- // Filler Data
14739
- case 12:
15082
+
15083
+ // VPS
15084
+ case 32:
14740
15085
  push = true;
14741
- break;
14742
- default:
14743
- push = false;
14744
- if (VideoSample) {
14745
- VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
15086
+ if (!track.vps) {
15087
+ var config = _this2.readVPS(unit.data);
15088
+ track.params = _objectSpread2({}, config);
15089
+ _this2.initVPS = unit.data;
14746
15090
  }
15091
+ track.vps = [unit.data];
14747
15092
  break;
14748
- }
14749
- if (VideoSample && push) {
14750
- var _units = VideoSample.units;
14751
- _units.push(unit);
14752
- }
14753
- });
14754
- // if last PES packet, push samples
14755
- if (last && VideoSample) {
14756
- this.pushAccessUnit(VideoSample, track);
14757
- this.VideoSample = null;
14758
- }
14759
- };
14760
- _proto.parseAVCNALu = function parseAVCNALu(track, array) {
14761
- var len = array.byteLength;
14762
- var state = track.naluState || 0;
14763
- var lastState = state;
14764
- var units = [];
14765
- var i = 0;
14766
- var value;
14767
- var overflow;
14768
- var unitType;
14769
- var lastUnitStart = -1;
14770
- var lastUnitType = 0;
14771
- // logger.log('PES:' + Hex.hexDump(array));
14772
15093
 
14773
- if (state === -1) {
14774
- // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14775
- lastUnitStart = 0;
14776
- // NALu type is value read from offset 0
14777
- lastUnitType = array[0] & 0x1f;
14778
- state = 0;
14779
- i = 1;
14780
- }
14781
- while (i < len) {
14782
- value = array[i++];
14783
- // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14784
- if (!state) {
14785
- state = value ? 0 : 1;
14786
- continue;
14787
- }
14788
- if (state === 1) {
14789
- state = value ? 0 : 2;
14790
- continue;
14791
- }
14792
- // here we have state either equal to 2 or 3
14793
- if (!value) {
14794
- state = 3;
14795
- } else if (value === 1) {
14796
- overflow = i - state - 1;
14797
- if (lastUnitStart >= 0) {
14798
- var unit = {
14799
- data: array.subarray(lastUnitStart, overflow),
14800
- type: lastUnitType
14801
- };
14802
- // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14803
- units.push(unit);
14804
- } else {
14805
- // lastUnitStart is undefined => this is the first start code found in this PES packet
14806
- // first check if start code delimiter is overlapping between 2 PES packets,
14807
- // ie it started in last packet (lastState not zero)
14808
- // and ended at the beginning of this PES packet (i <= 4 - lastState)
14809
- var lastUnit = this.getLastNalUnit(track.samples);
14810
- if (lastUnit) {
14811
- if (lastState && i <= 4 - lastState) {
14812
- // start delimiter overlapping between PES packets
14813
- // strip start delimiter bytes from the end of last NAL unit
14814
- // check if lastUnit had a state different from zero
14815
- if (lastUnit.state) {
14816
- // strip last bytes
14817
- lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
15094
+ // SPS
15095
+ case 33:
15096
+ push = true;
15097
+ spsfound = true;
15098
+ if (typeof track.params === 'object') {
15099
+ if (track.vps !== undefined && track.vps[0] !== _this2.initVPS && track.sps !== undefined && !_this2.matchSPS(track.sps[0], unit.data)) {
15100
+ _this2.initVPS = track.vps[0];
15101
+ track.sps = track.pps = undefined;
15102
+ }
15103
+ if (!track.sps) {
15104
+ var _config = _this2.readSPS(unit.data);
15105
+ track.width = _config.width;
15106
+ track.height = _config.height;
15107
+ track.pixelRatio = _config.pixelRatio;
15108
+ track.duration = duration;
15109
+ track.codec = _config.codecString;
15110
+ track.sps = [];
15111
+ for (var prop in _config.params) {
15112
+ track.params[prop] = _config.params[prop];
14818
15113
  }
14819
15114
  }
14820
- // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
15115
+ if (track.vps !== undefined && track.vps[0] === _this2.initVPS) {
15116
+ track.sps.push(unit.data);
15117
+ }
15118
+ }
15119
+ if (!VideoSample) {
15120
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
15121
+ }
15122
+ VideoSample.key = true;
15123
+ break;
14821
15124
 
14822
- if (overflow > 0) {
14823
- // logger.log('first NALU found with overflow:' + overflow);
14824
- lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14825
- lastUnit.state = 0;
15125
+ // PPS
15126
+ case 34:
15127
+ push = true;
15128
+ if (typeof track.params === 'object') {
15129
+ if (!track.pps) {
15130
+ track.pps = [];
15131
+ var _config2 = _this2.readPPS(unit.data);
15132
+ for (var _prop in _config2) {
15133
+ track.params[_prop] = _config2[_prop];
15134
+ }
15135
+ }
15136
+ if (_this2.initVPS !== null || track.pps.length === 0) {
15137
+ track.pps.push(unit.data);
14826
15138
  }
14827
15139
  }
15140
+ break;
15141
+
15142
+ // ACCESS UNIT DELIMITER
15143
+ case 35:
15144
+ push = true;
15145
+ track.audFound = true;
15146
+ if (VideoSample) {
15147
+ _this2.pushAccessUnit(VideoSample, track);
15148
+ }
15149
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(false, pes.pts, pes.dts, '');
15150
+ break;
15151
+ default:
15152
+ push = false;
15153
+ if (VideoSample) {
15154
+ VideoSample.debug += 'unknown or irrelevant NAL ' + unit.type + ' ';
15155
+ }
15156
+ break;
15157
+ }
15158
+ if (VideoSample && push) {
15159
+ var _units = VideoSample.units;
15160
+ _units.push(unit);
15161
+ }
15162
+ });
15163
+ // if last PES packet, push samples
15164
+ if (last && VideoSample) {
15165
+ this.pushAccessUnit(VideoSample, track);
15166
+ this.VideoSample = null;
15167
+ }
15168
+ };
15169
+ _proto.getNALuType = function getNALuType(data, offset) {
15170
+ return (data[offset] & 0x7e) >>> 1;
15171
+ };
15172
+ _proto.ebsp2rbsp = function ebsp2rbsp(arr) {
15173
+ var dst = new Uint8Array(arr.byteLength);
15174
+ var dstIdx = 0;
15175
+ for (var i = 0; i < arr.byteLength; i++) {
15176
+ if (i >= 2) {
15177
+ // Unescape: Skip 0x03 after 00 00
15178
+ if (arr[i] === 0x03 && arr[i - 1] === 0x00 && arr[i - 2] === 0x00) {
15179
+ continue;
14828
15180
  }
14829
- // check if we can read unit type
14830
- if (i < len) {
14831
- unitType = array[i] & 0x1f;
14832
- // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14833
- lastUnitStart = i;
14834
- lastUnitType = unitType;
14835
- state = 0;
14836
- } else {
14837
- // not enough byte to read unit type. let's read it on next PES parsing
14838
- state = -1;
15181
+ }
15182
+ dst[dstIdx] = arr[i];
15183
+ dstIdx++;
15184
+ }
15185
+ return new Uint8Array(dst.buffer, 0, dstIdx);
15186
+ };
15187
+ _proto.readVPS = function readVPS(vps) {
15188
+ var eg = new ExpGolomb(vps);
15189
+ // remove header
15190
+ eg.readUByte();
15191
+ eg.readUByte();
15192
+ eg.readBits(4); // video_parameter_set_id
15193
+ eg.skipBits(2);
15194
+ eg.readBits(6); // max_layers_minus1
15195
+ var max_sub_layers_minus1 = eg.readBits(3);
15196
+ var temporal_id_nesting_flag = eg.readBoolean();
15197
+ // ...vui fps can be here, but empty fps value is not critical for metadata
15198
+
15199
+ return {
15200
+ numTemporalLayers: max_sub_layers_minus1 + 1,
15201
+ temporalIdNested: temporal_id_nesting_flag
15202
+ };
15203
+ };
15204
+ _proto.readSPS = function readSPS(sps) {
15205
+ var eg = new ExpGolomb(this.ebsp2rbsp(sps));
15206
+ eg.readUByte();
15207
+ eg.readUByte();
15208
+ eg.readBits(4); //video_parameter_set_id
15209
+ var max_sub_layers_minus1 = eg.readBits(3);
15210
+ eg.readBoolean(); // temporal_id_nesting_flag
15211
+
15212
+ // profile_tier_level
15213
+ var general_profile_space = eg.readBits(2);
15214
+ var general_tier_flag = eg.readBoolean();
15215
+ var general_profile_idc = eg.readBits(5);
15216
+ var general_profile_compatibility_flags_1 = eg.readUByte();
15217
+ var general_profile_compatibility_flags_2 = eg.readUByte();
15218
+ var general_profile_compatibility_flags_3 = eg.readUByte();
15219
+ var general_profile_compatibility_flags_4 = eg.readUByte();
15220
+ var general_constraint_indicator_flags_1 = eg.readUByte();
15221
+ var general_constraint_indicator_flags_2 = eg.readUByte();
15222
+ var general_constraint_indicator_flags_3 = eg.readUByte();
15223
+ var general_constraint_indicator_flags_4 = eg.readUByte();
15224
+ var general_constraint_indicator_flags_5 = eg.readUByte();
15225
+ var general_constraint_indicator_flags_6 = eg.readUByte();
15226
+ var general_level_idc = eg.readUByte();
15227
+ var sub_layer_profile_present_flags = [];
15228
+ var sub_layer_level_present_flags = [];
15229
+ for (var i = 0; i < max_sub_layers_minus1; i++) {
15230
+ sub_layer_profile_present_flags.push(eg.readBoolean());
15231
+ sub_layer_level_present_flags.push(eg.readBoolean());
15232
+ }
15233
+ if (max_sub_layers_minus1 > 0) {
15234
+ for (var _i = max_sub_layers_minus1; _i < 8; _i++) {
15235
+ eg.readBits(2);
15236
+ }
15237
+ }
15238
+ for (var _i2 = 0; _i2 < max_sub_layers_minus1; _i2++) {
15239
+ if (sub_layer_profile_present_flags[_i2]) {
15240
+ eg.readUByte(); // sub_layer_profile_space, sub_layer_tier_flag, sub_layer_profile_idc
15241
+ eg.readUByte();
15242
+ eg.readUByte();
15243
+ eg.readUByte();
15244
+ eg.readUByte(); // sub_layer_profile_compatibility_flag
15245
+ eg.readUByte();
15246
+ eg.readUByte();
15247
+ eg.readUByte();
15248
+ eg.readUByte();
15249
+ eg.readUByte();
15250
+ eg.readUByte();
15251
+ }
15252
+ if (sub_layer_level_present_flags[_i2]) {
15253
+ eg.readUByte();
15254
+ }
15255
+ }
15256
+ eg.readUEG(); // seq_parameter_set_id
15257
+ var chroma_format_idc = eg.readUEG();
15258
+ if (chroma_format_idc == 3) {
15259
+ eg.skipBits(1); //separate_colour_plane_flag
15260
+ }
15261
+ var pic_width_in_luma_samples = eg.readUEG();
15262
+ var pic_height_in_luma_samples = eg.readUEG();
15263
+ var conformance_window_flag = eg.readBoolean();
15264
+ var pic_left_offset = 0,
15265
+ pic_right_offset = 0,
15266
+ pic_top_offset = 0,
15267
+ pic_bottom_offset = 0;
15268
+ if (conformance_window_flag) {
15269
+ pic_left_offset += eg.readUEG();
15270
+ pic_right_offset += eg.readUEG();
15271
+ pic_top_offset += eg.readUEG();
15272
+ pic_bottom_offset += eg.readUEG();
15273
+ }
15274
+ var bit_depth_luma_minus8 = eg.readUEG();
15275
+ var bit_depth_chroma_minus8 = eg.readUEG();
15276
+ var log2_max_pic_order_cnt_lsb_minus4 = eg.readUEG();
15277
+ var sub_layer_ordering_info_present_flag = eg.readBoolean();
15278
+ for (var _i3 = sub_layer_ordering_info_present_flag ? 0 : max_sub_layers_minus1; _i3 <= max_sub_layers_minus1; _i3++) {
15279
+ eg.skipUEG(); // max_dec_pic_buffering_minus1[i]
15280
+ eg.skipUEG(); // max_num_reorder_pics[i]
15281
+ eg.skipUEG(); // max_latency_increase_plus1[i]
15282
+ }
15283
+ eg.skipUEG(); // log2_min_luma_coding_block_size_minus3
15284
+ eg.skipUEG(); // log2_diff_max_min_luma_coding_block_size
15285
+ eg.skipUEG(); // log2_min_transform_block_size_minus2
15286
+ eg.skipUEG(); // log2_diff_max_min_transform_block_size
15287
+ eg.skipUEG(); // max_transform_hierarchy_depth_inter
15288
+ eg.skipUEG(); // max_transform_hierarchy_depth_intra
15289
+ var scaling_list_enabled_flag = eg.readBoolean();
15290
+ if (scaling_list_enabled_flag) {
15291
+ var sps_scaling_list_data_present_flag = eg.readBoolean();
15292
+ if (sps_scaling_list_data_present_flag) {
15293
+ for (var sizeId = 0; sizeId < 4; sizeId++) {
15294
+ for (var matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) {
15295
+ var scaling_list_pred_mode_flag = eg.readBoolean();
15296
+ if (!scaling_list_pred_mode_flag) {
15297
+ eg.readUEG(); // scaling_list_pred_matrix_id_delta
15298
+ } else {
15299
+ var coefNum = Math.min(64, 1 << 4 + (sizeId << 1));
15300
+ if (sizeId > 1) {
15301
+ eg.readEG();
15302
+ }
15303
+ for (var _i4 = 0; _i4 < coefNum; _i4++) {
15304
+ eg.readEG();
15305
+ }
15306
+ }
15307
+ }
14839
15308
  }
14840
- } else {
14841
- state = 0;
14842
15309
  }
14843
15310
  }
14844
- if (lastUnitStart >= 0 && state >= 0) {
14845
- var _unit = {
14846
- data: array.subarray(lastUnitStart, len),
14847
- type: lastUnitType,
14848
- state: state
14849
- };
14850
- units.push(_unit);
14851
- // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
15311
+ eg.readBoolean(); // amp_enabled_flag
15312
+ eg.readBoolean(); // sample_adaptive_offset_enabled_flag
15313
+ var pcm_enabled_flag = eg.readBoolean();
15314
+ if (pcm_enabled_flag) {
15315
+ eg.readUByte();
15316
+ eg.skipUEG();
15317
+ eg.skipUEG();
15318
+ eg.readBoolean();
15319
+ }
15320
+ var num_short_term_ref_pic_sets = eg.readUEG();
15321
+ var num_delta_pocs = 0;
15322
+ for (var _i5 = 0; _i5 < num_short_term_ref_pic_sets; _i5++) {
15323
+ var inter_ref_pic_set_prediction_flag = false;
15324
+ if (_i5 !== 0) {
15325
+ inter_ref_pic_set_prediction_flag = eg.readBoolean();
15326
+ }
15327
+ if (inter_ref_pic_set_prediction_flag) {
15328
+ if (_i5 === num_short_term_ref_pic_sets) {
15329
+ eg.readUEG();
15330
+ }
15331
+ eg.readBoolean();
15332
+ eg.readUEG();
15333
+ var next_num_delta_pocs = 0;
15334
+ for (var j = 0; j <= num_delta_pocs; j++) {
15335
+ var used_by_curr_pic_flag = eg.readBoolean();
15336
+ var use_delta_flag = false;
15337
+ if (!used_by_curr_pic_flag) {
15338
+ use_delta_flag = eg.readBoolean();
15339
+ }
15340
+ if (used_by_curr_pic_flag || use_delta_flag) {
15341
+ next_num_delta_pocs++;
15342
+ }
15343
+ }
15344
+ num_delta_pocs = next_num_delta_pocs;
15345
+ } else {
15346
+ var num_negative_pics = eg.readUEG();
15347
+ var num_positive_pics = eg.readUEG();
15348
+ num_delta_pocs = num_negative_pics + num_positive_pics;
15349
+ for (var _j = 0; _j < num_negative_pics; _j++) {
15350
+ eg.readUEG();
15351
+ eg.readBoolean();
15352
+ }
15353
+ for (var _j2 = 0; _j2 < num_positive_pics; _j2++) {
15354
+ eg.readUEG();
15355
+ eg.readBoolean();
15356
+ }
15357
+ }
14852
15358
  }
14853
- // no NALu found
14854
- if (units.length === 0) {
14855
- // append pes.data to previous NAL unit
14856
- var _lastUnit = this.getLastNalUnit(track.samples);
14857
- if (_lastUnit) {
14858
- _lastUnit.data = appendUint8Array(_lastUnit.data, array);
15359
+ var long_term_ref_pics_present_flag = eg.readBoolean();
15360
+ if (long_term_ref_pics_present_flag) {
15361
+ var num_long_term_ref_pics_sps = eg.readUEG();
15362
+ for (var _i6 = 0; _i6 < num_long_term_ref_pics_sps; _i6++) {
15363
+ for (var _j3 = 0; _j3 < log2_max_pic_order_cnt_lsb_minus4 + 4; _j3++) {
15364
+ eg.readBits(1);
15365
+ }
15366
+ eg.readBits(1);
15367
+ }
15368
+ }
15369
+ var min_spatial_segmentation_idc = 0;
15370
+ var sar_width = 1,
15371
+ sar_height = 1;
15372
+ var fps_fixed = true,
15373
+ fps_den = 1,
15374
+ fps_num = 0;
15375
+ eg.readBoolean(); // sps_temporal_mvp_enabled_flag
15376
+ eg.readBoolean(); // strong_intra_smoothing_enabled_flag
15377
+ var default_display_window_flag = false;
15378
+ var vui_parameters_present_flag = eg.readBoolean();
15379
+ if (vui_parameters_present_flag) {
15380
+ var aspect_ratio_info_present_flag = eg.readBoolean();
15381
+ if (aspect_ratio_info_present_flag) {
15382
+ var aspect_ratio_idc = eg.readUByte();
15383
+ var sar_width_table = [1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2];
15384
+ var sar_height_table = [1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1];
15385
+ if (aspect_ratio_idc > 0 && aspect_ratio_idc < 16) {
15386
+ sar_width = sar_width_table[aspect_ratio_idc - 1];
15387
+ sar_height = sar_height_table[aspect_ratio_idc - 1];
15388
+ } else if (aspect_ratio_idc === 255) {
15389
+ sar_width = eg.readBits(16);
15390
+ sar_height = eg.readBits(16);
15391
+ }
15392
+ }
15393
+ var overscan_info_present_flag = eg.readBoolean();
15394
+ if (overscan_info_present_flag) {
15395
+ eg.readBoolean();
15396
+ }
15397
+ var video_signal_type_present_flag = eg.readBoolean();
15398
+ if (video_signal_type_present_flag) {
15399
+ eg.readBits(3);
15400
+ eg.readBoolean();
15401
+ var colour_description_present_flag = eg.readBoolean();
15402
+ if (colour_description_present_flag) {
15403
+ eg.readUByte();
15404
+ eg.readUByte();
15405
+ eg.readUByte();
15406
+ }
15407
+ }
15408
+ var chroma_loc_info_present_flag = eg.readBoolean();
15409
+ if (chroma_loc_info_present_flag) {
15410
+ eg.readUEG();
15411
+ eg.readUEG();
15412
+ }
15413
+ eg.readBoolean(); // neutral_chroma_indication_flag
15414
+ eg.readBoolean(); // field_seq_flag
15415
+ eg.readBoolean(); // frame_field_info_present_flag
15416
+ default_display_window_flag = eg.readBoolean();
15417
+ if (default_display_window_flag) {
15418
+ pic_left_offset += eg.readUEG();
15419
+ pic_right_offset += eg.readUEG();
15420
+ pic_top_offset += eg.readUEG();
15421
+ pic_bottom_offset += eg.readUEG();
15422
+ }
15423
+ var vui_timing_info_present_flag = eg.readBoolean();
15424
+ if (vui_timing_info_present_flag) {
15425
+ fps_den = eg.readBits(32);
15426
+ fps_num = eg.readBits(32);
15427
+ var vui_poc_proportional_to_timing_flag = eg.readBoolean();
15428
+ if (vui_poc_proportional_to_timing_flag) {
15429
+ eg.readUEG();
15430
+ }
15431
+ var vui_hrd_parameters_present_flag = eg.readBoolean();
15432
+ if (vui_hrd_parameters_present_flag) {
15433
+ //const commonInfPresentFlag = true;
15434
+ //if (commonInfPresentFlag) {
15435
+ var nal_hrd_parameters_present_flag = eg.readBoolean();
15436
+ var vcl_hrd_parameters_present_flag = eg.readBoolean();
15437
+ var sub_pic_hrd_params_present_flag = false;
15438
+ if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
15439
+ sub_pic_hrd_params_present_flag = eg.readBoolean();
15440
+ if (sub_pic_hrd_params_present_flag) {
15441
+ eg.readUByte();
15442
+ eg.readBits(5);
15443
+ eg.readBoolean();
15444
+ eg.readBits(5);
15445
+ }
15446
+ eg.readBits(4); // bit_rate_scale
15447
+ eg.readBits(4); // cpb_size_scale
15448
+ if (sub_pic_hrd_params_present_flag) {
15449
+ eg.readBits(4);
15450
+ }
15451
+ eg.readBits(5);
15452
+ eg.readBits(5);
15453
+ eg.readBits(5);
15454
+ }
15455
+ //}
15456
+ for (var _i7 = 0; _i7 <= max_sub_layers_minus1; _i7++) {
15457
+ fps_fixed = eg.readBoolean(); // fixed_pic_rate_general_flag
15458
+ var fixed_pic_rate_within_cvs_flag = fps_fixed || eg.readBoolean();
15459
+ var low_delay_hrd_flag = false;
15460
+ if (fixed_pic_rate_within_cvs_flag) {
15461
+ eg.readEG();
15462
+ } else {
15463
+ low_delay_hrd_flag = eg.readBoolean();
15464
+ }
15465
+ var cpb_cnt = low_delay_hrd_flag ? 1 : eg.readUEG() + 1;
15466
+ if (nal_hrd_parameters_present_flag) {
15467
+ for (var _j4 = 0; _j4 < cpb_cnt; _j4++) {
15468
+ eg.readUEG();
15469
+ eg.readUEG();
15470
+ if (sub_pic_hrd_params_present_flag) {
15471
+ eg.readUEG();
15472
+ eg.readUEG();
15473
+ }
15474
+ eg.skipBits(1);
15475
+ }
15476
+ }
15477
+ if (vcl_hrd_parameters_present_flag) {
15478
+ for (var _j5 = 0; _j5 < cpb_cnt; _j5++) {
15479
+ eg.readUEG();
15480
+ eg.readUEG();
15481
+ if (sub_pic_hrd_params_present_flag) {
15482
+ eg.readUEG();
15483
+ eg.readUEG();
15484
+ }
15485
+ eg.skipBits(1);
15486
+ }
15487
+ }
15488
+ }
15489
+ }
14859
15490
  }
15491
+ var bitstream_restriction_flag = eg.readBoolean();
15492
+ if (bitstream_restriction_flag) {
15493
+ eg.readBoolean(); // tiles_fixed_structure_flag
15494
+ eg.readBoolean(); // motion_vectors_over_pic_boundaries_flag
15495
+ eg.readBoolean(); // restricted_ref_pic_lists_flag
15496
+ min_spatial_segmentation_idc = eg.readUEG();
15497
+ }
15498
+ }
15499
+ var width = pic_width_in_luma_samples,
15500
+ height = pic_height_in_luma_samples;
15501
+ if (conformance_window_flag || default_display_window_flag) {
15502
+ var chroma_scale_w = 1,
15503
+ chroma_scale_h = 1;
15504
+ if (chroma_format_idc === 1) {
15505
+ // YUV 420
15506
+ chroma_scale_w = chroma_scale_h = 2;
15507
+ } else if (chroma_format_idc == 2) {
15508
+ // YUV 422
15509
+ chroma_scale_w = 2;
15510
+ }
15511
+ width = pic_width_in_luma_samples - chroma_scale_w * pic_right_offset - chroma_scale_w * pic_left_offset;
15512
+ height = pic_height_in_luma_samples - chroma_scale_h * pic_bottom_offset - chroma_scale_h * pic_top_offset;
15513
+ }
15514
+ var profile_space_string = general_profile_space ? ['A', 'B', 'C'][general_profile_space] : '';
15515
+ var profile_compatibility_buf = general_profile_compatibility_flags_1 << 24 | general_profile_compatibility_flags_2 << 16 | general_profile_compatibility_flags_3 << 8 | general_profile_compatibility_flags_4;
15516
+ var profile_compatibility_rev = 0;
15517
+ for (var _i8 = 0; _i8 < 32; _i8++) {
15518
+ profile_compatibility_rev = (profile_compatibility_rev | (profile_compatibility_buf >> _i8 & 1) << 31 - _i8) >>> 0; // reverse bit position (and cast as UInt32)
15519
+ }
15520
+ var profile_compatibility_flags_string = profile_compatibility_rev.toString(16);
15521
+ if (general_profile_idc === 1 && profile_compatibility_flags_string === '2') {
15522
+ profile_compatibility_flags_string = '6';
15523
+ }
15524
+ var tier_flag_string = general_tier_flag ? 'H' : 'L';
15525
+ return {
15526
+ codecString: "hvc1." + profile_space_string + general_profile_idc + "." + profile_compatibility_flags_string + "." + tier_flag_string + general_level_idc + ".B0",
15527
+ params: {
15528
+ general_tier_flag: general_tier_flag,
15529
+ general_profile_idc: general_profile_idc,
15530
+ general_profile_space: general_profile_space,
15531
+ general_profile_compatibility_flags: [general_profile_compatibility_flags_1, general_profile_compatibility_flags_2, general_profile_compatibility_flags_3, general_profile_compatibility_flags_4],
15532
+ general_constraint_indicator_flags: [general_constraint_indicator_flags_1, general_constraint_indicator_flags_2, general_constraint_indicator_flags_3, general_constraint_indicator_flags_4, general_constraint_indicator_flags_5, general_constraint_indicator_flags_6],
15533
+ general_level_idc: general_level_idc,
15534
+ bit_depth: bit_depth_luma_minus8 + 8,
15535
+ bit_depth_luma_minus8: bit_depth_luma_minus8,
15536
+ bit_depth_chroma_minus8: bit_depth_chroma_minus8,
15537
+ min_spatial_segmentation_idc: min_spatial_segmentation_idc,
15538
+ chroma_format_idc: chroma_format_idc,
15539
+ frame_rate: {
15540
+ fixed: fps_fixed,
15541
+ fps: fps_num / fps_den
15542
+ }
15543
+ },
15544
+ width: width,
15545
+ height: height,
15546
+ pixelRatio: [sar_width, sar_height]
15547
+ };
15548
+ };
15549
+ _proto.readPPS = function readPPS(pps) {
15550
+ var eg = new ExpGolomb(this.ebsp2rbsp(pps));
15551
+ eg.readUByte();
15552
+ eg.readUByte();
15553
+ eg.skipUEG(); // pic_parameter_set_id
15554
+ eg.skipUEG(); // seq_parameter_set_id
15555
+ eg.skipBits(2); // dependent_slice_segments_enabled_flag, output_flag_present_flag
15556
+ eg.skipBits(3); // num_extra_slice_header_bits
15557
+ eg.skipBits(2); // sign_data_hiding_enabled_flag, cabac_init_present_flag
15558
+ eg.skipUEG();
15559
+ eg.skipUEG();
15560
+ eg.skipEG(); // init_qp_minus26
15561
+ eg.skipBits(2); // constrained_intra_pred_flag, transform_skip_enabled_flag
15562
+ var cu_qp_delta_enabled_flag = eg.readBoolean();
15563
+ if (cu_qp_delta_enabled_flag) {
15564
+ eg.skipUEG();
15565
+ }
15566
+ eg.skipEG(); // cb_qp_offset
15567
+ eg.skipEG(); // cr_qp_offset
15568
+ eg.skipBits(4); // pps_slice_chroma_qp_offsets_present_flag, weighted_pred_flag, weighted_bipred_flag, transquant_bypass_enabled_flag
15569
+ var tiles_enabled_flag = eg.readBoolean();
15570
+ var entropy_coding_sync_enabled_flag = eg.readBoolean();
15571
+ var parallelismType = 1; // slice-based parallel decoding
15572
+ if (entropy_coding_sync_enabled_flag && tiles_enabled_flag) {
15573
+ parallelismType = 0; // mixed-type parallel decoding
15574
+ } else if (entropy_coding_sync_enabled_flag) {
15575
+ parallelismType = 3; // wavefront-based parallel decoding
15576
+ } else if (tiles_enabled_flag) {
15577
+ parallelismType = 2; // tile-based parallel decoding
14860
15578
  }
14861
- track.naluState = state;
14862
- return units;
15579
+ return {
15580
+ parallelismType: parallelismType
15581
+ };
14863
15582
  };
14864
- return AvcVideoParser;
15583
+ _proto.matchSPS = function matchSPS(sps1, sps2) {
15584
+ // compare without headers and VPS related params
15585
+ return String.fromCharCode.apply(null, sps1).substr(3) === String.fromCharCode.apply(null, sps2).substr(3);
15586
+ };
15587
+ return HevcVideoParser;
14865
15588
  }(BaseVideoParser);
14866
15589
 
14867
15590
  /**
@@ -14879,7 +15602,7 @@
14879
15602
  }
14880
15603
  var _proto = SampleAesDecrypter.prototype;
14881
15604
  _proto.decryptBuffer = function decryptBuffer(encryptedData) {
14882
- return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
15605
+ return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
14883
15606
  }
14884
15607
 
14885
15608
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -14998,7 +15721,7 @@
14998
15721
  this.observer = observer;
14999
15722
  this.config = config;
15000
15723
  this.typeSupported = typeSupported;
15001
- this.videoParser = new AvcVideoParser();
15724
+ this.videoParser = null;
15002
15725
  }
15003
15726
  TSDemuxer.probe = function probe(data) {
15004
15727
  var syncOffset = TSDemuxer.syncOffset(data);
@@ -15168,7 +15891,19 @@
15168
15891
  case videoPid:
15169
15892
  if (stt) {
15170
15893
  if (videoData && (pes = parsePES(videoData))) {
15171
- this.videoParser.parseAVCPES(videoTrack, textTrack, pes, false, this._duration);
15894
+ if (this.videoParser === null) {
15895
+ switch (videoTrack.segmentCodec) {
15896
+ case 'avc':
15897
+ this.videoParser = new AvcVideoParser();
15898
+ break;
15899
+ case 'hevc':
15900
+ this.videoParser = new HevcVideoParser();
15901
+ break;
15902
+ }
15903
+ }
15904
+ if (this.videoParser !== null) {
15905
+ this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
15906
+ }
15172
15907
  }
15173
15908
  videoData = {
15174
15909
  data: [],
@@ -15326,8 +16061,20 @@
15326
16061
  // try to parse last PES packets
15327
16062
  var pes;
15328
16063
  if (videoData && (pes = parsePES(videoData))) {
15329
- this.videoParser.parseAVCPES(videoTrack, textTrack, pes, true, this._duration);
15330
- videoTrack.pesData = null;
16064
+ if (this.videoParser === null) {
16065
+ switch (videoTrack.segmentCodec) {
16066
+ case 'avc':
16067
+ this.videoParser = new AvcVideoParser();
16068
+ break;
16069
+ case 'hevc':
16070
+ this.videoParser = new HevcVideoParser();
16071
+ break;
16072
+ }
16073
+ }
16074
+ if (this.videoParser !== null) {
16075
+ this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
16076
+ videoTrack.pesData = null;
16077
+ }
15331
16078
  } else {
15332
16079
  // either avcData null or PES truncated, keep it for next frag parsing
15333
16080
  videoTrack.pesData = videoData;
@@ -15629,7 +16376,12 @@
15629
16376
  logger.warn('Unsupported EC-3 in M2TS found');
15630
16377
  break;
15631
16378
  case 0x24:
15632
- logger.warn('Unsupported HEVC in M2TS found');
16379
+ // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
16380
+ if (result.videoPid === -1) {
16381
+ result.videoPid = pid;
16382
+ result.segmentVideoCodec = 'hevc';
16383
+ logger.log('HEVC in M2TS found');
16384
+ }
15633
16385
  break;
15634
16386
  }
15635
16387
  // move to the next table entry
@@ -15857,6 +16609,8 @@
15857
16609
  avc1: [],
15858
16610
  // codingname
15859
16611
  avcC: [],
16612
+ hvc1: [],
16613
+ hvcC: [],
15860
16614
  btrt: [],
15861
16615
  dinf: [],
15862
16616
  dref: [],
@@ -16284,8 +17038,10 @@
16284
17038
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
16285
17039
  }
16286
17040
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
16287
- } else {
17041
+ } else if (track.segmentCodec === 'avc') {
16288
17042
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
17043
+ } else {
17044
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
16289
17045
  }
16290
17046
  };
16291
17047
  MP4.tkhd = function tkhd(track) {
@@ -16423,6 +17179,84 @@
16423
17179
  var result = appendUint8Array(MP4.FTYP, movie);
16424
17180
  return result;
16425
17181
  };
17182
+ MP4.hvc1 = function hvc1(track) {
17183
+ var ps = track.params;
17184
+ var units = [track.vps, track.sps, track.pps];
17185
+ var NALuLengthSize = 4;
17186
+ var config = new Uint8Array([0x01, ps.general_profile_space << 6 | (ps.general_tier_flag ? 32 : 0) | ps.general_profile_idc, ps.general_profile_compatibility_flags[0], ps.general_profile_compatibility_flags[1], ps.general_profile_compatibility_flags[2], ps.general_profile_compatibility_flags[3], ps.general_constraint_indicator_flags[0], ps.general_constraint_indicator_flags[1], ps.general_constraint_indicator_flags[2], ps.general_constraint_indicator_flags[3], ps.general_constraint_indicator_flags[4], ps.general_constraint_indicator_flags[5], ps.general_level_idc, 240 | ps.min_spatial_segmentation_idc >> 8, 255 & ps.min_spatial_segmentation_idc, 252 | ps.parallelismType, 252 | ps.chroma_format_idc, 248 | ps.bit_depth_luma_minus8, 248 | ps.bit_depth_chroma_minus8, 0x00, parseInt(ps.frame_rate.fps), NALuLengthSize - 1 | ps.temporal_id_nested << 2 | ps.num_temporal_layers << 3 | (ps.frame_rate.fixed ? 64 : 0), units.length]);
17187
+
17188
+ // compute hvcC size in bytes
17189
+ var length = config.length;
17190
+ for (var i = 0; i < units.length; i += 1) {
17191
+ length += 3;
17192
+ for (var j = 0; j < units[i].length; j += 1) {
17193
+ length += 2 + units[i][j].length;
17194
+ }
17195
+ }
17196
+ var hvcC = new Uint8Array(length);
17197
+ hvcC.set(config, 0);
17198
+ length = config.length;
17199
+ // append parameter set units: one vps, one or more sps and pps
17200
+ var iMax = units.length - 1;
17201
+ for (var _i = 0; _i < units.length; _i += 1) {
17202
+ hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
17203
+ length += 3;
17204
+ for (var _j = 0; _j < units[_i].length; _j += 1) {
17205
+ hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
17206
+ length += 2;
17207
+ hvcC.set(units[_i][_j], length);
17208
+ length += units[_i][_j].length;
17209
+ }
17210
+ }
17211
+ var hvcc = MP4.box(MP4.types.hvcC, hvcC);
17212
+ var width = track.width;
17213
+ var height = track.height;
17214
+ var hSpacing = track.pixelRatio[0];
17215
+ var vSpacing = track.pixelRatio[1];
17216
+ return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
17217
+ // reserved
17218
+ 0x00, 0x00, 0x00,
17219
+ // reserved
17220
+ 0x00, 0x01,
17221
+ // data_reference_index
17222
+ 0x00, 0x00,
17223
+ // pre_defined
17224
+ 0x00, 0x00,
17225
+ // reserved
17226
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17227
+ // pre_defined
17228
+ width >> 8 & 0xff, width & 0xff,
17229
+ // width
17230
+ height >> 8 & 0xff, height & 0xff,
17231
+ // height
17232
+ 0x00, 0x48, 0x00, 0x00,
17233
+ // horizresolution
17234
+ 0x00, 0x48, 0x00, 0x00,
17235
+ // vertresolution
17236
+ 0x00, 0x00, 0x00, 0x00,
17237
+ // reserved
17238
+ 0x00, 0x01,
17239
+ // frame_count
17240
+ 0x12, 0x64, 0x61, 0x69, 0x6c,
17241
+ // dailymotion/hls.js
17242
+ 0x79, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x68, 0x6c, 0x73, 0x2e, 0x6a, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
17243
+ // compressorname
17244
+ 0x00, 0x18,
17245
+ // depth = 24
17246
+ 0x11, 0x11]),
17247
+ // pre_defined = -1
17248
+ hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
17249
+ // bufferSizeDB
17250
+ 0x00, 0x2d, 0xc6, 0xc0,
17251
+ // maxBitrate
17252
+ 0x00, 0x2d, 0xc6, 0xc0])),
17253
+ // avgBitrate
17254
+ MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
17255
+ // hSpacing
17256
+ hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
17257
+ // vSpacing
17258
+ vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
17259
+ };
16426
17260
  return MP4;
16427
17261
  }();
16428
17262
  MP4.types = void 0;
@@ -16809,9 +17643,9 @@
16809
17643
  var foundOverlap = delta < -1;
16810
17644
  if (foundHole || foundOverlap) {
16811
17645
  if (foundHole) {
16812
- logger.warn("AVC: " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
17646
+ logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
16813
17647
  } else {
16814
- logger.warn("AVC: " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
17648
+ logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
16815
17649
  }
16816
17650
  if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
16817
17651
  firstDTS = nextAvcDts;
@@ -16820,12 +17654,24 @@
16820
17654
  inputSamples[0].dts = firstDTS;
16821
17655
  inputSamples[0].pts = firstPTS;
16822
17656
  } else {
17657
+ var isPTSOrderRetained = true;
16823
17658
  for (var _i = 0; _i < inputSamples.length; _i++) {
16824
- if (inputSamples[_i].dts > firstPTS) {
17659
+ if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
16825
17660
  break;
16826
17661
  }
17662
+ var prevPTS = inputSamples[_i].pts;
16827
17663
  inputSamples[_i].dts -= delta;
16828
17664
  inputSamples[_i].pts -= delta;
17665
+
17666
+ // check to see if this sample's PTS order has changed
17667
+ // relative to the next one
17668
+ if (_i < inputSamples.length - 1) {
17669
+ var nextSamplePTS = inputSamples[_i + 1].pts;
17670
+ var currentSamplePTS = inputSamples[_i].pts;
17671
+ var currentOrder = nextSamplePTS <= currentSamplePTS;
17672
+ var prevOrder = nextSamplePTS <= prevPTS;
17673
+ isPTSOrderRetained = currentOrder == prevOrder;
17674
+ }
16829
17675
  }
16830
17676
  }
16831
17677
  logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
@@ -16973,7 +17819,7 @@
16973
17819
  }
16974
17820
  }
16975
17821
  }
16976
- // next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
17822
+ // next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
16977
17823
  mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
16978
17824
  this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
16979
17825
  this.videoSampleDuration = mp4SampleDuration;
@@ -17108,7 +17954,7 @@
17108
17954
  logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
17109
17955
  for (var j = 0; j < missing; j++) {
17110
17956
  var newStamp = Math.max(nextPts, 0);
17111
- var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17957
+ var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17112
17958
  if (!fillFrame) {
17113
17959
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17114
17960
  fillFrame = sample.unit.subarray();
@@ -17236,7 +18082,7 @@
17236
18082
  // samples count of this segment's duration
17237
18083
  var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
17238
18084
  // silent frame
17239
- var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
18085
+ var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17240
18086
  logger.warn('[mp4-remuxer]: remux empty Audio');
17241
18087
  // Can't remux if we can't generate a silent frame...
17242
18088
  if (!silentFrame) {
@@ -17623,13 +18469,15 @@
17623
18469
  duration = transmuxConfig.duration,
17624
18470
  initSegmentData = transmuxConfig.initSegmentData;
17625
18471
  var keyData = getEncryptionType(uintData, decryptdata);
17626
- if (keyData && keyData.method === 'AES-128') {
18472
+ if (keyData && isFullSegmentEncryption(keyData.method)) {
17627
18473
  var decrypter = this.getDecrypter();
18474
+ var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
18475
+
17628
18476
  // Software decryption is synchronous; webCrypto is not
17629
18477
  if (decrypter.isSync()) {
17630
18478
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
17631
18479
  // data is handled in the flush() call
17632
- var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
18480
+ var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
17633
18481
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
17634
18482
  var loadingParts = chunkMeta.part > -1;
17635
18483
  if (loadingParts) {
@@ -17641,7 +18489,7 @@
17641
18489
  }
17642
18490
  uintData = new Uint8Array(decryptedData);
17643
18491
  } else {
17644
- this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
18492
+ this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
17645
18493
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
17646
18494
  // the decrypted data has been transmuxed
17647
18495
  var result = _this.push(decryptedData, null, chunkMeta);
@@ -18262,7 +19110,7 @@
18262
19110
  observer.on(Events.ERROR, forwardMessage);
18263
19111
 
18264
19112
  // forward logger events to main thread
18265
- var forwardWorkerLogs = function forwardWorkerLogs() {
19113
+ var forwardWorkerLogs = function forwardWorkerLogs(logger) {
18266
19114
  var _loop = function _loop(logFn) {
18267
19115
  var func = function func(message) {
18268
19116
  forwardMessage('workerLog', {
@@ -18283,8 +19131,8 @@
18283
19131
  {
18284
19132
  var config = JSON.parse(data.config);
18285
19133
  self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
18286
- enableLogs(config.debug, data.id);
18287
- forwardWorkerLogs();
19134
+ var logger = enableLogs(config.debug, data.id);
19135
+ forwardWorkerLogs(logger);
18288
19136
  forwardMessage('init', null);
18289
19137
  break;
18290
19138
  }
@@ -18458,16 +19306,7 @@
18458
19306
  this.observer = new EventEmitter();
18459
19307
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
18460
19308
  this.observer.on(Events.ERROR, forwardMessage);
18461
- var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
18462
- isTypeSupported: function isTypeSupported() {
18463
- return false;
18464
- }
18465
- };
18466
- var m2tsTypeSupported = {
18467
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
18468
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
18469
- ac3: false
18470
- };
19309
+ var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
18471
19310
 
18472
19311
  // navigator.vendor is not always available in Web Worker
18473
19312
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -18724,21 +19563,26 @@
18724
19563
  var MAX_START_GAP_JUMP = 2.0;
18725
19564
  var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
18726
19565
  var SKIP_BUFFER_RANGE_START = 0.05;
18727
- var GapController = /*#__PURE__*/function () {
19566
+ var GapController = /*#__PURE__*/function (_Logger) {
19567
+ _inheritsLoose(GapController, _Logger);
18728
19568
  function GapController(config, media, fragmentTracker, hls) {
18729
- this.config = void 0;
18730
- this.media = null;
18731
- this.fragmentTracker = void 0;
18732
- this.hls = void 0;
18733
- this.nudgeRetry = 0;
18734
- this.stallReported = false;
18735
- this.stalled = null;
18736
- this.moved = false;
18737
- this.seeking = false;
18738
- this.config = config;
18739
- this.media = media;
18740
- this.fragmentTracker = fragmentTracker;
18741
- this.hls = hls;
19569
+ var _this;
19570
+ _this = _Logger.call(this, 'gap-controller', hls.logger) || this;
19571
+ _this.config = void 0;
19572
+ _this.media = null;
19573
+ _this.fragmentTracker = void 0;
19574
+ _this.hls = void 0;
19575
+ _this.nudgeRetry = 0;
19576
+ _this.stallReported = false;
19577
+ _this.stalled = null;
19578
+ _this.moved = false;
19579
+ _this.seeking = false;
19580
+ _this.ended = 0;
19581
+ _this.config = config;
19582
+ _this.media = media;
19583
+ _this.fragmentTracker = fragmentTracker;
19584
+ _this.hls = hls;
19585
+ return _this;
18742
19586
  }
18743
19587
  var _proto = GapController.prototype;
18744
19588
  _proto.destroy = function destroy() {
@@ -18753,7 +19597,7 @@
18753
19597
  *
18754
19598
  * @param lastCurrentTime - Previously read playhead position
18755
19599
  */;
18756
- _proto.poll = function poll(lastCurrentTime, activeFrag) {
19600
+ _proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
18757
19601
  var config = this.config,
18758
19602
  media = this.media,
18759
19603
  stalled = this.stalled;
@@ -18768,6 +19612,7 @@
18768
19612
 
18769
19613
  // The playhead is moving, no-op
18770
19614
  if (currentTime !== lastCurrentTime) {
19615
+ this.ended = 0;
18771
19616
  this.moved = true;
18772
19617
  if (!seeking) {
18773
19618
  this.nudgeRetry = 0;
@@ -18776,7 +19621,7 @@
18776
19621
  // The playhead is now moving, but was previously stalled
18777
19622
  if (this.stallReported) {
18778
19623
  var _stalledDuration = self.performance.now() - stalled;
18779
- logger.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
19624
+ this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
18780
19625
  this.stallReported = false;
18781
19626
  }
18782
19627
  this.stalled = null;
@@ -18812,7 +19657,6 @@
18812
19657
  // Skip start gaps if we haven't played, but the last poll detected the start of a stall
18813
19658
  // The addition poll gives the browser a chance to jump the gap for us
18814
19659
  if (!this.moved && this.stalled !== null) {
18815
- var _level$details;
18816
19660
  // There is no playable buffer (seeked, waiting for buffer)
18817
19661
  var isBuffered = bufferInfo.len > 0;
18818
19662
  if (!isBuffered && !nextStart) {
@@ -18824,9 +19668,8 @@
18824
19668
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
18825
19669
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
18826
19670
  // that begins over 1 target duration after the video start position.
18827
- var level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
18828
- var isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
18829
- var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
19671
+ var isLive = !!(levelDetails != null && levelDetails.live);
19672
+ var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
18830
19673
  var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
18831
19674
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
18832
19675
  if (!media.paused) {
@@ -18844,6 +19687,17 @@
18844
19687
  }
18845
19688
  var stalledDuration = tnow - stalled;
18846
19689
  if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
19690
+ // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
19691
+ if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
19692
+ if (stalledDuration < 1000 || this.ended) {
19693
+ return;
19694
+ }
19695
+ this.ended = currentTime;
19696
+ this.hls.trigger(Events.MEDIA_ENDED, {
19697
+ stalled: true
19698
+ });
19699
+ return;
19700
+ }
18847
19701
  // Report stalling after trying to fix
18848
19702
  this._reportStall(bufferInfo);
18849
19703
  if (!this.media) {
@@ -18885,7 +19739,7 @@
18885
19739
  // needs to cross some sort of threshold covering all source-buffers content
18886
19740
  // to start playing properly.
18887
19741
  if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
18888
- logger.warn('Trying to nudge playhead over buffer-hole');
19742
+ this.warn('Trying to nudge playhead over buffer-hole');
18889
19743
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
18890
19744
  // We only try to jump the hole if it's under the configured size
18891
19745
  // Reset stalled so to rearm watchdog timer
@@ -18907,7 +19761,7 @@
18907
19761
  // Report stalled error once
18908
19762
  this.stallReported = true;
18909
19763
  var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
18910
- logger.warn(error.message);
19764
+ this.warn(error.message);
18911
19765
  hls.trigger(Events.ERROR, {
18912
19766
  type: ErrorTypes.MEDIA_ERROR,
18913
19767
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -18971,7 +19825,7 @@
18971
19825
  }
18972
19826
  }
18973
19827
  var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
18974
- logger.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
19828
+ this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
18975
19829
  this.moved = true;
18976
19830
  this.stalled = null;
18977
19831
  media.currentTime = targetTime;
@@ -19010,7 +19864,7 @@
19010
19864
  var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
19011
19865
  // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
19012
19866
  var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
19013
- logger.warn(error.message);
19867
+ this.warn(error.message);
19014
19868
  media.currentTime = targetTime;
19015
19869
  hls.trigger(Events.ERROR, {
19016
19870
  type: ErrorTypes.MEDIA_ERROR,
@@ -19020,7 +19874,7 @@
19020
19874
  });
19021
19875
  } else {
19022
19876
  var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
19023
- logger.error(_error.message);
19877
+ this.error(_error.message);
19024
19878
  hls.trigger(Events.ERROR, {
19025
19879
  type: ErrorTypes.MEDIA_ERROR,
19026
19880
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19030,14 +19884,14 @@
19030
19884
  }
19031
19885
  };
19032
19886
  return GapController;
19033
- }();
19887
+ }(Logger);
19034
19888
 
19035
19889
  var TICK_INTERVAL = 100; // how often to tick in ms
19036
19890
  var StreamController = /*#__PURE__*/function (_BaseStreamController) {
19037
19891
  _inheritsLoose(StreamController, _BaseStreamController);
19038
19892
  function StreamController(hls, fragmentTracker, keyLoader) {
19039
19893
  var _this;
19040
- _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[stream-controller]', PlaylistLevelType.MAIN) || this;
19894
+ _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
19041
19895
  _this.audioCodecSwap = false;
19042
19896
  _this.gapController = null;
19043
19897
  _this.level = -1;
@@ -19045,27 +19899,43 @@
19045
19899
  _this.altAudio = false;
19046
19900
  _this.audioOnly = false;
19047
19901
  _this.fragPlaying = null;
19048
- _this.onvplaying = null;
19049
- _this.onvseeked = null;
19050
19902
  _this.fragLastKbps = 0;
19051
19903
  _this.couldBacktrack = false;
19052
19904
  _this.backtrackFragment = null;
19053
19905
  _this.audioCodecSwitch = false;
19054
19906
  _this.videoBuffer = null;
19055
- _this._registerListeners();
19907
+ _this.onMediaPlaying = function () {
19908
+ // tick to speed up FRAG_CHANGED triggering
19909
+ _this.tick();
19910
+ };
19911
+ _this.onMediaSeeked = function () {
19912
+ var media = _this.media;
19913
+ var currentTime = media ? media.currentTime : null;
19914
+ if (isFiniteNumber(currentTime)) {
19915
+ _this.log("Media seeked to " + currentTime.toFixed(3));
19916
+ }
19917
+
19918
+ // If seeked was issued before buffer was appended do not tick immediately
19919
+ var bufferInfo = _this.getMainFwdBufferInfo();
19920
+ if (bufferInfo === null || bufferInfo.len === 0) {
19921
+ _this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19922
+ return;
19923
+ }
19924
+
19925
+ // tick to speed up FRAG_CHANGED triggering
19926
+ _this.tick();
19927
+ };
19928
+ _this.registerListeners();
19056
19929
  return _this;
19057
19930
  }
19058
19931
  var _proto = StreamController.prototype;
19059
- _proto._registerListeners = function _registerListeners() {
19932
+ _proto.registerListeners = function registerListeners() {
19933
+ _BaseStreamController.prototype.registerListeners.call(this);
19060
19934
  var hls = this.hls;
19061
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19062
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19063
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19064
19935
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19065
19936
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
19066
19937
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19067
19938
  hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19068
- hls.on(Events.ERROR, this.onError, this);
19069
19939
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19070
19940
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19071
19941
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19073,15 +19943,12 @@
19073
19943
  hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
19074
19944
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19075
19945
  };
19076
- _proto._unregisterListeners = function _unregisterListeners() {
19946
+ _proto.unregisterListeners = function unregisterListeners() {
19947
+ _BaseStreamController.prototype.unregisterListeners.call(this);
19077
19948
  var hls = this.hls;
19078
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19079
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19080
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19081
19949
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19082
19950
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19083
19951
  hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19084
- hls.off(Events.ERROR, this.onError, this);
19085
19952
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19086
19953
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19087
19954
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19090,7 +19957,9 @@
19090
19957
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19091
19958
  };
19092
19959
  _proto.onHandlerDestroying = function onHandlerDestroying() {
19093
- this._unregisterListeners();
19960
+ // @ts-ignore
19961
+ this.onMediaPlaying = this.onMediaSeeked = null;
19962
+ this.unregisterListeners();
19094
19963
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
19095
19964
  };
19096
19965
  _proto.startLoad = function startLoad(startPosition) {
@@ -19114,7 +19983,8 @@
19114
19983
  }
19115
19984
  // set new level to playlist loader : this will trigger start level load
19116
19985
  // hls.nextLoadLevel remains until it is set to a new value or until a new frag is successfully loaded
19117
- this.level = hls.nextLoadLevel = startLevel;
19986
+ hls.nextLoadLevel = startLevel;
19987
+ this.level = hls.loadLevel;
19118
19988
  this.loadedmetadata = false;
19119
19989
  }
19120
19990
  // if startPosition undefined but lastCurrentTime set, set startPosition to last currentTime
@@ -19199,7 +20069,7 @@
19199
20069
  if (this.altAudio && this.audioOnly) {
19200
20070
  return;
19201
20071
  }
19202
- if (!(levels != null && levels[level])) {
20072
+ if (!this.buffering || !(levels != null && levels[level])) {
19203
20073
  return;
19204
20074
  }
19205
20075
  var levelInfo = levels[level];
@@ -19405,18 +20275,15 @@
19405
20275
  _proto.onMediaAttached = function onMediaAttached(event, data) {
19406
20276
  _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
19407
20277
  var media = data.media;
19408
- this.onvplaying = this.onMediaPlaying.bind(this);
19409
- this.onvseeked = this.onMediaSeeked.bind(this);
19410
- media.addEventListener('playing', this.onvplaying);
19411
- media.addEventListener('seeked', this.onvseeked);
20278
+ media.addEventListener('playing', this.onMediaPlaying);
20279
+ media.addEventListener('seeked', this.onMediaSeeked);
19412
20280
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
19413
20281
  };
19414
20282
  _proto.onMediaDetaching = function onMediaDetaching() {
19415
20283
  var media = this.media;
19416
- if (media && this.onvplaying && this.onvseeked) {
19417
- media.removeEventListener('playing', this.onvplaying);
19418
- media.removeEventListener('seeked', this.onvseeked);
19419
- this.onvplaying = this.onvseeked = null;
20284
+ if (media) {
20285
+ media.removeEventListener('playing', this.onMediaPlaying);
20286
+ media.removeEventListener('seeked', this.onMediaSeeked);
19420
20287
  this.videoBuffer = null;
19421
20288
  }
19422
20289
  this.fragPlaying = null;
@@ -19426,27 +20293,6 @@
19426
20293
  }
19427
20294
  _BaseStreamController.prototype.onMediaDetaching.call(this);
19428
20295
  };
19429
- _proto.onMediaPlaying = function onMediaPlaying() {
19430
- // tick to speed up FRAG_CHANGED triggering
19431
- this.tick();
19432
- };
19433
- _proto.onMediaSeeked = function onMediaSeeked() {
19434
- var media = this.media;
19435
- var currentTime = media ? media.currentTime : null;
19436
- if (isFiniteNumber(currentTime)) {
19437
- this.log("Media seeked to " + currentTime.toFixed(3));
19438
- }
19439
-
19440
- // If seeked was issued before buffer was appended do not tick immediately
19441
- var bufferInfo = this.getMainFwdBufferInfo();
19442
- if (bufferInfo === null || bufferInfo.len === 0) {
19443
- this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19444
- return;
19445
- }
19446
-
19447
- // tick to speed up FRAG_CHANGED triggering
19448
- this.tick();
19449
- };
19450
20296
  _proto.onManifestLoading = function onManifestLoading() {
19451
20297
  // reset buffer on manifest loading
19452
20298
  this.log('Trigger BUFFER_RESET');
@@ -19727,8 +20573,10 @@
19727
20573
  }
19728
20574
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
19729
20575
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
19730
- var activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
19731
- gapController.poll(this.lastCurrentTime, activeFrag);
20576
+ var state = this.state;
20577
+ var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
20578
+ var levelDetails = this.getLevelDetails();
20579
+ gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
19732
20580
  }
19733
20581
  this.lastCurrentTime = media.currentTime;
19734
20582
  };
@@ -20193,9 +21041,12 @@
20193
21041
  * The configuration object provided on player instantiation.
20194
21042
  */
20195
21043
  this.userConfig = void 0;
21044
+ /**
21045
+ * The logger functions used by this player instance, configured on player instantiation.
21046
+ */
21047
+ this.logger = void 0;
20196
21048
  this.coreComponents = void 0;
20197
21049
  this.networkControllers = void 0;
20198
- this.started = false;
20199
21050
  this._emitter = new EventEmitter();
20200
21051
  this._autoLevelCapping = -1;
20201
21052
  this._maxHdcpLevel = null;
@@ -20212,11 +21063,11 @@
20212
21063
  this._media = null;
20213
21064
  this.url = null;
20214
21065
  this.triggeringException = void 0;
20215
- enableLogs(userConfig.debug || false, 'Hls instance');
20216
- var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
21066
+ var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
21067
+ var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
20217
21068
  this.userConfig = userConfig;
20218
21069
  if (config.progressive) {
20219
- enableStreamingMode(config);
21070
+ enableStreamingMode(config, logger);
20220
21071
  }
20221
21072
 
20222
21073
  // core controllers and network loaders
@@ -20324,7 +21175,7 @@
20324
21175
  try {
20325
21176
  return this.emit(event, event, eventObject);
20326
21177
  } catch (error) {
20327
- logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
21178
+ this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
20328
21179
  // Prevent recursion in error event handlers that throw #5497
20329
21180
  if (!this.triggeringException) {
20330
21181
  this.triggeringException = true;
@@ -20350,7 +21201,7 @@
20350
21201
  * Dispose of the instance
20351
21202
  */;
20352
21203
  _proto.destroy = function destroy() {
20353
- logger.log('destroy');
21204
+ this.logger.log('destroy');
20354
21205
  this.trigger(Events.DESTROYING, undefined);
20355
21206
  this.detachMedia();
20356
21207
  this.removeAllListeners();
@@ -20375,7 +21226,7 @@
20375
21226
  * Attaches Hls.js to a media element
20376
21227
  */;
20377
21228
  _proto.attachMedia = function attachMedia(media) {
20378
- logger.log('attachMedia');
21229
+ this.logger.log('attachMedia');
20379
21230
  this._media = media;
20380
21231
  this.trigger(Events.MEDIA_ATTACHING, {
20381
21232
  media: media
@@ -20386,7 +21237,7 @@
20386
21237
  * Detach Hls.js from the media
20387
21238
  */;
20388
21239
  _proto.detachMedia = function detachMedia() {
20389
- logger.log('detachMedia');
21240
+ this.logger.log('detachMedia');
20390
21241
  this.trigger(Events.MEDIA_DETACHING, undefined);
20391
21242
  this._media = null;
20392
21243
  }
@@ -20403,7 +21254,7 @@
20403
21254
  });
20404
21255
  this._autoLevelCapping = -1;
20405
21256
  this._maxHdcpLevel = null;
20406
- logger.log("loadSource:" + loadingSource);
21257
+ this.logger.log("loadSource:" + loadingSource);
20407
21258
  if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
20408
21259
  this.detachMedia();
20409
21260
  this.attachMedia(media);
@@ -20425,8 +21276,7 @@
20425
21276
  if (startPosition === void 0) {
20426
21277
  startPosition = -1;
20427
21278
  }
20428
- logger.log("startLoad(" + startPosition + ")");
20429
- this.started = true;
21279
+ this.logger.log("startLoad(" + startPosition + ")");
20430
21280
  this.networkControllers.forEach(function (controller) {
20431
21281
  controller.startLoad(startPosition);
20432
21282
  });
@@ -20436,34 +21286,31 @@
20436
21286
  * Stop loading of any stream data.
20437
21287
  */;
20438
21288
  _proto.stopLoad = function stopLoad() {
20439
- logger.log('stopLoad');
20440
- this.started = false;
21289
+ this.logger.log('stopLoad');
20441
21290
  this.networkControllers.forEach(function (controller) {
20442
21291
  controller.stopLoad();
20443
21292
  });
20444
21293
  }
20445
21294
 
20446
21295
  /**
20447
- * Resumes stream controller segment loading if previously started.
21296
+ * Resumes stream controller segment loading after `pauseBuffering` has been called.
20448
21297
  */;
20449
21298
  _proto.resumeBuffering = function resumeBuffering() {
20450
- if (this.started) {
20451
- this.networkControllers.forEach(function (controller) {
20452
- if ('fragmentLoader' in controller) {
20453
- controller.startLoad(-1);
20454
- }
20455
- });
20456
- }
21299
+ this.networkControllers.forEach(function (controller) {
21300
+ if (controller.resumeBuffering) {
21301
+ controller.resumeBuffering();
21302
+ }
21303
+ });
20457
21304
  }
20458
21305
 
20459
21306
  /**
20460
- * Stops stream controller segment loading without changing 'started' state like stopLoad().
21307
+ * Prevents stream controller from loading new segments until `resumeBuffering` is called.
20461
21308
  * This allows for media buffering to be paused without interupting playlist loading.
20462
21309
  */;
20463
21310
  _proto.pauseBuffering = function pauseBuffering() {
20464
21311
  this.networkControllers.forEach(function (controller) {
20465
- if ('fragmentLoader' in controller) {
20466
- controller.stopLoad();
21312
+ if (controller.pauseBuffering) {
21313
+ controller.pauseBuffering();
20467
21314
  }
20468
21315
  });
20469
21316
  }
@@ -20472,7 +21319,7 @@
20472
21319
  * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
20473
21320
  */;
20474
21321
  _proto.swapAudioCodec = function swapAudioCodec() {
20475
- logger.log('swapAudioCodec');
21322
+ this.logger.log('swapAudioCodec');
20476
21323
  this.streamController.swapAudioCodec();
20477
21324
  }
20478
21325
 
@@ -20483,7 +21330,7 @@
20483
21330
  * Automatic recovery of media-errors by this process is configurable.
20484
21331
  */;
20485
21332
  _proto.recoverMediaError = function recoverMediaError() {
20486
- logger.log('recoverMediaError');
21333
+ this.logger.log('recoverMediaError');
20487
21334
  var media = this._media;
20488
21335
  this.detachMedia();
20489
21336
  if (media) {
@@ -20538,7 +21385,7 @@
20538
21385
  * Set quality level index immediately. This will flush the current buffer to replace the quality asap. That means playback will interrupt at least shortly to re-buffer and re-sync eventually. Set to -1 for automatic level selection.
20539
21386
  */,
20540
21387
  set: function set(newLevel) {
20541
- logger.log("set currentLevel:" + newLevel);
21388
+ this.logger.log("set currentLevel:" + newLevel);
20542
21389
  this.levelController.manualLevel = newLevel;
20543
21390
  this.streamController.immediateLevelSwitch();
20544
21391
  }
@@ -20559,7 +21406,7 @@
20559
21406
  * @param newLevel - Pass -1 for automatic level selection
20560
21407
  */,
20561
21408
  set: function set(newLevel) {
20562
- logger.log("set nextLevel:" + newLevel);
21409
+ this.logger.log("set nextLevel:" + newLevel);
20563
21410
  this.levelController.manualLevel = newLevel;
20564
21411
  this.streamController.nextLevelSwitch();
20565
21412
  }
@@ -20580,7 +21427,7 @@
20580
21427
  * @param newLevel - Pass -1 for automatic level selection
20581
21428
  */,
20582
21429
  set: function set(newLevel) {
20583
- logger.log("set loadLevel:" + newLevel);
21430
+ this.logger.log("set loadLevel:" + newLevel);
20584
21431
  this.levelController.manualLevel = newLevel;
20585
21432
  }
20586
21433
 
@@ -20615,7 +21462,7 @@
20615
21462
  * Sets "first-level", see getter.
20616
21463
  */,
20617
21464
  set: function set(newLevel) {
20618
- logger.log("set firstLevel:" + newLevel);
21465
+ this.logger.log("set firstLevel:" + newLevel);
20619
21466
  this.levelController.firstLevel = newLevel;
20620
21467
  }
20621
21468
 
@@ -20642,7 +21489,7 @@
20642
21489
  * (determined from download of first segment)
20643
21490
  */,
20644
21491
  set: function set(newLevel) {
20645
- logger.log("set startLevel:" + newLevel);
21492
+ this.logger.log("set startLevel:" + newLevel);
20646
21493
  // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
20647
21494
  if (newLevel !== -1) {
20648
21495
  newLevel = Math.max(newLevel, this.minAutoLevel);
@@ -20695,7 +21542,7 @@
20695
21542
  */
20696
21543
  function set(newLevel) {
20697
21544
  if (this._autoLevelCapping !== newLevel) {
20698
- logger.log("set autoLevelCapping:" + newLevel);
21545
+ this.logger.log("set autoLevelCapping:" + newLevel);
20699
21546
  this._autoLevelCapping = newLevel;
20700
21547
  this.levelController.checkMaxAutoUpdated();
20701
21548
  }
@@ -21020,7 +21867,7 @@
21020
21867
  * Get the video-dev/hls.js package version.
21021
21868
  */
21022
21869
  function get() {
21023
- return "1.5.3";
21870
+ return "1.5.5-0.canary.9977";
21024
21871
  }
21025
21872
  }, {
21026
21873
  key: "Events",