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