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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +1 -0
  2. package/dist/hls-demo.js +10 -0
  3. package/dist/hls-demo.js.map +1 -1
  4. package/dist/hls.js +1954 -1103
  5. package/dist/hls.js.d.ts +63 -50
  6. package/dist/hls.js.map +1 -1
  7. package/dist/hls.light.js +1631 -784
  8. package/dist/hls.light.js.map +1 -1
  9. package/dist/hls.light.min.js +1 -1
  10. package/dist/hls.light.min.js.map +1 -1
  11. package/dist/hls.light.mjs +1428 -590
  12. package/dist/hls.light.mjs.map +1 -1
  13. package/dist/hls.min.js +1 -1
  14. package/dist/hls.min.js.map +1 -1
  15. package/dist/hls.mjs +1703 -866
  16. package/dist/hls.mjs.map +1 -1
  17. package/dist/hls.worker.js +1 -1
  18. package/dist/hls.worker.js.map +1 -1
  19. package/package.json +18 -18
  20. package/src/config.ts +3 -2
  21. package/src/controller/abr-controller.ts +24 -22
  22. package/src/controller/audio-stream-controller.ts +16 -17
  23. package/src/controller/audio-track-controller.ts +1 -1
  24. package/src/controller/base-playlist-controller.ts +7 -7
  25. package/src/controller/base-stream-controller.ts +56 -29
  26. package/src/controller/buffer-controller.ts +11 -11
  27. package/src/controller/cap-level-controller.ts +1 -2
  28. package/src/controller/cmcd-controller.ts +25 -3
  29. package/src/controller/content-steering-controller.ts +8 -6
  30. package/src/controller/eme-controller.ts +9 -22
  31. package/src/controller/error-controller.ts +6 -8
  32. package/src/controller/fps-controller.ts +2 -3
  33. package/src/controller/gap-controller.ts +43 -16
  34. package/src/controller/latency-controller.ts +9 -11
  35. package/src/controller/level-controller.ts +5 -17
  36. package/src/controller/stream-controller.ts +27 -33
  37. package/src/controller/subtitle-stream-controller.ts +14 -15
  38. package/src/controller/subtitle-track-controller.ts +5 -3
  39. package/src/controller/timeline-controller.ts +23 -30
  40. package/src/crypt/aes-crypto.ts +21 -2
  41. package/src/crypt/decrypter-aes-mode.ts +4 -0
  42. package/src/crypt/decrypter.ts +32 -18
  43. package/src/crypt/fast-aes-key.ts +24 -5
  44. package/src/demux/audio/adts.ts +9 -4
  45. package/src/demux/sample-aes.ts +2 -0
  46. package/src/demux/transmuxer-interface.ts +4 -12
  47. package/src/demux/transmuxer-worker.ts +4 -4
  48. package/src/demux/transmuxer.ts +16 -3
  49. package/src/demux/tsdemuxer.ts +63 -37
  50. package/src/demux/video/avc-video-parser.ts +208 -119
  51. package/src/demux/video/base-video-parser.ts +134 -2
  52. package/src/demux/video/exp-golomb.ts +0 -208
  53. package/src/demux/video/hevc-video-parser.ts +746 -0
  54. package/src/events.ts +7 -0
  55. package/src/hls.ts +42 -34
  56. package/src/loader/fragment-loader.ts +9 -2
  57. package/src/loader/key-loader.ts +2 -0
  58. package/src/loader/level-key.ts +10 -9
  59. package/src/remux/mp4-generator.ts +196 -1
  60. package/src/remux/mp4-remuxer.ts +23 -7
  61. package/src/task-loop.ts +5 -2
  62. package/src/types/component-api.ts +2 -0
  63. package/src/types/demuxer.ts +3 -0
  64. package/src/types/events.ts +4 -0
  65. package/src/utils/codecs.ts +33 -4
  66. package/src/utils/encryption-methods-util.ts +21 -0
  67. package/src/utils/logger.ts +53 -24
  68. package/src/utils/mp4-tools.ts +28 -9
package/dist/hls.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;
@@ -394,6 +383,7 @@
394
383
  Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
395
384
  Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
396
385
  Events["MEDIA_DETACHED"] = "hlsMediaDetached";
386
+ Events["MEDIA_ENDED"] = "hlsMediaEnded";
397
387
  Events["BUFFER_RESET"] = "hlsBufferReset";
398
388
  Events["BUFFER_CODECS"] = "hlsBufferCodecs";
399
389
  Events["BUFFER_CREATED"] = "hlsBufferCreated";
@@ -507,6 +497,21 @@
507
497
  return ErrorDetails;
508
498
  }({});
509
499
 
500
+ var Logger = function Logger(label, logger) {
501
+ this.trace = void 0;
502
+ this.debug = void 0;
503
+ this.log = void 0;
504
+ this.warn = void 0;
505
+ this.info = void 0;
506
+ this.error = void 0;
507
+ var lb = "[" + label + "]:";
508
+ this.trace = noop;
509
+ this.debug = logger.debug.bind(null, lb);
510
+ this.log = logger.log.bind(null, lb);
511
+ this.warn = logger.warn.bind(null, lb);
512
+ this.info = logger.info.bind(null, lb);
513
+ this.error = logger.error.bind(null, lb);
514
+ };
510
515
  var noop = function noop() {};
511
516
  var fakeLogger = {
512
517
  trace: noop,
@@ -516,7 +521,9 @@
516
521
  info: noop,
517
522
  error: noop
518
523
  };
519
- var exportedLogger = fakeLogger;
524
+ function createLogger() {
525
+ return _extends({}, fakeLogger);
526
+ }
520
527
 
521
528
  // let lastCallTime;
522
529
  // function formatMsgWithTimeInfo(type, msg) {
@@ -527,38 +534,36 @@
527
534
  // return msg;
528
535
  // }
529
536
 
530
- function consolePrintFn(type) {
537
+ function consolePrintFn(type, id) {
531
538
  var func = self.console[type];
532
- if (func) {
533
- return func.bind(self.console, "[" + type + "] >");
534
- }
535
- return noop;
539
+ return func ? func.bind(self.console, (id ? '[' + id + '] ' : '') + "[" + type + "] >") : noop;
536
540
  }
537
- function exportLoggerFunctions(debugConfig) {
538
- for (var _len = arguments.length, functions = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
539
- functions[_key - 1] = arguments[_key];
540
- }
541
- functions.forEach(function (type) {
542
- exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
543
- });
541
+ function getLoggerFn(key, debugConfig, id) {
542
+ return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
544
543
  }
545
- function enableLogs(debugConfig, id) {
544
+ var exportedLogger = createLogger();
545
+ function enableLogs(debugConfig, context, id) {
546
546
  // check that console is available
547
+ var newLogger = createLogger();
547
548
  if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
548
- exportLoggerFunctions(debugConfig,
549
+ var keys = [
549
550
  // Remove out from list here to hard-disable a log-level
550
551
  // 'trace',
551
- 'debug', 'log', 'info', 'warn', 'error');
552
+ 'debug', 'log', 'info', 'warn', 'error'];
553
+ keys.forEach(function (key) {
554
+ newLogger[key] = getLoggerFn(key, debugConfig, id);
555
+ });
552
556
  // Some browsers don't allow to use bind on console object anyway
553
557
  // fallback to default if needed
554
558
  try {
555
- exportedLogger.log("Debug logs enabled for \"" + id + "\" in hls.js version " + "1.5.3");
559
+ newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.5-0.canary.9977");
556
560
  } catch (e) {
557
- exportedLogger = fakeLogger;
561
+ /* log fn threw an exception. All logger methods are no-ops. */
562
+ return createLogger();
558
563
  }
559
- } else {
560
- exportedLogger = fakeLogger;
561
564
  }
565
+ exportedLogger = newLogger;
566
+ return newLogger;
562
567
  }
563
568
  var logger = exportedLogger;
564
569
 
@@ -1253,6 +1258,26 @@
1253
1258
  });
1254
1259
  }
1255
1260
 
1261
+ var DecrypterAesMode = {
1262
+ cbc: 0,
1263
+ ctr: 1
1264
+ };
1265
+
1266
+ function isFullSegmentEncryption(method) {
1267
+ return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
1268
+ }
1269
+ function getAesModeFromFullSegmentMethod(method) {
1270
+ switch (method) {
1271
+ case 'AES-128':
1272
+ case 'AES-256':
1273
+ return DecrypterAesMode.cbc;
1274
+ case 'AES-256-CTR':
1275
+ return DecrypterAesMode.ctr;
1276
+ default:
1277
+ throw new Error("invalid full segment method " + method);
1278
+ }
1279
+ }
1280
+
1256
1281
  /** returns `undefined` is `self` is missing, e.g. in node */
1257
1282
  var optionalSelf = typeof self !== 'undefined' ? self : undefined;
1258
1283
 
@@ -1774,6 +1799,12 @@
1774
1799
  var val = readSint32(buffer, offset);
1775
1800
  return val < 0 ? 4294967296 + val : val;
1776
1801
  }
1802
+ function readUint64(buffer, offset) {
1803
+ var result = readUint32(buffer, offset);
1804
+ result *= Math.pow(2, 32);
1805
+ result += readUint32(buffer, offset + 4);
1806
+ return result;
1807
+ }
1777
1808
  function readSint32(buffer, offset) {
1778
1809
  return buffer[offset] << 24 | buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3];
1779
1810
  }
@@ -1836,15 +1867,14 @@
1836
1867
  var index = 8;
1837
1868
  var timescale = readUint32(sidx, index);
1838
1869
  index += 4;
1839
-
1840
- // TODO: parse earliestPresentationTime and firstOffset
1841
- // usually zero in our case
1842
1870
  var earliestPresentationTime = 0;
1843
1871
  var firstOffset = 0;
1844
1872
  if (version === 0) {
1845
- index += 8;
1873
+ earliestPresentationTime = readUint32(sidx, index += 4);
1874
+ firstOffset = readUint32(sidx, index += 4);
1846
1875
  } else {
1847
- index += 16;
1876
+ earliestPresentationTime = readUint64(sidx, index += 8);
1877
+ firstOffset = readUint64(sidx, index += 8);
1848
1878
  }
1849
1879
 
1850
1880
  // skip reserved
@@ -2294,17 +2324,24 @@
2294
2324
  }
2295
2325
  if (videoDuration === 0 && audioDuration === 0) {
2296
2326
  // If duration samples are not available in the traf use sidx subsegment_duration
2327
+ var sidxMinStart = Infinity;
2328
+ var sidxMaxEnd = 0;
2297
2329
  var sidxDuration = 0;
2298
2330
  var sidxs = findBox(data, ['sidx']);
2299
2331
  for (var _i2 = 0; _i2 < sidxs.length; _i2++) {
2300
2332
  var sidx = parseSegmentIndex(sidxs[_i2]);
2301
2333
  if (sidx != null && sidx.references) {
2302
- sidxDuration += sidx.references.reduce(function (dur, ref) {
2334
+ sidxMinStart = Math.min(sidxMinStart, sidx.earliestPresentationTime / sidx.timescale);
2335
+ var subSegmentDuration = sidx.references.reduce(function (dur, ref) {
2303
2336
  return dur + ref.info.duration || 0;
2304
2337
  }, 0);
2338
+ sidxMaxEnd = Math.max(sidxMaxEnd, subSegmentDuration + sidx.earliestPresentationTime / sidx.timescale);
2339
+ sidxDuration = sidxMaxEnd - sidxMinStart;
2305
2340
  }
2306
2341
  }
2307
- return sidxDuration;
2342
+ if (sidxDuration && isFiniteNumber(sidxDuration)) {
2343
+ return sidxDuration;
2344
+ }
2308
2345
  }
2309
2346
  if (videoDuration) {
2310
2347
  return videoDuration;
@@ -2911,13 +2948,13 @@
2911
2948
  this.keyFormatVersions = formatversions;
2912
2949
  this.iv = iv;
2913
2950
  this.encrypted = method ? method !== 'NONE' : false;
2914
- this.isCommonEncryption = this.encrypted && method !== 'AES-128';
2951
+ this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
2915
2952
  }
2916
2953
  var _proto = LevelKey.prototype;
2917
2954
  _proto.isSupported = function isSupported() {
2918
2955
  // If it's Segment encryption or No encryption, just select that key system
2919
2956
  if (this.method) {
2920
- if (this.method === 'AES-128' || this.method === 'NONE') {
2957
+ if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
2921
2958
  return true;
2922
2959
  }
2923
2960
  if (this.keyFormat === 'identity') {
@@ -2939,14 +2976,13 @@
2939
2976
  if (!this.encrypted || !this.uri) {
2940
2977
  return null;
2941
2978
  }
2942
- if (this.method === 'AES-128' && this.uri && !this.iv) {
2979
+ if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
2943
2980
  if (typeof sn !== 'number') {
2944
2981
  // We are fetching decryption data for a initialization segment
2945
- // If the segment was encrypted with AES-128
2982
+ // If the segment was encrypted with AES-128/256
2946
2983
  // It must have an IV defined. We cannot substitute the Segment Number in.
2947
- if (this.method === 'AES-128' && !this.iv) {
2948
- logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2949
- }
2984
+ logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
2985
+
2950
2986
  // Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
2951
2987
  sn = 0;
2952
2988
  }
@@ -3240,23 +3276,28 @@
3240
3276
  if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
3241
3277
  return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
3242
3278
  }
3243
-
3244
- // Idealy fLaC and Opus would be first (spec-compliant) but
3245
- // some browsers will report that fLaC is supported then fail.
3246
- // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
3247
3279
  var codecsToCheck = {
3280
+ // Idealy fLaC and Opus would be first (spec-compliant) but
3281
+ // some browsers will report that fLaC is supported then fail.
3282
+ // see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
3248
3283
  flac: ['flac', 'fLaC', 'FLAC'],
3249
- opus: ['opus', 'Opus']
3284
+ opus: ['opus', 'Opus'],
3285
+ // Replace audio codec info if browser does not support mp4a.40.34,
3286
+ // and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
3287
+ 'mp4a.40.34': ['mp3']
3250
3288
  }[lowerCaseCodec];
3251
3289
  for (var i = 0; i < codecsToCheck.length; i++) {
3290
+ var _getMediaSource;
3252
3291
  if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
3253
3292
  CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
3254
3293
  return codecsToCheck[i];
3294
+ } else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
3295
+ return '';
3255
3296
  }
3256
3297
  }
3257
3298
  return lowerCaseCodec;
3258
3299
  }
3259
- var AUDIO_CODEC_REGEXP = /flac|opus/i;
3300
+ var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
3260
3301
  function getCodecCompatibleName(codec, preferManagedMediaSource) {
3261
3302
  if (preferManagedMediaSource === void 0) {
3262
3303
  preferManagedMediaSource = true;
@@ -3284,6 +3325,18 @@
3284
3325
  }
3285
3326
  return codec;
3286
3327
  }
3328
+ function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
3329
+ var MediaSource = getMediaSource(preferManagedMediaSource) || {
3330
+ isTypeSupported: function isTypeSupported() {
3331
+ return false;
3332
+ }
3333
+ };
3334
+ return {
3335
+ mpeg: MediaSource.isTypeSupported('audio/mpeg'),
3336
+ mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
3337
+ ac3: MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
3338
+ };
3339
+ }
3287
3340
 
3288
3341
  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;
3289
3342
  var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
@@ -4947,8 +5000,43 @@
4947
5000
  this.currentTime = 0;
4948
5001
  this.stallCount = 0;
4949
5002
  this._latency = null;
4950
- this.timeupdateHandler = function () {
4951
- return _this.timeupdate();
5003
+ this.onTimeupdate = function () {
5004
+ var media = _this.media,
5005
+ levelDetails = _this.levelDetails;
5006
+ if (!media || !levelDetails) {
5007
+ return;
5008
+ }
5009
+ _this.currentTime = media.currentTime;
5010
+ var latency = _this.computeLatency();
5011
+ if (latency === null) {
5012
+ return;
5013
+ }
5014
+ _this._latency = latency;
5015
+
5016
+ // Adapt playbackRate to meet target latency in low-latency mode
5017
+ var _this$config = _this.config,
5018
+ lowLatencyMode = _this$config.lowLatencyMode,
5019
+ maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
5020
+ if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
5021
+ return;
5022
+ }
5023
+ var targetLatency = _this.targetLatency;
5024
+ if (targetLatency === null) {
5025
+ return;
5026
+ }
5027
+ var distanceFromTarget = latency - targetLatency;
5028
+ // Only adjust playbackRate when within one target duration of targetLatency
5029
+ // and more than one second from under-buffering.
5030
+ // Playback further than one target duration from target can be considered DVR playback.
5031
+ var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
5032
+ var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
5033
+ if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
5034
+ var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
5035
+ var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
5036
+ media.playbackRate = Math.min(max, Math.max(1, rate));
5037
+ } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
5038
+ media.playbackRate = 1;
5039
+ }
4952
5040
  };
4953
5041
  this.hls = hls;
4954
5042
  this.config = hls.config;
@@ -4960,7 +5048,7 @@
4960
5048
  this.onMediaDetaching();
4961
5049
  this.levelDetails = null;
4962
5050
  // @ts-ignore
4963
- this.hls = this.timeupdateHandler = null;
5051
+ this.hls = null;
4964
5052
  };
4965
5053
  _proto.registerListeners = function registerListeners() {
4966
5054
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -4978,11 +5066,11 @@
4978
5066
  };
4979
5067
  _proto.onMediaAttached = function onMediaAttached(event, data) {
4980
5068
  this.media = data.media;
4981
- this.media.addEventListener('timeupdate', this.timeupdateHandler);
5069
+ this.media.addEventListener('timeupdate', this.onTimeupdate);
4982
5070
  };
4983
5071
  _proto.onMediaDetaching = function onMediaDetaching() {
4984
5072
  if (this.media) {
4985
- this.media.removeEventListener('timeupdate', this.timeupdateHandler);
5073
+ this.media.removeEventListener('timeupdate', this.onTimeupdate);
4986
5074
  this.media = null;
4987
5075
  }
4988
5076
  };
@@ -4995,10 +5083,10 @@
4995
5083
  var details = _ref.details;
4996
5084
  this.levelDetails = details;
4997
5085
  if (details.advanced) {
4998
- this.timeupdate();
5086
+ this.onTimeupdate();
4999
5087
  }
5000
5088
  if (!details.live && this.media) {
5001
- this.media.removeEventListener('timeupdate', this.timeupdateHandler);
5089
+ this.media.removeEventListener('timeupdate', this.onTimeupdate);
5002
5090
  }
5003
5091
  };
5004
5092
  _proto.onError = function onError(event, data) {
@@ -5008,45 +5096,7 @@
5008
5096
  }
5009
5097
  this.stallCount++;
5010
5098
  if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
5011
- logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
5012
- }
5013
- };
5014
- _proto.timeupdate = function timeupdate() {
5015
- var media = this.media,
5016
- levelDetails = this.levelDetails;
5017
- if (!media || !levelDetails) {
5018
- return;
5019
- }
5020
- this.currentTime = media.currentTime;
5021
- var latency = this.computeLatency();
5022
- if (latency === null) {
5023
- return;
5024
- }
5025
- this._latency = latency;
5026
-
5027
- // Adapt playbackRate to meet target latency in low-latency mode
5028
- var _this$config = this.config,
5029
- lowLatencyMode = _this$config.lowLatencyMode,
5030
- maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
5031
- if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
5032
- return;
5033
- }
5034
- var targetLatency = this.targetLatency;
5035
- if (targetLatency === null) {
5036
- return;
5037
- }
5038
- var distanceFromTarget = latency - targetLatency;
5039
- // Only adjust playbackRate when within one target duration of targetLatency
5040
- // and more than one second from under-buffering.
5041
- // Playback further than one target duration from target can be considered DVR playback.
5042
- var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
5043
- var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
5044
- if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
5045
- var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
5046
- var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
5047
- media.playbackRate = Math.min(max, Math.max(1, rate));
5048
- } else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
5049
- media.playbackRate = 1;
5099
+ this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
5050
5100
  }
5051
5101
  };
5052
5102
  _proto.estimateLiveEdge = function estimateLiveEdge() {
@@ -5954,19 +6004,17 @@
5954
6004
  MoveAllAlternatesMatchingHDCP: 2,
5955
6005
  SwitchToSDR: 4
5956
6006
  }; // Reserved for future use
5957
- var ErrorController = /*#__PURE__*/function () {
6007
+ var ErrorController = /*#__PURE__*/function (_Logger) {
6008
+ _inheritsLoose(ErrorController, _Logger);
5958
6009
  function ErrorController(hls) {
5959
- this.hls = void 0;
5960
- this.playlistError = 0;
5961
- this.penalizedRenditions = {};
5962
- this.log = void 0;
5963
- this.warn = void 0;
5964
- this.error = void 0;
5965
- this.hls = hls;
5966
- this.log = logger.log.bind(logger, "[info]:");
5967
- this.warn = logger.warn.bind(logger, "[warning]:");
5968
- this.error = logger.error.bind(logger, "[error]:");
5969
- this.registerListeners();
6010
+ var _this;
6011
+ _this = _Logger.call(this, 'error-controller', hls.logger) || this;
6012
+ _this.hls = void 0;
6013
+ _this.playlistError = 0;
6014
+ _this.penalizedRenditions = {};
6015
+ _this.hls = hls;
6016
+ _this.registerListeners();
6017
+ return _this;
5970
6018
  }
5971
6019
  var _proto = ErrorController.prototype;
5972
6020
  _proto.registerListeners = function registerListeners() {
@@ -6322,19 +6370,19 @@
6322
6370
  }
6323
6371
  };
6324
6372
  return ErrorController;
6325
- }();
6373
+ }(Logger);
6326
6374
 
6327
- var BasePlaylistController = /*#__PURE__*/function () {
6375
+ var BasePlaylistController = /*#__PURE__*/function (_Logger) {
6376
+ _inheritsLoose(BasePlaylistController, _Logger);
6328
6377
  function BasePlaylistController(hls, logPrefix) {
6329
- this.hls = void 0;
6330
- this.timer = -1;
6331
- this.requestScheduled = -1;
6332
- this.canLoad = false;
6333
- this.log = void 0;
6334
- this.warn = void 0;
6335
- this.log = logger.log.bind(logger, logPrefix + ":");
6336
- this.warn = logger.warn.bind(logger, logPrefix + ":");
6337
- this.hls = hls;
6378
+ var _this;
6379
+ _this = _Logger.call(this, logPrefix, hls.logger) || this;
6380
+ _this.hls = void 0;
6381
+ _this.timer = -1;
6382
+ _this.requestScheduled = -1;
6383
+ _this.canLoad = false;
6384
+ _this.hls = hls;
6385
+ return _this;
6338
6386
  }
6339
6387
  var _proto = BasePlaylistController.prototype;
6340
6388
  _proto.destroy = function destroy() {
@@ -6367,7 +6415,7 @@
6367
6415
  try {
6368
6416
  uri = new self.URL(attr.URI, previous.url).href;
6369
6417
  } catch (error) {
6370
- logger.warn("Could not construct new URL for Rendition Report: " + error);
6418
+ this.warn("Could not construct new URL for Rendition Report: " + error);
6371
6419
  uri = attr.URI || '';
6372
6420
  }
6373
6421
  // Use exact match. Otherwise, the last partial match, if any, will be used
@@ -6406,7 +6454,7 @@
6406
6454
  return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
6407
6455
  };
6408
6456
  _proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
6409
- var _this = this;
6457
+ var _this2 = this;
6410
6458
  var details = data.details,
6411
6459
  stats = data.stats;
6412
6460
 
@@ -6511,7 +6559,7 @@
6511
6559
  // );
6512
6560
 
6513
6561
  this.timer = self.setTimeout(function () {
6514
- return _this.loadPlaylist(deliveryDirectives);
6562
+ return _this2.loadPlaylist(deliveryDirectives);
6515
6563
  }, estimatedTimeUntilUpdate);
6516
6564
  } else {
6517
6565
  this.clearTimer();
@@ -6527,7 +6575,7 @@
6527
6575
  return new HlsUrlParameters(msn, part, skip);
6528
6576
  };
6529
6577
  _proto.checkRetry = function checkRetry(errorEvent) {
6530
- var _this2 = this;
6578
+ var _this3 = this;
6531
6579
  var errorDetails = errorEvent.details;
6532
6580
  var isTimeout = isTimeoutError(errorEvent);
6533
6581
  var errorAction = errorEvent.errorAction;
@@ -6551,7 +6599,7 @@
6551
6599
  var delay = getRetryDelay(retryConfig, retryCount);
6552
6600
  // Schedule level/track reload
6553
6601
  this.timer = self.setTimeout(function () {
6554
- return _this2.loadPlaylist();
6602
+ return _this3.loadPlaylist();
6555
6603
  }, delay);
6556
6604
  this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
6557
6605
  }
@@ -6562,7 +6610,7 @@
6562
6610
  return retry;
6563
6611
  };
6564
6612
  return BasePlaylistController;
6565
- }();
6613
+ }(Logger);
6566
6614
 
