hls.js 1.5.4 → 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 (67) 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 +1930 -1095
  5. package/dist/hls.js.d.ts +63 -50
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1609 -778
  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 +1363 -542
  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 +1635 -815
  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 +21 -20
  22. package/src/controller/audio-stream-controller.ts +15 -16
  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 +25 -32
  37. package/src/controller/subtitle-stream-controller.ts +13 -14
  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
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.4");
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;
@@ -2626,13 +2651,13 @@
2626
2651
  this.keyFormatVersions = formatversions;
2627
2652
  this.iv = iv;
2628
2653
  this.encrypted = method ? method !== 'NONE' : false;
2629
- this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2654
+ this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2630
2655
  }
2631
2656
  var _proto = LevelKey.prototype;
2632
2657
  _proto.isSupported = function isSupported() {
2633
2658
  // If it's Segment encryption or No encryption, just select that key system
2634
2659
  if (this.method) {
2635
- if (this.method === 'AES-128' || this.method === 'NONE') {
2660
+ if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2636
2661
  return true;
2637
2662
  }
2638
2663
  if (this.keyFormat === 'identity') {
@@ -2646,14 +2671,13 @@
2646
2671
  if (!this.encrypted || !this.uri) {
2647
2672
  return null;
2648
2673
  }
2649
- if (this.method === 'AES-128' && this.uri && !this.iv) {
2674
+ if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2650
2675
  if (typeof sn !== 'number') {
2651
2676
  // We are fetching decryption data for a initialization segment
2652
- // If the segment was encrypted with AES-128
2677
+ // If the segment was encrypted with AES-128/256
2653
2678
  // It must have an IV defined. We cannot substitute the Segment Number in.
2654
- if (this.method === 'AES-128' && !this.iv) {
2655
- logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2656
- }
2679
+ logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2680
+
2657
2681
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2658
2682
  sn = 0;
2659
2683
  }
@@ -2815,23 +2839,28 @@
2815
2839
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
2816
2840
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
2817
2841
  }
2818
-
2819
- // Idealy fLaC and Opus would be first (spec-compliant) but
2820
- // some browsers will report that fLaC is supported then fail.
2821
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
2822
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
2823
2846
  flac: ['flac', 'fLaC', 'FLAC'],
2824
- 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']
2825
2851
  }[lowerCaseCodec];
2826
2852
  for (var i = 0; i < codecsToCheck.length; i++) {
2853
+ var _getMediaSource;
2827
2854
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
2828
2855
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
2829
2856
  return codecsToCheck[i];
2857
+ } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
2858
+ return '';
2830
2859
  }
2831
2860
  }
2832
2861
  return lowerCaseCodec;
2833
2862
  }
2834
- var AUDIO_CODEC_REGEXP = /flac|opus/i;
2863
+ var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
2835
2864
  function getCodecCompatibleName(codec, preferManagedMediaSource) {
2836
2865
  if (preferManagedMediaSource === void 0) {
2837
2866
  preferManagedMediaSource = true;
@@ -2859,6 +2888,18 @@
2859
2888
  }
2860
2889
  return codec;
2861
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
+ }
2862
2903
 
2863
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;
2864
2905
  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -4433,8 +4474,43 @@
4433
4474
  this.currentTime = 0;
4434
4475
  this.stallCount = 0;
4435
4476
  this._latency = null;
4436
- this.timeupdateHandler = function () {
4437
- 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
+ }
4438
4514
  };
4439
4515
  this.hls = hls;
4440
4516
  this.config = hls.config;
@@ -4446,7 +4522,7 @@
4446
4522
  this.onMediaDetaching();
4447
4523
  this.levelDetails = null;
4448
4524
  // @ts-ignore
4449
- this.hls = this.timeupdateHandler = null;
4525
+ this.hls = null;
4450
4526
  };
4451
4527
  _proto.registerListeners = function registerListeners() {
4452
4528
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4464,11 +4540,11 @@
4464
4540
  };
4465
4541
  _proto.onMediaAttached = function onMediaAttached(event, data) {
4466
4542
  this.media = data.media;
4467
- this.media.addEventListener('timeupdate', this.timeupdateHandler);
4543
+ this.media.addEventListener('timeupdate', this.onTimeupdate);
4468
4544
  };
4469
4545
  _proto.onMediaDetaching = function onMediaDetaching() {
4470
4546
  if (this.media) {
4471
- this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4547
+ this.media.removeEventListener('timeupdate', this.onTimeupdate);
4472
4548
  this.media = null;
4473
4549
  }
4474
4550
  };
@@ -4481,10 +4557,10 @@
4481
4557
  var details = _ref.details;
4482
4558
  this.levelDetails = details;
4483
4559
  if (details.advanced) {
4484
- this.timeupdate();
4560
+ this.onTimeupdate();
4485
4561
  }
4486
4562
  if (!details.live && this.media) {
4487
- this.media.removeEventListener('timeupdate', this.timeupdateHandler);
4563
+ this.media.removeEventListener('timeupdate', this.onTimeupdate);
4488
4564
  }
4489
4565
  };
4490
4566
  _proto.onError = function onError(event, data) {
@@ -4494,45 +4570,7 @@
4494
4570
  }
4495
4571
  this.stallCount++;
4496
4572
  if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
4497
- logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
4498
- }
4499
- };
4500
- _proto.timeupdate = function timeupdate() {
4501
- var media = this.media,
4502
- levelDetails = this.levelDetails;
4503
- if (!media || !levelDetails) {
4504
- return;
4505
- }
4506
- this.currentTime = media.currentTime;
4507
- var latency = this.computeLatency();
4508
- if (latency === null) {
4509
- return;
4510
- }
4511
- this._latency = latency;
4512
-
4513
- // Adapt playbackRate to meet target latency in low-latency mode
4514
- var _this$config = this.config,
4515
- lowLatencyMode = _this$config.lowLatencyMode,
4516
- maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
4517
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
4518
- return;
4519
- }
4520
- var targetLatency = this.targetLatency;
4521
- if (targetLatency === null) {
4522
- return;
4523
- }
4524
- var distanceFromTarget = latency - targetLatency;
4525
- // Only adjust playbackRate when within one target duration of targetLatency
4526
- // and more than one second from under-buffering.
4527
- // Playback further than one target duration from target can be considered DVR playback.
4528
- var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
4529
- var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
4530
- if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
4531
- var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
4532
- var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
4533
- media.playbackRate = Math.min(max, Math.max(1, rate));
4534
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
4535
- media.playbackRate = 1;
4573
+ this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
4536
4574
  }
4537
4575
  };
4538
4576
  _proto.estimateLiveEdge = function estimateLiveEdge() {
@@ -5440,19 +5478,17 @@
5440
5478
  MoveAllAlternatesMatchingHDCP: 2,
5441
5479
  SwitchToSDR: 4
5442
5480
  }; // Reserved for future use
5443
- var ErrorController = /*#__PURE__*/function () {
5481
+ var ErrorController = /*#__PURE__*/function (_Logger) {
5482
+ _inheritsLoose(ErrorController, _Logger);
5444
5483
  function ErrorController(hls) {
5445
- this.hls = void 0;
5446
- this.playlistError = 0;
5447
- this.penalizedRenditions = {};
5448
- this.log = void 0;
5449
- this.warn = void 0;
5450
- this.error = void 0;
5451
- this.hls = hls;
5452
- this.log = logger.log.bind(logger, "[info]:");
5453
- this.warn = logger.warn.bind(logger, "[warning]:");
5454
- this.error = logger.error.bind(logger, "[error]:");
5455
- 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;
5456
5492
  }
5457
5493
  var _proto = ErrorController.prototype;
5458
5494
  _proto.registerListeners = function registerListeners() {
@@ -5808,19 +5844,19 @@
5808
5844
  }
5809
5845
  };
5810
5846
  return ErrorController;
5811
- }();
5847
+ }(Logger);
5812
5848
 
5813
- var BasePlaylistController = /*#__PURE__*/function () {
5849
+ var BasePlaylistController = /*#__PURE__*/function (_Logger) {
5850
+ _inheritsLoose(BasePlaylistController, _Logger);
5814
5851
  function BasePlaylistController(hls, logPrefix) {
5815
- this.hls = void 0;
5816
- this.timer = -1;
5817
- this.requestScheduled = -1;
5818
- this.canLoad = false;
5819
- this.log = void 0;
5820
- this.warn = void 0;
5821
- this.log = logger.log.bind(logger, logPrefix + ":");
5822
- this.warn = logger.warn.bind(logger, logPrefix + ":");
5823
- 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;
5824
5860
  }
5825
5861
  var _proto = BasePlaylistController.prototype;
5826
5862
  _proto.destroy = function destroy() {
@@ -5853,7 +5889,7 @@
5853
5889
  try {
5854
5890
  uri = new self.URL(attr.URI, previous.url).href;
5855
5891
  } catch (error) {
5856
- logger.warn("Could not construct new URL for Rendition Report: " + error);
5892
+ this.warn("Could not construct new URL for Rendition Report: " + error);
5857
5893
  uri = attr.URI || '';
5858
5894
  }
5859
5895
  // Use exact match. Otherwise, the last partial match, if any, will be used
@@ -5892,7 +5928,7 @@
5892
5928
  return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
5893
5929
  };
5894
5930
  _proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
5895
- var _this = this;
5931
+ var _this2 = this;
5896
5932
  var details = data.details,
5897
5933
  stats = data.stats;
5898
5934
 
@@ -5997,7 +6033,7 @@
5997
6033
  // );
5998
6034
 
5999
6035
  this.timer = self.setTimeout(function () {
6000
- return _this.loadPlaylist(deliveryDirectives);
6036
+ return _this2.loadPlaylist(deliveryDirectives);
6001
6037
  }, estimatedTimeUntilUpdate);
6002
6038
  } else {
6003
6039
  this.clearTimer();
@@ -6013,7 +6049,7 @@
6013
6049
  return new HlsUrlParameters(msn, part, skip);
6014
6050
  };
6015
6051
  _proto.checkRetry = function checkRetry(errorEvent) {
6016
- var _this2 = this;
6052
+ var _this3 = this;
6017
6053
  var errorDetails = errorEvent.details;
6018
6054
  var isTimeout = isTimeoutError(errorEvent);
6019
6055
  var errorAction = errorEvent.errorAction;
@@ -6037,7 +6073,7 @@
6037
6073
  var delay = getRetryDelay(retryConfig, retryCount);
6038
6074
  // Schedule level/track reload
6039
6075
  this.timer = self.setTimeout(function () {
6040
- return _this2.loadPlaylist();
6076
+ return _this3.loadPlaylist();
6041
6077
  }, delay);
6042
6078
  this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
6043
6079
  }
@@ -6048,7 +6084,7 @@
6048
6084
  return retry;
6049
6085
  };
6050
6086
  return BasePlaylistController;
6051
- }();
6087
+ }(Logger);
6052
6088
 
