hls.js 1.5.5 → 1.5.6-0.canary.10003
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 +2075 -1166
- package/dist/hls.js.d.ts +65 -50
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +1148 -859
- 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 +984 -696
- 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 +1757 -863
- 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 +20 -20
- 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 +25 -32
- package/src/controller/subtitle-stream-controller.ts +13 -14
- package/src/controller/subtitle-track-controller.ts +5 -3
- package/src/controller/timeline-controller.ts +23 -30
- package/src/crypt/aes-crypto.ts +21 -2
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +32 -18
- package/src/crypt/fast-aes-key.ts +24 -5
- package/src/demux/audio/adts.ts +9 -4
- package/src/demux/sample-aes.ts +2 -0
- package/src/demux/transmuxer-interface.ts +4 -12
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +16 -3
- package/src/demux/tsdemuxer.ts +71 -37
- package/src/demux/video/avc-video-parser.ts +208 -119
- package/src/demux/video/base-video-parser.ts +134 -2
- package/src/demux/video/exp-golomb.ts +0 -208
- package/src/demux/video/hevc-video-parser.ts +746 -0
- package/src/events.ts +7 -0
- package/src/hls.ts +42 -34
- package/src/loader/fragment-loader.ts +9 -2
- package/src/loader/key-loader.ts +2 -0
- package/src/loader/level-key.ts +10 -9
- package/src/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/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.5");
|
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.6-0.canary.10003");
|
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.
|
@@ -2626,13 +2652,13 @@
|
|
2626
2652
|
this.keyFormatVersions = formatversions;
|
2627
2653
|
this.iv = iv;
|
2628
2654
|
this.encrypted = method ? method !== 'NONE' : false;
|
2629
|
-
this.isCommonEncryption = this.encrypted && method
|
2655
|
+
this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
|
2630
2656
|
}
|
2631
2657
|
var _proto = LevelKey.prototype;
|
2632
2658
|
_proto.isSupported = function isSupported() {
|
2633
2659
|
// If it's Segment encryption or No encryption, just select that key system
|
2634
2660
|
if (this.method) {
|
2635
|
-
if (this.method
|
2661
|
+
if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
|
2636
2662
|
return true;
|
2637
2663
|
}
|
2638
2664
|
if (this.keyFormat === 'identity') {
|
@@ -2646,14 +2672,13 @@
|
|
2646
2672
|
if (!this.encrypted || !this.uri) {
|
2647
2673
|
return null;
|
2648
2674
|
}
|
2649
|
-
if (this.method
|
2675
|
+
if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
|
2650
2676
|
if (typeof sn !== 'number') {
|
2651
2677
|
// We are fetching decryption data for a initialization segment
|
2652
|
-
// If the segment was encrypted with AES-128
|
2678
|
+
// If the segment was encrypted with AES-128/256
|
2653
2679
|
// It must have an IV defined. We cannot substitute the Segment Number in.
|
2654
|
-
|
2655
|
-
|
2656
|
-
}
|
2680
|
+
logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
|
2681
|
+
|
2657
2682
|
// Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
|
2658
2683
|
sn = 0;
|
2659
2684
|
}
|
@@ -2815,23 +2840,28 @@
|
|
2815
2840
|
if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
|
2816
2841
|
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
|
2817
2842
|
}
|
2818
|
-
|
2819
|
-
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2820
|
-
// some browsers will report that fLaC is supported then fail.
|
2821
|
-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2822
2843
|
var codecsToCheck = {
|
2844
|
+
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2845
|
+
// some browsers will report that fLaC is supported then fail.
|
2846
|
+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2823
2847
|
flac: ['flac', 'fLaC', 'FLAC'],
|
2824
|
-
opus: ['opus', 'Opus']
|
2848
|
+
opus: ['opus', 'Opus'],
|
2849
|
+
// Replace audio codec info if browser does not support mp4a.40.34,
|
2850
|
+
// and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
|
2851
|
+
'mp4a.40.34': ['mp3']
|
2825
2852
|
}[lowerCaseCodec];
|
2826
2853
|
for (var i = 0; i < codecsToCheck.length; i++) {
|
2854
|
+
var _getMediaSource;
|
2827
2855
|
if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
|
2828
2856
|
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
|
2829
2857
|
return codecsToCheck[i];
|
2858
|
+
} else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
|
2859
|
+
return '';
|
2830
2860
|
}
|
2831
2861
|
}
|
2832
2862
|
return lowerCaseCodec;
|
2833
2863
|
}
|
2834
|
-
var AUDIO_CODEC_REGEXP = /flac|opus/i;
|
2864
|
+
var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
|
2835
2865
|
function getCodecCompatibleName(codec, preferManagedMediaSource) {
|
2836
2866
|
if (preferManagedMediaSource === void 0) {
|
2837
2867
|
preferManagedMediaSource = true;
|
@@ -2859,6 +2889,18 @@
|
|
2859
2889
|
}
|
2860
2890
|
return codec;
|
2861
2891
|
}
|
2892
|
+
function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
|
2893
|
+
var MediaSource = getMediaSource(preferManagedMediaSource) || {
|
2894
|
+
isTypeSupported: function isTypeSupported() {
|
2895
|
+
return false;
|
2896
|
+
}
|
2897
|
+
};
|
2898
|
+
return {
|
2899
|
+
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
2900
|
+
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
2901
|
+
ac3: false
|
2902
|
+
};
|
2903
|
+
}
|
2862
2904
|
|
2863
2905
|
var MASTER_PLAYLIST_REGEX = /#EXT-X-STREAM-INF:([^\r\n]*)(?:[\r\n](?:#[^\r\n]*)?)*([^\r\n]+)|#EXT-X-(SESSION-DATA|SESSION-KEY|DEFINE|CONTENT-STEERING|START):([^\r\n]*)[\r\n]+/g;
|
2864
2906
|
var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
|
@@ -3659,10 +3701,10 @@
|
|
3659
3701
|
var loaderContext = loader.context;
|
3660
3702
|
if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
|
3661
3703
|
// same URL can't overlap
|
3662
|
-
logger.trace('[playlist-loader]: playlist request ongoing');
|
3704
|
+
this.hls.logger.trace('[playlist-loader]: playlist request ongoing');
|
3663
3705
|
return;
|
3664
3706
|
}
|
3665
|
-
logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
|
3707
|
+
this.hls.logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
|
3666
3708
|
loader.abort();
|
3667
3709
|
}
|
3668
3710
|
|
@@ -3772,7 +3814,7 @@
|
|
3772
3814
|
// alt audio rendition in which quality levels (main)
|
3773
3815
|
// contains both audio+video. but with mixed audio track not signaled
|
3774
3816
|
if (!embeddedAudioFound && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
|
3775
|
-
logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
|
3817
|
+
this.hls.logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
|
3776
3818
|
audioTracks.unshift({
|
3777
3819
|
type: 'main',
|
3778
3820
|
name: 'main',
|
@@ -3872,7 +3914,7 @@
|
|
3872
3914
|
message += " id: " + context.id + " group-id: \"" + context.groupId + "\"";
|
3873
3915
|
}
|
3874
3916
|
var error = new Error(message);
|
3875
|
-
logger.warn("[playlist-loader]: " + message);
|
3917
|
+
this.hls.logger.warn("[playlist-loader]: " + message);
|
3876
3918
|
var details = ErrorDetails.UNKNOWN;
|
3877
3919
|
var fatal = false;
|
3878
3920
|
var loader = this.getInternalLoader(context);
|
@@ -4433,8 +4475,43 @@
|
|
4433
4475
|
this.currentTime = 0;
|
4434
4476
|
this.stallCount = 0;
|
4435
4477
|
this._latency = null;
|
4436
|
-
this.
|
4437
|
-
|
4478
|
+
this.onTimeupdate = function () {
|
4479
|
+
var media = _this.media,
|
4480
|
+
levelDetails = _this.levelDetails;
|
4481
|
+
if (!media || !levelDetails) {
|
4482
|
+
return;
|
4483
|
+
}
|
4484
|
+
_this.currentTime = media.currentTime;
|
4485
|
+
var latency = _this.computeLatency();
|
4486
|
+
if (latency === null) {
|
4487
|
+
return;
|
4488
|
+
}
|
4489
|
+
_this._latency = latency;
|
4490
|
+
|
4491
|
+
// Adapt playbackRate to meet target latency in low-latency mode
|
4492
|
+
var _this$config = _this.config,
|
4493
|
+
lowLatencyMode = _this$config.lowLatencyMode,
|
4494
|
+
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4495
|
+
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4496
|
+
return;
|
4497
|
+
}
|
4498
|
+
var targetLatency = _this.targetLatency;
|
4499
|
+
if (targetLatency === null) {
|
4500
|
+
return;
|
4501
|
+
}
|
4502
|
+
var distanceFromTarget = latency - targetLatency;
|
4503
|
+
// Only adjust playbackRate when within one target duration of targetLatency
|
4504
|
+
// and more than one second from under-buffering.
|
4505
|
+
// Playback further than one target duration from target can be considered DVR playback.
|
4506
|
+
var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
|
4507
|
+
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4508
|
+
if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
|
4509
|
+
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4510
|
+
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
|
4511
|
+
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4512
|
+
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4513
|
+
media.playbackRate = 1;
|
4514
|
+
}
|
4438
4515
|
};
|
4439
4516
|
this.hls = hls;
|
4440
4517
|
this.config = hls.config;
|
@@ -4446,7 +4523,7 @@
|
|
4446
4523
|
this.onMediaDetaching();
|
4447
4524
|
this.levelDetails = null;
|
4448
4525
|
// @ts-ignore
|
4449
|
-
this.hls =
|
4526
|
+
this.hls = null;
|
4450
4527
|
};
|
4451
4528
|
_proto.registerListeners = function registerListeners() {
|
4452
4529
|
this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
@@ -4464,11 +4541,11 @@
|
|
4464
4541
|
};
|
4465
4542
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
4466
4543
|
this.media = data.media;
|
4467
|
-
this.media.addEventListener('timeupdate', this.
|
4544
|
+
this.media.addEventListener('timeupdate', this.onTimeupdate);
|
4468
4545
|
};
|
4469
4546
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
4470
4547
|
if (this.media) {
|
4471
|
-
this.media.removeEventListener('timeupdate', this.
|
4548
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4472
4549
|
this.media = null;
|
4473
4550
|
}
|
4474
4551
|
};
|
@@ -4481,10 +4558,10 @@
|
|
4481
4558
|
var details = _ref.details;
|
4482
4559
|
this.levelDetails = details;
|
4483
4560
|
if (details.advanced) {
|
4484
|
-
this.
|
4561
|
+
this.onTimeupdate();
|
4485
4562
|
}
|
4486
4563
|
if (!details.live && this.media) {
|
4487
|
-
this.media.removeEventListener('timeupdate', this.
|
4564
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4488
4565
|
}
|
4489
4566
|
};
|
4490
4567
|
_proto.onError = function onError(event, data) {
|
@@ -4494,45 +4571,7 @@
|
|
4494
4571
|
}
|
4495
4572
|
this.stallCount++;
|
4496
4573
|
if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
|
4497
|
-
logger.warn('[
|
4498
|
-
}
|
4499
|
-
};
|
4500
|
-
_proto.timeupdate = function timeupdate() {
|
4501
|
-
var media = this.media,
|
4502
|
-
levelDetails = this.levelDetails;
|
4503
|
-
if (!media || !levelDetails) {
|
4504
|
-
return;
|
4505
|
-
}
|
4506
|
-
this.currentTime = media.currentTime;
|
4507
|
-
var latency = this.computeLatency();
|
4508
|
-
if (latency === null) {
|
4509
|
-
return;
|
4510
|
-
}
|
4511
|
-
this._latency = latency;
|
4512
|
-
|
4513
|
-
// Adapt playbackRate to meet target latency in low-latency mode
|
4514
|
-
var _this$config = this.config,
|
4515
|
-
lowLatencyMode = _this$config.lowLatencyMode,
|
4516
|
-
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4517
|
-
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4518
|
-
return;
|
4519
|
-
}
|
4520
|
-
var targetLatency = this.targetLatency;
|
4521
|
-
if (targetLatency === null) {
|
4522
|
-
return;
|
4523
|
-
}
|
4524
|
-
var distanceFromTarget = latency - targetLatency;
|
4525
|
-
// Only adjust playbackRate when within one target duration of targetLatency
|
4526
|
-
// and more than one second from under-buffering.
|
4527
|
-
// Playback further than one target duration from target can be considered DVR playback.
|
4528
|
-
var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
|
4529
|
-
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4530
|
-
if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
|
4531
|
-
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4532
|
-
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
|
4533
|
-
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4534
|
-
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4535
|
-
media.playbackRate = 1;
|
4574
|
+
this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
|
4536
4575
|
}
|
4537
4576
|
};
|
4538
4577
|
_proto.estimateLiveEdge = function estimateLiveEdge() {
|
@@ -5440,19 +5479,17 @@
|
|
5440
5479
|
MoveAllAlternatesMatchingHDCP: 2,
|
5441
5480
|
SwitchToSDR: 4
|
5442
5481
|
}; // Reserved for future use
|
5443
|
-
var ErrorController = /*#__PURE__*/function () {
|
5482
|
+
var ErrorController = /*#__PURE__*/function (_Logger) {
|
5483
|
+
_inheritsLoose(ErrorController, _Logger);
|
5444
5484
|
function ErrorController(hls) {
|
5445
|
-
|
5446
|
-
this.
|
5447
|
-
|
5448
|
-
|
5449
|
-
|
5450
|
-
|
5451
|
-
|
5452
|
-
|
5453
|
-
this.warn = logger.warn.bind(logger, "[warning]:");
|
5454
|
-
this.error = logger.error.bind(logger, "[error]:");
|
5455
|
-
this.registerListeners();
|
5485
|
+
var _this;
|
5486
|
+
_this = _Logger.call(this, 'error-controller', hls.logger) || this;
|
5487
|
+
_this.hls = void 0;
|
5488
|
+
_this.playlistError = 0;
|
5489
|
+
_this.penalizedRenditions = {};
|
5490
|
+
_this.hls = hls;
|
5491
|
+
_this.registerListeners();
|
5492
|
+
return _this;
|
5456
5493
|
}
|
5457
5494
|
var _proto = ErrorController.prototype;
|
5458
5495
|
_proto.registerListeners = function registerListeners() {
|
@@ -5808,19 +5845,19 @@
|
|
5808
5845
|
}
|
5809
5846
|
};
|
5810
5847
|
return ErrorController;
|
5811
|
-
}();
|
5848
|
+
}(Logger);
|
5812
5849
|
|
5813
|
-
var BasePlaylistController = /*#__PURE__*/function () {
|
5850
|
+
var BasePlaylistController = /*#__PURE__*/function (_Logger) {
|
5851
|
+
_inheritsLoose(BasePlaylistController, _Logger);
|
5814
5852
|
function BasePlaylistController(hls, logPrefix) {
|
5815
|
-
|
5816
|
-
this.
|
5817
|
-
|
5818
|
-
|
5819
|
-
|
5820
|
-
|
5821
|
-
|
5822
|
-
|
5823
|
-
this.hls = hls;
|
5853
|
+
var _this;
|
5854
|
+
_this = _Logger.call(this, logPrefix, hls.logger) || this;
|
5855
|
+
_this.hls = void 0;
|
5856
|
+
_this.timer = -1;
|
5857
|
+
_this.requestScheduled = -1;
|
5858
|
+
_this.canLoad = false;
|
5859
|
+
_this.hls = hls;
|
5860
|
+
return _this;
|
5824
5861
|
}
|
5825
5862
|
var _proto = BasePlaylistController.prototype;
|
5826
5863
|
_proto.destroy = function destroy() {
|
@@ -5853,7 +5890,7 @@
|
|
5853
5890
|
try {
|
5854
5891
|
uri = new self.URL(attr.URI, previous.url).href;
|
5855
5892
|
} catch (error) {
|
5856
|
-
|
5893
|
+
this.warn("Could not construct new URL for Rendition Report: " + error);
|
5857
5894
|
uri = attr.URI || '';
|
5858
5895
|
}
|
5859
5896
|
// Use exact match. Otherwise, the last partial match, if any, will be used
|
@@ -5892,7 +5929,7 @@
|
|
5892
5929
|
return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
|
5893
5930
|
};
|
5894
5931
|
_proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
|
5895
|
-
var
|
5932
|
+
var _this2 = this;
|
5896
5933
|
var details = data.details,
|
5897
5934
|
stats = data.stats;
|
5898
5935
|
|
@@ -5939,7 +5976,12 @@
|
|
5939
5976
|
var cdnAge = lastAdvanced + details.ageHeader;
|
5940
5977
|
var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
|
5941
5978
|
if (currentGoal > 0) {
|
5942
|
-
if (
|
5979
|
+
if (cdnAge > details.targetduration * 3) {
|
5980
|
+
// Omit segment and part directives when the last response was more than 3 target durations ago,
|
5981
|
+
this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
|
5982
|
+
msn = undefined;
|
5983
|
+
part = undefined;
|
5984
|
+
} else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
|
5943
5985
|
// If we attempted to get the next or latest playlist update, but currentGoal increased,
|
5944
5986
|
// then we either can't catchup, or the "age" header cannot be trusted.
|
5945
5987
|
this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
|
@@ -5997,7 +6039,7 @@
|
|
5997
6039
|
// );
|
5998
6040
|
|
5999
6041
|
this.timer = self.setTimeout(function () {
|
6000
|
-
return
|
6042
|
+
return _this2.loadPlaylist(deliveryDirectives);
|
6001
6043
|
}, estimatedTimeUntilUpdate);
|
6002
6044
|
} else {
|
6003
6045
|
this.clearTimer();
|
@@ -6013,7 +6055,7 @@
|
|
6013
6055
|
return new HlsUrlParameters(msn, part, skip);
|
6014
6056
|
};
|
6015
6057
|
_proto.checkRetry = function checkRetry(errorEvent) {
|
6016
|
-
var
|
6058
|
+
var _this3 = this;
|
6017
6059
|
var errorDetails = errorEvent.details;
|
6018
6060
|
var isTimeout = isTimeoutError(errorEvent);
|
6019
6061
|
var errorAction = errorEvent.errorAction;
|
@@ -6037,7 +6079,7 @@
|
|
6037
6079
|
var delay = getRetryDelay(retryConfig, retryCount);
|
6038
6080
|
// Schedule level/track reload
|
6039
6081
|
this.timer = self.setTimeout(function () {
|
6040
|
-
return
|
6082
|
+
return _this3.loadPlaylist();
|
6041
6083
|
}, delay);
|
6042
6084
|
this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
|
6043
6085
|
}
|
@@ -6048,7 +6090,7 @@
|
|
6048
6090
|
return retry;
|
6049
6091
|
};
|
6050
6092
|
return BasePlaylistController;
|
6051
|
-
}();
|
6093
|
+
}(Logger);
|
6052
6094
|
|
6053
6095
|
/*
|
6054
6096
|
* compute an Exponential Weighted moving average
|
@@ -6422,30 +6464,33 @@
|
|
6422
6464
|
}, {});
|
6423
6465
|
}
|
6424
6466
|
|
6425
|
-
var AbrController = /*#__PURE__*/function () {
|
6467
|
+
var AbrController = /*#__PURE__*/function (_Logger) {
|
6468
|
+
_inheritsLoose(AbrController, _Logger);
|
6426
6469
|
function AbrController(_hls) {
|
6427
|
-
var _this
|
6428
|
-
this.
|
6429
|
-
|
6430
|
-
|
6431
|
-
|
6432
|
-
|
6433
|
-
|
6434
|
-
|
6435
|
-
|
6436
|
-
|
6437
|
-
|
6438
|
-
|
6439
|
-
|
6440
|
-
|
6470
|
+
var _this;
|
6471
|
+
_this = _Logger.call(this, 'abr', _hls.logger) || this;
|
6472
|
+
_this.hls = void 0;
|
6473
|
+
_this.lastLevelLoadSec = 0;
|
6474
|
+
_this.lastLoadedFragLevel = -1;
|
6475
|
+
_this.firstSelection = -1;
|
6476
|
+
_this._nextAutoLevel = -1;
|
6477
|
+
_this.nextAutoLevelKey = '';
|
6478
|
+
_this.audioTracksByGroup = null;
|
6479
|
+
_this.codecTiers = null;
|
6480
|
+
_this.timer = -1;
|
6481
|
+
_this.fragCurrent = null;
|
6482
|
+
_this.partCurrent = null;
|
6483
|
+
_this.bitrateTestDelay = 0;
|
6484
|
+
_this.bwEstimator = void 0;
|
6441
6485
|
/*
|
6442
6486
|
This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
|
6443
6487
|
quickly enough to prevent underbuffering
|
6444
6488
|
*/
|
6445
|
-
|
6446
|
-
var
|
6447
|
-
|
6448
|
-
|
6489
|
+
_this._abandonRulesCheck = function () {
|
6490
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
6491
|
+
frag = _assertThisInitialize.fragCurrent,
|
6492
|
+
part = _assertThisInitialize.partCurrent,
|
6493
|
+
hls = _assertThisInitialize.hls;
|
6449
6494
|
var autoLevelEnabled = hls.autoLevelEnabled,
|
6450
6495
|
media = hls.media;
|
6451
6496
|
if (!frag || !media) {
|
@@ -6534,21 +6579,22 @@
|
|
6534
6579
|
_this.resetEstimator(nextLoadLevelBitrate);
|
6535
6580
|
}
|
6536
6581
|
_this.clearTimer();
|
6537
|
-
|
6582
|
+
_this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
|
6538
6583
|
hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
|
6539
6584
|
frag: frag,
|
6540
6585
|
part: part,
|
6541
6586
|
stats: stats
|
6542
6587
|
});
|
6543
6588
|
};
|
6544
|
-
|
6545
|
-
|
6546
|
-
|
6589
|
+
_this.hls = _hls;
|
6590
|
+
_this.bwEstimator = _this.initEstimator();
|
6591
|
+
_this.registerListeners();
|
6592
|
+
return _this;
|
6547
6593
|
}
|
6548
6594
|
var _proto = AbrController.prototype;
|
6549
6595
|
_proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
|
6550
6596
|
if (abrEwmaDefaultEstimate) {
|
6551
|
-
|
6597
|
+
this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
|
6552
6598
|
this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
|
6553
6599
|
}
|
6554
6600
|
this.firstSelection = -1;
|
@@ -6800,13 +6846,13 @@
|
|
6800
6846
|
// cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
|
6801
6847
|
var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
|
6802
6848
|
maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
|
6803
|
-
|
6849
|
+
this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
|
6804
6850
|
// don't use conservative factor on bitrate test
|
6805
6851
|
bwFactor = bwUpFactor = 1;
|
6806
6852
|
}
|
6807
6853
|
}
|
6808
6854
|
var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
|
6809
|
-
|
6855
|
+
this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
|
6810
6856
|
if (bestLevel > -1) {
|
6811
6857
|
return bestLevel;
|
6812
6858
|
}
|
@@ -6862,7 +6908,7 @@
|
|
6862
6908
|
currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
|
6863
6909
|
currentFrameRate = minFramerate;
|
6864
6910
|
currentBw = Math.max(currentBw, minBitrate);
|
6865
|
-
|
6911
|
+
this.log("picked start tier " + JSON.stringify(startTier));
|
6866
6912
|
} else {
|
6867
6913
|
currentCodecSet = level == null ? void 0 : level.codecSet;
|
6868
6914
|
currentVideoRange = level == null ? void 0 : level.videoRange;
|
@@ -6915,9 +6961,9 @@
|
|
6915
6961
|
var forcedAutoLevel = _this2.forcedAutoLevel;
|
6916
6962
|
if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
|
6917
6963
|
if (levelsSkipped.length) {
|
6918
|
-
|
6964
|
+
_this2.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
|
6919
6965
|
}
|
6920
|
-
|
6966
|
+
_this2.info("switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
|
6921
6967
|
}
|
6922
6968
|
if (firstSelection) {
|
6923
6969
|
_this2.firstSelection = i;
|
@@ -6951,7 +6997,7 @@
|
|
6951
6997
|
}
|
6952
6998
|
var firstLevel = this.hls.firstLevel;
|
6953
6999
|
var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
|
6954
|
-
|
7000
|
+
this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
|
6955
7001
|
return clamped;
|
6956
7002
|
}
|
6957
7003
|
}, {
|
@@ -7004,7 +7050,7 @@
|
|
7004
7050
|
}
|
7005
7051
|
}]);
|
7006
7052
|
return AbrController;
|
7007
|
-
}();
|
7053
|
+
}(Logger);
|
7008
7054
|
|
7009
7055
|
/**
|
7010
7056
|
* Provides methods dealing with buffer length retrieval for example.
|
@@ -7225,57 +7271,57 @@
|
|
7225
7271
|
}();
|
7226
7272
|
|
7227
7273
|
var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
|
7228
|
-
var BufferController = /*#__PURE__*/function () {
|
7274
|
+
var BufferController = /*#__PURE__*/function (_Logger) {
|
7275
|
+
_inheritsLoose(BufferController, _Logger);
|
7229
7276
|
function BufferController(hls) {
|
7230
|
-
var _this
|
7277
|
+
var _this;
|
7278
|
+
_this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
|
7231
7279
|
// The level details used to determine duration, target-duration and live
|
7232
|
-
|
7280
|
+
_this.details = null;
|
7233
7281
|
// cache the self generated object url to detect hijack of video tag
|
7234
|
-
|
7282
|
+
_this._objectUrl = null;
|
7235
7283
|
// A queue of buffer operations which require the SourceBuffer to not be updating upon execution
|
7236
|
-
|
7284
|
+
_this.operationQueue = void 0;
|
7237
7285
|
// References to event listeners for each SourceBuffer, so that they can be referenced for event removal
|
7238
|
-
|
7239
|
-
|
7286
|
+
_this.listeners = void 0;
|
7287
|
+
_this.hls = void 0;
|
7240
7288
|
// The number of BUFFER_CODEC events received before any sourceBuffers are created
|
7241
|
-
|
7289
|
+
_this.bufferCodecEventsExpected = 0;
|
7242
7290
|
// The total number of BUFFER_CODEC events received
|
7243
|
-
|
7291
|
+
_this._bufferCodecEventsTotal = 0;
|
7244
7292
|
// A reference to the attached media element
|
7245
|
-
|
7293
|
+
_this.media = null;
|
7246
7294
|
// A reference to the active media source
|
7247
|
-
|
7295
|
+
_this.mediaSource = null;
|
7248
7296
|
// Last MP3 audio chunk appended
|
7249
|
-
|
7250
|
-
|
7297
|
+
_this.lastMpegAudioChunk = null;
|
7298
|
+
_this.appendSource = void 0;
|
7251
7299
|
// counters
|
7252
|
-
|
7300
|
+
_this.appendErrors = {
|
7253
7301
|
audio: 0,
|
7254
7302
|
video: 0,
|
7255
7303
|
audiovideo: 0
|
7256
7304
|
};
|
7257
|
-
|
7258
|
-
|
7259
|
-
|
7260
|
-
|
7261
|
-
this.warn = void 0;
|
7262
|
-
this.error = void 0;
|
7263
|
-
this._onEndStreaming = function (event) {
|
7305
|
+
_this.tracks = {};
|
7306
|
+
_this.pendingTracks = {};
|
7307
|
+
_this.sourceBuffer = void 0;
|
7308
|
+
_this._onEndStreaming = function (event) {
|
7264
7309
|
if (!_this.hls) {
|
7265
7310
|
return;
|
7266
7311
|
}
|
7267
7312
|
_this.hls.pauseBuffering();
|
7268
7313
|
};
|
7269
|
-
|
7314
|
+
_this._onStartStreaming = function (event) {
|
7270
7315
|
if (!_this.hls) {
|
7271
7316
|
return;
|
7272
7317
|
}
|
7273
7318
|
_this.hls.resumeBuffering();
|
7274
7319
|
};
|
7275
7320
|
// Keep as arrow functions so that we can directly reference these functions directly as event listeners
|
7276
|
-
|
7277
|
-
var
|
7278
|
-
|
7321
|
+
_this._onMediaSourceOpen = function () {
|
7322
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
7323
|
+
media = _assertThisInitialize.media,
|
7324
|
+
mediaSource = _assertThisInitialize.mediaSource;
|
7279
7325
|
_this.log('Media source opened');
|
7280
7326
|
if (media) {
|
7281
7327
|
media.removeEventListener('emptied', _this._onMediaEmptied);
|
@@ -7291,27 +7337,25 @@
|
|
7291
7337
|
}
|
7292
7338
|
_this.checkPendingTracks();
|
7293
7339
|
};
|
7294
|
-
|
7340
|
+
_this._onMediaSourceClose = function () {
|
7295
7341
|
_this.log('Media source closed');
|
7296
7342
|
};
|
7297
|
-
|
7343
|
+
_this._onMediaSourceEnded = function () {
|
7298
7344
|
_this.log('Media source ended');
|
7299
7345
|
};
|
7300
|
-
|
7301
|
-
var
|
7302
|
-
|
7346
|
+
_this._onMediaEmptied = function () {
|
7347
|
+
var _assertThisInitialize2 = _assertThisInitialized(_this),
|
7348
|
+
mediaSrc = _assertThisInitialize2.mediaSrc,
|
7349
|
+
_objectUrl = _assertThisInitialize2._objectUrl;
|
7303
7350
|
if (mediaSrc !== _objectUrl) {
|
7304
|
-
|
7351
|
+
_this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
|
7305
7352
|
}
|
7306
7353
|
};
|
7307
|
-
|
7308
|
-
|
7309
|
-
|
7310
|
-
|
7311
|
-
|
7312
|
-
this.error = logger.error.bind(logger, logPrefix);
|
7313
|
-
this._initSourceBuffer();
|
7314
|
-
this.registerListeners();
|
7354
|
+
_this.hls = hls;
|
7355
|
+
_this.appendSource = hls.config.preferManagedMediaSource;
|
7356
|
+
_this._initSourceBuffer();
|
7357
|
+
_this.registerListeners();
|
7358
|
+
return _this;
|
7315
7359
|
}
|
7316
7360
|
var _proto = BufferController.prototype;
|
7317
7361
|
_proto.hasSourceTypes = function hasSourceTypes() {
|
@@ -7323,6 +7367,12 @@
|
|
7323
7367
|
this.lastMpegAudioChunk = null;
|
7324
7368
|
// @ts-ignore
|
7325
7369
|
this.hls = null;
|
7370
|
+
// @ts-ignore
|
7371
|
+
this._onMediaSourceOpen = this._onMediaSourceClose = null;
|
7372
|
+
// @ts-ignore
|
7373
|
+
this._onMediaSourceEnded = null;
|
7374
|
+
// @ts-ignore
|
7375
|
+
this._onStartStreaming = this._onEndStreaming = null;
|
7326
7376
|
};
|
7327
7377
|
_proto.registerListeners = function registerListeners() {
|
7328
7378
|
var hls = this.hls;
|
@@ -7480,6 +7530,7 @@
|
|
7480
7530
|
_this2.resetBuffer(type);
|
7481
7531
|
});
|
7482
7532
|
this._initSourceBuffer();
|
7533
|
+
this.hls.resumeBuffering();
|
7483
7534
|
};
|
7484
7535
|
_proto.resetBuffer = function resetBuffer(type) {
|
7485
7536
|
var sb = this.sourceBuffer[type];
|
@@ -8183,7 +8234,7 @@
|
|
8183
8234
|
}
|
8184
8235
|
}]);
|
8185
8236
|
return BufferController;
|
8186
|
-
}();
|
8237
|
+
}(Logger);
|
8187
8238
|
function removeSourceChildren(node) {
|
8188
8239
|
var sourceChildren = node.querySelectorAll('source');
|
8189
8240
|
[].slice.call(sourceChildren).forEach(function (source) {
|
@@ -8307,7 +8358,7 @@
|
|
8307
8358
|
var hls = this.hls;
|
8308
8359
|
var maxLevel = this.getMaxLevel(levels.length - 1);
|
8309
8360
|
if (maxLevel !== this.autoLevelCapping) {
|
8310
|
-
logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8361
|
+
hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8311
8362
|
}
|
8312
8363
|
hls.autoLevelCapping = maxLevel;
|
8313
8364
|
if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
|
@@ -8497,10 +8548,10 @@
|
|
8497
8548
|
totalDroppedFrames: droppedFrames
|
8498
8549
|
});
|
8499
8550
|
if (droppedFPS > 0) {
|
8500
|
-
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8551
|
+
// hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8501
8552
|
if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
|
8502
8553
|
var currentLevel = hls.currentLevel;
|
8503
|
-
logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8554
|
+
hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8504
8555
|
if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
|
8505
8556
|
currentLevel = currentLevel - 1;
|
8506
8557
|
hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
|
@@ -8534,26 +8585,28 @@
|
|
8534
8585
|
}();
|
8535
8586
|
|
8536
8587
|
var PATHWAY_PENALTY_DURATION_MS = 300000;
|
8537
|
-
var ContentSteeringController = /*#__PURE__*/function () {
|
8588
|
+
var ContentSteeringController = /*#__PURE__*/function (_Logger) {
|
8589
|
+
_inheritsLoose(ContentSteeringController, _Logger);
|
8538
8590
|
function ContentSteeringController(hls) {
|
8539
|
-
|
8540
|
-
this.
|
8541
|
-
|
8542
|
-
|
8543
|
-
|
8544
|
-
|
8545
|
-
|
8546
|
-
|
8547
|
-
|
8548
|
-
|
8549
|
-
|
8550
|
-
|
8551
|
-
|
8552
|
-
|
8553
|
-
|
8554
|
-
|
8555
|
-
|
8556
|
-
|
8591
|
+
var _this;
|
8592
|
+
_this = _Logger.call(this, 'content-steering', hls.logger) || this;
|
8593
|
+
_this.hls = void 0;
|
8594
|
+
_this.loader = null;
|
8595
|
+
_this.uri = null;
|
8596
|
+
_this.pathwayId = '.';
|
8597
|
+
_this.pathwayPriority = null;
|
8598
|
+
_this.timeToLoad = 300;
|
8599
|
+
_this.reloadTimer = -1;
|
8600
|
+
_this.updated = 0;
|
8601
|
+
_this.started = false;
|
8602
|
+
_this.enabled = true;
|
8603
|
+
_this.levels = null;
|
8604
|
+
_this.audioTracks = null;
|
8605
|
+
_this.subtitleTracks = null;
|
8606
|
+
_this.penalizedPathways = {};
|
8607
|
+
_this.hls = hls;
|
8608
|
+
_this.registerListeners();
|
8609
|
+
return _this;
|
8557
8610
|
}
|
8558
8611
|
var _proto = ContentSteeringController.prototype;
|
8559
8612
|
_proto.registerListeners = function registerListeners() {
|
@@ -8674,7 +8727,7 @@
|
|
8674
8727
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
8675
8728
|
}
|
8676
8729
|
if (!errorAction.resolved) {
|
8677
|
-
|
8730
|
+
this.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
|
8678
8731
|
}
|
8679
8732
|
}
|
8680
8733
|
};
|
@@ -8754,7 +8807,7 @@
|
|
8754
8807
|
return defaultPathway;
|
8755
8808
|
};
|
8756
8809
|
_proto.clonePathways = function clonePathways(pathwayClones) {
|
8757
|
-
var
|
8810
|
+
var _this2 = this;
|
8758
8811
|
var levels = this.levels;
|
8759
8812
|
if (!levels) {
|
8760
8813
|
return;
|
@@ -8770,7 +8823,7 @@
|
|
8770
8823
|
})) {
|
8771
8824
|
return;
|
8772
8825
|
}
|
8773
|
-
var clonedVariants =
|
8826
|
+
var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
|
8774
8827
|
var attributes = new AttrList(baseLevel.attrs);
|
8775
8828
|
attributes['PATHWAY-ID'] = cloneId;
|
8776
8829
|
var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
|
@@ -8807,12 +8860,12 @@
|
|
8807
8860
|
return clonedLevel;
|
8808
8861
|
});
|
8809
8862
|
levels.push.apply(levels, clonedVariants);
|
8810
|
-
cloneRenditionGroups(
|
8811
|
-
cloneRenditionGroups(
|
8863
|
+
cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
|
8864
|
+
cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
|
8812
8865
|
});
|
8813
8866
|
};
|
8814
8867
|
_proto.loadSteeringManifest = function loadSteeringManifest(uri) {
|
8815
|
-
var
|
8868
|
+
var _this3 = this;
|
8816
8869
|
var config = this.hls.config;
|
8817
8870
|
var Loader = config.loader;
|
8818
8871
|
if (this.loader) {
|
@@ -8847,87 +8900,87 @@
|
|
8847
8900
|
};
|
8848
8901
|
var callbacks = {
|
8849
8902
|
onSuccess: function onSuccess(response, stats, context, networkDetails) {
|
8850
|
-
|
8903
|
+
_this3.log("Loaded steering manifest: \"" + url + "\"");
|
8851
8904
|
var steeringData = response.data;
|
8852
|
-
if (steeringData.VERSION !== 1) {
|
8853
|
-
|
8905
|
+
if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
|
8906
|
+
_this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
|
8854
8907
|
return;
|
8855
8908
|
}
|
8856
|
-
|
8857
|
-
|
8909
|
+
_this3.updated = performance.now();
|
8910
|
+
_this3.timeToLoad = steeringData.TTL;
|
8858
8911
|
var reloadUri = steeringData['RELOAD-URI'],
|
8859
8912
|
pathwayClones = steeringData['PATHWAY-CLONES'],
|
8860
8913
|
pathwayPriority = steeringData['PATHWAY-PRIORITY'];
|
8861
8914
|
if (reloadUri) {
|
8862
8915
|
try {
|
8863
|
-
|
8916
|
+
_this3.uri = new self.URL(reloadUri, url).href;
|
8864
8917
|
} catch (error) {
|
8865
|
-
|
8866
|
-
|
8918
|
+
_this3.enabled = false;
|
8919
|
+
_this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
|
8867
8920
|
return;
|
8868
8921
|
}
|
8869
8922
|
}
|
8870
|
-
|
8923
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8871
8924
|
if (pathwayClones) {
|
8872
|
-
|
8925
|
+
_this3.clonePathways(pathwayClones);
|
8873
8926
|
}
|
8874
8927
|
var loadedSteeringData = {
|
8875
8928
|
steeringManifest: steeringData,
|
8876
8929
|
url: url.toString()
|
8877
8930
|
};
|
8878
|
-
|
8931
|
+
_this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
|
8879
8932
|
if (pathwayPriority) {
|
8880
|
-
|
8933
|
+
_this3.updatePathwayPriority(pathwayPriority);
|
8881
8934
|
}
|
8882
8935
|
},
|
8883
8936
|
onError: function onError(error, context, networkDetails, stats) {
|
8884
|
-
|
8885
|
-
|
8937
|
+
_this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
|
8938
|
+
_this3.stopLoad();
|
8886
8939
|
if (error.code === 410) {
|
8887
|
-
|
8888
|
-
|
8940
|
+
_this3.enabled = false;
|
8941
|
+
_this3.log("Steering manifest " + context.url + " no longer available");
|
8889
8942
|
return;
|
8890
8943
|
}
|
8891
|
-
var ttl =
|
8944
|
+
var ttl = _this3.timeToLoad * 1000;
|
8892
8945
|
if (error.code === 429) {
|
8893
|
-
var loader =
|
8946
|
+
var loader = _this3.loader;
|
8894
8947
|
if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
|
8895
8948
|
var retryAfter = loader.getResponseHeader('Retry-After');
|
8896
8949
|
if (retryAfter) {
|
8897
8950
|
ttl = parseFloat(retryAfter) * 1000;
|
8898
8951
|
}
|
8899
8952
|
}
|
8900
|
-
|
8953
|
+
_this3.log("Steering manifest " + context.url + " rate limited");
|
8901
8954
|
return;
|
8902
8955
|
}
|
8903
|
-
|
8956
|
+
_this3.scheduleRefresh(_this3.uri || context.url, ttl);
|
8904
8957
|
},
|
8905
8958
|
onTimeout: function onTimeout(stats, context, networkDetails) {
|
8906
|
-
|
8907
|
-
|
8959
|
+
_this3.log("Timeout loading steering manifest (" + context.url + ")");
|
8960
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8908
8961
|
}
|
8909
8962
|
};
|
8910
8963
|
this.log("Requesting steering manifest: " + url);
|
8911
8964
|
this.loader.load(context, loaderConfig, callbacks);
|
8912
8965
|
};
|
8913
8966
|
_proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
|
8914
|
-
var
|
8967
|
+
var _this4 = this;
|
8915
8968
|
if (ttlMs === void 0) {
|
8916
8969
|
ttlMs = this.timeToLoad * 1000;
|
8917
8970
|
}
|
8918
8971
|
this.clearTimeout();
|
8919
8972
|
this.reloadTimer = self.setTimeout(function () {
|
8920
|
-
var
|
8921
|
-
var media = (
|
8973
|
+
var _this4$hls;
|
8974
|
+
var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
|
8922
8975
|
if (media && !media.ended) {
|
8923
|
-
|
8976
|
+
_this4.loadSteeringManifest(uri);
|
8924
8977
|
return;
|
8925
8978
|
}
|
8926
|
-
|
8979
|
+
_this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
|
8927
8980
|
}, ttlMs);
|
8928
8981
|
};
|
8929
8982
|
return ContentSteeringController;
|
8930
|
-
}();
|
8983
|
+
}(Logger);
|
8931
8984
|
function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
|
8932
8985
|
if (!tracks) {
|
8933
8986
|
return;
|
@@ -9763,7 +9816,7 @@
|
|
9763
9816
|
});
|
9764
9817
|
function timelineConfig() {
|
9765
9818
|
return {
|
9766
|
-
cueHandler:
|
9819
|
+
cueHandler: HevcVideoParser,
|
9767
9820
|
// used by timeline-controller
|
9768
9821
|
enableWebVTT: false,
|
9769
9822
|
// used by timeline-controller
|
@@ -9794,7 +9847,7 @@
|
|
9794
9847
|
/**
|
9795
9848
|
* @ignore
|
9796
9849
|
*/
|
9797
|
-
function mergeConfig(defaultConfig, userConfig) {
|
9850
|
+
function mergeConfig(defaultConfig, userConfig, logger) {
|
9798
9851
|
if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
|
9799
9852
|
throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
|
9800
9853
|
}
|
@@ -9864,7 +9917,7 @@
|
|
9864
9917
|
/**
|
9865
9918
|
* @ignore
|
9866
9919
|
*/
|
9867
|
-
function enableStreamingMode(config) {
|
9920
|
+
function enableStreamingMode(config, logger) {
|
9868
9921
|
var currentLoader = config.loader;
|
9869
9922
|
if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
|
9870
9923
|
// If a developer has configured their own loader, respect that choice
|
@@ -9881,12 +9934,11 @@
|
|
9881
9934
|
}
|
9882
9935
|
}
|
9883
9936
|
|
9884
|
-
var chromeOrFirefox;
|
9885
9937
|
var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
|
9886
9938
|
_inheritsLoose(LevelController, _BasePlaylistControll);
|
9887
9939
|
function LevelController(hls, contentSteeringController) {
|
9888
9940
|
var _this;
|
9889
|
-
_this = _BasePlaylistControll.call(this, hls, '
|
9941
|
+
_this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
|
9890
9942
|
_this._levels = [];
|
9891
9943
|
_this._firstLevel = -1;
|
9892
9944
|
_this._maxAutoLevel = -1;
|
@@ -9955,21 +10007,13 @@
|
|
9955
10007
|
var videoCodecFound = false;
|
9956
10008
|
var audioCodecFound = false;
|
9957
10009
|
data.levels.forEach(function (levelParsed) {
|
9958
|
-
var
|
10010
|
+
var _videoCodec;
|
9959
10011
|
var attributes = levelParsed.attrs;
|
9960
|
-
|
9961
|
-
// erase audio codec info if browser does not support mp4a.40.34.
|
9962
|
-
// demuxer will autodetect codec and fallback to mpeg/audio
|
9963
10012
|
var audioCodec = levelParsed.audioCodec,
|
9964
10013
|
videoCodec = levelParsed.videoCodec;
|
9965
|
-
if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
|
9966
|
-
chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
|
9967
|
-
if (chromeOrFirefox) {
|
9968
|
-
levelParsed.audioCodec = audioCodec = undefined;
|
9969
|
-
}
|
9970
|
-
}
|
9971
10014
|
if (audioCodec) {
|
9972
|
-
|
10015
|
+
// Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
|
10016
|
+
levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
|
9973
10017
|
}
|
9974
10018
|
if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
|
9975
10019
|
videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
|
@@ -10201,7 +10245,12 @@
|
|
10201
10245
|
if (curLevel.fragmentError === 0) {
|
10202
10246
|
curLevel.loadError = 0;
|
10203
10247
|
}
|
10204
|
-
|
10248
|
+
// Ignore matching details populated by loading a Media Playlist directly
|
10249
|
+
var previousDetails = curLevel.details;
|
10250
|
+
if (previousDetails === data.details && previousDetails.advanced) {
|
10251
|
+
previousDetails = undefined;
|
10252
|
+
}
|
10253
|
+
this.playlistLoaded(level, data, previousDetails);
|
10205
10254
|
} else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
|
10206
10255
|
// received a delta playlist update that cannot be merged
|
10207
10256
|
details.deltaUpdateFailed = true;
|
@@ -11116,8 +11165,8 @@
|
|
11116
11165
|
var _frag$decryptdata;
|
11117
11166
|
var byteRangeStart = start;
|
11118
11167
|
var byteRangeEnd = end;
|
11119
|
-
if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)
|
11120
|
-
// MAP segment encrypted with method 'AES-128', when served with HTTP Range,
|
11168
|
+
if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
|
11169
|
+
// MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
|
11121
11170
|
// has the unencrypted size specified in the range.
|
11122
11171
|
// Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
11123
11172
|
var fragmentLen = end - start;
|
@@ -11150,6 +11199,9 @@
|
|
11150
11199
|
(part ? part : frag).stats.aborted = true;
|
11151
11200
|
return new LoadError(errorData);
|
11152
11201
|
}
|
11202
|
+
function isMethodFullSegmentAesCbc(method) {
|
11203
|
+
return method === 'AES-128' || method === 'AES-256';
|
11204
|
+
}
|
11153
11205
|
var LoadError = /*#__PURE__*/function (_Error) {
|
11154
11206
|
_inheritsLoose(LoadError, _Error);
|
11155
11207
|
function LoadError(data) {
|
@@ -11306,6 +11358,8 @@
|
|
11306
11358
|
}
|
11307
11359
|
return this.loadKeyEME(keyInfo, frag);
|
11308
11360
|
case 'AES-128':
|
11361
|
+
case 'AES-256':
|
11362
|
+
case 'AES-256-CTR':
|
11309
11363
|
return this.loadKeyHTTP(keyInfo, frag);
|
11310
11364
|
default:
|
11311
11365
|
return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
|
@@ -11439,13 +11493,17 @@
|
|
11439
11493
|
* we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
|
11440
11494
|
* task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
|
11441
11495
|
*/
|
11442
|
-
var TaskLoop = /*#__PURE__*/function () {
|
11443
|
-
|
11444
|
-
|
11445
|
-
|
11446
|
-
|
11447
|
-
|
11448
|
-
|
11496
|
+
var TaskLoop = /*#__PURE__*/function (_Logger) {
|
11497
|
+
_inheritsLoose(TaskLoop, _Logger);
|
11498
|
+
function TaskLoop(label, logger) {
|
11499
|
+
var _this;
|
11500
|
+
_this = _Logger.call(this, label, logger) || this;
|
11501
|
+
_this._boundTick = void 0;
|
11502
|
+
_this._tickTimer = null;
|
11503
|
+
_this._tickInterval = null;
|
11504
|
+
_this._tickCallCount = 0;
|
11505
|
+
_this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
|
11506
|
+
return _this;
|
11449
11507
|
}
|
11450
11508
|
var _proto = TaskLoop.prototype;
|
11451
11509
|
_proto.destroy = function destroy() {
|
@@ -11531,7 +11589,7 @@
|
|
11531
11589
|
*/;
|
11532
11590
|
_proto.doTick = function doTick() {};
|
11533
11591
|
return TaskLoop;
|
11534
|
-
}();
|
11592
|
+
}(Logger);
|
11535
11593
|
|
11536
11594
|
var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
|
11537
11595
|
if (size === void 0) {
|
@@ -11717,37 +11775,65 @@
|
|
11717
11775
|
}
|
11718
11776
|
|
11719
11777
|
var AESCrypto = /*#__PURE__*/function () {
|
11720
|
-
function AESCrypto(subtle, iv) {
|
11778
|
+
function AESCrypto(subtle, iv, aesMode) {
|
11721
11779
|
this.subtle = void 0;
|
11722
11780
|
this.aesIV = void 0;
|
11781
|
+
this.aesMode = void 0;
|
11723
11782
|
this.subtle = subtle;
|
11724
11783
|
this.aesIV = iv;
|
11784
|
+
this.aesMode = aesMode;
|
11725
11785
|
}
|
11726
11786
|
var _proto = AESCrypto.prototype;
|
11727
11787
|
_proto.decrypt = function decrypt(data, key) {
|
11728
|
-
|
11729
|
-
|
11730
|
-
|
11731
|
-
|
11788
|
+
switch (this.aesMode) {
|
11789
|
+
case DecrypterAesMode.cbc:
|
11790
|
+
return this.subtle.decrypt({
|
11791
|
+
name: 'AES-CBC',
|
11792
|
+
iv: this.aesIV
|
11793
|
+
}, key, data);
|
11794
|
+
case DecrypterAesMode.ctr:
|
11795
|
+
return this.subtle.decrypt({
|
11796
|
+
name: 'AES-CTR',
|
11797
|
+
counter: this.aesIV,
|
11798
|
+
length: 64
|
11799
|
+
},
|
11800
|
+
//64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
|
11801
|
+
key, data);
|
11802
|
+
default:
|
11803
|
+
throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
|
11804
|
+
}
|
11732
11805
|
};
|
11733
11806
|
return AESCrypto;
|
11734
11807
|
}();
|
11735
11808
|
|
11736
11809
|
var FastAESKey = /*#__PURE__*/function () {
|
11737
|
-
function FastAESKey(subtle, key) {
|
11810
|
+
function FastAESKey(subtle, key, aesMode) {
|
11738
11811
|
this.subtle = void 0;
|
11739
11812
|
this.key = void 0;
|
11813
|
+
this.aesMode = void 0;
|
11740
11814
|
this.subtle = subtle;
|
11741
11815
|
this.key = key;
|
11816
|
+
this.aesMode = aesMode;
|
11742
11817
|
}
|
11743
11818
|
var _proto = FastAESKey.prototype;
|
11744
11819
|
_proto.expandKey = function expandKey() {
|
11820
|
+
var subtleAlgoName = getSubtleAlgoName(this.aesMode);
|
11745
11821
|
return this.subtle.importKey('raw', this.key, {
|
11746
|
-
name:
|
11822
|
+
name: subtleAlgoName
|
11747
11823
|
}, false, ['encrypt', 'decrypt']);
|
11748
11824
|
};
|
11749
11825
|
return FastAESKey;
|
11750
11826
|
}();
|
11827
|
+
function getSubtleAlgoName(aesMode) {
|
11828
|
+
switch (aesMode) {
|
11829
|
+
case DecrypterAesMode.cbc:
|
11830
|
+
return 'AES-CBC';
|
11831
|
+
case DecrypterAesMode.ctr:
|
11832
|
+
return 'AES-CTR';
|
11833
|
+
default:
|
11834
|
+
throw new Error("[FastAESKey] invalid aes mode " + aesMode);
|
11835
|
+
}
|
11836
|
+
}
|
11751
11837
|
|
11752
11838
|
// PKCS7
|
11753
11839
|
function removePadding(array) {
|
@@ -12000,7 +12086,8 @@
|
|
12000
12086
|
this.currentIV = null;
|
12001
12087
|
this.currentResult = null;
|
12002
12088
|
this.useSoftware = void 0;
|
12003
|
-
this.
|
12089
|
+
this.enableSoftwareAES = void 0;
|
12090
|
+
this.enableSoftwareAES = config.enableSoftwareAES;
|
12004
12091
|
this.removePKCS7Padding = removePKCS7Padding;
|
12005
12092
|
// built in decryptor expects PKCS7 padding
|
12006
12093
|
if (removePKCS7Padding) {
|
@@ -12013,9 +12100,7 @@
|
|
12013
12100
|
/* no-op */
|
12014
12101
|
}
|
12015
12102
|
}
|
12016
|
-
|
12017
|
-
this.useSoftware = true;
|
12018
|
-
}
|
12103
|
+
this.useSoftware = this.subtle === null;
|
12019
12104
|
}
|
12020
12105
|
var _proto = Decrypter.prototype;
|
12021
12106
|
_proto.destroy = function destroy() {
|
@@ -12052,11 +12137,11 @@
|
|
12052
12137
|
this.softwareDecrypter = null;
|
12053
12138
|
}
|
12054
12139
|
};
|
12055
|
-
_proto.decrypt = function decrypt(data, key, iv) {
|
12140
|
+
_proto.decrypt = function decrypt(data, key, iv, aesMode) {
|
12056
12141
|
var _this = this;
|
12057
12142
|
if (this.useSoftware) {
|
12058
12143
|
return new Promise(function (resolve, reject) {
|
12059
|
-
_this.softwareDecrypt(new Uint8Array(data), key, iv);
|
12144
|
+
_this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12060
12145
|
var decryptResult = _this.flush();
|
12061
12146
|
if (decryptResult) {
|
12062
12147
|
resolve(decryptResult.buffer);
|
@@ -12065,16 +12150,20 @@
|
|
12065
12150
|
}
|
12066
12151
|
});
|
12067
12152
|
}
|
12068
|
-
return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
|
12153
|
+
return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12069
12154
|
}
|
12070
12155
|
|
12071
12156
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
12072
12157
|
// data is handled in the flush() call
|
12073
12158
|
;
|
12074
|
-
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
|
12159
|
+
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
|
12075
12160
|
var currentIV = this.currentIV,
|
12076
12161
|
currentResult = this.currentResult,
|
12077
12162
|
remainderData = this.remainderData;
|
12163
|
+
if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
|
12164
|
+
logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
|
12165
|
+
return null;
|
12166
|
+
}
|
12078
12167
|
this.logOnce('JS AES decrypt');
|
12079
12168
|
// The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
|
12080
12169
|
// This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
|
@@ -12107,12 +12196,12 @@
|
|
12107
12196
|
}
|
12108
12197
|
return result;
|
12109
12198
|
};
|
12110
|
-
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
|
12199
|
+
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
|
12111
12200
|
var _this2 = this;
|
12112
12201
|
var subtle = this.subtle;
|
12113
12202
|
if (this.key !== key || !this.fastAesKey) {
|
12114
12203
|
this.key = key;
|
12115
|
-
this.fastAesKey = new FastAESKey(subtle, key);
|
12204
|
+
this.fastAesKey = new FastAESKey(subtle, key, aesMode);
|
12116
12205
|
}
|
12117
12206
|
return this.fastAesKey.expandKey().then(function (aesKey) {
|
12118
12207
|
// decrypt using web crypto
|
@@ -12120,22 +12209,25 @@
|
|
12120
12209
|
return Promise.reject(new Error('web crypto not initialized'));
|
12121
12210
|
}
|
12122
12211
|
_this2.logOnce('WebCrypto AES decrypt');
|
12123
|
-
var crypto = new AESCrypto(subtle, new Uint8Array(iv));
|
12212
|
+
var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
|
12124
12213
|
return crypto.decrypt(data.buffer, aesKey);
|
12125
12214
|
}).catch(function (err) {
|
12126
12215
|
logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
|
12127
|
-
return _this2.onWebCryptoError(data, key, iv);
|
12216
|
+
return _this2.onWebCryptoError(data, key, iv, aesMode);
|
12128
12217
|
});
|
12129
12218
|
};
|
12130
|
-
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
|
12131
|
-
|
12132
|
-
|
12133
|
-
|
12134
|
-
|
12135
|
-
|
12136
|
-
|
12219
|
+
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
|
12220
|
+
var enableSoftwareAES = this.enableSoftwareAES;
|
12221
|
+
if (enableSoftwareAES) {
|
12222
|
+
this.useSoftware = true;
|
12223
|
+
this.logEnabled = true;
|
12224
|
+
this.softwareDecrypt(data, key, iv, aesMode);
|
12225
|
+
var decryptResult = this.flush();
|
12226
|
+
if (decryptResult) {
|
12227
|
+
return decryptResult.buffer;
|
12228
|
+
}
|
12137
12229
|
}
|
12138
|
-
throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
|
12230
|
+
throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
|
12139
12231
|
};
|
12140
12232
|
_proto.getValidChunk = function getValidChunk(data) {
|
12141
12233
|
var currentChunk = data;
|
@@ -12189,7 +12281,7 @@
|
|
12189
12281
|
_inheritsLoose(BaseStreamController, _TaskLoop);
|
12190
12282
|
function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
|
12191
12283
|
var _this;
|
12192
|
-
_this = _TaskLoop.call(this) || this;
|
12284
|
+
_this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
|
12193
12285
|
_this.hls = void 0;
|
12194
12286
|
_this.fragPrevious = null;
|
12195
12287
|
_this.fragCurrent = null;
|
@@ -12214,30 +12306,101 @@
|
|
12214
12306
|
_this.startFragRequested = false;
|
12215
12307
|
_this.decrypter = void 0;
|
12216
12308
|
_this.initPTS = [];
|
12217
|
-
_this.
|
12218
|
-
_this.
|
12219
|
-
_this.
|
12220
|
-
|
12221
|
-
|
12309
|
+
_this.buffering = true;
|
12310
|
+
_this.loadingParts = false;
|
12311
|
+
_this.onMediaSeeking = function () {
|
12312
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
12313
|
+
config = _assertThisInitialize.config,
|
12314
|
+
fragCurrent = _assertThisInitialize.fragCurrent,
|
12315
|
+
media = _assertThisInitialize.media,
|
12316
|
+
mediaBuffer = _assertThisInitialize.mediaBuffer,
|
12317
|
+
state = _assertThisInitialize.state;
|
12318
|
+
var currentTime = media ? media.currentTime : 0;
|
12319
|
+
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12320
|
+
_this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12321
|
+
if (_this.state === State.ENDED) {
|
12322
|
+
_this.resetLoadingState();
|
12323
|
+
} else if (fragCurrent) {
|
12324
|
+
// Seeking while frag load is in progress
|
12325
|
+
var tolerance = config.maxFragLookUpTolerance;
|
12326
|
+
var fragStartOffset = fragCurrent.start - tolerance;
|
12327
|
+
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12328
|
+
// if seeking out of buffered range or into new one
|
12329
|
+
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12330
|
+
var pastFragment = currentTime > fragEndOffset;
|
12331
|
+
// if the seek position is outside the current fragment range
|
12332
|
+
if (currentTime < fragStartOffset || pastFragment) {
|
12333
|
+
if (pastFragment && fragCurrent.loader) {
|
12334
|
+
_this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12335
|
+
fragCurrent.abortRequests();
|
12336
|
+
_this.resetLoadingState();
|
12337
|
+
}
|
12338
|
+
_this.fragPrevious = null;
|
12339
|
+
}
|
12340
|
+
}
|
12341
|
+
}
|
12342
|
+
if (media) {
|
12343
|
+
// Remove gap fragments
|
12344
|
+
_this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
|
12345
|
+
_this.lastCurrentTime = currentTime;
|
12346
|
+
if (!_this.loadingParts) {
|
12347
|
+
var bufferEnd = Math.max(bufferInfo.end, currentTime);
|
12348
|
+
var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
|
12349
|
+
if (shouldLoadParts) {
|
12350
|
+
_this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
|
12351
|
+
_this.loadingParts = shouldLoadParts;
|
12352
|
+
}
|
12353
|
+
}
|
12354
|
+
}
|
12355
|
+
|
12356
|
+
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12357
|
+
if (!_this.loadedmetadata && !bufferInfo.len) {
|
12358
|
+
_this.nextLoadPosition = _this.startPosition = currentTime;
|
12359
|
+
}
|
12360
|
+
|
12361
|
+
// Async tick to speed up processing
|
12362
|
+
_this.tickImmediate();
|
12363
|
+
};
|
12364
|
+
_this.onMediaEnded = function () {
|
12365
|
+
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12366
|
+
_this.startPosition = _this.lastCurrentTime = 0;
|
12367
|
+
if (_this.playlistType === PlaylistLevelType.MAIN) {
|
12368
|
+
_this.hls.trigger(Events.MEDIA_ENDED, {
|
12369
|
+
stalled: false
|
12370
|
+
});
|
12371
|
+
}
|
12372
|
+
};
|
12222
12373
|
_this.playlistType = playlistType;
|
12223
|
-
_this.logPrefix = logPrefix;
|
12224
|
-
_this.log = logger.log.bind(logger, logPrefix + ":");
|
12225
|
-
_this.warn = logger.warn.bind(logger, logPrefix + ":");
|
12226
12374
|
_this.hls = hls;
|
12227
12375
|
_this.fragmentLoader = new FragmentLoader(hls.config);
|
12228
12376
|
_this.keyLoader = keyLoader;
|
12229
12377
|
_this.fragmentTracker = fragmentTracker;
|
12230
12378
|
_this.config = hls.config;
|
12231
12379
|
_this.decrypter = new Decrypter(hls.config);
|
12232
|
-
hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
|
12233
12380
|
return _this;
|
12234
12381
|
}
|
12235
12382
|
var _proto = BaseStreamController.prototype;
|
12236
|
-
_proto.
|
12237
|
-
this.
|
12238
|
-
|
12239
|
-
|
12240
|
-
|
12383
|
+
_proto.registerListeners = function registerListeners() {
|
12384
|
+
var hls = this.hls;
|
12385
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12386
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12387
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12388
|
+
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12389
|
+
hls.on(Events.ERROR, this.onError, this);
|
12390
|
+
};
|
12391
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
12392
|
+
var hls = this.hls;
|
12393
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12394
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12395
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12396
|
+
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12397
|
+
hls.off(Events.ERROR, this.onError, this);
|
12398
|
+
};
|
12399
|
+
_proto.doTick = function doTick() {
|
12400
|
+
this.onTickEnd();
|
12401
|
+
};
|
12402
|
+
_proto.onTickEnd = function onTickEnd() {}
|
12403
|
+
|
12241
12404
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
12242
12405
|
;
|
12243
12406
|
_proto.startLoad = function startLoad(startPosition) {};
|
@@ -12256,6 +12419,12 @@
|
|
12256
12419
|
this.clearNextTick();
|
12257
12420
|
this.state = State.STOPPED;
|
12258
12421
|
};
|
12422
|
+
_proto.pauseBuffering = function pauseBuffering() {
|
12423
|
+
this.buffering = false;
|
12424
|
+
};
|
12425
|
+
_proto.resumeBuffering = function resumeBuffering() {
|
12426
|
+
this.buffering = true;
|
12427
|
+
};
|
12259
12428
|
_proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
|
12260
12429
|
// If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
|
12261
12430
|
// of nothing loading/loaded return false
|
@@ -12286,10 +12455,8 @@
|
|
12286
12455
|
};
|
12287
12456
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
12288
12457
|
var media = this.media = this.mediaBuffer = data.media;
|
12289
|
-
|
12290
|
-
|
12291
|
-
media.addEventListener('seeking', this.onvseeking);
|
12292
|
-
media.addEventListener('ended', this.onvended);
|
12458
|
+
media.addEventListener('seeking', this.onMediaSeeking);
|
12459
|
+
media.addEventListener('ended', this.onMediaEnded);
|
12293
12460
|
var config = this.config;
|
12294
12461
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
12295
12462
|
this.startLoad(config.startPosition);
|
@@ -12303,10 +12470,9 @@
|
|
12303
12470
|
}
|
12304
12471
|
|
12305
12472
|
// remove video listeners
|
12306
|
-
if (media
|
12307
|
-
media.removeEventListener('seeking', this.
|
12308
|
-
media.removeEventListener('ended', this.
|
12309
|
-
this.onvseeking = this.onvended = null;
|
12473
|
+
if (media) {
|
12474
|
+
media.removeEventListener('seeking', this.onMediaSeeking);
|
12475
|
+
media.removeEventListener('ended', this.onMediaEnded);
|
12310
12476
|
}
|
12311
12477
|
if (this.keyLoader) {
|
12312
12478
|
this.keyLoader.detach();
|
@@ -12316,54 +12482,8 @@
|
|
12316
12482
|
this.fragmentTracker.removeAllFragments();
|
12317
12483
|
this.stopLoad();
|
12318
12484
|
};
|
12319
|
-
_proto.
|
12320
|
-
|
12321
|
-
fragCurrent = this.fragCurrent,
|
12322
|
-
media = this.media,
|
12323
|
-
mediaBuffer = this.mediaBuffer,
|
12324
|
-
state = this.state;
|
12325
|
-
var currentTime = media ? media.currentTime : 0;
|
12326
|
-
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12327
|
-
this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12328
|
-
if (this.state === State.ENDED) {
|
12329
|
-
this.resetLoadingState();
|
12330
|
-
} else if (fragCurrent) {
|
12331
|
-
// Seeking while frag load is in progress
|
12332
|
-
var tolerance = config.maxFragLookUpTolerance;
|
12333
|
-
var fragStartOffset = fragCurrent.start - tolerance;
|
12334
|
-
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12335
|
-
// if seeking out of buffered range or into new one
|
12336
|
-
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12337
|
-
var pastFragment = currentTime > fragEndOffset;
|
12338
|
-
// if the seek position is outside the current fragment range
|
12339
|
-
if (currentTime < fragStartOffset || pastFragment) {
|
12340
|
-
if (pastFragment && fragCurrent.loader) {
|
12341
|
-
this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12342
|
-
fragCurrent.abortRequests();
|
12343
|
-
this.resetLoadingState();
|
12344
|
-
}
|
12345
|
-
this.fragPrevious = null;
|
12346
|
-
}
|
12347
|
-
}
|
12348
|
-
}
|
12349
|
-
if (media) {
|
12350
|
-
// Remove gap fragments
|
12351
|
-
this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
|
12352
|
-
this.lastCurrentTime = currentTime;
|
12353
|
-
}
|
12354
|
-
|
12355
|
-
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12356
|
-
if (!this.loadedmetadata && !bufferInfo.len) {
|
12357
|
-
this.nextLoadPosition = this.startPosition = currentTime;
|
12358
|
-
}
|
12359
|
-
|
12360
|
-
// Async tick to speed up processing
|
12361
|
-
this.tickImmediate();
|
12362
|
-
};
|
12363
|
-
_proto.onMediaEnded = function onMediaEnded() {
|
12364
|
-
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12365
|
-
this.startPosition = this.lastCurrentTime = 0;
|
12366
|
-
};
|
12485
|
+
_proto.onManifestLoading = function onManifestLoading() {};
|
12486
|
+
_proto.onError = function onError(event, data) {};
|
12367
12487
|
_proto.onManifestLoaded = function onManifestLoaded(event, data) {
|
12368
12488
|
this.startTimeOffset = data.startTimeOffset;
|
12369
12489
|
this.initPTS = [];
|
@@ -12373,7 +12493,7 @@
|
|
12373
12493
|
this.stopLoad();
|
12374
12494
|
_TaskLoop.prototype.onHandlerDestroying.call(this);
|
12375
12495
|
// @ts-ignore
|
12376
|
-
this.hls = null;
|
12496
|
+
this.hls = this.onMediaSeeking = this.onMediaEnded = null;
|
12377
12497
|
};
|
12378
12498
|
_proto.onHandlerDestroyed = function onHandlerDestroyed() {
|
12379
12499
|
this.state = State.STOPPED;
|
@@ -12503,10 +12623,10 @@
|
|
12503
12623
|
var decryptData = frag.decryptdata;
|
12504
12624
|
|
12505
12625
|
// check to see if the payload needs to be decrypted
|
12506
|
-
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method
|
12626
|
+
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
|
12507
12627
|
var startTime = self.performance.now();
|
12508
12628
|
// decrypt init segment data
|
12509
|
-
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
|
12629
|
+
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
|
12510
12630
|
hls.trigger(Events.ERROR, {
|
12511
12631
|
type: ErrorTypes.MEDIA_ERROR,
|
12512
12632
|
details: ErrorDetails.FRAG_DECRYPT_ERROR,
|
@@ -12619,7 +12739,7 @@
|
|
12619
12739
|
}
|
12620
12740
|
var keyLoadingPromise = null;
|
12621
12741
|
if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
|
12622
|
-
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.
|
12742
|
+
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
|
12623
12743
|
this.state = State.KEY_LOADING;
|
12624
12744
|
this.fragCurrent = frag;
|
12625
12745
|
keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
|
@@ -12640,8 +12760,16 @@
|
|
12640
12760
|
} else if (!frag.encrypted && details.encryptedFragments.length) {
|
12641
12761
|
this.keyLoader.loadClear(frag, details.encryptedFragments);
|
12642
12762
|
}
|
12763
|
+
var fragPrevious = this.fragPrevious;
|
12764
|
+
if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
|
12765
|
+
var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
|
12766
|
+
if (shouldLoadParts !== this.loadingParts) {
|
12767
|
+
this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
|
12768
|
+
this.loadingParts = shouldLoadParts;
|
12769
|
+
}
|
12770
|
+
}
|
12643
12771
|
targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
|
12644
|
-
if (this.
|
12772
|
+
if (this.loadingParts && frag.sn !== 'initSegment') {
|
12645
12773
|
var partList = details.partList;
|
12646
12774
|
if (partList && progressCallback) {
|
12647
12775
|
if (targetBufferTime > frag.end && details.fragmentHint) {
|
@@ -12650,7 +12778,7 @@
|
|
12650
12778
|
var partIndex = this.getNextPart(partList, frag, targetBufferTime);
|
12651
12779
|
if (partIndex > -1) {
|
12652
12780
|
var part = partList[partIndex];
|
12653
|
-
this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.
|
12781
|
+
this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12654
12782
|
this.nextLoadPosition = part.start + part.duration;
|
12655
12783
|
this.state = State.FRAG_LOADING;
|
12656
12784
|
var _result;
|
@@ -12683,7 +12811,14 @@
|
|
12683
12811
|
}
|
12684
12812
|
}
|
12685
12813
|
}
|
12686
|
-
|
12814
|
+
if (frag.sn !== 'initSegment' && this.loadingParts) {
|
12815
|
+
this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
|
12816
|
+
this.loadingParts = false;
|
12817
|
+
} else if (!frag.url) {
|
12818
|
+
// Selected fragment hint for part but not loading parts
|
12819
|
+
return Promise.resolve(null);
|
12820
|
+
}
|
12821
|
+
this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12687
12822
|
// Don't update nextLoadPosition for fragments which are not buffered
|
12688
12823
|
if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
|
12689
12824
|
this.nextLoadPosition = frag.start + frag.duration;
|
@@ -12785,8 +12920,36 @@
|
|
12785
12920
|
if (part) {
|
12786
12921
|
part.stats.parsing.end = now;
|
12787
12922
|
}
|
12923
|
+
// See if part loading should be disabled/enabled based on buffer and playback position.
|
12924
|
+
if (frag.sn !== 'initSegment') {
|
12925
|
+
var levelDetails = this.getLevelDetails();
|
12926
|
+
var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
|
12927
|
+
var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
|
12928
|
+
if (shouldLoadParts !== this.loadingParts) {
|
12929
|
+
this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
|
12930
|
+
this.loadingParts = shouldLoadParts;
|
12931
|
+
}
|
12932
|
+
}
|
12788
12933
|
this.updateLevelTiming(frag, part, level, chunkMeta.partial);
|
12789
12934
|
};
|
12935
|
+
_proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
|
12936
|
+
if (this.config.lowLatencyMode) {
|
12937
|
+
if (!details) {
|
12938
|
+
return this.loadingParts;
|
12939
|
+
}
|
12940
|
+
if (details != null && details.partList) {
|
12941
|
+
var _details$fragmentHint;
|
12942
|
+
// Buffer must be ahead of first part + duration of parts after last segment
|
12943
|
+
// and playback must be at or past segment adjacent to part list
|
12944
|
+
var firstPart = details.partList[0];
|
12945
|
+
var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
|
12946
|
+
if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
|
12947
|
+
return true;
|
12948
|
+
}
|
12949
|
+
}
|
12950
|
+
}
|
12951
|
+
return false;
|
12952
|
+
};
|
12790
12953
|
_proto.getCurrentContext = function getCurrentContext(chunkMeta) {
|
12791
12954
|
var levels = this.levels,
|
12792
12955
|
fragCurrent = this.fragCurrent;
|
@@ -12921,7 +13084,8 @@
|
|
12921
13084
|
// find fragment index, contiguous with end of buffer position
|
12922
13085
|
var config = this.config;
|
12923
13086
|
var start = fragments[0].start;
|
12924
|
-
var
|
13087
|
+
var canLoadParts = config.lowLatencyMode && !!levelDetails.partList;
|
13088
|
+
var frag = null;
|
12925
13089
|
if (levelDetails.live) {
|
12926
13090
|
var initialLiveManifestSize = config.initialLiveManifestSize;
|
12927
13091
|
if (fragLen < initialLiveManifestSize) {
|
@@ -12933,6 +13097,10 @@
|
|
12933
13097
|
// Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
|
12934
13098
|
// we get the fragment matching that start time
|
12935
13099
|
if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
|
13100
|
+
if (canLoadParts && !this.loadingParts) {
|
13101
|
+
this.log("LL-Part loading ON for initial live fragment");
|
13102
|
+
this.loadingParts = true;
|
13103
|
+
}
|
12936
13104
|
frag = this.getInitialLiveFragment(levelDetails, fragments);
|
12937
13105
|
this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
|
12938
13106
|
}
|
@@ -12943,7 +13111,7 @@
|
|
12943
13111
|
|
12944
13112
|
// If we haven't run into any special cases already, just load the fragment most closely matching the requested position
|
12945
13113
|
if (!frag) {
|
12946
|
-
var end =
|
13114
|
+
var end = this.loadingParts ? levelDetails.partEnd : levelDetails.fragmentEnd;
|
12947
13115
|
frag = this.getFragmentAtPosition(pos, end, levelDetails);
|
12948
13116
|
}
|
12949
13117
|
return this.mapToInitFragWhenRequired(frag);
|
@@ -13057,7 +13225,7 @@
|
|
13057
13225
|
var fragmentHint = levelDetails.fragmentHint;
|
13058
13226
|
var tolerance = config.maxFragLookUpTolerance;
|
13059
13227
|
var partList = levelDetails.partList;
|
13060
|
-
var loadingParts = !!(
|
13228
|
+
var loadingParts = !!(this.loadingParts && partList != null && partList.length && fragmentHint);
|
13061
13229
|
if (loadingParts && fragmentHint && !this.bitrateTest) {
|
13062
13230
|
// Include incomplete fragment with parts at end
|
13063
13231
|
fragments = fragments.concat(fragmentHint);
|
@@ -13244,7 +13412,7 @@
|
|
13244
13412
|
errorAction.resolved = true;
|
13245
13413
|
}
|
13246
13414
|
} else {
|
13247
|
-
|
13415
|
+
this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
|
13248
13416
|
return;
|
13249
13417
|
}
|
13250
13418
|
} else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
@@ -13634,6 +13802,7 @@
|
|
13634
13802
|
*/
|
13635
13803
|
function getAudioConfig(observer, data, offset, audioCodec) {
|
13636
13804
|
var adtsObjectType;
|
13805
|
+
var originalAdtsObjectType;
|
13637
13806
|
var adtsExtensionSamplingIndex;
|
13638
13807
|
var adtsChannelConfig;
|
13639
13808
|
var config;
|
@@ -13641,7 +13810,7 @@
|
|
13641
13810
|
var manifestCodec = audioCodec;
|
13642
13811
|
var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
13643
13812
|
// byte 2
|
13644
|
-
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13813
|
+
adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13645
13814
|
var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
13646
13815
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
13647
13816
|
var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
|
@@ -13658,8 +13827,8 @@
|
|
13658
13827
|
// byte 3
|
13659
13828
|
adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
|
13660
13829
|
logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
|
13661
|
-
//
|
13662
|
-
if (/firefox/i.test(userAgent)) {
|
13830
|
+
// Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
|
13831
|
+
if (/firefox|palemoon/i.test(userAgent)) {
|
13663
13832
|
if (adtsSamplingIndex >= 6) {
|
13664
13833
|
adtsObjectType = 5;
|
13665
13834
|
config = new Array(4);
|
@@ -13753,6 +13922,7 @@
|
|
13753
13922
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
13754
13923
|
channelCount: adtsChannelConfig,
|
13755
13924
|
codec: 'mp4a.40.' + adtsObjectType,
|
13925
|
+
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
13756
13926
|
manifestCodec: manifestCodec
|
13757
13927
|
};
|
13758
13928
|
}
|
@@ -13807,7 +13977,8 @@
|
|
13807
13977
|
track.channelCount = config.channelCount;
|
13808
13978
|
track.codec = config.codec;
|
13809
13979
|
track.manifestCodec = config.manifestCodec;
|
13810
|
-
|
13980
|
+
track.parsedCodec = config.parsedCodec;
|
13981
|
+
logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
|
13811
13982
|
}
|
13812
13983
|
}
|
13813
13984
|
function getFrameDuration(samplerate) {
|
@@ -14287,6 +14458,110 @@
|
|
14287
14458
|
logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
|
14288
14459
|
}
|
14289
14460
|
};
|
14461
|
+
_proto.parseNALu = function parseNALu(track, array) {
|
14462
|
+
var len = array.byteLength;
|
14463
|
+
var state = track.naluState || 0;
|
14464
|
+
var lastState = state;
|
14465
|
+
var units = [];
|
14466
|
+
var i = 0;
|
14467
|
+
var value;
|
14468
|
+
var overflow;
|
14469
|
+
var unitType;
|
14470
|
+
var lastUnitStart = -1;
|
14471
|
+
var lastUnitType = 0;
|
14472
|
+
// logger.log('PES:' + Hex.hexDump(array));
|
14473
|
+
|
14474
|
+
if (state === -1) {
|
14475
|
+
// special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
|
14476
|
+
lastUnitStart = 0;
|
14477
|
+
// NALu type is value read from offset 0
|
14478
|
+
lastUnitType = this.getNALuType(array, 0);
|
14479
|
+
state = 0;
|
14480
|
+
i = 1;
|
14481
|
+
}
|
14482
|
+
while (i < len) {
|
14483
|
+
value = array[i++];
|
14484
|
+
// optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
|
14485
|
+
if (!state) {
|
14486
|
+
state = value ? 0 : 1;
|
14487
|
+
continue;
|
14488
|
+
}
|
14489
|
+
if (state === 1) {
|
14490
|
+
state = value ? 0 : 2;
|
14491
|
+
continue;
|
14492
|
+
}
|
14493
|
+
// here we have state either equal to 2 or 3
|
14494
|
+
if (!value) {
|
14495
|
+
state = 3;
|
14496
|
+
} else if (value === 1) {
|
14497
|
+
overflow = i - state - 1;
|
14498
|
+
if (lastUnitStart >= 0) {
|
14499
|
+
var unit = {
|
14500
|
+
data: array.subarray(lastUnitStart, overflow),
|
14501
|
+
type: lastUnitType
|
14502
|
+
};
|
14503
|
+
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14504
|
+
units.push(unit);
|
14505
|
+
} else {
|
14506
|
+
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14507
|
+
// first check if start code delimiter is overlapping between 2 PES packets,
|
14508
|
+
// ie it started in last packet (lastState not zero)
|
14509
|
+
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14510
|
+
var lastUnit = this.getLastNalUnit(track.samples);
|
14511
|
+
if (lastUnit) {
|
14512
|
+
if (lastState && i <= 4 - lastState) {
|
14513
|
+
// start delimiter overlapping between PES packets
|
14514
|
+
// strip start delimiter bytes from the end of last NAL unit
|
14515
|
+
// check if lastUnit had a state different from zero
|
14516
|
+
if (lastUnit.state) {
|
14517
|
+
// strip last bytes
|
14518
|
+
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14519
|
+
}
|
14520
|
+
}
|
14521
|
+
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14522
|
+
|
14523
|
+
if (overflow > 0) {
|
14524
|
+
// logger.log('first NALU found with overflow:' + overflow);
|
14525
|
+
lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
|
14526
|
+
lastUnit.state = 0;
|
14527
|
+
}
|
14528
|
+
}
|
14529
|
+
}
|
14530
|
+
// check if we can read unit type
|
14531
|
+
if (i < len) {
|
14532
|
+
unitType = this.getNALuType(array, i);
|
14533
|
+
// logger.log('find NALU @ offset:' + i + ',type:' + unitType);
|
14534
|
+
lastUnitStart = i;
|
14535
|
+
lastUnitType = unitType;
|
14536
|
+
state = 0;
|
14537
|
+
} else {
|
14538
|
+
// not enough byte to read unit type. let's read it on next PES parsing
|
14539
|
+
state = -1;
|
14540
|
+
}
|
14541
|
+
} else {
|
14542
|
+
state = 0;
|
14543
|
+
}
|
14544
|
+
}
|
14545
|
+
if (lastUnitStart >= 0 && state >= 0) {
|
14546
|
+
var _unit = {
|
14547
|
+
data: array.subarray(lastUnitStart, len),
|
14548
|
+
type: lastUnitType,
|
14549
|
+
state: state
|
14550
|
+
};
|
14551
|
+
units.push(_unit);
|
14552
|
+
// logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
|
14553
|
+
}
|
14554
|
+
// no NALu found
|
14555
|
+
if (units.length === 0) {
|
14556
|
+
// append pes.data to previous NAL unit
|
14557
|
+
var _lastUnit = this.getLastNalUnit(track.samples);
|
14558
|
+
if (_lastUnit) {
|
14559
|
+
_lastUnit.data = appendUint8Array(_lastUnit.data, array);
|
14560
|
+
}
|
14561
|
+
}
|
14562
|
+
track.naluState = state;
|
14563
|
+
return units;
|
14564
|
+
};
|
14290
14565
|
return BaseVideoParser;
|
14291
14566
|
}();
|
14292
14567
|
|
@@ -14441,189 +14716,6 @@
|
|
14441
14716
|
;
|
14442
14717
|
_proto.readUInt = function readUInt() {
|
14443
14718
|
return this.readBits(32);
|
14444
|
-
}
|
14445
|
-
|
14446
|
-
/**
|
14447
|
-
* Advance the ExpGolomb decoder past a scaling list. The scaling
|
14448
|
-
* list is optionally transmitted as part of a sequence parameter
|
14449
|
-
* set and is not relevant to transmuxing.
|
14450
|
-
* @param count the number of entries in this scaling list
|
14451
|
-
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14452
|
-
*/;
|
14453
|
-
_proto.skipScalingList = function skipScalingList(count) {
|
14454
|
-
var lastScale = 8;
|
14455
|
-
var nextScale = 8;
|
14456
|
-
var deltaScale;
|
14457
|
-
for (var j = 0; j < count; j++) {
|
14458
|
-
if (nextScale !== 0) {
|
14459
|
-
deltaScale = this.readEG();
|
14460
|
-
nextScale = (lastScale + deltaScale + 256) % 256;
|
14461
|
-
}
|
14462
|
-
lastScale = nextScale === 0 ? lastScale : nextScale;
|
14463
|
-
}
|
14464
|
-
}
|
14465
|
-
|
14466
|
-
/**
|
14467
|
-
* Read a sequence parameter set and return some interesting video
|
14468
|
-
* properties. A sequence parameter set is the H264 metadata that
|
14469
|
-
* describes the properties of upcoming video frames.
|
14470
|
-
* @returns an object with configuration parsed from the
|
14471
|
-
* sequence parameter set, including the dimensions of the
|
14472
|
-
* associated video frames.
|
14473
|
-
*/;
|
14474
|
-
_proto.readSPS = function readSPS() {
|
14475
|
-
var frameCropLeftOffset = 0;
|
14476
|
-
var frameCropRightOffset = 0;
|
14477
|
-
var frameCropTopOffset = 0;
|
14478
|
-
var frameCropBottomOffset = 0;
|
14479
|
-
var numRefFramesInPicOrderCntCycle;
|
14480
|
-
var scalingListCount;
|
14481
|
-
var i;
|
14482
|
-
var readUByte = this.readUByte.bind(this);
|
14483
|
-
var readBits = this.readBits.bind(this);
|
14484
|
-
var readUEG = this.readUEG.bind(this);
|
14485
|
-
var readBoolean = this.readBoolean.bind(this);
|
14486
|
-
var skipBits = this.skipBits.bind(this);
|
14487
|
-
var skipEG = this.skipEG.bind(this);
|
14488
|
-
var skipUEG = this.skipUEG.bind(this);
|
14489
|
-
var skipScalingList = this.skipScalingList.bind(this);
|
14490
|
-
readUByte();
|
14491
|
-
var profileIdc = readUByte(); // profile_idc
|
14492
|
-
readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
|
14493
|
-
skipBits(3); // reserved_zero_3bits u(3),
|
14494
|
-
readUByte(); // level_idc u(8)
|
14495
|
-
skipUEG(); // seq_parameter_set_id
|
14496
|
-
// some profiles have more optional data we don't need
|
14497
|
-
if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
|
14498
|
-
var chromaFormatIdc = readUEG();
|
14499
|
-
if (chromaFormatIdc === 3) {
|
14500
|
-
skipBits(1);
|
14501
|
-
} // separate_colour_plane_flag
|
14502
|
-
|
14503
|
-
skipUEG(); // bit_depth_luma_minus8
|
14504
|
-
skipUEG(); // bit_depth_chroma_minus8
|
14505
|
-
skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
14506
|
-
if (readBoolean()) {
|
14507
|
-
// seq_scaling_matrix_present_flag
|
14508
|
-
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
|
14509
|
-
for (i = 0; i < scalingListCount; i++) {
|
14510
|
-
if (readBoolean()) {
|
14511
|
-
// seq_scaling_list_present_flag[ i ]
|
14512
|
-
if (i < 6) {
|
14513
|
-
skipScalingList(16);
|
14514
|
-
} else {
|
14515
|
-
skipScalingList(64);
|
14516
|
-
}
|
14517
|
-
}
|
14518
|
-
}
|
14519
|
-
}
|
14520
|
-
}
|
14521
|
-
skipUEG(); // log2_max_frame_num_minus4
|
14522
|
-
var picOrderCntType = readUEG();
|
14523
|
-
if (picOrderCntType === 0) {
|
14524
|
-
readUEG(); // log2_max_pic_order_cnt_lsb_minus4
|
14525
|
-
} else if (picOrderCntType === 1) {
|
14526
|
-
skipBits(1); // delta_pic_order_always_zero_flag
|
14527
|
-
skipEG(); // offset_for_non_ref_pic
|
14528
|
-
skipEG(); // offset_for_top_to_bottom_field
|
14529
|
-
numRefFramesInPicOrderCntCycle = readUEG();
|
14530
|
-
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
14531
|
-
skipEG();
|
14532
|
-
} // offset_for_ref_frame[ i ]
|
14533
|
-
}
|
14534
|
-
skipUEG(); // max_num_ref_frames
|
14535
|
-
skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
14536
|
-
var picWidthInMbsMinus1 = readUEG();
|
14537
|
-
var picHeightInMapUnitsMinus1 = readUEG();
|
14538
|
-
var frameMbsOnlyFlag = readBits(1);
|
14539
|
-
if (frameMbsOnlyFlag === 0) {
|
14540
|
-
skipBits(1);
|
14541
|
-
} // mb_adaptive_frame_field_flag
|
14542
|
-
|
14543
|
-
skipBits(1); // direct_8x8_inference_flag
|
14544
|
-
if (readBoolean()) {
|
14545
|
-
// frame_cropping_flag
|
14546
|
-
frameCropLeftOffset = readUEG();
|
14547
|
-
frameCropRightOffset = readUEG();
|
14548
|
-
frameCropTopOffset = readUEG();
|
14549
|
-
frameCropBottomOffset = readUEG();
|
14550
|
-
}
|
14551
|
-
var pixelRatio = [1, 1];
|
14552
|
-
if (readBoolean()) {
|
14553
|
-
// vui_parameters_present_flag
|
14554
|
-
if (readBoolean()) {
|
14555
|
-
// aspect_ratio_info_present_flag
|
14556
|
-
var aspectRatioIdc = readUByte();
|
14557
|
-
switch (aspectRatioIdc) {
|
14558
|
-
case 1:
|
14559
|
-
pixelRatio = [1, 1];
|
14560
|
-
break;
|
14561
|
-
case 2:
|
14562
|
-
pixelRatio = [12, 11];
|
14563
|
-
break;
|
14564
|
-
case 3:
|
14565
|
-
pixelRatio = [10, 11];
|
14566
|
-
break;
|
14567
|
-
case 4:
|
14568
|
-
pixelRatio = [16, 11];
|
14569
|
-
break;
|
14570
|
-
case 5:
|
14571
|
-
pixelRatio = [40, 33];
|
14572
|
-
break;
|
14573
|
-
case 6:
|
14574
|
-
pixelRatio = [24, 11];
|
14575
|
-
break;
|
14576
|
-
case 7:
|
14577
|
-
pixelRatio = [20, 11];
|
14578
|
-
break;
|
14579
|
-
case 8:
|
14580
|
-
pixelRatio = [32, 11];
|
14581
|
-
break;
|
14582
|
-
case 9:
|
14583
|
-
pixelRatio = [80, 33];
|
14584
|
-
break;
|
14585
|
-
case 10:
|
14586
|
-
pixelRatio = [18, 11];
|
14587
|
-
break;
|
14588
|
-
case 11:
|
14589
|
-
pixelRatio = [15, 11];
|
14590
|
-
break;
|
14591
|
-
case 12:
|
14592
|
-
pixelRatio = [64, 33];
|
14593
|
-
break;
|
14594
|
-
case 13:
|
14595
|
-
pixelRatio = [160, 99];
|
14596
|
-
break;
|
14597
|
-
case 14:
|
14598
|
-
pixelRatio = [4, 3];
|
14599
|
-
break;
|
14600
|
-
case 15:
|
14601
|
-
pixelRatio = [3, 2];
|
14602
|
-
break;
|
14603
|
-
case 16:
|
14604
|
-
pixelRatio = [2, 1];
|
14605
|
-
break;
|
14606
|
-
case 255:
|
14607
|
-
{
|
14608
|
-
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
|
14609
|
-
break;
|
14610
|
-
}
|
14611
|
-
}
|
14612
|
-
}
|
14613
|
-
}
|
14614
|
-
return {
|
14615
|
-
width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
|
14616
|
-
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
|
14617
|
-
pixelRatio: pixelRatio
|
14618
|
-
};
|
14619
|
-
};
|
14620
|
-
_proto.readSliceType = function readSliceType() {
|
14621
|
-
// skip NALu type
|
14622
|
-
this.readUByte();
|
14623
|
-
// discard first_mb_in_slice
|
14624
|
-
this.readUEG();
|
14625
|
-
// return slice_type
|
14626
|
-
return this.readUEG();
|
14627
14719
|
};
|
14628
14720
|
return ExpGolomb;
|
14629
14721
|
}();
|
@@ -14634,9 +14726,9 @@
|
|
14634
14726
|
return _BaseVideoParser.apply(this, arguments) || this;
|
14635
14727
|
}
|
14636
14728
|
var _proto = AvcVideoParser.prototype;
|
14637
|
-
_proto.
|
14729
|
+
_proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
|
14638
14730
|
var _this = this;
|
14639
|
-
var units = this.
|
14731
|
+
var units = this.parseNALu(track, pes.data);
|
14640
14732
|
var VideoSample = this.VideoSample;
|
14641
14733
|
var push;
|
14642
14734
|
var spsfound = false;
|
@@ -14661,7 +14753,7 @@
|
|
14661
14753
|
// only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
|
14662
14754
|
if (spsfound && data.length > 4) {
|
14663
14755
|
// retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
|
14664
|
-
var sliceType =
|
14756
|
+
var sliceType = _this.readSliceType(data);
|
14665
14757
|
// 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
|
14666
14758
|
// SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
|
14667
14759
|
// An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
|
@@ -14715,8 +14807,7 @@
|
|
14715
14807
|
push = true;
|
14716
14808
|
spsfound = true;
|
14717
14809
|
var sps = unit.data;
|
14718
|
-
var
|
14719
|
-
var config = expGolombDecoder.readSPS();
|
14810
|
+
var config = _this.readSPS(sps);
|
14720
14811
|
if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) {
|
14721
14812
|
track.width = config.width;
|
14722
14813
|
track.height = config.height;
|
@@ -14772,109 +14863,192 @@
|
|
14772
14863
|
this.VideoSample = null;
|
14773
14864
|
}
|
14774
14865
|
};
|
14775
|
-
_proto.
|
14776
|
-
|
14777
|
-
|
14778
|
-
|
14779
|
-
var
|
14780
|
-
|
14781
|
-
|
14782
|
-
|
14783
|
-
|
14784
|
-
|
14785
|
-
|
14786
|
-
|
14866
|
+
_proto.getNALuType = function getNALuType(data, offset) {
|
14867
|
+
return data[offset] & 0x1f;
|
14868
|
+
};
|
14869
|
+
_proto.readSliceType = function readSliceType(data) {
|
14870
|
+
var eg = new ExpGolomb(data);
|
14871
|
+
// skip NALu type
|
14872
|
+
eg.readUByte();
|
14873
|
+
// discard first_mb_in_slice
|
14874
|
+
eg.readUEG();
|
14875
|
+
// return slice_type
|
14876
|
+
return eg.readUEG();
|
14877
|
+
}
|
14787
14878
|
|
14788
|
-
|
14789
|
-
|
14790
|
-
|
14791
|
-
|
14792
|
-
|
14793
|
-
|
14794
|
-
|
14795
|
-
|
14796
|
-
|
14797
|
-
|
14798
|
-
|
14799
|
-
if (
|
14800
|
-
|
14801
|
-
|
14802
|
-
}
|
14803
|
-
if (state === 1) {
|
14804
|
-
state = value ? 0 : 2;
|
14805
|
-
continue;
|
14879
|
+
/**
|
14880
|
+
* The scaling list is optionally transmitted as part of a sequence parameter
|
14881
|
+
* set and is not relevant to transmuxing.
|
14882
|
+
* @param count the number of entries in this scaling list
|
14883
|
+
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14884
|
+
*/;
|
14885
|
+
_proto.skipScalingList = function skipScalingList(count, reader) {
|
14886
|
+
var lastScale = 8;
|
14887
|
+
var nextScale = 8;
|
14888
|
+
var deltaScale;
|
14889
|
+
for (var j = 0; j < count; j++) {
|
14890
|
+
if (nextScale !== 0) {
|
14891
|
+
deltaScale = reader.readEG();
|
14892
|
+
nextScale = (lastScale + deltaScale + 256) % 256;
|
14806
14893
|
}
|
14807
|
-
|
14808
|
-
|
14809
|
-
|
14810
|
-
} else if (value === 1) {
|
14811
|
-
overflow = i - state - 1;
|
14812
|
-
if (lastUnitStart >= 0) {
|
14813
|
-
var unit = {
|
14814
|
-
data: array.subarray(lastUnitStart, overflow),
|
14815
|
-
type: lastUnitType
|
14816
|
-
};
|
14817
|
-
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14818
|
-
units.push(unit);
|
14819
|
-
} else {
|
14820
|
-
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14821
|
-
// first check if start code delimiter is overlapping between 2 PES packets,
|
14822
|
-
// ie it started in last packet (lastState not zero)
|
14823
|
-
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14824
|
-
var lastUnit = this.getLastNalUnit(track.samples);
|
14825
|
-
if (lastUnit) {
|
14826
|
-
if (lastState && i <= 4 - lastState) {
|
14827
|
-
// start delimiter overlapping between PES packets
|
14828
|
-
// strip start delimiter bytes from the end of last NAL unit
|
14829
|
-
// check if lastUnit had a state different from zero
|
14830
|
-
if (lastUnit.state) {
|
14831
|
-
// strip last bytes
|
14832
|
-
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14833
|
-
}
|
14834
|
-
}
|
14835
|
-
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14894
|
+
lastScale = nextScale === 0 ? lastScale : nextScale;
|
14895
|
+
}
|
14896
|
+
}
|
14836
14897
|
|
14837
|
-
|
14838
|
-
|
14839
|
-
|
14840
|
-
|
14841
|
-
|
14842
|
-
|
14843
|
-
|
14844
|
-
|
14845
|
-
|
14846
|
-
|
14847
|
-
|
14848
|
-
|
14849
|
-
|
14850
|
-
|
14851
|
-
|
14852
|
-
|
14853
|
-
|
14898
|
+
/**
|
14899
|
+
* Read a sequence parameter set and return some interesting video
|
14900
|
+
* properties. A sequence parameter set is the H264 metadata that
|
14901
|
+
* describes the properties of upcoming video frames.
|
14902
|
+
* @returns an object with configuration parsed from the
|
14903
|
+
* sequence parameter set, including the dimensions of the
|
14904
|
+
* associated video frames.
|
14905
|
+
*/;
|
14906
|
+
_proto.readSPS = function readSPS(sps) {
|
14907
|
+
var eg = new ExpGolomb(sps);
|
14908
|
+
var frameCropLeftOffset = 0;
|
14909
|
+
var frameCropRightOffset = 0;
|
14910
|
+
var frameCropTopOffset = 0;
|
14911
|
+
var frameCropBottomOffset = 0;
|
14912
|
+
var numRefFramesInPicOrderCntCycle;
|
14913
|
+
var scalingListCount;
|
14914
|
+
var i;
|
14915
|
+
var readUByte = eg.readUByte.bind(eg);
|
14916
|
+
var readBits = eg.readBits.bind(eg);
|
14917
|
+
var readUEG = eg.readUEG.bind(eg);
|
14918
|
+
var readBoolean = eg.readBoolean.bind(eg);
|
14919
|
+
var skipBits = eg.skipBits.bind(eg);
|
14920
|
+
var skipEG = eg.skipEG.bind(eg);
|
14921
|
+
var skipUEG = eg.skipUEG.bind(eg);
|
14922
|
+
var skipScalingList = this.skipScalingList.bind(this);
|
14923
|
+
readUByte();
|
14924
|
+
var profileIdc = readUByte(); // profile_idc
|
14925
|
+
readBits(5); // profileCompat constraint_set[0-4]_flag, u(5)
|
14926
|
+
skipBits(3); // reserved_zero_3bits u(3),
|
14927
|
+
readUByte(); // level_idc u(8)
|
14928
|
+
skipUEG(); // seq_parameter_set_id
|
14929
|
+
// some profiles have more optional data we don't need
|
14930
|
+
if (profileIdc === 100 || profileIdc === 110 || profileIdc === 122 || profileIdc === 244 || profileIdc === 44 || profileIdc === 83 || profileIdc === 86 || profileIdc === 118 || profileIdc === 128) {
|
14931
|
+
var chromaFormatIdc = readUEG();
|
14932
|
+
if (chromaFormatIdc === 3) {
|
14933
|
+
skipBits(1);
|
14934
|
+
} // separate_colour_plane_flag
|
14935
|
+
|
14936
|
+
skipUEG(); // bit_depth_luma_minus8
|
14937
|
+
skipUEG(); // bit_depth_chroma_minus8
|
14938
|
+
skipBits(1); // qpprime_y_zero_transform_bypass_flag
|
14939
|
+
if (readBoolean()) {
|
14940
|
+
// seq_scaling_matrix_present_flag
|
14941
|
+
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
|
14942
|
+
for (i = 0; i < scalingListCount; i++) {
|
14943
|
+
if (readBoolean()) {
|
14944
|
+
// seq_scaling_list_present_flag[ i ]
|
14945
|
+
if (i < 6) {
|
14946
|
+
skipScalingList(16, eg);
|
14947
|
+
} else {
|
14948
|
+
skipScalingList(64, eg);
|
14949
|
+
}
|
14950
|
+
}
|
14854
14951
|
}
|
14855
|
-
} else {
|
14856
|
-
state = 0;
|
14857
14952
|
}
|
14858
14953
|
}
|
14859
|
-
|
14860
|
-
|
14861
|
-
|
14862
|
-
|
14863
|
-
|
14864
|
-
|
14865
|
-
|
14866
|
-
|
14954
|
+
skipUEG(); // log2_max_frame_num_minus4
|
14955
|
+
var picOrderCntType = readUEG();
|
14956
|
+
if (picOrderCntType === 0) {
|
14957
|
+
readUEG(); // log2_max_pic_order_cnt_lsb_minus4
|
14958
|
+
} else if (picOrderCntType === 1) {
|
14959
|
+
skipBits(1); // delta_pic_order_always_zero_flag
|
14960
|
+
skipEG(); // offset_for_non_ref_pic
|
14961
|
+
skipEG(); // offset_for_top_to_bottom_field
|
14962
|
+
numRefFramesInPicOrderCntCycle = readUEG();
|
14963
|
+
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
14964
|
+
skipEG();
|
14965
|
+
} // offset_for_ref_frame[ i ]
|
14867
14966
|
}
|
14868
|
-
//
|
14869
|
-
|
14870
|
-
|
14871
|
-
|
14872
|
-
|
14873
|
-
|
14967
|
+
skipUEG(); // max_num_ref_frames
|
14968
|
+
skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
14969
|
+
var picWidthInMbsMinus1 = readUEG();
|
14970
|
+
var picHeightInMapUnitsMinus1 = readUEG();
|
14971
|
+
var frameMbsOnlyFlag = readBits(1);
|
14972
|
+
if (frameMbsOnlyFlag === 0) {
|
14973
|
+
skipBits(1);
|
14974
|
+
} // mb_adaptive_frame_field_flag
|
14975
|
+
|
14976
|
+
skipBits(1); // direct_8x8_inference_flag
|
14977
|
+
if (readBoolean()) {
|
14978
|
+
// frame_cropping_flag
|
14979
|
+
frameCropLeftOffset = readUEG();
|
14980
|
+
frameCropRightOffset = readUEG();
|
14981
|
+
frameCropTopOffset = readUEG();
|
14982
|
+
frameCropBottomOffset = readUEG();
|
14983
|
+
}
|
14984
|
+
var pixelRatio = [1, 1];
|
14985
|
+
if (readBoolean()) {
|
14986
|
+
// vui_parameters_present_flag
|
14987
|
+
if (readBoolean()) {
|
14988
|
+
// aspect_ratio_info_present_flag
|
14989
|
+
var aspectRatioIdc = readUByte();
|
14990
|
+
switch (aspectRatioIdc) {
|
14991
|
+
case 1:
|
14992
|
+
pixelRatio = [1, 1];
|
14993
|
+
break;
|
14994
|
+
case 2:
|
14995
|
+
pixelRatio = [12, 11];
|
14996
|
+
break;
|
14997
|
+
case 3:
|
14998
|
+
pixelRatio = [10, 11];
|
14999
|
+
break;
|
15000
|
+
case 4:
|
15001
|
+
pixelRatio = [16, 11];
|
15002
|
+
break;
|
15003
|
+
case 5:
|
15004
|
+
pixelRatio = [40, 33];
|
15005
|
+
break;
|
15006
|
+
case 6:
|
15007
|
+
pixelRatio = [24, 11];
|
15008
|
+
break;
|
15009
|
+
case 7:
|
15010
|
+
pixelRatio = [20, 11];
|
15011
|
+
break;
|
15012
|
+
case 8:
|
15013
|
+
pixelRatio = [32, 11];
|
15014
|
+
break;
|
15015
|
+
case 9:
|
15016
|
+
pixelRatio = [80, 33];
|
15017
|
+
break;
|
15018
|
+
case 10:
|
15019
|
+
pixelRatio = [18, 11];
|
15020
|
+
break;
|
15021
|
+
case 11:
|
15022
|
+
pixelRatio = [15, 11];
|
15023
|
+
break;
|
15024
|
+
case 12:
|
15025
|
+
pixelRatio = [64, 33];
|
15026
|
+
break;
|
15027
|
+
case 13:
|
15028
|
+
pixelRatio = [160, 99];
|
15029
|
+
break;
|
15030
|
+
case 14:
|
15031
|
+
pixelRatio = [4, 3];
|
15032
|
+
break;
|
15033
|
+
case 15:
|
15034
|
+
pixelRatio = [3, 2];
|
15035
|
+
break;
|
15036
|
+
case 16:
|
15037
|
+
pixelRatio = [2, 1];
|
15038
|
+
break;
|
15039
|
+
case 255:
|
15040
|
+
{
|
15041
|
+
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
|
15042
|
+
break;
|
15043
|
+
}
|
15044
|
+
}
|
14874
15045
|
}
|
14875
15046
|
}
|
14876
|
-
|
14877
|
-
|
15047
|
+
return {
|
15048
|
+
width: Math.ceil((picWidthInMbsMinus1 + 1) * 16 - frameCropLeftOffset * 2 - frameCropRightOffset * 2),
|
15049
|
+
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
|
15050
|
+
pixelRatio: pixelRatio
|
15051
|
+
};
|
14878
15052
|
};
|
14879
15053
|
return AvcVideoParser;
|
14880
15054
|
}(BaseVideoParser);
|
@@ -14894,7 +15068,7 @@
|
|
14894
15068
|
}
|
14895
15069
|
var _proto = SampleAesDecrypter.prototype;
|
14896
15070
|
_proto.decryptBuffer = function decryptBuffer(encryptedData) {
|
14897
|
-
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
|
15071
|
+
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
|
14898
15072
|
}
|
14899
15073
|
|
14900
15074
|
// AAC - encrypt all full 16 bytes blocks starting from offset 16
|
@@ -15013,7 +15187,7 @@
|
|
15013
15187
|
this.observer = observer;
|
15014
15188
|
this.config = config;
|
15015
15189
|
this.typeSupported = typeSupported;
|
15016
|
-
this.videoParser =
|
15190
|
+
this.videoParser = null;
|
15017
15191
|
}
|
15018
15192
|
TSDemuxer.probe = function probe(data) {
|
15019
15193
|
var syncOffset = TSDemuxer.syncOffset(data);
|
@@ -15183,7 +15357,16 @@
|
|
15183
15357
|
case videoPid:
|
15184
15358
|
if (stt) {
|
15185
15359
|
if (videoData && (pes = parsePES(videoData))) {
|
15186
|
-
this.videoParser
|
15360
|
+
if (this.videoParser === null) {
|
15361
|
+
switch (videoTrack.segmentCodec) {
|
15362
|
+
case 'avc':
|
15363
|
+
this.videoParser = new AvcVideoParser();
|
15364
|
+
break;
|
15365
|
+
}
|
15366
|
+
}
|
15367
|
+
if (this.videoParser !== null) {
|
15368
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
|
15369
|
+
}
|
15187
15370
|
}
|
15188
15371
|
videoData = {
|
15189
15372
|
data: [],
|
@@ -15341,8 +15524,17 @@
|
|
15341
15524
|
// try to parse last PES packets
|
15342
15525
|
var pes;
|
15343
15526
|
if (videoData && (pes = parsePES(videoData))) {
|
15344
|
-
this.videoParser
|
15345
|
-
|
15527
|
+
if (this.videoParser === null) {
|
15528
|
+
switch (videoTrack.segmentCodec) {
|
15529
|
+
case 'avc':
|
15530
|
+
this.videoParser = new AvcVideoParser();
|
15531
|
+
break;
|
15532
|
+
}
|
15533
|
+
}
|
15534
|
+
if (this.videoParser !== null) {
|
15535
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
|
15536
|
+
videoTrack.pesData = null;
|
15537
|
+
}
|
15346
15538
|
} else {
|
15347
15539
|
// either avcData null or PES truncated, keep it for next frag parsing
|
15348
15540
|
videoTrack.pesData = videoData;
|
@@ -15644,7 +15836,10 @@
|
|
15644
15836
|
logger.warn('Unsupported EC-3 in M2TS found');
|
15645
15837
|
break;
|
15646
15838
|
case 0x24:
|
15647
|
-
|
15839
|
+
// ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
|
15840
|
+
{
|
15841
|
+
logger.warn('Unsupported HEVC in M2TS found');
|
15842
|
+
}
|
15648
15843
|
break;
|
15649
15844
|
}
|
15650
15845
|
// move to the next table entry
|
@@ -15872,6 +16067,8 @@
|
|
15872
16067
|
avc1: [],
|
15873
16068
|
// codingname
|
15874
16069
|
avcC: [],
|
16070
|
+
hvc1: [],
|
16071
|
+
hvcC: [],
|
15875
16072
|
btrt: [],
|
15876
16073
|
dinf: [],
|
15877
16074
|
dref: [],
|
@@ -16299,8 +16496,10 @@
|
|
16299
16496
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
|
16300
16497
|
}
|
16301
16498
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
|
16302
|
-
} else {
|
16499
|
+
} else if (track.segmentCodec === 'avc') {
|
16303
16500
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
|
16501
|
+
} else {
|
16502
|
+
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
|
16304
16503
|
}
|
16305
16504
|
};
|
16306
16505
|
MP4.tkhd = function tkhd(track) {
|
@@ -16438,6 +16637,84 @@
|
|
16438
16637
|
var result = appendUint8Array(MP4.FTYP, movie);
|
16439
16638
|
return result;
|
16440
16639
|
};
|
16640
|
+
MP4.hvc1 = function hvc1(track) {
|
16641
|
+
var ps = track.params;
|
16642
|
+
var units = [track.vps, track.sps, track.pps];
|
16643
|
+
var NALuLengthSize = 4;
|
16644
|
+
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]);
|
16645
|
+
|
16646
|
+
// compute hvcC size in bytes
|
16647
|
+
var length = config.length;
|
16648
|
+
for (var i = 0; i < units.length; i += 1) {
|
16649
|
+
length += 3;
|
16650
|
+
for (var j = 0; j < units[i].length; j += 1) {
|
16651
|
+
length += 2 + units[i][j].length;
|
16652
|
+
}
|
16653
|
+
}
|
16654
|
+
var hvcC = new Uint8Array(length);
|
16655
|
+
hvcC.set(config, 0);
|
16656
|
+
length = config.length;
|
16657
|
+
// append parameter set units: one vps, one or more sps and pps
|
16658
|
+
var iMax = units.length - 1;
|
16659
|
+
for (var _i = 0; _i < units.length; _i += 1) {
|
16660
|
+
hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
|
16661
|
+
length += 3;
|
16662
|
+
for (var _j = 0; _j < units[_i].length; _j += 1) {
|
16663
|
+
hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
|
16664
|
+
length += 2;
|
16665
|
+
hvcC.set(units[_i][_j], length);
|
16666
|
+
length += units[_i][_j].length;
|
16667
|
+
}
|
16668
|
+
}
|
16669
|
+
var hvcc = MP4.box(MP4.types.hvcC, hvcC);
|
16670
|
+
var width = track.width;
|
16671
|
+
var height = track.height;
|
16672
|
+
var hSpacing = track.pixelRatio[0];
|
16673
|
+
var vSpacing = track.pixelRatio[1];
|
16674
|
+
return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
|
16675
|
+
// reserved
|
16676
|
+
0x00, 0x00, 0x00,
|
16677
|
+
// reserved
|
16678
|
+
0x00, 0x01,
|
16679
|
+
// data_reference_index
|
16680
|
+
0x00, 0x00,
|
16681
|
+
// pre_defined
|
16682
|
+
0x00, 0x00,
|
16683
|
+
// reserved
|
16684
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
16685
|
+
// pre_defined
|
16686
|
+
width >> 8 & 0xff, width & 0xff,
|
16687
|
+
// width
|
16688
|
+
height >> 8 & 0xff, height & 0xff,
|
16689
|
+
// height
|
16690
|
+
0x00, 0x48, 0x00, 0x00,
|
16691
|
+
// horizresolution
|
16692
|
+
0x00, 0x48, 0x00, 0x00,
|
16693
|
+
// vertresolution
|
16694
|
+
0x00, 0x00, 0x00, 0x00,
|
16695
|
+
// reserved
|
16696
|
+
0x00, 0x01,
|
16697
|
+
// frame_count
|
16698
|
+
0x12, 0x64, 0x61, 0x69, 0x6c,
|
16699
|
+
// dailymotion/hls.js
|
16700
|
+
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,
|
16701
|
+
// compressorname
|
16702
|
+
0x00, 0x18,
|
16703
|
+
// depth = 24
|
16704
|
+
0x11, 0x11]),
|
16705
|
+
// pre_defined = -1
|
16706
|
+
hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
|
16707
|
+
// bufferSizeDB
|
16708
|
+
0x00, 0x2d, 0xc6, 0xc0,
|
16709
|
+
// maxBitrate
|
16710
|
+
0x00, 0x2d, 0xc6, 0xc0])),
|
16711
|
+
// avgBitrate
|
16712
|
+
MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
|
16713
|
+
// hSpacing
|
16714
|
+
hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
|
16715
|
+
// vSpacing
|
16716
|
+
vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
|
16717
|
+
};
|
16441
16718
|
return MP4;
|
16442
16719
|
}();
|
16443
16720
|
MP4.types = void 0;
|
@@ -16824,9 +17101,9 @@
|
|
16824
17101
|
var foundOverlap = delta < -1;
|
16825
17102
|
if (foundHole || foundOverlap) {
|
16826
17103
|
if (foundHole) {
|
16827
|
-
logger.warn("
|
17104
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
|
16828
17105
|
} else {
|
16829
|
-
logger.warn("
|
17106
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
|
16830
17107
|
}
|
16831
17108
|
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
|
16832
17109
|
firstDTS = nextAvcDts;
|
@@ -16835,12 +17112,24 @@
|
|
16835
17112
|
inputSamples[0].dts = firstDTS;
|
16836
17113
|
inputSamples[0].pts = firstPTS;
|
16837
17114
|
} else {
|
17115
|
+
var isPTSOrderRetained = true;
|
16838
17116
|
for (var _i = 0; _i < inputSamples.length; _i++) {
|
16839
|
-
if (inputSamples[_i].dts > firstPTS) {
|
17117
|
+
if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
|
16840
17118
|
break;
|
16841
17119
|
}
|
17120
|
+
var prevPTS = inputSamples[_i].pts;
|
16842
17121
|
inputSamples[_i].dts -= delta;
|
16843
17122
|
inputSamples[_i].pts -= delta;
|
17123
|
+
|
17124
|
+
// check to see if this sample's PTS order has changed
|
17125
|
+
// relative to the next one
|
17126
|
+
if (_i < inputSamples.length - 1) {
|
17127
|
+
var nextSamplePTS = inputSamples[_i + 1].pts;
|
17128
|
+
var currentSamplePTS = inputSamples[_i].pts;
|
17129
|
+
var currentOrder = nextSamplePTS <= currentSamplePTS;
|
17130
|
+
var prevOrder = nextSamplePTS <= prevPTS;
|
17131
|
+
isPTSOrderRetained = currentOrder == prevOrder;
|
17132
|
+
}
|
16844
17133
|
}
|
16845
17134
|
}
|
16846
17135
|
logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
|
@@ -16988,7 +17277,7 @@
|
|
16988
17277
|
}
|
16989
17278
|
}
|
16990
17279
|
}
|
16991
|
-
// next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
17280
|
+
// next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
16992
17281
|
mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
|
16993
17282
|
this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
|
16994
17283
|
this.videoSampleDuration = mp4SampleDuration;
|
@@ -17123,7 +17412,7 @@
|
|
17123
17412
|
logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
|
17124
17413
|
for (var j = 0; j < missing; j++) {
|
17125
17414
|
var newStamp = Math.max(nextPts, 0);
|
17126
|
-
var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17415
|
+
var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17127
17416
|
if (!fillFrame) {
|
17128
17417
|
logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
17129
17418
|
fillFrame = sample.unit.subarray();
|
@@ -17251,7 +17540,7 @@
|
|
17251
17540
|
// samples count of this segment's duration
|
17252
17541
|
var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
|
17253
17542
|
// silent frame
|
17254
|
-
var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17543
|
+
var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17255
17544
|
logger.warn('[mp4-remuxer]: remux empty Audio');
|
17256
17545
|
// Can't remux if we can't generate a silent frame...
|
17257
17546
|
if (!silentFrame) {
|
@@ -17638,13 +17927,15 @@
|
|
17638
17927
|
duration = transmuxConfig.duration,
|
17639
17928
|
initSegmentData = transmuxConfig.initSegmentData;
|
17640
17929
|
var keyData = getEncryptionType(uintData, decryptdata);
|
17641
|
-
if (keyData && keyData.method
|
17930
|
+
if (keyData && isFullSegmentEncryption(keyData.method)) {
|
17642
17931
|
var decrypter = this.getDecrypter();
|
17932
|
+
var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
17933
|
+
|
17643
17934
|
// Software decryption is synchronous; webCrypto is not
|
17644
17935
|
if (decrypter.isSync()) {
|
17645
17936
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
17646
17937
|
// data is handled in the flush() call
|
17647
|
-
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
|
17938
|
+
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
|
17648
17939
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
17649
17940
|
var loadingParts = chunkMeta.part > -1;
|
17650
17941
|
if (loadingParts) {
|
@@ -17656,7 +17947,7 @@
|
|
17656
17947
|
}
|
17657
17948
|
uintData = new Uint8Array(decryptedData);
|
17658
17949
|
} else {
|
17659
|
-
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
|
17950
|
+
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
|
17660
17951
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
17661
17952
|
// the decrypted data has been transmuxed
|
17662
17953
|
var result = _this.push(decryptedData, null, chunkMeta);
|
@@ -18277,7 +18568,7 @@
|
|
18277
18568
|
observer.on(Events.ERROR, forwardMessage);
|
18278
18569
|
|
18279
18570
|
// forward logger events to main thread
|
18280
|
-
var forwardWorkerLogs = function forwardWorkerLogs() {
|
18571
|
+
var forwardWorkerLogs = function forwardWorkerLogs(logger) {
|
18281
18572
|
var _loop = function _loop(logFn) {
|
18282
18573
|
var func = function func(message) {
|
18283
18574
|
forwardMessage('workerLog', {
|
@@ -18298,8 +18589,8 @@
|
|
18298
18589
|
{
|
18299
18590
|
var config = JSON.parse(data.config);
|
18300
18591
|
self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
|
18301
|
-
enableLogs(config.debug, data.id);
|
18302
|
-
forwardWorkerLogs();
|
18592
|
+
var logger = enableLogs(config.debug, data.id);
|
18593
|
+
forwardWorkerLogs(logger);
|
18303
18594
|
forwardMessage('init', null);
|
18304
18595
|
break;
|
18305
18596
|
}
|
@@ -18473,16 +18764,7 @@
|
|
18473
18764
|
this.observer = new EventEmitter();
|
18474
18765
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
18475
18766
|
this.observer.on(Events.ERROR, forwardMessage);
|
18476
|
-
var
|
18477
|
-
isTypeSupported: function isTypeSupported() {
|
18478
|
-
return false;
|
18479
|
-
}
|
18480
|
-
};
|
18481
|
-
var m2tsTypeSupported = {
|
18482
|
-
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
18483
|
-
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
18484
|
-
ac3: false
|
18485
|
-
};
|
18767
|
+
var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
|
18486
18768
|
|
18487
18769
|
// navigator.vendor is not always available in Web Worker
|
18488
18770
|
// refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
|
@@ -18739,21 +19021,26 @@
|
|
18739
19021
|
var MAX_START_GAP_JUMP = 2.0;
|
18740
19022
|
var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
18741
19023
|
var SKIP_BUFFER_RANGE_START = 0.05;
|
18742
|
-
var GapController = /*#__PURE__*/function () {
|
19024
|
+
var GapController = /*#__PURE__*/function (_Logger) {
|
19025
|
+
_inheritsLoose(GapController, _Logger);
|
18743
19026
|
function GapController(config, media, fragmentTracker, hls) {
|
18744
|
-
|
18745
|
-
this.
|
18746
|
-
|
18747
|
-
|
18748
|
-
|
18749
|
-
|
18750
|
-
|
18751
|
-
|
18752
|
-
|
18753
|
-
|
18754
|
-
|
18755
|
-
|
18756
|
-
|
19027
|
+
var _this;
|
19028
|
+
_this = _Logger.call(this, 'gap-controller', hls.logger) || this;
|
19029
|
+
_this.config = void 0;
|
19030
|
+
_this.media = null;
|
19031
|
+
_this.fragmentTracker = void 0;
|
19032
|
+
_this.hls = void 0;
|
19033
|
+
_this.nudgeRetry = 0;
|
19034
|
+
_this.stallReported = false;
|
19035
|
+
_this.stalled = null;
|
19036
|
+
_this.moved = false;
|
19037
|
+
_this.seeking = false;
|
19038
|
+
_this.ended = 0;
|
19039
|
+
_this.config = config;
|
19040
|
+
_this.media = media;
|
19041
|
+
_this.fragmentTracker = fragmentTracker;
|
19042
|
+
_this.hls = hls;
|
19043
|
+
return _this;
|
18757
19044
|
}
|
18758
19045
|
var _proto = GapController.prototype;
|
18759
19046
|
_proto.destroy = function destroy() {
|
@@ -18768,7 +19055,7 @@
|
|
18768
19055
|
*
|
18769
19056
|
* @param lastCurrentTime - Previously read playhead position
|
18770
19057
|
*/;
|
18771
|
-
_proto.poll = function poll(lastCurrentTime, activeFrag) {
|
19058
|
+
_proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
|
18772
19059
|
var config = this.config,
|
18773
19060
|
media = this.media,
|
18774
19061
|
stalled = this.stalled;
|
@@ -18783,6 +19070,7 @@
|
|
18783
19070
|
|
18784
19071
|
// The playhead is moving, no-op
|
18785
19072
|
if (currentTime !== lastCurrentTime) {
|
19073
|
+
this.ended = 0;
|
18786
19074
|
this.moved = true;
|
18787
19075
|
if (!seeking) {
|
18788
19076
|
this.nudgeRetry = 0;
|
@@ -18791,7 +19079,7 @@
|
|
18791
19079
|
// The playhead is now moving, but was previously stalled
|
18792
19080
|
if (this.stallReported) {
|
18793
19081
|
var _stalledDuration = self.performance.now() - stalled;
|
18794
|
-
|
19082
|
+
this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
|
18795
19083
|
this.stallReported = false;
|
18796
19084
|
}
|
18797
19085
|
this.stalled = null;
|
@@ -18827,7 +19115,6 @@
|
|
18827
19115
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
18828
19116
|
// The addition poll gives the browser a chance to jump the gap for us
|
18829
19117
|
if (!this.moved && this.stalled !== null) {
|
18830
|
-
var _level$details;
|
18831
19118
|
// There is no playable buffer (seeked, waiting for buffer)
|
18832
19119
|
var isBuffered = bufferInfo.len > 0;
|
18833
19120
|
if (!isBuffered && !nextStart) {
|
@@ -18839,9 +19126,8 @@
|
|
18839
19126
|
// When joining a live stream with audio tracks, account for live playlist window sliding by allowing
|
18840
19127
|
// a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
|
18841
19128
|
// that begins over 1 target duration after the video start position.
|
18842
|
-
var
|
18843
|
-
var
|
18844
|
-
var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
|
19129
|
+
var isLive = !!(levelDetails != null && levelDetails.live);
|
19130
|
+
var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
|
18845
19131
|
var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
|
18846
19132
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
18847
19133
|
if (!media.paused) {
|
@@ -18859,6 +19145,17 @@
|
|
18859
19145
|
}
|
18860
19146
|
var stalledDuration = tnow - stalled;
|
18861
19147
|
if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
|
19148
|
+
// Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
|
19149
|
+
if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
|
19150
|
+
if (stalledDuration < 1000 || this.ended) {
|
19151
|
+
return;
|
19152
|
+
}
|
19153
|
+
this.ended = currentTime;
|
19154
|
+
this.hls.trigger(Events.MEDIA_ENDED, {
|
19155
|
+
stalled: true
|
19156
|
+
});
|
19157
|
+
return;
|
19158
|
+
}
|
18862
19159
|
// Report stalling after trying to fix
|
18863
19160
|
this._reportStall(bufferInfo);
|
18864
19161
|
if (!this.media) {
|
@@ -18900,7 +19197,7 @@
|
|
18900
19197
|
// needs to cross some sort of threshold covering all source-buffers content
|
18901
19198
|
// to start playing properly.
|
18902
19199
|
if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
18903
|
-
|
19200
|
+
this.warn('Trying to nudge playhead over buffer-hole');
|
18904
19201
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
18905
19202
|
// We only try to jump the hole if it's under the configured size
|
18906
19203
|
// Reset stalled so to rearm watchdog timer
|
@@ -18922,7 +19219,7 @@
|
|
18922
19219
|
// Report stalled error once
|
18923
19220
|
this.stallReported = true;
|
18924
19221
|
var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
|
18925
|
-
|
19222
|
+
this.warn(error.message);
|
18926
19223
|
hls.trigger(Events.ERROR, {
|
18927
19224
|
type: ErrorTypes.MEDIA_ERROR,
|
18928
19225
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -18986,7 +19283,7 @@
|
|
18986
19283
|
}
|
18987
19284
|
}
|
18988
19285
|
var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
18989
|
-
|
19286
|
+
this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
|
18990
19287
|
this.moved = true;
|
18991
19288
|
this.stalled = null;
|
18992
19289
|
media.currentTime = targetTime;
|
@@ -19025,7 +19322,7 @@
|
|
19025
19322
|
var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
|
19026
19323
|
// playback stalled in buffered area ... let's nudge currentTime to try to overcome this
|
19027
19324
|
var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
|
19028
|
-
|
19325
|
+
this.warn(error.message);
|
19029
19326
|
media.currentTime = targetTime;
|
19030
19327
|
hls.trigger(Events.ERROR, {
|
19031
19328
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -19035,7 +19332,7 @@
|
|
19035
19332
|
});
|
19036
19333
|
} else {
|
19037
19334
|
var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
|
19038
|
-
|
19335
|
+
this.error(_error.message);
|
19039
19336
|
hls.trigger(Events.ERROR, {
|
19040
19337
|
type: ErrorTypes.MEDIA_ERROR,
|
19041
19338
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -19045,14 +19342,14 @@
|
|
19045
19342
|
}
|
19046
19343
|
};
|
19047
19344
|
return GapController;
|
19048
|
-
}();
|
19345
|
+
}(Logger);
|
19049
19346
|
|
19050
19347
|
var TICK_INTERVAL = 100; // how often to tick in ms
|
19051
19348
|
var StreamController = /*#__PURE__*/function (_BaseStreamController) {
|
19052
19349
|
_inheritsLoose(StreamController, _BaseStreamController);
|
19053
19350
|
function StreamController(hls, fragmentTracker, keyLoader) {
|
19054
19351
|
var _this;
|
19055
|
-
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '
|
19352
|
+
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
|
19056
19353
|
_this.audioCodecSwap = false;
|
19057
19354
|
_this.gapController = null;
|
19058
19355
|
_this.level = -1;
|
@@ -19060,27 +19357,43 @@
|
|
19060
19357
|
_this.altAudio = false;
|
19061
19358
|
_this.audioOnly = false;
|
19062
19359
|
_this.fragPlaying = null;
|
19063
|
-
_this.onvplaying = null;
|
19064
|
-
_this.onvseeked = null;
|
19065
19360
|
_this.fragLastKbps = 0;
|
19066
19361
|
_this.couldBacktrack = false;
|
19067
19362
|
_this.backtrackFragment = null;
|
19068
19363
|
_this.audioCodecSwitch = false;
|
19069
19364
|
_this.videoBuffer = null;
|
19070
|
-
_this.
|
19365
|
+
_this.onMediaPlaying = function () {
|
19366
|
+
// tick to speed up FRAG_CHANGED triggering
|
19367
|
+
_this.tick();
|
19368
|
+
};
|
19369
|
+
_this.onMediaSeeked = function () {
|
19370
|
+
var media = _this.media;
|
19371
|
+
var currentTime = media ? media.currentTime : null;
|
19372
|
+
if (isFiniteNumber(currentTime)) {
|
19373
|
+
_this.log("Media seeked to " + currentTime.toFixed(3));
|
19374
|
+
}
|
19375
|
+
|
19376
|
+
// If seeked was issued before buffer was appended do not tick immediately
|
19377
|
+
var bufferInfo = _this.getMainFwdBufferInfo();
|
19378
|
+
if (bufferInfo === null || bufferInfo.len === 0) {
|
19379
|
+
_this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19380
|
+
return;
|
19381
|
+
}
|
19382
|
+
|
19383
|
+
// tick to speed up FRAG_CHANGED triggering
|
19384
|
+
_this.tick();
|
19385
|
+
};
|
19386
|
+
_this.registerListeners();
|
19071
19387
|
return _this;
|
19072
19388
|
}
|
19073
19389
|
var _proto = StreamController.prototype;
|
19074
|
-
_proto.
|
19390
|
+
_proto.registerListeners = function registerListeners() {
|
19391
|
+
_BaseStreamController.prototype.registerListeners.call(this);
|
19075
19392
|
var hls = this.hls;
|
19076
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19077
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19078
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19079
19393
|
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19080
19394
|
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
|
19081
19395
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19082
19396
|
hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19083
|
-
hls.on(Events.ERROR, this.onError, this);
|
19084
19397
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19085
19398
|
hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19086
19399
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19088,15 +19401,12 @@
|
|
19088
19401
|
hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
|
19089
19402
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19090
19403
|
};
|
19091
|
-
_proto.
|
19404
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
19405
|
+
_BaseStreamController.prototype.unregisterListeners.call(this);
|
19092
19406
|
var hls = this.hls;
|
19093
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19094
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19095
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19096
19407
|
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19097
19408
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19098
19409
|
hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19099
|
-
hls.off(Events.ERROR, this.onError, this);
|
19100
19410
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19101
19411
|
hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19102
19412
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19105,7 +19415,9 @@
|
|
19105
19415
|
hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19106
19416
|
};
|
19107
19417
|
_proto.onHandlerDestroying = function onHandlerDestroying() {
|
19108
|
-
|
19418
|
+
// @ts-ignore
|
19419
|
+
this.onMediaPlaying = this.onMediaSeeked = null;
|
19420
|
+
this.unregisterListeners();
|
19109
19421
|
_BaseStreamController.prototype.onHandlerDestroying.call(this);
|
19110
19422
|
};
|
19111
19423
|
_proto.startLoad = function startLoad(startPosition) {
|
@@ -19215,7 +19527,7 @@
|
|
19215
19527
|
if (this.altAudio && this.audioOnly) {
|
19216
19528
|
return;
|
19217
19529
|
}
|
19218
|
-
if (!(levels != null && levels[level])) {
|
19530
|
+
if (!this.buffering || !(levels != null && levels[level])) {
|
19219
19531
|
return;
|
19220
19532
|
}
|
19221
19533
|
var levelInfo = levels[level];
|
@@ -19421,18 +19733,15 @@
|
|
19421
19733
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
19422
19734
|
_BaseStreamController.prototype.onMediaAttached.call(this, event, data);
|
19423
19735
|
var media = data.media;
|
19424
|
-
|
19425
|
-
|
19426
|
-
media.addEventListener('playing', this.onvplaying);
|
19427
|
-
media.addEventListener('seeked', this.onvseeked);
|
19736
|
+
media.addEventListener('playing', this.onMediaPlaying);
|
19737
|
+
media.addEventListener('seeked', this.onMediaSeeked);
|
19428
19738
|
this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
|
19429
19739
|
};
|
19430
19740
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
19431
19741
|
var media = this.media;
|
19432
|
-
if (media
|
19433
|
-
media.removeEventListener('playing', this.
|
19434
|
-
media.removeEventListener('seeked', this.
|
19435
|
-
this.onvplaying = this.onvseeked = null;
|
19742
|
+
if (media) {
|
19743
|
+
media.removeEventListener('playing', this.onMediaPlaying);
|
19744
|
+
media.removeEventListener('seeked', this.onMediaSeeked);
|
19436
19745
|
this.videoBuffer = null;
|
19437
19746
|
}
|
19438
19747
|
this.fragPlaying = null;
|
@@ -19442,27 +19751,6 @@
|
|
19442
19751
|
}
|
19443
19752
|
_BaseStreamController.prototype.onMediaDetaching.call(this);
|
19444
19753
|
};
|
19445
|
-
_proto.onMediaPlaying = function onMediaPlaying() {
|
19446
|
-
// tick to speed up FRAG_CHANGED triggering
|
19447
|
-
this.tick();
|
19448
|
-
};
|
19449
|
-
_proto.onMediaSeeked = function onMediaSeeked() {
|
19450
|
-
var media = this.media;
|
19451
|
-
var currentTime = media ? media.currentTime : null;
|
19452
|
-
if (isFiniteNumber(currentTime)) {
|
19453
|
-
this.log("Media seeked to " + currentTime.toFixed(3));
|
19454
|
-
}
|
19455
|
-
|
19456
|
-
// If seeked was issued before buffer was appended do not tick immediately
|
19457
|
-
var bufferInfo = this.getMainFwdBufferInfo();
|
19458
|
-
if (bufferInfo === null || bufferInfo.len === 0) {
|
19459
|
-
this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19460
|
-
return;
|
19461
|
-
}
|
19462
|
-
|
19463
|
-
// tick to speed up FRAG_CHANGED triggering
|
19464
|
-
this.tick();
|
19465
|
-
};
|
19466
19754
|
_proto.onManifestLoading = function onManifestLoading() {
|
19467
19755
|
// reset buffer on manifest loading
|
19468
19756
|
this.log('Trigger BUFFER_RESET');
|
@@ -19743,8 +20031,10 @@
|
|
19743
20031
|
}
|
19744
20032
|
if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
|
19745
20033
|
// Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
|
19746
|
-
var
|
19747
|
-
|
20034
|
+
var state = this.state;
|
20035
|
+
var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
|
20036
|
+
var levelDetails = this.getLevelDetails();
|
20037
|
+
gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
|
19748
20038
|
}
|
19749
20039
|
this.lastCurrentTime = media.currentTime;
|
19750
20040
|
};
|
@@ -20209,9 +20499,12 @@
|
|
20209
20499
|
* The configuration object provided on player instantiation.
|
20210
20500
|
*/
|
20211
20501
|
this.userConfig = void 0;
|
20502
|
+
/**
|
20503
|
+
* The logger functions used by this player instance, configured on player instantiation.
|
20504
|
+
*/
|
20505
|
+
this.logger = void 0;
|
20212
20506
|
this.coreComponents = void 0;
|
20213
20507
|
this.networkControllers = void 0;
|
20214
|
-
this.started = false;
|
20215
20508
|
this._emitter = new EventEmitter();
|
20216
20509
|
this._autoLevelCapping = -1;
|
20217
20510
|
this._maxHdcpLevel = null;
|
@@ -20228,11 +20521,11 @@
|
|
20228
20521
|
this._media = null;
|
20229
20522
|
this.url = null;
|
20230
20523
|
this.triggeringException = void 0;
|
20231
|
-
enableLogs(userConfig.debug || false, 'Hls instance');
|
20232
|
-
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
|
20524
|
+
var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
|
20525
|
+
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
|
20233
20526
|
this.userConfig = userConfig;
|
20234
20527
|
if (config.progressive) {
|
20235
|
-
enableStreamingMode(config);
|
20528
|
+
enableStreamingMode(config, logger);
|
20236
20529
|
}
|
20237
20530
|
|
20238
20531
|
// core controllers and network loaders
|
@@ -20340,7 +20633,7 @@
|
|
20340
20633
|
try {
|
20341
20634
|
return this.emit(event, event, eventObject);
|
20342
20635
|
} catch (error) {
|
20343
|
-
logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20636
|
+
this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20344
20637
|
// Prevent recursion in error event handlers that throw #5497
|
20345
20638
|
if (!this.triggeringException) {
|
20346
20639
|
this.triggeringException = true;
|
@@ -20366,7 +20659,7 @@
|
|
20366
20659
|
* Dispose of the instance
|
20367
20660
|
*/;
|
20368
20661
|
_proto.destroy = function destroy() {
|
20369
|
-
logger.log('destroy');
|
20662
|
+
this.logger.log('destroy');
|
20370
20663
|
this.trigger(Events.DESTROYING, undefined);
|
20371
20664
|
this.detachMedia();
|
20372
20665
|
this.removeAllListeners();
|
@@ -20391,7 +20684,7 @@
|
|
20391
20684
|
* Attaches Hls.js to a media element
|
20392
20685
|
*/;
|
20393
20686
|
_proto.attachMedia = function attachMedia(media) {
|
20394
|
-
logger.log('attachMedia');
|
20687
|
+
this.logger.log('attachMedia');
|
20395
20688
|
this._media = media;
|
20396
20689
|
this.trigger(Events.MEDIA_ATTACHING, {
|
20397
20690
|
media: media
|
@@ -20402,7 +20695,7 @@
|
|
20402
20695
|
* Detach Hls.js from the media
|
20403
20696
|
*/;
|
20404
20697
|
_proto.detachMedia = function detachMedia() {
|
20405
|
-
logger.log('detachMedia');
|
20698
|
+
this.logger.log('detachMedia');
|
20406
20699
|
this.trigger(Events.MEDIA_DETACHING, undefined);
|
20407
20700
|
this._media = null;
|
20408
20701
|
}
|
@@ -20419,7 +20712,7 @@
|
|
20419
20712
|
});
|
20420
20713
|
this._autoLevelCapping = -1;
|
20421
20714
|
this._maxHdcpLevel = null;
|
20422
|
-
logger.log("loadSource:" + loadingSource);
|
20715
|
+
this.logger.log("loadSource:" + loadingSource);
|
20423
20716
|
if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
|
20424
20717
|
this.detachMedia();
|
20425
20718
|
this.attachMedia(media);
|
@@ -20441,8 +20734,7 @@
|
|
20441
20734
|
if (startPosition === void 0) {
|
20442
20735
|
startPosition = -1;
|
20443
20736
|
}
|
20444
|
-
logger.log("startLoad(" + startPosition + ")");
|
20445
|
-
this.started = true;
|
20737
|
+
this.logger.log("startLoad(" + startPosition + ")");
|
20446
20738
|
this.networkControllers.forEach(function (controller) {
|
20447
20739
|
controller.startLoad(startPosition);
|
20448
20740
|
});
|
@@ -20452,34 +20744,31 @@
|
|
20452
20744
|
* Stop loading of any stream data.
|
20453
20745
|
*/;
|
20454
20746
|
_proto.stopLoad = function stopLoad() {
|
20455
|
-
logger.log('stopLoad');
|
20456
|
-
this.started = false;
|
20747
|
+
this.logger.log('stopLoad');
|
20457
20748
|
this.networkControllers.forEach(function (controller) {
|
20458
20749
|
controller.stopLoad();
|
20459
20750
|
});
|
20460
20751
|
}
|
20461
20752
|
|
20462
20753
|
/**
|
20463
|
-
* Resumes stream controller segment loading
|
20754
|
+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
|
20464
20755
|
*/;
|
20465
20756
|
_proto.resumeBuffering = function resumeBuffering() {
|
20466
|
-
|
20467
|
-
|
20468
|
-
|
20469
|
-
|
20470
|
-
|
20471
|
-
});
|
20472
|
-
}
|
20757
|
+
this.networkControllers.forEach(function (controller) {
|
20758
|
+
if (controller.resumeBuffering) {
|
20759
|
+
controller.resumeBuffering();
|
20760
|
+
}
|
20761
|
+
});
|
20473
20762
|
}
|
20474
20763
|
|
20475
20764
|
/**
|
20476
|
-
*
|
20765
|
+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
|
20477
20766
|
* This allows for media buffering to be paused without interupting playlist loading.
|
20478
20767
|
*/;
|
20479
20768
|
_proto.pauseBuffering = function pauseBuffering() {
|
20480
20769
|
this.networkControllers.forEach(function (controller) {
|
20481
|
-
if (
|
20482
|
-
controller.
|
20770
|
+
if (controller.pauseBuffering) {
|
20771
|
+
controller.pauseBuffering();
|
20483
20772
|
}
|
20484
20773
|
});
|
20485
20774
|
}
|
@@ -20488,7 +20777,7 @@
|
|
20488
20777
|
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
20489
20778
|
*/;
|
20490
20779
|
_proto.swapAudioCodec = function swapAudioCodec() {
|
20491
|
-
logger.log('swapAudioCodec');
|
20780
|
+
this.logger.log('swapAudioCodec');
|
20492
20781
|
this.streamController.swapAudioCodec();
|
20493
20782
|
}
|
20494
20783
|
|
@@ -20499,7 +20788,7 @@
|
|
20499
20788
|
* Automatic recovery of media-errors by this process is configurable.
|
20500
20789
|
*/;
|
20501
20790
|
_proto.recoverMediaError = function recoverMediaError() {
|
20502
|
-
logger.log('recoverMediaError');
|
20791
|
+
this.logger.log('recoverMediaError');
|
20503
20792
|
var media = this._media;
|
20504
20793
|
this.detachMedia();
|
20505
20794
|
if (media) {
|
@@ -20554,7 +20843,7 @@
|
|
20554
20843
|
* Set quality level index immediately. This will flush the current buffer to replace the quality asap. That means playback will interrupt at least shortly to re-buffer and re-sync eventually. Set to -1 for automatic level selection.
|
20555
20844
|
*/,
|
20556
20845
|
set: function set(newLevel) {
|
20557
|
-
logger.log("set currentLevel:" + newLevel);
|
20846
|
+
this.logger.log("set currentLevel:" + newLevel);
|
20558
20847
|
this.levelController.manualLevel = newLevel;
|
20559
20848
|
this.streamController.immediateLevelSwitch();
|
20560
20849
|
}
|
@@ -20575,7 +20864,7 @@
|
|
20575
20864
|
* @param newLevel - Pass -1 for automatic level selection
|
20576
20865
|
*/,
|
20577
20866
|
set: function set(newLevel) {
|
20578
|
-
logger.log("set nextLevel:" + newLevel);
|
20867
|
+
this.logger.log("set nextLevel:" + newLevel);
|
20579
20868
|
this.levelController.manualLevel = newLevel;
|
20580
20869
|
this.streamController.nextLevelSwitch();
|
20581
20870
|
}
|
@@ -20596,7 +20885,7 @@
|
|
20596
20885
|
* @param newLevel - Pass -1 for automatic level selection
|
20597
20886
|
*/,
|
20598
20887
|
set: function set(newLevel) {
|
20599
|
-
logger.log("set loadLevel:" + newLevel);
|
20888
|
+
this.logger.log("set loadLevel:" + newLevel);
|
20600
20889
|
this.levelController.manualLevel = newLevel;
|
20601
20890
|
}
|
20602
20891
|
|
@@ -20631,7 +20920,7 @@
|
|
20631
20920
|
* Sets "first-level", see getter.
|
20632
20921
|
*/,
|
20633
20922
|
set: function set(newLevel) {
|
20634
|
-
logger.log("set firstLevel:" + newLevel);
|
20923
|
+
this.logger.log("set firstLevel:" + newLevel);
|
20635
20924
|
this.levelController.firstLevel = newLevel;
|
20636
20925
|
}
|
20637
20926
|
|
@@ -20658,7 +20947,7 @@
|
|
20658
20947
|
* (determined from download of first segment)
|
20659
20948
|
*/,
|
20660
20949
|
set: function set(newLevel) {
|
20661
|
-
logger.log("set startLevel:" + newLevel);
|
20950
|
+
this.logger.log("set startLevel:" + newLevel);
|
20662
20951
|
// if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
|
20663
20952
|
if (newLevel !== -1) {
|
20664
20953
|
newLevel = Math.max(newLevel, this.minAutoLevel);
|
@@ -20711,7 +21000,7 @@
|
|
20711
21000
|
*/
|
20712
21001
|
function set(newLevel) {
|
20713
21002
|
if (this._autoLevelCapping !== newLevel) {
|
20714
|
-
logger.log("set autoLevelCapping:" + newLevel);
|
21003
|
+
this.logger.log("set autoLevelCapping:" + newLevel);
|
20715
21004
|
this._autoLevelCapping = newLevel;
|
20716
21005
|
this.levelController.checkMaxAutoUpdated();
|
20717
21006
|
}
|
@@ -21036,7 +21325,7 @@
|
|
21036
21325
|
* Get the video-dev/hls.js package version.
|
21037
21326
|
*/
|
21038
21327
|
function get() {
|
21039
|
-
return "1.5.
|
21328
|
+
return "1.5.6-0.canary.10003";
|
21040
21329
|
}
|
21041
21330
|
}, {
|
21042
21331
|
key: "Events",
|