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