6053
6089
  /*
6054
6090
  * compute an Exponential Weighted moving average
@@ -6422,30 +6458,33 @@
6422
6458
  }, {});
6423
6459
  }
6424
6460
 
6425
- var AbrController = /*#__PURE__*/function () {
6461
+ var AbrController = /*#__PURE__*/function (_Logger) {
6462
+ _inheritsLoose(AbrController, _Logger);
6426
6463
  function AbrController(_hls) {
6427
- var _this = this;
6428
- this.hls = void 0;
6429
- this.lastLevelLoadSec = 0;
6430
- this.lastLoadedFragLevel = -1;
6431
- this.firstSelection = -1;
6432
- this._nextAutoLevel = -1;
6433
- this.nextAutoLevelKey = '';
6434
- this.audioTracksByGroup = null;
6435
- this.codecTiers = null;
6436
- this.timer = -1;
6437
- this.fragCurrent = null;
6438
- this.partCurrent = null;
6439
- this.bitrateTestDelay = 0;
6440
- 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;
6441
6479
  /*
6442
6480
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
6443
6481
  quickly enough to prevent underbuffering
6444
6482
  */
6445
- this._abandonRulesCheck = function () {
6446
- var frag = _this.fragCurrent,
6447
- part = _this.partCurrent,
6448
- hls = _this.hls;
6483
+ _this._abandonRulesCheck = function () {
6484
+ var _assertThisInitialize = _assertThisInitialized(_this),
6485
+ frag = _assertThisInitialize.fragCurrent,
6486
+ part = _assertThisInitialize.partCurrent,
6487
+ hls = _assertThisInitialize.hls;
6449
6488
  var autoLevelEnabled = hls.autoLevelEnabled,
6450
6489
  media = hls.media;
6451
6490
  if (!frag || !media) {
@@ -6534,21 +6573,22 @@
6534
6573
  _this.resetEstimator(nextLoadLevelBitrate);
6535
6574
  }
6536
6575
  _this.clearTimer();
6537
- 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");
6538
6577
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
6539
6578
  frag: frag,
6540
6579
  part: part,
6541
6580
  stats: stats
6542
6581
  });
6543
6582
  };
6544
- this.hls = _hls;
6545
- this.bwEstimator = this.initEstimator();
6546
- this.registerListeners();
6583
+ _this.hls = _hls;
6584
+ _this.bwEstimator = _this.initEstimator();
6585
+ _this.registerListeners();
6586
+ return _this;
6547
6587
  }
6548
6588
  var _proto = AbrController.prototype;
6549
6589
  _proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
6550
6590
  if (abrEwmaDefaultEstimate) {
6551
- logger.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6591
+ this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
6552
6592
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
6553
6593
  }
6554
6594
  this.firstSelection = -1;
@@ -6800,13 +6840,13 @@
6800
6840
  // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
6801
6841
  var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
6802
6842
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
6803
- 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");
6804
6844
  // don't use conservative factor on bitrate test
6805
6845
  bwFactor = bwUpFactor = 1;
6806
6846
  }
6807
6847
  }
6808
6848
  var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
6809
- 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);
6810
6850
  if (bestLevel > -1) {
6811
6851
  return bestLevel;
6812
6852
  }
@@ -6862,7 +6902,7 @@
6862
6902
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
6863
6903
  currentFrameRate = minFramerate;
6864
6904
  currentBw = Math.max(currentBw, minBitrate);
6865
- logger.log("[abr] picked start tier " + JSON.stringify(startTier));
6905
+ this.log("picked start tier " + JSON.stringify(startTier));
6866
6906
  } else {
6867
6907
  currentCodecSet = level == null ? void 0 : level.codecSet;
6868
6908
  currentVideoRange = level == null ? void 0 : level.videoRange;
@@ -6915,9 +6955,9 @@
6915
6955
  var forcedAutoLevel = _this2.forcedAutoLevel;
6916
6956
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
6917
6957
  if (levelsSkipped.length) {
6918
- 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);
6919
6959
  }
6920
- 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);
6921
6961
  }
6922
6962
  if (firstSelection) {
6923
6963
  _this2.firstSelection = i;
@@ -6951,7 +6991,7 @@
6951
6991
  }
6952
6992
  var firstLevel = this.hls.firstLevel;
6953
6993
  var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
6954
- 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);
6955
6995
  return clamped;
6956
6996
  }
6957
6997
  }, {
@@ -7004,7 +7044,7 @@
7004
7044
  }
7005
7045
  }]);
7006
7046
  return AbrController;
7007
- }();
7047
+ }(Logger);
7008
7048
 
7009
7049
  /**
7010
7050
  * Provides methods dealing with buffer length retrieval for example.
@@ -7225,57 +7265,57 @@
7225
7265
  }();
7226
7266
 
7227
7267
  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
7228
- var BufferController = /*#__PURE__*/function () {
7268
+ var BufferController = /*#__PURE__*/function (_Logger) {
7269
+ _inheritsLoose(BufferController, _Logger);
7229
7270
  function BufferController(hls) {
7230
- var _this = this;
7271
+ var _this;
7272
+ _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
7231
7273
  // The level details used to determine duration, target-duration and live
7232
- this.details = null;
7274
+ _this.details = null;
7233
7275
  // cache the self generated object url to detect hijack of video tag
7234
- this._objectUrl = null;
7276
+ _this._objectUrl = null;
7235
7277
  // A queue of buffer operations which require the SourceBuffer to not be updating upon execution
7236
- this.operationQueue = void 0;
7278
+ _this.operationQueue = void 0;
7237
7279
  // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
7238
- this.listeners = void 0;
7239
- this.hls = void 0;
7280
+ _this.listeners = void 0;
7281
+ _this.hls = void 0;
7240
7282
  // The number of BUFFER_CODEC events received before any sourceBuffers are created
7241
- this.bufferCodecEventsExpected = 0;
7283
+ _this.bufferCodecEventsExpected = 0;
7242
7284
  // The total number of BUFFER_CODEC events received
7243
- this._bufferCodecEventsTotal = 0;
7285
+ _this._bufferCodecEventsTotal = 0;
7244
7286
  // A reference to the attached media element
7245
- this.media = null;
7287
+ _this.media = null;
7246
7288
  // A reference to the active media source
7247
- this.mediaSource = null;
7289
+ _this.mediaSource = null;
7248
7290
  // Last MP3 audio chunk appended
7249
- this.lastMpegAudioChunk = null;
7250
- this.appendSource = void 0;
7291
+ _this.lastMpegAudioChunk = null;
7292
+ _this.appendSource = void 0;
7251
7293
  // counters
7252
- this.appendErrors = {
7294
+ _this.appendErrors = {
7253
7295
  audio: 0,
7254
7296
  video: 0,
7255
7297
  audiovideo: 0
7256
7298
  };
7257
- this.tracks = {};
7258
- this.pendingTracks = {};
7259
- this.sourceBuffer = void 0;
7260
- this.log = void 0;
7261
- this.warn = void 0;
7262
- this.error = void 0;
7263
- this._onEndStreaming = function (event) {
7299
+ _this.tracks = {};
7300
+ _this.pendingTracks = {};
7301
+ _this.sourceBuffer = void 0;
7302
+ _this._onEndStreaming = function (event) {
7264
7303
  if (!_this.hls) {
7265
7304
  return;
7266
7305
  }
7267
7306
  _this.hls.pauseBuffering();
7268
7307
  };
7269
- this._onStartStreaming = function (event) {
7308
+ _this._onStartStreaming = function (event) {
7270
7309
  if (!_this.hls) {
7271
7310
  return;
7272
7311
  }
7273
7312
  _this.hls.resumeBuffering();
7274
7313
  };
7275
7314
  // Keep as arrow functions so that we can directly reference these functions directly as event listeners
7276
- this._onMediaSourceOpen = function () {
7277
- var media = _this.media,
7278
- mediaSource = _this.mediaSource;
7315
+ _this._onMediaSourceOpen = function () {
7316
+ var _assertThisInitialize = _assertThisInitialized(_this),
7317
+ media = _assertThisInitialize.media,
7318
+ mediaSource = _assertThisInitialize.mediaSource;
7279
7319
  _this.log('Media source opened');
7280
7320
  if (media) {
7281
7321
  media.removeEventListener('emptied', _this._onMediaEmptied);
@@ -7291,27 +7331,25 @@
7291
7331
  }
7292
7332
  _this.checkPendingTracks();
7293
7333
  };
7294
- this._onMediaSourceClose = function () {
7334
+ _this._onMediaSourceClose = function () {
7295
7335
  _this.log('Media source closed');
7296
7336
  };
7297
- this._onMediaSourceEnded = function () {
7337
+ _this._onMediaSourceEnded = function () {
7298
7338
  _this.log('Media source ended');
7299
7339
  };
7300
- this._onMediaEmptied = function () {
7301
- var mediaSrc = _this.mediaSrc,
7302
- _objectUrl = _this._objectUrl;
7340
+ _this._onMediaEmptied = function () {
7341
+ var _assertThisInitialize2 = _assertThisInitialized(_this),
7342
+ mediaSrc = _assertThisInitialize2.mediaSrc,
7343
+ _objectUrl = _assertThisInitialize2._objectUrl;
7303
7344
  if (mediaSrc !== _objectUrl) {
7304
- 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 + ")");
7305
7346
  }
7306
7347
  };
7307
- this.hls = hls;
7308
- var logPrefix = '[buffer-controller]';
7309
- this.appendSource = hls.config.preferManagedMediaSource;
7310
- this.log = logger.log.bind(logger, logPrefix);
7311
- this.warn = logger.warn.bind(logger, logPrefix);
7312
- this.error = logger.error.bind(logger, logPrefix);
7313
- this._initSourceBuffer();
7314
- this.registerListeners();
7348
+ _this.hls = hls;
7349
+ _this.appendSource = hls.config.preferManagedMediaSource;
7350
+ _this._initSourceBuffer();
7351
+ _this.registerListeners();
7352
+ return _this;
7315
7353
  }
7316
7354
  var _proto = BufferController.prototype;
7317
7355
  _proto.hasSourceTypes = function hasSourceTypes() {
@@ -7323,6 +7361,12 @@
7323
7361
  this.lastMpegAudioChunk = null;
7324
7362
  // @ts-ignore
7325
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;
7326
7370
  };
7327
7371
  _proto.registerListeners = function registerListeners() {
7328
7372
  var hls = this.hls;
@@ -7480,6 +7524,7 @@
7480
7524
  _this2.resetBuffer(type);
7481
7525
  });
7482
7526
  this._initSourceBuffer();
7527
+ this.hls.resumeBuffering();
7483
7528
  };
7484
7529
  _proto.resetBuffer = function resetBuffer(type) {
7485
7530
  var sb = this.sourceBuffer[type];
@@ -8183,7 +8228,7 @@
8183
8228
  }
8184
8229
  }]);
8185
8230
  return BufferController;
8186
- }();
8231
+ }(Logger);
8187
8232
  function removeSourceChildren(node) {
8188
8233
  var sourceChildren = node.querySelectorAll('source');
8189
8234
  [].slice.call(sourceChildren).forEach(function (source) {
@@ -8307,7 +8352,7 @@
8307
8352
  var hls = this.hls;
8308
8353
  var maxLevel = this.getMaxLevel(levels.length - 1);
8309
8354
  if (maxLevel !== this.autoLevelCapping) {
8310
- 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);
8311
8356
  }
8312
8357
  hls.autoLevelCapping = maxLevel;
8313
8358
  if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
@@ -8497,10 +8542,10 @@
8497
8542
  totalDroppedFrames: droppedFrames
8498
8543
  });
8499
8544
  if (droppedFPS > 0) {
8500
- // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8545
+ // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
8501
8546
  if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
8502
8547
  var currentLevel = hls.currentLevel;
8503
- 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);
8504
8549
  if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
8505
8550
  currentLevel = currentLevel - 1;
8506
8551
  hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
@@ -8534,26 +8579,28 @@
8534
8579
  }();
