hls.js 1.4.6 → 1.4.8
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 +58 -50
- package/dist/hls.js.map +1 -1
- package/dist/hls.light.js +15 -9
- 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 +15 -9
- 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 +62 -56
- package/dist/hls.mjs.map +1 -1
- package/dist/hls.worker.js +1 -1
- package/package.json +1 -1
- package/src/controller/base-stream-controller.ts +10 -5
- package/src/controller/stream-controller.ts +6 -2
- package/src/controller/subtitle-stream-controller.ts +21 -20
- package/src/controller/timeline-controller.ts +23 -24
- package/src/utils/webvtt-parser.ts +8 -6
- package/src/utils/xhr-loader.ts +1 -0
package/dist/hls.mjs
CHANGED
|
@@ -402,7 +402,7 @@ function enableLogs(debugConfig, id) {
|
|
|
402
402
|
// Some browsers don't allow to use bind on console object anyway
|
|
403
403
|
// fallback to default if needed
|
|
404
404
|
try {
|
|
405
|
-
exportedLogger.log(`Debug logs enabled for "${id}" in hls.js version ${"1.4.
|
|
405
|
+
exportedLogger.log(`Debug logs enabled for "${id}" in hls.js version ${"1.4.8"}`);
|
|
406
406
|
} catch (e) {
|
|
407
407
|
exportedLogger = fakeLogger;
|
|
408
408
|
}
|
|
@@ -9320,10 +9320,8 @@ class BaseStreamController extends TaskLoop {
|
|
|
9320
9320
|
retryConfig
|
|
9321
9321
|
} = errorAction || {};
|
|
9322
9322
|
if (errorAction && action === NetworkErrorAction.RetryRequest && retryConfig) {
|
|
9323
|
-
|
|
9324
|
-
|
|
9325
|
-
this.nextLoadPosition = this.startPosition;
|
|
9326
|
-
}
|
|
9323
|
+
var _this$levelLastLoaded;
|
|
9324
|
+
this.resetStartWhenNotLoaded((_this$levelLastLoaded = this.levelLastLoaded) != null ? _this$levelLastLoaded : frag.level);
|
|
9327
9325
|
const delay = getRetryDelay(retryConfig, retryCount);
|
|
9328
9326
|
this.warn(`Fragment ${frag.sn} of ${filterType} ${frag.level} errored with ${data.details}, retrying loading ${retryCount + 1}/${retryConfig.maxNumRetry} in ${delay}ms`);
|
|
9329
9327
|
errorAction.resolved = true;
|
|
@@ -9339,6 +9337,8 @@ class BaseStreamController extends TaskLoop {
|
|
|
9339
9337
|
} else {
|
|
9340
9338
|
logger.warn(`${data.details} reached or exceeded max retry (${retryCount})`);
|
|
9341
9339
|
}
|
|
9340
|
+
} else if ((errorAction == null ? void 0 : errorAction.action) === NetworkErrorAction.SendAlternateToPenaltyBox) {
|
|
9341
|
+
this.state = State.WAITING_LEVEL;
|
|
9342
9342
|
} else {
|
|
9343
9343
|
this.state = State.ERROR;
|
|
9344
9344
|
}
|
|
@@ -9421,9 +9421,10 @@ class BaseStreamController extends TaskLoop {
|
|
|
9421
9421
|
}
|
|
9422
9422
|
}
|
|
9423
9423
|
resetWhenMissingContext(chunkMeta) {
|
|
9424
|
+
var _this$levelLastLoaded2;
|
|
9424
9425
|
this.warn(`The loading context changed while buffering fragment ${chunkMeta.sn} of level ${chunkMeta.level}. This chunk will not be buffered.`);
|
|
9425
9426
|
this.removeUnbufferedFrags();
|
|
9426
|
-
this.resetStartWhenNotLoaded(chunkMeta.level);
|
|
9427
|
+
this.resetStartWhenNotLoaded((_this$levelLastLoaded2 = this.levelLastLoaded) != null ? _this$levelLastLoaded2 : chunkMeta.level);
|
|
9427
9428
|
this.resetLoadingState();
|
|
9428
9429
|
}
|
|
9429
9430
|
removeUnbufferedFrags(start = 0) {
|
|
@@ -9495,7 +9496,10 @@ class BaseStreamController extends TaskLoop {
|
|
|
9495
9496
|
}
|
|
9496
9497
|
recoverWorkerError(data) {
|
|
9497
9498
|
if (data.event === 'demuxerWorker') {
|
|
9499
|
+
var _ref, _this$levelLastLoaded3, _this$fragCurrent3;
|
|
9500
|
+
this.fragmentTracker.removeAllFragments();
|
|
9498
9501
|
this.resetTransmuxer();
|
|
9502
|
+
this.resetStartWhenNotLoaded((_ref = (_this$levelLastLoaded3 = this.levelLastLoaded) != null ? _this$levelLastLoaded3 : (_this$fragCurrent3 = this.fragCurrent) == null ? void 0 : _this$fragCurrent3.level) != null ? _ref : 0);
|
|
9499
9503
|
this.resetLoadingState();
|
|
9500
9504
|
}
|
|
9501
9505
|
}
|
|
@@ -15695,6 +15699,7 @@ class StreamController extends BaseStreamController {
|
|
|
15695
15699
|
}
|
|
15696
15700
|
|
|
15697
15701
|
// Avoid buffering if backtracking this fragment
|
|
15702
|
+
const notFirstFragment = frag.sn !== (details == null ? void 0 : details.startSN);
|
|
15698
15703
|
if (video && remuxResult.independent !== false) {
|
|
15699
15704
|
if (details) {
|
|
15700
15705
|
const {
|
|
@@ -15720,7 +15725,7 @@ class StreamController extends BaseStreamController {
|
|
|
15720
15725
|
const bufferInfo = this.getMainFwdBufferInfo();
|
|
15721
15726
|
const targetBufferTime = (bufferInfo ? bufferInfo.end : this.getLoadPosition()) + this.config.maxBufferHole;
|
|
15722
15727
|
const startTime = video.firstKeyFramePTS ? video.firstKeyFramePTS : startPTS;
|
|
15723
|
-
if (targetBufferTime < startTime - this.config.maxBufferHole) {
|
|
15728
|
+
if (notFirstFragment && targetBufferTime < startTime - this.config.maxBufferHole) {
|
|
15724
15729
|
this.backtrack(frag);
|
|
15725
15730
|
return;
|
|
15726
15731
|
}
|
|
@@ -15734,7 +15739,7 @@ class StreamController extends BaseStreamController {
|
|
|
15734
15739
|
}
|
|
15735
15740
|
this.bufferFragmentData(video, frag, part, chunkMeta);
|
|
15736
15741
|
}
|
|
15737
|
-
} else if (remuxResult.independent === false) {
|
|
15742
|
+
} else if (notFirstFragment && remuxResult.independent === false) {
|
|
15738
15743
|
this.backtrack(frag);
|
|
15739
15744
|
return;
|
|
15740
15745
|
}
|
|
@@ -17605,16 +17610,7 @@ class SubtitleStreamController extends BaseStreamController {
|
|
|
17605
17610
|
endOffset
|
|
17606
17611
|
} = data;
|
|
17607
17612
|
if (startOffset === 0 && endOffset !== Number.POSITIVE_INFINITY) {
|
|
17608
|
-
const
|
|
17609
|
-
currentTrackId,
|
|
17610
|
-
levels
|
|
17611
|
-
} = this;
|
|
17612
|
-
if (!levels.length || !levels[currentTrackId] || !levels[currentTrackId].details) {
|
|
17613
|
-
return;
|
|
17614
|
-
}
|
|
17615
|
-
const trackDetails = levels[currentTrackId].details;
|
|
17616
|
-
const targetDuration = trackDetails.targetduration;
|
|
17617
|
-
const endOffsetSubtitles = endOffset - targetDuration;
|
|
17613
|
+
const endOffsetSubtitles = endOffset - 1;
|
|
17618
17614
|
if (endOffsetSubtitles <= 0) {
|
|
17619
17615
|
return;
|
|
17620
17616
|
}
|
|
@@ -17810,21 +17806,18 @@ class SubtitleStreamController extends BaseStreamController {
|
|
|
17810
17806
|
if (!levels.length || !track || !track.details) {
|
|
17811
17807
|
return;
|
|
17812
17808
|
}
|
|
17813
|
-
|
|
17814
|
-
// Expand range of subs loaded by one target-duration in either direction to make up for misaligned playlists
|
|
17815
|
-
const trackDetails = track.details;
|
|
17816
|
-
const targetDuration = trackDetails.targetduration;
|
|
17817
17809
|
const {
|
|
17818
17810
|
config
|
|
17819
17811
|
} = this;
|
|
17820
17812
|
const currentTime = this.getLoadPosition();
|
|
17821
|
-
const bufferedInfo = BufferHelper.bufferedInfo(this.tracksBuffered[this.currentTrackId] || [], currentTime
|
|
17813
|
+
const bufferedInfo = BufferHelper.bufferedInfo(this.tracksBuffered[this.currentTrackId] || [], currentTime, config.maxBufferHole);
|
|
17822
17814
|
const {
|
|
17823
17815
|
end: targetBufferTime,
|
|
17824
17816
|
len: bufferLen
|
|
17825
17817
|
} = bufferedInfo;
|
|
17826
17818
|
const mainBufferInfo = this.getFwdBufferInfo(this.media, PlaylistLevelType.MAIN);
|
|
17827
|
-
const
|
|
17819
|
+
const trackDetails = track.details;
|
|
17820
|
+
const maxBufLen = this.getMaxBufferLength(mainBufferInfo == null ? void 0 : mainBufferInfo.len) + trackDetails.levelTargetDuration;
|
|
17828
17821
|
if (bufferLen > maxBufLen) {
|
|
17829
17822
|
return;
|
|
17830
17823
|
}
|
|
@@ -17834,10 +17827,9 @@ class SubtitleStreamController extends BaseStreamController {
|
|
|
17834
17827
|
let foundFrag = null;
|
|
17835
17828
|
const fragPrevious = this.fragPrevious;
|
|
17836
17829
|
if (targetBufferTime < end) {
|
|
17837
|
-
const
|
|
17838
|
-
|
|
17839
|
-
|
|
17840
|
-
foundFrag = findFragmentByPTS(fragPrevious, fragments, Math.max(fragments[0].start, targetBufferTime), maxFragLookUpTolerance);
|
|
17830
|
+
const tolerance = config.maxFragLookUpTolerance;
|
|
17831
|
+
const lookupTolerance = targetBufferTime > end - tolerance ? 0 : tolerance;
|
|
17832
|
+
foundFrag = findFragmentByPTS(fragPrevious, fragments, Math.max(fragments[0].start, targetBufferTime), lookupTolerance);
|
|
17841
17833
|
if (!foundFrag && fragPrevious && fragPrevious.start < fragments[0].start) {
|
|
17842
17834
|
foundFrag = fragments[0];
|
|
17843
17835
|
}
|
|
@@ -17848,6 +17840,14 @@ class SubtitleStreamController extends BaseStreamController {
|
|
|
17848
17840
|
return;
|
|
17849
17841
|
}
|
|
17850
17842
|
foundFrag = this.mapToInitFragWhenRequired(foundFrag);
|
|
17843
|
+
if (foundFrag.sn !== 'initSegment') {
|
|
17844
|
+
// Load earlier fragment in same discontinuity to make up for misaligned playlists and cues that extend beyond end of segment
|
|
17845
|
+
const curSNIdx = foundFrag.sn - trackDetails.startSN;
|
|
17846
|
+
const prevFrag = fragments[curSNIdx - 1];
|
|
17847
|
+
if (prevFrag && prevFrag.cc === foundFrag.cc && this.fragmentTracker.getState(prevFrag) === FragmentState.NOT_LOADED) {
|
|
17848
|
+
foundFrag = prevFrag;
|
|
17849
|
+
}
|
|
17850
|
+
}
|
|
17851
17851
|
if (this.fragmentTracker.getState(foundFrag) === FragmentState.NOT_LOADED) {
|
|
17852
17852
|
// only load if fragment is not loaded
|
|
17853
17853
|
this.loadFragment(foundFrag, track, targetBufferTime);
|
|
@@ -21191,7 +21191,7 @@ function parseWebVTT(vttByteArray, initPTS, vttCCs, cc, timeOffset, callBack, er
|
|
|
21191
21191
|
// Uint8Array.prototype.reduce is not implemented in IE11
|
|
21192
21192
|
const vttLines = utf8ArrayToStr(new Uint8Array(vttByteArray)).trim().replace(LINEBREAKS, '\n').split('\n');
|
|
21193
21193
|
const cues = [];
|
|
21194
|
-
const init90kHz = toMpegTsClockFromTimescale(initPTS.baseTime, initPTS.timescale);
|
|
21194
|
+
const init90kHz = initPTS ? toMpegTsClockFromTimescale(initPTS.baseTime, initPTS.timescale) : 0;
|
|
21195
21195
|
let cueTime = '00:00.000';
|
|
21196
21196
|
let timestampMapMPEGTS = 0;
|
|
21197
21197
|
let timestampMapLOCAL = 0;
|
|
@@ -21215,6 +21215,10 @@ function parseWebVTT(vttByteArray, initPTS, vttCCs, cc, timeOffset, callBack, er
|
|
|
21215
21215
|
}
|
|
21216
21216
|
}
|
|
21217
21217
|
if (webVttMpegTsMapOffset) {
|
|
21218
|
+
if (!initPTS) {
|
|
21219
|
+
parsingError = new Error('Missing initPTS for VTT MPEGTS');
|
|
21220
|
+
return;
|
|
21221
|
+
}
|
|
21218
21222
|
// If we have MPEGTS, offset = presentation time + discontinuity offset
|
|
21219
21223
|
cueOffset = webVttMpegTsMapOffset - vttCCs.presentationOffset;
|
|
21220
21224
|
}
|
|
@@ -21710,7 +21714,7 @@ class TimelineController {
|
|
|
21710
21714
|
this.captionsTracks = {};
|
|
21711
21715
|
this.nonNativeCaptionsTracks = {};
|
|
21712
21716
|
this.textTracks = [];
|
|
21713
|
-
this.unparsedVttFrags =
|
|
21717
|
+
this.unparsedVttFrags = [];
|
|
21714
21718
|
this.initPTS = [];
|
|
21715
21719
|
if (this.cea608Parser1 && this.cea608Parser2) {
|
|
21716
21720
|
this.cea608Parser1.reset();
|
|
@@ -21854,26 +21858,9 @@ class TimelineController {
|
|
|
21854
21858
|
frag,
|
|
21855
21859
|
payload
|
|
21856
21860
|
} = data;
|
|
21857
|
-
const {
|
|
21858
|
-
initPTS,
|
|
21859
|
-
unparsedVttFrags
|
|
21860
|
-
} = this;
|
|
21861
21861
|
if (frag.type === PlaylistLevelType.SUBTITLE) {
|
|
21862
21862
|
// If fragment is subtitle type, parse as WebVTT.
|
|
21863
21863
|
if (payload.byteLength) {
|
|
21864
|
-
// We need an initial synchronisation PTS. Store fragments as long as none has arrived.
|
|
21865
|
-
if (!initPTS[frag.cc]) {
|
|
21866
|
-
unparsedVttFrags.push(data);
|
|
21867
|
-
if (initPTS.length) {
|
|
21868
|
-
// finish unsuccessfully, otherwise the subtitle-stream-controller could be blocked from loading new frags.
|
|
21869
|
-
this.hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
|
|
21870
|
-
success: false,
|
|
21871
|
-
frag,
|
|
21872
|
-
error: new Error('Missing initial subtitle PTS')
|
|
21873
|
-
});
|
|
21874
|
-
}
|
|
21875
|
-
return;
|
|
21876
|
-
}
|
|
21877
21864
|
const decryptData = frag.decryptdata;
|
|
21878
21865
|
// fragment after decryption has a stats object
|
|
21879
21866
|
const decrypted = ('stats' in data);
|
|
@@ -21892,7 +21879,7 @@ class TimelineController {
|
|
|
21892
21879
|
if (trackPlaylistMedia && trackPlaylistMedia.textCodec === IMSC1_CODEC) {
|
|
21893
21880
|
this._parseIMSC1(frag, payload);
|
|
21894
21881
|
} else {
|
|
21895
|
-
this._parseVTTs(
|
|
21882
|
+
this._parseVTTs(data);
|
|
21896
21883
|
}
|
|
21897
21884
|
}
|
|
21898
21885
|
} else {
|
|
@@ -21922,21 +21909,43 @@ class TimelineController {
|
|
|
21922
21909
|
});
|
|
21923
21910
|
});
|
|
21924
21911
|
}
|
|
21925
|
-
_parseVTTs(
|
|
21912
|
+
_parseVTTs(data) {
|
|
21926
21913
|
var _frag$initSegment;
|
|
21914
|
+
const {
|
|
21915
|
+
frag,
|
|
21916
|
+
payload
|
|
21917
|
+
} = data;
|
|
21918
|
+
// We need an initial synchronisation PTS. Store fragments as long as none has arrived
|
|
21919
|
+
const {
|
|
21920
|
+
initPTS,
|
|
21921
|
+
unparsedVttFrags
|
|
21922
|
+
} = this;
|
|
21923
|
+
const maxAvCC = initPTS.length - 1;
|
|
21924
|
+
if (!initPTS[frag.cc] && maxAvCC === -1) {
|
|
21925
|
+
unparsedVttFrags.push(data);
|
|
21926
|
+
return;
|
|
21927
|
+
}
|
|
21927
21928
|
const hls = this.hls;
|
|
21928
21929
|
// Parse the WebVTT file contents.
|
|
21929
21930
|
const payloadWebVTT = (_frag$initSegment = frag.initSegment) != null && _frag$initSegment.data ? appendUint8Array(frag.initSegment.data, new Uint8Array(payload)) : payload;
|
|
21930
|
-
parseWebVTT(payloadWebVTT, this.initPTS[frag.cc], vttCCs, frag.cc, frag.start, cues => {
|
|
21931
|
+
parseWebVTT(payloadWebVTT, this.initPTS[frag.cc], this.vttCCs, frag.cc, frag.start, cues => {
|
|
21931
21932
|
this._appendCues(cues, frag.level);
|
|
21932
21933
|
hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
|
|
21933
21934
|
success: true,
|
|
21934
21935
|
frag: frag
|
|
21935
21936
|
});
|
|
21936
21937
|
}, error => {
|
|
21937
|
-
|
|
21938
|
+
const missingInitPTS = error.message === 'Missing initPTS for VTT MPEGTS';
|
|
21939
|
+
if (missingInitPTS) {
|
|
21940
|
+
unparsedVttFrags.push(data);
|
|
21941
|
+
} else {
|
|
21942
|
+
this._fallbackToIMSC1(frag, payload);
|
|
21943
|
+
}
|
|
21938
21944
|
// Something went wrong while parsing. Trigger event with success false.
|
|
21939
21945
|
logger.log(`Failed to parse VTT cue: ${error}`);
|
|
21946
|
+
if (missingInitPTS && maxAvCC > frag.cc) {
|
|
21947
|
+
return;
|
|
21948
|
+
}
|
|
21940
21949
|
hls.trigger(Events.SUBTITLE_FRAG_PROCESSED, {
|
|
21941
21950
|
success: false,
|
|
21942
21951
|
frag: frag,
|
|
@@ -21986,10 +21995,6 @@ class TimelineController {
|
|
|
21986
21995
|
frag
|
|
21987
21996
|
} = data;
|
|
21988
21997
|
if (frag.type === PlaylistLevelType.SUBTITLE) {
|
|
21989
|
-
if (!this.initPTS[frag.cc]) {
|
|
21990
|
-
this.unparsedVttFrags.push(data);
|
|
21991
|
-
return;
|
|
21992
|
-
}
|
|
21993
21998
|
this.onFragLoaded(Events.FRAG_LOADED, data);
|
|
21994
21999
|
}
|
|
21995
22000
|
}
|
|
@@ -24122,6 +24127,7 @@ class XhrLoader {
|
|
|
24122
24127
|
const stats = this.stats;
|
|
24123
24128
|
stats.loading.first = 0;
|
|
24124
24129
|
stats.loaded = 0;
|
|
24130
|
+
stats.aborted = false;
|
|
24125
24131
|
const xhrSetup = this.xhrSetup;
|
|
24126
24132
|
if (xhrSetup) {
|
|
24127
24133
|
Promise.resolve().then(() => {
|
|
@@ -24993,7 +24999,7 @@ class Hls {
|
|
|
24993
24999
|
* Get the video-dev/hls.js package version.
|
|
24994
25000
|
*/
|
|
24995
25001
|
static get version() {
|
|
24996
|
-
return "1.4.
|
|
25002
|
+
return "1.4.8";
|
|
24997
25003
|
}
|
|
24998
25004
|
|
|
24999
25005
|
/**
|