6567
6615
  /*
6568
6616
  * compute an Exponential Weighted moving average
@@ -7164,30 +7212,33 @@
7164
7212
  return -1;
7165
7213
  }
7166
7214
 
7167
- var AbrController = /*#__PURE__*/function () {
7215
+ var AbrController = /*#__PURE__*/function (_Logger) {
7216
+ _inheritsLoose(AbrController, _Logger);
7168
7217
  function AbrController(_hls) {
7169
- var _this = this;
7170
- this.hls = void 0;
7171
- this.lastLevelLoadSec = 0;
7172
- this.lastLoadedFragLevel = -1;
7173
- this.firstSelection = -1;
7174
- this._nextAutoLevel = -1;
7175
- this.nextAutoLevelKey = '';
7176
- this.audioTracksByGroup = null;
7177
- this.codecTiers = null;
7178
- this.timer = -1;
7179
- this.fragCurrent = null;
7180
- this.partCurrent = null;
7181
- this.bitrateTestDelay = 0;
7182
- this.bwEstimator = void 0;
7218
+ var _this;
7219
+ _this = _Logger.call(this, 'abr', _hls.logger) || this;
7220
+ _this.hls = void 0;
7221
+ _this.lastLevelLoadSec = 0;
7222
+ _this.lastLoadedFragLevel = -1;
7223
+ _this.firstSelection = -1;
7224
+ _this._nextAutoLevel = -1;
7225
+ _this.nextAutoLevelKey = '';
7226
+ _this.audioTracksByGroup = null;
7227
+ _this.codecTiers = null;
7228
+ _this.timer = -1;
7229
+ _this.fragCurrent = null;
7230
+ _this.partCurrent = null;
7231
+ _this.bitrateTestDelay = 0;
7232
+ _this.bwEstimator = void 0;
7183
7233
  /*
7184
7234
  This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
7185
7235
  quickly enough to prevent underbuffering
7186
7236
  */
7187
- this._abandonRulesCheck = function () {
7188
- var frag = _this.fragCurrent,
7189
- part = _this.partCurrent,
7190
- hls = _this.hls;
7237
+ _this._abandonRulesCheck = function () {
7238
+ var _assertThisInitialize = _assertThisInitialized(_this),
7239
+ frag = _assertThisInitialize.fragCurrent,
7240
+ part = _assertThisInitialize.partCurrent,
7241
+ hls = _assertThisInitialize.hls;
7191
7242
  var autoLevelEnabled = hls.autoLevelEnabled,
7192
7243
  media = hls.media;
7193
7244
  if (!frag || !media) {
@@ -7276,21 +7327,22 @@
7276
7327
  _this.resetEstimator(nextLoadLevelBitrate);
7277
7328
  }
7278
7329
  _this.clearTimer();
7279
- 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");
7330
+ _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");
7280
7331
  hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
7281
7332
  frag: frag,
7282
7333
  part: part,
7283
7334
  stats: stats
7284
7335
  });
7285
7336
  };
7286
- this.hls = _hls;
7287
- this.bwEstimator = this.initEstimator();
7288
- this.registerListeners();
7337
+ _this.hls = _hls;
7338
+ _this.bwEstimator = _this.initEstimator();
7339
+ _this.registerListeners();
7340
+ return _this;
7289
7341
  }
7290
7342
  var _proto = AbrController.prototype;
7291
7343
  _proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
7292
7344
  if (abrEwmaDefaultEstimate) {
7293
- logger.log("setting initial bwe to " + abrEwmaDefaultEstimate);
7345
+ this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
7294
7346
  this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
7295
7347
  }
7296
7348
  this.firstSelection = -1;
@@ -7542,13 +7594,13 @@
7542
7594
  // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
7543
7595
  var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
7544
7596
  maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
7545
- logger.info("[abr] bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
7597
+ this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
7546
7598
  // don't use conservative factor on bitrate test
7547
7599
  bwFactor = bwUpFactor = 1;
7548
7600
  }
7549
7601
  }
7550
7602
  var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
7551
- logger.info("[abr] " + (bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
7603
+ this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
7552
7604
  if (bestLevel > -1) {
7553
7605
  return bestLevel;
7554
7606
  }
@@ -7604,7 +7656,7 @@
7604
7656
  currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
7605
7657
  currentFrameRate = minFramerate;
7606
7658
  currentBw = Math.max(currentBw, minBitrate);
7607
- logger.log("[abr] picked start tier " + JSON.stringify(startTier));
7659
+ this.log("picked start tier " + JSON.stringify(startTier));
7608
7660
  } else {
7609
7661
  currentCodecSet = level == null ? void 0 : level.codecSet;
7610
7662
  currentVideoRange = level == null ? void 0 : level.videoRange;
@@ -7628,11 +7680,11 @@
7628
7680
  var levels = _this2.hls.levels;
7629
7681
  var index = levels.indexOf(levelInfo);
7630
7682
  if (decodingInfo.error) {
7631
- logger.warn("[abr] MediaCapabilities decodingInfo error: \"" + decodingInfo.error + "\" for level " + index + " " + JSON.stringify(decodingInfo));
7683
+ _this2.warn("MediaCapabilities decodingInfo error: \"" + decodingInfo.error + "\" for level " + index + " " + JSON.stringify(decodingInfo));
7632
7684
  } else if (!decodingInfo.supported) {
7633
- logger.warn("[abr] Unsupported MediaCapabilities decodingInfo result for level " + index + " " + JSON.stringify(decodingInfo));
7685
+ _this2.warn("Unsupported MediaCapabilities decodingInfo result for level " + index + " " + JSON.stringify(decodingInfo));
7634
7686
  if (index > -1 && levels.length > 1) {
7635
- logger.log("[abr] Removing unsupported level " + index);
7687
+ _this2.log("Removing unsupported level " + index);
7636
7688
  _this2.hls.removeLevel(index);
7637
7689
  }
7638
7690
  }
@@ -7679,9 +7731,9 @@
7679
7731
  var forcedAutoLevel = _this2.forcedAutoLevel;
7680
7732
  if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
7681
7733
  if (levelsSkipped.length) {
7682
- 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);
7734
+ _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);
7683
7735
  }
7684
- 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);
7736
+ _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);
7685
7737
  }
7686
7738
  if (firstSelection) {
7687
7739
  _this2.firstSelection = i;
@@ -7715,7 +7767,7 @@
7715
7767
  }
7716
7768
  var firstLevel = this.hls.firstLevel;
7717
7769
  var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
7718
- logger.warn("[abr] Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
7770
+ this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
7719
7771
  return clamped;
7720
7772
  }
7721
7773
  }, {
@@ -7757,15 +7809,18 @@
7757
7809
  return nextABRAutoLevel;
7758
7810
  },
7759
7811
  set: function set(nextLevel) {
7760
- var value = Math.max(this.hls.minAutoLevel, nextLevel);
7761
- if (this._nextAutoLevel != value) {
7812
+ var _this$hls3 = this.hls,
7813
+ maxAutoLevel = _this$hls3.maxAutoLevel,
7814
+ minAutoLevel = _this$hls3.minAutoLevel;
7815
+ var value = Math.min(Math.max(nextLevel, minAutoLevel), maxAutoLevel);
7816
+ if (this._nextAutoLevel !== value) {
7762
7817
  this.nextAutoLevelKey = '';
7763
7818
  this._nextAutoLevel = value;
7764
7819
  }
7765
7820
  }
7766
7821
  }]);
7767
7822
  return AbrController;
7768
- }();
7823
+ }(Logger);
7769
7824
 
7770
7825
  /**
7771
7826
  * @ignore
@@ -7796,13 +7851,17 @@
7796
7851
  * we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
7797
7852
  * task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
7798
7853
  */
7799
- var TaskLoop = /*#__PURE__*/function () {
7800
- function TaskLoop() {
7801
- this._boundTick = void 0;
7802
- this._tickTimer = null;
7803
- this._tickInterval = null;
7804
- this._tickCallCount = 0;
7805
- this._boundTick = this.tick.bind(this);
7854
+ var TaskLoop = /*#__PURE__*/function (_Logger) {
7855
+ _inheritsLoose(TaskLoop, _Logger);
7856
+ function TaskLoop(label, logger) {
7857
+ var _this;
7858
+ _this = _Logger.call(this, label, logger) || this;
7859
+ _this._boundTick = void 0;
7860
+ _this._tickTimer = null;
7861
+ _this._tickInterval = null;
7862
+ _this._tickCallCount = 0;
7863
+ _this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
7864
+ return _this;
7806
7865
  }
7807
7866
  var _proto = TaskLoop.prototype;
7808
7867
  _proto.destroy = function destroy() {
@@ -7888,7 +7947,7 @@
7888
7947
  */;
7889
7948
  _proto.doTick = function doTick() {};
7890
7949
  return TaskLoop;
7891
- }();
7950
+ }(Logger);
7892
7951
 
7893
7952
  var FragmentState = {
7894
7953
  NOT_LOADED: "NOT_LOADED",
@@ -8907,8 +8966,8 @@
8907
8966
  var _frag$decryptdata;
8908
8967
  var byteRangeStart = start;
8909
8968
  var byteRangeEnd = end;
8910
- if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
8911
- // MAP segment encrypted with method 'AES-128', when served with HTTP Range,
8969
+ if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
8970
+ // MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
8912
8971
  // has the unencrypted size specified in the range.
8913
8972
  // Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
8914
8973
  var fragmentLen = end - start;
@@ -8941,6 +9000,9 @@
8941
9000
  (part ? part : frag).stats.aborted = true;
8942
9001
  return new LoadError(errorData);
8943
9002
  }
9003
+ function isMethodFullSegmentAesCbc(method) {
9004
+ return method === 'AES-128' || method === 'AES-256';
9005
+ }
8944
9006
  var LoadError = /*#__PURE__*/function (_Error) {
8945
9007
  _inheritsLoose(LoadError, _Error);
8946
9008
  function LoadError(data) {
@@ -8954,37 +9016,65 @@
8954
9016
  }( /*#__PURE__*/_wrapNativeSuper(Error));
8955
9017
 
8956
9018
  var AESCrypto = /*#__PURE__*/function () {
8957
- function AESCrypto(subtle, iv) {
9019
+ function AESCrypto(subtle, iv, aesMode) {
8958
9020
  this.subtle = void 0;
8959
9021
  this.aesIV = void 0;
9022
+ this.aesMode = void 0;
8960
9023
  this.subtle = subtle;
8961
9024
  this.aesIV = iv;
9025
+ this.aesMode = aesMode;
8962
9026
  }
8963
9027
  var _proto = AESCrypto.prototype;
8964
9028
  _proto.decrypt = function decrypt(data, key) {
8965
- return this.subtle.decrypt({
8966
- name: 'AES-CBC',
8967
- iv: this.aesIV
8968
- }, key, data);
9029
+ switch (this.aesMode) {
9030
+ case DecrypterAesMode.cbc:
9031
+ return this.subtle.decrypt({
9032
+ name: 'AES-CBC',
9033
+ iv: this.aesIV
9034
+ }, key, data);
9035
+ case DecrypterAesMode.ctr:
9036
+ return this.subtle.decrypt({
9037
+ name: 'AES-CTR',
9038
+ counter: this.aesIV,
9039
+ length: 64
9040
+ },
9041
+ //64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
9042
+ key, data);
9043
+ default:
9044
+ throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
9045
+ }
8969
9046
  };
8970
9047
  return AESCrypto;
8971
9048
  }();
8972
9049
 
8973
9050
  var FastAESKey = /*#__PURE__*/function () {
8974
- function FastAESKey(subtle, key) {
9051
+ function FastAESKey(subtle, key, aesMode) {
8975
9052
  this.subtle = void 0;
8976
9053
  this.key = void 0;
9054
+ this.aesMode = void 0;
8977
9055
  this.subtle = subtle;
8978
9056
  this.key = key;
9057
+ this.aesMode = aesMode;
8979
9058
  }
8980
9059
  var _proto = FastAESKey.prototype;
8981
9060
  _proto.expandKey = function expandKey() {
9061
+ var subtleAlgoName = getSubtleAlgoName(this.aesMode);
8982
9062
  return this.subtle.importKey('raw', this.key, {
8983
- name: 'AES-CBC'
9063
+ name: subtleAlgoName
8984
9064
  }, false, ['encrypt', 'decrypt']);
8985
9065
  };
8986
9066
  return FastAESKey;
8987
9067
  }();
9068
+ function getSubtleAlgoName(aesMode) {
9069
+ switch (aesMode) {
9070
+ case DecrypterAesMode.cbc:
9071
+ return 'AES-CBC';
9072
+ case DecrypterAesMode.ctr:
9073
+ return 'AES-CTR';
9074
+ default:
9075
+ throw new Error("[FastAESKey] invalid aes mode " + aesMode);
9076
+ }
9077
+ }
8988
9078
 
8989
9079
  // PKCS7
8990
9080
  function removePadding(array) {
@@ -9237,7 +9327,8 @@
9237
9327
  this.currentIV = null;
9238
9328
  this.currentResult = null;
9239
9329
  this.useSoftware = void 0;
9240
- this.useSoftware = config.enableSoftwareAES;
9330
+ this.enableSoftwareAES = void 0;
9331
+ this.enableSoftwareAES = config.enableSoftwareAES;
9241
9332
  this.removePKCS7Padding = removePKCS7Padding;
9242
9333
  // built in decryptor expects PKCS7 padding
9243
9334
  if (removePKCS7Padding) {
@@ -9250,9 +9341,7 @@
9250
9341
  /* no-op */
9251
9342
  }
9252
9343
  }
9253
- if (this.subtle === null) {
9254
- this.useSoftware = true;
9255
- }
9344
+ this.useSoftware = this.subtle === null;
9256
9345
  }
9257
9346
  var _proto = Decrypter.prototype;
9258
9347
  _proto.destroy = function destroy() {
@@ -9289,11 +9378,11 @@
9289
9378
  this.softwareDecrypter = null;
9290
9379
  }
9291
9380
  };
9292
- _proto.decrypt = function decrypt(data, key, iv) {
9381
+ _proto.decrypt = function decrypt(data, key, iv, aesMode) {
9293
9382
  var _this = this;
9294
9383
  if (this.useSoftware) {
9295
9384
  return new Promise(function (resolve, reject) {
9296
- _this.softwareDecrypt(new Uint8Array(data), key, iv);
9385
+ _this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
9297
9386
  var decryptResult = _this.flush();
9298
9387
  if (decryptResult) {
9299
9388
  resolve(decryptResult.buffer);
@@ -9302,16 +9391,20 @@
9302
9391
  }
9303
9392
  });
9304
9393
  }
9305
- return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
9394
+ return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
9306
9395
  }
9307
9396
 
9308
9397
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
9309
9398
  // data is handled in the flush() call
9310
9399
  ;
9311
- _proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
9400
+ _proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
9312
9401
  var currentIV = this.currentIV,
9313
9402
  currentResult = this.currentResult,
9314
9403
  remainderData = this.remainderData;
9404
+ if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
9405
+ logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
9406
+ return null;
9407
+ }
9315
9408
  this.logOnce('JS AES decrypt');
9316
9409
  // The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
9317
9410
  // This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
@@ -9344,12 +9437,12 @@
9344
9437
  }
9345
9438
  return result;
9346
9439
  };
9347
- _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
9440
+ _proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
9348
9441
  var _this2 = this;
9349
9442
  var subtle = this.subtle;
9350
9443
  if (this.key !== key || !this.fastAesKey) {
9351
9444
  this.key = key;
9352
- this.fastAesKey = new FastAESKey(subtle, key);
9445
+ this.fastAesKey = new FastAESKey(subtle, key, aesMode);
9353
9446
  }
9354
9447
  return this.fastAesKey.expandKey().then(function (aesKey) {
9355
9448
  // decrypt using web crypto
@@ -9357,22 +9450,25 @@
9357
9450
  return Promise.reject(new Error('web crypto not initialized'));
9358
9451
  }
9359
9452
  _this2.logOnce('WebCrypto AES decrypt');
9360
- var crypto = new AESCrypto(subtle, new Uint8Array(iv));
9453
+ var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
9361
9454
  return crypto.decrypt(data.buffer, aesKey);
9362
9455
  }).catch(function (err) {
9363
9456
  logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
9364
- return _this2.onWebCryptoError(data, key, iv);
9457
+ return _this2.onWebCryptoError(data, key, iv, aesMode);
9365
9458
  });
9366
9459
  };
9367
- _proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
9368
- this.useSoftware = true;
9369
- this.logEnabled = true;
9370
- this.softwareDecrypt(data, key, iv);
9371
- var decryptResult = this.flush();
9372
- if (decryptResult) {
9373
- return decryptResult.buffer;
9460
+ _proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
9461
+ var enableSoftwareAES = this.enableSoftwareAES;
9462
+ if (enableSoftwareAES) {
9463
+ this.useSoftware = true;
9464
+ this.logEnabled = true;
9465
+ this.softwareDecrypt(data, key, iv, aesMode);
9466
+ var decryptResult = this.flush();
9467
+ if (decryptResult) {
9468
+ return decryptResult.buffer;
9469
+ }
9374
9470
  }
9375
- throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
9471
+ throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
9376
9472
  };
9377
9473
  _proto.getValidChunk = function getValidChunk(data) {
9378
9474
  var currentChunk = data;
@@ -9426,7 +9522,7 @@
9426
9522
  _inheritsLoose(BaseStreamController, _TaskLoop);
9427
9523
  function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
9428
9524
  var _this;
9429
- _this = _TaskLoop.call(this) || this;
9525
+ _this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
9430
9526
  _this.hls = void 0;
9431
9527
  _this.fragPrevious = null;
9432
9528
  _this.fragCurrent = null;
@@ -9451,25 +9547,87 @@
9451
9547
  _this.startFragRequested = false;
9452
9548
  _this.decrypter = void 0;
9453
9549
  _this.initPTS = [];
9454
- _this.onvseeking = null;
9455
- _this.onvended = null;
9456
- _this.logPrefix = '';
9457
- _this.log = void 0;
9458
- _this.warn = void 0;
9550
+ _this.buffering = true;
9551
+ _this.onMediaSeeking = function () {
9552
+ var _assertThisInitialize = _assertThisInitialized(_this),
9553
+ config = _assertThisInitialize.config,
9554
+ fragCurrent = _assertThisInitialize.fragCurrent,
9555
+ media = _assertThisInitialize.media,
9556
+ mediaBuffer = _assertThisInitialize.mediaBuffer,
9557
+ state = _assertThisInitialize.state;
9558
+ var currentTime = media ? media.currentTime : 0;
9559
+ var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
9560
+ _this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
9561
+ if (_this.state === State.ENDED) {
9562
+ _this.resetLoadingState();
9563
+ } else if (fragCurrent) {
9564
+ // Seeking while frag load is in progress
9565
+ var tolerance = config.maxFragLookUpTolerance;
9566
+ var fragStartOffset = fragCurrent.start - tolerance;
9567
+ var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
9568
+ // if seeking out of buffered range or into new one
9569
+ if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
9570
+ var pastFragment = currentTime > fragEndOffset;
9571
+ // if the seek position is outside the current fragment range
9572
+ if (currentTime < fragStartOffset || pastFragment) {
9573
+ if (pastFragment && fragCurrent.loader) {
9574
+ _this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
9575
+ fragCurrent.abortRequests();
9576
+ _this.resetLoadingState();
9577
+ }
9578
+ _this.fragPrevious = null;
9579
+ }
9580
+ }
9581
+ }
9582
+ if (media) {
9583
+ // Remove gap fragments
9584
+ _this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
9585
+ _this.lastCurrentTime = currentTime;
9586
+ }
9587
+
9588
+ // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
9589
+ if (!_this.loadedmetadata && !bufferInfo.len) {
9590
+ _this.nextLoadPosition = _this.startPosition = currentTime;
9591
+ }
9592
+
9593
+ // Async tick to speed up processing
9594
+ _this.tickImmediate();
9595
+ };
9596
+ _this.onMediaEnded = function () {
9597
+ // reset startPosition and lastCurrentTime to restart playback @ stream beginning
9598
+ _this.startPosition = _this.lastCurrentTime = 0;
9599
+ if (_this.playlistType === PlaylistLevelType.MAIN) {
9600
+ _this.hls.trigger(Events.MEDIA_ENDED, {
9601
+ stalled: false
9602
+ });
9603
+ }
9604
+ };
9459
9605
  _this.playlistType = playlistType;
9460
- _this.logPrefix = logPrefix;
9461
- _this.log = logger.log.bind(logger, logPrefix + ":");
9462
- _this.warn = logger.warn.bind(logger, logPrefix + ":");
9463
9606
  _this.hls = hls;
9464
9607
  _this.fragmentLoader = new FragmentLoader(hls.config);
9465
9608
  _this.keyLoader = keyLoader;
9466
9609
  _this.fragmentTracker = fragmentTracker;
9467
9610
  _this.config = hls.config;
9468
9611
  _this.decrypter = new Decrypter(hls.config);
9469
- hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
9470
9612
  return _this;
9471
9613
  }
9472
9614
  var _proto = BaseStreamController.prototype;
9615
+ _proto.registerListeners = function registerListeners() {
9616
+ var hls = this.hls;
9617
+ hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
9618
+ hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
9619
+ hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
9620
+ hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
9621
+ hls.on(Events.ERROR, this.onError, this);
9622
+ };
9623
+ _proto.unregisterListeners = function unregisterListeners() {
9624
+ var hls = this.hls;
9625
+ hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
9626
+ hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
9627
+ hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
9628
+ hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
9629
+ hls.off(Events.ERROR, this.onError, this);
9630
+ };
9473
9631
  _proto.doTick = function doTick() {
9474
9632
  this.onTickEnd();
9475
9633
  };
@@ -9493,6 +9651,12 @@
9493
9651
  this.clearNextTick();
9494
9652
  this.state = State.STOPPED;
9495
9653
  };
9654
+ _proto.pauseBuffering = function pauseBuffering() {
9655
+ this.buffering = false;
9656
+ };
9657
+ _proto.resumeBuffering = function resumeBuffering() {
9658
+ this.buffering = true;
9659
+ };
9496
9660
  _proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
9497
9661
  // If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
9498
9662
  // of nothing loading/loaded return false
@@ -9523,10 +9687,8 @@
9523
9687
  };
9524
9688
  _proto.onMediaAttached = function onMediaAttached(event, data) {
9525
9689
  var media = this.media = this.mediaBuffer = data.media;
9526
- this.onvseeking = this.onMediaSeeking.bind(this);
9527
- this.onvended = this.onMediaEnded.bind(this);
9528
- media.addEventListener('seeking', this.onvseeking);
9529
- media.addEventListener('ended', this.onvended);
9690
+ media.addEventListener('seeking', this.onMediaSeeking);
9691
+ media.addEventListener('ended', this.onMediaEnded);
9530
9692
  var config = this.config;
9531
9693
  if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
9532
9694
  this.startLoad(config.startPosition);
@@ -9540,10 +9702,9 @@
9540
9702
  }
9541
9703
 
9542
9704
  // remove video listeners
9543
- if (media && this.onvseeking && this.onvended) {
9544
- media.removeEventListener('seeking', this.onvseeking);
9545
- media.removeEventListener('ended', this.onvended);
9546
- this.onvseeking = this.onvended = null;
9705
+ if (media) {
9706
+ media.removeEventListener('seeking', this.onMediaSeeking);
9707
+ media.removeEventListener('ended', this.onMediaEnded);
9547
9708
  }
9548
9709
  if (this.keyLoader) {
9549
9710
  this.keyLoader.detach();
@@ -9553,54 +9714,8 @@
9553
9714
  this.fragmentTracker.removeAllFragments();
9554
9715
  this.stopLoad();
9555
9716
  };
9556
- _proto.onMediaSeeking = function onMediaSeeking() {
9557
- var config = this.config,
9558
- fragCurrent = this.fragCurrent,
9559
- media = this.media,
9560
- mediaBuffer = this.mediaBuffer,
9561
- state = this.state;
9562
- var currentTime = media ? media.currentTime : 0;
9563
- var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
9564
- this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
9565
- if (this.state === State.ENDED) {
9566
- this.resetLoadingState();
9567
- } else if (fragCurrent) {
9568
- // Seeking while frag load is in progress
9569
- var tolerance = config.maxFragLookUpTolerance;
9570
- var fragStartOffset = fragCurrent.start - tolerance;
9571
- var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
9572
- // if seeking out of buffered range or into new one
9573
- if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
9574
- var pastFragment = currentTime > fragEndOffset;
9575
- // if the seek position is outside the current fragment range
9576
- if (currentTime < fragStartOffset || pastFragment) {
9577
- if (pastFragment && fragCurrent.loader) {
9578
- this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
9579
- fragCurrent.abortRequests();
9580
- this.resetLoadingState();
9581
- }
9582
- this.fragPrevious = null;
9583
- }
9584
- }
9585
- }
9586
- if (media) {
9587
- // Remove gap fragments
9588
- this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
9589
- this.lastCurrentTime = currentTime;
9590
- }
9591
-
9592
- // in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
9593
- if (!this.loadedmetadata && !bufferInfo.len) {
9594
- this.nextLoadPosition = this.startPosition = currentTime;
9595
- }
9596
-
9597
- // Async tick to speed up processing
9598
- this.tickImmediate();
9599
- };
9600
- _proto.onMediaEnded = function onMediaEnded() {
9601
- // reset startPosition and lastCurrentTime to restart playback @ stream beginning
9602
- this.startPosition = this.lastCurrentTime = 0;
9603
- };
9717
+ _proto.onManifestLoading = function onManifestLoading() {};
9718
+ _proto.onError = function onError(event, data) {};
9604
9719
  _proto.onManifestLoaded = function onManifestLoaded(event, data) {
9605
9720
  this.startTimeOffset = data.startTimeOffset;
9606
9721
  this.initPTS = [];
@@ -9610,7 +9725,7 @@
9610
9725
  this.stopLoad();
9611
9726
  _TaskLoop.prototype.onHandlerDestroying.call(this);
9612
9727
  // @ts-ignore
9613
- this.hls = null;
9728
+ this.hls = this.onMediaSeeking = this.onMediaEnded = null;
9614
9729
  };
9615
9730
  _proto.onHandlerDestroyed = function onHandlerDestroyed() {
9616
9731
  this.state = State.STOPPED;
@@ -9740,10 +9855,10 @@
9740
9855
  var decryptData = frag.decryptdata;
9741
9856
 
9742
9857
  // check to see if the payload needs to be decrypted
9743
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
9858
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
9744
9859
  var startTime = self.performance.now();
9745
9860
  // decrypt init segment data
9746
- return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
9861
+ return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
9747
9862
  hls.trigger(Events.ERROR, {
9748
9863
  type: ErrorTypes.MEDIA_ERROR,
9749
9864
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -9856,7 +9971,7 @@
9856
9971
  }
9857
9972
  var keyLoadingPromise = null;
9858
9973
  if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
9859
- this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + " " + frag.level);
9974
+ this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
9860
9975
  this.state = State.KEY_LOADING;
9861
9976
  this.fragCurrent = frag;
9862
9977
  keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
@@ -9887,7 +10002,7 @@
9887
10002
  var partIndex = this.getNextPart(partList, frag, targetBufferTime);
9888
10003
  if (partIndex > -1) {
9889
10004
  var part = partList[partIndex];
9890
- 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)));
10005
+ 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)));
9891
10006
  this.nextLoadPosition = part.start + part.duration;
9892
10007
  this.state = State.FRAG_LOADING;
9893
10008
  var _result;
@@ -9920,7 +10035,7 @@
9920
10035
  }
9921
10036
  }
9922
10037
  }
9923
- 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)));
10038
+ 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)));
9924
10039
  // Don't update nextLoadPosition for fragments which are not buffered
9925
10040
  if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
9926
10041
  this.nextLoadPosition = frag.start + frag.duration;
@@ -10481,7 +10596,7 @@
10481
10596
  errorAction.resolved = true;
10482
10597
  }
10483
10598
  } else {
10484
- logger.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
10599
+ this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
10485
10600
  return;
10486
10601
  }
10487
10602
  } else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
@@ -10881,6 +10996,7 @@
10881
10996
  */