8535
8580
 
8536
8581
  var PATHWAY_PENALTY_DURATION_MS = 300000;
8537
- var ContentSteeringController = /*#__PURE__*/function () {
8582
+ var ContentSteeringController = /*#__PURE__*/function (_Logger) {
8583
+ _inheritsLoose(ContentSteeringController, _Logger);
8538
8584
  function ContentSteeringController(hls) {
8539
- this.hls = void 0;
8540
- this.log = void 0;
8541
- this.loader = null;
8542
- this.uri = null;
8543
- this.pathwayId = '.';
8544
- this.pathwayPriority = null;
8545
- this.timeToLoad = 300;
8546
- this.reloadTimer = -1;
8547
- this.updated = 0;
8548
- this.started = false;
8549
- this.enabled = true;
8550
- this.levels = null;
8551
- this.audioTracks = null;
8552
- this.subtitleTracks = null;
8553
- this.penalizedPathways = {};
8554
- this.hls = hls;
8555
- this.log = logger.log.bind(logger, "[content-steering]:");
8556
- 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;
8557
8604
  }
8558
8605
  var _proto = ContentSteeringController.prototype;
8559
8606
  _proto.registerListeners = function registerListeners() {
@@ -8674,7 +8721,7 @@
8674
8721
  errorAction.resolved = this.pathwayId !== errorPathway;
8675
8722
  }
8676
8723
  if (!errorAction.resolved) {
8677
- 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));
8678
8725
  }
8679
8726
  }
8680
8727
  };
@@ -8754,7 +8801,7 @@
8754
8801
  return defaultPathway;
8755
8802
  };
8756
8803
  _proto.clonePathways = function clonePathways(pathwayClones) {
8757
- var _this = this;
8804
+ var _this2 = this;
8758
8805
  var levels = this.levels;
8759
8806
  if (!levels) {
8760
8807
  return;
@@ -8770,7 +8817,7 @@
8770
8817
  })) {
8771
8818
  return;
8772
8819
  }
8773
- var clonedVariants = _this.getLevelsForPathway(baseId).map(function (baseLevel) {
8820
+ var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
8774
8821
  var attributes = new AttrList(baseLevel.attrs);
8775
8822
  attributes['PATHWAY-ID'] = cloneId;
8776
8823
  var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
@@ -8807,12 +8854,12 @@
8807
8854
  return clonedLevel;
8808
8855
  });
8809
8856
  levels.push.apply(levels, clonedVariants);
8810
- cloneRenditionGroups(_this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8811
- cloneRenditionGroups(_this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8857
+ cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
8858
+ cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
8812
8859
  });
8813
8860
  };
8814
8861
  _proto.loadSteeringManifest = function loadSteeringManifest(uri) {
8815
- var _this2 = this;
8862
+ var _this3 = this;
8816
8863
  var config = this.hls.config;
8817
8864
  var Loader = config.loader;
8818
8865
  if (this.loader) {
@@ -8847,87 +8894,87 @@
8847
8894
  };
8848
8895
  var callbacks = {
8849
8896
  onSuccess: function onSuccess(response, stats, context, networkDetails) {
8850
- _this2.log("Loaded steering manifest: \"" + url + "\"");
8897
+ _this3.log("Loaded steering manifest: \"" + url + "\"");
8851
8898
  var steeringData = response.data;
8852
- if (steeringData.VERSION !== 1) {
8853
- _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!");
8854
8901
  return;
8855
8902
  }
8856
- _this2.updated = performance.now();
8857
- _this2.timeToLoad = steeringData.TTL;
8903
+ _this3.updated = performance.now();
8904
+ _this3.timeToLoad = steeringData.TTL;
8858
8905
  var reloadUri = steeringData['RELOAD-URI'],
8859
8906
  pathwayClones = steeringData['PATHWAY-CLONES'],
8860
8907
  pathwayPriority = steeringData['PATHWAY-PRIORITY'];
8861
8908
  if (reloadUri) {
8862
8909
  try {
8863
- _this2.uri = new self.URL(reloadUri, url).href;
8910
+ _this3.uri = new self.URL(reloadUri, url).href;
8864
8911
  } catch (error) {
8865
- _this2.enabled = false;
8866
- _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);
8867
8914
  return;
8868
8915
  }
8869
8916
  }
8870
- _this2.scheduleRefresh(_this2.uri || context.url);
8917
+ _this3.scheduleRefresh(_this3.uri || context.url);
8871
8918
  if (pathwayClones) {
8872
- _this2.clonePathways(pathwayClones);
8919
+ _this3.clonePathways(pathwayClones);
8873
8920
  }
8874
8921
  var loadedSteeringData = {
8875
8922
  steeringManifest: steeringData,
8876
8923
  url: url.toString()
8877
8924
  };
8878
- _this2.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8925
+ _this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
8879
8926
  if (pathwayPriority) {
8880
- _this2.updatePathwayPriority(pathwayPriority);
8927
+ _this3.updatePathwayPriority(pathwayPriority);
8881
8928
  }
8882
8929
  },
8883
8930
  onError: function onError(error, context, networkDetails, stats) {
8884
- _this2.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8885
- _this2.stopLoad();
8931
+ _this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
8932
+ _this3.stopLoad();
8886
8933
  if (error.code === 410) {
8887
- _this2.enabled = false;
8888
- _this2.log("Steering manifest " + context.url + " no longer available");
8934
+ _this3.enabled = false;
8935
+ _this3.log("Steering manifest " + context.url + " no longer available");
8889
8936
  return;
8890
8937
  }
8891
- var ttl = _this2.timeToLoad * 1000;
8938
+ var ttl = _this3.timeToLoad * 1000;
8892
8939
  if (error.code === 429) {
8893
- var loader = _this2.loader;
8940
+ var loader = _this3.loader;
8894
8941
  if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
8895
8942
  var retryAfter = loader.getResponseHeader('Retry-After');
8896
8943
  if (retryAfter) {
8897
8944
  ttl = parseFloat(retryAfter) * 1000;
8898
8945
  }
8899
8946
  }
8900
- _this2.log("Steering manifest " + context.url + " rate limited");
8947
+ _this3.log("Steering manifest " + context.url + " rate limited");
8901
8948
  return;
8902
8949
  }
8903
- _this2.scheduleRefresh(_this2.uri || context.url, ttl);
8950
+ _this3.scheduleRefresh(_this3.uri || context.url, ttl);
8904
8951
  },
8905
8952
  onTimeout: function onTimeout(stats, context, networkDetails) {
8906
- _this2.log("Timeout loading steering manifest (" + context.url + ")");
8907
- _this2.scheduleRefresh(_this2.uri || context.url);
8953
+ _this3.log("Timeout loading steering manifest (" + context.url + ")");
8954
+ _this3.scheduleRefresh(_this3.uri || context.url);
8908
8955
  }
8909
8956
  };
8910
8957
  this.log("Requesting steering manifest: " + url);
8911
8958
  this.loader.load(context, loaderConfig, callbacks);
8912
8959
  };
8913
8960
  _proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
8914
- var _this3 = this;
8961
+ var _this4 = this;
8915
8962
  if (ttlMs === void 0) {
8916
8963
  ttlMs = this.timeToLoad * 1000;
8917
8964
  }
8918
8965
  this.clearTimeout();
8919
8966
  this.reloadTimer = self.setTimeout(function () {
8920
- var _this3$hls;
8921
- 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;
8922
8969
  if (media && !media.ended) {
8923
- _this3.loadSteeringManifest(uri);
8970
+ _this4.loadSteeringManifest(uri);
8924
8971
  return;
8925
8972
  }
8926
- _this3.scheduleRefresh(uri, _this3.timeToLoad * 1000);
8973
+ _this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
8927
8974
  }, ttlMs);
8928
8975
  };
8929
8976
  return ContentSteeringController;
8930
- }();
8977
+ }(Logger);
8931
8978
  function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
