hls.js 1.5.3 → 1.5.5-0.canary.9977
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/hls-demo.js +10 -0
- package/dist/hls-demo.js.map +1 -1
- package/dist/hls.js +1954 -1103
- package/dist/hls.js.d.ts +63 -50
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +1631 -784
- 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 +1428 -590
- 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 +1703 -866
- 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 +18 -18
- package/src/config.ts +3 -2
- package/src/controller/abr-controller.ts +24 -22
- package/src/controller/audio-stream-controller.ts +16 -17
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +7 -7
- package/src/controller/base-stream-controller.ts +56 -29
- package/src/controller/buffer-controller.ts +11 -11
- package/src/controller/cap-level-controller.ts +1 -2
- package/src/controller/cmcd-controller.ts +25 -3
- package/src/controller/content-steering-controller.ts +8 -6
- package/src/controller/eme-controller.ts +9 -22
- package/src/controller/error-controller.ts +6 -8
- package/src/controller/fps-controller.ts +2 -3
- package/src/controller/gap-controller.ts +43 -16
- package/src/controller/latency-controller.ts +9 -11
- package/src/controller/level-controller.ts +5 -17
- package/src/controller/stream-controller.ts +27 -33
- package/src/controller/subtitle-stream-controller.ts +14 -15
- package/src/controller/subtitle-track-controller.ts +5 -3
- package/src/controller/timeline-controller.ts +23 -30
- package/src/crypt/aes-crypto.ts +21 -2
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +32 -18
- package/src/crypt/fast-aes-key.ts +24 -5
- package/src/demux/audio/adts.ts +9 -4
- package/src/demux/sample-aes.ts +2 -0
- package/src/demux/transmuxer-interface.ts +4 -12
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +16 -3
- package/src/demux/tsdemuxer.ts +63 -37
- package/src/demux/video/avc-video-parser.ts +208 -119
- package/src/demux/video/base-video-parser.ts +134 -2
- package/src/demux/video/exp-golomb.ts +0 -208
- package/src/demux/video/hevc-video-parser.ts +746 -0
- package/src/events.ts +7 -0
- package/src/hls.ts +42 -34
- package/src/loader/fragment-loader.ts +9 -2
- package/src/loader/key-loader.ts +2 -0
- package/src/loader/level-key.ts +10 -9
- package/src/remux/mp4-generator.ts +196 -1
- package/src/remux/mp4-remuxer.ts +23 -7
- package/src/task-loop.ts +5 -2
- package/src/types/component-api.ts +2 -0
- package/src/types/demuxer.ts +3 -0
- package/src/types/events.ts +4 -0
- package/src/utils/codecs.ts +33 -4
- package/src/utils/encryption-methods-util.ts +21 -0
- package/src/utils/logger.ts +53 -24
- package/src/utils/mp4-tools.ts +28 -9
package/dist/hls.light.js
CHANGED
@@ -5,6 +5,21 @@
|
|
5
5
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Hls = factory());
|
6
6
|
})(this, (function () { 'use strict';
|
7
7
|
|
8
|
+
function _construct(t, e, r) {
|
9
|
+
if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
|
10
|
+
var o = [null];
|
11
|
+
o.push.apply(o, e);
|
12
|
+
var p = new (t.bind.apply(t, o))();
|
13
|
+
return r && _setPrototypeOf(p, r.prototype), p;
|
14
|
+
}
|
15
|
+
function _isNativeReflectConstruct() {
|
16
|
+
try {
|
17
|
+
var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
18
|
+
} catch (t) {}
|
19
|
+
return (_isNativeReflectConstruct = function () {
|
20
|
+
return !!t;
|
21
|
+
})();
|
22
|
+
}
|
8
23
|
function ownKeys(e, r) {
|
9
24
|
var t = Object.keys(e);
|
10
25
|
if (Object.getOwnPropertySymbols) {
|
@@ -103,32 +118,6 @@
|
|
103
118
|
};
|
104
119
|
return _setPrototypeOf(o, p);
|
105
120
|
}
|
106
|
-
function _isNativeReflectConstruct() {
|
107
|
-
if (typeof Reflect === "undefined" || !Reflect.construct) return false;
|
108
|
-
if (Reflect.construct.sham) return false;
|
109
|
-
if (typeof Proxy === "function") return true;
|
110
|
-
try {
|
111
|
-
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
|
112
|
-
return true;
|
113
|
-
} catch (e) {
|
114
|
-
return false;
|
115
|
-
}
|
116
|
-
}
|
117
|
-
function _construct(Parent, args, Class) {
|
118
|
-
if (_isNativeReflectConstruct()) {
|
119
|
-
_construct = Reflect.construct.bind();
|
120
|
-
} else {
|
121
|
-
_construct = function _construct(Parent, args, Class) {
|
122
|
-
var a = [null];
|
123
|
-
a.push.apply(a, args);
|
124
|
-
var Constructor = Function.bind.apply(Parent, a);
|
125
|
-
var instance = new Constructor();
|
126
|
-
if (Class) _setPrototypeOf(instance, Class.prototype);
|
127
|
-
return instance;
|
128
|
-
};
|
129
|
-
}
|
130
|
-
return _construct.apply(null, arguments);
|
131
|
-
}
|
132
121
|
function _isNativeFunction(fn) {
|
133
122
|
try {
|
134
123
|
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
@@ -363,6 +352,7 @@
|
|
363
352
|
Events["MEDIA_ATTACHED"] = "hlsMediaAttached";
|
364
353
|
Events["MEDIA_DETACHING"] = "hlsMediaDetaching";
|
365
354
|
Events["MEDIA_DETACHED"] = "hlsMediaDetached";
|
355
|
+
Events["MEDIA_ENDED"] = "hlsMediaEnded";
|
366
356
|
Events["BUFFER_RESET"] = "hlsBufferReset";
|
367
357
|
Events["BUFFER_CODECS"] = "hlsBufferCodecs";
|
368
358
|
Events["BUFFER_CREATED"] = "hlsBufferCreated";
|
@@ -476,6 +466,21 @@
|
|
476
466
|
return ErrorDetails;
|
477
467
|
}({});
|
478
468
|
|
469
|
+
var Logger = function Logger(label, logger) {
|
470
|
+
this.trace = void 0;
|
471
|
+
this.debug = void 0;
|
472
|
+
this.log = void 0;
|
473
|
+
this.warn = void 0;
|
474
|
+
this.info = void 0;
|
475
|
+
this.error = void 0;
|
476
|
+
var lb = "[" + label + "]:";
|
477
|
+
this.trace = noop;
|
478
|
+
this.debug = logger.debug.bind(null, lb);
|
479
|
+
this.log = logger.log.bind(null, lb);
|
480
|
+
this.warn = logger.warn.bind(null, lb);
|
481
|
+
this.info = logger.info.bind(null, lb);
|
482
|
+
this.error = logger.error.bind(null, lb);
|
483
|
+
};
|
479
484
|
var noop = function noop() {};
|
480
485
|
var fakeLogger = {
|
481
486
|
trace: noop,
|
@@ -485,7 +490,9 @@
|
|
485
490
|
info: noop,
|
486
491
|
error: noop
|
487
492
|
};
|
488
|
-
|
493
|
+
function createLogger() {
|
494
|
+
return _extends({}, fakeLogger);
|
495
|
+
}
|
489
496
|
|
490
497
|
// let lastCallTime;
|
491
498
|
// function formatMsgWithTimeInfo(type, msg) {
|
@@ -496,38 +503,36 @@
|
|
496
503
|
// return msg;
|
497
504
|
// }
|
498
505
|
|
499
|
-
function consolePrintFn(type) {
|
506
|
+
function consolePrintFn(type, id) {
|
500
507
|
var func = self.console[type];
|
501
|
-
|
502
|
-
return func.bind(self.console, "[" + type + "] >");
|
503
|
-
}
|
504
|
-
return noop;
|
508
|
+
return func ? func.bind(self.console, (id ? '[' + id + '] ' : '') + "[" + type + "] >") : noop;
|
505
509
|
}
|
506
|
-
function
|
507
|
-
|
508
|
-
functions[_key - 1] = arguments[_key];
|
509
|
-
}
|
510
|
-
functions.forEach(function (type) {
|
511
|
-
exportedLogger[type] = debugConfig[type] ? debugConfig[type].bind(debugConfig) : consolePrintFn(type);
|
512
|
-
});
|
510
|
+
function getLoggerFn(key, debugConfig, id) {
|
511
|
+
return debugConfig[key] ? debugConfig[key].bind(debugConfig) : consolePrintFn(key, id);
|
513
512
|
}
|
514
|
-
|
513
|
+
var exportedLogger = createLogger();
|
514
|
+
function enableLogs(debugConfig, context, id) {
|
515
515
|
// check that console is available
|
516
|
+
var newLogger = createLogger();
|
516
517
|
if (typeof console === 'object' && debugConfig === true || typeof debugConfig === 'object') {
|
517
|
-
|
518
|
+
var keys = [
|
518
519
|
// Remove out from list here to hard-disable a log-level
|
519
520
|
// 'trace',
|
520
|
-
'debug', 'log', 'info', 'warn', 'error'
|
521
|
+
'debug', 'log', 'info', 'warn', 'error'];
|
522
|
+
keys.forEach(function (key) {
|
523
|
+
newLogger[key] = getLoggerFn(key, debugConfig, id);
|
524
|
+
});
|
521
525
|
// Some browsers don't allow to use bind on console object anyway
|
522
526
|
// fallback to default if needed
|
523
527
|
try {
|
524
|
-
|
528
|
+
newLogger.log("Debug logs enabled for \"" + context + "\" in hls.js version " + "1.5.5-0.canary.9977");
|
525
529
|
} catch (e) {
|
526
|
-
|
530
|
+
/* log fn threw an exception. All logger methods are no-ops. */
|
531
|
+
return createLogger();
|
527
532
|
}
|
528
|
-
} else {
|
529
|
-
exportedLogger = fakeLogger;
|
530
533
|
}
|
534
|
+
exportedLogger = newLogger;
|
535
|
+
return newLogger;
|
531
536
|
}
|
532
537
|
var logger = exportedLogger;
|
533
538
|
|
@@ -1173,6 +1178,26 @@
|
|
1173
1178
|
return LevelDetails;
|
1174
1179
|
}();
|
1175
1180
|
|
1181
|
+
var DecrypterAesMode = {
|
1182
|
+
cbc: 0,
|
1183
|
+
ctr: 1
|
1184
|
+
};
|
1185
|
+
|
1186
|
+
function isFullSegmentEncryption(method) {
|
1187
|
+
return method === 'AES-128' || method === 'AES-256' || method === 'AES-256-CTR';
|
1188
|
+
}
|
1189
|
+
function getAesModeFromFullSegmentMethod(method) {
|
1190
|
+
switch (method) {
|
1191
|
+
case 'AES-128':
|
1192
|
+
case 'AES-256':
|
1193
|
+
return DecrypterAesMode.cbc;
|
1194
|
+
case 'AES-256-CTR':
|
1195
|
+
return DecrypterAesMode.ctr;
|
1196
|
+
default:
|
1197
|
+
throw new Error("invalid full segment method " + method);
|
1198
|
+
}
|
1199
|
+
}
|
1200
|
+
|
1176
1201
|
// This file is inserted as a shim for modules which we do not want to include into the distro.
|
1177
1202
|
// This replacement is done in the "alias" plugin of the rollup config.
|
1178
1203
|
var empty = undefined;
|
@@ -1577,6 +1602,12 @@
|
|
1577
1602
|
var val = readSint32(buffer, offset);
|
1578
1603
|
return val < 0 ? 4294967296 + val : val;
|
1579
1604
|
}
|
1605
|
+
function readUint64(buffer, offset) {
|
1606
|
+
var result = readUint32(buffer, offset);
|
1607
|
+
result *= Math.pow(2, 32);
|
1608
|
+
result += readUint32(buffer, offset + 4);
|
1609
|
+
return result;
|
1610
|
+
}
|
1580
1611
|
function readSint32(buffer, offset) {
|
1581
1612
|
return buffer[offset] << 24 | buffer[offset + 1] << 16 | buffer[offset + 2] << 8 | buffer[offset + 3];
|
1582
1613
|
}
|
@@ -1639,15 +1670,14 @@
|
|
1639
1670
|
var index = 8;
|
1640
1671
|
var timescale = readUint32(sidx, index);
|
1641
1672
|
index += 4;
|
1642
|
-
|
1643
|
-
// TODO: parse earliestPresentationTime and firstOffset
|
1644
|
-
// usually zero in our case
|
1645
1673
|
var earliestPresentationTime = 0;
|
1646
1674
|
var firstOffset = 0;
|
1647
1675
|
if (version === 0) {
|
1648
|
-
index +=
|
1676
|
+
earliestPresentationTime = readUint32(sidx, index += 4);
|
1677
|
+
firstOffset = readUint32(sidx, index += 4);
|
1649
1678
|
} else {
|
1650
|
-
index +=
|
1679
|
+
earliestPresentationTime = readUint64(sidx, index += 8);
|
1680
|
+
firstOffset = readUint64(sidx, index += 8);
|
1651
1681
|
}
|
1652
1682
|
|
1653
1683
|
// skip reserved
|
@@ -2097,17 +2127,24 @@
|
|
2097
2127
|
}
|
2098
2128
|
if (videoDuration === 0 && audioDuration === 0) {
|
2099
2129
|
// If duration samples are not available in the traf use sidx subsegment_duration
|
2130
|
+
var sidxMinStart = Infinity;
|
2131
|
+
var sidxMaxEnd = 0;
|
2100
2132
|
var sidxDuration = 0;
|
2101
2133
|
var sidxs = findBox(data, ['sidx']);
|
2102
2134
|
for (var _i2 = 0; _i2 < sidxs.length; _i2++) {
|
2103
2135
|
var sidx = parseSegmentIndex(sidxs[_i2]);
|
2104
2136
|
if (sidx != null && sidx.references) {
|
2105
|
-
|
2137
|
+
sidxMinStart = Math.min(sidxMinStart, sidx.earliestPresentationTime / sidx.timescale);
|
2138
|
+
var subSegmentDuration = sidx.references.reduce(function (dur, ref) {
|
2106
2139
|
return dur + ref.info.duration || 0;
|
2107
2140
|
}, 0);
|
2141
|
+
sidxMaxEnd = Math.max(sidxMaxEnd, subSegmentDuration + sidx.earliestPresentationTime / sidx.timescale);
|
2142
|
+
sidxDuration = sidxMaxEnd - sidxMinStart;
|
2108
2143
|
}
|
2109
2144
|
}
|
2110
|
-
|
2145
|
+
if (sidxDuration && isFiniteNumber(sidxDuration)) {
|
2146
|
+
return sidxDuration;
|
2147
|
+
}
|
2111
2148
|
}
|
2112
2149
|
if (videoDuration) {
|
2113
2150
|
return videoDuration;
|
@@ -2614,13 +2651,13 @@
|
|
2614
2651
|
this.keyFormatVersions = formatversions;
|
2615
2652
|
this.iv = iv;
|
2616
2653
|
this.encrypted = method ? method !== 'NONE' : false;
|
2617
|
-
this.isCommonEncryption = this.encrypted && method
|
2654
|
+
this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
|
2618
2655
|
}
|
2619
2656
|
var _proto = LevelKey.prototype;
|
2620
2657
|
_proto.isSupported = function isSupported() {
|
2621
2658
|
// If it's Segment encryption or No encryption, just select that key system
|
2622
2659
|
if (this.method) {
|
2623
|
-
if (this.method
|
2660
|
+
if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
|
2624
2661
|
return true;
|
2625
2662
|
}
|
2626
2663
|
if (this.keyFormat === 'identity') {
|
@@ -2634,14 +2671,13 @@
|
|
2634
2671
|
if (!this.encrypted || !this.uri) {
|
2635
2672
|
return null;
|
2636
2673
|
}
|
2637
|
-
if (this.method
|
2674
|
+
if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
|
2638
2675
|
if (typeof sn !== 'number') {
|
2639
2676
|
// We are fetching decryption data for a initialization segment
|
2640
|
-
// If the segment was encrypted with AES-128
|
2677
|
+
// If the segment was encrypted with AES-128/256
|
2641
2678
|
// It must have an IV defined. We cannot substitute the Segment Number in.
|
2642
|
-
|
2643
|
-
|
2644
|
-
}
|
2679
|
+
logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
|
2680
|
+
|
2645
2681
|
// Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
|
2646
2682
|
sn = 0;
|
2647
2683
|
}
|
@@ -2803,23 +2839,28 @@
|
|
2803
2839
|
if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
|
2804
2840
|
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
|
2805
2841
|
}
|
2806
|
-
|
2807
|
-
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2808
|
-
// some browsers will report that fLaC is supported then fail.
|
2809
|
-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2810
2842
|
var codecsToCheck = {
|
2843
|
+
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2844
|
+
// some browsers will report that fLaC is supported then fail.
|
2845
|
+
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2811
2846
|
flac: ['flac', 'fLaC', 'FLAC'],
|
2812
|
-
opus: ['opus', 'Opus']
|
2847
|
+
opus: ['opus', 'Opus'],
|
2848
|
+
// Replace audio codec info if browser does not support mp4a.40.34,
|
2849
|
+
// and demuxer can fallback to 'audio/mpeg' or 'audio/mp4;codecs="mp3"'
|
2850
|
+
'mp4a.40.34': ['mp3']
|
2813
2851
|
}[lowerCaseCodec];
|
2814
2852
|
for (var i = 0; i < codecsToCheck.length; i++) {
|
2853
|
+
var _getMediaSource;
|
2815
2854
|
if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
|
2816
2855
|
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
|
2817
2856
|
return codecsToCheck[i];
|
2857
|
+
} else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
|
2858
|
+
return '';
|
2818
2859
|
}
|
2819
2860
|
}
|
2820
2861
|
return lowerCaseCodec;
|
2821
2862
|
}
|
2822
|
-
var AUDIO_CODEC_REGEXP = /flac|opus/i;
|
2863
|
+
var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
|
2823
2864
|
function getCodecCompatibleName(codec, preferManagedMediaSource) {
|
2824
2865
|
if (preferManagedMediaSource === void 0) {
|
2825
2866
|
preferManagedMediaSource = true;
|
@@ -2847,6 +2888,18 @@
|
|
2847
2888
|
}
|
2848
2889
|
return codec;
|
2849
2890
|
}
|
2891
|
+
function getM2TSSupportedAudioTypes(preferManagedMediaSource) {
|
2892
|
+
var MediaSource = getMediaSource(preferManagedMediaSource) || {
|
2893
|
+
isTypeSupported: function isTypeSupported() {
|
2894
|
+
return false;
|
2895
|
+
}
|
2896
|
+
};
|
2897
|
+
return {
|
2898
|
+
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
2899
|
+
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
2900
|
+
ac3: false
|
2901
|
+
};
|
2902
|
+
}
|
2850
2903
|
|
2851
2904
|
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;
|
2852
2905
|
var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
|
@@ -4421,8 +4474,43 @@
|
|
4421
4474
|
this.currentTime = 0;
|
4422
4475
|
this.stallCount = 0;
|
4423
4476
|
this._latency = null;
|
4424
|
-
this.
|
4425
|
-
|
4477
|
+
this.onTimeupdate = function () {
|
4478
|
+
var media = _this.media,
|
4479
|
+
levelDetails = _this.levelDetails;
|
4480
|
+
if (!media || !levelDetails) {
|
4481
|
+
return;
|
4482
|
+
}
|
4483
|
+
_this.currentTime = media.currentTime;
|
4484
|
+
var latency = _this.computeLatency();
|
4485
|
+
if (latency === null) {
|
4486
|
+
return;
|
4487
|
+
}
|
4488
|
+
_this._latency = latency;
|
4489
|
+
|
4490
|
+
// Adapt playbackRate to meet target latency in low-latency mode
|
4491
|
+
var _this$config = _this.config,
|
4492
|
+
lowLatencyMode = _this$config.lowLatencyMode,
|
4493
|
+
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4494
|
+
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4495
|
+
return;
|
4496
|
+
}
|
4497
|
+
var targetLatency = _this.targetLatency;
|
4498
|
+
if (targetLatency === null) {
|
4499
|
+
return;
|
4500
|
+
}
|
4501
|
+
var distanceFromTarget = latency - targetLatency;
|
4502
|
+
// Only adjust playbackRate when within one target duration of targetLatency
|
4503
|
+
// and more than one second from under-buffering.
|
4504
|
+
// Playback further than one target duration from target can be considered DVR playback.
|
4505
|
+
var liveMinLatencyDuration = Math.min(_this.maxLatency, targetLatency + levelDetails.targetduration);
|
4506
|
+
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4507
|
+
if (inLiveRange && distanceFromTarget > 0.05 && _this.forwardBufferLength > 1) {
|
4508
|
+
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4509
|
+
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - _this.edgeStalled)) * 20) / 20;
|
4510
|
+
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4511
|
+
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4512
|
+
media.playbackRate = 1;
|
4513
|
+
}
|
4426
4514
|
};
|
4427
4515
|
this.hls = hls;
|
4428
4516
|
this.config = hls.config;
|
@@ -4434,7 +4522,7 @@
|
|
4434
4522
|
this.onMediaDetaching();
|
4435
4523
|
this.levelDetails = null;
|
4436
4524
|
// @ts-ignore
|
4437
|
-
this.hls =
|
4525
|
+
this.hls = null;
|
4438
4526
|
};
|
4439
4527
|
_proto.registerListeners = function registerListeners() {
|
4440
4528
|
this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
@@ -4452,11 +4540,11 @@
|
|
4452
4540
|
};
|
4453
4541
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
4454
4542
|
this.media = data.media;
|
4455
|
-
this.media.addEventListener('timeupdate', this.
|
4543
|
+
this.media.addEventListener('timeupdate', this.onTimeupdate);
|
4456
4544
|
};
|
4457
4545
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
4458
4546
|
if (this.media) {
|
4459
|
-
this.media.removeEventListener('timeupdate', this.
|
4547
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4460
4548
|
this.media = null;
|
4461
4549
|
}
|
4462
4550
|
};
|
@@ -4469,10 +4557,10 @@
|
|
4469
4557
|
var details = _ref.details;
|
4470
4558
|
this.levelDetails = details;
|
4471
4559
|
if (details.advanced) {
|
4472
|
-
this.
|
4560
|
+
this.onTimeupdate();
|
4473
4561
|
}
|
4474
4562
|
if (!details.live && this.media) {
|
4475
|
-
this.media.removeEventListener('timeupdate', this.
|
4563
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4476
4564
|
}
|
4477
4565
|
};
|
4478
4566
|
_proto.onError = function onError(event, data) {
|
@@ -4482,45 +4570,7 @@
|
|
4482
4570
|
}
|
4483
4571
|
this.stallCount++;
|
4484
4572
|
if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
|
4485
|
-
logger.warn('[
|
4486
|
-
}
|
4487
|
-
};
|
4488
|
-
_proto.timeupdate = function timeupdate() {
|
4489
|
-
var media = this.media,
|
4490
|
-
levelDetails = this.levelDetails;
|
4491
|
-
if (!media || !levelDetails) {
|
4492
|
-
return;
|
4493
|
-
}
|
4494
|
-
this.currentTime = media.currentTime;
|
4495
|
-
var latency = this.computeLatency();
|
4496
|
-
if (latency === null) {
|
4497
|
-
return;
|
4498
|
-
}
|
4499
|
-
this._latency = latency;
|
4500
|
-
|
4501
|
-
// Adapt playbackRate to meet target latency in low-latency mode
|
4502
|
-
var _this$config = this.config,
|
4503
|
-
lowLatencyMode = _this$config.lowLatencyMode,
|
4504
|
-
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4505
|
-
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4506
|
-
return;
|
4507
|
-
}
|
4508
|
-
var targetLatency = this.targetLatency;
|
4509
|
-
if (targetLatency === null) {
|
4510
|
-
return;
|
4511
|
-
}
|
4512
|
-
var distanceFromTarget = latency - targetLatency;
|
4513
|
-
// Only adjust playbackRate when within one target duration of targetLatency
|
4514
|
-
// and more than one second from under-buffering.
|
4515
|
-
// Playback further than one target duration from target can be considered DVR playback.
|
4516
|
-
var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
|
4517
|
-
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4518
|
-
if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
|
4519
|
-
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4520
|
-
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
|
4521
|
-
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4522
|
-
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4523
|
-
media.playbackRate = 1;
|
4573
|
+
this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
|
4524
4574
|
}
|
4525
4575
|
};
|
4526
4576
|
_proto.estimateLiveEdge = function estimateLiveEdge() {
|
@@ -5428,19 +5478,17 @@
|
|
5428
5478
|
MoveAllAlternatesMatchingHDCP: 2,
|
5429
5479
|
SwitchToSDR: 4
|
5430
5480
|
}; // Reserved for future use
|
5431
|
-
var ErrorController = /*#__PURE__*/function () {
|
5481
|
+
var ErrorController = /*#__PURE__*/function (_Logger) {
|
5482
|
+
_inheritsLoose(ErrorController, _Logger);
|
5432
5483
|
function ErrorController(hls) {
|
5433
|
-
|
5434
|
-
this.
|
5435
|
-
|
5436
|
-
|
5437
|
-
|
5438
|
-
|
5439
|
-
|
5440
|
-
|
5441
|
-
this.warn = logger.warn.bind(logger, "[warning]:");
|
5442
|
-
this.error = logger.error.bind(logger, "[error]:");
|
5443
|
-
this.registerListeners();
|
5484
|
+
var _this;
|
5485
|
+
_this = _Logger.call(this, 'error-controller', hls.logger) || this;
|
5486
|
+
_this.hls = void 0;
|
5487
|
+
_this.playlistError = 0;
|
5488
|
+
_this.penalizedRenditions = {};
|
5489
|
+
_this.hls = hls;
|
5490
|
+
_this.registerListeners();
|
5491
|
+
return _this;
|
5444
5492
|
}
|
5445
5493
|
var _proto = ErrorController.prototype;
|
5446
5494
|
_proto.registerListeners = function registerListeners() {
|
@@ -5796,19 +5844,19 @@
|
|
5796
5844
|
}
|
5797
5845
|
};
|
5798
5846
|
return ErrorController;
|
5799
|
-
}();
|
5847
|
+
}(Logger);
|
5800
5848
|
|
5801
|
-
var BasePlaylistController = /*#__PURE__*/function () {
|
5849
|
+
var BasePlaylistController = /*#__PURE__*/function (_Logger) {
|
5850
|
+
_inheritsLoose(BasePlaylistController, _Logger);
|
5802
5851
|
function BasePlaylistController(hls, logPrefix) {
|
5803
|
-
|
5804
|
-
this.
|
5805
|
-
|
5806
|
-
|
5807
|
-
|
5808
|
-
|
5809
|
-
|
5810
|
-
|
5811
|
-
this.hls = hls;
|
5852
|
+
var _this;
|
5853
|
+
_this = _Logger.call(this, logPrefix, hls.logger) || this;
|
5854
|
+
_this.hls = void 0;
|
5855
|
+
_this.timer = -1;
|
5856
|
+
_this.requestScheduled = -1;
|
5857
|
+
_this.canLoad = false;
|
5858
|
+
_this.hls = hls;
|
5859
|
+
return _this;
|
5812
5860
|
}
|
5813
5861
|
var _proto = BasePlaylistController.prototype;
|
5814
5862
|
_proto.destroy = function destroy() {
|
@@ -5841,7 +5889,7 @@
|
|
5841
5889
|
try {
|
5842
5890
|
uri = new self.URL(attr.URI, previous.url).href;
|
5843
5891
|
} catch (error) {
|
5844
|
-
|
5892
|
+
this.warn("Could not construct new URL for Rendition Report: " + error);
|
5845
5893
|
uri = attr.URI || '';
|
5846
5894
|
}
|
5847
5895
|
// Use exact match. Otherwise, the last partial match, if any, will be used
|
@@ -5880,7 +5928,7 @@
|
|
5880
5928
|
return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
|
5881
5929
|
};
|
5882
5930
|
_proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
|
5883
|
-
var
|
5931
|
+
var _this2 = this;
|
5884
5932
|
var details = data.details,
|
5885
5933
|
stats = data.stats;
|
5886
5934
|
|
@@ -5985,7 +6033,7 @@
|
|
5985
6033
|
// );
|
5986
6034
|
|
5987
6035
|
this.timer = self.setTimeout(function () {
|
5988
|
-
return
|
6036
|
+
return _this2.loadPlaylist(deliveryDirectives);
|
5989
6037
|
}, estimatedTimeUntilUpdate);
|
5990
6038
|
} else {
|
5991
6039
|
this.clearTimer();
|
@@ -6001,7 +6049,7 @@
|
|
6001
6049
|
return new HlsUrlParameters(msn, part, skip);
|
6002
6050
|
};
|
6003
6051
|
_proto.checkRetry = function checkRetry(errorEvent) {
|
6004
|
-
var
|
6052
|
+
var _this3 = this;
|
6005
6053
|
var errorDetails = errorEvent.details;
|
6006
6054
|
var isTimeout = isTimeoutError(errorEvent);
|
6007
6055
|
var errorAction = errorEvent.errorAction;
|
@@ -6025,7 +6073,7 @@
|
|
6025
6073
|
var delay = getRetryDelay(retryConfig, retryCount);
|
6026
6074
|
// Schedule level/track reload
|
6027
6075
|
this.timer = self.setTimeout(function () {
|
6028
|
-
return
|
6076
|
+
return _this3.loadPlaylist();
|
6029
6077
|
}, delay);
|
6030
6078
|
this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
|
6031
6079
|
}
|
@@ -6036,7 +6084,7 @@
|
|
6036
6084
|
return retry;
|
6037
6085
|
};
|
6038
6086
|
return BasePlaylistController;
|
6039
|
-
}();
|
6087
|
+
}(Logger);
|
6040
6088
|
|
6041
6089
|
/*
|
6042
6090
|
* compute an Exponential Weighted moving average
|
@@ -6410,30 +6458,33 @@
|
|
6410
6458
|
}, {});
|
6411
6459
|
}
|
6412
6460
|
|
6413
|
-
var AbrController = /*#__PURE__*/function () {
|
6461
|
+
var AbrController = /*#__PURE__*/function (_Logger) {
|
6462
|
+
_inheritsLoose(AbrController, _Logger);
|
6414
6463
|
function AbrController(_hls) {
|
6415
|
-
var _this
|
6416
|
-
this.
|
6417
|
-
|
6418
|
-
|
6419
|
-
|
6420
|
-
|
6421
|
-
|
6422
|
-
|
6423
|
-
|
6424
|
-
|
6425
|
-
|
6426
|
-
|
6427
|
-
|
6428
|
-
|
6464
|
+
var _this;
|
6465
|
+
_this = _Logger.call(this, 'abr', _hls.logger) || this;
|
6466
|
+
_this.hls = void 0;
|
6467
|
+
_this.lastLevelLoadSec = 0;
|
6468
|
+
_this.lastLoadedFragLevel = -1;
|
6469
|
+
_this.firstSelection = -1;
|
6470
|
+
_this._nextAutoLevel = -1;
|
6471
|
+
_this.nextAutoLevelKey = '';
|
6472
|
+
_this.audioTracksByGroup = null;
|
6473
|
+
_this.codecTiers = null;
|
6474
|
+
_this.timer = -1;
|
6475
|
+
_this.fragCurrent = null;
|
6476
|
+
_this.partCurrent = null;
|
6477
|
+
_this.bitrateTestDelay = 0;
|
6478
|
+
_this.bwEstimator = void 0;
|
6429
6479
|
/*
|
6430
6480
|
This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
|
6431
6481
|
quickly enough to prevent underbuffering
|
6432
6482
|
*/
|
6433
|
-
|
6434
|
-
var
|
6435
|
-
|
6436
|
-
|
6483
|
+
_this._abandonRulesCheck = function () {
|
6484
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
6485
|
+
frag = _assertThisInitialize.fragCurrent,
|
6486
|
+
part = _assertThisInitialize.partCurrent,
|
6487
|
+
hls = _assertThisInitialize.hls;
|
6437
6488
|
var autoLevelEnabled = hls.autoLevelEnabled,
|
6438
6489
|
media = hls.media;
|
6439
6490
|
if (!frag || !media) {
|
@@ -6522,21 +6573,22 @@
|
|
6522
6573
|
_this.resetEstimator(nextLoadLevelBitrate);
|
6523
6574
|
}
|
6524
6575
|
_this.clearTimer();
|
6525
|
-
|
6576
|
+
_this.warn("Fragment " + frag.sn + (part ? ' part ' + part.index : '') + " of level " + frag.level + " is loading too slowly;\n Time to underbuffer: " + bufferStarvationDelay.toFixed(3) + " s\n Estimated load time for current fragment: " + fragLoadedDelay.toFixed(3) + " s\n Estimated load time for down switch fragment: " + fragLevelNextLoadedDelay.toFixed(3) + " s\n TTFB estimate: " + (ttfb | 0) + " ms\n Current BW estimate: " + (isFiniteNumber(bwEstimate) ? bwEstimate | 0 : 'Unknown') + " bps\n New BW estimate: " + (_this.getBwEstimate() | 0) + " bps\n Switching to level " + nextLoadLevel + " @ " + (nextLoadLevelBitrate | 0) + " bps");
|
6526
6577
|
hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
|
6527
6578
|
frag: frag,
|
6528
6579
|
part: part,
|
6529
6580
|
stats: stats
|
6530
6581
|
});
|
6531
6582
|
};
|
6532
|
-
|
6533
|
-
|
6534
|
-
|
6583
|
+
_this.hls = _hls;
|
6584
|
+
_this.bwEstimator = _this.initEstimator();
|
6585
|
+
_this.registerListeners();
|
6586
|
+
return _this;
|
6535
6587
|
}
|
6536
6588
|
var _proto = AbrController.prototype;
|
6537
6589
|
_proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
|
6538
6590
|
if (abrEwmaDefaultEstimate) {
|
6539
|
-
|
6591
|
+
this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
|
6540
6592
|
this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
|
6541
6593
|
}
|
6542
6594
|
this.firstSelection = -1;
|
@@ -6788,13 +6840,13 @@
|
|
6788
6840
|
// cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
|
6789
6841
|
var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
|
6790
6842
|
maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
|
6791
|
-
|
6843
|
+
this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
|
6792
6844
|
// don't use conservative factor on bitrate test
|
6793
6845
|
bwFactor = bwUpFactor = 1;
|
6794
6846
|
}
|
6795
6847
|
}
|
6796
6848
|
var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
|
6797
|
-
|
6849
|
+
this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
|
6798
6850
|
if (bestLevel > -1) {
|
6799
6851
|
return bestLevel;
|
6800
6852
|
}
|
@@ -6850,7 +6902,7 @@
|
|
6850
6902
|
currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
|
6851
6903
|
currentFrameRate = minFramerate;
|
6852
6904
|
currentBw = Math.max(currentBw, minBitrate);
|
6853
|
-
|
6905
|
+
this.log("picked start tier " + JSON.stringify(startTier));
|
6854
6906
|
} else {
|
6855
6907
|
currentCodecSet = level == null ? void 0 : level.codecSet;
|
6856
6908
|
currentVideoRange = level == null ? void 0 : level.videoRange;
|
@@ -6903,9 +6955,9 @@
|
|
6903
6955
|
var forcedAutoLevel = _this2.forcedAutoLevel;
|
6904
6956
|
if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
|
6905
6957
|
if (levelsSkipped.length) {
|
6906
|
-
|
6958
|
+
_this2.trace("Skipped level(s) " + levelsSkipped.join(',') + " of " + maxAutoLevel + " max with CODECS and VIDEO-RANGE:\"" + levels[levelsSkipped[0]].codecs + "\" " + levels[levelsSkipped[0]].videoRange + "; not compatible with \"" + level.codecs + "\" " + currentVideoRange);
|
6907
6959
|
}
|
6908
|
-
|
6960
|
+
_this2.info("switch candidate:" + selectionBaseLevel + "->" + i + " adjustedbw(" + Math.round(adjustedbw) + ")-bitrate=" + Math.round(adjustedbw - bitrate) + " ttfb:" + ttfbEstimateSec.toFixed(1) + " avgDuration:" + avgDuration.toFixed(1) + " maxFetchDuration:" + maxFetchDuration.toFixed(1) + " fetchDuration:" + fetchDuration.toFixed(1) + " firstSelection:" + firstSelection + " codecSet:" + currentCodecSet + " videoRange:" + currentVideoRange + " hls.loadLevel:" + loadLevel);
|
6909
6961
|
}
|
6910
6962
|
if (firstSelection) {
|
6911
6963
|
_this2.firstSelection = i;
|
@@ -6939,7 +6991,7 @@
|
|
6939
6991
|
}
|
6940
6992
|
var firstLevel = this.hls.firstLevel;
|
6941
6993
|
var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
|
6942
|
-
|
6994
|
+
this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
|
6943
6995
|
return clamped;
|
6944
6996
|
}
|
6945
6997
|
}, {
|
@@ -6981,15 +7033,18 @@
|
|
6981
7033
|
return nextABRAutoLevel;
|
6982
7034
|
},
|
6983
7035
|
set: function set(nextLevel) {
|
6984
|
-
var
|
6985
|
-
|
7036
|
+
var _this$hls3 = this.hls,
|
7037
|
+
maxAutoLevel = _this$hls3.maxAutoLevel,
|
7038
|
+
minAutoLevel = _this$hls3.minAutoLevel;
|
7039
|
+
var value = Math.min(Math.max(nextLevel, minAutoLevel), maxAutoLevel);
|
7040
|
+
if (this._nextAutoLevel !== value) {
|
6986
7041
|
this.nextAutoLevelKey = '';
|
6987
7042
|
this._nextAutoLevel = value;
|
6988
7043
|
}
|
6989
7044
|
}
|
6990
7045
|
}]);
|
6991
7046
|
return AbrController;
|
6992
|
-
}();
|
7047
|
+
}(Logger);
|
6993
7048
|
|
6994
7049
|
/**
|
6995
7050
|
* Provides methods dealing with buffer length retrieval for example.
|
@@ -7210,57 +7265,57 @@
|
|
7210
7265
|
}();
|
7211
7266
|
|
7212
7267
|
var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
|
7213
|
-
var BufferController = /*#__PURE__*/function () {
|
7268
|
+
var BufferController = /*#__PURE__*/function (_Logger) {
|
7269
|
+
_inheritsLoose(BufferController, _Logger);
|
7214
7270
|
function BufferController(hls) {
|
7215
|
-
var _this
|
7271
|
+
var _this;
|
7272
|
+
_this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
|
7216
7273
|
// The level details used to determine duration, target-duration and live
|
7217
|
-
|
7274
|
+
_this.details = null;
|
7218
7275
|
// cache the self generated object url to detect hijack of video tag
|
7219
|
-
|
7276
|
+
_this._objectUrl = null;
|
7220
7277
|
// A queue of buffer operations which require the SourceBuffer to not be updating upon execution
|
7221
|
-
|
7278
|
+
_this.operationQueue = void 0;
|
7222
7279
|
// References to event listeners for each SourceBuffer, so that they can be referenced for event removal
|
7223
|
-
|
7224
|
-
|
7280
|
+
_this.listeners = void 0;
|
7281
|
+
_this.hls = void 0;
|
7225
7282
|
// The number of BUFFER_CODEC events received before any sourceBuffers are created
|
7226
|
-
|
7283
|
+
_this.bufferCodecEventsExpected = 0;
|
7227
7284
|
// The total number of BUFFER_CODEC events received
|
7228
|
-
|
7285
|
+
_this._bufferCodecEventsTotal = 0;
|
7229
7286
|
// A reference to the attached media element
|
7230
|
-
|
7287
|
+
_this.media = null;
|
7231
7288
|
// A reference to the active media source
|
7232
|
-
|
7289
|
+
_this.mediaSource = null;
|
7233
7290
|
// Last MP3 audio chunk appended
|
7234
|
-
|
7235
|
-
|
7291
|
+
_this.lastMpegAudioChunk = null;
|
7292
|
+
_this.appendSource = void 0;
|
7236
7293
|
// counters
|
7237
|
-
|
7294
|
+
_this.appendErrors = {
|
7238
7295
|
audio: 0,
|
7239
7296
|
video: 0,
|
7240
7297
|
audiovideo: 0
|
7241
7298
|
};
|
7242
|
-
|
7243
|
-
|
7244
|
-
|
7245
|
-
|
7246
|
-
this.warn = void 0;
|
7247
|
-
this.error = void 0;
|
7248
|
-
this._onEndStreaming = function (event) {
|
7299
|
+
_this.tracks = {};
|
7300
|
+
_this.pendingTracks = {};
|
7301
|
+
_this.sourceBuffer = void 0;
|
7302
|
+
_this._onEndStreaming = function (event) {
|
7249
7303
|
if (!_this.hls) {
|
7250
7304
|
return;
|
7251
7305
|
}
|
7252
7306
|
_this.hls.pauseBuffering();
|
7253
7307
|
};
|
7254
|
-
|
7308
|
+
_this._onStartStreaming = function (event) {
|
7255
7309
|
if (!_this.hls) {
|
7256
7310
|
return;
|
7257
7311
|
}
|
7258
7312
|
_this.hls.resumeBuffering();
|
7259
7313
|
};
|
7260
7314
|
// Keep as arrow functions so that we can directly reference these functions directly as event listeners
|
7261
|
-
|
7262
|
-
var
|
7263
|
-
|
7315
|
+
_this._onMediaSourceOpen = function () {
|
7316
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
7317
|
+
media = _assertThisInitialize.media,
|
7318
|
+
mediaSource = _assertThisInitialize.mediaSource;
|
7264
7319
|
_this.log('Media source opened');
|
7265
7320
|
if (media) {
|
7266
7321
|
media.removeEventListener('emptied', _this._onMediaEmptied);
|
@@ -7276,27 +7331,25 @@
|
|
7276
7331
|
}
|
7277
7332
|
_this.checkPendingTracks();
|
7278
7333
|
};
|
7279
|
-
|
7334
|
+
_this._onMediaSourceClose = function () {
|
7280
7335
|
_this.log('Media source closed');
|
7281
7336
|
};
|
7282
|
-
|
7337
|
+
_this._onMediaSourceEnded = function () {
|
7283
7338
|
_this.log('Media source ended');
|
7284
7339
|
};
|
7285
|
-
|
7286
|
-
var
|
7287
|
-
|
7340
|
+
_this._onMediaEmptied = function () {
|
7341
|
+
var _assertThisInitialize2 = _assertThisInitialized(_this),
|
7342
|
+
mediaSrc = _assertThisInitialize2.mediaSrc,
|
7343
|
+
_objectUrl = _assertThisInitialize2._objectUrl;
|
7288
7344
|
if (mediaSrc !== _objectUrl) {
|
7289
|
-
|
7345
|
+
_this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
|
7290
7346
|
}
|
7291
7347
|
};
|
7292
|
-
|
7293
|
-
|
7294
|
-
|
7295
|
-
|
7296
|
-
|
7297
|
-
this.error = logger.error.bind(logger, logPrefix);
|
7298
|
-
this._initSourceBuffer();
|
7299
|
-
this.registerListeners();
|
7348
|
+
_this.hls = hls;
|
7349
|
+
_this.appendSource = hls.config.preferManagedMediaSource;
|
7350
|
+
_this._initSourceBuffer();
|
7351
|
+
_this.registerListeners();
|
7352
|
+
return _this;
|
7300
7353
|
}
|
7301
7354
|
var _proto = BufferController.prototype;
|
7302
7355
|
_proto.hasSourceTypes = function hasSourceTypes() {
|
@@ -7308,6 +7361,12 @@
|
|
7308
7361
|
this.lastMpegAudioChunk = null;
|
7309
7362
|
// @ts-ignore
|
7310
7363
|
this.hls = null;
|
7364
|
+
// @ts-ignore
|
7365
|
+
this._onMediaSourceOpen = this._onMediaSourceClose = null;
|
7366
|
+
// @ts-ignore
|
7367
|
+
this._onMediaSourceEnded = null;
|
7368
|
+
// @ts-ignore
|
7369
|
+
this._onStartStreaming = this._onEndStreaming = null;
|
7311
7370
|
};
|
7312
7371
|
_proto.registerListeners = function registerListeners() {
|
7313
7372
|
var hls = this.hls;
|
@@ -7465,6 +7524,7 @@
|
|
7465
7524
|
_this2.resetBuffer(type);
|
7466
7525
|
});
|
7467
7526
|
this._initSourceBuffer();
|
7527
|
+
this.hls.resumeBuffering();
|
7468
7528
|
};
|
7469
7529
|
_proto.resetBuffer = function resetBuffer(type) {
|
7470
7530
|
var sb = this.sourceBuffer[type];
|
@@ -8168,7 +8228,7 @@
|
|
8168
8228
|
}
|
8169
8229
|
}]);
|
8170
8230
|
return BufferController;
|
8171
|
-
}();
|
8231
|
+
}(Logger);
|
8172
8232
|
function removeSourceChildren(node) {
|
8173
8233
|
var sourceChildren = node.querySelectorAll('source');
|
8174
8234
|
[].slice.call(sourceChildren).forEach(function (source) {
|
@@ -8292,7 +8352,7 @@
|
|
8292
8352
|
var hls = this.hls;
|
8293
8353
|
var maxLevel = this.getMaxLevel(levels.length - 1);
|
8294
8354
|
if (maxLevel !== this.autoLevelCapping) {
|
8295
|
-
logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8355
|
+
hls.logger.log("Setting autoLevelCapping to " + maxLevel + ": " + levels[maxLevel].height + "p@" + levels[maxLevel].bitrate + " for media " + this.mediaWidth + "x" + this.mediaHeight);
|
8296
8356
|
}
|
8297
8357
|
hls.autoLevelCapping = maxLevel;
|
8298
8358
|
if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
|
@@ -8482,10 +8542,10 @@
|
|
8482
8542
|
totalDroppedFrames: droppedFrames
|
8483
8543
|
});
|
8484
8544
|
if (droppedFPS > 0) {
|
8485
|
-
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8545
|
+
// hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8486
8546
|
if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
|
8487
8547
|
var currentLevel = hls.currentLevel;
|
8488
|
-
logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8548
|
+
hls.logger.warn('drop FPS ratio greater than max allowed value for currentLevel: ' + currentLevel);
|
8489
8549
|
if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
|
8490
8550
|
currentLevel = currentLevel - 1;
|
8491
8551
|
hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
|
@@ -8519,26 +8579,28 @@
|
|
8519
8579
|
}();
|
8520
8580
|
|
8521
8581
|
var PATHWAY_PENALTY_DURATION_MS = 300000;
|
8522
|
-
var ContentSteeringController = /*#__PURE__*/function () {
|
8582
|
+
var ContentSteeringController = /*#__PURE__*/function (_Logger) {
|
8583
|
+
_inheritsLoose(ContentSteeringController, _Logger);
|
8523
8584
|
function ContentSteeringController(hls) {
|
8524
|
-
|
8525
|
-
this.
|
8526
|
-
|
8527
|
-
|
8528
|
-
|
8529
|
-
|
8530
|
-
|
8531
|
-
|
8532
|
-
|
8533
|
-
|
8534
|
-
|
8535
|
-
|
8536
|
-
|
8537
|
-
|
8538
|
-
|
8539
|
-
|
8540
|
-
|
8541
|
-
|
8585
|
+
var _this;
|
8586
|
+
_this = _Logger.call(this, 'content-steering', hls.logger) || this;
|
8587
|
+
_this.hls = void 0;
|
8588
|
+
_this.loader = null;
|
8589
|
+
_this.uri = null;
|
8590
|
+
_this.pathwayId = '.';
|
8591
|
+
_this.pathwayPriority = null;
|
8592
|
+
_this.timeToLoad = 300;
|
8593
|
+
_this.reloadTimer = -1;
|
8594
|
+
_this.updated = 0;
|
8595
|
+
_this.started = false;
|
8596
|
+
_this.enabled = true;
|
8597
|
+
_this.levels = null;
|
8598
|
+
_this.audioTracks = null;
|
8599
|
+
_this.subtitleTracks = null;
|
8600
|
+
_this.penalizedPathways = {};
|
8601
|
+
_this.hls = hls;
|
8602
|
+
_this.registerListeners();
|
8603
|
+
return _this;
|
8542
8604
|
}
|
8543
8605
|
var _proto = ContentSteeringController.prototype;
|
8544
8606
|
_proto.registerListeners = function registerListeners() {
|
@@ -8659,7 +8721,7 @@
|
|
8659
8721
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
8660
8722
|
}
|
8661
8723
|
if (!errorAction.resolved) {
|
8662
|
-
|
8724
|
+
this.warn("Could not resolve " + data.details + " (\"" + data.error.message + "\") with content-steering for Pathway: " + errorPathway + " levels: " + (levels ? levels.length : levels) + " priorities: " + JSON.stringify(pathwayPriority) + " penalized: " + JSON.stringify(this.penalizedPathways));
|
8663
8725
|
}
|
8664
8726
|
}
|
8665
8727
|
};
|
@@ -8739,7 +8801,7 @@
|
|
8739
8801
|
return defaultPathway;
|
8740
8802
|
};
|
8741
8803
|
_proto.clonePathways = function clonePathways(pathwayClones) {
|
8742
|
-
var
|
8804
|
+
var _this2 = this;
|
8743
8805
|
var levels = this.levels;
|
8744
8806
|
if (!levels) {
|
8745
8807
|
return;
|
@@ -8755,7 +8817,7 @@
|
|
8755
8817
|
})) {
|
8756
8818
|
return;
|
8757
8819
|
}
|
8758
|
-
var clonedVariants =
|
8820
|
+
var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
|
8759
8821
|
var attributes = new AttrList(baseLevel.attrs);
|
8760
8822
|
attributes['PATHWAY-ID'] = cloneId;
|
8761
8823
|
var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
|
@@ -8792,12 +8854,12 @@
|
|
8792
8854
|
return clonedLevel;
|
8793
8855
|
});
|
8794
8856
|
levels.push.apply(levels, clonedVariants);
|
8795
|
-
cloneRenditionGroups(
|
8796
|
-
cloneRenditionGroups(
|
8857
|
+
cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
|
8858
|
+
cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
|
8797
8859
|
});
|
8798
8860
|
};
|
8799
8861
|
_proto.loadSteeringManifest = function loadSteeringManifest(uri) {
|
8800
|
-
var
|
8862
|
+
var _this3 = this;
|
8801
8863
|
var config = this.hls.config;
|
8802
8864
|
var Loader = config.loader;
|
8803
8865
|
if (this.loader) {
|
@@ -8832,87 +8894,87 @@
|
|
8832
8894
|
};
|
8833
8895
|
var callbacks = {
|
8834
8896
|
onSuccess: function onSuccess(response, stats, context, networkDetails) {
|
8835
|
-
|
8897
|
+
_this3.log("Loaded steering manifest: \"" + url + "\"");
|
8836
8898
|
var steeringData = response.data;
|
8837
|
-
if (steeringData.VERSION !== 1) {
|
8838
|
-
|
8899
|
+
if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
|
8900
|
+
_this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
|
8839
8901
|
return;
|
8840
8902
|
}
|
8841
|
-
|
8842
|
-
|
8903
|
+
_this3.updated = performance.now();
|
8904
|
+
_this3.timeToLoad = steeringData.TTL;
|
8843
8905
|
var reloadUri = steeringData['RELOAD-URI'],
|
8844
8906
|
pathwayClones = steeringData['PATHWAY-CLONES'],
|
8845
8907
|
pathwayPriority = steeringData['PATHWAY-PRIORITY'];
|
8846
8908
|
if (reloadUri) {
|
8847
8909
|
try {
|
8848
|
-
|
8910
|
+
_this3.uri = new self.URL(reloadUri, url).href;
|
8849
8911
|
} catch (error) {
|
8850
|
-
|
8851
|
-
|
8912
|
+
_this3.enabled = false;
|
8913
|
+
_this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
|
8852
8914
|
return;
|
8853
8915
|
}
|
8854
8916
|
}
|
8855
|
-
|
8917
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8856
8918
|
if (pathwayClones) {
|
8857
|
-
|
8919
|
+
_this3.clonePathways(pathwayClones);
|
8858
8920
|
}
|
8859
8921
|
var loadedSteeringData = {
|
8860
8922
|
steeringManifest: steeringData,
|
8861
8923
|
url: url.toString()
|
8862
8924
|
};
|
8863
|
-
|
8925
|
+
_this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
|
8864
8926
|
if (pathwayPriority) {
|
8865
|
-
|
8927
|
+
_this3.updatePathwayPriority(pathwayPriority);
|
8866
8928
|
}
|
8867
8929
|
},
|
8868
8930
|
onError: function onError(error, context, networkDetails, stats) {
|
8869
|
-
|
8870
|
-
|
8931
|
+
_this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
|
8932
|
+
_this3.stopLoad();
|
8871
8933
|
if (error.code === 410) {
|
8872
|
-
|
8873
|
-
|
8934
|
+
_this3.enabled = false;
|
8935
|
+
_this3.log("Steering manifest " + context.url + " no longer available");
|
8874
8936
|
return;
|
8875
8937
|
}
|
8876
|
-
var ttl =
|
8938
|
+
var ttl = _this3.timeToLoad * 1000;
|
8877
8939
|
if (error.code === 429) {
|
8878
|
-
var loader =
|
8940
|
+
var loader = _this3.loader;
|
8879
8941
|
if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
|
8880
8942
|
var retryAfter = loader.getResponseHeader('Retry-After');
|
8881
8943
|
if (retryAfter) {
|
8882
8944
|
ttl = parseFloat(retryAfter) * 1000;
|
8883
8945
|
}
|
8884
8946
|
}
|
8885
|
-
|
8947
|
+
_this3.log("Steering manifest " + context.url + " rate limited");
|
8886
8948
|
return;
|
8887
8949
|
}
|
8888
|
-
|
8950
|
+
_this3.scheduleRefresh(_this3.uri || context.url, ttl);
|
8889
8951
|
},
|
8890
8952
|
onTimeout: function onTimeout(stats, context, networkDetails) {
|
8891
|
-
|
8892
|
-
|
8953
|
+
_this3.log("Timeout loading steering manifest (" + context.url + ")");
|
8954
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8893
8955
|
}
|
8894
8956
|
};
|
8895
8957
|
this.log("Requesting steering manifest: " + url);
|
8896
8958
|
this.loader.load(context, loaderConfig, callbacks);
|
8897
8959
|
};
|
8898
8960
|
_proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
|
8899
|
-
var
|
8961
|
+
var _this4 = this;
|
8900
8962
|
if (ttlMs === void 0) {
|
8901
8963
|
ttlMs = this.timeToLoad * 1000;
|
8902
8964
|
}
|
8903
8965
|
this.clearTimeout();
|
8904
8966
|
this.reloadTimer = self.setTimeout(function () {
|
8905
|
-
var
|
8906
|
-
var media = (
|
8967
|
+
var _this4$hls;
|
8968
|
+
var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
|
8907
8969
|
if (media && !media.ended) {
|
8908
|
-
|
8970
|
+
_this4.loadSteeringManifest(uri);
|
8909
8971
|
return;
|
8910
8972
|
}
|
8911
|
-
|
8973
|
+
_this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
|
8912
8974
|
}, ttlMs);
|
8913
8975
|
};
|
8914
8976
|
return ContentSteeringController;
|
8915
|
-
}();
|
8977
|
+
}(Logger);
|
8916
8978
|
function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
|
8917
8979
|
if (!tracks) {
|
8918
8980
|
return;
|
@@ -9779,7 +9841,7 @@
|
|
9779
9841
|
/**
|
9780
9842
|
* @ignore
|
9781
9843
|
*/
|
9782
|
-
function mergeConfig(defaultConfig, userConfig) {
|
9844
|
+
function mergeConfig(defaultConfig, userConfig, logger) {
|
9783
9845
|
if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
|
9784
9846
|
throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
|
9785
9847
|
}
|
@@ -9849,7 +9911,7 @@
|
|
9849
9911
|
/**
|
9850
9912
|
* @ignore
|
9851
9913
|
*/
|
9852
|
-
function enableStreamingMode(config) {
|
9914
|
+
function enableStreamingMode(config, logger) {
|
9853
9915
|
var currentLoader = config.loader;
|
9854
9916
|
if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
|
9855
9917
|
// If a developer has configured their own loader, respect that choice
|
@@ -9866,12 +9928,11 @@
|
|
9866
9928
|
}
|
9867
9929
|
}
|
9868
9930
|
|
9869
|
-
var chromeOrFirefox;
|
9870
9931
|
var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
|
9871
9932
|
_inheritsLoose(LevelController, _BasePlaylistControll);
|
9872
9933
|
function LevelController(hls, contentSteeringController) {
|
9873
9934
|
var _this;
|
9874
|
-
_this = _BasePlaylistControll.call(this, hls, '
|
9935
|
+
_this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
|
9875
9936
|
_this._levels = [];
|
9876
9937
|
_this._firstLevel = -1;
|
9877
9938
|
_this._maxAutoLevel = -1;
|
@@ -9940,21 +10001,13 @@
|
|
9940
10001
|
var videoCodecFound = false;
|
9941
10002
|
var audioCodecFound = false;
|
9942
10003
|
data.levels.forEach(function (levelParsed) {
|
9943
|
-
var
|
10004
|
+
var _videoCodec;
|
9944
10005
|
var attributes = levelParsed.attrs;
|
9945
|
-
|
9946
|
-
// erase audio codec info if browser does not support mp4a.40.34.
|
9947
|
-
// demuxer will autodetect codec and fallback to mpeg/audio
|
9948
10006
|
var audioCodec = levelParsed.audioCodec,
|
9949
10007
|
videoCodec = levelParsed.videoCodec;
|
9950
|
-
if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
|
9951
|
-
chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
|
9952
|
-
if (chromeOrFirefox) {
|
9953
|
-
levelParsed.audioCodec = audioCodec = undefined;
|
9954
|
-
}
|
9955
|
-
}
|
9956
10008
|
if (audioCodec) {
|
9957
|
-
|
10009
|
+
// Returns empty and set to undefined for 'mp4a.40.34' with fallback to 'audio/mpeg' SourceBuffer
|
10010
|
+
levelParsed.audioCodec = audioCodec = getCodecCompatibleName(audioCodec, preferManagedMediaSource) || undefined;
|
9958
10011
|
}
|
9959
10012
|
if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
|
9960
10013
|
videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
|
@@ -11101,8 +11154,8 @@
|
|
11101
11154
|
var _frag$decryptdata;
|
11102
11155
|
var byteRangeStart = start;
|
11103
11156
|
var byteRangeEnd = end;
|
11104
|
-
if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)
|
11105
|
-
// MAP segment encrypted with method 'AES-128', when served with HTTP Range,
|
11157
|
+
if (frag.sn === 'initSegment' && isMethodFullSegmentAesCbc((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)) {
|
11158
|
+
// MAP segment encrypted with method 'AES-128' or 'AES-256' (cbc), when served with HTTP Range,
|
11106
11159
|
// has the unencrypted size specified in the range.
|
11107
11160
|
// Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
11108
11161
|
var fragmentLen = end - start;
|
@@ -11135,6 +11188,9 @@
|
|
11135
11188
|
(part ? part : frag).stats.aborted = true;
|
11136
11189
|
return new LoadError(errorData);
|
11137
11190
|
}
|
11191
|
+
function isMethodFullSegmentAesCbc(method) {
|
11192
|
+
return method === 'AES-128' || method === 'AES-256';
|
11193
|
+
}
|
11138
11194
|
var LoadError = /*#__PURE__*/function (_Error) {
|
11139
11195
|
_inheritsLoose(LoadError, _Error);
|
11140
11196
|
function LoadError(data) {
|
@@ -11291,6 +11347,8 @@
|
|
11291
11347
|
}
|
11292
11348
|
return this.loadKeyEME(keyInfo, frag);
|
11293
11349
|
case 'AES-128':
|
11350
|
+
case 'AES-256':
|
11351
|
+
case 'AES-256-CTR':
|
11294
11352
|
return this.loadKeyHTTP(keyInfo, frag);
|
11295
11353
|
default:
|
11296
11354
|
return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
|
@@ -11424,13 +11482,17 @@
|
|
11424
11482
|
* we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
|
11425
11483
|
* task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
|
11426
11484
|
*/
|
11427
|
-
var TaskLoop = /*#__PURE__*/function () {
|
11428
|
-
|
11429
|
-
|
11430
|
-
|
11431
|
-
|
11432
|
-
|
11433
|
-
|
11485
|
+
var TaskLoop = /*#__PURE__*/function (_Logger) {
|
11486
|
+
_inheritsLoose(TaskLoop, _Logger);
|
11487
|
+
function TaskLoop(label, logger) {
|
11488
|
+
var _this;
|
11489
|
+
_this = _Logger.call(this, label, logger) || this;
|
11490
|
+
_this._boundTick = void 0;
|
11491
|
+
_this._tickTimer = null;
|
11492
|
+
_this._tickInterval = null;
|
11493
|
+
_this._tickCallCount = 0;
|
11494
|
+
_this._boundTick = _this.tick.bind(_assertThisInitialized(_this));
|
11495
|
+
return _this;
|
11434
11496
|
}
|
11435
11497
|
var _proto = TaskLoop.prototype;
|
11436
11498
|
_proto.destroy = function destroy() {
|
@@ -11516,7 +11578,7 @@
|
|
11516
11578
|
*/;
|
11517
11579
|
_proto.doTick = function doTick() {};
|
11518
11580
|
return TaskLoop;
|
11519
|
-
}();
|
11581
|
+
}(Logger);
|
11520
11582
|
|
11521
11583
|
var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
|
11522
11584
|
if (size === void 0) {
|
@@ -11702,37 +11764,65 @@
|
|
11702
11764
|
}
|
11703
11765
|
|
11704
11766
|
var AESCrypto = /*#__PURE__*/function () {
|
11705
|
-
function AESCrypto(subtle, iv) {
|
11767
|
+
function AESCrypto(subtle, iv, aesMode) {
|
11706
11768
|
this.subtle = void 0;
|
11707
11769
|
this.aesIV = void 0;
|
11770
|
+
this.aesMode = void 0;
|
11708
11771
|
this.subtle = subtle;
|
11709
11772
|
this.aesIV = iv;
|
11773
|
+
this.aesMode = aesMode;
|
11710
11774
|
}
|
11711
11775
|
var _proto = AESCrypto.prototype;
|
11712
11776
|
_proto.decrypt = function decrypt(data, key) {
|
11713
|
-
|
11714
|
-
|
11715
|
-
|
11716
|
-
|
11777
|
+
switch (this.aesMode) {
|
11778
|
+
case DecrypterAesMode.cbc:
|
11779
|
+
return this.subtle.decrypt({
|
11780
|
+
name: 'AES-CBC',
|
11781
|
+
iv: this.aesIV
|
11782
|
+
}, key, data);
|
11783
|
+
case DecrypterAesMode.ctr:
|
11784
|
+
return this.subtle.decrypt({
|
11785
|
+
name: 'AES-CTR',
|
11786
|
+
counter: this.aesIV,
|
11787
|
+
length: 64
|
11788
|
+
},
|
11789
|
+
//64 : NIST SP800-38A standard suggests that the counter should occupy half of the counter block
|
11790
|
+
key, data);
|
11791
|
+
default:
|
11792
|
+
throw new Error("[AESCrypto] invalid aes mode " + this.aesMode);
|
11793
|
+
}
|
11717
11794
|
};
|
11718
11795
|
return AESCrypto;
|
11719
11796
|
}();
|
11720
11797
|
|
11721
11798
|
var FastAESKey = /*#__PURE__*/function () {
|
11722
|
-
function FastAESKey(subtle, key) {
|
11799
|
+
function FastAESKey(subtle, key, aesMode) {
|
11723
11800
|
this.subtle = void 0;
|
11724
11801
|
this.key = void 0;
|
11802
|
+
this.aesMode = void 0;
|
11725
11803
|
this.subtle = subtle;
|
11726
11804
|
this.key = key;
|
11805
|
+
this.aesMode = aesMode;
|
11727
11806
|
}
|
11728
11807
|
var _proto = FastAESKey.prototype;
|
11729
11808
|
_proto.expandKey = function expandKey() {
|
11809
|
+
var subtleAlgoName = getSubtleAlgoName(this.aesMode);
|
11730
11810
|
return this.subtle.importKey('raw', this.key, {
|
11731
|
-
name:
|
11811
|
+
name: subtleAlgoName
|
11732
11812
|
}, false, ['encrypt', 'decrypt']);
|
11733
11813
|
};
|
11734
11814
|
return FastAESKey;
|
11735
11815
|
}();
|
11816
|
+
function getSubtleAlgoName(aesMode) {
|
11817
|
+
switch (aesMode) {
|
11818
|
+
case DecrypterAesMode.cbc:
|
11819
|
+
return 'AES-CBC';
|
11820
|
+
case DecrypterAesMode.ctr:
|
11821
|
+
return 'AES-CTR';
|
11822
|
+
default:
|
11823
|
+
throw new Error("[FastAESKey] invalid aes mode " + aesMode);
|
11824
|
+
}
|
11825
|
+
}
|
11736
11826
|
|
11737
11827
|
// PKCS7
|
11738
11828
|
function removePadding(array) {
|
@@ -11985,7 +12075,8 @@
|
|
11985
12075
|
this.currentIV = null;
|
11986
12076
|
this.currentResult = null;
|
11987
12077
|
this.useSoftware = void 0;
|
11988
|
-
this.
|
12078
|
+
this.enableSoftwareAES = void 0;
|
12079
|
+
this.enableSoftwareAES = config.enableSoftwareAES;
|
11989
12080
|
this.removePKCS7Padding = removePKCS7Padding;
|
11990
12081
|
// built in decryptor expects PKCS7 padding
|
11991
12082
|
if (removePKCS7Padding) {
|
@@ -11998,9 +12089,7 @@
|
|
11998
12089
|
/* no-op */
|
11999
12090
|
}
|
12000
12091
|
}
|
12001
|
-
|
12002
|
-
this.useSoftware = true;
|
12003
|
-
}
|
12092
|
+
this.useSoftware = this.subtle === null;
|
12004
12093
|
}
|
12005
12094
|
var _proto = Decrypter.prototype;
|
12006
12095
|
_proto.destroy = function destroy() {
|
@@ -12037,11 +12126,11 @@
|
|
12037
12126
|
this.softwareDecrypter = null;
|
12038
12127
|
}
|
12039
12128
|
};
|
12040
|
-
_proto.decrypt = function decrypt(data, key, iv) {
|
12129
|
+
_proto.decrypt = function decrypt(data, key, iv, aesMode) {
|
12041
12130
|
var _this = this;
|
12042
12131
|
if (this.useSoftware) {
|
12043
12132
|
return new Promise(function (resolve, reject) {
|
12044
|
-
_this.softwareDecrypt(new Uint8Array(data), key, iv);
|
12133
|
+
_this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12045
12134
|
var decryptResult = _this.flush();
|
12046
12135
|
if (decryptResult) {
|
12047
12136
|
resolve(decryptResult.buffer);
|
@@ -12050,16 +12139,20 @@
|
|
12050
12139
|
}
|
12051
12140
|
});
|
12052
12141
|
}
|
12053
|
-
return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
|
12142
|
+
return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12054
12143
|
}
|
12055
12144
|
|
12056
12145
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
12057
12146
|
// data is handled in the flush() call
|
12058
12147
|
;
|
12059
|
-
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
|
12148
|
+
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
|
12060
12149
|
var currentIV = this.currentIV,
|
12061
12150
|
currentResult = this.currentResult,
|
12062
12151
|
remainderData = this.remainderData;
|
12152
|
+
if (aesMode !== DecrypterAesMode.cbc || key.byteLength !== 16) {
|
12153
|
+
logger.warn('SoftwareDecrypt: can only handle AES-128-CBC');
|
12154
|
+
return null;
|
12155
|
+
}
|
12063
12156
|
this.logOnce('JS AES decrypt');
|
12064
12157
|
// The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
|
12065
12158
|
// This is done in order to strip PKCS7 padding, which is found at the end of each segment. We only know we've reached
|
@@ -12092,12 +12185,12 @@
|
|
12092
12185
|
}
|
12093
12186
|
return result;
|
12094
12187
|
};
|
12095
|
-
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
|
12188
|
+
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
|
12096
12189
|
var _this2 = this;
|
12097
12190
|
var subtle = this.subtle;
|
12098
12191
|
if (this.key !== key || !this.fastAesKey) {
|
12099
12192
|
this.key = key;
|
12100
|
-
this.fastAesKey = new FastAESKey(subtle, key);
|
12193
|
+
this.fastAesKey = new FastAESKey(subtle, key, aesMode);
|
12101
12194
|
}
|
12102
12195
|
return this.fastAesKey.expandKey().then(function (aesKey) {
|
12103
12196
|
// decrypt using web crypto
|
@@ -12105,22 +12198,25 @@
|
|
12105
12198
|
return Promise.reject(new Error('web crypto not initialized'));
|
12106
12199
|
}
|
12107
12200
|
_this2.logOnce('WebCrypto AES decrypt');
|
12108
|
-
var crypto = new AESCrypto(subtle, new Uint8Array(iv));
|
12201
|
+
var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
|
12109
12202
|
return crypto.decrypt(data.buffer, aesKey);
|
12110
12203
|
}).catch(function (err) {
|
12111
12204
|
logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
|
12112
|
-
return _this2.onWebCryptoError(data, key, iv);
|
12205
|
+
return _this2.onWebCryptoError(data, key, iv, aesMode);
|
12113
12206
|
});
|
12114
12207
|
};
|
12115
|
-
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
|
12116
|
-
|
12117
|
-
|
12118
|
-
|
12119
|
-
|
12120
|
-
|
12121
|
-
|
12208
|
+
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv, aesMode) {
|
12209
|
+
var enableSoftwareAES = this.enableSoftwareAES;
|
12210
|
+
if (enableSoftwareAES) {
|
12211
|
+
this.useSoftware = true;
|
12212
|
+
this.logEnabled = true;
|
12213
|
+
this.softwareDecrypt(data, key, iv, aesMode);
|
12214
|
+
var decryptResult = this.flush();
|
12215
|
+
if (decryptResult) {
|
12216
|
+
return decryptResult.buffer;
|
12217
|
+
}
|
12122
12218
|
}
|
12123
|
-
throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
|
12219
|
+
throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
|
12124
12220
|
};
|
12125
12221
|
_proto.getValidChunk = function getValidChunk(data) {
|
12126
12222
|
var currentChunk = data;
|
@@ -12174,7 +12270,7 @@
|
|
12174
12270
|
_inheritsLoose(BaseStreamController, _TaskLoop);
|
12175
12271
|
function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
|
12176
12272
|
var _this;
|
12177
|
-
_this = _TaskLoop.call(this) || this;
|
12273
|
+
_this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
|
12178
12274
|
_this.hls = void 0;
|
12179
12275
|
_this.fragPrevious = null;
|
12180
12276
|
_this.fragCurrent = null;
|
@@ -12199,25 +12295,87 @@
|
|
12199
12295
|
_this.startFragRequested = false;
|
12200
12296
|
_this.decrypter = void 0;
|
12201
12297
|
_this.initPTS = [];
|
12202
|
-
_this.
|
12203
|
-
_this.
|
12204
|
-
|
12205
|
-
|
12206
|
-
|
12298
|
+
_this.buffering = true;
|
12299
|
+
_this.onMediaSeeking = function () {
|
12300
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
12301
|
+
config = _assertThisInitialize.config,
|
12302
|
+
fragCurrent = _assertThisInitialize.fragCurrent,
|
12303
|
+
media = _assertThisInitialize.media,
|
12304
|
+
mediaBuffer = _assertThisInitialize.mediaBuffer,
|
12305
|
+
state = _assertThisInitialize.state;
|
12306
|
+
var currentTime = media ? media.currentTime : 0;
|
12307
|
+
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12308
|
+
_this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12309
|
+
if (_this.state === State.ENDED) {
|
12310
|
+
_this.resetLoadingState();
|
12311
|
+
} else if (fragCurrent) {
|
12312
|
+
// Seeking while frag load is in progress
|
12313
|
+
var tolerance = config.maxFragLookUpTolerance;
|
12314
|
+
var fragStartOffset = fragCurrent.start - tolerance;
|
12315
|
+
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12316
|
+
// if seeking out of buffered range or into new one
|
12317
|
+
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12318
|
+
var pastFragment = currentTime > fragEndOffset;
|
12319
|
+
// if the seek position is outside the current fragment range
|
12320
|
+
if (currentTime < fragStartOffset || pastFragment) {
|
12321
|
+
if (pastFragment && fragCurrent.loader) {
|
12322
|
+
_this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12323
|
+
fragCurrent.abortRequests();
|
12324
|
+
_this.resetLoadingState();
|
12325
|
+
}
|
12326
|
+
_this.fragPrevious = null;
|
12327
|
+
}
|
12328
|
+
}
|
12329
|
+
}
|
12330
|
+
if (media) {
|
12331
|
+
// Remove gap fragments
|
12332
|
+
_this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, _this.playlistType, true);
|
12333
|
+
_this.lastCurrentTime = currentTime;
|
12334
|
+
}
|
12335
|
+
|
12336
|
+
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12337
|
+
if (!_this.loadedmetadata && !bufferInfo.len) {
|
12338
|
+
_this.nextLoadPosition = _this.startPosition = currentTime;
|
12339
|
+
}
|
12340
|
+
|
12341
|
+
// Async tick to speed up processing
|
12342
|
+
_this.tickImmediate();
|
12343
|
+
};
|
12344
|
+
_this.onMediaEnded = function () {
|
12345
|
+
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12346
|
+
_this.startPosition = _this.lastCurrentTime = 0;
|
12347
|
+
if (_this.playlistType === PlaylistLevelType.MAIN) {
|
12348
|
+
_this.hls.trigger(Events.MEDIA_ENDED, {
|
12349
|
+
stalled: false
|
12350
|
+
});
|
12351
|
+
}
|
12352
|
+
};
|
12207
12353
|
_this.playlistType = playlistType;
|
12208
|
-
_this.logPrefix = logPrefix;
|
12209
|
-
_this.log = logger.log.bind(logger, logPrefix + ":");
|
12210
|
-
_this.warn = logger.warn.bind(logger, logPrefix + ":");
|
12211
12354
|
_this.hls = hls;
|
12212
12355
|
_this.fragmentLoader = new FragmentLoader(hls.config);
|
12213
12356
|
_this.keyLoader = keyLoader;
|
12214
12357
|
_this.fragmentTracker = fragmentTracker;
|
12215
12358
|
_this.config = hls.config;
|
12216
12359
|
_this.decrypter = new Decrypter(hls.config);
|
12217
|
-
hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
|
12218
12360
|
return _this;
|
12219
12361
|
}
|
12220
12362
|
var _proto = BaseStreamController.prototype;
|
12363
|
+
_proto.registerListeners = function registerListeners() {
|
12364
|
+
var hls = this.hls;
|
12365
|
+
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12366
|
+
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12367
|
+
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12368
|
+
hls.on(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12369
|
+
hls.on(Events.ERROR, this.onError, this);
|
12370
|
+
};
|
12371
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
12372
|
+
var hls = this.hls;
|
12373
|
+
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
12374
|
+
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
12375
|
+
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
12376
|
+
hls.off(Events.MANIFEST_LOADED, this.onManifestLoaded, this);
|
12377
|
+
hls.off(Events.ERROR, this.onError, this);
|
12378
|
+
};
|
12221
12379
|
_proto.doTick = function doTick() {
|
12222
12380
|
this.onTickEnd();
|
12223
12381
|
};
|
@@ -12241,6 +12399,12 @@
|
|
12241
12399
|
this.clearNextTick();
|
12242
12400
|
this.state = State.STOPPED;
|
12243
12401
|
};
|
12402
|
+
_proto.pauseBuffering = function pauseBuffering() {
|
12403
|
+
this.buffering = false;
|
12404
|
+
};
|
12405
|
+
_proto.resumeBuffering = function resumeBuffering() {
|
12406
|
+
this.buffering = true;
|
12407
|
+
};
|
12244
12408
|
_proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
|
12245
12409
|
// If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
|
12246
12410
|
// of nothing loading/loaded return false
|
@@ -12271,10 +12435,8 @@
|
|
12271
12435
|
};
|
12272
12436
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
12273
12437
|
var media = this.media = this.mediaBuffer = data.media;
|
12274
|
-
|
12275
|
-
|
12276
|
-
media.addEventListener('seeking', this.onvseeking);
|
12277
|
-
media.addEventListener('ended', this.onvended);
|
12438
|
+
media.addEventListener('seeking', this.onMediaSeeking);
|
12439
|
+
media.addEventListener('ended', this.onMediaEnded);
|
12278
12440
|
var config = this.config;
|
12279
12441
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
12280
12442
|
this.startLoad(config.startPosition);
|
@@ -12288,10 +12450,9 @@
|
|
12288
12450
|
}
|
12289
12451
|
|
12290
12452
|
// remove video listeners
|
12291
|
-
if (media
|
12292
|
-
media.removeEventListener('seeking', this.
|
12293
|
-
media.removeEventListener('ended', this.
|
12294
|
-
this.onvseeking = this.onvended = null;
|
12453
|
+
if (media) {
|
12454
|
+
media.removeEventListener('seeking', this.onMediaSeeking);
|
12455
|
+
media.removeEventListener('ended', this.onMediaEnded);
|
12295
12456
|
}
|
12296
12457
|
if (this.keyLoader) {
|
12297
12458
|
this.keyLoader.detach();
|
@@ -12301,54 +12462,8 @@
|
|
12301
12462
|
this.fragmentTracker.removeAllFragments();
|
12302
12463
|
this.stopLoad();
|
12303
12464
|
};
|
12304
|
-
_proto.
|
12305
|
-
|
12306
|
-
fragCurrent = this.fragCurrent,
|
12307
|
-
media = this.media,
|
12308
|
-
mediaBuffer = this.mediaBuffer,
|
12309
|
-
state = this.state;
|
12310
|
-
var currentTime = media ? media.currentTime : 0;
|
12311
|
-
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12312
|
-
this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12313
|
-
if (this.state === State.ENDED) {
|
12314
|
-
this.resetLoadingState();
|
12315
|
-
} else if (fragCurrent) {
|
12316
|
-
// Seeking while frag load is in progress
|
12317
|
-
var tolerance = config.maxFragLookUpTolerance;
|
12318
|
-
var fragStartOffset = fragCurrent.start - tolerance;
|
12319
|
-
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12320
|
-
// if seeking out of buffered range or into new one
|
12321
|
-
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12322
|
-
var pastFragment = currentTime > fragEndOffset;
|
12323
|
-
// if the seek position is outside the current fragment range
|
12324
|
-
if (currentTime < fragStartOffset || pastFragment) {
|
12325
|
-
if (pastFragment && fragCurrent.loader) {
|
12326
|
-
this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12327
|
-
fragCurrent.abortRequests();
|
12328
|
-
this.resetLoadingState();
|
12329
|
-
}
|
12330
|
-
this.fragPrevious = null;
|
12331
|
-
}
|
12332
|
-
}
|
12333
|
-
}
|
12334
|
-
if (media) {
|
12335
|
-
// Remove gap fragments
|
12336
|
-
this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
|
12337
|
-
this.lastCurrentTime = currentTime;
|
12338
|
-
}
|
12339
|
-
|
12340
|
-
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12341
|
-
if (!this.loadedmetadata && !bufferInfo.len) {
|
12342
|
-
this.nextLoadPosition = this.startPosition = currentTime;
|
12343
|
-
}
|
12344
|
-
|
12345
|
-
// Async tick to speed up processing
|
12346
|
-
this.tickImmediate();
|
12347
|
-
};
|
12348
|
-
_proto.onMediaEnded = function onMediaEnded() {
|
12349
|
-
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12350
|
-
this.startPosition = this.lastCurrentTime = 0;
|
12351
|
-
};
|
12465
|
+
_proto.onManifestLoading = function onManifestLoading() {};
|
12466
|
+
_proto.onError = function onError(event, data) {};
|
12352
12467
|
_proto.onManifestLoaded = function onManifestLoaded(event, data) {
|
12353
12468
|
this.startTimeOffset = data.startTimeOffset;
|
12354
12469
|
this.initPTS = [];
|
@@ -12358,7 +12473,7 @@
|
|
12358
12473
|
this.stopLoad();
|
12359
12474
|
_TaskLoop.prototype.onHandlerDestroying.call(this);
|
12360
12475
|
// @ts-ignore
|
12361
|
-
this.hls = null;
|
12476
|
+
this.hls = this.onMediaSeeking = this.onMediaEnded = null;
|
12362
12477
|
};
|
12363
12478
|
_proto.onHandlerDestroyed = function onHandlerDestroyed() {
|
12364
12479
|
this.state = State.STOPPED;
|
@@ -12488,10 +12603,10 @@
|
|
12488
12603
|
var decryptData = frag.decryptdata;
|
12489
12604
|
|
12490
12605
|
// check to see if the payload needs to be decrypted
|
12491
|
-
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && decryptData.method
|
12606
|
+
if (payload && payload.byteLength > 0 && decryptData != null && decryptData.key && decryptData.iv && isFullSegmentEncryption(decryptData.method)) {
|
12492
12607
|
var startTime = self.performance.now();
|
12493
12608
|
// decrypt init segment data
|
12494
|
-
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer).catch(function (err) {
|
12609
|
+
return _this3.decrypter.decrypt(new Uint8Array(payload), decryptData.key.buffer, decryptData.iv.buffer, getAesModeFromFullSegmentMethod(decryptData.method)).catch(function (err) {
|
12495
12610
|
hls.trigger(Events.ERROR, {
|
12496
12611
|
type: ErrorTypes.MEDIA_ERROR,
|
12497
12612
|
details: ErrorDetails.FRAG_DECRYPT_ERROR,
|
@@ -12604,7 +12719,7 @@
|
|
12604
12719
|
}
|
12605
12720
|
var keyLoadingPromise = null;
|
12606
12721
|
if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
|
12607
|
-
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.
|
12722
|
+
this.log("Loading key for " + frag.sn + " of [" + details.startSN + "-" + details.endSN + "], " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + " " + frag.level);
|
12608
12723
|
this.state = State.KEY_LOADING;
|
12609
12724
|
this.fragCurrent = frag;
|
12610
12725
|
keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
|
@@ -12635,7 +12750,7 @@
|
|
12635
12750
|
var partIndex = this.getNextPart(partList, frag, targetBufferTime);
|
12636
12751
|
if (partIndex > -1) {
|
12637
12752
|
var part = partList[partIndex];
|
12638
|
-
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.
|
12753
|
+
this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.playlistType === PlaylistLevelType.MAIN ? 'level' : 'track') + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3)));
|
12639
12754
|
this.nextLoadPosition = part.start + part.duration;
|
12640
12755
|
this.state = State.FRAG_LOADING;
|
12641
12756
|
var _result;
|
@@ -12668,7 +12783,7 @@
|
|
12668
12783
|
}
|
12669
12784
|
}
|
12670
12785
|
}
|
12671
|
-
this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? 'of [' + details.startSN + '-' + details.endSN + '] ' : '') + (this.
|
12786
|
+
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)));
|
12672
12787
|
// Don't update nextLoadPosition for fragments which are not buffered
|
12673
12788
|
if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
|
12674
12789
|
this.nextLoadPosition = frag.start + frag.duration;
|
@@ -13229,7 +13344,7 @@
|
|
13229
13344
|
errorAction.resolved = true;
|
13230
13345
|
}
|
13231
13346
|
} else {
|
13232
|
-
|
13347
|
+
this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
|
13233
13348
|
return;
|
13234
13349
|
}
|
13235
13350
|
} else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
@@ -13619,6 +13734,7 @@
|
|
13619
13734
|
*/
|
13620
13735
|
function getAudioConfig(observer, data, offset, audioCodec) {
|
13621
13736
|
var adtsObjectType;
|
13737
|
+
var originalAdtsObjectType;
|
13622
13738
|
var adtsExtensionSamplingIndex;
|
13623
13739
|
var adtsChannelConfig;
|
13624
13740
|
var config;
|
@@ -13626,7 +13742,7 @@
|
|
13626
13742
|
var manifestCodec = audioCodec;
|
13627
13743
|
var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
13628
13744
|
// byte 2
|
13629
|
-
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13745
|
+
adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13630
13746
|
var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
13631
13747
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
13632
13748
|
var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
|
@@ -13643,8 +13759,8 @@
|
|
13643
13759
|
// byte 3
|
13644
13760
|
adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
|
13645
13761
|
logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
|
13646
|
-
//
|
13647
|
-
if (/firefox/i.test(userAgent)) {
|
13762
|
+
// Firefox and Pale Moon: freq less than 24kHz = AAC SBR (HE-AAC)
|
13763
|
+
if (/firefox|palemoon/i.test(userAgent)) {
|
13648
13764
|
if (adtsSamplingIndex >= 6) {
|
13649
13765
|
adtsObjectType = 5;
|
13650
13766
|
config = new Array(4);
|
@@ -13738,6 +13854,7 @@
|
|
13738
13854
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
13739
13855
|
channelCount: adtsChannelConfig,
|
13740
13856
|
codec: 'mp4a.40.' + adtsObjectType,
|
13857
|
+
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
13741
13858
|
manifestCodec: manifestCodec
|
13742
13859
|
};
|
13743
13860
|
}
|
@@ -13792,7 +13909,8 @@
|
|
13792
13909
|
track.channelCount = config.channelCount;
|
13793
13910
|
track.codec = config.codec;
|
13794
13911
|
track.manifestCodec = config.manifestCodec;
|
13795
|
-
|
13912
|
+
track.parsedCodec = config.parsedCodec;
|
13913
|
+
logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
|
13796
13914
|
}
|
13797
13915
|
}
|
13798
13916
|
function getFrameDuration(samplerate) {
|
@@ -14272,32 +14390,136 @@
|
|
14272
14390
|
logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
|
14273
14391
|
}
|
14274
14392
|
};
|
14275
|
-
|
14276
|
-
|
14277
|
-
|
14278
|
-
|
14279
|
-
|
14280
|
-
|
14281
|
-
|
14282
|
-
|
14283
|
-
|
14284
|
-
|
14285
|
-
|
14286
|
-
|
14287
|
-
this.bitsAvailable = void 0;
|
14288
|
-
this.data = data;
|
14289
|
-
// the number of bytes left to examine in this.data
|
14290
|
-
this.bytesAvailable = data.byteLength;
|
14291
|
-
// the current word being examined
|
14292
|
-
this.word = 0; // :uint
|
14293
|
-
// the number of bits left to examine in the current word
|
14294
|
-
this.bitsAvailable = 0; // :uint
|
14295
|
-
}
|
14393
|
+
_proto.parseNALu = function parseNALu(track, array) {
|
14394
|
+
var len = array.byteLength;
|
14395
|
+
var state = track.naluState || 0;
|
14396
|
+
var lastState = state;
|
14397
|
+
var units = [];
|
14398
|
+
var i = 0;
|
14399
|
+
var value;
|
14400
|
+
var overflow;
|
14401
|
+
var unitType;
|
14402
|
+
var lastUnitStart = -1;
|
14403
|
+
var lastUnitType = 0;
|
14404
|
+
// logger.log('PES:' + Hex.hexDump(array));
|
14296
14405
|
|
14297
|
-
|
14298
|
-
|
14299
|
-
|
14300
|
-
|
14406
|
+
if (state === -1) {
|
14407
|
+
// special use case where we found 3 or 4-byte start codes exactly at the end of previous PES packet
|
14408
|
+
lastUnitStart = 0;
|
14409
|
+
// NALu type is value read from offset 0
|
14410
|
+
lastUnitType = this.getNALuType(array, 0);
|
14411
|
+
state = 0;
|
14412
|
+
i = 1;
|
14413
|
+
}
|
14414
|
+
while (i < len) {
|
14415
|
+
value = array[i++];
|
14416
|
+
// optimization. state 0 and 1 are the predominant case. let's handle them outside of the switch/case
|
14417
|
+
if (!state) {
|
14418
|
+
state = value ? 0 : 1;
|
14419
|
+
continue;
|
14420
|
+
}
|
14421
|
+
if (state === 1) {
|
14422
|
+
state = value ? 0 : 2;
|
14423
|
+
continue;
|
14424
|
+
}
|
14425
|
+
// here we have state either equal to 2 or 3
|
14426
|
+
if (!value) {
|
14427
|
+
state = 3;
|
14428
|
+
} else if (value === 1) {
|
14429
|
+
overflow = i - state - 1;
|
14430
|
+
if (lastUnitStart >= 0) {
|
14431
|
+
var unit = {
|
14432
|
+
data: array.subarray(lastUnitStart, overflow),
|
14433
|
+
type: lastUnitType
|
14434
|
+
};
|
14435
|
+
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14436
|
+
units.push(unit);
|
14437
|
+
} else {
|
14438
|
+
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14439
|
+
// first check if start code delimiter is overlapping between 2 PES packets,
|
14440
|
+
// ie it started in last packet (lastState not zero)
|
14441
|
+
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14442
|
+
var lastUnit = this.getLastNalUnit(track.samples);
|
14443
|
+
if (lastUnit) {
|
14444
|
+
if (lastState && i <= 4 - lastState) {
|
14445
|
+
// start delimiter overlapping between PES packets
|
14446
|
+
// strip start delimiter bytes from the end of last NAL unit
|
14447
|
+
// check if lastUnit had a state different from zero
|
14448
|
+
if (lastUnit.state) {
|
14449
|
+
// strip last bytes
|
14450
|
+
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
14451
|
+
}
|
14452
|
+
}
|
14453
|
+
// If NAL units are not starting right at the beginning of the PES packet, push preceding data into previous NAL unit.
|
14454
|
+
|
14455
|
+
if (overflow > 0) {
|
14456
|
+
// logger.log('first NALU found with overflow:' + overflow);
|
14457
|
+
lastUnit.data = appendUint8Array(lastUnit.data, array.subarray(0, overflow));
|
14458
|
+
lastUnit.state = 0;
|
14459
|
+
}
|
14460
|
+
}
|
14461
|
+
}
|
14462
|
+
// check if we can read unit type
|
14463
|
+
if (i < len) {
|
14464
|
+
unitType = this.getNALuType(array, i);
|
14465
|
+
// logger.log('find NALU @ offset:' + i + ',type:' + unitType);
|
14466
|
+
lastUnitStart = i;
|
14467
|
+
lastUnitType = unitType;
|
14468
|
+
state = 0;
|
14469
|
+
} else {
|
14470
|
+
// not enough byte to read unit type. let's read it on next PES parsing
|
14471
|
+
state = -1;
|
14472
|
+
}
|
14473
|
+
} else {
|
14474
|
+
state = 0;
|
14475
|
+
}
|
14476
|
+
}
|
14477
|
+
if (lastUnitStart >= 0 && state >= 0) {
|
14478
|
+
var _unit = {
|
14479
|
+
data: array.subarray(lastUnitStart, len),
|
14480
|
+
type: lastUnitType,
|
14481
|
+
state: state
|
14482
|
+
};
|
14483
|
+
units.push(_unit);
|
14484
|
+
// logger.log('pushing NALU, type/size/state:' + unit.type + '/' + unit.data.byteLength + '/' + state);
|
14485
|
+
}
|
14486
|
+
// no NALu found
|
14487
|
+
if (units.length === 0) {
|
14488
|
+
// append pes.data to previous NAL unit
|
14489
|
+
var _lastUnit = this.getLastNalUnit(track.samples);
|
14490
|
+
if (_lastUnit) {
|
14491
|
+
_lastUnit.data = appendUint8Array(_lastUnit.data, array);
|
14492
|
+
}
|
14493
|
+
}
|
14494
|
+
track.naluState = state;
|
14495
|
+
return units;
|
14496
|
+
};
|
14497
|
+
return BaseVideoParser;
|
14498
|
+
}();
|
14499
|
+
|
14500
|
+
/**
|
14501
|
+
* Parser for exponential Golomb codes, a variable-bitwidth number encoding scheme used by h264.
|
14502
|
+
*/
|
14503
|
+
|
14504
|
+
var ExpGolomb = /*#__PURE__*/function () {
|
14505
|
+
function ExpGolomb(data) {
|
14506
|
+
this.data = void 0;
|
14507
|
+
this.bytesAvailable = void 0;
|
14508
|
+
this.word = void 0;
|
14509
|
+
this.bitsAvailable = void 0;
|
14510
|
+
this.data = data;
|
14511
|
+
// the number of bytes left to examine in this.data
|
14512
|
+
this.bytesAvailable = data.byteLength;
|
14513
|
+
// the current word being examined
|
14514
|
+
this.word = 0; // :uint
|
14515
|
+
// the number of bits left to examine in the current word
|
14516
|
+
this.bitsAvailable = 0; // :uint
|
14517
|
+
}
|
14518
|
+
|
14519
|
+
// ():void
|
14520
|
+
var _proto = ExpGolomb.prototype;
|
14521
|
+
_proto.loadWord = function loadWord() {
|
14522
|
+
var data = this.data;
|
14301
14523
|
var bytesAvailable = this.bytesAvailable;
|
14302
14524
|
var position = data.byteLength - bytesAvailable;
|
14303
14525
|
var workingBytes = new Uint8Array(4);
|
@@ -14426,22 +14648,179 @@
|
|
14426
14648
|
;
|
14427
14649
|
_proto.readUInt = function readUInt() {
|
14428
14650
|
return this.readBits(32);
|
14651
|
+
};
|
14652
|
+
return ExpGolomb;
|
14653
|
+
}();
|
14654
|
+
|
14655
|
+
var AvcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
|
14656
|
+
_inheritsLoose(AvcVideoParser, _BaseVideoParser);
|
14657
|
+
function AvcVideoParser() {
|
14658
|
+
return _BaseVideoParser.apply(this, arguments) || this;
|
14659
|
+
}
|
14660
|
+
var _proto = AvcVideoParser.prototype;
|
14661
|
+
_proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
|
14662
|
+
var _this = this;
|
14663
|
+
var units = this.parseNALu(track, pes.data);
|
14664
|
+
var VideoSample = this.VideoSample;
|
14665
|
+
var push;
|
14666
|
+
var spsfound = false;
|
14667
|
+
// free pes.data to save up some memory
|
14668
|
+
pes.data = null;
|
14669
|
+
|
14670
|
+
// if new NAL units found and last sample still there, let's push ...
|
14671
|
+
// this helps parsing streams with missing AUD (only do this if AUD never found)
|
14672
|
+
if (VideoSample && units.length && !track.audFound) {
|
14673
|
+
this.pushAccessUnit(VideoSample, track);
|
14674
|
+
VideoSample = this.VideoSample = this.createVideoSample(false, pes.pts, pes.dts, '');
|
14675
|
+
}
|
14676
|
+
units.forEach(function (unit) {
|
14677
|
+
var _VideoSample2;
|
14678
|
+
switch (unit.type) {
|
14679
|
+
// NDR
|
14680
|
+
case 1:
|
14681
|
+
{
|
14682
|
+
var iskey = false;
|
14683
|
+
push = true;
|
14684
|
+
var data = unit.data;
|
14685
|
+
// only check slice type to detect KF in case SPS found in same packet (any keyframe is preceded by SPS ...)
|
14686
|
+
if (spsfound && data.length > 4) {
|
14687
|
+
// retrieve slice type by parsing beginning of NAL unit (follow H264 spec, slice_header definition) to detect keyframe embedded in NDR
|
14688
|
+
var sliceType = _this.readSliceType(data);
|
14689
|
+
// 2 : I slice, 4 : SI slice, 7 : I slice, 9: SI slice
|
14690
|
+
// SI slice : A slice that is coded using intra prediction only and using quantisation of the prediction samples.
|
14691
|
+
// An SI slice can be coded such that its decoded samples can be constructed identically to an SP slice.
|
14692
|
+
// I slice: A slice that is not an SI slice that is decoded using intra prediction only.
|
14693
|
+
// if (sliceType === 2 || sliceType === 7) {
|
14694
|
+
if (sliceType === 2 || sliceType === 4 || sliceType === 7 || sliceType === 9) {
|
14695
|
+
iskey = true;
|
14696
|
+
}
|
14697
|
+
}
|
14698
|
+
if (iskey) {
|
14699
|
+
var _VideoSample;
|
14700
|
+
// if we have non-keyframe data already, that cannot belong to the same frame as a keyframe, so force a push
|
14701
|
+
if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
|
14702
|
+
_this.pushAccessUnit(VideoSample, track);
|
14703
|
+
VideoSample = _this.VideoSample = null;
|
14704
|
+
}
|
14705
|
+
}
|
14706
|
+
if (!VideoSample) {
|
14707
|
+
VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
|
14708
|
+
}
|
14709
|
+
VideoSample.frame = true;
|
14710
|
+
VideoSample.key = iskey;
|
14711
|
+
break;
|
14712
|
+
// IDR
|
14713
|
+
}
|
14714
|
+
case 5:
|
14715
|
+
push = true;
|
14716
|
+
// handle PES not starting with AUD
|
14717
|
+
// if we have frame data already, that cannot belong to the same frame, so force a push
|
14718
|
+
if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
|
14719
|
+
_this.pushAccessUnit(VideoSample, track);
|
14720
|
+
VideoSample = _this.VideoSample = null;
|
14721
|
+
}
|
14722
|
+
if (!VideoSample) {
|
14723
|
+
VideoSample = _this.VideoSample = _this.createVideoSample(true, pes.pts, pes.dts, '');
|
14724
|
+
}
|
14725
|
+
VideoSample.key = true;
|
14726
|
+
VideoSample.frame = true;
|
14727
|
+
break;
|
14728
|
+
// SEI
|
14729
|
+
case 6:
|
14730
|
+
{
|
14731
|
+
push = true;
|
14732
|
+
parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
|
14733
|
+
break;
|
14734
|
+
// SPS
|
14735
|
+
}
|
14736
|
+
case 7:
|
14737
|
+
{
|
14738
|
+
var _track$pixelRatio, _track$pixelRatio2;
|
14739
|
+
push = true;
|
14740
|
+
spsfound = true;
|
14741
|
+
var sps = unit.data;
|
14742
|
+
var config = _this.readSPS(sps);
|
14743
|
+
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]) {
|
14744
|
+
track.width = config.width;
|
14745
|
+
track.height = config.height;
|
14746
|
+
track.pixelRatio = config.pixelRatio;
|
14747
|
+
track.sps = [sps];
|
14748
|
+
track.duration = duration;
|
14749
|
+
var codecarray = sps.subarray(1, 4);
|
14750
|
+
var codecstring = 'avc1.';
|
14751
|
+
for (var i = 0; i < 3; i++) {
|
14752
|
+
var h = codecarray[i].toString(16);
|
14753
|
+
if (h.length < 2) {
|
14754
|
+
h = '0' + h;
|
14755
|
+
}
|
14756
|
+
codecstring += h;
|
14757
|
+
}
|
14758
|
+
track.codec = codecstring;
|
14759
|
+
}
|
14760
|
+
break;
|
14761
|
+
}
|
14762
|
+
// PPS
|
14763
|
+
case 8:
|
14764
|
+
push = true;
|
14765
|
+
track.pps = [unit.data];
|
14766
|
+
break;
|
14767
|
+
// AUD
|
14768
|
+
case 9:
|
14769
|
+
push = true;
|
14770
|
+
track.audFound = true;
|
14771
|
+
if (VideoSample) {
|
14772
|
+
_this.pushAccessUnit(VideoSample, track);
|
14773
|
+
}
|
14774
|
+
VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
|
14775
|
+
break;
|
14776
|
+
// Filler Data
|
14777
|
+
case 12:
|
14778
|
+
push = true;
|
14779
|
+
break;
|
14780
|
+
default:
|
14781
|
+
push = false;
|
14782
|
+
if (VideoSample) {
|
14783
|
+
VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
|
14784
|
+
}
|
14785
|
+
break;
|
14786
|
+
}
|
14787
|
+
if (VideoSample && push) {
|
14788
|
+
var _units = VideoSample.units;
|
14789
|
+
_units.push(unit);
|
14790
|
+
}
|
14791
|
+
});
|
14792
|
+
// if last PES packet, push samples
|
14793
|
+
if (last && VideoSample) {
|
14794
|
+
this.pushAccessUnit(VideoSample, track);
|
14795
|
+
this.VideoSample = null;
|
14796
|
+
}
|
14797
|
+
};
|
14798
|
+
_proto.getNALuType = function getNALuType(data, offset) {
|
14799
|
+
return data[offset] & 0x1f;
|
14800
|
+
};
|
14801
|
+
_proto.readSliceType = function readSliceType(data) {
|
14802
|
+
var eg = new ExpGolomb(data);
|
14803
|
+
// skip NALu type
|
14804
|
+
eg.readUByte();
|
14805
|
+
// discard first_mb_in_slice
|
14806
|
+
eg.readUEG();
|
14807
|
+
// return slice_type
|
14808
|
+
return eg.readUEG();
|
14429
14809
|
}
|
14430
14810
|
|
14431
14811
|
/**
|
14432
|
-
*
|
14433
|
-
* list is optionally transmitted as part of a sequence parameter
|
14812
|
+
* The scaling list is optionally transmitted as part of a sequence parameter
|
14434
14813
|
* set and is not relevant to transmuxing.
|
14435
14814
|
* @param count the number of entries in this scaling list
|
14436
14815
|
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14437
14816
|
*/;
|
14438
|
-
_proto.skipScalingList = function skipScalingList(count) {
|
14817
|
+
_proto.skipScalingList = function skipScalingList(count, reader) {
|
14439
14818
|
var lastScale = 8;
|
14440
14819
|
var nextScale = 8;
|
14441
14820
|
var deltaScale;
|
14442
14821
|
for (var j = 0; j < count; j++) {
|
14443
14822
|
if (nextScale !== 0) {
|
14444
|
-
deltaScale =
|
14823
|
+
deltaScale = reader.readEG();
|
14445
14824
|
nextScale = (lastScale + deltaScale + 256) % 256;
|
14446
14825
|
}
|
14447
14826
|
lastScale = nextScale === 0 ? lastScale : nextScale;
|
@@ -14456,7 +14835,8 @@
|
|
14456
14835
|
* sequence parameter set, including the dimensions of the
|
14457
14836
|
* associated video frames.
|
14458
14837
|
*/;
|
14459
|
-
_proto.readSPS = function readSPS() {
|
14838
|
+
_proto.readSPS = function readSPS(sps) {
|
14839
|
+
var eg = new ExpGolomb(sps);
|
14460
14840
|
var frameCropLeftOffset = 0;
|
14461
14841
|
var frameCropRightOffset = 0;
|
14462
14842
|
var frameCropTopOffset = 0;
|
@@ -14464,13 +14844,13 @@
|
|
14464
14844
|
var numRefFramesInPicOrderCntCycle;
|
14465
14845
|
var scalingListCount;
|
14466
14846
|
var i;
|
14467
|
-
var readUByte =
|
14468
|
-
var readBits =
|
14469
|
-
var readUEG =
|
14470
|
-
var readBoolean =
|
14471
|
-
var skipBits =
|
14472
|
-
var skipEG =
|
14473
|
-
var skipUEG =
|
14847
|
+
var readUByte = eg.readUByte.bind(eg);
|
14848
|
+
var readBits = eg.readBits.bind(eg);
|
14849
|
+
var readUEG = eg.readUEG.bind(eg);
|
14850
|
+
var readBoolean = eg.readBoolean.bind(eg);
|
14851
|
+
var skipBits = eg.skipBits.bind(eg);
|
14852
|
+
var skipEG = eg.skipEG.bind(eg);
|
14853
|
+
var skipUEG = eg.skipUEG.bind(eg);
|
14474
14854
|
var skipScalingList = this.skipScalingList.bind(this);
|
14475
14855
|
readUByte();
|
14476
14856
|
var profileIdc = readUByte(); // profile_idc
|
@@ -14495,9 +14875,9 @@
|
|
14495
14875
|
if (readBoolean()) {
|
14496
14876
|
// seq_scaling_list_present_flag[ i ]
|
14497
14877
|
if (i < 6) {
|
14498
|
-
skipScalingList(16);
|
14878
|
+
skipScalingList(16, eg);
|
14499
14879
|
} else {
|
14500
|
-
skipScalingList(64);
|
14880
|
+
skipScalingList(64, eg);
|
14501
14881
|
}
|
14502
14882
|
}
|
14503
14883
|
}
|
@@ -14602,26 +14982,24 @@
|
|
14602
14982
|
pixelRatio: pixelRatio
|
14603
14983
|
};
|
14604
14984
|
};
|
14605
|
-
|
14606
|
-
|
14607
|
-
this.readUByte();
|
14608
|
-
// discard first_mb_in_slice
|
14609
|
-
this.readUEG();
|
14610
|
-
// return slice_type
|
14611
|
-
return this.readUEG();
|
14612
|
-
};
|
14613
|
-
return ExpGolomb;
|
14614
|
-
}();
|
14985
|
+
return AvcVideoParser;
|
14986
|
+
}(BaseVideoParser);
|
14615
14987
|
|
14616
|
-
var
|
14617
|
-
_inheritsLoose(
|
14618
|
-
function
|
14619
|
-
|
14988
|
+
var HevcVideoParser = /*#__PURE__*/function (_BaseVideoParser) {
|
14989
|
+
_inheritsLoose(HevcVideoParser, _BaseVideoParser);
|
14990
|
+
function HevcVideoParser() {
|
14991
|
+
var _this;
|
14992
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
14993
|
+
args[_key] = arguments[_key];
|
14994
|
+
}
|
14995
|
+
_this = _BaseVideoParser.call.apply(_BaseVideoParser, [this].concat(args)) || this;
|
14996
|
+
_this.initVPS = null;
|
14997
|
+
return _this;
|
14620
14998
|
}
|
14621
|
-
var _proto =
|
14622
|
-
_proto.
|
14623
|
-
var
|
14624
|
-
var units = this.
|
14999
|
+
var _proto = HevcVideoParser.prototype;
|
15000
|
+
_proto.parsePES = function parsePES(track, textTrack, pes, last, duration) {
|
15001
|
+
var _this2 = this;
|
15002
|
+
var units = this.parseNALu(track, pes.data);
|
14625
15003
|
var VideoSample = this.VideoSample;
|
14626
15004
|
var push;
|
14627
15005
|
var spsfound = false;
|
@@ -14637,231 +15015,576 @@
|
|
14637
15015
|
units.forEach(function (unit) {
|
14638
15016
|
var _VideoSample2;
|
14639
15017
|
switch (unit.type) {
|
14640
|
-
//
|
15018
|
+
// NON-IDR, NON RANDOM ACCESS SLICE
|
15019
|
+
case 0:
|
14641
15020
|
case 1:
|
14642
|
-
|
14643
|
-
|
14644
|
-
|
14645
|
-
|
14646
|
-
|
14647
|
-
|
14648
|
-
|
14649
|
-
|
14650
|
-
|
14651
|
-
|
14652
|
-
|
14653
|
-
|
14654
|
-
|
14655
|
-
|
14656
|
-
|
14657
|
-
|
14658
|
-
|
14659
|
-
|
14660
|
-
|
14661
|
-
|
14662
|
-
|
14663
|
-
|
14664
|
-
|
14665
|
-
|
14666
|
-
|
14667
|
-
if (!VideoSample) {
|
14668
|
-
|
15021
|
+
case 2:
|
15022
|
+
case 3:
|
15023
|
+
case 4:
|
15024
|
+
case 5:
|
15025
|
+
case 6:
|
15026
|
+
case 7:
|
15027
|
+
case 8:
|
15028
|
+
case 9:
|
15029
|
+
if (!VideoSample) {
|
15030
|
+
VideoSample = _this2.VideoSample = _this2.createVideoSample(false, pes.pts, pes.dts, '');
|
15031
|
+
}
|
15032
|
+
VideoSample.frame = true;
|
15033
|
+
push = true;
|
15034
|
+
break;
|
15035
|
+
|
15036
|
+
// CRA, BLA (random access picture)
|
15037
|
+
case 16:
|
15038
|
+
case 17:
|
15039
|
+
case 18:
|
15040
|
+
case 21:
|
15041
|
+
push = true;
|
15042
|
+
if (spsfound) {
|
15043
|
+
var _VideoSample;
|
15044
|
+
// handle PES not starting with AUD
|
15045
|
+
// if we have frame data already, that cannot belong to the same frame, so force a push
|
15046
|
+
if ((_VideoSample = VideoSample) != null && _VideoSample.frame && !VideoSample.key) {
|
15047
|
+
_this2.pushAccessUnit(VideoSample, track);
|
15048
|
+
VideoSample = _this2.VideoSample = null;
|
14669
15049
|
}
|
14670
|
-
VideoSample.frame = true;
|
14671
|
-
VideoSample.key = iskey;
|
14672
|
-
break;
|
14673
|
-
// IDR
|
14674
15050
|
}
|
14675
|
-
|
15051
|
+
if (!VideoSample) {
|
15052
|
+
VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
|
15053
|
+
}
|
15054
|
+
VideoSample.key = true;
|
15055
|
+
VideoSample.frame = true;
|
15056
|
+
break;
|
15057
|
+
|
15058
|
+
// IDR
|
15059
|
+
case 19:
|
15060
|
+
case 20:
|
14676
15061
|
push = true;
|
14677
15062
|
// handle PES not starting with AUD
|
14678
15063
|
// if we have frame data already, that cannot belong to the same frame, so force a push
|
14679
15064
|
if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
|
14680
|
-
|
14681
|
-
VideoSample =
|
15065
|
+
_this2.pushAccessUnit(VideoSample, track);
|
15066
|
+
VideoSample = _this2.VideoSample = null;
|
14682
15067
|
}
|
14683
15068
|
if (!VideoSample) {
|
14684
|
-
VideoSample =
|
15069
|
+
VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
|
14685
15070
|
}
|
14686
15071
|
VideoSample.key = true;
|
14687
15072
|
VideoSample.frame = true;
|
14688
15073
|
break;
|
15074
|
+
|
14689
15075
|
// SEI
|
14690
|
-
case
|
14691
|
-
{
|
14692
|
-
push = true;
|
14693
|
-
parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
|
14694
|
-
break;
|
14695
|
-
// SPS
|
14696
|
-
}
|
14697
|
-
case 7:
|
14698
|
-
{
|
14699
|
-
var _track$pixelRatio, _track$pixelRatio2;
|
14700
|
-
push = true;
|
14701
|
-
spsfound = true;
|
14702
|
-
var sps = unit.data;
|
14703
|
-
var expGolombDecoder = new ExpGolomb(sps);
|
14704
|
-
var config = expGolombDecoder.readSPS();
|
14705
|
-
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]) {
|
14706
|
-
track.width = config.width;
|
14707
|
-
track.height = config.height;
|
14708
|
-
track.pixelRatio = config.pixelRatio;
|
14709
|
-
track.sps = [sps];
|
14710
|
-
track.duration = duration;
|
14711
|
-
var codecarray = sps.subarray(1, 4);
|
14712
|
-
var codecstring = 'avc1.';
|
14713
|
-
for (var i = 0; i < 3; i++) {
|
14714
|
-
var h = codecarray[i].toString(16);
|
14715
|
-
if (h.length < 2) {
|
14716
|
-
h = '0' + h;
|
14717
|
-
}
|
14718
|
-
codecstring += h;
|
14719
|
-
}
|
14720
|
-
track.codec = codecstring;
|
14721
|
-
}
|
14722
|
-
break;
|
14723
|
-
}
|
14724
|
-
// PPS
|
14725
|
-
case 8:
|
15076
|
+
case 39:
|
14726
15077
|
push = true;
|
14727
|
-
|
15078
|
+
parseSEIMessageFromNALu(unit.data, 2,
|
15079
|
+
// NALu header size
|
15080
|
+
pes.pts, textTrack.samples);
|
14728
15081
|
break;
|
14729
|
-
|
14730
|
-
|
14731
|
-
|
14732
|
-
track.audFound = true;
|
14733
|
-
if (VideoSample) {
|
14734
|
-
_this.pushAccessUnit(VideoSample, track);
|
14735
|
-
}
|
14736
|
-
VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
|
14737
|
-
break;
|
14738
|
-
// Filler Data
|
14739
|
-
case 12:
|
15082
|
+
|
15083
|
+
// VPS
|
15084
|
+
case 32:
|
14740
15085
|
push = true;
|
14741
|
-
|
14742
|
-
|
14743
|
-
|
14744
|
-
|
14745
|
-
VideoSample.debug += 'unknown NAL ' + unit.type + ' ';
|
15086
|
+
if (!track.vps) {
|
15087
|
+
var config = _this2.readVPS(unit.data);
|
15088
|
+
track.params = _objectSpread2({}, config);
|
15089
|
+
_this2.initVPS = unit.data;
|
14746
15090
|
}
|
15091
|
+
track.vps = [unit.data];
|
14747
15092
|
break;
|
14748
|
-
}
|
14749
|
-
if (VideoSample && push) {
|
14750
|
-
var _units = VideoSample.units;
|
14751
|
-
_units.push(unit);
|
14752
|
-
}
|
14753
|
-
});
|
14754
|
-
// if last PES packet, push samples
|
14755
|
-
if (last && VideoSample) {
|
14756
|
-
this.pushAccessUnit(VideoSample, track);
|
14757
|
-
this.VideoSample = null;
|
14758
|
-
}
|
14759
|
-
};
|
14760
|
-
_proto.parseAVCNALu = function parseAVCNALu(track, array) {
|
14761
|
-
var len = array.byteLength;
|
14762
|
-
var state = track.naluState || 0;
|
14763
|
-
var lastState = state;
|
14764
|
-
var units = [];
|
14765
|
-
var i = 0;
|
14766
|
-
var value;
|
14767
|
-
var overflow;
|
14768
|
-
var unitType;
|
14769
|
-
var lastUnitStart = -1;
|
14770
|
-
var lastUnitType = 0;
|
14771
|
-
// logger.log('PES:' + Hex.hexDump(array));
|
14772
15093
|
|
14773
|
-
|
14774
|
-
|
14775
|
-
|
14776
|
-
|
14777
|
-
|
14778
|
-
|
14779
|
-
|
14780
|
-
|
14781
|
-
|
14782
|
-
|
14783
|
-
|
14784
|
-
|
14785
|
-
|
14786
|
-
|
14787
|
-
|
14788
|
-
|
14789
|
-
|
14790
|
-
|
14791
|
-
|
14792
|
-
// here we have state either equal to 2 or 3
|
14793
|
-
if (!value) {
|
14794
|
-
state = 3;
|
14795
|
-
} else if (value === 1) {
|
14796
|
-
overflow = i - state - 1;
|
14797
|
-
if (lastUnitStart >= 0) {
|
14798
|
-
var unit = {
|
14799
|
-
data: array.subarray(lastUnitStart, overflow),
|
14800
|
-
type: lastUnitType
|
14801
|
-
};
|
14802
|
-
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14803
|
-
units.push(unit);
|
14804
|
-
} else {
|
14805
|
-
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14806
|
-
// first check if start code delimiter is overlapping between 2 PES packets,
|
14807
|
-
// ie it started in last packet (lastState not zero)
|
14808
|
-
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14809
|
-
var lastUnit = this.getLastNalUnit(track.samples);
|
14810
|
-
if (lastUnit) {
|
14811
|
-
if (lastState && i <= 4 - lastState) {
|
14812
|
-
// start delimiter overlapping between PES packets
|
14813
|
-
// strip start delimiter bytes from the end of last NAL unit
|
14814
|
-
// check if lastUnit had a state different from zero
|
14815
|
-
if (lastUnit.state) {
|
14816
|
-
// strip last bytes
|
14817
|
-
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
15094
|
+
// SPS
|
15095
|
+
case 33:
|
15096
|
+
push = true;
|
15097
|
+
spsfound = true;
|
15098
|
+
if (typeof track.params === 'object') {
|
15099
|
+
if (track.vps !== undefined && track.vps[0] !== _this2.initVPS && track.sps !== undefined && !_this2.matchSPS(track.sps[0], unit.data)) {
|
15100
|
+
_this2.initVPS = track.vps[0];
|
15101
|
+
track.sps = track.pps = undefined;
|
15102
|
+
}
|
15103
|
+
if (!track.sps) {
|
15104
|
+
var _config = _this2.readSPS(unit.data);
|
15105
|
+
track.width = _config.width;
|
15106
|
+
track.height = _config.height;
|
15107
|
+
track.pixelRatio = _config.pixelRatio;
|
15108
|
+
track.duration = duration;
|
15109
|
+
track.codec = _config.codecString;
|
15110
|
+
track.sps = [];
|
15111
|
+
for (var prop in _config.params) {
|
15112
|
+
track.params[prop] = _config.params[prop];
|
14818
15113
|
}
|
14819
15114
|
}
|
14820
|
-
|
15115
|
+
if (track.vps !== undefined && track.vps[0] === _this2.initVPS) {
|
15116
|
+
track.sps.push(unit.data);
|
15117
|
+
}
|
15118
|
+
}
|
15119
|
+
if (!VideoSample) {
|
15120
|
+
VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
|
15121
|
+
}
|
15122
|
+
VideoSample.key = true;
|
15123
|
+
break;
|
14821
15124
|
|
14822
|
-
|
14823
|
-
|
14824
|
-
|
14825
|
-
|
15125
|
+
// PPS
|
15126
|
+
case 34:
|
15127
|
+
push = true;
|
15128
|
+
if (typeof track.params === 'object') {
|
15129
|
+
if (!track.pps) {
|
15130
|
+
track.pps = [];
|
15131
|
+
var _config2 = _this2.readPPS(unit.data);
|
15132
|
+
for (var _prop in _config2) {
|
15133
|
+
track.params[_prop] = _config2[_prop];
|
15134
|
+
}
|
15135
|
+
}
|
15136
|
+
if (_this2.initVPS !== null || track.pps.length === 0) {
|
15137
|
+
track.pps.push(unit.data);
|
14826
15138
|
}
|
14827
15139
|
}
|
15140
|
+
break;
|
15141
|
+
|
15142
|
+
// ACCESS UNIT DELIMITER
|
15143
|
+
case 35:
|
15144
|
+
push = true;
|
15145
|
+
track.audFound = true;
|
15146
|
+
if (VideoSample) {
|
15147
|
+
_this2.pushAccessUnit(VideoSample, track);
|
15148
|
+
}
|
15149
|
+
VideoSample = _this2.VideoSample = _this2.createVideoSample(false, pes.pts, pes.dts, '');
|
15150
|
+
break;
|
15151
|
+
default:
|
15152
|
+
push = false;
|
15153
|
+
if (VideoSample) {
|
15154
|
+
VideoSample.debug += 'unknown or irrelevant NAL ' + unit.type + ' ';
|
15155
|
+
}
|
15156
|
+
break;
|
15157
|
+
}
|
15158
|
+
if (VideoSample && push) {
|
15159
|
+
var _units = VideoSample.units;
|
15160
|
+
_units.push(unit);
|
15161
|
+
}
|
15162
|
+
});
|
15163
|
+
// if last PES packet, push samples
|
15164
|
+
if (last && VideoSample) {
|
15165
|
+
this.pushAccessUnit(VideoSample, track);
|
15166
|
+
this.VideoSample = null;
|
15167
|
+
}
|
15168
|
+
};
|
15169
|
+
_proto.getNALuType = function getNALuType(data, offset) {
|
15170
|
+
return (data[offset] & 0x7e) >>> 1;
|
15171
|
+
};
|
15172
|
+
_proto.ebsp2rbsp = function ebsp2rbsp(arr) {
|
15173
|
+
var dst = new Uint8Array(arr.byteLength);
|
15174
|
+
var dstIdx = 0;
|
15175
|
+
for (var i = 0; i < arr.byteLength; i++) {
|
15176
|
+
if (i >= 2) {
|
15177
|
+
// Unescape: Skip 0x03 after 00 00
|
15178
|
+
if (arr[i] === 0x03 && arr[i - 1] === 0x00 && arr[i - 2] === 0x00) {
|
15179
|
+
continue;
|
14828
15180
|
}
|
14829
|
-
|
14830
|
-
|
14831
|
-
|
14832
|
-
|
14833
|
-
|
14834
|
-
|
14835
|
-
|
14836
|
-
|
14837
|
-
|
14838
|
-
|
15181
|
+
}
|
15182
|
+
dst[dstIdx] = arr[i];
|
15183
|
+
dstIdx++;
|
15184
|
+
}
|
15185
|
+
return new Uint8Array(dst.buffer, 0, dstIdx);
|
15186
|
+
};
|
15187
|
+
_proto.readVPS = function readVPS(vps) {
|
15188
|
+
var eg = new ExpGolomb(vps);
|
15189
|
+
// remove header
|
15190
|
+
eg.readUByte();
|
15191
|
+
eg.readUByte();
|
15192
|
+
eg.readBits(4); // video_parameter_set_id
|
15193
|
+
eg.skipBits(2);
|
15194
|
+
eg.readBits(6); // max_layers_minus1
|
15195
|
+
var max_sub_layers_minus1 = eg.readBits(3);
|
15196
|
+
var temporal_id_nesting_flag = eg.readBoolean();
|
15197
|
+
// ...vui fps can be here, but empty fps value is not critical for metadata
|
15198
|
+
|
15199
|
+
return {
|
15200
|
+
numTemporalLayers: max_sub_layers_minus1 + 1,
|
15201
|
+
temporalIdNested: temporal_id_nesting_flag
|
15202
|
+
};
|
15203
|
+
};
|
15204
|
+
_proto.readSPS = function readSPS(sps) {
|
15205
|
+
var eg = new ExpGolomb(this.ebsp2rbsp(sps));
|
15206
|
+
eg.readUByte();
|
15207
|
+
eg.readUByte();
|
15208
|
+
eg.readBits(4); //video_parameter_set_id
|
15209
|
+
var max_sub_layers_minus1 = eg.readBits(3);
|
15210
|
+
eg.readBoolean(); // temporal_id_nesting_flag
|
15211
|
+
|
15212
|
+
// profile_tier_level
|
15213
|
+
var general_profile_space = eg.readBits(2);
|
15214
|
+
var general_tier_flag = eg.readBoolean();
|
15215
|
+
var general_profile_idc = eg.readBits(5);
|
15216
|
+
var general_profile_compatibility_flags_1 = eg.readUByte();
|
15217
|
+
var general_profile_compatibility_flags_2 = eg.readUByte();
|
15218
|
+
var general_profile_compatibility_flags_3 = eg.readUByte();
|
15219
|
+
var general_profile_compatibility_flags_4 = eg.readUByte();
|
15220
|
+
var general_constraint_indicator_flags_1 = eg.readUByte();
|
15221
|
+
var general_constraint_indicator_flags_2 = eg.readUByte();
|
15222
|
+
var general_constraint_indicator_flags_3 = eg.readUByte();
|
15223
|
+
var general_constraint_indicator_flags_4 = eg.readUByte();
|
15224
|
+
var general_constraint_indicator_flags_5 = eg.readUByte();
|
15225
|
+
var general_constraint_indicator_flags_6 = eg.readUByte();
|
15226
|
+
var general_level_idc = eg.readUByte();
|
15227
|
+
var sub_layer_profile_present_flags = [];
|
15228
|
+
var sub_layer_level_present_flags = [];
|
15229
|
+
for (var i = 0; i < max_sub_layers_minus1; i++) {
|
15230
|
+
sub_layer_profile_present_flags.push(eg.readBoolean());
|
15231
|
+
sub_layer_level_present_flags.push(eg.readBoolean());
|
15232
|
+
}
|
15233
|
+
if (max_sub_layers_minus1 > 0) {
|
15234
|
+
for (var _i = max_sub_layers_minus1; _i < 8; _i++) {
|
15235
|
+
eg.readBits(2);
|
15236
|
+
}
|
15237
|
+
}
|
15238
|
+
for (var _i2 = 0; _i2 < max_sub_layers_minus1; _i2++) {
|
15239
|
+
if (sub_layer_profile_present_flags[_i2]) {
|
15240
|
+
eg.readUByte(); // sub_layer_profile_space, sub_layer_tier_flag, sub_layer_profile_idc
|
15241
|
+
eg.readUByte();
|
15242
|
+
eg.readUByte();
|
15243
|
+
eg.readUByte();
|
15244
|
+
eg.readUByte(); // sub_layer_profile_compatibility_flag
|
15245
|
+
eg.readUByte();
|
15246
|
+
eg.readUByte();
|
15247
|
+
eg.readUByte();
|
15248
|
+
eg.readUByte();
|
15249
|
+
eg.readUByte();
|
15250
|
+
eg.readUByte();
|
15251
|
+
}
|
15252
|
+
if (sub_layer_level_present_flags[_i2]) {
|
15253
|
+
eg.readUByte();
|
15254
|
+
}
|
15255
|
+
}
|
15256
|
+
eg.readUEG(); // seq_parameter_set_id
|
15257
|
+
var chroma_format_idc = eg.readUEG();
|
15258
|
+
if (chroma_format_idc == 3) {
|
15259
|
+
eg.skipBits(1); //separate_colour_plane_flag
|
15260
|
+
}
|
15261
|
+
var pic_width_in_luma_samples = eg.readUEG();
|
15262
|
+
var pic_height_in_luma_samples = eg.readUEG();
|
15263
|
+
var conformance_window_flag = eg.readBoolean();
|
15264
|
+
var pic_left_offset = 0,
|
15265
|
+
pic_right_offset = 0,
|
15266
|
+
pic_top_offset = 0,
|
15267
|
+
pic_bottom_offset = 0;
|
15268
|
+
if (conformance_window_flag) {
|
15269
|
+
pic_left_offset += eg.readUEG();
|
15270
|
+
pic_right_offset += eg.readUEG();
|
15271
|
+
pic_top_offset += eg.readUEG();
|
15272
|
+
pic_bottom_offset += eg.readUEG();
|
15273
|
+
}
|
15274
|
+
var bit_depth_luma_minus8 = eg.readUEG();
|
15275
|
+
var bit_depth_chroma_minus8 = eg.readUEG();
|
15276
|
+
var log2_max_pic_order_cnt_lsb_minus4 = eg.readUEG();
|
15277
|
+
var sub_layer_ordering_info_present_flag = eg.readBoolean();
|
15278
|
+
for (var _i3 = sub_layer_ordering_info_present_flag ? 0 : max_sub_layers_minus1; _i3 <= max_sub_layers_minus1; _i3++) {
|
15279
|
+
eg.skipUEG(); // max_dec_pic_buffering_minus1[i]
|
15280
|
+
eg.skipUEG(); // max_num_reorder_pics[i]
|
15281
|
+
eg.skipUEG(); // max_latency_increase_plus1[i]
|
15282
|
+
}
|
15283
|
+
eg.skipUEG(); // log2_min_luma_coding_block_size_minus3
|
15284
|
+
eg.skipUEG(); // log2_diff_max_min_luma_coding_block_size
|
15285
|
+
eg.skipUEG(); // log2_min_transform_block_size_minus2
|
15286
|
+
eg.skipUEG(); // log2_diff_max_min_transform_block_size
|
15287
|
+
eg.skipUEG(); // max_transform_hierarchy_depth_inter
|
15288
|
+
eg.skipUEG(); // max_transform_hierarchy_depth_intra
|
15289
|
+
var scaling_list_enabled_flag = eg.readBoolean();
|
15290
|
+
if (scaling_list_enabled_flag) {
|
15291
|
+
var sps_scaling_list_data_present_flag = eg.readBoolean();
|
15292
|
+
if (sps_scaling_list_data_present_flag) {
|
15293
|
+
for (var sizeId = 0; sizeId < 4; sizeId++) {
|
15294
|
+
for (var matrixId = 0; matrixId < (sizeId === 3 ? 2 : 6); matrixId++) {
|
15295
|
+
var scaling_list_pred_mode_flag = eg.readBoolean();
|
15296
|
+
if (!scaling_list_pred_mode_flag) {
|
15297
|
+
eg.readUEG(); // scaling_list_pred_matrix_id_delta
|
15298
|
+
} else {
|
15299
|
+
var coefNum = Math.min(64, 1 << 4 + (sizeId << 1));
|
15300
|
+
if (sizeId > 1) {
|
15301
|
+
eg.readEG();
|
15302
|
+
}
|
15303
|
+
for (var _i4 = 0; _i4 < coefNum; _i4++) {
|
15304
|
+
eg.readEG();
|
15305
|
+
}
|
15306
|
+
}
|
15307
|
+
}
|
14839
15308
|
}
|
14840
|
-
} else {
|
14841
|
-
state = 0;
|
14842
15309
|
}
|
14843
15310
|
}
|
14844
|
-
|
14845
|
-
|
14846
|
-
|
14847
|
-
|
14848
|
-
|
14849
|
-
|
14850
|
-
|
14851
|
-
|
15311
|
+
eg.readBoolean(); // amp_enabled_flag
|
15312
|
+
eg.readBoolean(); // sample_adaptive_offset_enabled_flag
|
15313
|
+
var pcm_enabled_flag = eg.readBoolean();
|
15314
|
+
if (pcm_enabled_flag) {
|
15315
|
+
eg.readUByte();
|
15316
|
+
eg.skipUEG();
|
15317
|
+
eg.skipUEG();
|
15318
|
+
eg.readBoolean();
|
15319
|
+
}
|
15320
|
+
var num_short_term_ref_pic_sets = eg.readUEG();
|
15321
|
+
var num_delta_pocs = 0;
|
15322
|
+
for (var _i5 = 0; _i5 < num_short_term_ref_pic_sets; _i5++) {
|
15323
|
+
var inter_ref_pic_set_prediction_flag = false;
|
15324
|
+
if (_i5 !== 0) {
|
15325
|
+
inter_ref_pic_set_prediction_flag = eg.readBoolean();
|
15326
|
+
}
|
15327
|
+
if (inter_ref_pic_set_prediction_flag) {
|
15328
|
+
if (_i5 === num_short_term_ref_pic_sets) {
|
15329
|
+
eg.readUEG();
|
15330
|
+
}
|
15331
|
+
eg.readBoolean();
|
15332
|
+
eg.readUEG();
|
15333
|
+
var next_num_delta_pocs = 0;
|
15334
|
+
for (var j = 0; j <= num_delta_pocs; j++) {
|
15335
|
+
var used_by_curr_pic_flag = eg.readBoolean();
|
15336
|
+
var use_delta_flag = false;
|
15337
|
+
if (!used_by_curr_pic_flag) {
|
15338
|
+
use_delta_flag = eg.readBoolean();
|
15339
|
+
}
|
15340
|
+
if (used_by_curr_pic_flag || use_delta_flag) {
|
15341
|
+
next_num_delta_pocs++;
|
15342
|
+
}
|
15343
|
+
}
|
15344
|
+
num_delta_pocs = next_num_delta_pocs;
|
15345
|
+
} else {
|
15346
|
+
var num_negative_pics = eg.readUEG();
|
15347
|
+
var num_positive_pics = eg.readUEG();
|
15348
|
+
num_delta_pocs = num_negative_pics + num_positive_pics;
|
15349
|
+
for (var _j = 0; _j < num_negative_pics; _j++) {
|
15350
|
+
eg.readUEG();
|
15351
|
+
eg.readBoolean();
|
15352
|
+
}
|
15353
|
+
for (var _j2 = 0; _j2 < num_positive_pics; _j2++) {
|
15354
|
+
eg.readUEG();
|
15355
|
+
eg.readBoolean();
|
15356
|
+
}
|
15357
|
+
}
|
14852
15358
|
}
|
14853
|
-
|
14854
|
-
if (
|
14855
|
-
|
14856
|
-
var
|
14857
|
-
|
14858
|
-
|
15359
|
+
var long_term_ref_pics_present_flag = eg.readBoolean();
|
15360
|
+
if (long_term_ref_pics_present_flag) {
|
15361
|
+
var num_long_term_ref_pics_sps = eg.readUEG();
|
15362
|
+
for (var _i6 = 0; _i6 < num_long_term_ref_pics_sps; _i6++) {
|
15363
|
+
for (var _j3 = 0; _j3 < log2_max_pic_order_cnt_lsb_minus4 + 4; _j3++) {
|
15364
|
+
eg.readBits(1);
|
15365
|
+
}
|
15366
|
+
eg.readBits(1);
|
15367
|
+
}
|
15368
|
+
}
|
15369
|
+
var min_spatial_segmentation_idc = 0;
|
15370
|
+
var sar_width = 1,
|
15371
|
+
sar_height = 1;
|
15372
|
+
var fps_fixed = true,
|
15373
|
+
fps_den = 1,
|
15374
|
+
fps_num = 0;
|
15375
|
+
eg.readBoolean(); // sps_temporal_mvp_enabled_flag
|
15376
|
+
eg.readBoolean(); // strong_intra_smoothing_enabled_flag
|
15377
|
+
var default_display_window_flag = false;
|
15378
|
+
var vui_parameters_present_flag = eg.readBoolean();
|
15379
|
+
if (vui_parameters_present_flag) {
|
15380
|
+
var aspect_ratio_info_present_flag = eg.readBoolean();
|
15381
|
+
if (aspect_ratio_info_present_flag) {
|
15382
|
+
var aspect_ratio_idc = eg.readUByte();
|
15383
|
+
var sar_width_table = [1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2];
|
15384
|
+
var sar_height_table = [1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1];
|
15385
|
+
if (aspect_ratio_idc > 0 && aspect_ratio_idc < 16) {
|
15386
|
+
sar_width = sar_width_table[aspect_ratio_idc - 1];
|
15387
|
+
sar_height = sar_height_table[aspect_ratio_idc - 1];
|
15388
|
+
} else if (aspect_ratio_idc === 255) {
|
15389
|
+
sar_width = eg.readBits(16);
|
15390
|
+
sar_height = eg.readBits(16);
|
15391
|
+
}
|
15392
|
+
}
|
15393
|
+
var overscan_info_present_flag = eg.readBoolean();
|
15394
|
+
if (overscan_info_present_flag) {
|
15395
|
+
eg.readBoolean();
|
15396
|
+
}
|
15397
|
+
var video_signal_type_present_flag = eg.readBoolean();
|
15398
|
+
if (video_signal_type_present_flag) {
|
15399
|
+
eg.readBits(3);
|
15400
|
+
eg.readBoolean();
|
15401
|
+
var colour_description_present_flag = eg.readBoolean();
|
15402
|
+
if (colour_description_present_flag) {
|
15403
|
+
eg.readUByte();
|
15404
|
+
eg.readUByte();
|
15405
|
+
eg.readUByte();
|
15406
|
+
}
|
15407
|
+
}
|
15408
|
+
var chroma_loc_info_present_flag = eg.readBoolean();
|
15409
|
+
if (chroma_loc_info_present_flag) {
|
15410
|
+
eg.readUEG();
|
15411
|
+
eg.readUEG();
|
15412
|
+
}
|
15413
|
+
eg.readBoolean(); // neutral_chroma_indication_flag
|
15414
|
+
eg.readBoolean(); // field_seq_flag
|
15415
|
+
eg.readBoolean(); // frame_field_info_present_flag
|
15416
|
+
default_display_window_flag = eg.readBoolean();
|
15417
|
+
if (default_display_window_flag) {
|
15418
|
+
pic_left_offset += eg.readUEG();
|
15419
|
+
pic_right_offset += eg.readUEG();
|
15420
|
+
pic_top_offset += eg.readUEG();
|
15421
|
+
pic_bottom_offset += eg.readUEG();
|
15422
|
+
}
|
15423
|
+
var vui_timing_info_present_flag = eg.readBoolean();
|
15424
|
+
if (vui_timing_info_present_flag) {
|
15425
|
+
fps_den = eg.readBits(32);
|
15426
|
+
fps_num = eg.readBits(32);
|
15427
|
+
var vui_poc_proportional_to_timing_flag = eg.readBoolean();
|
15428
|
+
if (vui_poc_proportional_to_timing_flag) {
|
15429
|
+
eg.readUEG();
|
15430
|
+
}
|
15431
|
+
var vui_hrd_parameters_present_flag = eg.readBoolean();
|
15432
|
+
if (vui_hrd_parameters_present_flag) {
|
15433
|
+
//const commonInfPresentFlag = true;
|
15434
|
+
//if (commonInfPresentFlag) {
|
15435
|
+
var nal_hrd_parameters_present_flag = eg.readBoolean();
|
15436
|
+
var vcl_hrd_parameters_present_flag = eg.readBoolean();
|
15437
|
+
var sub_pic_hrd_params_present_flag = false;
|
15438
|
+
if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) {
|
15439
|
+
sub_pic_hrd_params_present_flag = eg.readBoolean();
|
15440
|
+
if (sub_pic_hrd_params_present_flag) {
|
15441
|
+
eg.readUByte();
|
15442
|
+
eg.readBits(5);
|
15443
|
+
eg.readBoolean();
|
15444
|
+
eg.readBits(5);
|
15445
|
+
}
|
15446
|
+
eg.readBits(4); // bit_rate_scale
|
15447
|
+
eg.readBits(4); // cpb_size_scale
|
15448
|
+
if (sub_pic_hrd_params_present_flag) {
|
15449
|
+
eg.readBits(4);
|
15450
|
+
}
|
15451
|
+
eg.readBits(5);
|
15452
|
+
eg.readBits(5);
|
15453
|
+
eg.readBits(5);
|
15454
|
+
}
|
15455
|
+
//}
|
15456
|
+
for (var _i7 = 0; _i7 <= max_sub_layers_minus1; _i7++) {
|
15457
|
+
fps_fixed = eg.readBoolean(); // fixed_pic_rate_general_flag
|
15458
|
+
var fixed_pic_rate_within_cvs_flag = fps_fixed || eg.readBoolean();
|
15459
|
+
var low_delay_hrd_flag = false;
|
15460
|
+
if (fixed_pic_rate_within_cvs_flag) {
|
15461
|
+
eg.readEG();
|
15462
|
+
} else {
|
15463
|
+
low_delay_hrd_flag = eg.readBoolean();
|
15464
|
+
}
|
15465
|
+
var cpb_cnt = low_delay_hrd_flag ? 1 : eg.readUEG() + 1;
|
15466
|
+
if (nal_hrd_parameters_present_flag) {
|
15467
|
+
for (var _j4 = 0; _j4 < cpb_cnt; _j4++) {
|
15468
|
+
eg.readUEG();
|
15469
|
+
eg.readUEG();
|
15470
|
+
if (sub_pic_hrd_params_present_flag) {
|
15471
|
+
eg.readUEG();
|
15472
|
+
eg.readUEG();
|
15473
|
+
}
|
15474
|
+
eg.skipBits(1);
|
15475
|
+
}
|
15476
|
+
}
|
15477
|
+
if (vcl_hrd_parameters_present_flag) {
|
15478
|
+
for (var _j5 = 0; _j5 < cpb_cnt; _j5++) {
|
15479
|
+
eg.readUEG();
|
15480
|
+
eg.readUEG();
|
15481
|
+
if (sub_pic_hrd_params_present_flag) {
|
15482
|
+
eg.readUEG();
|
15483
|
+
eg.readUEG();
|
15484
|
+
}
|
15485
|
+
eg.skipBits(1);
|
15486
|
+
}
|
15487
|
+
}
|
15488
|
+
}
|
15489
|
+
}
|
14859
15490
|
}
|
15491
|
+
var bitstream_restriction_flag = eg.readBoolean();
|
15492
|
+
if (bitstream_restriction_flag) {
|
15493
|
+
eg.readBoolean(); // tiles_fixed_structure_flag
|
15494
|
+
eg.readBoolean(); // motion_vectors_over_pic_boundaries_flag
|
15495
|
+
eg.readBoolean(); // restricted_ref_pic_lists_flag
|
15496
|
+
min_spatial_segmentation_idc = eg.readUEG();
|
15497
|
+
}
|
15498
|
+
}
|
15499
|
+
var width = pic_width_in_luma_samples,
|
15500
|
+
height = pic_height_in_luma_samples;
|
15501
|
+
if (conformance_window_flag || default_display_window_flag) {
|
15502
|
+
var chroma_scale_w = 1,
|
15503
|
+
chroma_scale_h = 1;
|
15504
|
+
if (chroma_format_idc === 1) {
|
15505
|
+
// YUV 420
|
15506
|
+
chroma_scale_w = chroma_scale_h = 2;
|
15507
|
+
} else if (chroma_format_idc == 2) {
|
15508
|
+
// YUV 422
|
15509
|
+
chroma_scale_w = 2;
|
15510
|
+
}
|
15511
|
+
width = pic_width_in_luma_samples - chroma_scale_w * pic_right_offset - chroma_scale_w * pic_left_offset;
|
15512
|
+
height = pic_height_in_luma_samples - chroma_scale_h * pic_bottom_offset - chroma_scale_h * pic_top_offset;
|
15513
|
+
}
|
15514
|
+
var profile_space_string = general_profile_space ? ['A', 'B', 'C'][general_profile_space] : '';
|
15515
|
+
var profile_compatibility_buf = general_profile_compatibility_flags_1 << 24 | general_profile_compatibility_flags_2 << 16 | general_profile_compatibility_flags_3 << 8 | general_profile_compatibility_flags_4;
|
15516
|
+
var profile_compatibility_rev = 0;
|
15517
|
+
for (var _i8 = 0; _i8 < 32; _i8++) {
|
15518
|
+
profile_compatibility_rev = (profile_compatibility_rev | (profile_compatibility_buf >> _i8 & 1) << 31 - _i8) >>> 0; // reverse bit position (and cast as UInt32)
|
15519
|
+
}
|
15520
|
+
var profile_compatibility_flags_string = profile_compatibility_rev.toString(16);
|
15521
|
+
if (general_profile_idc === 1 && profile_compatibility_flags_string === '2') {
|
15522
|
+
profile_compatibility_flags_string = '6';
|
15523
|
+
}
|
15524
|
+
var tier_flag_string = general_tier_flag ? 'H' : 'L';
|
15525
|
+
return {
|
15526
|
+
codecString: "hvc1." + profile_space_string + general_profile_idc + "." + profile_compatibility_flags_string + "." + tier_flag_string + general_level_idc + ".B0",
|
15527
|
+
params: {
|
15528
|
+
general_tier_flag: general_tier_flag,
|
15529
|
+
general_profile_idc: general_profile_idc,
|
15530
|
+
general_profile_space: general_profile_space,
|
15531
|
+
general_profile_compatibility_flags: [general_profile_compatibility_flags_1, general_profile_compatibility_flags_2, general_profile_compatibility_flags_3, general_profile_compatibility_flags_4],
|
15532
|
+
general_constraint_indicator_flags: [general_constraint_indicator_flags_1, general_constraint_indicator_flags_2, general_constraint_indicator_flags_3, general_constraint_indicator_flags_4, general_constraint_indicator_flags_5, general_constraint_indicator_flags_6],
|
15533
|
+
general_level_idc: general_level_idc,
|
15534
|
+
bit_depth: bit_depth_luma_minus8 + 8,
|
15535
|
+
bit_depth_luma_minus8: bit_depth_luma_minus8,
|
15536
|
+
bit_depth_chroma_minus8: bit_depth_chroma_minus8,
|
15537
|
+
min_spatial_segmentation_idc: min_spatial_segmentation_idc,
|
15538
|
+
chroma_format_idc: chroma_format_idc,
|
15539
|
+
frame_rate: {
|
15540
|
+
fixed: fps_fixed,
|
15541
|
+
fps: fps_num / fps_den
|
15542
|
+
}
|
15543
|
+
},
|
15544
|
+
width: width,
|
15545
|
+
height: height,
|
15546
|
+
pixelRatio: [sar_width, sar_height]
|
15547
|
+
};
|
15548
|
+
};
|
15549
|
+
_proto.readPPS = function readPPS(pps) {
|
15550
|
+
var eg = new ExpGolomb(this.ebsp2rbsp(pps));
|
15551
|
+
eg.readUByte();
|
15552
|
+
eg.readUByte();
|
15553
|
+
eg.skipUEG(); // pic_parameter_set_id
|
15554
|
+
eg.skipUEG(); // seq_parameter_set_id
|
15555
|
+
eg.skipBits(2); // dependent_slice_segments_enabled_flag, output_flag_present_flag
|
15556
|
+
eg.skipBits(3); // num_extra_slice_header_bits
|
15557
|
+
eg.skipBits(2); // sign_data_hiding_enabled_flag, cabac_init_present_flag
|
15558
|
+
eg.skipUEG();
|
15559
|
+
eg.skipUEG();
|
15560
|
+
eg.skipEG(); // init_qp_minus26
|
15561
|
+
eg.skipBits(2); // constrained_intra_pred_flag, transform_skip_enabled_flag
|
15562
|
+
var cu_qp_delta_enabled_flag = eg.readBoolean();
|
15563
|
+
if (cu_qp_delta_enabled_flag) {
|
15564
|
+
eg.skipUEG();
|
15565
|
+
}
|
15566
|
+
eg.skipEG(); // cb_qp_offset
|
15567
|
+
eg.skipEG(); // cr_qp_offset
|
15568
|
+
eg.skipBits(4); // pps_slice_chroma_qp_offsets_present_flag, weighted_pred_flag, weighted_bipred_flag, transquant_bypass_enabled_flag
|
15569
|
+
var tiles_enabled_flag = eg.readBoolean();
|
15570
|
+
var entropy_coding_sync_enabled_flag = eg.readBoolean();
|
15571
|
+
var parallelismType = 1; // slice-based parallel decoding
|
15572
|
+
if (entropy_coding_sync_enabled_flag && tiles_enabled_flag) {
|
15573
|
+
parallelismType = 0; // mixed-type parallel decoding
|
15574
|
+
} else if (entropy_coding_sync_enabled_flag) {
|
15575
|
+
parallelismType = 3; // wavefront-based parallel decoding
|
15576
|
+
} else if (tiles_enabled_flag) {
|
15577
|
+
parallelismType = 2; // tile-based parallel decoding
|
14860
15578
|
}
|
14861
|
-
|
14862
|
-
|
15579
|
+
return {
|
15580
|
+
parallelismType: parallelismType
|
15581
|
+
};
|
14863
15582
|
};
|
14864
|
-
|
15583
|
+
_proto.matchSPS = function matchSPS(sps1, sps2) {
|
15584
|
+
// compare without headers and VPS related params
|
15585
|
+
return String.fromCharCode.apply(null, sps1).substr(3) === String.fromCharCode.apply(null, sps2).substr(3);
|
15586
|
+
};
|
15587
|
+
return HevcVideoParser;
|
14865
15588
|
}(BaseVideoParser);
|
14866
15589
|
|
14867
15590
|
/**
|
@@ -14879,7 +15602,7 @@
|
|
14879
15602
|
}
|
14880
15603
|
var _proto = SampleAesDecrypter.prototype;
|
14881
15604
|
_proto.decryptBuffer = function decryptBuffer(encryptedData) {
|
14882
|
-
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer);
|
15605
|
+
return this.decrypter.decrypt(encryptedData, this.keyData.key.buffer, this.keyData.iv.buffer, DecrypterAesMode.cbc);
|
14883
15606
|
}
|
14884
15607
|
|
14885
15608
|
// AAC - encrypt all full 16 bytes blocks starting from offset 16
|
@@ -14998,7 +15721,7 @@
|
|
14998
15721
|
this.observer = observer;
|
14999
15722
|
this.config = config;
|
15000
15723
|
this.typeSupported = typeSupported;
|
15001
|
-
this.videoParser =
|
15724
|
+
this.videoParser = null;
|
15002
15725
|
}
|
15003
15726
|
TSDemuxer.probe = function probe(data) {
|
15004
15727
|
var syncOffset = TSDemuxer.syncOffset(data);
|
@@ -15168,7 +15891,19 @@
|
|
15168
15891
|
case videoPid:
|
15169
15892
|
if (stt) {
|
15170
15893
|
if (videoData && (pes = parsePES(videoData))) {
|
15171
|
-
this.videoParser
|
15894
|
+
if (this.videoParser === null) {
|
15895
|
+
switch (videoTrack.segmentCodec) {
|
15896
|
+
case 'avc':
|
15897
|
+
this.videoParser = new AvcVideoParser();
|
15898
|
+
break;
|
15899
|
+
case 'hevc':
|
15900
|
+
this.videoParser = new HevcVideoParser();
|
15901
|
+
break;
|
15902
|
+
}
|
15903
|
+
}
|
15904
|
+
if (this.videoParser !== null) {
|
15905
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, false, this._duration);
|
15906
|
+
}
|
15172
15907
|
}
|
15173
15908
|
videoData = {
|
15174
15909
|
data: [],
|
@@ -15326,8 +16061,20 @@
|
|
15326
16061
|
// try to parse last PES packets
|
15327
16062
|
var pes;
|
15328
16063
|
if (videoData && (pes = parsePES(videoData))) {
|
15329
|
-
this.videoParser
|
15330
|
-
|
16064
|
+
if (this.videoParser === null) {
|
16065
|
+
switch (videoTrack.segmentCodec) {
|
16066
|
+
case 'avc':
|
16067
|
+
this.videoParser = new AvcVideoParser();
|
16068
|
+
break;
|
16069
|
+
case 'hevc':
|
16070
|
+
this.videoParser = new HevcVideoParser();
|
16071
|
+
break;
|
16072
|
+
}
|
16073
|
+
}
|
16074
|
+
if (this.videoParser !== null) {
|
16075
|
+
this.videoParser.parsePES(videoTrack, textTrack, pes, true, this._duration);
|
16076
|
+
videoTrack.pesData = null;
|
16077
|
+
}
|
15331
16078
|
} else {
|
15332
16079
|
// either avcData null or PES truncated, keep it for next frag parsing
|
15333
16080
|
videoTrack.pesData = videoData;
|
@@ -15629,7 +16376,12 @@
|
|
15629
16376
|
logger.warn('Unsupported EC-3 in M2TS found');
|
15630
16377
|
break;
|
15631
16378
|
case 0x24:
|
15632
|
-
|
16379
|
+
// ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
|
16380
|
+
if (result.videoPid === -1) {
|
16381
|
+
result.videoPid = pid;
|
16382
|
+
result.segmentVideoCodec = 'hevc';
|
16383
|
+
logger.log('HEVC in M2TS found');
|
16384
|
+
}
|
15633
16385
|
break;
|
15634
16386
|
}
|
15635
16387
|
// move to the next table entry
|
@@ -15857,6 +16609,8 @@
|
|
15857
16609
|
avc1: [],
|
15858
16610
|
// codingname
|
15859
16611
|
avcC: [],
|
16612
|
+
hvc1: [],
|
16613
|
+
hvcC: [],
|
15860
16614
|
btrt: [],
|
15861
16615
|
dinf: [],
|
15862
16616
|
dref: [],
|
@@ -16284,8 +17038,10 @@
|
|
16284
17038
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
|
16285
17039
|
}
|
16286
17040
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
|
16287
|
-
} else {
|
17041
|
+
} else if (track.segmentCodec === 'avc') {
|
16288
17042
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.avc1(track));
|
17043
|
+
} else {
|
17044
|
+
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.hvc1(track));
|
16289
17045
|
}
|
16290
17046
|
};
|
16291
17047
|
MP4.tkhd = function tkhd(track) {
|
@@ -16423,6 +17179,84 @@
|
|
16423
17179
|
var result = appendUint8Array(MP4.FTYP, movie);
|
16424
17180
|
return result;
|
16425
17181
|
};
|
17182
|
+
MP4.hvc1 = function hvc1(track) {
|
17183
|
+
var ps = track.params;
|
17184
|
+
var units = [track.vps, track.sps, track.pps];
|
17185
|
+
var NALuLengthSize = 4;
|
17186
|
+
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]);
|
17187
|
+
|
17188
|
+
// compute hvcC size in bytes
|
17189
|
+
var length = config.length;
|
17190
|
+
for (var i = 0; i < units.length; i += 1) {
|
17191
|
+
length += 3;
|
17192
|
+
for (var j = 0; j < units[i].length; j += 1) {
|
17193
|
+
length += 2 + units[i][j].length;
|
17194
|
+
}
|
17195
|
+
}
|
17196
|
+
var hvcC = new Uint8Array(length);
|
17197
|
+
hvcC.set(config, 0);
|
17198
|
+
length = config.length;
|
17199
|
+
// append parameter set units: one vps, one or more sps and pps
|
17200
|
+
var iMax = units.length - 1;
|
17201
|
+
for (var _i = 0; _i < units.length; _i += 1) {
|
17202
|
+
hvcC.set(new Uint8Array([32 + _i | (_i === iMax ? 128 : 0), 0x00, units[_i].length]), length);
|
17203
|
+
length += 3;
|
17204
|
+
for (var _j = 0; _j < units[_i].length; _j += 1) {
|
17205
|
+
hvcC.set(new Uint8Array([units[_i][_j].length >> 8, units[_i][_j].length & 255]), length);
|
17206
|
+
length += 2;
|
17207
|
+
hvcC.set(units[_i][_j], length);
|
17208
|
+
length += units[_i][_j].length;
|
17209
|
+
}
|
17210
|
+
}
|
17211
|
+
var hvcc = MP4.box(MP4.types.hvcC, hvcC);
|
17212
|
+
var width = track.width;
|
17213
|
+
var height = track.height;
|
17214
|
+
var hSpacing = track.pixelRatio[0];
|
17215
|
+
var vSpacing = track.pixelRatio[1];
|
17216
|
+
return MP4.box(MP4.types.hvc1, new Uint8Array([0x00, 0x00, 0x00,
|
17217
|
+
// reserved
|
17218
|
+
0x00, 0x00, 0x00,
|
17219
|
+
// reserved
|
17220
|
+
0x00, 0x01,
|
17221
|
+
// data_reference_index
|
17222
|
+
0x00, 0x00,
|
17223
|
+
// pre_defined
|
17224
|
+
0x00, 0x00,
|
17225
|
+
// reserved
|
17226
|
+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
17227
|
+
// pre_defined
|
17228
|
+
width >> 8 & 0xff, width & 0xff,
|
17229
|
+
// width
|
17230
|
+
height >> 8 & 0xff, height & 0xff,
|
17231
|
+
// height
|
17232
|
+
0x00, 0x48, 0x00, 0x00,
|
17233
|
+
// horizresolution
|
17234
|
+
0x00, 0x48, 0x00, 0x00,
|
17235
|
+
// vertresolution
|
17236
|
+
0x00, 0x00, 0x00, 0x00,
|
17237
|
+
// reserved
|
17238
|
+
0x00, 0x01,
|
17239
|
+
// frame_count
|
17240
|
+
0x12, 0x64, 0x61, 0x69, 0x6c,
|
17241
|
+
// dailymotion/hls.js
|
17242
|
+
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,
|
17243
|
+
// compressorname
|
17244
|
+
0x00, 0x18,
|
17245
|
+
// depth = 24
|
17246
|
+
0x11, 0x11]),
|
17247
|
+
// pre_defined = -1
|
17248
|
+
hvcc, MP4.box(MP4.types.btrt, new Uint8Array([0x00, 0x1c, 0x9c, 0x80,
|
17249
|
+
// bufferSizeDB
|
17250
|
+
0x00, 0x2d, 0xc6, 0xc0,
|
17251
|
+
// maxBitrate
|
17252
|
+
0x00, 0x2d, 0xc6, 0xc0])),
|
17253
|
+
// avgBitrate
|
17254
|
+
MP4.box(MP4.types.pasp, new Uint8Array([hSpacing >> 24,
|
17255
|
+
// hSpacing
|
17256
|
+
hSpacing >> 16 & 0xff, hSpacing >> 8 & 0xff, hSpacing & 0xff, vSpacing >> 24,
|
17257
|
+
// vSpacing
|
17258
|
+
vSpacing >> 16 & 0xff, vSpacing >> 8 & 0xff, vSpacing & 0xff])));
|
17259
|
+
};
|
16426
17260
|
return MP4;
|
16427
17261
|
}();
|
16428
17262
|
MP4.types = void 0;
|
@@ -16809,9 +17643,9 @@
|
|
16809
17643
|
var foundOverlap = delta < -1;
|
16810
17644
|
if (foundHole || foundOverlap) {
|
16811
17645
|
if (foundHole) {
|
16812
|
-
logger.warn("
|
17646
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
|
16813
17647
|
} else {
|
16814
|
-
logger.warn("
|
17648
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
|
16815
17649
|
}
|
16816
17650
|
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
|
16817
17651
|
firstDTS = nextAvcDts;
|
@@ -16820,12 +17654,24 @@
|
|
16820
17654
|
inputSamples[0].dts = firstDTS;
|
16821
17655
|
inputSamples[0].pts = firstPTS;
|
16822
17656
|
} else {
|
17657
|
+
var isPTSOrderRetained = true;
|
16823
17658
|
for (var _i = 0; _i < inputSamples.length; _i++) {
|
16824
|
-
if (inputSamples[_i].dts > firstPTS) {
|
17659
|
+
if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
|
16825
17660
|
break;
|
16826
17661
|
}
|
17662
|
+
var prevPTS = inputSamples[_i].pts;
|
16827
17663
|
inputSamples[_i].dts -= delta;
|
16828
17664
|
inputSamples[_i].pts -= delta;
|
17665
|
+
|
17666
|
+
// check to see if this sample's PTS order has changed
|
17667
|
+
// relative to the next one
|
17668
|
+
if (_i < inputSamples.length - 1) {
|
17669
|
+
var nextSamplePTS = inputSamples[_i + 1].pts;
|
17670
|
+
var currentSamplePTS = inputSamples[_i].pts;
|
17671
|
+
var currentOrder = nextSamplePTS <= currentSamplePTS;
|
17672
|
+
var prevOrder = nextSamplePTS <= prevPTS;
|
17673
|
+
isPTSOrderRetained = currentOrder == prevOrder;
|
17674
|
+
}
|
16829
17675
|
}
|
16830
17676
|
}
|
16831
17677
|
logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
|
@@ -16973,7 +17819,7 @@
|
|
16973
17819
|
}
|
16974
17820
|
}
|
16975
17821
|
}
|
16976
|
-
// next AVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
17822
|
+
// next AVC/HEVC sample DTS should be equal to last sample DTS + last sample duration (in PES timescale)
|
16977
17823
|
mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
|
16978
17824
|
this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
|
16979
17825
|
this.videoSampleDuration = mp4SampleDuration;
|
@@ -17108,7 +17954,7 @@
|
|
17108
17954
|
logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
|
17109
17955
|
for (var j = 0; j < missing; j++) {
|
17110
17956
|
var newStamp = Math.max(nextPts, 0);
|
17111
|
-
var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17957
|
+
var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17112
17958
|
if (!fillFrame) {
|
17113
17959
|
logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
17114
17960
|
fillFrame = sample.unit.subarray();
|
@@ -17236,7 +18082,7 @@
|
|
17236
18082
|
// samples count of this segment's duration
|
17237
18083
|
var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
|
17238
18084
|
// silent frame
|
17239
|
-
var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
18085
|
+
var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17240
18086
|
logger.warn('[mp4-remuxer]: remux empty Audio');
|
17241
18087
|
// Can't remux if we can't generate a silent frame...
|
17242
18088
|
if (!silentFrame) {
|
@@ -17623,13 +18469,15 @@
|
|
17623
18469
|
duration = transmuxConfig.duration,
|
17624
18470
|
initSegmentData = transmuxConfig.initSegmentData;
|
17625
18471
|
var keyData = getEncryptionType(uintData, decryptdata);
|
17626
|
-
if (keyData && keyData.method
|
18472
|
+
if (keyData && isFullSegmentEncryption(keyData.method)) {
|
17627
18473
|
var decrypter = this.getDecrypter();
|
18474
|
+
var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
18475
|
+
|
17628
18476
|
// Software decryption is synchronous; webCrypto is not
|
17629
18477
|
if (decrypter.isSync()) {
|
17630
18478
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
17631
18479
|
// data is handled in the flush() call
|
17632
|
-
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
|
18480
|
+
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
|
17633
18481
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
17634
18482
|
var loadingParts = chunkMeta.part > -1;
|
17635
18483
|
if (loadingParts) {
|
@@ -17641,7 +18489,7 @@
|
|
17641
18489
|
}
|
17642
18490
|
uintData = new Uint8Array(decryptedData);
|
17643
18491
|
} else {
|
17644
|
-
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer).then(function (decryptedData) {
|
18492
|
+
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(function (decryptedData) {
|
17645
18493
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
17646
18494
|
// the decrypted data has been transmuxed
|
17647
18495
|
var result = _this.push(decryptedData, null, chunkMeta);
|
@@ -18262,7 +19110,7 @@
|
|
18262
19110
|
observer.on(Events.ERROR, forwardMessage);
|
18263
19111
|
|
18264
19112
|
// forward logger events to main thread
|
18265
|
-
var forwardWorkerLogs = function forwardWorkerLogs() {
|
19113
|
+
var forwardWorkerLogs = function forwardWorkerLogs(logger) {
|
18266
19114
|
var _loop = function _loop(logFn) {
|
18267
19115
|
var func = function func(message) {
|
18268
19116
|
forwardMessage('workerLog', {
|
@@ -18283,8 +19131,8 @@
|
|
18283
19131
|
{
|
18284
19132
|
var config = JSON.parse(data.config);
|
18285
19133
|
self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
|
18286
|
-
enableLogs(config.debug, data.id);
|
18287
|
-
forwardWorkerLogs();
|
19134
|
+
var logger = enableLogs(config.debug, data.id);
|
19135
|
+
forwardWorkerLogs(logger);
|
18288
19136
|
forwardMessage('init', null);
|
18289
19137
|
break;
|
18290
19138
|
}
|
@@ -18458,16 +19306,7 @@
|
|
18458
19306
|
this.observer = new EventEmitter();
|
18459
19307
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
18460
19308
|
this.observer.on(Events.ERROR, forwardMessage);
|
18461
|
-
var
|
18462
|
-
isTypeSupported: function isTypeSupported() {
|
18463
|
-
return false;
|
18464
|
-
}
|
18465
|
-
};
|
18466
|
-
var m2tsTypeSupported = {
|
18467
|
-
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
18468
|
-
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
18469
|
-
ac3: false
|
18470
|
-
};
|
19309
|
+
var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
|
18471
19310
|
|
18472
19311
|
// navigator.vendor is not always available in Web Worker
|
18473
19312
|
// refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
|
@@ -18724,21 +19563,26 @@
|
|
18724
19563
|
var MAX_START_GAP_JUMP = 2.0;
|
18725
19564
|
var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
18726
19565
|
var SKIP_BUFFER_RANGE_START = 0.05;
|
18727
|
-
var GapController = /*#__PURE__*/function () {
|
19566
|
+
var GapController = /*#__PURE__*/function (_Logger) {
|
19567
|
+
_inheritsLoose(GapController, _Logger);
|
18728
19568
|
function GapController(config, media, fragmentTracker, hls) {
|
18729
|
-
|
18730
|
-
this.
|
18731
|
-
|
18732
|
-
|
18733
|
-
|
18734
|
-
|
18735
|
-
|
18736
|
-
|
18737
|
-
|
18738
|
-
|
18739
|
-
|
18740
|
-
|
18741
|
-
|
19569
|
+
var _this;
|
19570
|
+
_this = _Logger.call(this, 'gap-controller', hls.logger) || this;
|
19571
|
+
_this.config = void 0;
|
19572
|
+
_this.media = null;
|
19573
|
+
_this.fragmentTracker = void 0;
|
19574
|
+
_this.hls = void 0;
|
19575
|
+
_this.nudgeRetry = 0;
|
19576
|
+
_this.stallReported = false;
|
19577
|
+
_this.stalled = null;
|
19578
|
+
_this.moved = false;
|
19579
|
+
_this.seeking = false;
|
19580
|
+
_this.ended = 0;
|
19581
|
+
_this.config = config;
|
19582
|
+
_this.media = media;
|
19583
|
+
_this.fragmentTracker = fragmentTracker;
|
19584
|
+
_this.hls = hls;
|
19585
|
+
return _this;
|
18742
19586
|
}
|
18743
19587
|
var _proto = GapController.prototype;
|
18744
19588
|
_proto.destroy = function destroy() {
|
@@ -18753,7 +19597,7 @@
|
|
18753
19597
|
*
|
18754
19598
|
* @param lastCurrentTime - Previously read playhead position
|
18755
19599
|
*/;
|
18756
|
-
_proto.poll = function poll(lastCurrentTime, activeFrag) {
|
19600
|
+
_proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
|
18757
19601
|
var config = this.config,
|
18758
19602
|
media = this.media,
|
18759
19603
|
stalled = this.stalled;
|
@@ -18768,6 +19612,7 @@
|
|
18768
19612
|
|
18769
19613
|
// The playhead is moving, no-op
|
18770
19614
|
if (currentTime !== lastCurrentTime) {
|
19615
|
+
this.ended = 0;
|
18771
19616
|
this.moved = true;
|
18772
19617
|
if (!seeking) {
|
18773
19618
|
this.nudgeRetry = 0;
|
@@ -18776,7 +19621,7 @@
|
|
18776
19621
|
// The playhead is now moving, but was previously stalled
|
18777
19622
|
if (this.stallReported) {
|
18778
19623
|
var _stalledDuration = self.performance.now() - stalled;
|
18779
|
-
|
19624
|
+
this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
|
18780
19625
|
this.stallReported = false;
|
18781
19626
|
}
|
18782
19627
|
this.stalled = null;
|
@@ -18812,7 +19657,6 @@
|
|
18812
19657
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
18813
19658
|
// The addition poll gives the browser a chance to jump the gap for us
|
18814
19659
|
if (!this.moved && this.stalled !== null) {
|
18815
|
-
var _level$details;
|
18816
19660
|
// There is no playable buffer (seeked, waiting for buffer)
|
18817
19661
|
var isBuffered = bufferInfo.len > 0;
|
18818
19662
|
if (!isBuffered && !nextStart) {
|
@@ -18824,9 +19668,8 @@
|
|
18824
19668
|
// When joining a live stream with audio tracks, account for live playlist window sliding by allowing
|
18825
19669
|
// a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
|
18826
19670
|
// that begins over 1 target duration after the video start position.
|
18827
|
-
var
|
18828
|
-
var
|
18829
|
-
var maxStartGapJump = isLive ? level.details.targetduration * 2 : MAX_START_GAP_JUMP;
|
19671
|
+
var isLive = !!(levelDetails != null && levelDetails.live);
|
19672
|
+
var maxStartGapJump = isLive ? levelDetails.targetduration * 2 : MAX_START_GAP_JUMP;
|
18830
19673
|
var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
|
18831
19674
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
18832
19675
|
if (!media.paused) {
|
@@ -18844,6 +19687,17 @@
|
|
18844
19687
|
}
|
18845
19688
|
var stalledDuration = tnow - stalled;
|
18846
19689
|
if (!seeking && stalledDuration >= STALL_MINIMUM_DURATION_MS) {
|
19690
|
+
// Dispatch MEDIA_ENDED when media.ended/ended event is not signalled at end of stream
|
19691
|
+
if (state === State.ENDED && !(levelDetails && levelDetails.live) && Math.abs(currentTime - ((levelDetails == null ? void 0 : levelDetails.edge) || 0)) < 1) {
|
19692
|
+
if (stalledDuration < 1000 || this.ended) {
|
19693
|
+
return;
|
19694
|
+
}
|
19695
|
+
this.ended = currentTime;
|
19696
|
+
this.hls.trigger(Events.MEDIA_ENDED, {
|
19697
|
+
stalled: true
|
19698
|
+
});
|
19699
|
+
return;
|
19700
|
+
}
|
18847
19701
|
// Report stalling after trying to fix
|
18848
19702
|
this._reportStall(bufferInfo);
|
18849
19703
|
if (!this.media) {
|
@@ -18885,7 +19739,7 @@
|
|
18885
19739
|
// needs to cross some sort of threshold covering all source-buffers content
|
18886
19740
|
// to start playing properly.
|
18887
19741
|
if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
18888
|
-
|
19742
|
+
this.warn('Trying to nudge playhead over buffer-hole');
|
18889
19743
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
18890
19744
|
// We only try to jump the hole if it's under the configured size
|
18891
19745
|
// Reset stalled so to rearm watchdog timer
|
@@ -18907,7 +19761,7 @@
|
|
18907
19761
|
// Report stalled error once
|
18908
19762
|
this.stallReported = true;
|
18909
19763
|
var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
|
18910
|
-
|
19764
|
+
this.warn(error.message);
|
18911
19765
|
hls.trigger(Events.ERROR, {
|
18912
19766
|
type: ErrorTypes.MEDIA_ERROR,
|
18913
19767
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -18971,7 +19825,7 @@
|
|
18971
19825
|
}
|
18972
19826
|
}
|
18973
19827
|
var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
18974
|
-
|
19828
|
+
this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
|
18975
19829
|
this.moved = true;
|
18976
19830
|
this.stalled = null;
|
18977
19831
|
media.currentTime = targetTime;
|
@@ -19010,7 +19864,7 @@
|
|
19010
19864
|
var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
|
19011
19865
|
// playback stalled in buffered area ... let's nudge currentTime to try to overcome this
|
19012
19866
|
var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
|
19013
|
-
|
19867
|
+
this.warn(error.message);
|
19014
19868
|
media.currentTime = targetTime;
|
19015
19869
|
hls.trigger(Events.ERROR, {
|
19016
19870
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -19020,7 +19874,7 @@
|
|
19020
19874
|
});
|
19021
19875
|
} else {
|
19022
19876
|
var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
|
19023
|
-
|
19877
|
+
this.error(_error.message);
|
19024
19878
|
hls.trigger(Events.ERROR, {
|
19025
19879
|
type: ErrorTypes.MEDIA_ERROR,
|
19026
19880
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -19030,14 +19884,14 @@
|
|
19030
19884
|
}
|
19031
19885
|
};
|
19032
19886
|
return GapController;
|
19033
|
-
}();
|
19887
|
+
}(Logger);
|
19034
19888
|
|
19035
19889
|
var TICK_INTERVAL = 100; // how often to tick in ms
|
19036
19890
|
var StreamController = /*#__PURE__*/function (_BaseStreamController) {
|
19037
19891
|
_inheritsLoose(StreamController, _BaseStreamController);
|
19038
19892
|
function StreamController(hls, fragmentTracker, keyLoader) {
|
19039
19893
|
var _this;
|
19040
|
-
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '
|
19894
|
+
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
|
19041
19895
|
_this.audioCodecSwap = false;
|
19042
19896
|
_this.gapController = null;
|
19043
19897
|
_this.level = -1;
|
@@ -19045,27 +19899,43 @@
|
|
19045
19899
|
_this.altAudio = false;
|
19046
19900
|
_this.audioOnly = false;
|
19047
19901
|
_this.fragPlaying = null;
|
19048
|
-
_this.onvplaying = null;
|
19049
|
-
_this.onvseeked = null;
|
19050
19902
|
_this.fragLastKbps = 0;
|
19051
19903
|
_this.couldBacktrack = false;
|
19052
19904
|
_this.backtrackFragment = null;
|
19053
19905
|
_this.audioCodecSwitch = false;
|
19054
19906
|
_this.videoBuffer = null;
|
19055
|
-
_this.
|
19907
|
+
_this.onMediaPlaying = function () {
|
19908
|
+
// tick to speed up FRAG_CHANGED triggering
|
19909
|
+
_this.tick();
|
19910
|
+
};
|
19911
|
+
_this.onMediaSeeked = function () {
|
19912
|
+
var media = _this.media;
|
19913
|
+
var currentTime = media ? media.currentTime : null;
|
19914
|
+
if (isFiniteNumber(currentTime)) {
|
19915
|
+
_this.log("Media seeked to " + currentTime.toFixed(3));
|
19916
|
+
}
|
19917
|
+
|
19918
|
+
// If seeked was issued before buffer was appended do not tick immediately
|
19919
|
+
var bufferInfo = _this.getMainFwdBufferInfo();
|
19920
|
+
if (bufferInfo === null || bufferInfo.len === 0) {
|
19921
|
+
_this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19922
|
+
return;
|
19923
|
+
}
|
19924
|
+
|
19925
|
+
// tick to speed up FRAG_CHANGED triggering
|
19926
|
+
_this.tick();
|
19927
|
+
};
|
19928
|
+
_this.registerListeners();
|
19056
19929
|
return _this;
|
19057
19930
|
}
|
19058
19931
|
var _proto = StreamController.prototype;
|
19059
|
-
_proto.
|
19932
|
+
_proto.registerListeners = function registerListeners() {
|
19933
|
+
_BaseStreamController.prototype.registerListeners.call(this);
|
19060
19934
|
var hls = this.hls;
|
19061
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19062
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19063
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19064
19935
|
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19065
19936
|
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
|
19066
19937
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19067
19938
|
hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19068
|
-
hls.on(Events.ERROR, this.onError, this);
|
19069
19939
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19070
19940
|
hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19071
19941
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19073,15 +19943,12 @@
|
|
19073
19943
|
hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
|
19074
19944
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19075
19945
|
};
|
19076
|
-
_proto.
|
19946
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
19947
|
+
_BaseStreamController.prototype.unregisterListeners.call(this);
|
19077
19948
|
var hls = this.hls;
|
19078
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19079
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19080
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19081
19949
|
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19082
19950
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19083
19951
|
hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19084
|
-
hls.off(Events.ERROR, this.onError, this);
|
19085
19952
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19086
19953
|
hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19087
19954
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19090,7 +19957,9 @@
|
|
19090
19957
|
hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19091
19958
|
};
|
19092
19959
|
_proto.onHandlerDestroying = function onHandlerDestroying() {
|
19093
|
-
|
19960
|
+
// @ts-ignore
|
19961
|
+
this.onMediaPlaying = this.onMediaSeeked = null;
|
19962
|
+
this.unregisterListeners();
|
19094
19963
|
_BaseStreamController.prototype.onHandlerDestroying.call(this);
|
19095
19964
|
};
|
19096
19965
|
_proto.startLoad = function startLoad(startPosition) {
|
@@ -19114,7 +19983,8 @@
|
|
19114
19983
|
}
|
19115
19984
|
// set new level to playlist loader : this will trigger start level load
|
19116
19985
|
// hls.nextLoadLevel remains until it is set to a new value or until a new frag is successfully loaded
|
19117
|
-
|
19986
|
+
hls.nextLoadLevel = startLevel;
|
19987
|
+
this.level = hls.loadLevel;
|
19118
19988
|
this.loadedmetadata = false;
|
19119
19989
|
}
|
19120
19990
|
// if startPosition undefined but lastCurrentTime set, set startPosition to last currentTime
|
@@ -19199,7 +20069,7 @@
|
|
19199
20069
|
if (this.altAudio && this.audioOnly) {
|
19200
20070
|
return;
|
19201
20071
|
}
|
19202
|
-
if (!(levels != null && levels[level])) {
|
20072
|
+
if (!this.buffering || !(levels != null && levels[level])) {
|
19203
20073
|
return;
|
19204
20074
|
}
|
19205
20075
|
var levelInfo = levels[level];
|
@@ -19405,18 +20275,15 @@
|
|
19405
20275
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
19406
20276
|
_BaseStreamController.prototype.onMediaAttached.call(this, event, data);
|
19407
20277
|
var media = data.media;
|
19408
|
-
|
19409
|
-
|
19410
|
-
media.addEventListener('playing', this.onvplaying);
|
19411
|
-
media.addEventListener('seeked', this.onvseeked);
|
20278
|
+
media.addEventListener('playing', this.onMediaPlaying);
|
20279
|
+
media.addEventListener('seeked', this.onMediaSeeked);
|
19412
20280
|
this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
|
19413
20281
|
};
|
19414
20282
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
19415
20283
|
var media = this.media;
|
19416
|
-
if (media
|
19417
|
-
media.removeEventListener('playing', this.
|
19418
|
-
media.removeEventListener('seeked', this.
|
19419
|
-
this.onvplaying = this.onvseeked = null;
|
20284
|
+
if (media) {
|
20285
|
+
media.removeEventListener('playing', this.onMediaPlaying);
|
20286
|
+
media.removeEventListener('seeked', this.onMediaSeeked);
|
19420
20287
|
this.videoBuffer = null;
|
19421
20288
|
}
|
19422
20289
|
this.fragPlaying = null;
|
@@ -19426,27 +20293,6 @@
|
|
19426
20293
|
}
|
19427
20294
|
_BaseStreamController.prototype.onMediaDetaching.call(this);
|
19428
20295
|
};
|
19429
|
-
_proto.onMediaPlaying = function onMediaPlaying() {
|
19430
|
-
// tick to speed up FRAG_CHANGED triggering
|
19431
|
-
this.tick();
|
19432
|
-
};
|
19433
|
-
_proto.onMediaSeeked = function onMediaSeeked() {
|
19434
|
-
var media = this.media;
|
19435
|
-
var currentTime = media ? media.currentTime : null;
|
19436
|
-
if (isFiniteNumber(currentTime)) {
|
19437
|
-
this.log("Media seeked to " + currentTime.toFixed(3));
|
19438
|
-
}
|
19439
|
-
|
19440
|
-
// If seeked was issued before buffer was appended do not tick immediately
|
19441
|
-
var bufferInfo = this.getMainFwdBufferInfo();
|
19442
|
-
if (bufferInfo === null || bufferInfo.len === 0) {
|
19443
|
-
this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19444
|
-
return;
|
19445
|
-
}
|
19446
|
-
|
19447
|
-
// tick to speed up FRAG_CHANGED triggering
|
19448
|
-
this.tick();
|
19449
|
-
};
|
19450
20296
|
_proto.onManifestLoading = function onManifestLoading() {
|
19451
20297
|
// reset buffer on manifest loading
|
19452
20298
|
this.log('Trigger BUFFER_RESET');
|
@@ -19727,8 +20573,10 @@
|
|
19727
20573
|
}
|
19728
20574
|
if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
|
19729
20575
|
// Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
|
19730
|
-
var
|
19731
|
-
|
20576
|
+
var state = this.state;
|
20577
|
+
var activeFrag = state !== State.IDLE ? this.fragCurrent : null;
|
20578
|
+
var levelDetails = this.getLevelDetails();
|
20579
|
+
gapController.poll(this.lastCurrentTime, activeFrag, levelDetails, state);
|
19732
20580
|
}
|
19733
20581
|
this.lastCurrentTime = media.currentTime;
|
19734
20582
|
};
|
@@ -20193,9 +21041,12 @@
|
|
20193
21041
|
* The configuration object provided on player instantiation.
|
20194
21042
|
*/
|
20195
21043
|
this.userConfig = void 0;
|
21044
|
+
/**
|
21045
|
+
* The logger functions used by this player instance, configured on player instantiation.
|
21046
|
+
*/
|
21047
|
+
this.logger = void 0;
|
20196
21048
|
this.coreComponents = void 0;
|
20197
21049
|
this.networkControllers = void 0;
|
20198
|
-
this.started = false;
|
20199
21050
|
this._emitter = new EventEmitter();
|
20200
21051
|
this._autoLevelCapping = -1;
|
20201
21052
|
this._maxHdcpLevel = null;
|
@@ -20212,11 +21063,11 @@
|
|
20212
21063
|
this._media = null;
|
20213
21064
|
this.url = null;
|
20214
21065
|
this.triggeringException = void 0;
|
20215
|
-
enableLogs(userConfig.debug || false, 'Hls instance');
|
20216
|
-
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig);
|
21066
|
+
var logger = this.logger = enableLogs(userConfig.debug || false, 'Hls instance');
|
21067
|
+
var config = this.config = mergeConfig(Hls.DefaultConfig, userConfig, logger);
|
20217
21068
|
this.userConfig = userConfig;
|
20218
21069
|
if (config.progressive) {
|
20219
|
-
enableStreamingMode(config);
|
21070
|
+
enableStreamingMode(config, logger);
|
20220
21071
|
}
|
20221
21072
|
|
20222
21073
|
// core controllers and network loaders
|
@@ -20324,7 +21175,7 @@
|
|
20324
21175
|
try {
|
20325
21176
|
return this.emit(event, event, eventObject);
|
20326
21177
|
} catch (error) {
|
20327
|
-
logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
21178
|
+
this.logger.error('An internal error happened while handling event ' + event + '. Error message: "' + error.message + '". Here is a stacktrace:', error);
|
20328
21179
|
// Prevent recursion in error event handlers that throw #5497
|
20329
21180
|
if (!this.triggeringException) {
|
20330
21181
|
this.triggeringException = true;
|
@@ -20350,7 +21201,7 @@
|
|
20350
21201
|
* Dispose of the instance
|
20351
21202
|
*/;
|
20352
21203
|
_proto.destroy = function destroy() {
|
20353
|
-
logger.log('destroy');
|
21204
|
+
this.logger.log('destroy');
|
20354
21205
|
this.trigger(Events.DESTROYING, undefined);
|
20355
21206
|
this.detachMedia();
|
20356
21207
|
this.removeAllListeners();
|
@@ -20375,7 +21226,7 @@
|
|
20375
21226
|
* Attaches Hls.js to a media element
|
20376
21227
|
*/;
|
20377
21228
|
_proto.attachMedia = function attachMedia(media) {
|
20378
|
-
logger.log('attachMedia');
|
21229
|
+
this.logger.log('attachMedia');
|
20379
21230
|
this._media = media;
|
20380
21231
|
this.trigger(Events.MEDIA_ATTACHING, {
|
20381
21232
|
media: media
|
@@ -20386,7 +21237,7 @@
|
|
20386
21237
|
* Detach Hls.js from the media
|
20387
21238
|
*/;
|
20388
21239
|
_proto.detachMedia = function detachMedia() {
|
20389
|
-
logger.log('detachMedia');
|
21240
|
+
this.logger.log('detachMedia');
|
20390
21241
|
this.trigger(Events.MEDIA_DETACHING, undefined);
|
20391
21242
|
this._media = null;
|
20392
21243
|
}
|
@@ -20403,7 +21254,7 @@
|
|
20403
21254
|
});
|
20404
21255
|
this._autoLevelCapping = -1;
|
20405
21256
|
this._maxHdcpLevel = null;
|
20406
|
-
logger.log("loadSource:" + loadingSource);
|
21257
|
+
this.logger.log("loadSource:" + loadingSource);
|
20407
21258
|
if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
|
20408
21259
|
this.detachMedia();
|
20409
21260
|
this.attachMedia(media);
|
@@ -20425,8 +21276,7 @@
|
|
20425
21276
|
if (startPosition === void 0) {
|
20426
21277
|
startPosition = -1;
|
20427
21278
|
}
|
20428
|
-
logger.log("startLoad(" + startPosition + ")");
|
20429
|
-
this.started = true;
|
21279
|
+
this.logger.log("startLoad(" + startPosition + ")");
|
20430
21280
|
this.networkControllers.forEach(function (controller) {
|
20431
21281
|
controller.startLoad(startPosition);
|
20432
21282
|
});
|
@@ -20436,34 +21286,31 @@
|
|
20436
21286
|
* Stop loading of any stream data.
|
20437
21287
|
*/;
|
20438
21288
|
_proto.stopLoad = function stopLoad() {
|
20439
|
-
logger.log('stopLoad');
|
20440
|
-
this.started = false;
|
21289
|
+
this.logger.log('stopLoad');
|
20441
21290
|
this.networkControllers.forEach(function (controller) {
|
20442
21291
|
controller.stopLoad();
|
20443
21292
|
});
|
20444
21293
|
}
|
20445
21294
|
|
20446
21295
|
/**
|
20447
|
-
* Resumes stream controller segment loading
|
21296
|
+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
|
20448
21297
|
*/;
|
20449
21298
|
_proto.resumeBuffering = function resumeBuffering() {
|
20450
|
-
|
20451
|
-
|
20452
|
-
|
20453
|
-
|
20454
|
-
|
20455
|
-
});
|
20456
|
-
}
|
21299
|
+
this.networkControllers.forEach(function (controller) {
|
21300
|
+
if (controller.resumeBuffering) {
|
21301
|
+
controller.resumeBuffering();
|
21302
|
+
}
|
21303
|
+
});
|
20457
21304
|
}
|
20458
21305
|
|
20459
21306
|
/**
|
20460
|
-
*
|
21307
|
+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
|
20461
21308
|
* This allows for media buffering to be paused without interupting playlist loading.
|
20462
21309
|
*/;
|
20463
21310
|
_proto.pauseBuffering = function pauseBuffering() {
|
20464
21311
|
this.networkControllers.forEach(function (controller) {
|
20465
|
-
if (
|
20466
|
-
controller.
|
21312
|
+
if (controller.pauseBuffering) {
|
21313
|
+
controller.pauseBuffering();
|
20467
21314
|
}
|
20468
21315
|
});
|
20469
21316
|
}
|
@@ -20472,7 +21319,7 @@
|
|
20472
21319
|
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
20473
21320
|
*/;
|
20474
21321
|
_proto.swapAudioCodec = function swapAudioCodec() {
|
20475
|
-
logger.log('swapAudioCodec');
|
21322
|
+
this.logger.log('swapAudioCodec');
|
20476
21323
|
this.streamController.swapAudioCodec();
|
20477
21324
|
}
|
20478
21325
|
|
@@ -20483,7 +21330,7 @@
|
|
20483
21330
|
* Automatic recovery of media-errors by this process is configurable.
|
20484
21331
|
*/;
|
20485
21332
|
_proto.recoverMediaError = function recoverMediaError() {
|
20486
|
-
logger.log('recoverMediaError');
|
21333
|
+
this.logger.log('recoverMediaError');
|
20487
21334
|
var media = this._media;
|
20488
21335
|
this.detachMedia();
|
20489
21336
|
if (media) {
|
@@ -20538,7 +21385,7 @@
|
|
20538
21385
|
* 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.
|
20539
21386
|
*/,
|
20540
21387
|
set: function set(newLevel) {
|
20541
|
-
logger.log("set currentLevel:" + newLevel);
|
21388
|
+
this.logger.log("set currentLevel:" + newLevel);
|
20542
21389
|
this.levelController.manualLevel = newLevel;
|
20543
21390
|
this.streamController.immediateLevelSwitch();
|
20544
21391
|
}
|
@@ -20559,7 +21406,7 @@
|
|
20559
21406
|
* @param newLevel - Pass -1 for automatic level selection
|
20560
21407
|
*/,
|
20561
21408
|
set: function set(newLevel) {
|
20562
|
-
logger.log("set nextLevel:" + newLevel);
|
21409
|
+
this.logger.log("set nextLevel:" + newLevel);
|
20563
21410
|
this.levelController.manualLevel = newLevel;
|
20564
21411
|
this.streamController.nextLevelSwitch();
|
20565
21412
|
}
|
@@ -20580,7 +21427,7 @@
|
|
20580
21427
|
* @param newLevel - Pass -1 for automatic level selection
|
20581
21428
|
*/,
|
20582
21429
|
set: function set(newLevel) {
|
20583
|
-
logger.log("set loadLevel:" + newLevel);
|
21430
|
+
this.logger.log("set loadLevel:" + newLevel);
|
20584
21431
|
this.levelController.manualLevel = newLevel;
|
20585
21432
|
}
|
20586
21433
|
|
@@ -20615,7 +21462,7 @@
|
|
20615
21462
|
* Sets "first-level", see getter.
|
20616
21463
|
*/,
|
20617
21464
|
set: function set(newLevel) {
|
20618
|
-
logger.log("set firstLevel:" + newLevel);
|
21465
|
+
this.logger.log("set firstLevel:" + newLevel);
|
20619
21466
|
this.levelController.firstLevel = newLevel;
|
20620
21467
|
}
|
20621
21468
|
|
@@ -20642,7 +21489,7 @@
|
|
20642
21489
|
* (determined from download of first segment)
|
20643
21490
|
*/,
|
20644
21491
|
set: function set(newLevel) {
|
20645
|
-
logger.log("set startLevel:" + newLevel);
|
21492
|
+
this.logger.log("set startLevel:" + newLevel);
|
20646
21493
|
// if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
|
20647
21494
|
if (newLevel !== -1) {
|
20648
21495
|
newLevel = Math.max(newLevel, this.minAutoLevel);
|
@@ -20695,7 +21542,7 @@
|
|
20695
21542
|
*/
|
20696
21543
|
function set(newLevel) {
|
20697
21544
|
if (this._autoLevelCapping !== newLevel) {
|
20698
|
-
logger.log("set autoLevelCapping:" + newLevel);
|
21545
|
+
this.logger.log("set autoLevelCapping:" + newLevel);
|
20699
21546
|
this._autoLevelCapping = newLevel;
|
20700
21547
|
this.levelController.checkMaxAutoUpdated();
|
20701
21548
|
}
|
@@ -21020,7 +21867,7 @@
|
|
21020
21867
|
* Get the video-dev/hls.js package version.
|
21021
21868
|
*/
|
21022
21869
|
function get() {
|
21023
|
-
return "1.5.
|
21870
|
+
return "1.5.5-0.canary.9977";
|
21024
21871
|
}
|
21025
21872
|
}, {
|
21026
21873
|
key: "Events",
|