10882
10997
  function getAudioConfig(observer, data, offset, audioCodec) {
10883
10998
  var adtsObjectType;
10999
+ var originalAdtsObjectType;
10884
11000
  var adtsExtensionSamplingIndex;
10885
11001
  var adtsChannelConfig;
10886
11002
  var config;
@@ -10888,7 +11004,7 @@
10888
11004
  var manifestCodec = audioCodec;
10889
11005
  var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
10890
11006
  // byte 2
10891
- adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
11007
+ adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
10892
11008
  var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
10893
11009
  if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
10894
11010
  var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
@@ -10905,8 +11021,8 @@
10905
11021
  // byte 3
10906
11022
  adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
10907
11023
  logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
10908
- // firefox: freq less than 24kHz = AAC SBR (HE-AAC)
10909
- if (/firefox/i.test(userAgent)) {
11024
+ // Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
11025
+ if (/firefox|palemoon/i.test(userAgent)) {
10910
11026
  if (adtsSamplingIndex >= 6) {
10911
11027
  adtsObjectType = 5;
10912
11028
  config = new Array(4);
@@ -11000,6 +11116,7 @@
11000
11116
  samplerate: adtsSamplingRates[adtsSamplingIndex],
11001
11117
  channelCount: adtsChannelConfig,
11002
11118
  codec: 'mp4a.40.' + adtsObjectType,
11119
+ parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
11003
11120
  manifestCodec: manifestCodec
11004
11121
  };
11005
11122
  }
@@ -11054,7 +11171,8 @@
11054
11171
  track.channelCount = config.channelCount;
11055
11172
  track.codec = config.codec;
11056
11173
  track.manifestCodec = config.manifestCodec;
11057
- logger.log("parsed codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
11174
+ track.parsedCodec = config.parsedCodec;
11175
+ logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
11058
11176
  }
11059
11177
  }
11060
11178
  function getFrameDuration(samplerate) {
@@ -11652,65 +11770,169 @@
11652
11770
  logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
11653
11771
  }
11654
11772
  };
11655
- return BaseVideoParser;
11656
- }();
11657
-
11658
- /**
11659
- * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
11660
- */
11661
-
11662
- var ExpGolomb = /*#__PURE__*/function () {
11663
- function ExpGolomb(data) {
11664
- this.data = void 0;
11665
- this.bytesAvailable = void 0;
11666
- this.word = void 0;
11667
- this.bitsAvailable = void 0;
11668
- this.data = data;
11669
- // the number of bytes left to examine in this.data
11670
- this.bytesAvailable = data.byteLength;
11671
- // the current word being examined
11672
- this.word = 0; // :uint
11673
- // the number of bits left to examine in the current word
11674
- this.bitsAvailable = 0; // :uint
11675
- }
11676
-
11677
- // ():void
11678
- var _proto = ExpGolomb.prototype;
11679
- _proto.loadWord = function loadWord() {
11680
- var data = this.data;
11681
- var bytesAvailable = this.bytesAvailable;
11682
- var position = data.byteLength - bytesAvailable;
11683
- var workingBytes = new Uint8Array(4);
11684
- var availableBytes = Math.min(4, bytesAvailable);
11685
- if (availableBytes === 0) {
11686
- throw new Error('no bytes available');
11687
- }
11688
- workingBytes.set(data.subarray(position, position + availableBytes));
11689
- this.word = new DataView(workingBytes.buffer).getUint32(0);
11690
- // track the amount of this.data that has been processed
11691
- this.bitsAvailable = availableBytes * 8;
11692
- this.bytesAvailable -= availableBytes;
11693
- }
11773
+ _proto.parseNALu = function parseNALu(track, array) {
11774
+ var len = array.byteLength;
11775
+ var state = track.naluState || 0;
11776
+ var lastState = state;
11777
+ var units = [];
11778
+ var i = 0;
11779
+ var value;
11780
+ var overflow;
11781
+ var unitType;
11782
+ var lastUnitStart = -1;
11783
+ var lastUnitType = 0;
11784
+ // logger.log('PES:' + Hex.hexDump(array));
11694
11785
 
11695
- // (count:int):void
11696
- ;
11697
- _proto.skipBits = function skipBits(count) {
11698
- var skipBytes; // :int
11699
- count = Math.min(count, this.bytesAvailable * 8 + this.bitsAvailable);
11700
- if (this.bitsAvailable > count) {
11701
- this.word <<= count;
11702
- this.bitsAvailable -= count;
11703
- } else {
11704
- count -= this.bitsAvailable;
11705
- skipBytes = count >> 3;
11706
- count -= skipBytes << 3;
11707
- this.bytesAvailable -= skipBytes;
11708
- this.loadWord();
11709
- this.word <<= count;
11710
- this.bitsAvailable -= count;
11786
+ if (state === -1) {
11787
+ // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
11788
+ lastUnitStart = 0;
11789
+ // NALu type is value read from offset 0
11790
+ lastUnitType = this.getNALuType(array, 0);
11791
+ state = 0;
11792
+ i = 1;
11711
11793
  }
11712
- }
11713
-
11794
+ while (i < len) {
11795
+ value = array[i++];
11796
+ // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
11797
+ if (!state) {
11798
+ state = value ? 0 : 1;
11799
+ continue;
11800
+ }
11801
+ if (state === 1) {
11802
+ state = value ? 0 : 2;
11803
+ continue;
11804
+ }
11805
+ // here we have state either equal to 2 or 3
11806
+ if (!value) {
11807
+ state = 3;
11808
+ } else if (value === 1) {
11809
+ overflow = i - state - 1;
11810
+ if (lastUnitStart >= 0) {
11811
+ var unit = {
11812
+ data: array.subarray(lastUnitStart, overflow),
11813
+ type: lastUnitType
11814
+ };
11815
+ // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
11816
+ units.push(unit);
11817
+ } else {
11818
+ // lastUnitStart is undefined => this is the first start code found in this PES packet
11819
+ // first check if start code delimiter is overlapping between 2 PES packets,
11820
+ // ie it started in last packet (lastState not zero)
11821
+ // and ended at the beginning of this PES packet (i <= 4 - lastState)
11822
+ var lastUnit = this.getLastNalUnit(track.samples);
11823
+ if (lastUnit) {
11824
+ if (lastState && i <= 4 - lastState) {
11825
+ // start delimiter overlapping between PES packets
11826
+ // strip start delimiter bytes from the end of last NAL unit
11827
+ // check if lastUnit had a state different from zero
11828
+ if (lastUnit.state) {
11829
+ // strip last bytes
11830
+ lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
11831
+ }
11832
+ }
11833
+ // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
11834
+
11835
+ if (overflow > 0) {
11836
+ // logger.log('first NALU found with overflow:' + overflow);
11837
+ lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
11838
+ lastUnit.state = 0;
11839
+ }
11840
+ }
11841
+ }
11842
+ // check if we can read unit type
11843
+ if (i < len) {
11844
+ unitType = this.getNALuType(array, i);
11845
+ // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
11846
+ lastUnitStart = i;
11847
+ lastUnitType = unitType;
11848
+ state = 0;
11849
+ } else {
11850
+ // not enough byte to read unit type. let's read it on next PES parsing
11851
+ state = -1;
11852
+ }
11853
+ } else {
11854
+ state = 0;
11855
+ }
11856
+ }
11857
+ if (lastUnitStart >= 0 && state >= 0) {
11858
+ var _unit = {
11859
+ data: array.subarray(lastUnitStart, len),
11860
+ type: lastUnitType,
11861
+ state: state
11862
+ };
11863
+ units.push(_unit);
11864
+ // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
11865
+ }
11866
+ // no NALu found
11867
+ if (units.length === 0) {
11868
+ // append pes.data to previous NAL unit
11869
+ var _lastUnit = this.getLastNalUnit(track.samples);
11870
+ if (_lastUnit) {
11871
+ _lastUnit.data = appendUint8Array(_lastUnit.data, array);
11872
+ }
11873
+ }
11874
+ track.naluState = state;
11875
+ return units;
11876
+ };
11877
+ return BaseVideoParser;
11878
+ }();
11879
+
11880
+ /**
11881
+ * Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
11882
+ */
11883
+
11884
+ var ExpGolomb = /*#__PURE__*/function () {
11885
+ function ExpGolomb(data) {
11886
+ this.data = void 0;
11887
+ this.bytesAvailable = void 0;
11888
+ this.word = void 0;
11889
+ this.bitsAvailable = void 0;
11890
+ this.data = data;
11891
+ // the number of bytes left to examine in this.data
11892
+ this.bytesAvailable = data.byteLength;
11893
+ // the current word being examined
11894
+ this.word = 0; // :uint
11895
+ // the number of bits left to examine in the current word
11896
+ this.bitsAvailable = 0; // :uint
11897
+ }
11898
+
11899
+ // ():void
11900
+ var _proto = ExpGolomb.prototype;
11901
+ _proto.loadWord = function loadWord() {
11902
+ var data = this.data;
11903
+ var bytesAvailable = this.bytesAvailable;
11904
+ var position = data.byteLength - bytesAvailable;
11905
+ var workingBytes = new Uint8Array(4);
11906
+ var availableBytes = Math.min(4, bytesAvailable);
11907
+ if (availableBytes === 0) {
11908
+ throw new Error('no bytes available');
11909
+ }
11910
+ workingBytes.set(data.subarray(position, position + availableBytes));
11911
+ this.word = new DataView(workingBytes.buffer).getUint32(0);
11912
+ // track the amount of this.data that has been processed
11913
+ this.bitsAvailable = availableBytes * 8;
11914
+ this.bytesAvailable -= availableBytes;
11915
+ }
11916
+
11917
+ // (count:int):void
11918
+ ;
11919
+ _proto.skipBits = function skipBits(count) {
11920
+ var skipBytes; // :int
11921
+ count = Math.min(count, this.bytesAvailable * 8 + this.bitsAvailable);
11922
+ if (this.bitsAvailable > count) {
11923
+ this.word <<= count;
11924
+ this.bitsAvailable -= count;
11925
+ } else {
11926
+ count -= this.bitsAvailable;
11927
+ skipBytes = count >> 3;
11928
+ count -= skipBytes << 3;
11929
+ this.bytesAvailable -= skipBytes;
11930
+ this.loadWord();
11931
+ this.word <<= count;
11932
+ this.bitsAvailable -= count;
11933
+ }
11934
+ }
11935
+
11714
11936
  // (size:int):uint
11715
11937
  ;
11716
11938
  _proto.readBits = function readBits(size) {
@@ -11806,22 +12028,179 @@
11806
12028
  ;
11807
12029
  _proto.readUInt = function readUInt() {
11808
12030
  return this.readBits(32);
12031
+ };
12032
+ return ExpGolomb;
12033
+ }();
12034
+
12035
+ var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
12036
+ _inheritsLoose(AvcVideoParser, _BaseVideoParser);
12037
+ function AvcVideoParser() {
12038
+ return _BaseVideoParser.apply(this, arguments) || this;
12039
+ }
12040
+ var _proto = AvcVideoParser.prototype;
12041
+ _proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
12042
+ var _this = this;
12043
+ var units = this.parseNALu(track, pes.data);
12044
+ var VideoSample = this.VideoSample;
12045
+ var push;
12046
+ var spsfound = false;
12047
+ // free pes.data to save up some memory
12048
+ pes.data = null;
12049
+
12050
+ // if new NAL units found and last sample still there, let's push ...
12051
+ // this helps parsing streams with missing AUD (only do this if AUD never found)
12052
+ if (VideoSample && units.length && !track.audFound) {
12053
+ this.pushAccessUnit(VideoSample, track);
12054
+ VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts, '');
12055
+ }
12056
+ units.forEach(function (unit) {
12057
+ var _VideoSample2;
12058
+ switch (unit.type) {
12059
+ // NDR
12060
+ case 1:
12061
+ {
12062
+ var iskey = false;
12063
+ push = true;
12064
+ var data = unit.data;
12065
+ // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
12066
+ if (spsfound && data.length > 4) {
12067
+ // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
12068
+ var sliceType = _this.readSliceType(data);
12069
+ // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
12070
+ // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
12071
+ // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
12072
+ // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
12073
+ // if (sliceType === 2 || sliceType === 7) {
12074
+ if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
12075
+ iskey = true;
12076
+ }
12077
+ }
12078
+ if (iskey) {
12079
+ var _VideoSample;
12080
+ // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
12081
+ if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
12082
+ _this.pushAccessUnit(VideoSample, track);
12083
+ VideoSample = _this.VideoSample = null;
12084
+ }
12085
+ }
12086
+ if (!VideoSample) {
12087
+ VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
12088
+ }
12089
+ VideoSample.frame = true;
12090
+ VideoSample.key = iskey;
12091
+ break;
12092
+ // IDR
12093
+ }
12094
+ case 5:
12095
+ push = true;
12096
+ // handle PES not starting with AUD
12097
+ // if we have frame data already, that cannot belong to the same frame, so force a push
12098
+ if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
12099
+ _this.pushAccessUnit(VideoSample, track);
12100
+ VideoSample = _this.VideoSample = null;
12101
+ }
12102
+ if (!VideoSample) {
12103
+ VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
12104
+ }
12105
+ VideoSample.key = true;
12106
+ VideoSample.frame = true;
12107
+ break;
12108
+ // SEI
12109
+ case 6:
12110
+ {
12111
+ push = true;
12112
+ parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
12113
+ break;
12114
+ // SPS
12115
+ }
12116
+ case 7:
12117
+ {
12118
+ var _track$pixelRatio, _track$pixelRatio2;
12119
+ push = true;
12120
+ spsfound = true;
12121
+ var sps = unit.data;
12122
+ var config = _this.readSPS(sps);
12123
+ 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]) {
12124
+ track.width = config.width;
12125
+ track.height = config.height;
12126
+ track.pixelRatio = config.pixelRatio;
12127
+ track.sps = [sps];
12128
+ track.duration = duration;
12129
+ var codecarray = sps.subarray(1, 4);
12130
+ var codecstring = 'avc1.';
12131
+ for (var i = 0; i < 3; i++) {
12132
+ var h = codecarray[i].toString(16);
12133
+ if (h.length < 2) {
12134
+ h = '0' + h;
12135
+ }
12136
+ codecstring += h;
12137
+ }
12138
+ track.codec = codecstring;
12139
+ }
12140
+ break;
12141
+ }
12142
+ // PPS
12143
+ case 8:
12144
+ push = true;
12145
+ track.pps = [unit.data];
12146
+ break;
12147
+ // AUD
12148
+ case 9:
12149
+ push = true;
12150
+ track.audFound = true;
12151
+ if (VideoSample) {
12152
+ _this.pushAccessUnit(VideoSample, track);
12153
+ }
12154
+ VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
12155
+ break;
12156
+ // Filler Data
12157
+ case 12:
12158
+ push = true;
12159
+ break;
12160
+ default:
12161
+ push = false;
12162
+ if (VideoSample) {
12163
+ VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
12164
+ }
12165
+ break;
12166
+ }
12167
+ if (VideoSample && push) {
12168
+ var _units = VideoSample.units;
12169
+ _units.push(unit);
12170
+ }
12171
+ });
12172
+ // if last PES packet, push samples
12173
+ if (last && VideoSample) {
12174
+ this.pushAccessUnit(VideoSample, track);
12175
+ this.VideoSample = null;
12176
+ }
12177
+ };
12178
+ _proto.getNALuType = function getNALuType(data, offset) {
12179
+ return data[offset] & 0x1f;
12180
+ };
12181
+ _proto.readSliceType = function readSliceType(data) {
12182
+ var eg = new ExpGolomb(data);
12183
+ // skip NALu type
12184
+ eg.readUByte();
12185
+ // discard first_mb_in_slice
12186
+ eg.readUEG();
12187
+ // return slice_type
12188
+ return eg.readUEG();
11809
12189
  }
11810
12190
 
11811
12191
  /**
11812
- * Advance the ExpGolomb decoder past a scaling list. The scaling
11813
- * list is optionally transmitted as part of a sequence parameter
12192
+ * The scaling list is optionally transmitted as part of a sequence parameter
11814
12193
  * set and is not relevant to transmuxing.
11815
12194
  * @param count the number of entries in this scaling list
11816
12195
  * @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
11817
12196
  */;
11818
- _proto.skipScalingList = function skipScalingList(count) {
12197
+ _proto.skipScalingList = function skipScalingList(count, reader) {
11819
12198
  var lastScale = 8;
11820
12199
  var nextScale = 8;
11821
12200
  var deltaScale;
11822
12201
  for (var j = 0; j < count; j++) {
11823
12202
  if (nextScale !== 0) {
11824
- deltaScale = this.readEG();
12203
+ deltaScale = reader.readEG();
11825
12204
  nextScale = (lastScale + deltaScale + 256) % 256;
11826
12205
  }
11827
12206
  lastScale = nextScale === 0 ? lastScale : nextScale;
@@ -11836,7 +12215,8 @@
11836
12215
  * sequence parameter set, including the dimensions of the
11837
12216
  * associated video frames.
11838
12217
  */;
11839
- _proto.readSPS = function readSPS() {
12218
+ _proto.readSPS = function readSPS(sps) {
12219
+ var eg = new ExpGolomb(sps);
11840
12220
  var frameCropLeftOffset = 0;
11841
12221
  var frameCropRightOffset = 0;
11842
12222
  var frameCropTopOffset = 0;
@@ -11844,13 +12224,13 @@
11844
12224
  var numRefFramesInPicOrderCntCycle;
11845
12225
  var scalingListCount;
11846
12226
  var i;
11847
- var readUByte = this.readUByte.bind(this);
11848
- var readBits = this.readBits.bind(this);
11849
- var readUEG = this.readUEG.bind(this);
11850
- var readBoolean = this.readBoolean.bind(this);
11851
- var skipBits = this.skipBits.bind(this);
11852
- var skipEG = this.skipEG.bind(this);
11853
- var skipUEG = this.skipUEG.bind(this);
12227
+ var readUByte = eg.readUByte.bind(eg);
12228
+ var readBits = eg.readBits.bind(eg);
12229
+ var readUEG = eg.readUEG.bind(eg);
12230
+ var readBoolean = eg.readBoolean.bind(eg);
12231
+ var skipBits = eg.skipBits.bind(eg);
12232
+ var skipEG = eg.skipEG.bind(eg);
12233
+ var skipUEG = eg.skipUEG.bind(eg);
11854
12234
  var skipScalingList = this.skipScalingList.bind(this);
11855
12235
  readUByte();
11856
12236
  var profileIdc = readUByte(); // profile_idc
@@ -11875,9 +12255,9 @@
11875
12255
  if (readBoolean()) {
11876
12256
  // seq_scaling_list_present_flag[ i ]
11877
12257
  if (i < 6) {
11878
- skipScalingList(16);
12258
+ skipScalingList(16, eg);
11879
12259
  } else {
11880
- skipScalingList(64);
12260
+ skipScalingList(64, eg);
11881
12261
  }
11882
12262
  }
11883
12263
  }
@@ -11982,26 +12362,24 @@
11982
12362
  pixelRatio: pixelRatio
11983
12363
  };
11984
12364
  };
11985
- _proto.readSliceType = function readSliceType() {
11986
- // skip NALu type
11987
- this.readUByte();
11988
- // discard first_mb_in_slice
11989
- this.readUEG();
11990
- // return slice_type
11991
- return this.readUEG();
11992
- };
11993
- return ExpGolomb;
11994
- }();
12365
+ return AvcVideoParser;
12366
+ }(BaseVideoParser);
11995
12367
 
11996
- var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
11997
- _inheritsLoose(AvcVideoParser, _BaseVideoParser);
11998
- function AvcVideoParser() {
11999
- return _BaseVideoParser.apply(this, arguments) || this;
12000
- }
12001
- var _proto = AvcVideoParser.prototype;
12002
- _proto.parseAVCPES = function parseAVCPES(track, textTrack, pes, last, duration) {
12003
- var _this = this;
12004
- var units = this.parseAVCNALu(track, pes.data);
12368
+ var HevcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
12369
+ _inheritsLoose(HevcVideoParser, _BaseVideoParser);
12370
+ function HevcVideoParser() {
12371
+ var _this;
12372
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
12373
+ args[_key] = arguments[_key];
12374
+ }
12375
+ _this = _BaseVideoParser.call.apply(_BaseVideoParser, [this].concat(args)) || this;
12376
+ _this.initVPS = null;
12377
+ return _this;
12378
+ }
12379
+ var _proto = HevcVideoParser.prototype;
12380
+ _proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
12381
+ var _this2 = this;
12382
+ var units = this.parseNALu(track, pes.data);
12005
12383
  var VideoSample = this.VideoSample;
12006
12384
  var push;
12007
12385
  var spsfound = false;
@@ -12017,112 +12395,143 @@
12017
12395
  units.forEach(function (unit) {
12018
12396
  var _VideoSample2;
12019
12397
  switch (unit.type) {
12020
- // NDR
12398
+ // NON-IDR, NON RANDOM ACCESS SLICE
12399
+ case 0:
12021
12400
  case 1:
12022
- {
12023
- var iskey = false;
12024
- push = true;
12025
- var data = unit.data;
12026
- // only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
12027
- if (spsfound && data.length > 4) {
12028
- // retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
12029
- var sliceType = new ExpGolomb(data).readSliceType();
12030
- // 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
12031
- // SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
12032
- // An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
12033
- // I slice: A slice that is not an SI slice that is decoded using intra prediction only.
12034
- // if (sliceType === 2 || sliceType === 7) {
12035
- if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
12036
- iskey = true;
12037
- }
12038
- }
12039
- if (iskey) {
12040
- var _VideoSample;
12041
- // if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
12042
- if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
12043
- _this.pushAccessUnit(VideoSample, track);
12044
- VideoSample = _this.VideoSample = null;
12045
- }
12046
- }
12047
- if (!VideoSample) {
12048
- VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
12401
+ case 2:
12402
+ case 3:
12403
+ case 4:
12404
+ case 5:
12405
+ case 6:
12406
+ case 7:
12407
+ case 8:
12408
+ case 9:
12409
+ if (!VideoSample) {
12410
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(false, pes.pts, pes.dts, '');
12411
+ }
12412
+ VideoSample.frame = true;
12413
+ push = true;
12414
+ break;
12415
+
12416
+ // CRA, BLA (random access picture)
12417
+ case 16:
12418
+ case 17:
12419
+ case 18:
12420
+ case 21:
12421
+ push = true;
12422
+ if (spsfound) {
12423
+ var _VideoSample;
12424
+ // handle PES not starting with AUD
12425
+ // if we have frame data already, that cannot belong to the same frame, so force a push
12426
+ if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
12427
+ _this2.pushAccessUnit(VideoSample, track);
12428
+ VideoSample = _this2.VideoSample = null;
12049
12429
  }
12050
- VideoSample.frame = true;
12051
- VideoSample.key = iskey;
12052
- break;
12053
- // IDR
12054
12430
  }
12055
- case 5:
12431
+ if (!VideoSample) {
12432
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
12433
+ }
12434
+ VideoSample.key = true;
12435
+ VideoSample.frame = true;
12436
+ break;
12437
+
12438
+ // IDR
12439
+ case 19:
12440
+ case 20:
12056
12441
  push = true;
12057
12442
  // handle PES not starting with AUD
12058
12443
  // if we have frame data already, that cannot belong to the same frame, so force a push
12059
12444
  if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
12060
- _this.pushAccessUnit(VideoSample, track);
12061
- VideoSample = _this.VideoSample = null;
12445
+ _this2.pushAccessUnit(VideoSample, track);
12446
+ VideoSample = _this2.VideoSample = null;
12062
12447
  }
12063
12448
  if (!VideoSample) {
12064
- VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
12449
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
12065
12450
  }
12066
12451
  VideoSample.key = true;
12067
12452
  VideoSample.frame = true;
12068
12453
  break;
12454
+
12069
12455
  // SEI
12070
- case 6:
12071
- {
12072
- push = true;
12073
- parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
12074
- break;
12075
- // SPS
12456
+ case 39:
12457
+ push = true;
12458
+ parseSEIMessageFromNALu(unit.data, 2,
12459
+ // NALu header size
12460
+ pes.pts, textTrack.samples);
12461
+ break;
12462
+
12463
+ // VPS
12464
+ case 32:
12465
+ push = true;
12466
+ if (!track.vps) {
12467
+ var config = _this2.readVPS(unit.data);
12468
+ track.params = _objectSpread2({}, config);
12469
+ _this2.initVPS = unit.data;
12076
12470
  }
12077
- case 7:
12078
- {
12079
- var _track$pixelRatio, _track$pixelRatio2;
12080
- push = true;
12081
- spsfound = true;
12082
- var sps = unit.data;
12083
- var expGolombDecoder = new ExpGolomb(sps);
12084
- var config = expGolombDecoder.readSPS();
12085
- 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]) {
12086
- track.width = config.width;
12087
- track.height = config.height;
12088
- track.pixelRatio = config.pixelRatio;
12089
- track.sps = [sps];
12471
+ track.vps = [unit.data];
12472
+ break;
12473
+
12474
+ // SPS
12475
+ case 33:
12476
+ push = true;
12477
+ spsfound = true;
12478
+ if (typeof track.params === 'object') {
12479
+ if (track.vps !== undefined && track.vps[0] !== _this2.initVPS && track.sps !== undefined && !_this2.matchSPS(track.sps[0], unit.data)) {
12480
+ _this2.initVPS = track.vps[0];
12481
+ track.sps = track.pps = undefined;
12482
+ }
12483
+ if (!track.sps) {
12484
+ var _config = _this2.readSPS(unit.data);
12485
+ track.width = _config.width;
12486
+ track.height = _config.height;
12487
+ track.pixelRatio = _config.pixelRatio;
12090
12488
  track.duration = duration;
12091
- var codecarray = sps.subarray(1, 4);
12092
- var codecstring = 'avc1.';
12093
- for (var i = 0; i < 3; i++) {
12094
- var h = codecarray[i].toString(16);
12095
- if (h.length < 2) {
12096
- h = '0' + h;
12097
- }
12098
- codecstring += h;
12489
+ track.codec = _config.codecString;
12490
+ track.sps = [];
12491
+ for (var prop in _config.params) {
12492
+ track.params[prop] = _config.params[prop];
12099
12493
  }
12100
- track.codec = codecstring;
12101
12494
  }
12102
- break;
12495
+ if (track.vps !== undefined && track.vps[0] === _this2.initVPS) {
12496
+ track.sps.push(unit.data);
12497
+ }
12103
12498
  }
12499
+ if (!VideoSample) {
12500
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
12501
+ }
12502
+ VideoSample.key = true;
12503
+ break;
12504
+
12104
12505
  // PPS
12105
- case 8:
12506
+ case 34:
12106
12507
  push = true;
12107
- track.pps = [unit.data];
12508
+ if (typeof track.params === 'object') {
12509
+ if (!track.pps) {
12510
+ track.pps = [];
12511
+ var _config2 = _this2.readPPS(unit.data);
12512
+ for (var _prop in _config2) {
12513
+ track.params[_prop] = _config2[_prop];
12514
+ }
12515
+ }
12516
+ if (_this2.initVPS !== null || track.pps.length === 0) {
12517
+ track.pps.push(unit.data);
12518
+ }
12519
+ }
12108
12520
  break;
12109
- // AUD
12110
- case 9:
12521
+
12522
+ // ACCESS UNIT DELIMITER
12523
+ case 35:
12111
12524
  push = true;
12112
12525
  track.audFound = true;
12113
12526
  if (VideoSample) {
12114
- _this.pushAccessUnit(VideoSample, track);
12527
+ _this2.pushAccessUnit(VideoSample, track);
12115
12528
  }
12116
- VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
12117
- break;
12118
- // Filler Data
12119
- case 12:
12120
- push = true;
12529
+ VideoSample = _this2.VideoSample = _this2.createVideoSample(false, pes.pts, pes.dts, '');
12121
12530
  break;
12122
12531
  default:
12123
12532
  push = false;
12124
12533
  if (VideoSample) {
12125
- VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
12534
+ VideoSample.debug += 'unknown or irrelevant NAL ' + unit.type + ' ';
12126
12535
  }
12127
12536
  break;
12128
12537
  }
@@ -12137,111 +12546,425 @@
12137
12546
  this.VideoSample = null;
12138
12547
  }
12139
12548
  };