8932
8979
  if (!tracks) {
8933
8980
  return;
@@ -9794,7 +9841,7 @@
9794
9841
  /**
9795
9842
  * @ignore
9796
9843
  */
9797
- function mergeConfig(defaultConfig, userConfig) {
9844
+ function mergeConfig(defaultConfig, userConfig, logger) {
9798
9845
  if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
9799
9846
  throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
9800
9847
  }
@@ -9864,7 +9911,7 @@
9864
9911
  /**
9865
9912
  * @ignore
9866
9913
  */
9867
- function enableStreamingMode(config) {
9914
+ function enableStreamingMode(config, logger) {
9868
9915
  var currentLoader = config.loader;
9869
9916
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
9870
9917
  // If a developer has configured their own loader, respect that choice
@@ -9881,12 +9928,11 @@
9881
9928
  }
9882
9929
  }
9883
9930
 
9884
- var chromeOrFirefox;
9885
9931
  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
9886
9932
  _inheritsLoose(LevelController, _BasePlaylistControll);
9887
9933
  function LevelController(hls, contentSteeringController) {
9888
9934
  var _this;
9889
- _this = _BasePlaylistControll.call(this, hls, '[level-controller]') || this;
9935
+ _this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
9890
9936
  _this._levels = [];
9891
9937
  _this._firstLevel = -1;
9892
9938
  _this._maxAutoLevel = -1;
@@ -9955,21 +10001,13 @@
9955
10001
  var videoCodecFound = false;
9956
10002
  var audioCodecFound = false;
9957
10003
  data.levels.forEach(function (levelParsed) {
9958
- var _audioCodec, _videoCodec;
10004
+ var _videoCodec;
9959
10005
  var attributes = levelParsed.attrs;
9960
-
9961
- // erase audio codec info if browser does not support mp4a.40.34.
9962
- // demuxer will autodetect codec and fallback to mpeg/audio
9963
10006
  var audioCodec = levelParsed.audioCodec,
9964
10007
  videoCodec = levelParsed.videoCodec;
9965
- if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
9966
- chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
9967
- if (chromeOrFirefox) {
9968
- levelParsed.audioCodec = audioCodec = undefined;
9969
- }
9970
- }
9971
10008
  if (audioCodec) {
9972
- 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;
9973
10011
  }
9974
10012
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
9975
10013
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -11116,8 +11154,8 @@
11116
11154
  var _frag$decryptdata;
11117
11155
  var byteRangeStart = start;
11118
11156
  var byteRangeEnd = end;
11119
- if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
11120
- // 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,
11121
11159
  // has the unencrypted size specified in the range.
11122
11160
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
11123
11161
  var fragmentLen = end - start;
@@ -11150,6 +11188,9 @@
11150
11188
  (part ? part : frag).stats.aborted = true;
11151
11189
  return new LoadError(errorData);
11152
11190
  }
11191
+ function isMethodFullSegmentAesCbc(method) {
11192
+ return method === 'AES-128' || method === 'AES-256';
11193
+ }
11153
11194
  var LoadError = /*#__PURE__*/function (_Error) {
11154
11195
  _inheritsLoose(LoadError, _Error);
11155
11196
  function LoadError(data) {
@@ -11306,6 +11347,8 @@
11306
11347
  }
11307
11348
  return this.loadKeyEME(keyInfo, frag);
11308
11349
  case 'AES-128':
11350
+ case 'AES-256':
11351
+ case 'AES-256-CTR':
11309
11352
  return this.loadKeyHTTP(keyInfo, frag);
11310
11353
  default:
11311
11354
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
@@ -11439,13 +11482,17 @@
11439
11482
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
11440
11483
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
11441
11484
  */
11442
- var TaskLoop = /*#__PURE__*/function () {
11443
- function TaskLoop() {
11444
- this._boundTick = void 0;
11445
- this._tickTimer = null;
11446
- this._tickInterval = null;
11447
- this._tickCallCount = 0;
11448
- 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;
11449
11496
  }
11450
11497
  var _proto = TaskLoop.prototype;
11451
11498
  _proto.destroy = function destroy() {
@@ -11531,7 +11578,7 @@
11531
11578
  */;
11532
11579
  _proto.doTick = function doTick() {};
11533
11580
  return TaskLoop;
11534
- }();
11581
+ }(Logger);
11535
11582
 
11536
11583
  var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
11537
11584
  if (size === void 0) {
@@ -11717,37 +11764,65 @@
11717
11764
  }
11718
11765
 
11719
11766
  var AESCrypto = /*#__PURE__*/function () {
11720
- function AESCrypto(subtle, iv) {
11767
+ function AESCrypto(subtle, iv, aesMode) {
11721
11768
  this.subtle = void 0;
11722
11769
  this.aesIV = void 0;
11770
+ this.aesMode = void 0;
11723
11771
  this.subtle = subtle;
11724
11772
  this.aesIV = iv;
11773
+ this.aesMode = aesMode;
11725
11774
  }
11726
11775
  var _proto = AESCrypto.prototype;
11727
11776
  _proto.decrypt = function decrypt(data, key) {
11728
- return this.subtle.decrypt({
11729
- name: 'AES-CBC',
11730
- iv: this.aesIV
11731
- }, 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
+ }
11732
11794
  };
11733
11795
  return AESCrypto;
11734
11796
  }();
11735
11797
 
11736
11798
  var FastAESKey = /*#__PURE__*/function () {
11737
- function FastAESKey(subtle, key) {
11799
+ function FastAESKey(subtle, key, aesMode) {
11738
11800
  this.subtle = void 0;
11739
11801
  this.key = void 0;
11802
+ this.aesMode = void 0;
11740
11803
  this.subtle = subtle;
11741
11804
  this.key = key;
11805
+ this.aesMode = aesMode;
11742
11806
  }
11743
11807
  var _proto = FastAESKey.prototype;
11744
11808
  _proto.expandKey = function expandKey() {
11809
+ var subtleAlgoName = getSubtleAlgoName(this.aesMode);
11745
11810
  return this.subtle.importKey('raw', this.key, {
11746
- name: 'AES-CBC'
11811
+ name: subtleAlgoName
11747
11812
  }, false, ['encrypt', 'decrypt']);
11748
11813
  };
11749
11814
  return FastAESKey;
11750
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
+ }
11751
11826
 
11752
11827
  // PKCS7
11753
11828
  function removePadding(array) {
@@ -12000,7 +12075,8 @@
12000
12075
  this.currentIV = null;
12001
12076
  this.currentResult = null;
12002
12077
  this.useSoftware = void 0;
12003
- this.useSoftware = config.enableSoftwareAES;
12078
+ this.enableSoftwareAES = void 0;
12079
+ this.enableSoftwareAES = config.enableSoftwareAES;
12004
12080
  this.removePKCS7Padding = removePKCS7Padding;
12005
12081
  // built in decryptor expects PKCS7 padding
12006
12082
  if (removePKCS7Padding) {
@@ -12013,9 +12089,7 @@
12013
12089
  /* no-op */
12014
12090
  }
12015
12091
  }
12016
- if (this.subtle === null) {
12017
- this.useSoftware = true;
12018
- }
12092
+ this.useSoftware = this.subtle === null;
12019
12093
  }
12020
12094
  var _proto = Decrypter.prototype;
12021
12095
  _proto.destroy = function destroy() {
@@ -12052,11 +12126,11 @@
12052
12126
  this.softwareDecrypter = null;
12053
12127
  }
12054
12128
  };
12055
- _proto.decrypt = function decrypt(data, key, iv) {
12129
+ _proto.decrypt = function decrypt(data, key, iv, aesMode) {
12056
12130
  var _this = this;
12057
12131
  if (this.useSoftware) {
12058
12132
  return new Promise(function (resolve, reject) {
12059
- _this.softwareDecrypt(new Uint8Array(data), key, iv);
12133
+ _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
12060
12134
  var decryptResult = _this.flush();
12061
12135
  if (decryptResult) {
12062
12136
  resolve(decryptResult.buffer);
@@ -12065,16 +12139,20 @@
12065
12139
  }
12066
12140
  });
12067
12141
  }
12068
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
12142
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
12069
12143
  }
12070
12144
 
12071
12145
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
12072
12146
  // data is handled in the flush() call
12073
12147
  ;
12074
- _proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
12148
+ _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
12075
12149
  var currentIV = this.currentIV,
12076
12150
  currentResult = this.currentResult,
12077
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
+ }
12078
12156
  this.logOnce('JS AES decrypt');
12079
12157
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
12080
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
@@ -12107,12 +12185,12 @@
12107
12185
  }
12108
12186
  return result;
12109
12187
  };
12110
- _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
12188
+ _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
12111
12189
  var _this2 = this;
12112
12190
  var subtle = this.subtle;
12113
12191
  if (this.key !== key || !this.fastAesKey) {
12114
12192
  this.key = key;
12115
- this.fastAesKey = new FastAESKey(subtle, key);
12193
+ this.fastAesKey = new FastAESKey(subtle, key, aesMode);
12116
12194
  }
12117
12195
  return this.fastAesKey.expandKey().then(function (aesKey) {
12118
12196
  // decrypt using web crypto
@@ -12120,22 +12198,25 @@
12120
12198
  return Promise.reject(new Error('web crypto not initialized'));
12121
12199
  }
12122
12200
  _this2.logOnce('WebCrypto AES decrypt');
12123
- var crypto = new AESCrypto(subtle, new Uint8Array(iv));
12201
+ var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
12124
12202
  return crypto.decrypt(data.buffer, aesKey);
12125
12203
  }).catch(function (err) {
12126
12204
  logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
12127
- return _this2.onWebCryptoError(data, key, iv);
12205
+ return _this2.onWebCryptoError(data, key, iv, aesMode);
12128
12206
  });
12129
12207
  };
12130
- _proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
12131
- this.useSoftware = true;
12132
- this.logEnabled = true;
12133
- this.softwareDecrypt(data, key, iv);
12134
- var decryptResult = this.flush();
12135
- if (decryptResult) {
12136
- 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
+ }
12137
12218
  }
12138
- throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
12219
+ throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
12139
12220
  };
12140
12221
  _proto.getValidChunk = function getValidChunk(data) {
12141
12222
  var currentChunk = data;
@@ -12189,7 +12270,7 @@
12189
12270
  _inheritsLoose(BaseStreamController, _TaskLoop);
12190
12271
  function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
12191
12272
  var _this;
12192
- _this = _TaskLoop.call(this) || this;
12273
+ _this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
12193
12274
  _this.hls = void 0;
12194
12275
  _this.fragPrevious = null;
12195
12276
  _this.fragCurrent = null;
@@ -12214,25 +12295,87 @@
12214
12295
  _this.startFragRequested = false;
12215
12296
  _this.decrypter = void 0;
12216
12297
  _this.initPTS = [];
12217
- _this.onvseeking = null;
12218
- _this.onvended = null;
12219
- _this.logPrefix = '';
12220
- _this.log = void 0;
12221
- _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
+ };
12222
12353
  _this.playlistType = playlistType;
12223
- _this.logPrefix = logPrefix;
12224
- _this.log = logger.log.bind(logger, logPrefix + ":");
12225
- _this.warn = logger.warn.bind(logger, logPrefix + ":");
12226
12354
  _this.hls = hls;
12227
12355
  _this.fragmentLoader = new FragmentLoader(hls.config);
12228
12356
  _this.keyLoader = keyLoader;
12229
12357
  _this.fragmentTracker = fragmentTracker;
12230
12358
  _this.config = hls.config;
12231
12359
  _this.decrypter = new Decrypter(hls.config);
12232
- hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
12233
12360
  return _this;
12234
12361
  }
12235
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
+ };
12236
12379
  _proto.doTick = function doTick() {
12237
12380
  this.onTickEnd();
12238
12381
  };
@@ -12256,6 +12399,12 @@
12256
12399
  this.clearNextTick();
12257
12400
  this.state = State.STOPPED;
12258
12401
  };
12402
+ _proto.pauseBuffering = function pauseBuffering() {
12403
+ this.buffering = false;
12404
+ };
12405
+ _proto.resumeBuffering = function resumeBuffering() {
12406
+ this.buffering = true;
12407
+ };
12259
12408
  _proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
12260
12409
  // If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
12261
12410
  // of nothing loading/loaded return false
@@ -12286,10 +12435,8 @@
12286
12435
  };
12287
12436
  _proto.onMediaAttached = function onMediaAttached(event, data) {
12288
12437
  var media = this.media = this.mediaBuffer = data.media;
12289
- this.onvseeking = this.onMediaSeeking.bind(this);
12290
- this.onvended = this.onMediaEnded.bind(this);
12291
- media.addEventListener('seeking', this.onvseeking);
12292
- media.addEventListener('ended', this.onvended);
12438
+ media.addEventListener('seeking', this.onMediaSeeking);
12439
+ media.addEventListener('ended', this.onMediaEnded);
12293
12440
  var config = this.config;
12294
12441
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
12295
12442
  this.startLoad(config.startPosition);
@@ -12303,10 +12450,9 @@
12303
12450
  }
12304
12451
 
12305
12452
  // remove video listeners
12306
- if (media && this.onvseeking && this.onvended) {
12307
- media.removeEventListener('seeking', this.onvseeking);
12308
- media.removeEventListener('ended', this.onvended);
12309
- this.onvseeking = this.onvended = null;
12453
+ if (media) {
12454
+ media.removeEventListener('seeking', this.onMediaSeeking);
12455
+ media.removeEventListener('ended', this.onMediaEnded);
12310
12456
  }
12311
12457
  if (this.keyLoader) {
12312
12458
  this.keyLoader.detach();
@@ -12316,54 +12462,8 @@
12316
12462
  this.fragmentTracker.removeAllFragments();
12317
12463
  this.stopLoad();
12318
12464
  };
12319
- _proto.onMediaSeeking = function onMediaSeeking() {
12320
- var config = this.config,
12321
- fragCurrent = this.fragCurrent,
12322
- media = this.media,
12323
- mediaBuffer = this.mediaBuffer,
12324
- state = this.state;
12325
- var currentTime = media ? media.currentTime : 0;
12326
- var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
12327
- this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
12328
- if (this.state === State.ENDED) {
12329
- this.resetLoadingState();
12330
- } else if (fragCurrent) {
12331
- // Seeking while frag load is in progress
12332
- var tolerance = config.maxFragLookUpTolerance;
12333
- var fragStartOffset = fragCurrent.start - tolerance;
12334
- var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
12335
- // if seeking out of buffered range or into new one
12336
- if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
12337
- var pastFragment = currentTime > fragEndOffset;
12338
- // if the seek position is outside the current fragment range
12339
- if (currentTime < fragStartOffset || pastFragment) {
12340
- if (pastFragment && fragCurrent.loader) {
12341
- this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
12342
- fragCurrent.abortRequests();
12343
- this.resetLoadingState();
12344
- }
12345
- this.fragPrevious = null;
12346
- }
12347
- }
12348
- }
12349
- if (media) {
12350
- // Remove gap fragments
12351
- this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
12352
- this.lastCurrentTime = currentTime;
12353
- }
12354
-
12355
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
12356
- if (!this.loadedmetadata && !bufferInfo.len) {
12357
- this.nextLoadPosition = this.startPosition = currentTime;
12358
- }
12359
-
12360
- // Async tick to speed up processing
12361
- this.tickImmediate();
12362
- };
12363
- _proto.onMediaEnded = function onMediaEnded() {
12364
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
12365
- this.startPosition = this.lastCurrentTime = 0;
12366
- };
12465
+ _proto.onManifestLoading = function onManifestLoading() {};
12466
+ _proto.onError = function onError(event, data) {};
12367
12467
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
12368
12468
  this.startTimeOffset = data.startTimeOffset;
