hls.js 1.5.6-0.canary.9999 → 1.5.6
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 +0 -1
- package/dist/hls-demo.js +0 -10
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +1169 -2069
- package/dist/hls.js.d.ts +51 -65
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +875 -1158
- 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 +709 -993
- 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 +869 -1756
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/dist/hls.worker.js.map +1 -1
- package/package.json +20 -20
- package/src/config.ts +2 -3
- package/src/controller/abr-controller.ts +40 -31
- package/src/controller/audio-stream-controller.ts +16 -15
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +8 -20
- package/src/controller/base-stream-controller.ts +33 -149
- package/src/controller/buffer-controller.ts +11 -11
- package/src/controller/cap-level-controller.ts +2 -1
- package/src/controller/cmcd-controller.ts +6 -27
- package/src/controller/content-steering-controller.ts +6 -8
- package/src/controller/eme-controller.ts +22 -9
- package/src/controller/error-controller.ts +8 -6
- package/src/controller/fps-controller.ts +3 -2
- package/src/controller/gap-controller.ts +16 -43
- package/src/controller/latency-controller.ts +11 -9
- package/src/controller/level-controller.ts +18 -12
- package/src/controller/stream-controller.ts +34 -27
- package/src/controller/subtitle-stream-controller.ts +14 -13
- package/src/controller/subtitle-track-controller.ts +3 -5
- package/src/controller/timeline-controller.ts +30 -23
- package/src/crypt/aes-crypto.ts +2 -21
- package/src/crypt/decrypter.ts +18 -32
- package/src/crypt/fast-aes-key.ts +5 -24
- package/src/demux/audio/adts.ts +4 -9
- package/src/demux/sample-aes.ts +0 -2
- package/src/demux/transmuxer-interface.ts +12 -4
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +3 -16
- package/src/demux/tsdemuxer.ts +37 -71
- package/src/demux/video/avc-video-parser.ts +119 -208
- package/src/demux/video/base-video-parser.ts +2 -134
- package/src/demux/video/exp-golomb.ts +208 -0
- package/src/events.ts +0 -7
- package/src/hls.ts +34 -42
- package/src/loader/fragment-loader.ts +2 -9
- package/src/loader/key-loader.ts +0 -2
- package/src/loader/level-key.ts +9 -10
- package/src/loader/playlist-loader.ts +5 -4
- package/src/remux/mp4-generator.ts +1 -196
- package/src/remux/mp4-remuxer.ts +7 -23
- package/src/task-loop.ts +2 -5
- package/src/types/component-api.ts +0 -2
- package/src/types/demuxer.ts +0 -3
- package/src/types/events.ts +0 -4
- package/src/utils/codecs.ts +4 -33
- package/src/utils/logger.ts +24 -54
- package/src/utils/mp4-tools.ts +6 -4
- package/src/crypt/decrypter-aes-mode.ts +0 -4
- package/src/demux/video/hevc-video-parser.ts +0 -746
- package/src/utils/encryption-methods-util.ts +0 -21
package/dist/hls.light.js
CHANGED
@@ -5,21 +5,6 @@
|
|
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
|
-
}
|
23
8
|
function ownKeys(e, r) {
|
24
9
|
var t = Object.keys(e);
|
25
10
|
if (Object.getOwnPropertySymbols) {
|
@@ -118,6 +103,32 @@
|
|
118
103
|
};
|
119
104
|
return _setPrototypeOf(o, p);
|
120
105
|
}
|
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
|
+
}
|
121
132
|
function _isNativeFunction(fn) {
|
122
133
|
try {
|
123
134
|
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
@@ -352,7 +363,6 @@
|
|
352
363
|
Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
|
353
364
|
Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
|
354
365
|
Events["MEDIA_DETACHED"] = "hlsMediaDetached";
|
355
|
-
Events["MEDIA_ENDED"] = "hlsMediaEnded";
|
356
366
|
Events["BUFFER_RESET"] = "hlsBufferReset";
|
357
367
|
Events["BUFFER_CODECS"] = "hlsBufferCodecs";
|
358
368
|
Events["BUFFER_CREATED"] = "hlsBufferCreated";
|
@@ -466,6 +476,61 @@
|
|
466
476
|
return ErrorDetails;
|
467
477
|
}({});
|
468
478
|
|
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
|
+
|
469
534
|
var DECIMAL_RESOLUTION_REGEX = /^(\d+)x(\d+)$/;
|
470
535
|
var ATTR_LIST_REGEX = /(.+?)=(".*?"|.*?)(?:,|$)/g;
|
471
536
|
|
@@ -554,77 +619,6 @@
|
|
554
619
|
return AttrList;
|
555
620
|
}();
|
556
621
|
|
557
|
-
var Logger = function Logger(label, logger) {
|
558
|
-
this.trace = void 0;
|
559
|
-
this.debug = void 0;
|
560
|
-
this.log = void 0;
|
561
|
-
this.warn = void 0;
|
562
|
-
this.info = void 0;
|
563
|
-
this.error = void 0;
|
564
|
-
var lb = "[" + label + "]:";
|
565
|
-
this.trace = noop;
|
566
|
-
this.debug = logger.debug.bind(null, lb);
|
567
|
-
this.log = logger.log.bind(null, lb);
|
568
|
-
this.warn = logger.warn.bind(null, lb);
|
569
|
-
this.info = logger.info.bind(null, lb);
|
570
|
-
this.error = logger.error.bind(null, lb);
|
571
|
-
};
|
572
|
-
var noop = function noop() {};
|
573
|
-
var fakeLogger = {
|
574
|
-
trace: noop,
|
575
|
-
debug: noop,
|
576
|
-
log: noop,
|
577
|
-
warn: noop,
|
578
|
-
info: noop,
|
579
|
-
error: noop
|
580
|
-
};
|
581
|
-
function createLogger() {
|
582
|
-
return _extends({}, fakeLogger);
|
583
|
-
}
|
584
|
-
|
585
|
-
// let lastCallTime;
|
586
|
-
// function formatMsgWithTimeInfo(type, msg) {
|
587
|
-
// const now = Date.now();
|
588
|
-
// const diff = lastCallTime ? '+' + (now - lastCallTime) : '0';
|
589
|
-
// lastCallTime = now;
|
590
|
-
// msg = (new Date(now)).toISOString() + ' | [' + type + '] > ' + msg + ' ( ' + diff + ' ms )';
|
591
|
-
// return msg;
|
592
|
-
// }
|
593
|
-
|
594
|
-
function consolePrintFn(type, id) {
|
595
|
-
var func = self.console[type];
|
596
|
-
return func ? func.bind(self.console, (id ? '[' + id + '] ' : '') + "[" + type + "] >") : noop;
|
597
|
-
}
|
598
|
-
function getLoggerFn(key, debugConfig, id) {
|
599
|
-
return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
|
600
|
-
}
|
601
|
-
var exportedLogger = createLogger();
|
602
|
-
function enableLogs(debugConfig, context, id) {
|
603
|
-
// check that console is available
|
604
|
-
var newLogger = createLogger();
|
605
|
-
if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
|
606
|
-
var keys = [
|
607
|
-
// Remove out from list here to hard-disable a log-level
|
608
|
-
// 'trace',
|
609
|
-
'debug', 'log', 'info', 'warn', 'error'];
|
610
|
-
keys.forEach(function (key) {
|
611
|
-
newLogger[key] = getLoggerFn(key, debugConfig, id);
|
612
|
-
});
|
613
|
-
// Some browsers don't allow to use bind on console object anyway
|
614
|
-
// fallback to default if needed
|
615
|
-
try {
|
616
|
-
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.6-0.canary.9999");
|
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
|
-
|
628
622
|
// Avoid exporting const enum so that these values can be inlined
|
629
623
|
|
630
624
|
function isDateRangeCueAttribute(attrName) {
|
@@ -1179,30 +1173,10 @@
|
|
1179
1173
|
return LevelDetails;
|
1180
1174
|
}();
|
1181
1175
|
|
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
|
-
|
1202
1176
|
// This file is inserted as a shim for modules which we do not want to include into the distro.
|
1203
1177
|
// This replacement is done in the "alias" plugin of the rollup config.
|
1204
1178
|
var empty = undefined;
|
1205
|
-
var
|
1179
|
+
var Cues = /*@__PURE__*/getDefaultExportFromCjs(empty);
|
1206
1180
|
|
1207
1181
|
function sliceUint8(array, start, end) {
|
1208
1182
|
// @ts-expect-error This polyfills IE11 usage of Uint8Array slice.
|
@@ -1674,11 +1648,13 @@
|
|
1674
1648
|
var earliestPresentationTime = 0;
|
1675
1649
|
var firstOffset = 0;
|
1676
1650
|
if (version === 0) {
|
1677
|
-
earliestPresentationTime = readUint32(sidx, index
|
1678
|
-
firstOffset = readUint32(sidx, index
|
1651
|
+
earliestPresentationTime = readUint32(sidx, index);
|
1652
|
+
firstOffset = readUint32(sidx, index + 4);
|
1653
|
+
index += 8;
|
1679
1654
|
} else {
|
1680
|
-
earliestPresentationTime = readUint64(sidx, index
|
1681
|
-
firstOffset = readUint64(sidx, index
|
1655
|
+
earliestPresentationTime = readUint64(sidx, index);
|
1656
|
+
firstOffset = readUint64(sidx, index + 8);
|
1657
|
+
index += 16;
|
1682
1658
|
}
|
1683
1659
|
|
1684
1660
|
// skip reserved
|
@@ -2652,13 +2628,13 @@
|
|
2652
2628
|
this.keyFormatVersions = formatversions;
|
2653
2629
|
this.iv = iv;
|
2654
2630
|
this.encrypted = method ? method !== 'NONE' : false;
|
2655
|
-
this.isCommonEncryption = this.encrypted &&
|
2631
|
+
this.isCommonEncryption = this.encrypted && method !== 'AES-128';
|
2656
2632
|
}
|
2657
2633
|
var _proto = LevelKey.prototype;
|
2658
2634
|
_proto.isSupported = function isSupported() {
|
2659
2635
|
// If it's Segment encryption or No encryption, just select that key system
|
2660
2636
|
if (this.method) {
|
2661
|
-
if (
|
2637
|
+
if (this.method === 'AES-128' || this.method === 'NONE') {
|
2662
2638
|
return true;
|
2663
2639
|
}
|
2664
2640
|
if (this.keyFormat === 'identity') {
|
@@ -2672,13 +2648,14 @@
|
|
2672
2648
|
if (!this.encrypted || !this.uri) {
|
2673
2649
|
return null;
|
2674
2650
|
}
|
2675
|
-
if (
|
2651
|
+
if (this.method === 'AES-128' && this.uri && !this.iv) {
|
2676
2652
|
if (typeof sn !== 'number') {
|
2677
2653
|
// We are fetching decryption data for a initialization segment
|
2678
|
-
// If the segment was encrypted with AES-128
|
2654
|
+
// If the segment was encrypted with AES-128
|
2679
2655
|
// It must have an IV defined. We cannot substitute the Segment Number in.
|
2680
|
-
|
2681
|
-
|
2656
|
+
if (this.method === 'AES-128' && !this.iv) {
|
2657
|
+
logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
|
2658
|
+
}
|
2682
2659
|
// Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
|
2683
2660
|
sn = 0;
|
2684
2661
|
}
|
@@ -2840,28 +2817,23 @@
|
|
2840
2817
|
if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
|
2841
2818
|
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
|
2842
2819
|
}
|
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
|
2843
2824
|
var codecsToCheck = {
|
2844
|
-
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2845
|
-
// some browsers will report that fLaC is supported then fail.
|
2846
|
-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2847
2825
|
flac: ['flac', 'fLaC', 'FLAC'],
|
2848
|
-
opus: ['opus', 'Opus']
|
2849
|
-
// Replace audio codec info if browser does not support mp4a.40.34,
|
2850
|
-
// and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
|
2851
|
-
'mp4a.40.34': ['mp3']
|
2826
|
+
opus: ['opus', 'Opus']
|
2852
2827
|
}[lowerCaseCodec];
|
2853
2828
|
for (var i = 0; i < codecsToCheck.length; i++) {
|
2854
|
-
var _getMediaSource;
|
2855
2829
|
if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
|
2856
2830
|
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
|
2857
2831
|
return codecsToCheck[i];
|
2858
|
-
} else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
|
2859
|
-
return '';
|
2860
2832
|
}
|
2861
2833
|
}
|
2862
2834
|
return lowerCaseCodec;
|
2863
2835
|
}
|
2864
|
-
var AUDIO_CODEC_REGEXP = /flac|opus
|
2836
|
+
var AUDIO_CODEC_REGEXP = /flac|opus/i;
|
2865
2837
|
function getCodecCompatibleName(codec, preferManagedMediaSource) {
|
2866
2838
|
if (preferManagedMediaSource === void 0) {
|
2867
2839
|
preferManagedMediaSource = true;
|
@@ -2889,18 +2861,6 @@
|
|
2889
2861
|
}
|
2890
2862
|
return codec;
|
2891
2863
|
}
|
2892
|
-
function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
|
2893
|
-
var MediaSource = getMediaSource(preferManagedMediaSource) || {
|
2894
|
-
isTypeSupported: function isTypeSupported() {
|
2895
|
-
return false;
|
2896
|
-
}
|
2897
|
-
};
|
2898
|
-
return {
|
2899
|
-
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
2900
|
-
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
2901
|
-
ac3: false
|
2902
|
-
};
|
2903
|
-
}
|
2904
2864
|
|
2905
2865
|
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;
|
2906
2866
|
var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
|
@@ -3701,10 +3661,10 @@
|
|
3701
3661
|
var loaderContext = loader.context;
|
3702
3662
|
if (loaderContext && loaderContext.url === context.url && loaderContext.level === context.level) {
|
3703
3663
|
// same URL can't overlap
|
3704
|
-
|
3664
|
+
logger.trace('[playlist-loader]: playlist request ongoing');
|
3705
3665
|
return;
|
3706
3666
|
}
|
3707
|
-
|
3667
|
+
logger.log("[playlist-loader]: aborting previous loader for type: " + context.type);
|
3708
3668
|
loader.abort();
|
3709
3669
|
}
|
3710
3670
|
|
@@ -3814,7 +3774,7 @@
|
|
3814
3774
|
// alt audio rendition in which quality levels (main)
|
3815
3775
|
// contains both audio+video. but with mixed audio track not signaled
|
3816
3776
|
if (!embeddedAudioFound && levels[0].audioCodec && !levels[0].attrs.AUDIO) {
|
3817
|
-
|
3777
|
+
logger.log('[playlist-loader]: audio codec signaled in quality level, but no embedded audio track signaled, create one');
|
3818
3778
|
audioTracks.unshift({
|
3819
3779
|
type: 'main',
|
3820
3780
|
name: 'main',
|
@@ -3914,7 +3874,7 @@
|
|
3914
3874
|
message += " id: " + context.id + " group-id: \"" + context.groupId + "\"";
|
3915
3875
|
}
|
3916
3876
|
var error = new Error(message);
|
3917
|
-
|
3877
|
+
logger.warn("[playlist-loader]: " + message);
|
3918
3878
|
var details = ErrorDetails.UNKNOWN;
|
3919
3879
|
var fatal = false;
|
3920
3880
|
var loader = this.getInternalLoader(context);
|
@@ -4475,43 +4435,8 @@
|
|
4475
4435
|
this.currentTime = 0;
|
4476
4436
|
this.stallCount = 0;
|
4477
4437
|
this._latency = null;
|
4478
|
-
this.
|
4479
|
-
|
4480
|
-
levelDetails = _this.levelDetails;
|
4481
|
-
if (!media || !levelDetails) {
|
4482
|
-
return;
|
4483
|
-
}
|
4484
|
-
_this.currentTime = media.currentTime;
|
4485
|
-
var latency = _this.computeLatency();
|
4486
|
-
if (latency === null) {
|
4487
|
-
return;
|
4488
|
-
}
|
4489
|
-
_this._latency = latency;
|
4490
|
-
|
4491
|
-
// Adapt playbackRate to meet target latency in low-latency mode
|
4492
|
-
var _this$config = _this.config,
|
4493
|
-
lowLatencyMode = _this$config.lowLatencyMode,
|
4494
|
-
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4495
|
-
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4496
|
-
return;
|
4497
|
-
}
|
4498
|
-
var targetLatency = _this.targetLatency;
|
4499
|
-
if (targetLatency === null) {
|
4500
|
-
return;
|
4501
|
-
}
|
4502
|
-
var distanceFromTarget = latency - targetLatency;
|
4503
|
-
// Only adjust playbackRate when within one target duration of targetLatency
|
4504
|
-
// and more than one second from under-buffering.
|
4505
|
-
// Playback further than one target duration from target can be considered DVR playback.
|
4506
|
-
var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
|
4507
|
-
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4508
|
-
if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
|
4509
|
-
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4510
|
-
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
|
4511
|
-
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4512
|
-
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4513
|
-
media.playbackRate = 1;
|
4514
|
-
}
|
4438
|
+
this.timeupdateHandler = function () {
|
4439
|
+
return _this.timeupdate();
|
4515
4440
|
};
|
4516
4441
|
this.hls = hls;
|
4517
4442
|
this.config = hls.config;
|
@@ -4523,7 +4448,7 @@
|
|
4523
4448
|
this.onMediaDetaching();
|
4524
4449
|
this.levelDetails = null;
|
4525
4450
|
// @ts-ignore
|
4526
|
-
this.hls = null;
|
4451
|
+
this.hls = this.timeupdateHandler = null;
|
4527
4452
|
};
|
4528
4453
|
_proto.registerListeners = function registerListeners() {
|
4529
4454
|
this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
@@ -4541,11 +4466,11 @@
|
|
4541
4466
|
};
|
4542
4467
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
4543
4468
|
this.media = data.media;
|
4544
|
-
this.media.addEventListener('timeupdate', this.
|
4469
|
+
this.media.addEventListener('timeupdate', this.timeupdateHandler);
|
4545
4470
|
};
|
4546
4471
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
4547
4472
|
if (this.media) {
|
4548
|
-
this.media.removeEventListener('timeupdate', this.
|
4473
|
+
this.media.removeEventListener('timeupdate', this.timeupdateHandler);
|
4549
4474
|
this.media = null;
|
4550
4475
|
}
|
4551
4476
|
};
|
@@ -4558,10 +4483,10 @@
|
|
4558
4483
|
var details = _ref.details;
|
4559
4484
|
this.levelDetails = details;
|
4560
4485
|
if (details.advanced) {
|
4561
|
-
this.
|
4486
|
+
this.timeupdate();
|
4562
4487
|
}
|
4563
4488
|
if (!details.live && this.media) {
|
4564
|
-
this.media.removeEventListener('timeupdate', this.
|
4489
|
+
this.media.removeEventListener('timeupdate', this.timeupdateHandler);
|
4565
4490
|
}
|
4566
4491
|
};
|
4567
4492
|
_proto.onError = function onError(event, data) {
|
@@ -4571,7 +4496,45 @@
|
|
4571
4496
|
}
|
4572
4497
|
this.stallCount++;
|
4573
4498
|
if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
|
4574
|
-
|
4499
|
+
logger.warn('[playback-rate-controller]: Stall detected, adjusting target latency');
|
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;
|
4575
4538
|
}
|
4576
4539
|
};
|
4577
4540
|
_proto.estimateLiveEdge = function estimateLiveEdge() {
|
@@ -5479,17 +5442,19 @@
|
|
5479
5442
|
MoveAllAlternatesMatchingHDCP: 2,
|
5480
5443
|
SwitchToSDR: 4
|
5481
5444
|
}; // Reserved for future use
|
5482
|
-
var ErrorController = /*#__PURE__*/function (
|
5483
|
-
_inheritsLoose(ErrorController, _Logger);
|
5445
|
+
var ErrorController = /*#__PURE__*/function () {
|
5484
5446
|
function ErrorController(hls) {
|
5485
|
-
|
5486
|
-
|
5487
|
-
|
5488
|
-
|
5489
|
-
|
5490
|
-
|
5491
|
-
|
5492
|
-
|
5447
|
+
this.hls = void 0;
|
5448
|
+
this.playlistError = 0;
|
5449
|
+
this.penalizedRenditions = {};
|
5450
|
+
this.log = void 0;
|
5451
|
+
this.warn = void 0;
|
5452
|
+
this.error = void 0;
|
5453
|
+
this.hls = hls;
|
5454
|
+
this.log = logger.log.bind(logger, "[info]:");
|
5455
|
+
this.warn = logger.warn.bind(logger, "[warning]:");
|
5456
|
+
this.error = logger.error.bind(logger, "[error]:");
|
5457
|
+
this.registerListeners();
|
5493
5458
|
}
|
5494
5459
|
var _proto = ErrorController.prototype;
|
5495
5460
|
_proto.registerListeners = function registerListeners() {
|
@@ -5845,19 +5810,19 @@
|
|
5845
5810
|
}
|
5846
5811
|
};
|
5847
5812
|
return ErrorController;
|
5848
|
-
}(
|
5813
|
+
}();
|
5849
5814
|
|
5850
|
-
var BasePlaylistController = /*#__PURE__*/function (
|
5851
|
-
_inheritsLoose(BasePlaylistController, _Logger);
|
5815
|
+
var BasePlaylistController = /*#__PURE__*/function () {
|
5852
5816
|
function BasePlaylistController(hls, logPrefix) {
|
5853
|
-
|
5854
|
-
|
5855
|
-
|
5856
|
-
|
5857
|
-
|
5858
|
-
|
5859
|
-
|
5860
|
-
|
5817
|
+
this.hls = void 0;
|
5818
|
+
this.timer = -1;
|
5819
|
+
this.requestScheduled = -1;
|
5820
|
+
this.canLoad = false;
|
5821
|
+
this.log = void 0;
|
5822
|
+
this.warn = void 0;
|
5823
|
+
this.log = logger.log.bind(logger, logPrefix + ":");
|
5824
|
+
this.warn = logger.warn.bind(logger, logPrefix + ":");
|
5825
|
+
this.hls = hls;
|
5861
5826
|
}
|
5862
5827
|
var _proto = BasePlaylistController.prototype;
|
5863
5828
|
_proto.destroy = function destroy() {
|
@@ -5890,7 +5855,7 @@
|
|
5890
5855
|
try {
|
5891
5856
|
uri = new self.URL(attr.URI, previous.url).href;
|
5892
5857
|
} catch (error) {
|
5893
|
-
|
5858
|
+
logger.warn("Could not construct new URL for Rendition Report: " + error);
|
5894
5859
|
uri = attr.URI || '';
|
5895
5860
|
}
|
5896
5861
|
// Use exact match. Otherwise, the last partial match, if any, will be used
|
@@ -5929,7 +5894,7 @@
|
|
5929
5894
|
return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
|
5930
5895
|
};
|
5931
5896
|
_proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
|
5932
|
-
var
|
5897
|
+
var _this = this;
|
5933
5898
|
var details = data.details,
|
5934
5899
|
stats = data.stats;
|
5935
5900
|
|
@@ -5976,12 +5941,7 @@
|
|
5976
5941
|
var cdnAge = lastAdvanced + details.ageHeader;
|
5977
5942
|
var currentGoal = Math.min(cdnAge - details.partTarget, details.targetduration * 1.5);
|
5978
5943
|
if (currentGoal > 0) {
|
5979
|
-
if (
|
5980
|
-
// Omit segment and part directives when the last response was more than 3 target durations ago,
|
5981
|
-
this.log("Playlist last advanced " + lastAdvanced.toFixed(2) + "s ago. Omitting segment and part directives.");
|
5982
|
-
msn = undefined;
|
5983
|
-
part = undefined;
|
5984
|
-
} else if (previousDetails != null && previousDetails.tuneInGoal && cdnAge - details.partTarget > previousDetails.tuneInGoal) {
|
5944
|
+
if (previousDetails && currentGoal > previousDetails.tuneInGoal) {
|
5985
5945
|
// If we attempted to get the next or latest playlist update, but currentGoal increased,
|
5986
5946
|
// then we either can't catchup, or the "age" header cannot be trusted.
|
5987
5947
|
this.warn("CDN Tune-in goal increased from: " + previousDetails.tuneInGoal + " to: " + currentGoal + " with playlist age: " + details.age);
|
@@ -6039,7 +5999,7 @@
|
|
6039
5999
|
// );
|
6040
6000
|
|
6041
6001
|
this.timer = self.setTimeout(function () {
|
6042
|
-
return
|
6002
|
+
return _this.loadPlaylist(deliveryDirectives);
|
6043
6003
|
}, estimatedTimeUntilUpdate);
|
6044
6004
|
} else {
|
6045
6005
|
this.clearTimer();
|
@@ -6055,7 +6015,7 @@
|
|
6055
6015
|
return new HlsUrlParameters(msn, part, skip);
|
6056
6016
|
};
|
6057
6017
|
_proto.checkRetry = function checkRetry(errorEvent) {
|
6058
|
-
var
|
6018
|
+
var _this2 = this;
|
6059
6019
|
var errorDetails = errorEvent.details;
|
6060
6020
|
var isTimeout = isTimeoutError(errorEvent);
|
6061
6021
|
var errorAction = errorEvent.errorAction;
|
@@ -6079,7 +6039,7 @@
|
|
6079
6039
|
var delay = getRetryDelay(retryConfig, retryCount);
|
6080
6040
|
// Schedule level/track reload
|
6081
6041
|
this.timer = self.setTimeout(function () {
|
6082
|
-
return
|
6042
|
+
return _this2.loadPlaylist();
|
6083
6043
|
}, delay);
|
6084
6044
|
this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
|
6085
6045
|
}
|
@@ -6090,7 +6050,7 @@
|
|
6090
6050
|
return retry;
|
6091
6051
|
};
|
6092
6052
|
return BasePlaylistController;
|
6093
|
-
}(
|
6053
|
+
}();
|
6094
6054
|
|
6095
6055
|
/*
|
6096
6056
|
* compute an Exponential Weighted moving average
|
@@ -6464,33 +6424,30 @@
|
|
6464
6424
|
}, {});
|
6465
6425
|
}
|
6466
6426
|
|
6467
|
-
var AbrController = /*#__PURE__*/function (
|
6468
|
-
_inheritsLoose(AbrController, _Logger);
|
6427
|
+
var AbrController = /*#__PURE__*/function () {
|
6469
6428
|
function AbrController(_hls) {
|
6470
|
-
var _this;
|
6471
|
-
|
6472
|
-
|
6473
|
-
|
6474
|
-
|
6475
|
-
|
6476
|
-
|
6477
|
-
|
6478
|
-
|
6479
|
-
|
6480
|
-
|
6481
|
-
|
6482
|
-
|
6483
|
-
|
6484
|
-
_this.bwEstimator = void 0;
|
6429
|
+
var _this = this;
|
6430
|
+
this.hls = void 0;
|
6431
|
+
this.lastLevelLoadSec = 0;
|
6432
|
+
this.lastLoadedFragLevel = -1;
|
6433
|
+
this.firstSelection = -1;
|
6434
|
+
this._nextAutoLevel = -1;
|
6435
|
+
this.nextAutoLevelKey = '';
|
6436
|
+
this.audioTracksByGroup = null;
|
6437
|
+
this.codecTiers = null;
|
6438
|
+
this.timer = -1;
|
6439
|
+
this.fragCurrent = null;
|
6440
|
+
this.partCurrent = null;
|
6441
|
+
this.bitrateTestDelay = 0;
|
6442
|
+
this.bwEstimator = void 0;
|
6485
6443
|
/*
|
6486
6444
|
This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
|
6487
6445
|
quickly enough to prevent underbuffering
|
6488
6446
|
*/
|
6489
|
-
|
6490
|
-
var
|
6491
|
-
|
6492
|
-
|
6493
|
-
hls = _assertThisInitialize.hls;
|
6447
|
+
this._abandonRulesCheck = function () {
|
6448
|
+
var frag = _this.fragCurrent,
|
6449
|
+
part = _this.partCurrent,
|
6450
|
+
hls = _this.hls;
|
6494
6451
|
var autoLevelEnabled = hls.autoLevelEnabled,
|
6495
6452
|
media = hls.media;
|
6496
6453
|
if (!frag || !media) {
|
@@ -6579,22 +6536,21 @@
|
|
6579
6536
|
_this.resetEstimator(nextLoadLevelBitrate);
|
6580
6537
|
}
|
6581
6538
|
_this.clearTimer();
|
6582
|
-
|
6539
|
+
logger.warn("[abr] Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
|
6583
6540
|
hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
|
6584
6541
|
frag: frag,
|
6585
6542
|
part: part,
|
6586
6543
|
stats: stats
|
6587
6544
|
});
|
6588
6545
|
};
|
6589
|
-
|
6590
|
-
|
6591
|
-
|
6592
|
-
return _this;
|
6546
|
+
this.hls = _hls;
|
6547
|
+
this.bwEstimator = this.initEstimator();
|
6548
|
+
this.registerListeners();
|
6593
6549
|
}
|
6594
6550
|
var _proto = AbrController.prototype;
|
6595
6551
|
_proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
|
6596
6552
|
if (abrEwmaDefaultEstimate) {
|
6597
|
-
|
6553
|
+
logger.log("setting initial bwe to " + abrEwmaDefaultEstimate);
|
6598
6554
|
this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
|
6599
6555
|
}
|
6600
6556
|
this.firstSelection = -1;
|
@@ -6803,8 +6759,7 @@
|
|
6803
6759
|
}
|
6804
6760
|
};
|
6805
6761
|
_proto.getAutoLevelKey = function getAutoLevelKey() {
|
6806
|
-
|
6807
|
-
return this.getBwEstimate() + "_" + ((_this$hls$mainForward = this.hls.mainForwardBufferInfo) == null ? void 0 : _this$hls$mainForward.len);
|
6762
|
+
return this.getBwEstimate() + "_" + this.getStarvationDelay().toFixed(2);
|
6808
6763
|
};
|
6809
6764
|
_proto.getNextABRAutoLevel = function getNextABRAutoLevel() {
|
6810
6765
|
var fragCurrent = this.fragCurrent,
|
@@ -6812,17 +6767,11 @@
|
|
6812
6767
|
hls = this.hls;
|
6813
6768
|
var maxAutoLevel = hls.maxAutoLevel,
|
6814
6769
|
config = hls.config,
|
6815
|
-
minAutoLevel = hls.minAutoLevel
|
6816
|
-
media = hls.media;
|
6770
|
+
minAutoLevel = hls.minAutoLevel;
|
6817
6771
|
var currentFragDuration = partCurrent ? partCurrent.duration : fragCurrent ? fragCurrent.duration : 0;
|
6818
|
-
|
6819
|
-
// playbackRate is the absolute value of the playback rate; if media.playbackRate is 0, we use 1 to load as
|
6820
|
-
// if we're playing back at the normal rate.
|
6821
|
-
var playbackRate = media && media.playbackRate !== 0 ? Math.abs(media.playbackRate) : 1.0;
|
6822
6772
|
var avgbw = this.getBwEstimate();
|
6823
6773
|
// bufferStarvationDelay is the wall-clock time left until the playback buffer is exhausted.
|
6824
|
-
var
|
6825
|
-
var bufferStarvationDelay = (bufferInfo ? bufferInfo.len : 0) / playbackRate;
|
6774
|
+
var bufferStarvationDelay = this.getStarvationDelay();
|
6826
6775
|
var bwFactor = config.abrBandWidthFactor;
|
6827
6776
|
var bwUpFactor = config.abrBandWidthUpFactor;
|
6828
6777
|
|
@@ -6846,13 +6795,13 @@
|
|
6846
6795
|
// cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
|
6847
6796
|
var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
|
6848
6797
|
maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
|
6849
|
-
|
6798
|
+
logger.info("[abr] bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
|
6850
6799
|
// don't use conservative factor on bitrate test
|
6851
6800
|
bwFactor = bwUpFactor = 1;
|
6852
6801
|
}
|
6853
6802
|
}
|
6854
6803
|
var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
|
6855
|
-
|
6804
|
+
logger.info("[abr] " + (bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
|
6856
6805
|
if (bestLevel > -1) {
|
6857
6806
|
return bestLevel;
|
6858
6807
|
}
|
@@ -6865,6 +6814,18 @@
|
|
6865
6814
|
// or if bitrate is not lower, continue to use loadLevel
|
6866
6815
|
return hls.loadLevel;
|
6867
6816
|
};
|
6817
|
+
_proto.getStarvationDelay = function getStarvationDelay() {
|
6818
|
+
var hls = this.hls;
|
6819
|
+
var media = hls.media;
|
6820
|
+
if (!media) {
|
6821
|
+
return Infinity;
|
6822
|
+
}
|
6823
|
+
// playbackRate is the absolute value of the playback rate; if media.playbackRate is 0, we use 1 to load as
|
6824
|
+
// if we're playing back at the normal rate.
|
6825
|
+
var playbackRate = media && media.playbackRate !== 0 ? Math.abs(media.playbackRate) : 1.0;
|
6826
|
+
var bufferInfo = hls.mainForwardBufferInfo;
|
6827
|
+
return (bufferInfo ? bufferInfo.len : 0) / playbackRate;
|
6828
|
+
};
|
6868
6829
|
_proto.getBwEstimate = function getBwEstimate() {
|
6869
6830
|
return this.bwEstimator.canEstimate() ? this.bwEstimator.getEstimate() : this.hls.config.abrEwmaDefaultEstimate;
|
6870
6831
|
};
|
@@ -6908,7 +6869,7 @@
|
|
6908
6869
|
currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
|
6909
6870
|
currentFrameRate = minFramerate;
|
6910
6871
|
currentBw = Math.max(currentBw, minBitrate);
|
6911
|
-
|
6872
|
+
logger.log("[abr] picked start tier " + JSON.stringify(startTier));
|
6912
6873
|
} else {
|
6913
6874
|
currentCodecSet = level == null ? void 0 : level.codecSet;
|
6914
6875
|
currentVideoRange = level == null ? void 0 : level.videoRange;
|
@@ -6961,9 +6922,9 @@
|
|
6961
6922
|
var forcedAutoLevel = _this2.forcedAutoLevel;
|
6962
6923
|
if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
|
6963
6924
|
if (levelsSkipped.length) {
|
6964
|
-
|
6925
|
+
logger.trace("[abr] Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
|
6965
6926
|
}
|
6966
|
-
|
6927
|
+
logger.info("[abr] switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
|
6967
6928
|
}
|
6968
6929
|
if (firstSelection) {
|
6969
6930
|
_this2.firstSelection = i;
|
@@ -6997,7 +6958,7 @@
|
|
6997
6958
|
}
|
6998
6959
|
var firstLevel = this.hls.firstLevel;
|
6999
6960
|
var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
|
7000
|
-
|
6961
|
+
logger.warn("[abr] Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
|
7001
6962
|
return clamped;
|
7002
6963
|
}
|
7003
6964
|
}, {
|
@@ -7050,7 +7011,7 @@
|
|
7050
7011
|
}
|
7051
7012
|
}]);
|
7052
7013
|
return AbrController;
|
7053
|
-
}(
|
7014
|
+
}();
|
7054
7015
|
|
7055
7016
|
/**
|
7056
7017
|
* Provides methods dealing with buffer length retrieval for example.
|
@@ -7271,57 +7232,57 @@
|
|
7271
7232
|
}();
|
7272
7233
|
|
7273
7234
|
var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
|
7274
|
-
var BufferController = /*#__PURE__*/function (
|
7275
|
-
_inheritsLoose(BufferController, _Logger);
|
7235
|
+
var BufferController = /*#__PURE__*/function () {
|
7276
7236
|
function BufferController(hls) {
|
7277
|
-
var _this;
|
7278
|
-
_this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
|
7237
|
+
var _this = this;
|
7279
7238
|
// The level details used to determine duration, target-duration and live
|
7280
|
-
|
7239
|
+
this.details = null;
|
7281
7240
|
// cache the self generated object url to detect hijack of video tag
|
7282
|
-
|
7241
|
+
this._objectUrl = null;
|
7283
7242
|
// A queue of buffer operations which require the SourceBuffer to not be updating upon execution
|
7284
|
-
|
7243
|
+
this.operationQueue = void 0;
|
7285
7244
|
// References to event listeners for each SourceBuffer, so that they can be referenced for event removal
|
7286
|
-
|
7287
|
-
|
7245
|
+
this.listeners = void 0;
|
7246
|
+
this.hls = void 0;
|
7288
7247
|
// The number of BUFFER_CODEC events received before any sourceBuffers are created
|
7289
|
-
|
7248
|
+
this.bufferCodecEventsExpected = 0;
|
7290
7249
|
// The total number of BUFFER_CODEC events received
|
7291
|
-
|
7250
|
+
this._bufferCodecEventsTotal = 0;
|
7292
7251
|
// A reference to the attached media element
|
7293
|
-
|
7252
|
+
this.media = null;
|
7294
7253
|
// A reference to the active media source
|
7295
|
-
|
7254
|
+
this.mediaSource = null;
|
7296
7255
|
// Last MP3 audio chunk appended
|
7297
|
-
|
7298
|
-
|
7256
|
+
this.lastMpegAudioChunk = null;
|
7257
|
+
this.appendSource = void 0;
|
7299
7258
|
// counters
|
7300
|
-
|
7259
|
+
this.appendErrors = {
|
7301
7260
|
audio: 0,
|
7302
7261
|
video: 0,
|
7303
7262
|
audiovideo: 0
|
7304
7263
|
};
|
7305
|
-
|
7306
|
-
|
7307
|
-
|
7308
|
-
|
7264
|
+
this.tracks = {};
|
7265
|
+
this.pendingTracks = {};
|
7266
|
+
this.sourceBuffer = void 0;
|
7267
|
+
this.log = void 0;
|
7268
|
+
this.warn = void 0;
|
7269
|
+
this.error = void 0;
|
7270
|
+
this._onEndStreaming = function (event) {
|
7309
7271
|
if (!_this.hls) {
|
7310
7272
|
return;
|
7311
7273
|
}
|
7312
7274
|
_this.hls.pauseBuffering();
|
7313
7275
|
};
|
7314
|
-
|
7276
|
+
this._onStartStreaming = function (event) {
|
7315
7277
|
if (!_this.hls) {
|
7316
7278
|
return;
|
7317
7279
|
}
|
7318
7280
|
_this.hls.resumeBuffering();
|
7319
7281
|
};
|
7320
7282
|
// Keep as arrow functions so that we can directly reference these functions directly as event listeners
|
7321
|
-
|
7322
|
-
var
|
7323
|
-
|
7324
|
-
mediaSource = _assertThisInitialize.mediaSource;
|
7283
|
+
this._onMediaSourceOpen = function () {
|
7284
|
+
var media = _this.media,
|
7285
|
+
mediaSource = _this.mediaSource;
|
7325
7286
|
_this.log('Media source opened');
|
7326
7287
|
if (media) {
|
7327
7288
|
media.removeEventListener('emptied', _this._onMediaEmptied);
|
@@ -7337,25 +7298,27 @@
|
|
7337
7298
|
}
|
7338
7299
|
_this.checkPendingTracks();
|
7339
7300
|
};
|
7340
|
-
|
7301
|
+
this._onMediaSourceClose = function () {
|
7341
7302
|
_this.log('Media source closed');
|
7342
7303
|
};
|
7343
|
-
|
7304
|
+
this._onMediaSourceEnded = function () {
|
7344
7305
|
_this.log('Media source ended');
|
7345
7306
|
};
|
7346
|
-
|
7347
|
-
var
|
7348
|
-
|
7349
|
-
_objectUrl = _assertThisInitialize2._objectUrl;
|
7307
|
+
this._onMediaEmptied = function () {
|
7308
|
+
var mediaSrc = _this.mediaSrc,
|
7309
|
+
_objectUrl = _this._objectUrl;
|
7350
7310
|
if (mediaSrc !== _objectUrl) {
|
7351
|
-
|
7311
|
+
logger.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
|
7352
7312
|
}
|
7353
7313
|
};
|
7354
|
-
|
7355
|
-
|
7356
|
-
|
7357
|
-
|
7358
|
-
|
7314
|
+
this.hls = hls;
|
7315
|
+
var logPrefix = '[buffer-controller]';
|
7316
|
+
this.appendSource = hls.config.preferManagedMediaSource;
|
7317
|
+
this.log = logger.log.bind(logger, logPrefix);
|
7318
|
+
this.warn = logger.warn.bind(logger, logPrefix);
|
7319
|
+
this.error = logger.error.bind(logger, logPrefix);
|
7320
|
+
this._initSourceBuffer();
|
7321
|
+
this.registerListeners();
|
7359
7322
|
}
|
7360
7323
|
var _proto = BufferController.prototype;
|
7361
7324
|
_proto.hasSourceTypes = function hasSourceTypes() {
|
@@ -7367,12 +7330,6 @@
|
|
7367
7330
|
this.lastMpegAudioChunk = null;
|
7368
7331
|
// @ts-ignore
|
7369
7332
|
this.hls = null;
|
7370
|
-
// @ts-ignore
|
7371
|
-
this._onMediaSourceOpen = this._onMediaSourceClose = null;
|
7372
|
-
// @ts-ignore
|
7373
|
-
this._onMediaSourceEnded = null;
|
7374
|
-
// @ts-ignore
|
7375
|
-
this._onStartStreaming = this._onEndStreaming = null;
|
7376
7333
|
};
|
7377
7334
|
_proto.registerListeners = function registerListeners() {
|
7378
7335
|
var hls = this.hls;
|
@@ -7530,7 +7487,6 @@
|
|
7530
7487
|
_this2.resetBuffer(type);
|
7531
7488
|
});
|
7532
7489
|
this._initSourceBuffer();
|
7533
|
-
this.hls.resumeBuffering();
|
7534
7490
|
};
|
7535
7491
|
_proto.resetBuffer = function resetBuffer(type) {
|
7536
7492
|
var sb = this.sourceBuffer[type];
|
@@ -8234,7 +8190,7 @@
|
|
8234
8190
|
}
|
8235
8191
|
}]);
|
8236
8192
|
return BufferController;
|
8237
|
-
}(
|
8193
|
+
}();
|
8238
8194
|
function removeSourceChildren(node) {
|
8239
8195
|
var sourceChildren = node.querySelectorAll('source');
|
8240
8196
|
[].slice.call(sourceChildren).forEach(function (source) {
|
@@ -8358,7 +8314,7 @@
|
|
8358
8314
|
var hls = this.hls;
|
8359
8315
|
var maxLevel = this.getMaxLevel(levels.length - 1);
|
8360
8316
|
if (maxLevel !== this.autoLevelCapping) {
|
8361
|
-
|
8317
|
+
logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8362
8318
|
}
|
8363
8319
|
hls.autoLevelCapping = maxLevel;
|
8364
8320
|
if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
|
@@ -8548,10 +8504,10 @@
|
|
8548
8504
|
totalDroppedFrames: droppedFrames
|
8549
8505
|
});
|
8550
8506
|
if (droppedFPS > 0) {
|
8551
|
-
//
|
8507
|
+
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8552
8508
|
if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
|
8553
8509
|
var currentLevel = hls.currentLevel;
|
8554
|
-
|
8510
|
+
logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8555
8511
|
if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
|
8556
8512
|
currentLevel = currentLevel - 1;
|
8557
8513
|
hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
|
@@ -8585,28 +8541,26 @@
|
|
8585
8541
|
}();
|
8586
8542
|
|
8587
8543
|
var PATHWAY_PENALTY_DURATION_MS = 300000;
|
8588
|
-
var ContentSteeringController = /*#__PURE__*/function (
|
8589
|
-
_inheritsLoose(ContentSteeringController, _Logger);
|
8544
|
+
var ContentSteeringController = /*#__PURE__*/function () {
|
8590
8545
|
function ContentSteeringController(hls) {
|
8591
|
-
|
8592
|
-
|
8593
|
-
|
8594
|
-
|
8595
|
-
|
8596
|
-
|
8597
|
-
|
8598
|
-
|
8599
|
-
|
8600
|
-
|
8601
|
-
|
8602
|
-
|
8603
|
-
|
8604
|
-
|
8605
|
-
|
8606
|
-
|
8607
|
-
|
8608
|
-
|
8609
|
-
return _this;
|
8546
|
+
this.hls = void 0;
|
8547
|
+
this.log = void 0;
|
8548
|
+
this.loader = null;
|
8549
|
+
this.uri = null;
|
8550
|
+
this.pathwayId = '.';
|
8551
|
+
this.pathwayPriority = null;
|
8552
|
+
this.timeToLoad = 300;
|
8553
|
+
this.reloadTimer = -1;
|
8554
|
+
this.updated = 0;
|
8555
|
+
this.started = false;
|
8556
|
+
this.enabled = true;
|
8557
|
+
this.levels = null;
|
8558
|
+
this.audioTracks = null;
|
8559
|
+
this.subtitleTracks = null;
|
8560
|
+
this.penalizedPathways = {};
|
8561
|
+
this.hls = hls;
|
8562
|
+
this.log = logger.log.bind(logger, "[content-steering]:");
|
8563
|
+
this.registerListeners();
|
8610
8564
|
}
|
8611
8565
|
var _proto = ContentSteeringController.prototype;
|
8612
8566
|
_proto.registerListeners = function registerListeners() {
|
@@ -8727,7 +8681,7 @@
|
|
8727
8681
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
8728
8682
|
}
|
8729
8683
|
if (!errorAction.resolved) {
|
8730
|
-
|
8684
|
+
logger.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
|
8731
8685
|
}
|
8732
8686
|
}
|
8733
8687
|
};
|
@@ -8807,7 +8761,7 @@
|
|
8807
8761
|
return defaultPathway;
|
8808
8762
|
};
|
8809
8763
|
_proto.clonePathways = function clonePathways(pathwayClones) {
|
8810
|
-
var
|
8764
|
+
var _this = this;
|
8811
8765
|
var levels = this.levels;
|
8812
8766
|
if (!levels) {
|
8813
8767
|
return;
|
@@ -8823,7 +8777,7 @@
|
|
8823
8777
|
})) {
|
8824
8778
|
return;
|
8825
8779
|
}
|
8826
|
-
var clonedVariants =
|
8780
|
+
var clonedVariants = _this.getLevelsForPathway(baseId).map(function (baseLevel) {
|
8827
8781
|
var attributes = new AttrList(baseLevel.attrs);
|
8828
8782
|
attributes['PATHWAY-ID'] = cloneId;
|
8829
8783
|
var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
|
@@ -8860,12 +8814,12 @@
|
|
8860
8814
|
return clonedLevel;
|
8861
8815
|
});
|
8862
8816
|
levels.push.apply(levels, clonedVariants);
|
8863
|
-
cloneRenditionGroups(
|
8864
|
-
cloneRenditionGroups(
|
8817
|
+
cloneRenditionGroups(_this.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
|
8818
|
+
cloneRenditionGroups(_this.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
|
8865
8819
|
});
|
8866
8820
|
};
|
8867
8821
|
_proto.loadSteeringManifest = function loadSteeringManifest(uri) {
|
8868
|
-
var
|
8822
|
+
var _this2 = this;
|
8869
8823
|
var config = this.hls.config;
|
8870
8824
|
var Loader = config.loader;
|
8871
8825
|
if (this.loader) {
|
@@ -8900,87 +8854,87 @@
|
|
8900
8854
|
};
|
8901
8855
|
var callbacks = {
|
8902
8856
|
onSuccess: function onSuccess(response, stats, context, networkDetails) {
|
8903
|
-
|
8857
|
+
_this2.log("Loaded steering manifest: \"" + url + "\"");
|
8904
8858
|
var steeringData = response.data;
|
8905
|
-
if (
|
8906
|
-
|
8859
|
+
if (steeringData.VERSION !== 1) {
|
8860
|
+
_this2.log("Steering VERSION " + steeringData.VERSION + " not supported!");
|
8907
8861
|
return;
|
8908
8862
|
}
|
8909
|
-
|
8910
|
-
|
8863
|
+
_this2.updated = performance.now();
|
8864
|
+
_this2.timeToLoad = steeringData.TTL;
|
8911
8865
|
var reloadUri = steeringData['RELOAD-URI'],
|
8912
8866
|
pathwayClones = steeringData['PATHWAY-CLONES'],
|
8913
8867
|
pathwayPriority = steeringData['PATHWAY-PRIORITY'];
|
8914
8868
|
if (reloadUri) {
|
8915
8869
|
try {
|
8916
|
-
|
8870
|
+
_this2.uri = new self.URL(reloadUri, url).href;
|
8917
8871
|
} catch (error) {
|
8918
|
-
|
8919
|
-
|
8872
|
+
_this2.enabled = false;
|
8873
|
+
_this2.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
|
8920
8874
|
return;
|
8921
8875
|
}
|
8922
8876
|
}
|
8923
|
-
|
8877
|
+
_this2.scheduleRefresh(_this2.uri || context.url);
|
8924
8878
|
if (pathwayClones) {
|
8925
|
-
|
8879
|
+
_this2.clonePathways(pathwayClones);
|
8926
8880
|
}
|
8927
8881
|
var loadedSteeringData = {
|
8928
8882
|
steeringManifest: steeringData,
|
8929
8883
|
url: url.toString()
|
8930
8884
|
};
|
8931
|
-
|
8885
|
+
_this2.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
|
8932
8886
|
if (pathwayPriority) {
|
8933
|
-
|
8887
|
+
_this2.updatePathwayPriority(pathwayPriority);
|
8934
8888
|
}
|
8935
8889
|
},
|
8936
8890
|
onError: function onError(error, context, networkDetails, stats) {
|
8937
|
-
|
8938
|
-
|
8891
|
+
_this2.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
|
8892
|
+
_this2.stopLoad();
|
8939
8893
|
if (error.code === 410) {
|
8940
|
-
|
8941
|
-
|
8894
|
+
_this2.enabled = false;
|
8895
|
+
_this2.log("Steering manifest " + context.url + " no longer available");
|
8942
8896
|
return;
|
8943
8897
|
}
|
8944
|
-
var ttl =
|
8898
|
+
var ttl = _this2.timeToLoad * 1000;
|
8945
8899
|
if (error.code === 429) {
|
8946
|
-
var loader =
|
8900
|
+
var loader = _this2.loader;
|
8947
8901
|
if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
|
8948
8902
|
var retryAfter = loader.getResponseHeader('Retry-After');
|
8949
8903
|
if (retryAfter) {
|
8950
8904
|
ttl = parseFloat(retryAfter) * 1000;
|
8951
8905
|
}
|
8952
8906
|
}
|
8953
|
-
|
8907
|
+
_this2.log("Steering manifest " + context.url + " rate limited");
|
8954
8908
|
return;
|
8955
8909
|
}
|
8956
|
-
|
8910
|
+
_this2.scheduleRefresh(_this2.uri || context.url, ttl);
|
8957
8911
|
},
|
8958
8912
|
onTimeout: function onTimeout(stats, context, networkDetails) {
|
8959
|
-
|
8960
|
-
|
8913
|
+
_this2.log("Timeout loading steering manifest (" + context.url + ")");
|
8914
|
+
_this2.scheduleRefresh(_this2.uri || context.url);
|
8961
8915
|
}
|
8962
8916
|
};
|
8963
8917
|
this.log("Requesting steering manifest: " + url);
|
8964
8918
|
this.loader.load(context, loaderConfig, callbacks);
|
8965
8919
|
};
|
8966
8920
|
_proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
|
8967
|
-
var
|
8921
|
+
var _this3 = this;
|
8968
8922
|
if (ttlMs === void 0) {
|
8969
8923
|
ttlMs = this.timeToLoad * 1000;
|
8970
8924
|
}
|
8971
8925
|
this.clearTimeout();
|
8972
8926
|
this.reloadTimer = self.setTimeout(function () {
|
8973
|
-
var
|
8974
|
-
var media = (
|
8927
|
+
var _this3$hls;
|
8928
|
+
var media = (_this3$hls = _this3.hls) == null ? void 0 : _this3$hls.media;
|
8975
8929
|
if (media && !media.ended) {
|
8976
|
-
|
8930
|
+
_this3.loadSteeringManifest(uri);
|
8977
8931
|
return;
|
8978
8932
|
}
|
8979
|
-
|
8933
|
+
_this3.scheduleRefresh(uri, _this3.timeToLoad * 1000);
|
8980
8934
|
}, ttlMs);
|
8981
8935
|
};
|
8982
8936
|
return ContentSteeringController;
|
8983
|
-
}(
|
8937
|
+
}();
|
8984
8938
|
function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
|
8985
8939
|
if (!tracks) {
|
8986
8940
|
return;
|
@@ -9816,7 +9770,7 @@
|
|
9816
9770
|
});
|
9817
9771
|
function timelineConfig() {
|
9818
9772
|
return {
|
9819
|
-
cueHandler:
|
9773
|
+
cueHandler: Cues,
|
9820
9774
|
// used by timeline-controller
|
9821
9775
|
enableWebVTT: false,
|
9822
9776
|
// used by timeline-controller
|
@@ -9847,7 +9801,7 @@
|
|
9847
9801
|
/**
|
9848
9802
|
* @ignore
|
9849
9803
|
*/
|
9850
|
-
function mergeConfig(defaultConfig, userConfig
|
9804
|
+
function mergeConfig(defaultConfig, userConfig) {
|
9851
9805
|
if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
|
9852
9806
|
throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
|
9853
9807
|
}
|
@@ -9917,7 +9871,7 @@
|
|
9917
9871
|
/**
|
9918
9872
|
* @ignore
|
9919
9873
|
*/
|
9920
|
-
function enableStreamingMode(config
|
9874
|
+
function enableStreamingMode(config) {
|
9921
9875
|
var currentLoader = config.loader;
|
9922
9876
|
if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
|
9923
9877
|
// If a developer has configured their own loader, respect that choice
|
@@ -9934,11 +9888,12 @@
|
|
9934
9888
|
}
|
9935
9889
|
}
|
9936
9890
|
|
9891
|
+
var chromeOrFirefox;
|
9937
9892
|
var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
|
9938
9893
|
_inheritsLoose(LevelController, _BasePlaylistControll);
|
9939
9894
|
function LevelController(hls, contentSteeringController) {
|
9940
9895
|
var _this;
|
9941
|
-
_this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
|
9896
|
+
_this = _BasePlaylistControll.call(this, hls, '[level-controller]') || this;
|
9942
9897
|
_this._levels = [];
|
9943
9898
|
_this._firstLevel = -1;
|
9944
9899
|
_this._maxAutoLevel = -1;
|
@@ -10007,13 +9962,21 @@
|
|
10007
9962
|
var videoCodecFound = false;
|
10008
9963
|
var audioCodecFound = false;
|
10009
9964
|
data.levels.forEach(function (levelParsed) {
|
10010
|
-
var _videoCodec;
|
9965
|
+
var _audioCodec, _videoCodec;
|
10011
9966
|
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
|
10012
9970
|
var audioCodec = levelParsed.audioCodec,
|
10013
9971
|
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
|
+
}
|
10014
9978
|
if (audioCodec) {
|
10015
|
-
|
10016
|
-
levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
|
9979
|
+
levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource);
|
10017
9980
|
}
|
10018
9981
|
if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
|
10019
9982
|
videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
|
@@ -10245,12 +10208,7 @@
|
|
10245
10208
|
if (curLevel.fragmentError === 0) {
|
10246
10209
|
curLevel.loadError = 0;
|
10247
10210
|
}
|
10248
|
-
|
10249
|
-
var previousDetails = curLevel.details;
|
10250
|
-
if (previousDetails === data.details && previousDetails.advanced) {
|
10251
|
-
previousDetails = undefined;
|
10252
|
-
}
|
10253
|
-
this.playlistLoaded(level, data, previousDetails);
|
10211
|
+
this.playlistLoaded(level, data, curLevel.details);
|
10254
10212
|
} else if ((_data$deliveryDirecti2 = data.deliveryDirectives) != null && _data$deliveryDirecti2.skip) {
|
10255
10213
|
// received a delta playlist update that cannot be merged
|
10256
10214
|
details.deltaUpdateFailed = true;
|
@@ -11165,8 +11123,8 @@
|
|
11165
11123
|
var _frag$decryptdata;
|
11166
11124
|
var byteRangeStart = start;
|
11167
11125
|
var byteRangeEnd = end;
|
11168
|
-
if (frag.sn === 'initSegment' &&
|
11169
|
-
// MAP segment encrypted with method 'AES-128'
|
11126
|
+
if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method) === 'AES-128') {
|
11127
|
+
// MAP segment encrypted with method 'AES-128', when served with HTTP Range,
|
11170
11128
|
// has the unencrypted size specified in the range.
|
11171
11129
|
// Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
11172
11130
|
var fragmentLen = end - start;
|
@@ -11199,9 +11157,6 @@
|
|
11199
11157
|
(part ? part : frag).stats.aborted = true;
|
11200
11158
|
return new LoadError(errorData);
|
11201
11159
|
}
|
11202
|
-
function isMethodFullSegmentAesCbc(method) {
|
11203
|
-
return method === 'AES-128' || method === 'AES-256';
|
11204
|
-
}
|
11205
11160
|
var LoadError = /*#__PURE__*/function (_Error) {
|
11206
11161
|
_inheritsLoose(LoadError, _Error);
|
11207
11162
|
function LoadError(data) {
|
@@ -11358,8 +11313,6 @@
|
|
11358
11313
|
}
|
11359
11314
|
return this.loadKeyEME(keyInfo, frag);
|
11360
11315
|
case 'AES-128':
|
11361
|
-
case 'AES-256':
|
11362
|
-
case 'AES-256-CTR':
|
11363
11316
|
return this.loadKeyHTTP(keyInfo, frag);
|
11364
11317
|
default:
|
11365
11318
|
return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
|
@@ -11493,17 +11446,13 @@
|
|
11493
11446
|
* we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
|
11494
11447
|
* task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
|
11495
11448
|
*/
|
11496
|
-
var TaskLoop = /*#__PURE__*/function (
|
11497
|
-
|
11498
|
-
|
11499
|
-
|
11500
|
-
|
11501
|
-
|
11502
|
-
|
11503
|
-
_this._tickInterval = null;
|
11504
|
-
_this._tickCallCount = 0;
|
11505
|
-
_this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
|
11506
|
-
return _this;
|
11449
|
+
var TaskLoop = /*#__PURE__*/function () {
|
11450
|
+
function TaskLoop() {
|
11451
|
+
this._boundTick = void 0;
|
11452
|
+
this._tickTimer = null;
|
11453
|
+
this._tickInterval = null;
|
11454
|
+
this._tickCallCount = 0;
|
11455
|
+
this._boundTick = this.tick.bind(this);
|
11507
11456
|
}
|
11508
11457
|
var _proto = TaskLoop.prototype;
|
11509
11458
|
_proto.destroy = function destroy() {
|
@@ -11589,7 +11538,7 @@
|
|
11589
11538
|
*/;
|
11590
11539
|
_proto.doTick = function doTick() {};
|
11591
11540
|
return TaskLoop;
|
11592
|
-
}(
|
11541
|
+
}();
|
11593
11542
|
|
11594
11543
|
var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
|
11595
11544
|
if (size === void 0) {
|
@@ -11775,65 +11724,37 @@
|
|
11775
11724
|
}
|
11776
11725
|
|
11777
11726
|
var AESCrypto = /*#__PURE__*/function () {
|
11778
|
-
function AESCrypto(subtle, iv
|
11727
|
+
function AESCrypto(subtle, iv) {
|
11779
11728
|
this.subtle = void 0;
|
11780
11729
|
this.aesIV = void 0;
|
11781
|
-
this.aesMode = void 0;
|
11782
11730
|
this.subtle = subtle;
|
11783
11731
|
this.aesIV = iv;
|
11784
|
-
this.aesMode = aesMode;
|
11785
11732
|
}
|
11786
11733
|
var _proto = AESCrypto.prototype;
|
11787
11734
|
_proto.decrypt = function decrypt(data, key) {
|
11788
|
-
|
11789
|
-
|
11790
|
-
|
11791
|
-
|
11792
|
-
iv: this.aesIV
|
11793
|
-
}, key, data);
|
11794
|
-
case DecrypterAesMode.ctr:
|
11795
|
-
return this.subtle.decrypt({
|
11796
|
-
name: 'AES-CTR',
|
11797
|
-
counter: this.aesIV,
|
11798
|
-
length: 64
|
11799
|
-
},
|
11800
|
-
//64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
|
11801
|
-
key, data);
|
11802
|
-
default:
|
11803
|
-
throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
|
11804
|
-
}
|
11735
|
+
return this.subtle.decrypt({
|
11736
|
+
name: 'AES-CBC',
|
11737
|
+
iv: this.aesIV
|
11738
|
+
}, key, data);
|
11805
11739
|
};
|
11806
11740
|
return AESCrypto;
|
11807
11741
|
}();
|
11808
11742
|
|
11809
11743
|
var FastAESKey = /*#__PURE__*/function () {
|
11810
|
-
function FastAESKey(subtle, key
|
11744
|
+
function FastAESKey(subtle, key) {
|
11811
11745
|
this.subtle = void 0;
|
11812
11746
|
this.key = void 0;
|
11813
|
-
this.aesMode = void 0;
|
11814
11747
|
this.subtle = subtle;
|
11815
11748
|
this.key = key;
|
11816
|
-
this.aesMode = aesMode;
|
11817
11749
|
}
|
11818
11750
|
var _proto = FastAESKey.prototype;
|
11819
11751
|
_proto.expandKey = function expandKey() {
|
11820
|
-
var subtleAlgoName = getSubtleAlgoName(this.aesMode);
|
11821
11752
|
return this.subtle.importKey('raw', this.key, {
|
11822
|
-
name:
|
11753
|
+
name: 'AES-CBC'
|
11823
11754
|
}, false, ['encrypt', 'decrypt']);
|
11824
11755
|
};
|
11825
11756
|
return FastAESKey;
|
11826
11757
|
}();
|
11827
|
-
function getSubtleAlgoName(aesMode) {
|
11828
|
-
switch (aesMode) {
|
11829
|
-
case DecrypterAesMode.cbc:
|
11830
|
-
return 'AES-CBC';
|
11831
|
-
case DecrypterAesMode.ctr:
|
11832
|
-
return 'AES-CTR';
|
11833
|
-
default:
|
11834
|
-
throw new Error("[FastAESKey] invalid aes mode " + aesMode);
|
11835
|
-
}
|
11836
|
-
}
|
11837
11758
|
|
11838
11759
|
// PKCS7
|
11839
11760
|
function removePadding(array) {
|
@@ -12086,8 +12007,7 @@
|
|
12086
12007
|
this.currentIV = null;
|
12087
12008
|
this.currentResult = null;
|
12088
12009
|
this.useSoftware = void 0;
|
12089
|
-
this.
|
12090
|
-
this.enableSoftwareAES = config.enableSoftwareAES;
|
12010
|
+
this.useSoftware = config.enableSoftwareAES;
|
12091
12011
|
this.removePKCS7Padding = removePKCS7Padding;
|
12092
12012
|
// built in decryptor expects PKCS7 padding
|
12093
12013
|
if (removePKCS7Padding) {
|
@@ -12100,7 +12020,9 @@
|
|
12100
12020
|
/* no-op */
|
12101
12021
|
}
|
12102
12022
|
}
|
12103
|
-
|
12023
|
+
if (this.subtle === null) {
|
12024
|
+
this.useSoftware = true;
|
12025
|
+
}
|
12104
12026
|
}
|
12105
12027
|
var _proto = Decrypter.prototype;
|
12106
12028
|
_proto.destroy = function destroy() {
|
@@ -12137,11 +12059,11 @@
|
|
12137
12059
|
this.softwareDecrypter = null;
|
12138
12060
|
}
|
12139
12061
|
};
|
12140
|
-
_proto.decrypt = function decrypt(data, key, iv
|
12062
|
+
_proto.decrypt = function decrypt(data, key, iv) {
|
12141
12063
|
var _this = this;
|
12142
12064
|
if (this.useSoftware) {
|
12143
12065
|
return new Promise(function (resolve, reject) {
|
12144
|
-
_this.softwareDecrypt(new Uint8Array(data), key, iv
|
12066
|
+
_this.softwareDecrypt(new Uint8Array(data), key, iv);
|
12145
12067
|
var decryptResult = _this.flush();
|
12146
12068
|
if (decryptResult) {
|
12147
12069
|
resolve(decryptResult.buffer);
|
@@ -12150,20 +12072,16 @@
|
|
12150
12072
|
}
|
12151
12073
|
});
|
12152
12074
|
}
|
12153
|
-
return this.webCryptoDecrypt(new Uint8Array(data), key, iv
|
12075
|
+
return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
|
12154
12076
|
}
|
12155
12077
|
|
12156
12078
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
12157
12079
|
// data is handled in the flush() call
|
12158
12080
|
;
|
12159
|
-
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv
|
12081
|
+
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
|
12160
12082
|
var currentIV = this.currentIV,
|
12161
12083
|
currentResult = this.currentResult,
|
12162
12084
|
remainderData = this.remainderData;
|
12163
|
-
if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
|
12164
|
-
logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
|
12165
|
-
return null;
|
12166
|
-
}
|
12167
12085
|
this.logOnce('JS AES decrypt');
|
12168
12086
|
// The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
|
12169
12087
|
// This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
|
@@ -12196,12 +12114,12 @@
|
|
12196
12114
|
}
|
12197
12115
|
return result;
|
12198
12116
|
};
|
12199
|
-
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv
|
12117
|
+
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
|
12200
12118
|
var _this2 = this;
|
12201
12119
|
var subtle = this.subtle;
|
12202
12120
|
if (this.key !== key || !this.fastAesKey) {
|
12203
12121
|
this.key = key;
|
12204
|
-
this.fastAesKey = new FastAESKey(subtle, key
|
12122
|
+
this.fastAesKey = new FastAESKey(subtle, key);
|
12205
12123
|
}
|
12206
12124
|
return this.fastAesKey.expandKey().then(function (aesKey) {
|
12207
12125
|
// decrypt using web crypto
|
@@ -12209,25 +12127,22 @@
|
|
12209
12127
|
return Promise.reject(new Error('web crypto not initialized'));
|
12210
12128
|
}
|
12211
12129
|
_this2.logOnce('WebCrypto AES decrypt');
|
12212
|
-
var crypto = new AESCrypto(subtle, new Uint8Array(iv)
|
12130
|
+
var crypto = new AESCrypto(subtle, new Uint8Array(iv));
|
12213
12131
|
return crypto.decrypt(data.buffer, aesKey);
|
12214
12132
|
}).catch(function (err) {
|
12215
12133
|
logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
|
12216
|
-
return _this2.onWebCryptoError(data, key, iv
|
12134
|
+
return _this2.onWebCryptoError(data, key, iv);
|
12217
12135
|
});
|
12218
12136
|
};
|
12219
|
-
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv
|
12220
|
-
|
12221
|
-
|
12222
|
-
|
12223
|
-
|
12224
|
-
|
12225
|
-
|
12226
|
-
if (decryptResult) {
|
12227
|
-
return decryptResult.buffer;
|
12228
|
-
}
|
12137
|
+
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
|
12138
|
+
this.useSoftware = true;
|
12139
|
+
this.logEnabled = true;
|
12140
|
+
this.softwareDecrypt(data, key, iv);
|
12141
|
+
var decryptResult = this.flush();
|
12142
|
+
if (decryptResult) {
|
12143
|
+
return decryptResult.buffer;
|
12229
12144
|
}
|
12230
|
-
throw new Error('WebCrypto
|
12145
|
+
throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
|
12231
12146
|
};
|
12232
12147
|
_proto.getValidChunk = function getValidChunk(data) {
|
12233
12148
|
var currentChunk = data;
|
@@ -12281,7 +12196,7 @@
|
|
12281
12196
|
_inheritsLoose(BaseStreamController, _TaskLoop);
|
12282
12197
|
function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
|
12283
12198
|
var _this;
|
12284
|
-
_this = _TaskLoop.call(this
|
12199
|
+
_this = _TaskLoop.call(this) || this;
|
12285
12200
|
_this.hls = void 0;
|
12286
12201
|
_this.fragPrevious = null;
|
12287
12202
|
_this.fragCurrent = null;
|
@@ -12306,96 +12221,25 @@
|
|
12306
12221
|
_this.startFragRequested = false;
|
12307
12222
|
_this.decrypter = void 0;
|
12308
12223
|
_this.initPTS = [];
|
12309
|
-
_this.
|
12310
|
-
_this.
|
12311
|
-
_this.
|
12312
|
-
|
12313
|
-
|
12314
|
-
fragCurrent = _assertThisInitialize.fragCurrent,
|
12315
|
-
media = _assertThisInitialize.media,
|
12316
|
-
mediaBuffer = _assertThisInitialize.mediaBuffer,
|
12317
|
-
state = _assertThisInitialize.state;
|
12318
|
-
var currentTime = media ? media.currentTime : 0;
|
12319
|
-
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12320
|
-
_this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12321
|
-
if (_this.state === State.ENDED) {
|
12322
|
-
_this.resetLoadingState();
|
12323
|
-
} else if (fragCurrent) {
|
12324
|
-
// Seeking while frag load is in progress
|
12325
|
-
var tolerance = config.maxFragLookUpTolerance;
|
12326
|
-
var fragStartOffset = fragCurrent.start - tolerance;
|
12327
|
-
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12328
|
-
// if seeking out of buffered range or into new one
|
12329
|
-
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12330
|
-
var pastFragment = currentTime > fragEndOffset;
|
12331
|
-
// if the seek position is outside the current fragment range
|
12332
|
-
if (currentTime < fragStartOffset || pastFragment) {
|
12333
|
-
if (pastFragment && fragCurrent.loader) {
|
12334
|
-
_this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12335
|
-
fragCurrent.abortRequests();
|
12336
|
-
_this.resetLoadingState();
|
12337
|
-
}
|
12338
|
-
_this.fragPrevious = null;
|
12339
|
-
}
|
12340
|
-
}
|
12341
|
-
}
|
12342
|
-
if (media) {
|
12343
|
-
// Remove gap fragments
|
12344
|
-
_this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
|
12345
|
-
_this.lastCurrentTime = currentTime;
|
12346
|
-
if (!_this.loadingParts) {
|
12347
|
-
var bufferEnd = Math.max(bufferInfo.end, currentTime);
|
12348
|
-
var shouldLoadParts = _this.shouldLoadParts(_this.getLevelDetails(), bufferEnd);
|
12349
|
-
if (shouldLoadParts) {
|
12350
|
-
_this.log("LL-Part loading ON after seeking to " + currentTime.toFixed(2) + " with buffer @" + bufferEnd.toFixed(2));
|
12351
|
-
_this.loadingParts = shouldLoadParts;
|
12352
|
-
}
|
12353
|
-
}
|
12354
|
-
}
|
12355
|
-
|
12356
|
-
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12357
|
-
if (!_this.loadedmetadata && !bufferInfo.len) {
|
12358
|
-
_this.nextLoadPosition = _this.startPosition = currentTime;
|
12359
|
-
}
|
12360
|
-
|
12361
|
-
// Async tick to speed up processing
|
12362
|
-
_this.tickImmediate();
|
12363
|
-
};
|
12364
|
-
_this.onMediaEnded = function () {
|
12365
|
-
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12366
|
-
_this.startPosition = _this.lastCurrentTime = 0;
|
12367
|
-
if (_this.playlistType === PlaylistLevelType.MAIN) {
|
12368
|
-
_this.hls.trigger(Events.MEDIA_ENDED, {
|
12369
|
-
stalled: false
|
12370
|
-
});
|
12371
|
-
}
|
12372
|
-
};
|
12224
|
+
_this.onvseeking = null;
|
12225
|
+
_this.onvended = null;
|
12226
|
+
_this.logPrefix = '';
|
12227
|
+
_this.log = void 0;
|
12228
|
+
_this.warn = void 0;
|
12373
12229
|
_this.playlistType = playlistType;
|
12230
|
+
_this.logPrefix = logPrefix;
|
12231
|
+
_this.log = logger.log.bind(logger, logPrefix + ":");
|
12232
|
+
_this.warn = logger.warn.bind(logger, logPrefix + ":");
|
12374
12233
|
_this.hls = hls;
|
12375
12234
|
_this.fragmentLoader = new FragmentLoader(hls.config);
|
12376
12235
|
_this.keyLoader = keyLoader;
|
12377
12236
|
_this.fragmentTracker = fragmentTracker;
|
12378
12237
|
_this.config = hls.config;
|
12379
12238
|
_this.decrypter = new Decrypter(hls.config);
|
12239
|
+
hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
|
12380
12240
|
return _this;
|
12381
12241
|
}
|
12382
12242
|
var _proto = BaseStreamController.prototype;
|
12383
|
-
_proto.registerListeners = function registerListeners() {
|
12384
|
-
var hls = this.hls;
|
12385
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12386
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12387
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12388
|
-
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12389
|
-
hls.on(Events.ERROR, this.onError, this);
|
12390
|
-
};
|
12391
|
-
_proto.unregisterListeners = function unregisterListeners() {
|
12392
|
-
var hls = this.hls;
|
12393
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12394
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12395
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12396
|
-
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12397
|
-
hls.off(Events.ERROR, this.onError, this);
|
12398
|
-
};
|
12399
12243
|
_proto.doTick = function doTick() {
|
12400
12244
|
this.onTickEnd();
|
12401
12245
|
};
|
@@ -12419,12 +12263,6 @@
|
|
12419
12263
|
this.clearNextTick();
|
12420
12264
|
this.state = State.STOPPED;
|
12421
12265
|
};
|
12422
|
-
_proto.pauseBuffering = function pauseBuffering() {
|
12423
|
-
this.buffering = false;
|
12424
|
-
};
|
12425
|
-
_proto.resumeBuffering = function resumeBuffering() {
|
12426
|
-
this.buffering = true;
|
12427
|
-
};
|
12428
12266
|
_proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
|
12429
12267
|
// If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
|
12430
12268
|
// of nothing loading/loaded return false
|
@@ -12455,8 +12293,10 @@
|
|
12455
12293
|
};
|
12456
12294
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
12457
12295
|
var media = this.media = this.mediaBuffer = data.media;
|
12458
|
-
|
12459
|
-
|
12296
|
+
this.onvseeking = this.onMediaSeeking.bind(this);
|
12297
|
+
this.onvended = this.onMediaEnded.bind(this);
|
12298
|
+
media.addEventListener('seeking', this.onvseeking);
|
12299
|
+
media.addEventListener('ended', this.onvended);
|
12460
12300
|
var config = this.config;
|
12461
12301
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
12462
12302
|
this.startLoad(config.startPosition);
|
@@ -12470,9 +12310,10 @@
|
|
12470
12310
|
}
|
12471
12311
|
|
12472
12312
|
// remove video listeners
|
12473
|
-
if (media) {
|
12474
|
-
media.removeEventListener('seeking', this.
|
12475
|
-
media.removeEventListener('ended', this.
|
12313
|
+
if (media && this.onvseeking && this.onvended) {
|
12314
|
+
media.removeEventListener('seeking', this.onvseeking);
|
12315
|
+
media.removeEventListener('ended', this.onvended);
|
12316
|
+
this.onvseeking = this.onvended = null;
|
12476
12317
|
}
|
12477
12318
|
if (this.keyLoader) {
|
12478
12319
|
this.keyLoader.detach();
|
@@ -12482,8 +12323,54 @@
|
|
12482
12323
|
this.fragmentTracker.removeAllFragments();
|
12483
12324
|
this.stopLoad();
|
12484
12325
|
};
|
12485
|
-
_proto.
|
12486
|
-
|
12326
|
+
_proto.onMediaSeeking = function onMediaSeeking() {
|
12327
|
+
var config = this.config,
|
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
|
+
};
|
12487
12374
|
_proto.onManifestLoaded = function onManifestLoaded(event, data) {
|
12488
12375
|
this.startTimeOffset = data.startTimeOffset;
|
12489
12376
|
this.initPTS = [];
|
@@ -12493,7 +12380,7 @@
|
|
12493
12380
|
this.stopLoad();
|
12494
12381
|
_TaskLoop.prototype.onHandlerDestroying.call(this);
|
12495
12382
|
// @ts-ignore
|
12496
|
-
this.hls =
|
12383
|
+
this.hls = null;
|
12497
12384
|
};
|
12498
12385
|
_proto.onHandlerDestroyed = function onHandlerDestroyed() {
|
12499
12386
|
this.state = State.STOPPED;
|
@@ -12623,10 +12510,10 @@
|
|
12623
12510
|
var decryptData = frag.decryptdata;
|
12624
12511
|
|
12625
12512
|
// check to see if the payload needs to be decrypted
|
12626
|
-
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv &&
|
12513
|
+
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method === 'AES-128') {
|
12627
12514
|
var startTime = self.performance.now();
|
12628
12515
|
// decrypt init segment data
|
12629
|
-
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer
|
12516
|
+
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
|
12630
12517
|
hls.trigger(Events.ERROR, {
|
12631
12518
|
type: ErrorTypes.MEDIA_ERROR,
|
12632
12519
|
details: ErrorDetails.FRAG_DECRYPT_ERROR,
|
@@ -12739,7 +12626,7 @@
|
|
12739
12626
|
}
|
12740
12627
|
var keyLoadingPromise = null;
|
12741
12628
|
if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
|
12742
|
-
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.
|
12629
|
+
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + " " + frag.level);
|
12743
12630
|
this.state = State.KEY_LOADING;
|
12744
12631
|
this.fragCurrent = frag;
|
12745
12632
|
keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
|
@@ -12760,16 +12647,8 @@
|
|
12760
12647
|
} else if (!frag.encrypted && details.encryptedFragments.length) {
|
12761
12648
|
this.keyLoader.loadClear(frag, details.encryptedFragments);
|
12762
12649
|
}
|
12763
|
-
var fragPrevious = this.fragPrevious;
|
12764
|
-
if (frag.sn !== 'initSegment' && (!fragPrevious || frag.sn !== fragPrevious.sn)) {
|
12765
|
-
var shouldLoadParts = this.shouldLoadParts(level.details, frag.end);
|
12766
|
-
if (shouldLoadParts !== this.loadingParts) {
|
12767
|
-
this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " loading sn " + (fragPrevious == null ? void 0 : fragPrevious.sn) + "->" + frag.sn);
|
12768
|
-
this.loadingParts = shouldLoadParts;
|
12769
|
-
}
|
12770
|
-
}
|
12771
12650
|
targetBufferTime = Math.max(frag.start, targetBufferTime || 0);
|
12772
|
-
if (this.
|
12651
|
+
if (this.config.lowLatencyMode && frag.sn !== 'initSegment') {
|
12773
12652
|
var partList = details.partList;
|
12774
12653
|
if (partList && progressCallback) {
|
12775
12654
|
if (targetBufferTime > frag.end && details.fragmentHint) {
|
@@ -12778,7 +12657,7 @@
|
|
12778
12657
|
var partIndex = this.getNextPart(partList, frag, targetBufferTime);
|
12779
12658
|
if (partIndex > -1) {
|
12780
12659
|
var part = partList[partIndex];
|
12781
|
-
this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.
|
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.logPrefix === '[stream-controller]' ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12782
12661
|
this.nextLoadPosition = part.start + part.duration;
|
12783
12662
|
this.state = State.FRAG_LOADING;
|
12784
12663
|
var _result;
|
@@ -12811,14 +12690,7 @@
|
|
12811
12690
|
}
|
12812
12691
|
}
|
12813
12692
|
}
|
12814
|
-
|
12815
|
-
this.log("LL-Part loading OFF after next part miss @" + targetBufferTime.toFixed(2));
|
12816
|
-
this.loadingParts = false;
|
12817
|
-
} else if (!frag.url) {
|
12818
|
-
// Selected fragment hint for part but not loading parts
|
12819
|
-
return Promise.resolve(null);
|
12820
|
-
}
|
12821
|
-
this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12693
|
+
this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.logPrefix === '[stream-controller]' ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12822
12694
|
// Don't update nextLoadPosition for fragments which are not buffered
|
12823
12695
|
if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
|
12824
12696
|
this.nextLoadPosition = frag.start + frag.duration;
|
@@ -12920,36 +12792,8 @@
|
|
12920
12792
|
if (part) {
|
12921
12793
|
part.stats.parsing.end = now;
|
12922
12794
|
}
|
12923
|
-
// See if part loading should be disabled/enabled based on buffer and playback position.
|
12924
|
-
if (frag.sn !== 'initSegment') {
|
12925
|
-
var levelDetails = this.getLevelDetails();
|
12926
|
-
var loadingPartsAtEdge = levelDetails && frag.sn > levelDetails.endSN;
|
12927
|
-
var shouldLoadParts = loadingPartsAtEdge || this.shouldLoadParts(levelDetails, frag.end);
|
12928
|
-
if (shouldLoadParts !== this.loadingParts) {
|
12929
|
-
this.log("LL-Part loading " + (shouldLoadParts ? 'ON' : 'OFF') + " after parsing segment ending @" + frag.end.toFixed(2));
|
12930
|
-
this.loadingParts = shouldLoadParts;
|
12931
|
-
}
|
12932
|
-
}
|
12933
12795
|
this.updateLevelTiming(frag, part, level, chunkMeta.partial);
|
12934
12796
|
};
|
12935
|
-
_proto.shouldLoadParts = function shouldLoadParts(details, bufferEnd) {
|
12936
|
-
if (this.config.lowLatencyMode) {
|
12937
|
-
if (!details) {
|
12938
|
-
return this.loadingParts;
|
12939
|
-
}
|
12940
|
-
if (details != null && details.partList) {
|
12941
|
-
var _details$fragmentHint;
|
12942
|
-
// Buffer must be ahead of first part + duration of parts after last segment
|
12943
|
-
// and playback must be at or past segment adjacent to part list
|
12944
|
-
var firstPart = details.partList[0];
|
12945
|
-
var safePartStart = firstPart.end + (((_details$fragmentHint = details.fragmentHint) == null ? void 0 : _details$fragmentHint.duration) || 0);
|
12946
|
-
if (bufferEnd >= safePartStart && this.lastCurrentTime > firstPart.start - firstPart.fragment.duration) {
|
12947
|
-
return true;
|
12948
|
-
}
|
12949
|
-
}
|
12950
|
-
}
|
12951
|
-
return false;
|
12952
|
-
};
|
12953
12797
|
_proto.getCurrentContext = function getCurrentContext(chunkMeta) {
|
12954
12798
|
var levels = this.levels,
|
12955
12799
|
fragCurrent = this.fragCurrent;
|
@@ -13084,8 +12928,7 @@
|
|
13084
12928
|
// find fragment index, contiguous with end of buffer position
|
13085
12929
|
var config = this.config;
|
13086
12930
|
var start = fragments[0].start;
|
13087
|
-
var
|
13088
|
-
var frag = null;
|
12931
|
+
var frag;
|
13089
12932
|
if (levelDetails.live) {
|
13090
12933
|
var initialLiveManifestSize = config.initialLiveManifestSize;
|
13091
12934
|
if (fragLen < initialLiveManifestSize) {
|
@@ -13097,10 +12940,6 @@
|
|
13097
12940
|
// Do not load using live logic if the starting frag is requested - we want to use getFragmentAtPosition() so that
|
13098
12941
|
// we get the fragment matching that start time
|
13099
12942
|
if (!levelDetails.PTSKnown && !this.startFragRequested && this.startPosition === -1 || pos < start) {
|
13100
|
-
if (canLoadParts && !this.loadingParts) {
|
13101
|
-
this.log("LL-Part loading ON for initial live fragment");
|
13102
|
-
this.loadingParts = true;
|
13103
|
-
}
|
13104
12943
|
frag = this.getInitialLiveFragment(levelDetails, fragments);
|
13105
12944
|
this.startPosition = this.nextLoadPosition = frag ? this.hls.liveSyncPosition || frag.start : pos;
|
13106
12945
|
}
|
@@ -13111,7 +12950,7 @@
|
|
13111
12950
|
|
13112
12951
|
// If we haven't run into any special cases already, just load the fragment most closely matching the requested position
|
13113
12952
|
if (!frag) {
|
13114
|
-
var end =
|
12953
|
+
var end = config.lowLatencyMode ? levelDetails.partEnd : levelDetails.fragmentEnd;
|
13115
12954
|
frag = this.getFragmentAtPosition(pos, end, levelDetails);
|
13116
12955
|
}
|
13117
12956
|
return this.mapToInitFragWhenRequired(frag);
|
@@ -13225,7 +13064,7 @@
|
|
13225
13064
|
var fragmentHint = levelDetails.fragmentHint;
|
13226
13065
|
var tolerance = config.maxFragLookUpTolerance;
|
13227
13066
|
var partList = levelDetails.partList;
|
13228
|
-
var loadingParts = !!(
|
13067
|
+
var loadingParts = !!(config.lowLatencyMode && partList != null && partList.length && fragmentHint);
|
13229
13068
|
if (loadingParts && fragmentHint && !this.bitrateTest) {
|
13230
13069
|
// Include incomplete fragment with parts at end
|
13231
13070
|
fragments = fragments.concat(fragmentHint);
|
@@ -13412,7 +13251,7 @@
|
|
13412
13251
|
errorAction.resolved = true;
|
13413
13252
|
}
|
13414
13253
|
} else {
|
13415
|
-
|
13254
|
+
logger.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
|
13416
13255
|
return;
|
13417
13256
|
}
|
13418
13257
|
} else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
@@ -13802,7 +13641,6 @@
|
|
13802
13641
|
*/
|
13803
13642
|
function getAudioConfig(observer, data, offset, audioCodec) {
|
13804
13643
|
var adtsObjectType;
|
13805
|
-
var originalAdtsObjectType;
|
13806
13644
|
var adtsExtensionSamplingIndex;
|
13807
13645
|
var adtsChannelConfig;
|
13808
13646
|
var config;
|
@@ -13810,7 +13648,7 @@
|
|
13810
13648
|
var manifestCodec = audioCodec;
|
13811
13649
|
var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
13812
13650
|
// byte 2
|
13813
|
-
adtsObjectType =
|
13651
|
+
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13814
13652
|
var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
13815
13653
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
13816
13654
|
var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
|
@@ -13827,8 +13665,8 @@
|
|
13827
13665
|
// byte 3
|
13828
13666
|
adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
|
13829
13667
|
logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
|
13830
|
-
//
|
13831
|
-
if (/firefox
|
13668
|
+
// firefox: freq less than 24kHz = AAC SBR (HE-AAC)
|
13669
|
+
if (/firefox/i.test(userAgent)) {
|
13832
13670
|
if (adtsSamplingIndex >= 6) {
|
13833
13671
|
adtsObjectType = 5;
|
13834
13672
|
config = new Array(4);
|
@@ -13922,7 +13760,6 @@
|
|
13922
13760
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
13923
13761
|
channelCount: adtsChannelConfig,
|
13924
13762
|
codec: 'mp4a.40.' + adtsObjectType,
|
13925
|
-
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
13926
13763
|
manifestCodec: manifestCodec
|
13927
13764
|
};
|
13928
13765
|
}
|
@@ -13977,8 +13814,7 @@
|
|
13977
13814
|
track.channelCount = config.channelCount;
|
13978
13815
|
track.codec = config.codec;
|
13979
13816
|
track.manifestCodec = config.manifestCodec;
|
13980
|
-
track.
|
13981
|
-
logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
|
13817
|
+
logger.log("parsed codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
|
13982
13818
|
}
|
13983
13819
|
}
|
13984
13820
|
function getFrameDuration(samplerate) {
|
@@ -14458,110 +14294,6 @@
|
|
14458
14294
|
logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
|
14459
14295
|
}
|
14460
14296
|
};
|
14461
|
-
_proto.parseNALu = function parseNALu(track, array) {
|
14462
|
-
var len = array.byteLength;
|
14463
|
-
var state = track.naluState || 0;
|
14464
|
-
var lastState = state;
|
14465
|
-
var units = [];
|
14466
|
-
var i = 0;
|
14467
|
-
var value;
|
14468
|
-
var overflow;
|
14469
|
-
var unitType;
|
14470
|
-
var lastUnitStart = -1;
|
14471
|
-
var lastUnitType = 0;
|
14472
|
-
// logger.log('PES:' + Hex.hexDump(array));
|
14473
|
-
|
14474
|
-
if (state === -1) {
|
14475
|
-
// special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
|
14476
|
-
lastUnitStart = 0;
|
14477
|
-
// NALu type is value read from offset 0
|
14478
|
-
lastUnitType = this.getNALuType(array, 0);
|
14479
|
-
state = 0;
|
14480
|
-
i = 1;
|
14481
|
-
}
|
14482
|
-
while (i < len) {
|
14483
|
-
value = array[i++];
|
14484
|
-
// optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
|
14485
|
-
if (!state) {
|
14486
|
-
state = value ? 0 : 1;
|
14487
|
-
continue;
|
14488
|
-
}
|
14489
|
-
if (state === 1) {
|
14490
|
-
state = value ? 0 : 2;
|
14491
|
-
continue;
|
14492
|
-
}
|
14493
|
-
// here we have state either equal to 2 or 3
|
14494
|
-
if (!value) {
|
14495
|
-
state = 3;
|
14496
|
-
} else if (value === 1) {
|
14497
|
-
overflow = i - state - 1;
|
14498
|
-
if (lastUnitStart >= 0) {
|
14499
|
-
var unit = {
|
14500
|
-
data: array.subarray(lastUnitStart, overflow),
|
14501
|
-
type: lastUnitType
|
14502
|
-
};
|
14503
|
-
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14504
|
-
units.push(unit);
|
14505
|
-
} else {
|
14506
|
-
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14507
|
-
// first check if start code delimiter is overlapping between 2 PES packets,
|
14508
|
-
// ie it started in last packet (lastState not zero)
|
14509
|
-
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14510
|
-
var lastUnit = this.getLastNalUnit(track.samples);
|
14511
|
-
if (lastUnit) {
|
14512
|
-
if (lastState && i <= 4 - lastState) {
|
14513
|
-
// start delimiter overlapping between PES packets
|
14514
|
-
// strip start delimiter bytes from the end of last NAL unit
|
14515
|
-
// check if lastUnit had a state different from zero
|
14516
|
-
if (lastUnit.state) {
|
14517
|
-
// strip last bytes
|
14518
|
-
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14519
|
-
}
|
14520
|
-
}
|
14521
|
-
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14522
|
-
|
14523
|
-
if (overflow > 0) {
|
14524
|
-
// logger.log('first NALU found with overflow:' + overflow);
|
14525
|
-
lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
|
14526
|
-
lastUnit.state = 0;
|
14527
|
-
}
|
14528
|
-
}
|
14529
|
-
}
|
14530
|
-
// check if we can read unit type
|
14531
|
-
if (i < len) {
|
14532
|
-
unitType = this.getNALuType(array, i);
|
14533
|
-
// logger.log('find NALU @ offset:' + i + ',type:' + unitType);
|
14534
|
-
lastUnitStart = i;
|
14535
|
-
lastUnitType = unitType;
|
14536
|
-
state = 0;
|
14537
|
-
} else {
|
14538
|
-
// not enough byte to read unit type. let's read it on next PES parsing
|
14539
|
-
state = -1;
|
14540
|
-
}
|
14541
|
-
} else {
|
14542
|
-
state = 0;
|
14543
|
-
}
|
14544
|
-
}
|
14545
|
-
if (lastUnitStart >= 0 && state >= 0) {
|
14546
|
-
var _unit = {
|
14547
|
-
data: array.subarray(lastUnitStart, len),
|
14548
|
-
type: lastUnitType,
|
14549
|
-
state: state
|
14550
|
-
};
|
14551
|
-
units.push(_unit);
|
14552
|
-
// logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
|
14553
|
-
}
|
14554
|
-
// no NALu found
|
14555
|
-
if (units.length === 0) {
|
14556
|
-
// append pes.data to previous NAL unit
|
14557
|
-
var _lastUnit = this.getLastNalUnit(track.samples);
|
14558
|
-
if (_lastUnit) {
|
14559
|
-
_lastUnit.data = appendUint8Array(_lastUnit.data, array);
|
14560
|
-
}
|
14561
|
-
}
|
14562
|
-
track.naluState = state;
|
14563
|
-
return units;
|
14564
|
-
};
|
14565
14297
|
return BaseVideoParser;
|
14566
14298
|
}();
|
14567
14299
|
|
@@ -14716,6 +14448,189 @@
|
|
14716
14448
|
;
|
14717
14449
|
_proto.readUInt = function readUInt() {
|
14718
14450
|
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();
|
14719
14634
|
};
|
14720
14635
|
return ExpGolomb;
|
14721
14636
|
}();
|
@@ -14726,9 +14641,9 @@
|
|
14726
14641
|
return _BaseVideoParser.apply(this, arguments) || this;
|
14727
14642
|
}
|
14728
14643
|
var _proto = AvcVideoParser.prototype;
|
14729
|
-
_proto.
|
14644
|
+
_proto.parseAVCPES = function parseAVCPES(track, textTrack, pes, last, duration) {
|
14730
14645
|
var _this = this;
|
14731
|
-
var units = this.
|
14646
|
+
var units = this.parseAVCNALu(track, pes.data);
|
14732
14647
|
var VideoSample = this.VideoSample;
|
14733
14648
|
var push;
|
14734
14649
|
var spsfound = false;
|
@@ -14753,7 +14668,7 @@
|
|
14753
14668
|
// only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
|
14754
14669
|
if (spsfound && data.length > 4) {
|
14755
14670
|
// retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
|
14756
|
-
var sliceType =
|
14671
|
+
var sliceType = new ExpGolomb(data).readSliceType();
|
14757
14672
|
// 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
|
14758
14673
|
// SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
|
14759
14674
|
// An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
|
@@ -14807,7 +14722,8 @@
|
|
14807
14722
|
push = true;
|
14808
14723
|
spsfound = true;
|
14809
14724
|
var sps = unit.data;
|
14810
|
-
var
|
14725
|
+
var expGolombDecoder = new ExpGolomb(sps);
|
14726
|
+
var config = expGolombDecoder.readSPS();
|
14811
14727
|
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]) {
|
14812
14728
|
track.width = config.width;
|
14813
14729
|
track.height = config.height;
|
@@ -14863,192 +14779,109 @@
|
|
14863
14779
|
this.VideoSample = null;
|
14864
14780
|
}
|
14865
14781
|
};
|
14866
|
-
_proto.
|
14867
|
-
|
14868
|
-
|
14869
|
-
|
14870
|
-
var
|
14871
|
-
|
14872
|
-
|
14873
|
-
|
14874
|
-
|
14875
|
-
|
14876
|
-
|
14877
|
-
|
14782
|
+
_proto.parseAVCNALu = function parseAVCNALu(track, array) {
|
14783
|
+
var len = array.byteLength;
|
14784
|
+
var state = track.naluState || 0;
|
14785
|
+
var lastState = state;
|
14786
|
+
var units = [];
|
14787
|
+
var i = 0;
|
14788
|
+
var value;
|
14789
|
+
var overflow;
|
14790
|
+
var unitType;
|
14791
|
+
var lastUnitStart = -1;
|
14792
|
+
var lastUnitType = 0;
|
14793
|
+
// logger.log('PES:' + Hex.hexDump(array));
|
14878
14794
|
|
14879
|
-
|
14880
|
-
|
14881
|
-
|
14882
|
-
|
14883
|
-
|
14884
|
-
|
14885
|
-
|
14886
|
-
var lastScale = 8;
|
14887
|
-
var nextScale = 8;
|
14888
|
-
var deltaScale;
|
14889
|
-
for (var j = 0; j < count; j++) {
|
14890
|
-
if (nextScale !== 0) {
|
14891
|
-
deltaScale = reader.readEG();
|
14892
|
-
nextScale = (lastScale + deltaScale + 256) % 256;
|
14893
|
-
}
|
14894
|
-
lastScale = nextScale === 0 ? lastScale : nextScale;
|
14795
|
+
if (state === -1) {
|
14796
|
+
// special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
|
14797
|
+
lastUnitStart = 0;
|
14798
|
+
// NALu type is value read from offset 0
|
14799
|
+
lastUnitType = array[0] & 0x1f;
|
14800
|
+
state = 0;
|
14801
|
+
i = 1;
|
14895
14802
|
}
|
14896
|
-
|
14897
|
-
|
14898
|
-
|
14899
|
-
|
14900
|
-
|
14901
|
-
|
14902
|
-
|
14903
|
-
|
14904
|
-
|
14905
|
-
|
14906
|
-
|
14907
|
-
|
14908
|
-
|
14909
|
-
|
14910
|
-
|
14911
|
-
|
14912
|
-
|
14913
|
-
|
14914
|
-
|
14915
|
-
|
14916
|
-
|
14917
|
-
|
14918
|
-
|
14919
|
-
|
14920
|
-
|
14921
|
-
|
14922
|
-
|
14923
|
-
|
14924
|
-
|
14925
|
-
|
14926
|
-
|
14927
|
-
|
14928
|
-
|
14929
|
-
|
14930
|
-
|
14931
|
-
|
14932
|
-
|
14933
|
-
|
14934
|
-
|
14803
|
+
while (i < len) {
|
14804
|
+
value = array[i++];
|
14805
|
+
// optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
|
14806
|
+
if (!state) {
|
14807
|
+
state = value ? 0 : 1;
|
14808
|
+
continue;
|
14809
|
+
}
|
14810
|
+
if (state === 1) {
|
14811
|
+
state = value ? 0 : 2;
|
14812
|
+
continue;
|
14813
|
+
}
|
14814
|
+
// here we have state either equal to 2 or 3
|
14815
|
+
if (!value) {
|
14816
|
+
state = 3;
|
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.
|
14935
14843
|
|
14936
|
-
|
14937
|
-
|
14938
|
-
|
14939
|
-
|
14940
|
-
// seq_scaling_matrix_present_flag
|
14941
|
-
scalingListCount = chromaFormatIdc !== 3 ? 8 : 12;
|
14942
|
-
for (i = 0; i < scalingListCount; i++) {
|
14943
|
-
if (readBoolean()) {
|
14944
|
-
// seq_scaling_list_present_flag[ i ]
|
14945
|
-
if (i < 6) {
|
14946
|
-
skipScalingList(16, eg);
|
14947
|
-
} else {
|
14948
|
-
skipScalingList(64, eg);
|
14844
|
+
if (overflow > 0) {
|
14845
|
+
// logger.log('first NALU found with overflow:' + overflow);
|
14846
|
+
lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
|
14847
|
+
lastUnit.state = 0;
|
14949
14848
|
}
|
14950
14849
|
}
|
14951
14850
|
}
|
14851
|
+
// check if we can read unit type
|
14852
|
+
if (i < len) {
|
14853
|
+
unitType = array[i] & 0x1f;
|
14854
|
+
// logger.log('find NALU @ offset:' + i + ',type:' + unitType);
|
14855
|
+
lastUnitStart = i;
|
14856
|
+
lastUnitType = unitType;
|
14857
|
+
state = 0;
|
14858
|
+
} else {
|
14859
|
+
// not enough byte to read unit type. let's read it on next PES parsing
|
14860
|
+
state = -1;
|
14861
|
+
}
|
14862
|
+
} else {
|
14863
|
+
state = 0;
|
14952
14864
|
}
|
14953
14865
|
}
|
14954
|
-
|
14955
|
-
|
14956
|
-
|
14957
|
-
|
14958
|
-
|
14959
|
-
|
14960
|
-
|
14961
|
-
|
14962
|
-
numRefFramesInPicOrderCntCycle = readUEG();
|
14963
|
-
for (i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
14964
|
-
skipEG();
|
14965
|
-
} // offset_for_ref_frame[ i ]
|
14966
|
-
}
|
14967
|
-
skipUEG(); // max_num_ref_frames
|
14968
|
-
skipBits(1); // gaps_in_frame_num_value_allowed_flag
|
14969
|
-
var picWidthInMbsMinus1 = readUEG();
|
14970
|
-
var picHeightInMapUnitsMinus1 = readUEG();
|
14971
|
-
var frameMbsOnlyFlag = readBits(1);
|
14972
|
-
if (frameMbsOnlyFlag === 0) {
|
14973
|
-
skipBits(1);
|
14974
|
-
} // mb_adaptive_frame_field_flag
|
14975
|
-
|
14976
|
-
skipBits(1); // direct_8x8_inference_flag
|
14977
|
-
if (readBoolean()) {
|
14978
|
-
// frame_cropping_flag
|
14979
|
-
frameCropLeftOffset = readUEG();
|
14980
|
-
frameCropRightOffset = readUEG();
|
14981
|
-
frameCropTopOffset = readUEG();
|
14982
|
-
frameCropBottomOffset = readUEG();
|
14866
|
+
if (lastUnitStart >= 0 && state >= 0) {
|
14867
|
+
var _unit = {
|
14868
|
+
data: array.subarray(lastUnitStart, len),
|
14869
|
+
type: lastUnitType,
|
14870
|
+
state: state
|
14871
|
+
};
|
14872
|
+
units.push(_unit);
|
14873
|
+
// logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
|
14983
14874
|
}
|
14984
|
-
|
14985
|
-
if (
|
14986
|
-
//
|
14987
|
-
|
14988
|
-
|
14989
|
-
|
14990
|
-
switch (aspectRatioIdc) {
|
14991
|
-
case 1:
|
14992
|
-
pixelRatio = [1, 1];
|
14993
|
-
break;
|
14994
|
-
case 2:
|
14995
|
-
pixelRatio = [12, 11];
|
14996
|
-
break;
|
14997
|
-
case 3:
|
14998
|
-
pixelRatio = [10, 11];
|
14999
|
-
break;
|
15000
|
-
case 4:
|
15001
|
-
pixelRatio = [16, 11];
|
15002
|
-
break;
|
15003
|
-
case 5:
|
15004
|
-
pixelRatio = [40, 33];
|
15005
|
-
break;
|
15006
|
-
case 6:
|
15007
|
-
pixelRatio = [24, 11];
|
15008
|
-
break;
|
15009
|
-
case 7:
|
15010
|
-
pixelRatio = [20, 11];
|
15011
|
-
break;
|
15012
|
-
case 8:
|
15013
|
-
pixelRatio = [32, 11];
|
15014
|
-
break;
|
15015
|
-
case 9:
|
15016
|
-
pixelRatio = [80, 33];
|
15017
|
-
break;
|
15018
|
-
case 10:
|
15019
|
-
pixelRatio = [18, 11];
|
15020
|
-
break;
|
15021
|
-
case 11:
|
15022
|
-
pixelRatio = [15, 11];
|
15023
|
-
break;
|
15024
|
-
case 12:
|
15025
|
-
pixelRatio = [64, 33];
|
15026
|
-
break;
|
15027
|
-
case 13:
|
15028
|
-
pixelRatio = [160, 99];
|
15029
|
-
break;
|
15030
|
-
case 14:
|
15031
|
-
pixelRatio = [4, 3];
|
15032
|
-
break;
|
15033
|
-
case 15:
|
15034
|
-
pixelRatio = [3, 2];
|
15035
|
-
break;
|
15036
|
-
case 16:
|
15037
|
-
pixelRatio = [2, 1];
|
15038
|
-
break;
|
15039
|
-
case 255:
|
15040
|
-
{
|
15041
|
-
pixelRatio = [readUByte() << 8 | readUByte(), readUByte() << 8 | readUByte()];
|
15042
|
-
break;
|
15043
|
-
}
|
15044
|
-
}
|
14875
|
+
// no NALu found
|
14876
|
+
if (units.length === 0) {
|
14877
|
+
// append pes.data to previous NAL unit
|
14878
|
+
var _lastUnit = this.getLastNalUnit(track.samples);
|
14879
|
+
if (_lastUnit) {
|
14880
|
+
_lastUnit.data = appendUint8Array(_lastUnit.data, array);
|
15045
14881
|
}
|
15046
14882
|
}
|
15047
|
-
|
15048
|
-
|
15049
|
-
height: (2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16 - (frameMbsOnlyFlag ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset),
|
15050
|
-
pixelRatio: pixelRatio
|
15051
|
-
};
|
14883
|
+
track.naluState = state;
|
14884
|
+
return units;
|
15052
14885
|
};
|
15053
14886
|
return AvcVideoParser;
|
15054
14887
|
}(BaseVideoParser);
|
@@ -15068,7 +14901,7 @@
|
|
15068
14901
|
}
|
15069
14902
|
var _proto = SampleAesDecrypter.prototype;
|
15070
14903
|
_proto.decryptBuffer = function decryptBuffer(encryptedData) {
|
15071
|
-
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer
|
14904
|
+
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
|
15072
14905
|
}
|
15073
14906
|
|
15074
14907
|
// AAC - encrypt all full 16 bytes blocks starting from offset 16
|
@@ -15187,7 +15020,7 @@
|
|
15187
15020
|
this.observer = observer;
|
15188
15021
|
this.config = config;
|
15189
15022
|
this.typeSupported = typeSupported;
|
15190
|
-
this.videoParser =
|
15023
|
+
this.videoParser = new AvcVideoParser();
|
15191
15024
|
}
|
15192
15025
|
TSDemuxer.probe = function probe(data) {
|
15193
15026
|
var syncOffset = TSDemuxer.syncOffset(data);
|
@@ -15357,16 +15190,7 @@
|
|
15357
15190
|
case videoPid:
|
15358
15191
|
if (stt) {
|
15359
15192
|
if (videoData && (pes = parsePES(videoData))) {
|
15360
|
-
|
15361
|
-
switch (videoTrack.segmentCodec) {
|
15362
|
-
case 'avc':
|
15363
|
-
this.videoParser = new AvcVideoParser();
|
15364
|
-
break;
|
15365
|
-
}
|
15366
|
-
}
|
15367
|
-
if (this.videoParser !== null) {
|
15368
|
-
this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
|
15369
|
-
}
|
15193
|
+
this.videoParser.parseAVCPES(videoTrack, textTrack, pes, false, this._duration);
|
15370
15194
|
}
|
15371
15195
|
videoData = {
|
15372
15196
|
data: [],
|
@@ -15524,17 +15348,8 @@
|
|
15524
15348
|
// try to parse last PES packets
|
15525
15349
|
var pes;
|
15526
15350
|
if (videoData && (pes = parsePES(videoData))) {
|
15527
|
-
|
15528
|
-
|
15529
|
-
case 'avc':
|
15530
|
-
this.videoParser = new AvcVideoParser();
|
15531
|
-
break;
|
15532
|
-
}
|
15533
|
-
}
|
15534
|
-
if (this.videoParser !== null) {
|
15535
|
-
this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
|
15536
|
-
videoTrack.pesData = null;
|
15537
|
-
}
|
15351
|
+
this.videoParser.parseAVCPES(videoTrack, textTrack, pes, true, this._duration);
|
15352
|
+
videoTrack.pesData = null;
|
15538
15353
|
} else {
|
15539
15354
|
// either avcData null or PES truncated, keep it for next frag parsing
|
15540
15355
|
videoTrack.pesData = videoData;
|
@@ -15836,10 +15651,7 @@
|
|
15836
15651
|
logger.warn('Unsupported EC-3 in M2TS found');
|
15837
15652
|
break;
|
15838
15653
|
case 0x24:
|
15839
|
-
|
15840
|
-
{
|
15841
|
-
logger.warn('Unsupported HEVC in M2TS found');
|
15842
|
-
}
|
15654
|
+
logger.warn('Unsupported HEVC in M2TS found');
|
15843
15655
|
break;
|
15844
15656
|
}
|
15845
15657
|
// move to the next table entry
|
@@ -16067,8 +15879,6 @@
|
|
16067
15879
|
avc1: [],
|
16068
15880
|
// codingname
|
16069
15881
|
avcC: [],
|
16070
|
-
hvc1: [],
|
16071
|
-
hvcC: [],
|
16072
15882
|
btrt: [],
|
16073
15883
|
dinf: [],
|
16074
15884
|
dref: [],
|
@@ -16496,10 +16306,8 @@
|
|
16496
16306
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
|
16497
16307
|
}
|
16498
16308
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
|
16499
|
-
} else if (track.segmentCodec === 'avc') {
|
16500
|
-
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
|
16501
16309
|
} else {
|
16502
|
-
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.
|
16310
|
+
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
|
16503
16311
|
}
|
16504
16312
|
};
|
16505
16313
|
MP4.tkhd = function tkhd(track) {
|
@@ -16637,84 +16445,6 @@
|
|
16637
16445
|
var result = appendUint8Array(MP4.FTYP, movie);
|
16638
16446
|
return result;
|
16639
16447
|
};
|
16640
|
-
MP4.hvc1 = function hvc1(track) {
|
16641
|
-
var ps = track.params;
|
16642
|
-
var units = [track.vps, track.sps, track.pps];
|
16643
|
-
var NALuLengthSize = 4;
|
16644
|
-
var config = new Uint8Array([0x01, ps.general_profile_space << 6 | (ps.general_tier_flag ? 32 : 0) | ps.general_profile_idc, ps.general_profile_compatibility_flags[0], ps.general_profile_compatibility_flags[1], ps.general_profile_compatibility_flags[2], ps.general_profile_compatibility_flags[3], ps.general_constraint_indicator_flags[0], ps.general_constraint_indicator_flags[1], ps.general_constraint_indicator_flags[2], ps.general_constraint_indicator_flags[3], ps.general_constraint_indicator_flags[4], ps.general_constraint_indicator_flags[5], ps.general_level_idc, 240 | ps.min_spatial_segmentation_idc >> 8, 255 & ps.min_spatial_segmentation_idc, 252 | ps.parallelismType, 252 | ps.chroma_format_idc, 248 | ps.bit_depth_luma_minus8, 248 | ps.bit_depth_chroma_minus8, 0x00, parseInt(ps.frame_rate.fps), NALuLengthSize - 1 | ps.temporal_id_nested << 2 | ps.num_temporal_layers << 3 | (ps.frame_rate.fixed ? 64 : 0), units.length]);
|
16645
|
-
|
16646
|
-
// compute hvcC size in bytes
|
16647
|
-
var length = config.length;
|
16648
|
-
for (var i = 0; i < units.length; i += 1) {
|
16649
|
-
length += 3;
|
16650
|
-
for (var j = 0; j < units[i].length; j += 1) {
|
16651
|
-
length += 2 + units[i][j].length;
|
16652
|
-
}
|
16653
|
-
}
|
16654
|
-
var hvcC = new Uint8Array(length);
|
16655
|
-
hvcC.set(config, 0);
|
16656
|
-
length = config.length;
|
16657
|
-
// append parameter set units: one vps, one or more sps and pps
|
16658
|
-
var iMax = units.length - 1;
|
16659
|
-
for (var _i = 0; _i < units.length; _i += 1) {
|
16660
|
-
hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
|
16661
|
-
length += 3;
|
16662
|
-
for (var _j = 0; _j < units[_i].length; _j += 1) {
|
16663
|
-
hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
|
16664
|
-
length += 2;
|
16665
|
-
hvcC.set(units[_i][_j], length);
|
16666
|
-
length += units[_i][_j].length;
|
16667
|
-
}
|
16668
|
-
}
|
16669
|
-
var hvcc = MP4.box(MP4.types.hvcC, hvcC);
|
16670
|
-
var width = track.width;
|
16671
|
-
var height = track.height;
|
16672
|
-
var hSpacing = track.pixelRatio[0];
|
16673
|
-
var vSpacing = track.pixelRatio[1];
|
16674
|
-
return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
|
16675
|
-
// reserved
|
16676
|
-
0x00, 0x00, 0x00,
|
16677
|
-
// reserved
|
16678
|
-
0x00, 0x01,
|
16679
|
-
// data_reference_index
|
16680
|
-
0x00, 0x00,
|
16681
|
-
// pre_defined
|
16682
|
-
0x00, 0x00,
|
16683
|
-
// reserved
|
16684
|
-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
16685
|
-
// pre_defined
|
16686
|
-
width >> 8 & 0xff, width & 0xff,
|
16687
|
-
// width
|
16688
|
-
height >> 8 & 0xff, height & 0xff,
|
16689
|
-
// height
|
16690
|
-
0x00, 0x48, 0x00, 0x00,
|
16691
|
-
// horizresolution
|
16692
|
-
0x00, 0x48, 0x00, 0x00,
|
16693
|
-
// vertresolution
|
16694
|
-
0x00, 0x00, 0x00, 0x00,
|
16695
|
-
// reserved
|
16696
|
-
0x00, 0x01,
|
16697
|
-
// frame_count
|
16698
|
-
0x12, 0x64, 0x61, 0x69, 0x6c,
|
16699
|
-
// dailymotion/hls.js
|
16700
|
-
0x79, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x68, 0x6c, 0x73, 0x2e, 0x6a, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
16701
|
-
// compressorname
|
16702
|
-
0x00, 0x18,
|
16703
|
-
// depth = 24
|
16704
|
-
0x11, 0x11]),
|
16705
|
-
// pre_defined = -1
|
16706
|
-
hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
|
16707
|
-
// bufferSizeDB
|
16708
|
-
0x00, 0x2d, 0xc6, 0xc0,
|
16709
|
-
// maxBitrate
|
16710
|
-
0x00, 0x2d, 0xc6, 0xc0])),
|
16711
|
-
// avgBitrate
|
16712
|
-
MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
|
16713
|
-
// hSpacing
|
16714
|
-
hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
|
16715
|
-
// vSpacing
|
16716
|
-
vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
|
16717
|
-
};
|
16718
16448
|
return MP4;
|
16719
16449
|
}();
|
16720
16450
|
MP4.types = void 0;
|
@@ -17101,9 +16831,9 @@
|
|
17101
16831
|
var foundOverlap = delta < -1;
|
17102
16832
|
if (foundHole || foundOverlap) {
|
17103
16833
|
if (foundHole) {
|
17104
|
-
logger.warn(
|
16834
|
+
logger.warn("AVC: " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
|
17105
16835
|
} else {
|
17106
|
-
logger.warn(
|
16836
|
+
logger.warn("AVC: " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
|
17107
16837
|
}
|
17108
16838
|
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
|
17109
16839
|
firstDTS = nextAvcDts;
|
@@ -17112,24 +16842,12 @@
|
|
17112
16842
|
inputSamples[0].dts = firstDTS;
|
17113
16843
|
inputSamples[0].pts = firstPTS;
|
17114
16844
|
} else {
|
17115
|
-
var isPTSOrderRetained = true;
|
17116
16845
|
for (var _i = 0; _i < inputSamples.length; _i++) {
|
17117
|
-
if (inputSamples[_i].dts > firstPTS
|
16846
|
+
if (inputSamples[_i].dts > firstPTS) {
|
17118
16847
|
break;
|
17119
16848
|
}
|
17120
|
-
var prevPTS = inputSamples[_i].pts;
|
17121
16849
|
inputSamples[_i].dts -= delta;
|
17122
16850
|
inputSamples[_i].pts -= delta;
|
17123
|
-
|
17124
|
-
// check to see if this sample's PTS order has changed
|
17125
|
-
// relative to the next one
|
17126
|
-
if (_i < inputSamples.length - 1) {
|
17127
|
-
var nextSamplePTS = inputSamples[_i + 1].pts;
|
17128
|
-
var currentSamplePTS = inputSamples[_i].pts;
|
17129
|
-
var currentOrder = nextSamplePTS <= currentSamplePTS;
|
17130
|
-
var prevOrder = nextSamplePTS <= prevPTS;
|
17131
|
-
isPTSOrderRetained = currentOrder == prevOrder;
|
17132
|
-
}
|
17133
16851
|
}
|
17134
16852
|
}
|
17135
16853
|
logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
|
@@ -17277,7 +16995,7 @@
|
|
17277
16995
|
}
|
17278
16996
|
}
|
17279
16997
|
}
|
17280
|
-
// next AVC
|
16998
|
+
// next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
17281
16999
|
mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
|
17282
17000
|
this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
|
17283
17001
|
this.videoSampleDuration = mp4SampleDuration;
|
@@ -17412,7 +17130,7 @@
|
|
17412
17130
|
logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
|
17413
17131
|
for (var j = 0; j < missing; j++) {
|
17414
17132
|
var newStamp = Math.max(nextPts, 0);
|
17415
|
-
var fillFrame = AAC.getSilentFrame(track.
|
17133
|
+
var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17416
17134
|
if (!fillFrame) {
|
17417
17135
|
logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
17418
17136
|
fillFrame = sample.unit.subarray();
|
@@ -17540,7 +17258,7 @@
|
|
17540
17258
|
// samples count of this segment's duration
|
17541
17259
|
var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
|
17542
17260
|
// silent frame
|
17543
|
-
var silentFrame = AAC.getSilentFrame(track.
|
17261
|
+
var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17544
17262
|
logger.warn('[mp4-remuxer]: remux empty Audio');
|
17545
17263
|
// Can't remux if we can't generate a silent frame...
|
17546
17264
|
if (!silentFrame) {
|
@@ -17927,15 +17645,13 @@
|
|
17927
17645
|
duration = transmuxConfig.duration,
|
17928
17646
|
initSegmentData = transmuxConfig.initSegmentData;
|
17929
17647
|
var keyData = getEncryptionType(uintData, decryptdata);
|
17930
|
-
if (keyData &&
|
17648
|
+
if (keyData && keyData.method === 'AES-128') {
|
17931
17649
|
var decrypter = this.getDecrypter();
|
17932
|
-
var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
17933
|
-
|
17934
17650
|
// Software decryption is synchronous; webCrypto is not
|
17935
17651
|
if (decrypter.isSync()) {
|
17936
17652
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
17937
17653
|
// data is handled in the flush() call
|
17938
|
-
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer
|
17654
|
+
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
|
17939
17655
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
17940
17656
|
var loadingParts = chunkMeta.part > -1;
|
17941
17657
|
if (loadingParts) {
|
@@ -17947,7 +17663,7 @@
|
|
17947
17663
|
}
|
17948
17664
|
uintData = new Uint8Array(decryptedData);
|
17949
17665
|
} else {
|
17950
|
-
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer
|
17666
|
+
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
|
17951
17667
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
17952
17668
|
// the decrypted data has been transmuxed
|
17953
17669
|
var result = _this.push(decryptedData, null, chunkMeta);
|
@@ -18568,7 +18284,7 @@
|
|
18568
18284
|
observer.on(Events.ERROR, forwardMessage);
|
18569
18285
|
|
18570
18286
|
// forward logger events to main thread
|
18571
|
-
var forwardWorkerLogs = function forwardWorkerLogs(
|
18287
|
+
var forwardWorkerLogs = function forwardWorkerLogs() {
|
18572
18288
|
var _loop = function _loop(logFn) {
|
18573
18289
|
var func = function func(message) {
|
18574
18290
|
forwardMessage('workerLog', {
|
@@ -18589,8 +18305,8 @@
|
|
18589
18305
|
{
|
18590
18306
|
var config = JSON.parse(data.config);
|
18591
18307
|
self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
|
18592
|
-
|
18593
|
-
forwardWorkerLogs(
|
18308
|
+
enableLogs(config.debug, data.id);
|
18309
|
+
forwardWorkerLogs();
|
18594
18310
|
forwardMessage('init', null);
|
18595
18311
|
break;
|
18596
18312
|
}
|
@@ -18764,7 +18480,16 @@
|
|
18764
18480
|
this.observer = new EventEmitter();
|
18765
18481
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
18766
18482
|
this.observer.on(Events.ERROR, forwardMessage);
|
18767
|
-
var
|
18483
|
+
var MediaSource = getMediaSource(config.preferManagedMediaSource) || {
|
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
|
+
};
|
18768
18493
|
|
18769
18494
|
// navigator.vendor is not always available in Web Worker
|
18770
18495
|
// refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
|
@@ -19021,26 +18746,21 @@
|
|
19021
18746
|
var MAX_START_GAP_JUMP = 2.0;
|
19022
18747
|
var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
19023
18748
|
var SKIP_BUFFER_RANGE_START = 0.05;
|
19024
|
-
var GapController = /*#__PURE__*/function (
|
19025
|
-
_inheritsLoose(GapController, _Logger);
|
18749
|
+
var GapController = /*#__PURE__*/function () {
|
19026
18750
|
function GapController(config, media, fragmentTracker, hls) {
|
19027
|
-
|
19028
|
-
|
19029
|
-
|
19030
|
-
|
19031
|
-
|
19032
|
-
|
19033
|
-
|
19034
|
-
|
19035
|
-
|
19036
|
-
|
19037
|
-
|
19038
|
-
|
19039
|
-
|
19040
|
-
_this.media = media;
|
19041
|
-
_this.fragmentTracker = fragmentTracker;
|
19042
|
-
_this.hls = hls;
|
19043
|
-
return _this;
|
18751
|
+
this.config = void 0;
|
18752
|
+
this.media = null;
|
18753
|
+
this.fragmentTracker = void 0;
|
18754
|
+
this.hls = void 0;
|
18755
|
+
this.nudgeRetry = 0;
|
18756
|
+
this.stallReported = false;
|
18757
|
+
this.stalled = null;
|
18758
|
+
this.moved = false;
|
18759
|
+
this.seeking = false;
|
18760
|
+
this.config = config;
|
18761
|
+
this.media = media;
|
18762
|
+
this.fragmentTracker = fragmentTracker;
|
18763
|
+
this.hls = hls;
|
19044
18764
|
}
|
19045
18765
|
var _proto = GapController.prototype;
|
19046
18766
|
_proto.destroy = function destroy() {
|
@@ -19055,7 +18775,7 @@
|
|
19055
18775
|
*
|
19056
18776
|
* @param lastCurrentTime - Previously read playhead position
|
19057
18777
|
*/;
|
19058
|
-
_proto.poll = function poll(lastCurrentTime, activeFrag
|
18778
|
+
_proto.poll = function poll(lastCurrentTime, activeFrag) {
|
19059
18779
|
var config = this.config,
|
19060
18780
|
media = this.media,
|
19061
18781
|
stalled = this.stalled;
|
@@ -19070,7 +18790,6 @@
|
|
19070
18790
|
|
19071
18791
|
// The playhead is moving, no-op
|
19072
18792
|
if (currentTime !== lastCurrentTime) {
|
19073
|
-
this.ended = 0;
|
19074
18793
|
this.moved = true;
|
19075
18794
|
if (!seeking) {
|
19076
18795
|
this.nudgeRetry = 0;
|
@@ -19079,7 +18798,7 @@
|
|
19079
18798
|
// The playhead is now moving, but was previously stalled
|
19080
18799
|
if (this.stallReported) {
|
19081
18800
|
var _stalledDuration = self.performance.now() - stalled;
|
19082
|
-
|
18801
|
+
logger.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
|
19083
18802
|
this.stallReported = false;
|
19084
18803
|
}
|
19085
18804
|
this.stalled = null;
|
@@ -19115,6 +18834,7 @@
|
|
19115
18834
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
19116
18835
|
// The addition poll gives the browser a chance to jump the gap for us
|
19117
18836
|
if (!this.moved && this.stalled !== null) {
|
18837
|
+
var _level$details;
|
19118
18838
|
// There is no playable buffer (seeked, waiting for buffer)
|
19119
18839
|
var isBuffered = bufferInfo.len > 0;
|
19120
18840
|
if (!isBuffered && !nextStart) {
|
@@ -19126,8 +18846,9 @@
|
|
19126
18846
|
// When joining a live stream with audio tracks, account for live playlist window sliding by allowing
|
19127
18847
|
// a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
|
19128
18848
|
// that begins over 1 target duration after the video start position.
|
19129
|
-
var
|
19130
|
-
var
|
18849
|
+
var level = this.hls.levels ? this.hls.levels[this.hls.currentLevel] : null;
|
18850
|
+
var isLive = level == null ? void 0 : (_level$details = level.details) == null ? void 0 : _level$details.live;
|
18851
|
+
var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
|
19131
18852
|
var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
|
19132
18853
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
19133
18854
|
if (!media.paused) {
|
@@ -19145,17 +18866,6 @@
|
|
19145
18866
|
}
|
19146
18867
|
var stalledDuration = tnow - stalled;
|
19147
18868
|
if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
|
19148
|
-
// Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
|
19149
|
-
if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
|
19150
|
-
if (stalledDuration < 1000 || this.ended) {
|
19151
|
-
return;
|
19152
|
-
}
|
19153
|
-
this.ended = currentTime;
|
19154
|
-
this.hls.trigger(Events.MEDIA_ENDED, {
|
19155
|
-
stalled: true
|
19156
|
-
});
|
19157
|
-
return;
|
19158
|
-
}
|
19159
18869
|
// Report stalling after trying to fix
|
19160
18870
|
this._reportStall(bufferInfo);
|
19161
18871
|
if (!this.media) {
|
@@ -19197,7 +18907,7 @@
|
|
19197
18907
|
// needs to cross some sort of threshold covering all source-buffers content
|
19198
18908
|
// to start playing properly.
|
19199
18909
|
if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
19200
|
-
|
18910
|
+
logger.warn('Trying to nudge playhead over buffer-hole');
|
19201
18911
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
19202
18912
|
// We only try to jump the hole if it's under the configured size
|
19203
18913
|
// Reset stalled so to rearm watchdog timer
|
@@ -19219,7 +18929,7 @@
|
|
19219
18929
|
// Report stalled error once
|
19220
18930
|
this.stallReported = true;
|
19221
18931
|
var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
|
19222
|
-
|
18932
|
+
logger.warn(error.message);
|
19223
18933
|
hls.trigger(Events.ERROR, {
|
19224
18934
|
type: ErrorTypes.MEDIA_ERROR,
|
19225
18935
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -19283,7 +18993,7 @@
|
|
19283
18993
|
}
|
19284
18994
|
}
|
19285
18995
|
var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
19286
|
-
|
18996
|
+
logger.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
|
19287
18997
|
this.moved = true;
|
19288
18998
|
this.stalled = null;
|
19289
18999
|
media.currentTime = targetTime;
|
@@ -19322,7 +19032,7 @@
|
|
19322
19032
|
var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
|
19323
19033
|
// playback stalled in buffered area ... let's nudge currentTime to try to overcome this
|
19324
19034
|
var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
|
19325
|
-
|
19035
|
+
logger.warn(error.message);
|
19326
19036
|
media.currentTime = targetTime;
|
19327
19037
|
hls.trigger(Events.ERROR, {
|
19328
19038
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -19332,7 +19042,7 @@
|
|
19332
19042
|
});
|
19333
19043
|
} else {
|
19334
19044
|
var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
|
19335
|
-
|
19045
|
+
logger.error(_error.message);
|
19336
19046
|
hls.trigger(Events.ERROR, {
|
19337
19047
|
type: ErrorTypes.MEDIA_ERROR,
|
19338
19048
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -19342,14 +19052,14 @@
|
|
19342
19052
|
}
|
19343
19053
|
};
|
19344
19054
|
return GapController;
|
19345
|
-
}(
|
19055
|
+
}();
|
19346
19056
|
|
19347
19057
|
var TICK_INTERVAL = 100; // how often to tick in ms
|
19348
19058
|
var StreamController = /*#__PURE__*/function (_BaseStreamController) {
|
19349
19059
|
_inheritsLoose(StreamController, _BaseStreamController);
|
19350
19060
|
function StreamController(hls, fragmentTracker, keyLoader) {
|
19351
19061
|
var _this;
|
19352
|
-
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
|
19062
|
+
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '[stream-controller]', PlaylistLevelType.MAIN) || this;
|
19353
19063
|
_this.audioCodecSwap = false;
|
19354
19064
|
_this.gapController = null;
|
19355
19065
|
_this.level = -1;
|
@@ -19357,43 +19067,27 @@
|
|
19357
19067
|
_this.altAudio = false;
|
19358
19068
|
_this.audioOnly = false;
|
19359
19069
|
_this.fragPlaying = null;
|
19070
|
+
_this.onvplaying = null;
|
19071
|
+
_this.onvseeked = null;
|
19360
19072
|
_this.fragLastKbps = 0;
|
19361
19073
|
_this.couldBacktrack = false;
|
19362
19074
|
_this.backtrackFragment = null;
|
19363
19075
|
_this.audioCodecSwitch = false;
|
19364
19076
|
_this.videoBuffer = null;
|
19365
|
-
_this.
|
19366
|
-
// tick to speed up FRAG_CHANGED triggering
|
19367
|
-
_this.tick();
|
19368
|
-
};
|
19369
|
-
_this.onMediaSeeked = function () {
|
19370
|
-
var media = _this.media;
|
19371
|
-
var currentTime = media ? media.currentTime : null;
|
19372
|
-
if (isFiniteNumber(currentTime)) {
|
19373
|
-
_this.log("Media seeked to " + currentTime.toFixed(3));
|
19374
|
-
}
|
19375
|
-
|
19376
|
-
// If seeked was issued before buffer was appended do not tick immediately
|
19377
|
-
var bufferInfo = _this.getMainFwdBufferInfo();
|
19378
|
-
if (bufferInfo === null || bufferInfo.len === 0) {
|
19379
|
-
_this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19380
|
-
return;
|
19381
|
-
}
|
19382
|
-
|
19383
|
-
// tick to speed up FRAG_CHANGED triggering
|
19384
|
-
_this.tick();
|
19385
|
-
};
|
19386
|
-
_this.registerListeners();
|
19077
|
+
_this._registerListeners();
|
19387
19078
|
return _this;
|
19388
19079
|
}
|
19389
19080
|
var _proto = StreamController.prototype;
|
19390
|
-
_proto.
|
19391
|
-
_BaseStreamController.prototype.registerListeners.call(this);
|
19081
|
+
_proto._registerListeners = function _registerListeners() {
|
19392
19082
|
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);
|
19393
19086
|
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19394
19087
|
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
|
19395
19088
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19396
19089
|
hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19090
|
+
hls.on(Events.ERROR, this.onError, this);
|
19397
19091
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19398
19092
|
hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19399
19093
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19401,12 +19095,15 @@
|
|
19401
19095
|
hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
|
19402
19096
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19403
19097
|
};
|
19404
|
-
_proto.
|
19405
|
-
_BaseStreamController.prototype.unregisterListeners.call(this);
|
19098
|
+
_proto._unregisterListeners = function _unregisterListeners() {
|
19406
19099
|
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);
|
19407
19103
|
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19408
19104
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19409
19105
|
hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19106
|
+
hls.off(Events.ERROR, this.onError, this);
|
19410
19107
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19411
19108
|
hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19412
19109
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19415,9 +19112,7 @@
|
|
19415
19112
|
hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19416
19113
|
};
|
19417
19114
|
_proto.onHandlerDestroying = function onHandlerDestroying() {
|
19418
|
-
|
19419
|
-
this.onMediaPlaying = this.onMediaSeeked = null;
|
19420
|
-
this.unregisterListeners();
|
19115
|
+
this._unregisterListeners();
|
19421
19116
|
_BaseStreamController.prototype.onHandlerDestroying.call(this);
|
19422
19117
|
};
|
19423
19118
|
_proto.startLoad = function startLoad(startPosition) {
|
@@ -19513,13 +19208,11 @@
|
|
19513
19208
|
levelLastLoaded = this.levelLastLoaded,
|
19514
19209
|
levels = this.levels,
|
19515
19210
|
media = this.media;
|
19516
|
-
var config = hls.config,
|
19517
|
-
level = hls.nextLoadLevel;
|
19518
19211
|
|
19519
19212
|
// if start level not parsed yet OR
|
19520
19213
|
// if video not attached AND start fragment already requested OR start frag prefetch not enabled
|
19521
19214
|
// exit loop, as we either need more info (level not parsed) or we need media to be attached to load new fragment
|
19522
|
-
if (levelLastLoaded === null || !media && (this.startFragRequested || !config.startFragPrefetch)) {
|
19215
|
+
if (levelLastLoaded === null || !media && (this.startFragRequested || !hls.config.startFragPrefetch)) {
|
19523
19216
|
return;
|
19524
19217
|
}
|
19525
19218
|
|
@@ -19527,7 +19220,8 @@
|
|
19527
19220
|
if (this.altAudio && this.audioOnly) {
|
19528
19221
|
return;
|
19529
19222
|
}
|
19530
|
-
|
19223
|
+
var level = hls.nextLoadLevel;
|
19224
|
+
if (!(levels != null && levels[level])) {
|
19531
19225
|
return;
|
19532
19226
|
}
|
19533
19227
|
var levelInfo = levels[level];
|
@@ -19733,15 +19427,18 @@
|
|
19733
19427
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
19734
19428
|
_BaseStreamController.prototype.onMediaAttached.call(this, event, data);
|
19735
19429
|
var media = data.media;
|
19736
|
-
|
19737
|
-
|
19430
|
+
this.onvplaying = this.onMediaPlaying.bind(this);
|
19431
|
+
this.onvseeked = this.onMediaSeeked.bind(this);
|
19432
|
+
media.addEventListener('playing', this.onvplaying);
|
19433
|
+
media.addEventListener('seeked', this.onvseeked);
|
19738
19434
|
this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
|
19739
19435
|
};
|
19740
19436
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
19741
19437
|
var media = this.media;
|
19742
|
-
if (media) {
|
19743
|
-
media.removeEventListener('playing', this.
|
19744
|
-
media.removeEventListener('seeked', this.
|
19438
|
+
if (media && this.onvplaying && this.onvseeked) {
|
19439
|
+
media.removeEventListener('playing', this.onvplaying);
|
19440
|
+
media.removeEventListener('seeked', this.onvseeked);
|
19441
|
+
this.onvplaying = this.onvseeked = null;
|
19745
19442
|
this.videoBuffer = null;
|
19746
19443
|
}
|
19747
19444
|
this.fragPlaying = null;
|
@@ -19751,6 +19448,27 @@
|
|
19751
19448
|
}
|
19752
19449
|
_BaseStreamController.prototype.onMediaDetaching.call(this);
|
19753
19450
|
};
|
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
|
+
};
|
19754
19472
|
_proto.onManifestLoading = function onManifestLoading() {
|
19755
19473
|
// reset buffer on manifest loading
|
19756
19474
|
this.log('Trigger BUFFER_RESET');
|
@@ -20031,10 +19749,8 @@
|
|
20031
19749
|
}
|
20032
19750
|
if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
|
20033
19751
|
// Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
|
20034
|
-
var
|
20035
|
-
|
20036
|
-
var levelDetails = this.getLevelDetails();
|
20037
|
-
gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
|
19752
|
+
var activeFrag = this.state !== State.IDLE ? this.fragCurrent : null;
|
19753
|
+
gapController.poll(this.lastCurrentTime, activeFrag);
|
20038
19754
|
}
|
20039
19755
|
this.lastCurrentTime = media.currentTime;
|
20040
19756
|
};
|
@@ -20499,12 +20215,9 @@
|
|
20499
20215
|
* The configuration object provided on player instantiation.
|
20500
20216
|
*/
|
20501
20217
|
this.userConfig = void 0;
|
20502
|
-
/**
|
20503
|
-
* The logger functions used by this player instance, configured on player instantiation.
|
20504
|
-
*/
|
20505
|
-
this.logger = void 0;
|
20506
20218
|
this.coreComponents = void 0;
|
20507
20219
|
this.networkControllers = void 0;
|
20220
|
+
this.started = false;
|
20508
20221
|
this._emitter = new EventEmitter();
|
20509
20222
|
this._autoLevelCapping = -1;
|
20510
20223
|
this._maxHdcpLevel = null;
|
@@ -20521,11 +20234,11 @@
|
|
20521
20234
|
this._media = null;
|
20522
20235
|
this.url = null;
|
20523
20236
|
this.triggeringException = void 0;
|
20524
|
-
|
20525
|
-
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig
|
20237
|
+
enableLogs(userConfig.debug || false, 'Hls instance');
|
20238
|
+
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
|
20526
20239
|
this.userConfig = userConfig;
|
20527
20240
|
if (config.progressive) {
|
20528
|
-
enableStreamingMode(config
|
20241
|
+
enableStreamingMode(config);
|
20529
20242
|
}
|
20530
20243
|
|
20531
20244
|
// core controllers and network loaders
|
@@ -20633,7 +20346,7 @@
|
|
20633
20346
|
try {
|
20634
20347
|
return this.emit(event, event, eventObject);
|
20635
20348
|
} catch (error) {
|
20636
|
-
|
20349
|
+
logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20637
20350
|
// Prevent recursion in error event handlers that throw #5497
|
20638
20351
|
if (!this.triggeringException) {
|
20639
20352
|
this.triggeringException = true;
|
@@ -20659,7 +20372,7 @@
|
|
20659
20372
|
* Dispose of the instance
|
20660
20373
|
*/;
|
20661
20374
|
_proto.destroy = function destroy() {
|
20662
|
-
|
20375
|
+
logger.log('destroy');
|
20663
20376
|
this.trigger(Events.DESTROYING, undefined);
|
20664
20377
|
this.detachMedia();
|
20665
20378
|
this.removeAllListeners();
|
@@ -20684,7 +20397,7 @@
|
|
20684
20397
|
* Attaches Hls.js to a media element
|
20685
20398
|
*/;
|
20686
20399
|
_proto.attachMedia = function attachMedia(media) {
|
20687
|
-
|
20400
|
+
logger.log('attachMedia');
|
20688
20401
|
this._media = media;
|
20689
20402
|
this.trigger(Events.MEDIA_ATTACHING, {
|
20690
20403
|
media: media
|
@@ -20695,7 +20408,7 @@
|
|
20695
20408
|
* Detach Hls.js from the media
|
20696
20409
|
*/;
|
20697
20410
|
_proto.detachMedia = function detachMedia() {
|
20698
|
-
|
20411
|
+
logger.log('detachMedia');
|
20699
20412
|
this.trigger(Events.MEDIA_DETACHING, undefined);
|
20700
20413
|
this._media = null;
|
20701
20414
|
}
|
@@ -20712,7 +20425,7 @@
|
|
20712
20425
|
});
|
20713
20426
|
this._autoLevelCapping = -1;
|
20714
20427
|
this._maxHdcpLevel = null;
|
20715
|
-
|
20428
|
+
logger.log("loadSource:" + loadingSource);
|
20716
20429
|
if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
|
20717
20430
|
this.detachMedia();
|
20718
20431
|
this.attachMedia(media);
|
@@ -20734,7 +20447,8 @@
|
|
20734
20447
|
if (startPosition === void 0) {
|
20735
20448
|
startPosition = -1;
|
20736
20449
|
}
|
20737
|
-
|
20450
|
+
logger.log("startLoad(" + startPosition + ")");
|
20451
|
+
this.started = true;
|
20738
20452
|
this.networkControllers.forEach(function (controller) {
|
20739
20453
|
controller.startLoad(startPosition);
|
20740
20454
|
});
|
@@ -20744,31 +20458,34 @@
|
|
20744
20458
|
* Stop loading of any stream data.
|
20745
20459
|
*/;
|
20746
20460
|
_proto.stopLoad = function stopLoad() {
|
20747
|
-
|
20461
|
+
logger.log('stopLoad');
|
20462
|
+
this.started = false;
|
20748
20463
|
this.networkControllers.forEach(function (controller) {
|
20749
20464
|
controller.stopLoad();
|
20750
20465
|
});
|
20751
20466
|
}
|
20752
20467
|
|
20753
20468
|
/**
|
20754
|
-
* Resumes stream controller segment loading
|
20469
|
+
* Resumes stream controller segment loading if previously started.
|
20755
20470
|
*/;
|
20756
20471
|
_proto.resumeBuffering = function resumeBuffering() {
|
20757
|
-
this.
|
20758
|
-
|
20759
|
-
controller
|
20760
|
-
|
20761
|
-
|
20472
|
+
if (this.started) {
|
20473
|
+
this.networkControllers.forEach(function (controller) {
|
20474
|
+
if ('fragmentLoader' in controller) {
|
20475
|
+
controller.startLoad(-1);
|
20476
|
+
}
|
20477
|
+
});
|
20478
|
+
}
|
20762
20479
|
}
|
20763
20480
|
|
20764
20481
|
/**
|
20765
|
-
*
|
20482
|
+
* Stops stream controller segment loading without changing 'started' state like stopLoad().
|
20766
20483
|
* This allows for media buffering to be paused without interupting playlist loading.
|
20767
20484
|
*/;
|
20768
20485
|
_proto.pauseBuffering = function pauseBuffering() {
|
20769
20486
|
this.networkControllers.forEach(function (controller) {
|
20770
|
-
if (controller
|
20771
|
-
controller.
|
20487
|
+
if ('fragmentLoader' in controller) {
|
20488
|
+
controller.stopLoad();
|
20772
20489
|
}
|
20773
20490
|
});
|
20774
20491
|
}
|
@@ -20777,7 +20494,7 @@
|
|
20777
20494
|
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
20778
20495
|
*/;
|
20779
20496
|
_proto.swapAudioCodec = function swapAudioCodec() {
|
20780
|
-
|
20497
|
+
logger.log('swapAudioCodec');
|
20781
20498
|
this.streamController.swapAudioCodec();
|
20782
20499
|
}
|
20783
20500
|
|
@@ -20788,7 +20505,7 @@
|
|
20788
20505
|
* Automatic recovery of media-errors by this process is configurable.
|
20789
20506
|
*/;
|
20790
20507
|
_proto.recoverMediaError = function recoverMediaError() {
|
20791
|
-
|
20508
|
+
logger.log('recoverMediaError');
|
20792
20509
|
var media = this._media;
|
20793
20510
|
this.detachMedia();
|
20794
20511
|
if (media) {
|
@@ -20843,7 +20560,7 @@
|
|
20843
20560
|
* 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.
|
20844
20561
|
*/,
|
20845
20562
|
set: function set(newLevel) {
|
20846
|
-
|
20563
|
+
logger.log("set currentLevel:" + newLevel);
|
20847
20564
|
this.levelController.manualLevel = newLevel;
|
20848
20565
|
this.streamController.immediateLevelSwitch();
|
20849
20566
|
}
|
@@ -20864,7 +20581,7 @@
|
|
20864
20581
|
* @param newLevel - Pass -1 for automatic level selection
|
20865
20582
|
*/,
|
20866
20583
|
set: function set(newLevel) {
|
20867
|
-
|
20584
|
+
logger.log("set nextLevel:" + newLevel);
|
20868
20585
|
this.levelController.manualLevel = newLevel;
|
20869
20586
|
this.streamController.nextLevelSwitch();
|
20870
20587
|
}
|
@@ -20885,7 +20602,7 @@
|
|
20885
20602
|
* @param newLevel - Pass -1 for automatic level selection
|
20886
20603
|
*/,
|
20887
20604
|
set: function set(newLevel) {
|
20888
|
-
|
20605
|
+
logger.log("set loadLevel:" + newLevel);
|
20889
20606
|
this.levelController.manualLevel = newLevel;
|
20890
20607
|
}
|
20891
20608
|
|
@@ -20920,7 +20637,7 @@
|
|
20920
20637
|
* Sets "first-level", see getter.
|
20921
20638
|
*/,
|
20922
20639
|
set: function set(newLevel) {
|
20923
|
-
|
20640
|
+
logger.log("set firstLevel:" + newLevel);
|
20924
20641
|
this.levelController.firstLevel = newLevel;
|
20925
20642
|
}
|
20926
20643
|
|
@@ -20947,7 +20664,7 @@
|
|
20947
20664
|
* (determined from download of first segment)
|
20948
20665
|
*/,
|
20949
20666
|
set: function set(newLevel) {
|
20950
|
-
|
20667
|
+
logger.log("set startLevel:" + newLevel);
|
20951
20668
|
// if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
|
20952
20669
|
if (newLevel !== -1) {
|
20953
20670
|
newLevel = Math.max(newLevel, this.minAutoLevel);
|
@@ -21000,7 +20717,7 @@
|
|
21000
20717
|
*/
|
21001
20718
|
function set(newLevel) {
|
21002
20719
|
if (this._autoLevelCapping !== newLevel) {
|
21003
|
-
|
20720
|
+
logger.log("set autoLevelCapping:" + newLevel);
|
21004
20721
|
this._autoLevelCapping = newLevel;
|
21005
20722
|
this.levelController.checkMaxAutoUpdated();
|
21006
20723
|
}
|
@@ -21325,7 +21042,7 @@
|
|
21325
21042
|
* Get the video-dev/hls.js package version.
|
21326
21043
|
*/
|
21327
21044
|
function get() {
|
21328
|
-
return "1.5.6
|
21045
|
+
return "1.5.6";
|
21329
21046
|
}
|
21330
21047
|
}, {
|
21331
21048
|
key: "Events",
|