hls.js 1.5.6 → 1.5.7-0.canary.10015
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 +2077 -1166
- package/dist/hls.js.d.ts +65 -50
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +1149 -858
- 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 +985 -695
- 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 +1758 -862
- 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 +21 -21
- 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 +20 -8
- package/src/controller/base-stream-controller.ts +149 -33
- package/src/controller/buffer-controller.ts +11 -11
- package/src/controller/cap-level-controller.ts +1 -2
- package/src/controller/cmcd-controller.ts +27 -6
- 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 +12 -18
- package/src/controller/stream-controller.ts +24 -31
- 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/loader/playlist-loader.ts +4 -5
- 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 +54 -24
- package/src/utils/mp4-tools.ts +3 -1
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,61 +466,6 @@
|
|
476
466
|
return ErrorDetails;
|
477
467
|
}({});
|
478
468
|
|
479
|
-
var noop = function noop() {};
|
480
|
-
var fakeLogger = {
|
481
|
-
trace: noop,
|
482
|
-
debug: noop,
|
483
|
-
log: noop,
|
484
|
-
warn: noop,
|
485
|
-
info: noop,
|
486
|
-
error: noop
|
487
|
-
};
|
488
|
-
var exportedLogger = fakeLogger;
|
489
|
-
|
490
|
-
// let lastCallTime;
|
491
|
-
// function formatMsgWithTimeInfo(type, msg) {
|
492
|
-
// const now = Date.now();
|
493
|
-
// const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
|
494
|
-
// lastCallTime = now;
|
495
|
-
// msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
|
496
|
-
// return msg;
|
497
|
-
// }
|
498
|
-
|
499
|
-
function consolePrintFn(type) {
|
500
|
-
var func = self.console[type];
|
501
|
-
if (func) {
|
502
|
-
return func.bind(self.console, "[" + type + "] >");
|
503
|
-
}
|
504
|
-
return noop;
|
505
|
-
}
|
506
|
-
function exportLoggerFunctions(debugConfig) {
|
507
|
-
for (var _len = arguments.length, functions = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
508
|
-
functions[_key - 1] = arguments[_key];
|
509
|
-
}
|
510
|
-
functions.forEach(function (type) {
|
511
|
-
exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
|
512
|
-
});
|
513
|
-
}
|
514
|
-
function enableLogs(debugConfig, id) {
|
515
|
-
// check that console is available
|
516
|
-
if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
|
517
|
-
exportLoggerFunctions(debugConfig,
|
518
|
-
// Remove out from list here to hard-disable a log-level
|
519
|
-
// 'trace',
|
520
|
-
'debug', 'log', 'info', 'warn', 'error');
|
521
|
-
// Some browsers don't allow to use bind on console object anyway
|
522
|
-
// fallback to default if needed
|
523
|
-
try {
|
524
|
-
exportedLogger.log("Debug logs enabled for \"" + id + "\" in hls.js version " + "1.5.6");
|
525
|
-
} catch (e) {
|
526
|
-
exportedLogger = fakeLogger;
|
527
|
-
}
|
528
|
-
} else {
|
529
|
-
exportedLogger = fakeLogger;
|
530
|
-
}
|
531
|
-
}
|
532
|
-
var logger = exportedLogger;
|
533
|
-
|
534
469
|
var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/;
|
535
470
|
var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g;
|
536
471
|
|
@@ -619,6 +554,77 @@
|
|
619
554
|
return AttrList;
|
620
555
|
}();
|
621
556
|
|
557
|
+
var Logger = function Logger(label, logger) {
|
558
|
+
this.trace = void 0;
|
559
|
+
this.debug = void 0;
|
560
|
+
this.log = void 0;
|
561
|
+
this.warn = void 0;
|
562
|
+
this.info = void 0;
|
563
|
+
this.error = void 0;
|
564
|
+
var lb = "[" + label + "]:";
|
565
|
+
this.trace = noop;
|
566
|
+
this.debug = logger.debug.bind(null, lb);
|
567
|
+
this.log = logger.log.bind(null, lb);
|
568
|
+
this.warn = logger.warn.bind(null, lb);
|
569
|
+
this.info = logger.info.bind(null, lb);
|
570
|
+
this.error = logger.error.bind(null, lb);
|
571
|
+
};
|
572
|
+
var noop = function noop() {};
|
573
|
+
var fakeLogger = {
|
574
|
+
trace: noop,
|
575
|
+
debug: noop,
|
576
|
+
log: noop,
|
577
|
+
warn: noop,
|
578
|
+
info: noop,
|
579
|
+
error: noop
|
580
|
+
};
|
581
|
+
function createLogger() {
|
582
|
+
return _extends({}, fakeLogger);
|
583
|
+
}
|
584
|
+
|
585
|
+
// let lastCallTime;
|
586
|
+
// function formatMsgWithTimeInfo(type, msg) {
|
587
|
+
// const now = Date.now();
|
588
|
+
// const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
|
589
|
+
// lastCallTime = now;
|
590
|
+
// msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
|
591
|
+
// return msg;
|
592
|
+
// }
|
593
|
+
|
594
|
+
function consolePrintFn(type, id) {
|
595
|
+
var func = self.console[type];
|
596
|
+
return func ? func.bind(self.console, (id ? '[' + id + '] ' : '') + "[" + type + "] >") : noop;
|
597
|
+
}
|
598
|
+
function getLoggerFn(key, debugConfig, id) {
|
599
|
+
return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
|
600
|
+
}
|
601
|
+
var exportedLogger = createLogger();
|
602
|
+
function enableLogs(debugConfig, context, id) {
|
603
|
+
// check that console is available
|
604
|
+
var newLogger = createLogger();
|
605
|
+
if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
|
606
|
+
var keys = [
|
607
|
+
// Remove out from list here to hard-disable a log-level
|
608
|
+
// 'trace',
|
609
|
+
'debug', 'log', 'info', 'warn', 'error'];
|
610
|
+
keys.forEach(function (key) {
|
611
|
+
newLogger[key] = getLoggerFn(key, debugConfig, id);
|
612
|
+
});
|
613
|
+
// Some browsers don't allow to use bind on console object anyway
|
614
|
+
// fallback to default if needed
|
615
|
+
try {
|
616
|
+
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.7-0.canary.10015");
|
617
|
+
} catch (e) {
|
618
|
+
/* log fn threw an exception. All logger methods are no-ops. */
|
619
|
+
return createLogger();
|
620
|
+
}
|
621
|
+
}
|
622
|
+
// global exported logger uses the log methods from last call to `enableLogs`
|
623
|
+
_extends(exportedLogger, newLogger);
|
624
|
+
return newLogger;
|
625
|
+
}
|
626
|
+
var logger = exportedLogger;
|
627
|
+
|
622
628
|
// Avoid exporting const enum so that these values can be inlined
|
623
629
|
|
624
630
|
function isDateRangeCueAttribute(attrName) {
|
@@ -1173,10 +1179,30 @@
|
|
1173
1179
|
return LevelDetails;
|
1174
1180
|
}();
|
1175
1181
|
|
1182
|
+
var DecrypterAesMode = {
|
1183
|
+
cbc: 0,
|
1184
|
+
ctr: 1
|
1185
|
+
};
|
1186
|
+
|
1187
|
+
function isFullSegmentEncryption(method) {
|
1188
|
+
return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
|
1189
|
+
}
|
1190
|
+
function getAesModeFromFullSegmentMethod(method) {
|
1191
|
+
switch (method) {
|
1192
|
+
case 'AES-128':
|
1193
|
+
case 'AES-256':
|
1194
|
+
return DecrypterAesMode.cbc;
|
1195
|
+
case 'AES-256-CTR':
|
1196
|
+
return DecrypterAesMode.ctr;
|
1197
|
+
default:
|
1198
|
+
throw new Error("invalid full segment method " + method);
|
1199
|
+
}
|
1200
|
+
}
|
1201
|
+
|
1176
1202
|
// This file is inserted as a shim for modules which we do not want to include into the distro.
|
1177
1203
|
// This replacement is done in the "alias" plugin of the rollup config.
|
1178
1204
|
var empty = undefined;
|
1179
|
-
var
|
1205
|
+
var HevcVideoParser = /*@__PURE__*/getDefaultExportFromCjs(empty);
|
1180
1206
|
|
1181
1207
|
function sliceUint8(array, start, end) {
|
1182
1208
|
// @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
|
@@ -1926,7 +1952,9 @@
|
|
1926
1952
|
}
|
1927
1953
|
function skipBERInteger(bytes, i) {
|
1928
1954
|
var limit = i + 5;
|
1929
|
-
while (bytes[i++] & 0x80 && i < limit) {
|
1955
|
+
while (bytes[i++] & 0x80 && i < limit) {
|
1956
|
+
/* do nothing */
|
1957
|
+
}
|
1930
1958
|
return i;
|
1931
1959
|
}
|
1932
1960
|
function toHex(x) {
|
@@ -2628,13 +2656,13 @@
|
|
2628
2656
|
this.keyFormatVersions = formatversions;
|
2629
2657
|
this.iv = iv;
|
2630
2658
|
this.encrypted = method ? method !== 'NONE' : false;
|
2631
|
-
this.isCommonEncryption = this.encrypted && method
|
2659
|
+
this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
|
2632
2660
|
}
|
2633
2661
|
var _proto = LevelKey.prototype;
|
2634
2662
|
_proto.isSupported = function isSupported() {
|
2635
2663
|
// If it's Segment encryption or No encryption, just select that key system
|
2636
2664
|
if (this.method) {
|
2637
|
-
if (this.method
|
2665
|
+
if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
|
2638
2666
|
return true;
|
2639
2667
|
}
|
2640
2668
|
if (this.keyFormat === 'identity') {
|
@@ -2648,14 +2676,13 @@
|
|
2648
2676
|
if (!this.encrypted || !this.uri) {
|
2649
2677
|
return null;
|
2650
2678
|
}
|
2651
|
-
if (this.method
|
2679
|
+
if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
|
2652
2680
|
if (typeof sn !== 'number') {
|
2653
2681
|
// We are fetching decryption data for a initialization segment
|
2654
|
-
// If the segment was encrypted with AES-128
|
2682
|
+
// If the segment was encrypted with AES-128/256
|
2655
2683
|
// It must have an IV defined. We cannot substitute the Segment Number in.
|
2656
|
-
|
2657
|
-
|
2658
|
-
}
|
2684
|
+
logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
|
2685
|
+
|
2659
2686
|
// Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
|
2660
2687
|
sn = 0;
|
2661
2688
|
}
|
@@ -2817,23 +2844,28 @@
|
|
2817
2844
|
if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
|
2818
2845
|
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
|
2819
2846
|
}
|
2820
|
-
|
2821
|
-
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2822
|
-
// some browsers will report that fLaC is supported then fail.
|
2823
|
-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2824
2847
|
var codecsToCheck = {
|
2848
|
+
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2849
|
+
// some browsers will report that fLaC is supported then fail.
|
2850
|
+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2825
2851
|
flac: ['flac', 'fLaC', 'FLAC'],
|
2826
|
-
opus: ['opus', 'Opus']
|
2852
|
+
opus: ['opus', 'Opus'],
|
2853
|
+
// Replace audio codec info if browser does not support mp4a.40.34,
|
2854
|
+
// and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
|
2855
|
+
'mp4a.40.34': ['mp3']
|
2827
2856
|
}[lowerCaseCodec];
|
2828
2857
|
for (var i = 0; i < codecsToCheck.length; i++) {
|
2858
|
+
var _getMediaSource;
|
2829
2859
|
if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
|
2830
2860
|
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
|
2831
2861
|
return codecsToCheck[i];
|
2862
|
+
} else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
|
2863
|
+
return '';
|
2832
2864
|
}
|
2833
2865
|
}
|
2834
2866
|
return lowerCaseCodec;
|
2835
2867
|
}
|
2836
|
-
var AUDIO_CODEC_REGEXP = /flac|opus/i;
|
2868
|
+
var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
|
2837
2869
|
function getCodecCompatibleName(codec, preferManagedMediaSource) {
|
2838
2870
|
if (preferManagedMediaSource === void 0) {
|
2839
2871
|
preferManagedMediaSource = true;
|
@@ -2861,6 +2893,18 @@
|
|
2861
2893
|
}
|
2862
2894
|
return codec;
|
2863
2895
|
}
|
2896
|
+
function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
|
2897
|
+
var MediaSource = getMediaSource(preferManagedMediaSource) || {
|
2898
|
+
isTypeSupported: function isTypeSupported() {
|
2899
|
+
return false;
|
2900
|
+
}
|
2901
|
+
};
|
2902
|
+
return {
|
2903
|
+
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
2904
|
+
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
2905
|
+
ac3: false
|
2906
|
+
};
|
2907
|
+
}
|
2864
2908
|
|
2865
2909
|
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;
|
2866
2910
|
var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
|
@@ -3661,10 +3705,10 @@
|
|
3661
3705
|
var loaderContext = loader.context;
|
3662
3706
|
if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
|
3663
3707
|
// same URL can't overlap
|
3664
|
-
logger.trace('[playlist-loader]: playlist request ongoing');
|
3708
|
+
this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
|
3665
3709
|
return;
|
3666
3710
|
}
|
3667
|
-
logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
|
3711
|
+
this.hls.logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
|
3668
3712
|
loader.abort();
|
3669
3713
|
}
|
3670
3714
|
|
@@ -3774,7 +3818,7 @@
|
|
3774
3818
|
// alt audio rendition in which quality levels (main)
|
3775
3819
|
// contains both audio+video. but with mixed audio track not signaled
|
3776
3820
|
if (!embeddedAudioFound && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
|
3777
|
-
logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
|
3821
|
+
this.hls.logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
|
3778
3822
|
audioTracks.unshift({
|
3779
3823
|
type: 'main',
|
3780
3824
|
name: 'main',
|
@@ -3874,7 +3918,7 @@
|
|
3874
3918
|
message += " id: " + context.id + " group-id: \"" + context.groupId + "\"";
|
3875
3919
|
}
|
3876
3920
|
var error = new Error(message);
|
3877
|
-
logger.warn("[playlist-loader]: " + message);
|
3921
|
+
this.hls.logger.warn("[playlist-loader]: " + message);
|
3878
3922
|
var details = ErrorDetails.UNKNOWN;
|
3879
3923
|
var fatal = false;
|
3880
3924
|
var loader = this.getInternalLoader(context);
|
@@ -4435,8 +4479,43 @@
|
|
4435
4479
|
this.currentTime = 0;
|
4436
4480
|
this.stallCount = 0;
|
4437
4481
|
this._latency = null;
|
4438
|
-
this.
|
4439
|
-
|
4482
|
+
this.onTimeupdate = function () {
|
4483
|
+
var media = _this.media,
|
4484
|
+
levelDetails = _this.levelDetails;
|
4485
|
+
if (!media || !levelDetails) {
|
4486
|
+
return;
|
4487
|
+
}
|
4488
|
+
_this.currentTime = media.currentTime;
|
4489
|
+
var latency = _this.computeLatency();
|
4490
|
+
if (latency === null) {
|
4491
|
+
return;
|
4492
|
+
}
|
4493
|
+
_this._latency = latency;
|
4494
|
+
|
4495
|
+
// Adapt playbackRate to meet target latency in low-latency mode
|
4496
|
+
var _this$config = _this.config,
|
4497
|
+
lowLatencyMode = _this$config.lowLatencyMode,
|
4498
|
+
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4499
|
+
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4500
|
+
return;
|
4501
|
+
}
|
4502
|
+
var targetLatency = _this.targetLatency;
|
4503
|
+
if (targetLatency === null) {
|
4504
|
+
return;
|
4505
|
+
}
|
4506
|
+
var distanceFromTarget = latency - targetLatency;
|
4507
|
+
// Only adjust playbackRate when within one target duration of targetLatency
|
4508
|
+
// and more than one second from under-buffering.
|
4509
|
+
// Playback further than one target duration from target can be considered DVR playback.
|
4510
|
+
var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
|
4511
|
+
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4512
|
+
if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
|
4513
|
+
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4514
|
+
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
|
4515
|
+
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4516
|
+
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4517
|
+
media.playbackRate = 1;
|
4518
|
+
}
|
4440
4519
|
};
|
4441
4520
|
this.hls = hls;
|
4442
4521
|
this.config = hls.config;
|
@@ -4448,7 +4527,7 @@
|
|
4448
4527
|
this.onMediaDetaching();
|
4449
4528
|
this.levelDetails = null;
|
4450
4529
|
// @ts-ignore
|
4451
|
-
this.hls =
|
4530
|
+
this.hls = null;
|
4452
4531
|
};
|
4453
4532
|
_proto.registerListeners = function registerListeners() {
|
4454
4533
|
this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
@@ -4466,11 +4545,11 @@
|
|
4466
4545
|
};
|
4467
4546
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
4468
4547
|
this.media = data.media;
|
4469
|
-
this.media.addEventListener('timeupdate', this.
|
4548
|
+
this.media.addEventListener('timeupdate', this.onTimeupdate);
|
4470
4549
|
};
|
4471
4550
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
4472
4551
|
if (this.media) {
|
4473
|
-
this.media.removeEventListener('timeupdate', this.
|
4552
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4474
4553
|
this.media = null;
|
4475
4554
|
}
|
4476
4555
|
};
|
@@ -4483,10 +4562,10 @@
|
|
4483
4562
|
var details = _ref.details;
|
4484
4563
|
this.levelDetails = details;
|
4485
4564
|
if (details.advanced) {
|
4486
|
-
this.
|
4565
|
+
this.onTimeupdate();
|
4487
4566
|
}
|
4488
4567
|
if (!details.live && this.media) {
|
4489
|
-
this.media.removeEventListener('timeupdate', this.
|
4568
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4490
4569
|
}
|
4491
4570
|
};
|
4492
4571
|
_proto.onError = function onError(event, data) {
|
@@ -4496,45 +4575,7 @@
|
|
4496
4575
|
}
|
4497
4576
|
this.stallCount++;
|
4498
4577
|
if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
|
4499
|
-
logger.warn('[
|
4500
|
-
}
|
4501
|
-
};
|
4502
|
-
_proto.timeupdate = function timeupdate() {
|
4503
|
-
var media = this.media,
|
4504
|
-
levelDetails = this.levelDetails;
|
4505
|
-
if (!media || !levelDetails) {
|
4506
|
-
return;
|
4507
|
-
}
|
4508
|
-
this.currentTime = media.currentTime;
|
4509
|
-
var latency = this.computeLatency();
|
4510
|
-
if (latency === null) {
|
4511
|
-
return;
|
4512
|
-
}
|
4513
|
-
this._latency = latency;
|
4514
|
-
|
4515
|
-
// Adapt playbackRate to meet target latency in low-latency mode
|
4516
|
-
var _this$config = this.config,
|
4517
|
-
lowLatencyMode = _this$config.lowLatencyMode,
|
4518
|
-
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4519
|
-
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4520
|
-
return;
|
4521
|
-
}
|
4522
|
-
var targetLatency = this.targetLatency;
|
4523
|
-
if (targetLatency === null) {
|
4524
|
-
return;
|
4525
|
-
}
|
4526
|
-
var distanceFromTarget = latency - targetLatency;
|
4527
|
-
// Only adjust playbackRate when within one target duration of targetLatency
|
4528
|
-
// and more than one second from under-buffering.
|
4529
|
-
// Playback further than one target duration from target can be considered DVR playback.
|
4530
|
-
var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
|
4531
|
-
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4532
|
-
if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
|
4533
|
-
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4534
|
-
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
|
4535
|
-
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4536
|
-
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4537
|
-
media.playbackRate = 1;
|
4578
|
+
this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
|
4538
4579
|
}
|
4539
4580
|
};
|
4540
4581
|
_proto.estimateLiveEdge = function estimateLiveEdge() {
|
@@ -5442,19 +5483,17 @@
|
|
5442
5483
|
MoveAllAlternatesMatchingHDCP: 2,
|
5443
5484
|
SwitchToSDR: 4
|
5444
5485
|
}; // Reserved for future use
|
5445
|
-
var ErrorController = /*#__PURE__*/function () {
|
5486
|
+
var ErrorController = /*#__PURE__*/function (_Logger) {
|
5487
|
+
_inheritsLoose(ErrorController, _Logger);
|
5446
5488
|
function ErrorController(hls) {
|
5447
|
-
|
5448
|
-
this.
|
5449
|
-
|
5450
|
-
|
5451
|
-
|
5452
|
-
|
5453
|
-
|
5454
|
-
|
5455
|
-
this.warn = logger.warn.bind(logger, "[warning]:");
|
5456
|
-
this.error = logger.error.bind(logger, "[error]:");
|
5457
|
-
this.registerListeners();
|
5489
|
+
var _this;
|
5490
|
+
_this = _Logger.call(this, 'error-controller', hls.logger) || this;
|
5491
|
+
_this.hls = void 0;
|
5492
|
+
_this.playlistError = 0;
|
5493
|
+
_this.penalizedRenditions = {};
|
5494
|
+
_this.hls = hls;
|
5495
|
+
_this.registerListeners();
|
5496
|
+
return _this;
|
5458
5497
|
}
|
5459
5498
|
var _proto = ErrorController.prototype;
|
5460
5499
|
_proto.registerListeners = function registerListeners() {
|
@@ -5810,19 +5849,19 @@
|
|
5810
5849
|
}
|
5811
5850
|
};
|
5812
5851
|
return ErrorController;
|
5813
|
-
}();
|
5852
|
+
}(Logger);
|
5814
5853
|
|
5815
|
-
var BasePlaylistController = /*#__PURE__*/function () {
|
5854
|
+
var BasePlaylistController = /*#__PURE__*/function (_Logger) {
|
5855
|
+
_inheritsLoose(BasePlaylistController, _Logger);
|
5816
5856
|
function BasePlaylistController(hls, logPrefix) {
|
5817
|
-
|
5818
|
-
this.
|
5819
|
-
|
5820
|
-
|
5821
|
-
|
5822
|
-
|
5823
|
-
|
5824
|
-
|
5825
|
-
this.hls = hls;
|
5857
|
+
var _this;
|
5858
|
+
_this = _Logger.call(this, logPrefix, hls.logger) || this;
|
5859
|
+
_this.hls = void 0;
|
5860
|
+
_this.timer = -1;
|
5861
|
+
_this.requestScheduled = -1;
|
5862
|
+
_this.canLoad = false;
|
5863
|
+
_this.hls = hls;
|
5864
|
+
return _this;
|
5826
5865
|
}
|
5827
5866
|
var _proto = BasePlaylistController.prototype;
|
5828
5867
|
_proto.destroy = function destroy() {
|
@@ -5855,7 +5894,7 @@
|
|
5855
5894
|
try {
|
5856
5895
|
uri = new self.URL(attr.URI, previous.url).href;
|
5857
5896
|
} catch (error) {
|
5858
|
-
|
5897
|
+
this.warn("Could not construct new URL for Rendition Report: " + error);
|
5859
5898
|
uri = attr.URI || '';
|
5860
5899
|
}
|
5861
5900
|
// Use exact match. Otherwise, the last partial match, if any, will be used
|
@@ -5894,7 +5933,7 @@
|
|
5894
5933
|
return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
|
5895
5934
|
};
|
5896
5935
|
_proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
|
5897
|
-
var
|
5936
|
+
var _this2 = this;
|
5898
5937
|
var details = data.details,
|
5899
5938
|
stats = data.stats;
|
5900
5939
|
|
@@ -5941,7 +5980,12 @@
|
|
5941
5980
|
var cdnAge = lastAdvanced + details.ageHeader;
|
5942
5981
|
var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
|
5943
5982
|
if (currentGoal > 0) {
|
5944
|
-
if (
|
5983
|
+
if (cdnAge > details.targetduration * 3) {
|
5984
|
+
// Omit segment and part directives when the last response was more than 3 target durations ago,
|
5985
|
+
this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
|
5986
|
+
msn = undefined;
|
5987
|
+
part = undefined;
|
5988
|
+
} else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
|
5945
5989
|
// If we attempted to get the next or latest playlist update, but currentGoal increased,
|
5946
5990
|
// then we either can't catchup, or the "age" header cannot be trusted.
|
5947
5991
|
this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
|
@@ -5999,7 +6043,7 @@
|
|
5999
6043
|
// );
|
6000
6044
|
|
6001
6045
|
this.timer = self.setTimeout(function () {
|
6002
|
-
return
|
6046
|
+
return _this2.loadPlaylist(deliveryDirectives);
|
6003
6047
|
}, estimatedTimeUntilUpdate);
|
6004
6048
|
} else {
|
6005
6049
|
this.clearTimer();
|
@@ -6015,7 +6059,7 @@
|
|
6015
6059
|
return new HlsUrlParameters(msn, part, skip);
|
6016
6060
|
};
|
6017
6061
|
_proto.checkRetry = function checkRetry(errorEvent) {
|
6018
|
-
var
|
6062
|
+
var _this3 = this;
|
6019
6063
|
var errorDetails = errorEvent.details;
|
6020
6064
|
var isTimeout = isTimeoutError(errorEvent);
|
6021
6065
|
var errorAction = errorEvent.errorAction;
|
@@ -6039,7 +6083,7 @@
|
|
6039
6083
|
var delay = getRetryDelay(retryConfig, retryCount);
|
6040
6084
|
// Schedule level/track reload
|
6041
6085
|
this.timer = self.setTimeout(function () {
|
6042
|
-
return
|
6086
|
+
return _this3.loadPlaylist();
|
6043
6087
|
}, delay);
|
6044
6088
|
this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
|
6045
6089
|
}
|
@@ -6050,7 +6094,7 @@
|
|
6050
6094
|
return retry;
|
6051
6095
|
};
|
6052
6096
|
return BasePlaylistController;
|
6053
|
-
}();
|
6097
|
+
}(Logger);
|
6054
6098
|
|
6055
6099
|
/*
|
6056
6100
|
* compute an Exponential Weighted moving average
|
@@ -6424,30 +6468,33 @@
|
|
6424
6468
|
}, {});
|
6425
6469
|
}
|
6426
6470
|
|
6427
|
-
var AbrController = /*#__PURE__*/function () {
|
6471
|
+
var AbrController = /*#__PURE__*/function (_Logger) {
|
6472
|
+
_inheritsLoose(AbrController, _Logger);
|
6428
6473
|
function AbrController(_hls) {
|
6429
|
-
var _this
|
6430
|
-
this.
|
6431
|
-
|
6432
|
-
|
6433
|
-
|
6434
|
-
|
6435
|
-
|
6436
|
-
|
6437
|
-
|
6438
|
-
|
6439
|
-
|
6440
|
-
|
6441
|
-
|
6442
|
-
|
6474
|
+
var _this;
|
6475
|
+
_this = _Logger.call(this, 'abr', _hls.logger) || this;
|
6476
|
+
_this.hls = void 0;
|
6477
|
+
_this.lastLevelLoadSec = 0;
|
6478
|
+
_this.lastLoadedFragLevel = -1;
|
6479
|
+
_this.firstSelection = -1;
|
6480
|
+
_this._nextAutoLevel = -1;
|
6481
|
+
_this.nextAutoLevelKey = '';
|
6482
|
+
_this.audioTracksByGroup = null;
|
6483
|
+
_this.codecTiers = null;
|
6484
|
+
_this.timer = -1;
|
6485
|
+
_this.fragCurrent = null;
|
6486
|
+
_this.partCurrent = null;
|
6487
|
+
_this.bitrateTestDelay = 0;
|
6488
|
+
_this.bwEstimator = void 0;
|
6443
6489
|
/*
|
6444
6490
|
This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
|
6445
6491
|
quickly enough to prevent underbuffering
|
6446
6492
|
*/
|
6447
|
-
|
6448
|
-
var
|
6449
|
-
|
6450
|
-
|
6493
|
+
_this._abandonRulesCheck = function () {
|
6494
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
6495
|
+
frag = _assertThisInitialize.fragCurrent,
|
6496
|
+
part = _assertThisInitialize.partCurrent,
|
6497
|
+
hls = _assertThisInitialize.hls;
|
6451
6498
|
var autoLevelEnabled = hls.autoLevelEnabled,
|
6452
6499
|
media = hls.media;
|
6453
6500
|
if (!frag || !media) {
|
@@ -6536,21 +6583,22 @@
|
|
6536
6583
|
_this.resetEstimator(nextLoadLevelBitrate);
|
6537
6584
|
}
|
6538
6585
|
_this.clearTimer();
|
6539
|
-
|
6586
|
+
_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");
|
6540
6587
|
hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
|
6541
6588
|
frag: frag,
|
6542
6589
|
part: part,
|
6543
6590
|
stats: stats
|
6544
6591
|
});
|
6545
6592
|
};
|
6546
|
-
|
6547
|
-
|
6548
|
-
|
6593
|
+
_this.hls = _hls;
|
6594
|
+
_this.bwEstimator = _this.initEstimator();
|
6595
|
+
_this.registerListeners();
|
6596
|
+
return _this;
|
6549
6597
|
}
|
6550
6598
|
var _proto = AbrController.prototype;
|
6551
6599
|
_proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
|
6552
6600
|
if (abrEwmaDefaultEstimate) {
|
6553
|
-
|
6601
|
+
this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
|
6554
6602
|
this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
|
6555
6603
|
}
|
6556
6604
|
this.firstSelection = -1;
|
@@ -6795,13 +6843,13 @@
|
|
6795
6843
|
// cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
|
6796
6844
|
var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
|
6797
6845
|
maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
|
6798
|
-
|
6846
|
+
this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
|
6799
6847
|
// don't use conservative factor on bitrate test
|
6800
6848
|
bwFactor = bwUpFactor = 1;
|
6801
6849
|
}
|
6802
6850
|
}
|
6803
6851
|
var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
|
6804
|
-
|
6852
|
+
this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
|
6805
6853
|
if (bestLevel > -1) {
|
6806
6854
|
return bestLevel;
|
6807
6855
|
}
|
@@ -6869,7 +6917,7 @@
|
|
6869
6917
|
currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
|
6870
6918
|
currentFrameRate = minFramerate;
|
6871
6919
|
currentBw = Math.max(currentBw, minBitrate);
|
6872
|
-
|
6920
|
+
this.log("picked start tier " + JSON.stringify(startTier));
|
6873
6921
|
} else {
|
6874
6922
|
currentCodecSet = level == null ? void 0 : level.codecSet;
|
6875
6923
|
currentVideoRange = level == null ? void 0 : level.videoRange;
|
@@ -6922,9 +6970,9 @@
|
|
6922
6970
|
var forcedAutoLevel = _this2.forcedAutoLevel;
|
6923
6971
|
if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
|
6924
6972
|
if (levelsSkipped.length) {
|
6925
|
-
|
6973
|
+
_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);
|
6926
6974
|
}
|
6927
|
-
|
6975
|
+
_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);
|
6928
6976
|
}
|
6929
6977
|
if (firstSelection) {
|
6930
6978
|
_this2.firstSelection = i;
|
@@ -6958,7 +7006,7 @@
|
|
6958
7006
|
}
|
6959
7007
|
var firstLevel = this.hls.firstLevel;
|
6960
7008
|
var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
|
6961
|
-
|
7009
|
+
this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
|
6962
7010
|
return clamped;
|
6963
7011
|
}
|
6964
7012
|
}, {
|
@@ -7011,7 +7059,7 @@
|
|
7011
7059
|
}
|
7012
7060
|
}]);
|
7013
7061
|
return AbrController;
|
7014
|
-
}();
|
7062
|
+
}(Logger);
|
7015
7063
|
|
7016
7064
|
/**
|
7017
7065
|
* Provides methods dealing with buffer length retrieval for example.
|
@@ -7232,57 +7280,57 @@
|
|
7232
7280
|
}();
|
7233
7281
|
|
7234
7282
|
var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
|
7235
|
-
var BufferController = /*#__PURE__*/function () {
|
7283
|
+
var BufferController = /*#__PURE__*/function (_Logger) {
|
7284
|
+
_inheritsLoose(BufferController, _Logger);
|
7236
7285
|
function BufferController(hls) {
|
7237
|
-
var _this
|
7286
|
+
var _this;
|
7287
|
+
_this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
|
7238
7288
|
// The level details used to determine duration, target-duration and live
|
7239
|
-
|
7289
|
+
_this.details = null;
|
7240
7290
|
// cache the self generated object url to detect hijack of video tag
|
7241
|
-
|
7291
|
+
_this._objectUrl = null;
|
7242
7292
|
// A queue of buffer operations which require the SourceBuffer to not be updating upon execution
|
7243
|
-
|
7293
|
+
_this.operationQueue = void 0;
|
7244
7294
|
// References to event listeners for each SourceBuffer, so that they can be referenced for event removal
|
7245
|
-
|
7246
|
-
|
7295
|
+
_this.listeners = void 0;
|
7296
|
+
_this.hls = void 0;
|
7247
7297
|
// The number of BUFFER_CODEC events received before any sourceBuffers are created
|
7248
|
-
|
7298
|
+
_this.bufferCodecEventsExpected = 0;
|
7249
7299
|
// The total number of BUFFER_CODEC events received
|
7250
|
-
|
7300
|
+
_this._bufferCodecEventsTotal = 0;
|
7251
7301
|
// A reference to the attached media element
|
7252
|
-
|
7302
|
+
_this.media = null;
|
7253
7303
|
// A reference to the active media source
|
7254
|
-
|
7304
|
+
_this.mediaSource = null;
|
7255
7305
|
// Last MP3 audio chunk appended
|
7256
|
-
|
7257
|
-
|
7306
|
+
_this.lastMpegAudioChunk = null;
|
7307
|
+
_this.appendSource = void 0;
|
7258
7308
|
// counters
|
7259
|
-
|
7309
|
+
_this.appendErrors = {
|
7260
7310
|
audio: 0,
|
7261
7311
|
video: 0,
|
7262
7312
|
audiovideo: 0
|
7263
7313
|
};
|
7264
|
-
|
7265
|
-
|
7266
|
-
|
7267
|
-
|
7268
|
-
this.warn = void 0;
|
7269
|
-
this.error = void 0;
|
7270
|
-
this._onEndStreaming = function (event) {
|
7314
|
+
_this.tracks = {};
|
7315
|
+
_this.pendingTracks = {};
|
7316
|
+
_this.sourceBuffer = void 0;
|
7317
|
+
_this._onEndStreaming = function (event) {
|
7271
7318
|
if (!_this.hls) {
|
7272
7319
|
return;
|
7273
7320
|
}
|
7274
7321
|
_this.hls.pauseBuffering();
|
7275
7322
|
};
|
7276
|
-
|
7323
|
+
_this._onStartStreaming = function (event) {
|
7277
7324
|
if (!_this.hls) {
|
7278
7325
|
return;
|
7279
7326
|
}
|
7280
7327
|
_this.hls.resumeBuffering();
|
7281
7328
|
};
|
7282
7329
|
// Keep as arrow functions so that we can directly reference these functions directly as event listeners
|
7283
|
-
|
7284
|
-
var
|
7285
|
-
|
7330
|
+
_this._onMediaSourceOpen = function () {
|
7331
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
7332
|
+
media = _assertThisInitialize.media,
|
7333
|
+
mediaSource = _assertThisInitialize.mediaSource;
|
7286
7334
|
_this.log('Media source opened');
|
7287
7335
|
if (media) {
|
7288
7336
|
media.removeEventListener('emptied', _this._onMediaEmptied);
|
@@ -7298,27 +7346,25 @@
|
|
7298
7346
|
}
|
7299
7347
|
_this.checkPendingTracks();
|
7300
7348
|
};
|
7301
|
-
|
7349
|
+
_this._onMediaSourceClose = function () {
|
7302
7350
|
_this.log('Media source closed');
|
7303
7351
|
};
|
7304
|
-
|
7352
|
+
_this._onMediaSourceEnded = function () {
|
7305
7353
|
_this.log('Media source ended');
|
7306
7354
|
};
|
7307
|
-
|
7308
|
-
var
|
7309
|
-
|
7355
|
+
_this._onMediaEmptied = function () {
|
7356
|
+
var _assertThisInitialize2 = _assertThisInitialized(_this),
|
7357
|
+
mediaSrc = _assertThisInitialize2.mediaSrc,
|
7358
|
+
_objectUrl = _assertThisInitialize2._objectUrl;
|
7310
7359
|
if (mediaSrc !== _objectUrl) {
|
7311
|
-
|
7360
|
+
_this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
|
7312
7361
|
}
|
7313
7362
|
};
|
7314
|
-
|
7315
|
-
|
7316
|
-
|
7317
|
-
|
7318
|
-
|
7319
|
-
this.error = logger.error.bind(logger, logPrefix);
|
7320
|
-
this._initSourceBuffer();
|
7321
|
-
this.registerListeners();
|
7363
|
+
_this.hls = hls;
|
7364
|
+
_this.appendSource = hls.config.preferManagedMediaSource;
|
7365
|
+
_this._initSourceBuffer();
|
7366
|
+
_this.registerListeners();
|
7367
|
+
return _this;
|
7322
7368
|
}
|
7323
7369
|
var _proto = BufferController.prototype;
|
7324
7370
|
_proto.hasSourceTypes = function hasSourceTypes() {
|
@@ -7330,6 +7376,12 @@
|
|
7330
7376
|
this.lastMpegAudioChunk = null;
|
7331
7377
|
// @ts-ignore
|
7332
7378
|
this.hls = null;
|
7379
|
+
// @ts-ignore
|
7380
|
+
this._onMediaSourceOpen = this._onMediaSourceClose = null;
|
7381
|
+
// @ts-ignore
|
7382
|
+
this._onMediaSourceEnded = null;
|
7383
|
+
// @ts-ignore
|
7384
|
+
this._onStartStreaming = this._onEndStreaming = null;
|
7333
7385
|
};
|
7334
7386
|
_proto.registerListeners = function registerListeners() {
|
7335
7387
|
var hls = this.hls;
|
@@ -7487,6 +7539,7 @@
|
|
7487
7539
|
_this2.resetBuffer(type);
|
7488
7540
|
});
|
7489
7541
|
this._initSourceBuffer();
|
7542
|
+
this.hls.resumeBuffering();
|
7490
7543
|
};
|
7491
7544
|
_proto.resetBuffer = function resetBuffer(type) {
|
7492
7545
|
var sb = this.sourceBuffer[type];
|
@@ -8190,7 +8243,7 @@
|
|
8190
8243
|
}
|
8191
8244
|
}]);
|
8192
8245
|
return BufferController;
|
8193
|
-
}();
|
8246
|
+
}(Logger);
|
8194
8247
|
function removeSourceChildren(node) {
|
8195
8248
|
var sourceChildren = node.querySelectorAll('source');
|
8196
8249
|
[].slice.call(sourceChildren).forEach(function (source) {
|
@@ -8314,7 +8367,7 @@
|
|
8314
8367
|
var hls = this.hls;
|
8315
8368
|
var maxLevel = this.getMaxLevel(levels.length - 1);
|
8316
8369
|
if (maxLevel !== this.autoLevelCapping) {
|
8317
|
-
logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8370
|
+
hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8318
8371
|
}
|
8319
8372
|
hls.autoLevelCapping = maxLevel;
|
8320
8373
|
if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
|
@@ -8504,10 +8557,10 @@
|
|
8504
8557
|
totalDroppedFrames: droppedFrames
|
8505
8558
|
});
|
8506
8559
|
if (droppedFPS > 0) {
|
8507
|
-
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8560
|
+
// hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8508
8561
|
if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
|
8509
8562
|
var currentLevel = hls.currentLevel;
|
8510
|
-
logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8563
|
+
hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8511
8564
|
if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
|
8512
8565
|
currentLevel = currentLevel - 1;
|
8513
8566
|
hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
|
@@ -8541,26 +8594,28 @@
|
|
8541
8594
|
}();
|
8542
8595
|
|
8543
8596
|
var PATHWAY_PENALTY_DURATION_MS = 300000;
|
8544
|
-
var ContentSteeringController = /*#__PURE__*/function () {
|
8597
|
+
var ContentSteeringController = /*#__PURE__*/function (_Logger) {
|
8598
|
+
_inheritsLoose(ContentSteeringController, _Logger);
|
8545
8599
|
function ContentSteeringController(hls) {
|
8546
|
-
|
8547
|
-
this.
|
8548
|
-
|
8549
|
-
|
8550
|
-
|
8551
|
-
|
8552
|
-
|
8553
|
-
|
8554
|
-
|
8555
|
-
|
8556
|
-
|
8557
|
-
|
8558
|
-
|
8559
|
-
|
8560
|
-
|
8561
|
-
|
8562
|
-
|
8563
|
-
|
8600
|
+
var _this;
|
8601
|
+
_this = _Logger.call(this, 'content-steering', hls.logger) || this;
|
8602
|
+
_this.hls = void 0;
|
8603
|
+
_this.loader = null;
|
8604
|
+
_this.uri = null;
|
8605
|
+
_this.pathwayId = '.';
|
8606
|
+
_this.pathwayPriority = null;
|
8607
|
+
_this.timeToLoad = 300;
|
8608
|
+
_this.reloadTimer = -1;
|
8609
|
+
_this.updated = 0;
|
8610
|
+
_this.started = false;
|
8611
|
+
_this.enabled = true;
|
8612
|
+
_this.levels = null;
|
8613
|
+
_this.audioTracks = null;
|
8614
|
+
_this.subtitleTracks = null;
|
8615
|
+
_this.penalizedPathways = {};
|
8616
|
+
_this.hls = hls;
|
8617
|
+
_this.registerListeners();
|
8618
|
+
return _this;
|
8564
8619
|
}
|
8565
8620
|
var _proto = ContentSteeringController.prototype;
|
8566
8621
|
_proto.registerListeners = function registerListeners() {
|
@@ -8681,7 +8736,7 @@
|
|
8681
8736
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
8682
8737
|
}
|
8683
8738
|
if (!errorAction.resolved) {
|
8684
|
-
|
8739
|
+
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));
|
8685
8740
|
}
|
8686
8741
|
}
|
8687
8742
|
};
|
@@ -8761,7 +8816,7 @@
|
|
8761
8816
|
return defaultPathway;
|
8762
8817
|
};
|
8763
8818
|
_proto.clonePathways = function clonePathways(pathwayClones) {
|
8764
|
-
var
|
8819
|
+
var _this2 = this;
|
8765
8820
|
var levels = this.levels;
|
8766
8821
|
if (!levels) {
|
8767
8822
|
return;
|
@@ -8777,7 +8832,7 @@
|
|
8777
8832
|
})) {
|
8778
8833
|
return;
|
8779
8834
|
}
|
8780
|
-
var clonedVariants =
|
8835
|
+
var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
|
8781
8836
|
var attributes = new AttrList(baseLevel.attrs);
|
8782
8837
|
attributes['PATHWAY-ID'] = cloneId;
|
8783
8838
|
var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
|
@@ -8814,12 +8869,12 @@
|
|
8814
8869
|
return clonedLevel;
|
8815
8870
|
});
|
8816
8871
|
levels.push.apply(levels, clonedVariants);
|
8817
|
-
cloneRenditionGroups(
|
8818
|
-
cloneRenditionGroups(
|
8872
|
+
cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
|
8873
|
+
cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
|
8819
8874
|
});
|
8820
8875
|
};
|
8821
8876
|
_proto.loadSteeringManifest = function loadSteeringManifest(uri) {
|
8822
|
-
var
|
8877
|
+
var _this3 = this;
|
8823
8878
|
var config = this.hls.config;
|
8824
8879
|
var Loader = config.loader;
|
8825
8880
|
if (this.loader) {
|
@@ -8854,87 +8909,87 @@
|
|
8854
8909
|
};
|
8855
8910
|
var callbacks = {
|
8856
8911
|
onSuccess: function onSuccess(response, stats, context, networkDetails) {
|
8857
|
-
|
8912
|
+
_this3.log("Loaded steering manifest: \"" + url + "\"");
|
8858
8913
|
var steeringData = response.data;
|
8859
|
-
if (steeringData.VERSION !== 1) {
|
8860
|
-
|
8914
|
+
if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
|
8915
|
+
_this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
|
8861
8916
|
return;
|
8862
8917
|
}
|
8863
|
-
|
8864
|
-
|
8918
|
+
_this3.updated = performance.now();
|
8919
|
+
_this3.timeToLoad = steeringData.TTL;
|
8865
8920
|
var reloadUri = steeringData['RELOAD-URI'],
|
8866
8921
|
pathwayClones = steeringData['PATHWAY-CLONES'],
|
8867
8922
|
pathwayPriority = steeringData['PATHWAY-PRIORITY'];
|
8868
8923
|
if (reloadUri) {
|
8869
8924
|
try {
|
8870
|
-
|
8925
|
+
_this3.uri = new self.URL(reloadUri, url).href;
|
8871
8926
|
} catch (error) {
|
8872
|
-
|
8873
|
-
|
8927
|
+
_this3.enabled = false;
|
8928
|
+
_this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
|
8874
8929
|
return;
|
8875
8930
|
}
|
8876
8931
|
}
|
8877
|
-
|
8932
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8878
8933
|
if (pathwayClones) {
|
8879
|
-
|
8934
|
+
_this3.clonePathways(pathwayClones);
|
8880
8935
|
}
|
8881
8936
|
var loadedSteeringData = {
|
8882
8937
|
steeringManifest: steeringData,
|
8883
8938
|
url: url.toString()
|
8884
8939
|
};
|
8885
|
-
|
8940
|
+
_this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
|
8886
8941
|
if (pathwayPriority) {
|
8887
|
-
|
8942
|
+
_this3.updatePathwayPriority(pathwayPriority);
|
8888
8943
|
}
|
8889
8944
|
},
|
8890
8945
|
onError: function onError(error, context, networkDetails, stats) {
|
8891
|
-
|
8892
|
-
|
8946
|
+
_this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
|
8947
|
+
_this3.stopLoad();
|
8893
8948
|
if (error.code === 410) {
|
8894
|
-
|
8895
|
-
|
8949
|
+
_this3.enabled = false;
|
8950
|
+
_this3.log("Steering manifest " + context.url + " no longer available");
|
8896
8951
|
return;
|
8897
8952
|
}
|
8898
|
-
var ttl =
|
8953
|
+
var ttl = _this3.timeToLoad * 1000;
|
8899
8954
|
if (error.code === 429) {
|
8900
|
-
var loader =
|
8955
|
+
var loader = _this3.loader;
|
8901
8956
|
if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
|
8902
8957
|
var retryAfter = loader.getResponseHeader('Retry-After');
|
8903
8958
|
if (retryAfter) {
|
8904
8959
|
ttl = parseFloat(retryAfter) * 1000;
|
8905
8960
|
}
|
8906
8961
|
}
|
8907
|
-
|
8962
|
+
_this3.log("Steering manifest " + context.url + " rate limited");
|
8908
8963
|
return;
|
8909
8964
|
}
|
8910
|
-
|
8965
|
+
_this3.scheduleRefresh(_this3.uri || context.url, ttl);
|
8911
8966
|
},
|
8912
8967
|
onTimeout: function onTimeout(stats, context, networkDetails) {
|
8913
|
-
|
8914
|
-
|
8968
|
+
_this3.log("Timeout loading steering manifest (" + context.url + ")");
|
8969
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8915
8970
|
}
|
8916
8971
|
};
|
8917
8972
|
this.log("Requesting steering manifest: " + url);
|
8918
8973
|
this.loader.load(context, loaderConfig, callbacks);
|
8919
8974
|
};
|
8920
8975
|
_proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
|
8921
|
-
var
|
8976
|
+
var _this4 = this;
|
8922
8977
|
if (ttlMs === void 0) {
|
8923
8978
|
ttlMs = this.timeToLoad * 1000;
|
8924
8979
|
}
|
8925
8980
|
this.clearTimeout();
|
8926
8981
|
this.reloadTimer = self.setTimeout(function () {
|
8927
|
-
var
|
8928
|
-
var media = (
|
8982
|
+
var _this4$hls;
|
8983
|
+
var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
|
8929
8984
|
if (media && !media.ended) {
|
8930
|
-
|
8985
|
+
_this4.loadSteeringManifest(uri);
|
8931
8986
|
return;
|
8932
8987
|
}
|
8933
|
-
|
8988
|
+
_this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
|
8934
8989
|
}, ttlMs);
|
8935
8990
|
};
|
8936
8991
|
return ContentSteeringController;
|
8937
|
-
}();
|
8992
|
+
}(Logger);
|
8938
8993
|
function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
|
8939
8994
|
if (!tracks) {
|
8940
8995
|
return;
|
@@ -9770,7 +9825,7 @@
|
|
9770
9825
|
});
|
9771
9826
|
function timelineConfig() {
|
9772
9827
|
return {
|
9773
|
-
cueHandler:
|
9828
|
+
cueHandler: HevcVideoParser,
|
9774
9829
|
// used by timeline-controller
|
9775
9830
|
enableWebVTT: false,
|
9776
9831
|
// used by timeline-controller
|
@@ -9801,7 +9856,7 @@
|
|
9801
9856
|
/**
|
9802
9857
|
* @ignore
|
9803
9858
|
*/
|
9804
|
-
function mergeConfig(defaultConfig, userConfig) {
|
9859
|
+
function mergeConfig(defaultConfig, userConfig, logger) {
|
9805
9860
|
if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
|
9806
9861
|
throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
|
9807
9862
|
}
|
@@ -9871,7 +9926,7 @@
|
|
9871
9926
|
/**
|
9872
9927
|
* @ignore
|
9873
9928
|
*/
|
9874
|
-
function enableStreamingMode(config) {
|
9929
|
+
function enableStreamingMode(config, logger) {
|
9875
9930
|
var currentLoader = config.loader;
|
9876
9931
|
if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
|
9877
9932
|
// If a developer has configured their own loader, respect that choice
|
@@ -9888,12 +9943,11 @@
|
|
9888
9943
|
}
|
9889
9944
|
}
|
9890
9945
|
|
9891
|
-
var chromeOrFirefox;
|
9892
9946
|
var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
|
9893
9947
|
_inheritsLoose(LevelController, _BasePlaylistControll);
|
9894
9948
|
function LevelController(hls, contentSteeringController) {
|
9895
9949
|
var _this;
|
9896
|
-
_this = _BasePlaylistControll.call(this, hls, '
|
9950
|
+
_this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
|
9897
9951
|
_this._levels = [];
|
9898
9952
|
_this._firstLevel = -1;
|
9899
9953
|
_this._maxAutoLevel = -1;
|
@@ -9962,21 +10016,13 @@
|
|
9962
10016
|
var videoCodecFound = false;
|
9963
10017
|
var audioCodecFound = false;
|
9964
10018
|
data.levels.forEach(function (levelParsed) {
|
9965
|
-
var
|
10019
|
+
var _videoCodec;
|
9966
10020
|
var attributes = levelParsed.attrs;
|
9967
|
-
|
9968
|
-
// erase audio codec info if browser does not support mp4a.40.34.
|
9969
|
-
// demuxer will autodetect codec and fallback to mpeg/audio
|
9970
10021
|
var audioCodec = levelParsed.audioCodec,
|
9971
10022
|
videoCodec = levelParsed.videoCodec;
|
9972
|
-
if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
|
9973
|
-
chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
|
9974
|
-
if (chromeOrFirefox) {
|
9975
|
-
levelParsed.audioCodec = audioCodec = undefined;
|
9976
|
-
}
|
9977
|
-
}
|
9978
10023
|
if (audioCodec) {
|
9979
|
-
|
10024
|
+
// Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
|
10025
|
+
levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
|
9980
10026
|
}
|
9981
10027
|
if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
|
9982
10028
|
videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
|
@@ -10208,7 +10254,12 @@
|
|
10208
10254
|
if (curLevel.fragmentError === 0) {
|
10209
10255
|
curLevel.loadError = 0;
|
10210
10256
|
}
|
10211
|
-
|
10257
|
+
// Ignore matching details populated by loading a Media Playlist directly
|
10258
|
+
var previousDetails = curLevel.details;
|
10259
|
+
if (previousDetails === data.details && previousDetails.advanced) {
|
10260
|
+
previousDetails = undefined;
|
10261
|
+
}
|
10262
|
+
this.playlistLoaded(level, data, previousDetails);
|
10212
10263
|
} else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
|
10213
10264
|
// received a delta playlist update that cannot be merged
|
10214
10265
|
details.deltaUpdateFailed = true;
|
@@ -11123,8 +11174,8 @@
|
|
11123
11174
|
var _frag$decryptdata;
|
11124
11175
|
var byteRangeStart = start;
|
11125
11176
|
var byteRangeEnd = end;
|
11126
|
-
if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)
|
11127
|
-
// MAP segment encrypted with method 'AES-128', when served with HTTP Range,
|
11177
|
+
if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
|
11178
|
+
// MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
|
11128
11179
|
// has the unencrypted size specified in the range.
|
11129
11180
|
// Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
11130
11181
|
var fragmentLen = end - start;
|
@@ -11157,6 +11208,9 @@
|
|
11157
11208
|
(part ? part : frag).stats.aborted = true;
|
11158
11209
|
return new LoadError(errorData);
|
11159
11210
|
}
|
11211
|
+
function isMethodFullSegmentAesCbc(method) {
|
11212
|
+
return method === 'AES-128' || method === 'AES-256';
|
11213
|
+
}
|
11160
11214
|
var LoadError = /*#__PURE__*/function (_Error) {
|
11161
11215
|
_inheritsLoose(LoadError, _Error);
|
11162
11216
|
function LoadError(data) {
|
@@ -11313,6 +11367,8 @@
|
|
11313
11367
|
}
|
11314
11368
|
return this.loadKeyEME(keyInfo, frag);
|
11315
11369
|
case 'AES-128':
|
11370
|
+
case 'AES-256':
|
11371
|
+
case 'AES-256-CTR':
|
11316
11372
|
return this.loadKeyHTTP(keyInfo, frag);
|
11317
11373
|
default:
|
11318
11374
|
return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
|
@@ -11446,13 +11502,17 @@
|
|
11446
11502
|
* we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
|
11447
11503
|
* task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
|
11448
11504
|
*/
|
11449
|
-
var TaskLoop = /*#__PURE__*/function () {
|
11450
|
-
|
11451
|
-
|
11452
|
-
|
11453
|
-
|
11454
|
-
|
11455
|
-
|
11505
|
+
var TaskLoop = /*#__PURE__*/function (_Logger) {
|
11506
|
+
_inheritsLoose(TaskLoop, _Logger);
|
11507
|
+
function TaskLoop(label, logger) {
|
11508
|
+
var _this;
|
11509
|
+
_this = _Logger.call(this, label, logger) || this;
|
11510
|
+
_this._boundTick = void 0;
|
11511
|
+
_this._tickTimer = null;
|
11512
|
+
_this._tickInterval = null;
|
11513
|
+
_this._tickCallCount = 0;
|
11514
|
+
_this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
|
11515
|
+
return _this;
|
11456
11516
|
}
|
11457
11517
|
var _proto = TaskLoop.prototype;
|
11458
11518
|
_proto.destroy = function destroy() {
|
@@ -11538,7 +11598,7 @@
|
|
11538
11598
|
*/;
|
11539
11599
|
_proto.doTick = function doTick() {};
|
11540
11600
|
return TaskLoop;
|
11541
|
-
}();
|
11601
|
+
}(Logger);
|
11542
11602
|
|
11543
11603
|
var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
|
11544
11604
|
if (size === void 0) {
|
@@ -11724,37 +11784,65 @@
|
|
11724
11784
|
}
|
11725
11785
|
|
11726
11786
|
var AESCrypto = /*#__PURE__*/function () {
|
11727
|
-
function AESCrypto(subtle, iv) {
|
11787
|
+
function AESCrypto(subtle, iv, aesMode) {
|
11728
11788
|
this.subtle = void 0;
|
11729
11789
|
this.aesIV = void 0;
|
11790
|
+
this.aesMode = void 0;
|
11730
11791
|
this.subtle = subtle;
|
11731
11792
|
this.aesIV = iv;
|
11793
|
+
this.aesMode = aesMode;
|
11732
11794
|
}
|
11733
11795
|
var _proto = AESCrypto.prototype;
|
11734
11796
|
_proto.decrypt = function decrypt(data, key) {
|
11735
|
-
|
11736
|
-
|
11737
|
-
|
11738
|
-
|
11797
|
+
switch (this.aesMode) {
|
11798
|
+
case DecrypterAesMode.cbc:
|
11799
|
+
return this.subtle.decrypt({
|
11800
|
+
name: 'AES-CBC',
|
11801
|
+
iv: this.aesIV
|
11802
|
+
}, key, data);
|
11803
|
+
case DecrypterAesMode.ctr:
|
11804
|
+
return this.subtle.decrypt({
|
11805
|
+
name: 'AES-CTR',
|
11806
|
+
counter: this.aesIV,
|
11807
|
+
length: 64
|
11808
|
+
},
|
11809
|
+
//64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
|
11810
|
+
key, data);
|
11811
|
+
default:
|
11812
|
+
throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
|
11813
|
+
}
|
11739
11814
|
};
|
11740
11815
|
return AESCrypto;
|
11741
11816
|
}();
|
11742
11817
|
|
11743
11818
|
var FastAESKey = /*#__PURE__*/function () {
|
11744
|
-
function FastAESKey(subtle, key) {
|
11819
|
+
function FastAESKey(subtle, key, aesMode) {
|
11745
11820
|
this.subtle = void 0;
|
11746
11821
|
this.key = void 0;
|
11822
|
+
this.aesMode = void 0;
|
11747
11823
|
this.subtle = subtle;
|
11748
11824
|
this.key = key;
|
11825
|
+
this.aesMode = aesMode;
|
11749
11826
|
}
|
11750
11827
|
var _proto = FastAESKey.prototype;
|
11751
11828
|
_proto.expandKey = function expandKey() {
|
11829
|
+
var subtleAlgoName = getSubtleAlgoName(this.aesMode);
|
11752
11830
|
return this.subtle.importKey('raw', this.key, {
|
11753
|
-
name:
|
11831
|
+
name: subtleAlgoName
|
11754
11832
|
}, false, ['encrypt', 'decrypt']);
|
11755
11833
|
};
|
11756
11834
|
return FastAESKey;
|
11757
11835
|
}();
|
11836
|
+
function getSubtleAlgoName(aesMode) {
|
11837
|
+
switch (aesMode) {
|
11838
|
+
case DecrypterAesMode.cbc:
|
11839
|
+
return 'AES-CBC';
|
11840
|
+
case DecrypterAesMode.ctr:
|
11841
|
+
return 'AES-CTR';
|
11842
|
+
default:
|
11843
|
+
throw new Error("[FastAESKey] invalid aes mode " + aesMode);
|
11844
|
+
}
|
11845
|
+
}
|
11758
11846
|
|
11759
11847
|
// PKCS7
|
11760
11848
|
function removePadding(array) {
|
@@ -12007,7 +12095,8 @@
|
|
12007
12095
|
this.currentIV = null;
|
12008
12096
|
this.currentResult = null;
|
12009
12097
|
this.useSoftware = void 0;
|
12010
|
-
this.
|
12098
|
+
this.enableSoftwareAES = void 0;
|
12099
|
+
this.enableSoftwareAES = config.enableSoftwareAES;
|
12011
12100
|
this.removePKCS7Padding = removePKCS7Padding;
|
12012
12101
|
// built in decryptor expects PKCS7 padding
|
12013
12102
|
if (removePKCS7Padding) {
|
@@ -12020,9 +12109,7 @@
|
|
12020
12109
|
/* no-op */
|
12021
12110
|
}
|
12022
12111
|
}
|
12023
|
-
|
12024
|
-
this.useSoftware = true;
|
12025
|
-
}
|
12112
|
+
this.useSoftware = this.subtle === null;
|
12026
12113
|
}
|
12027
12114
|
var _proto = Decrypter.prototype;
|
12028
12115
|
_proto.destroy = function destroy() {
|
@@ -12059,11 +12146,11 @@
|
|
12059
12146
|
this.softwareDecrypter = null;
|
12060
12147
|
}
|
12061
12148
|
};
|
12062
|
-
_proto.decrypt = function decrypt(data, key, iv) {
|
12149
|
+
_proto.decrypt = function decrypt(data, key, iv, aesMode) {
|
12063
12150
|
var _this = this;
|
12064
12151
|
if (this.useSoftware) {
|
12065
12152
|
return new Promise(function (resolve, reject) {
|
12066
|
-
_this.softwareDecrypt(new Uint8Array(data), key, iv);
|
12153
|
+
_this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12067
12154
|
var decryptResult = _this.flush();
|
12068
12155
|
if (decryptResult) {
|
12069
12156
|
resolve(decryptResult.buffer);
|
@@ -12072,16 +12159,20 @@
|
|
12072
12159
|
}
|
12073
12160
|
});
|
12074
12161
|
}
|
12075
|
-
return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
|
12162
|
+
return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12076
12163
|
}
|
12077
12164
|
|
12078
12165
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
12079
12166
|
// data is handled in the flush() call
|
12080
12167
|
;
|
12081
|
-
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
|
12168
|
+
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
|
12082
12169
|
var currentIV = this.currentIV,
|
12083
12170
|
currentResult = this.currentResult,
|
12084
12171
|
remainderData = this.remainderData;
|
12172
|
+
if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
|
12173
|
+
logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
|
12174
|
+
return null;
|
12175
|
+
}
|
12085
12176
|
this.logOnce('JS AES decrypt');
|
12086
12177
|
// The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
|
12087
12178
|
// This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
|
@@ -12114,12 +12205,12 @@
|
|
12114
12205
|
}
|
12115
12206
|
return result;
|
12116
12207
|
};
|
12117
|
-
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
|
12208
|
+
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
|
12118
12209
|
var _this2 = this;
|
12119
12210
|
var subtle = this.subtle;
|
12120
12211
|
if (this.key !== key || !this.fastAesKey) {
|
12121
12212
|
this.key = key;
|
12122
|
-
this.fastAesKey = new FastAESKey(subtle, key);
|
12213
|
+
this.fastAesKey = new FastAESKey(subtle, key, aesMode);
|
12123
12214
|
}
|
12124
12215
|
return this.fastAesKey.expandKey().then(function (aesKey) {
|
12125
12216
|
// decrypt using web crypto
|
@@ -12127,22 +12218,25 @@
|
|
12127
12218
|
return Promise.reject(new Error('web crypto not initialized'));
|
12128
12219
|
}
|
12129
12220
|
_this2.logOnce('WebCrypto AES decrypt');
|
12130
|
-
var crypto = new AESCrypto(subtle, new Uint8Array(iv));
|
12221
|
+
var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
|
12131
12222
|
return crypto.decrypt(data.buffer, aesKey);
|
12132
12223
|
}).catch(function (err) {
|
12133
12224
|
logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
|
12134
|
-
return _this2.onWebCryptoError(data, key, iv);
|
12225
|
+
return _this2.onWebCryptoError(data, key, iv, aesMode);
|
12135
12226
|
});
|
12136
12227
|
};
|
12137
|
-
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
|
12138
|
-
|
12139
|
-
|
12140
|
-
|
12141
|
-
|
12142
|
-
|
12143
|
-
|
12228
|
+
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
|
12229
|
+
var enableSoftwareAES = this.enableSoftwareAES;
|
12230
|
+
if (enableSoftwareAES) {
|
12231
|
+
this.useSoftware = true;
|
12232
|
+
this.logEnabled = true;
|
12233
|
+
this.softwareDecrypt(data, key, iv, aesMode);
|
12234
|
+
var decryptResult = this.flush();
|
12235
|
+
if (decryptResult) {
|
12236
|
+
return decryptResult.buffer;
|
12237
|
+
}
|
12144
12238
|
}
|
12145
|
-
throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
|
12239
|
+
throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
|
12146
12240
|
};
|
12147
12241
|
_proto.getValidChunk = function getValidChunk(data) {
|
12148
12242
|
var currentChunk = data;
|
@@ -12196,7 +12290,7 @@
|
|
12196
12290
|
_inheritsLoose(BaseStreamController, _TaskLoop);
|
12197
12291
|
function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
|
12198
12292
|
var _this;
|
12199
|
-
_this = _TaskLoop.call(this) || this;
|
12293
|
+
_this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
|
12200
12294
|
_this.hls = void 0;
|
12201
12295
|
_this.fragPrevious = null;
|
12202
12296
|
_this.fragCurrent = null;
|
@@ -12221,29 +12315,100 @@
|
|
12221
12315
|
_this.startFragRequested = false;
|
12222
12316
|
_this.decrypter = void 0;
|
12223
12317
|
_this.initPTS = [];
|
12224
|
-
_this.
|
12225
|
-
_this.
|
12226
|
-
_this.
|
12227
|
-
|
12228
|
-
|
12318
|
+
_this.buffering = true;
|
12319
|
+
_this.loadingParts = false;
|
12320
|
+
_this.onMediaSeeking = function () {
|
12321
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
12322
|
+
config = _assertThisInitialize.config,
|
12323
|
+
fragCurrent = _assertThisInitialize.fragCurrent,
|
12324
|
+
media = _assertThisInitialize.media,
|
12325
|
+
mediaBuffer = _assertThisInitialize.mediaBuffer,
|
12326
|
+
state = _assertThisInitialize.state;
|
12327
|
+
var currentTime = media ? media.currentTime : 0;
|
12328
|
+
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12329
|
+
_this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12330
|
+
if (_this.state === State.ENDED) {
|
12331
|
+
_this.resetLoadingState();
|
12332
|
+
} else if (fragCurrent) {
|
12333
|
+
// Seeking while frag load is in progress
|
12334
|
+
var tolerance = config.maxFragLookUpTolerance;
|
12335
|
+
var fragStartOffset = fragCurrent.start - tolerance;
|
12336
|
+
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12337
|
+
// if seeking out of buffered range or into new one
|
12338
|
+
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12339
|
+
var pastFragment = currentTime > fragEndOffset;
|
12340
|
+
// if the seek position is outside the current fragment range
|
12341
|
+
if (currentTime < fragStartOffset || pastFragment) {
|
12342
|
+
if (pastFragment && fragCurrent.loader) {
|
12343
|
+
_this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12344
|
+
fragCurrent.abortRequests();
|
12345
|
+
_this.resetLoadingState();
|
12346
|
+
}
|
12347
|
+
_this.fragPrevious = null;
|
12348
|
+
}
|
12349
|
+
}
|
12350
|
+
}
|
12351
|
+
if (media) {
|
12352
|
+
// Remove gap fragments
|
12353
|
+
_this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
|
12354
|
+
_this.lastCurrentTime = currentTime;
|
12355
|
+
if (!_this.loadingParts) {
|
12356
|
+
var bufferEnd = Math.max(bufferInfo.end, currentTime);
|
12357
|
+
var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
|
12358
|
+
if (shouldLoadParts) {
|
12359
|
+
_this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
|
12360
|
+
_this.loadingParts = shouldLoadParts;
|
12361
|
+
}
|
12362
|
+
}
|
12363
|
+
}
|
12364
|
+
|
12365
|
+
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12366
|
+
if (!_this.loadedmetadata && !bufferInfo.len) {
|
12367
|
+
_this.nextLoadPosition = _this.startPosition = currentTime;
|
12368
|
+
}
|
12369
|
+
|
12370
|
+
// Async tick to speed up processing
|
12371
|
+
_this.tickImmediate();
|
12372
|
+
};
|
12373
|
+
_this.onMediaEnded = function () {
|
12374
|
+
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12375
|
+
_this.startPosition = _this.lastCurrentTime = 0;
|
12376
|
+
if (_this.playlistType === PlaylistLevelType.MAIN) {
|
12377
|
+
_this.hls.trigger(Events.MEDIA_ENDED, {
|
12378
|
+
stalled: false
|
12379
|
+
});
|
12380
|
+
}
|
12381
|
+
};
|
12229
12382
|
_this.playlistType = playlistType;
|
12230
|
-
_this.logPrefix = logPrefix;
|
12231
|
-
_this.log = logger.log.bind(logger, logPrefix + ":");
|
12232
|
-
_this.warn = logger.warn.bind(logger, logPrefix + ":");
|
12233
12383
|
_this.hls = hls;
|
12234
12384
|
_this.fragmentLoader = new FragmentLoader(hls.config);
|
12235
12385
|
_this.keyLoader = keyLoader;
|
12236
12386
|
_this.fragmentTracker = fragmentTracker;
|
12237
12387
|
_this.config = hls.config;
|
12238
12388
|
_this.decrypter = new Decrypter(hls.config);
|
12239
|
-
hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
|
12240
12389
|
return _this;
|
12241
12390
|
}
|
12242
12391
|
var _proto = BaseStreamController.prototype;
|
12243
|
-
_proto.
|
12244
|
-
this.
|
12245
|
-
|
12246
|
-
|
12392
|
+
_proto.registerListeners = function registerListeners() {
|
12393
|
+
var hls = this.hls;
|
12394
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12395
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12396
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12397
|
+
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12398
|
+
hls.on(Events.ERROR, this.onError, this);
|
12399
|
+
};
|
12400
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
12401
|
+
var hls = this.hls;
|
12402
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12403
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12404
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12405
|
+
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12406
|
+
hls.off(Events.ERROR, this.onError, this);
|
12407
|
+
};
|
12408
|
+
_proto.doTick = function doTick() {
|
12409
|
+
this.onTickEnd();
|
12410
|
+
};
|
12411
|
+
_proto.onTickEnd = function onTickEnd() {}
|
12247
12412
|
|
12248
12413
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
12249
12414
|
;
|
@@ -12263,6 +12428,12 @@
|
|
12263
12428
|
this.clearNextTick();
|
12264
12429
|
this.state = State.STOPPED;
|
12265
12430
|
};
|
12431
|
+
_proto.pauseBuffering = function pauseBuffering() {
|
12432
|
+
this.buffering = false;
|
12433
|
+
};
|
12434
|
+
_proto.resumeBuffering = function resumeBuffering() {
|
12435
|
+
this.buffering = true;
|
12436
|
+
};
|
12266
12437
|
_proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
|
12267
12438
|
// If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
|
12268
12439
|
// of nothing loading/loaded return false
|
@@ -12293,10 +12464,8 @@
|
|
12293
12464
|
};
|
12294
12465
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
12295
12466
|
var media = this.media = this.mediaBuffer = data.media;
|
12296
|
-
|
12297
|
-
|
12298
|
-
media.addEventListener('seeking', this.onvseeking);
|
12299
|
-
media.addEventListener('ended', this.onvended);
|
12467
|
+
media.addEventListener('seeking', this.onMediaSeeking);
|
12468
|
+
media.addEventListener('ended', this.onMediaEnded);
|
12300
12469
|
var config = this.config;
|
12301
12470
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
12302
12471
|
this.startLoad(config.startPosition);
|
@@ -12310,10 +12479,9 @@
|
|
12310
12479
|
}
|
12311
12480
|
|
12312
12481
|
// remove video listeners
|
12313
|
-
if (media
|
12314
|
-
media.removeEventListener('seeking', this.
|
12315
|
-
media.removeEventListener('ended', this.
|
12316
|
-
this.onvseeking = this.onvended = null;
|
12482
|
+
if (media) {
|
12483
|
+
media.removeEventListener('seeking', this.onMediaSeeking);
|
12484
|
+
media.removeEventListener('ended', this.onMediaEnded);
|
12317
12485
|
}
|
12318
12486
|
if (this.keyLoader) {
|
12319
12487
|
this.keyLoader.detach();
|
@@ -12323,54 +12491,8 @@
|
|
12323
12491
|
this.fragmentTracker.removeAllFragments();
|
12324
12492
|
this.stopLoad();
|
12325
12493
|
};
|
12326
|
-
_proto.
|
12327
|
-
|
12328
|
-
fragCurrent = this.fragCurrent,
|
12329
|
-
media = this.media,
|
12330
|
-
mediaBuffer = this.mediaBuffer,
|
12331
|
-
state = this.state;
|
12332
|
-
var currentTime = media ? media.currentTime : 0;
|
12333
|
-
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12334
|
-
this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12335
|
-
if (this.state === State.ENDED) {
|
12336
|
-
this.resetLoadingState();
|
12337
|
-
} else if (fragCurrent) {
|
12338
|
-
// Seeking while frag load is in progress
|
12339
|
-
var tolerance = config.maxFragLookUpTolerance;
|
12340
|
-
var fragStartOffset = fragCurrent.start - tolerance;
|
12341
|
-
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12342
|
-
// if seeking out of buffered range or into new one
|
12343
|
-
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12344
|
-
var pastFragment = currentTime > fragEndOffset;
|
12345
|
-
// if the seek position is outside the current fragment range
|
12346
|
-
if (currentTime < fragStartOffset || pastFragment) {
|
12347
|
-
if (pastFragment && fragCurrent.loader) {
|
12348
|
-
this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12349
|
-
fragCurrent.abortRequests();
|
12350
|
-
this.resetLoadingState();
|
12351
|
-
}
|
12352
|
-
this.fragPrevious = null;
|
12353
|
-
}
|
12354
|
-
}
|
12355
|
-
}
|
12356
|
-
if (media) {
|
12357
|
-
// Remove gap fragments
|
12358
|
-
this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
|
12359
|
-
this.lastCurrentTime = currentTime;
|
12360
|
-
}
|
12361
|
-
|
12362
|
-
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12363
|
-
if (!this.loadedmetadata && !bufferInfo.len) {
|
12364
|
-
this.nextLoadPosition = this.startPosition = currentTime;
|
12365
|
-
}
|
12366
|
-
|
12367
|
-
// Async tick to speed up processing
|
12368
|
-
this.tickImmediate();
|
12369
|
-
};
|
12370
|
-
_proto.onMediaEnded = function onMediaEnded() {
|
12371
|
-
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12372
|
-
this.startPosition = this.lastCurrentTime = 0;
|
12373
|
-
};
|
12494
|
+
_proto.onManifestLoading = function onManifestLoading() {};
|
12495
|
+
_proto.onError = function onError(event, data) {};
|
12374
12496
|
_proto.onManifestLoaded = function onManifestLoaded(event, data) {
|
12375
12497
|
this.startTimeOffset = data.startTimeOffset;
|
12376
12498
|
this.initPTS = [];
|
@@ -12380,7 +12502,7 @@
|
|
12380
12502
|
this.stopLoad();
|
12381
12503
|
_TaskLoop.prototype.onHandlerDestroying.call(this);
|
12382
12504
|
// @ts-ignore
|
12383
|
-
this.hls = null;
|
12505
|
+
this.hls = this.onMediaSeeking = this.onMediaEnded = null;
|
12384
12506
|
};
|
12385
12507
|
_proto.onHandlerDestroyed = function onHandlerDestroyed() {
|
12386
12508
|
this.state = State.STOPPED;
|
@@ -12510,10 +12632,10 @@
|
|
12510
12632
|
var decryptData = frag.decryptdata;
|
12511
12633
|
|
12512
12634
|
// check to see if the payload needs to be decrypted
|
12513
|
-
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method
|
12635
|
+
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
|
12514
12636
|
var startTime = self.performance.now();
|
12515
12637
|
// decrypt init segment data
|
12516
|
-
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
|
12638
|
+
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
|
12517
12639
|
hls.trigger(Events.ERROR, {
|
12518
12640
|
type: ErrorTypes.MEDIA_ERROR,
|
12519
12641
|
details: ErrorDetails.FRAG_DECRYPT_ERROR,
|
@@ -12626,7 +12748,7 @@
|
|
12626
12748
|
}
|
12627
12749
|
var keyLoadingPromise = null;
|
12628
12750
|
if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
|
12629
|
-
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.
|
12751
|
+
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
|
12630
12752
|
this.state = State.KEY_LOADING;
|
12631
12753
|
this.fragCurrent = frag;
|
12632
12754
|
keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
|
@@ -12647,8 +12769,16 @@
|
|
12647
12769
|
} else if (!frag.encrypted && details.encryptedFragments.length) {
|
12648
12770
|
this.keyLoader.loadClear(frag, details.encryptedFragments);
|
12649
12771
|
}
|
12772
|
+
var fragPrevious = this.fragPrevious;
|
12773
|
+
if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
|
12774
|
+
var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
|
12775
|
+
if (shouldLoadParts !== this.loadingParts) {
|
12776
|
+
this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
|
12777
|
+
this.loadingParts = shouldLoadParts;
|
12778
|
+
}
|
12779
|
+
}
|
12650
12780
|
targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
|
12651
|
-
if (this.
|
12781
|
+
if (this.loadingParts && frag.sn !== 'initSegment') {
|
12652
12782
|
var partList = details.partList;
|
12653
12783
|
if (partList && progressCallback) {
|
12654
12784
|
if (targetBufferTime > frag.end && details.fragmentHint) {
|
@@ -12657,7 +12787,7 @@
|
|
12657
12787
|
var partIndex = this.getNextPart(partList, frag, targetBufferTime);
|
12658
12788
|
if (partIndex > -1) {
|
12659
12789
|
var part = partList[partIndex];
|
12660
|
-
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.
|
12790
|
+
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)));
|
12661
12791
|
this.nextLoadPosition = part.start + part.duration;
|
12662
12792
|
this.state = State.FRAG_LOADING;
|
12663
12793
|
var _result;
|
@@ -12690,7 +12820,14 @@
|
|
12690
12820
|
}
|
12691
12821
|
}
|
12692
12822
|
}
|
12693
|
-
|
12823
|
+
if (frag.sn !== 'initSegment' && this.loadingParts) {
|
12824
|
+
this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
|
12825
|
+
this.loadingParts = false;
|
12826
|
+
} else if (!frag.url) {
|
12827
|
+
// Selected fragment hint for part but not loading parts
|
12828
|
+
return Promise.resolve(null);
|
12829
|
+
}
|
12830
|
+
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)));
|
12694
12831
|
// Don't update nextLoadPosition for fragments which are not buffered
|
12695
12832
|
if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
|
12696
12833
|
this.nextLoadPosition = frag.start + frag.duration;
|
@@ -12792,8 +12929,36 @@
|
|
12792
12929
|
if (part) {
|
12793
12930
|
part.stats.parsing.end = now;
|
12794
12931
|
}
|
12932
|
+
// See if part loading should be disabled/enabled based on buffer and playback position.
|
12933
|
+
if (frag.sn !== 'initSegment') {
|
12934
|
+
var levelDetails = this.getLevelDetails();
|
12935
|
+
var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
|
12936
|
+
var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
|
12937
|
+
if (shouldLoadParts !== this.loadingParts) {
|
12938
|
+
this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
|
12939
|
+
this.loadingParts = shouldLoadParts;
|
12940
|
+
}
|
12941
|
+
}
|
12795
12942
|
this.updateLevelTiming(frag, part, level, chunkMeta.partial);
|
12796
12943
|
};
|
12944
|
+
_proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
|
12945
|
+
if (this.config.lowLatencyMode) {
|
12946
|
+
if (!details) {
|
12947
|
+
return this.loadingParts;
|
12948
|
+
}
|
12949
|
+
if (details != null && details.partList) {
|
12950
|
+
var _details$fragmentHint;
|
12951
|
+
// Buffer must be ahead of first part + duration of parts after last segment
|
12952
|
+
// and playback must be at or past segment adjacent to part list
|
12953
|
+
var firstPart = details.partList[0];
|
12954
|
+
var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
|
12955
|
+
if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
|
12956
|
+
return true;
|
12957
|
+
}
|
12958
|
+
}
|
12959
|
+
}
|
12960
|
+
return false;
|
12961
|
+
};
|
12797
12962
|
_proto.getCurrentContext = function getCurrentContext(chunkMeta) {
|
12798
12963
|
var levels = this.levels,
|
12799
12964
|
fragCurrent = this.fragCurrent;
|
@@ -12928,7 +13093,8 @@
|
|
12928
13093
|
// find fragment index, contiguous with end of buffer position
|
12929
13094
|
var config = this.config;
|
12930
13095
|
var start = fragments[0].start;
|
12931
|
-
var
|
13096
|
+
var canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
|
13097
|
+
var frag = null;
|
12932
13098
|
if (levelDetails.live) {
|
12933
13099
|
var initialLiveManifestSize = config.initialLiveManifestSize;
|
12934
13100
|
if (fragLen < initialLiveManifestSize) {
|
@@ -12940,6 +13106,10 @@
|
|
12940
13106
|
// Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
|
12941
13107
|
// we get the fragment matching that start time
|
12942
13108
|
if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
|
13109
|
+
if (canLoadParts && !this.loadingParts) {
|
13110
|
+
this.log("LL-Part loading ON for initial live fragment");
|
13111
|
+
this.loadingParts = true;
|
13112
|
+
}
|
12943
13113
|
frag = this.getInitialLiveFragment(levelDetails, fragments);
|
12944
13114
|
this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
|
12945
13115
|
}
|
@@ -12950,7 +13120,7 @@
|
|
12950
13120
|
|
12951
13121
|
// If we haven't run into any special cases already, just load the fragment most closely matching the requested position
|
12952
13122
|
if (!frag) {
|
12953
|
-
var end =
|
13123
|
+
var end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
|
12954
13124
|
frag = this.getFragmentAtPosition(pos, end, levelDetails);
|
12955
13125
|
}
|
12956
13126
|
return this.mapToInitFragWhenRequired(frag);
|
@@ -13064,7 +13234,7 @@
|
|
13064
13234
|
var fragmentHint = levelDetails.fragmentHint;
|
13065
13235
|
var tolerance = config.maxFragLookUpTolerance;
|
13066
13236
|
var partList = levelDetails.partList;
|
13067
|
-
var loadingParts = !!(
|
13237
|
+
var loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
|
13068
13238
|
if (loadingParts && fragmentHint && !this.bitrateTest) {
|
13069
13239
|
// Include incomplete fragment with parts at end
|
13070
13240
|
fragments = fragments.concat(fragmentHint);
|
@@ -13251,7 +13421,7 @@
|
|
13251
13421
|
errorAction.resolved = true;
|
13252
13422
|
}
|
13253
13423
|
} else {
|
13254
|
-
|
13424
|
+
this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
|
13255
13425
|
return;
|
13256
13426
|
}
|
13257
13427
|
} else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
@@ -13641,6 +13811,7 @@
|
|
13641
13811
|
*/
|
13642
13812
|
function getAudioConfig(observer, data, offset, audioCodec) {
|
13643
13813
|
var adtsObjectType;
|
13814
|
+
var originalAdtsObjectType;
|
13644
13815
|
var adtsExtensionSamplingIndex;
|
13645
13816
|
var adtsChannelConfig;
|
13646
13817
|
var config;
|
@@ -13648,7 +13819,7 @@
|
|
13648
13819
|
var manifestCodec = audioCodec;
|
13649
13820
|
var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
13650
13821
|
// byte 2
|
13651
|
-
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13822
|
+
adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13652
13823
|
var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
13653
13824
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
13654
13825
|
var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
|
@@ -13665,8 +13836,8 @@
|
|
13665
13836
|
// byte 3
|
13666
13837
|
adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
|
13667
13838
|
logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
|
13668
|
-
//
|
13669
|
-
if (/firefox/i.test(userAgent)) {
|
13839
|
+
// Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
|
13840
|
+
if (/firefox|palemoon/i.test(userAgent)) {
|
13670
13841
|
if (adtsSamplingIndex >= 6) {
|
13671
13842
|
adtsObjectType = 5;
|
13672
13843
|
config = new Array(4);
|
@@ -13760,6 +13931,7 @@
|
|
13760
13931
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
13761
13932
|
channelCount: adtsChannelConfig,
|
13762
13933
|
codec: 'mp4a.40.' + adtsObjectType,
|
13934
|
+
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
13763
13935
|
manifestCodec: manifestCodec
|
13764
13936
|
};
|
13765
13937
|
}
|
@@ -13814,7 +13986,8 @@
|
|
13814
13986
|
track.channelCount = config.channelCount;
|
13815
13987
|
track.codec = config.codec;
|
13816
13988
|
track.manifestCodec = config.manifestCodec;
|
13817
|
-
|
13989
|
+
track.parsedCodec = config.parsedCodec;
|
13990
|
+
logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
|
13818
13991
|
}
|
13819
13992
|
}
|
13820
13993
|
function getFrameDuration(samplerate) {
|
@@ -14294,6 +14467,110 @@
|
|
14294
14467
|
logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
|
14295
14468
|
}
|
14296
14469
|
};
|
14470
|
+
_proto.parseNALu = function parseNALu(track, array) {
|
14471
|
+
var len = array.byteLength;
|
14472
|
+
var state = track.naluState || 0;
|
14473
|
+
var lastState = state;
|
14474
|
+
var units = [];
|
14475
|
+
var i = 0;
|
14476
|
+
var value;
|
14477
|
+
var overflow;
|
14478
|
+
var unitType;
|
14479
|
+
var lastUnitStart = -1;
|
14480
|
+
var lastUnitType = 0;
|
14481
|
+
// logger.log('PES:' + Hex.hexDump(array));
|
14482
|
+
|
14483
|
+
if (state === -1) {
|
14484
|
+
// special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
|
14485
|
+
lastUnitStart = 0;
|
14486
|
+
// NALu type is value read from offset 0
|
14487
|
+
lastUnitType = this.getNALuType(array, 0);
|
14488
|
+
state = 0;
|
14489
|
+
i = 1;
|
14490
|
+
}
|
14491
|
+
while (i < len) {
|
14492
|
+
value = array[i++];
|
14493
|
+
// optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
|
14494
|
+
if (!state) {
|
14495
|
+
state = value ? 0 : 1;
|
14496
|
+
continue;
|
14497
|
+
}
|
14498
|
+
if (state === 1) {
|
14499
|
+
state = value ? 0 : 2;
|
14500
|
+
continue;
|
14501
|
+
}
|
14502
|
+
// here we have state either equal to 2 or 3
|
14503
|
+
if (!value) {
|
14504
|
+
state = 3;
|
14505
|
+
} else if (value === 1) {
|
14506
|
+
overflow = i - state - 1;
|
14507
|
+
if (lastUnitStart >= 0) {
|
14508
|
+
var unit = {
|
14509
|
+
data: array.subarray(lastUnitStart, overflow),
|
14510
|
+
type: lastUnitType
|
14511
|
+
};
|
14512
|
+
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14513
|
+
units.push(unit);
|
14514
|
+
} else {
|
14515
|
+
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14516
|
+
// first check if start code delimiter is overlapping between 2 PES packets,
|
14517
|
+
// ie it started in last packet (lastState not zero)
|
14518
|
+
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14519
|
+
var lastUnit = this.getLastNalUnit(track.samples);
|
14520
|
+
if (lastUnit) {
|
14521
|
+
if (lastState && i <= 4 - lastState) {
|
14522
|
+
// start delimiter overlapping between PES packets
|
14523
|
+
// strip start delimiter bytes from the end of last NAL unit
|
14524
|
+
// check if lastUnit had a state different from zero
|
14525
|
+
if (lastUnit.state) {
|
14526
|
+
// strip last bytes
|
14527
|
+
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14528
|
+
}
|
14529
|
+
}
|
14530
|
+
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14531
|
+
|
14532
|
+
if (overflow > 0) {
|
14533
|
+
// logger.log('first NALU found with overflow:' + overflow);
|
14534
|
+
lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
|
14535
|
+
lastUnit.state = 0;
|
14536
|
+
}
|
14537
|
+
}
|
14538
|
+
}
|
14539
|
+
// check if we can read unit type
|
14540
|
+
if (i < len) {
|
14541
|
+
unitType = this.getNALuType(array, i);
|
14542
|
+
// logger.log('find NALU @ offset:' + i + ',type:' + unitType);
|
14543
|
+
lastUnitStart = i;
|
14544
|
+
lastUnitType = unitType;
|
14545
|
+
state = 0;
|
14546
|
+
} else {
|
14547
|
+
// not enough byte to read unit type. let's read it on next PES parsing
|
14548
|
+
state = -1;
|
14549
|
+
}
|
14550
|
+
} else {
|
14551
|
+
state = 0;
|
14552
|
+
}
|
14553
|
+
}
|
14554
|
+
if (lastUnitStart >= 0 && state >= 0) {
|
14555
|
+
var _unit = {
|
14556
|
+
data: array.subarray(lastUnitStart, len),
|
14557
|
+
type: lastUnitType,
|
14558
|
+
state: state
|
14559
|
+
};
|
14560
|
+
units.push(_unit);
|
14561
|
+
// logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
|
14562
|
+
}
|
14563
|
+
// no NALu found
|
14564
|
+
if (units.length === 0) {
|
14565
|
+
// append pes.data to previous NAL unit
|
14566
|
+
var _lastUnit = this.getLastNalUnit(track.samples);
|
14567
|
+
if (_lastUnit) {
|
14568
|
+
_lastUnit.data = appendUint8Array(_lastUnit.data, array);
|
14569
|
+
}
|
14570
|
+
}
|
14571
|
+
track.naluState = state;
|
14572
|
+
return units;
|
14573
|
+
};
|
14297
14574
|
return BaseVideoParser;
|
14298
14575
|
}();
|
14299
14576
|
|
@@ -14448,189 +14725,6 @@
|
|
14448
14725
|
;
|
14449
14726
|
_proto.readUInt = function readUInt() {
|
14450
14727
|
return this.readBits(32);
|
14451
|
-
}
|
14452
|
-
|
14453
|
-
/**
|
14454
|
-
* Advance the ExpGolomb decoder past a scaling list. The scaling
|
14455
|
-
* list is optionally transmitted as part of a sequence parameter
|
14456
|
-
* set and is not relevant to transmuxing.
|
14457
|
-
* @param count the number of entries in this scaling list
|
14458
|
-
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14459
|
-
*/;
|
14460
|
-
_proto.skipScalingList = function skipScalingList(count) {
|
14461
|
-
var lastScale = 8;
|
14462
|
-
var nextScale = 8;
|
14463
|
-
var deltaScale;
|
14464
|
-
for (var j = 0; j < count; j++) {
|
14465
|
-
if (nextScale !== 0) {
|
14466
|
-
deltaScale = this.readEG();
|
14467
|
-
nextScale = (lastScale + deltaScale + 256) % 256;
|
14468
|
-
}
|
14469
|
-
lastScale = nextScale === 0 ? lastScale : nextScale;
|
14470
|
-
}
|
14471
|
-
}
|
14472
|
-
|
14473
|
-
/**
|
14474
|
-
* Read a sequence parameter set and return some interesting video
|
14475
|
-
* properties. A sequence parameter set is the H264 metadata that
|
14476
|
-
* describes the properties of upcoming video frames.
|
14477
|
-
* @returns an object with configuration parsed from the
|
14478
|
-
* sequence parameter set, including the dimensions of the
|
14479
|
-
* associated video frames.
|
14480
|
-
*/;
|
14481
|
-
_proto.readSPS = function readSPS() {
|
14482
|
-
var frameCropLeftOffset = 0;
|
14483
|
-
var frameCropRightOffset = 0;
|
14484
|
-
var frameCropTopOffset = 0;
|
14485
|
-
var frameCropBottomOffset = 0;
|
14486
|
-
var numRefFramesInPicOrderCntCycle;
|
14487
|
-
var scalingListCount;
|
14488
|
-
var i;
|
14489
|
-
var readUByte = this.readUByte.bind(this);
|
14490
|
-
var readBits = this.readBits.bind(this);
|
14491
|
-
var readUEG = this.readUEG.bind(this);
|
14492
|
-
var readBoolean = this.readBoolean.bind(this);
|
14493
|
-
var skipBits = this.skipBits.bind(this);
|
14494
|
-
var skipEG = this.skipEG.bind(this);
|
14495
|
-
var skipUEG = this.skipUEG.bind(this);
|
14496
|
-
var skipScalingList = this.skipScalingList.bind(this);
|
14497
|
-
readUByte();
|
14498
|
-
var profileIdc = readUByte(); // profile_idc
|
14499
|
-
readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
|
14500
|
-
skipBits(3); // reserved_zero_3bits u(3),
|
14501
|
-
readUByte(); // level_idc u(8)
|
14502
|
-
skipUEG(); // seq_parameter_set_id
|
14503
|
-
// some profiles have more optional data we don't need
|
14504
|
-
if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
|
14505
|
-
var chromaFormatIdc = readUEG();
|
14506
|
-
if (chromaFormatIdc === 3) {
|
14507
|
-
skipBits(1);
|
14508
|
-
} // separate_colour_plane_flag
|
14509
|
-
|
14510
|
-
skipUEG(); // bit_depth_luma_minus8
|
14511
|
-
skipUEG(); // bit_depth_chroma_minus8
|
14512
|
-
skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
14513
|
-
if (readBoolean()) {
|
14514
|
-
// seq_scaling_matrix_present_flag
|
14515
|
-
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
|
14516
|
-
for (i = 0; i < scalingListCount; i++) {
|
14517
|
-
if (readBoolean()) {
|
14518
|
-
// seq_scaling_list_present_flag[ i ]
|
14519
|
-
if (i < 6) {
|
14520
|
-
skipScalingList(16);
|
14521
|
-
} else {
|
14522
|
-
skipScalingList(64);
|
14523
|
-
}
|
14524
|
-
}
|
14525
|
-
}
|
14526
|
-
}
|
14527
|
-
}
|
14528
|
-
skipUEG(); // log2_max_frame_num_minus4
|
14529
|
-
var picOrderCntType = readUEG();
|
14530
|
-
if (picOrderCntType === 0) {
|
14531
|
-
readUEG(); // log2_max_pic_order_cnt_lsb_minus4
|
14532
|
-
} else if (picOrderCntType === 1) {
|
14533
|
-
skipBits(1); // delta_pic_order_always_zero_flag
|
14534
|
-
skipEG(); // offset_for_non_ref_pic
|
14535
|
-
skipEG(); // offset_for_top_to_bottom_field
|
14536
|
-
numRefFramesInPicOrderCntCycle = readUEG();
|
14537
|
-
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
14538
|
-
skipEG();
|
14539
|
-
} // offset_for_ref_frame[ i ]
|
14540
|
-
}
|
14541
|
-
skipUEG(); // max_num_ref_frames
|
14542
|
-
skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
14543
|
-
var picWidthInMbsMinus1 = readUEG();
|
14544
|
-
var picHeightInMapUnitsMinus1 = readUEG();
|
14545
|
-
var frameMbsOnlyFlag = readBits(1);
|
14546
|
-
if (frameMbsOnlyFlag === 0) {
|
14547
|
-
skipBits(1);
|
14548
|
-
} // mb_adaptive_frame_field_flag
|
14549
|
-
|
14550
|
-
skipBits(1); // direct_8x8_inference_flag
|
14551
|
-
if (readBoolean()) {
|
14552
|
-
// frame_cropping_flag
|
14553
|
-
frameCropLeftOffset = readUEG();
|
14554
|
-
frameCropRightOffset = readUEG();
|
14555
|
-
frameCropTopOffset = readUEG();
|
14556
|
-
frameCropBottomOffset = readUEG();
|
14557
|
-
}
|
14558
|
-
var pixelRatio = [1, 1];
|
14559
|
-
if (readBoolean()) {
|
14560
|
-
// vui_parameters_present_flag
|
14561
|
-
if (readBoolean()) {
|
14562
|
-
// aspect_ratio_info_present_flag
|
14563
|
-
var aspectRatioIdc = readUByte();
|
14564
|
-
switch (aspectRatioIdc) {
|
14565
|
-
case 1:
|
14566
|
-
pixelRatio = [1, 1];
|
14567
|
-
break;
|
14568
|
-
case 2:
|
14569
|
-
pixelRatio = [12, 11];
|
14570
|
-
break;
|
14571
|
-
case 3:
|
14572
|
-
pixelRatio = [10, 11];
|
14573
|
-
break;
|
14574
|
-
case 4:
|
14575
|
-
pixelRatio = [16, 11];
|
14576
|
-
break;
|
14577
|
-
case 5:
|
14578
|
-
pixelRatio = [40, 33];
|
14579
|
-
break;
|
14580
|
-
case 6:
|
14581
|
-
pixelRatio = [24, 11];
|
14582
|
-
break;
|
14583
|
-
case 7:
|
14584
|
-
pixelRatio = [20, 11];
|
14585
|
-
break;
|
14586
|
-
case 8:
|
14587
|
-
pixelRatio = [32, 11];
|
14588
|
-
break;
|
14589
|
-
case 9:
|
14590
|
-
pixelRatio = [80, 33];
|
14591
|
-
break;
|
14592
|
-
case 10:
|
14593
|
-
pixelRatio = [18, 11];
|
14594
|
-
break;
|
14595
|
-
case 11:
|
14596
|
-
pixelRatio = [15, 11];
|
14597
|
-
break;
|
14598
|
-
case 12:
|
14599
|
-
pixelRatio = [64, 33];
|
14600
|
-
break;
|
14601
|
-
case 13:
|
14602
|
-
pixelRatio = [160, 99];
|
14603
|
-
break;
|
14604
|
-
case 14:
|
14605
|
-
pixelRatio = [4, 3];
|
14606
|
-
break;
|
14607
|
-
case 15:
|
14608
|
-
pixelRatio = [3, 2];
|
14609
|
-
break;
|
14610
|
-
case 16:
|
14611
|
-
pixelRatio = [2, 1];
|
14612
|
-
break;
|
14613
|
-
case 255:
|
14614
|
-
{
|
14615
|
-
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
|
14616
|
-
break;
|
14617
|
-
}
|
14618
|
-
}
|
14619
|
-
}
|
14620
|
-
}
|
14621
|
-
return {
|
14622
|
-
width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
|
14623
|
-
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
|
14624
|
-
pixelRatio: pixelRatio
|
14625
|
-
};
|
14626
|
-
};
|
14627
|
-
_proto.readSliceType = function readSliceType() {
|
14628
|
-
// skip NALu type
|
14629
|
-
this.readUByte();
|
14630
|
-
// discard first_mb_in_slice
|
14631
|
-
this.readUEG();
|
14632
|
-
// return slice_type
|
14633
|
-
return this.readUEG();
|
14634
14728
|
};
|
14635
14729
|
return ExpGolomb;
|
14636
14730
|
}();
|
@@ -14641,9 +14735,9 @@
|
|
14641
14735
|
return _BaseVideoParser.apply(this, arguments) || this;
|
14642
14736
|
}
|
14643
14737
|
var _proto = AvcVideoParser.prototype;
|
14644
|
-
_proto.
|
14738
|
+
_proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
|
14645
14739
|
var _this = this;
|
14646
|
-
var units = this.
|
14740
|
+
var units = this.parseNALu(track, pes.data);
|
14647
14741
|
var VideoSample = this.VideoSample;
|
14648
14742
|
var push;
|
14649
14743
|
var spsfound = false;
|
@@ -14668,7 +14762,7 @@
|
|
14668
14762
|
// only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
|
14669
14763
|
if (spsfound && data.length > 4) {
|
14670
14764
|
// retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
|
14671
|
-
var sliceType =
|
14765
|
+
var sliceType = _this.readSliceType(data);
|
14672
14766
|
// 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
|
14673
14767
|
// SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
|
14674
14768
|
// An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
|
@@ -14722,8 +14816,7 @@
|
|
14722
14816
|
push = true;
|
14723
14817
|
spsfound = true;
|
14724
14818
|
var sps = unit.data;
|
14725
|
-
var
|
14726
|
-
var config = expGolombDecoder.readSPS();
|
14819
|
+
var config = _this.readSPS(sps);
|
14727
14820
|
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]) {
|
14728
14821
|
track.width = config.width;
|
14729
14822
|
track.height = config.height;
|
@@ -14779,109 +14872,192 @@
|
|
14779
14872
|
this.VideoSample = null;
|
14780
14873
|
}
|
14781
14874
|
};
|
14782
|
-
_proto.
|
14783
|
-
|
14784
|
-
|
14785
|
-
|
14786
|
-
var
|
14787
|
-
|
14788
|
-
|
14789
|
-
|
14790
|
-
|
14791
|
-
|
14792
|
-
|
14793
|
-
|
14875
|
+
_proto.getNALuType = function getNALuType(data, offset) {
|
14876
|
+
return data[offset] & 0x1f;
|
14877
|
+
};
|
14878
|
+
_proto.readSliceType = function readSliceType(data) {
|
14879
|
+
var eg = new ExpGolomb(data);
|
14880
|
+
// skip NALu type
|
14881
|
+
eg.readUByte();
|
14882
|
+
// discard first_mb_in_slice
|
14883
|
+
eg.readUEG();
|
14884
|
+
// return slice_type
|
14885
|
+
return eg.readUEG();
|
14886
|
+
}
|
14794
14887
|
|
14795
|
-
|
14796
|
-
|
14797
|
-
|
14798
|
-
|
14799
|
-
|
14800
|
-
|
14801
|
-
|
14802
|
-
|
14803
|
-
|
14804
|
-
|
14805
|
-
|
14806
|
-
if (
|
14807
|
-
|
14808
|
-
|
14809
|
-
}
|
14810
|
-
if (state === 1) {
|
14811
|
-
state = value ? 0 : 2;
|
14812
|
-
continue;
|
14888
|
+
/**
|
14889
|
+
* The scaling list is optionally transmitted as part of a sequence parameter
|
14890
|
+
* set and is not relevant to transmuxing.
|
14891
|
+
* @param count the number of entries in this scaling list
|
14892
|
+
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14893
|
+
*/;
|
14894
|
+
_proto.skipScalingList = function skipScalingList(count, reader) {
|
14895
|
+
var lastScale = 8;
|
14896
|
+
var nextScale = 8;
|
14897
|
+
var deltaScale;
|
14898
|
+
for (var j = 0; j < count; j++) {
|
14899
|
+
if (nextScale !== 0) {
|
14900
|
+
deltaScale = reader.readEG();
|
14901
|
+
nextScale = (lastScale + deltaScale + 256) % 256;
|
14813
14902
|
}
|
14814
|
-
|
14815
|
-
|
14816
|
-
|
14817
|
-
} else if (value === 1) {
|
14818
|
-
overflow = i - state - 1;
|
14819
|
-
if (lastUnitStart >= 0) {
|
14820
|
-
var unit = {
|
14821
|
-
data: array.subarray(lastUnitStart, overflow),
|
14822
|
-
type: lastUnitType
|
14823
|
-
};
|
14824
|
-
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14825
|
-
units.push(unit);
|
14826
|
-
} else {
|
14827
|
-
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14828
|
-
// first check if start code delimiter is overlapping between 2 PES packets,
|
14829
|
-
// ie it started in last packet (lastState not zero)
|
14830
|
-
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14831
|
-
var lastUnit = this.getLastNalUnit(track.samples);
|
14832
|
-
if (lastUnit) {
|
14833
|
-
if (lastState && i <= 4 - lastState) {
|
14834
|
-
// start delimiter overlapping between PES packets
|
14835
|
-
// strip start delimiter bytes from the end of last NAL unit
|
14836
|
-
// check if lastUnit had a state different from zero
|
14837
|
-
if (lastUnit.state) {
|
14838
|
-
// strip last bytes
|
14839
|
-
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14840
|
-
}
|
14841
|
-
}
|
14842
|
-
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14903
|
+
lastScale = nextScale === 0 ? lastScale : nextScale;
|
14904
|
+
}
|
14905
|
+
}
|
14843
14906
|
|
14844
|
-
|
14845
|
-
|
14846
|
-
|
14847
|
-
|
14848
|
-
|
14849
|
-
|
14850
|
-
|
14851
|
-
|
14852
|
-
|
14853
|
-
|
14854
|
-
|
14855
|
-
|
14856
|
-
|
14857
|
-
|
14858
|
-
|
14859
|
-
|
14860
|
-
|
14907
|
+
/**
|
14908
|
+
* Read a sequence parameter set and return some interesting video
|
14909
|
+
* properties. A sequence parameter set is the H264 metadata that
|
14910
|
+
* describes the properties of upcoming video frames.
|
14911
|
+
* @returns an object with configuration parsed from the
|
14912
|
+
* sequence parameter set, including the dimensions of the
|
14913
|
+
* associated video frames.
|
14914
|
+
*/;
|
14915
|
+
_proto.readSPS = function readSPS(sps) {
|
14916
|
+
var eg = new ExpGolomb(sps);
|
14917
|
+
var frameCropLeftOffset = 0;
|
14918
|
+
var frameCropRightOffset = 0;
|
14919
|
+
var frameCropTopOffset = 0;
|
14920
|
+
var frameCropBottomOffset = 0;
|
14921
|
+
var numRefFramesInPicOrderCntCycle;
|
14922
|
+
var scalingListCount;
|
14923
|
+
var i;
|
14924
|
+
var readUByte = eg.readUByte.bind(eg);
|
14925
|
+
var readBits = eg.readBits.bind(eg);
|
14926
|
+
var readUEG = eg.readUEG.bind(eg);
|
14927
|
+
var readBoolean = eg.readBoolean.bind(eg);
|
14928
|
+
var skipBits = eg.skipBits.bind(eg);
|
14929
|
+
var skipEG = eg.skipEG.bind(eg);
|
14930
|
+
var skipUEG = eg.skipUEG.bind(eg);
|
14931
|
+
var skipScalingList = this.skipScalingList.bind(this);
|
14932
|
+
readUByte();
|
14933
|
+
var profileIdc = readUByte(); // profile_idc
|
14934
|
+
readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
|
14935
|
+
skipBits(3); // reserved_zero_3bits u(3),
|
14936
|
+
readUByte(); // level_idc u(8)
|
14937
|
+
skipUEG(); // seq_parameter_set_id
|
14938
|
+
// some profiles have more optional data we don't need
|
14939
|
+
if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
|
14940
|
+
var chromaFormatIdc = readUEG();
|
14941
|
+
if (chromaFormatIdc === 3) {
|
14942
|
+
skipBits(1);
|
14943
|
+
} // separate_colour_plane_flag
|
14944
|
+
|
14945
|
+
skipUEG(); // bit_depth_luma_minus8
|
14946
|
+
skipUEG(); // bit_depth_chroma_minus8
|
14947
|
+
skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
14948
|
+
if (readBoolean()) {
|
14949
|
+
// seq_scaling_matrix_present_flag
|
14950
|
+
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
|
14951
|
+
for (i = 0; i < scalingListCount; i++) {
|
14952
|
+
if (readBoolean()) {
|
14953
|
+
// seq_scaling_list_present_flag[ i ]
|
14954
|
+
if (i < 6) {
|
14955
|
+
skipScalingList(16, eg);
|
14956
|
+
} else {
|
14957
|
+
skipScalingList(64, eg);
|
14958
|
+
}
|
14959
|
+
}
|
14861
14960
|
}
|
14862
|
-
} else {
|
14863
|
-
state = 0;
|
14864
14961
|
}
|
14865
14962
|
}
|
14866
|
-
|
14867
|
-
|
14868
|
-
|
14869
|
-
|
14870
|
-
|
14871
|
-
|
14872
|
-
|
14873
|
-
|
14963
|
+
skipUEG(); // log2_max_frame_num_minus4
|
14964
|
+
var picOrderCntType = readUEG();
|
14965
|
+
if (picOrderCntType === 0) {
|
14966
|
+
readUEG(); // log2_max_pic_order_cnt_lsb_minus4
|
14967
|
+
} else if (picOrderCntType === 1) {
|
14968
|
+
skipBits(1); // delta_pic_order_always_zero_flag
|
14969
|
+
skipEG(); // offset_for_non_ref_pic
|
14970
|
+
skipEG(); // offset_for_top_to_bottom_field
|
14971
|
+
numRefFramesInPicOrderCntCycle = readUEG();
|
14972
|
+
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
14973
|
+
skipEG();
|
14974
|
+
} // offset_for_ref_frame[ i ]
|
14874
14975
|
}
|
14875
|
-
//
|
14876
|
-
|
14877
|
-
|
14878
|
-
|
14879
|
-
|
14880
|
-
|
14976
|
+
skipUEG(); // max_num_ref_frames
|
14977
|
+
skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
14978
|
+
var picWidthInMbsMinus1 = readUEG();
|
14979
|
+
var picHeightInMapUnitsMinus1 = readUEG();
|
14980
|
+
var frameMbsOnlyFlag = readBits(1);
|
14981
|
+
if (frameMbsOnlyFlag === 0) {
|
14982
|
+
skipBits(1);
|
14983
|
+
} // mb_adaptive_frame_field_flag
|
14984
|
+
|
14985
|
+
skipBits(1); // direct_8x8_inference_flag
|
14986
|
+
if (readBoolean()) {
|
14987
|
+
// frame_cropping_flag
|
14988
|
+
frameCropLeftOffset = readUEG();
|
14989
|
+
frameCropRightOffset = readUEG();
|
14990
|
+
frameCropTopOffset = readUEG();
|
14991
|
+
frameCropBottomOffset = readUEG();
|
14992
|
+
}
|
14993
|
+
var pixelRatio = [1, 1];
|
14994
|
+
if (readBoolean()) {
|
14995
|
+
// vui_parameters_present_flag
|
14996
|
+
if (readBoolean()) {
|
14997
|
+
// aspect_ratio_info_present_flag
|
14998
|
+
var aspectRatioIdc = readUByte();
|
14999
|
+
switch (aspectRatioIdc) {
|
15000
|
+
case 1:
|
15001
|
+
pixelRatio = [1, 1];
|
15002
|
+
break;
|
15003
|
+
case 2:
|
15004
|
+
pixelRatio = [12, 11];
|
15005
|
+
break;
|
15006
|
+
case 3:
|
15007
|
+
pixelRatio = [10, 11];
|
15008
|
+
break;
|
15009
|
+
case 4:
|
15010
|
+
pixelRatio = [16, 11];
|
15011
|
+
break;
|
15012
|
+
case 5:
|
15013
|
+
pixelRatio = [40, 33];
|
15014
|
+
break;
|
15015
|
+
case 6:
|
15016
|
+
pixelRatio = [24, 11];
|
15017
|
+
break;
|
15018
|
+
case 7:
|
15019
|
+
pixelRatio = [20, 11];
|
15020
|
+
break;
|
15021
|
+
case 8:
|
15022
|
+
pixelRatio = [32, 11];
|
15023
|
+
break;
|
15024
|
+
case 9:
|
15025
|
+
pixelRatio = [80, 33];
|
15026
|
+
break;
|
15027
|
+
case 10:
|
15028
|
+
pixelRatio = [18, 11];
|
15029
|
+
break;
|
15030
|
+
case 11:
|
15031
|
+
pixelRatio = [15, 11];
|
15032
|
+
break;
|
15033
|
+
case 12:
|
15034
|
+
pixelRatio = [64, 33];
|
15035
|
+
break;
|
15036
|
+
case 13:
|
15037
|
+
pixelRatio = [160, 99];
|
15038
|
+
break;
|
15039
|
+
case 14:
|
15040
|
+
pixelRatio = [4, 3];
|
15041
|
+
break;
|
15042
|
+
case 15:
|
15043
|
+
pixelRatio = [3, 2];
|
15044
|
+
break;
|
15045
|
+
case 16:
|
15046
|
+
pixelRatio = [2, 1];
|
15047
|
+
break;
|
15048
|
+
case 255:
|
15049
|
+
{
|
15050
|
+
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
|
15051
|
+
break;
|
15052
|
+
}
|
15053
|
+
}
|
14881
15054
|
}
|
14882
15055
|
}
|
14883
|
-
|
14884
|
-
|
15056
|
+
return {
|
15057
|
+
width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
|
15058
|
+
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
|
15059
|
+
pixelRatio: pixelRatio
|
15060
|
+
};
|
14885
15061
|
};
|
14886
15062
|
return AvcVideoParser;
|
14887
15063
|
}(BaseVideoParser);
|
@@ -14901,7 +15077,7 @@
|
|
14901
15077
|
}
|
14902
15078
|
var _proto = SampleAesDecrypter.prototype;
|
14903
15079
|
_proto.decryptBuffer = function decryptBuffer(encryptedData) {
|
14904
|
-
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
|
15080
|
+
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
|
14905
15081
|
}
|
14906
15082
|
|
14907
15083
|
// AAC - encrypt all full 16 bytes blocks starting from offset 16
|
@@ -15020,7 +15196,7 @@
|
|
15020
15196
|
this.observer = observer;
|
15021
15197
|
this.config = config;
|
15022
15198
|
this.typeSupported = typeSupported;
|
15023
|
-
this.videoParser =
|
15199
|
+
this.videoParser = null;
|
15024
15200
|
}
|
15025
15201
|
TSDemuxer.probe = function probe(data) {
|
15026
15202
|
var syncOffset = TSDemuxer.syncOffset(data);
|
@@ -15190,7 +15366,16 @@
|
|
15190
15366
|
case videoPid:
|
15191
15367
|
if (stt) {
|
15192
15368
|
if (videoData && (pes = parsePES(videoData))) {
|
15193
|
-
this.videoParser
|
15369
|
+
if (this.videoParser === null) {
|
15370
|
+
switch (videoTrack.segmentCodec) {
|
15371
|
+
case 'avc':
|
15372
|
+
this.videoParser = new AvcVideoParser();
|
15373
|
+
break;
|
15374
|
+
}
|
15375
|
+
}
|
15376
|
+
if (this.videoParser !== null) {
|
15377
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
|
15378
|
+
}
|
15194
15379
|
}
|
15195
15380
|
videoData = {
|
15196
15381
|
data: [],
|
@@ -15348,8 +15533,17 @@
|
|
15348
15533
|
// try to parse last PES packets
|
15349
15534
|
var pes;
|
15350
15535
|
if (videoData && (pes = parsePES(videoData))) {
|
15351
|
-
this.videoParser
|
15352
|
-
|
15536
|
+
if (this.videoParser === null) {
|
15537
|
+
switch (videoTrack.segmentCodec) {
|
15538
|
+
case 'avc':
|
15539
|
+
this.videoParser = new AvcVideoParser();
|
15540
|
+
break;
|
15541
|
+
}
|
15542
|
+
}
|
15543
|
+
if (this.videoParser !== null) {
|
15544
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
|
15545
|
+
videoTrack.pesData = null;
|
15546
|
+
}
|
15353
15547
|
} else {
|
15354
15548
|
// either avcData null or PES truncated, keep it for next frag parsing
|
15355
15549
|
videoTrack.pesData = videoData;
|
@@ -15651,7 +15845,10 @@
|
|
15651
15845
|
logger.warn('Unsupported EC-3 in M2TS found');
|
15652
15846
|
break;
|
15653
15847
|
case 0x24:
|
15654
|
-
|
15848
|
+
// ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
|
15849
|
+
{
|
15850
|
+
logger.warn('Unsupported HEVC in M2TS found');
|
15851
|
+
}
|
15655
15852
|
break;
|
15656
15853
|
}
|
15657
15854
|
// move to the next table entry
|
@@ -15879,6 +16076,8 @@
|
|
15879
16076
|
avc1: [],
|
15880
16077
|
// codingname
|
15881
16078
|
avcC: [],
|
16079
|
+
hvc1: [],
|
16080
|
+
hvcC: [],
|
15882
16081
|
btrt: [],
|
15883
16082
|
dinf: [],
|
15884
16083
|
dref: [],
|
@@ -16306,8 +16505,10 @@
|
|
16306
16505
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
|
16307
16506
|
}
|
16308
16507
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
|
16309
|
-
} else {
|
16508
|
+
} else if (track.segmentCodec === 'avc') {
|
16310
16509
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
|
16510
|
+
} else {
|
16511
|
+
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
|
16311
16512
|
}
|
16312
16513
|
};
|
16313
16514
|
MP4.tkhd = function tkhd(track) {
|
@@ -16445,6 +16646,84 @@
|
|
16445
16646
|
var result = appendUint8Array(MP4.FTYP, movie);
|
16446
16647
|
return result;
|
16447
16648
|
};
|
16649
|
+
MP4.hvc1 = function hvc1(track) {
|
16650
|
+
var ps = track.params;
|
16651
|
+
var units = [track.vps, track.sps, track.pps];
|
16652
|
+
var NALuLengthSize = 4;
|
16653
|
+
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]);
|
16654
|
+
|
16655
|
+
// compute hvcC size in bytes
|
16656
|
+
var length = config.length;
|
16657
|
+
for (var i = 0; i < units.length; i += 1) {
|
16658
|
+
length += 3;
|
16659
|
+
for (var j = 0; j < units[i].length; j += 1) {
|
16660
|
+
length += 2 + units[i][j].length;
|
16661
|
+
}
|
16662
|
+
}
|
16663
|
+
var hvcC = new Uint8Array(length);
|
16664
|
+
hvcC.set(config, 0);
|
16665
|
+
length = config.length;
|
16666
|
+
// append parameter set units: one vps, one or more sps and pps
|
16667
|
+
var iMax = units.length - 1;
|
16668
|
+
for (var _i = 0; _i < units.length; _i += 1) {
|
16669
|
+
hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
|
16670
|
+
length += 3;
|
16671
|
+
for (var _j = 0; _j < units[_i].length; _j += 1) {
|
16672
|
+
hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
|
16673
|
+
length += 2;
|
16674
|
+
hvcC.set(units[_i][_j], length);
|
16675
|
+
length += units[_i][_j].length;
|
16676
|
+
}
|
16677
|
+
}
|
16678
|
+
var hvcc = MP4.box(MP4.types.hvcC, hvcC);
|
16679
|
+
var width = track.width;
|
16680
|
+
var height = track.height;
|
16681
|
+
var hSpacing = track.pixelRatio[0];
|
16682
|
+
var vSpacing = track.pixelRatio[1];
|
16683
|
+
return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
|
16684
|
+
// reserved
|
16685
|
+
0x00, 0x00, 0x00,
|
16686
|
+
// reserved
|
16687
|
+
0x00, 0x01,
|
16688
|
+
// data_reference_index
|
16689
|
+
0x00, 0x00,
|
16690
|
+
// pre_defined
|
16691
|
+
0x00, 0x00,
|
16692
|
+
// reserved
|
16693
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
16694
|
+
// pre_defined
|
16695
|
+
width >> 8 & 0xff, width & 0xff,
|
16696
|
+
// width
|
16697
|
+
height >> 8 & 0xff, height & 0xff,
|
16698
|
+
// height
|
16699
|
+
0x00, 0x48, 0x00, 0x00,
|
16700
|
+
// horizresolution
|
16701
|
+
0x00, 0x48, 0x00, 0x00,
|
16702
|
+
// vertresolution
|
16703
|
+
0x00, 0x00, 0x00, 0x00,
|
16704
|
+
// reserved
|
16705
|
+
0x00, 0x01,
|
16706
|
+
// frame_count
|
16707
|
+
0x12, 0x64, 0x61, 0x69, 0x6c,
|
16708
|
+
// dailymotion/hls.js
|
16709
|
+
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,
|
16710
|
+
// compressorname
|
16711
|
+
0x00, 0x18,
|
16712
|
+
// depth = 24
|
16713
|
+
0x11, 0x11]),
|
16714
|
+
// pre_defined = -1
|
16715
|
+
hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
|
16716
|
+
// bufferSizeDB
|
16717
|
+
0x00, 0x2d, 0xc6, 0xc0,
|
16718
|
+
// maxBitrate
|
16719
|
+
0x00, 0x2d, 0xc6, 0xc0])),
|
16720
|
+
// avgBitrate
|
16721
|
+
MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
|
16722
|
+
// hSpacing
|
16723
|
+
hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
|
16724
|
+
// vSpacing
|
16725
|
+
vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
|
16726
|
+
};
|
16448
16727
|
return MP4;
|
16449
16728
|
}();
|
16450
16729
|
MP4.types = void 0;
|
@@ -16831,9 +17110,9 @@
|
|
16831
17110
|
var foundOverlap = delta < -1;
|
16832
17111
|
if (foundHole || foundOverlap) {
|
16833
17112
|
if (foundHole) {
|
16834
|
-
logger.warn("
|
17113
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
|
16835
17114
|
} else {
|
16836
|
-
logger.warn("
|
17115
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
|
16837
17116
|
}
|
16838
17117
|
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
|
16839
17118
|
firstDTS = nextAvcDts;
|
@@ -16842,12 +17121,24 @@
|
|
16842
17121
|
inputSamples[0].dts = firstDTS;
|
16843
17122
|
inputSamples[0].pts = firstPTS;
|
16844
17123
|
} else {
|
17124
|
+
var isPTSOrderRetained = true;
|
16845
17125
|
for (var _i = 0; _i < inputSamples.length; _i++) {
|
16846
|
-
if (inputSamples[_i].dts > firstPTS) {
|
17126
|
+
if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
|
16847
17127
|
break;
|
16848
17128
|
}
|
17129
|
+
var prevPTS = inputSamples[_i].pts;
|
16849
17130
|
inputSamples[_i].dts -= delta;
|
16850
17131
|
inputSamples[_i].pts -= delta;
|
17132
|
+
|
17133
|
+
// check to see if this sample's PTS order has changed
|
17134
|
+
// relative to the next one
|
17135
|
+
if (_i < inputSamples.length - 1) {
|
17136
|
+
var nextSamplePTS = inputSamples[_i + 1].pts;
|
17137
|
+
var currentSamplePTS = inputSamples[_i].pts;
|
17138
|
+
var currentOrder = nextSamplePTS <= currentSamplePTS;
|
17139
|
+
var prevOrder = nextSamplePTS <= prevPTS;
|
17140
|
+
isPTSOrderRetained = currentOrder == prevOrder;
|
17141
|
+
}
|
16851
17142
|
}
|
16852
17143
|
}
|
16853
17144
|
logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
|
@@ -16995,7 +17286,7 @@
|
|
16995
17286
|
}
|
16996
17287
|
}
|
16997
17288
|
}
|
16998
|
-
// next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
17289
|
+
// next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
16999
17290
|
mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
|
17000
17291
|
this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
|
17001
17292
|
this.videoSampleDuration = mp4SampleDuration;
|
@@ -17130,7 +17421,7 @@
|
|
17130
17421
|
logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
|
17131
17422
|
for (var j = 0; j < missing; j++) {
|
17132
17423
|
var newStamp = Math.max(nextPts, 0);
|
17133
|
-
var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17424
|
+
var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17134
17425
|
if (!fillFrame) {
|
17135
17426
|
logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
17136
17427
|
fillFrame = sample.unit.subarray();
|
@@ -17258,7 +17549,7 @@
|
|
17258
17549
|
// samples count of this segment's duration
|
17259
17550
|
var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
|
17260
17551
|
// silent frame
|
17261
|
-
var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17552
|
+
var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17262
17553
|
logger.warn('[mp4-remuxer]: remux empty Audio');
|
17263
17554
|
// Can't remux if we can't generate a silent frame...
|
17264
17555
|
if (!silentFrame) {
|
@@ -17645,13 +17936,15 @@
|
|
17645
17936
|
duration = transmuxConfig.duration,
|
17646
17937
|
initSegmentData = transmuxConfig.initSegmentData;
|
17647
17938
|
var keyData = getEncryptionType(uintData, decryptdata);
|
17648
|
-
if (keyData && keyData.method
|
17939
|
+
if (keyData && isFullSegmentEncryption(keyData.method)) {
|
17649
17940
|
var decrypter = this.getDecrypter();
|
17941
|
+
var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
17942
|
+
|
17650
17943
|
// Software decryption is synchronous; webCrypto is not
|
17651
17944
|
if (decrypter.isSync()) {
|
17652
17945
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
17653
17946
|
// data is handled in the flush() call
|
17654
|
-
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
|
17947
|
+
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
|
17655
17948
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
17656
17949
|
var loadingParts = chunkMeta.part > -1;
|
17657
17950
|
if (loadingParts) {
|
@@ -17663,7 +17956,7 @@
|
|
17663
17956
|
}
|
17664
17957
|
uintData = new Uint8Array(decryptedData);
|
17665
17958
|
} else {
|
17666
|
-
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
|
17959
|
+
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
|
17667
17960
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
17668
17961
|
// the decrypted data has been transmuxed
|
17669
17962
|
var result = _this.push(decryptedData, null, chunkMeta);
|
@@ -18284,7 +18577,7 @@
|
|
18284
18577
|
observer.on(Events.ERROR, forwardMessage);
|
18285
18578
|
|
18286
18579
|
// forward logger events to main thread
|
18287
|
-
var forwardWorkerLogs = function forwardWorkerLogs() {
|
18580
|
+
var forwardWorkerLogs = function forwardWorkerLogs(logger) {
|
18288
18581
|
var _loop = function _loop(logFn) {
|
18289
18582
|
var func = function func(message) {
|
18290
18583
|
forwardMessage('workerLog', {
|
@@ -18305,8 +18598,8 @@
|
|
18305
18598
|
{
|
18306
18599
|
var config = JSON.parse(data.config);
|
18307
18600
|
self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
|
18308
|
-
enableLogs(config.debug, data.id);
|
18309
|
-
forwardWorkerLogs();
|
18601
|
+
var logger = enableLogs(config.debug, data.id);
|
18602
|
+
forwardWorkerLogs(logger);
|
18310
18603
|
forwardMessage('init', null);
|
18311
18604
|
break;
|
18312
18605
|
}
|
@@ -18480,16 +18773,7 @@
|
|
18480
18773
|
this.observer = new EventEmitter();
|
18481
18774
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
18482
18775
|
this.observer.on(Events.ERROR, forwardMessage);
|
18483
|
-
var
|
18484
|
-
isTypeSupported: function isTypeSupported() {
|
18485
|
-
return false;
|
18486
|
-
}
|
18487
|
-
};
|
18488
|
-
var m2tsTypeSupported = {
|
18489
|
-
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
18490
|
-
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
18491
|
-
ac3: false
|
18492
|
-
};
|
18776
|
+
var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
|
18493
18777
|
|
18494
18778
|
// navigator.vendor is not always available in Web Worker
|
18495
18779
|
// refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
|
@@ -18746,21 +19030,26 @@
|
|
18746
19030
|
var MAX_START_GAP_JUMP = 2.0;
|
18747
19031
|
var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
18748
19032
|
var SKIP_BUFFER_RANGE_START = 0.05;
|
18749
|
-
var GapController = /*#__PURE__*/function () {
|
19033
|
+
var GapController = /*#__PURE__*/function (_Logger) {
|
19034
|
+
_inheritsLoose(GapController, _Logger);
|
18750
19035
|
function GapController(config, media, fragmentTracker, hls) {
|
18751
|
-
|
18752
|
-
this.
|
18753
|
-
|
18754
|
-
|
18755
|
-
|
18756
|
-
|
18757
|
-
|
18758
|
-
|
18759
|
-
|
18760
|
-
|
18761
|
-
|
18762
|
-
|
18763
|
-
|
19036
|
+
var _this;
|
19037
|
+
_this = _Logger.call(this, 'gap-controller', hls.logger) || this;
|
19038
|
+
_this.config = void 0;
|
19039
|
+
_this.media = null;
|
19040
|
+
_this.fragmentTracker = void 0;
|
19041
|
+
_this.hls = void 0;
|
19042
|
+
_this.nudgeRetry = 0;
|
19043
|
+
_this.stallReported = false;
|
19044
|
+
_this.stalled = null;
|
19045
|
+
_this.moved = false;
|
19046
|
+
_this.seeking = false;
|
19047
|
+
_this.ended = 0;
|
19048
|
+
_this.config = config;
|
19049
|
+
_this.media = media;
|
19050
|
+
_this.fragmentTracker = fragmentTracker;
|
19051
|
+
_this.hls = hls;
|
19052
|
+
return _this;
|
18764
19053
|
}
|
18765
19054
|
var _proto = GapController.prototype;
|
18766
19055
|
_proto.destroy = function destroy() {
|
@@ -18775,7 +19064,7 @@
|
|
18775
19064
|
*
|
18776
19065
|
* @param lastCurrentTime - Previously read playhead position
|
18777
19066
|
*/;
|
18778
|
-
_proto.poll = function poll(lastCurrentTime, activeFrag) {
|
19067
|
+
_proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
|
18779
19068
|
var config = this.config,
|
18780
19069
|
media = this.media,
|
18781
19070
|
stalled = this.stalled;
|
@@ -18790,6 +19079,7 @@
|
|
18790
19079
|
|
18791
19080
|
// The playhead is moving, no-op
|
18792
19081
|
if (currentTime !== lastCurrentTime) {
|
19082
|
+
this.ended = 0;
|
18793
19083
|
this.moved = true;
|
18794
19084
|
if (!seeking) {
|
18795
19085
|
this.nudgeRetry = 0;
|
@@ -18798,7 +19088,7 @@
|
|
18798
19088
|
// The playhead is now moving, but was previously stalled
|
18799
19089
|
if (this.stallReported) {
|
18800
19090
|
var _stalledDuration = self.performance.now() - stalled;
|
18801
|
-
|
19091
|
+
this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
|
18802
19092
|
this.stallReported = false;
|
18803
19093
|
}
|
18804
19094
|
this.stalled = null;
|
@@ -18834,7 +19124,6 @@
|
|
18834
19124
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
18835
19125
|
// The addition poll gives the browser a chance to jump the gap for us
|
18836
19126
|
if (!this.moved && this.stalled !== null) {
|
18837
|
-
var _level$details;
|
18838
19127
|
// There is no playable buffer (seeked, waiting for buffer)
|
18839
19128
|
var isBuffered = bufferInfo.len > 0;
|
18840
19129
|
if (!isBuffered && !nextStart) {
|
@@ -18846,9 +19135,8 @@
|
|
18846
19135
|
// When joining a live stream with audio tracks, account for live playlist window sliding by allowing
|
18847
19136
|
// a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
|
18848
19137
|
// that begins over 1 target duration after the video start position.
|
18849
|
-
var
|
18850
|
-
var
|
18851
|
-
var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
|
19138
|
+
var isLive = !!(levelDetails != null && levelDetails.live);
|
19139
|
+
var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
|
18852
19140
|
var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
|
18853
19141
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
18854
19142
|
if (!media.paused) {
|
@@ -18866,6 +19154,17 @@
|
|
18866
19154
|
}
|
18867
19155
|
var stalledDuration = tnow - stalled;
|
18868
19156
|
if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
|
19157
|
+
// Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
|
19158
|
+
if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
|
19159
|
+
if (stalledDuration < 1000 || this.ended) {
|
19160
|
+
return;
|
19161
|
+
}
|
19162
|
+
this.ended = currentTime;
|
19163
|
+
this.hls.trigger(Events.MEDIA_ENDED, {
|
19164
|
+
stalled: true
|
19165
|
+
});
|
19166
|
+
return;
|
19167
|
+
}
|
18869
19168
|
// Report stalling after trying to fix
|
18870
19169
|
this._reportStall(bufferInfo);
|
18871
19170
|
if (!this.media) {
|
@@ -18907,7 +19206,7 @@
|
|
18907
19206
|
// needs to cross some sort of threshold covering all source-buffers content
|
18908
19207
|
// to start playing properly.
|
18909
19208
|
if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
18910
|
-
|
19209
|
+
this.warn('Trying to nudge playhead over buffer-hole');
|
18911
19210
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
18912
19211
|
// We only try to jump the hole if it's under the configured size
|
18913
19212
|
// Reset stalled so to rearm watchdog timer
|
@@ -18929,7 +19228,7 @@
|
|
18929
19228
|
// Report stalled error once
|
18930
19229
|
this.stallReported = true;
|
18931
19230
|
var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
|
18932
|
-
|
19231
|
+
this.warn(error.message);
|
18933
19232
|
hls.trigger(Events.ERROR, {
|
18934
19233
|
type: ErrorTypes.MEDIA_ERROR,
|
18935
19234
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -18993,7 +19292,7 @@
|
|
18993
19292
|
}
|
18994
19293
|
}
|
18995
19294
|
var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
18996
|
-
|
19295
|
+
this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
|
18997
19296
|
this.moved = true;
|
18998
19297
|
this.stalled = null;
|
18999
19298
|
media.currentTime = targetTime;
|
@@ -19032,7 +19331,7 @@
|
|
19032
19331
|
var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
|
19033
19332
|
// playback stalled in buffered area ... let's nudge currentTime to try to overcome this
|
19034
19333
|
var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
|
19035
|
-
|
19334
|
+
this.warn(error.message);
|
19036
19335
|
media.currentTime = targetTime;
|
19037
19336
|
hls.trigger(Events.ERROR, {
|
19038
19337
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -19042,7 +19341,7 @@
|
|
19042
19341
|
});
|
19043
19342
|
} else {
|
19044
19343
|
var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
|
19045
|
-
|
19344
|
+
this.error(_error.message);
|
19046
19345
|
hls.trigger(Events.ERROR, {
|
19047
19346
|
type: ErrorTypes.MEDIA_ERROR,
|
19048
19347
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -19052,14 +19351,14 @@
|
|
19052
19351
|
}
|
19053
19352
|
};
|
19054
19353
|
return GapController;
|
19055
|
-
}();
|
19354
|
+
}(Logger);
|
19056
19355
|
|
19057
19356
|
var TICK_INTERVAL = 100; // how often to tick in ms
|
19058
19357
|
var StreamController = /*#__PURE__*/function (_BaseStreamController) {
|
19059
19358
|
_inheritsLoose(StreamController, _BaseStreamController);
|
19060
19359
|
function StreamController(hls, fragmentTracker, keyLoader) {
|
19061
19360
|
var _this;
|
19062
|
-
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '
|
19361
|
+
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
|
19063
19362
|
_this.audioCodecSwap = false;
|
19064
19363
|
_this.gapController = null;
|
19065
19364
|
_this.level = -1;
|
@@ -19067,27 +19366,43 @@
|
|
19067
19366
|
_this.altAudio = false;
|
19068
19367
|
_this.audioOnly = false;
|
19069
19368
|
_this.fragPlaying = null;
|
19070
|
-
_this.onvplaying = null;
|
19071
|
-
_this.onvseeked = null;
|
19072
19369
|
_this.fragLastKbps = 0;
|
19073
19370
|
_this.couldBacktrack = false;
|
19074
19371
|
_this.backtrackFragment = null;
|
19075
19372
|
_this.audioCodecSwitch = false;
|
19076
19373
|
_this.videoBuffer = null;
|
19077
|
-
_this.
|
19374
|
+
_this.onMediaPlaying = function () {
|
19375
|
+
// tick to speed up FRAG_CHANGED triggering
|
19376
|
+
_this.tick();
|
19377
|
+
};
|
19378
|
+
_this.onMediaSeeked = function () {
|
19379
|
+
var media = _this.media;
|
19380
|
+
var currentTime = media ? media.currentTime : null;
|
19381
|
+
if (isFiniteNumber(currentTime)) {
|
19382
|
+
_this.log("Media seeked to " + currentTime.toFixed(3));
|
19383
|
+
}
|
19384
|
+
|
19385
|
+
// If seeked was issued before buffer was appended do not tick immediately
|
19386
|
+
var bufferInfo = _this.getMainFwdBufferInfo();
|
19387
|
+
if (bufferInfo === null || bufferInfo.len === 0) {
|
19388
|
+
_this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19389
|
+
return;
|
19390
|
+
}
|
19391
|
+
|
19392
|
+
// tick to speed up FRAG_CHANGED triggering
|
19393
|
+
_this.tick();
|
19394
|
+
};
|
19395
|
+
_this.registerListeners();
|
19078
19396
|
return _this;
|
19079
19397
|
}
|
19080
19398
|
var _proto = StreamController.prototype;
|
19081
|
-
_proto.
|
19399
|
+
_proto.registerListeners = function registerListeners() {
|
19400
|
+
_BaseStreamController.prototype.registerListeners.call(this);
|
19082
19401
|
var hls = this.hls;
|
19083
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19084
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19085
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19086
19402
|
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19087
19403
|
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
|
19088
19404
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19089
19405
|
hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19090
|
-
hls.on(Events.ERROR, this.onError, this);
|
19091
19406
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19092
19407
|
hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19093
19408
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19095,15 +19410,12 @@
|
|
19095
19410
|
hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
|
19096
19411
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19097
19412
|
};
|
19098
|
-
_proto.
|
19413
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
19414
|
+
_BaseStreamController.prototype.unregisterListeners.call(this);
|
19099
19415
|
var hls = this.hls;
|
19100
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19101
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19102
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19103
19416
|
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19104
19417
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19105
19418
|
hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19106
|
-
hls.off(Events.ERROR, this.onError, this);
|
19107
19419
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19108
19420
|
hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19109
19421
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19112,7 +19424,9 @@
|
|
19112
19424
|
hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19113
19425
|
};
|
19114
19426
|
_proto.onHandlerDestroying = function onHandlerDestroying() {
|
19115
|
-
|
19427
|
+
// @ts-ignore
|
19428
|
+
this.onMediaPlaying = this.onMediaSeeked = null;
|
19429
|
+
this.unregisterListeners();
|
19116
19430
|
_BaseStreamController.prototype.onHandlerDestroying.call(this);
|
19117
19431
|
};
|
19118
19432
|
_proto.startLoad = function startLoad(startPosition) {
|
@@ -19427,18 +19741,15 @@
|
|
19427
19741
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
19428
19742
|
_BaseStreamController.prototype.onMediaAttached.call(this, event, data);
|
19429
19743
|
var media = data.media;
|
19430
|
-
|
19431
|
-
|
19432
|
-
media.addEventListener('playing', this.onvplaying);
|
19433
|
-
media.addEventListener('seeked', this.onvseeked);
|
19744
|
+
media.addEventListener('playing', this.onMediaPlaying);
|
19745
|
+
media.addEventListener('seeked', this.onMediaSeeked);
|
19434
19746
|
this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
|
19435
19747
|
};
|
19436
19748
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
19437
19749
|
var media = this.media;
|
19438
|
-
if (media
|
19439
|
-
media.removeEventListener('playing', this.
|
19440
|
-
media.removeEventListener('seeked', this.
|
19441
|
-
this.onvplaying = this.onvseeked = null;
|
19750
|
+
if (media) {
|
19751
|
+
media.removeEventListener('playing', this.onMediaPlaying);
|
19752
|
+
media.removeEventListener('seeked', this.onMediaSeeked);
|
19442
19753
|
this.videoBuffer = null;
|
19443
19754
|
}
|
19444
19755
|
this.fragPlaying = null;
|
@@ -19448,27 +19759,6 @@
|
|
19448
19759
|
}
|
19449
19760
|
_BaseStreamController.prototype.onMediaDetaching.call(this);
|
19450
19761
|
};
|
19451
|
-
_proto.onMediaPlaying = function onMediaPlaying() {
|
19452
|
-
// tick to speed up FRAG_CHANGED triggering
|
19453
|
-
this.tick();
|
19454
|
-
};
|
19455
|
-
_proto.onMediaSeeked = function onMediaSeeked() {
|
19456
|
-
var media = this.media;
|
19457
|
-
var currentTime = media ? media.currentTime : null;
|
19458
|
-
if (isFiniteNumber(currentTime)) {
|
19459
|
-
this.log("Media seeked to " + currentTime.toFixed(3));
|
19460
|
-
}
|
19461
|
-
|
19462
|
-
// If seeked was issued before buffer was appended do not tick immediately
|
19463
|
-
var bufferInfo = this.getMainFwdBufferInfo();
|
19464
|
-
if (bufferInfo === null || bufferInfo.len === 0) {
|
19465
|
-
this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19466
|
-
return;
|
19467
|
-
}
|
19468
|
-
|
19469
|
-
// tick to speed up FRAG_CHANGED triggering
|
19470
|
-
this.tick();
|
19471
|
-
};
|
19472
19762
|
_proto.onManifestLoading = function onManifestLoading() {
|
19473
19763
|
// reset buffer on manifest loading
|
19474
19764
|
this.log('Trigger BUFFER_RESET');
|
@@ -19749,8 +20039,10 @@
|
|
19749
20039
|
}
|
19750
20040
|
if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
|
19751
20041
|
// Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
|
19752
|
-
var
|
19753
|
-
|
20042
|
+
var state = this.state;
|
20043
|
+
var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
|
20044
|
+
var levelDetails = this.getLevelDetails();
|
20045
|
+
gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
|
19754
20046
|
}
|
19755
20047
|
this.lastCurrentTime = media.currentTime;
|
19756
20048
|
};
|
@@ -20215,9 +20507,12 @@
|
|
20215
20507
|
* The configuration object provided on player instantiation.
|
20216
20508
|
*/
|
20217
20509
|
this.userConfig = void 0;
|
20510
|
+
/**
|
20511
|
+
* The logger functions used by this player instance, configured on player instantiation.
|
20512
|
+
*/
|
20513
|
+
this.logger = void 0;
|
20218
20514
|
this.coreComponents = void 0;
|
20219
20515
|
this.networkControllers = void 0;
|
20220
|
-
this.started = false;
|
20221
20516
|
this._emitter = new EventEmitter();
|
20222
20517
|
this._autoLevelCapping = -1;
|
20223
20518
|
this._maxHdcpLevel = null;
|
@@ -20234,11 +20529,11 @@
|
|
20234
20529
|
this._media = null;
|
20235
20530
|
this.url = null;
|
20236
20531
|
this.triggeringException = void 0;
|
20237
|
-
enableLogs(userConfig.debug || false, 'Hls instance');
|
20238
|
-
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
|
20532
|
+
var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
|
20533
|
+
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
|
20239
20534
|
this.userConfig = userConfig;
|
20240
20535
|
if (config.progressive) {
|
20241
|
-
enableStreamingMode(config);
|
20536
|
+
enableStreamingMode(config, logger);
|
20242
20537
|
}
|
20243
20538
|
|
20244
20539
|
// core controllers and network loaders
|
@@ -20346,7 +20641,7 @@
|
|
20346
20641
|
try {
|
20347
20642
|
return this.emit(event, event, eventObject);
|
20348
20643
|
} catch (error) {
|
20349
|
-
logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20644
|
+
this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20350
20645
|
// Prevent recursion in error event handlers that throw #5497
|
20351
20646
|
if (!this.triggeringException) {
|
20352
20647
|
this.triggeringException = true;
|
@@ -20372,7 +20667,7 @@
|
|
20372
20667
|
* Dispose of the instance
|
20373
20668
|
*/;
|
20374
20669
|
_proto.destroy = function destroy() {
|
20375
|
-
logger.log('destroy');
|
20670
|
+
this.logger.log('destroy');
|
20376
20671
|
this.trigger(Events.DESTROYING, undefined);
|
20377
20672
|
this.detachMedia();
|
20378
20673
|
this.removeAllListeners();
|
@@ -20397,7 +20692,7 @@
|
|
20397
20692
|
* Attaches Hls.js to a media element
|
20398
20693
|
*/;
|
20399
20694
|
_proto.attachMedia = function attachMedia(media) {
|
20400
|
-
logger.log('attachMedia');
|
20695
|
+
this.logger.log('attachMedia');
|
20401
20696
|
this._media = media;
|
20402
20697
|
this.trigger(Events.MEDIA_ATTACHING, {
|
20403
20698
|
media: media
|
@@ -20408,7 +20703,7 @@
|
|
20408
20703
|
* Detach Hls.js from the media
|
20409
20704
|
*/;
|
20410
20705
|
_proto.detachMedia = function detachMedia() {
|
20411
|
-
logger.log('detachMedia');
|
20706
|
+
this.logger.log('detachMedia');
|
20412
20707
|
this.trigger(Events.MEDIA_DETACHING, undefined);
|
20413
20708
|
this._media = null;
|
20414
20709
|
}
|
@@ -20425,7 +20720,7 @@
|
|
20425
20720
|
});
|
20426
20721
|
this._autoLevelCapping = -1;
|
20427
20722
|
this._maxHdcpLevel = null;
|
20428
|
-
logger.log("loadSource:" + loadingSource);
|
20723
|
+
this.logger.log("loadSource:" + loadingSource);
|
20429
20724
|
if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
|
20430
20725
|
this.detachMedia();
|
20431
20726
|
this.attachMedia(media);
|
@@ -20447,8 +20742,7 @@
|
|
20447
20742
|
if (startPosition === void 0) {
|
20448
20743
|
startPosition = -1;
|
20449
20744
|
}
|
20450
|
-
logger.log("startLoad(" + startPosition + ")");
|
20451
|
-
this.started = true;
|
20745
|
+
this.logger.log("startLoad(" + startPosition + ")");
|
20452
20746
|
this.networkControllers.forEach(function (controller) {
|
20453
20747
|
controller.startLoad(startPosition);
|
20454
20748
|
});
|
@@ -20458,34 +20752,31 @@
|
|
20458
20752
|
* Stop loading of any stream data.
|
20459
20753
|
*/;
|
20460
20754
|
_proto.stopLoad = function stopLoad() {
|
20461
|
-
logger.log('stopLoad');
|
20462
|
-
this.started = false;
|
20755
|
+
this.logger.log('stopLoad');
|
20463
20756
|
this.networkControllers.forEach(function (controller) {
|
20464
20757
|
controller.stopLoad();
|
20465
20758
|
});
|
20466
20759
|
}
|
20467
20760
|
|
20468
20761
|
/**
|
20469
|
-
* Resumes stream controller segment loading
|
20762
|
+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
|
20470
20763
|
*/;
|
20471
20764
|
_proto.resumeBuffering = function resumeBuffering() {
|
20472
|
-
|
20473
|
-
|
20474
|
-
|
20475
|
-
|
20476
|
-
|
20477
|
-
});
|
20478
|
-
}
|
20765
|
+
this.networkControllers.forEach(function (controller) {
|
20766
|
+
if (controller.resumeBuffering) {
|
20767
|
+
controller.resumeBuffering();
|
20768
|
+
}
|
20769
|
+
});
|
20479
20770
|
}
|
20480
20771
|
|
20481
20772
|
/**
|
20482
|
-
*
|
20773
|
+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
|
20483
20774
|
* This allows for media buffering to be paused without interupting playlist loading.
|
20484
20775
|
*/;
|
20485
20776
|
_proto.pauseBuffering = function pauseBuffering() {
|
20486
20777
|
this.networkControllers.forEach(function (controller) {
|
20487
|
-
if (
|
20488
|
-
controller.
|
20778
|
+
if (controller.pauseBuffering) {
|
20779
|
+
controller.pauseBuffering();
|
20489
20780
|
}
|
20490
20781
|
});
|
20491
20782
|
}
|
@@ -20494,7 +20785,7 @@
|
|
20494
20785
|
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
20495
20786
|
*/;
|
20496
20787
|
_proto.swapAudioCodec = function swapAudioCodec() {
|
20497
|
-
logger.log('swapAudioCodec');
|
20788
|
+
this.logger.log('swapAudioCodec');
|
20498
20789
|
this.streamController.swapAudioCodec();
|
20499
20790
|
}
|
20500
20791
|
|
@@ -20505,7 +20796,7 @@
|
|
20505
20796
|
* Automatic recovery of media-errors by this process is configurable.
|
20506
20797
|
*/;
|
20507
20798
|
_proto.recoverMediaError = function recoverMediaError() {
|
20508
|
-
logger.log('recoverMediaError');
|
20799
|
+
this.logger.log('recoverMediaError');
|
20509
20800
|
var media = this._media;
|
20510
20801
|
this.detachMedia();
|
20511
20802
|
if (media) {
|
@@ -20560,7 +20851,7 @@
|
|
20560
20851
|
* 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.
|
20561
20852
|
*/,
|
20562
20853
|
set: function set(newLevel) {
|
20563
|
-
logger.log("set currentLevel:" + newLevel);
|
20854
|
+
this.logger.log("set currentLevel:" + newLevel);
|
20564
20855
|
this.levelController.manualLevel = newLevel;
|
20565
20856
|
this.streamController.immediateLevelSwitch();
|
20566
20857
|
}
|
@@ -20581,7 +20872,7 @@
|
|
20581
20872
|
* @param newLevel - Pass -1 for automatic level selection
|
20582
20873
|
*/,
|
20583
20874
|
set: function set(newLevel) {
|
20584
|
-
logger.log("set nextLevel:" + newLevel);
|
20875
|
+
this.logger.log("set nextLevel:" + newLevel);
|
20585
20876
|
this.levelController.manualLevel = newLevel;
|
20586
20877
|
this.streamController.nextLevelSwitch();
|
20587
20878
|
}
|
@@ -20602,7 +20893,7 @@
|
|
20602
20893
|
* @param newLevel - Pass -1 for automatic level selection
|
20603
20894
|
*/,
|
20604
20895
|
set: function set(newLevel) {
|
20605
|
-
logger.log("set loadLevel:" + newLevel);
|
20896
|
+
this.logger.log("set loadLevel:" + newLevel);
|
20606
20897
|
this.levelController.manualLevel = newLevel;
|
20607
20898
|
}
|
20608
20899
|
|
@@ -20637,7 +20928,7 @@
|
|
20637
20928
|
* Sets "first-level", see getter.
|
20638
20929
|
*/,
|
20639
20930
|
set: function set(newLevel) {
|
20640
|
-
logger.log("set firstLevel:" + newLevel);
|
20931
|
+
this.logger.log("set firstLevel:" + newLevel);
|
20641
20932
|
this.levelController.firstLevel = newLevel;
|
20642
20933
|
}
|
20643
20934
|
|
@@ -20664,7 +20955,7 @@
|
|
20664
20955
|
* (determined from download of first segment)
|
20665
20956
|
*/,
|
20666
20957
|
set: function set(newLevel) {
|
20667
|
-
logger.log("set startLevel:" + newLevel);
|
20958
|
+
this.logger.log("set startLevel:" + newLevel);
|
20668
20959
|
// if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
|
20669
20960
|
if (newLevel !== -1) {
|
20670
20961
|
newLevel = Math.max(newLevel, this.minAutoLevel);
|
@@ -20717,7 +21008,7 @@
|
|
20717
21008
|
*/
|
20718
21009
|
function set(newLevel) {
|
20719
21010
|
if (this._autoLevelCapping !== newLevel) {
|
20720
|
-
logger.log("set autoLevelCapping:" + newLevel);
|
21011
|
+
this.logger.log("set autoLevelCapping:" + newLevel);
|
20721
21012
|
this._autoLevelCapping = newLevel;
|
20722
21013
|
this.levelController.checkMaxAutoUpdated();
|
20723
21014
|
}
|
@@ -21042,7 +21333,7 @@
|
|
21042
21333
|
* Get the video-dev/hls.js package version.
|
21043
21334
|
*/
|
21044
21335
|
function get() {
|
21045
|
-
return "1.5.
|
21336
|
+
return "1.5.7-0.canary.10015";
|
21046
21337
|
}
|
21047
21338
|
}, {
|
21048
21339
|
key: "Events",
|