12369
12469
  this.initPTS = [];
@@ -12373,7 +12473,7 @@
12373
12473
  this.stopLoad();
12374
12474
  _TaskLoop.prototype.onHandlerDestroying.call(this);
12375
12475
  // @ts-ignore
12376
- this.hls = null;
12476
+ this.hls = this.onMediaSeeking = this.onMediaEnded = null;
12377
12477
  };
12378
12478
  _proto.onHandlerDestroyed = function onHandlerDestroyed() {
12379
12479
  this.state = State.STOPPED;
@@ -12503,10 +12603,10 @@
12503
12603
  var decryptData = frag.decryptdata;
12504
12604
 
12505
12605
  // check to see if the payload needs to be decrypted
12506
- 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)) {
12507
12607
  var startTime = self.performance.now();
12508
12608
  // decrypt init segment data
12509
- 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) {
12510
12610
  hls.trigger(Events.ERROR, {
12511
12611
  type: ErrorTypes.MEDIA_ERROR,
12512
12612
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -12619,7 +12719,7 @@
12619
12719
  }
12620
12720
  var keyLoadingPromise = null;
12621
12721
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
12622
- 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);
12623
12723
  this.state = State.KEY_LOADING;
12624
12724
  this.fragCurrent = frag;
12625
12725
  keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
@@ -12650,7 +12750,7 @@
12650
12750
  var partIndex = this.getNextPart(partList, frag, targetBufferTime);
12651
12751
  if (partIndex > -1) {
12652
12752
  var part = partList[partIndex];
12653
- 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)));
12654
12754
  this.nextLoadPosition = part.start + part.duration;
12655
12755
  this.state = State.FRAG_LOADING;
12656
12756
  var _result;
@@ -12683,7 +12783,7 @@
12683
12783
  }
12684
12784
  }
12685
12785
  }
12686
- 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)));
12687
12787
  // Don't update nextLoadPosition for fragments which are not buffered
12688
12788
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
12689
12789
  this.nextLoadPosition = frag.start + frag.duration;
@@ -13244,7 +13344,7 @@
13244
13344
  errorAction.resolved = true;
13245
13345
  }
13246
13346
  } else {
13247
- logger.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13347
+ this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
13248
13348
  return;
13249
13349
  }
13250
13350
  } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
@@ -13634,6 +13734,7 @@
13634
13734
  */
13635
13735
  function getAudioConfig(observer, data, offset, audioCodec) {
13636
13736
  var adtsObjectType;
13737
+ var originalAdtsObjectType;
13637
13738
  var adtsExtensionSamplingIndex;
13638
13739
  var adtsChannelConfig;
13639
13740
  var config;
@@ -13641,7 +13742,7 @@
13641
13742
  var manifestCodec = audioCodec;
13642
13743
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
13643
13744
  // byte 2
13644
- adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13745
+ adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
13645
13746
  var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
13646
13747
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
13647
13748
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
@@ -13658,8 +13759,8 @@
13658
13759
  // byte 3
13659
13760
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
13660
13761
  logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
13661
- // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
13662
- 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)) {
13663
13764
  if (adtsSamplingIndex >= 6) {
13664
13765
  adtsObjectType = 5;
13665
13766
  config = new Array(4);
@@ -13753,6 +13854,7 @@
13753
13854
  samplerate: adtsSamplingRates[adtsSamplingIndex],
13754
13855
  channelCount: adtsChannelConfig,
13755
13856
  codec: 'mp4a.40.' + adtsObjectType,
13857
+ parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
13756
13858
  manifestCodec: manifestCodec
13757
13859
  };
13758
13860
  }
@@ -13807,7 +13909,8 @@
13807
13909
  track.channelCount = config.channelCount;
13808
13910
  track.codec = config.codec;
13809
13911
  track.manifestCodec = config.manifestCodec;
13810
- 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);
13811
13914
  }
13812
13915
  }
13813
13916
  function getFrameDuration(samplerate) {
@@ -14287,36 +14390,140 @@
14287
14390
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
14288
14391
  }
14289
14392
  };
14290
- return BaseVideoParser;
14291
- }();
14292
-
14293
- /**
14294
- * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
14295
- */
14296
-
14297
- var ExpGolomb = /*#__PURE__*/function () {
14298
- function ExpGolomb(data) {
14299
- this.data = void 0;
14300
- this.bytesAvailable = void 0;
14301
- this.word = void 0;
14302
- this.bitsAvailable = void 0;
14303
- this.data = data;
14304
- // the number of bytes left to examine in this.data
14305
- this.bytesAvailable = data.byteLength;
14306
- // the current word being examined
14307
- this.word = 0; // :uint
14308
- // the number of bits left to examine in the current word
14309
- this.bitsAvailable = 0; // :uint
14310
- }
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));
14311
14405
 
14312
- // ():void
14313
- var _proto = ExpGolomb.prototype;
14314
- _proto.loadWord = function loadWord() {
14315
- var data = this.data;
14316
- var bytesAvailable = this.bytesAvailable;
14317
- var position = data.byteLength - bytesAvailable;
14318
- var workingBytes = new Uint8Array(4);
14319
- var availableBytes = Math.min(4, bytesAvailable);
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;
14523
+ var bytesAvailable = this.bytesAvailable;
14524
+ var position = data.byteLength - bytesAvailable;
14525
+ var workingBytes = new Uint8Array(4);
14526
+ var availableBytes = Math.min(4, bytesAvailable);
14320
14527
  if (availableBytes === 0) {
14321
14528
  throw new Error('no bytes available');
14322
14529
  }
@@ -14441,22 +14648,179 @@
14441
14648
  ;
14442
14649
  _proto.readUInt = function readUInt() {
14443
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();
14444
14809
  }
14445
14810
 
14446
14811
  /**
14447
- * Advance the ExpGolomb decoder past a scaling list. The scaling
14448
- * list is optionally transmitted as part of a sequence parameter
14812
+ * The scaling list is optionally transmitted as part of a sequence parameter
14449
14813
  * set and is not relevant to transmuxing.
14450
14814
  * @param count the number of entries in this scaling list
14451
14815
  * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
14452
14816
  */;
14453
- _proto.skipScalingList = function skipScalingList(count) {
14817
+ _proto.skipScalingList = function skipScalingList(count, reader) {
14454
14818
  var lastScale = 8;
14455
14819
  var nextScale = 8;
14456
14820
  var deltaScale;
14457
14821
  for (var j = 0; j < count; j++) {
14458
14822
  if (nextScale !== 0) {
14459
- deltaScale = this.readEG();
14823
+ deltaScale = reader.readEG();
14460
14824
  nextScale = (lastScale + deltaScale + 256) % 256;
14461
14825
  }
14462
14826
  lastScale = nextScale === 0 ? lastScale : nextScale;
@@ -14471,7 +14835,8 @@
14471
14835
  * sequence parameter set, including the dimensions of the
14472
14836
  * associated video frames.
14473
14837
  */;
14474
- _proto.readSPS = function readSPS() {
14838
+ _proto.readSPS = function readSPS(sps) {
14839
+ var eg = new ExpGolomb(sps);
14475
14840
  var frameCropLeftOffset = 0;
14476
14841
  var frameCropRightOffset = 0;
14477
14842
  var frameCropTopOffset = 0;
@@ -14479,13 +14844,13 @@
14479
14844
  var numRefFramesInPicOrderCntCycle;
14480
14845
  var scalingListCount;
14481
14846
  var i;
14482
- var readUByte = this.readUByte.bind(this);
14483
- var readBits = this.readBits.bind(this);
14484
- var readUEG = this.readUEG.bind(this);
14485
- var readBoolean = this.readBoolean.bind(this);
14486
- var skipBits = this.skipBits.bind(this);
14487
- var skipEG = this.skipEG.bind(this);
14488
- 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);
14489
14854
  var skipScalingList = this.skipScalingList.bind(this);
14490
14855
  readUByte();
14491
14856
  var profileIdc = readUByte(); // profile_idc
@@ -14510,9 +14875,9 @@
14510
14875
  if (readBoolean()) {
14511
14876
  // seq_scaling_list_present_flag[ i ]
14512
14877
  if (i < 6) {
14513
- skipScalingList(16);
14878
+ skipScalingList(16, eg);
14514
14879
  } else {
14515
- skipScalingList(64);
14880
+ skipScalingList(64, eg);
14516
14881
  }
14517
14882
  }
14518
14883
  }
@@ -14617,26 +14982,24 @@
14617
14982
  pixelRatio: pixelRatio
14618
14983
  };
14619
14984
  };
14620
- _proto.readSliceType = function readSliceType() {
14621
- // skip NALu type
14622
- this.readUByte();
14623
- // discard first_mb_in_slice
14624
- this.readUEG();
14625
- // return slice_type
14626
- return this.readUEG();
14627
- };
14628
- return ExpGolomb;
14629
- }();
14985
+ return AvcVideoParser;
14986
+ }(BaseVideoParser);
14630
14987
 
14631
- var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
14632
- _inheritsLoose(AvcVideoParser, _BaseVideoParser);
14633
- function AvcVideoParser() {
14634
- 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;
14635
14998
  }
14636
- var _proto = AvcVideoParser.prototype;
14637
- _proto.parseAVCPES = function parseAVCPES(track, textTrack, pes, last, duration) {
14638
- var _this = this;
14639
- 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);
14640
15003
  var VideoSample = this.VideoSample;
14641
15004
  var push;
14642
15005
  var spsfound = false;
@@ -14652,231 +15015,576 @@
14652
15015
  units.forEach(function (unit) {
14653
15016
  var _VideoSample2;
14654
15017
  switch (unit.type) {
14655
- // NDR
15018
+ // NON-IDR, NON RANDOM ACCESS SLICE
15019
+ case 0:
14656
15020
  case 1:
14657
- {
14658
- var iskey = false;
14659
- push = true;
14660
- var data = unit.data;
14661
- // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
14662
- if (spsfound && data.length > 4) {
14663
- // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
14664
- var sliceType = new ExpGolomb(data).readSliceType();
14665
- // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
14666
- // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
14667
- // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
14668
- // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
14669
- // if (sliceType === 2 || sliceType === 7) {
14670
- if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
14671
- iskey = true;
14672
- }
14673
- }
14674
- if (iskey) {
14675
- var _VideoSample;
14676
- // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
14677
- if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
14678
- _this.pushAccessUnit(VideoSample, track);
14679
- VideoSample = _this.VideoSample = null;
14680
- }
14681
- }
14682
- if (!VideoSample) {
14683
- 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;
14684
15049
  }
14685
- VideoSample.frame = true;
14686
- VideoSample.key = iskey;
14687
- break;
14688
- // IDR
14689
15050
  }
14690
- 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:
14691
15061
  push = true;
14692
15062
  // handle PES not starting with AUD
14693
15063
  // if we have frame data already, that cannot belong to the same frame, so force a push
14694
15064
  if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
14695
- _this.pushAccessUnit(VideoSample, track);
14696
- VideoSample = _this.VideoSample = null;
15065
+ _this2.pushAccessUnit(VideoSample, track);
15066
+ VideoSample = _this2.VideoSample = null;
14697
15067
  }
