hls.js 1.5.14-0.canary.10431 → 1.5.14-0.canary.10432
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/dist/hls.js +316 -232
- package/dist/hls.js.d.ts +4 -2
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +316 -235
- 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 +244 -168
- 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 +244 -165
- 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 +1 -1
- package/src/controller/base-stream-controller.ts +5 -4
- package/src/demux/audio/aacdemuxer.ts +3 -3
- package/src/demux/audio/ac3-demuxer.ts +1 -1
- package/src/demux/inject-worker.ts +38 -4
- package/src/demux/transmuxer-interface.ts +98 -67
- package/src/demux/transmuxer-worker.ts +110 -76
- package/src/demux/transmuxer.ts +29 -16
- package/src/demux/tsdemuxer.ts +47 -24
- package/src/hls.ts +2 -1
- package/src/remux/mp4-remuxer.ts +24 -23
- package/src/remux/passthrough-remuxer.ts +22 -7
- package/src/version.ts +1 -0
package/dist/hls.mjs
CHANGED
@@ -420,7 +420,7 @@ function enableLogs(debugConfig, context, id) {
|
|
420
420
|
// Some browsers don't allow to use bind on console object anyway
|
421
421
|
// fallback to default if needed
|
422
422
|
try {
|
423
|
-
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.14-0.canary.
|
423
|
+
newLogger.log(`Debug logs enabled for "${context}" in hls.js version ${"1.5.14-0.canary.10432"}`);
|
424
424
|
} catch (e) {
|
425
425
|
/* log fn threw an exception. All logger methods are no-ops. */
|
426
426
|
return createLogger();
|
@@ -9838,6 +9838,10 @@ class BaseStreamController extends TaskLoop {
|
|
9838
9838
|
}
|
9839
9839
|
onHandlerDestroying() {
|
9840
9840
|
this.stopLoad();
|
9841
|
+
if (this.transmuxer) {
|
9842
|
+
this.transmuxer.destroy();
|
9843
|
+
this.transmuxer = null;
|
9844
|
+
}
|
9841
9845
|
super.onHandlerDestroying();
|
9842
9846
|
// @ts-ignore
|
9843
9847
|
this.hls = this.onMediaSeeking = this.onMediaEnded = null;
|
@@ -10961,10 +10965,8 @@ class BaseStreamController extends TaskLoop {
|
|
10961
10965
|
return `${this.playlistLabel()} ${frag.level} (frag:[${((_ref = pts ? frag.startPTS : frag.start) != null ? _ref : NaN).toFixed(3)}-${((_ref2 = pts ? frag.endPTS : frag.end) != null ? _ref2 : NaN).toFixed(3)}]`;
|
10962
10966
|
}
|
10963
10967
|
resetTransmuxer() {
|
10964
|
-
|
10965
|
-
|
10966
|
-
this.transmuxer = null;
|
10967
|
-
}
|
10968
|
+
var _this$transmuxer2;
|
10969
|
+
(_this$transmuxer2 = this.transmuxer) == null ? void 0 : _this$transmuxer2.reset();
|
10968
10970
|
}
|
10969
10971
|
recoverWorkerError(data) {
|
10970
10972
|
if (data.event === 'demuxerWorker') {
|
@@ -11027,29 +11029,66 @@ function concatUint8Arrays(chunks, dataLength) {
|
|
11027
11029
|
return result;
|
11028
11030
|
}
|
11029
11031
|
|
11032
|
+
const version = "1.5.14-0.canary.10432";
|
11033
|
+
|
11030
11034
|
// ensure the worker ends up in the bundle
|
11031
11035
|
// If the worker should not be included this gets aliased to empty.js
|
11036
|
+
const workerStore = {};
|
11032
11037
|
function hasUMDWorker() {
|
11033
11038
|
return typeof __HLS_WORKER_BUNDLE__ === 'function';
|
11034
11039
|
}
|
11035
11040
|
function injectWorker() {
|
11041
|
+
const workerContext = workerStore[version];
|
11042
|
+
if (workerContext) {
|
11043
|
+
workerContext.clientCount++;
|
11044
|
+
return workerContext;
|
11045
|
+
}
|
11036
11046
|
const blob = new self.Blob([`var exports={};var module={exports:exports};function define(f){f()};define.amd=true;(${__HLS_WORKER_BUNDLE__.toString()})(true);`], {
|
11037
11047
|
type: 'text/javascript'
|
11038
11048
|
});
|
11039
11049
|
const objectURL = self.URL.createObjectURL(blob);
|
11040
11050
|
const worker = new self.Worker(objectURL);
|
11041
|
-
|
11051
|
+
const result = {
|
11042
11052
|
worker,
|
11043
|
-
objectURL
|
11053
|
+
objectURL,
|
11054
|
+
clientCount: 1
|
11044
11055
|
};
|
11056
|
+
workerStore[version] = result;
|
11057
|
+
return result;
|
11045
11058
|
}
|
11046
11059
|
function loadWorker(path) {
|
11060
|
+
const workerContext = workerStore[path];
|
11061
|
+
if (workerContext) {
|
11062
|
+
workerContext.clientCount++;
|
11063
|
+
return workerContext;
|
11064
|
+
}
|
11047
11065
|
const scriptURL = new self.URL(path, self.location.href).href;
|
11048
11066
|
const worker = new self.Worker(scriptURL);
|
11049
|
-
|
11067
|
+
const result = {
|
11050
11068
|
worker,
|
11051
|
-
scriptURL
|
11069
|
+
scriptURL,
|
11070
|
+
clientCount: 1
|
11052
11071
|
};
|
11072
|
+
workerStore[path] = result;
|
11073
|
+
return result;
|
11074
|
+
}
|
11075
|
+
function removeWorkerFromStore(path) {
|
11076
|
+
const workerContext = workerStore[path || version];
|
11077
|
+
if (workerContext) {
|
11078
|
+
const clientCount = workerContext.clientCount--;
|
11079
|
+
if (clientCount === 1) {
|
11080
|
+
const {
|
11081
|
+
worker,
|
11082
|
+
objectURL
|
11083
|
+
} = workerContext;
|
11084
|
+
delete workerStore[path || version];
|
11085
|
+
if (objectURL) {
|
11086
|
+
// revoke the Object URL that was used to create transmuxer worker, so as not to leak it
|
11087
|
+
self.URL.revokeObjectURL(objectURL);
|
11088
|
+
}
|
11089
|
+
worker.terminate();
|
11090
|
+
}
|
11091
|
+
}
|
11053
11092
|
}
|
11054
11093
|
|
11055
11094
|
function dummyTrack(type = '', inputTimeScale = 90000) {
|
@@ -11726,7 +11765,7 @@ class AACDemuxer extends BaseAudioDemuxer {
|
|
11726
11765
|
}
|
11727
11766
|
|
11728
11767
|
// Source for probe info - https://wiki.multimedia.cx/index.php?title=ADTS
|
11729
|
-
static probe(data) {
|
11768
|
+
static probe(data, logger) {
|
11730
11769
|
if (!data) {
|
11731
11770
|
return false;
|
11732
11771
|
}
|
@@ -13352,7 +13391,8 @@ class SampleAesDecrypter {
|
|
13352
13391
|
|
13353
13392
|
const PACKET_LENGTH = 188;
|
13354
13393
|
class TSDemuxer {
|
13355
|
-
constructor(observer, config, typeSupported) {
|
13394
|
+
constructor(observer, config, typeSupported, logger) {
|
13395
|
+
this.logger = void 0;
|
13356
13396
|
this.observer = void 0;
|
13357
13397
|
this.config = void 0;
|
13358
13398
|
this.typeSupported = void 0;
|
@@ -13372,9 +13412,10 @@ class TSDemuxer {
|
|
13372
13412
|
this.observer = observer;
|
13373
13413
|
this.config = config;
|
13374
13414
|
this.typeSupported = typeSupported;
|
13415
|
+
this.logger = logger;
|
13375
13416
|
this.videoParser = null;
|
13376
13417
|
}
|
13377
|
-
static probe(data) {
|
13418
|
+
static probe(data, logger) {
|
13378
13419
|
const syncOffset = TSDemuxer.syncOffset(data);
|
13379
13420
|
if (syncOffset > 0) {
|
13380
13421
|
logger.warn(`MPEG2-TS detected but first sync word found @ offset ${syncOffset}`);
|
@@ -13536,7 +13577,7 @@ class TSDemuxer {
|
|
13536
13577
|
switch (pid) {
|
13537
13578
|
case videoPid:
|
13538
13579
|
if (stt) {
|
13539
|
-
if (videoData && (pes = parsePES(videoData))) {
|
13580
|
+
if (videoData && (pes = parsePES(videoData, this.logger))) {
|
13540
13581
|
if (this.videoParser === null) {
|
13541
13582
|
switch (videoTrack.segmentCodec) {
|
13542
13583
|
case 'avc':
|
@@ -13565,7 +13606,7 @@ class TSDemuxer {
|
|
13565
13606
|
break;
|
13566
13607
|
case audioPid:
|
13567
13608
|
if (stt) {
|
13568
|
-
if (audioData && (pes = parsePES(audioData))) {
|
13609
|
+
if (audioData && (pes = parsePES(audioData, this.logger))) {
|
13569
13610
|
switch (audioTrack.segmentCodec) {
|
13570
13611
|
case 'aac':
|
13571
13612
|
this.parseAACPES(audioTrack, pes);
|
@@ -13592,7 +13633,7 @@ class TSDemuxer {
|
|
13592
13633
|
break;
|
13593
13634
|
case id3Pid:
|
13594
13635
|
if (stt) {
|
13595
|
-
if (id3Data && (pes = parsePES(id3Data))) {
|
13636
|
+
if (id3Data && (pes = parsePES(id3Data, this.logger))) {
|
13596
13637
|
this.parseID3PES(id3Track, pes);
|
13597
13638
|
}
|
13598
13639
|
id3Data = {
|
@@ -13610,14 +13651,14 @@ class TSDemuxer {
|
|
13610
13651
|
offset += data[offset] + 1;
|
13611
13652
|
}
|
13612
13653
|
pmtId = this._pmtId = parsePAT(data, offset);
|
13613
|
-
// logger.log('PMT PID:' + this._pmtId);
|
13654
|
+
// this.logger.log('PMT PID:' + this._pmtId);
|
13614
13655
|
break;
|
13615
13656
|
case pmtId:
|
13616
13657
|
{
|
13617
13658
|
if (stt) {
|
13618
13659
|
offset += data[offset] + 1;
|
13619
13660
|
}
|
13620
|
-
const parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes, this.observer);
|
13661
|
+
const parsedPIDs = parsePMT(data, offset, this.typeSupported, isSampleAes, this.observer, this.logger);
|
13621
13662
|
|
13622
13663
|
// only update track id if track PID found while parsing PMT
|
13623
13664
|
// this is to avoid resetting the PID to -1 in case
|
@@ -13640,7 +13681,7 @@ class TSDemuxer {
|
|
13640
13681
|
id3Track.pid = id3Pid;
|
13641
13682
|
}
|
13642
13683
|
if (unknownPID !== null && !pmtParsed) {
|
13643
|
-
logger.warn(`MPEG-TS PMT found at ${start} after unknown PID '${unknownPID}'. Backtracking to sync byte @${syncOffset} to parse all TS packets.`);
|
13684
|
+
this.logger.warn(`MPEG-TS PMT found at ${start} after unknown PID '${unknownPID}'. Backtracking to sync byte @${syncOffset} to parse all TS packets.`);
|
13644
13685
|
unknownPID = null;
|
13645
13686
|
// we set it to -188, the += 188 in the for loop will reset start to 0
|
13646
13687
|
start = syncOffset - 188;
|
@@ -13660,7 +13701,7 @@ class TSDemuxer {
|
|
13660
13701
|
}
|
13661
13702
|
}
|
13662
13703
|
if (tsPacketErrors > 0) {
|
13663
|
-
emitParsingError(this.observer, new Error(`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`));
|
13704
|
+
emitParsingError(this.observer, new Error(`Found ${tsPacketErrors} TS packet/s that do not start with 0x47`), undefined, this.logger);
|
13664
13705
|
}
|
13665
13706
|
videoTrack.pesData = videoData;
|
13666
13707
|
audioTrack.pesData = audioData;
|
@@ -13710,7 +13751,7 @@ class TSDemuxer {
|
|
13710
13751
|
const id3Data = id3Track.pesData;
|
13711
13752
|
// try to parse last PES packets
|
13712
13753
|
let pes;
|
13713
|
-
if (videoData && (pes = parsePES(videoData))) {
|
13754
|
+
if (videoData && (pes = parsePES(videoData, this.logger))) {
|
13714
13755
|
if (this.videoParser === null) {
|
13715
13756
|
switch (videoTrack.segmentCodec) {
|
13716
13757
|
case 'avc':
|
@@ -13731,7 +13772,7 @@ class TSDemuxer {
|
|
13731
13772
|
// either avcData null or PES truncated, keep it for next frag parsing
|
13732
13773
|
videoTrack.pesData = videoData;
|
13733
13774
|
}
|
13734
|
-
if (audioData && (pes = parsePES(audioData))) {
|
13775
|
+
if (audioData && (pes = parsePES(audioData, this.logger))) {
|
13735
13776
|
switch (audioTrack.segmentCodec) {
|
13736
13777
|
case 'aac':
|
13737
13778
|
this.parseAACPES(audioTrack, pes);
|
@@ -13748,13 +13789,13 @@ class TSDemuxer {
|
|
13748
13789
|
audioTrack.pesData = null;
|
13749
13790
|
} else {
|
13750
13791
|
if (audioData != null && audioData.size) {
|
13751
|
-
logger.log('last AAC PES packet truncated,might overlap between fragments');
|
13792
|
+
this.logger.log('last AAC PES packet truncated,might overlap between fragments');
|
13752
13793
|
}
|
13753
13794
|
|
13754
13795
|
// either audioData null or PES truncated, keep it for next frag parsing
|
13755
13796
|
audioTrack.pesData = audioData;
|
13756
13797
|
}
|
13757
|
-
if (id3Data && (pes = parsePES(id3Data))) {
|
13798
|
+
if (id3Data && (pes = parsePES(id3Data, this.logger))) {
|
13758
13799
|
this.parseID3PES(id3Track, pes);
|
13759
13800
|
id3Track.pesData = null;
|
13760
13801
|
} else {
|
@@ -13828,7 +13869,7 @@ class TSDemuxer {
|
|
13828
13869
|
} else {
|
13829
13870
|
reason = 'No ADTS header found in AAC PES';
|
13830
13871
|
}
|
13831
|
-
emitParsingError(this.observer, new Error(reason), recoverable);
|
13872
|
+
emitParsingError(this.observer, new Error(reason), recoverable, this.logger);
|
13832
13873
|
if (!recoverable) {
|
13833
13874
|
return;
|
13834
13875
|
}
|
@@ -13843,7 +13884,7 @@ class TSDemuxer {
|
|
13843
13884
|
const frameDuration = getFrameDuration(track.samplerate);
|
13844
13885
|
pts = aacOverFlow.sample.pts + frameDuration;
|
13845
13886
|
} else {
|
13846
|
-
logger.warn('[tsdemuxer]: AAC PES unknown PTS');
|
13887
|
+
this.logger.warn('[tsdemuxer]: AAC PES unknown PTS');
|
13847
13888
|
return;
|
13848
13889
|
}
|
13849
13890
|
|
@@ -13873,7 +13914,7 @@ class TSDemuxer {
|
|
13873
13914
|
let offset = 0;
|
13874
13915
|
const pts = pes.pts;
|
13875
13916
|
if (pts === undefined) {
|
13876
|
-
logger.warn('[tsdemuxer]: MPEG PES unknown PTS');
|
13917
|
+
this.logger.warn('[tsdemuxer]: MPEG PES unknown PTS');
|
13877
13918
|
return;
|
13878
13919
|
}
|
13879
13920
|
while (offset < length) {
|
@@ -13897,7 +13938,7 @@ class TSDemuxer {
|
|
13897
13938
|
const data = pes.data;
|
13898
13939
|
const pts = pes.pts;
|
13899
13940
|
if (pts === undefined) {
|
13900
|
-
logger.warn('[tsdemuxer]: AC3 PES unknown PTS');
|
13941
|
+
this.logger.warn('[tsdemuxer]: AC3 PES unknown PTS');
|
13901
13942
|
return;
|
13902
13943
|
}
|
13903
13944
|
const length = data.length;
|
@@ -13911,7 +13952,7 @@ class TSDemuxer {
|
|
13911
13952
|
}
|
13912
13953
|
parseID3PES(id3Track, pes) {
|
13913
13954
|
if (pes.pts === undefined) {
|
13914
|
-
logger.warn('[tsdemuxer]: ID3 PES unknown PTS');
|
13955
|
+
this.logger.warn('[tsdemuxer]: ID3 PES unknown PTS');
|
13915
13956
|
return;
|
13916
13957
|
}
|
13917
13958
|
const id3Sample = _extends({}, pes, {
|
@@ -13929,7 +13970,7 @@ function parsePAT(data, offset) {
|
|
13929
13970
|
// skip the PSI header and parse the first PMT entry
|
13930
13971
|
return (data[offset + 10] & 0x1f) << 8 | data[offset + 11];
|
13931
13972
|
}
|
13932
|
-
function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
|
13973
|
+
function parsePMT(data, offset, typeSupported, isSampleAes, observer, logger) {
|
13933
13974
|
const result = {
|
13934
13975
|
audioPid: -1,
|
13935
13976
|
videoPid: -1,
|
@@ -13951,7 +13992,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
|
|
13951
13992
|
case 0xcf:
|
13952
13993
|
// SAMPLE-AES AAC
|
13953
13994
|
if (!isSampleAes) {
|
13954
|
-
logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC');
|
13995
|
+
logEncryptedSamplesFoundInUnencryptedStream('ADTS AAC', this.logger);
|
13955
13996
|
break;
|
13956
13997
|
}
|
13957
13998
|
/* falls through */
|
@@ -13973,7 +14014,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
|
|
13973
14014
|
case 0xdb:
|
13974
14015
|
// SAMPLE-AES AVC
|
13975
14016
|
if (!isSampleAes) {
|
13976
|
-
logEncryptedSamplesFoundInUnencryptedStream('H.264');
|
14017
|
+
logEncryptedSamplesFoundInUnencryptedStream('H.264', this.logger);
|
13977
14018
|
break;
|
13978
14019
|
}
|
13979
14020
|
/* falls through */
|
@@ -14001,7 +14042,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
|
|
14001
14042
|
case 0xc1:
|
14002
14043
|
// SAMPLE-AES AC3
|
14003
14044
|
if (!isSampleAes) {
|
14004
|
-
logEncryptedSamplesFoundInUnencryptedStream('AC-3');
|
14045
|
+
logEncryptedSamplesFoundInUnencryptedStream('AC-3', this.logger);
|
14005
14046
|
break;
|
14006
14047
|
}
|
14007
14048
|
/* falls through */
|
@@ -14047,7 +14088,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
|
|
14047
14088
|
case 0xc2: // SAMPLE-AES EC3
|
14048
14089
|
/* falls through */
|
14049
14090
|
case 0x87:
|
14050
|
-
emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'));
|
14091
|
+
emitParsingError(observer, new Error('Unsupported EC-3 in M2TS found'), undefined, this.logger);
|
14051
14092
|
return result;
|
14052
14093
|
case 0x24:
|
14053
14094
|
// ITU-T Rec. H.265 and ISO/IEC 23008-2 (HEVC)
|
@@ -14066,7 +14107,7 @@ function parsePMT(data, offset, typeSupported, isSampleAes, observer) {
|
|
14066
14107
|
}
|
14067
14108
|
return result;
|
14068
14109
|
}
|
14069
|
-
function emitParsingError(observer, error, levelRetry) {
|
14110
|
+
function emitParsingError(observer, error, levelRetry, logger) {
|
14070
14111
|
logger.warn(`parsing error: ${error.message}`);
|
14071
14112
|
observer.emit(Events.ERROR, Events.ERROR, {
|
14072
14113
|
type: ErrorTypes.MEDIA_ERROR,
|
@@ -14077,10 +14118,10 @@ function emitParsingError(observer, error, levelRetry) {
|
|
14077
14118
|
reason: error.message
|
14078
14119
|
});
|
14079
14120
|
}
|
14080
|
-
function logEncryptedSamplesFoundInUnencryptedStream(type) {
|
14121
|
+
function logEncryptedSamplesFoundInUnencryptedStream(type, logger) {
|
14081
14122
|
logger.log(`${type} with AES-128-CBC encryption found in unencrypted stream`);
|
14082
14123
|
}
|
14083
|
-
function parsePES(stream) {
|
14124
|
+
function parsePES(stream, logger) {
|
14084
14125
|
let i = 0;
|
14085
14126
|
let frag;
|
14086
14127
|
let pesLen;
|
@@ -14971,7 +15012,8 @@ const AC3_SAMPLES_PER_FRAME = 1536;
|
|
14971
15012
|
let chromeVersion = null;
|
14972
15013
|
let safariWebkitVersion = null;
|
14973
15014
|
class MP4Remuxer {
|
14974
|
-
constructor(observer, config, typeSupported,
|
15015
|
+
constructor(observer, config, typeSupported, logger) {
|
15016
|
+
this.logger = void 0;
|
14975
15017
|
this.observer = void 0;
|
14976
15018
|
this.config = void 0;
|
14977
15019
|
this.typeSupported = void 0;
|
@@ -14987,6 +15029,7 @@ class MP4Remuxer {
|
|
14987
15029
|
this.observer = observer;
|
14988
15030
|
this.config = config;
|
14989
15031
|
this.typeSupported = typeSupported;
|
15032
|
+
this.logger = logger;
|
14990
15033
|
this.ISGenerated = false;
|
14991
15034
|
if (chromeVersion === null) {
|
14992
15035
|
const userAgent = navigator.userAgent || '';
|
@@ -15003,16 +15046,16 @@ class MP4Remuxer {
|
|
15003
15046
|
this.config = this.videoTrackConfig = this._initPTS = this._initDTS = null;
|
15004
15047
|
}
|
15005
15048
|
resetTimeStamp(defaultTimeStamp) {
|
15006
|
-
logger.log('[mp4-remuxer]: initPTS & initDTS reset');
|
15049
|
+
this.logger.log('[mp4-remuxer]: initPTS & initDTS reset');
|
15007
15050
|
this._initPTS = this._initDTS = defaultTimeStamp;
|
15008
15051
|
}
|
15009
15052
|
resetNextTimestamp() {
|
15010
|
-
logger.log('[mp4-remuxer]: reset next timestamp');
|
15053
|
+
this.logger.log('[mp4-remuxer]: reset next timestamp');
|
15011
15054
|
this.isVideoContiguous = false;
|
15012
15055
|
this.isAudioContiguous = false;
|
15013
15056
|
}
|
15014
15057
|
resetInitSegment() {
|
15015
|
-
logger.log('[mp4-remuxer]: ISGenerated flag reset');
|
15058
|
+
this.logger.log('[mp4-remuxer]: ISGenerated flag reset');
|
15016
15059
|
this.ISGenerated = false;
|
15017
15060
|
this.videoTrackConfig = undefined;
|
15018
15061
|
}
|
@@ -15031,7 +15074,7 @@ class MP4Remuxer {
|
|
15031
15074
|
}
|
15032
15075
|
}, videoSamples[0].pts);
|
15033
15076
|
if (rolloverDetected) {
|
15034
|
-
logger.debug('PTS rollover detected');
|
15077
|
+
this.logger.debug('PTS rollover detected');
|
15035
15078
|
}
|
15036
15079
|
return startPTS;
|
15037
15080
|
}
|
@@ -15075,14 +15118,14 @@ class MP4Remuxer {
|
|
15075
15118
|
if (!isVideoContiguous && this.config.forceKeyFrameOnDiscontinuity) {
|
15076
15119
|
independent = true;
|
15077
15120
|
if (firstKeyFrameIndex > 0) {
|
15078
|
-
logger.warn(`[mp4-remuxer]: Dropped ${firstKeyFrameIndex} out of ${length} video samples due to a missing keyframe`);
|
15121
|
+
this.logger.warn(`[mp4-remuxer]: Dropped ${firstKeyFrameIndex} out of ${length} video samples due to a missing keyframe`);
|
15079
15122
|
const startPTS = this.getVideoStartPts(videoTrack.samples);
|
15080
15123
|
videoTrack.samples = videoTrack.samples.slice(firstKeyFrameIndex);
|
15081
15124
|
videoTrack.dropped += firstKeyFrameIndex;
|
15082
15125
|
videoTimeOffset += (videoTrack.samples[0].pts - startPTS) / videoTrack.inputTimeScale;
|
15083
15126
|
firstKeyFramePTS = videoTimeOffset;
|
15084
15127
|
} else if (firstKeyFrameIndex === -1) {
|
15085
|
-
logger.warn(`[mp4-remuxer]: No keyframe found out of ${length} video samples`);
|
15128
|
+
this.logger.warn(`[mp4-remuxer]: No keyframe found out of ${length} video samples`);
|
15086
15129
|
independent = false;
|
15087
15130
|
}
|
15088
15131
|
}
|
@@ -15104,7 +15147,7 @@ class MP4Remuxer {
|
|
15104
15147
|
if (enoughAudioSamples) {
|
15105
15148
|
// if initSegment was generated without audio samples, regenerate it again
|
15106
15149
|
if (!audioTrack.samplerate) {
|
15107
|
-
logger.warn('[mp4-remuxer]: regenerate InitSegment as audio detected');
|
15150
|
+
this.logger.warn('[mp4-remuxer]: regenerate InitSegment as audio detected');
|
15108
15151
|
initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
|
15109
15152
|
}
|
15110
15153
|
audio = this.remuxAudio(audioTrack, audioTimeOffset, this.isAudioContiguous, accurateTimeOffset, hasVideo || enoughVideoSamples || playlistType === PlaylistLevelType.AUDIO ? videoTimeOffset : undefined);
|
@@ -15112,7 +15155,7 @@ class MP4Remuxer {
|
|
15112
15155
|
const audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0;
|
15113
15156
|
// if initSegment was generated without video samples, regenerate it again
|
15114
15157
|
if (!videoTrack.inputTimeScale) {
|
15115
|
-
logger.warn('[mp4-remuxer]: regenerate InitSegment as video detected');
|
15158
|
+
this.logger.warn('[mp4-remuxer]: regenerate InitSegment as video detected');
|
15116
15159
|
initSegment = this.generateIS(audioTrack, videoTrack, timeOffset, accurateTimeOffset);
|
15117
15160
|
}
|
15118
15161
|
video = this.remuxVideo(videoTrack, videoTimeOffset, isVideoContiguous, audioTrackLength);
|
@@ -15318,9 +15361,9 @@ class MP4Remuxer {
|
|
15318
15361
|
const foundOverlap = delta < -1;
|
15319
15362
|
if (foundHole || foundOverlap) {
|
15320
15363
|
if (foundHole) {
|
15321
|
-
logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(delta, true)} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(3)}`);
|
15364
|
+
this.logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(delta, true)} ms (${delta}dts) hole between fragments detected at ${timeOffset.toFixed(3)}`);
|
15322
15365
|
} else {
|
15323
|
-
logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(-delta, true)} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(3)}`);
|
15366
|
+
this.logger.warn(`${(track.segmentCodec || '').toUpperCase()}: ${toMsFromMpegTsClock(-delta, true)} ms (${delta}dts) overlapping between fragments detected at ${timeOffset.toFixed(3)}`);
|
15324
15367
|
}
|
15325
15368
|
if (!foundOverlap || nextAvcDts >= inputSamples[0].pts || chromeVersion) {
|
15326
15369
|
firstDTS = nextAvcDts;
|
@@ -15349,7 +15392,7 @@ class MP4Remuxer {
|
|
15349
15392
|
}
|
15350
15393
|
}
|
15351
15394
|
}
|
15352
|
-
logger.log(`Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(firstPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
|
15395
|
+
this.logger.log(`Video: Initial PTS/DTS adjusted: ${toMsFromMpegTsClock(firstPTS, true)}/${toMsFromMpegTsClock(firstDTS, true)}, delta: ${toMsFromMpegTsClock(delta, true)} ms`);
|
15353
15396
|
}
|
15354
15397
|
}
|
15355
15398
|
}
|
@@ -15449,7 +15492,7 @@ class MP4Remuxer {
|
|
15449
15492
|
} else {
|
15450
15493
|
stretchedLastFrame = true;
|
15451
15494
|
}
|
15452
|
-
logger.log(`[mp4-remuxer]: It is approximately ${deltaToFrameEnd / 90} ms to the next segment; using duration ${mp4SampleDuration / 90} ms for the last video frame.`);
|
15495
|
+
this.logger.log(`[mp4-remuxer]: It is approximately ${deltaToFrameEnd / 90} ms to the next segment; using duration ${mp4SampleDuration / 90} ms for the last video frame.`);
|
15453
15496
|
} else {
|
15454
15497
|
mp4SampleDuration = lastFrameDuration;
|
15455
15498
|
}
|
@@ -15477,7 +15520,7 @@ class MP4Remuxer {
|
|
15477
15520
|
// Fix for "CNN special report, with CC" in test-streams (Safari browser only)
|
15478
15521
|
// Ignore DTS when frame durations are irregular. Safari MSE does not handle this leading to gaps.
|
15479
15522
|
if (maxPtsDelta - minPtsDelta < maxDtsDelta - minDtsDelta && averageSampleDuration / maxDtsDelta < 0.025 && outputSamples[0].cts === 0) {
|
15480
|
-
logger.warn('Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration.');
|
15523
|
+
this.logger.warn('Found irregular gaps in sample duration. Using PTS instead of DTS to determine MP4 sample duration.');
|
15481
15524
|
let dts = firstDTS;
|
15482
15525
|
for (let i = 0, len = outputSamples.length; i < len; i++) {
|
15483
15526
|
const nextDts = dts + outputSamples[i].duration;
|
@@ -15602,7 +15645,7 @@ class MP4Remuxer {
|
|
15602
15645
|
// When remuxing with video, if we're overlapping by more than a duration, drop this sample to stay in sync
|
15603
15646
|
if (delta <= -maxAudioFramesDrift * inputSampleDuration && alignedWithVideo) {
|
15604
15647
|
if (i === 0) {
|
15605
|
-
logger.warn(`Audio frame @ ${(pts / inputTimeScale).toFixed(3)}s overlaps nextAudioPts by ${Math.round(1000 * delta / inputTimeScale)} ms.`);
|
15648
|
+
this.logger.warn(`Audio frame @ ${(pts / inputTimeScale).toFixed(3)}s overlaps nextAudioPts by ${Math.round(1000 * delta / inputTimeScale)} ms.`);
|
15606
15649
|
this.nextAudioPts = nextAudioPts = nextPts = pts;
|
15607
15650
|
}
|
15608
15651
|
} // eslint-disable-line brace-style
|
@@ -15624,12 +15667,12 @@ class MP4Remuxer {
|
|
15624
15667
|
if (i === 0) {
|
15625
15668
|
this.nextAudioPts = nextAudioPts = nextPts;
|
15626
15669
|
}
|
15627
|
-
logger.warn(`[mp4-remuxer]: Injecting ${missing} audio frame @ ${(nextPts / inputTimeScale).toFixed(3)}s due to ${Math.round(1000 * delta / inputTimeScale)} ms gap.`);
|
15670
|
+
this.logger.warn(`[mp4-remuxer]: Injecting ${missing} audio frame @ ${(nextPts / inputTimeScale).toFixed(3)}s due to ${Math.round(1000 * delta / inputTimeScale)} ms gap.`);
|
15628
15671
|
for (let j = 0; j < missing; j++) {
|
15629
15672
|
const newStamp = Math.max(nextPts, 0);
|
15630
15673
|
let fillFrame = AAC.getSilentFrame(track.parsedCodec || track.manifestCodec || track.codec, track.channelCount);
|
15631
15674
|
if (!fillFrame) {
|
15632
|
-
logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
15675
|
+
this.logger.log('[mp4-remuxer]: Unable to get silent frame for given audio codec; duplicating last frame instead.');
|
15633
15676
|
fillFrame = sample.unit.subarray();
|
15634
15677
|
}
|
15635
15678
|
inputSamples.splice(i, 0, {
|
@@ -15828,7 +15871,8 @@ class Mp4Sample {
|
|
15828
15871
|
}
|
15829
15872
|
|
15830
15873
|
class PassThroughRemuxer {
|
15831
|
-
constructor() {
|
15874
|
+
constructor(observer, config, typeSupported, logger) {
|
15875
|
+
this.logger = void 0;
|
15832
15876
|
this.emitInitSegment = false;
|
15833
15877
|
this.audioCodec = void 0;
|
15834
15878
|
this.videoCodec = void 0;
|
@@ -15836,6 +15880,7 @@ class PassThroughRemuxer {
|
|
15836
15880
|
this.initPTS = null;
|
15837
15881
|
this.initTracks = void 0;
|
15838
15882
|
this.lastEndTime = null;
|
15883
|
+
this.logger = logger;
|
15839
15884
|
}
|
15840
15885
|
destroy() {}
|
15841
15886
|
resetTimeStamp(defaultInitPTS) {
|
@@ -15893,7 +15938,7 @@ class PassThroughRemuxer {
|
|
15893
15938
|
id: 'main'
|
15894
15939
|
};
|
15895
15940
|
} else {
|
15896
|
-
logger.warn('[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes.');
|
15941
|
+
this.logger.warn('[passthrough-remuxer.ts]: initSegment does not contain moov or trak boxes.');
|
15897
15942
|
}
|
15898
15943
|
this.initTracks = tracks;
|
15899
15944
|
}
|
@@ -15935,7 +15980,7 @@ class PassThroughRemuxer {
|
|
15935
15980
|
}
|
15936
15981
|
if (!((_initData2 = initData) != null && _initData2.length)) {
|
15937
15982
|
// We can't remux if the initSegment could not be generated
|
15938
|
-
logger.warn('[passthrough-remuxer.ts]: Failed to generate initSegment.');
|
15983
|
+
this.logger.warn('[passthrough-remuxer.ts]: Failed to generate initSegment.');
|
15939
15984
|
return result;
|
15940
15985
|
}
|
15941
15986
|
if (this.emitInitSegment) {
|
@@ -15948,7 +15993,7 @@ class PassThroughRemuxer {
|
|
15948
15993
|
if (isInvalidInitPts(initPTS, decodeTime, timeOffset, duration) || initSegment.timescale !== initPTS.timescale && accurateTimeOffset) {
|
15949
15994
|
initSegment.initPTS = decodeTime - timeOffset;
|
15950
15995
|
if (initPTS && initPTS.timescale === 1) {
|
15951
|
-
logger.warn(`Adjusting initPTS @${timeOffset} from ${initPTS.baseTime / initPTS.timescale} to ${initSegment.initPTS}`);
|
15996
|
+
this.logger.warn(`Adjusting initPTS @${timeOffset} from ${initPTS.baseTime / initPTS.timescale} to ${initSegment.initPTS}`);
|
15952
15997
|
}
|
15953
15998
|
this.initPTS = initPTS = {
|
15954
15999
|
baseTime: initSegment.initPTS,
|
@@ -15961,7 +16006,7 @@ class PassThroughRemuxer {
|
|
15961
16006
|
if (duration > 0) {
|
15962
16007
|
this.lastEndTime = endTime;
|
15963
16008
|
} else {
|
15964
|
-
logger.warn('Duration parsed from mp4 should be greater than zero');
|
16009
|
+
this.logger.warn('Duration parsed from mp4 should be greater than zero');
|
15965
16010
|
this.resetNextTimestamp();
|
15966
16011
|
}
|
15967
16012
|
const hasAudio = !!initData.audio;
|
@@ -16019,12 +16064,12 @@ function getParsedTrackCodec(track, type) {
|
|
16019
16064
|
return getCodecCompatibleName(parsedCodec, preferManagedMediaSource);
|
16020
16065
|
}
|
16021
16066
|
const result = 'mp4a.40.5';
|
16022
|
-
logger.info(`Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`);
|
16067
|
+
this.logger.info(`Parsed audio codec "${parsedCodec}" or audio object type not handled. Using "${result}"`);
|
16023
16068
|
return result;
|
16024
16069
|
}
|
16025
16070
|
// Provide defaults based on codec type
|
16026
16071
|
// This allows for some playback of some fmp4 playlists without CODECS defined in manifest
|
16027
|
-
logger.warn(`Unhandled video codec "${parsedCodec}"`);
|
16072
|
+
this.logger.warn(`Unhandled video codec "${parsedCodec}"`);
|
16028
16073
|
if (parsedCodec === 'hvc1' || parsedCodec === 'hev1') {
|
16029
16074
|
return 'hvc1.1.6.L120.90';
|
16030
16075
|
}
|
@@ -16039,8 +16084,7 @@ let now;
|
|
16039
16084
|
try {
|
16040
16085
|
now = self.performance.now.bind(self.performance);
|
16041
16086
|
} catch (err) {
|
16042
|
-
|
16043
|
-
now = optionalSelf == null ? void 0 : optionalSelf.Date.now;
|
16087
|
+
now = Date.now;
|
16044
16088
|
}
|
16045
16089
|
const muxConfig = [{
|
16046
16090
|
demux: MP4Demuxer,
|
@@ -16062,8 +16106,9 @@ const muxConfig = [{
|
|
16062
16106
|
});
|
16063
16107
|
}
|
16064
16108
|
class Transmuxer {
|
16065
|
-
constructor(observer, typeSupported, config, vendor, id) {
|
16066
|
-
this.
|
16109
|
+
constructor(observer, typeSupported, config, vendor, id, logger) {
|
16110
|
+
this.asyncResult = false;
|
16111
|
+
this.logger = void 0;
|
16067
16112
|
this.observer = void 0;
|
16068
16113
|
this.typeSupported = void 0;
|
16069
16114
|
this.config = void 0;
|
@@ -16081,6 +16126,7 @@ class Transmuxer {
|
|
16081
16126
|
this.config = config;
|
16082
16127
|
this.vendor = vendor;
|
16083
16128
|
this.id = id;
|
16129
|
+
this.logger = logger;
|
16084
16130
|
}
|
16085
16131
|
configure(transmuxConfig) {
|
16086
16132
|
this.transmuxConfig = transmuxConfig;
|
@@ -16135,6 +16181,7 @@ class Transmuxer {
|
|
16135
16181
|
}
|
16136
16182
|
uintData = new Uint8Array(decryptedData);
|
16137
16183
|
} else {
|
16184
|
+
this.asyncResult = true;
|
16138
16185
|
this.decryptionPromise = decrypter.webCryptoDecrypt(uintData, keyData.key.buffer, keyData.iv.buffer, aesMode).then(decryptedData => {
|
16139
16186
|
// Calling push here is important; if flush() is called while this is still resolving, this ensures that
|
16140
16187
|
// the decrypted data has been transmuxed
|
@@ -16149,7 +16196,7 @@ class Transmuxer {
|
|
16149
16196
|
if (resetMuxers) {
|
16150
16197
|
const error = this.configureTransmuxer(uintData);
|
16151
16198
|
if (error) {
|
16152
|
-
logger.warn(`[transmuxer] ${error.message}`);
|
16199
|
+
this.logger.warn(`[transmuxer] ${error.message}`);
|
16153
16200
|
this.observer.emit(Events.ERROR, Events.ERROR, {
|
16154
16201
|
type: ErrorTypes.MEDIA_ERROR,
|
16155
16202
|
details: ErrorDetails.FRAG_PARSING_ERROR,
|
@@ -16171,6 +16218,7 @@ class Transmuxer {
|
|
16171
16218
|
this.resetContiguity();
|
16172
16219
|
}
|
16173
16220
|
const result = this.transmux(uintData, keyData, timeOffset, accurateTimeOffset, chunkMeta);
|
16221
|
+
this.asyncResult = isPromise(result);
|
16174
16222
|
const currentState = this.currentTransmuxState;
|
16175
16223
|
currentState.contiguous = true;
|
16176
16224
|
currentState.discontinuity = false;
|
@@ -16189,6 +16237,7 @@ class Transmuxer {
|
|
16189
16237
|
decryptionPromise
|
16190
16238
|
} = this;
|
16191
16239
|
if (decryptionPromise) {
|
16240
|
+
this.asyncResult = true;
|
16192
16241
|
// Upon resolution, the decryption promise calls push() and returns its TransmuxerResult up the stack. Therefore
|
16193
16242
|
// only flushing is required for async decryption
|
16194
16243
|
return decryptionPromise.then(() => {
|
@@ -16216,10 +16265,15 @@ class Transmuxer {
|
|
16216
16265
|
if (!demuxer || !remuxer) {
|
16217
16266
|
// If probing failed, then Hls.js has been given content its not able to handle
|
16218
16267
|
stats.executeEnd = now();
|
16219
|
-
|
16268
|
+
const emptyResults = [emptyResult(chunkMeta)];
|
16269
|
+
if (this.asyncResult) {
|
16270
|
+
return Promise.resolve(emptyResults);
|
16271
|
+
}
|
16272
|
+
return emptyResults;
|
16220
16273
|
}
|
16221
16274
|
const demuxResultOrPromise = demuxer.flush(timeOffset);
|
16222
16275
|
if (isPromise(demuxResultOrPromise)) {
|
16276
|
+
this.asyncResult = true;
|
16223
16277
|
// Decrypt final SAMPLE-AES samples
|
16224
16278
|
return demuxResultOrPromise.then(demuxResult => {
|
16225
16279
|
this.flushRemux(transmuxResults, demuxResult, chunkMeta);
|
@@ -16227,6 +16281,9 @@ class Transmuxer {
|
|
16227
16281
|
});
|
16228
16282
|
}
|
16229
16283
|
this.flushRemux(transmuxResults, demuxResultOrPromise, chunkMeta);
|
16284
|
+
if (this.asyncResult) {
|
16285
|
+
return Promise.resolve(transmuxResults);
|
16286
|
+
}
|
16230
16287
|
return transmuxResults;
|
16231
16288
|
}
|
16232
16289
|
flushRemux(transmuxResults, demuxResult, chunkMeta) {
|
@@ -16240,7 +16297,7 @@ class Transmuxer {
|
|
16240
16297
|
accurateTimeOffset,
|
16241
16298
|
timeOffset
|
16242
16299
|
} = this.currentTransmuxState;
|
16243
|
-
logger.log(`[transmuxer.ts]: Flushed
|
16300
|
+
this.logger.log(`[transmuxer.ts]: Flushed ${this.id} sn: ${chunkMeta.sn}${chunkMeta.part > -1 ? ' p: ' + chunkMeta.part : ''} of ${this.id === PlaylistLevelType.MAIN ? 'level' : 'track'} ${chunkMeta.level}`);
|
16244
16301
|
const remuxResult = this.remuxer.remux(audioTrack, videoTrack, id3Track, textTrack, timeOffset, accurateTimeOffset, true, this.id);
|
16245
16302
|
transmuxResults.push({
|
16246
16303
|
remuxResult,
|
@@ -16333,7 +16390,7 @@ class Transmuxer {
|
|
16333
16390
|
let mux;
|
16334
16391
|
for (let i = 0, len = muxConfig.length; i < len; i++) {
|
16335
16392
|
var _muxConfig$i$demux;
|
16336
|
-
if ((_muxConfig$i$demux = muxConfig[i].demux) != null && _muxConfig$i$demux.probe(data)) {
|
16393
|
+
if ((_muxConfig$i$demux = muxConfig[i].demux) != null && _muxConfig$i$demux.probe(data, this.logger)) {
|
16337
16394
|
mux = muxConfig[i];
|
16338
16395
|
break;
|
16339
16396
|
}
|
@@ -16347,10 +16404,10 @@ class Transmuxer {
|
|
16347
16404
|
const Remuxer = mux.remux;
|
16348
16405
|
const Demuxer = mux.demux;
|
16349
16406
|
if (!remuxer || !(remuxer instanceof Remuxer)) {
|
16350
|
-
this.remuxer = new Remuxer(observer, config, typeSupported,
|
16407
|
+
this.remuxer = new Remuxer(observer, config, typeSupported, this.logger);
|
16351
16408
|
}
|
16352
16409
|
if (!demuxer || !(demuxer instanceof Demuxer)) {
|
16353
|
-
this.demuxer = new Demuxer(observer, config, typeSupported);
|
16410
|
+
this.demuxer = new Demuxer(observer, config, typeSupported, this.logger);
|
16354
16411
|
this.probe = Demuxer.probe;
|
16355
16412
|
}
|
16356
16413
|
}
|
@@ -16755,31 +16812,96 @@ var eventemitter3 = {exports: {}};
|
|
16755
16812
|
var eventemitter3Exports = eventemitter3.exports;
|
16756
16813
|
var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
|
16757
16814
|
|
16815
|
+
let transmuxerInstanceCount = 0;
|
16758
16816
|
class TransmuxerInterface {
|
16759
|
-
constructor(
|
16817
|
+
constructor(_hls, id, onTransmuxComplete, onFlush) {
|
16760
16818
|
this.error = null;
|
16761
16819
|
this.hls = void 0;
|
16762
16820
|
this.id = void 0;
|
16821
|
+
this.instanceNo = transmuxerInstanceCount++;
|
16763
16822
|
this.observer = void 0;
|
16764
16823
|
this.frag = null;
|
16765
16824
|
this.part = null;
|
16766
16825
|
this.useWorker = void 0;
|
16767
16826
|
this.workerContext = null;
|
16768
|
-
this.onwmsg = void 0;
|
16769
16827
|
this.transmuxer = null;
|
16770
16828
|
this.onTransmuxComplete = void 0;
|
16771
16829
|
this.onFlush = void 0;
|
16772
|
-
|
16773
|
-
|
16830
|
+
this.onWorkerMessage = event => {
|
16831
|
+
const data = event.data;
|
16832
|
+
const hls = this.hls;
|
16833
|
+
if (!hls || !(data != null && data.event) || data.instanceNo !== this.instanceNo) {
|
16834
|
+
return;
|
16835
|
+
}
|
16836
|
+
switch (data.event) {
|
16837
|
+
case 'init':
|
16838
|
+
{
|
16839
|
+
var _this$workerContext;
|
16840
|
+
const objectURL = (_this$workerContext = this.workerContext) == null ? void 0 : _this$workerContext.objectURL;
|
16841
|
+
if (objectURL) {
|
16842
|
+
// revoke the Object URL that was used to create transmuxer worker, so as not to leak it
|
16843
|
+
self.URL.revokeObjectURL(objectURL);
|
16844
|
+
}
|
16845
|
+
break;
|
16846
|
+
}
|
16847
|
+
case 'transmuxComplete':
|
16848
|
+
{
|
16849
|
+
this.handleTransmuxComplete(data.data);
|
16850
|
+
break;
|
16851
|
+
}
|
16852
|
+
case 'flush':
|
16853
|
+
{
|
16854
|
+
this.onFlush(data.data);
|
16855
|
+
break;
|
16856
|
+
}
|
16857
|
+
|
16858
|
+
// pass logs from the worker thread to the main logger
|
16859
|
+
case 'workerLog':
|
16860
|
+
{
|
16861
|
+
if (hls.logger[data.data.logType]) {
|
16862
|
+
hls.logger[data.data.logType](data.data.message);
|
16863
|
+
}
|
16864
|
+
break;
|
16865
|
+
}
|
16866
|
+
default:
|
16867
|
+
{
|
16868
|
+
data.data = data.data || {};
|
16869
|
+
data.data.frag = this.frag;
|
16870
|
+
data.data.part = this.part;
|
16871
|
+
data.data.id = this.id;
|
16872
|
+
hls.trigger(data.event, data.data);
|
16873
|
+
break;
|
16874
|
+
}
|
16875
|
+
}
|
16876
|
+
};
|
16877
|
+
this.onWorkerError = event => {
|
16878
|
+
if (!this.hls) {
|
16879
|
+
return;
|
16880
|
+
}
|
16881
|
+
const error = new Error(`${event.message} (${event.filename}:${event.lineno})`);
|
16882
|
+
this.hls.config.enableWorker = false;
|
16883
|
+
this.hls.logger.warn(`Error in "${this.id}" Web Worker, fallback to inline`);
|
16884
|
+
this.hls.trigger(Events.ERROR, {
|
16885
|
+
type: ErrorTypes.OTHER_ERROR,
|
16886
|
+
details: ErrorDetails.INTERNAL_EXCEPTION,
|
16887
|
+
fatal: false,
|
16888
|
+
event: 'demuxerWorker',
|
16889
|
+
error
|
16890
|
+
});
|
16891
|
+
};
|
16892
|
+
const config = _hls.config;
|
16893
|
+
this.hls = _hls;
|
16774
16894
|
this.id = id;
|
16775
16895
|
this.useWorker = !!config.enableWorker;
|
16776
16896
|
this.onTransmuxComplete = onTransmuxComplete;
|
16777
16897
|
this.onFlush = onFlush;
|
16778
16898
|
const forwardMessage = (ev, data) => {
|
16779
16899
|
data = data || {};
|
16780
|
-
data.frag = this.frag;
|
16781
|
-
data.id = this.id;
|
16900
|
+
data.frag = this.frag || undefined;
|
16782
16901
|
if (ev === Events.ERROR) {
|
16902
|
+
data = data;
|
16903
|
+
data.parent = this.id;
|
16904
|
+
data.part = this.part;
|
16783
16905
|
this.error = data.error;
|
16784
16906
|
}
|
16785
16907
|
this.hls.trigger(ev, data);
|
@@ -16791,6 +16913,7 @@ class TransmuxerInterface {
|
|
16791
16913
|
this.observer.on(Events.ERROR, forwardMessage);
|
16792
16914
|
const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
|
16793
16915
|
if (this.useWorker && typeof Worker !== 'undefined') {
|
16916
|
+
const logger = this.hls.logger;
|
16794
16917
|
const canCreateWorker = config.workerPath || hasUMDWorker();
|
16795
16918
|
if (canCreateWorker) {
|
16796
16919
|
try {
|
@@ -16801,61 +16924,63 @@ class TransmuxerInterface {
|
|
16801
16924
|
logger.log(`injecting Web Worker for "${id}"`);
|
16802
16925
|
this.workerContext = injectWorker();
|
16803
16926
|
}
|
16804
|
-
this.onwmsg = event => this.onWorkerMessage(event);
|
16805
16927
|
const {
|
16806
16928
|
worker
|
16807
16929
|
} = this.workerContext;
|
16808
|
-
worker.addEventListener('message', this.
|
16809
|
-
worker.
|
16810
|
-
const error = new Error(`${event.message} (${event.filename}:${event.lineno})`);
|
16811
|
-
config.enableWorker = false;
|
16812
|
-
logger.warn(`Error in "${id}" Web Worker, fallback to inline`);
|
16813
|
-
this.hls.trigger(Events.ERROR, {
|
16814
|
-
type: ErrorTypes.OTHER_ERROR,
|
16815
|
-
details: ErrorDetails.INTERNAL_EXCEPTION,
|
16816
|
-
fatal: false,
|
16817
|
-
event: 'demuxerWorker',
|
16818
|
-
error
|
16819
|
-
});
|
16820
|
-
};
|
16930
|
+
worker.addEventListener('message', this.onWorkerMessage);
|
16931
|
+
worker.addEventListener('error', this.onWorkerError);
|
16821
16932
|
worker.postMessage({
|
16933
|
+
instanceNo: this.instanceNo,
|
16822
16934
|
cmd: 'init',
|
16823
16935
|
typeSupported: m2tsTypeSupported,
|
16824
|
-
|
16825
|
-
id: id,
|
16936
|
+
id,
|
16826
16937
|
config: JSON.stringify(config)
|
16827
16938
|
});
|
16828
16939
|
} catch (err) {
|
16829
16940
|
logger.warn(`Error setting up "${id}" Web Worker, fallback to inline`, err);
|
16830
|
-
this.
|
16941
|
+
this.terminateWorker();
|
16831
16942
|
this.error = null;
|
16832
|
-
this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id);
|
16943
|
+
this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id, _hls.logger);
|
16833
16944
|
}
|
16834
16945
|
return;
|
16835
16946
|
}
|
16836
16947
|
}
|
16837
|
-
this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id);
|
16948
|
+
this.transmuxer = new Transmuxer(this.observer, m2tsTypeSupported, config, '', id, _hls.logger);
|
16838
16949
|
}
|
16839
|
-
|
16950
|
+
reset() {
|
16951
|
+
this.frag = null;
|
16952
|
+
this.part = null;
|
16953
|
+
if (this.workerContext) {
|
16954
|
+
const instanceNo = this.instanceNo;
|
16955
|
+
this.instanceNo = transmuxerInstanceCount++;
|
16956
|
+
const config = this.hls.config;
|
16957
|
+
const m2tsTypeSupported = getM2TSSupportedAudioTypes(config.preferManagedMediaSource);
|
16958
|
+
this.workerContext.worker.postMessage({
|
16959
|
+
instanceNo: this.instanceNo,
|
16960
|
+
cmd: 'reset',
|
16961
|
+
resetNo: instanceNo,
|
16962
|
+
typeSupported: m2tsTypeSupported,
|
16963
|
+
id: this.id,
|
16964
|
+
config: JSON.stringify(config)
|
16965
|
+
});
|
16966
|
+
}
|
16967
|
+
}
|
16968
|
+
terminateWorker() {
|
16840
16969
|
if (this.workerContext) {
|
16841
16970
|
const {
|
16842
|
-
worker
|
16843
|
-
objectURL
|
16971
|
+
worker
|
16844
16972
|
} = this.workerContext;
|
16845
|
-
if (objectURL) {
|
16846
|
-
// revoke the Object URL that was used to create transmuxer worker, so as not to leak it
|
16847
|
-
self.URL.revokeObjectURL(objectURL);
|
16848
|
-
}
|
16849
|
-
worker.removeEventListener('message', this.onwmsg);
|
16850
|
-
worker.onerror = null;
|
16851
|
-
worker.terminate();
|
16852
16973
|
this.workerContext = null;
|
16974
|
+
worker.removeEventListener('message', this.onWorkerMessage);
|
16975
|
+
worker.removeEventListener('error', this.onWorkerError);
|
16976
|
+
removeWorkerFromStore(this.hls.config.workerPath);
|
16853
16977
|
}
|
16854
16978
|
}
|
16855
16979
|
destroy() {
|
16856
16980
|
if (this.workerContext) {
|
16857
|
-
this.
|
16858
|
-
|
16981
|
+
this.terminateWorker();
|
16982
|
+
// @ts-ignore
|
16983
|
+
this.onWorkerMessage = this.onWorkerError = null;
|
16859
16984
|
} else {
|
16860
16985
|
const transmuxer = this.transmuxer;
|
16861
16986
|
if (transmuxer) {
|
@@ -16868,6 +16993,7 @@ class TransmuxerInterface {
|
|
16868
16993
|
observer.removeAllListeners();
|
16869
16994
|
}
|
16870
16995
|
this.frag = null;
|
16996
|
+
this.part = null;
|
16871
16997
|
// @ts-ignore
|
16872
16998
|
this.observer = null;
|
16873
16999
|
// @ts-ignore
|
@@ -16877,6 +17003,7 @@ class TransmuxerInterface {
|
|
16877
17003
|
var _frag$initSegment, _lastFrag$initSegment;
|
16878
17004
|
chunkMeta.transmuxing.start = self.performance.now();
|
16879
17005
|
const {
|
17006
|
+
instanceNo,
|
16880
17007
|
transmuxer
|
16881
17008
|
} = this;
|
16882
17009
|
const timeOffset = part ? part.start : frag.start;
|
@@ -16899,7 +17026,7 @@ class TransmuxerInterface {
|
|
16899
17026
|
const initSegmentChange = !(lastFrag && ((_frag$initSegment = frag.initSegment) == null ? void 0 : _frag$initSegment.url) === ((_lastFrag$initSegment = lastFrag.initSegment) == null ? void 0 : _lastFrag$initSegment.url));
|
16900
17027
|
const state = new TransmuxState(discontinuity, contiguous, accurateTimeOffset, trackSwitch, timeOffset, initSegmentChange);
|
16901
17028
|
if (!contiguous || discontinuity || initSegmentChange) {
|
16902
|
-
logger.log(`[transmuxer-interface, ${frag.type}]: Starting new transmux session for sn: ${chunkMeta.sn} p: ${chunkMeta.part} level: ${chunkMeta.level} id: ${chunkMeta.id}
|
17029
|
+
this.hls.logger.log(`[transmuxer-interface, ${frag.type}]: Starting new transmux session for sn: ${chunkMeta.sn} p: ${chunkMeta.part} level: ${chunkMeta.level} id: ${chunkMeta.id}
|
16903
17030
|
discontinuity: ${discontinuity}
|
16904
17031
|
trackSwitch: ${trackSwitch}
|
16905
17032
|
contiguous: ${contiguous}
|
@@ -16916,6 +17043,7 @@ class TransmuxerInterface {
|
|
16916
17043
|
if (this.workerContext) {
|
16917
17044
|
// post fragment payload as transferable objects for ArrayBuffer (no copy)
|
16918
17045
|
this.workerContext.worker.postMessage({
|
17046
|
+
instanceNo,
|
16919
17047
|
cmd: 'demux',
|
16920
17048
|
data,
|
16921
17049
|
decryptdata,
|
@@ -16925,14 +17053,12 @@ class TransmuxerInterface {
|
|
16925
17053
|
} else if (transmuxer) {
|
16926
17054
|
const transmuxResult = transmuxer.push(data, decryptdata, chunkMeta, state);
|
16927
17055
|
if (isPromise(transmuxResult)) {
|
16928
|
-
transmuxer.async = true;
|
16929
17056
|
transmuxResult.then(data => {
|
16930
17057
|
this.handleTransmuxComplete(data);
|
16931
17058
|
}).catch(error => {
|
16932
17059
|
this.transmuxerError(error, chunkMeta, 'transmuxer-interface push error');
|
16933
17060
|
});
|
16934
17061
|
} else {
|
16935
|
-
transmuxer.async = false;
|
16936
17062
|
this.handleTransmuxComplete(transmuxResult);
|
16937
17063
|
}
|
16938
17064
|
}
|
@@ -16940,20 +17066,18 @@ class TransmuxerInterface {
|
|
16940
17066
|
flush(chunkMeta) {
|
16941
17067
|
chunkMeta.transmuxing.start = self.performance.now();
|
16942
17068
|
const {
|
17069
|
+
instanceNo,
|
16943
17070
|
transmuxer
|
16944
17071
|
} = this;
|
16945
17072
|
if (this.workerContext) {
|
16946
17073
|
this.workerContext.worker.postMessage({
|
17074
|
+
instanceNo,
|
16947
17075
|
cmd: 'flush',
|
16948
17076
|
chunkMeta
|
16949
17077
|
});
|
16950
17078
|
} else if (transmuxer) {
|
16951
|
-
|
16952
|
-
|
16953
|
-
if (asyncFlush || transmuxer.async) {
|
16954
|
-
if (!isPromise(transmuxResult)) {
|
16955
|
-
transmuxResult = Promise.resolve(transmuxResult);
|
16956
|
-
}
|
17079
|
+
const transmuxResult = transmuxer.flush(chunkMeta);
|
17080
|
+
if (isPromise(transmuxResult)) {
|
16957
17081
|
transmuxResult.then(data => {
|
16958
17082
|
this.handleFlushResult(data, chunkMeta);
|
16959
17083
|
}).catch(error => {
|
@@ -16974,6 +17098,7 @@ class TransmuxerInterface {
|
|
16974
17098
|
details: ErrorDetails.FRAG_PARSING_ERROR,
|
16975
17099
|
chunkMeta,
|
16976
17100
|
frag: this.frag || undefined,
|
17101
|
+
part: this.part || undefined,
|
16977
17102
|
fatal: false,
|
16978
17103
|
error,
|
16979
17104
|
err: error,
|
@@ -16986,60 +17111,14 @@ class TransmuxerInterface {
|
|
16986
17111
|
});
|
16987
17112
|
this.onFlush(chunkMeta);
|
16988
17113
|
}
|
16989
|
-
onWorkerMessage(event) {
|
16990
|
-
const data = event.data;
|
16991
|
-
if (!(data != null && data.event)) {
|
16992
|
-
logger.warn(`worker message received with no ${data ? 'event name' : 'data'}`);
|
16993
|
-
return;
|
16994
|
-
}
|
16995
|
-
const hls = this.hls;
|
16996
|
-
if (!this.hls) {
|
16997
|
-
return;
|
16998
|
-
}
|
16999
|
-
switch (data.event) {
|
17000
|
-
case 'init':
|
17001
|
-
{
|
17002
|
-
var _this$workerContext;
|
17003
|
-
const objectURL = (_this$workerContext = this.workerContext) == null ? void 0 : _this$workerContext.objectURL;
|
17004
|
-
if (objectURL) {
|
17005
|
-
// revoke the Object URL that was used to create transmuxer worker, so as not to leak it
|
17006
|
-
self.URL.revokeObjectURL(objectURL);
|
17007
|
-
}
|
17008
|
-
break;
|
17009
|
-
}
|
17010
|
-
case 'transmuxComplete':
|
17011
|
-
{
|
17012
|
-
this.handleTransmuxComplete(data.data);
|
17013
|
-
break;
|
17014
|
-
}
|
17015
|
-
case 'flush':
|
17016
|
-
{
|
17017
|
-
this.onFlush(data.data);
|
17018
|
-
break;
|
17019
|
-
}
|
17020
|
-
|
17021
|
-
// pass logs from the worker thread to the main logger
|
17022
|
-
case 'workerLog':
|
17023
|
-
if (logger[data.data.logType]) {
|
17024
|
-
logger[data.data.logType](data.data.message);
|
17025
|
-
}
|
17026
|
-
break;
|
17027
|
-
default:
|
17028
|
-
{
|
17029
|
-
data.data = data.data || {};
|
17030
|
-
data.data.frag = this.frag;
|
17031
|
-
data.data.id = this.id;
|
17032
|
-
hls.trigger(data.event, data.data);
|
17033
|
-
break;
|
17034
|
-
}
|
17035
|
-
}
|
17036
|
-
}
|
17037
17114
|
configureTransmuxer(config) {
|
17038
17115
|
const {
|
17116
|
+
instanceNo,
|
17039
17117
|
transmuxer
|
17040
17118
|
} = this;
|
17041
17119
|
if (this.workerContext) {
|
17042
17120
|
this.workerContext.worker.postMessage({
|
17121
|
+
instanceNo,
|
17043
17122
|
cmd: 'configure',
|
17044
17123
|
config
|
17045
17124
|
});
|
@@ -29264,7 +29343,7 @@ class Hls {
|
|
29264
29343
|
* Get the video-dev/hls.js package version.
|
29265
29344
|
*/
|
29266
29345
|
static get version() {
|
29267
|
-
return
|
29346
|
+
return version;
|
29268
29347
|
}
|
29269
29348
|
|
29270
29349
|
/**
|