hls.js 1.5.4 → 1.5.5-0.canary.9978
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/hls-demo.js +10 -0
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +1935 -1094
- package/dist/hls.js.d.ts +63 -50
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +1059 -838
- package/dist/hls.light.js.map +1 -1
- package/dist/hls.light.min.js +1 -1
- package/dist/hls.light.min.js.map +1 -1
- package/dist/hls.light.mjs +846 -626
- package/dist/hls.light.mjs.map +1 -1
- package/dist/hls.min.js +1 -1
- package/dist/hls.min.js.map +1 -1
- package/dist/hls.mjs +1640 -814
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +18 -18
- package/src/config.ts +3 -2
- package/src/controller/abr-controller.ts +21 -20
- package/src/controller/audio-stream-controller.ts +15 -16
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +7 -7
- package/src/controller/base-stream-controller.ts +56 -29
- package/src/controller/buffer-controller.ts +11 -11
- package/src/controller/cap-level-controller.ts +1 -2
- package/src/controller/cmcd-controller.ts +25 -3
- package/src/controller/content-steering-controller.ts +8 -6
- package/src/controller/eme-controller.ts +9 -22
- package/src/controller/error-controller.ts +6 -8
- package/src/controller/fps-controller.ts +2 -3
- package/src/controller/gap-controller.ts +43 -16
- package/src/controller/latency-controller.ts +9 -11
- package/src/controller/level-controller.ts +5 -17
- package/src/controller/stream-controller.ts +25 -32
- package/src/controller/subtitle-stream-controller.ts +13 -14
- package/src/controller/subtitle-track-controller.ts +5 -3
- package/src/controller/timeline-controller.ts +23 -30
- package/src/crypt/aes-crypto.ts +21 -2
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +32 -18
- package/src/crypt/fast-aes-key.ts +24 -5
- package/src/demux/audio/adts.ts +9 -4
- package/src/demux/sample-aes.ts +2 -0
- package/src/demux/transmuxer-interface.ts +4 -12
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +16 -3
- package/src/demux/tsdemuxer.ts +71 -37
- package/src/demux/video/avc-video-parser.ts +208 -119
- package/src/demux/video/base-video-parser.ts +134 -2
- package/src/demux/video/exp-golomb.ts +0 -208
- package/src/demux/video/hevc-video-parser.ts +746 -0
- package/src/events.ts +7 -0
- package/src/hls.ts +42 -34
- package/src/loader/fragment-loader.ts +9 -2
- package/src/loader/key-loader.ts +2 -0
- package/src/loader/level-key.ts +10 -9
- package/src/remux/mp4-generator.ts +196 -1
- package/src/remux/mp4-remuxer.ts +23 -7
- package/src/task-loop.ts +5 -2
- package/src/types/component-api.ts +2 -0
- package/src/types/demuxer.ts +3 -0
- package/src/types/events.ts +4 -0
- package/src/utils/codecs.ts +33 -4
- package/src/utils/encryption-methods-util.ts +21 -0
- package/src/utils/logger.ts +53 -24
package/dist/hls.light.js
CHANGED
@@ -5,6 +5,21 @@
|
|
5
5
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Hls = factory());
|
6
6
|
})(this, (function () { 'use strict';
|
7
7
|
|
8
|
+
function _construct(t, e, r) {
|
9
|
+
if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
|
10
|
+
var o = [null];
|
11
|
+
o.push.apply(o, e);
|
12
|
+
var p = new (t.bind.apply(t, o))();
|
13
|
+
return r && _setPrototypeOf(p, r.prototype), p;
|
14
|
+
}
|
15
|
+
function _isNativeReflectConstruct() {
|
16
|
+
try {
|
17
|
+
var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
18
|
+
} catch (t) {}
|
19
|
+
return (_isNativeReflectConstruct = function () {
|
20
|
+
return !!t;
|
21
|
+
})();
|
22
|
+
}
|
8
23
|
function ownKeys(e, r) {
|
9
24
|
var t = Object.keys(e);
|
10
25
|
if (Object.getOwnPropertySymbols) {
|
@@ -103,32 +118,6 @@
|
|
103
118
|
};
|
104
119
|
return _setPrototypeOf(o, p);
|
105
120
|
}
|
106
|
-
function _isNativeReflectConstruct() {
|
107
|
-
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
|
108
|
-
if (Reflect.construct.sham) return false;
|
109
|
-
if (typeof Proxy === "function") return true;
|
110
|
-
try {
|
111
|
-
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
112
|
-
return true;
|
113
|
-
} catch (e) {
|
114
|
-
return false;
|
115
|
-
}
|
116
|
-
}
|
117
|
-
function _construct(Parent, args, Class) {
|
118
|
-
if (_isNativeReflectConstruct()) {
|
119
|
-
_construct = Reflect.construct.bind();
|
120
|
-
} else {
|
121
|
-
_construct = function _construct(Parent, args, Class) {
|
122
|
-
var a = [null];
|
123
|
-
a.push.apply(a, args);
|
124
|
-
var Constructor = Function.bind.apply(Parent, a);
|
125
|
-
var instance = new Constructor();
|
126
|
-
if (Class) _setPrototypeOf(instance, Class.prototype);
|
127
|
-
return instance;
|
128
|
-
};
|
129
|
-
}
|
130
|
-
return _construct.apply(null, arguments);
|
131
|
-
}
|
132
121
|
function _isNativeFunction(fn) {
|
133
122
|
try {
|
134
123
|
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
@@ -363,6 +352,7 @@
|
|
363
352
|
Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
|
364
353
|
Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
|
365
354
|
Events["MEDIA_DETACHED"] = "hlsMediaDetached";
|
355
|
+
Events["MEDIA_ENDED"] = "hlsMediaEnded";
|
366
356
|
Events["BUFFER_RESET"] = "hlsBufferReset";
|
367
357
|
Events["BUFFER_CODECS"] = "hlsBufferCodecs";
|
368
358
|
Events["BUFFER_CREATED"] = "hlsBufferCreated";
|
@@ -476,6 +466,21 @@
|
|
476
466
|
return ErrorDetails;
|
477
467
|
}({});
|
478
468
|
|
469
|
+
var Logger = function Logger(label, logger) {
|
470
|
+
this.trace = void 0;
|
471
|
+
this.debug = void 0;
|
472
|
+
this.log = void 0;
|
473
|
+
this.warn = void 0;
|
474
|
+
this.info = void 0;
|
475
|
+
this.error = void 0;
|
476
|
+
var lb = "[" + label + "]:";
|
477
|
+
this.trace = noop;
|
478
|
+
this.debug = logger.debug.bind(null, lb);
|
479
|
+
this.log = logger.log.bind(null, lb);
|
480
|
+
this.warn = logger.warn.bind(null, lb);
|
481
|
+
this.info = logger.info.bind(null, lb);
|
482
|
+
this.error = logger.error.bind(null, lb);
|
483
|
+
};
|
479
484
|
var noop = function noop() {};
|
480
485
|
var fakeLogger = {
|
481
486
|
trace: noop,
|
@@ -485,7 +490,9 @@
|
|
485
490
|
info: noop,
|
486
491
|
error: noop
|
487
492
|
};
|
488
|
-
|
493
|
+
function createLogger() {
|
494
|
+
return _extends({}, fakeLogger);
|
495
|
+
}
|
489
496
|
|
490
497
|
// let lastCallTime;
|
491
498
|
// function formatMsgWithTimeInfo(type, msg) {
|
@@ -496,38 +503,36 @@
|
|
496
503
|
// return msg;
|
497
504
|
// }
|
498
505
|
|
499
|
-
function consolePrintFn(type) {
|
506
|
+
function consolePrintFn(type, id) {
|
500
507
|
var func = self.console[type];
|
501
|
-
|
502
|
-
return func.bind(self.console, "[" + type + "] >");
|
503
|
-
}
|
504
|
-
return noop;
|
508
|
+
return func ? func.bind(self.console, (id ? '[' + id + '] ' : '') + "[" + type + "] >") : noop;
|
505
509
|
}
|
506
|
-
function
|
507
|
-
|
508
|
-
functions[_key - 1] = arguments[_key];
|
509
|
-
}
|
510
|
-
functions.forEach(function (type) {
|
511
|
-
exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
|
512
|
-
});
|
510
|
+
function getLoggerFn(key, debugConfig, id) {
|
511
|
+
return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
|
513
512
|
}
|
514
|
-
|
513
|
+
var exportedLogger = createLogger();
|
514
|
+
function enableLogs(debugConfig, context, id) {
|
515
515
|
// check that console is available
|
516
|
+
var newLogger = createLogger();
|
516
517
|
if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
|
517
|
-
|
518
|
+
var keys = [
|
518
519
|
// Remove out from list here to hard-disable a log-level
|
519
520
|
// 'trace',
|
520
|
-
'debug', 'log', 'info', 'warn', 'error'
|
521
|
+
'debug', 'log', 'info', 'warn', 'error'];
|
522
|
+
keys.forEach(function (key) {
|
523
|
+
newLogger[key] = getLoggerFn(key, debugConfig, id);
|
524
|
+
});
|
521
525
|
// Some browsers don't allow to use bind on console object anyway
|
522
526
|
// fallback to default if needed
|
523
527
|
try {
|
524
|
-
|
528
|
+
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.5-0.canary.9978");
|
525
529
|
} catch (e) {
|
526
|
-
|
530
|
+
/* log fn threw an exception. All logger methods are no-ops. */
|
531
|
+
return createLogger();
|
527
532
|
}
|
528
|
-
} else {
|
529
|
-
exportedLogger = fakeLogger;
|
530
533
|
}
|
534
|
+
exportedLogger = newLogger;
|
535
|
+
return newLogger;
|
531
536
|
}
|
532
537
|
var logger = exportedLogger;
|
533
538
|
|
@@ -1173,10 +1178,30 @@
|
|
1173
1178
|
return LevelDetails;
|
1174
1179
|
}();
|
1175
1180
|
|
1181
|
+
var DecrypterAesMode = {
|
1182
|
+
cbc: 0,
|
1183
|
+
ctr: 1
|
1184
|
+
};
|
1185
|
+
|
1186
|
+
function isFullSegmentEncryption(method) {
|
1187
|
+
return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
|
1188
|
+
}
|
1189
|
+
function getAesModeFromFullSegmentMethod(method) {
|
1190
|
+
switch (method) {
|
1191
|
+
case 'AES-128':
|
1192
|
+
case 'AES-256':
|
1193
|
+
return DecrypterAesMode.cbc;
|
1194
|
+
case 'AES-256-CTR':
|
1195
|
+
return DecrypterAesMode.ctr;
|
1196
|
+
default:
|
1197
|
+
throw new Error("invalid full segment method " + method);
|
1198
|
+
}
|
1199
|
+
}
|
1200
|
+
|
1176
1201
|
// This file is inserted as a shim for modules which we do not want to include into the distro.
|
1177
1202
|
// This replacement is done in the "alias" plugin of the rollup config.
|
1178
1203
|
var empty = undefined;
|
1179
|
-
var
|
1204
|
+
var HevcVideoParser = /*@__PURE__*/getDefaultExportFromCjs(empty);
|
1180
1205
|
|
1181
1206
|
function sliceUint8(array, start, end) {
|
1182
1207
|
// @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
|
@@ -2626,13 +2651,13 @@
|
|
2626
2651
|
this.keyFormatVersions = formatversions;
|
2627
2652
|
this.iv = iv;
|
2628
2653
|
this.encrypted = method ? method !== 'NONE' : false;
|
2629
|
-
this.isCommonEncryption = this.encrypted && method
|
2654
|
+
this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
|
2630
2655
|
}
|
2631
2656
|
var _proto = LevelKey.prototype;
|
2632
2657
|
_proto.isSupported = function isSupported() {
|
2633
2658
|
// If it's Segment encryption or No encryption, just select that key system
|
2634
2659
|
if (this.method) {
|
2635
|
-
if (this.method
|
2660
|
+
if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
|
2636
2661
|
return true;
|
2637
2662
|
}
|
2638
2663
|
if (this.keyFormat === 'identity') {
|
@@ -2646,14 +2671,13 @@
|
|
2646
2671
|
if (!this.encrypted || !this.uri) {
|
2647
2672
|
return null;
|
2648
2673
|
}
|
2649
|
-
if (this.method
|
2674
|
+
if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
|
2650
2675
|
if (typeof sn !== 'number') {
|
2651
2676
|
// We are fetching decryption data for a initialization segment
|
2652
|
-
// If the segment was encrypted with AES-128
|
2677
|
+
// If the segment was encrypted with AES-128/256
|
2653
2678
|
// It must have an IV defined. We cannot substitute the Segment Number in.
|
2654
|
-
|
2655
|
-
|
2656
|
-
}
|
2679
|
+
logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
|
2680
|
+
|
2657
2681
|
// Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
|
2658
2682
|
sn = 0;
|
2659
2683
|
}
|
@@ -2815,23 +2839,28 @@
|
|
2815
2839
|
if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
|
2816
2840
|
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
|
2817
2841
|
}
|
2818
|
-
|
2819
|
-
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2820
|
-
// some browsers will report that fLaC is supported then fail.
|
2821
|
-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2822
2842
|
var codecsToCheck = {
|
2843
|
+
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2844
|
+
// some browsers will report that fLaC is supported then fail.
|
2845
|
+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2823
2846
|
flac: ['flac', 'fLaC', 'FLAC'],
|
2824
|
-
opus: ['opus', 'Opus']
|
2847
|
+
opus: ['opus', 'Opus'],
|
2848
|
+
// Replace audio codec info if browser does not support mp4a.40.34,
|
2849
|
+
// and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
|
2850
|
+
'mp4a.40.34': ['mp3']
|
2825
2851
|
}[lowerCaseCodec];
|
2826
2852
|
for (var i = 0; i < codecsToCheck.length; i++) {
|
2853
|
+
var _getMediaSource;
|
2827
2854
|
if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
|
2828
2855
|
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
|
2829
2856
|
return codecsToCheck[i];
|
2857
|
+
} else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
|
2858
|
+
return '';
|
2830
2859
|
}
|
2831
2860
|
}
|
2832
2861
|
return lowerCaseCodec;
|
2833
2862
|
}
|
2834
|
-
var AUDIO_CODEC_REGEXP = /flac|opus/i;
|
2863
|
+
var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
|
2835
2864
|
function getCodecCompatibleName(codec, preferManagedMediaSource) {
|
2836
2865
|
if (preferManagedMediaSource === void 0) {
|
2837
2866
|
preferManagedMediaSource = true;
|
@@ -2859,6 +2888,18 @@
|
|
2859
2888
|
}
|
2860
2889
|
return codec;
|
2861
2890
|
}
|
2891
|
+
function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
|
2892
|
+
var MediaSource = getMediaSource(preferManagedMediaSource) || {
|
2893
|
+
isTypeSupported: function isTypeSupported() {
|
2894
|
+
return false;
|
2895
|
+
}
|
2896
|
+
};
|
2897
|
+
return {
|
2898
|
+
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
2899
|
+
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
2900
|
+
ac3: false
|
2901
|
+
};
|
2902
|
+
}
|
2862
2903
|
|
2863
2904
|
var MASTER_PLAYLIST_REGEX = /#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-(SESSION-DATA|SESSION-KEY|DEFINE|CONTENT-STEERING|START):([^\r\n]*)[\r\n]+/g;
|
2864
2905
|
var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
|
@@ -4433,8 +4474,43 @@
|
|
4433
4474
|
this.currentTime = 0;
|
4434
4475
|
this.stallCount = 0;
|
4435
4476
|
this._latency = null;
|
4436
|
-
this.
|
4437
|
-
|
4477
|
+
this.onTimeupdate = function () {
|
4478
|
+
var media = _this.media,
|
4479
|
+
levelDetails = _this.levelDetails;
|
4480
|
+
if (!media || !levelDetails) {
|
4481
|
+
return;
|
4482
|
+
}
|
4483
|
+
_this.currentTime = media.currentTime;
|
4484
|
+
var latency = _this.computeLatency();
|
4485
|
+
if (latency === null) {
|
4486
|
+
return;
|
4487
|
+
}
|
4488
|
+
_this._latency = latency;
|
4489
|
+
|
4490
|
+
// Adapt playbackRate to meet target latency in low-latency mode
|
4491
|
+
var _this$config = _this.config,
|
4492
|
+
lowLatencyMode = _this$config.lowLatencyMode,
|
4493
|
+
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4494
|
+
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4495
|
+
return;
|
4496
|
+
}
|
4497
|
+
var targetLatency = _this.targetLatency;
|
4498
|
+
if (targetLatency === null) {
|
4499
|
+
return;
|
4500
|
+
}
|
4501
|
+
var distanceFromTarget = latency - targetLatency;
|
4502
|
+
// Only adjust playbackRate when within one target duration of targetLatency
|
4503
|
+
// and more than one second from under-buffering.
|
4504
|
+
// Playback further than one target duration from target can be considered DVR playback.
|
4505
|
+
var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
|
4506
|
+
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4507
|
+
if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
|
4508
|
+
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4509
|
+
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
|
4510
|
+
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4511
|
+
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4512
|
+
media.playbackRate = 1;
|
4513
|
+
}
|
4438
4514
|
};
|
4439
4515
|
this.hls = hls;
|
4440
4516
|
this.config = hls.config;
|
@@ -4446,7 +4522,7 @@
|
|
4446
4522
|
this.onMediaDetaching();
|
4447
4523
|
this.levelDetails = null;
|
4448
4524
|
// @ts-ignore
|
4449
|
-
this.hls =
|
4525
|
+
this.hls = null;
|
4450
4526
|
};
|
4451
4527
|
_proto.registerListeners = function registerListeners() {
|
4452
4528
|
this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
@@ -4464,11 +4540,11 @@
|
|
4464
4540
|
};
|
4465
4541
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
4466
4542
|
this.media = data.media;
|
4467
|
-
this.media.addEventListener('timeupdate', this.
|
4543
|
+
this.media.addEventListener('timeupdate', this.onTimeupdate);
|
4468
4544
|
};
|
4469
4545
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
4470
4546
|
if (this.media) {
|
4471
|
-
this.media.removeEventListener('timeupdate', this.
|
4547
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4472
4548
|
this.media = null;
|
4473
4549
|
}
|
4474
4550
|
};
|
@@ -4481,10 +4557,10 @@
|
|
4481
4557
|
var details = _ref.details;
|
4482
4558
|
this.levelDetails = details;
|
4483
4559
|
if (details.advanced) {
|
4484
|
-
this.
|
4560
|
+
this.onTimeupdate();
|
4485
4561
|
}
|
4486
4562
|
if (!details.live && this.media) {
|
4487
|
-
this.media.removeEventListener('timeupdate', this.
|
4563
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4488
4564
|
}
|
4489
4565
|
};
|
4490
4566
|
_proto.onError = function onError(event, data) {
|
@@ -4494,45 +4570,7 @@
|
|
4494
4570
|
}
|
4495
4571
|
this.stallCount++;
|
4496
4572
|
if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
|
4497
|
-
logger.warn('[
|
4498
|
-
}
|
4499
|
-
};
|
4500
|
-
_proto.timeupdate = function timeupdate() {
|
4501
|
-
var media = this.media,
|
4502
|
-
levelDetails = this.levelDetails;
|
4503
|
-
if (!media || !levelDetails) {
|
4504
|
-
return;
|
4505
|
-
}
|
4506
|
-
this.currentTime = media.currentTime;
|
4507
|
-
var latency = this.computeLatency();
|
4508
|
-
if (latency === null) {
|
4509
|
-
return;
|
4510
|
-
}
|
4511
|
-
this._latency = latency;
|
4512
|
-
|
4513
|
-
// Adapt playbackRate to meet target latency in low-latency mode
|
4514
|
-
var _this$config = this.config,
|
4515
|
-
lowLatencyMode = _this$config.lowLatencyMode,
|
4516
|
-
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4517
|
-
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4518
|
-
return;
|
4519
|
-
}
|
4520
|
-
var targetLatency = this.targetLatency;
|
4521
|
-
if (targetLatency === null) {
|
4522
|
-
return;
|
4523
|
-
}
|
4524
|
-
var distanceFromTarget = latency - targetLatency;
|
4525
|
-
// Only adjust playbackRate when within one target duration of targetLatency
|
4526
|
-
// and more than one second from under-buffering.
|
4527
|
-
// Playback further than one target duration from target can be considered DVR playback.
|
4528
|
-
var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
|
4529
|
-
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4530
|
-
if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
|
4531
|
-
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4532
|
-
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
|
4533
|
-
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4534
|
-
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4535
|
-
media.playbackRate = 1;
|
4573
|
+
this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
|
4536
4574
|
}
|
4537
4575
|
};
|
4538
4576
|
_proto.estimateLiveEdge = function estimateLiveEdge() {
|
@@ -5440,19 +5478,17 @@
|
|
5440
5478
|
MoveAllAlternatesMatchingHDCP: 2,
|
5441
5479
|
SwitchToSDR: 4
|
5442
5480
|
}; // Reserved for future use
|
5443
|
-
var ErrorController = /*#__PURE__*/function () {
|
5481
|
+
var ErrorController = /*#__PURE__*/function (_Logger) {
|
5482
|
+
_inheritsLoose(ErrorController, _Logger);
|
5444
5483
|
function ErrorController(hls) {
|
5445
|
-
|
5446
|
-
this.
|
5447
|
-
|
5448
|
-
|
5449
|
-
|
5450
|
-
|
5451
|
-
|
5452
|
-
|
5453
|
-
this.warn = logger.warn.bind(logger, "[warning]:");
|
5454
|
-
this.error = logger.error.bind(logger, "[error]:");
|
5455
|
-
this.registerListeners();
|
5484
|
+
var _this;
|
5485
|
+
_this = _Logger.call(this, 'error-controller', hls.logger) || this;
|
5486
|
+
_this.hls = void 0;
|
5487
|
+
_this.playlistError = 0;
|
5488
|
+
_this.penalizedRenditions = {};
|
5489
|
+
_this.hls = hls;
|
5490
|
+
_this.registerListeners();
|
5491
|
+
return _this;
|
5456
5492
|
}
|
5457
5493
|
var _proto = ErrorController.prototype;
|
5458
5494
|
_proto.registerListeners = function registerListeners() {
|
@@ -5808,19 +5844,19 @@
|
|
5808
5844
|
}
|
5809
5845
|
};
|
5810
5846
|
return ErrorController;
|
5811
|
-
}();
|
5847
|
+
}(Logger);
|
5812
5848
|
|
5813
|
-
var BasePlaylistController = /*#__PURE__*/function () {
|
5849
|
+
var BasePlaylistController = /*#__PURE__*/function (_Logger) {
|
5850
|
+
_inheritsLoose(BasePlaylistController, _Logger);
|
5814
5851
|
function BasePlaylistController(hls, logPrefix) {
|
5815
|
-
|
5816
|
-
this.
|
5817
|
-
|
5818
|
-
|
5819
|
-
|
5820
|
-
|
5821
|
-
|
5822
|
-
|
5823
|
-
this.hls = hls;
|
5852
|
+
var _this;
|
5853
|
+
_this = _Logger.call(this, logPrefix, hls.logger) || this;
|
5854
|
+
_this.hls = void 0;
|
5855
|
+
_this.timer = -1;
|
5856
|
+
_this.requestScheduled = -1;
|
5857
|
+
_this.canLoad = false;
|
5858
|
+
_this.hls = hls;
|
5859
|
+
return _this;
|
5824
5860
|
}
|
5825
5861
|
var _proto = BasePlaylistController.prototype;
|
5826
5862
|
_proto.destroy = function destroy() {
|
@@ -5853,7 +5889,7 @@
|
|
5853
5889
|
try {
|
5854
5890
|
uri = new self.URL(attr.URI, previous.url).href;
|
5855
5891
|
} catch (error) {
|
5856
|
-
|
5892
|
+
this.warn("Could not construct new URL for Rendition Report: " + error);
|
5857
5893
|
uri = attr.URI || '';
|
5858
5894
|
}
|
5859
5895
|
// Use exact match. Otherwise, the last partial match, if any, will be used
|
@@ -5892,7 +5928,7 @@
|
|
5892
5928
|
return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
|
5893
5929
|
};
|
5894
5930
|
_proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
|
5895
|
-
var
|
5931
|
+
var _this2 = this;
|
5896
5932
|
var details = data.details,
|
5897
5933
|
stats = data.stats;
|
5898
5934
|
|
@@ -5997,7 +6033,7 @@
|
|
5997
6033
|
// );
|
5998
6034
|
|
5999
6035
|
this.timer = self.setTimeout(function () {
|
6000
|
-
return
|
6036
|
+
return _this2.loadPlaylist(deliveryDirectives);
|
6001
6037
|
}, estimatedTimeUntilUpdate);
|
6002
6038
|
} else {
|
6003
6039
|
this.clearTimer();
|
@@ -6013,7 +6049,7 @@
|
|
6013
6049
|
return new HlsUrlParameters(msn, part, skip);
|
6014
6050
|
};
|
6015
6051
|
_proto.checkRetry = function checkRetry(errorEvent) {
|
6016
|
-
var
|
6052
|
+
var _this3 = this;
|
6017
6053
|
var errorDetails = errorEvent.details;
|
6018
6054
|
var isTimeout = isTimeoutError(errorEvent);
|
6019
6055
|
var errorAction = errorEvent.errorAction;
|
@@ -6037,7 +6073,7 @@
|
|
6037
6073
|
var delay = getRetryDelay(retryConfig, retryCount);
|
6038
6074
|
// Schedule level/track reload
|
6039
6075
|
this.timer = self.setTimeout(function () {
|
6040
|
-
return
|
6076
|
+
return _this3.loadPlaylist();
|
6041
6077
|
}, delay);
|
6042
6078
|
this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
|
6043
6079
|
}
|
@@ -6048,7 +6084,7 @@
|
|
6048
6084
|
return retry;
|
6049
6085
|
};
|
6050
6086
|
return BasePlaylistController;
|
6051
|
-
}();
|
6087
|
+
}(Logger);
|
6052
6088
|
|
6053
6089
|
/*
|
6054
6090
|
* compute an Exponential Weighted moving average
|
@@ -6422,30 +6458,33 @@
|
|
6422
6458
|
}, {});
|
6423
6459
|
}
|
6424
6460
|
|
6425
|
-
var AbrController = /*#__PURE__*/function () {
|
6461
|
+
var AbrController = /*#__PURE__*/function (_Logger) {
|
6462
|
+
_inheritsLoose(AbrController, _Logger);
|
6426
6463
|
function AbrController(_hls) {
|
6427
|
-
var _this
|
6428
|
-
this.
|
6429
|
-
|
6430
|
-
|
6431
|
-
|
6432
|
-
|
6433
|
-
|
6434
|
-
|
6435
|
-
|
6436
|
-
|
6437
|
-
|
6438
|
-
|
6439
|
-
|
6440
|
-
|
6464
|
+
var _this;
|
6465
|
+
_this = _Logger.call(this, 'abr', _hls.logger) || this;
|
6466
|
+
_this.hls = void 0;
|
6467
|
+
_this.lastLevelLoadSec = 0;
|
6468
|
+
_this.lastLoadedFragLevel = -1;
|
6469
|
+
_this.firstSelection = -1;
|
6470
|
+
_this._nextAutoLevel = -1;
|
6471
|
+
_this.nextAutoLevelKey = '';
|
6472
|
+
_this.audioTracksByGroup = null;
|
6473
|
+
_this.codecTiers = null;
|
6474
|
+
_this.timer = -1;
|
6475
|
+
_this.fragCurrent = null;
|
6476
|
+
_this.partCurrent = null;
|
6477
|
+
_this.bitrateTestDelay = 0;
|
6478
|
+
_this.bwEstimator = void 0;
|
6441
6479
|
/*
|
6442
6480
|
This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
|
6443
6481
|
quickly enough to prevent underbuffering
|
6444
6482
|
*/
|
6445
|
-
|
6446
|
-
var
|
6447
|
-
|
6448
|
-
|
6483
|
+
_this._abandonRulesCheck = function () {
|
6484
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
6485
|
+
frag = _assertThisInitialize.fragCurrent,
|
6486
|
+
part = _assertThisInitialize.partCurrent,
|
6487
|
+
hls = _assertThisInitialize.hls;
|
6449
6488
|
var autoLevelEnabled = hls.autoLevelEnabled,
|
6450
6489
|
media = hls.media;
|
6451
6490
|
if (!frag || !media) {
|
@@ -6534,21 +6573,22 @@
|
|
6534
6573
|
_this.resetEstimator(nextLoadLevelBitrate);
|
6535
6574
|
}
|
6536
6575
|
_this.clearTimer();
|
6537
|
-
|
6576
|
+
_this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
|
6538
6577
|
hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
|
6539
6578
|
frag: frag,
|
6540
6579
|
part: part,
|
6541
6580
|
stats: stats
|
6542
6581
|
});
|
6543
6582
|
};
|
6544
|
-
|
6545
|
-
|
6546
|
-
|
6583
|
+
_this.hls = _hls;
|
6584
|
+
_this.bwEstimator = _this.initEstimator();
|
6585
|
+
_this.registerListeners();
|
6586
|
+
return _this;
|
6547
6587
|
}
|
6548
6588
|
var _proto = AbrController.prototype;
|
6549
6589
|
_proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
|
6550
6590
|
if (abrEwmaDefaultEstimate) {
|
6551
|
-
|
6591
|
+
this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
|
6552
6592
|
this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
|
6553
6593
|
}
|
6554
6594
|
this.firstSelection = -1;
|
@@ -6800,13 +6840,13 @@
|
|
6800
6840
|
// cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
|
6801
6841
|
var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
|
6802
6842
|
maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
|
6803
|
-
|
6843
|
+
this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
|
6804
6844
|
// don't use conservative factor on bitrate test
|
6805
6845
|
bwFactor = bwUpFactor = 1;
|
6806
6846
|
}
|
6807
6847
|
}
|
6808
6848
|
var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
|
6809
|
-
|
6849
|
+
this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
|
6810
6850
|
if (bestLevel > -1) {
|
6811
6851
|
return bestLevel;
|
6812
6852
|
}
|
@@ -6862,7 +6902,7 @@
|
|
6862
6902
|
currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
|
6863
6903
|
currentFrameRate = minFramerate;
|
6864
6904
|
currentBw = Math.max(currentBw, minBitrate);
|
6865
|
-
|
6905
|
+
this.log("picked start tier " + JSON.stringify(startTier));
|
6866
6906
|
} else {
|
6867
6907
|
currentCodecSet = level == null ? void 0 : level.codecSet;
|
6868
6908
|
currentVideoRange = level == null ? void 0 : level.videoRange;
|
@@ -6915,9 +6955,9 @@
|
|
6915
6955
|
var forcedAutoLevel = _this2.forcedAutoLevel;
|
6916
6956
|
if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
|
6917
6957
|
if (levelsSkipped.length) {
|
6918
|
-
|
6958
|
+
_this2.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
|
6919
6959
|
}
|
6920
|
-
|
6960
|
+
_this2.info("switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
|
6921
6961
|
}
|
6922
6962
|
if (firstSelection) {
|
6923
6963
|
_this2.firstSelection = i;
|
@@ -6951,7 +6991,7 @@
|
|
6951
6991
|
}
|
6952
6992
|
var firstLevel = this.hls.firstLevel;
|
6953
6993
|
var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
|
6954
|
-
|
6994
|
+
this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
|
6955
6995
|
return clamped;
|
6956
6996
|
}
|
6957
6997
|
}, {
|
@@ -7004,7 +7044,7 @@
|
|
7004
7044
|
}
|
7005
7045
|
}]);
|
7006
7046
|
return AbrController;
|
7007
|
-
}();
|
7047
|
+
}(Logger);
|
7008
7048
|
|
7009
7049
|
/**
|
7010
7050
|
* Provides methods dealing with buffer length retrieval for example.
|
@@ -7225,57 +7265,57 @@
|
|
7225
7265
|
}();
|
7226
7266
|
|
7227
7267
|
var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
|
7228
|
-
var BufferController = /*#__PURE__*/function () {
|
7268
|
+
var BufferController = /*#__PURE__*/function (_Logger) {
|
7269
|
+
_inheritsLoose(BufferController, _Logger);
|
7229
7270
|
function BufferController(hls) {
|
7230
|
-
var _this
|
7271
|
+
var _this;
|
7272
|
+
_this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
|
7231
7273
|
// The level details used to determine duration, target-duration and live
|
7232
|
-
|
7274
|
+
_this.details = null;
|
7233
7275
|
// cache the self generated object url to detect hijack of video tag
|
7234
|
-
|
7276
|
+
_this._objectUrl = null;
|
7235
7277
|
// A queue of buffer operations which require the SourceBuffer to not be updating upon execution
|
7236
|
-
|
7278
|
+
_this.operationQueue = void 0;
|
7237
7279
|
// References to event listeners for each SourceBuffer, so that they can be referenced for event removal
|
7238
|
-
|
7239
|
-
|
7280
|
+
_this.listeners = void 0;
|
7281
|
+
_this.hls = void 0;
|
7240
7282
|
// The number of BUFFER_CODEC events received before any sourceBuffers are created
|
7241
|
-
|
7283
|
+
_this.bufferCodecEventsExpected = 0;
|
7242
7284
|
// The total number of BUFFER_CODEC events received
|
7243
|
-
|
7285
|
+
_this._bufferCodecEventsTotal = 0;
|
7244
7286
|
// A reference to the attached media element
|
7245
|
-
|
7287
|
+
_this.media = null;
|
7246
7288
|
// A reference to the active media source
|
7247
|
-
|
7289
|
+
_this.mediaSource = null;
|
7248
7290
|
// Last MP3 audio chunk appended
|
7249
|
-
|
7250
|
-
|
7291
|
+
_this.lastMpegAudioChunk = null;
|
7292
|
+
_this.appendSource = void 0;
|
7251
7293
|
// counters
|
7252
|
-
|
7294
|
+
_this.appendErrors = {
|
7253
7295
|
audio: 0,
|
7254
7296
|
video: 0,
|
7255
7297
|
audiovideo: 0
|
7256
7298
|
};
|
7257
|
-
|
7258
|
-
|
7259
|
-
|
7260
|
-
|
7261
|
-
this.warn = void 0;
|
7262
|
-
this.error = void 0;
|
7263
|
-
this._onEndStreaming = function (event) {
|
7299
|
+
_this.tracks = {};
|
7300
|
+
_this.pendingTracks = {};
|
7301
|
+
_this.sourceBuffer = void 0;
|
7302
|
+
_this._onEndStreaming = function (event) {
|
7264
7303
|
if (!_this.hls) {
|
7265
7304
|
return;
|
7266
7305
|
}
|
7267
7306
|
_this.hls.pauseBuffering();
|
7268
7307
|
};
|
7269
|
-
|
7308
|
+
_this._onStartStreaming = function (event) {
|
7270
7309
|
if (!_this.hls) {
|
7271
7310
|
return;
|
7272
7311
|
}
|
7273
7312
|
_this.hls.resumeBuffering();
|
7274
7313
|
};
|
7275
7314
|
// Keep as arrow functions so that we can directly reference these functions directly as event listeners
|
7276
|
-
|
7277
|
-
var
|
7278
|
-
|
7315
|
+
_this._onMediaSourceOpen = function () {
|
7316
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
7317
|
+
media = _assertThisInitialize.media,
|
7318
|
+
mediaSource = _assertThisInitialize.mediaSource;
|
7279
7319
|
_this.log('Media source opened');
|
7280
7320
|
if (media) {
|
7281
7321
|
media.removeEventListener('emptied', _this._onMediaEmptied);
|
@@ -7291,27 +7331,25 @@
|
|
7291
7331
|
}
|
7292
7332
|
_this.checkPendingTracks();
|
7293
7333
|
};
|
7294
|
-
|
7334
|
+
_this._onMediaSourceClose = function () {
|
7295
7335
|
_this.log('Media source closed');
|
7296
7336
|
};
|
7297
|
-
|
7337
|
+
_this._onMediaSourceEnded = function () {
|
7298
7338
|
_this.log('Media source ended');
|
7299
7339
|
};
|
7300
|
-
|
7301
|
-
var
|
7302
|
-
|
7340
|
+
_this._onMediaEmptied = function () {
|
7341
|
+
var _assertThisInitialize2 = _assertThisInitialized(_this),
|
7342
|
+
mediaSrc = _assertThisInitialize2.mediaSrc,
|
7343
|
+
_objectUrl = _assertThisInitialize2._objectUrl;
|
7303
7344
|
if (mediaSrc !== _objectUrl) {
|
7304
|
-
|
7345
|
+
_this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
|
7305
7346
|
}
|
7306
7347
|
};
|
7307
|
-
|
7308
|
-
|
7309
|
-
|
7310
|
-
|
7311
|
-
|
7312
|
-
this.error = logger.error.bind(logger, logPrefix);
|
7313
|
-
this._initSourceBuffer();
|
7314
|
-
this.registerListeners();
|
7348
|
+
_this.hls = hls;
|
7349
|
+
_this.appendSource = hls.config.preferManagedMediaSource;
|
7350
|
+
_this._initSourceBuffer();
|
7351
|
+
_this.registerListeners();
|
7352
|
+
return _this;
|
7315
7353
|
}
|
7316
7354
|
var _proto = BufferController.prototype;
|
7317
7355
|
_proto.hasSourceTypes = function hasSourceTypes() {
|
@@ -7323,6 +7361,12 @@
|
|
7323
7361
|
this.lastMpegAudioChunk = null;
|
7324
7362
|
// @ts-ignore
|
7325
7363
|
this.hls = null;
|
7364
|
+
// @ts-ignore
|
7365
|
+
this._onMediaSourceOpen = this._onMediaSourceClose = null;
|
7366
|
+
// @ts-ignore
|
7367
|
+
this._onMediaSourceEnded = null;
|
7368
|
+
// @ts-ignore
|
7369
|
+
this._onStartStreaming = this._onEndStreaming = null;
|
7326
7370
|
};
|
7327
7371
|
_proto.registerListeners = function registerListeners() {
|
7328
7372
|
var hls = this.hls;
|
@@ -7480,6 +7524,7 @@
|
|
7480
7524
|
_this2.resetBuffer(type);
|
7481
7525
|
});
|
7482
7526
|
this._initSourceBuffer();
|
7527
|
+
this.hls.resumeBuffering();
|
7483
7528
|
};
|
7484
7529
|
_proto.resetBuffer = function resetBuffer(type) {
|
7485
7530
|
var sb = this.sourceBuffer[type];
|
@@ -8183,7 +8228,7 @@
|
|
8183
8228
|
}
|
8184
8229
|
}]);
|
8185
8230
|
return BufferController;
|
8186
|
-
}();
|
8231
|
+
}(Logger);
|
8187
8232
|
function removeSourceChildren(node) {
|
8188
8233
|
var sourceChildren = node.querySelectorAll('source');
|
8189
8234
|
[].slice.call(sourceChildren).forEach(function (source) {
|
@@ -8307,7 +8352,7 @@
|
|
8307
8352
|
var hls = this.hls;
|
8308
8353
|
var maxLevel = this.getMaxLevel(levels.length - 1);
|
8309
8354
|
if (maxLevel !== this.autoLevelCapping) {
|
8310
|
-
logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8355
|
+
hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8311
8356
|
}
|
8312
8357
|
hls.autoLevelCapping = maxLevel;
|
8313
8358
|
if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
|
@@ -8497,10 +8542,10 @@
|
|
8497
8542
|
totalDroppedFrames: droppedFrames
|
8498
8543
|
});
|
8499
8544
|
if (droppedFPS > 0) {
|
8500
|
-
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8545
|
+
// hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8501
8546
|
if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
|
8502
8547
|
var currentLevel = hls.currentLevel;
|
8503
|
-
logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8548
|
+
hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8504
8549
|
if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
|
8505
8550
|
currentLevel = currentLevel - 1;
|
8506
8551
|
hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
|
@@ -8534,26 +8579,28 @@
|
|
8534
8579
|
}();
|
8535
8580
|
|
8536
8581
|
var PATHWAY_PENALTY_DURATION_MS = 300000;
|
8537
|
-
var ContentSteeringController = /*#__PURE__*/function () {
|
8582
|
+
var ContentSteeringController = /*#__PURE__*/function (_Logger) {
|
8583
|
+
_inheritsLoose(ContentSteeringController, _Logger);
|
8538
8584
|
function ContentSteeringController(hls) {
|
8539
|
-
|
8540
|
-
this.
|
8541
|
-
|
8542
|
-
|
8543
|
-
|
8544
|
-
|
8545
|
-
|
8546
|
-
|
8547
|
-
|
8548
|
-
|
8549
|
-
|
8550
|
-
|
8551
|
-
|
8552
|
-
|
8553
|
-
|
8554
|
-
|
8555
|
-
|
8556
|
-
|
8585
|
+
var _this;
|
8586
|
+
_this = _Logger.call(this, 'content-steering', hls.logger) || this;
|
8587
|
+
_this.hls = void 0;
|
8588
|
+
_this.loader = null;
|
8589
|
+
_this.uri = null;
|
8590
|
+
_this.pathwayId = '.';
|
8591
|
+
_this.pathwayPriority = null;
|
8592
|
+
_this.timeToLoad = 300;
|
8593
|
+
_this.reloadTimer = -1;
|
8594
|
+
_this.updated = 0;
|
8595
|
+
_this.started = false;
|
8596
|
+
_this.enabled = true;
|
8597
|
+
_this.levels = null;
|
8598
|
+
_this.audioTracks = null;
|
8599
|
+
_this.subtitleTracks = null;
|
8600
|
+
_this.penalizedPathways = {};
|
8601
|
+
_this.hls = hls;
|
8602
|
+
_this.registerListeners();
|
8603
|
+
return _this;
|
8557
8604
|
}
|
8558
8605
|
var _proto = ContentSteeringController.prototype;
|
8559
8606
|
_proto.registerListeners = function registerListeners() {
|
@@ -8674,7 +8721,7 @@
|
|
8674
8721
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
8675
8722
|
}
|
8676
8723
|
if (!errorAction.resolved) {
|
8677
|
-
|
8724
|
+
this.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
|
8678
8725
|
}
|
8679
8726
|
}
|
8680
8727
|
};
|
@@ -8754,7 +8801,7 @@
|
|
8754
8801
|
return defaultPathway;
|
8755
8802
|
};
|
8756
8803
|
_proto.clonePathways = function clonePathways(pathwayClones) {
|
8757
|
-
var
|
8804
|
+
var _this2 = this;
|
8758
8805
|
var levels = this.levels;
|
8759
8806
|
if (!levels) {
|
8760
8807
|
return;
|
@@ -8770,7 +8817,7 @@
|
|
8770
8817
|
})) {
|
8771
8818
|
return;
|
8772
8819
|
}
|
8773
|
-
var clonedVariants =
|
8820
|
+
var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
|
8774
8821
|
var attributes = new AttrList(baseLevel.attrs);
|
8775
8822
|
attributes['PATHWAY-ID'] = cloneId;
|
8776
8823
|
var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
|
@@ -8807,12 +8854,12 @@
|
|
8807
8854
|
return clonedLevel;
|
8808
8855
|
});
|
8809
8856
|
levels.push.apply(levels, clonedVariants);
|
8810
|
-
cloneRenditionGroups(
|
8811
|
-
cloneRenditionGroups(
|
8857
|
+
cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
|
8858
|
+
cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
|
8812
8859
|
});
|
8813
8860
|
};
|
8814
8861
|
_proto.loadSteeringManifest = function loadSteeringManifest(uri) {
|
8815
|
-
var
|
8862
|
+
var _this3 = this;
|
8816
8863
|
var config = this.hls.config;
|
8817
8864
|
var Loader = config.loader;
|
8818
8865
|
if (this.loader) {
|
@@ -8847,87 +8894,87 @@
|
|
8847
8894
|
};
|
8848
8895
|
var callbacks = {
|
8849
8896
|
onSuccess: function onSuccess(response, stats, context, networkDetails) {
|
8850
|
-
|
8897
|
+
_this3.log("Loaded steering manifest: \"" + url + "\"");
|
8851
8898
|
var steeringData = response.data;
|
8852
|
-
if (steeringData.VERSION !== 1) {
|
8853
|
-
|
8899
|
+
if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
|
8900
|
+
_this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
|
8854
8901
|
return;
|
8855
8902
|
}
|
8856
|
-
|
8857
|
-
|
8903
|
+
_this3.updated = performance.now();
|
8904
|
+
_this3.timeToLoad = steeringData.TTL;
|
8858
8905
|
var reloadUri = steeringData['RELOAD-URI'],
|
8859
8906
|
pathwayClones = steeringData['PATHWAY-CLONES'],
|
8860
8907
|
pathwayPriority = steeringData['PATHWAY-PRIORITY'];
|
8861
8908
|
if (reloadUri) {
|
8862
8909
|
try {
|
8863
|
-
|
8910
|
+
_this3.uri = new self.URL(reloadUri, url).href;
|
8864
8911
|
} catch (error) {
|
8865
|
-
|
8866
|
-
|
8912
|
+
_this3.enabled = false;
|
8913
|
+
_this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
|
8867
8914
|
return;
|
8868
8915
|
}
|
8869
8916
|
}
|
8870
|
-
|
8917
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8871
8918
|
if (pathwayClones) {
|
8872
|
-
|
8919
|
+
_this3.clonePathways(pathwayClones);
|
8873
8920
|
}
|
8874
8921
|
var loadedSteeringData = {
|
8875
8922
|
steeringManifest: steeringData,
|
8876
8923
|
url: url.toString()
|
8877
8924
|
};
|
8878
|
-
|
8925
|
+
_this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
|
8879
8926
|
if (pathwayPriority) {
|
8880
|
-
|
8927
|
+
_this3.updatePathwayPriority(pathwayPriority);
|
8881
8928
|
}
|
8882
8929
|
},
|
8883
8930
|
onError: function onError(error, context, networkDetails, stats) {
|
8884
|
-
|
8885
|
-
|
8931
|
+
_this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
|
8932
|
+
_this3.stopLoad();
|
8886
8933
|
if (error.code === 410) {
|
8887
|
-
|
8888
|
-
|
8934
|
+
_this3.enabled = false;
|
8935
|
+
_this3.log("Steering manifest " + context.url + " no longer available");
|
8889
8936
|
return;
|
8890
8937
|
}
|
8891
|
-
var ttl =
|
8938
|
+
var ttl = _this3.timeToLoad * 1000;
|
8892
8939
|
if (error.code === 429) {
|
8893
|
-
var loader =
|
8940
|
+
var loader = _this3.loader;
|
8894
8941
|
if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
|
8895
8942
|
var retryAfter = loader.getResponseHeader('Retry-After');
|
8896
8943
|
if (retryAfter) {
|
8897
8944
|
ttl = parseFloat(retryAfter) * 1000;
|
8898
8945
|
}
|
8899
8946
|
}
|
8900
|
-
|
8947
|
+
_this3.log("Steering manifest " + context.url + " rate limited");
|
8901
8948
|
return;
|
8902
8949
|
}
|
8903
|
-
|
8950
|
+
_this3.scheduleRefresh(_this3.uri || context.url, ttl);
|
8904
8951
|
},
|
8905
8952
|
onTimeout: function onTimeout(stats, context, networkDetails) {
|
8906
|
-
|
8907
|
-
|
8953
|
+
_this3.log("Timeout loading steering manifest (" + context.url + ")");
|
8954
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8908
8955
|
}
|
8909
8956
|
};
|
8910
8957
|
this.log("Requesting steering manifest: " + url);
|
8911
8958
|
this.loader.load(context, loaderConfig, callbacks);
|
8912
8959
|
};
|
8913
8960
|
_proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
|
8914
|
-
var
|
8961
|
+
var _this4 = this;
|
8915
8962
|
if (ttlMs === void 0) {
|
8916
8963
|
ttlMs = this.timeToLoad * 1000;
|
8917
8964
|
}
|
8918
8965
|
this.clearTimeout();
|
8919
8966
|
this.reloadTimer = self.setTimeout(function () {
|
8920
|
-
var
|
8921
|
-
var media = (
|
8967
|
+
var _this4$hls;
|
8968
|
+
var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
|
8922
8969
|
if (media && !media.ended) {
|
8923
|
-
|
8970
|
+
_this4.loadSteeringManifest(uri);
|
8924
8971
|
return;
|
8925
8972
|
}
|
8926
|
-
|
8973
|
+
_this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
|
8927
8974
|
}, ttlMs);
|
8928
8975
|
};
|
8929
8976
|
return ContentSteeringController;
|
8930
|
-
}();
|
8977
|
+
}(Logger);
|
8931
8978
|
function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
|
8932
8979
|
if (!tracks) {
|
8933
8980
|
return;
|
@@ -9763,7 +9810,7 @@
|
|
9763
9810
|
});
|
9764
9811
|
function timelineConfig() {
|
9765
9812
|
return {
|
9766
|
-
cueHandler:
|
9813
|
+
cueHandler: HevcVideoParser,
|
9767
9814
|
// used by timeline-controller
|
9768
9815
|
enableWebVTT: false,
|
9769
9816
|
// used by timeline-controller
|
@@ -9794,7 +9841,7 @@
|
|
9794
9841
|
/**
|
9795
9842
|
* @ignore
|
9796
9843
|
*/
|
9797
|
-
function mergeConfig(defaultConfig, userConfig) {
|
9844
|
+
function mergeConfig(defaultConfig, userConfig, logger) {
|
9798
9845
|
if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
|
9799
9846
|
throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
|
9800
9847
|
}
|
@@ -9864,7 +9911,7 @@
|
|
9864
9911
|
/**
|
9865
9912
|
* @ignore
|
9866
9913
|
*/
|
9867
|
-
function enableStreamingMode(config) {
|
9914
|
+
function enableStreamingMode(config, logger) {
|
9868
9915
|
var currentLoader = config.loader;
|
9869
9916
|
if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
|
9870
9917
|
// If a developer has configured their own loader, respect that choice
|
@@ -9881,12 +9928,11 @@
|
|
9881
9928
|
}
|
9882
9929
|
}
|
9883
9930
|
|
9884
|
-
var chromeOrFirefox;
|
9885
9931
|
var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
|
9886
9932
|
_inheritsLoose(LevelController, _BasePlaylistControll);
|
9887
9933
|
function LevelController(hls, contentSteeringController) {
|
9888
9934
|
var _this;
|
9889
|
-
_this = _BasePlaylistControll.call(this, hls, '
|
9935
|
+
_this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
|
9890
9936
|
_this._levels = [];
|
9891
9937
|
_this._firstLevel = -1;
|
9892
9938
|
_this._maxAutoLevel = -1;
|
@@ -9955,21 +10001,13 @@
|
|
9955
10001
|
var videoCodecFound = false;
|
9956
10002
|
var audioCodecFound = false;
|
9957
10003
|
data.levels.forEach(function (levelParsed) {
|
9958
|
-
var
|
10004
|
+
var _videoCodec;
|
9959
10005
|
var attributes = levelParsed.attrs;
|
9960
|
-
|
9961
|
-
// erase audio codec info if browser does not support mp4a.40.34.
|
9962
|
-
// demuxer will autodetect codec and fallback to mpeg/audio
|
9963
10006
|
var audioCodec = levelParsed.audioCodec,
|
9964
10007
|
videoCodec = levelParsed.videoCodec;
|
9965
|
-
if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
|
9966
|
-
chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
|
9967
|
-
if (chromeOrFirefox) {
|
9968
|
-
levelParsed.audioCodec = audioCodec = undefined;
|
9969
|
-
}
|
9970
|
-
}
|
9971
10008
|
if (audioCodec) {
|
9972
|
-
|
10009
|
+
// Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
|
10010
|
+
levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
|
9973
10011
|
}
|
9974
10012
|
if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
|
9975
10013
|
videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
|
@@ -11116,8 +11154,8 @@
|
|
11116
11154
|
var _frag$decryptdata;
|
11117
11155
|
var byteRangeStart = start;
|
11118
11156
|
var byteRangeEnd = end;
|
11119
|
-
if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)
|
11120
|
-
// MAP segment encrypted with method 'AES-128', when served with HTTP Range,
|
11157
|
+
if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
|
11158
|
+
// MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
|
11121
11159
|
// has the unencrypted size specified in the range.
|
11122
11160
|
// Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
11123
11161
|
var fragmentLen = end - start;
|
@@ -11150,6 +11188,9 @@
|
|
11150
11188
|
(part ? part : frag).stats.aborted = true;
|
11151
11189
|
return new LoadError(errorData);
|
11152
11190
|
}
|
11191
|
+
function isMethodFullSegmentAesCbc(method) {
|
11192
|
+
return method === 'AES-128' || method === 'AES-256';
|
11193
|
+
}
|
11153
11194
|
var LoadError = /*#__PURE__*/function (_Error) {
|
11154
11195
|
_inheritsLoose(LoadError, _Error);
|
11155
11196
|
function LoadError(data) {
|
@@ -11306,6 +11347,8 @@
|
|
11306
11347
|
}
|
11307
11348
|
return this.loadKeyEME(keyInfo, frag);
|
11308
11349
|
case 'AES-128':
|
11350
|
+
case 'AES-256':
|
11351
|
+
case 'AES-256-CTR':
|
11309
11352
|
return this.loadKeyHTTP(keyInfo, frag);
|
11310
11353
|
default:
|
11311
11354
|
return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
|
@@ -11439,13 +11482,17 @@
|
|
11439
11482
|
* we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
|
11440
11483
|
* task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
|
11441
11484
|
*/
|
11442
|
-
var TaskLoop = /*#__PURE__*/function () {
|
11443
|
-
|
11444
|
-
|
11445
|
-
|
11446
|
-
|
11447
|
-
|
11448
|
-
|
11485
|
+
var TaskLoop = /*#__PURE__*/function (_Logger) {
|
11486
|
+
_inheritsLoose(TaskLoop, _Logger);
|
11487
|
+
function TaskLoop(label, logger) {
|
11488
|
+
var _this;
|
11489
|
+
_this = _Logger.call(this, label, logger) || this;
|
11490
|
+
_this._boundTick = void 0;
|
11491
|
+
_this._tickTimer = null;
|
11492
|
+
_this._tickInterval = null;
|
11493
|
+
_this._tickCallCount = 0;
|
11494
|
+
_this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
|
11495
|
+
return _this;
|
11449
11496
|
}
|
11450
11497
|
var _proto = TaskLoop.prototype;
|
11451
11498
|
_proto.destroy = function destroy() {
|
@@ -11531,7 +11578,7 @@
|
|
11531
11578
|
*/;
|
11532
11579
|
_proto.doTick = function doTick() {};
|
11533
11580
|
return TaskLoop;
|
11534
|
-
}();
|
11581
|
+
}(Logger);
|
11535
11582
|
|
11536
11583
|
var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
|
11537
11584
|
if (size === void 0) {
|
@@ -11717,37 +11764,65 @@
|
|
11717
11764
|
}
|
11718
11765
|
|
11719
11766
|
var AESCrypto = /*#__PURE__*/function () {
|
11720
|
-
function AESCrypto(subtle, iv) {
|
11767
|
+
function AESCrypto(subtle, iv, aesMode) {
|
11721
11768
|
this.subtle = void 0;
|
11722
11769
|
this.aesIV = void 0;
|
11770
|
+
this.aesMode = void 0;
|
11723
11771
|
this.subtle = subtle;
|
11724
11772
|
this.aesIV = iv;
|
11773
|
+
this.aesMode = aesMode;
|
11725
11774
|
}
|
11726
11775
|
var _proto = AESCrypto.prototype;
|
11727
11776
|
_proto.decrypt = function decrypt(data, key) {
|
11728
|
-
|
11729
|
-
|
11730
|
-
|
11731
|
-
|
11777
|
+
switch (this.aesMode) {
|
11778
|
+
case DecrypterAesMode.cbc:
|
11779
|
+
return this.subtle.decrypt({
|
11780
|
+
name: 'AES-CBC',
|
11781
|
+
iv: this.aesIV
|
11782
|
+
}, key, data);
|
11783
|
+
case DecrypterAesMode.ctr:
|
11784
|
+
return this.subtle.decrypt({
|
11785
|
+
name: 'AES-CTR',
|
11786
|
+
counter: this.aesIV,
|
11787
|
+
length: 64
|
11788
|
+
},
|
11789
|
+
//64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
|
11790
|
+
key, data);
|
11791
|
+
default:
|
11792
|
+
throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
|
11793
|
+
}
|
11732
11794
|
};
|
11733
11795
|
return AESCrypto;
|
11734
11796
|
}();
|
11735
11797
|
|
11736
11798
|
var FastAESKey = /*#__PURE__*/function () {
|
11737
|
-
function FastAESKey(subtle, key) {
|
11799
|
+
function FastAESKey(subtle, key, aesMode) {
|
11738
11800
|
this.subtle = void 0;
|
11739
11801
|
this.key = void 0;
|
11802
|
+
this.aesMode = void 0;
|
11740
11803
|
this.subtle = subtle;
|
11741
11804
|
this.key = key;
|
11805
|
+
this.aesMode = aesMode;
|
11742
11806
|
}
|
11743
11807
|
var _proto = FastAESKey.prototype;
|
11744
11808
|
_proto.expandKey = function expandKey() {
|
11809
|
+
var subtleAlgoName = getSubtleAlgoName(this.aesMode);
|
11745
11810
|
return this.subtle.importKey('raw', this.key, {
|
11746
|
-
name:
|
11811
|
+
name: subtleAlgoName
|
11747
11812
|
}, false, ['encrypt', 'decrypt']);
|
11748
11813
|
};
|
11749
11814
|
return FastAESKey;
|
11750
11815
|
}();
|
11816
|
+
function getSubtleAlgoName(aesMode) {
|
11817
|
+
switch (aesMode) {
|
11818
|
+
case DecrypterAesMode.cbc:
|
11819
|
+
return 'AES-CBC';
|
11820
|
+
case DecrypterAesMode.ctr:
|
11821
|
+
return 'AES-CTR';
|
11822
|
+
default:
|
11823
|
+
throw new Error("[FastAESKey] invalid aes mode " + aesMode);
|
11824
|
+
}
|
11825
|
+
}
|
11751
11826
|
|
11752
11827
|
// PKCS7
|
11753
11828
|
function removePadding(array) {
|
@@ -12000,7 +12075,8 @@
|
|
12000
12075
|
this.currentIV = null;
|
12001
12076
|
this.currentResult = null;
|
12002
12077
|
this.useSoftware = void 0;
|
12003
|
-
this.
|
12078
|
+
this.enableSoftwareAES = void 0;
|
12079
|
+
this.enableSoftwareAES = config.enableSoftwareAES;
|
12004
12080
|
this.removePKCS7Padding = removePKCS7Padding;
|
12005
12081
|
// built in decryptor expects PKCS7 padding
|
12006
12082
|
if (removePKCS7Padding) {
|
@@ -12013,9 +12089,7 @@
|
|
12013
12089
|
/* no-op */
|
12014
12090
|
}
|
12015
12091
|
}
|
12016
|
-
|
12017
|
-
this.useSoftware = true;
|
12018
|
-
}
|
12092
|
+
this.useSoftware = this.subtle === null;
|
12019
12093
|
}
|
12020
12094
|
var _proto = Decrypter.prototype;
|
12021
12095
|
_proto.destroy = function destroy() {
|
@@ -12052,11 +12126,11 @@
|
|
12052
12126
|
this.softwareDecrypter = null;
|
12053
12127
|
}
|
12054
12128
|
};
|
12055
|
-
_proto.decrypt = function decrypt(data, key, iv) {
|
12129
|
+
_proto.decrypt = function decrypt(data, key, iv, aesMode) {
|
12056
12130
|
var _this = this;
|
12057
12131
|
if (this.useSoftware) {
|
12058
12132
|
return new Promise(function (resolve, reject) {
|
12059
|
-
_this.softwareDecrypt(new Uint8Array(data), key, iv);
|
12133
|
+
_this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12060
12134
|
var decryptResult = _this.flush();
|
12061
12135
|
if (decryptResult) {
|
12062
12136
|
resolve(decryptResult.buffer);
|
@@ -12065,16 +12139,20 @@
|
|
12065
12139
|
}
|
12066
12140
|
});
|
12067
12141
|
}
|
12068
|
-
return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
|
12142
|
+
return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12069
12143
|
}
|
12070
12144
|
|
12071
12145
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
12072
12146
|
// data is handled in the flush() call
|
12073
12147
|
;
|
12074
|
-
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
|
12148
|
+
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
|
12075
12149
|
var currentIV = this.currentIV,
|
12076
12150
|
currentResult = this.currentResult,
|
12077
12151
|
remainderData = this.remainderData;
|
12152
|
+
if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
|
12153
|
+
logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
|
12154
|
+
return null;
|
12155
|
+
}
|
12078
12156
|
this.logOnce('JS AES decrypt');
|
12079
12157
|
// The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
|
12080
12158
|
// This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
|
@@ -12107,12 +12185,12 @@
|
|
12107
12185
|
}
|
12108
12186
|
return result;
|
12109
12187
|
};
|
12110
|
-
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
|
12188
|
+
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
|
12111
12189
|
var _this2 = this;
|
12112
12190
|
var subtle = this.subtle;
|
12113
12191
|
if (this.key !== key || !this.fastAesKey) {
|
12114
12192
|
this.key = key;
|
12115
|
-
this.fastAesKey = new FastAESKey(subtle, key);
|
12193
|
+
this.fastAesKey = new FastAESKey(subtle, key, aesMode);
|
12116
12194
|
}
|
12117
12195
|
return this.fastAesKey.expandKey().then(function (aesKey) {
|
12118
12196
|
// decrypt using web crypto
|
@@ -12120,22 +12198,25 @@
|
|
12120
12198
|
return Promise.reject(new Error('web crypto not initialized'));
|
12121
12199
|
}
|
12122
12200
|
_this2.logOnce('WebCrypto AES decrypt');
|
12123
|
-
var crypto = new AESCrypto(subtle, new Uint8Array(iv));
|
12201
|
+
var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
|
12124
12202
|
return crypto.decrypt(data.buffer, aesKey);
|
12125
12203
|
}).catch(function (err) {
|
12126
12204
|
logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
|
12127
|
-
return _this2.onWebCryptoError(data, key, iv);
|
12205
|
+
return _this2.onWebCryptoError(data, key, iv, aesMode);
|
12128
12206
|
});
|
12129
12207
|
};
|
12130
|
-
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
|
12131
|
-
|
12132
|
-
|
12133
|
-
|
12134
|
-
|
12135
|
-
|
12136
|
-
|
12208
|
+
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
|
12209
|
+
var enableSoftwareAES = this.enableSoftwareAES;
|
12210
|
+
if (enableSoftwareAES) {
|
12211
|
+
this.useSoftware = true;
|
12212
|
+
this.logEnabled = true;
|
12213
|
+
this.softwareDecrypt(data, key, iv, aesMode);
|
12214
|
+
var decryptResult = this.flush();
|
12215
|
+
if (decryptResult) {
|
12216
|
+
return decryptResult.buffer;
|
12217
|
+
}
|
12137
12218
|
}
|
12138
|
-
throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
|
12219
|
+
throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
|
12139
12220
|
};
|
12140
12221
|
_proto.getValidChunk = function getValidChunk(data) {
|
12141
12222
|
var currentChunk = data;
|
@@ -12189,7 +12270,7 @@
|
|
12189
12270
|
_inheritsLoose(BaseStreamController, _TaskLoop);
|
12190
12271
|
function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
|
12191
12272
|
var _this;
|
12192
|
-
_this = _TaskLoop.call(this) || this;
|
12273
|
+
_this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
|
12193
12274
|
_this.hls = void 0;
|
12194
12275
|
_this.fragPrevious = null;
|
12195
12276
|
_this.fragCurrent = null;
|
@@ -12214,25 +12295,87 @@
|
|
12214
12295
|
_this.startFragRequested = false;
|
12215
12296
|
_this.decrypter = void 0;
|
12216
12297
|
_this.initPTS = [];
|
12217
|
-
_this.
|
12218
|
-
_this.
|
12219
|
-
|
12220
|
-
|
12221
|
-
|
12298
|
+
_this.buffering = true;
|
12299
|
+
_this.onMediaSeeking = function () {
|
12300
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
12301
|
+
config = _assertThisInitialize.config,
|
12302
|
+
fragCurrent = _assertThisInitialize.fragCurrent,
|
12303
|
+
media = _assertThisInitialize.media,
|
12304
|
+
mediaBuffer = _assertThisInitialize.mediaBuffer,
|
12305
|
+
state = _assertThisInitialize.state;
|
12306
|
+
var currentTime = media ? media.currentTime : 0;
|
12307
|
+
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12308
|
+
_this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12309
|
+
if (_this.state === State.ENDED) {
|
12310
|
+
_this.resetLoadingState();
|
12311
|
+
} else if (fragCurrent) {
|
12312
|
+
// Seeking while frag load is in progress
|
12313
|
+
var tolerance = config.maxFragLookUpTolerance;
|
12314
|
+
var fragStartOffset = fragCurrent.start - tolerance;
|
12315
|
+
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12316
|
+
// if seeking out of buffered range or into new one
|
12317
|
+
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12318
|
+
var pastFragment = currentTime > fragEndOffset;
|
12319
|
+
// if the seek position is outside the current fragment range
|
12320
|
+
if (currentTime < fragStartOffset || pastFragment) {
|
12321
|
+
if (pastFragment && fragCurrent.loader) {
|
12322
|
+
_this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12323
|
+
fragCurrent.abortRequests();
|
12324
|
+
_this.resetLoadingState();
|
12325
|
+
}
|
12326
|
+
_this.fragPrevious = null;
|
12327
|
+
}
|
12328
|
+
}
|
12329
|
+
}
|
12330
|
+
if (media) {
|
12331
|
+
// Remove gap fragments
|
12332
|
+
_this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
|
12333
|
+
_this.lastCurrentTime = currentTime;
|
12334
|
+
}
|
12335
|
+
|
12336
|
+
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12337
|
+
if (!_this.loadedmetadata && !bufferInfo.len) {
|
12338
|
+
_this.nextLoadPosition = _this.startPosition = currentTime;
|
12339
|
+
}
|
12340
|
+
|
12341
|
+
// Async tick to speed up processing
|
12342
|
+
_this.tickImmediate();
|
12343
|
+
};
|
12344
|
+
_this.onMediaEnded = function () {
|
12345
|
+
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12346
|
+
_this.startPosition = _this.lastCurrentTime = 0;
|
12347
|
+
if (_this.playlistType === PlaylistLevelType.MAIN) {
|
12348
|
+
_this.hls.trigger(Events.MEDIA_ENDED, {
|
12349
|
+
stalled: false
|
12350
|
+
});
|
12351
|
+
}
|
12352
|
+
};
|
12222
12353
|
_this.playlistType = playlistType;
|
12223
|
-
_this.logPrefix = logPrefix;
|
12224
|
-
_this.log = logger.log.bind(logger, logPrefix + ":");
|
12225
|
-
_this.warn = logger.warn.bind(logger, logPrefix + ":");
|
12226
12354
|
_this.hls = hls;
|
12227
12355
|
_this.fragmentLoader = new FragmentLoader(hls.config);
|
12228
12356
|
_this.keyLoader = keyLoader;
|
12229
12357
|
_this.fragmentTracker = fragmentTracker;
|
12230
12358
|
_this.config = hls.config;
|
12231
12359
|
_this.decrypter = new Decrypter(hls.config);
|
12232
|
-
hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
|
12233
12360
|
return _this;
|
12234
12361
|
}
|
12235
12362
|
var _proto = BaseStreamController.prototype;
|
12363
|
+
_proto.registerListeners = function registerListeners() {
|
12364
|
+
var hls = this.hls;
|
12365
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12366
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12367
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12368
|
+
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12369
|
+
hls.on(Events.ERROR, this.onError, this);
|
12370
|
+
};
|
12371
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
12372
|
+
var hls = this.hls;
|
12373
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12374
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12375
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12376
|
+
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12377
|
+
hls.off(Events.ERROR, this.onError, this);
|
12378
|
+
};
|
12236
12379
|
_proto.doTick = function doTick() {
|
12237
12380
|
this.onTickEnd();
|
12238
12381
|
};
|
@@ -12256,6 +12399,12 @@
|
|
12256
12399
|
this.clearNextTick();
|
12257
12400
|
this.state = State.STOPPED;
|
12258
12401
|
};
|
12402
|
+
_proto.pauseBuffering = function pauseBuffering() {
|
12403
|
+
this.buffering = false;
|
12404
|
+
};
|
12405
|
+
_proto.resumeBuffering = function resumeBuffering() {
|
12406
|
+
this.buffering = true;
|
12407
|
+
};
|
12259
12408
|
_proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
|
12260
12409
|
// If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
|
12261
12410
|
// of nothing loading/loaded return false
|
@@ -12286,10 +12435,8 @@
|
|
12286
12435
|
};
|
12287
12436
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
12288
12437
|
var media = this.media = this.mediaBuffer = data.media;
|
12289
|
-
|
12290
|
-
|
12291
|
-
media.addEventListener('seeking', this.onvseeking);
|
12292
|
-
media.addEventListener('ended', this.onvended);
|
12438
|
+
media.addEventListener('seeking', this.onMediaSeeking);
|
12439
|
+
media.addEventListener('ended', this.onMediaEnded);
|
12293
12440
|
var config = this.config;
|
12294
12441
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
12295
12442
|
this.startLoad(config.startPosition);
|
@@ -12303,10 +12450,9 @@
|
|
12303
12450
|
}
|
12304
12451
|
|
12305
12452
|
// remove video listeners
|
12306
|
-
if (media
|
12307
|
-
media.removeEventListener('seeking', this.
|
12308
|
-
media.removeEventListener('ended', this.
|
12309
|
-
this.onvseeking = this.onvended = null;
|
12453
|
+
if (media) {
|
12454
|
+
media.removeEventListener('seeking', this.onMediaSeeking);
|
12455
|
+
media.removeEventListener('ended', this.onMediaEnded);
|
12310
12456
|
}
|
12311
12457
|
if (this.keyLoader) {
|
12312
12458
|
this.keyLoader.detach();
|
@@ -12316,54 +12462,8 @@
|
|
12316
12462
|
this.fragmentTracker.removeAllFragments();
|
12317
12463
|
this.stopLoad();
|
12318
12464
|
};
|
12319
|
-
_proto.
|
12320
|
-
|
12321
|
-
fragCurrent = this.fragCurrent,
|
12322
|
-
media = this.media,
|
12323
|
-
mediaBuffer = this.mediaBuffer,
|
12324
|
-
state = this.state;
|
12325
|
-
var currentTime = media ? media.currentTime : 0;
|
12326
|
-
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12327
|
-
this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12328
|
-
if (this.state === State.ENDED) {
|
12329
|
-
this.resetLoadingState();
|
12330
|
-
} else if (fragCurrent) {
|
12331
|
-
// Seeking while frag load is in progress
|
12332
|
-
var tolerance = config.maxFragLookUpTolerance;
|
12333
|
-
var fragStartOffset = fragCurrent.start - tolerance;
|
12334
|
-
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12335
|
-
// if seeking out of buffered range or into new one
|
12336
|
-
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12337
|
-
var pastFragment = currentTime > fragEndOffset;
|
12338
|
-
// if the seek position is outside the current fragment range
|
12339
|
-
if (currentTime < fragStartOffset || pastFragment) {
|
12340
|
-
if (pastFragment && fragCurrent.loader) {
|
12341
|
-
this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12342
|
-
fragCurrent.abortRequests();
|
12343
|
-
this.resetLoadingState();
|
12344
|
-
}
|
12345
|
-
this.fragPrevious = null;
|
12346
|
-
}
|
12347
|
-
}
|
12348
|
-
}
|
12349
|
-
if (media) {
|
12350
|
-
// Remove gap fragments
|
12351
|
-
this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
|
12352
|
-
this.lastCurrentTime = currentTime;
|
12353
|
-
}
|
12354
|
-
|
12355
|
-
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12356
|
-
if (!this.loadedmetadata && !bufferInfo.len) {
|
12357
|
-
this.nextLoadPosition = this.startPosition = currentTime;
|
12358
|
-
}
|
12359
|
-
|
12360
|
-
// Async tick to speed up processing
|
12361
|
-
this.tickImmediate();
|
12362
|
-
};
|
12363
|
-
_proto.onMediaEnded = function onMediaEnded() {
|
12364
|
-
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12365
|
-
this.startPosition = this.lastCurrentTime = 0;
|
12366
|
-
};
|
12465
|
+
_proto.onManifestLoading = function onManifestLoading() {};
|
12466
|
+
_proto.onError = function onError(event, data) {};
|
12367
12467
|
_proto.onManifestLoaded = function onManifestLoaded(event, data) {
|
12368
12468
|
this.startTimeOffset = data.startTimeOffset;
|
12369
12469
|
this.initPTS = [];
|
@@ -12373,7 +12473,7 @@
|
|
12373
12473
|
this.stopLoad();
|
12374
12474
|
_TaskLoop.prototype.onHandlerDestroying.call(this);
|
12375
12475
|
// @ts-ignore
|
12376
|
-
this.hls = null;
|
12476
|
+
this.hls = this.onMediaSeeking = this.onMediaEnded = null;
|
12377
12477
|
};
|
12378
12478
|
_proto.onHandlerDestroyed = function onHandlerDestroyed() {
|
12379
12479
|
this.state = State.STOPPED;
|
@@ -12503,10 +12603,10 @@
|
|
12503
12603
|
var decryptData = frag.decryptdata;
|
12504
12604
|
|
12505
12605
|
// check to see if the payload needs to be decrypted
|
12506
|
-
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method
|
12606
|
+
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
|
12507
12607
|
var startTime = self.performance.now();
|
12508
12608
|
// decrypt init segment data
|
12509
|
-
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
|
12609
|
+
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
|
12510
12610
|
hls.trigger(Events.ERROR, {
|
12511
12611
|
type: ErrorTypes.MEDIA_ERROR,
|
12512
12612
|
details: ErrorDetails.FRAG_DECRYPT_ERROR,
|
@@ -12619,7 +12719,7 @@
|
|
12619
12719
|
}
|
12620
12720
|
var keyLoadingPromise = null;
|
12621
12721
|
if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
|
12622
|
-
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.
|
12722
|
+
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
|
12623
12723
|
this.state = State.KEY_LOADING;
|
12624
12724
|
this.fragCurrent = frag;
|
12625
12725
|
keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
|
@@ -12650,7 +12750,7 @@
|
|
12650
12750
|
var partIndex = this.getNextPart(partList, frag, targetBufferTime);
|
12651
12751
|
if (partIndex > -1) {
|
12652
12752
|
var part = partList[partIndex];
|
12653
|
-
this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.
|
12753
|
+
this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12654
12754
|
this.nextLoadPosition = part.start + part.duration;
|
12655
12755
|
this.state = State.FRAG_LOADING;
|
12656
12756
|
var _result;
|
@@ -12683,7 +12783,7 @@
|
|
12683
12783
|
}
|
12684
12784
|
}
|
12685
12785
|
}
|
12686
|
-
this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.
|
12786
|
+
this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12687
12787
|
// Don't update nextLoadPosition for fragments which are not buffered
|
12688
12788
|
if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
|
12689
12789
|
this.nextLoadPosition = frag.start + frag.duration;
|
@@ -13244,7 +13344,7 @@
|
|
13244
13344
|
errorAction.resolved = true;
|
13245
13345
|
}
|
13246
13346
|
} else {
|
13247
|
-
|
13347
|
+
this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
|
13248
13348
|
return;
|
13249
13349
|
}
|
13250
13350
|
} else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
@@ -13634,6 +13734,7 @@
|
|
13634
13734
|
*/
|
13635
13735
|
function getAudioConfig(observer, data, offset, audioCodec) {
|
13636
13736
|
var adtsObjectType;
|
13737
|
+
var originalAdtsObjectType;
|
13637
13738
|
var adtsExtensionSamplingIndex;
|
13638
13739
|
var adtsChannelConfig;
|
13639
13740
|
var config;
|
@@ -13641,7 +13742,7 @@
|
|
13641
13742
|
var manifestCodec = audioCodec;
|
13642
13743
|
var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
13643
13744
|
// byte 2
|
13644
|
-
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13745
|
+
adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13645
13746
|
var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
13646
13747
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
13647
13748
|
var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
|
@@ -13658,8 +13759,8 @@
|
|
13658
13759
|
// byte 3
|
13659
13760
|
adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
|
13660
13761
|
logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
|
13661
|
-
//
|
13662
|
-
if (/firefox/i.test(userAgent)) {
|
13762
|
+
// Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
|
13763
|
+
if (/firefox|palemoon/i.test(userAgent)) {
|
13663
13764
|
if (adtsSamplingIndex >= 6) {
|
13664
13765
|
adtsObjectType = 5;
|
13665
13766
|
config = new Array(4);
|
@@ -13753,6 +13854,7 @@
|
|
13753
13854
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
13754
13855
|
channelCount: adtsChannelConfig,
|
13755
13856
|
codec: 'mp4a.40.' + adtsObjectType,
|
13857
|
+
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
13756
13858
|
manifestCodec: manifestCodec
|
13757
13859
|
};
|
13758
13860
|
}
|
@@ -13807,7 +13909,8 @@
|
|
13807
13909
|
track.channelCount = config.channelCount;
|
13808
13910
|
track.codec = config.codec;
|
13809
13911
|
track.manifestCodec = config.manifestCodec;
|
13810
|
-
|
13912
|
+
track.parsedCodec = config.parsedCodec;
|
13913
|
+
logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
|
13811
13914
|
}
|
13812
13915
|
}
|
13813
13916
|
function getFrameDuration(samplerate) {
|
@@ -14287,36 +14390,140 @@
|
|
14287
14390
|
logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
|
14288
14391
|
}
|
14289
14392
|
};
|
14290
|
-
|
14291
|
-
|
14292
|
-
|
14293
|
-
|
14294
|
-
|
14295
|
-
|
14296
|
-
|
14297
|
-
|
14298
|
-
|
14299
|
-
|
14300
|
-
|
14301
|
-
|
14302
|
-
this.bitsAvailable = void 0;
|
14303
|
-
this.data = data;
|
14304
|
-
// the number of bytes left to examine in this.data
|
14305
|
-
this.bytesAvailable = data.byteLength;
|
14306
|
-
// the current word being examined
|
14307
|
-
this.word = 0; // :uint
|
14308
|
-
// the number of bits left to examine in the current word
|
14309
|
-
this.bitsAvailable = 0; // :uint
|
14310
|
-
}
|
14393
|
+
_proto.parseNALu = function parseNALu(track, array) {
|
14394
|
+
var len = array.byteLength;
|
14395
|
+
var state = track.naluState || 0;
|
14396
|
+
var lastState = state;
|
14397
|
+
var units = [];
|
14398
|
+
var i = 0;
|
14399
|
+
var value;
|
14400
|
+
var overflow;
|
14401
|
+
var unitType;
|
14402
|
+
var lastUnitStart = -1;
|
14403
|
+
var lastUnitType = 0;
|
14404
|
+
// logger.log('PES:' + Hex.hexDump(array));
|
14311
14405
|
|
14312
|
-
|
14313
|
-
|
14314
|
-
|
14315
|
-
|
14316
|
-
|
14317
|
-
|
14318
|
-
|
14319
|
-
|
14406
|
+
if (state === -1) {
|
14407
|
+
// special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
|
14408
|
+
lastUnitStart = 0;
|
14409
|
+
// NALu type is value read from offset 0
|
14410
|
+
lastUnitType = this.getNALuType(array, 0);
|
14411
|
+
state = 0;
|
14412
|
+
i = 1;
|
14413
|
+
}
|
14414
|
+
while (i < len) {
|
14415
|
+
value = array[i++];
|
14416
|
+
// optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
|
14417
|
+
if (!state) {
|
14418
|
+
state = value ? 0 : 1;
|
14419
|
+
continue;
|
14420
|
+
}
|
14421
|
+
if (state === 1) {
|
14422
|
+
state = value ? 0 : 2;
|
14423
|
+
continue;
|
14424
|
+
}
|
14425
|
+
// here we have state either equal to 2 or 3
|
14426
|
+
if (!value) {
|
14427
|
+
state = 3;
|
14428
|
+
} else if (value === 1) {
|
14429
|
+
overflow = i - state - 1;
|
14430
|
+
if (lastUnitStart >= 0) {
|
14431
|
+
var unit = {
|
14432
|
+
data: array.subarray(lastUnitStart, overflow),
|
14433
|
+
type: lastUnitType
|
14434
|
+
};
|
14435
|
+
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14436
|
+
units.push(unit);
|
14437
|
+
} else {
|
14438
|
+
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14439
|
+
// first check if start code delimiter is overlapping between 2 PES packets,
|
14440
|
+
// ie it started in last packet (lastState not zero)
|
14441
|
+
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14442
|
+
var lastUnit = this.getLastNalUnit(track.samples);
|
14443
|
+
if (lastUnit) {
|
14444
|
+
if (lastState && i <= 4 - lastState) {
|
14445
|
+
// start delimiter overlapping between PES packets
|
14446
|
+
// strip start delimiter bytes from the end of last NAL unit
|
14447
|
+
// check if lastUnit had a state different from zero
|
14448
|
+
if (lastUnit.state) {
|
14449
|
+
// strip last bytes
|
14450
|
+
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14451
|
+
}
|
14452
|
+
}
|
14453
|
+
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14454
|
+
|
14455
|
+
if (overflow > 0) {
|
14456
|
+
// logger.log('first NALU found with overflow:' + overflow);
|
14457
|
+
lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
|
14458
|
+
lastUnit.state = 0;
|
14459
|
+
}
|
14460
|
+
}
|
14461
|
+
}
|
14462
|
+
// check if we can read unit type
|
14463
|
+
if (i < len) {
|
14464
|
+
unitType = this.getNALuType(array, i);
|
14465
|
+
// logger.log('find NALU @ offset:' + i + ',type:' + unitType);
|
14466
|
+
lastUnitStart = i;
|
14467
|
+
lastUnitType = unitType;
|
14468
|
+
state = 0;
|
14469
|
+
} else {
|
14470
|
+
// not enough byte to read unit type. let's read it on next PES parsing
|
14471
|
+
state = -1;
|
14472
|
+
}
|
14473
|
+
} else {
|
14474
|
+
state = 0;
|
14475
|
+
}
|
14476
|
+
}
|
14477
|
+
if (lastUnitStart >= 0 && state >= 0) {
|
14478
|
+
var _unit = {
|
14479
|
+
data: array.subarray(lastUnitStart, len),
|
14480
|
+
type: lastUnitType,
|
14481
|
+
state: state
|
14482
|
+
};
|
14483
|
+
units.push(_unit);
|
14484
|
+
// logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
|
14485
|
+
}
|
14486
|
+
// no NALu found
|
14487
|
+
if (units.length === 0) {
|
14488
|
+
// append pes.data to previous NAL unit
|
14489
|
+
var _lastUnit = this.getLastNalUnit(track.samples);
|
14490
|
+
if (_lastUnit) {
|
14491
|
+
_lastUnit.data = appendUint8Array(_lastUnit.data, array);
|
14492
|
+
}
|
14493
|
+
}
|
14494
|
+
track.naluState = state;
|
14495
|
+
return units;
|
14496
|
+
};
|
14497
|
+
return BaseVideoParser;
|
14498
|
+
}();
|
14499
|
+
|
14500
|
+
/**
|
14501
|
+
* Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
|
14502
|
+
*/
|
14503
|
+
|
14504
|
+
var ExpGolomb = /*#__PURE__*/function () {
|
14505
|
+
function ExpGolomb(data) {
|
14506
|
+
this.data = void 0;
|
14507
|
+
this.bytesAvailable = void 0;
|
14508
|
+
this.word = void 0;
|
14509
|
+
this.bitsAvailable = void 0;
|
14510
|
+
this.data = data;
|
14511
|
+
// the number of bytes left to examine in this.data
|
14512
|
+
this.bytesAvailable = data.byteLength;
|
14513
|
+
// the current word being examined
|
14514
|
+
this.word = 0; // :uint
|
14515
|
+
// the number of bits left to examine in the current word
|
14516
|
+
this.bitsAvailable = 0; // :uint
|
14517
|
+
}
|
14518
|
+
|
14519
|
+
// ():void
|
14520
|
+
var _proto = ExpGolomb.prototype;
|
14521
|
+
_proto.loadWord = function loadWord() {
|
14522
|
+
var data = this.data;
|
14523
|
+
var bytesAvailable = this.bytesAvailable;
|
14524
|
+
var position = data.byteLength - bytesAvailable;
|
14525
|
+
var workingBytes = new Uint8Array(4);
|
14526
|
+
var availableBytes = Math.min(4, bytesAvailable);
|
14320
14527
|
if (availableBytes === 0) {
|
14321
14528
|
throw new Error('no bytes available');
|
14322
14529
|
}
|
@@ -14441,189 +14648,6 @@
|
|
14441
14648
|
;
|
14442
14649
|
_proto.readUInt = function readUInt() {
|
14443
14650
|
return this.readBits(32);
|
14444
|
-
}
|
14445
|
-
|
14446
|
-
/**
|
14447
|
-
* Advance the ExpGolomb decoder past a scaling list. The scaling
|
14448
|
-
* list is optionally transmitted as part of a sequence parameter
|
14449
|
-
* set and is not relevant to transmuxing.
|
14450
|
-
* @param count the number of entries in this scaling list
|
14451
|
-
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14452
|
-
*/;
|
14453
|
-
_proto.skipScalingList = function skipScalingList(count) {
|
14454
|
-
var lastScale = 8;
|
14455
|
-
var nextScale = 8;
|
14456
|
-
var deltaScale;
|
14457
|
-
for (var j = 0; j < count; j++) {
|
14458
|
-
if (nextScale !== 0) {
|
14459
|
-
deltaScale = this.readEG();
|
14460
|
-
nextScale = (lastScale + deltaScale + 256) % 256;
|
14461
|
-
}
|
14462
|
-
lastScale = nextScale === 0 ? lastScale : nextScale;
|
14463
|
-
}
|
14464
|
-
}
|
14465
|
-
|
14466
|
-
/**
|
14467
|
-
* Read a sequence parameter set and return some interesting video
|
14468
|
-
* properties. A sequence parameter set is the H264 metadata that
|
14469
|
-
* describes the properties of upcoming video frames.
|
14470
|
-
* @returns an object with configuration parsed from the
|
14471
|
-
* sequence parameter set, including the dimensions of the
|
14472
|
-
* associated video frames.
|
14473
|
-
*/;
|
14474
|
-
_proto.readSPS = function readSPS() {
|
14475
|
-
var frameCropLeftOffset = 0;
|
14476
|
-
var frameCropRightOffset = 0;
|
14477
|
-
var frameCropTopOffset = 0;
|
14478
|
-
var frameCropBottomOffset = 0;
|
14479
|
-
var numRefFramesInPicOrderCntCycle;
|
14480
|
-
var scalingListCount;
|
14481
|
-
var i;
|
14482
|
-
var readUByte = this.readUByte.bind(this);
|
14483
|
-
var readBits = this.readBits.bind(this);
|
14484
|
-
var readUEG = this.readUEG.bind(this);
|
14485
|
-
var readBoolean = this.readBoolean.bind(this);
|
14486
|
-
var skipBits = this.skipBits.bind(this);
|
14487
|
-
var skipEG = this.skipEG.bind(this);
|
14488
|
-
var skipUEG = this.skipUEG.bind(this);
|
14489
|
-
var skipScalingList = this.skipScalingList.bind(this);
|
14490
|
-
readUByte();
|
14491
|
-
var profileIdc = readUByte(); // profile_idc
|
14492
|
-
readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
|
14493
|
-
skipBits(3); // reserved_zero_3bits u(3),
|
14494
|
-
readUByte(); // level_idc u(8)
|
14495
|
-
skipUEG(); // seq_parameter_set_id
|
14496
|
-
// some profiles have more optional data we don't need
|
14497
|
-
if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
|
14498
|
-
var chromaFormatIdc = readUEG();
|
14499
|
-
if (chromaFormatIdc === 3) {
|
14500
|
-
skipBits(1);
|
14501
|
-
} // separate_colour_plane_flag
|
14502
|
-
|
14503
|
-
skipUEG(); // bit_depth_luma_minus8
|
14504
|
-
skipUEG(); // bit_depth_chroma_minus8
|
14505
|
-
skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
14506
|
-
if (readBoolean()) {
|
14507
|
-
// seq_scaling_matrix_present_flag
|
14508
|
-
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
|
14509
|
-
for (i = 0; i < scalingListCount; i++) {
|
14510
|
-
if (readBoolean()) {
|
14511
|
-
// seq_scaling_list_present_flag[ i ]
|
14512
|
-
if (i < 6) {
|
14513
|
-
skipScalingList(16);
|
14514
|
-
} else {
|
14515
|
-
skipScalingList(64);
|
14516
|
-
}
|
14517
|
-
}
|
14518
|
-
}
|
14519
|
-
}
|
14520
|
-
}
|
14521
|
-
skipUEG(); // log2_max_frame_num_minus4
|
14522
|
-
var picOrderCntType = readUEG();
|
14523
|
-
if (picOrderCntType === 0) {
|
14524
|
-
readUEG(); // log2_max_pic_order_cnt_lsb_minus4
|
14525
|
-
} else if (picOrderCntType === 1) {
|
14526
|
-
skipBits(1); // delta_pic_order_always_zero_flag
|
14527
|
-
skipEG(); // offset_for_non_ref_pic
|
14528
|
-
skipEG(); // offset_for_top_to_bottom_field
|
14529
|
-
numRefFramesInPicOrderCntCycle = readUEG();
|
14530
|
-
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
14531
|
-
skipEG();
|
14532
|
-
} // offset_for_ref_frame[ i ]
|
14533
|
-
}
|
14534
|
-
skipUEG(); // max_num_ref_frames
|
14535
|
-
skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
14536
|
-
var picWidthInMbsMinus1 = readUEG();
|
14537
|
-
var picHeightInMapUnitsMinus1 = readUEG();
|
14538
|
-
var frameMbsOnlyFlag = readBits(1);
|
14539
|
-
if (frameMbsOnlyFlag === 0) {
|
14540
|
-
skipBits(1);
|
14541
|
-
} // mb_adaptive_frame_field_flag
|
14542
|
-
|
14543
|
-
skipBits(1); // direct_8x8_inference_flag
|
14544
|
-
if (readBoolean()) {
|
14545
|
-
// frame_cropping_flag
|
14546
|
-
frameCropLeftOffset = readUEG();
|
14547
|
-
frameCropRightOffset = readUEG();
|
14548
|
-
frameCropTopOffset = readUEG();
|
14549
|
-
frameCropBottomOffset = readUEG();
|
14550
|
-
}
|
14551
|
-
var pixelRatio = [1, 1];
|
14552
|
-
if (readBoolean()) {
|
14553
|
-
// vui_parameters_present_flag
|
14554
|
-
if (readBoolean()) {
|
14555
|
-
// aspect_ratio_info_present_flag
|
14556
|
-
var aspectRatioIdc = readUByte();
|
14557
|
-
switch (aspectRatioIdc) {
|
14558
|
-
case 1:
|
14559
|
-
pixelRatio = [1, 1];
|
14560
|
-
break;
|
14561
|
-
case 2:
|
14562
|
-
pixelRatio = [12, 11];
|
14563
|
-
break;
|
14564
|
-
case 3:
|
14565
|
-
pixelRatio = [10, 11];
|
14566
|
-
break;
|
14567
|
-
case 4:
|
14568
|
-
pixelRatio = [16, 11];
|
14569
|
-
break;
|
14570
|
-
case 5:
|
14571
|
-
pixelRatio = [40, 33];
|
14572
|
-
break;
|
14573
|
-
case 6:
|
14574
|
-
pixelRatio = [24, 11];
|
14575
|
-
break;
|
14576
|
-
case 7:
|
14577
|
-
pixelRatio = [20, 11];
|
14578
|
-
break;
|
14579
|
-
case 8:
|
14580
|
-
pixelRatio = [32, 11];
|
14581
|
-
break;
|
14582
|
-
case 9:
|
14583
|
-
pixelRatio = [80, 33];
|
14584
|
-
break;
|
14585
|
-
case 10:
|
14586
|
-
pixelRatio = [18, 11];
|
14587
|
-
break;
|
14588
|
-
case 11:
|
14589
|
-
pixelRatio = [15, 11];
|
14590
|
-
break;
|
14591
|
-
case 12:
|
14592
|
-
pixelRatio = [64, 33];
|
14593
|
-
break;
|
14594
|
-
case 13:
|
14595
|
-
pixelRatio = [160, 99];
|
14596
|
-
break;
|
14597
|
-
case 14:
|
14598
|
-
pixelRatio = [4, 3];
|
14599
|
-
break;
|
14600
|
-
case 15:
|
14601
|
-
pixelRatio = [3, 2];
|
14602
|
-
break;
|
14603
|
-
case 16:
|
14604
|
-
pixelRatio = [2, 1];
|
14605
|
-
break;
|
14606
|
-
case 255:
|
14607
|
-
{
|
14608
|
-
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
|
14609
|
-
break;
|
14610
|
-
}
|
14611
|
-
}
|
14612
|
-
}
|
14613
|
-
}
|
14614
|
-
return {
|
14615
|
-
width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
|
14616
|
-
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
|
14617
|
-
pixelRatio: pixelRatio
|
14618
|
-
};
|
14619
|
-
};
|
14620
|
-
_proto.readSliceType = function readSliceType() {
|
14621
|
-
// skip NALu type
|
14622
|
-
this.readUByte();
|
14623
|
-
// discard first_mb_in_slice
|
14624
|
-
this.readUEG();
|
14625
|
-
// return slice_type
|
14626
|
-
return this.readUEG();
|
14627
14651
|
};
|
14628
14652
|
return ExpGolomb;
|
14629
14653
|
}();
|
@@ -14634,9 +14658,9 @@
|
|
14634
14658
|
return _BaseVideoParser.apply(this, arguments) || this;
|
14635
14659
|
}
|
14636
14660
|
var _proto = AvcVideoParser.prototype;
|
14637
|
-
_proto.
|
14661
|
+
_proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
|
14638
14662
|
var _this = this;
|
14639
|
-
var units = this.
|
14663
|
+
var units = this.parseNALu(track, pes.data);
|
14640
14664
|
var VideoSample = this.VideoSample;
|
14641
14665
|
var push;
|
14642
14666
|
var spsfound = false;
|
@@ -14661,7 +14685,7 @@
|
|
14661
14685
|
// only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
|
14662
14686
|
if (spsfound && data.length > 4) {
|
14663
14687
|
// retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
|
14664
|
-
var sliceType =
|
14688
|
+
var sliceType = _this.readSliceType(data);
|
14665
14689
|
// 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
|
14666
14690
|
// SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
|
14667
14691
|
// An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
|
@@ -14715,8 +14739,7 @@
|
|
14715
14739
|
push = true;
|
14716
14740
|
spsfound = true;
|
14717
14741
|
var sps = unit.data;
|
14718
|
-
var
|
14719
|
-
var config = expGolombDecoder.readSPS();
|
14742
|
+
var config = _this.readSPS(sps);
|
14720
14743
|
if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) {
|
14721
14744
|
track.width = config.width;
|
14722
14745
|
track.height = config.height;
|
@@ -14772,109 +14795,192 @@
|
|
14772
14795
|
this.VideoSample = null;
|
14773
14796
|
}
|
14774
14797
|
};
|
14775
|
-
_proto.
|
14776
|
-
|
14777
|
-
|
14778
|
-
|
14779
|
-
var
|
14780
|
-
|
14781
|
-
|
14782
|
-
|
14783
|
-
|
14784
|
-
|
14785
|
-
|
14786
|
-
|
14798
|
+
_proto.getNALuType = function getNALuType(data, offset) {
|
14799
|
+
return data[offset] & 0x1f;
|
14800
|
+
};
|
14801
|
+
_proto.readSliceType = function readSliceType(data) {
|
14802
|
+
var eg = new ExpGolomb(data);
|
14803
|
+
// skip NALu type
|
14804
|
+
eg.readUByte();
|
14805
|
+
// discard first_mb_in_slice
|
14806
|
+
eg.readUEG();
|
14807
|
+
// return slice_type
|
14808
|
+
return eg.readUEG();
|
14809
|
+
}
|
14787
14810
|
|
14788
|
-
|
14789
|
-
|
14790
|
-
|
14791
|
-
|
14792
|
-
|
14793
|
-
|
14794
|
-
|
14795
|
-
|
14796
|
-
|
14797
|
-
|
14798
|
-
|
14799
|
-
if (
|
14800
|
-
|
14801
|
-
|
14802
|
-
}
|
14803
|
-
if (state === 1) {
|
14804
|
-
state = value ? 0 : 2;
|
14805
|
-
continue;
|
14811
|
+
/**
|
14812
|
+
* The scaling list is optionally transmitted as part of a sequence parameter
|
14813
|
+
* set and is not relevant to transmuxing.
|
14814
|
+
* @param count the number of entries in this scaling list
|
14815
|
+
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14816
|
+
*/;
|
14817
|
+
_proto.skipScalingList = function skipScalingList(count, reader) {
|
14818
|
+
var lastScale = 8;
|
14819
|
+
var nextScale = 8;
|
14820
|
+
var deltaScale;
|
14821
|
+
for (var j = 0; j < count; j++) {
|
14822
|
+
if (nextScale !== 0) {
|
14823
|
+
deltaScale = reader.readEG();
|
14824
|
+
nextScale = (lastScale + deltaScale + 256) % 256;
|
14806
14825
|
}
|
14807
|
-
|
14808
|
-
|
14809
|
-
|
14810
|
-
} else if (value === 1) {
|
14811
|
-
overflow = i - state - 1;
|
14812
|
-
if (lastUnitStart >= 0) {
|
14813
|
-
var unit = {
|
14814
|
-
data: array.subarray(lastUnitStart, overflow),
|
14815
|
-
type: lastUnitType
|
14816
|
-
};
|
14817
|
-
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14818
|
-
units.push(unit);
|
14819
|
-
} else {
|
14820
|
-
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14821
|
-
// first check if start code delimiter is overlapping between 2 PES packets,
|
14822
|
-
// ie it started in last packet (lastState not zero)
|
14823
|
-
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14824
|
-
var lastUnit = this.getLastNalUnit(track.samples);
|
14825
|
-
if (lastUnit) {
|
14826
|
-
if (lastState && i <= 4 - lastState) {
|
14827
|
-
// start delimiter overlapping between PES packets
|
14828
|
-
// strip start delimiter bytes from the end of last NAL unit
|
14829
|
-
// check if lastUnit had a state different from zero
|
14830
|
-
if (lastUnit.state) {
|
14831
|
-
// strip last bytes
|
14832
|
-
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14833
|
-
}
|
14834
|
-
}
|
14835
|
-
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14826
|
+
lastScale = nextScale === 0 ? lastScale : nextScale;
|
14827
|
+
}
|
14828
|
+
}
|
14836
14829
|
|
14837
|
-
|
14838
|
-
|
14839
|
-
|
14840
|
-
|
14841
|
-
|
14842
|
-
|
14843
|
-
|
14844
|
-
|
14845
|
-
|
14846
|
-
|
14847
|
-
|
14848
|
-
|
14849
|
-
|
14850
|
-
|
14851
|
-
|
14852
|
-
|
14853
|
-
|
14830
|
+
/**
|
14831
|
+
* Read a sequence parameter set and return some interesting video
|
14832
|
+
* properties. A sequence parameter set is the H264 metadata that
|
14833
|
+
* describes the properties of upcoming video frames.
|
14834
|
+
* @returns an object with configuration parsed from the
|
14835
|
+
* sequence parameter set, including the dimensions of the
|
14836
|
+
* associated video frames.
|
14837
|
+
*/;
|
14838
|
+
_proto.readSPS = function readSPS(sps) {
|
14839
|
+
var eg = new ExpGolomb(sps);
|
14840
|
+
var frameCropLeftOffset = 0;
|
14841
|
+
var frameCropRightOffset = 0;
|
14842
|
+
var frameCropTopOffset = 0;
|
14843
|
+
var frameCropBottomOffset = 0;
|
14844
|
+
var numRefFramesInPicOrderCntCycle;
|
14845
|
+
var scalingListCount;
|
14846
|
+
var i;
|
14847
|
+
var readUByte = eg.readUByte.bind(eg);
|
14848
|
+
var readBits = eg.readBits.bind(eg);
|
14849
|
+
var readUEG = eg.readUEG.bind(eg);
|
14850
|
+
var readBoolean = eg.readBoolean.bind(eg);
|
14851
|
+
var skipBits = eg.skipBits.bind(eg);
|
14852
|
+
var skipEG = eg.skipEG.bind(eg);
|
14853
|
+
var skipUEG = eg.skipUEG.bind(eg);
|
14854
|
+
var skipScalingList = this.skipScalingList.bind(this);
|
14855
|
+
readUByte();
|
14856
|
+
var profileIdc = readUByte(); // profile_idc
|
14857
|
+
readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
|
14858
|
+
skipBits(3); // reserved_zero_3bits u(3),
|
14859
|
+
readUByte(); // level_idc u(8)
|
14860
|
+
skipUEG(); // seq_parameter_set_id
|
14861
|
+
// some profiles have more optional data we don't need
|
14862
|
+
if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
|
14863
|
+
var chromaFormatIdc = readUEG();
|
14864
|
+
if (chromaFormatIdc === 3) {
|
14865
|
+
skipBits(1);
|
14866
|
+
} // separate_colour_plane_flag
|
14867
|
+
|
14868
|
+
skipUEG(); // bit_depth_luma_minus8
|
14869
|
+
skipUEG(); // bit_depth_chroma_minus8
|
14870
|
+
skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
14871
|
+
if (readBoolean()) {
|
14872
|
+
// seq_scaling_matrix_present_flag
|
14873
|
+
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
|
14874
|
+
for (i = 0; i < scalingListCount; i++) {
|
14875
|
+
if (readBoolean()) {
|
14876
|
+
// seq_scaling_list_present_flag[ i ]
|
14877
|
+
if (i < 6) {
|
14878
|
+
skipScalingList(16, eg);
|
14879
|
+
} else {
|
14880
|
+
skipScalingList(64, eg);
|
14881
|
+
}
|
14882
|
+
}
|
14854
14883
|
}
|
14855
|
-
} else {
|
14856
|
-
state = 0;
|
14857
14884
|
}
|
14858
14885
|
}
|
14859
|
-
|
14860
|
-
|
14861
|
-
|
14862
|
-
|
14863
|
-
|
14864
|
-
|
14865
|
-
|
14866
|
-
|
14886
|
+
skipUEG(); // log2_max_frame_num_minus4
|
14887
|
+
var picOrderCntType = readUEG();
|
14888
|
+
if (picOrderCntType === 0) {
|
14889
|
+
readUEG(); // log2_max_pic_order_cnt_lsb_minus4
|
14890
|
+
} else if (picOrderCntType === 1) {
|
14891
|
+
skipBits(1); // delta_pic_order_always_zero_flag
|
14892
|
+
skipEG(); // offset_for_non_ref_pic
|
14893
|
+
skipEG(); // offset_for_top_to_bottom_field
|
14894
|
+
numRefFramesInPicOrderCntCycle = readUEG();
|
14895
|
+
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
14896
|
+
skipEG();
|
14897
|
+
} // offset_for_ref_frame[ i ]
|
14867
14898
|
}
|
14868
|
-
//
|
14869
|
-
|
14870
|
-
|
14871
|
-
|
14872
|
-
|
14873
|
-
|
14899
|
+
skipUEG(); // max_num_ref_frames
|
14900
|
+
skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
14901
|
+
var picWidthInMbsMinus1 = readUEG();
|
14902
|
+
var picHeightInMapUnitsMinus1 = readUEG();
|
14903
|
+
var frameMbsOnlyFlag = readBits(1);
|
14904
|
+
if (frameMbsOnlyFlag === 0) {
|
14905
|
+
skipBits(1);
|
14906
|
+
} // mb_adaptive_frame_field_flag
|
14907
|
+
|
14908
|
+
skipBits(1); // direct_8x8_inference_flag
|
14909
|
+
if (readBoolean()) {
|
14910
|
+
// frame_cropping_flag
|
14911
|
+
frameCropLeftOffset = readUEG();
|
14912
|
+
frameCropRightOffset = readUEG();
|
14913
|
+
frameCropTopOffset = readUEG();
|
14914
|
+
frameCropBottomOffset = readUEG();
|
14915
|
+
}
|
14916
|
+
var pixelRatio = [1, 1];
|
14917
|
+
if (readBoolean()) {
|
14918
|
+
// vui_parameters_present_flag
|
14919
|
+
if (readBoolean()) {
|
14920
|
+
// aspect_ratio_info_present_flag
|
14921
|
+
var aspectRatioIdc = readUByte();
|
14922
|
+
switch (aspectRatioIdc) {
|
14923
|
+
case 1:
|
14924
|
+
pixelRatio = [1, 1];
|
14925
|
+
break;
|
14926
|
+
case 2:
|
14927
|
+
pixelRatio = [12, 11];
|
14928
|
+
break;
|
14929
|
+
case 3:
|
14930
|
+
pixelRatio = [10, 11];
|
14931
|
+
break;
|
14932
|
+
case 4:
|
14933
|
+
pixelRatio = [16, 11];
|
14934
|
+
break;
|
14935
|
+
case 5:
|
14936
|
+
pixelRatio = [40, 33];
|
14937
|
+
break;
|
14938
|
+
case 6:
|
14939
|
+
pixelRatio = [24, 11];
|
14940
|
+
break;
|
14941
|
+
case 7:
|
14942
|
+
pixelRatio = [20, 11];
|
14943
|
+
break;
|
14944
|
+
case 8:
|
14945
|
+
pixelRatio = [32, 11];
|
14946
|
+
break;
|
14947
|
+
case 9:
|
14948
|
+
pixelRatio = [80, 33];
|
14949
|
+
break;
|
14950
|
+
case 10:
|
14951
|
+
pixelRatio = [18, 11];
|
14952
|
+
break;
|
14953
|
+
case 11:
|
14954
|
+
pixelRatio = [15, 11];
|
14955
|
+
break;
|
14956
|
+
case 12:
|
14957
|
+
pixelRatio = [64, 33];
|
14958
|
+
break;
|
14959
|
+
case 13:
|
14960
|
+
pixelRatio = [160, 99];
|
14961
|
+
break;
|
14962
|
+
case 14:
|
14963
|
+
pixelRatio = [4, 3];
|
14964
|
+
break;
|
14965
|
+
case 15:
|
14966
|
+
pixelRatio = [3, 2];
|
14967
|
+
break;
|
14968
|
+
case 16:
|
14969
|
+
pixelRatio = [2, 1];
|
14970
|
+
break;
|
14971
|
+
case 255:
|
14972
|
+
{
|
14973
|
+
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
|
14974
|
+
break;
|
14975
|
+
}
|
14976
|
+
}
|
14874
14977
|
}
|
14875
14978
|
}
|
14876
|
-
|
14877
|
-
|
14979
|
+
return {
|
14980
|
+
width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
|
14981
|
+
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
|
14982
|
+
pixelRatio: pixelRatio
|
14983
|
+
};
|
14878
14984
|
};
|
14879
14985
|
return AvcVideoParser;
|
14880
14986
|
}(BaseVideoParser);
|
@@ -14894,7 +15000,7 @@
|
|
14894
15000
|
}
|
14895
15001
|
var _proto = SampleAesDecrypter.prototype;
|
14896
15002
|
_proto.decryptBuffer = function decryptBuffer(encryptedData) {
|
14897
|
-
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
|
15003
|
+
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
|
14898
15004
|
}
|
14899
15005
|
|
14900
15006
|
// AAC - encrypt all full 16 bytes blocks starting from offset 16
|
@@ -15013,7 +15119,7 @@
|
|
15013
15119
|
this.observer = observer;
|
15014
15120
|
this.config = config;
|
15015
15121
|
this.typeSupported = typeSupported;
|
15016
|
-
this.videoParser =
|
15122
|
+
this.videoParser = null;
|
15017
15123
|
}
|
15018
15124
|
TSDemuxer.probe = function probe(data) {
|
15019
15125
|
var syncOffset = TSDemuxer.syncOffset(data);
|
@@ -15183,7 +15289,16 @@
|
|
15183
15289
|
case videoPid:
|
15184
15290
|
if (stt) {
|
15185
15291
|
if (videoData && (pes = parsePES(videoData))) {
|
15186
|
-
this.videoParser
|
15292
|
+
if (this.videoParser === null) {
|
15293
|
+
switch (videoTrack.segmentCodec) {
|
15294
|
+
case 'avc':
|
15295
|
+
this.videoParser = new AvcVideoParser();
|
15296
|
+
break;
|
15297
|
+
}
|
15298
|
+
}
|
15299
|
+
if (this.videoParser !== null) {
|
15300
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
|
15301
|
+
}
|
15187
15302
|
}
|
15188
15303
|
videoData = {
|
15189
15304
|
data: [],
|
@@ -15341,8 +15456,17 @@
|
|
15341
15456
|
// try to parse last PES packets
|
15342
15457
|
var pes;
|
15343
15458
|
if (videoData && (pes = parsePES(videoData))) {
|
15344
|
-
this.videoParser
|
15345
|
-
|
15459
|
+
if (this.videoParser === null) {
|
15460
|
+
switch (videoTrack.segmentCodec) {
|
15461
|
+
case 'avc':
|
15462
|
+
this.videoParser = new AvcVideoParser();
|
15463
|
+
break;
|
15464
|
+
}
|
15465
|
+
}
|
15466
|
+
if (this.videoParser !== null) {
|
15467
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
|
15468
|
+
videoTrack.pesData = null;
|
15469
|
+
}
|
15346
15470
|
} else {
|
15347
15471
|
// either avcData null or PES truncated, keep it for next frag parsing
|
15348
15472
|
videoTrack.pesData = videoData;
|
@@ -15644,7 +15768,10 @@
|
|
15644
15768
|
logger.warn('Unsupported EC-3 in M2TS found');
|
15645
15769
|
break;
|
15646
15770
|
case 0x24:
|
15647
|
-
|
15771
|
+
// ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
|
15772
|
+
{
|
15773
|
+
logger.warn('Unsupported HEVC in M2TS found');
|
15774
|
+
}
|
15648
15775
|
break;
|
15649
15776
|
}
|
15650
15777
|
// move to the next table entry
|
@@ -15872,6 +15999,8 @@
|
|
15872
15999
|
avc1: [],
|
15873
16000
|
// codingname
|
15874
16001
|
avcC: [],
|
16002
|
+
hvc1: [],
|
16003
|
+
hvcC: [],
|
15875
16004
|
btrt: [],
|
15876
16005
|
dinf: [],
|
15877
16006
|
dref: [],
|
@@ -16299,8 +16428,10 @@
|
|
16299
16428
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
|
16300
16429
|
}
|
16301
16430
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
|
16302
|
-
} else {
|
16431
|
+
} else if (track.segmentCodec === 'avc') {
|
16303
16432
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
|
16433
|
+
} else {
|
16434
|
+
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
|
16304
16435
|
}
|
16305
16436
|
};
|
16306
16437
|
MP4.tkhd = function tkhd(track) {
|
@@ -16438,6 +16569,84 @@
|
|
16438
16569
|
var result = appendUint8Array(MP4.FTYP, movie);
|
16439
16570
|
return result;
|
16440
16571
|
};
|
16572
|
+
MP4.hvc1 = function hvc1(track) {
|
16573
|
+
var ps = track.params;
|
16574
|
+
var units = [track.vps, track.sps, track.pps];
|
16575
|
+
var NALuLengthSize = 4;
|
16576
|
+
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]);
|
16577
|
+
|
16578
|
+
// compute hvcC size in bytes
|
16579
|
+
var length = config.length;
|
16580
|
+
for (var i = 0; i < units.length; i += 1) {
|
16581
|
+
length += 3;
|
16582
|
+
for (var j = 0; j < units[i].length; j += 1) {
|
16583
|
+
length += 2 + units[i][j].length;
|
16584
|
+
}
|
16585
|
+
}
|
16586
|
+
var hvcC = new Uint8Array(length);
|
16587
|
+
hvcC.set(config, 0);
|
16588
|
+
length = config.length;
|
16589
|
+
// append parameter set units: one vps, one or more sps and pps
|
16590
|
+
var iMax = units.length - 1;
|
16591
|
+
for (var _i = 0; _i < units.length; _i += 1) {
|
16592
|
+
hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
|
16593
|
+
length += 3;
|
16594
|
+
for (var _j = 0; _j < units[_i].length; _j += 1) {
|
16595
|
+
hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
|
16596
|
+
length += 2;
|
16597
|
+
hvcC.set(units[_i][_j], length);
|
16598
|
+
length += units[_i][_j].length;
|
16599
|
+
}
|
16600
|
+
}
|
16601
|
+
var hvcc = MP4.box(MP4.types.hvcC, hvcC);
|
16602
|
+
var width = track.width;
|
16603
|
+
var height = track.height;
|
16604
|
+
var hSpacing = track.pixelRatio[0];
|
16605
|
+
var vSpacing = track.pixelRatio[1];
|
16606
|
+
return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
|
16607
|
+
// reserved
|
16608
|
+
0x00, 0x00, 0x00,
|
16609
|
+
// reserved
|
16610
|
+
0x00, 0x01,
|
16611
|
+
// data_reference_index
|
16612
|
+
0x00, 0x00,
|
16613
|
+
// pre_defined
|
16614
|
+
0x00, 0x00,
|
16615
|
+
// reserved
|
16616
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
16617
|
+
// pre_defined
|
16618
|
+
width >> 8 & 0xff, width & 0xff,
|
16619
|
+
// width
|
16620
|
+
height >> 8 & 0xff, height & 0xff,
|
16621
|
+
// height
|
16622
|
+
0x00, 0x48, 0x00, 0x00,
|
16623
|
+
// horizresolution
|
16624
|
+
0x00, 0x48, 0x00, 0x00,
|
16625
|
+
// vertresolution
|
16626
|
+
0x00, 0x00, 0x00, 0x00,
|
16627
|
+
// reserved
|
16628
|
+
0x00, 0x01,
|
16629
|
+
// frame_count
|
16630
|
+
0x12, 0x64, 0x61, 0x69, 0x6c,
|
16631
|
+
// dailymotion/hls.js
|
16632
|
+
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,
|
16633
|
+
// compressorname
|
16634
|
+
0x00, 0x18,
|
16635
|
+
// depth = 24
|
16636
|
+
0x11, 0x11]),
|
16637
|
+
// pre_defined = -1
|
16638
|
+
hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
|
16639
|
+
// bufferSizeDB
|
16640
|
+
0x00, 0x2d, 0xc6, 0xc0,
|
16641
|
+
// maxBitrate
|
16642
|
+
0x00, 0x2d, 0xc6, 0xc0])),
|
16643
|
+
// avgBitrate
|
16644
|
+
MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
|
16645
|
+
// hSpacing
|
16646
|
+
hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
|
16647
|
+
// vSpacing
|
16648
|
+
vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
|
16649
|
+
};
|
16441
16650
|
return MP4;
|
16442
16651
|
}();
|
16443
16652
|
MP4.types = void 0;
|
@@ -16824,9 +17033,9 @@
|
|
16824
17033
|
var foundOverlap = delta < -1;
|
16825
17034
|
if (foundHole || foundOverlap) {
|
16826
17035
|
if (foundHole) {
|
16827
|
-
logger.warn("
|
17036
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
|
16828
17037
|
} else {
|
16829
|
-
logger.warn("
|
17038
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
|
16830
17039
|
}
|
16831
17040
|
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
|
16832
17041
|
firstDTS = nextAvcDts;
|
@@ -16835,12 +17044,24 @@
|
|
16835
17044
|
inputSamples[0].dts = firstDTS;
|
16836
17045
|
inputSamples[0].pts = firstPTS;
|
16837
17046
|
} else {
|
17047
|
+
var isPTSOrderRetained = true;
|
16838
17048
|
for (var _i = 0; _i < inputSamples.length; _i++) {
|
16839
|
-
if (inputSamples[_i].dts > firstPTS) {
|
17049
|
+
if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
|
16840
17050
|
break;
|
16841
17051
|
}
|
17052
|
+
var prevPTS = inputSamples[_i].pts;
|
16842
17053
|
inputSamples[_i].dts -= delta;
|
16843
17054
|
inputSamples[_i].pts -= delta;
|
17055
|
+
|
17056
|
+
// check to see if this sample's PTS order has changed
|
17057
|
+
// relative to the next one
|
17058
|
+
if (_i < inputSamples.length - 1) {
|
17059
|
+
var nextSamplePTS = inputSamples[_i + 1].pts;
|
17060
|
+
var currentSamplePTS = inputSamples[_i].pts;
|
17061
|
+
var currentOrder = nextSamplePTS <= currentSamplePTS;
|
17062
|
+
var prevOrder = nextSamplePTS <= prevPTS;
|
17063
|
+
isPTSOrderRetained = currentOrder == prevOrder;
|
17064
|
+
}
|
16844
17065
|
}
|
16845
17066
|
}
|
16846
17067
|
logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
|
@@ -16988,7 +17209,7 @@
|
|
16988
17209
|
}
|
16989
17210
|
}
|
16990
17211
|
}
|
16991
|
-
// next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
17212
|
+
// next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
16992
17213
|
mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
|
16993
17214
|
this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
|
16994
17215
|
this.videoSampleDuration = mp4SampleDuration;
|
@@ -17123,7 +17344,7 @@
|
|
17123
17344
|
logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
|
17124
17345
|
for (var j = 0; j < missing; j++) {
|
17125
17346
|
var newStamp = Math.max(nextPts, 0);
|
17126
|
-
var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17347
|
+
var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17127
17348
|
if (!fillFrame) {
|
17128
17349
|
logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
17129
17350
|
fillFrame = sample.unit.subarray();
|
@@ -17251,7 +17472,7 @@
|
|
17251
17472
|
// samples count of this segment's duration
|
17252
17473
|
var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
|
17253
17474
|
// silent frame
|
17254
|
-
var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17475
|
+
var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17255
17476
|
logger.warn('[mp4-remuxer]: remux empty Audio');
|
17256
17477
|
// Can't remux if we can't generate a silent frame...
|
17257
17478
|
if (!silentFrame) {
|
@@ -17638,13 +17859,15 @@
|
|
17638
17859
|
duration = transmuxConfig.duration,
|
17639
17860
|
initSegmentData = transmuxConfig.initSegmentData;
|
17640
17861
|
var keyData = getEncryptionType(uintData, decryptdata);
|
17641
|
-
if (keyData && keyData.method
|
17862
|
+
if (keyData && isFullSegmentEncryption(keyData.method)) {
|
17642
17863
|
var decrypter = this.getDecrypter();
|
17864
|
+
var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
17865
|
+
|
17643
17866
|
// Software decryption is synchronous; webCrypto is not
|
17644
17867
|
if (decrypter.isSync()) {
|
17645
17868
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
17646
17869
|
// data is handled in the flush() call
|
17647
|
-
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
|
17870
|
+
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
|
17648
17871
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
17649
17872
|
var loadingParts = chunkMeta.part > -1;
|
17650
17873
|
if (loadingParts) {
|
@@ -17656,7 +17879,7 @@
|
|
17656
17879
|
}
|
17657
17880
|
uintData = new Uint8Array(decryptedData);
|
17658
17881
|
} else {
|
17659
|
-
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
|
17882
|
+
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
|
17660
17883
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
17661
17884
|
// the decrypted data has been transmuxed
|
17662
17885
|
var result = _this.push(decryptedData, null, chunkMeta);
|
@@ -18277,7 +18500,7 @@
|
|
18277
18500
|
observer.on(Events.ERROR, forwardMessage);
|
18278
18501
|
|
18279
18502
|
// forward logger events to main thread
|
18280
|
-
var forwardWorkerLogs = function forwardWorkerLogs() {
|
18503
|
+
var forwardWorkerLogs = function forwardWorkerLogs(logger) {
|
18281
18504
|
var _loop = function _loop(logFn) {
|
18282
18505
|
var func = function func(message) {
|
18283
18506
|
forwardMessage('workerLog', {
|
@@ -18298,8 +18521,8 @@
|
|
18298
18521
|
{
|
18299
18522
|
var config = JSON.parse(data.config);
|
18300
18523
|
self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
|
18301
|
-
enableLogs(config.debug, data.id);
|
18302
|
-
forwardWorkerLogs();
|
18524
|
+
var logger = enableLogs(config.debug, data.id);
|
18525
|
+
forwardWorkerLogs(logger);
|
18303
18526
|
forwardMessage('init', null);
|
18304
18527
|
break;
|
18305
18528
|
}
|
@@ -18473,16 +18696,7 @@
|
|
18473
18696
|
this.observer = new EventEmitter();
|
18474
18697
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
18475
18698
|
this.observer.on(Events.ERROR, forwardMessage);
|
18476
|
-
var
|
18477
|
-
isTypeSupported: function isTypeSupported() {
|
18478
|
-
return false;
|
18479
|
-
}
|
18480
|
-
};
|
18481
|
-
var m2tsTypeSupported = {
|
18482
|
-
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
18483
|
-
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
18484
|
-
ac3: false
|
18485
|
-
};
|
18699
|
+
var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
|
18486
18700
|
|
18487
18701
|
// navigator.vendor is not always available in Web Worker
|
18488
18702
|
// refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
|
@@ -18739,21 +18953,26 @@
|
|
18739
18953
|
var MAX_START_GAP_JUMP = 2.0;
|
18740
18954
|
var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
18741
18955
|
var SKIP_BUFFER_RANGE_START = 0.05;
|
18742
|
-
var GapController = /*#__PURE__*/function () {
|
18956
|
+
var GapController = /*#__PURE__*/function (_Logger) {
|
18957
|
+
_inheritsLoose(GapController, _Logger);
|
18743
18958
|
function GapController(config, media, fragmentTracker, hls) {
|
18744
|
-
|
18745
|
-
this.
|
18746
|
-
|
18747
|
-
|
18748
|
-
|
18749
|
-
|
18750
|
-
|
18751
|
-
|
18752
|
-
|
18753
|
-
|
18754
|
-
|
18755
|
-
|
18756
|
-
|
18959
|
+
var _this;
|
18960
|
+
_this = _Logger.call(this, 'gap-controller', hls.logger) || this;
|
18961
|
+
_this.config = void 0;
|
18962
|
+
_this.media = null;
|
18963
|
+
_this.fragmentTracker = void 0;
|
18964
|
+
_this.hls = void 0;
|
18965
|
+
_this.nudgeRetry = 0;
|
18966
|
+
_this.stallReported = false;
|
18967
|
+
_this.stalled = null;
|
18968
|
+
_this.moved = false;
|
18969
|
+
_this.seeking = false;
|
18970
|
+
_this.ended = 0;
|
18971
|
+
_this.config = config;
|
18972
|
+
_this.media = media;
|
18973
|
+
_this.fragmentTracker = fragmentTracker;
|
18974
|
+
_this.hls = hls;
|
18975
|
+
return _this;
|
18757
18976
|
}
|
18758
18977
|
var _proto = GapController.prototype;
|
18759
18978
|
_proto.destroy = function destroy() {
|
@@ -18768,7 +18987,7 @@
|
|
18768
18987
|
*
|
18769
18988
|
* @param lastCurrentTime - Previously read playhead position
|
18770
18989
|
*/;
|
18771
|
-
_proto.poll = function poll(lastCurrentTime, activeFrag) {
|
18990
|
+
_proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
|
18772
18991
|
var config = this.config,
|
18773
18992
|
media = this.media,
|
18774
18993
|
stalled = this.stalled;
|
@@ -18783,6 +19002,7 @@
|
|
18783
19002
|
|
18784
19003
|
// The playhead is moving, no-op
|
18785
19004
|
if (currentTime !== lastCurrentTime) {
|
19005
|
+
this.ended = 0;
|
18786
19006
|
this.moved = true;
|
18787
19007
|
if (!seeking) {
|
18788
19008
|
this.nudgeRetry = 0;
|
@@ -18791,7 +19011,7 @@
|
|
18791
19011
|
// The playhead is now moving, but was previously stalled
|
18792
19012
|
if (this.stallReported) {
|
18793
19013
|
var _stalledDuration = self.performance.now() - stalled;
|
18794
|
-
|
19014
|
+
this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
|
18795
19015
|
this.stallReported = false;
|
18796
19016
|
}
|
18797
19017
|
this.stalled = null;
|
@@ -18827,7 +19047,6 @@
|
|
18827
19047
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
18828
19048
|
// The addition poll gives the browser a chance to jump the gap for us
|
18829
19049
|
if (!this.moved && this.stalled !== null) {
|
18830
|
-
var _level$details;
|
18831
19050
|
// There is no playable buffer (seeked, waiting for buffer)
|
18832
19051
|
var isBuffered = bufferInfo.len > 0;
|
18833
19052
|
if (!isBuffered && !nextStart) {
|
@@ -18839,9 +19058,8 @@
|
|
18839
19058
|
// When joining a live stream with audio tracks, account for live playlist window sliding by allowing
|
18840
19059
|
// a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
|
18841
19060
|
// that begins over 1 target duration after the video start position.
|
18842
|
-
var
|
18843
|
-
var
|
18844
|
-
var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
|
19061
|
+
var isLive = !!(levelDetails != null && levelDetails.live);
|
19062
|
+
var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
|
18845
19063
|
var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
|
18846
19064
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
18847
19065
|
if (!media.paused) {
|
@@ -18859,6 +19077,17 @@
|
|
18859
19077
|
}
|
18860
19078
|
var stalledDuration = tnow - stalled;
|
18861
19079
|
if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
|
19080
|
+
// Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
|
19081
|
+
if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
|
19082
|
+
if (stalledDuration < 1000 || this.ended) {
|
19083
|
+
return;
|
19084
|
+
}
|
19085
|
+
this.ended = currentTime;
|
19086
|
+
this.hls.trigger(Events.MEDIA_ENDED, {
|
19087
|
+
stalled: true
|
19088
|
+
});
|
19089
|
+
return;
|
19090
|
+
}
|
18862
19091
|
// Report stalling after trying to fix
|
18863
19092
|
this._reportStall(bufferInfo);
|
18864
19093
|
if (!this.media) {
|
@@ -18900,7 +19129,7 @@
|
|
18900
19129
|
// needs to cross some sort of threshold covering all source-buffers content
|
18901
19130
|
// to start playing properly.
|
18902
19131
|
if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
18903
|
-
|
19132
|
+
this.warn('Trying to nudge playhead over buffer-hole');
|
18904
19133
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
18905
19134
|
// We only try to jump the hole if it's under the configured size
|
18906
19135
|
// Reset stalled so to rearm watchdog timer
|
@@ -18922,7 +19151,7 @@
|
|
18922
19151
|
// Report stalled error once
|
18923
19152
|
this.stallReported = true;
|
18924
19153
|
var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
|
18925
|
-
|
19154
|
+
this.warn(error.message);
|
18926
19155
|
hls.trigger(Events.ERROR, {
|
18927
19156
|
type: ErrorTypes.MEDIA_ERROR,
|
18928
19157
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -18986,7 +19215,7 @@
|
|
18986
19215
|
}
|
18987
19216
|
}
|
18988
19217
|
var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
18989
|
-
|
19218
|
+
this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
|
18990
19219
|
this.moved = true;
|
18991
19220
|
this.stalled = null;
|
18992
19221
|
media.currentTime = targetTime;
|
@@ -19025,7 +19254,7 @@
|
|
19025
19254
|
var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
|
19026
19255
|
// playback stalled in buffered area ... let's nudge currentTime to try to overcome this
|
19027
19256
|
var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
|
19028
|
-
|
19257
|
+
this.warn(error.message);
|
19029
19258
|
media.currentTime = targetTime;
|
19030
19259
|
hls.trigger(Events.ERROR, {
|
19031
19260
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -19035,7 +19264,7 @@
|
|
19035
19264
|
});
|
19036
19265
|
} else {
|
19037
19266
|
var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
|
19038
|
-
|
19267
|
+
this.error(_error.message);
|
19039
19268
|
hls.trigger(Events.ERROR, {
|
19040
19269
|
type: ErrorTypes.MEDIA_ERROR,
|
19041
19270
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -19045,14 +19274,14 @@
|
|
19045
19274
|
}
|
19046
19275
|
};
|
19047
19276
|
return GapController;
|
19048
|
-
}();
|
19277
|
+
}(Logger);
|
19049
19278
|
|
19050
19279
|
var TICK_INTERVAL = 100; // how often to tick in ms
|
19051
19280
|
var StreamController = /*#__PURE__*/function (_BaseStreamController) {
|
19052
19281
|
_inheritsLoose(StreamController, _BaseStreamController);
|
19053
19282
|
function StreamController(hls, fragmentTracker, keyLoader) {
|
19054
19283
|
var _this;
|
19055
|
-
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '
|
19284
|
+
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
|
19056
19285
|
_this.audioCodecSwap = false;
|
19057
19286
|
_this.gapController = null;
|
19058
19287
|
_this.level = -1;
|
@@ -19060,27 +19289,43 @@
|
|
19060
19289
|
_this.altAudio = false;
|
19061
19290
|
_this.audioOnly = false;
|
19062
19291
|
_this.fragPlaying = null;
|
19063
|
-
_this.onvplaying = null;
|
19064
|
-
_this.onvseeked = null;
|
19065
19292
|
_this.fragLastKbps = 0;
|
19066
19293
|
_this.couldBacktrack = false;
|
19067
19294
|
_this.backtrackFragment = null;
|
19068
19295
|
_this.audioCodecSwitch = false;
|
19069
19296
|
_this.videoBuffer = null;
|
19070
|
-
_this.
|
19297
|
+
_this.onMediaPlaying = function () {
|
19298
|
+
// tick to speed up FRAG_CHANGED triggering
|
19299
|
+
_this.tick();
|
19300
|
+
};
|
19301
|
+
_this.onMediaSeeked = function () {
|
19302
|
+
var media = _this.media;
|
19303
|
+
var currentTime = media ? media.currentTime : null;
|
19304
|
+
if (isFiniteNumber(currentTime)) {
|
19305
|
+
_this.log("Media seeked to " + currentTime.toFixed(3));
|
19306
|
+
}
|
19307
|
+
|
19308
|
+
// If seeked was issued before buffer was appended do not tick immediately
|
19309
|
+
var bufferInfo = _this.getMainFwdBufferInfo();
|
19310
|
+
if (bufferInfo === null || bufferInfo.len === 0) {
|
19311
|
+
_this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19312
|
+
return;
|
19313
|
+
}
|
19314
|
+
|
19315
|
+
// tick to speed up FRAG_CHANGED triggering
|
19316
|
+
_this.tick();
|
19317
|
+
};
|
19318
|
+
_this.registerListeners();
|
19071
19319
|
return _this;
|
19072
19320
|
}
|
19073
19321
|
var _proto = StreamController.prototype;
|
19074
|
-
_proto.
|
19322
|
+
_proto.registerListeners = function registerListeners() {
|
19323
|
+
_BaseStreamController.prototype.registerListeners.call(this);
|
19075
19324
|
var hls = this.hls;
|
19076
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19077
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19078
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19079
19325
|
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19080
19326
|
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
|
19081
19327
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19082
19328
|
hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19083
|
-
hls.on(Events.ERROR, this.onError, this);
|
19084
19329
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19085
19330
|
hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19086
19331
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19088,15 +19333,12 @@
|
|
19088
19333
|
hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
|
19089
19334
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19090
19335
|
};
|
19091
|
-
_proto.
|
19336
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
19337
|
+
_BaseStreamController.prototype.unregisterListeners.call(this);
|
19092
19338
|
var hls = this.hls;
|
19093
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19094
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19095
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19096
19339
|
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19097
19340
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19098
19341
|
hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19099
|
-
hls.off(Events.ERROR, this.onError, this);
|
19100
19342
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19101
19343
|
hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19102
19344
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19105,7 +19347,9 @@
|
|
19105
19347
|
hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19106
19348
|
};
|
19107
19349
|
_proto.onHandlerDestroying = function onHandlerDestroying() {
|
19108
|
-
|
19350
|
+
// @ts-ignore
|
19351
|
+
this.onMediaPlaying = this.onMediaSeeked = null;
|
19352
|
+
this.unregisterListeners();
|
19109
19353
|
_BaseStreamController.prototype.onHandlerDestroying.call(this);
|
19110
19354
|
};
|
19111
19355
|
_proto.startLoad = function startLoad(startPosition) {
|
@@ -19215,7 +19459,7 @@
|
|
19215
19459
|
if (this.altAudio && this.audioOnly) {
|
19216
19460
|
return;
|
19217
19461
|
}
|
19218
|
-
if (!(levels != null && levels[level])) {
|
19462
|
+
if (!this.buffering || !(levels != null && levels[level])) {
|
19219
19463
|
return;
|
19220
19464
|
}
|
19221
19465
|
var levelInfo = levels[level];
|
@@ -19421,18 +19665,15 @@
|
|
19421
19665
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
19422
19666
|
_BaseStreamController.prototype.onMediaAttached.call(this, event, data);
|
19423
19667
|
var media = data.media;
|
19424
|
-
|
19425
|
-
|
19426
|
-
media.addEventListener('playing', this.onvplaying);
|
19427
|
-
media.addEventListener('seeked', this.onvseeked);
|
19668
|
+
media.addEventListener('playing', this.onMediaPlaying);
|
19669
|
+
media.addEventListener('seeked', this.onMediaSeeked);
|
19428
19670
|
this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
|
19429
19671
|
};
|
19430
19672
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
19431
19673
|
var media = this.media;
|
19432
|
-
if (media
|
19433
|
-
media.removeEventListener('playing', this.
|
19434
|
-
media.removeEventListener('seeked', this.
|
19435
|
-
this.onvplaying = this.onvseeked = null;
|
19674
|
+
if (media) {
|
19675
|
+
media.removeEventListener('playing', this.onMediaPlaying);
|
19676
|
+
media.removeEventListener('seeked', this.onMediaSeeked);
|
19436
19677
|
this.videoBuffer = null;
|
19437
19678
|
}
|
19438
19679
|
this.fragPlaying = null;
|
@@ -19442,27 +19683,6 @@
|
|
19442
19683
|
}
|
19443
19684
|
_BaseStreamController.prototype.onMediaDetaching.call(this);
|
19444
19685
|
};
|
19445
|
-
_proto.onMediaPlaying = function onMediaPlaying() {
|
19446
|
-
// tick to speed up FRAG_CHANGED triggering
|
19447
|
-
this.tick();
|
19448
|
-
};
|
19449
|
-
_proto.onMediaSeeked = function onMediaSeeked() {
|
19450
|
-
var media = this.media;
|
19451
|
-
var currentTime = media ? media.currentTime : null;
|
19452
|
-
if (isFiniteNumber(currentTime)) {
|
19453
|
-
this.log("Media seeked to " + currentTime.toFixed(3));
|
19454
|
-
}
|
19455
|
-
|
19456
|
-
// If seeked was issued before buffer was appended do not tick immediately
|
19457
|
-
var bufferInfo = this.getMainFwdBufferInfo();
|
19458
|
-
if (bufferInfo === null || bufferInfo.len === 0) {
|
19459
|
-
this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19460
|
-
return;
|
19461
|
-
}
|
19462
|
-
|
19463
|
-
// tick to speed up FRAG_CHANGED triggering
|
19464
|
-
this.tick();
|
19465
|
-
};
|
19466
19686
|
_proto.onManifestLoading = function onManifestLoading() {
|
19467
19687
|
// reset buffer on manifest loading
|
19468
19688
|
this.log('Trigger BUFFER_RESET');
|
@@ -19743,8 +19963,10 @@
|
|
19743
19963
|
}
|
19744
19964
|
if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
|
19745
19965
|
// Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
|
19746
|
-
var
|
19747
|
-
|
19966
|
+
var state = this.state;
|
19967
|
+
var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
|
19968
|
+
var levelDetails = this.getLevelDetails();
|
19969
|
+
gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
|
19748
19970
|
}
|
19749
19971
|
this.lastCurrentTime = media.currentTime;
|
19750
19972
|
};
|
@@ -20209,9 +20431,12 @@
|
|
20209
20431
|
* The configuration object provided on player instantiation.
|
20210
20432
|
*/
|
20211
20433
|
this.userConfig = void 0;
|
20434
|
+
/**
|
20435
|
+
* The logger functions used by this player instance, configured on player instantiation.
|
20436
|
+
*/
|
20437
|
+
this.logger = void 0;
|
20212
20438
|
this.coreComponents = void 0;
|
20213
20439
|
this.networkControllers = void 0;
|
20214
|
-
this.started = false;
|
20215
20440
|
this._emitter = new EventEmitter();
|
20216
20441
|
this._autoLevelCapping = -1;
|
20217
20442
|
this._maxHdcpLevel = null;
|
@@ -20228,11 +20453,11 @@
|
|
20228
20453
|
this._media = null;
|
20229
20454
|
this.url = null;
|
20230
20455
|
this.triggeringException = void 0;
|
20231
|
-
enableLogs(userConfig.debug || false, 'Hls instance');
|
20232
|
-
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
|
20456
|
+
var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
|
20457
|
+
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
|
20233
20458
|
this.userConfig = userConfig;
|
20234
20459
|
if (config.progressive) {
|
20235
|
-
enableStreamingMode(config);
|
20460
|
+
enableStreamingMode(config, logger);
|
20236
20461
|
}
|
20237
20462
|
|
20238
20463
|
// core controllers and network loaders
|
@@ -20340,7 +20565,7 @@
|
|
20340
20565
|
try {
|
20341
20566
|
return this.emit(event, event, eventObject);
|
20342
20567
|
} catch (error) {
|
20343
|
-
logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20568
|
+
this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20344
20569
|
// Prevent recursion in error event handlers that throw #5497
|
20345
20570
|
if (!this.triggeringException) {
|
20346
20571
|
this.triggeringException = true;
|
@@ -20366,7 +20591,7 @@
|
|
20366
20591
|
* Dispose of the instance
|
20367
20592
|
*/;
|
20368
20593
|
_proto.destroy = function destroy() {
|
20369
|
-
logger.log('destroy');
|
20594
|
+
this.logger.log('destroy');
|
20370
20595
|
this.trigger(Events.DESTROYING, undefined);
|
20371
20596
|
this.detachMedia();
|
20372
20597
|
this.removeAllListeners();
|
@@ -20391,7 +20616,7 @@
|
|
20391
20616
|
* Attaches Hls.js to a media element
|
20392
20617
|
*/;
|
20393
20618
|
_proto.attachMedia = function attachMedia(media) {
|
20394
|
-
logger.log('attachMedia');
|
20619
|
+
this.logger.log('attachMedia');
|
20395
20620
|
this._media = media;
|
20396
20621
|
this.trigger(Events.MEDIA_ATTACHING, {
|
20397
20622
|
media: media
|
@@ -20402,7 +20627,7 @@
|
|
20402
20627
|
* Detach Hls.js from the media
|
20403
20628
|
*/;
|
20404
20629
|
_proto.detachMedia = function detachMedia() {
|
20405
|
-
logger.log('detachMedia');
|
20630
|
+
this.logger.log('detachMedia');
|
20406
20631
|
this.trigger(Events.MEDIA_DETACHING, undefined);
|
20407
20632
|
this._media = null;
|
20408
20633
|
}
|
@@ -20419,7 +20644,7 @@
|
|
20419
20644
|
});
|
20420
20645
|
this._autoLevelCapping = -1;
|
20421
20646
|
this._maxHdcpLevel = null;
|
20422
|
-
logger.log("loadSource:" + loadingSource);
|
20647
|
+
this.logger.log("loadSource:" + loadingSource);
|
20423
20648
|
if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
|
20424
20649
|
this.detachMedia();
|
20425
20650
|
this.attachMedia(media);
|
@@ -20441,8 +20666,7 @@
|
|
20441
20666
|
if (startPosition === void 0) {
|
20442
20667
|
startPosition = -1;
|
20443
20668
|
}
|
20444
|
-
logger.log("startLoad(" + startPosition + ")");
|
20445
|
-
this.started = true;
|
20669
|
+
this.logger.log("startLoad(" + startPosition + ")");
|
20446
20670
|
this.networkControllers.forEach(function (controller) {
|
20447
20671
|
controller.startLoad(startPosition);
|
20448
20672
|
});
|
@@ -20452,34 +20676,31 @@
|
|
20452
20676
|
* Stop loading of any stream data.
|
20453
20677
|
*/;
|
20454
20678
|
_proto.stopLoad = function stopLoad() {
|
20455
|
-
logger.log('stopLoad');
|
20456
|
-
this.started = false;
|
20679
|
+
this.logger.log('stopLoad');
|
20457
20680
|
this.networkControllers.forEach(function (controller) {
|
20458
20681
|
controller.stopLoad();
|
20459
20682
|
});
|
20460
20683
|
}
|
20461
20684
|
|
20462
20685
|
/**
|
20463
|
-
* Resumes stream controller segment loading
|
20686
|
+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
|
20464
20687
|
*/;
|
20465
20688
|
_proto.resumeBuffering = function resumeBuffering() {
|
20466
|
-
|
20467
|
-
|
20468
|
-
|
20469
|
-
|
20470
|
-
|
20471
|
-
});
|
20472
|
-
}
|
20689
|
+
this.networkControllers.forEach(function (controller) {
|
20690
|
+
if (controller.resumeBuffering) {
|
20691
|
+
controller.resumeBuffering();
|
20692
|
+
}
|
20693
|
+
});
|
20473
20694
|
}
|
20474
20695
|
|
20475
20696
|
/**
|
20476
|
-
*
|
20697
|
+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
|
20477
20698
|
* This allows for media buffering to be paused without interupting playlist loading.
|
20478
20699
|
*/;
|
20479
20700
|
_proto.pauseBuffering = function pauseBuffering() {
|
20480
20701
|
this.networkControllers.forEach(function (controller) {
|
20481
|
-
if (
|
20482
|
-
controller.
|
20702
|
+
if (controller.pauseBuffering) {
|
20703
|
+
controller.pauseBuffering();
|
20483
20704
|
}
|
20484
20705
|
});
|
20485
20706
|
}
|
@@ -20488,7 +20709,7 @@
|
|
20488
20709
|
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
20489
20710
|
*/;
|
20490
20711
|
_proto.swapAudioCodec = function swapAudioCodec() {
|
20491
|
-
logger.log('swapAudioCodec');
|
20712
|
+
this.logger.log('swapAudioCodec');
|
20492
20713
|
this.streamController.swapAudioCodec();
|
20493
20714
|
}
|
20494
20715
|
|
@@ -20499,7 +20720,7 @@
|
|
20499
20720
|
* Automatic recovery of media-errors by this process is configurable.
|
20500
20721
|
*/;
|
20501
20722
|
_proto.recoverMediaError = function recoverMediaError() {
|
20502
|
-
logger.log('recoverMediaError');
|
20723
|
+
this.logger.log('recoverMediaError');
|
20503
20724
|
var media = this._media;
|
20504
20725
|
this.detachMedia();
|
20505
20726
|
if (media) {
|
@@ -20554,7 +20775,7 @@
|
|
20554
20775
|
* Set quality level index immediately. This will flush the current buffer to replace the quality asap. That means playback will interrupt at least shortly to re-buffer and re-sync eventually. Set to -1 for automatic level selection.
|
20555
20776
|
*/,
|
20556
20777
|
set: function set(newLevel) {
|
20557
|
-
logger.log("set currentLevel:" + newLevel);
|
20778
|
+
this.logger.log("set currentLevel:" + newLevel);
|
20558
20779
|
this.levelController.manualLevel = newLevel;
|
20559
20780
|
this.streamController.immediateLevelSwitch();
|
20560
20781
|
}
|
@@ -20575,7 +20796,7 @@
|
|
20575
20796
|
* @param newLevel - Pass -1 for automatic level selection
|
20576
20797
|
*/,
|
20577
20798
|
set: function set(newLevel) {
|
20578
|
-
logger.log("set nextLevel:" + newLevel);
|
20799
|
+
this.logger.log("set nextLevel:" + newLevel);
|
20579
20800
|
this.levelController.manualLevel = newLevel;
|
20580
20801
|
this.streamController.nextLevelSwitch();
|
20581
20802
|
}
|
@@ -20596,7 +20817,7 @@
|
|
20596
20817
|
* @param newLevel - Pass -1 for automatic level selection
|
20597
20818
|
*/,
|
20598
20819
|
set: function set(newLevel) {
|
20599
|
-
logger.log("set loadLevel:" + newLevel);
|
20820
|
+
this.logger.log("set loadLevel:" + newLevel);
|
20600
20821
|
this.levelController.manualLevel = newLevel;
|
20601
20822
|
}
|
20602
20823
|
|
@@ -20631,7 +20852,7 @@
|
|
20631
20852
|
* Sets "first-level", see getter.
|
20632
20853
|
*/,
|
20633
20854
|
set: function set(newLevel) {
|
20634
|
-
logger.log("set firstLevel:" + newLevel);
|
20855
|
+
this.logger.log("set firstLevel:" + newLevel);
|
20635
20856
|
this.levelController.firstLevel = newLevel;
|
20636
20857
|
}
|
20637
20858
|
|
@@ -20658,7 +20879,7 @@
|
|
20658
20879
|
* (determined from download of first segment)
|
20659
20880
|
*/,
|
20660
20881
|
set: function set(newLevel) {
|
20661
|
-
logger.log("set startLevel:" + newLevel);
|
20882
|
+
this.logger.log("set startLevel:" + newLevel);
|
20662
20883
|
// if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
|
20663
20884
|
if (newLevel !== -1) {
|
20664
20885
|
newLevel = Math.max(newLevel, this.minAutoLevel);
|
@@ -20711,7 +20932,7 @@
|
|
20711
20932
|
*/
|
20712
20933
|
function set(newLevel) {
|
20713
20934
|
if (this._autoLevelCapping !== newLevel) {
|
20714
|
-
logger.log("set autoLevelCapping:" + newLevel);
|
20935
|
+
this.logger.log("set autoLevelCapping:" + newLevel);
|
20715
20936
|
this._autoLevelCapping = newLevel;
|
20716
20937
|
this.levelController.checkMaxAutoUpdated();
|
20717
20938
|
}
|
@@ -21036,7 +21257,7 @@
|
|
21036
21257
|
* Get the video-dev/hls.js package version.
|
21037
21258
|
*/
|
21038
21259
|
function get() {
|
21039
|
-
return "1.5.
|
21260
|
+
return "1.5.5-0.canary.9978";
|
21040
21261
|
}
|
21041
21262
|
}, {
|
21042
21263
|
key: "Events",
|