14698
15068
  if (!VideoSample) {
14699
- VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
15069
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
14700
15070
  }
14701
15071
  VideoSample.key = true;
14702
15072
  VideoSample.frame = true;
14703
15073
  break;
15074
+
14704
15075
  // SEI
14705
- case 6:
14706
- {
14707
- push = true;
14708
- parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
14709
- break;
14710
- // SPS
14711
- }
14712
- case 7:
14713
- {
14714
- var _track$pixelRatio, _track$pixelRatio2;
14715
- push = true;
14716
- spsfound = true;
14717
- var sps = unit.data;
14718
- var expGolombDecoder = new ExpGolomb(sps);
14719
- var config = expGolombDecoder.readSPS();
14720
- 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]) {
14721
- track.width = config.width;
14722
- track.height = config.height;
14723
- track.pixelRatio = config.pixelRatio;
14724
- track.sps = [sps];
14725
- track.duration = duration;
14726
- var codecarray = sps.subarray(1, 4);
14727
- var codecstring = 'avc1.';
14728
- for (var i = 0; i < 3; i++) {
14729
- var h = codecarray[i].toString(16);
14730
- if (h.length < 2) {
14731
- h = '0' + h;
14732
- }
14733
- codecstring += h;
14734
- }
14735
- track.codec = codecstring;
14736
- }
14737
- break;
14738
- }
14739
- // PPS
14740
- case 8:
15076
+ case 39:
14741
15077
  push = true;
14742
- track.pps = [unit.data];
14743
- break;
14744
- // AUD
14745
- case 9:
14746
- push = true;
14747
- track.audFound = true;
14748
- if (VideoSample) {
14749
- _this.pushAccessUnit(VideoSample, track);
14750
- }
14751
- VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
15078
+ parseSEIMessageFromNALu(unit.data, 2,
15079
+ // NALu header size
15080
+ pes.pts, textTrack.samples);
14752
15081
  break;
14753
- // Filler Data
14754
- case 12:
15082
+
15083
+ // VPS
15084
+ case 32:
14755
15085
  push = true;
14756
- break;
14757
- default:
14758
- push = false;
14759
- if (VideoSample) {
14760
- 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;
14761
15090
  }
15091
+ track.vps = [unit.data];
14762
15092
  break;
14763
- }
14764
- if (VideoSample && push) {
14765
- var _units = VideoSample.units;
14766
- _units.push(unit);
14767
- }
14768
- });
14769
- // if last PES packet, push samples
14770
- if (last && VideoSample) {
14771
- this.pushAccessUnit(VideoSample, track);
14772
- this.VideoSample = null;
14773
- }
14774
- };
14775
- _proto.parseAVCNALu = function parseAVCNALu(track, array) {
14776
- var len = array.byteLength;
14777
- var state = track.naluState || 0;
14778
- var lastState = state;
14779
- var units = [];
14780
- var i = 0;
14781
- var value;
14782
- var overflow;
14783
- var unitType;
14784
- var lastUnitStart = -1;
14785
- var lastUnitType = 0;
14786
- // logger.log('PES:' + Hex.hexDump(array));
14787
15093
 
14788
- if (state === -1) {
14789
- // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
14790
- lastUnitStart = 0;
14791
- // NALu type is value read from offset 0
14792
- lastUnitType = array[0] & 0x1f;
14793
- state = 0;
14794
- i = 1;
14795
- }
14796
- while (i < len) {
14797
- value = array[i++];
14798
- // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
14799
- if (!state) {
14800
- state = value ? 0 : 1;
14801
- continue;
14802
- }
14803
- if (state === 1) {
14804
- state = value ? 0 : 2;
14805
- continue;
14806
- }
14807
- // here we have state either equal to 2 or 3
14808
- if (!value) {
14809
- state = 3;
14810
- } else if (value === 1) {
14811
- overflow = i - state - 1;
14812
- if (lastUnitStart >= 0) {
14813
- var unit = {
14814
- data: array.subarray(lastUnitStart, overflow),
14815
- type: lastUnitType
14816
- };
14817
- // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
14818
- units.push(unit);
14819
- } else {
14820
- // lastUnitStart is undefined => this is the first start code found in this PES packet
14821
- // first check if start code delimiter is overlapping between 2 PES packets,
14822
- // ie it started in last packet (lastState not zero)
14823
- // and ended at the beginning of this PES packet (i <= 4 - lastState)
14824
- var lastUnit = this.getLastNalUnit(track.samples);
14825
- if (lastUnit) {
14826
- if (lastState && i <= 4 - lastState) {
14827
- // start delimiter overlapping between PES packets
14828
- // strip start delimiter bytes from the end of last NAL unit
14829
- // check if lastUnit had a state different from zero
14830
- if (lastUnit.state) {
14831
- // strip last bytes
14832
- 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];
14833
15113
  }
14834
15114
  }
14835
- // 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;
14836
15124
 
14837
- if (overflow > 0) {
14838
- // logger.log('first NALU found with overflow:' + overflow);
14839
- lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
14840
- 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);
14841
15138
  }
14842
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;
14843
15180
  }
14844
- // check if we can read unit type
14845
- if (i < len) {
14846
- unitType = array[i] & 0x1f;
14847
- // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
14848
- lastUnitStart = i;
14849
- lastUnitType = unitType;
14850
- state = 0;
14851
- } else {
14852
- // not enough byte to read unit type. let's read it on next PES parsing
14853
- 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
+ }
14854
15308
  }
14855
- } else {
14856
- state = 0;
14857
15309
  }
14858
15310
  }
14859
- if (lastUnitStart >= 0 && state >= 0) {
14860
- var _unit = {
14861
- data: array.subarray(lastUnitStart, len),
14862
- type: lastUnitType,
14863
- state: state
14864
- };
14865
- units.push(_unit);
14866
- // 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
+ }
14867
15358
  }
14868
- // no NALu found
14869
- if (units.length === 0) {
14870
- // append pes.data to previous NAL unit
14871
- var _lastUnit = this.getLastNalUnit(track.samples);
14872
- if (_lastUnit) {
14873
- _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
+ }
14874
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
14875
15578
  }
14876
- track.naluState = state;
14877
- return units;
15579
+ return {
15580
+ parallelismType: parallelismType
15581
+ };
14878
15582
  };
14879
- 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;
14880
15588
  }(BaseVideoParser);
14881
15589
 
