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