12140
- _proto.parseAVCNALu = function parseAVCNALu(track, array) {
12141
- var len = array.byteLength;
12142
- var state = track.naluState || 0;
12143
- var lastState = state;
12144
- var units = [];
12145
- var i = 0;
12146
- var value;
12147
- var overflow;
12148
- var unitType;
12149
- var lastUnitStart = -1;
12150
- var lastUnitType = 0;
12151
- // logger.log('PES:' + Hex.hexDump(array));
12152
-
12153
- if (state === -1) {
12154
- // special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
12155
- lastUnitStart = 0;
12156
- // NALu type is value read from offset 0
12157
- lastUnitType = array[0] & 0x1f;
12158
- state = 0;
12159
- i = 1;
12160
- }
12161
- while (i < len) {
12162
- value = array[i++];
12163
- // optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
12164
- if (!state) {
12165
- state = value ? 0 : 1;
12166
- continue;
12167
- }
12168
- if (state === 1) {
12169
- state = value ? 0 : 2;
12170
- continue;
12549
+ _proto.getNALuType = function getNALuType(data, offset) {
12550
+ return (data[offset] & 0x7e) >>> 1;
12551
+ };
12552
+ _proto.ebsp2rbsp = function ebsp2rbsp(arr) {
12553
+ var dst = new Uint8Array(arr.byteLength);
12554
+ var dstIdx = 0;
12555
+ for (var i = 0; i < arr.byteLength; i++) {
12556
+ if (i >= 2) {
12557
+ // Unescape: Skip 0x03 after 00 00
12558
+ if (arr[i] === 0x03 && arr[i - 1] === 0x00 && arr[i - 2] === 0x00) {
12559
+ continue;
12560
+ }
12171
12561
  }
12172
- // here we have state either equal to 2 or 3
12173
- if (!value) {
12174
- state = 3;
12175
- } else if (value === 1) {
12176
- overflow = i - state - 1;
12177
- if (lastUnitStart >= 0) {
12178
- var unit = {
12179
- data: array.subarray(lastUnitStart, overflow),
12180
- type: lastUnitType
12181
- };
12182
- // logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
12183
- units.push(unit);
12184
- } else {
12185
- // lastUnitStart is undefined => this is the first start code found in this PES packet
12186
- // first check if start code delimiter is overlapping between 2 PES packets,
12187
- // ie it started in last packet (lastState not zero)
12188
- // and ended at the beginning of this PES packet (i <= 4 - lastState)
12189
- var lastUnit = this.getLastNalUnit(track.samples);
12190
- if (lastUnit) {
12191
- if (lastState && i <= 4 - lastState) {
12192
- // start delimiter overlapping between PES packets
12193
- // strip start delimiter bytes from the end of last NAL unit
12194
- // check if lastUnit had a state different from zero
12195
- if (lastUnit.state) {
12196
- // strip last bytes
12197
- lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
12198
- }
12199
- }
12200
- // If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
12562
+ dst[dstIdx] = arr[i];
12563
+ dstIdx++;
12564
+ }
12565
+ return new Uint8Array(dst.buffer, 0, dstIdx);
12566
+ };
12567
+ _proto.readVPS = function readVPS(vps) {
12568
+ var eg = new ExpGolomb(vps);
12569
+ // remove header
12570
+ eg.readUByte();
12571
+ eg.readUByte();
12572
+ eg.readBits(4); // video_parameter_set_id
12573
+ eg.skipBits(2);
12574
+ eg.readBits(6); // max_layers_minus1
12575
+ var max_sub_layers_minus1 = eg.readBits(3);
12576
+ var temporal_id_nesting_flag = eg.readBoolean();
12577
+ // ...vui fps can be here, but empty fps value is not critical for metadata
12201
12578
 
12202
- if (overflow > 0) {
12203
- // logger.log('first NALU found with overflow:' + overflow);
12204
- lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
12205
- lastUnit.state = 0;
12579
+ return {
12580
+ numTemporalLayers: max_sub_layers_minus1 + 1,
12581
+ temporalIdNested: temporal_id_nesting_flag
12582
+ };
12583
+ };
12584
+ _proto.readSPS = function readSPS(sps) {
12585
+ var eg = new ExpGolomb(this.ebsp2rbsp(sps));
12586
+ eg.readUByte();
12587
+ eg.readUByte();
12588
+ eg.readBits(4); //video_parameter_set_id
12589
+ var max_sub_layers_minus1 = eg.readBits(3);
12590
+ eg.readBoolean(); // temporal_id_nesting_flag
12591
+
12592
+ // profile_tier_level
12593
+ var general_profile_space = eg.readBits(2);
12594
+ var general_tier_flag = eg.readBoolean();
12595
+ var general_profile_idc = eg.readBits(5);
12596
+ var general_profile_compatibility_flags_1 = eg.readUByte();
12597
+ var general_profile_compatibility_flags_2 = eg.readUByte();
12598
+ var general_profile_compatibility_flags_3 = eg.readUByte();
12599
+ var general_profile_compatibility_flags_4 = eg.readUByte();
12600
+ var general_constraint_indicator_flags_1 = eg.readUByte();
12601
+ var general_constraint_indicator_flags_2 = eg.readUByte();
12602
+ var general_constraint_indicator_flags_3 = eg.readUByte();
12603
+ var general_constraint_indicator_flags_4 = eg.readUByte();
12604
+ var general_constraint_indicator_flags_5 = eg.readUByte();
12605
+ var general_constraint_indicator_flags_6 = eg.readUByte();
12606
+ var general_level_idc = eg.readUByte();
12607
+ var sub_layer_profile_present_flags = [];
12608
+ var sub_layer_level_present_flags = [];
12609
+ for (var i = 0; i < max_sub_layers_minus1; i++) {
12610
+ sub_layer_profile_present_flags.push(eg.readBoolean());
12611
+ sub_layer_level_present_flags.push(eg.readBoolean());
12612
+ }
12613
+ if (max_sub_layers_minus1 > 0) {
12614
+ for (var _i = max_sub_layers_minus1; _i < 8; _i++) {
12615
+ eg.readBits(2);
12616
+ }
12617
+ }
12618
+ for (var _i2 = 0; _i2 < max_sub_layers_minus1; _i2++) {
12619
+ if (sub_layer_profile_present_flags[_i2]) {
12620
+ eg.readUByte(); // sub_layer_profile_space, sub_layer_tier_flag, sub_layer_profile_idc
12621
+ eg.readUByte();
12622
+ eg.readUByte();
12623
+ eg.readUByte();
12624
+ eg.readUByte(); // sub_layer_profile_compatibility_flag
12625
+ eg.readUByte();
12626
+ eg.readUByte();
12627
+ eg.readUByte();
12628
+ eg.readUByte();
12629
+ eg.readUByte();
12630
+ eg.readUByte();
12631
+ }
12632
+ if (sub_layer_level_present_flags[_i2]) {
12633
+ eg.readUByte();
12634
+ }
12635
+ }
12636
+ eg.readUEG(); // seq_parameter_set_id
12637
+ var chroma_format_idc = eg.readUEG();
12638
+ if (chroma_format_idc == 3) {
12639
+ eg.skipBits(1); //separate_colour_plane_flag
12640
+ }
12641
+ var pic_width_in_luma_samples = eg.readUEG();
12642
+ var pic_height_in_luma_samples = eg.readUEG();
12643
+ var conformance_window_flag = eg.readBoolean();
12644
+ var pic_left_offset = 0,
12645
+ pic_right_offset = 0,
12646
+ pic_top_offset = 0,
12647
+ pic_bottom_offset = 0;
12648
+ if (conformance_window_flag) {
12649
+ pic_left_offset += eg.readUEG();
12650
+ pic_right_offset += eg.readUEG();
12651
+ pic_top_offset += eg.readUEG();
12652
+ pic_bottom_offset += eg.readUEG();
12653
+ }
12654
+ var bit_depth_luma_minus8 = eg.readUEG();
12655
+ var bit_depth_chroma_minus8 = eg.readUEG();
12656
+ var log2_max_pic_order_cnt_lsb_minus4 = eg.readUEG();
12657
+ var sub_layer_ordering_info_present_flag = eg.readBoolean();
12658
+ for (var _i3 = sub_layer_ordering_info_present_flag ? 0 : max_sub_layers_minus1; _i3 <= max_sub_layers_minus1; _i3++) {
12659
+ eg.skipUEG(); // max_dec_pic_buffering_minus1[i]
12660
+ eg.skipUEG(); // max_num_reorder_pics[i]
12661
+ eg.skipUEG(); // max_latency_increase_plus1[i]
12662
+ }
12663
+ eg.skipUEG(); // log2_min_luma_coding_block_size_minus3
12664
+ eg.skipUEG(); // log2_diff_max_min_luma_coding_block_size
12665
+ eg.skipUEG(); // log2_min_transform_block_size_minus2
12666
+ eg.skipUEG(); // log2_diff_max_min_transform_block_size
12667
+ eg.skipUEG(); // max_transform_hierarchy_depth_inter
12668
+ eg.skipUEG(); // max_transform_hierarchy_depth_intra
12669
+ var scaling_list_enabled_flag = eg.readBoolean();
12670
+ if (scaling_list_enabled_flag) {
12671
+ var sps_scaling_list_data_present_flag = eg.readBoolean();
12672
+ if (sps_scaling_list_data_present_flag) {
12673
+ for (var sizeId = 0; sizeId < 4; sizeId++) {
12674
+ for (var matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) {
12675
+ var scaling_list_pred_mode_flag = eg.readBoolean();
12676
+ if (!scaling_list_pred_mode_flag) {
12677
+ eg.readUEG(); // scaling_list_pred_matrix_id_delta
12678
+ } else {
12679
+ var coefNum = Math.min(64, 1 << 4 + (sizeId << 1));
12680
+ if (sizeId > 1) {
12681
+ eg.readEG();
12682
+ }
12683
+ for (var _i4 = 0; _i4 < coefNum; _i4++) {
12684
+ eg.readEG();
12685
+ }
12206
12686
  }
12207
12687
  }
12208
12688
  }
12209
- // check if we can read unit type
12210
- if (i < len) {
12211
- unitType = array[i] & 0x1f;
12212
- // logger.log('find NALU @ offset:' + i + ',type:' + unitType);
12213
- lastUnitStart = i;
12214
- lastUnitType = unitType;
12215
- state = 0;
12216
- } else {
12217
- // not enough byte to read unit type. let's read it on next PES parsing
12218
- state = -1;
12219
- }
12220
- } else {
12221
- state = 0;
12222
12689
  }
12223
12690
  }
12224
- if (lastUnitStart >= 0 && state >= 0) {
12225
- var _unit = {
12226
- data: array.subarray(lastUnitStart, len),
12227
- type: lastUnitType,
12228
- state: state
12229
- };
12230
- units.push(_unit);
12231
- // logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
12232
- }
12233
- // no NALu found
12234
- if (units.length === 0) {
12235
- // append pes.data to previous NAL unit
12236
- var _lastUnit = this.getLastNalUnit(track.samples);
12237
- if (_lastUnit) {
12238
- _lastUnit.data = appendUint8Array(_lastUnit.data, array);
12691
+ eg.readBoolean(); // amp_enabled_flag
12692
+ eg.readBoolean(); // sample_adaptive_offset_enabled_flag
12693
+ var pcm_enabled_flag = eg.readBoolean();
12694
+ if (pcm_enabled_flag) {
12695
+ eg.readUByte();
12696
+ eg.skipUEG();
12697
+ eg.skipUEG();
12698
+ eg.readBoolean();
12699
+ }
12700
+ var num_short_term_ref_pic_sets = eg.readUEG();
12701
+ var num_delta_pocs = 0;
12702
+ for (var _i5 = 0; _i5 < num_short_term_ref_pic_sets; _i5++) {
12703
+ var inter_ref_pic_set_prediction_flag = false;
12704
+ if (_i5 !== 0) {
12705
+ inter_ref_pic_set_prediction_flag = eg.readBoolean();
12706
+ }
12707
+ if (inter_ref_pic_set_prediction_flag) {
12708
+ if (_i5 === num_short_term_ref_pic_sets) {
12709
+ eg.readUEG();
12710
+ }
12711
+ eg.readBoolean();
12712
+ eg.readUEG();
12713
+ var next_num_delta_pocs = 0;
12714
+ for (var j = 0; j <= num_delta_pocs; j++) {
12715
+ var used_by_curr_pic_flag = eg.readBoolean();
12716
+ var use_delta_flag = false;
12717
+ if (!used_by_curr_pic_flag) {
12718
+ use_delta_flag = eg.readBoolean();
12719
+ }
12720
+ if (used_by_curr_pic_flag || use_delta_flag) {
12721
+ next_num_delta_pocs++;
12722
+ }
12723
+ }
12724
+ num_delta_pocs = next_num_delta_pocs;
12725
+ } else {
12726
+ var num_negative_pics = eg.readUEG();
12727
+ var num_positive_pics = eg.readUEG();
12728
+ num_delta_pocs = num_negative_pics + num_positive_pics;
12729
+ for (var _j = 0; _j < num_negative_pics; _j++) {
12730
+ eg.readUEG();
12731
+ eg.readBoolean();
12732
+ }
12733
+ for (var _j2 = 0; _j2 < num_positive_pics; _j2++) {
12734
+ eg.readUEG();
12735
+ eg.readBoolean();
12736
+ }
12737
+ }
12738
+ }
12739
+ var long_term_ref_pics_present_flag = eg.readBoolean();
12740
+ if (long_term_ref_pics_present_flag) {
12741
+ var num_long_term_ref_pics_sps = eg.readUEG();
12742
+ for (var _i6 = 0; _i6 < num_long_term_ref_pics_sps; _i6++) {
12743
+ for (var _j3 = 0; _j3 < log2_max_pic_order_cnt_lsb_minus4 + 4; _j3++) {
12744
+ eg.readBits(1);
12745
+ }
12746
+ eg.readBits(1);
12747
+ }
12748
+ }
12749
+ var min_spatial_segmentation_idc = 0;
12750
+ var sar_width = 1,
12751
+ sar_height = 1;
12752
+ var fps_fixed = true,
12753
+ fps_den = 1,
12754
+ fps_num = 0;
12755
+ eg.readBoolean(); // sps_temporal_mvp_enabled_flag
12756
+ eg.readBoolean(); // strong_intra_smoothing_enabled_flag
12757
+ var default_display_window_flag = false;
12758
+ var vui_parameters_present_flag = eg.readBoolean();
12759
+ if (vui_parameters_present_flag) {
12760
+ var aspect_ratio_info_present_flag = eg.readBoolean();
12761
+ if (aspect_ratio_info_present_flag) {
12762
+ var aspect_ratio_idc = eg.readUByte();
12763
+ var sar_width_table = [1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2];
12764
+ var sar_height_table = [1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1];
12765
+ if (aspect_ratio_idc > 0 && aspect_ratio_idc < 16) {
12766
+ sar_width = sar_width_table[aspect_ratio_idc - 1];
12767
+ sar_height = sar_height_table[aspect_ratio_idc - 1];
12768
+ } else if (aspect_ratio_idc === 255) {
12769
+ sar_width = eg.readBits(16);
12770
+ sar_height = eg.readBits(16);
12771
+ }
12772
+ }
12773
+ var overscan_info_present_flag = eg.readBoolean();
12774
+ if (overscan_info_present_flag) {
12775
+ eg.readBoolean();
12776
+ }
12777
+ var video_signal_type_present_flag = eg.readBoolean();
12778
+ if (video_signal_type_present_flag) {
12779
+ eg.readBits(3);
12780
+ eg.readBoolean();
12781
+ var colour_description_present_flag = eg.readBoolean();
12782
+ if (colour_description_present_flag) {
12783
+ eg.readUByte();
12784
+ eg.readUByte();
12785
+ eg.readUByte();
12786
+ }
12787
+ }
12788
+ var chroma_loc_info_present_flag = eg.readBoolean();
12789
+ if (chroma_loc_info_present_flag) {
12790
+ eg.readUEG();
12791
+ eg.readUEG();
12792
+ }
12793
+ eg.readBoolean(); // neutral_chroma_indication_flag
12794
+ eg.readBoolean(); // field_seq_flag
12795
+ eg.readBoolean(); // frame_field_info_present_flag
12796
+ default_display_window_flag = eg.readBoolean();
12797
+ if (default_display_window_flag) {
12798
+ pic_left_offset += eg.readUEG();
12799
+ pic_right_offset += eg.readUEG();
12800
+ pic_top_offset += eg.readUEG();
12801
+ pic_bottom_offset += eg.readUEG();
12802
+ }
12803
+ var vui_timing_info_present_flag = eg.readBoolean();
12804
+ if (vui_timing_info_present_flag) {
12805
+ fps_den = eg.readBits(32);
12806
+ fps_num = eg.readBits(32);
12807
+ var vui_poc_proportional_to_timing_flag = eg.readBoolean();
12808
+ if (vui_poc_proportional_to_timing_flag) {
12809
+ eg.readUEG();
12810
+ }
12811
+ var vui_hrd_parameters_present_flag = eg.readBoolean();
12812
+ if (vui_hrd_parameters_present_flag) {
12813
+ //const commonInfPresentFlag = true;
12814
+ //if (commonInfPresentFlag) {
12815
+ var nal_hrd_parameters_present_flag = eg.readBoolean();
12816
+ var vcl_hrd_parameters_present_flag = eg.readBoolean();
12817
+ var sub_pic_hrd_params_present_flag = false;
12818
+ if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
12819
+ sub_pic_hrd_params_present_flag = eg.readBoolean();
12820
+ if (sub_pic_hrd_params_present_flag) {
12821
+ eg.readUByte();
12822
+ eg.readBits(5);
12823
+ eg.readBoolean();
12824
+ eg.readBits(5);
12825
+ }
12826
+ eg.readBits(4); // bit_rate_scale
12827
+ eg.readBits(4); // cpb_size_scale
12828
+ if (sub_pic_hrd_params_present_flag) {
12829
+ eg.readBits(4);
12830
+ }
12831
+ eg.readBits(5);
12832
+ eg.readBits(5);
12833
+ eg.readBits(5);
12834
+ }
12835
+ //}
12836
+ for (var _i7 = 0; _i7 <= max_sub_layers_minus1; _i7++) {
12837
+ fps_fixed = eg.readBoolean(); // fixed_pic_rate_general_flag
12838
+ var fixed_pic_rate_within_cvs_flag = fps_fixed || eg.readBoolean();
12839
+ var low_delay_hrd_flag = false;
12840
+ if (fixed_pic_rate_within_cvs_flag) {
12841
+ eg.readEG();
12842
+ } else {
12843
+ low_delay_hrd_flag = eg.readBoolean();
12844
+ }
12845
+ var cpb_cnt = low_delay_hrd_flag ? 1 : eg.readUEG() + 1;
12846
+ if (nal_hrd_parameters_present_flag) {
12847
+ for (var _j4 = 0; _j4 < cpb_cnt; _j4++) {
12848
+ eg.readUEG();
12849
+ eg.readUEG();
12850
+ if (sub_pic_hrd_params_present_flag) {
12851
+ eg.readUEG();
12852
+ eg.readUEG();
12853
+ }
12854
+ eg.skipBits(1);
12855
+ }
12856
+ }
12857
+ if (vcl_hrd_parameters_present_flag) {
12858
+ for (var _j5 = 0; _j5 < cpb_cnt; _j5++) {
12859
+ eg.readUEG();
12860
+ eg.readUEG();
12861
+ if (sub_pic_hrd_params_present_flag) {
12862
+ eg.readUEG();
12863
+ eg.readUEG();
12864
+ }
12865
+ eg.skipBits(1);
12866
+ }
12867
+ }
12868
+ }
12869
+ }
12239
12870
  }
12871
+ var bitstream_restriction_flag = eg.readBoolean();
12872
+ if (bitstream_restriction_flag) {
12873
+ eg.readBoolean(); // tiles_fixed_structure_flag
12874
+ eg.readBoolean(); // motion_vectors_over_pic_boundaries_flag
12875
+ eg.readBoolean(); // restricted_ref_pic_lists_flag
12876
+ min_spatial_segmentation_idc = eg.readUEG();
12877
+ }
12878
+ }
12879
+ var width = pic_width_in_luma_samples,
12880
+ height = pic_height_in_luma_samples;
12881
+ if (conformance_window_flag || default_display_window_flag) {
12882
+ var chroma_scale_w = 1,
12883
+ chroma_scale_h = 1;
12884
+ if (chroma_format_idc === 1) {
12885
+ // YUV 420
12886
+ chroma_scale_w = chroma_scale_h = 2;
12887
+ } else if (chroma_format_idc == 2) {
12888
+ // YUV 422
12889
+ chroma_scale_w = 2;
12890
+ }
12891
+ width = pic_width_in_luma_samples - chroma_scale_w * pic_right_offset - chroma_scale_w * pic_left_offset;
12892
+ height = pic_height_in_luma_samples - chroma_scale_h * pic_bottom_offset - chroma_scale_h * pic_top_offset;
12893
+ }
12894
+ var profile_space_string = general_profile_space ? ['A', 'B', 'C'][general_profile_space] : '';
12895
+ 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;
12896
+ var profile_compatibility_rev = 0;
12897
+ for (var _i8 = 0; _i8 < 32; _i8++) {
12898
+ profile_compatibility_rev = (profile_compatibility_rev | (profile_compatibility_buf >> _i8 & 1) << 31 - _i8) >>> 0; // reverse bit position (and cast as UInt32)
12899
+ }
12900
+ var profile_compatibility_flags_string = profile_compatibility_rev.toString(16);
12901
+ if (general_profile_idc === 1 && profile_compatibility_flags_string === '2') {
12902
+ profile_compatibility_flags_string = '6';
12903
+ }
12904
+ var tier_flag_string = general_tier_flag ? 'H' : 'L';
12905
+ return {
12906
+ codecString: "hvc1." + profile_space_string + general_profile_idc + "." + profile_compatibility_flags_string + "." + tier_flag_string + general_level_idc + ".B0",
12907
+ params: {
12908
+ general_tier_flag: general_tier_flag,
12909
+ general_profile_idc: general_profile_idc,
12910
+ general_profile_space: general_profile_space,
12911
+ general_profile_compatibility_flags: [general_profile_compatibility_flags_1, general_profile_compatibility_flags_2, general_profile_compatibility_flags_3, general_profile_compatibility_flags_4],
12912
+ 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],
12913
+ general_level_idc: general_level_idc,
12914
+ bit_depth: bit_depth_luma_minus8 + 8,
12915
+ bit_depth_luma_minus8: bit_depth_luma_minus8,
12916
+ bit_depth_chroma_minus8: bit_depth_chroma_minus8,
12917
+ min_spatial_segmentation_idc: min_spatial_segmentation_idc,
12918
+ chroma_format_idc: chroma_format_idc,
12919
+ frame_rate: {
12920
+ fixed: fps_fixed,
12921
+ fps: fps_num / fps_den
12922
+ }
12923
+ },
12924
+ width: width,
12925
+ height: height,
12926
+ pixelRatio: [sar_width, sar_height]
12927
+ };
12928
+ };
12929
+ _proto.readPPS = function readPPS(pps) {
12930
+ var eg = new ExpGolomb(this.ebsp2rbsp(pps));
12931
+ eg.readUByte();
12932
+ eg.readUByte();
12933
+ eg.skipUEG(); // pic_parameter_set_id
12934
+ eg.skipUEG(); // seq_parameter_set_id
12935
+ eg.skipBits(2); // dependent_slice_segments_enabled_flag, output_flag_present_flag
12936
+ eg.skipBits(3); // num_extra_slice_header_bits
12937
+ eg.skipBits(2); // sign_data_hiding_enabled_flag, cabac_init_present_flag
12938
+ eg.skipUEG();
12939
+ eg.skipUEG();
12940
+ eg.skipEG(); // init_qp_minus26
12941
+ eg.skipBits(2); // constrained_intra_pred_flag, transform_skip_enabled_flag
12942
+ var cu_qp_delta_enabled_flag = eg.readBoolean();
12943
+ if (cu_qp_delta_enabled_flag) {
12944
+ eg.skipUEG();
12945
+ }
12946
+ eg.skipEG(); // cb_qp_offset
12947
+ eg.skipEG(); // cr_qp_offset
12948
+ eg.skipBits(4); // pps_slice_chroma_qp_offsets_present_flag, weighted_pred_flag, weighted_bipred_flag, transquant_bypass_enabled_flag
12949
+ var tiles_enabled_flag = eg.readBoolean();
12950
+ var entropy_coding_sync_enabled_flag = eg.readBoolean();
12951
+ var parallelismType = 1; // slice-based parallel decoding
12952
+ if (entropy_coding_sync_enabled_flag && tiles_enabled_flag) {
12953
+ parallelismType = 0; // mixed-type parallel decoding
12954
+ } else if (entropy_coding_sync_enabled_flag) {
12955
+ parallelismType = 3; // wavefront-based parallel decoding
12956
+ } else if (tiles_enabled_flag) {
12957
+ parallelismType = 2; // tile-based parallel decoding
12240
12958
  }
12241
- track.naluState = state;
12242
- return units;
12959
+ return {
12960
+ parallelismType: parallelismType
12961
+ };
12243
12962
  };
12244
- return AvcVideoParser;
12963
+ _proto.matchSPS = function matchSPS(sps1, sps2) {
12964
+ // compare without headers and VPS related params
12965
+ return String.fromCharCode.apply(null, sps1).substr(3) === String.fromCharCode.apply(null, sps2).substr(3);
12966
+ };
12967
+ return HevcVideoParser;
12245
12968
  }(BaseVideoParser);
12246
12969
 
12247
12970
  /**
@@ -12259,7 +12982,7 @@
12259
12982
  }
12260
12983
  var _proto = SampleAesDecrypter.prototype;
12261
12984
  _proto.decryptBuffer = function decryptBuffer(encryptedData) {
12262
- return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
12985
+ return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
12263
12986
  }
12264
12987
 
12265
12988
  // AAC - encrypt all full 16 bytes blocks starting from offset 16
@@ -12378,7 +13101,7 @@
12378
13101
  this.observer = observer;
12379
13102
  this.config = config;
12380
13103
  this.typeSupported = typeSupported;
12381
- this.videoParser = new AvcVideoParser();
13104
+ this.videoParser = null;
12382
13105
  }
12383
13106
  TSDemuxer.probe = function probe(data) {
12384
13107
  var syncOffset = TSDemuxer.syncOffset(data);
@@ -12548,7 +13271,19 @@
12548
13271
  case videoPid:
12549
13272
  if (stt) {
12550
13273
  if (videoData && (pes = parsePES(videoData))) {
12551
- this.videoParser.parseAVCPES(videoTrack, textTrack, pes, false, this._duration);
13274
+ if (this.videoParser === null) {
13275
+ switch (videoTrack.segmentCodec) {
13276
+ case 'avc':
13277
+ this.videoParser = new AvcVideoParser();
13278
+ break;
13279
+ case 'hevc':
13280
+ this.videoParser = new HevcVideoParser();
13281
+ break;
13282
+ }
13283
+ }
13284
+ if (this.videoParser !== null) {
13285
+ this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
13286
+ }
12552
13287
  }
12553
13288
  videoData = {
12554
13289
  data: [],
@@ -12711,8 +13446,20 @@
12711
13446
  // try to parse last PES packets
12712
13447
  var pes;
12713
13448
  if (videoData && (pes = parsePES(videoData))) {
12714
- this.videoParser.parseAVCPES(videoTrack, textTrack, pes, true, this._duration);
12715
- videoTrack.pesData = null;
13449
+ if (this.videoParser === null) {
13450
+ switch (videoTrack.segmentCodec) {
13451
+ case 'avc':
13452
+ this.videoParser = new AvcVideoParser();
13453
+ break;
13454
+ case 'hevc':
13455
+ this.videoParser = new HevcVideoParser();
13456
+ break;
13457
+ }
13458
+ }
13459
+ if (this.videoParser !== null) {
13460
+ this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
13461
+ videoTrack.pesData = null;
13462
+ }
12716
13463
  } else {
12717
13464
  // either avcData null or PES truncated, keep it for next frag parsing
12718
13465
  videoTrack.pesData = videoData;
@@ -13044,7 +13791,12 @@
13044
13791
  logger.warn('Unsupported EC-3 in M2TS found');
13045
13792
  break;
13046
13793
  case 0x24:
13047
- logger.warn('Unsupported HEVC in M2TS found');
13794
+ // ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
13795
+ if (result.videoPid === -1) {
13796
+ result.videoPid = pid;
13797
+ result.segmentVideoCodec = 'hevc';
13798
+ logger.log('HEVC in M2TS found');
13799
+ }
13048
13800
  break;
13049
13801
  }
13050
13802
  // move to the next table entry
@@ -13272,6 +14024,8 @@
13272
14024
  avc1: [],
13273
14025
  // codingname
13274
14026
  avcC: [],
14027
+ hvc1: [],
14028
+ hvcC: [],
13275
14029
  btrt: [],
13276
14030
  dinf: [],
13277
14031
  dref: [],
@@ -13699,8 +14453,10 @@
13699
14453
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
13700
14454
  }
13701
14455
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
13702
- } else {
14456
+ } else if (track.segmentCodec === 'avc') {
13703
14457
  return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
14458
+ } else {
14459
+ return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
13704
14460
  }
13705
14461
  };
13706
14462
  MP4.tkhd = function tkhd(track) {
@@ -13838,6 +14594,84 @@
13838
14594
  var result = appendUint8Array(MP4.FTYP, movie);
13839
14595
  return result;
13840
14596
  };
14597
+ MP4.hvc1 = function hvc1(track) {
14598
+ var ps = track.params;
14599
+ var units = [track.vps, track.sps, track.pps];
14600
+ var NALuLengthSize = 4;
14601
+ 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]);
14602
+
14603
+ // compute hvcC size in bytes
14604
+ var length = config.length;
14605
+ for (var i = 0; i < units.length; i += 1) {
14606
+ length += 3;
14607
+ for (var j = 0; j < units[i].length; j += 1) {
14608
+ length += 2 + units[i][j].length;
14609
+ }
14610
+ }
14611
+ var hvcC = new Uint8Array(length);
14612
+ hvcC.set(config, 0);
14613
+ length = config.length;
14614
+ // append parameter set units: one vps, one or more sps and pps
14615
+ var iMax = units.length - 1;
14616
+ for (var _i = 0; _i < units.length; _i += 1) {
14617
+ hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
14618
+ length += 3;
14619
+ for (var _j = 0; _j < units[_i].length; _j += 1) {
14620
+ hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
14621
+ length += 2;
14622
+ hvcC.set(units[_i][_j], length);
14623
+ length += units[_i][_j].length;
14624
+ }
14625
+ }
14626
+ var hvcc = MP4.box(MP4.types.hvcC, hvcC);
14627
+ var width = track.width;
14628
+ var height = track.height;
14629
+ var hSpacing = track.pixelRatio[0];
14630
+ var vSpacing = track.pixelRatio[1];
14631
+ return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
14632
+ // reserved
14633
+ 0x00, 0x00, 0x00,
14634
+ // reserved
14635
+ 0x00, 0x01,
14636
+ // data_reference_index
14637
+ 0x00, 0x00,
14638
+ // pre_defined
14639
+ 0x00, 0x00,
14640
+ // reserved
14641
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14642
+ // pre_defined
14643
+ width >> 8 & 0xff, width & 0xff,
14644
+ // width
14645
+ height >> 8 & 0xff, height & 0xff,
14646
+ // height
14647
+ 0x00, 0x48, 0x00, 0x00,
14648
+ // horizresolution
14649
+ 0x00, 0x48, 0x00, 0x00,
14650
+ // vertresolution
14651
+ 0x00, 0x00, 0x00, 0x00,
14652
+ // reserved
14653
+ 0x00, 0x01,
14654
+ // frame_count
14655
+ 0x12, 0x64, 0x61, 0x69, 0x6c,
14656
+ // dailymotion/hls.js
14657
+ 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,
14658
+ // compressorname
14659
+ 0x00, 0x18,
14660
+ // depth = 24
14661
+ 0x11, 0x11]),
14662
+ // pre_defined = -1
14663
+ hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
14664
+ // bufferSizeDB
14665
+ 0x00, 0x2d, 0xc6, 0xc0,
14666
+ // maxBitrate
14667
+ 0x00, 0x2d, 0xc6, 0xc0])),
14668
+ // avgBitrate
14669
+ MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
14670
+ // hSpacing
14671
+ hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
14672
+ // vSpacing
14673
+ vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
14674
+ };
13841
14675
  return MP4;
13842
14676
  }();
13843
14677
  MP4.types = void 0;
@@ -14239,9 +15073,9 @@
14239
15073
  var foundOverlap = delta < -1;
14240
15074
  if (foundHole || foundOverlap) {
14241
15075
  if (foundHole) {
14242
- logger.warn("AVC: " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
15076
+ logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
14243
15077
  } else {
14244
- logger.warn("AVC: " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
15078
+ logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
14245
15079
  }
14246
15080
  if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
14247
15081
  firstDTS = nextAvcDts;
@@ -14250,12 +15084,24 @@
14250
15084
  inputSamples[0].dts = firstDTS;
14251
15085
  inputSamples[0].pts = firstPTS;
14252
15086
  } else {
15087
+ var isPTSOrderRetained = true;
14253
15088
  for (var _i = 0; _i < inputSamples.length; _i++) {
14254
- if (inputSamples[_i].dts > firstPTS) {
15089
+ if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
14255
15090
  break;
14256
15091
  }
15092
+ var prevPTS = inputSamples[_i].pts;
14257
15093
  inputSamples[_i].dts -= delta;
14258
15094
  inputSamples[_i].pts -= delta;
15095
+
15096
+ // check to see if this sample's PTS order has changed
15097
+ // relative to the next one
15098
+ if (_i < inputSamples.length - 1) {
15099
+ var nextSamplePTS = inputSamples[_i + 1].pts;
15100
+ var currentSamplePTS = inputSamples[_i].pts;
15101
+ var currentOrder = nextSamplePTS <= currentSamplePTS;
15102
+ var prevOrder = nextSamplePTS <= prevPTS;
15103
+ isPTSOrderRetained = currentOrder == prevOrder;
15104
+ }
14259
15105
  }
14260
15106
  }
14261
15107
  logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
@@ -14403,7 +15249,7 @@
14403
15249
  }
14404
15250
  }
14405
15251
  }
14406
- // next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
15252
+ // next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
14407
15253
  mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
14408
15254
  this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
14409
15255
  this.videoSampleDuration = mp4SampleDuration;
@@ -14538,7 +15384,7 @@
14538
15384
  logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
14539
15385
  for (var j = 0; j < missing; j++) {
14540
15386
  var newStamp = Math.max(nextPts, 0);
14541
- var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
15387
+ var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
14542
15388
  if (!fillFrame) {
14543
15389
  logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
14544
15390
  fillFrame = sample.unit.subarray();
@@ -14666,7 +15512,7 @@
14666
15512
  // samples count of this segment's duration
14667
15513
  var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
14668
15514
  // silent frame
14669
- var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
15515
+ var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
14670
15516
  logger.warn('[mp4-remuxer]: remux empty Audio');
14671
15517
  // Can't remux if we can't generate a silent frame...
14672
15518
  if (!silentFrame) {
@@ -15056,13 +15902,15 @@
15056
15902
  duration = transmuxConfig.duration,
15057
15903
  initSegmentData = transmuxConfig.initSegmentData;
15058
15904
  var keyData = getEncryptionType(uintData, decryptdata);
15059
- if (keyData && keyData.method === 'AES-128') {
15905
+ if (keyData && isFullSegmentEncryption(keyData.method)) {
15060
15906
  var decrypter = this.getDecrypter();
15907
+ var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
15908
+
15061
15909
  // Software decryption is synchronous; webCrypto is not
15062
15910
  if (decrypter.isSync()) {
15063
15911
  // Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
15064
15912
  // data is handled in the flush() call
15065
- var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
15913
+ var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
15066
15914
  // For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
15067
15915
  var loadingParts = chunkMeta.part > -1;
15068
15916
  if (loadingParts) {
@@ -15074,7 +15922,7 @@
15074
15922
  }
15075
15923
  uintData = new Uint8Array(decryptedData);
15076
15924
  } else {
15077
- this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
15925
+ this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
15078
15926
  // Calling push here is important; if flush() is called while this is still resolving, this ensures that
15079
15927
  // the decrypted data has been transmuxed
15080
15928
  var result = _this.push(decryptedData, null, chunkMeta);
@@ -15695,7 +16543,7 @@
15695
16543
  observer.on(Events.ERROR, forwardMessage);
15696
16544
 
15697
16545
  // forward logger events to main thread
15698
- var forwardWorkerLogs = function forwardWorkerLogs() {
16546
+ var forwardWorkerLogs = function forwardWorkerLogs(logger) {
15699
16547
  var _loop = function _loop(logFn) {
15700
16548
  var func = function func(message) {
15701
16549
  forwardMessage('workerLog', {
@@ -15716,8 +16564,8 @@
15716
16564
  {
15717
16565
  var config = JSON.parse(data.config);
15718
16566
  self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
15719
- enableLogs(config.debug, data.id);
15720
- forwardWorkerLogs();
16567
+ var logger = enableLogs(config.debug, data.id);
16568
+ forwardWorkerLogs(logger);
15721
16569
  forwardMessage('init', null);
15722
16570
  break;
15723
16571
  }
@@ -15891,16 +16739,7 @@
15891
16739
  this.observer = new EventEmitter();
15892
16740
  this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
15893
16741
  this.observer.on(Events.ERROR, forwardMessage);
15894
- var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
15895
- isTypeSupported: function isTypeSupported() {
15896
- return false;
15897
- }
15898
- };
15899
- var m2tsTypeSupported = {
15900
- mpeg: MediaSource.isTypeSupported('audio/mpeg'),
15901
- mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
15902
- ac3: MediaSource.isTypeSupported('audio/mp4; codecs="ac-3"')
15903
- };
16742
+ var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
15904
16743
 
15905
16744
  // navigator.vendor is not always available in Web Worker
15906
16745
  // refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
@@ -16184,7 +17023,7 @@
16184
17023
  _inheritsLoose(AudioStreamController, _BaseStreamController);
16185
17024
  function AudioStreamController(hls, fragmentTracker, keyLoader) {
16186
17025
  var _this;
16187
- _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[audio-stream-controller]', PlaylistLevelType.AUDIO) || this;
17026
+ _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'audio-stream-controller', PlaylistLevelType.AUDIO) || this;
16188
17027
  _this.videoBuffer = null;
16189
17028
  _this.videoTrackCC = -1;
16190
17029
  _this.waitingVideoCC = -1;
@@ -16196,27 +17035,24 @@
16196
17035
  _this.flushing = false;
16197
17036
  _this.bufferFlushed = false;
16198
17037
  _this.cachedTrackLoadedData = null;
16199
- _this._registerListeners();
17038
+ _this.registerListeners();
16200
17039
  return _this;
16201
17040
  }
16202
17041
  var _proto = AudioStreamController.prototype;
16203
17042
  _proto.onHandlerDestroying = function onHandlerDestroying() {
16204
- this._unregisterListeners();
17043
+ this.unregisterListeners();
16205
17044
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
16206
17045
  this.mainDetails = null;
16207
17046
  this.bufferedTrack = null;
16208
17047
  this.switchingTrack = null;
16209
17048
  };
16210
- _proto._registerListeners = function _registerListeners() {
17049
+ _proto.registerListeners = function registerListeners() {
17050
+ _BaseStreamController.prototype.registerListeners.call(this);
16211
17051
  var hls = this.hls;
16212
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
16213
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
16214
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
16215
17052
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
16216
17053
  hls.on(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this);
16217
17054
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
16218
17055
  hls.on(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
16219
- hls.on(Events.ERROR, this.onError, this);
16220
17056
  hls.on(Events.BUFFER_RESET, this.onBufferReset, this);
16221
17057
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
16222
17058
  hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
@@ -16224,16 +17060,16 @@
16224
17060
  hls.on(Events.INIT_PTS_FOUND, this.onInitPtsFound, this);
16225
17061
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
16226
17062
  };
16227
- _proto._unregisterListeners = function _unregisterListeners() {
17063
+ _proto.unregisterListeners = function unregisterListeners() {
16228
17064
  var hls = this.hls;
16229
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
16230
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
16231
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
17065
+ if (!hls) {
17066
+ return;
17067
+ }
17068
+ _BaseStreamController.prototype.unregisterListeners.call(this);
16232
17069
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
16233
17070
  hls.off(Events.AUDIO_TRACKS_UPDATED, this.onAudioTracksUpdated, this);
16234
17071
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
16235
17072
  hls.off(Events.AUDIO_TRACK_LOADED, this.onAudioTrackLoaded, this);
16236
- hls.off(Events.ERROR, this.onError, this);
16237
17073
  hls.off(Events.BUFFER_RESET, this.onBufferReset, this);
16238
17074
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
16239
17075
  hls.off(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
@@ -16392,12 +17228,13 @@
16392
17228
  trackId = this.trackId;
16393
17229
  var config = hls.config;
16394
17230
 
16395
- // 1. if video not attached AND
17231
+ // 1. if buffering is suspended
17232
+ // 2. if video not attached AND
16396
17233
  // start fragment already requested OR start frag prefetch not enabled
16397
- // 2. if tracks or track not loaded and selected
17234
+ // 3. if tracks or track not loaded and selected
16398
17235
  // then exit loop
16399
17236
  // => if media not attached but start frag prefetch is enabled and start frag not requested yet, we will not exit loop
16400
- if (!media && (this.startFragRequested || !config.startFragPrefetch) || !(levels != null && levels[trackId])) {
17237
+ if (!this.buffering || !media && (this.startFragRequested || !config.startFragPrefetch) || !(levels != null && levels[trackId])) {
16401
17238
  return;
16402
17239
  }
16403
17240
  var levelInfo = levels[trackId];
@@ -16583,7 +17420,7 @@
16583
17420
 
16584
17421
  // compute start position if we are aligned with the main playlist
16585
17422
  if (!this.startFragRequested && (this.mainDetails || !newDetails.live)) {
16586
- this.setStartPosition(track.details, sliding);
17423
+ this.setStartPosition(this.mainDetails || newDetails, sliding);
16587
17424
  }
16588
17425
  // only switch back to IDLE state if we were waiting for track to start downloading a new fragment
16589
17426
  if (this.state === State.WAITING_TRACK && !this.waitForCdnTuneIn(newDetails)) {
@@ -16926,7 +17763,7 @@
16926
17763
  _inheritsLoose(AudioTrackController, _BasePlaylistControll);
16927
17764
  function AudioTrackController(hls) {
16928
17765
  var _this;
16929
- _this = _BasePlaylistControll.call(this, hls, '[audio-track-controller]') || this;
17766
+ _this = _BasePlaylistControll.call(this, hls, 'audio-track-controller') || this;
16930
17767
  _this.tracks = [];
16931
17768
  _this.groupIds = null;
16932
17769
  _this.tracksInGroup = [];
@@ -17255,26 +18092,23 @@
17255
18092
  _inheritsLoose(SubtitleStreamController, _BaseStreamController);
17256
18093
  function SubtitleStreamController(hls, fragmentTracker, keyLoader) {
17257
18094
  var _this;
17258
- _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[subtitle-stream-controller]', PlaylistLevelType.SUBTITLE) || this;
18095
+ _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'subtitle-stream-controller', PlaylistLevelType.SUBTITLE) || this;
17259
18096
  _this.currentTrackId = -1;
17260
18097
  _this.tracksBuffered = [];
17261
18098
  _this.mainDetails = null;
17262
- _this._registerListeners();
18099
+ _this.registerListeners();
17263
18100
  return _this;
17264
18101
  }
17265
18102
  var _proto = SubtitleStreamController.prototype;
17266
18103
  _proto.onHandlerDestroying = function onHandlerDestroying() {
17267
- this._unregisterListeners();
18104
+ this.unregisterListeners();
17268
18105
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
17269
18106
  this.mainDetails = null;
17270
18107
  };
17271
- _proto._registerListeners = function _registerListeners() {
18108
+ _proto.registerListeners = function registerListeners() {
18109
+ _BaseStreamController.prototype.registerListeners.call(this);
17272
18110
  var hls = this.hls;
17273
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
17274
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
17275
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
17276
18111
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
17277
- hls.on(Events.ERROR, this.onError, this);
17278
18112
  hls.on(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
17279
18113
  hls.on(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
17280
18114
  hls.on(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
@@ -17282,13 +18116,10 @@
17282
18116
  hls.on(Events.BUFFER_FLUSHING, this.onBufferFlushing, this);
17283
18117
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
17284
18118
  };
17285
- _proto._unregisterListeners = function _unregisterListeners() {
18119
+ _proto.unregisterListeners = function unregisterListeners() {
18120
+ _BaseStreamController.prototype.unregisterListeners.call(this);
17286
18121
  var hls = this.hls;
17287
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
17288
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
17289
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
17290
18122
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
17291
- hls.off(Events.ERROR, this.onError, this);
17292
18123
  hls.off(Events.SUBTITLE_TRACKS_UPDATED, this.onSubtitleTracksUpdated, this);
17293
18124
  hls.off(Events.SUBTITLE_TRACK_SWITCH, this.onSubtitleTrackSwitch, this);
17294
18125
  hls.off(Events.SUBTITLE_TRACK_LOADED, this.onSubtitleTrackLoaded, this);
@@ -17486,7 +18317,7 @@
17486
18317
  track.details = newDetails;
17487
18318
  this.levelLastLoaded = track;
17488
18319
  if (!this.startFragRequested && (this.mainDetails || !newDetails.live)) {
17489
- this.setStartPosition(track.details, sliding);
18320
+ this.setStartPosition(this.mainDetails || newDetails, sliding);
17490
18321
  }
17491
18322
 
17492
18323
  // trigger handler right now
@@ -17511,10 +18342,10 @@
17511
18342
  return;
17512
18343
  }
17513
18344
  // check to see if the payload needs to be decrypted
17514
- if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
18345
+ if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
17515
18346
  var startTime = performance.now();
17516
18347
  // decrypt the subtitles
17517
- this.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
18348
+ this.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
17518
18349
  hls.trigger(Events.ERROR, {
17519
18350
  type: ErrorTypes.MEDIA_ERROR,
17520
18351
  details: ErrorDetails.FRAG_DECRYPT_ERROR,
@@ -17646,7 +18477,7 @@
17646
18477
  _inheritsLoose(SubtitleTrackController, _BasePlaylistControll);
17647
18478
  function SubtitleTrackController(hls) {
17648
18479
  var _this;
17649
- _this = _BasePlaylistControll.call(this, hls, '[subtitle-track-controller]') || this;
18480
+ _this = _BasePlaylistControll.call(this, hls, 'subtitle-track-controller') || this;
17650
18481
  _this.media = null;
17651
18482
  _this.tracks = [];
17652
18483
  _this.groupIds = null;
@@ -17655,12 +18486,12 @@
17655
18486
  _this.currentTrack = null;
17656
18487
  _this.selectDefaultTrack = true;
17657
18488
  _this.queuedDefaultTrack = -1;
17658
- _this.asyncPollTrackChange = function () {
17659
- return _this.pollTrackChange(0);
17660
- };
17661
18489
  _this.useTextTrackPolling = false;
17662
18490
  _this.subtitlePollingInterval = -1;
17663
18491
  _this._subtitleDisplay = true;
18492
+ _this.asyncPollTrackChange = function () {
18493
+ return _this.pollTrackChange(0);
18494
+ };
17664
18495
  _this.onTextTracksChanged = function () {
17665
18496
  if (!_this.useTextTrackPolling) {
17666
18497
  self.clearInterval(_this.subtitlePollingInterval);
@@ -17696,6 +18527,7 @@
17696
18527
  this.tracks.length = 0;
17697
18528
  this.tracksInGroup.length = 0;
17698
18529
  this.currentTrack = null;
18530
+ // @ts-ignore
17699
18531
  this.onTextTracksChanged = this.asyncPollTrackChange = null;
17700
18532
  _BasePlaylistControll.prototype.destroy.call(this);
17701
18533
  };
@@ -18169,57 +19001,57 @@
18169
19001
  }();
18170
19002
 
18171
19003
  var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
18172
- var BufferController = /*#__PURE__*/function () {
19004
+ var BufferController = /*#__PURE__*/function (_Logger) {
19005
+ _inheritsLoose(BufferController, _Logger);
18173
19006
  function BufferController(hls) {
18174
- var _this = this;
19007
+ var _this;
19008
+ _this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
18175
19009
  // The level details used to determine duration, target-duration and live
18176
- this.details = null;
19010
+ _this.details = null;
18177
19011
  // cache the self generated object url to detect hijack of video tag
18178
- this._objectUrl = null;
19012
+ _this._objectUrl = null;
18179
19013
  // A queue of buffer operations which require the SourceBuffer to not be updating upon execution
18180
- this.operationQueue = void 0;
19014
+ _this.operationQueue = void 0;
18181
19015
  // References to event listeners for each SourceBuffer, so that they can be referenced for event removal
18182
- this.listeners = void 0;
18183
- this.hls = void 0;
19016
+ _this.listeners = void 0;
19017
+ _this.hls = void 0;
18184
19018
  // The number of BUFFER_CODEC events received before any sourceBuffers are created
18185
- this.bufferCodecEventsExpected = 0;
19019
+ _this.bufferCodecEventsExpected = 0;
18186
19020
  // The total number of BUFFER_CODEC events received
18187
- this._bufferCodecEventsTotal = 0;
19021
+ _this._bufferCodecEventsTotal = 0;
18188
19022
  // A reference to the attached media element
18189
- this.media = null;
19023
+ _this.media = null;
18190
19024
  // A reference to the active media source
18191
- this.mediaSource = null;
19025
+ _this.mediaSource = null;
18192
19026
  // Last MP3 audio chunk appended
18193
- this.lastMpegAudioChunk = null;
18194
- this.appendSource = void 0;
19027
+ _this.lastMpegAudioChunk = null;
19028
+ _this.appendSource = void 0;
18195
19029
  // counters
18196
- this.appendErrors = {
19030
+ _this.appendErrors = {
18197
19031
  audio: 0,
18198
19032
  video: 0,
18199
19033
  audiovideo: 0
18200
19034
  };
18201
- this.tracks = {};
18202
- this.pendingTracks = {};
18203
- this.sourceBuffer = void 0;
18204
- this.log = void 0;
18205
- this.warn = void 0;
18206
- this.error = void 0;
18207
- this._onEndStreaming = function (event) {
19035
+ _this.tracks = {};
19036
+ _this.pendingTracks = {};
19037
+ _this.sourceBuffer = void 0;
19038
+ _this._onEndStreaming = function (event) {
18208
19039
  if (!_this.hls) {
18209
19040
  return;
18210
19041
  }
18211
19042
  _this.hls.pauseBuffering();
18212
19043
  };
18213
- this._onStartStreaming = function (event) {
19044
+ _this._onStartStreaming = function (event) {
18214
19045
  if (!_this.hls) {
18215
19046
  return;
18216
19047
  }
18217
19048
  _this.hls.resumeBuffering();
18218
19049
  };
18219
19050
  // Keep as arrow functions so that we can directly reference these functions directly as event listeners
18220
- this._onMediaSourceOpen = function () {
18221
- var media = _this.media,
18222
- mediaSource = _this.mediaSource;
19051
+ _this._onMediaSourceOpen = function () {
19052
+ var _assertThisInitialize = _assertThisInitialized(_this),
19053
+ media = _assertThisInitialize.media,
19054
+ mediaSource = _assertThisInitialize.mediaSource;
18223
19055
  _this.log('Media source opened');
18224
19056
  if (media) {
18225
19057
  media.removeEventListener('emptied', _this._onMediaEmptied);
@@ -18235,27 +19067,25 @@
18235
19067
  }
18236
19068
  _this.checkPendingTracks();
18237
19069
  };
18238
- this._onMediaSourceClose = function () {
19070
+ _this._onMediaSourceClose = function () {
18239
19071
  _this.log('Media source closed');
18240
19072
  };
18241
- this._onMediaSourceEnded = function () {
19073
+ _this._onMediaSourceEnded = function () {
18242
19074
  _this.log('Media source ended');
18243
19075
  };
18244
- this._onMediaEmptied = function () {
18245
- var mediaSrc = _this.mediaSrc,
18246
- _objectUrl = _this._objectUrl;
19076
+ _this._onMediaEmptied = function () {
19077
+ var _assertThisInitialize2 = _assertThisInitialized(_this),
19078
+ mediaSrc = _assertThisInitialize2.mediaSrc,
19079
+ _objectUrl = _assertThisInitialize2._objectUrl;
18247
19080
  if (mediaSrc !== _objectUrl) {
18248
- logger.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
19081
+ _this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
18249
19082
  }
18250
19083
  };
18251
- this.hls = hls;
18252
- var logPrefix = '[buffer-controller]';
18253
- this.appendSource = hls.config.preferManagedMediaSource;
18254
- this.log = logger.log.bind(logger, logPrefix);
18255
- this.warn = logger.warn.bind(logger, logPrefix);
18256
- this.error = logger.error.bind(logger, logPrefix);
18257
- this._initSourceBuffer();
18258
- this.registerListeners();
19084
+ _this.hls = hls;
19085
+ _this.appendSource = hls.config.preferManagedMediaSource;
19086
+ _this._initSourceBuffer();
19087
+ _this.registerListeners();
19088
+ return _this;
18259
19089
  }
18260
19090
  var _proto = BufferController.prototype;
18261
19091
  _proto.hasSourceTypes = function hasSourceTypes() {
@@ -18267,6 +19097,12 @@
18267
19097
  this.lastMpegAudioChunk = null;
18268
19098
  // @ts-ignore
18269
19099
  this.hls = null;
19100
+ // @ts-ignore
19101
+ this._onMediaSourceOpen = this._onMediaSourceClose = null;
19102
+ // @ts-ignore
19103
+ this._onMediaSourceEnded = null;
19104
+ // @ts-ignore
19105
+ this._onStartStreaming = this._onEndStreaming = null;
18270
19106
  };
18271
19107
  _proto.registerListeners = function registerListeners() {
18272
19108
  var hls = this.hls;
@@ -18424,6 +19260,7 @@
18424
19260
  _this2.resetBuffer(type);
18425
19261
  });
18426
19262
  this._initSourceBuffer();
19263
+ this.hls.resumeBuffering();
18427
19264
  };
18428
19265
  _proto.resetBuffer = function resetBuffer(type) {
18429
19266
  var sb = this.sourceBuffer[type];
@@ -19127,7 +19964,7 @@
19127
19964
  }
19128
19965
  }]);
19129
19966
  return BufferController;
19130
- }();
19967
+ }(Logger);
19131
19968
  function removeSourceChildren(node) {
19132
19969
  var sourceChildren = node.querySelectorAll('source');
19133
19970
  [].slice.call(sourceChildren).forEach(function (source) {
@@ -21566,14 +22403,12 @@
21566
22403
  this.cea608Parser1 = this.cea608Parser2 = undefined;
21567
22404
  };
21568
22405
  _proto.initCea608Parsers = function initCea608Parsers() {
21569
- if (this.config.enableCEA708Captions && (!this.cea608Parser1 || !this.cea608Parser2)) {
21570
- var channel1 = new OutputFilter(this, 'textTrack1');
21571
- var channel2 = new OutputFilter(this, 'textTrack2');
21572
- var channel3 = new OutputFilter(this, 'textTrack3');
21573
- var channel4 = new OutputFilter(this, 'textTrack4');
21574
- this.cea608Parser1 = new Cea608Parser(1, channel1, channel2);
21575
- this.cea608Parser2 = new Cea608Parser(3, channel3, channel4);
21576
- }
22406
+ var channel1 = new OutputFilter(this, 'textTrack1');
22407
+ var channel2 = new OutputFilter(this, 'textTrack2');
22408
+ var channel3 = new OutputFilter(this, 'textTrack3');
22409
+ var channel4 = new OutputFilter(this, 'textTrack4');
22410
+ this.cea608Parser1 = new Cea608Parser(1, channel1, channel2);
22411
+ this.cea608Parser2 = new Cea608Parser(3, channel3, channel4);
21577
22412
  };
21578
22413
  _proto.addCues = function addCues(trackName, startTime, endTime, screen, cueRanges) {
21579
22414
  // skip cues which overlap more than 50% with previously parsed time ranges
@@ -21808,7 +22643,7 @@
21808
22643
  return t.label;
21809
22644
  });
21810
22645
  if (unusedTextTracks.length) {
21811
- logger.warn("Media element contains unused subtitle tracks: " + unusedTextTracks.join(', ') + ". Replace media element for each source to clear TextTracks and captions menu.");
22646
+ this.hls.logger.warn("Media element contains unused subtitle tracks: " + unusedTextTracks.join(', ') + ". Replace media element for each source to clear TextTracks and captions menu.");
21812
22647
  }
21813
22648
  }
21814
22649
  } else if (this.tracks.length) {
@@ -21854,23 +22689,20 @@
21854
22689
  return level == null ? void 0 : level.attrs['CLOSED-CAPTIONS'];
21855
22690
  };
21856
22691
  _proto.onFragLoading = function onFragLoading(event, data) {
21857
- this.initCea608Parsers();
21858
- var cea608Parser1 = this.cea608Parser1,
21859
- cea608Parser2 = this.cea608Parser2,
21860
- lastCc = this.lastCc,
21861
- lastSn = this.lastSn,
21862
- lastPartIndex = this.lastPartIndex;
21863
- if (!this.enabled || !cea608Parser1 || !cea608Parser2) {
21864
- return;
21865
- }
21866
22692
  // if this frag isn't contiguous, clear the parser so cues with bad start/end times aren't added to the textTrack
21867
- if (data.frag.type === PlaylistLevelType.MAIN) {
22693
+ if (this.enabled && data.frag.type === PlaylistLevelType.MAIN) {
21868
22694
  var _data$part$index, _data$part;
22695
+ var cea608Parser1 = this.cea608Parser1,
22696
+ cea608Parser2 = this.cea608Parser2,
22697
+ lastSn = this.lastSn;
22698
+ if (!cea608Parser1 || !cea608Parser2) {
22699
+ return;
22700
+ }
21869
22701
  var _data$frag = data.frag,
21870
22702
  cc = _data$frag.cc,
21871
22703
  sn = _data$frag.sn;
21872
- var partIndex = (_data$part$index = data == null ? void 0 : (_data$part = data.part) == null ? void 0 : _data$part.index) != null ? _data$part$index : -1;
21873
- if (!(sn === lastSn + 1 || sn === lastSn && partIndex === lastPartIndex + 1 || cc === lastCc)) {
22704
+ var partIndex = (_data$part$index = (_data$part = data.part) == null ? void 0 : _data$part.index) != null ? _data$part$index : -1;
22705
+ if (!(sn === lastSn + 1 || sn === lastSn && partIndex === this.lastPartIndex + 1 || cc === this.lastCc)) {
21874
22706
  cea608Parser1.reset();
21875
22707
  cea608Parser2.reset();
21876
22708
  }
@@ -21926,7 +22758,7 @@
21926
22758
  frag: frag
21927
22759
  });
21928
22760
  }, function (error) {
21929
- logger.log("Failed to parse IMSC1: " + error);
22761
+ hls.logger.log("Failed to parse IMSC1: " + error);
21930
22762
  hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
21931
22763
  success: false,
21932
22764
  frag: frag,
@@ -21964,7 +22796,7 @@
21964
22796
  _this5._fallbackToIMSC1(frag, payload);
21965
22797
  }
21966
22798
  // Something went wrong while parsing. Trigger event with success false.
21967
- logger.log("Failed to parse VTT cue: " + error);
22799
+ hls.logger.log("Failed to parse VTT cue: " + error);
21968
22800
  if (missingInitPTS && maxAvCC > frag.cc) {
21969
22801
  return;
21970
22802
  }
@@ -22026,10 +22858,7 @@
22026
22858
  this.captionsTracks = {};
22027
22859
  };
22028
22860
  _proto.onFragParsingUserdata = function onFragParsingUserdata(event, data) {
22029
- this.initCea608Parsers();
22030
- var cea608Parser1 = this.cea608Parser1,
22031
- cea608Parser2 = this.cea608Parser2;
22032
- if (!this.enabled || !cea608Parser1 || !cea608Parser2) {
22861
+ if (!this.enabled || !this.config.enableCEA708Captions) {
22033
22862
  return;
22034
22863
  }
22035
22864
  var frag = data.frag,
@@ -22042,9 +22871,12 @@
22042
22871
  for (var i = 0; i < samples.length; i++) {
22043
22872
  var ccBytes = samples[i].bytes;
22044
22873
  if (ccBytes) {
22874
+ if (!this.cea608Parser1) {
22875
+ this.initCea608Parsers();
22876
+ }
22045
22877
  var ccdatas = this.extractCea608Data(ccBytes);
22046
- cea608Parser1.addData(samples[i].pts, ccdatas[0]);
22047
- cea608Parser2.addData(samples[i].pts, ccdatas[1]);
22878
+ this.cea608Parser1.addData(samples[i].pts, ccdatas[0]);
22879
+ this.cea608Parser2.addData(samples[i].pts, ccdatas[1]);
22048
22880
  }
22049
22881
  }
22050
22882
  };
@@ -22236,7 +23068,7 @@
22236
23068
  var hls = this.hls;
22237
23069
  var maxLevel = this.getMaxLevel(levels.length - 1);
22238
23070
  if (maxLevel !== this.autoLevelCapping) {
22239
- logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
23071
+ hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
22240
23072
  }
22241
23073
  hls.autoLevelCapping = maxLevel;
22242
23074
  if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
@@ -22426,10 +23258,10 @@
22426
23258
  totalDroppedFrames: droppedFrames
22427
23259
  });
22428
23260
  if (droppedFPS > 0) {
22429
- // logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
23261
+ // hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
22430
23262
  if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
22431
23263
  var currentLevel = hls.currentLevel;
22432
- logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
23264
+ hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
22433
23265
  if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
22434
23266
  currentLevel = currentLevel - 1;
22435
23267
  hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
@@ -22462,7 +23294,6 @@
22462
23294
  return FPSController;
22463
23295
  }();
22464
23296
 
22465
- var LOGGER_PREFIX = '[eme]';
22466
23297
  /**
22467
23298
  * Controller to deal with encrypted media extensions (EME)
22468
23299
  * @see https://developer.mozilla.org/en-US/docs/Web/API/Encrypted_Media_Extensions_API
@@ -22470,26 +23301,122 @@
22470
23301
  * @class
22471
23302
  * @constructor
22472
23303
  */
22473
- var EMEController = /*#__PURE__*/function () {
23304
+ var EMEController = /*#__PURE__*/function (_Logger) {
23305
+ _inheritsLoose(EMEController, _Logger);
22474
23306
  function EMEController(hls) {
22475
- this.hls = void 0;
22476
- this.config = void 0;
22477
- this.media = null;
22478
- this.keyFormatPromise = null;
22479
- this.keySystemAccessPromises = {};
22480
- this._requestLicenseFailureCount = 0;
22481
- this.mediaKeySessions = [];
22482
- this.keyIdToKeySessionPromise = {};
22483
- this.setMediaKeysQueue = EMEController.CDMCleanupPromise ? [EMEController.CDMCleanupPromise] : [];
22484
- this.onMediaEncrypted = this._onMediaEncrypted.bind(this);
22485
- this.onWaitingForKey = this._onWaitingForKey.bind(this);
22486
- this.debug = logger.debug.bind(logger, LOGGER_PREFIX);
22487
- this.log = logger.log.bind(logger, LOGGER_PREFIX);
22488
- this.warn = logger.warn.bind(logger, LOGGER_PREFIX);
22489
- this.error = logger.error.bind(logger, LOGGER_PREFIX);
22490
- this.hls = hls;
22491
- this.config = hls.config;
22492
- this.registerListeners();
23307
+ var _this;
23308
+ _this = _Logger.call(this, 'eme', hls.logger) || this;
23309
+ _this.hls = void 0;
23310
+ _this.config = void 0;
23311
+ _this.media = null;
23312
+ _this.keyFormatPromise = null;
23313
+ _this.keySystemAccessPromises = {};
23314
+ _this._requestLicenseFailureCount = 0;
23315
+ _this.mediaKeySessions = [];
23316
+ _this.keyIdToKeySessionPromise = {};
23317
+ _this.setMediaKeysQueue = EMEController.CDMCleanupPromise ? [EMEController.CDMCleanupPromise] : [];
23318
+ _this.onMediaEncrypted = function (event) {
23319
+ var initDataType = event.initDataType,
23320
+ initData = event.initData;
23321
+ _this.debug("\"" + event.type + "\" event: init data type: \"" + initDataType + "\"");
23322
+
23323
+ // Ignore event when initData is null
23324
+ if (initData === null) {
23325
+ return;
23326
+ }
23327
+ var keyId;
23328
+ var keySystemDomain;
23329
+ if (initDataType === 'sinf' && _this.config.drmSystems[KeySystems.FAIRPLAY]) {
23330
+ // Match sinf keyId to playlist skd://keyId=
23331
+ var json = bin2str(new Uint8Array(initData));
23332
+ try {
23333
+ var sinf = base64Decode(JSON.parse(json).sinf);
23334
+ var tenc = parseSinf(new Uint8Array(sinf));
23335
+ if (!tenc) {
23336
+ return;
23337
+ }
23338
+ keyId = tenc.subarray(8, 24);
23339
+ keySystemDomain = KeySystems.FAIRPLAY;
23340
+ } catch (error) {
23341
+ _this.warn('Failed to parse sinf "encrypted" event message initData');
23342
+ return;
23343
+ }
23344
+ } else {
23345
+ // Support clear-lead key-session creation (otherwise depend on playlist keys)
23346
+ var psshInfo = parsePssh(initData);
23347
+ if (psshInfo === null) {
23348
+ return;
23349
+ }
23350
+ if (psshInfo.version === 0 && psshInfo.systemId === KeySystemIds.WIDEVINE && psshInfo.data) {
23351
+ keyId = psshInfo.data.subarray(8, 24);
23352
+ }
23353
+ keySystemDomain = keySystemIdToKeySystemDomain(psshInfo.systemId);
23354
+ }
23355
+ if (!keySystemDomain || !keyId) {
23356
+ return;
23357
+ }
23358
+ var keyIdHex = Hex.hexDump(keyId);
23359
+ var _assertThisInitialize = _assertThisInitialized(_this),
23360
+ keyIdToKeySessionPromise = _assertThisInitialize.keyIdToKeySessionPromise,
23361
+ mediaKeySessions = _assertThisInitialize.mediaKeySessions;
23362
+ var keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex];
23363
+ var _loop = function _loop() {
23364
+ // Match playlist key
23365
+ var keyContext = mediaKeySessions[i];
23366
+ var decryptdata = keyContext.decryptdata;
23367
+ if (decryptdata.pssh || !decryptdata.keyId) {
23368
+ return 0; // continue
23369
+ }
23370
+ var oldKeyIdHex = Hex.hexDump(decryptdata.keyId);
23371
+ if (keyIdHex === oldKeyIdHex || decryptdata.uri.replace(/-/g, '').indexOf(keyIdHex) !== -1) {
23372
+ keySessionContextPromise = keyIdToKeySessionPromise[oldKeyIdHex];
23373
+ delete keyIdToKeySessionPromise[oldKeyIdHex];
23374
+ decryptdata.pssh = new Uint8Array(initData);
23375
+ decryptdata.keyId = keyId;
23376
+ keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = keySessionContextPromise.then(function () {
23377
+ return _this.generateRequestWithPreferredKeySession(keyContext, initDataType, initData, 'encrypted-event-key-match');
23378
+ });
23379
+ return 1; // break
23380
+ }
23381
+ },
23382
+ _ret;
23383
+ for (var i = 0; i < mediaKeySessions.length; i++) {
23384
+ _ret = _loop();
23385
+ if (_ret === 0) continue;
23386
+ if (_ret === 1) break;
23387
+ }
23388
+ if (!keySessionContextPromise) {
23389
+ // Clear-lead key (not encountered in playlist)
23390
+ keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = _this.getKeySystemSelectionPromise([keySystemDomain]).then(function (_ref) {
23391
+ var _keySystemToKeySystem;
23392
+ var keySystem = _ref.keySystem,
23393
+ mediaKeys = _ref.mediaKeys;
23394
+ _this.throwIfDestroyed();
23395
+ var decryptdata = new LevelKey('ISO-23001-7', keyIdHex, (_keySystemToKeySystem = keySystemDomainToKeySystemFormat(keySystem)) != null ? _keySystemToKeySystem : '');
23396
+ decryptdata.pssh = new Uint8Array(initData);
23397
+ decryptdata.keyId = keyId;
23398
+ return _this.attemptSetMediaKeys(keySystem, mediaKeys).then(function () {
23399
+ _this.throwIfDestroyed();
23400
+ var keySessionContext = _this.createMediaKeySessionContext({
23401
+ decryptdata: decryptdata,
23402
+ keySystem: keySystem,
23403
+ mediaKeys: mediaKeys
23404
+ });
23405
+ return _this.generateRequestWithPreferredKeySession(keySessionContext, initDataType, initData, 'encrypted-event-no-match');
23406
+ });
23407
+ });
23408
+ }
23409
+ keySessionContextPromise.catch(function (error) {
23410
+ return _this.handleError(error);
23411
+ });
23412
+ };
23413
+ _this.onWaitingForKey = function (event) {
23414
+ _this.log("\"" + event.type + "\" event");
23415
+ };
23416
+ _this.hls = hls;
23417
+ _this.config = hls.config;
23418
+ _this.registerListeners();
23419
+ return _this;
22493
23420
  }
22494
23421
  var _proto = EMEController.prototype;
22495
23422
  _proto.destroy = function destroy() {
@@ -22501,9 +23428,9 @@
22501
23428
  config.licenseXhrSetup = config.licenseResponseCallback = undefined;
22502
23429
  config.drmSystems = config.drmSystemOptions = {};
22503
23430
  // @ts-ignore
22504
- this.hls = this.onMediaEncrypted = this.onWaitingForKey = this.keyIdToKeySessionPromise = null;
23431
+ this.hls = this.config = this.keyIdToKeySessionPromise = null;
22505
23432
  // @ts-ignore
22506
- this.config = null;
23433
+ this.onMediaEncrypted = this.onWaitingForKey = null;
22507
23434
  };
22508
23435
  _proto.registerListeners = function registerListeners() {
22509
23436
  this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
@@ -22542,7 +23469,7 @@
22542
23469
  }
22543
23470
  };
22544
23471
  _proto.attemptKeySystemAccess = function attemptKeySystemAccess(keySystemsToAttempt) {
22545
- var _this = this;
23472
+ var _this2 = this;
22546
23473
  var levels = this.hls.levels;
22547
23474
  var uniqueCodec = function uniqueCodec(value, i, a) {
22548
23475
  return !!value && a.indexOf(value) === i;
@@ -22559,7 +23486,7 @@
22559
23486
  return new Promise(function (resolve, reject) {
22560
23487
  var attempt = function attempt(keySystems) {
22561
23488
  var keySystem = keySystems.shift();
22562
- _this.getMediaKeysPromise(keySystem, audioCodecs, videoCodecs).then(function (mediaKeys) {
23489
+ _this2.getMediaKeysPromise(keySystem, audioCodecs, videoCodecs).then(function (mediaKeys) {
22563
23490
  return resolve({
22564
23491
  keySystem: keySystem,
22565
23492
  mediaKeys: mediaKeys
@@ -22594,7 +23521,7 @@
22594
23521
  return requestMediaKeySystemAccessFunc(keySystem, supportedConfigurations);
22595
23522
  };
22596
23523
  _proto.getMediaKeysPromise = function getMediaKeysPromise(keySystem, audioCodecs, videoCodecs) {
22597
- var _this2 = this;
23524
+ var _this3 = this;
22598
23525
  // This can throw, but is caught in event handler callpath
22599
23526
  var mediaKeySystemConfigs = getSupportedMediaKeySystemConfigurations(keySystem, audioCodecs, videoCodecs, this.config.drmSystemOptions);
22600
23527
  var keySystemAccessPromises = this.keySystemAccessPromises[keySystem];
@@ -22606,23 +23533,23 @@
22606
23533
  keySystemAccess: keySystemAccess
22607
23534
  };
22608
23535
  keySystemAccess.catch(function (error) {
22609
- _this2.log("Failed to obtain access to key-system \"" + keySystem + "\": " + error);
23536
+ _this3.log("Failed to obtain access to key-system \"" + keySystem + "\": " + error);
22610
23537
  });
22611
23538
  return keySystemAccess.then(function (mediaKeySystemAccess) {
22612
- _this2.log("Access for key-system \"" + mediaKeySystemAccess.keySystem + "\" obtained");
22613
- var certificateRequest = _this2.fetchServerCertificate(keySystem);
22614
- _this2.log("Create media-keys for \"" + keySystem + "\"");
23539
+ _this3.log("Access for key-system \"" + mediaKeySystemAccess.keySystem + "\" obtained");
23540
+ var certificateRequest = _this3.fetchServerCertificate(keySystem);
23541
+ _this3.log("Create media-keys for \"" + keySystem + "\"");
22615
23542
  _keySystemAccessPromises.mediaKeys = mediaKeySystemAccess.createMediaKeys().then(function (mediaKeys) {
22616
- _this2.log("Media-keys created for \"" + keySystem + "\"");
23543
+ _this3.log("Media-keys created for \"" + keySystem + "\"");
22617
23544
  return certificateRequest.then(function (certificate) {
22618
23545
  if (certificate) {
22619
- return _this2.setMediaKeysServerCertificate(mediaKeys, keySystem, certificate);
23546
+ return _this3.setMediaKeysServerCertificate(mediaKeys, keySystem, certificate);
22620
23547
  }
22621
23548
  return mediaKeys;
22622
23549
  });
22623
23550
  });
22624
23551
  _keySystemAccessPromises.mediaKeys.catch(function (error) {
22625
- _this2.error("Failed to create media-keys for \"" + keySystem + "\"}: " + error);
23552
+ _this3.error("Failed to create media-keys for \"" + keySystem + "\"}: " + error);
22626
23553
  });
22627
23554
  return _keySystemAccessPromises.mediaKeys;
22628
23555
  });
@@ -22631,10 +23558,10 @@
22631
23558
  return keySystemAccessPromises.mediaKeys;
22632
23559
  });
22633
23560
  };
22634
- _proto.createMediaKeySessionContext = function createMediaKeySessionContext(_ref) {
22635
- var decryptdata = _ref.decryptdata,
22636
- keySystem = _ref.keySystem,
22637
- mediaKeys = _ref.mediaKeys;
23561
+ _proto.createMediaKeySessionContext = function createMediaKeySessionContext(_ref2) {
23562
+ var decryptdata = _ref2.decryptdata,
23563
+ keySystem = _ref2.keySystem,
23564
+ mediaKeys = _ref2.mediaKeys;
22638
23565
  this.log("Creating key-system session \"" + keySystem + "\" keyId: " + Hex.hexDump(decryptdata.keyId || []));
22639
23566
  var mediaKeysSession = mediaKeys.createSession();
22640
23567
  var mediaKeySessionContext = {
@@ -22683,14 +23610,14 @@
22683
23610
  return this.keyFormatPromise;
22684
23611
  };
22685
23612
  _proto.getKeyFormatPromise = function getKeyFormatPromise(keyFormats) {
22686
- var _this3 = this;
23613
+ var _this4 = this;
22687
23614
  return new Promise(function (resolve, reject) {
22688
- var keySystemsInConfig = getKeySystemsForConfig(_this3.config);
23615
+ var keySystemsInConfig = getKeySystemsForConfig(_this4.config);
22689
23616
  var keySystemsToAttempt = keyFormats.map(keySystemFormatToKeySystemDomain).filter(function (value) {
22690
23617
  return !!value && keySystemsInConfig.indexOf(value) !== -1;
22691
23618
  });
22692
- return _this3.getKeySystemSelectionPromise(keySystemsToAttempt).then(function (_ref2) {
22693
- var keySystem = _ref2.keySystem;
23619
+ return _this4.getKeySystemSelectionPromise(keySystemsToAttempt).then(function (_ref3) {
23620
+ var keySystem = _ref3.keySystem;
22694
23621
  var keySystemFormat = keySystemDomainToKeySystemFormat(keySystem);
22695
23622
  if (keySystemFormat) {
22696
23623
  resolve(keySystemFormat);
@@ -22701,31 +23628,31 @@
22701
23628
  });
22702
23629
  };
22703
23630
  _proto.loadKey = function loadKey(data) {
22704
- var _this4 = this;
23631
+ var _this5 = this;
22705
23632
  var decryptdata = data.keyInfo.decryptdata;
22706
23633
  var keyId = this.getKeyIdString(decryptdata);
22707
23634
  var keyDetails = "(keyId: " + keyId + " format: \"" + decryptdata.keyFormat + "\" method: " + decryptdata.method + " uri: " + decryptdata.uri + ")";
22708
23635
  this.log("Starting session for key " + keyDetails);
22709
23636
  var keySessionContextPromise = this.keyIdToKeySessionPromise[keyId];
22710
23637
  if (!keySessionContextPromise) {
22711
- keySessionContextPromise = this.keyIdToKeySessionPromise[keyId] = this.getKeySystemForKeyPromise(decryptdata).then(function (_ref3) {
22712
- var keySystem = _ref3.keySystem,
22713
- mediaKeys = _ref3.mediaKeys;
22714
- _this4.throwIfDestroyed();
22715
- _this4.log("Handle encrypted media sn: " + data.frag.sn + " " + data.frag.type + ": " + data.frag.level + " using key " + keyDetails);
22716
- return _this4.attemptSetMediaKeys(keySystem, mediaKeys).then(function () {
22717
- _this4.throwIfDestroyed();
22718
- var keySessionContext = _this4.createMediaKeySessionContext({
23638
+ keySessionContextPromise = this.keyIdToKeySessionPromise[keyId] = this.getKeySystemForKeyPromise(decryptdata).then(function (_ref4) {
23639
+ var keySystem = _ref4.keySystem,
23640
+ mediaKeys = _ref4.mediaKeys;
23641
+ _this5.throwIfDestroyed();
23642
+ _this5.log("Handle encrypted media sn: " + data.frag.sn + " " + data.frag.type + ": " + data.frag.level + " using key " + keyDetails);
23643
+ return _this5.attemptSetMediaKeys(keySystem, mediaKeys).then(function () {
23644
+ _this5.throwIfDestroyed();
23645
+ var keySessionContext = _this5.createMediaKeySessionContext({
22719
23646
  keySystem: keySystem,
22720
23647
  mediaKeys: mediaKeys,
22721
23648
  decryptdata: decryptdata
22722
23649
  });
22723
23650
  var scheme = 'cenc';
22724
- return _this4.generateRequestWithPreferredKeySession(keySessionContext, scheme, decryptdata.pssh, 'playlist-key');
23651
+ return _this5.generateRequestWithPreferredKeySession(keySessionContext, scheme, decryptdata.pssh, 'playlist-key');
22725
23652
  });
22726
23653
  });
22727
23654
  keySessionContextPromise.catch(function (error) {
22728
- return _this4.handleError(error);
23655
+ return _this5.handleError(error);
22729
23656
  });
22730
23657
  }
22731
23658
  return keySessionContextPromise;
@@ -22751,128 +23678,30 @@
22751
23678
  });
22752
23679
  }
22753
23680
  };
22754
- _proto.getKeySystemForKeyPromise = function getKeySystemForKeyPromise(decryptdata) {
22755
- var keyId = this.getKeyIdString(decryptdata);
22756
- var mediaKeySessionContext = this.keyIdToKeySessionPromise[keyId];
22757
- if (!mediaKeySessionContext) {
22758
- var keySystem = keySystemFormatToKeySystemDomain(decryptdata.keyFormat);
22759
- var keySystemsToAttempt = keySystem ? [keySystem] : getKeySystemsForConfig(this.config);
22760
- return this.attemptKeySystemAccess(keySystemsToAttempt);
22761
- }
22762
- return mediaKeySessionContext;
22763
- };
22764
- _proto.getKeySystemSelectionPromise = function getKeySystemSelectionPromise(keySystemsToAttempt) {
22765
- if (!keySystemsToAttempt.length) {
22766
- keySystemsToAttempt = getKeySystemsForConfig(this.config);
22767
- }
22768
- if (keySystemsToAttempt.length === 0) {
22769
- throw new EMEKeyError({
22770
- type: ErrorTypes.KEY_SYSTEM_ERROR,
22771
- details: ErrorDetails.KEY_SYSTEM_NO_CONFIGURED_LICENSE,
22772
- fatal: true
22773
- }, "Missing key-system license configuration options " + JSON.stringify({
22774
- drmSystems: this.config.drmSystems
22775
- }));
22776
- }
22777
- return this.attemptKeySystemAccess(keySystemsToAttempt);
22778
- };
22779
- _proto._onMediaEncrypted = function _onMediaEncrypted(event) {
22780
- var _this5 = this;
22781
- var initDataType = event.initDataType,
22782
- initData = event.initData;
22783
- this.debug("\"" + event.type + "\" event: init data type: \"" + initDataType + "\"");
22784
-
22785
- // Ignore event when initData is null
22786
- if (initData === null) {
22787
- return;
22788
- }
22789
- var keyId;
22790
- var keySystemDomain;
22791
- if (initDataType === 'sinf' && this.config.drmSystems[KeySystems.FAIRPLAY]) {
22792
- // Match sinf keyId to playlist skd://keyId=
22793
- var json = bin2str(new Uint8Array(initData));
22794
- try {
22795
- var sinf = base64Decode(JSON.parse(json).sinf);
22796
- var tenc = parseSinf(new Uint8Array(sinf));
22797
- if (!tenc) {
22798
- return;
22799
- }
22800
- keyId = tenc.subarray(8, 24);
22801
- keySystemDomain = KeySystems.FAIRPLAY;
22802
- } catch (error) {
22803
- this.warn('Failed to parse sinf "encrypted" event message initData');
22804
- return;
22805
- }
22806
- } else {
22807
- // Support clear-lead key-session creation (otherwise depend on playlist keys)
22808
- var psshInfo = parsePssh(initData);
22809
- if (psshInfo === null) {
22810
- return;
22811
- }
22812
- if (psshInfo.version === 0 && psshInfo.systemId === KeySystemIds.WIDEVINE && psshInfo.data) {
22813
- keyId = psshInfo.data.subarray(8, 24);
22814
- }
22815
- keySystemDomain = keySystemIdToKeySystemDomain(psshInfo.systemId);
22816
- }
22817
- if (!keySystemDomain || !keyId) {
22818
- return;
22819
- }
22820
- var keyIdHex = Hex.hexDump(keyId);
22821
- var keyIdToKeySessionPromise = this.keyIdToKeySessionPromise,
22822
- mediaKeySessions = this.mediaKeySessions;
22823
- var keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex];
22824
- var _loop = function _loop() {
22825
- // Match playlist key
22826
- var keyContext = mediaKeySessions[i];
22827
- var decryptdata = keyContext.decryptdata;
22828
- if (decryptdata.pssh || !decryptdata.keyId) {
22829
- return 0; // continue
22830
- }
22831
- var oldKeyIdHex = Hex.hexDump(decryptdata.keyId);
22832
- if (keyIdHex === oldKeyIdHex || decryptdata.uri.replace(/-/g, '').indexOf(keyIdHex) !== -1) {
22833
- keySessionContextPromise = keyIdToKeySessionPromise[oldKeyIdHex];
22834
- delete keyIdToKeySessionPromise[oldKeyIdHex];
22835
- decryptdata.pssh = new Uint8Array(initData);
22836
- decryptdata.keyId = keyId;
22837
- keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = keySessionContextPromise.then(function () {
22838
- return _this5.generateRequestWithPreferredKeySession(keyContext, initDataType, initData, 'encrypted-event-key-match');
22839
- });
22840
- return 1; // break
22841
- }
22842
- },
22843
- _ret;
22844
- for (var i = 0; i < mediaKeySessions.length; i++) {
22845
- _ret = _loop();
22846
- if (_ret === 0) continue;
22847
- if (_ret === 1) break;
22848
- }
22849
- if (!keySessionContextPromise) {
22850
- // Clear-lead key (not encountered in playlist)
22851
- keySessionContextPromise = keyIdToKeySessionPromise[keyIdHex] = this.getKeySystemSelectionPromise([keySystemDomain]).then(function (_ref4) {
22852
- var _keySystemToKeySystem;
22853
- var keySystem = _ref4.keySystem,
22854
- mediaKeys = _ref4.mediaKeys;
22855
- _this5.throwIfDestroyed();
22856
- var decryptdata = new LevelKey('ISO-23001-7', keyIdHex, (_keySystemToKeySystem = keySystemDomainToKeySystemFormat(keySystem)) != null ? _keySystemToKeySystem : '');
22857
- decryptdata.pssh = new Uint8Array(initData);
22858
- decryptdata.keyId = keyId;
22859
- return _this5.attemptSetMediaKeys(keySystem, mediaKeys).then(function () {
22860
- _this5.throwIfDestroyed();
22861
- var keySessionContext = _this5.createMediaKeySessionContext({
22862
- decryptdata: decryptdata,
22863
- keySystem: keySystem,
22864
- mediaKeys: mediaKeys
22865
- });
22866
- return _this5.generateRequestWithPreferredKeySession(keySessionContext, initDataType, initData, 'encrypted-event-no-match');
22867
- });
22868
- });
23681
+ _proto.getKeySystemForKeyPromise = function getKeySystemForKeyPromise(decryptdata) {
23682
+ var keyId = this.getKeyIdString(decryptdata);
23683
+ var mediaKeySessionContext = this.keyIdToKeySessionPromise[keyId];
23684
+ if (!mediaKeySessionContext) {
23685
+ var keySystem = keySystemFormatToKeySystemDomain(decryptdata.keyFormat);
23686
+ var keySystemsToAttempt = keySystem ? [keySystem] : getKeySystemsForConfig(this.config);
23687
+ return this.attemptKeySystemAccess(keySystemsToAttempt);
22869
23688
  }
22870
- keySessionContextPromise.catch(function (error) {
22871
- return _this5.handleError(error);
22872
- });
23689
+ return mediaKeySessionContext;
22873
23690
  };
22874
- _proto._onWaitingForKey = function _onWaitingForKey(event) {
22875
- this.log("\"" + event.type + "\" event");
23691
+ _proto.getKeySystemSelectionPromise = function getKeySystemSelectionPromise(keySystemsToAttempt) {
23692
+ if (!keySystemsToAttempt.length) {
23693
+ keySystemsToAttempt = getKeySystemsForConfig(this.config);
23694
+ }
23695
+ if (keySystemsToAttempt.length === 0) {
23696
+ throw new EMEKeyError({
23697
+ type: ErrorTypes.KEY_SYSTEM_ERROR,
23698
+ details: ErrorDetails.KEY_SYSTEM_NO_CONFIGURED_LICENSE,
23699
+ fatal: true
23700
+ }, "Missing key-system license configuration options " + JSON.stringify({
23701
+ drmSystems: this.config.drmSystems
23702
+ }));
23703
+ }
23704
+ return this.attemptKeySystemAccess(keySystemsToAttempt);
22876
23705
  };
22877
23706
  _proto.attemptSetMediaKeys = function attemptSetMediaKeys(keySystem, mediaKeys) {
22878
23707
  var _this6 = this;
@@ -23329,7 +24158,7 @@
23329
24158
  }
23330
24159
  };
23331
24160
  return EMEController;
23332
- }();
24161
+ }(Logger);
23333
24162
  EMEController.CDMCleanupPromise = void 0;
23334
24163
  var EMEKeyError = /*#__PURE__*/function (_Error) {
23335
24164
  _inheritsLoose(EMEKeyError, _Error);
@@ -23477,18 +24306,6 @@
23477
24306
  this.params = params;
23478
24307
  };
23479
24308
 
23480
- /**
23481
- * A class to represent structured field tokens when `Symbol` is not available.
23482
- *
23483
- * @group Structured Field
23484
- *
23485
- * @beta
23486
- */
23487
- var SfToken = function SfToken(description) {
23488
- this.description = void 0;
23489
- this.description = description;
23490
- };
23491
-
23492
24309
  var DICT = 'Dict';
23493
24310
 
23494
24311
  function format(value) {
@@ -23512,29 +24329,25 @@
23512
24329
  });
23513
24330
  }
23514
24331
 
23515
- var BARE_ITEM = 'Bare Item';
23516
-
23517
- var BOOLEAN = 'Boolean';
23518
-
23519
- var BYTES = 'Byte Sequence';
23520
-
23521
- var DECIMAL = 'Decimal';
23522
-
23523
- var INTEGER = 'Integer';
23524
-
23525
- function isInvalidInt(value) {
23526
- return value < -999999999999999 || 999999999999999 < value;
24332
+ function serializeError(src, type, cause) {
24333
+ return throwError('serialize', src, type, cause);
23527
24334
  }
23528
24335
 
23529
- var STRING_REGEX = /[\x00-\x1f\x7f]+/; // eslint-disable-line no-control-regex
23530
-
23531
- var TOKEN = 'Token';
24336
+ /**
24337
+ * A class to represent structured field tokens when `Symbol` is not available.
24338
+ *
24339
+ * @group Structured Field
24340
+ *
24341
+ * @beta
24342
+ */
24343
+ var SfToken = function SfToken(description) {
24344
+ this.description = void 0;
24345
+ this.description = description;
24346
+ };
23532
24347
 
23533
- var KEY = 'Key';
24348
+ var BARE_ITEM = 'Bare Item';
23534
24349
 
23535
- function serializeError(src, type, cause) {
23536
- return throwError('serialize', src, type, cause);
23537
- }
24350
+ var BOOLEAN = 'Boolean';
23538
24351
 
23539
24352
  // 4.1.9. Serializing a Boolean
23540
24353
  //
@@ -23573,6 +24386,8 @@
23573
24386
  return btoa(String.fromCharCode.apply(String, binary));
23574
24387
  }
23575
24388
 
24389
+ var BYTES = 'Byte Sequence';
24390
+
23576
24391
  // 4.1.8. Serializing a Byte Sequence
23577
24392
  //
23578
24393
  // Given a Byte Sequence as input_bytes, return an ASCII string suitable
@@ -23604,6 +24419,12 @@
23604
24419
  return ":" + base64encode(value) + ":";
23605
24420
  }
23606
24421
 
24422
+ var INTEGER = 'Integer';
24423
+
24424
+ function isInvalidInt(value) {
24425
+ return value < -999999999999999 || 999999999999999 < value;
24426
+ }
24427
+
23607
24428
  // 4.1.4. Serializing an Integer
23608
24429
  //
23609
24430
  // Given an Integer as input_integer, return an ASCII string suitable
@@ -23669,6 +24490,8 @@
23669
24490
  }
23670
24491
  }
23671
24492
 
24493
+ var DECIMAL = 'Decimal';
24494
+
23672
24495
  // 4.1.5. Serializing a Decimal
23673
24496
  //
23674
24497
  // Given a decimal number as input_decimal, return an ASCII string
@@ -23714,6 +24537,8 @@
23714
24537
 
23715
24538
  var STRING = 'String';
23716
24539
 
24540
+ var STRING_REGEX = /[\x00-\x1f\x7f]+/; // eslint-disable-line no-control-regex
24541
+
23717
24542
  // 4.1.6. Serializing a String
23718
24543
  //
23719
24544
  // Given a String as input_string, return an ASCII string suitable for
@@ -23749,6 +24574,8 @@
23749
24574
  return symbol.description || symbol.toString().slice(7, -1);
23750
24575
  }
23751
24576
 
24577
+ var TOKEN = 'Token';
24578
+
23752
24579
  function serializeToken(token) {
23753
24580
  var value = symbolToStr(token);
23754
24581
  if (/^([a-zA-Z*])([!#$%&'*+\-.^_`|~\w:/]*)$/.test(value) === false) {
@@ -23816,6 +24643,8 @@
23816
24643
  }
23817
24644
  }
23818
24645
 
24646
+ var KEY = 'Key';
24647
+
23819
24648
  // 4.1.1.3. Serializing a Key
23820
24649
  //
23821
24650
  // Given a key as input_key, return an ASCII string suitable for use in
@@ -24067,36 +24896,6 @@
24067
24896
  return toPath.join('/');
24068
24897
  }
24069
24898
 
24070
- /**
24071
- * Generate a random v4 UUID
24072
- *
24073
- * @returns A random v4 UUID
24074
- *
24075
- * @group Utils
24076
- *
24077
- * @beta
24078
- */
24079
- function uuid() {
24080
- try {
24081
- return crypto.randomUUID();
24082
- } catch (error) {
24083
- try {
24084
- var url = URL.createObjectURL(new Blob());
24085
- var _uuid = url.toString();
24086
- URL.revokeObjectURL(url);
24087
- return _uuid.slice(_uuid.lastIndexOf('/') + 1);
24088
- } catch (error) {
24089
- var dt = new Date().getTime();
24090
- var _uuid2 = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
24091
- var r = (dt + Math.random() * 16) % 16 | 0;
24092
- dt = Math.floor(dt / 16);
24093
- return (c == 'x' ? r : r & 0x3 | 0x8).toString(16);
24094
- });
24095
- return _uuid2;
24096
- }
24097
- }
24098
- }
24099
-
24100
24899
  var toRounded = function toRounded(value) {
24101
24900
  return Math.round(value);
24102
24901
  };
@@ -24341,6 +25140,36 @@
24341
25140
  return "" + url + separator + query;
24342
25141
  }
24343
25142
 
25143
+ /**
25144
+ * Generate a random v4 UUID
25145
+ *
25146
+ * @returns A random v4 UUID
25147
+ *
25148
+ * @group Utils
25149
+ *
25150
+ * @beta
25151
+ */
25152
+ function uuid() {
25153
+ try {
25154
+ return crypto.randomUUID();
25155
+ } catch (error) {
25156
+ try {
25157
+ var url = URL.createObjectURL(new Blob());
25158
+ var _uuid = url.toString();
25159
+ URL.revokeObjectURL(url);
25160
+ return _uuid.slice(_uuid.lastIndexOf('/') + 1);
25161
+ } catch (error) {
25162
+ var dt = new Date().getTime();
25163
+ var _uuid2 = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
25164
+ var r = (dt + Math.random() * 16) % 16 | 0;
25165
+ dt = Math.floor(dt / 16);
25166
+ return (c == 'x' ? r : r & 0x3 | 0x8).toString(16);
25167
+ });
25168
+ return _uuid2;
25169
+ }
25170
+ }
25171
+ }
25172
+
24344
25173
  /**
24345
25174
  * Controller to deal with Common Media Client Data (CMCD)
24346
25175
  * @see https://cdn.cta.tech/cta/media/media/resources/standards/pdfs/cta-5004-final.pdf
@@ -24405,6 +25234,12 @@
24405
25234
  data.tb = _this.getTopBandwidth(ot) / 1000;
24406
25235
  data.bl = _this.getBufferLength(ot);
24407
25236
  }
25237
+ var next = _this.getNextFrag(fragment);
25238
+ if (next) {
25239
+ if (next.url && next.url !== fragment.url) {
25240
+ data.nor = next.url;
25241
+ }
25242
+ }
24408
25243
  _this.apply(context, data);
24409
25244
  } catch (error) {
24410
25245
  logger.warn('Could not generate segment CMCD data.', error);
@@ -24499,7 +25334,7 @@
24499
25334
  data.su = this.buffering;
24500
25335
  }
24501
25336
 
24502
- // TODO: Implement rtp, nrr, nor, dl
25337
+ // TODO: Implement rtp, nrr, dl
24503
25338
 
24504
25339
  var includeKeys = this.includeKeys;
24505
25340
  if (includeKeys) {
@@ -24508,18 +25343,31 @@
24508
25343
  return acc;
24509
25344
  }, {});
24510
25345
  }
25346
+ var options = {
25347
+ baseUrl: context.url
25348
+ };
24511
25349
  if (this.useHeaders) {
24512
25350
  if (!context.headers) {
24513
25351
  context.headers = {};
24514
25352
  }
24515
- appendCmcdHeaders(context.headers, data);
25353
+ appendCmcdHeaders(context.headers, data, options);
24516
25354
  } else {
24517
- context.url = appendCmcdQuery(context.url, data);
25355
+ context.url = appendCmcdQuery(context.url, data, options);
24518
25356
  }
24519
25357
  };
25358
+ _proto.getNextFrag = function getNextFrag(fragment) {
25359
+ var _this$hls$levels$frag;
25360
+ var levelDetails = (_this$hls$levels$frag = this.hls.levels[fragment.level]) == null ? void 0 : _this$hls$levels$frag.details;
25361
+ if (levelDetails) {
25362
+ var index = fragment.sn - levelDetails.startSN;
25363
+ return levelDetails.fragments[index + 1];
25364
+ }
25365
+ return undefined;
25366
+ }
25367
+
24520
25368
  /**
24521
25369
  * The CMCD object type.
24522
- */
25370
+ */;
24523
25371
  _proto.getObjectType = function getObjectType(fragment) {
24524
25372
  var type = fragment.type;
24525
25373
  if (type === 'subtitle') {
@@ -24655,26 +25503,28 @@
24655
25503
  }();
24656
25504
 
24657
25505
  var PATHWAY_PENALTY_DURATION_MS = 300000;
24658
- var ContentSteeringController = /*#__PURE__*/function () {
25506
+ var ContentSteeringController = /*#__PURE__*/function (_Logger) {
25507
+ _inheritsLoose(ContentSteeringController, _Logger);
24659
25508
  function ContentSteeringController(hls) {
24660
- this.hls = void 0;
24661
- this.log = void 0;
24662
- this.loader = null;
24663
- this.uri = null;
24664
- this.pathwayId = '.';
24665
- this.pathwayPriority = null;
24666
- this.timeToLoad = 300;
24667
- this.reloadTimer = -1;
24668
- this.updated = 0;
24669
- this.started = false;
24670
- this.enabled = true;
24671
- this.levels = null;
24672
- this.audioTracks = null;
24673
- this.subtitleTracks = null;
24674
- this.penalizedPathways = {};
24675
- this.hls = hls;
24676
- this.log = logger.log.bind(logger, "[content-steering]:");
24677
- this.registerListeners();
25509
+ var _this;
25510
+ _this = _Logger.call(this, 'content-steering', hls.logger) || this;
25511
+ _this.hls = void 0;
25512
+ _this.loader = null;
25513
+ _this.uri = null;
25514
+ _this.pathwayId = '.';
25515
+ _this.pathwayPriority = null;
25516
+ _this.timeToLoad = 300;
25517
+ _this.reloadTimer = -1;
25518
+ _this.updated = 0;
25519
+ _this.started = false;
25520
+ _this.enabled = true;
25521
+ _this.levels = null;
25522
+ _this.audioTracks = null;
25523
+ _this.subtitleTracks = null;
25524
+ _this.penalizedPathways = {};
25525
+ _this.hls = hls;
25526
+ _this.registerListeners();
25527
+ return _this;
24678
25528
  }
24679
25529
  var _proto = ContentSteeringController.prototype;
24680
25530
  _proto.registerListeners = function registerListeners() {
@@ -24795,7 +25645,7 @@
24795
25645
  errorAction.resolved = this.pathwayId !== errorPathway;
24796
25646
  }
24797
25647
  if (!errorAction.resolved) {
24798
- 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));
25648
+ 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));
24799
25649
  }
24800
25650
  }
24801
25651
  };
@@ -24875,7 +25725,7 @@
24875
25725
  return defaultPathway;
24876
25726
  };
24877
25727
  _proto.clonePathways = function clonePathways(pathwayClones) {
24878
- var _this = this;
25728
+ var _this2 = this;
24879
25729
  var levels = this.levels;
24880
25730
  if (!levels) {
24881
25731
  return;
@@ -24891,7 +25741,7 @@
24891
25741
  })) {
24892
25742
  return;
24893
25743
  }
24894
- var clonedVariants = _this.getLevelsForPathway(baseId).map(function (baseLevel) {
25744
+ var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
24895
25745
  var attributes = new AttrList(baseLevel.attrs);
24896
25746
  attributes['PATHWAY-ID'] = cloneId;
24897
25747
  var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
@@ -24928,12 +25778,12 @@
24928
25778
  return clonedLevel;
24929
25779
  });
24930
25780
  levels.push.apply(levels, clonedVariants);
24931
- cloneRenditionGroups(_this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
24932
- cloneRenditionGroups(_this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
25781
+ cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
25782
+ cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
24933
25783
  });
24934
25784
  };
24935
25785
  _proto.loadSteeringManifest = function loadSteeringManifest(uri) {
24936
- var _this2 = this;
25786
+ var _this3 = this;
24937
25787
  var config = this.hls.config;
24938
25788
  var Loader = config.loader;
24939
25789
  if (this.loader) {
@@ -24968,87 +25818,87 @@
24968
25818
  };
24969
25819
  var callbacks = {
24970
25820
  onSuccess: function onSuccess(response, stats, context, networkDetails) {
24971
- _this2.log("Loaded steering manifest: \"" + url + "\"");
25821
+ _this3.log("Loaded steering manifest: \"" + url + "\"");
24972
25822
  var steeringData = response.data;
24973
- if (steeringData.VERSION !== 1) {
24974
- _this2.log("Steering VERSION " + steeringData.VERSION + " not supported!");
25823
+ if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
25824
+ _this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
24975
25825
  return;
24976
25826
  }
24977
- _this2.updated = performance.now();
24978
- _this2.timeToLoad = steeringData.TTL;
25827
+ _this3.updated = performance.now();
25828
+ _this3.timeToLoad = steeringData.TTL;
24979
25829
  var reloadUri = steeringData['RELOAD-URI'],
24980
25830
  pathwayClones = steeringData['PATHWAY-CLONES'],
24981
25831
  pathwayPriority = steeringData['PATHWAY-PRIORITY'];
24982
25832
  if (reloadUri) {
24983
25833
  try {
24984
- _this2.uri = new self.URL(reloadUri, url).href;
25834
+ _this3.uri = new self.URL(reloadUri, url).href;
24985
25835
  } catch (error) {
24986
- _this2.enabled = false;
24987
- _this2.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
25836
+ _this3.enabled = false;
25837
+ _this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
24988
25838
  return;
24989
25839
  }
24990
25840
  }
24991
- _this2.scheduleRefresh(_this2.uri || context.url);
25841
+ _this3.scheduleRefresh(_this3.uri || context.url);
24992
25842
  if (pathwayClones) {
24993
- _this2.clonePathways(pathwayClones);
25843
+ _this3.clonePathways(pathwayClones);
24994
25844
  }
24995
25845
  var loadedSteeringData = {
24996
25846
  steeringManifest: steeringData,
24997
25847
  url: url.toString()
24998
25848
  };
24999
- _this2.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
25849
+ _this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
25000
25850
  if (pathwayPriority) {
25001
- _this2.updatePathwayPriority(pathwayPriority);
25851
+ _this3.updatePathwayPriority(pathwayPriority);
25002
25852
  }
25003
25853
  },
25004
25854
  onError: function onError(error, context, networkDetails, stats) {
25005
- _this2.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
25006
- _this2.stopLoad();
25855
+ _this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
25856
+ _this3.stopLoad();
25007
25857
  if (error.code === 410) {
25008
- _this2.enabled = false;
25009
- _this2.log("Steering manifest " + context.url + " no longer available");
25858
+ _this3.enabled = false;
25859
+ _this3.log("Steering manifest " + context.url + " no longer available");
25010
25860
  return;
25011
25861
  }
25012
- var ttl = _this2.timeToLoad * 1000;
25862
+ var ttl = _this3.timeToLoad * 1000;
25013
25863
  if (error.code === 429) {
25014
- var loader = _this2.loader;
25864
+ var loader = _this3.loader;
25015
25865
  if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
25016
25866
  var retryAfter = loader.getResponseHeader('Retry-After');
25017
25867
  if (retryAfter) {
25018
25868
  ttl = parseFloat(retryAfter) * 1000;
25019
25869
  }
25020
25870
  }
25021
- _this2.log("Steering manifest " + context.url + " rate limited");
25871
+ _this3.log("Steering manifest " + context.url + " rate limited");
25022
25872
  return;
25023
25873
  }
25024
- _this2.scheduleRefresh(_this2.uri || context.url, ttl);
25874
+ _this3.scheduleRefresh(_this3.uri || context.url, ttl);
25025
25875
  },
25026
25876
  onTimeout: function onTimeout(stats, context, networkDetails) {
25027
- _this2.log("Timeout loading steering manifest (" + context.url + ")");
25028
- _this2.scheduleRefresh(_this2.uri || context.url);
25877
+ _this3.log("Timeout loading steering manifest (" + context.url + ")");
25878
+ _this3.scheduleRefresh(_this3.uri || context.url);
25029
25879
  }
25030
25880
  };
25031
25881
  this.log("Requesting steering manifest: " + url);
25032
25882
  this.loader.load(context, loaderConfig, callbacks);
25033
25883
  };
25034
25884
  _proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
25035
- var _this3 = this;
25885
+ var _this4 = this;
25036
25886
  if (ttlMs === void 0) {
25037
25887
  ttlMs = this.timeToLoad * 1000;
25038
25888
  }
25039
25889
  this.clearTimeout();
25040
25890
  this.reloadTimer = self.setTimeout(function () {
25041
- var _this3$hls;
25042
- var media = (_this3$hls = _this3.hls) == null ? void 0 : _this3$hls.media;
25891
+ var _this4$hls;
25892
+ var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
25043
25893
  if (media && !media.ended) {
25044
- _this3.loadSteeringManifest(uri);
25894
+ _this4.loadSteeringManifest(uri);
25045
25895
  return;
25046
25896
  }
25047
- _this3.scheduleRefresh(uri, _this3.timeToLoad * 1000);
25897
+ _this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
25048
25898
  }, ttlMs);
25049
25899
  };
25050
25900
  return ContentSteeringController;
25051
- }();
25901
+ }(Logger);
25052
25902
  function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
25053
25903
  if (!tracks) {
25054
25904
  return;
@@ -25948,7 +26798,7 @@
25948
26798
  /**
25949
26799
  * @ignore
25950
26800
  */
25951
- function mergeConfig(defaultConfig, userConfig) {
26801
+ function mergeConfig(defaultConfig, userConfig, logger) {
25952
26802
  if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
25953
26803
  throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
25954
26804
  }
@@ -26018,7 +26868,7 @@
26018
26868
  /**
26019
26869
  * @ignore
26020
26870
  */
26021
- function enableStreamingMode(config) {
26871
+ function enableStreamingMode(config, logger) {
26022
26872
  var currentLoader = config.loader;
26023
26873
  if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
26024
26874
  // If a developer has configured their own loader, respect that choice
@@ -26035,12 +26885,11 @@
26035
26885
  }
26036
26886
  }
26037
26887
 
26038
- var chromeOrFirefox;
26039
26888
  var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
26040
26889
  _inheritsLoose(LevelController, _BasePlaylistControll);
26041
26890
  function LevelController(hls, contentSteeringController) {
26042
26891
  var _this;
26043
- _this = _BasePlaylistControll.call(this, hls, '[level-controller]') || this;
26892
+ _this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
26044
26893
  _this._levels = [];
26045
26894
  _this._firstLevel = -1;
26046
26895
  _this._maxAutoLevel = -1;
@@ -26109,21 +26958,13 @@
26109
26958
  var videoCodecFound = false;
26110
26959
  var audioCodecFound = false;
26111
26960
  data.levels.forEach(function (levelParsed) {
26112
- var _audioCodec, _videoCodec;
26961
+ var _videoCodec;
26113
26962
  var attributes = levelParsed.attrs;
26114
-
26115
- // erase audio codec info if browser does not support mp4a.40.34.
26116
- // demuxer will autodetect codec and fallback to mpeg/audio
26117
26963
  var audioCodec = levelParsed.audioCodec,
26118
26964
  videoCodec = levelParsed.videoCodec;
26119
- if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
26120
- chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
26121
- if (chromeOrFirefox) {
26122
- levelParsed.audioCodec = audioCodec = undefined;
26123
- }
26124
- }
26125
26965
  if (audioCodec) {
26126
- levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
26966
+ // Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
26967
+ levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
26127
26968
  }
26128
26969
  if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
26129
26970
  videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
@@ -26731,6 +27572,8 @@
26731
27572
  }
26732
27573
  return this.loadKeyEME(keyInfo, frag);
26733
27574
  case 'AES-128':
27575
+ case 'AES-256':
27576
+ case 'AES-256-CTR':
26734
27577
  return this.loadKeyHTTP(keyInfo, frag);
26735
27578
  default:
26736
27579
  return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
@@ -26870,21 +27713,26 @@
26870
27713
  var MAX_START_GAP_JUMP = 2.0;
26871
27714
  var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
26872
27715
  var SKIP_BUFFER_RANGE_START = 0.05;
26873
- var GapController = /*#__PURE__*/function () {
27716
+ var GapController = /*#__PURE__*/function (_Logger) {
27717
+ _inheritsLoose(GapController, _Logger);
26874
27718
  function GapController(config, media, fragmentTracker, hls) {
26875
- this.config = void 0;
26876
- this.media = null;
26877
- this.fragmentTracker = void 0;
26878
- this.hls = void 0;
26879
- this.nudgeRetry = 0;
26880
- this.stallReported = false;
26881
- this.stalled = null;
26882
- this.moved = false;
26883
- this.seeking = false;
26884
- this.config = config;
26885
- this.media = media;
26886
- this.fragmentTracker = fragmentTracker;
26887
- this.hls = hls;
27719
+ var _this;
27720
+ _this = _Logger.call(this, 'gap-controller', hls.logger) || this;
27721
+ _this.config = void 0;
27722
+ _this.media = null;
27723
+ _this.fragmentTracker = void 0;
27724
+ _this.hls = void 0;
27725
+ _this.nudgeRetry = 0;
27726
+ _this.stallReported = false;
27727
+ _this.stalled = null;
27728
+ _this.moved = false;
27729
+ _this.seeking = false;
27730
+ _this.ended = 0;
27731
+ _this.config = config;
27732
+ _this.media = media;
27733
+ _this.fragmentTracker = fragmentTracker;
27734
+ _this.hls = hls;
27735
+ return _this;
26888
27736
  }
26889
27737
  var _proto = GapController.prototype;
26890
27738
  _proto.destroy = function destroy() {
@@ -26899,7 +27747,7 @@
26899
27747
  *
26900
27748
  * @param lastCurrentTime - Previously read playhead position
26901
27749
  */;
26902
- _proto.poll = function poll(lastCurrentTime, activeFrag) {
27750
+ _proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
26903
27751
  var config = this.config,
26904
27752
  media = this.media,
26905
27753
  stalled = this.stalled;
@@ -26914,6 +27762,7 @@
26914
27762
 
26915
27763
  // The playhead is moving, no-op
26916
27764
  if (currentTime !== lastCurrentTime) {
27765
+ this.ended = 0;
26917
27766
  this.moved = true;
26918
27767
  if (!seeking) {
26919
27768
  this.nudgeRetry = 0;
@@ -26922,7 +27771,7 @@
26922
27771
  // The playhead is now moving, but was previously stalled
26923
27772
  if (this.stallReported) {
26924
27773
  var _stalledDuration = self.performance.now() - stalled;
26925
- logger.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
27774
+ this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
26926
27775
  this.stallReported = false;
26927
27776
  }
26928
27777
  this.stalled = null;
@@ -26958,7 +27807,6 @@
26958
27807
  // Skip start gaps if we haven't played, but the last poll detected the start of a stall
26959
27808
  // The addition poll gives the browser a chance to jump the gap for us
26960
27809
  if (!this.moved && this.stalled !== null) {
26961
- var _level$details;
26962
27810
  // There is no playable buffer (seeked, waiting for buffer)
26963
27811
  var isBuffered = bufferInfo.len > 0;
26964
27812
  if (!isBuffered && !nextStart) {
@@ -26970,9 +27818,8 @@
26970
27818
  // When joining a live stream with audio tracks, account for live playlist window sliding by allowing
26971
27819
  // a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
26972
27820
  // that begins over 1 target duration after the video start position.
26973
- var level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
26974
- var isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
26975
- var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
27821
+ var isLive = !!(levelDetails != null && levelDetails.live);
27822
+ var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
26976
27823
  var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
26977
27824
  if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
26978
27825
  if (!media.paused) {
@@ -26990,6 +27837,17 @@
26990
27837
  }
26991
27838
  var stalledDuration = tnow - stalled;
26992
27839
  if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
27840
+ // Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
27841
+ if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
27842
+ if (stalledDuration < 1000 || this.ended) {
27843
+ return;
27844
+ }
27845
+ this.ended = currentTime;
27846
+ this.hls.trigger(Events.MEDIA_ENDED, {
27847
+ stalled: true
27848
+ });
27849
+ return;
27850
+ }
26993
27851
  // Report stalling after trying to fix
26994
27852
  this._reportStall(bufferInfo);
26995
27853
  if (!this.media) {
@@ -27031,7 +27889,7 @@
27031
27889
  // needs to cross some sort of threshold covering all source-buffers content
27032
27890
  // to start playing properly.
27033
27891
  if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
27034
- logger.warn('Trying to nudge playhead over buffer-hole');
27892
+ this.warn('Trying to nudge playhead over buffer-hole');
27035
27893
  // Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
27036
27894
  // We only try to jump the hole if it's under the configured size
27037
27895
  // Reset stalled so to rearm watchdog timer
@@ -27053,7 +27911,7 @@
27053
27911
  // Report stalled error once
27054
27912
  this.stallReported = true;
27055
27913
  var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
27056
- logger.warn(error.message);
27914
+ this.warn(error.message);
27057
27915
  hls.trigger(Events.ERROR, {
27058
27916
  type: ErrorTypes.MEDIA_ERROR,
27059
27917
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -27117,7 +27975,7 @@
27117
27975
  }
27118
27976
  }
27119
27977
  var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
27120
- logger.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
27978
+ this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
27121
27979
  this.moved = true;
27122
27980
  this.stalled = null;
27123
27981
  media.currentTime = targetTime;
@@ -27156,7 +28014,7 @@
27156
28014
  var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
27157
28015
  // playback stalled in buffered area ... let's nudge currentTime to try to overcome this
27158
28016
  var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
27159
- logger.warn(error.message);
28017
+ this.warn(error.message);
27160
28018
  media.currentTime = targetTime;
27161
28019
  hls.trigger(Events.ERROR, {
27162
28020
  type: ErrorTypes.MEDIA_ERROR,
@@ -27166,7 +28024,7 @@
27166
28024
  });
27167
28025
  } else {
27168
28026
  var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
27169
- logger.error(_error.message);
28027
+ this.error(_error.message);
27170
28028
  hls.trigger(Events.ERROR, {
27171
28029
  type: ErrorTypes.MEDIA_ERROR,
27172
28030
  details: ErrorDetails.BUFFER_STALLED_ERROR,
@@ -27176,14 +28034,14 @@
27176
28034
  }
27177
28035
  };
27178
28036
  return GapController;
27179
- }();
28037
+ }(Logger);
27180
28038
 
27181
28039
  var TICK_INTERVAL = 100; // how often to tick in ms
27182
28040
  var StreamController = /*#__PURE__*/function (_BaseStreamController) {
27183
28041
  _inheritsLoose(StreamController, _BaseStreamController);
27184
28042
  function StreamController(hls, fragmentTracker, keyLoader) {
27185
28043
  var _this;
27186
- _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[stream-controller]', PlaylistLevelType.MAIN) || this;
28044
+ _this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
27187
28045
  _this.audioCodecSwap = false;
27188
28046
  _this.gapController = null;
27189
28047
  _this.level = -1;
@@ -27191,27 +28049,43 @@
27191
28049
  _this.altAudio = false;
27192
28050
  _this.audioOnly = false;
27193
28051
  _this.fragPlaying = null;
27194
- _this.onvplaying = null;
27195
- _this.onvseeked = null;
27196
28052
  _this.fragLastKbps = 0;
27197
28053
  _this.couldBacktrack = false;
27198
28054
  _this.backtrackFragment = null;
27199
28055
  _this.audioCodecSwitch = false;
27200
28056
  _this.videoBuffer = null;
27201
- _this._registerListeners();
28057
+ _this.onMediaPlaying = function () {
28058
+ // tick to speed up FRAG_CHANGED triggering
28059
+ _this.tick();
28060
+ };
28061
+ _this.onMediaSeeked = function () {
28062
+ var media = _this.media;
28063
+ var currentTime = media ? media.currentTime : null;
28064
+ if (isFiniteNumber(currentTime)) {
28065
+ _this.log("Media seeked to " + currentTime.toFixed(3));
28066
+ }
28067
+
28068
+ // If seeked was issued before buffer was appended do not tick immediately
28069
+ var bufferInfo = _this.getMainFwdBufferInfo();
28070
+ if (bufferInfo === null || bufferInfo.len === 0) {
28071
+ _this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
28072
+ return;
28073
+ }
28074
+
28075
+ // tick to speed up FRAG_CHANGED triggering
28076
+ _this.tick();
28077
+ };
28078
+ _this.registerListeners();
27202
28079
  return _this;
27203
28080
  }
27204
28081
  var _proto = StreamController.prototype;
27205
- _proto._registerListeners = function _registerListeners() {
28082
+ _proto.registerListeners = function registerListeners() {
28083
+ _BaseStreamController.prototype.registerListeners.call(this);
27206
28084
  var hls = this.hls;
27207
- hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
27208
- hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
27209
- hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
27210
28085
  hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
27211
28086
  hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
27212
28087
  hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
27213
28088
  hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
27214
- hls.on(Events.ERROR, this.onError, this);
27215
28089
  hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
27216
28090
  hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
27217
28091
  hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -27219,15 +28093,12 @@
27219
28093
  hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
27220
28094
  hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
27221
28095
  };
27222
- _proto._unregisterListeners = function _unregisterListeners() {
28096
+ _proto.unregisterListeners = function unregisterListeners() {
28097
+ _BaseStreamController.prototype.unregisterListeners.call(this);
27223
28098
  var hls = this.hls;
27224
- hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
27225
- hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
27226
- hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
27227
28099
  hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
27228
28100
  hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
27229
28101
  hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
27230
- hls.off(Events.ERROR, this.onError, this);
27231
28102
  hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
27232
28103
  hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
27233
28104
  hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
@@ -27236,7 +28107,9 @@
27236
28107
  hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
27237
28108
  };
27238
28109
  _proto.onHandlerDestroying = function onHandlerDestroying() {
27239
- this._unregisterListeners();
28110
+ // @ts-ignore
28111
+ this.onMediaPlaying = this.onMediaSeeked = null;
28112
+ this.unregisterListeners();
27240
28113
  _BaseStreamController.prototype.onHandlerDestroying.call(this);
27241
28114
  };
27242
28115
  _proto.startLoad = function startLoad(startPosition) {
@@ -27260,7 +28133,8 @@
27260
28133
  }
27261
28134
  // set new level to playlist loader : this will trigger start level load
27262
28135
  // hls.nextLoadLevel remains until it is set to a new value or until a new frag is successfully loaded
27263
- this.level = hls.nextLoadLevel = startLevel;
28136
+ hls.nextLoadLevel = startLevel;
28137
+ this.level = hls.loadLevel;
27264
28138
  this.loadedmetadata = false;
27265
28139
  }
27266
28140
  // if startPosition undefined but lastCurrentTime set, set startPosition to last currentTime
@@ -27345,7 +28219,7 @@
27345
28219
  if (this.altAudio && this.audioOnly) {
27346
28220
  return;
27347
28221
  }
27348
- if (!(levels != null && levels[level])) {
28222
+ if (!this.buffering || !(levels != null && levels[level])) {
27349
28223
  return;
27350
28224
  }
27351
28225
  var levelInfo = levels[level];
@@ -27551,18 +28425,15 @@
27551
28425
  _proto.onMediaAttached = function onMediaAttached(event, data) {
27552
28426
  _BaseStreamController.prototype.onMediaAttached.call(this, event, data);
27553
28427
  var media = data.media;
27554
- this.onvplaying = this.onMediaPlaying.bind(this);
27555
- this.onvseeked = this.onMediaSeeked.bind(this);
27556
- media.addEventListener('playing', this.onvplaying);
27557
- media.addEventListener('seeked', this.onvseeked);
28428
+ media.addEventListener('playing', this.onMediaPlaying);
28429
+ media.addEventListener('seeked', this.onMediaSeeked);
27558
28430
  this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
27559
28431
  };
27560
28432
  _proto.onMediaDetaching = function onMediaDetaching() {
27561
28433
  var media = this.media;
27562
- if (media && this.onvplaying && this.onvseeked) {
27563
- media.removeEventListener('playing', this.onvplaying);
27564
- media.removeEventListener('seeked', this.onvseeked);
27565
- this.onvplaying = this.onvseeked = null;
28434
+ if (media) {
28435
+ media.removeEventListener('playing', this.onMediaPlaying);
28436
+ media.removeEventListener('seeked', this.onMediaSeeked);
27566
28437
  this.videoBuffer = null;
27567
28438
  }
27568
28439
  this.fragPlaying = null;
@@ -27572,27 +28443,6 @@
27572
28443
  }
27573
28444
  _BaseStreamController.prototype.onMediaDetaching.call(this);
27574
28445
  };
27575
- _proto.onMediaPlaying = function onMediaPlaying() {
27576
- // tick to speed up FRAG_CHANGED triggering
27577
- this.tick();
27578
- };
27579
- _proto.onMediaSeeked = function onMediaSeeked() {
27580
- var media = this.media;
27581
- var currentTime = media ? media.currentTime : null;
27582
- if (isFiniteNumber(currentTime)) {
27583
- this.log("Media seeked to " + currentTime.toFixed(3));
27584
- }
27585
-
27586
- // If seeked was issued before buffer was appended do not tick immediately
27587
- var bufferInfo = this.getMainFwdBufferInfo();
27588
- if (bufferInfo === null || bufferInfo.len === 0) {
27589
- this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
27590
- return;
27591
- }
27592
-
27593
- // tick to speed up FRAG_CHANGED triggering
27594
- this.tick();
27595
- };
27596
28446
  _proto.onManifestLoading = function onManifestLoading() {
27597
28447
  // reset buffer on manifest loading
27598
28448
  this.log('Trigger BUFFER_RESET');
@@ -27873,8 +28723,10 @@
27873
28723
  }
27874
28724
  if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
27875
28725
  // Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
27876
- var activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
27877
- gapController.poll(this.lastCurrentTime, activeFrag);
28726
+ var state = this.state;
28727
+ var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
28728
+ var levelDetails = this.getLevelDetails();
28729
+ gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
27878
28730
  }
27879
28731
  this.lastCurrentTime = media.currentTime;
27880
28732
  };
@@ -28339,9 +29191,12 @@
28339
29191
  * The configuration object provided on player instantiation.
28340
29192
  */
28341
29193
  this.userConfig = void 0;
29194
+ /**
29195
+ * The logger functions used by this player instance, configured on player instantiation.
29196
+ */
29197
+ this.logger = void 0;
28342
29198
  this.coreComponents = void 0;
28343
29199
  this.networkControllers = void 0;
28344
- this.started = false;
28345
29200
  this._emitter = new EventEmitter();
28346
29201
  this._autoLevelCapping = -1;
28347
29202
  this._maxHdcpLevel = null;
@@ -28358,11 +29213,11 @@
28358
29213
  this._media = null;
28359
29214
  this.url = null;
28360
29215
  this.triggeringException = void 0;
28361
- enableLogs(userConfig.debug || false, 'Hls instance');
28362
- var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
29216
+ var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
29217
+ var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
28363
29218
  this.userConfig = userConfig;
28364
29219
  if (config.progressive) {
28365
- enableStreamingMode(config);
29220
+ enableStreamingMode(config, logger);
28366
29221
  }
28367
29222
 
28368
29223
  // core controllers and network loaders
@@ -28470,7 +29325,7 @@
28470
29325
  try {
28471
29326
  return this.emit(event, event, eventObject);
28472
29327
  } catch (error) {
28473
- logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
29328
+ this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
28474
29329
  // Prevent recursion in error event handlers that throw #5497
28475
29330
  if (!this.triggeringException) {
28476
29331
  this.triggeringException = true;
@@ -28496,7 +29351,7 @@
28496
29351
  * Dispose of the instance
28497
29352
  */;
28498
29353
  _proto.destroy = function destroy() {
28499
- logger.log('destroy');
29354
+ this.logger.log('destroy');
28500
29355
  this.trigger(Events.DESTROYING, undefined);
28501
29356
  this.detachMedia();
28502
29357
  this.removeAllListeners();
@@ -28521,7 +29376,7 @@
28521
29376
  * Attaches Hls.js to a media element
28522
29377
  */;
28523
29378
  _proto.attachMedia = function attachMedia(media) {
28524
- logger.log('attachMedia');
29379
+ this.logger.log('attachMedia');
28525
29380
  this._media = media;
28526
29381
  this.trigger(Events.MEDIA_ATTACHING, {
28527
29382
  media: media
@@ -28532,7 +29387,7 @@
28532
29387
  * Detach Hls.js from the media
28533
29388
  */;
28534
29389
  _proto.detachMedia = function detachMedia() {
28535
- logger.log('detachMedia');
29390
+ this.logger.log('detachMedia');
28536
29391
  this.trigger(Events.MEDIA_DETACHING, undefined);
28537
29392
  this._media = null;
28538
29393
  }
@@ -28549,7 +29404,7 @@
28549
29404
  });
28550
29405
  this._autoLevelCapping = -1;
28551
29406
  this._maxHdcpLevel = null;
28552
- logger.log("loadSource:" + loadingSource);
29407
+ this.logger.log("loadSource:" + loadingSource);
28553
29408
  if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
28554
29409
  this.detachMedia();
28555
29410
  this.attachMedia(media);
@@ -28571,8 +29426,7 @@
28571
29426
  if (startPosition === void 0) {
28572
29427
  startPosition = -1;
28573
29428
  }
28574
- logger.log("startLoad(" + startPosition + ")");
28575
- this.started = true;
29429
+ this.logger.log("startLoad(" + startPosition + ")");
28576
29430
  this.networkControllers.forEach(function (controller) {
28577
29431
  controller.startLoad(startPosition);
28578
29432
  });
@@ -28582,34 +29436,31 @@
28582
29436
  * Stop loading of any stream data.
28583
29437
  */;
28584
29438
  _proto.stopLoad = function stopLoad() {
28585
- logger.log('stopLoad');
28586
- this.started = false;
29439
+ this.logger.log('stopLoad');
28587
29440
  this.networkControllers.forEach(function (controller) {
28588
29441
  controller.stopLoad();
28589
29442
  });
28590
29443
  }
28591
29444
 
28592
29445
  /**
28593
- * Resumes stream controller segment loading if previously started.
29446
+ * Resumes stream controller segment loading after `pauseBuffering` has been called.
28594
29447
  */;
28595
29448
  _proto.resumeBuffering = function resumeBuffering() {
28596
- if (this.started) {
28597
- this.networkControllers.forEach(function (controller) {
28598
- if ('fragmentLoader' in controller) {
28599
- controller.startLoad(-1);
28600
- }
28601
- });
28602
- }
29449
+ this.networkControllers.forEach(function (controller) {
29450
+ if (controller.resumeBuffering) {
29451
+ controller.resumeBuffering();
29452
+ }
29453
+ });
28603
29454
  }
28604
29455
 
28605
29456
  /**
28606
- * Stops stream controller segment loading without changing 'started' state like stopLoad().
29457
+ * Prevents stream controller from loading new segments until `resumeBuffering` is called.
28607
29458
  * This allows for media buffering to be paused without interupting playlist loading.
28608
29459
  */;
28609
29460
  _proto.pauseBuffering = function pauseBuffering() {
28610
29461
  this.networkControllers.forEach(function (controller) {
28611
- if ('fragmentLoader' in controller) {
28612
- controller.stopLoad();
29462
+ if (controller.pauseBuffering) {
29463
+ controller.pauseBuffering();
28613
29464
  }
28614
29465
  });
28615
29466
  }
@@ -28618,7 +29469,7 @@
28618
29469
  * Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
28619
29470
  */;
28620
29471
  _proto.swapAudioCodec = function swapAudioCodec() {
28621
- logger.log('swapAudioCodec');
29472
+ this.logger.log('swapAudioCodec');
28622
29473
  this.streamController.swapAudioCodec();
28623
29474
  }
28624
29475
 
@@ -28629,7 +29480,7 @@
28629
29480
  * Automatic recovery of media-errors by this process is configurable.
28630
29481
  */;
28631
29482
  _proto.recoverMediaError = function recoverMediaError() {
28632
- logger.log('recoverMediaError');
29483
+ this.logger.log('recoverMediaError');
28633
29484
  var media = this._media;
28634
29485
  this.detachMedia();
28635
29486
  if (media) {
@@ -28684,7 +29535,7 @@
28684
29535
  * 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.
28685
29536
  */,
28686
29537
  set: function set(newLevel) {
28687
- logger.log("set currentLevel:" + newLevel);
29538
+ this.logger.log("set currentLevel:" + newLevel);
28688
29539
  this.levelController.manualLevel = newLevel;
28689
29540
  this.streamController.immediateLevelSwitch();
28690
29541
  }
@@ -28705,7 +29556,7 @@
28705
29556
  * @param newLevel - Pass -1 for automatic level selection
28706
29557
  */,
28707
29558
  set: function set(newLevel) {
28708
- logger.log("set nextLevel:" + newLevel);
29559
+ this.logger.log("set nextLevel:" + newLevel);
28709
29560
  this.levelController.manualLevel = newLevel;
28710
29561
  this.streamController.nextLevelSwitch();
28711
29562
  }
@@ -28726,7 +29577,7 @@
28726
29577
  * @param newLevel - Pass -1 for automatic level selection
28727
29578
  */,
28728
29579
  set: function set(newLevel) {
28729
- logger.log("set loadLevel:" + newLevel);
29580
+ this.logger.log("set loadLevel:" + newLevel);
28730
29581
  this.levelController.manualLevel = newLevel;
28731
29582
  }
28732
29583
 
@@ -28761,7 +29612,7 @@
28761
29612
  * Sets "first-level", see getter.
28762
29613
  */,
28763
29614
  set: function set(newLevel) {
28764
- logger.log("set firstLevel:" + newLevel);
29615
+ this.logger.log("set firstLevel:" + newLevel);
28765
29616
  this.levelController.firstLevel = newLevel;
28766
29617
  }
28767
29618
 
@@ -28788,7 +29639,7 @@
28788
29639
  * (determined from download of first segment)
28789
29640
  */,
28790
29641
  set: function set(newLevel) {
28791
- logger.log("set startLevel:" + newLevel);
29642
+ this.logger.log("set startLevel:" + newLevel);
28792
29643
  // if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
28793
29644
  if (newLevel !== -1) {
28794
29645
  newLevel = Math.max(newLevel, this.minAutoLevel);
@@ -28841,7 +29692,7 @@
28841
29692
  */
28842
29693
  function set(newLevel) {
28843
29694
  if (this._autoLevelCapping !== newLevel) {
28844
- logger.log("set autoLevelCapping:" + newLevel);
29695
+ this.logger.log("set autoLevelCapping:" + newLevel);
28845
29696
  this._autoLevelCapping = newLevel;
28846
29697
  this.levelController.checkMaxAutoUpdated();
28847
29698
  }
@@ -29166,7 +30017,7 @@
29166
30017
  * Get the video-dev/hls.js package version.
29167
30018
  */
29168
30019
  function get() {
29169
- return "1.5.3";
30020
+ return "1.5.5-0.canary.9977";
29170
30021
  }
29171
30022
  }, {
29172
30023
  key: "Events",