14882
15590
  /**
@@ -14894,7 +15602,7 @@
14894
15602
  }
14895
15603
  var _proto = SampleAesDecrypter.prototype;
14896
15604
  _proto.decryptBuffer = function decryptBuffer(encryptedData) {
14897
- 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);
14898
15606
  }
14899
15607
 
14900
15608
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -15013,7 +15721,7 @@
15013
15721
  this.observer = observer;
15014
15722
  this.config = config;
15015
15723
  this.typeSupported = typeSupported;
15016
- this.videoParser = new AvcVideoParser();
15724
+ this.videoParser = null;
15017
15725
  }
15018
15726
  TSDemuxer.probe = function probe(data) {
15019
15727
  var syncOffset = TSDemuxer.syncOffset(data);
@@ -15183,7 +15891,19 @@
15183
15891
  case videoPid:
15184
15892
  if (stt) {
15185
15893
  if (videoData && (pes = parsePES(videoData))) {
15186
- 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
+ }
15187
15907
  }
15188
15908
  videoData = {
15189
15909
  data: [],
@@ -15341,8 +16061,20 @@
15341
16061
  // try to parse last PES packets
15342
16062
  var pes;
15343
16063
  if (videoData && (pes = parsePES(videoData))) {
15344
- this.videoParser.parseAVCPES(videoTrack, textTrack, pes, true, this._duration);
15345
- 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
+ }
15346
16078
  } else {
15347
16079
  // either avcData null or PES truncated, keep it for next frag parsing
15348
16080
  videoTrack.pesData = videoData;
@@ -15644,7 +16376,12 @@
15644
16376
  logger.warn('Unsupported EC-3 in M2TS found');
15645
16377
  break;
15646
16378
  case 0x24:
15647
- 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
+ }
15648
16385
  break;
15649
16386
  }
15650
16387
  // move to the next table entry
@@ -15872,6 +16609,8 @@
15872
16609
  avc1: [],
15873
16610
  // codingname
15874
16611
  avcC: [],
16612
+ hvc1: [],
16613
+ hvcC: [],
15875
16614
  btrt: [],
15876
16615
  dinf: [],
15877
16616
  dref: [],
@@ -16299,8 +17038,10 @@
16299
17038
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
16300
17039
  }
16301
17040
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
16302
- } else {
17041
+ } else if (track.segmentCodec === 'avc') {
16303
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));
16304
17045
  }
16305
17046
  };
16306
17047
  MP4.tkhd = function tkhd(track) {
@@ -16438,6 +17179,84 @@
16438
17179
  var result = appendUint8Array(MP4.FTYP, movie);
16439
17180
  return result;
16440
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
+ };
16441
17260
  return MP4;
16442
17261
  }();
16443
17262
  MP4.types = void 0;
@@ -16824,9 +17643,9 @@
16824
17643
  var foundOverlap = delta < -1;
16825
17644
  if (foundHole || foundOverlap) {
16826
17645
  if (foundHole) {
16827
- 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));
16828
17647
  } else {
16829
- 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));
16830
17649
  }
16831
17650
  if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
16832
17651
  firstDTS = nextAvcDts;
@@ -16835,12 +17654,24 @@
16835
17654
  inputSamples[0].dts = firstDTS;
16836
17655
  inputSamples[0].pts = firstPTS;
16837
17656
  } else {
17657
+ var isPTSOrderRetained = true;
16838
17658
  for (var _i = 0; _i < inputSamples.length; _i++) {
16839
- if (inputSamples[_i].dts > firstPTS) {
17659
+ if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
16840
17660
  break;
16841
17661
  }
17662
+ var prevPTS = inputSamples[_i].pts;
16842
17663
  inputSamples[_i].dts -= delta;
16843
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
+ }
16844
17675
  }
16845
17676
  }
16846
17677
  logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
@@ -16988,7 +17819,7 @@
16988
17819
  }
16989
17820
  }
16990
17821
  }
16991
- // 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)
16992
17823
  mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
16993
17824
  this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
16994
17825
  this.videoSampleDuration = mp4SampleDuration;
@@ -17123,7 +17954,7 @@
17123
17954
  logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
17124
17955
  for (var j = 0; j < missing; j++) {
17125
17956
  var newStamp = Math.max(nextPts, 0);
17126
- var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
17957
+ var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17127
17958
  if (!fillFrame) {
17128
17959
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
17129
17960
  fillFrame = sample.unit.subarray();
@@ -17251,7 +18082,7 @@
17251
18082
  // samples count of this segment's duration
17252
18083
  var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
17253
18084
  // silent frame
17254
- var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
18085
+ var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
17255
18086
  logger.warn('[mp4-remuxer]: remux empty Audio');
17256
18087
  // Can't remux if we can't generate a silent frame...
17257
18088
  if (!silentFrame) {
@@ -17638,13 +18469,15 @@
17638
18469
  duration = transmuxConfig.duration,
17639
18470
  initSegmentData = transmuxConfig.initSegmentData;
17640
18471
  var keyData = getEncryptionType(uintData, decryptdata);
17641
- if (keyData && keyData.method === 'AES-128') {
18472
+ if (keyData && isFullSegmentEncryption(keyData.method)) {
17642
18473
  var decrypter = this.getDecrypter();
18474
+ var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
18475
+
17643
18476
  // Software decryption is synchronous; webCrypto is not
17644
18477
  if (decrypter.isSync()) {
17645
18478
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
17646
18479
  // data is handled in the flush() call
17647
- var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
18480
+ var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
17648
18481
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
17649
18482
  var loadingParts = chunkMeta.part > -1;
17650
18483
  if (loadingParts) {
@@ -17656,7 +18489,7 @@
17656
18489
  }
17657
18490
  uintData = new Uint8Array(decryptedData);
17658
18491
  } else {
17659
- 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) {
17660
18493
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
17661
18494
  // the decrypted data has been transmuxed
17662
18495
  var result = _this.push(decryptedData, null, chunkMeta);
@@ -18277,7 +19110,7 @@
18277
19110
  observer.on(Events.ERROR, forwardMessage);
18278
19111
 
18279
19112
  // forward logger events to main thread
18280
- var forwardWorkerLogs = function forwardWorkerLogs() {
19113
+ var forwardWorkerLogs = function forwardWorkerLogs(logger) {
18281
19114
  var _loop = function _loop(logFn) {
18282
19115
  var func = function func(message) {
18283
19116
  forwardMessage('workerLog', {
@@ -18298,8 +19131,8 @@
18298
19131
  {
18299
19132
  var config = JSON.parse(data.config);
18300
19133
  self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
18301
- enableLogs(config.debug, data.id);
18302
- forwardWorkerLogs();
19134
+ var logger = enableLogs(config.debug, data.id);
19135
+ forwardWorkerLogs(logger);
18303
19136
  forwardMessage('init', null);
18304
19137
  break;
18305
19138
  }
@@ -18473,16 +19306,7 @@
18473
19306
  this.observer = new EventEmitter();
18474
19307
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
18475
19308
  this.observer.on(Events.ERROR, forwardMessage);
18476
- var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
18477
- isTypeSupported: function isTypeSupported() {
18478
- return false;
18479
- }
18480
- };
18481
- var m2tsTypeSupported = {
18482
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
18483
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
18484
- ac3: false
18485
- };
19309
+ var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
18486
19310
 
18487
19311
  // navigator.vendor is not always available in Web Worker
18488
19312
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -18739,21 +19563,26 @@
18739
19563
  var MAX_START_GAP_JUMP = 2.0;
18740
19564
  var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
18741
19565
  var SKIP_BUFFER_RANGE_START = 0.05;
18742
- var GapController = /*#__PURE__*/function () {
19566
+ var GapController = /*#__PURE__*/function (_Logger) {
19567
+ _inheritsLoose(GapController, _Logger);
18743
19568
  function GapController(config, media, fragmentTracker, hls) {
18744
- this.config = void 0;
18745
- this.media = null;
18746
- this.fragmentTracker = void 0;
18747
- this.hls = void 0;
18748
- this.nudgeRetry = 0;
18749
- this.stallReported = false;
18750
- this.stalled = null;
18751
- this.moved = false;
18752
- this.seeking = false;
18753
- this.config = config;
18754
- this.media = media;
18755
- this.fragmentTracker = fragmentTracker;
18756
- 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;
18757
19586
  }
18758
19587
  var _proto = GapController.prototype;
18759
19588
  _proto.destroy = function destroy() {
@@ -18768,7 +19597,7 @@
18768
19597
  *
18769
19598
  * @param lastCurrentTime - Previously read playhead position
18770
19599
  */;
18771
- _proto.poll = function poll(lastCurrentTime, activeFrag) {
19600
+ _proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
18772
19601
  var config = this.config,
18773
19602
  media = this.media,
18774
19603
  stalled = this.stalled;
@@ -18783,6 +19612,7 @@
18783
19612
 
18784
19613
  // The playhead is moving, no-op
18785
19614
  if (currentTime !== lastCurrentTime) {
19615
+ this.ended = 0;
18786
19616
  this.moved = true;
18787
19617
  if (!seeking) {
18788
19618
  this.nudgeRetry = 0;
@@ -18791,7 +19621,7 @@
18791
19621
  // The playhead is now moving, but was previously stalled
18792
19622
  if (this.stallReported) {
18793
19623
  var _stalledDuration = self.performance.now() - stalled;
18794
- 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");
18795
19625
  this.stallReported = false;
18796
19626
  }
18797
19627
  this.stalled = null;
@@ -18827,7 +19657,6 @@
18827
19657
  // Skip start gaps if we haven't played, but the last poll detected the start of a stall
18828
19658
  // The addition poll gives the browser a chance to jump the gap for us
18829
19659
  if (!this.moved && this.stalled !== null) {
18830
- var _level$details;
18831
19660
  // There is no playable buffer (seeked, waiting for buffer)
18832
19661
  var isBuffered = bufferInfo.len > 0;
18833
19662
  if (!isBuffered && !nextStart) {
@@ -18839,9 +19668,8 @@
18839
19668
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
18840
19669
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
18841
19670
  // that begins over 1 target duration after the video start position.
18842
- var level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
18843
- var isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
18844
- 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;
18845
19673
  var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
18846
19674
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
18847
19675
  if (!media.paused) {
@@ -18859,6 +19687,17 @@
18859
19687
  }
18860
19688
  var stalledDuration = tnow - stalled;
18861
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
+ }
18862
19701
  // Report stalling after trying to fix
18863
19702
  this._reportStall(bufferInfo);
18864
19703
  if (!this.media) {
@@ -18900,7 +19739,7 @@
18900
19739
  // needs to cross some sort of threshold covering all source-buffers content
18901
19740
  // to start playing properly.
18902
19741
  if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
18903
- logger.warn('Trying to nudge playhead over buffer-hole');
19742
+ this.warn('Trying to nudge playhead over buffer-hole');
18904
19743
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
18905
19744
  // We only try to jump the hole if it's under the configured size
18906
19745
  // Reset stalled so to rearm watchdog timer
@@ -18922,7 +19761,7 @@
18922
19761
  // Report stalled error once
18923
19762
  this.stallReported = true;
18924
19763
  var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
18925
- logger.warn(error.message);
19764
+ this.warn(error.message);
18926
19765
  hls.trigger(Events.ERROR, {
18927
19766
  type: ErrorTypes.MEDIA_ERROR,
18928
19767
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -18986,7 +19825,7 @@
18986
19825
  }
18987
19826
  }
18988
19827
  var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
18989
- logger.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
19828
+ this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
18990
19829
  this.moved = true;
18991
19830
  this.stalled = null;
18992
19831
  media.currentTime = targetTime;
@@ -19025,7 +19864,7 @@
19025
19864
  var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
19026
19865
  // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
19027
19866
  var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
19028
- logger.warn(error.message);
19867
+ this.warn(error.message);
19029
19868
  media.currentTime = targetTime;
19030
19869
  hls.trigger(Events.ERROR, {
19031
19870
  type: ErrorTypes.MEDIA_ERROR,
@@ -19035,7 +19874,7 @@
19035
19874
  });
19036
19875
  } else {
19037
19876
  var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
19038
- logger.error(_error.message);
19877
+ this.error(_error.message);
19039
19878
  hls.trigger(Events.ERROR, {
19040
19879
  type: ErrorTypes.MEDIA_ERROR,
19041
19880
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -19045,14 +19884,14 @@
19045
19884
  }
19046
19885
  };
19047
19886
  return GapController;
19048
- }();
19887
+ }(Logger);
19049
19888
 
19050
19889
  var TICK_INTERVAL = 100; // how often to tick in ms
19051
19890
  var StreamController = /*#__PURE__*/function (_BaseStreamController) {
19052
19891
  _inheritsLoose(StreamController, _BaseStreamController);
19053
19892
  function StreamController(hls, fragmentTracker, keyLoader) {
19054
19893
  var _this;
19055
- _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;
19056
19895
  _this.audioCodecSwap = false;
19057
19896
  _this.gapController = null;
19058
19897
  _this.level = -1;
@@ -19060,27 +19899,43 @@
19060
19899
  _this.altAudio = false;
19061
19900
  _this.audioOnly = false;
19062
19901
  _this.fragPlaying = null;
19063
- _this.onvplaying = null;
19064
- _this.onvseeked = null;
19065
19902
  _this.fragLastKbps = 0;
19066
19903
  _this.couldBacktrack = false;
19067
19904
  _this.backtrackFragment = null;
19068
19905
  _this.audioCodecSwitch = false;
19069
19906
  _this.videoBuffer = null;
19070
- _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();
19071
19929
  return _this;
19072
19930
  }
19073
19931
  var _proto = StreamController.prototype;
19074
- _proto._registerListeners = function _registerListeners() {
19932
+ _proto.registerListeners = function registerListeners() {
19933
+ _BaseStreamController.prototype.registerListeners.call(this);
19075
19934
  var hls = this.hls;
19076
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19077
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19078
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19079
19935
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19080
19936
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
19081
19937
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19082
19938
  hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19083
- hls.on(Events.ERROR, this.onError, this);
19084
19939
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19085
19940
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19086
19941
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19088,15 +19943,12 @@
19088
19943
  hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
19089
19944
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19090
19945
  };
19091
- _proto._unregisterListeners = function _unregisterListeners() {
19946
+ _proto.unregisterListeners = function unregisterListeners() {
19947
+ _BaseStreamController.prototype.unregisterListeners.call(this);
19092
19948
  var hls = this.hls;
19093
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
19094
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
19095
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
19096
19949
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
19097
19950
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
19098
19951
  hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
19099
- hls.off(Events.ERROR, this.onError, this);
19100
19952
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
19101
19953
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
19102
19954
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -19105,7 +19957,9 @@
19105
19957
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
19106
19958
  };
19107
19959
  _proto.onHandlerDestroying = function onHandlerDestroying() {
19108
- this._unregisterListeners();
19960
+ // @ts-ignore
19961
+ this.onMediaPlaying = this.onMediaSeeked = null;
19962
+ this.unregisterListeners();
19109
19963
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
19110
19964
  };
19111
19965
  _proto.startLoad = function startLoad(startPosition) {
@@ -19215,7 +20069,7 @@
19215
20069
  if (this.altAudio && this.audioOnly) {
19216
20070
  return;
19217
20071
  }
19218
- if (!(levels != null && levels[level])) {
20072
+ if (!this.buffering || !(levels != null && levels[level])) {
19219
20073
  return;
19220
20074
  }
19221
20075
  var levelInfo = levels[level];
@@ -19421,18 +20275,15 @@
19421
20275
  _proto.onMediaAttached = function onMediaAttached(event, data) {
19422
20276
  _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
19423
20277
  var media = data.media;
19424
- this.onvplaying = this.onMediaPlaying.bind(this);
19425
- this.onvseeked = this.onMediaSeeked.bind(this);
19426
- media.addEventListener('playing', this.onvplaying);
19427
- media.addEventListener('seeked', this.onvseeked);
20278
+ media.addEventListener('playing', this.onMediaPlaying);
20279
+ media.addEventListener('seeked', this.onMediaSeeked);
19428
20280
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
19429
20281
  };
19430
20282
  _proto.onMediaDetaching = function onMediaDetaching() {
19431
20283
  var media = this.media;
19432
- if (media && this.onvplaying && this.onvseeked) {
19433
- media.removeEventListener('playing', this.onvplaying);
19434
- media.removeEventListener('seeked', this.onvseeked);
19435
- this.onvplaying = this.onvseeked = null;
20284
+ if (media) {
20285
+ media.removeEventListener('playing', this.onMediaPlaying);
20286
+ media.removeEventListener('seeked', this.onMediaSeeked);
19436
20287
  this.videoBuffer = null;
19437
20288
  }
19438
20289
  this.fragPlaying = null;
@@ -19442,27 +20293,6 @@
19442
20293
  }
19443
20294
  _BaseStreamController.prototype.onMediaDetaching.call(this);
19444
20295
  };
19445
- _proto.onMediaPlaying = function onMediaPlaying() {
19446
- // tick to speed up FRAG_CHANGED triggering
19447
- this.tick();
19448
- };
19449
- _proto.onMediaSeeked = function onMediaSeeked() {
19450
- var media = this.media;
19451
- var currentTime = media ? media.currentTime : null;
19452
- if (isFiniteNumber(currentTime)) {
19453
- this.log("Media seeked to " + currentTime.toFixed(3));
19454
- }
19455
-
19456
- // If seeked was issued before buffer was appended do not tick immediately
19457
- var bufferInfo = this.getMainFwdBufferInfo();
19458
- if (bufferInfo === null || bufferInfo.len === 0) {
19459
- this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
19460
- return;
19461
- }
19462
-
19463
- // tick to speed up FRAG_CHANGED triggering
19464
- this.tick();
19465
- };
19466
20296
  _proto.onManifestLoading = function onManifestLoading() {
19467
20297
  // reset buffer on manifest loading
19468
20298
  this.log('Trigger BUFFER_RESET');
@@ -19743,8 +20573,10 @@
19743
20573
  }
19744
20574
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
19745
20575
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
19746
- var activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
19747
- 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);
19748
20580
  }
19749
20581
  this.lastCurrentTime = media.currentTime;
19750
20582
  };
@@ -20209,9 +21041,12 @@
20209
21041
  * The configuration object provided on player instantiation.
20210
21042
  */
20211
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;
20212
21048
  this.coreComponents = void 0;
20213
21049
  this.networkControllers = void 0;
20214
- this.started = false;
20215
21050
  this._emitter = new EventEmitter();
20216
21051
  this._autoLevelCapping = -1;
20217
21052
  this._maxHdcpLevel = null;
@@ -20228,11 +21063,11 @@
20228
21063
  this._media = null;
20229
21064
  this.url = null;
20230
21065
  this.triggeringException = void 0;
20231
- enableLogs(userConfig.debug || false, 'Hls instance');
20232
- 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);
20233
21068
  this.userConfig = userConfig;
20234
21069
  if (config.progressive) {
20235
- enableStreamingMode(config);
21070
+ enableStreamingMode(config, logger);
20236
21071
  }
20237
21072
 
20238
21073
  // core controllers and network loaders
@@ -20340,7 +21175,7 @@
20340
21175
  try {
20341
21176
  return this.emit(event, event, eventObject);
20342
21177
  } catch (error) {
20343
- 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);
20344
21179
  // Prevent recursion in error event handlers that throw #5497
20345
21180
  if (!this.triggeringException) {
20346
21181
  this.triggeringException = true;
@@ -20366,7 +21201,7 @@
20366
21201
  * Dispose of the instance
20367
21202
  */;
20368
21203
  _proto.destroy = function destroy() {
20369
- logger.log('destroy');
21204
+ this.logger.log('destroy');
20370
21205
  this.trigger(Events.DESTROYING, undefined);
20371
21206
  this.detachMedia();
20372
21207
  this.removeAllListeners();
@@ -20391,7 +21226,7 @@
20391
21226
  * Attaches Hls.js to a media element
20392
21227
  */;
20393
21228
  _proto.attachMedia = function attachMedia(media) {
20394
- logger.log('attachMedia');
21229
+ this.logger.log('attachMedia');
20395
21230
  this._media = media;
20396
21231
  this.trigger(Events.MEDIA_ATTACHING, {
20397
21232
  media: media
@@ -20402,7 +21237,7 @@
20402
21237
  * Detach Hls.js from the media
20403
21238
  */;
20404
21239
  _proto.detachMedia = function detachMedia() {
20405
- logger.log('detachMedia');
21240
+ this.logger.log('detachMedia');
20406
21241
  this.trigger(Events.MEDIA_DETACHING, undefined);
20407
21242
  this._media = null;
20408
21243
  }
@@ -20419,7 +21254,7 @@
20419
21254
  });
20420
21255
  this._autoLevelCapping = -1;
20421
21256
  this._maxHdcpLevel = null;
20422
- logger.log("loadSource:" + loadingSource);
21257
+ this.logger.log("loadSource:" + loadingSource);
20423
21258
  if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
20424
21259
  this.detachMedia();
20425
21260
  this.attachMedia(media);
@@ -20441,8 +21276,7 @@
20441
21276
  if (startPosition === void 0) {
20442
21277
  startPosition = -1;
20443
21278
  }
20444
- logger.log("startLoad(" + startPosition + ")");
20445
- this.started = true;
21279
+ this.logger.log("startLoad(" + startPosition + ")");
20446
21280
  this.networkControllers.forEach(function (controller) {
20447
21281
  controller.startLoad(startPosition);
20448
21282
  });
@@ -20452,34 +21286,31 @@
20452
21286
  * Stop loading of any stream data.
20453
21287
  */;
20454
21288
  _proto.stopLoad = function stopLoad() {
20455
- logger.log('stopLoad');
20456
- this.started = false;
21289
+ this.logger.log('stopLoad');
20457
21290
  this.networkControllers.forEach(function (controller) {
20458
21291
  controller.stopLoad();
20459
21292
  });
20460
21293
  }
20461
21294
 
20462
21295
  /**
20463
- * Resumes stream controller segment loading if previously started.
21296
+ * Resumes stream controller segment loading after `pauseBuffering` has been called.
20464
21297
  */;
20465
21298
  _proto.resumeBuffering = function resumeBuffering() {
20466
- if (this.started) {
20467
- this.networkControllers.forEach(function (controller) {
20468
- if ('fragmentLoader' in controller) {
20469
- controller.startLoad(-1);
20470
- }
20471
- });
20472
- }
21299
+ this.networkControllers.forEach(function (controller) {
21300
+ if (controller.resumeBuffering) {
21301
+ controller.resumeBuffering();
21302
+ }
21303
+ });
20473
21304
  }
20474
21305
 
20475
21306
  /**
20476
- * Stops stream controller segment loading without changing 'started' state like stopLoad().
21307
+ * Prevents stream controller from loading new segments until `resumeBuffering` is called.
20477
21308
  * This allows for media buffering to be paused without interupting playlist loading.
20478
21309
  */;
20479
21310
  _proto.pauseBuffering = function pauseBuffering() {
20480
21311
  this.networkControllers.forEach(function (controller) {
20481
- if ('fragmentLoader' in controller) {
20482
- controller.stopLoad();
21312
+ if (controller.pauseBuffering) {
21313
+ controller.pauseBuffering();
20483
21314
  }
20484
21315
  });
20485
21316
  }
@@ -20488,7 +21319,7 @@
20488
21319
  * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
20489
21320
  */;
20490
21321
  _proto.swapAudioCodec = function swapAudioCodec() {
20491
- logger.log('swapAudioCodec');
21322
+ this.logger.log('swapAudioCodec');
20492
21323
  this.streamController.swapAudioCodec();
20493
21324
  }
20494
21325
 
@@ -20499,7 +21330,7 @@
20499
21330
  * Automatic recovery of media-errors by this process is configurable.
20500
21331
  */;
20501
21332
  _proto.recoverMediaError = function recoverMediaError() {
20502
- logger.log('recoverMediaError');
21333
+ this.logger.log('recoverMediaError');
20503
21334
  var media = this._media;
20504
21335
  this.detachMedia();
20505
21336
  if (media) {
@@ -20554,7 +21385,7 @@
20554
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.
20555
21386
  */,
20556
21387
  set: function set(newLevel) {
20557
- logger.log("set currentLevel:" + newLevel);
21388
+ this.logger.log("set currentLevel:" + newLevel);
20558
21389
  this.levelController.manualLevel = newLevel;
20559
21390
  this.streamController.immediateLevelSwitch();
20560
21391
  }
@@ -20575,7 +21406,7 @@
20575
21406
  * @param newLevel - Pass -1 for automatic level selection
20576
21407
  */,
20577
21408
  set: function set(newLevel) {
20578
- logger.log("set nextLevel:" + newLevel);
21409
+ this.logger.log("set nextLevel:" + newLevel);
20579
21410
  this.levelController.manualLevel = newLevel;
20580
21411
  this.streamController.nextLevelSwitch();
20581
21412
  }
@@ -20596,7 +21427,7 @@
20596
21427
  * @param newLevel - Pass -1 for automatic level selection
20597
21428
  */,
20598
21429
  set: function set(newLevel) {
20599
- logger.log("set loadLevel:" + newLevel);
21430
+ this.logger.log("set loadLevel:" + newLevel);
20600
21431
  this.levelController.manualLevel = newLevel;
20601
21432
  }
20602
21433
 
@@ -20631,7 +21462,7 @@
20631
21462
  * Sets "first-level", see getter.
20632
21463
  */,
20633
21464
  set: function set(newLevel) {
20634
- logger.log("set firstLevel:" + newLevel);
21465
+ this.logger.log("set firstLevel:" + newLevel);
20635
21466
  this.levelController.firstLevel = newLevel;
20636
21467
  }
20637
21468
 
@@ -20658,7 +21489,7 @@
20658
21489
  * (determined from download of first segment)
20659
21490
  */,
20660
21491
  set: function set(newLevel) {
20661
- logger.log("set startLevel:" + newLevel);
21492
+ this.logger.log("set startLevel:" + newLevel);
20662
21493
  // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
20663
21494
  if (newLevel !== -1) {
20664
21495
  newLevel = Math.max(newLevel, this.minAutoLevel);
@@ -20711,7 +21542,7 @@
20711
21542
  */
20712
21543
  function set(newLevel) {
20713
21544
  if (this._autoLevelCapping !== newLevel) {
20714
- logger.log("set autoLevelCapping:" + newLevel);
21545
+ this.logger.log("set autoLevelCapping:" + newLevel);
20715
21546
  this._autoLevelCapping = newLevel;
20716
21547
  this.levelController.checkMaxAutoUpdated();
20717
21548
  }
@@ -21036,7 +21867,7 @@
21036
21867
  * Get the video-dev/hls.js package version.
21037
21868
  */
21038
21869
  function get() {
21039
- return "1.5.4";
21870
+ return "1.5.5-0.canary.9977";
21040
21871
  }
21041
21872
  }, {
21042
21873
  key: "Events",