hls.js 1.5.4 → 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 +1930 -1095
- package/dist/hls.js.d.ts +63 -50
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +1609 -778
- 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 +1363 -542
- 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 +1635 -815
- 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 +21 -20
- package/src/controller/audio-stream-controller.ts +15 -16
- package/src/controller/audio-track-controller.ts +1 -1
- package/src/controller/base-playlist-controller.ts +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 +25 -32
- package/src/controller/subtitle-stream-controller.ts +13 -14
- package/src/controller/subtitle-track-controller.ts +5 -3
- package/src/controller/timeline-controller.ts +23 -30
- package/src/crypt/aes-crypto.ts +21 -2
- package/src/crypt/decrypter-aes-mode.ts +4 -0
- package/src/crypt/decrypter.ts +32 -18
- package/src/crypt/fast-aes-key.ts +24 -5
- package/src/demux/audio/adts.ts +9 -4
- package/src/demux/sample-aes.ts +2 -0
- package/src/demux/transmuxer-interface.ts +4 -12
- package/src/demux/transmuxer-worker.ts +4 -4
- package/src/demux/transmuxer.ts +16 -3
- package/src/demux/tsdemuxer.ts +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/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;
|
@@ -2626,13 +2651,13 @@
|
|
2626
2651
|
this.keyFormatVersions = formatversions;
|
2627
2652
|
this.iv = iv;
|
2628
2653
|
this.encrypted = method ? method !== 'NONE' : false;
|
2629
|
-
this.isCommonEncryption = this.encrypted && method
|
2654
|
+
this.isCommonEncryption = this.encrypted && !isFullSegmentEncryption(method);
|
2630
2655
|
}
|
2631
2656
|
var _proto = LevelKey.prototype;
|
2632
2657
|
_proto.isSupported = function isSupported() {
|
2633
2658
|
// If it's Segment encryption or No encryption, just select that key system
|
2634
2659
|
if (this.method) {
|
2635
|
-
if (this.method
|
2660
|
+
if (isFullSegmentEncryption(this.method) || this.method === 'NONE') {
|
2636
2661
|
return true;
|
2637
2662
|
}
|
2638
2663
|
if (this.keyFormat === 'identity') {
|
@@ -2646,14 +2671,13 @@
|
|
2646
2671
|
if (!this.encrypted || !this.uri) {
|
2647
2672
|
return null;
|
2648
2673
|
}
|
2649
|
-
if (this.method
|
2674
|
+
if (isFullSegmentEncryption(this.method) && this.uri && !this.iv) {
|
2650
2675
|
if (typeof sn !== 'number') {
|
2651
2676
|
// We are fetching decryption data for a initialization segment
|
2652
|
-
// If the segment was encrypted with AES-128
|
2677
|
+
// If the segment was encrypted with AES-128/256
|
2653
2678
|
// It must have an IV defined. We cannot substitute the Segment Number in.
|
2654
|
-
|
2655
|
-
|
2656
|
-
}
|
2679
|
+
logger.warn("missing IV for initialization segment with method=\"" + this.method + "\" - compliance issue");
|
2680
|
+
|
2657
2681
|
// Explicitly set sn to resulting value from implicit conversions 'initSegment' values for IV generation.
|
2658
2682
|
sn = 0;
|
2659
2683
|
}
|
@@ -2815,23 +2839,28 @@
|
|
2815
2839
|
if (CODEC_COMPATIBLE_NAMES[lowerCaseCodec]) {
|
2816
2840
|
return CODEC_COMPATIBLE_NAMES[lowerCaseCodec];
|
2817
2841
|
}
|
2818
|
-
|
2819
|
-
// Idealy fLaC and Opus would be first (spec-compliant) but
|
2820
|
-
// some browsers will report that fLaC is supported then fail.
|
2821
|
-
// see: https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
2822
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
|
2823
2846
|
flac: ['flac', 'fLaC', 'FLAC'],
|
2824
|
-
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']
|
2825
2851
|
}[lowerCaseCodec];
|
2826
2852
|
for (var i = 0; i < codecsToCheck.length; i++) {
|
2853
|
+
var _getMediaSource;
|
2827
2854
|
if (isCodecMediaSourceSupported(codecsToCheck[i], 'audio', preferManagedMediaSource)) {
|
2828
2855
|
CODEC_COMPATIBLE_NAMES[lowerCaseCodec] = codecsToCheck[i];
|
2829
2856
|
return codecsToCheck[i];
|
2857
|
+
} else if (codecsToCheck[i] === 'mp3' && (_getMediaSource = getMediaSource(preferManagedMediaSource)) != null && _getMediaSource.isTypeSupported('audio/mpeg')) {
|
2858
|
+
return '';
|
2830
2859
|
}
|
2831
2860
|
}
|
2832
2861
|
return lowerCaseCodec;
|
2833
2862
|
}
|
2834
|
-
var AUDIO_CODEC_REGEXP = /flac|opus/i;
|
2863
|
+
var AUDIO_CODEC_REGEXP = /flac|opus|mp4a\.40\.34/i;
|
2835
2864
|
function getCodecCompatibleName(codec, preferManagedMediaSource) {
|
2836
2865
|
if (preferManagedMediaSource === void 0) {
|
2837
2866
|
preferManagedMediaSource = true;
|
@@ -2859,6 +2888,18 @@
|
|
2859
2888
|
}
|
2860
2889
|
return codec;
|
2861
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
|
+
}
|
2862
2903
|
|
2863
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;
|
2864
2905
|
var MASTER_PLAYLIST_MEDIA_REGEX = /#EXT-X-MEDIA:(.*)/g;
|
@@ -4433,8 +4474,43 @@
|
|
4433
4474
|
this.currentTime = 0;
|
4434
4475
|
this.stallCount = 0;
|
4435
4476
|
this._latency = null;
|
4436
|
-
this.
|
4437
|
-
|
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
|
+
}
|
4438
4514
|
};
|
4439
4515
|
this.hls = hls;
|
4440
4516
|
this.config = hls.config;
|
@@ -4446,7 +4522,7 @@
|
|
4446
4522
|
this.onMediaDetaching();
|
4447
4523
|
this.levelDetails = null;
|
4448
4524
|
// @ts-ignore
|
4449
|
-
this.hls =
|
4525
|
+
this.hls = null;
|
4450
4526
|
};
|
4451
4527
|
_proto.registerListeners = function registerListeners() {
|
4452
4528
|
this.hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
@@ -4464,11 +4540,11 @@
|
|
4464
4540
|
};
|
4465
4541
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
4466
4542
|
this.media = data.media;
|
4467
|
-
this.media.addEventListener('timeupdate', this.
|
4543
|
+
this.media.addEventListener('timeupdate', this.onTimeupdate);
|
4468
4544
|
};
|
4469
4545
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
4470
4546
|
if (this.media) {
|
4471
|
-
this.media.removeEventListener('timeupdate', this.
|
4547
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4472
4548
|
this.media = null;
|
4473
4549
|
}
|
4474
4550
|
};
|
@@ -4481,10 +4557,10 @@
|
|
4481
4557
|
var details = _ref.details;
|
4482
4558
|
this.levelDetails = details;
|
4483
4559
|
if (details.advanced) {
|
4484
|
-
this.
|
4560
|
+
this.onTimeupdate();
|
4485
4561
|
}
|
4486
4562
|
if (!details.live && this.media) {
|
4487
|
-
this.media.removeEventListener('timeupdate', this.
|
4563
|
+
this.media.removeEventListener('timeupdate', this.onTimeupdate);
|
4488
4564
|
}
|
4489
4565
|
};
|
4490
4566
|
_proto.onError = function onError(event, data) {
|
@@ -4494,45 +4570,7 @@
|
|
4494
4570
|
}
|
4495
4571
|
this.stallCount++;
|
4496
4572
|
if ((_this$levelDetails = this.levelDetails) != null && _this$levelDetails.live) {
|
4497
|
-
logger.warn('[
|
4498
|
-
}
|
4499
|
-
};
|
4500
|
-
_proto.timeupdate = function timeupdate() {
|
4501
|
-
var media = this.media,
|
4502
|
-
levelDetails = this.levelDetails;
|
4503
|
-
if (!media || !levelDetails) {
|
4504
|
-
return;
|
4505
|
-
}
|
4506
|
-
this.currentTime = media.currentTime;
|
4507
|
-
var latency = this.computeLatency();
|
4508
|
-
if (latency === null) {
|
4509
|
-
return;
|
4510
|
-
}
|
4511
|
-
this._latency = latency;
|
4512
|
-
|
4513
|
-
// Adapt playbackRate to meet target latency in low-latency mode
|
4514
|
-
var _this$config = this.config,
|
4515
|
-
lowLatencyMode = _this$config.lowLatencyMode,
|
4516
|
-
maxLiveSyncPlaybackRate = _this$config.maxLiveSyncPlaybackRate;
|
4517
|
-
if (!lowLatencyMode || maxLiveSyncPlaybackRate === 1 || !levelDetails.live) {
|
4518
|
-
return;
|
4519
|
-
}
|
4520
|
-
var targetLatency = this.targetLatency;
|
4521
|
-
if (targetLatency === null) {
|
4522
|
-
return;
|
4523
|
-
}
|
4524
|
-
var distanceFromTarget = latency - targetLatency;
|
4525
|
-
// Only adjust playbackRate when within one target duration of targetLatency
|
4526
|
-
// and more than one second from under-buffering.
|
4527
|
-
// Playback further than one target duration from target can be considered DVR playback.
|
4528
|
-
var liveMinLatencyDuration = Math.min(this.maxLatency, targetLatency + levelDetails.targetduration);
|
4529
|
-
var inLiveRange = distanceFromTarget < liveMinLatencyDuration;
|
4530
|
-
if (inLiveRange && distanceFromTarget > 0.05 && this.forwardBufferLength > 1) {
|
4531
|
-
var max = Math.min(2, Math.max(1.0, maxLiveSyncPlaybackRate));
|
4532
|
-
var rate = Math.round(2 / (1 + Math.exp(-0.75 * distanceFromTarget - this.edgeStalled)) * 20) / 20;
|
4533
|
-
media.playbackRate = Math.min(max, Math.max(1, rate));
|
4534
|
-
} else if (media.playbackRate !== 1 && media.playbackRate !== 0) {
|
4535
|
-
media.playbackRate = 1;
|
4573
|
+
this.hls.logger.warn('[latency-controller]: Stall detected, adjusting target latency');
|
4536
4574
|
}
|
4537
4575
|
};
|
4538
4576
|
_proto.estimateLiveEdge = function estimateLiveEdge() {
|
@@ -5440,19 +5478,17 @@
|
|
5440
5478
|
MoveAllAlternatesMatchingHDCP: 2,
|
5441
5479
|
SwitchToSDR: 4
|
5442
5480
|
}; // Reserved for future use
|
5443
|
-
var ErrorController = /*#__PURE__*/function () {
|
5481
|
+
var ErrorController = /*#__PURE__*/function (_Logger) {
|
5482
|
+
_inheritsLoose(ErrorController, _Logger);
|
5444
5483
|
function ErrorController(hls) {
|
5445
|
-
|
5446
|
-
this.
|
5447
|
-
|
5448
|
-
|
5449
|
-
|
5450
|
-
|
5451
|
-
|
5452
|
-
|
5453
|
-
this.warn = logger.warn.bind(logger, "[warning]:");
|
5454
|
-
this.error = logger.error.bind(logger, "[error]:");
|
5455
|
-
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;
|
5456
5492
|
}
|
5457
5493
|
var _proto = ErrorController.prototype;
|
5458
5494
|
_proto.registerListeners = function registerListeners() {
|
@@ -5808,19 +5844,19 @@
|
|
5808
5844
|
}
|
5809
5845
|
};
|
5810
5846
|
return ErrorController;
|
5811
|
-
}();
|
5847
|
+
}(Logger);
|
5812
5848
|
|
5813
|
-
var BasePlaylistController = /*#__PURE__*/function () {
|
5849
|
+
var BasePlaylistController = /*#__PURE__*/function (_Logger) {
|
5850
|
+
_inheritsLoose(BasePlaylistController, _Logger);
|
5814
5851
|
function BasePlaylistController(hls, logPrefix) {
|
5815
|
-
|
5816
|
-
this.
|
5817
|
-
|
5818
|
-
|
5819
|
-
|
5820
|
-
|
5821
|
-
|
5822
|
-
|
5823
|
-
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;
|
5824
5860
|
}
|
5825
5861
|
var _proto = BasePlaylistController.prototype;
|
5826
5862
|
_proto.destroy = function destroy() {
|
@@ -5853,7 +5889,7 @@
|
|
5853
5889
|
try {
|
5854
5890
|
uri = new self.URL(attr.URI, previous.url).href;
|
5855
5891
|
} catch (error) {
|
5856
|
-
|
5892
|
+
this.warn("Could not construct new URL for Rendition Report: " + error);
|
5857
5893
|
uri = attr.URI || '';
|
5858
5894
|
}
|
5859
5895
|
// Use exact match. Otherwise, the last partial match, if any, will be used
|
@@ -5892,7 +5928,7 @@
|
|
5892
5928
|
return this.timer === -1 && this.requestScheduled === -1 && this.shouldLoadPlaylist(playlist);
|
5893
5929
|
};
|
5894
5930
|
_proto.playlistLoaded = function playlistLoaded(index, data, previousDetails) {
|
5895
|
-
var
|
5931
|
+
var _this2 = this;
|
5896
5932
|
var details = data.details,
|
5897
5933
|
stats = data.stats;
|
5898
5934
|
|
@@ -5997,7 +6033,7 @@
|
|
5997
6033
|
// );
|
5998
6034
|
|
5999
6035
|
this.timer = self.setTimeout(function () {
|
6000
|
-
return
|
6036
|
+
return _this2.loadPlaylist(deliveryDirectives);
|
6001
6037
|
}, estimatedTimeUntilUpdate);
|
6002
6038
|
} else {
|
6003
6039
|
this.clearTimer();
|
@@ -6013,7 +6049,7 @@
|
|
6013
6049
|
return new HlsUrlParameters(msn, part, skip);
|
6014
6050
|
};
|
6015
6051
|
_proto.checkRetry = function checkRetry(errorEvent) {
|
6016
|
-
var
|
6052
|
+
var _this3 = this;
|
6017
6053
|
var errorDetails = errorEvent.details;
|
6018
6054
|
var isTimeout = isTimeoutError(errorEvent);
|
6019
6055
|
var errorAction = errorEvent.errorAction;
|
@@ -6037,7 +6073,7 @@
|
|
6037
6073
|
var delay = getRetryDelay(retryConfig, retryCount);
|
6038
6074
|
// Schedule level/track reload
|
6039
6075
|
this.timer = self.setTimeout(function () {
|
6040
|
-
return
|
6076
|
+
return _this3.loadPlaylist();
|
6041
6077
|
}, delay);
|
6042
6078
|
this.warn("Retrying playlist loading " + (retryCount + 1) + "/" + retryConfig.maxNumRetry + " after \"" + errorDetails + "\" in " + delay + "ms");
|
6043
6079
|
}
|
@@ -6048,7 +6084,7 @@
|
|
6048
6084
|
return retry;
|
6049
6085
|
};
|
6050
6086
|
return BasePlaylistController;
|
6051
|
-
}();
|
6087
|
+
}(Logger);
|
6052
6088
|
|
6053
6089
|
/*
|
6054
6090
|
* compute an Exponential Weighted moving average
|
@@ -6422,30 +6458,33 @@
|
|
6422
6458
|
}, {});
|
6423
6459
|
}
|
6424
6460
|
|
6425
|
-
var AbrController = /*#__PURE__*/function () {
|
6461
|
+
var AbrController = /*#__PURE__*/function (_Logger) {
|
6462
|
+
_inheritsLoose(AbrController, _Logger);
|
6426
6463
|
function AbrController(_hls) {
|
6427
|
-
var _this
|
6428
|
-
this.
|
6429
|
-
|
6430
|
-
|
6431
|
-
|
6432
|
-
|
6433
|
-
|
6434
|
-
|
6435
|
-
|
6436
|
-
|
6437
|
-
|
6438
|
-
|
6439
|
-
|
6440
|
-
|
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;
|
6441
6479
|
/*
|
6442
6480
|
This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load
|
6443
6481
|
quickly enough to prevent underbuffering
|
6444
6482
|
*/
|
6445
|
-
|
6446
|
-
var
|
6447
|
-
|
6448
|
-
|
6483
|
+
_this._abandonRulesCheck = function () {
|
6484
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
6485
|
+
frag = _assertThisInitialize.fragCurrent,
|
6486
|
+
part = _assertThisInitialize.partCurrent,
|
6487
|
+
hls = _assertThisInitialize.hls;
|
6449
6488
|
var autoLevelEnabled = hls.autoLevelEnabled,
|
6450
6489
|
media = hls.media;
|
6451
6490
|
if (!frag || !media) {
|
@@ -6534,21 +6573,22 @@
|
|
6534
6573
|
_this.resetEstimator(nextLoadLevelBitrate);
|
6535
6574
|
}
|
6536
6575
|
_this.clearTimer();
|
6537
|
-
|
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");
|
6538
6577
|
hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, {
|
6539
6578
|
frag: frag,
|
6540
6579
|
part: part,
|
6541
6580
|
stats: stats
|
6542
6581
|
});
|
6543
6582
|
};
|
6544
|
-
|
6545
|
-
|
6546
|
-
|
6583
|
+
_this.hls = _hls;
|
6584
|
+
_this.bwEstimator = _this.initEstimator();
|
6585
|
+
_this.registerListeners();
|
6586
|
+
return _this;
|
6547
6587
|
}
|
6548
6588
|
var _proto = AbrController.prototype;
|
6549
6589
|
_proto.resetEstimator = function resetEstimator(abrEwmaDefaultEstimate) {
|
6550
6590
|
if (abrEwmaDefaultEstimate) {
|
6551
|
-
|
6591
|
+
this.log("setting initial bwe to " + abrEwmaDefaultEstimate);
|
6552
6592
|
this.hls.config.abrEwmaDefaultEstimate = abrEwmaDefaultEstimate;
|
6553
6593
|
}
|
6554
6594
|
this.firstSelection = -1;
|
@@ -6800,13 +6840,13 @@
|
|
6800
6840
|
// cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration
|
6801
6841
|
var maxLoadingDelay = currentFragDuration ? Math.min(currentFragDuration, config.maxLoadingDelay) : config.maxLoadingDelay;
|
6802
6842
|
maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;
|
6803
|
-
|
6843
|
+
this.info("bitrate test took " + Math.round(1000 * bitrateTestDelay) + "ms, set first fragment max fetchDuration to " + Math.round(1000 * maxStarvationDelay) + " ms");
|
6804
6844
|
// don't use conservative factor on bitrate test
|
6805
6845
|
bwFactor = bwUpFactor = 1;
|
6806
6846
|
}
|
6807
6847
|
}
|
6808
6848
|
var bestLevel = this.findBestLevel(avgbw, minAutoLevel, maxAutoLevel, bufferStarvationDelay, maxStarvationDelay, bwFactor, bwUpFactor);
|
6809
|
-
|
6849
|
+
this.info((bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty') + ", optimal quality level " + bestLevel);
|
6810
6850
|
if (bestLevel > -1) {
|
6811
6851
|
return bestLevel;
|
6812
6852
|
}
|
@@ -6862,7 +6902,7 @@
|
|
6862
6902
|
currentVideoRange = preferHDR ? videoRanges[videoRanges.length - 1] : videoRanges[0];
|
6863
6903
|
currentFrameRate = minFramerate;
|
6864
6904
|
currentBw = Math.max(currentBw, minBitrate);
|
6865
|
-
|
6905
|
+
this.log("picked start tier " + JSON.stringify(startTier));
|
6866
6906
|
} else {
|
6867
6907
|
currentCodecSet = level == null ? void 0 : level.codecSet;
|
6868
6908
|
currentVideoRange = level == null ? void 0 : level.videoRange;
|
@@ -6915,9 +6955,9 @@
|
|
6915
6955
|
var forcedAutoLevel = _this2.forcedAutoLevel;
|
6916
6956
|
if (i !== loadLevel && (forcedAutoLevel === -1 || forcedAutoLevel !== loadLevel)) {
|
6917
6957
|
if (levelsSkipped.length) {
|
6918
|
-
|
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);
|
6919
6959
|
}
|
6920
|
-
|
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);
|
6921
6961
|
}
|
6922
6962
|
if (firstSelection) {
|
6923
6963
|
_this2.firstSelection = i;
|
@@ -6951,7 +6991,7 @@
|
|
6951
6991
|
}
|
6952
6992
|
var firstLevel = this.hls.firstLevel;
|
6953
6993
|
var clamped = Math.min(Math.max(firstLevel, minAutoLevel), maxAutoLevel);
|
6954
|
-
|
6994
|
+
this.warn("Could not find best starting auto level. Defaulting to first in playlist " + firstLevel + " clamped to " + clamped);
|
6955
6995
|
return clamped;
|
6956
6996
|
}
|
6957
6997
|
}, {
|
@@ -7004,7 +7044,7 @@
|
|
7004
7044
|
}
|
7005
7045
|
}]);
|
7006
7046
|
return AbrController;
|
7007
|
-
}();
|
7047
|
+
}(Logger);
|
7008
7048
|
|
7009
7049
|
/**
|
7010
7050
|
* Provides methods dealing with buffer length retrieval for example.
|
@@ -7225,57 +7265,57 @@
|
|
7225
7265
|
}();
|
7226
7266
|
|
7227
7267
|
var VIDEO_CODEC_PROFILE_REPLACE = /(avc[1234]|hvc1|hev1|dvh[1e]|vp09|av01)(?:\.[^.,]+)+/;
|
7228
|
-
var BufferController = /*#__PURE__*/function () {
|
7268
|
+
var BufferController = /*#__PURE__*/function (_Logger) {
|
7269
|
+
_inheritsLoose(BufferController, _Logger);
|
7229
7270
|
function BufferController(hls) {
|
7230
|
-
var _this
|
7271
|
+
var _this;
|
7272
|
+
_this = _Logger.call(this, 'buffer-controller', hls.logger) || this;
|
7231
7273
|
// The level details used to determine duration, target-duration and live
|
7232
|
-
|
7274
|
+
_this.details = null;
|
7233
7275
|
// cache the self generated object url to detect hijack of video tag
|
7234
|
-
|
7276
|
+
_this._objectUrl = null;
|
7235
7277
|
// A queue of buffer operations which require the SourceBuffer to not be updating upon execution
|
7236
|
-
|
7278
|
+
_this.operationQueue = void 0;
|
7237
7279
|
// References to event listeners for each SourceBuffer, so that they can be referenced for event removal
|
7238
|
-
|
7239
|
-
|
7280
|
+
_this.listeners = void 0;
|
7281
|
+
_this.hls = void 0;
|
7240
7282
|
// The number of BUFFER_CODEC events received before any sourceBuffers are created
|
7241
|
-
|
7283
|
+
_this.bufferCodecEventsExpected = 0;
|
7242
7284
|
// The total number of BUFFER_CODEC events received
|
7243
|
-
|
7285
|
+
_this._bufferCodecEventsTotal = 0;
|
7244
7286
|
// A reference to the attached media element
|
7245
|
-
|
7287
|
+
_this.media = null;
|
7246
7288
|
// A reference to the active media source
|
7247
|
-
|
7289
|
+
_this.mediaSource = null;
|
7248
7290
|
// Last MP3 audio chunk appended
|
7249
|
-
|
7250
|
-
|
7291
|
+
_this.lastMpegAudioChunk = null;
|
7292
|
+
_this.appendSource = void 0;
|
7251
7293
|
// counters
|
7252
|
-
|
7294
|
+
_this.appendErrors = {
|
7253
7295
|
audio: 0,
|
7254
7296
|
video: 0,
|
7255
7297
|
audiovideo: 0
|
7256
7298
|
};
|
7257
|
-
|
7258
|
-
|
7259
|
-
|
7260
|
-
|
7261
|
-
this.warn = void 0;
|
7262
|
-
this.error = void 0;
|
7263
|
-
this._onEndStreaming = function (event) {
|
7299
|
+
_this.tracks = {};
|
7300
|
+
_this.pendingTracks = {};
|
7301
|
+
_this.sourceBuffer = void 0;
|
7302
|
+
_this._onEndStreaming = function (event) {
|
7264
7303
|
if (!_this.hls) {
|
7265
7304
|
return;
|
7266
7305
|
}
|
7267
7306
|
_this.hls.pauseBuffering();
|
7268
7307
|
};
|
7269
|
-
|
7308
|
+
_this._onStartStreaming = function (event) {
|
7270
7309
|
if (!_this.hls) {
|
7271
7310
|
return;
|
7272
7311
|
}
|
7273
7312
|
_this.hls.resumeBuffering();
|
7274
7313
|
};
|
7275
7314
|
// Keep as arrow functions so that we can directly reference these functions directly as event listeners
|
7276
|
-
|
7277
|
-
var
|
7278
|
-
|
7315
|
+
_this._onMediaSourceOpen = function () {
|
7316
|
+
var _assertThisInitialize = _assertThisInitialized(_this),
|
7317
|
+
media = _assertThisInitialize.media,
|
7318
|
+
mediaSource = _assertThisInitialize.mediaSource;
|
7279
7319
|
_this.log('Media source opened');
|
7280
7320
|
if (media) {
|
7281
7321
|
media.removeEventListener('emptied', _this._onMediaEmptied);
|
@@ -7291,27 +7331,25 @@
|
|
7291
7331
|
}
|
7292
7332
|
_this.checkPendingTracks();
|
7293
7333
|
};
|
7294
|
-
|
7334
|
+
_this._onMediaSourceClose = function () {
|
7295
7335
|
_this.log('Media source closed');
|
7296
7336
|
};
|
7297
|
-
|
7337
|
+
_this._onMediaSourceEnded = function () {
|
7298
7338
|
_this.log('Media source ended');
|
7299
7339
|
};
|
7300
|
-
|
7301
|
-
var
|
7302
|
-
|
7340
|
+
_this._onMediaEmptied = function () {
|
7341
|
+
var _assertThisInitialize2 = _assertThisInitialized(_this),
|
7342
|
+
mediaSrc = _assertThisInitialize2.mediaSrc,
|
7343
|
+
_objectUrl = _assertThisInitialize2._objectUrl;
|
7303
7344
|
if (mediaSrc !== _objectUrl) {
|
7304
|
-
|
7345
|
+
_this.error("Media element src was set while attaching MediaSource (" + _objectUrl + " > " + mediaSrc + ")");
|
7305
7346
|
}
|
7306
7347
|
};
|
7307
|
-
|
7308
|
-
|
7309
|
-
|
7310
|
-
|
7311
|
-
|
7312
|
-
this.error = logger.error.bind(logger, logPrefix);
|
7313
|
-
this._initSourceBuffer();
|
7314
|
-
this.registerListeners();
|
7348
|
+
_this.hls = hls;
|
7349
|
+
_this.appendSource = hls.config.preferManagedMediaSource;
|
7350
|
+
_this._initSourceBuffer();
|
7351
|
+
_this.registerListeners();
|
7352
|
+
return _this;
|
7315
7353
|
}
|
7316
7354
|
var _proto = BufferController.prototype;
|
7317
7355
|
_proto.hasSourceTypes = function hasSourceTypes() {
|
@@ -7323,6 +7361,12 @@
|
|
7323
7361
|
this.lastMpegAudioChunk = null;
|
7324
7362
|
// @ts-ignore
|
7325
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;
|
7326
7370
|
};
|
7327
7371
|
_proto.registerListeners = function registerListeners() {
|
7328
7372
|
var hls = this.hls;
|
@@ -7480,6 +7524,7 @@
|
|
7480
7524
|
_this2.resetBuffer(type);
|
7481
7525
|
});
|
7482
7526
|
this._initSourceBuffer();
|
7527
|
+
this.hls.resumeBuffering();
|
7483
7528
|
};
|
7484
7529
|
_proto.resetBuffer = function resetBuffer(type) {
|
7485
7530
|
var sb = this.sourceBuffer[type];
|
@@ -8183,7 +8228,7 @@
|
|
8183
8228
|
}
|
8184
8229
|
}]);
|
8185
8230
|
return BufferController;
|
8186
|
-
}();
|
8231
|
+
}(Logger);
|
8187
8232
|
function removeSourceChildren(node) {
|
8188
8233
|
var sourceChildren = node.querySelectorAll('source');
|
8189
8234
|
[].slice.call(sourceChildren).forEach(function (source) {
|
@@ -8307,7 +8352,7 @@
|
|
8307
8352
|
var hls = this.hls;
|
8308
8353
|
var maxLevel = this.getMaxLevel(levels.length - 1);
|
8309
8354
|
if (maxLevel !== this.autoLevelCapping) {
|
8310
|
-
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);
|
8311
8356
|
}
|
8312
8357
|
hls.autoLevelCapping = maxLevel;
|
8313
8358
|
if (hls.autoLevelCapping > this.autoLevelCapping && this.streamController) {
|
@@ -8497,10 +8542,10 @@
|
|
8497
8542
|
totalDroppedFrames: droppedFrames
|
8498
8543
|
});
|
8499
8544
|
if (droppedFPS > 0) {
|
8500
|
-
// logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8545
|
+
// hls.logger.log('checkFPS : droppedFPS/decodedFPS:' + droppedFPS/(1000 * currentDecoded / currentPeriod));
|
8501
8546
|
if (currentDropped > hls.config.fpsDroppedMonitoringThreshold * currentDecoded) {
|
8502
8547
|
var currentLevel = hls.currentLevel;
|
8503
|
-
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);
|
8504
8549
|
if (currentLevel > 0 && (hls.autoLevelCapping === -1 || hls.autoLevelCapping >= currentLevel)) {
|
8505
8550
|
currentLevel = currentLevel - 1;
|
8506
8551
|
hls.trigger(Events.FPS_DROP_LEVEL_CAPPING, {
|
@@ -8534,26 +8579,28 @@
|
|
8534
8579
|
}();
|
8535
8580
|
|
8536
8581
|
var PATHWAY_PENALTY_DURATION_MS = 300000;
|
8537
|
-
var ContentSteeringController = /*#__PURE__*/function () {
|
8582
|
+
var ContentSteeringController = /*#__PURE__*/function (_Logger) {
|
8583
|
+
_inheritsLoose(ContentSteeringController, _Logger);
|
8538
8584
|
function ContentSteeringController(hls) {
|
8539
|
-
|
8540
|
-
this.
|
8541
|
-
|
8542
|
-
|
8543
|
-
|
8544
|
-
|
8545
|
-
|
8546
|
-
|
8547
|
-
|
8548
|
-
|
8549
|
-
|
8550
|
-
|
8551
|
-
|
8552
|
-
|
8553
|
-
|
8554
|
-
|
8555
|
-
|
8556
|
-
|
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;
|
8557
8604
|
}
|
8558
8605
|
var _proto = ContentSteeringController.prototype;
|
8559
8606
|
_proto.registerListeners = function registerListeners() {
|
@@ -8674,7 +8721,7 @@
|
|
8674
8721
|
errorAction.resolved = this.pathwayId !== errorPathway;
|
8675
8722
|
}
|
8676
8723
|
if (!errorAction.resolved) {
|
8677
|
-
|
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));
|
8678
8725
|
}
|
8679
8726
|
}
|
8680
8727
|
};
|
@@ -8754,7 +8801,7 @@
|
|
8754
8801
|
return defaultPathway;
|
8755
8802
|
};
|
8756
8803
|
_proto.clonePathways = function clonePathways(pathwayClones) {
|
8757
|
-
var
|
8804
|
+
var _this2 = this;
|
8758
8805
|
var levels = this.levels;
|
8759
8806
|
if (!levels) {
|
8760
8807
|
return;
|
@@ -8770,7 +8817,7 @@
|
|
8770
8817
|
})) {
|
8771
8818
|
return;
|
8772
8819
|
}
|
8773
|
-
var clonedVariants =
|
8820
|
+
var clonedVariants = _this2.getLevelsForPathway(baseId).map(function (baseLevel) {
|
8774
8821
|
var attributes = new AttrList(baseLevel.attrs);
|
8775
8822
|
attributes['PATHWAY-ID'] = cloneId;
|
8776
8823
|
var clonedAudioGroupId = attributes.AUDIO && attributes.AUDIO + "_clone_" + cloneId;
|
@@ -8807,12 +8854,12 @@
|
|
8807
8854
|
return clonedLevel;
|
8808
8855
|
});
|
8809
8856
|
levels.push.apply(levels, clonedVariants);
|
8810
|
-
cloneRenditionGroups(
|
8811
|
-
cloneRenditionGroups(
|
8857
|
+
cloneRenditionGroups(_this2.audioTracks, audioGroupCloneMap, uriReplacement, cloneId);
|
8858
|
+
cloneRenditionGroups(_this2.subtitleTracks, subtitleGroupCloneMap, uriReplacement, cloneId);
|
8812
8859
|
});
|
8813
8860
|
};
|
8814
8861
|
_proto.loadSteeringManifest = function loadSteeringManifest(uri) {
|
8815
|
-
var
|
8862
|
+
var _this3 = this;
|
8816
8863
|
var config = this.hls.config;
|
8817
8864
|
var Loader = config.loader;
|
8818
8865
|
if (this.loader) {
|
@@ -8847,87 +8894,87 @@
|
|
8847
8894
|
};
|
8848
8895
|
var callbacks = {
|
8849
8896
|
onSuccess: function onSuccess(response, stats, context, networkDetails) {
|
8850
|
-
|
8897
|
+
_this3.log("Loaded steering manifest: \"" + url + "\"");
|
8851
8898
|
var steeringData = response.data;
|
8852
|
-
if (steeringData.VERSION !== 1) {
|
8853
|
-
|
8899
|
+
if ((steeringData == null ? void 0 : steeringData.VERSION) !== 1) {
|
8900
|
+
_this3.log("Steering VERSION " + steeringData.VERSION + " not supported!");
|
8854
8901
|
return;
|
8855
8902
|
}
|
8856
|
-
|
8857
|
-
|
8903
|
+
_this3.updated = performance.now();
|
8904
|
+
_this3.timeToLoad = steeringData.TTL;
|
8858
8905
|
var reloadUri = steeringData['RELOAD-URI'],
|
8859
8906
|
pathwayClones = steeringData['PATHWAY-CLONES'],
|
8860
8907
|
pathwayPriority = steeringData['PATHWAY-PRIORITY'];
|
8861
8908
|
if (reloadUri) {
|
8862
8909
|
try {
|
8863
|
-
|
8910
|
+
_this3.uri = new self.URL(reloadUri, url).href;
|
8864
8911
|
} catch (error) {
|
8865
|
-
|
8866
|
-
|
8912
|
+
_this3.enabled = false;
|
8913
|
+
_this3.log("Failed to parse Steering Manifest RELOAD-URI: " + reloadUri);
|
8867
8914
|
return;
|
8868
8915
|
}
|
8869
8916
|
}
|
8870
|
-
|
8917
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8871
8918
|
if (pathwayClones) {
|
8872
|
-
|
8919
|
+
_this3.clonePathways(pathwayClones);
|
8873
8920
|
}
|
8874
8921
|
var loadedSteeringData = {
|
8875
8922
|
steeringManifest: steeringData,
|
8876
8923
|
url: url.toString()
|
8877
8924
|
};
|
8878
|
-
|
8925
|
+
_this3.hls.trigger(Events.STEERING_MANIFEST_LOADED, loadedSteeringData);
|
8879
8926
|
if (pathwayPriority) {
|
8880
|
-
|
8927
|
+
_this3.updatePathwayPriority(pathwayPriority);
|
8881
8928
|
}
|
8882
8929
|
},
|
8883
8930
|
onError: function onError(error, context, networkDetails, stats) {
|
8884
|
-
|
8885
|
-
|
8931
|
+
_this3.log("Error loading steering manifest: " + error.code + " " + error.text + " (" + context.url + ")");
|
8932
|
+
_this3.stopLoad();
|
8886
8933
|
if (error.code === 410) {
|
8887
|
-
|
8888
|
-
|
8934
|
+
_this3.enabled = false;
|
8935
|
+
_this3.log("Steering manifest " + context.url + " no longer available");
|
8889
8936
|
return;
|
8890
8937
|
}
|
8891
|
-
var ttl =
|
8938
|
+
var ttl = _this3.timeToLoad * 1000;
|
8892
8939
|
if (error.code === 429) {
|
8893
|
-
var loader =
|
8940
|
+
var loader = _this3.loader;
|
8894
8941
|
if (typeof (loader == null ? void 0 : loader.getResponseHeader) === 'function') {
|
8895
8942
|
var retryAfter = loader.getResponseHeader('Retry-After');
|
8896
8943
|
if (retryAfter) {
|
8897
8944
|
ttl = parseFloat(retryAfter) * 1000;
|
8898
8945
|
}
|
8899
8946
|
}
|
8900
|
-
|
8947
|
+
_this3.log("Steering manifest " + context.url + " rate limited");
|
8901
8948
|
return;
|
8902
8949
|
}
|
8903
|
-
|
8950
|
+
_this3.scheduleRefresh(_this3.uri || context.url, ttl);
|
8904
8951
|
},
|
8905
8952
|
onTimeout: function onTimeout(stats, context, networkDetails) {
|
8906
|
-
|
8907
|
-
|
8953
|
+
_this3.log("Timeout loading steering manifest (" + context.url + ")");
|
8954
|
+
_this3.scheduleRefresh(_this3.uri || context.url);
|
8908
8955
|
}
|
8909
8956
|
};
|
8910
8957
|
this.log("Requesting steering manifest: " + url);
|
8911
8958
|
this.loader.load(context, loaderConfig, callbacks);
|
8912
8959
|
};
|
8913
8960
|
_proto.scheduleRefresh = function scheduleRefresh(uri, ttlMs) {
|
8914
|
-
var
|
8961
|
+
var _this4 = this;
|
8915
8962
|
if (ttlMs === void 0) {
|
8916
8963
|
ttlMs = this.timeToLoad * 1000;
|
8917
8964
|
}
|
8918
8965
|
this.clearTimeout();
|
8919
8966
|
this.reloadTimer = self.setTimeout(function () {
|
8920
|
-
var
|
8921
|
-
var media = (
|
8967
|
+
var _this4$hls;
|
8968
|
+
var media = (_this4$hls = _this4.hls) == null ? void 0 : _this4$hls.media;
|
8922
8969
|
if (media && !media.ended) {
|
8923
|
-
|
8970
|
+
_this4.loadSteeringManifest(uri);
|
8924
8971
|
return;
|
8925
8972
|
}
|
8926
|
-
|
8973
|
+
_this4.scheduleRefresh(uri, _this4.timeToLoad * 1000);
|
8927
8974
|
}, ttlMs);
|
8928
8975
|
};
|
8929
8976
|
return ContentSteeringController;
|
8930
|
-
}();
|
8977
|
+
}(Logger);
|
8931
8978
|
function cloneRenditionGroups(tracks, groupCloneMap, uriReplacement, cloneId) {
|
8932
8979
|
if (!tracks) {
|
8933
8980
|
return;
|
@@ -9794,7 +9841,7 @@
|
|
9794
9841
|
/**
|
9795
9842
|
* @ignore
|
9796
9843
|
*/
|
9797
|
-
function mergeConfig(defaultConfig, userConfig) {
|
9844
|
+
function mergeConfig(defaultConfig, userConfig, logger) {
|
9798
9845
|
if ((userConfig.liveSyncDurationCount || userConfig.liveMaxLatencyDurationCount) && (userConfig.liveSyncDuration || userConfig.liveMaxLatencyDuration)) {
|
9799
9846
|
throw new Error("Illegal hls.js config: don't mix up liveSyncDurationCount/liveMaxLatencyDurationCount and liveSyncDuration/liveMaxLatencyDuration");
|
9800
9847
|
}
|
@@ -9864,7 +9911,7 @@
|
|
9864
9911
|
/**
|
9865
9912
|
* @ignore
|
9866
9913
|
*/
|
9867
|
-
function enableStreamingMode(config) {
|
9914
|
+
function enableStreamingMode(config, logger) {
|
9868
9915
|
var currentLoader = config.loader;
|
9869
9916
|
if (currentLoader !== FetchLoader && currentLoader !== XhrLoader) {
|
9870
9917
|
// If a developer has configured their own loader, respect that choice
|
@@ -9881,12 +9928,11 @@
|
|
9881
9928
|
}
|
9882
9929
|
}
|
9883
9930
|
|
9884
|
-
var chromeOrFirefox;
|
9885
9931
|
var LevelController = /*#__PURE__*/function (_BasePlaylistControll) {
|
9886
9932
|
_inheritsLoose(LevelController, _BasePlaylistControll);
|
9887
9933
|
function LevelController(hls, contentSteeringController) {
|
9888
9934
|
var _this;
|
9889
|
-
_this = _BasePlaylistControll.call(this, hls, '
|
9935
|
+
_this = _BasePlaylistControll.call(this, hls, 'level-controller') || this;
|
9890
9936
|
_this._levels = [];
|
9891
9937
|
_this._firstLevel = -1;
|
9892
9938
|
_this._maxAutoLevel = -1;
|
@@ -9955,21 +10001,13 @@
|
|
9955
10001
|
var videoCodecFound = false;
|
9956
10002
|
var audioCodecFound = false;
|
9957
10003
|
data.levels.forEach(function (levelParsed) {
|
9958
|
-
var
|
10004
|
+
var _videoCodec;
|
9959
10005
|
var attributes = levelParsed.attrs;
|
9960
|
-
|
9961
|
-
// erase audio codec info if browser does not support mp4a.40.34.
|
9962
|
-
// demuxer will autodetect codec and fallback to mpeg/audio
|
9963
10006
|
var audioCodec = levelParsed.audioCodec,
|
9964
10007
|
videoCodec = levelParsed.videoCodec;
|
9965
|
-
if (((_audioCodec = audioCodec) == null ? void 0 : _audioCodec.indexOf('mp4a.40.34')) !== -1) {
|
9966
|
-
chromeOrFirefox || (chromeOrFirefox = /chrome|firefox/i.test(navigator.userAgent));
|
9967
|
-
if (chromeOrFirefox) {
|
9968
|
-
levelParsed.audioCodec = audioCodec = undefined;
|
9969
|
-
}
|
9970
|
-
}
|
9971
10008
|
if (audioCodec) {
|
9972
|
-
|
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;
|
9973
10011
|
}
|
9974
10012
|
if (((_videoCodec = videoCodec) == null ? void 0 : _videoCodec.indexOf('avc1')) === 0) {
|
9975
10013
|
videoCodec = levelParsed.videoCodec = convertAVC1ToAVCOTI(videoCodec);
|
@@ -11116,8 +11154,8 @@
|
|
11116
11154
|
var _frag$decryptdata;
|
11117
11155
|
var byteRangeStart = start;
|
11118
11156
|
var byteRangeEnd = end;
|
11119
|
-
if (frag.sn === 'initSegment' && ((_frag$decryptdata = frag.decryptdata) == null ? void 0 : _frag$decryptdata.method)
|
11120
|
-
// 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,
|
11121
11159
|
// has the unencrypted size specified in the range.
|
11122
11160
|
// Ref: https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-08#section-6.3.6
|
11123
11161
|
var fragmentLen = end - start;
|
@@ -11150,6 +11188,9 @@
|
|
11150
11188
|
(part ? part : frag).stats.aborted = true;
|
11151
11189
|
return new LoadError(errorData);
|
11152
11190
|
}
|
11191
|
+
function isMethodFullSegmentAesCbc(method) {
|
11192
|
+
return method === 'AES-128' || method === 'AES-256';
|
11193
|
+
}
|
11153
11194
|
var LoadError = /*#__PURE__*/function (_Error) {
|
11154
11195
|
_inheritsLoose(LoadError, _Error);
|
11155
11196
|
function LoadError(data) {
|
@@ -11306,6 +11347,8 @@
|
|
11306
11347
|
}
|
11307
11348
|
return this.loadKeyEME(keyInfo, frag);
|
11308
11349
|
case 'AES-128':
|
11350
|
+
case 'AES-256':
|
11351
|
+
case 'AES-256-CTR':
|
11309
11352
|
return this.loadKeyHTTP(keyInfo, frag);
|
11310
11353
|
default:
|
11311
11354
|
return Promise.reject(this.createKeyLoadError(frag, ErrorDetails.KEY_LOAD_ERROR, new Error("Key supplied with unsupported METHOD: \"" + decryptdata.method + "\"")));
|
@@ -11439,13 +11482,17 @@
|
|
11439
11482
|
* we are limiting the task execution per call stack to exactly one, but scheduling/post-poning further
|
11440
11483
|
* task processing on the next main loop iteration (also known as "next tick" in the Node/JS runtime lingo).
|
11441
11484
|
*/
|
11442
|
-
var TaskLoop = /*#__PURE__*/function () {
|
11443
|
-
|
11444
|
-
|
11445
|
-
|
11446
|
-
|
11447
|
-
|
11448
|
-
|
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;
|
11449
11496
|
}
|
11450
11497
|
var _proto = TaskLoop.prototype;
|
11451
11498
|
_proto.destroy = function destroy() {
|
@@ -11531,7 +11578,7 @@
|
|
11531
11578
|
*/;
|
11532
11579
|
_proto.doTick = function doTick() {};
|
11533
11580
|
return TaskLoop;
|
11534
|
-
}();
|
11581
|
+
}(Logger);
|
11535
11582
|
|
11536
11583
|
var ChunkMetadata = function ChunkMetadata(level, sn, id, size, part, partial) {
|
11537
11584
|
if (size === void 0) {
|
@@ -11717,37 +11764,65 @@
|
|
11717
11764
|
}
|
11718
11765
|
|
11719
11766
|
var AESCrypto = /*#__PURE__*/function () {
|
11720
|
-
function AESCrypto(subtle, iv) {
|
11767
|
+
function AESCrypto(subtle, iv, aesMode) {
|
11721
11768
|
this.subtle = void 0;
|
11722
11769
|
this.aesIV = void 0;
|
11770
|
+
this.aesMode = void 0;
|
11723
11771
|
this.subtle = subtle;
|
11724
11772
|
this.aesIV = iv;
|
11773
|
+
this.aesMode = aesMode;
|
11725
11774
|
}
|
11726
11775
|
var _proto = AESCrypto.prototype;
|
11727
11776
|
_proto.decrypt = function decrypt(data, key) {
|
11728
|
-
|
11729
|
-
|
11730
|
-
|
11731
|
-
|
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
|
+
}
|
11732
11794
|
};
|
11733
11795
|
return AESCrypto;
|
11734
11796
|
}();
|
11735
11797
|
|
11736
11798
|
var FastAESKey = /*#__PURE__*/function () {
|
11737
|
-
function FastAESKey(subtle, key) {
|
11799
|
+
function FastAESKey(subtle, key, aesMode) {
|
11738
11800
|
this.subtle = void 0;
|
11739
11801
|
this.key = void 0;
|
11802
|
+
this.aesMode = void 0;
|
11740
11803
|
this.subtle = subtle;
|
11741
11804
|
this.key = key;
|
11805
|
+
this.aesMode = aesMode;
|
11742
11806
|
}
|
11743
11807
|
var _proto = FastAESKey.prototype;
|
11744
11808
|
_proto.expandKey = function expandKey() {
|
11809
|
+
var subtleAlgoName = getSubtleAlgoName(this.aesMode);
|
11745
11810
|
return this.subtle.importKey('raw', this.key, {
|
11746
|
-
name:
|
11811
|
+
name: subtleAlgoName
|
11747
11812
|
}, false, ['encrypt', 'decrypt']);
|
11748
11813
|
};
|
11749
11814
|
return FastAESKey;
|
11750
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
|
+
}
|
11751
11826
|
|
11752
11827
|
// PKCS7
|
11753
11828
|
function removePadding(array) {
|
@@ -12000,7 +12075,8 @@
|
|
12000
12075
|
this.currentIV = null;
|
12001
12076
|
this.currentResult = null;
|
12002
12077
|
this.useSoftware = void 0;
|
12003
|
-
this.
|
12078
|
+
this.enableSoftwareAES = void 0;
|
12079
|
+
this.enableSoftwareAES = config.enableSoftwareAES;
|
12004
12080
|
this.removePKCS7Padding = removePKCS7Padding;
|
12005
12081
|
// built in decryptor expects PKCS7 padding
|
12006
12082
|
if (removePKCS7Padding) {
|
@@ -12013,9 +12089,7 @@
|
|
12013
12089
|
/* no-op */
|
12014
12090
|
}
|
12015
12091
|
}
|
12016
|
-
|
12017
|
-
this.useSoftware = true;
|
12018
|
-
}
|
12092
|
+
this.useSoftware = this.subtle === null;
|
12019
12093
|
}
|
12020
12094
|
var _proto = Decrypter.prototype;
|
12021
12095
|
_proto.destroy = function destroy() {
|
@@ -12052,11 +12126,11 @@
|
|
12052
12126
|
this.softwareDecrypter = null;
|
12053
12127
|
}
|
12054
12128
|
};
|
12055
|
-
_proto.decrypt = function decrypt(data, key, iv) {
|
12129
|
+
_proto.decrypt = function decrypt(data, key, iv, aesMode) {
|
12056
12130
|
var _this = this;
|
12057
12131
|
if (this.useSoftware) {
|
12058
12132
|
return new Promise(function (resolve, reject) {
|
12059
|
-
_this.softwareDecrypt(new Uint8Array(data), key, iv);
|
12133
|
+
_this.softwareDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12060
12134
|
var decryptResult = _this.flush();
|
12061
12135
|
if (decryptResult) {
|
12062
12136
|
resolve(decryptResult.buffer);
|
@@ -12065,16 +12139,20 @@
|
|
12065
12139
|
}
|
12066
12140
|
});
|
12067
12141
|
}
|
12068
|
-
return this.webCryptoDecrypt(new Uint8Array(data), key, iv);
|
12142
|
+
return this.webCryptoDecrypt(new Uint8Array(data), key, iv, aesMode);
|
12069
12143
|
}
|
12070
12144
|
|
12071
12145
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
12072
12146
|
// data is handled in the flush() call
|
12073
12147
|
;
|
12074
|
-
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv) {
|
12148
|
+
_proto.softwareDecrypt = function softwareDecrypt(data, key, iv, aesMode) {
|
12075
12149
|
var currentIV = this.currentIV,
|
12076
12150
|
currentResult = this.currentResult,
|
12077
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
|
+
}
|
12078
12156
|
this.logOnce('JS AES decrypt');
|
12079
12157
|
// The output is staggered during progressive parsing - the current result is cached, and emitted on the next call
|
12080
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
|
@@ -12107,12 +12185,12 @@
|
|
12107
12185
|
}
|
12108
12186
|
return result;
|
12109
12187
|
};
|
12110
|
-
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv) {
|
12188
|
+
_proto.webCryptoDecrypt = function webCryptoDecrypt(data, key, iv, aesMode) {
|
12111
12189
|
var _this2 = this;
|
12112
12190
|
var subtle = this.subtle;
|
12113
12191
|
if (this.key !== key || !this.fastAesKey) {
|
12114
12192
|
this.key = key;
|
12115
|
-
this.fastAesKey = new FastAESKey(subtle, key);
|
12193
|
+
this.fastAesKey = new FastAESKey(subtle, key, aesMode);
|
12116
12194
|
}
|
12117
12195
|
return this.fastAesKey.expandKey().then(function (aesKey) {
|
12118
12196
|
// decrypt using web crypto
|
@@ -12120,22 +12198,25 @@
|
|
12120
12198
|
return Promise.reject(new Error('web crypto not initialized'));
|
12121
12199
|
}
|
12122
12200
|
_this2.logOnce('WebCrypto AES decrypt');
|
12123
|
-
var crypto = new AESCrypto(subtle, new Uint8Array(iv));
|
12201
|
+
var crypto = new AESCrypto(subtle, new Uint8Array(iv), aesMode);
|
12124
12202
|
return crypto.decrypt(data.buffer, aesKey);
|
12125
12203
|
}).catch(function (err) {
|
12126
12204
|
logger.warn("[decrypter]: WebCrypto Error, disable WebCrypto API, " + err.name + ": " + err.message);
|
12127
|
-
return _this2.onWebCryptoError(data, key, iv);
|
12205
|
+
return _this2.onWebCryptoError(data, key, iv, aesMode);
|
12128
12206
|
});
|
12129
12207
|
};
|
12130
|
-
_proto.onWebCryptoError = function onWebCryptoError(data, key, iv) {
|
12131
|
-
|
12132
|
-
|
12133
|
-
|
12134
|
-
|
12135
|
-
|
12136
|
-
|
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
|
+
}
|
12137
12218
|
}
|
12138
|
-
throw new Error('WebCrypto and softwareDecrypt: failed to decrypt data');
|
12219
|
+
throw new Error('WebCrypto' + (enableSoftwareAES ? ' and softwareDecrypt' : '') + ': failed to decrypt data');
|
12139
12220
|
};
|
12140
12221
|
_proto.getValidChunk = function getValidChunk(data) {
|
12141
12222
|
var currentChunk = data;
|
@@ -12189,7 +12270,7 @@
|
|
12189
12270
|
_inheritsLoose(BaseStreamController, _TaskLoop);
|
12190
12271
|
function BaseStreamController(hls, fragmentTracker, keyLoader, logPrefix, playlistType) {
|
12191
12272
|
var _this;
|
12192
|
-
_this = _TaskLoop.call(this) || this;
|
12273
|
+
_this = _TaskLoop.call(this, logPrefix, hls.logger) || this;
|
12193
12274
|
_this.hls = void 0;
|
12194
12275
|
_this.fragPrevious = null;
|
12195
12276
|
_this.fragCurrent = null;
|
@@ -12214,25 +12295,87 @@
|
|
12214
12295
|
_this.startFragRequested = false;
|
12215
12296
|
_this.decrypter = void 0;
|
12216
12297
|
_this.initPTS = [];
|
12217
|
-
_this.
|
12218
|
-
_this.
|
12219
|
-
|
12220
|
-
|
12221
|
-
|
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
|
+
};
|
12222
12353
|
_this.playlistType = playlistType;
|
12223
|
-
_this.logPrefix = logPrefix;
|
12224
|
-
_this.log = logger.log.bind(logger, logPrefix + ":");
|
12225
|
-
_this.warn = logger.warn.bind(logger, logPrefix + ":");
|
12226
12354
|
_this.hls = hls;
|
12227
12355
|
_this.fragmentLoader = new FragmentLoader(hls.config);
|
12228
12356
|
_this.keyLoader = keyLoader;
|
12229
12357
|
_this.fragmentTracker = fragmentTracker;
|
12230
12358
|
_this.config = hls.config;
|
12231
12359
|
_this.decrypter = new Decrypter(hls.config);
|
12232
|
-
hls.on(Events.MANIFEST_LOADED, _this.onManifestLoaded, _assertThisInitialized(_this));
|
12233
12360
|
return _this;
|
12234
12361
|
}
|
12235
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
|
+
};
|
12236
12379
|
_proto.doTick = function doTick() {
|
12237
12380
|
this.onTickEnd();
|
12238
12381
|
};
|
@@ -12256,6 +12399,12 @@
|
|
12256
12399
|
this.clearNextTick();
|
12257
12400
|
this.state = State.STOPPED;
|
12258
12401
|
};
|
12402
|
+
_proto.pauseBuffering = function pauseBuffering() {
|
12403
|
+
this.buffering = false;
|
12404
|
+
};
|
12405
|
+
_proto.resumeBuffering = function resumeBuffering() {
|
12406
|
+
this.buffering = true;
|
12407
|
+
};
|
12259
12408
|
_proto._streamEnded = function _streamEnded(bufferInfo, levelDetails) {
|
12260
12409
|
// If playlist is live, there is another buffered range after the current range, nothing buffered, media is detached,
|
12261
12410
|
// of nothing loading/loaded return false
|
@@ -12286,10 +12435,8 @@
|
|
12286
12435
|
};
|
12287
12436
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
12288
12437
|
var media = this.media = this.mediaBuffer = data.media;
|
12289
|
-
|
12290
|
-
|
12291
|
-
media.addEventListener('seeking', this.onvseeking);
|
12292
|
-
media.addEventListener('ended', this.onvended);
|
12438
|
+
media.addEventListener('seeking', this.onMediaSeeking);
|
12439
|
+
media.addEventListener('ended', this.onMediaEnded);
|
12293
12440
|
var config = this.config;
|
12294
12441
|
if (this.levels && config.autoStartLoad && this.state === State.STOPPED) {
|
12295
12442
|
this.startLoad(config.startPosition);
|
@@ -12303,10 +12450,9 @@
|
|
12303
12450
|
}
|
12304
12451
|
|
12305
12452
|
// remove video listeners
|
12306
|
-
if (media
|
12307
|
-
media.removeEventListener('seeking', this.
|
12308
|
-
media.removeEventListener('ended', this.
|
12309
|
-
this.onvseeking = this.onvended = null;
|
12453
|
+
if (media) {
|
12454
|
+
media.removeEventListener('seeking', this.onMediaSeeking);
|
12455
|
+
media.removeEventListener('ended', this.onMediaEnded);
|
12310
12456
|
}
|
12311
12457
|
if (this.keyLoader) {
|
12312
12458
|
this.keyLoader.detach();
|
@@ -12316,54 +12462,8 @@
|
|
12316
12462
|
this.fragmentTracker.removeAllFragments();
|
12317
12463
|
this.stopLoad();
|
12318
12464
|
};
|
12319
|
-
_proto.
|
12320
|
-
|
12321
|
-
fragCurrent = this.fragCurrent,
|
12322
|
-
media = this.media,
|
12323
|
-
mediaBuffer = this.mediaBuffer,
|
12324
|
-
state = this.state;
|
12325
|
-
var currentTime = media ? media.currentTime : 0;
|
12326
|
-
var bufferInfo = BufferHelper.bufferInfo(mediaBuffer ? mediaBuffer : media, currentTime, config.maxBufferHole);
|
12327
|
-
this.log("media seeking to " + (isFiniteNumber(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state);
|
12328
|
-
if (this.state === State.ENDED) {
|
12329
|
-
this.resetLoadingState();
|
12330
|
-
} else if (fragCurrent) {
|
12331
|
-
// Seeking while frag load is in progress
|
12332
|
-
var tolerance = config.maxFragLookUpTolerance;
|
12333
|
-
var fragStartOffset = fragCurrent.start - tolerance;
|
12334
|
-
var fragEndOffset = fragCurrent.start + fragCurrent.duration + tolerance;
|
12335
|
-
// if seeking out of buffered range or into new one
|
12336
|
-
if (!bufferInfo.len || fragEndOffset < bufferInfo.start || fragStartOffset > bufferInfo.end) {
|
12337
|
-
var pastFragment = currentTime > fragEndOffset;
|
12338
|
-
// if the seek position is outside the current fragment range
|
12339
|
-
if (currentTime < fragStartOffset || pastFragment) {
|
12340
|
-
if (pastFragment && fragCurrent.loader) {
|
12341
|
-
this.log('seeking outside of buffer while fragment load in progress, cancel fragment load');
|
12342
|
-
fragCurrent.abortRequests();
|
12343
|
-
this.resetLoadingState();
|
12344
|
-
}
|
12345
|
-
this.fragPrevious = null;
|
12346
|
-
}
|
12347
|
-
}
|
12348
|
-
}
|
12349
|
-
if (media) {
|
12350
|
-
// Remove gap fragments
|
12351
|
-
this.fragmentTracker.removeFragmentsInRange(currentTime, Infinity, this.playlistType, true);
|
12352
|
-
this.lastCurrentTime = currentTime;
|
12353
|
-
}
|
12354
|
-
|
12355
|
-
// in case seeking occurs although no media buffered, adjust startPosition and nextLoadPosition to seek target
|
12356
|
-
if (!this.loadedmetadata && !bufferInfo.len) {
|
12357
|
-
this.nextLoadPosition = this.startPosition = currentTime;
|
12358
|
-
}
|
12359
|
-
|
12360
|
-
// Async tick to speed up processing
|
12361
|
-
this.tickImmediate();
|
12362
|
-
};
|
12363
|
-
_proto.onMediaEnded = function onMediaEnded() {
|
12364
|
-
// reset startPosition and lastCurrentTime to restart playback @ stream beginning
|
12365
|
-
this.startPosition = this.lastCurrentTime = 0;
|
12366
|
-
};
|
12465
|
+
_proto.onManifestLoading = function onManifestLoading() {};
|
12466
|
+
_proto.onError = function onError(event, data) {};
|
12367
12467
|
_proto.onManifestLoaded = function onManifestLoaded(event, data) {
|
12368
12468
|
this.startTimeOffset = data.startTimeOffset;
|
12369
12469
|
this.initPTS = [];
|
@@ -12373,7 +12473,7 @@
|
|
12373
12473
|
this.stopLoad();
|
12374
12474
|
_TaskLoop.prototype.onHandlerDestroying.call(this);
|
12375
12475
|
// @ts-ignore
|
12376
|
-
this.hls = null;
|
12476
|
+
this.hls = this.onMediaSeeking = this.onMediaEnded = null;
|
12377
12477
|
};
|
12378
12478
|
_proto.onHandlerDestroyed = function onHandlerDestroyed() {
|
12379
12479
|
this.state = State.STOPPED;
|
@@ -12503,10 +12603,10 @@
|
|
12503
12603
|
var decryptData = frag.decryptdata;
|
12504
12604
|
|
12505
12605
|
// check to see if the payload needs to be decrypted
|
12506
|
-
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)) {
|
12507
12607
|
var startTime = self.performance.now();
|
12508
12608
|
// decrypt init segment data
|
12509
|
-
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) {
|
12510
12610
|
hls.trigger(Events.ERROR, {
|
12511
12611
|
type: ErrorTypes.MEDIA_ERROR,
|
12512
12612
|
details: ErrorDetails.FRAG_DECRYPT_ERROR,
|
@@ -12619,7 +12719,7 @@
|
|
12619
12719
|
}
|
12620
12720
|
var keyLoadingPromise = null;
|
12621
12721
|
if (frag.encrypted && !((_frag$decryptdata = frag.decryptdata) != null && _frag$decryptdata.key)) {
|
12622
|
-
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);
|
12623
12723
|
this.state = State.KEY_LOADING;
|
12624
12724
|
this.fragCurrent = frag;
|
12625
12725
|
keyLoadingPromise = this.keyLoader.load(frag).then(function (keyLoadedData) {
|
@@ -12650,7 +12750,7 @@
|
|
12650
12750
|
var partIndex = this.getNextPart(partList, frag, targetBufferTime);
|
12651
12751
|
if (partIndex > -1) {
|
12652
12752
|
var part = partList[partIndex];
|
12653
|
-
this.log("Loading part sn: " + frag.sn + " p: " + part.index + " cc: " + frag.cc + " of playlist [" + details.startSN + "-" + details.endSN + "] parts [0-" + partIndex + "-" + (partList.length - 1) + "] " + (this.
|
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)));
|
12654
12754
|
this.nextLoadPosition = part.start + part.duration;
|
12655
12755
|
this.state = State.FRAG_LOADING;
|
12656
12756
|
var _result;
|
@@ -12683,7 +12783,7 @@
|
|
12683
12783
|
}
|
12684
12784
|
}
|
12685
12785
|
}
|
12686
|
-
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)));
|
12687
12787
|
// Don't update nextLoadPosition for fragments which are not buffered
|
12688
12788
|
if (isFiniteNumber(frag.sn) && !this.bitrateTest) {
|
12689
12789
|
this.nextLoadPosition = frag.start + frag.duration;
|
@@ -13244,7 +13344,7 @@
|
|
13244
13344
|
errorAction.resolved = true;
|
13245
13345
|
}
|
13246
13346
|
} else {
|
13247
|
-
|
13347
|
+
this.warn(data.details + " reached or exceeded max retry (" + retryCount + ")");
|
13248
13348
|
return;
|
13249
13349
|
}
|
13250
13350
|
} else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
@@ -13634,6 +13734,7 @@
|
|
13634
13734
|
*/
|
13635
13735
|
function getAudioConfig(observer, data, offset, audioCodec) {
|
13636
13736
|
var adtsObjectType;
|
13737
|
+
var originalAdtsObjectType;
|
13637
13738
|
var adtsExtensionSamplingIndex;
|
13638
13739
|
var adtsChannelConfig;
|
13639
13740
|
var config;
|
@@ -13641,7 +13742,7 @@
|
|
13641
13742
|
var manifestCodec = audioCodec;
|
13642
13743
|
var adtsSamplingRates = [96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350];
|
13643
13744
|
// byte 2
|
13644
|
-
adtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13745
|
+
adtsObjectType = originalAdtsObjectType = ((data[offset + 2] & 0xc0) >>> 6) + 1;
|
13645
13746
|
var adtsSamplingIndex = (data[offset + 2] & 0x3c) >>> 2;
|
13646
13747
|
if (adtsSamplingIndex > adtsSamplingRates.length - 1) {
|
13647
13748
|
var error = new Error("invalid ADTS sampling index:" + adtsSamplingIndex);
|
@@ -13658,8 +13759,8 @@
|
|
13658
13759
|
// byte 3
|
13659
13760
|
adtsChannelConfig |= (data[offset + 3] & 0xc0) >>> 6;
|
13660
13761
|
logger.log("manifest codec:" + audioCodec + ", ADTS type:" + adtsObjectType + ", samplingIndex:" + adtsSamplingIndex);
|
13661
|
-
//
|
13662
|
-
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)) {
|
13663
13764
|
if (adtsSamplingIndex >= 6) {
|
13664
13765
|
adtsObjectType = 5;
|
13665
13766
|
config = new Array(4);
|
@@ -13753,6 +13854,7 @@
|
|
13753
13854
|
samplerate: adtsSamplingRates[adtsSamplingIndex],
|
13754
13855
|
channelCount: adtsChannelConfig,
|
13755
13856
|
codec: 'mp4a.40.' + adtsObjectType,
|
13857
|
+
parsedCodec: 'mp4a.40.' + originalAdtsObjectType,
|
13756
13858
|
manifestCodec: manifestCodec
|
13757
13859
|
};
|
13758
13860
|
}
|
@@ -13807,7 +13909,8 @@
|
|
13807
13909
|
track.channelCount = config.channelCount;
|
13808
13910
|
track.codec = config.codec;
|
13809
13911
|
track.manifestCodec = config.manifestCodec;
|
13810
|
-
|
13912
|
+
track.parsedCodec = config.parsedCodec;
|
13913
|
+
logger.log("parsed codec:" + track.parsedCodec + ", codec:" + track.codec + ", rate:" + config.samplerate + ", channels:" + config.channelCount);
|
13811
13914
|
}
|
13812
13915
|
}
|
13813
13916
|
function getFrameDuration(samplerate) {
|
@@ -14287,36 +14390,140 @@
|
|
14287
14390
|
logger.log(VideoSample.pts + '/' + VideoSample.dts + ':' + VideoSample.debug);
|
14288
14391
|
}
|
14289
14392
|
};
|
14290
|
-
|
14291
|
-
|
14292
|
-
|
14293
|
-
|
14294
|
-
|
14295
|
-
|
14296
|
-
|
14297
|
-
|
14298
|
-
|
14299
|
-
|
14300
|
-
|
14301
|
-
|
14302
|
-
this.bitsAvailable = void 0;
|
14303
|
-
this.data = data;
|
14304
|
-
// the number of bytes left to examine in this.data
|
14305
|
-
this.bytesAvailable = data.byteLength;
|
14306
|
-
// the current word being examined
|
14307
|
-
this.word = 0; // :uint
|
14308
|
-
// the number of bits left to examine in the current word
|
14309
|
-
this.bitsAvailable = 0; // :uint
|
14310
|
-
}
|
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));
|
14311
14405
|
|
14312
|
-
|
14313
|
-
|
14314
|
-
|
14315
|
-
|
14316
|
-
|
14317
|
-
|
14318
|
-
|
14319
|
-
|
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;
|
14523
|
+
var bytesAvailable = this.bytesAvailable;
|
14524
|
+
var position = data.byteLength - bytesAvailable;
|
14525
|
+
var workingBytes = new Uint8Array(4);
|
14526
|
+
var availableBytes = Math.min(4, bytesAvailable);
|
14320
14527
|
if (availableBytes === 0) {
|
14321
14528
|
throw new Error('no bytes available');
|
14322
14529
|
}
|
@@ -14441,22 +14648,179 @@
|
|
14441
14648
|
;
|
14442
14649
|
_proto.readUInt = function readUInt() {
|
14443
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();
|
14444
14809
|
}
|
14445
14810
|
|
14446
14811
|
/**
|
14447
|
-
*
|
14448
|
-
* list is optionally transmitted as part of a sequence parameter
|
14812
|
+
* The scaling list is optionally transmitted as part of a sequence parameter
|
14449
14813
|
* set and is not relevant to transmuxing.
|
14450
14814
|
* @param count the number of entries in this scaling list
|
14451
14815
|
* @see Recommendation ITU-T H.264, Section 7.3.2.1.1.1
|
14452
14816
|
*/;
|
14453
|
-
_proto.skipScalingList = function skipScalingList(count) {
|
14817
|
+
_proto.skipScalingList = function skipScalingList(count, reader) {
|
14454
14818
|
var lastScale = 8;
|
14455
14819
|
var nextScale = 8;
|
14456
14820
|
var deltaScale;
|
14457
14821
|
for (var j = 0; j < count; j++) {
|
14458
14822
|
if (nextScale !== 0) {
|
14459
|
-
deltaScale =
|
14823
|
+
deltaScale = reader.readEG();
|
14460
14824
|
nextScale = (lastScale + deltaScale + 256) % 256;
|
14461
14825
|
}
|
14462
14826
|
lastScale = nextScale === 0 ? lastScale : nextScale;
|
@@ -14471,7 +14835,8 @@
|
|
14471
14835
|
* sequence parameter set, including the dimensions of the
|
14472
14836
|
* associated video frames.
|
14473
14837
|
*/;
|
14474
|
-
_proto.readSPS = function readSPS() {
|
14838
|
+
_proto.readSPS = function readSPS(sps) {
|
14839
|
+
var eg = new ExpGolomb(sps);
|
14475
14840
|
var frameCropLeftOffset = 0;
|
14476
14841
|
var frameCropRightOffset = 0;
|
14477
14842
|
var frameCropTopOffset = 0;
|
@@ -14479,13 +14844,13 @@
|
|
14479
14844
|
var numRefFramesInPicOrderCntCycle;
|
14480
14845
|
var scalingListCount;
|
14481
14846
|
var i;
|
14482
|
-
var readUByte =
|
14483
|
-
var readBits =
|
14484
|
-
var readUEG =
|
14485
|
-
var readBoolean =
|
14486
|
-
var skipBits =
|
14487
|
-
var skipEG =
|
14488
|
-
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);
|
14489
14854
|
var skipScalingList = this.skipScalingList.bind(this);
|
14490
14855
|
readUByte();
|
14491
14856
|
var profileIdc = readUByte(); // profile_idc
|
@@ -14510,9 +14875,9 @@
|
|
14510
14875
|
if (readBoolean()) {
|
14511
14876
|
// seq_scaling_list_present_flag[ i ]
|
14512
14877
|
if (i < 6) {
|
14513
|
-
skipScalingList(16);
|
14878
|
+
skipScalingList(16, eg);
|
14514
14879
|
} else {
|
14515
|
-
skipScalingList(64);
|
14880
|
+
skipScalingList(64, eg);
|
14516
14881
|
}
|
14517
14882
|
}
|
14518
14883
|
}
|
@@ -14617,26 +14982,24 @@
|
|
14617
14982
|
pixelRatio: pixelRatio
|
14618
14983
|
};
|
14619
14984
|
};
|
14620
|
-
|
14621
|
-
|
14622
|
-
this.readUByte();
|
14623
|
-
// discard first_mb_in_slice
|
14624
|
-
this.readUEG();
|
14625
|
-
// return slice_type
|
14626
|
-
return this.readUEG();
|
14627
|
-
};
|
14628
|
-
return ExpGolomb;
|
14629
|
-
}();
|
14985
|
+
return AvcVideoParser;
|
14986
|
+
}(BaseVideoParser);
|
14630
14987
|
|
14631
|
-
var
|
14632
|
-
_inheritsLoose(
|
14633
|
-
function
|
14634
|
-
|
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;
|
14635
14998
|
}
|
14636
|
-
var _proto =
|
14637
|
-
_proto.
|
14638
|
-
var
|
14639
|
-
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);
|
14640
15003
|
var VideoSample = this.VideoSample;
|
14641
15004
|
var push;
|
14642
15005
|
var spsfound = false;
|
@@ -14652,231 +15015,576 @@
|
|
14652
15015
|
units.forEach(function (unit) {
|
14653
15016
|
var _VideoSample2;
|
14654
15017
|
switch (unit.type) {
|
14655
|
-
//
|
15018
|
+
// NON-IDR, NON RANDOM ACCESS SLICE
|
15019
|
+
case 0:
|
14656
15020
|
case 1:
|
14657
|
-
|
14658
|
-
|
14659
|
-
|
14660
|
-
|
14661
|
-
|
14662
|
-
|
14663
|
-
|
14664
|
-
|
14665
|
-
|
14666
|
-
|
14667
|
-
|
14668
|
-
|
14669
|
-
|
14670
|
-
|
14671
|
-
|
14672
|
-
|
14673
|
-
|
14674
|
-
|
14675
|
-
|
14676
|
-
|
14677
|
-
|
14678
|
-
|
14679
|
-
|
14680
|
-
|
14681
|
-
|
14682
|
-
if (!VideoSample) {
|
14683
|
-
|
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;
|
14684
15049
|
}
|
14685
|
-
VideoSample.frame = true;
|
14686
|
-
VideoSample.key = iskey;
|
14687
|
-
break;
|
14688
|
-
// IDR
|
14689
15050
|
}
|
14690
|
-
|
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:
|
14691
15061
|
push = true;
|
14692
15062
|
// handle PES not starting with AUD
|
14693
15063
|
// if we have frame data already, that cannot belong to the same frame, so force a push
|
14694
15064
|
if ((_VideoSample2 = VideoSample) != null && _VideoSample2.frame && !VideoSample.key) {
|
14695
|
-
|
14696
|
-
VideoSample =
|
15065
|
+
_this2.pushAccessUnit(VideoSample, track);
|
15066
|
+
VideoSample = _this2.VideoSample = null;
|
14697
15067
|
}
|
14698
15068
|
if (!VideoSample) {
|
14699
|
-
VideoSample =
|
15069
|
+
VideoSample = _this2.VideoSample = _this2.createVideoSample(true, pes.pts, pes.dts, '');
|
14700
15070
|
}
|
14701
15071
|
VideoSample.key = true;
|
14702
15072
|
VideoSample.frame = true;
|
14703
15073
|
break;
|
15074
|
+
|
14704
15075
|
// SEI
|
14705
|
-
case
|
14706
|
-
{
|
14707
|
-
push = true;
|
14708
|
-
parseSEIMessageFromNALu(unit.data, 1, pes.pts, textTrack.samples);
|
14709
|
-
break;
|
14710
|
-
// SPS
|
14711
|
-
}
|
14712
|
-
case 7:
|
14713
|
-
{
|
14714
|
-
var _track$pixelRatio, _track$pixelRatio2;
|
14715
|
-
push = true;
|
14716
|
-
spsfound = true;
|
14717
|
-
var sps = unit.data;
|
14718
|
-
var expGolombDecoder = new ExpGolomb(sps);
|
14719
|
-
var config = expGolombDecoder.readSPS();
|
14720
|
-
if (!track.sps || track.width !== config.width || track.height !== config.height || ((_track$pixelRatio = track.pixelRatio) == null ? void 0 : _track$pixelRatio[0]) !== config.pixelRatio[0] || ((_track$pixelRatio2 = track.pixelRatio) == null ? void 0 : _track$pixelRatio2[1]) !== config.pixelRatio[1]) {
|
14721
|
-
track.width = config.width;
|
14722
|
-
track.height = config.height;
|
14723
|
-
track.pixelRatio = config.pixelRatio;
|
14724
|
-
track.sps = [sps];
|
14725
|
-
track.duration = duration;
|
14726
|
-
var codecarray = sps.subarray(1, 4);
|
14727
|
-
var codecstring = 'avc1.';
|
14728
|
-
for (var i = 0; i < 3; i++) {
|
14729
|
-
var h = codecarray[i].toString(16);
|
14730
|
-
if (h.length < 2) {
|
14731
|
-
h = '0' + h;
|
14732
|
-
}
|
14733
|
-
codecstring += h;
|
14734
|
-
}
|
14735
|
-
track.codec = codecstring;
|
14736
|
-
}
|
14737
|
-
break;
|
14738
|
-
}
|
14739
|
-
// PPS
|
14740
|
-
case 8:
|
15076
|
+
case 39:
|
14741
15077
|
push = true;
|
14742
|
-
|
14743
|
-
|
14744
|
-
|
14745
|
-
case 9:
|
14746
|
-
push = true;
|
14747
|
-
track.audFound = true;
|
14748
|
-
if (VideoSample) {
|
14749
|
-
_this.pushAccessUnit(VideoSample, track);
|
14750
|
-
}
|
14751
|
-
VideoSample = _this.VideoSample = _this.createVideoSample(false, pes.pts, pes.dts, '');
|
15078
|
+
parseSEIMessageFromNALu(unit.data, 2,
|
15079
|
+
// NALu header size
|
15080
|
+
pes.pts, textTrack.samples);
|
14752
15081
|
break;
|
14753
|
-
|
14754
|
-
|
15082
|
+
|
15083
|
+
// VPS
|
15084
|
+
case 32:
|
14755
15085
|
push = true;
|
14756
|
-
|
14757
|
-
|
14758
|
-
|
14759
|
-
|
14760
|
-
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;
|
14761
15090
|
}
|
15091
|
+
track.vps = [unit.data];
|
14762
15092
|
break;
|
14763
|
-
}
|
14764
|
-
if (VideoSample && push) {
|
14765
|
-
var _units = VideoSample.units;
|
14766
|
-
_units.push(unit);
|
14767
|
-
}
|
14768
|
-
});
|
14769
|
-
// if last PES packet, push samples
|
14770
|
-
if (last && VideoSample) {
|
14771
|
-
this.pushAccessUnit(VideoSample, track);
|
14772
|
-
this.VideoSample = null;
|
14773
|
-
}
|
14774
|
-
};
|
14775
|
-
_proto.parseAVCNALu = function parseAVCNALu(track, array) {
|
14776
|
-
var len = array.byteLength;
|
14777
|
-
var state = track.naluState || 0;
|
14778
|
-
var lastState = state;
|
14779
|
-
var units = [];
|
14780
|
-
var i = 0;
|
14781
|
-
var value;
|
14782
|
-
var overflow;
|
14783
|
-
var unitType;
|
14784
|
-
var lastUnitStart = -1;
|
14785
|
-
var lastUnitType = 0;
|
14786
|
-
// logger.log('PES:' + Hex.hexDump(array));
|
14787
15093
|
|
14788
|
-
|
14789
|
-
|
14790
|
-
|
14791
|
-
|
14792
|
-
|
14793
|
-
|
14794
|
-
|
14795
|
-
|
14796
|
-
|
14797
|
-
|
14798
|
-
|
14799
|
-
|
14800
|
-
|
14801
|
-
|
14802
|
-
|
14803
|
-
|
14804
|
-
|
14805
|
-
|
14806
|
-
|
14807
|
-
// here we have state either equal to 2 or 3
|
14808
|
-
if (!value) {
|
14809
|
-
state = 3;
|
14810
|
-
} else if (value === 1) {
|
14811
|
-
overflow = i - state - 1;
|
14812
|
-
if (lastUnitStart >= 0) {
|
14813
|
-
var unit = {
|
14814
|
-
data: array.subarray(lastUnitStart, overflow),
|
14815
|
-
type: lastUnitType
|
14816
|
-
};
|
14817
|
-
// logger.log('pushing NALU, type/size:' + unit.type + '/' + unit.data.byteLength);
|
14818
|
-
units.push(unit);
|
14819
|
-
} else {
|
14820
|
-
// lastUnitStart is undefined => this is the first start code found in this PES packet
|
14821
|
-
// first check if start code delimiter is overlapping between 2 PES packets,
|
14822
|
-
// ie it started in last packet (lastState not zero)
|
14823
|
-
// and ended at the beginning of this PES packet (i <= 4 - lastState)
|
14824
|
-
var lastUnit = this.getLastNalUnit(track.samples);
|
14825
|
-
if (lastUnit) {
|
14826
|
-
if (lastState && i <= 4 - lastState) {
|
14827
|
-
// start delimiter overlapping between PES packets
|
14828
|
-
// strip start delimiter bytes from the end of last NAL unit
|
14829
|
-
// check if lastUnit had a state different from zero
|
14830
|
-
if (lastUnit.state) {
|
14831
|
-
// strip last bytes
|
14832
|
-
lastUnit.data = lastUnit.data.subarray(0, lastUnit.data.byteLength - lastState);
|
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];
|
14833
15113
|
}
|
14834
15114
|
}
|
14835
|
-
|
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;
|
14836
15124
|
|
14837
|
-
|
14838
|
-
|
14839
|
-
|
14840
|
-
|
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);
|
14841
15138
|
}
|
14842
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;
|
14843
15180
|
}
|
14844
|
-
|
14845
|
-
|
14846
|
-
|
14847
|
-
|
14848
|
-
|
14849
|
-
|
14850
|
-
|
14851
|
-
|
14852
|
-
|
14853
|
-
|
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
|
+
}
|
14854
15308
|
}
|
14855
|
-
} else {
|
14856
|
-
state = 0;
|
14857
15309
|
}
|
14858
15310
|
}
|
14859
|
-
|
14860
|
-
|
14861
|
-
|
14862
|
-
|
14863
|
-
|
14864
|
-
|
14865
|
-
|
14866
|
-
|
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
|
+
}
|
14867
15358
|
}
|
14868
|
-
|
14869
|
-
if (
|
14870
|
-
|
14871
|
-
var
|
14872
|
-
|
14873
|
-
|
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
|
+
}
|
14874
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
|
14875
15578
|
}
|
14876
|
-
|
14877
|
-
|
15579
|
+
return {
|
15580
|
+
parallelismType: parallelismType
|
15581
|
+
};
|
14878
15582
|
};
|
14879
|
-
|
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;
|
14880
15588
|
}(BaseVideoParser);
|
14881
15589
|
|
14882
15590
|
/**
|
@@ -14894,7 +15602,7 @@
|
|
14894
15602
|
}
|
14895
15603
|
var _proto = SampleAesDecrypter.prototype;
|
14896
15604
|
_proto.decryptBuffer = function decryptBuffer(encryptedData) {
|
14897
|
-
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);
|
14898
15606
|
}
|
14899
15607
|
|
14900
15608
|
// AAC - encrypt all full 16 bytes blocks starting from offset 16
|
@@ -15013,7 +15721,7 @@
|
|
15013
15721
|
this.observer = observer;
|
15014
15722
|
this.config = config;
|
15015
15723
|
this.typeSupported = typeSupported;
|
15016
|
-
this.videoParser =
|
15724
|
+
this.videoParser = null;
|
15017
15725
|
}
|
15018
15726
|
TSDemuxer.probe = function probe(data) {
|
15019
15727
|
var syncOffset = TSDemuxer.syncOffset(data);
|
@@ -15183,7 +15891,19 @@
|
|
15183
15891
|
case videoPid:
|
15184
15892
|
if (stt) {
|
15185
15893
|
if (videoData && (pes = parsePES(videoData))) {
|
15186
|
-
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
|
+
}
|
15187
15907
|
}
|
15188
15908
|
videoData = {
|
15189
15909
|
data: [],
|
@@ -15341,8 +16061,20 @@
|
|
15341
16061
|
// try to parse last PES packets
|
15342
16062
|
var pes;
|
15343
16063
|
if (videoData && (pes = parsePES(videoData))) {
|
15344
|
-
this.videoParser
|
15345
|
-
|
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
|
+
}
|
15346
16078
|
} else {
|
15347
16079
|
// either avcData null or PES truncated, keep it for next frag parsing
|
15348
16080
|
videoTrack.pesData = videoData;
|
@@ -15644,7 +16376,12 @@
|
|
15644
16376
|
logger.warn('Unsupported EC-3 in M2TS found');
|
15645
16377
|
break;
|
15646
16378
|
case 0x24:
|
15647
|
-
|
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
|
+
}
|
15648
16385
|
break;
|
15649
16386
|
}
|
15650
16387
|
// move to the next table entry
|
@@ -15872,6 +16609,8 @@
|
|
15872
16609
|
avc1: [],
|
15873
16610
|
// codingname
|
15874
16611
|
avcC: [],
|
16612
|
+
hvc1: [],
|
16613
|
+
hvcC: [],
|
15875
16614
|
btrt: [],
|
15876
16615
|
dinf: [],
|
15877
16616
|
dref: [],
|
@@ -16299,8 +17038,10 @@
|
|
16299
17038
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.ac3(track));
|
16300
17039
|
}
|
16301
17040
|
return MP4.box(MP4.types.stsd, MP4.STSD, MP4.mp4a(track));
|
16302
|
-
} else {
|
17041
|
+
} else if (track.segmentCodec === 'avc') {
|
16303
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));
|
16304
17045
|
}
|
16305
17046
|
};
|
16306
17047
|
MP4.tkhd = function tkhd(track) {
|
@@ -16438,6 +17179,84 @@
|
|
16438
17179
|
var result = appendUint8Array(MP4.FTYP, movie);
|
16439
17180
|
return result;
|
16440
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
|
+
};
|
16441
17260
|
return MP4;
|
16442
17261
|
}();
|
16443
17262
|
MP4.types = void 0;
|
@@ -16824,9 +17643,9 @@
|
|
16824
17643
|
var foundOverlap = delta < -1;
|
16825
17644
|
if (foundHole || foundOverlap) {
|
16826
17645
|
if (foundHole) {
|
16827
|
-
logger.warn("
|
17646
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(delta, true) + " ms (" + delta + "dts) hole between fragments detected at " + timeOffset.toFixed(3));
|
16828
17647
|
} else {
|
16829
|
-
logger.warn("
|
17648
|
+
logger.warn((track.segmentCodec || '').toUpperCase() + ": " + toMsFromMpegTsClock(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected at " + timeOffset.toFixed(3));
|
16830
17649
|
}
|
16831
17650
|
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
|
16832
17651
|
firstDTS = nextAvcDts;
|
@@ -16835,12 +17654,24 @@
|
|
16835
17654
|
inputSamples[0].dts = firstDTS;
|
16836
17655
|
inputSamples[0].pts = firstPTS;
|
16837
17656
|
} else {
|
17657
|
+
var isPTSOrderRetained = true;
|
16838
17658
|
for (var _i = 0; _i < inputSamples.length; _i++) {
|
16839
|
-
if (inputSamples[_i].dts > firstPTS) {
|
17659
|
+
if (inputSamples[_i].dts > firstPTS && isPTSOrderRetained) {
|
16840
17660
|
break;
|
16841
17661
|
}
|
17662
|
+
var prevPTS = inputSamples[_i].pts;
|
16842
17663
|
inputSamples[_i].dts -= delta;
|
16843
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
|
+
}
|
16844
17675
|
}
|
16845
17676
|
}
|
16846
17677
|
logger.log("Video: Initial PTS/DTS adjusted: " + toMsFromMpegTsClock(firstPTS, true) + "/" + toMsFromMpegTsClock(firstDTS, true) + ", delta: " + toMsFromMpegTsClock(delta, true) + " ms");
|
@@ -16988,7 +17819,7 @@
|
|
16988
17819
|
}
|
16989
17820
|
}
|
16990
17821
|
}
|
16991
|
-
// 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)
|
16992
17823
|
mp4SampleDuration = stretchedLastFrame || !mp4SampleDuration ? averageSampleDuration : mp4SampleDuration;
|
16993
17824
|
this.nextAvcDts = nextAvcDts = lastDTS + mp4SampleDuration;
|
16994
17825
|
this.videoSampleDuration = mp4SampleDuration;
|
@@ -17123,7 +17954,7 @@
|
|
17123
17954
|
logger.warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round(1000 * delta / inputTimeScale) + " ms gap.");
|
17124
17955
|
for (var j = 0; j < missing; j++) {
|
17125
17956
|
var newStamp = Math.max(nextPts, 0);
|
17126
|
-
var fillFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
17957
|
+
var fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17127
17958
|
if (!fillFrame) {
|
17128
17959
|
logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
17129
17960
|
fillFrame = sample.unit.subarray();
|
@@ -17251,7 +18082,7 @@
|
|
17251
18082
|
// samples count of this segment's duration
|
17252
18083
|
var nbSamples = Math.ceil((endDTS - startDTS) / frameDuration);
|
17253
18084
|
// silent frame
|
17254
|
-
var silentFrame = AAC.getSilentFrame(track.manifestCodec || track.codec, track.channelCount);
|
18085
|
+
var silentFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
17255
18086
|
logger.warn('[mp4-remuxer]: remux empty Audio');
|
17256
18087
|
// Can't remux if we can't generate a silent frame...
|
17257
18088
|
if (!silentFrame) {
|
@@ -17638,13 +18469,15 @@
|
|
17638
18469
|
duration = transmuxConfig.duration,
|
17639
18470
|
initSegmentData = transmuxConfig.initSegmentData;
|
17640
18471
|
var keyData = getEncryptionType(uintData, decryptdata);
|
17641
|
-
if (keyData && keyData.method
|
18472
|
+
if (keyData && isFullSegmentEncryption(keyData.method)) {
|
17642
18473
|
var decrypter = this.getDecrypter();
|
18474
|
+
var aesMode = getAesModeFromFullSegmentMethod(keyData.method);
|
18475
|
+
|
17643
18476
|
// Software decryption is synchronous; webCrypto is not
|
17644
18477
|
if (decrypter.isSync()) {
|
17645
18478
|
// Software decryption is progressive. Progressive decryption may not return a result on each call. Any cached
|
17646
18479
|
// data is handled in the flush() call
|
17647
|
-
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer);
|
18480
|
+
var decryptedData = decrypter.softwareDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode);
|
17648
18481
|
// For Low-Latency HLS Parts, decrypt in place, since part parsing is expected on push progress
|
17649
18482
|
var loadingParts = chunkMeta.part > -1;
|
17650
18483
|
if (loadingParts) {
|
@@ -17656,7 +18489,7 @@
|
|
17656
18489
|
}
|
17657
18490
|
uintData = new Uint8Array(decryptedData);
|
17658
18491
|
} else {
|
17659
|
-
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) {
|
17660
18493
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
17661
18494
|
// the decrypted data has been transmuxed
|
17662
18495
|
var result = _this.push(decryptedData, null, chunkMeta);
|
@@ -18277,7 +19110,7 @@
|
|
18277
19110
|
observer.on(Events.ERROR, forwardMessage);
|
18278
19111
|
|
18279
19112
|
// forward logger events to main thread
|
18280
|
-
var forwardWorkerLogs = function forwardWorkerLogs() {
|
19113
|
+
var forwardWorkerLogs = function forwardWorkerLogs(logger) {
|
18281
19114
|
var _loop = function _loop(logFn) {
|
18282
19115
|
var func = function func(message) {
|
18283
19116
|
forwardMessage('workerLog', {
|
@@ -18298,8 +19131,8 @@
|
|
18298
19131
|
{
|
18299
19132
|
var config = JSON.parse(data.config);
|
18300
19133
|
self.transmuxer = new Transmuxer(observer, data.typeSupported, config, data.vendor, data.id);
|
18301
|
-
enableLogs(config.debug, data.id);
|
18302
|
-
forwardWorkerLogs();
|
19134
|
+
var logger = enableLogs(config.debug, data.id);
|
19135
|
+
forwardWorkerLogs(logger);
|
18303
19136
|
forwardMessage('init', null);
|
18304
19137
|
break;
|
18305
19138
|
}
|
@@ -18473,16 +19306,7 @@
|
|
18473
19306
|
this.observer = new EventEmitter();
|
18474
19307
|
this.observer.on(Events.FRAG_DECRYPTED, forwardMessage);
|
18475
19308
|
this.observer.on(Events.ERROR, forwardMessage);
|
18476
|
-
var
|
18477
|
-
isTypeSupported: function isTypeSupported() {
|
18478
|
-
return false;
|
18479
|
-
}
|
18480
|
-
};
|
18481
|
-
var m2tsTypeSupported = {
|
18482
|
-
mpeg: MediaSource.isTypeSupported('audio/mpeg'),
|
18483
|
-
mp3: MediaSource.isTypeSupported('audio/mp4; codecs="mp3"'),
|
18484
|
-
ac3: false
|
18485
|
-
};
|
19309
|
+
var m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
|
18486
19310
|
|
18487
19311
|
// navigator.vendor is not always available in Web Worker
|
18488
19312
|
// refer to https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/navigator
|
@@ -18739,21 +19563,26 @@
|
|
18739
19563
|
var MAX_START_GAP_JUMP = 2.0;
|
18740
19564
|
var SKIP_BUFFER_HOLE_STEP_SECONDS = 0.1;
|
18741
19565
|
var SKIP_BUFFER_RANGE_START = 0.05;
|
18742
|
-
var GapController = /*#__PURE__*/function () {
|
19566
|
+
var GapController = /*#__PURE__*/function (_Logger) {
|
19567
|
+
_inheritsLoose(GapController, _Logger);
|
18743
19568
|
function GapController(config, media, fragmentTracker, hls) {
|
18744
|
-
|
18745
|
-
this.
|
18746
|
-
|
18747
|
-
|
18748
|
-
|
18749
|
-
|
18750
|
-
|
18751
|
-
|
18752
|
-
|
18753
|
-
|
18754
|
-
|
18755
|
-
|
18756
|
-
|
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;
|
18757
19586
|
}
|
18758
19587
|
var _proto = GapController.prototype;
|
18759
19588
|
_proto.destroy = function destroy() {
|
@@ -18768,7 +19597,7 @@
|
|
18768
19597
|
*
|
18769
19598
|
* @param lastCurrentTime - Previously read playhead position
|
18770
19599
|
*/;
|
18771
|
-
_proto.poll = function poll(lastCurrentTime, activeFrag) {
|
19600
|
+
_proto.poll = function poll(lastCurrentTime, activeFrag, levelDetails, state) {
|
18772
19601
|
var config = this.config,
|
18773
19602
|
media = this.media,
|
18774
19603
|
stalled = this.stalled;
|
@@ -18783,6 +19612,7 @@
|
|
18783
19612
|
|
18784
19613
|
// The playhead is moving, no-op
|
18785
19614
|
if (currentTime !== lastCurrentTime) {
|
19615
|
+
this.ended = 0;
|
18786
19616
|
this.moved = true;
|
18787
19617
|
if (!seeking) {
|
18788
19618
|
this.nudgeRetry = 0;
|
@@ -18791,7 +19621,7 @@
|
|
18791
19621
|
// The playhead is now moving, but was previously stalled
|
18792
19622
|
if (this.stallReported) {
|
18793
19623
|
var _stalledDuration = self.performance.now() - stalled;
|
18794
|
-
|
19624
|
+
this.warn("playback not stuck anymore @" + currentTime + ", after " + Math.round(_stalledDuration) + "ms");
|
18795
19625
|
this.stallReported = false;
|
18796
19626
|
}
|
18797
19627
|
this.stalled = null;
|
@@ -18827,7 +19657,6 @@
|
|
18827
19657
|
// Skip start gaps if we haven't played, but the last poll detected the start of a stall
|
18828
19658
|
// The addition poll gives the browser a chance to jump the gap for us
|
18829
19659
|
if (!this.moved && this.stalled !== null) {
|
18830
|
-
var _level$details;
|
18831
19660
|
// There is no playable buffer (seeked, waiting for buffer)
|
18832
19661
|
var isBuffered = bufferInfo.len > 0;
|
18833
19662
|
if (!isBuffered && !nextStart) {
|
@@ -18839,9 +19668,8 @@
|
|
18839
19668
|
// When joining a live stream with audio tracks, account for live playlist window sliding by allowing
|
18840
19669
|
// a larger jump over start gaps caused by the audio-stream-controller buffering a start fragment
|
18841
19670
|
// that begins over 1 target duration after the video start position.
|
18842
|
-
var
|
18843
|
-
var
|
18844
|
-
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;
|
18845
19673
|
var partialOrGap = this.fragmentTracker.getPartialFragment(currentTime);
|
18846
19674
|
if (startJump > 0 && (startJump <= maxStartGapJump || partialOrGap)) {
|
18847
19675
|
if (!media.paused) {
|
@@ -18859,6 +19687,17 @@
|
|
18859
19687
|
}
|
18860
19688
|
var stalledDuration = tnow - stalled;
|
18861
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
|
+
}
|
18862
19701
|
// Report stalling after trying to fix
|
18863
19702
|
this._reportStall(bufferInfo);
|
18864
19703
|
if (!this.media) {
|
@@ -18900,7 +19739,7 @@
|
|
18900
19739
|
// needs to cross some sort of threshold covering all source-buffers content
|
18901
19740
|
// to start playing properly.
|
18902
19741
|
if ((bufferInfo.len > config.maxBufferHole || bufferInfo.nextStart && bufferInfo.nextStart - currentTime < config.maxBufferHole) && stalledDurationMs > config.highBufferWatchdogPeriod * 1000) {
|
18903
|
-
|
19742
|
+
this.warn('Trying to nudge playhead over buffer-hole');
|
18904
19743
|
// Try to nudge currentTime over a buffer hole if we've been stalling for the configured amount of seconds
|
18905
19744
|
// We only try to jump the hole if it's under the configured size
|
18906
19745
|
// Reset stalled so to rearm watchdog timer
|
@@ -18922,7 +19761,7 @@
|
|
18922
19761
|
// Report stalled error once
|
18923
19762
|
this.stallReported = true;
|
18924
19763
|
var error = new Error("Playback stalling at @" + media.currentTime + " due to low buffer (" + JSON.stringify(bufferInfo) + ")");
|
18925
|
-
|
19764
|
+
this.warn(error.message);
|
18926
19765
|
hls.trigger(Events.ERROR, {
|
18927
19766
|
type: ErrorTypes.MEDIA_ERROR,
|
18928
19767
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -18986,7 +19825,7 @@
|
|
18986
19825
|
}
|
18987
19826
|
}
|
18988
19827
|
var targetTime = Math.max(startTime + SKIP_BUFFER_RANGE_START, currentTime + SKIP_BUFFER_HOLE_STEP_SECONDS);
|
18989
|
-
|
19828
|
+
this.warn("skipping hole, adjusting currentTime from " + currentTime + " to " + targetTime);
|
18990
19829
|
this.moved = true;
|
18991
19830
|
this.stalled = null;
|
18992
19831
|
media.currentTime = targetTime;
|
@@ -19025,7 +19864,7 @@
|
|
19025
19864
|
var targetTime = currentTime + (nudgeRetry + 1) * config.nudgeOffset;
|
19026
19865
|
// playback stalled in buffered area ... let's nudge currentTime to try to overcome this
|
19027
19866
|
var error = new Error("Nudging 'currentTime' from " + currentTime + " to " + targetTime);
|
19028
|
-
|
19867
|
+
this.warn(error.message);
|
19029
19868
|
media.currentTime = targetTime;
|
19030
19869
|
hls.trigger(Events.ERROR, {
|
19031
19870
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -19035,7 +19874,7 @@
|
|
19035
19874
|
});
|
19036
19875
|
} else {
|
19037
19876
|
var _error = new Error("Playhead still not moving while enough data buffered @" + currentTime + " after " + config.nudgeMaxRetry + " nudges");
|
19038
|
-
|
19877
|
+
this.error(_error.message);
|
19039
19878
|
hls.trigger(Events.ERROR, {
|
19040
19879
|
type: ErrorTypes.MEDIA_ERROR,
|
19041
19880
|
details: ErrorDetails.BUFFER_STALLED_ERROR,
|
@@ -19045,14 +19884,14 @@
|
|
19045
19884
|
}
|
19046
19885
|
};
|
19047
19886
|
return GapController;
|
19048
|
-
}();
|
19887
|
+
}(Logger);
|
19049
19888
|
|
19050
19889
|
var TICK_INTERVAL = 100; // how often to tick in ms
|
19051
19890
|
var StreamController = /*#__PURE__*/function (_BaseStreamController) {
|
19052
19891
|
_inheritsLoose(StreamController, _BaseStreamController);
|
19053
19892
|
function StreamController(hls, fragmentTracker, keyLoader) {
|
19054
19893
|
var _this;
|
19055
|
-
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, '
|
19894
|
+
_this = _BaseStreamController.call(this, hls, fragmentTracker, keyLoader, 'stream-controller', PlaylistLevelType.MAIN) || this;
|
19056
19895
|
_this.audioCodecSwap = false;
|
19057
19896
|
_this.gapController = null;
|
19058
19897
|
_this.level = -1;
|
@@ -19060,27 +19899,43 @@
|
|
19060
19899
|
_this.altAudio = false;
|
19061
19900
|
_this.audioOnly = false;
|
19062
19901
|
_this.fragPlaying = null;
|
19063
|
-
_this.onvplaying = null;
|
19064
|
-
_this.onvseeked = null;
|
19065
19902
|
_this.fragLastKbps = 0;
|
19066
19903
|
_this.couldBacktrack = false;
|
19067
19904
|
_this.backtrackFragment = null;
|
19068
19905
|
_this.audioCodecSwitch = false;
|
19069
19906
|
_this.videoBuffer = null;
|
19070
|
-
_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();
|
19071
19929
|
return _this;
|
19072
19930
|
}
|
19073
19931
|
var _proto = StreamController.prototype;
|
19074
|
-
_proto.
|
19932
|
+
_proto.registerListeners = function registerListeners() {
|
19933
|
+
_BaseStreamController.prototype.registerListeners.call(this);
|
19075
19934
|
var hls = this.hls;
|
19076
|
-
hls.on(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19077
|
-
hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19078
|
-
hls.on(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19079
19935
|
hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19080
19936
|
hls.on(Events.LEVEL_LOADING, this.onLevelLoading, this);
|
19081
19937
|
hls.on(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19082
19938
|
hls.on(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19083
|
-
hls.on(Events.ERROR, this.onError, this);
|
19084
19939
|
hls.on(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19085
19940
|
hls.on(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19086
19941
|
hls.on(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19088,15 +19943,12 @@
|
|
19088
19943
|
hls.on(Events.LEVELS_UPDATED, this.onLevelsUpdated, this);
|
19089
19944
|
hls.on(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19090
19945
|
};
|
19091
|
-
_proto.
|
19946
|
+
_proto.unregisterListeners = function unregisterListeners() {
|
19947
|
+
_BaseStreamController.prototype.unregisterListeners.call(this);
|
19092
19948
|
var hls = this.hls;
|
19093
|
-
hls.off(Events.MEDIA_ATTACHED, this.onMediaAttached, this);
|
19094
|
-
hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);
|
19095
|
-
hls.off(Events.MANIFEST_LOADING, this.onManifestLoading, this);
|
19096
19949
|
hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);
|
19097
19950
|
hls.off(Events.LEVEL_LOADED, this.onLevelLoaded, this);
|
19098
19951
|
hls.off(Events.FRAG_LOAD_EMERGENCY_ABORTED, this.onFragLoadEmergencyAborted, this);
|
19099
|
-
hls.off(Events.ERROR, this.onError, this);
|
19100
19952
|
hls.off(Events.AUDIO_TRACK_SWITCHING, this.onAudioTrackSwitching, this);
|
19101
19953
|
hls.off(Events.AUDIO_TRACK_SWITCHED, this.onAudioTrackSwitched, this);
|
19102
19954
|
hls.off(Events.BUFFER_CREATED, this.onBufferCreated, this);
|
@@ -19105,7 +19957,9 @@
|
|
19105
19957
|
hls.off(Events.FRAG_BUFFERED, this.onFragBuffered, this);
|
19106
19958
|
};
|
19107
19959
|
_proto.onHandlerDestroying = function onHandlerDestroying() {
|
19108
|
-
|
19960
|
+
// @ts-ignore
|
19961
|
+
this.onMediaPlaying = this.onMediaSeeked = null;
|
19962
|
+
this.unregisterListeners();
|
19109
19963
|
_BaseStreamController.prototype.onHandlerDestroying.call(this);
|
19110
19964
|
};
|
19111
19965
|
_proto.startLoad = function startLoad(startPosition) {
|
@@ -19215,7 +20069,7 @@
|
|
19215
20069
|
if (this.altAudio && this.audioOnly) {
|
19216
20070
|
return;
|
19217
20071
|
}
|
19218
|
-
if (!(levels != null && levels[level])) {
|
20072
|
+
if (!this.buffering || !(levels != null && levels[level])) {
|
19219
20073
|
return;
|
19220
20074
|
}
|
19221
20075
|
var levelInfo = levels[level];
|
@@ -19421,18 +20275,15 @@
|
|
19421
20275
|
_proto.onMediaAttached = function onMediaAttached(event, data) {
|
19422
20276
|
_BaseStreamController.prototype.onMediaAttached.call(this, event, data);
|
19423
20277
|
var media = data.media;
|
19424
|
-
|
19425
|
-
|
19426
|
-
media.addEventListener('playing', this.onvplaying);
|
19427
|
-
media.addEventListener('seeked', this.onvseeked);
|
20278
|
+
media.addEventListener('playing', this.onMediaPlaying);
|
20279
|
+
media.addEventListener('seeked', this.onMediaSeeked);
|
19428
20280
|
this.gapController = new GapController(this.config, media, this.fragmentTracker, this.hls);
|
19429
20281
|
};
|
19430
20282
|
_proto.onMediaDetaching = function onMediaDetaching() {
|
19431
20283
|
var media = this.media;
|
19432
|
-
if (media
|
19433
|
-
media.removeEventListener('playing', this.
|
19434
|
-
media.removeEventListener('seeked', this.
|
19435
|
-
this.onvplaying = this.onvseeked = null;
|
20284
|
+
if (media) {
|
20285
|
+
media.removeEventListener('playing', this.onMediaPlaying);
|
20286
|
+
media.removeEventListener('seeked', this.onMediaSeeked);
|
19436
20287
|
this.videoBuffer = null;
|
19437
20288
|
}
|
19438
20289
|
this.fragPlaying = null;
|
@@ -19442,27 +20293,6 @@
|
|
19442
20293
|
}
|
19443
20294
|
_BaseStreamController.prototype.onMediaDetaching.call(this);
|
19444
20295
|
};
|
19445
|
-
_proto.onMediaPlaying = function onMediaPlaying() {
|
19446
|
-
// tick to speed up FRAG_CHANGED triggering
|
19447
|
-
this.tick();
|
19448
|
-
};
|
19449
|
-
_proto.onMediaSeeked = function onMediaSeeked() {
|
19450
|
-
var media = this.media;
|
19451
|
-
var currentTime = media ? media.currentTime : null;
|
19452
|
-
if (isFiniteNumber(currentTime)) {
|
19453
|
-
this.log("Media seeked to " + currentTime.toFixed(3));
|
19454
|
-
}
|
19455
|
-
|
19456
|
-
// If seeked was issued before buffer was appended do not tick immediately
|
19457
|
-
var bufferInfo = this.getMainFwdBufferInfo();
|
19458
|
-
if (bufferInfo === null || bufferInfo.len === 0) {
|
19459
|
-
this.warn("Main forward buffer length on \"seeked\" event " + (bufferInfo ? bufferInfo.len : 'empty') + ")");
|
19460
|
-
return;
|
19461
|
-
}
|
19462
|
-
|
19463
|
-
// tick to speed up FRAG_CHANGED triggering
|
19464
|
-
this.tick();
|
19465
|
-
};
|
19466
20296
|
_proto.onManifestLoading = function onManifestLoading() {
|
19467
20297
|
// reset buffer on manifest loading
|
19468
20298
|
this.log('Trigger BUFFER_RESET');
|
@@ -19743,8 +20573,10 @@
|
|
19743
20573
|
}
|
19744
20574
|
if (this.loadedmetadata || !BufferHelper.getBuffered(media).length) {
|
19745
20575
|
// Resolve gaps using the main buffer, whose ranges are the intersections of the A/V sourcebuffers
|
19746
|
-
var
|
19747
|
-
|
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);
|
19748
20580
|
}
|
19749
20581
|
this.lastCurrentTime = media.currentTime;
|
19750
20582
|
};
|
@@ -20209,9 +21041,12 @@
|
|
20209
21041
|
* The configuration object provided on player instantiation.
|
20210
21042
|
*/
|
20211
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;
|
20212
21048
|
this.coreComponents = void 0;
|
20213
21049
|
this.networkControllers = void 0;
|
20214
|
-
this.started = false;
|
20215
21050
|
this._emitter = new EventEmitter();
|
20216
21051
|
this._autoLevelCapping = -1;
|
20217
21052
|
this._maxHdcpLevel = null;
|
@@ -20228,11 +21063,11 @@
|
|
20228
21063
|
this._media = null;
|
20229
21064
|
this.url = null;
|
20230
21065
|
this.triggeringException = void 0;
|
20231
|
-
enableLogs(userConfig.debug || false, 'Hls instance');
|
20232
|
-
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);
|
20233
21068
|
this.userConfig = userConfig;
|
20234
21069
|
if (config.progressive) {
|
20235
|
-
enableStreamingMode(config);
|
21070
|
+
enableStreamingMode(config, logger);
|
20236
21071
|
}
|
20237
21072
|
|
20238
21073
|
// core controllers and network loaders
|
@@ -20340,7 +21175,7 @@
|
|
20340
21175
|
try {
|
20341
21176
|
return this.emit(event, event, eventObject);
|
20342
21177
|
} catch (error) {
|
20343
|
-
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);
|
20344
21179
|
// Prevent recursion in error event handlers that throw #5497
|
20345
21180
|
if (!this.triggeringException) {
|
20346
21181
|
this.triggeringException = true;
|
@@ -20366,7 +21201,7 @@
|
|
20366
21201
|
* Dispose of the instance
|
20367
21202
|
*/;
|
20368
21203
|
_proto.destroy = function destroy() {
|
20369
|
-
logger.log('destroy');
|
21204
|
+
this.logger.log('destroy');
|
20370
21205
|
this.trigger(Events.DESTROYING, undefined);
|
20371
21206
|
this.detachMedia();
|
20372
21207
|
this.removeAllListeners();
|
@@ -20391,7 +21226,7 @@
|
|
20391
21226
|
* Attaches Hls.js to a media element
|
20392
21227
|
*/;
|
20393
21228
|
_proto.attachMedia = function attachMedia(media) {
|
20394
|
-
logger.log('attachMedia');
|
21229
|
+
this.logger.log('attachMedia');
|
20395
21230
|
this._media = media;
|
20396
21231
|
this.trigger(Events.MEDIA_ATTACHING, {
|
20397
21232
|
media: media
|
@@ -20402,7 +21237,7 @@
|
|
20402
21237
|
* Detach Hls.js from the media
|
20403
21238
|
*/;
|
20404
21239
|
_proto.detachMedia = function detachMedia() {
|
20405
|
-
logger.log('detachMedia');
|
21240
|
+
this.logger.log('detachMedia');
|
20406
21241
|
this.trigger(Events.MEDIA_DETACHING, undefined);
|
20407
21242
|
this._media = null;
|
20408
21243
|
}
|
@@ -20419,7 +21254,7 @@
|
|
20419
21254
|
});
|
20420
21255
|
this._autoLevelCapping = -1;
|
20421
21256
|
this._maxHdcpLevel = null;
|
20422
|
-
logger.log("loadSource:" + loadingSource);
|
21257
|
+
this.logger.log("loadSource:" + loadingSource);
|
20423
21258
|
if (media && loadedSource && (loadedSource !== loadingSource || this.bufferController.hasSourceTypes())) {
|
20424
21259
|
this.detachMedia();
|
20425
21260
|
this.attachMedia(media);
|
@@ -20441,8 +21276,7 @@
|
|
20441
21276
|
if (startPosition === void 0) {
|
20442
21277
|
startPosition = -1;
|
20443
21278
|
}
|
20444
|
-
logger.log("startLoad(" + startPosition + ")");
|
20445
|
-
this.started = true;
|
21279
|
+
this.logger.log("startLoad(" + startPosition + ")");
|
20446
21280
|
this.networkControllers.forEach(function (controller) {
|
20447
21281
|
controller.startLoad(startPosition);
|
20448
21282
|
});
|
@@ -20452,34 +21286,31 @@
|
|
20452
21286
|
* Stop loading of any stream data.
|
20453
21287
|
*/;
|
20454
21288
|
_proto.stopLoad = function stopLoad() {
|
20455
|
-
logger.log('stopLoad');
|
20456
|
-
this.started = false;
|
21289
|
+
this.logger.log('stopLoad');
|
20457
21290
|
this.networkControllers.forEach(function (controller) {
|
20458
21291
|
controller.stopLoad();
|
20459
21292
|
});
|
20460
21293
|
}
|
20461
21294
|
|
20462
21295
|
/**
|
20463
|
-
* Resumes stream controller segment loading
|
21296
|
+
* Resumes stream controller segment loading after `pauseBuffering` has been called.
|
20464
21297
|
*/;
|
20465
21298
|
_proto.resumeBuffering = function resumeBuffering() {
|
20466
|
-
|
20467
|
-
|
20468
|
-
|
20469
|
-
|
20470
|
-
|
20471
|
-
});
|
20472
|
-
}
|
21299
|
+
this.networkControllers.forEach(function (controller) {
|
21300
|
+
if (controller.resumeBuffering) {
|
21301
|
+
controller.resumeBuffering();
|
21302
|
+
}
|
21303
|
+
});
|
20473
21304
|
}
|
20474
21305
|
|
20475
21306
|
/**
|
20476
|
-
*
|
21307
|
+
* Prevents stream controller from loading new segments until `resumeBuffering` is called.
|
20477
21308
|
* This allows for media buffering to be paused without interupting playlist loading.
|
20478
21309
|
*/;
|
20479
21310
|
_proto.pauseBuffering = function pauseBuffering() {
|
20480
21311
|
this.networkControllers.forEach(function (controller) {
|
20481
|
-
if (
|
20482
|
-
controller.
|
21312
|
+
if (controller.pauseBuffering) {
|
21313
|
+
controller.pauseBuffering();
|
20483
21314
|
}
|
20484
21315
|
});
|
20485
21316
|
}
|
@@ -20488,7 +21319,7 @@
|
|
20488
21319
|
* Swap through possible audio codecs in the stream (for example to switch from stereo to 5.1)
|
20489
21320
|
*/;
|
20490
21321
|
_proto.swapAudioCodec = function swapAudioCodec() {
|
20491
|
-
logger.log('swapAudioCodec');
|
21322
|
+
this.logger.log('swapAudioCodec');
|
20492
21323
|
this.streamController.swapAudioCodec();
|
20493
21324
|
}
|
20494
21325
|
|
@@ -20499,7 +21330,7 @@
|
|
20499
21330
|
* Automatic recovery of media-errors by this process is configurable.
|
20500
21331
|
*/;
|
20501
21332
|
_proto.recoverMediaError = function recoverMediaError() {
|
20502
|
-
logger.log('recoverMediaError');
|
21333
|
+
this.logger.log('recoverMediaError');
|
20503
21334
|
var media = this._media;
|
20504
21335
|
this.detachMedia();
|
20505
21336
|
if (media) {
|
@@ -20554,7 +21385,7 @@
|
|
20554
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.
|
20555
21386
|
*/,
|
20556
21387
|
set: function set(newLevel) {
|
20557
|
-
logger.log("set currentLevel:" + newLevel);
|
21388
|
+
this.logger.log("set currentLevel:" + newLevel);
|
20558
21389
|
this.levelController.manualLevel = newLevel;
|
20559
21390
|
this.streamController.immediateLevelSwitch();
|
20560
21391
|
}
|
@@ -20575,7 +21406,7 @@
|
|
20575
21406
|
* @param newLevel - Pass -1 for automatic level selection
|
20576
21407
|
*/,
|
20577
21408
|
set: function set(newLevel) {
|
20578
|
-
logger.log("set nextLevel:" + newLevel);
|
21409
|
+
this.logger.log("set nextLevel:" + newLevel);
|
20579
21410
|
this.levelController.manualLevel = newLevel;
|
20580
21411
|
this.streamController.nextLevelSwitch();
|
20581
21412
|
}
|
@@ -20596,7 +21427,7 @@
|
|
20596
21427
|
* @param newLevel - Pass -1 for automatic level selection
|
20597
21428
|
*/,
|
20598
21429
|
set: function set(newLevel) {
|
20599
|
-
logger.log("set loadLevel:" + newLevel);
|
21430
|
+
this.logger.log("set loadLevel:" + newLevel);
|
20600
21431
|
this.levelController.manualLevel = newLevel;
|
20601
21432
|
}
|
20602
21433
|
|
@@ -20631,7 +21462,7 @@
|
|
20631
21462
|
* Sets "first-level", see getter.
|
20632
21463
|
*/,
|
20633
21464
|
set: function set(newLevel) {
|
20634
|
-
logger.log("set firstLevel:" + newLevel);
|
21465
|
+
this.logger.log("set firstLevel:" + newLevel);
|
20635
21466
|
this.levelController.firstLevel = newLevel;
|
20636
21467
|
}
|
20637
21468
|
|
@@ -20658,7 +21489,7 @@
|
|
20658
21489
|
* (determined from download of first segment)
|
20659
21490
|
*/,
|
20660
21491
|
set: function set(newLevel) {
|
20661
|
-
logger.log("set startLevel:" + newLevel);
|
21492
|
+
this.logger.log("set startLevel:" + newLevel);
|
20662
21493
|
// if not in automatic start level detection, ensure startLevel is greater than minAutoLevel
|
20663
21494
|
if (newLevel !== -1) {
|
20664
21495
|
newLevel = Math.max(newLevel, this.minAutoLevel);
|
@@ -20711,7 +21542,7 @@
|
|
20711
21542
|
*/
|
20712
21543
|
function set(newLevel) {
|
20713
21544
|
if (this._autoLevelCapping !== newLevel) {
|
20714
|
-
logger.log("set autoLevelCapping:" + newLevel);
|
21545
|
+
this.logger.log("set autoLevelCapping:" + newLevel);
|
20715
21546
|
this._autoLevelCapping = newLevel;
|
20716
21547
|
this.levelController.checkMaxAutoUpdated();
|
20717
21548
|
}
|
@@ -21036,7 +21867,7 @@
|
|
21036
21867
|
* Get the video-dev/hls.js package version.
|
21037
21868
|
*/
|
21038
21869
|
function get() {
|
21039
|
-
return "1.5.
|
21870
|
+
return "1.5.5-0.canary.9977";
|
21040
21871
|
}
|
21041
21872
|
}, {
|
21042
21873
|
key: "Events",
|