@remotion/media-parser 4.0.289 → 4.0.291
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/containers/flac/get-channel-count.d.ts +1 -1
- package/dist/containers/iso-base-media/base-media-box.d.ts +0 -1
- package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.d.ts +4 -1
- package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.js +9 -5
- package/dist/containers/iso-base-media/find-keyframe-before-time.js +16 -11
- package/dist/containers/iso-base-media/find-track-to-seek.d.ts +14 -0
- package/dist/containers/iso-base-media/find-track-to-seek.js +39 -0
- package/dist/containers/iso-base-media/get-children.js +2 -2
- package/dist/containers/iso-base-media/get-keyframes.js +6 -1
- package/dist/containers/iso-base-media/get-mfra-seeking-box.d.ts +3 -1
- package/dist/containers/iso-base-media/get-mfra-seeking-box.js +5 -1
- package/dist/containers/iso-base-media/get-moov-atom.js +6 -3
- package/dist/containers/iso-base-media/get-sample-position-bounds.js +3 -1
- package/dist/containers/iso-base-media/get-sample-positions-from-track.js +1 -1
- package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.d.ts +14 -0
- package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +89 -0
- package/dist/containers/iso-base-media/get-seeking-byte.d.ts +3 -3
- package/dist/containers/iso-base-media/get-seeking-byte.js +32 -96
- package/dist/containers/iso-base-media/get-video-codec-from-iso-track.d.ts +1 -1
- package/dist/containers/iso-base-media/mdat/calculate-jump-marks.d.ts +6 -0
- package/dist/containers/iso-base-media/mdat/calculate-jump-marks.js +131 -0
- package/dist/containers/iso-base-media/mdat/mdat.d.ts +2 -2
- package/dist/containers/iso-base-media/mdat/mdat.js +18 -2
- package/dist/containers/iso-base-media/mfra/find-best-segment-from-tfra.d.ts +3 -3
- package/dist/containers/iso-base-media/mfra/find-best-segment-from-tfra.js +2 -2
- package/dist/containers/iso-base-media/mfra/get-mfra-atom.d.ts +5 -1
- package/dist/containers/iso-base-media/mfra/get-mfra-atom.js +3 -1
- package/dist/containers/iso-base-media/mfra/get-mfro-atom.d.ts +5 -1
- package/dist/containers/iso-base-media/mfra/get-mfro-atom.js +3 -1
- package/dist/containers/iso-base-media/parse-boxes.js +5 -2
- package/dist/containers/iso-base-media/process-box.d.ts +16 -5
- package/dist/containers/iso-base-media/process-box.js +206 -118
- package/dist/containers/iso-base-media/sample-positions.d.ts +25 -0
- package/dist/containers/iso-base-media/sample-positions.js +37 -0
- package/dist/containers/iso-base-media/seeking-hints.d.ts +1 -1
- package/dist/containers/iso-base-media/stsd/samples.js +1 -0
- package/dist/containers/iso-base-media/stsd/stsc.d.ts +1 -6
- package/dist/containers/iso-base-media/stsd/stsc.js +2 -5
- package/dist/containers/iso-base-media/stsd/stss.d.ts +1 -1
- package/dist/containers/iso-base-media/stsd/stss.js +2 -2
- package/dist/containers/iso-base-media/turn-sample-positions-into-array.d.ts +19 -0
- package/dist/containers/iso-base-media/turn-sample-positions-into-array.js +73 -0
- package/dist/containers/m3u/after-manifest-fetch.d.ts +5 -1
- package/dist/containers/m3u/after-manifest-fetch.js +3 -1
- package/dist/containers/m3u/first-sample-in-m3u-chunk.d.ts +13 -0
- package/dist/containers/m3u/first-sample-in-m3u-chunk.js +31 -0
- package/dist/containers/m3u/get-seeking-byte.d.ts +13 -0
- package/dist/containers/m3u/get-seeking-byte.js +32 -0
- package/dist/containers/m3u/get-streams.d.ts +1 -0
- package/dist/containers/m3u/get-streams.js +1 -0
- package/dist/containers/m3u/iterate-over-segment-files.d.ts +5 -3
- package/dist/containers/m3u/iterate-over-segment-files.js +11 -1
- package/dist/containers/m3u/parse-m3u-media-directive.js +1 -0
- package/dist/containers/m3u/parse-m3u.js +8 -0
- package/dist/containers/m3u/process-m3u-chunk.d.ts +12 -0
- package/dist/containers/m3u/process-m3u-chunk.js +274 -0
- package/dist/containers/m3u/run-over-m3u.js +7 -80
- package/dist/containers/m3u/sample-sorter.d.ts +1 -0
- package/dist/containers/m3u/sample-sorter.js +4 -1
- package/dist/containers/m3u/seek/get-chunk-to-seek-to.d.ts +5 -0
- package/dist/containers/m3u/seek/get-chunk-to-seek-to.js +14 -0
- package/dist/containers/m3u/seeking-hints.d.ts +2 -0
- package/dist/containers/m3u/seeking-hints.js +9 -0
- package/dist/containers/m3u/select-stream.d.ts +2 -1
- package/dist/containers/m3u/select-stream.js +7 -2
- package/dist/containers/m3u/types.d.ts +1 -0
- package/dist/containers/mp3/get-duration.d.ts +5 -0
- package/dist/containers/riff/seek/fetch-idx1.d.ts +3 -1
- package/dist/containers/riff/seek/fetch-idx1.js +3 -1
- package/dist/containers/transport-stream/handle-aac-packet.d.ts +2 -2
- package/dist/containers/transport-stream/handle-avc-packet.d.ts +2 -2
- package/dist/containers/transport-stream/process-audio.d.ts +2 -2
- package/dist/containers/transport-stream/process-stream-buffers.d.ts +3 -3
- package/dist/containers/transport-stream/process-video.d.ts +2 -2
- package/dist/containers/wav/get-duration-from-wav.d.ts +0 -1
- package/dist/containers/webm/get-sample-from-block.d.ts +12 -2
- package/dist/containers/webm/get-sample-from-block.js +40 -9
- package/dist/containers/webm/parse-ebml.js +28 -10
- package/dist/containers/webm/seek/fetch-web-cues.d.ts +3 -1
- package/dist/containers/webm/seek/fetch-web-cues.js +3 -1
- package/dist/containers/webm/state-for-processing.d.ts +2 -2
- package/dist/controller/media-parser-controller.d.ts +1 -1
- package/dist/controller/media-parser-controller.js +6 -2
- package/dist/controller/seek-signal.d.ts +1 -5
- package/dist/download-and-parse-media.js +1 -1
- package/dist/esm/index.mjs +1400 -611
- package/dist/esm/node.mjs +23 -3
- package/dist/esm/server-worker.mjs +8 -1
- package/dist/esm/universal.mjs +168 -15
- package/dist/esm/web.mjs +145 -13
- package/dist/esm/worker-server-entry.mjs +1467 -635
- package/dist/esm/worker-web-entry.mjs +1439 -634
- package/dist/esm/worker.mjs +8 -1
- package/dist/get-audio-codec.js +3 -0
- package/dist/get-duration.js +2 -1
- package/dist/get-fps.js +2 -1
- package/dist/get-sample-positions-from-mp4.js +10 -5
- package/dist/get-sample-positions.js +4 -4
- package/dist/get-seeking-byte.d.ts +5 -3
- package/dist/get-seeking-byte.js +19 -10
- package/dist/get-seeking-hints.d.ts +3 -3
- package/dist/get-seeking-hints.js +18 -13
- package/dist/get-tracks.d.ts +9 -1
- package/dist/get-tracks.js +13 -6
- package/dist/index.d.ts +21 -5
- package/dist/init-video.js +3 -2
- package/dist/internal-parse-media.js +13 -4
- package/dist/iterator/buffer-iterator.js +5 -3
- package/dist/metadata/metadata-from-iso.js +2 -1
- package/dist/options.d.ts +6 -1
- package/dist/parse-loop.js +22 -6
- package/dist/parse-media-on-worker-entry.js +1 -0
- package/dist/parse-media.js +1 -1
- package/dist/parse-result.d.ts +2 -2
- package/dist/perform-seek.d.ts +3 -1
- package/dist/perform-seek.js +3 -1
- package/dist/readers/fetch/get-body-and-reader.js +17 -2
- package/dist/readers/from-fetch.d.ts +17 -1
- package/dist/readers/from-fetch.js +68 -13
- package/dist/readers/from-node.js +24 -2
- package/dist/readers/from-web-file.js +3 -0
- package/dist/readers/reader.d.ts +19 -2
- package/dist/readers/universal.js +9 -0
- package/dist/readers/web.js +6 -0
- package/dist/register-track.d.ts +3 -3
- package/dist/seek-backwards.d.ts +3 -1
- package/dist/seek-backwards.js +4 -1
- package/dist/seek-forwards.d.ts +3 -1
- package/dist/seek-forwards.js +3 -1
- package/dist/seeking-hints.d.ts +4 -1
- package/dist/set-seeking-hints.js +4 -0
- package/dist/skip.d.ts +5 -0
- package/dist/skip.js +6 -1
- package/dist/state/can-skip-tracks.d.ts +1 -0
- package/dist/state/can-skip-tracks.js +10 -6
- package/dist/state/iso-base-media/cached-sample-positions.d.ts +15 -1
- package/dist/state/iso-base-media/cached-sample-positions.js +9 -4
- package/dist/state/iso-base-media/iso-state.d.ts +5 -1
- package/dist/state/iso-base-media/iso-state.js +2 -1
- package/dist/state/iso-base-media/lazy-mfra-load.d.ts +3 -1
- package/dist/state/iso-base-media/lazy-mfra-load.js +2 -1
- package/dist/state/keyframes.js +1 -0
- package/dist/state/m3u-state.d.ts +15 -4
- package/dist/state/m3u-state.js +20 -0
- package/dist/state/matroska/lazy-cues-fetch.d.ts +3 -1
- package/dist/state/matroska/lazy-cues-fetch.js +2 -1
- package/dist/state/matroska/webm.d.ts +3 -1
- package/dist/state/matroska/webm.js +2 -1
- package/dist/state/mp3.d.ts +16 -5
- package/dist/state/mp3.js +7 -5
- package/dist/state/parser-state.d.ts +31 -15
- package/dist/state/parser-state.js +19 -5
- package/dist/state/riff/lazy-idx1-fetch.d.ts +5 -3
- package/dist/state/riff/lazy-idx1-fetch.js +2 -1
- package/dist/state/riff.d.ts +5 -3
- package/dist/state/riff.js +2 -1
- package/dist/state/sample-callbacks.d.ts +3 -2
- package/dist/state/sample-callbacks.js +3 -3
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/work-on-seek-request.d.ts +6 -3
- package/dist/work-on-seek-request.js +13 -13
- package/dist/worker/forward-controller-to-worker.js +1 -1
- package/dist/worker/serialize-error.js +26 -3
- package/dist/worker/worker-types.d.ts +7 -1
- package/dist/worker-server.js +2 -2
- package/package.json +3 -3
package/dist/esm/index.mjs
CHANGED
|
@@ -1328,7 +1328,7 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
1328
1328
|
const six = getUint8();
|
|
1329
1329
|
const seven = getUint8();
|
|
1330
1330
|
const eight = getUint8();
|
|
1331
|
-
return eight << 56 | seven << 48 | six << 40 | five << 32 | four << 24 | three << 16 | two << 8 | one;
|
|
1331
|
+
return (eight << 56 | seven << 48 | six << 40 | five << 32 | four << 24 | three << 16 | two << 8 | one) >>> 0;
|
|
1332
1332
|
}
|
|
1333
1333
|
function byteArrayToBigInt(byteArray) {
|
|
1334
1334
|
let result = BigInt(0);
|
|
@@ -1350,7 +1350,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
1350
1350
|
return Number(bigInt);
|
|
1351
1351
|
};
|
|
1352
1352
|
const getFourByteNumber = () => {
|
|
1353
|
-
|
|
1353
|
+
const unsigned = getUint8() << 24 | getUint8() << 16 | getUint8() << 8 | getUint8();
|
|
1354
|
+
return unsigned >>> 0;
|
|
1354
1355
|
};
|
|
1355
1356
|
const getPaddedFourByteNumber = () => {
|
|
1356
1357
|
let lastInt = 128;
|
|
@@ -1903,6 +1904,16 @@ var registerVideoTrackWhenProfileIsAvailable = ({
|
|
|
1903
1904
|
});
|
|
1904
1905
|
};
|
|
1905
1906
|
|
|
1907
|
+
// src/skip.ts
|
|
1908
|
+
var makeSkip = (skipTo) => ({
|
|
1909
|
+
action: "skip",
|
|
1910
|
+
skipTo
|
|
1911
|
+
});
|
|
1912
|
+
var makeFetchMoreData = (bytesNeeded) => ({
|
|
1913
|
+
action: "fetch-more-data",
|
|
1914
|
+
bytesNeeded
|
|
1915
|
+
});
|
|
1916
|
+
|
|
1906
1917
|
// src/containers/iso-base-media/esds/decoder-specific-config.ts
|
|
1907
1918
|
var parseDecoderSpecificConfig = (iterator) => {
|
|
1908
1919
|
const layerTag = iterator.getUint8();
|
|
@@ -2358,7 +2369,7 @@ var getFpsFromIsoMaseMedia = (state) => {
|
|
|
2358
2369
|
const moovBox = getMoovBoxFromState({
|
|
2359
2370
|
structureState: state.structure,
|
|
2360
2371
|
isoState: state.iso,
|
|
2361
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
2372
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
2362
2373
|
mayUsePrecomputed: true
|
|
2363
2374
|
});
|
|
2364
2375
|
if (!moovBox) {
|
|
@@ -3298,7 +3309,7 @@ var isoBaseMediaHasTracks = (state, mayUsePrecomputed) => {
|
|
|
3298
3309
|
return Boolean(getMoovBoxFromState({
|
|
3299
3310
|
structureState: state.structure,
|
|
3300
3311
|
isoState: state.iso,
|
|
3301
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
3312
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
3302
3313
|
mayUsePrecomputed
|
|
3303
3314
|
}));
|
|
3304
3315
|
};
|
|
@@ -3383,11 +3394,16 @@ var getTracksFromMoovBox = (moovBox) => {
|
|
|
3383
3394
|
otherTracks
|
|
3384
3395
|
};
|
|
3385
3396
|
};
|
|
3386
|
-
var getTracksFromIsoBaseMedia = (
|
|
3397
|
+
var getTracksFromIsoBaseMedia = ({
|
|
3398
|
+
mayUsePrecomputed,
|
|
3399
|
+
structure,
|
|
3400
|
+
isoState,
|
|
3401
|
+
m3uPlaylistContext
|
|
3402
|
+
}) => {
|
|
3387
3403
|
const moovBox = getMoovBoxFromState({
|
|
3388
|
-
structureState:
|
|
3389
|
-
isoState
|
|
3390
|
-
mp4HeaderSegment:
|
|
3404
|
+
structureState: structure,
|
|
3405
|
+
isoState,
|
|
3406
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
3391
3407
|
mayUsePrecomputed
|
|
3392
3408
|
});
|
|
3393
3409
|
if (!moovBox) {
|
|
@@ -3416,7 +3432,12 @@ var getTracks = (state, mayUsePrecomputed) => {
|
|
|
3416
3432
|
return getCategorizedTracksFromMatroska(state);
|
|
3417
3433
|
}
|
|
3418
3434
|
if (structure.type === "iso-base-media") {
|
|
3419
|
-
return getTracksFromIsoBaseMedia(
|
|
3435
|
+
return getTracksFromIsoBaseMedia({
|
|
3436
|
+
isoState: state.iso,
|
|
3437
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
3438
|
+
structure: state.structure,
|
|
3439
|
+
mayUsePrecomputed
|
|
3440
|
+
});
|
|
3420
3441
|
}
|
|
3421
3442
|
if (structure.type === "riff") {
|
|
3422
3443
|
return getTracksFromAvi(structure, state);
|
|
@@ -3622,6 +3643,9 @@ var getAudioCodecFromAudioCodecInfo = (codec) => {
|
|
|
3622
3643
|
if (codec.format === "ac-3") {
|
|
3623
3644
|
return "ac3";
|
|
3624
3645
|
}
|
|
3646
|
+
if (codec.format === "Opus") {
|
|
3647
|
+
return "opus";
|
|
3648
|
+
}
|
|
3625
3649
|
if (codec.format === "mp4a") {
|
|
3626
3650
|
if (codec.primarySpecificator === 64) {
|
|
3627
3651
|
return "aac";
|
|
@@ -4643,7 +4667,7 @@ var parseStsc = ({
|
|
|
4643
4667
|
}
|
|
4644
4668
|
const flags = iterator.getSlice(3);
|
|
4645
4669
|
const entryCount = iterator.getUint32();
|
|
4646
|
-
const entries =
|
|
4670
|
+
const entries = new Map;
|
|
4647
4671
|
for (let i = 0;i < entryCount; i++) {
|
|
4648
4672
|
const firstChunk = iterator.getUint32();
|
|
4649
4673
|
const samplesPerChunk = iterator.getUint32();
|
|
@@ -4651,10 +4675,7 @@ var parseStsc = ({
|
|
|
4651
4675
|
if (sampleDescriptionIndex !== 1) {
|
|
4652
4676
|
throw new Error(`Expected sampleDescriptionIndex to be 1, but got ${sampleDescriptionIndex}`);
|
|
4653
4677
|
}
|
|
4654
|
-
entries.
|
|
4655
|
-
firstChunk,
|
|
4656
|
-
samplesPerChunk
|
|
4657
|
-
});
|
|
4678
|
+
entries.set(firstChunk, samplesPerChunk);
|
|
4658
4679
|
}
|
|
4659
4680
|
return {
|
|
4660
4681
|
type: "stsc-box",
|
|
@@ -4712,9 +4733,9 @@ var parseStss = ({
|
|
|
4712
4733
|
}
|
|
4713
4734
|
const flags = iterator.getSlice(3);
|
|
4714
4735
|
const sampleCount = iterator.getUint32();
|
|
4715
|
-
const sampleNumber =
|
|
4736
|
+
const sampleNumber = new Set;
|
|
4716
4737
|
for (let i = 0;i < sampleCount; i++) {
|
|
4717
|
-
sampleNumber.
|
|
4738
|
+
sampleNumber.add(iterator.getUint32());
|
|
4718
4739
|
}
|
|
4719
4740
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - offset);
|
|
4720
4741
|
if (bytesRemainingInBox > 0) {
|
|
@@ -5030,8 +5051,11 @@ var processBox = async ({
|
|
|
5030
5051
|
const boxSizeRaw = iterator.getFourByteNumber();
|
|
5031
5052
|
if (boxSizeRaw === 0) {
|
|
5032
5053
|
return {
|
|
5033
|
-
type: "
|
|
5034
|
-
|
|
5054
|
+
type: "box",
|
|
5055
|
+
box: {
|
|
5056
|
+
type: "void-box",
|
|
5057
|
+
boxSize: 0
|
|
5058
|
+
}
|
|
5035
5059
|
};
|
|
5036
5060
|
}
|
|
5037
5061
|
if (boxSizeRaw === 1 && iterator.bytesRemaining() < 12 || iterator.bytesRemaining() < 4) {
|
|
@@ -5045,120 +5069,177 @@ var processBox = async ({
|
|
|
5045
5069
|
const headerLength = iterator.counter.getOffset() - startOff;
|
|
5046
5070
|
if (boxType === "mdat") {
|
|
5047
5071
|
if (!onlyIfMdatAtomExpected) {
|
|
5048
|
-
return
|
|
5072
|
+
return { type: "nothing" };
|
|
5049
5073
|
}
|
|
5050
5074
|
const { mediaSectionState } = onlyIfMdatAtomExpected;
|
|
5051
5075
|
mediaSectionState.addMediaSection({
|
|
5052
5076
|
size: boxSize - headerLength,
|
|
5053
5077
|
start: iterator.counter.getOffset()
|
|
5054
5078
|
});
|
|
5055
|
-
return
|
|
5079
|
+
return { type: "nothing" };
|
|
5056
5080
|
}
|
|
5057
5081
|
if (bytesRemaining < boxSize) {
|
|
5058
5082
|
returnToCheckpoint();
|
|
5059
|
-
return
|
|
5083
|
+
return {
|
|
5084
|
+
type: "fetch-more-data",
|
|
5085
|
+
bytesNeeded: makeFetchMoreData(boxSize - bytesRemaining)
|
|
5086
|
+
};
|
|
5060
5087
|
}
|
|
5061
5088
|
if (boxType === "ftyp") {
|
|
5062
|
-
return
|
|
5089
|
+
return {
|
|
5090
|
+
type: "box",
|
|
5091
|
+
box: await parseFtyp({ iterator, size: boxSize, offset: fileOffset })
|
|
5092
|
+
};
|
|
5063
5093
|
}
|
|
5064
5094
|
if (boxType === "colr") {
|
|
5065
|
-
return
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5095
|
+
return {
|
|
5096
|
+
type: "box",
|
|
5097
|
+
box: await parseColorParameterBox({
|
|
5098
|
+
iterator,
|
|
5099
|
+
size: boxSize
|
|
5100
|
+
})
|
|
5101
|
+
};
|
|
5069
5102
|
}
|
|
5070
5103
|
if (boxType === "mvhd") {
|
|
5071
|
-
return
|
|
5104
|
+
return {
|
|
5105
|
+
type: "box",
|
|
5106
|
+
box: await parseMvhd({ iterator, offset: fileOffset, size: boxSize })
|
|
5107
|
+
};
|
|
5072
5108
|
}
|
|
5073
5109
|
if (boxType === "tkhd") {
|
|
5074
|
-
return
|
|
5110
|
+
return {
|
|
5111
|
+
type: "box",
|
|
5112
|
+
box: await parseTkhd({ iterator, offset: fileOffset, size: boxSize })
|
|
5113
|
+
};
|
|
5075
5114
|
}
|
|
5076
5115
|
if (boxType === "trun") {
|
|
5077
|
-
return
|
|
5116
|
+
return {
|
|
5117
|
+
type: "box",
|
|
5118
|
+
box: await parseTrun({ iterator, offset: fileOffset, size: boxSize })
|
|
5119
|
+
};
|
|
5078
5120
|
}
|
|
5079
5121
|
if (boxType === "tfdt") {
|
|
5080
|
-
return
|
|
5122
|
+
return {
|
|
5123
|
+
type: "box",
|
|
5124
|
+
box: await parseTfdt({ iterator, size: boxSize, offset: fileOffset })
|
|
5125
|
+
};
|
|
5081
5126
|
}
|
|
5082
5127
|
if (boxType === "stsd") {
|
|
5083
|
-
return
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5128
|
+
return {
|
|
5129
|
+
type: "box",
|
|
5130
|
+
box: await parseStsd({
|
|
5131
|
+
offset: fileOffset,
|
|
5132
|
+
size: boxSize,
|
|
5133
|
+
iterator,
|
|
5134
|
+
logLevel,
|
|
5135
|
+
contentLength
|
|
5136
|
+
})
|
|
5137
|
+
};
|
|
5090
5138
|
}
|
|
5091
5139
|
if (boxType === "stsz") {
|
|
5092
|
-
return
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5140
|
+
return {
|
|
5141
|
+
type: "box",
|
|
5142
|
+
box: await parseStsz({
|
|
5143
|
+
iterator,
|
|
5144
|
+
offset: fileOffset,
|
|
5145
|
+
size: boxSize
|
|
5146
|
+
})
|
|
5147
|
+
};
|
|
5097
5148
|
}
|
|
5098
5149
|
if (boxType === "stco" || boxType === "co64") {
|
|
5099
|
-
return
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5150
|
+
return {
|
|
5151
|
+
type: "box",
|
|
5152
|
+
box: await parseStco({
|
|
5153
|
+
iterator,
|
|
5154
|
+
offset: fileOffset,
|
|
5155
|
+
size: boxSize,
|
|
5156
|
+
mode64Bit: boxType === "co64"
|
|
5157
|
+
})
|
|
5158
|
+
};
|
|
5105
5159
|
}
|
|
5106
5160
|
if (boxType === "pasp") {
|
|
5107
|
-
return
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5161
|
+
return {
|
|
5162
|
+
type: "box",
|
|
5163
|
+
box: await parsePasp({
|
|
5164
|
+
iterator,
|
|
5165
|
+
offset: fileOffset,
|
|
5166
|
+
size: boxSize
|
|
5167
|
+
})
|
|
5168
|
+
};
|
|
5112
5169
|
}
|
|
5113
5170
|
if (boxType === "stss") {
|
|
5114
|
-
return
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5171
|
+
return {
|
|
5172
|
+
type: "box",
|
|
5173
|
+
box: await parseStss({
|
|
5174
|
+
iterator,
|
|
5175
|
+
offset: fileOffset,
|
|
5176
|
+
boxSize
|
|
5177
|
+
})
|
|
5178
|
+
};
|
|
5119
5179
|
}
|
|
5120
5180
|
if (boxType === "ctts") {
|
|
5121
|
-
return
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5181
|
+
return {
|
|
5182
|
+
type: "box",
|
|
5183
|
+
box: await parseCtts({
|
|
5184
|
+
iterator,
|
|
5185
|
+
offset: fileOffset,
|
|
5186
|
+
size: boxSize
|
|
5187
|
+
})
|
|
5188
|
+
};
|
|
5126
5189
|
}
|
|
5127
5190
|
if (boxType === "stsc") {
|
|
5128
|
-
return
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5191
|
+
return {
|
|
5192
|
+
type: "box",
|
|
5193
|
+
box: await parseStsc({
|
|
5194
|
+
iterator,
|
|
5195
|
+
offset: fileOffset,
|
|
5196
|
+
size: boxSize
|
|
5197
|
+
})
|
|
5198
|
+
};
|
|
5133
5199
|
}
|
|
5134
5200
|
if (boxType === "mebx") {
|
|
5135
|
-
return
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5201
|
+
return {
|
|
5202
|
+
type: "box",
|
|
5203
|
+
box: await parseMebx({
|
|
5204
|
+
offset: fileOffset,
|
|
5205
|
+
size: boxSize,
|
|
5206
|
+
iterator,
|
|
5207
|
+
logLevel,
|
|
5208
|
+
contentLength
|
|
5209
|
+
})
|
|
5210
|
+
};
|
|
5142
5211
|
}
|
|
5143
5212
|
if (boxType === "hdlr") {
|
|
5144
|
-
return
|
|
5213
|
+
return {
|
|
5214
|
+
type: "box",
|
|
5215
|
+
box: await parseHdlr({ iterator, size: boxSize, offset: fileOffset })
|
|
5216
|
+
};
|
|
5145
5217
|
}
|
|
5146
5218
|
if (boxType === "keys") {
|
|
5147
|
-
return
|
|
5219
|
+
return {
|
|
5220
|
+
type: "box",
|
|
5221
|
+
box: await parseKeys({ iterator, size: boxSize, offset: fileOffset })
|
|
5222
|
+
};
|
|
5148
5223
|
}
|
|
5149
5224
|
if (boxType === "ilst") {
|
|
5150
|
-
return
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5225
|
+
return {
|
|
5226
|
+
type: "box",
|
|
5227
|
+
box: await parseIlstBox({
|
|
5228
|
+
iterator,
|
|
5229
|
+
offset: fileOffset,
|
|
5230
|
+
size: boxSize
|
|
5231
|
+
})
|
|
5232
|
+
};
|
|
5155
5233
|
}
|
|
5156
5234
|
if (boxType === "tfra") {
|
|
5157
|
-
return
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5235
|
+
return {
|
|
5236
|
+
type: "box",
|
|
5237
|
+
box: await parseTfraBox({
|
|
5238
|
+
iterator,
|
|
5239
|
+
offset: fileOffset,
|
|
5240
|
+
size: boxSize
|
|
5241
|
+
})
|
|
5242
|
+
};
|
|
5162
5243
|
}
|
|
5163
5244
|
if (boxType === "moov") {
|
|
5164
5245
|
if (!onlyIfMoovAtomExpected) {
|
|
@@ -5167,12 +5248,12 @@ var processBox = async ({
|
|
|
5167
5248
|
const { tracks: tracks2, isoState } = onlyIfMoovAtomExpected;
|
|
5168
5249
|
if (tracks2.hasAllTracks()) {
|
|
5169
5250
|
iterator.discard(boxSize - 8);
|
|
5170
|
-
return
|
|
5251
|
+
return { type: "nothing" };
|
|
5171
5252
|
}
|
|
5172
5253
|
if (isoState && isoState.moov.getMoovBoxAndPrecomputed() && !isoState.moov.getMoovBoxAndPrecomputed()?.precomputed) {
|
|
5173
5254
|
Log.verbose(logLevel, "Moov box already parsed, skipping");
|
|
5174
5255
|
iterator.discard(boxSize - 8);
|
|
5175
|
-
return
|
|
5256
|
+
return { type: "nothing" };
|
|
5176
5257
|
}
|
|
5177
5258
|
const box = await parseMoov({
|
|
5178
5259
|
offset: fileOffset,
|
|
@@ -5183,7 +5264,7 @@ var processBox = async ({
|
|
|
5183
5264
|
contentLength
|
|
5184
5265
|
});
|
|
5185
5266
|
tracks2.setIsDone(logLevel);
|
|
5186
|
-
return box;
|
|
5267
|
+
return { type: "box", box };
|
|
5187
5268
|
}
|
|
5188
5269
|
if (boxType === "trak") {
|
|
5189
5270
|
if (!onlyIfMoovAtomExpected) {
|
|
@@ -5218,54 +5299,75 @@ var processBox = async ({
|
|
|
5218
5299
|
onAudioTrack
|
|
5219
5300
|
});
|
|
5220
5301
|
}
|
|
5221
|
-
return box;
|
|
5302
|
+
return { type: "box", box };
|
|
5222
5303
|
}
|
|
5223
5304
|
if (boxType === "stts") {
|
|
5224
|
-
return
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5305
|
+
return {
|
|
5306
|
+
type: "box",
|
|
5307
|
+
box: await parseStts({
|
|
5308
|
+
data: iterator,
|
|
5309
|
+
size: boxSize,
|
|
5310
|
+
fileOffset
|
|
5311
|
+
})
|
|
5312
|
+
};
|
|
5229
5313
|
}
|
|
5230
5314
|
if (boxType === "avcC") {
|
|
5231
|
-
return
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5315
|
+
return {
|
|
5316
|
+
type: "box",
|
|
5317
|
+
box: await parseAvcc({
|
|
5318
|
+
data: iterator,
|
|
5319
|
+
size: boxSize
|
|
5320
|
+
})
|
|
5321
|
+
};
|
|
5235
5322
|
}
|
|
5236
5323
|
if (boxType === "av1C") {
|
|
5237
|
-
return
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5324
|
+
return {
|
|
5325
|
+
type: "box",
|
|
5326
|
+
box: await parseAv1C({
|
|
5327
|
+
data: iterator,
|
|
5328
|
+
size: boxSize
|
|
5329
|
+
})
|
|
5330
|
+
};
|
|
5241
5331
|
}
|
|
5242
5332
|
if (boxType === "hvcC") {
|
|
5243
|
-
return
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5333
|
+
return {
|
|
5334
|
+
type: "box",
|
|
5335
|
+
box: await parseHvcc({
|
|
5336
|
+
data: iterator,
|
|
5337
|
+
size: boxSize,
|
|
5338
|
+
offset: fileOffset
|
|
5339
|
+
})
|
|
5340
|
+
};
|
|
5248
5341
|
}
|
|
5249
5342
|
if (boxType === "tfhd") {
|
|
5250
|
-
return
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5343
|
+
return {
|
|
5344
|
+
type: "box",
|
|
5345
|
+
box: await getTfhd({
|
|
5346
|
+
iterator,
|
|
5347
|
+
offset: fileOffset,
|
|
5348
|
+
size: boxSize
|
|
5349
|
+
})
|
|
5350
|
+
};
|
|
5255
5351
|
}
|
|
5256
5352
|
if (boxType === "mdhd") {
|
|
5257
|
-
return
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5353
|
+
return {
|
|
5354
|
+
type: "box",
|
|
5355
|
+
box: await parseMdhd({
|
|
5356
|
+
data: iterator,
|
|
5357
|
+
size: boxSize,
|
|
5358
|
+
fileOffset
|
|
5359
|
+
})
|
|
5360
|
+
};
|
|
5262
5361
|
}
|
|
5263
5362
|
if (boxType === "esds") {
|
|
5264
|
-
return
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5363
|
+
return {
|
|
5364
|
+
type: "box",
|
|
5365
|
+
box: await parseEsds({
|
|
5366
|
+
data: iterator,
|
|
5367
|
+
size: boxSize,
|
|
5368
|
+
fileOffset
|
|
5369
|
+
})
|
|
5370
|
+
};
|
|
5269
5371
|
}
|
|
5270
5372
|
if (boxType === "moof") {
|
|
5271
5373
|
onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
|
|
@@ -5279,20 +5381,26 @@ var processBox = async ({
|
|
|
5279
5381
|
contentLength
|
|
5280
5382
|
});
|
|
5281
5383
|
return {
|
|
5282
|
-
type: "
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5384
|
+
type: "box",
|
|
5385
|
+
box: {
|
|
5386
|
+
type: "regular-box",
|
|
5387
|
+
boxType,
|
|
5388
|
+
boxSize,
|
|
5389
|
+
children,
|
|
5390
|
+
offset: fileOffset
|
|
5391
|
+
}
|
|
5287
5392
|
};
|
|
5288
5393
|
}
|
|
5289
5394
|
iterator.discard(boxSize - 8);
|
|
5290
5395
|
return {
|
|
5291
|
-
type: "
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5396
|
+
type: "box",
|
|
5397
|
+
box: {
|
|
5398
|
+
type: "regular-box",
|
|
5399
|
+
boxType,
|
|
5400
|
+
boxSize,
|
|
5401
|
+
children: [],
|
|
5402
|
+
offset: fileOffset
|
|
5403
|
+
}
|
|
5296
5404
|
};
|
|
5297
5405
|
};
|
|
5298
5406
|
|
|
@@ -5314,10 +5422,10 @@ var getIsoBaseMediaChildren = async ({
|
|
|
5314
5422
|
onlyIfMdatAtomExpected: null,
|
|
5315
5423
|
contentLength
|
|
5316
5424
|
});
|
|
5317
|
-
if (
|
|
5425
|
+
if (parsed.type !== "box") {
|
|
5318
5426
|
throw new Error("Expected box");
|
|
5319
5427
|
}
|
|
5320
|
-
boxes.push(parsed);
|
|
5428
|
+
boxes.push(parsed.box);
|
|
5321
5429
|
}
|
|
5322
5430
|
if (iterator.counter.getOffset() > size + initial) {
|
|
5323
5431
|
throw new Error(`read too many bytes - size: ${size}, read: ${iterator.counter.getOffset() - initial}. initial offset: ${initial}`);
|
|
@@ -5383,7 +5491,8 @@ var audioTags = [
|
|
|
5383
5491
|
1836253269,
|
|
5384
5492
|
".mp3",
|
|
5385
5493
|
"mp4a",
|
|
5386
|
-
"ac-3"
|
|
5494
|
+
"ac-3",
|
|
5495
|
+
"Opus"
|
|
5387
5496
|
];
|
|
5388
5497
|
var processIsoFormatBox = async ({
|
|
5389
5498
|
iterator,
|
|
@@ -5873,23 +5982,62 @@ var parseBlockFlags = (iterator, type) => {
|
|
|
5873
5982
|
};
|
|
5874
5983
|
|
|
5875
5984
|
// src/containers/webm/get-sample-from-block.ts
|
|
5876
|
-
var
|
|
5985
|
+
var addAvcToTrackAndActivateTrackIfNecessary = async ({
|
|
5877
5986
|
partialVideoSample,
|
|
5878
5987
|
codec,
|
|
5879
5988
|
structureState,
|
|
5880
5989
|
webmState,
|
|
5881
|
-
trackNumber: trackNumber2
|
|
5990
|
+
trackNumber: trackNumber2,
|
|
5991
|
+
logLevel,
|
|
5992
|
+
callbacks,
|
|
5993
|
+
onVideoTrack
|
|
5882
5994
|
}) => {
|
|
5883
|
-
if (codec
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5995
|
+
if (codec !== "V_MPEG4/ISO/AVC") {
|
|
5996
|
+
return;
|
|
5997
|
+
}
|
|
5998
|
+
const missingTracks = getTracksFromMatroska({
|
|
5999
|
+
structureState,
|
|
6000
|
+
webmState
|
|
6001
|
+
}).missingInfo;
|
|
6002
|
+
if (missingTracks.length === 0) {
|
|
6003
|
+
return;
|
|
6004
|
+
}
|
|
6005
|
+
const parsed = parseAvc(partialVideoSample.data);
|
|
6006
|
+
for (const parse of parsed) {
|
|
6007
|
+
if (parse.type === "avc-profile") {
|
|
6008
|
+
webmState.setAvcProfileForTrackNumber(trackNumber2, parse);
|
|
6009
|
+
const track = missingTracks.find((t) => t.trackId === trackNumber2);
|
|
6010
|
+
if (!track) {
|
|
6011
|
+
throw new Error("Could not find track " + trackNumber2);
|
|
6012
|
+
}
|
|
6013
|
+
const resolvedTracks = getTracksFromMatroska({
|
|
6014
|
+
structureState,
|
|
6015
|
+
webmState
|
|
6016
|
+
}).resolved;
|
|
6017
|
+
const resolvedTrack = resolvedTracks.find((t) => t.trackId === trackNumber2);
|
|
6018
|
+
if (!resolvedTrack) {
|
|
6019
|
+
throw new Error("Could not find track " + trackNumber2);
|
|
5888
6020
|
}
|
|
6021
|
+
await registerVideoTrack({
|
|
6022
|
+
track: resolvedTrack,
|
|
6023
|
+
container: "webm",
|
|
6024
|
+
logLevel,
|
|
6025
|
+
onVideoTrack,
|
|
6026
|
+
registerVideoSampleCallback: callbacks.registerVideoSampleCallback,
|
|
6027
|
+
tracks: callbacks.tracks
|
|
6028
|
+
});
|
|
5889
6029
|
}
|
|
5890
6030
|
}
|
|
5891
6031
|
};
|
|
5892
|
-
var getSampleFromBlock = (
|
|
6032
|
+
var getSampleFromBlock = async ({
|
|
6033
|
+
ebml,
|
|
6034
|
+
webmState,
|
|
6035
|
+
offset,
|
|
6036
|
+
structureState,
|
|
6037
|
+
callbacks,
|
|
6038
|
+
logLevel,
|
|
6039
|
+
onVideoTrack
|
|
6040
|
+
}) => {
|
|
5893
6041
|
const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
|
|
5894
6042
|
const trackNumber2 = iterator.getVint();
|
|
5895
6043
|
if (trackNumber2 === null) {
|
|
@@ -5927,12 +6075,15 @@ var getSampleFromBlock = (ebml, webmState, offset, structureState) => {
|
|
|
5927
6075
|
partialVideoSample
|
|
5928
6076
|
};
|
|
5929
6077
|
}
|
|
5930
|
-
|
|
6078
|
+
await addAvcToTrackAndActivateTrackIfNecessary({
|
|
5931
6079
|
codec,
|
|
5932
6080
|
partialVideoSample,
|
|
5933
6081
|
structureState,
|
|
5934
6082
|
webmState,
|
|
5935
|
-
trackNumber: trackNumber2
|
|
6083
|
+
trackNumber: trackNumber2,
|
|
6084
|
+
callbacks,
|
|
6085
|
+
logLevel,
|
|
6086
|
+
onVideoTrack
|
|
5936
6087
|
});
|
|
5937
6088
|
const sample = {
|
|
5938
6089
|
...partialVideoSample,
|
|
@@ -6092,21 +6243,31 @@ var postprocessEbml = async ({
|
|
|
6092
6243
|
});
|
|
6093
6244
|
}
|
|
6094
6245
|
if (track && track.type === "video") {
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
|
|
6246
|
+
if (track.codec !== NO_CODEC_PRIVATE_SHOULD_BE_DERIVED_FROM_SPS) {
|
|
6247
|
+
await registerVideoTrack({
|
|
6248
|
+
track,
|
|
6249
|
+
container: "webm",
|
|
6250
|
+
logLevel,
|
|
6251
|
+
onVideoTrack,
|
|
6252
|
+
registerVideoSampleCallback: callbacks.registerVideoSampleCallback,
|
|
6253
|
+
tracks: callbacks.tracks
|
|
6254
|
+
});
|
|
6255
|
+
}
|
|
6103
6256
|
}
|
|
6104
6257
|
}
|
|
6105
6258
|
if (ebml.type === "Timestamp") {
|
|
6106
6259
|
webmState.setTimestampOffset(offset, ebml.value.value);
|
|
6107
6260
|
}
|
|
6108
6261
|
if (ebml.type === "Block" || ebml.type === "SimpleBlock") {
|
|
6109
|
-
const sample = getSampleFromBlock(
|
|
6262
|
+
const sample = await getSampleFromBlock({
|
|
6263
|
+
ebml,
|
|
6264
|
+
webmState,
|
|
6265
|
+
offset,
|
|
6266
|
+
structureState,
|
|
6267
|
+
callbacks,
|
|
6268
|
+
logLevel,
|
|
6269
|
+
onVideoTrack
|
|
6270
|
+
});
|
|
6110
6271
|
if (sample.type === "video-sample") {
|
|
6111
6272
|
await callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
|
|
6112
6273
|
return {
|
|
@@ -6137,7 +6298,15 @@ var postprocessEbml = async ({
|
|
|
6137
6298
|
throw new Error("Expected block segment");
|
|
6138
6299
|
}
|
|
6139
6300
|
const hasReferenceBlock = ebml.value.find((c) => c.type === "ReferenceBlock");
|
|
6140
|
-
const sample = block2.value.length === 0 ? null : getSampleFromBlock(
|
|
6301
|
+
const sample = block2.value.length === 0 ? null : await getSampleFromBlock({
|
|
6302
|
+
ebml: block2,
|
|
6303
|
+
webmState,
|
|
6304
|
+
offset,
|
|
6305
|
+
structureState,
|
|
6306
|
+
callbacks,
|
|
6307
|
+
logLevel,
|
|
6308
|
+
onVideoTrack
|
|
6309
|
+
});
|
|
6141
6310
|
if (sample && sample.type === "partial-video-sample") {
|
|
6142
6311
|
const completeFrame = {
|
|
6143
6312
|
...sample.partialVideoSample,
|
|
@@ -6403,7 +6572,11 @@ var mediaParserController = () => {
|
|
|
6403
6572
|
const performedSeeksSignal = performedSeeksStats();
|
|
6404
6573
|
const checkForAbortAndPause = async () => {
|
|
6405
6574
|
if (abortController.signal.aborted) {
|
|
6406
|
-
|
|
6575
|
+
const err = new MediaParserAbortError("Aborted");
|
|
6576
|
+
if (abortController.signal.reason) {
|
|
6577
|
+
err.cause = abortController.signal.reason;
|
|
6578
|
+
}
|
|
6579
|
+
throw err;
|
|
6407
6580
|
}
|
|
6408
6581
|
await pauseSignal.waitUntilResume();
|
|
6409
6582
|
};
|
|
@@ -6425,7 +6598,7 @@ var mediaParserController = () => {
|
|
|
6425
6598
|
abortController.abort(reason);
|
|
6426
6599
|
emitter.dispatchAbort(reason);
|
|
6427
6600
|
},
|
|
6428
|
-
|
|
6601
|
+
seek: seekSignal.seek,
|
|
6429
6602
|
pause: pauseSignal.pause,
|
|
6430
6603
|
resume: pauseSignal.resume,
|
|
6431
6604
|
addEventListener: emitter.addEventListener,
|
|
@@ -6479,7 +6652,8 @@ var getM3uStreams = ({
|
|
|
6479
6652
|
language: audioTrack.language,
|
|
6480
6653
|
name: audioTrack.name,
|
|
6481
6654
|
src: readerInterface.createAdjacentFileSource(audioTrack.uri, originalSrc),
|
|
6482
|
-
id: associatedPlaylists.length
|
|
6655
|
+
id: associatedPlaylists.length,
|
|
6656
|
+
isAudio: true
|
|
6483
6657
|
});
|
|
6484
6658
|
}
|
|
6485
6659
|
}
|
|
@@ -6679,11 +6853,15 @@ var collectSamplePositionsFromMoofBoxes = ({
|
|
|
6679
6853
|
tkhdBox
|
|
6680
6854
|
}) => {
|
|
6681
6855
|
const isComplete = tfraBoxes.length > 0 && tfraBoxes.every((t) => t.entries.length === moofBoxes.length);
|
|
6682
|
-
const samplePositions = moofBoxes.map((m) => {
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6856
|
+
const samplePositions = moofBoxes.map((m, index) => {
|
|
6857
|
+
const isLastFragment = index === moofBoxes.length - 1 && isComplete;
|
|
6858
|
+
return {
|
|
6859
|
+
isLastFragment,
|
|
6860
|
+
samples: getSamplesFromMoof({
|
|
6861
|
+
moofBox: m,
|
|
6862
|
+
trackId: tkhdBox.trackId
|
|
6863
|
+
})
|
|
6864
|
+
};
|
|
6687
6865
|
});
|
|
6688
6866
|
return { samplePositions, isComplete };
|
|
6689
6867
|
};
|
|
@@ -6716,14 +6894,14 @@ var getSamplePositions = ({
|
|
|
6716
6894
|
const samples = [];
|
|
6717
6895
|
let samplesPerChunk = 1;
|
|
6718
6896
|
for (let i = 0;i < chunks.length; i++) {
|
|
6719
|
-
const hasEntry = stscBox.entries.
|
|
6720
|
-
if (hasEntry) {
|
|
6721
|
-
samplesPerChunk = hasEntry
|
|
6897
|
+
const hasEntry = stscBox.entries.get(i + 1);
|
|
6898
|
+
if (hasEntry !== undefined) {
|
|
6899
|
+
samplesPerChunk = hasEntry;
|
|
6722
6900
|
}
|
|
6723
6901
|
let offsetInThisChunk = 0;
|
|
6724
6902
|
for (let j = 0;j < samplesPerChunk; j++) {
|
|
6725
6903
|
const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
|
|
6726
|
-
const isKeyframe = stssBox ? stssBox.sampleNumber.
|
|
6904
|
+
const isKeyframe = stssBox ? stssBox.sampleNumber.has(samples.length + 1) : true;
|
|
6727
6905
|
const delta = sttsDeltas[samples.length];
|
|
6728
6906
|
const ctsOffset = cttsEntries[samples.length];
|
|
6729
6907
|
const cts = dts + ctsOffset;
|
|
@@ -6767,11 +6945,16 @@ var getGroupedSamplesPositionsFromMp4 = ({
|
|
|
6767
6945
|
}
|
|
6768
6946
|
const samples = [];
|
|
6769
6947
|
let timestamp = 0;
|
|
6948
|
+
const stscKeys = Array.from(stscBox.entries.keys());
|
|
6770
6949
|
for (let i = 0;i < stcoBox.entries.length; i++) {
|
|
6771
6950
|
const entry = stcoBox.entries[i];
|
|
6772
6951
|
const chunk = i + 1;
|
|
6773
|
-
const stscEntry =
|
|
6774
|
-
if (
|
|
6952
|
+
const stscEntry = stscKeys.findLast((e) => e <= chunk);
|
|
6953
|
+
if (stscEntry === undefined) {
|
|
6954
|
+
throw new Error("should not be");
|
|
6955
|
+
}
|
|
6956
|
+
const samplesPerChunk = stscBox.entries.get(stscEntry);
|
|
6957
|
+
if (samplesPerChunk === undefined) {
|
|
6775
6958
|
throw new Error("should not be");
|
|
6776
6959
|
}
|
|
6777
6960
|
samples.push({
|
|
@@ -6779,13 +6962,13 @@ var getGroupedSamplesPositionsFromMp4 = ({
|
|
|
6779
6962
|
cts: timestamp,
|
|
6780
6963
|
dts: timestamp,
|
|
6781
6964
|
offset: Number(entry),
|
|
6782
|
-
size: stszBox.sampleSize *
|
|
6783
|
-
duration:
|
|
6965
|
+
size: stszBox.sampleSize * samplesPerChunk,
|
|
6966
|
+
duration: samplesPerChunk,
|
|
6784
6967
|
isKeyframe: true,
|
|
6785
6968
|
bigEndian,
|
|
6786
6969
|
chunkSize: stszBox.sampleSize
|
|
6787
6970
|
});
|
|
6788
|
-
timestamp +=
|
|
6971
|
+
timestamp += samplesPerChunk;
|
|
6789
6972
|
}
|
|
6790
6973
|
return samples;
|
|
6791
6974
|
};
|
|
@@ -6862,7 +7045,7 @@ var getSamplePositionsFromTrack = ({
|
|
|
6862
7045
|
tkhdBox
|
|
6863
7046
|
});
|
|
6864
7047
|
return {
|
|
6865
|
-
samplePositions: samplePositions.flat(1),
|
|
7048
|
+
samplePositions: samplePositions.map((s) => s.samples).flat(1),
|
|
6866
7049
|
isComplete
|
|
6867
7050
|
};
|
|
6868
7051
|
}
|
|
@@ -7096,7 +7279,7 @@ var getDurationFromIsoBaseMedia = (parserState) => {
|
|
|
7096
7279
|
const moovBox = getMoovBoxFromState({
|
|
7097
7280
|
structureState: parserState.structure,
|
|
7098
7281
|
isoState: parserState.iso,
|
|
7099
|
-
mp4HeaderSegment: parserState.mp4HeaderSegment,
|
|
7282
|
+
mp4HeaderSegment: parserState.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
7100
7283
|
mayUsePrecomputed: true
|
|
7101
7284
|
});
|
|
7102
7285
|
if (!moovBox) {
|
|
@@ -7202,7 +7385,12 @@ var hasHdr = (state) => {
|
|
|
7202
7385
|
|
|
7203
7386
|
// src/containers/iso-base-media/get-keyframes.ts
|
|
7204
7387
|
var getKeyframesFromIsoBaseMedia = (state) => {
|
|
7205
|
-
const { videoTracks } = getTracksFromIsoBaseMedia(
|
|
7388
|
+
const { videoTracks } = getTracksFromIsoBaseMedia({
|
|
7389
|
+
isoState: state.iso,
|
|
7390
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
7391
|
+
structure: state.structure,
|
|
7392
|
+
mayUsePrecomputed: true
|
|
7393
|
+
});
|
|
7206
7394
|
const structure = state.structure.getIsoStructure();
|
|
7207
7395
|
const moofBoxes = getMoofBoxes(structure.boxes);
|
|
7208
7396
|
const tfraBoxes = getTfraBoxes(structure);
|
|
@@ -7356,7 +7544,7 @@ var getMetadataFromIsoBase = (state) => {
|
|
|
7356
7544
|
const moov = getMoovBoxFromState({
|
|
7357
7545
|
structureState: state.structure,
|
|
7358
7546
|
isoState: state.iso,
|
|
7359
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
7547
|
+
mp4HeaderSegment: state.m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
7360
7548
|
mayUsePrecomputed: true
|
|
7361
7549
|
});
|
|
7362
7550
|
if (!moov) {
|
|
@@ -7622,12 +7810,81 @@ var getSeekingByteForFlac = ({
|
|
|
7622
7810
|
return null;
|
|
7623
7811
|
};
|
|
7624
7812
|
|
|
7625
|
-
// src/
|
|
7626
|
-
var
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7813
|
+
// src/containers/iso-base-media/find-keyframe-before-time.ts
|
|
7814
|
+
var findKeyframeBeforeTime = ({
|
|
7815
|
+
samplePositions,
|
|
7816
|
+
time,
|
|
7817
|
+
timescale,
|
|
7818
|
+
mediaSections,
|
|
7819
|
+
logLevel
|
|
7820
|
+
}) => {
|
|
7821
|
+
let videoByte = 0;
|
|
7822
|
+
let videoSample = null;
|
|
7823
|
+
for (const sample of samplePositions) {
|
|
7824
|
+
const ctsInSeconds = sample.cts / timescale;
|
|
7825
|
+
const dtsInSeconds = sample.dts / timescale;
|
|
7826
|
+
if (!sample.isKeyframe) {
|
|
7827
|
+
continue;
|
|
7828
|
+
}
|
|
7829
|
+
if (!(ctsInSeconds <= time || dtsInSeconds <= time)) {
|
|
7830
|
+
continue;
|
|
7831
|
+
}
|
|
7832
|
+
if (videoByte <= sample.offset) {
|
|
7833
|
+
videoByte = sample.offset;
|
|
7834
|
+
videoSample = sample;
|
|
7835
|
+
}
|
|
7836
|
+
}
|
|
7837
|
+
if (!videoSample) {
|
|
7838
|
+
throw new Error("No sample found");
|
|
7839
|
+
}
|
|
7840
|
+
const mediaSection = mediaSections.find((section) => videoSample.offset >= section.start && videoSample.offset < section.start + section.size);
|
|
7841
|
+
if (!mediaSection) {
|
|
7842
|
+
Log.trace(logLevel, "Found a sample, but the offset has not yet been marked as a video section yet. Not yet able to seek, but probably once we have started reading the next box.", videoSample);
|
|
7843
|
+
return null;
|
|
7844
|
+
}
|
|
7845
|
+
return videoSample.offset;
|
|
7846
|
+
};
|
|
7847
|
+
|
|
7848
|
+
// src/containers/iso-base-media/find-track-to-seek.ts
|
|
7849
|
+
var findAnyTrackWithSamplePositions = (allTracks, struc) => {
|
|
7850
|
+
for (const track of allTracks) {
|
|
7851
|
+
if (track.type === "video" || track.type === "audio") {
|
|
7852
|
+
const { samplePositions } = getSamplePositionsFromTrack({
|
|
7853
|
+
trakBox: track.trakBox,
|
|
7854
|
+
moofBoxes: getMoofBoxes(struc.boxes),
|
|
7855
|
+
tfraBoxes: getTfraBoxes(struc)
|
|
7856
|
+
});
|
|
7857
|
+
if (samplePositions.length === 0) {
|
|
7858
|
+
continue;
|
|
7859
|
+
}
|
|
7860
|
+
return { track, samplePositions };
|
|
7861
|
+
}
|
|
7862
|
+
}
|
|
7863
|
+
return null;
|
|
7864
|
+
};
|
|
7865
|
+
var findTrackToSeek = (allTracks, structure) => {
|
|
7866
|
+
const firstVideoTrack = allTracks.find((t) => t.type === "video");
|
|
7867
|
+
const struc = structure.getIsoStructure();
|
|
7868
|
+
if (!firstVideoTrack) {
|
|
7869
|
+
return findAnyTrackWithSamplePositions(allTracks, struc);
|
|
7870
|
+
}
|
|
7871
|
+
const { samplePositions } = getSamplePositionsFromTrack({
|
|
7872
|
+
trakBox: firstVideoTrack.trakBox,
|
|
7873
|
+
moofBoxes: getMoofBoxes(struc.boxes),
|
|
7874
|
+
tfraBoxes: getTfraBoxes(struc)
|
|
7875
|
+
});
|
|
7876
|
+
if (samplePositions.length === 0) {
|
|
7877
|
+
return findAnyTrackWithSamplePositions(allTracks, struc);
|
|
7878
|
+
}
|
|
7879
|
+
return { track: firstVideoTrack, samplePositions };
|
|
7880
|
+
};
|
|
7881
|
+
|
|
7882
|
+
// src/state/video-section.ts
|
|
7883
|
+
var isByteInMediaSection = ({
|
|
7884
|
+
position,
|
|
7885
|
+
mediaSections
|
|
7886
|
+
}) => {
|
|
7887
|
+
if (mediaSections.length === 0) {
|
|
7631
7888
|
return "no-section-defined";
|
|
7632
7889
|
}
|
|
7633
7890
|
for (const section of mediaSections) {
|
|
@@ -7690,42 +7947,13 @@ var mediaSectionState = () => {
|
|
|
7690
7947
|
};
|
|
7691
7948
|
};
|
|
7692
7949
|
|
|
7693
|
-
// src/containers/iso-base-media/find-keyframe-before-time.ts
|
|
7694
|
-
var findKeyframeBeforeTime = ({
|
|
7695
|
-
samplePositions,
|
|
7696
|
-
time,
|
|
7697
|
-
timescale,
|
|
7698
|
-
mediaSections,
|
|
7699
|
-
logLevel
|
|
7700
|
-
}) => {
|
|
7701
|
-
let byte = 0;
|
|
7702
|
-
let sam = null;
|
|
7703
|
-
for (const sample of samplePositions) {
|
|
7704
|
-
const ctsInSeconds = sample.cts / timescale;
|
|
7705
|
-
const dtsInSeconds = sample.dts / timescale;
|
|
7706
|
-
if ((ctsInSeconds <= time || dtsInSeconds <= time) && byte <= sample.offset && sample.isKeyframe) {
|
|
7707
|
-
byte = sample.offset;
|
|
7708
|
-
sam = sample;
|
|
7709
|
-
}
|
|
7710
|
-
}
|
|
7711
|
-
if (!sam) {
|
|
7712
|
-
throw new Error("No sample found");
|
|
7713
|
-
}
|
|
7714
|
-
const mediaSection = mediaSections.find((section) => sam.offset >= section.start && sam.offset < section.start + section.size);
|
|
7715
|
-
if (!mediaSection) {
|
|
7716
|
-
Log.trace(logLevel, "Found a sample, but the offset has not yet been marked as a video section yet. Not yet able to seek, but probably once we have started reading the next box.", sam);
|
|
7717
|
-
return null;
|
|
7718
|
-
}
|
|
7719
|
-
return sam.offset;
|
|
7720
|
-
};
|
|
7721
|
-
|
|
7722
7950
|
// src/containers/iso-base-media/get-sample-position-bounds.ts
|
|
7723
7951
|
var getSamplePositionBounds = (samplePositions, timescale) => {
|
|
7724
7952
|
let min = Infinity;
|
|
7725
7953
|
let max = -Infinity;
|
|
7726
7954
|
for (const samplePosition of samplePositions) {
|
|
7727
7955
|
const timestampMin = Math.min(samplePosition.cts, samplePosition.dts);
|
|
7728
|
-
const timestampMax = Math.max(samplePosition.cts, samplePosition.dts);
|
|
7956
|
+
const timestampMax = Math.max(samplePosition.cts, samplePosition.dts) + (samplePosition.duration ?? 0);
|
|
7729
7957
|
if (timestampMin < min) {
|
|
7730
7958
|
min = timestampMin;
|
|
7731
7959
|
}
|
|
@@ -7740,10 +7968,10 @@ var getSamplePositionBounds = (samplePositions, timescale) => {
|
|
|
7740
7968
|
var findBestSegmentFromTfra = ({
|
|
7741
7969
|
mfra,
|
|
7742
7970
|
time,
|
|
7743
|
-
|
|
7971
|
+
firstTrack,
|
|
7744
7972
|
timescale
|
|
7745
7973
|
}) => {
|
|
7746
|
-
const tfra = mfra.find((b) => b.type === "tfra-box" && b.trackId ===
|
|
7974
|
+
const tfra = mfra.find((b) => b.type === "tfra-box" && b.trackId === firstTrack.trackId);
|
|
7747
7975
|
if (!tfra) {
|
|
7748
7976
|
return null;
|
|
7749
7977
|
}
|
|
@@ -7764,130 +7992,191 @@ var findBestSegmentFromTfra = ({
|
|
|
7764
7992
|
};
|
|
7765
7993
|
};
|
|
7766
7994
|
|
|
7995
|
+
// src/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.ts
|
|
7996
|
+
var getSeekingByteFromFragmentedMp4 = async ({
|
|
7997
|
+
info,
|
|
7998
|
+
time,
|
|
7999
|
+
logLevel,
|
|
8000
|
+
currentPosition,
|
|
8001
|
+
isoState,
|
|
8002
|
+
allTracks,
|
|
8003
|
+
isLastChunkInPlaylist
|
|
8004
|
+
}) => {
|
|
8005
|
+
const firstVideoTrack = allTracks.find((t) => t.type === "video");
|
|
8006
|
+
const firstTrack = firstVideoTrack ?? allTracks.find((t) => t.type === "audio");
|
|
8007
|
+
if (!firstTrack) {
|
|
8008
|
+
throw new Error("no video and no audio tracks");
|
|
8009
|
+
}
|
|
8010
|
+
const tkhdBox = getTkhdBox(firstTrack.trakBox);
|
|
8011
|
+
if (!tkhdBox) {
|
|
8012
|
+
throw new Error("Expected tkhd box in trak box");
|
|
8013
|
+
}
|
|
8014
|
+
const { samplePositions: samplePositionsArray } = collectSamplePositionsFromMoofBoxes({
|
|
8015
|
+
moofBoxes: info.moofBoxes,
|
|
8016
|
+
tfraBoxes: info.tfraBoxes,
|
|
8017
|
+
tkhdBox
|
|
8018
|
+
});
|
|
8019
|
+
Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
|
|
8020
|
+
for (const positions of samplePositionsArray) {
|
|
8021
|
+
const { min, max } = getSamplePositionBounds(positions.samples, firstTrack.timescale);
|
|
8022
|
+
if (min <= time && (positions.isLastFragment || isLastChunkInPlaylist || time <= max)) {
|
|
8023
|
+
Log.trace(logLevel, `Fragmented MP4 - Found that we have seeking info for this time range: ${min} <= ${time} <= ${max}`);
|
|
8024
|
+
const kf = findKeyframeBeforeTime({
|
|
8025
|
+
samplePositions: positions.samples,
|
|
8026
|
+
time,
|
|
8027
|
+
timescale: firstTrack.timescale,
|
|
8028
|
+
logLevel,
|
|
8029
|
+
mediaSections: info.mediaSections
|
|
8030
|
+
});
|
|
8031
|
+
if (kf) {
|
|
8032
|
+
return {
|
|
8033
|
+
type: "do-seek",
|
|
8034
|
+
byte: kf
|
|
8035
|
+
};
|
|
8036
|
+
}
|
|
8037
|
+
}
|
|
8038
|
+
}
|
|
8039
|
+
const atom = await (info.mfraAlreadyLoaded ? Promise.resolve(info.mfraAlreadyLoaded) : isoState.mfra.triggerLoad());
|
|
8040
|
+
if (atom) {
|
|
8041
|
+
const moofOffset = findBestSegmentFromTfra({
|
|
8042
|
+
mfra: atom,
|
|
8043
|
+
time,
|
|
8044
|
+
firstTrack,
|
|
8045
|
+
timescale: firstTrack.timescale
|
|
8046
|
+
});
|
|
8047
|
+
if (moofOffset !== null && !(moofOffset.start <= currentPosition && currentPosition < moofOffset.end)) {
|
|
8048
|
+
Log.verbose(logLevel, `Fragmented MP4 - Found based on mfra information that we should seek to: ${moofOffset.start} ${moofOffset.end}`);
|
|
8049
|
+
return {
|
|
8050
|
+
type: "intermediary-seek",
|
|
8051
|
+
byte: moofOffset.start
|
|
8052
|
+
};
|
|
8053
|
+
}
|
|
8054
|
+
}
|
|
8055
|
+
Log.trace(logLevel, "Fragmented MP4 - No seeking info found for this time range.");
|
|
8056
|
+
if (isByteInMediaSection({
|
|
8057
|
+
position: currentPosition,
|
|
8058
|
+
mediaSections: info.mediaSections
|
|
8059
|
+
}) !== "in-section") {
|
|
8060
|
+
return {
|
|
8061
|
+
type: "valid-but-must-wait"
|
|
8062
|
+
};
|
|
8063
|
+
}
|
|
8064
|
+
Log.trace(logLevel, "Fragmented MP4 - Inside the wrong video section, skipping to the end of the section");
|
|
8065
|
+
const mediaSection = getCurrentMediaSection({
|
|
8066
|
+
offset: currentPosition,
|
|
8067
|
+
mediaSections: info.mediaSections
|
|
8068
|
+
});
|
|
8069
|
+
if (!mediaSection) {
|
|
8070
|
+
throw new Error("No video section defined");
|
|
8071
|
+
}
|
|
8072
|
+
return {
|
|
8073
|
+
type: "intermediary-seek",
|
|
8074
|
+
byte: mediaSection.start + mediaSection.size
|
|
8075
|
+
};
|
|
8076
|
+
};
|
|
8077
|
+
|
|
7767
8078
|
// src/containers/iso-base-media/get-seeking-byte.ts
|
|
7768
|
-
var getSeekingByteFromIsoBaseMedia =
|
|
8079
|
+
var getSeekingByteFromIsoBaseMedia = ({
|
|
7769
8080
|
info,
|
|
7770
8081
|
time,
|
|
7771
8082
|
logLevel,
|
|
7772
8083
|
currentPosition,
|
|
7773
8084
|
isoState,
|
|
7774
|
-
|
|
8085
|
+
m3uPlaylistContext,
|
|
7775
8086
|
structure
|
|
7776
8087
|
}) => {
|
|
7777
|
-
const tracks2 =
|
|
8088
|
+
const tracks2 = getTracksFromIsoBaseMedia({
|
|
8089
|
+
isoState,
|
|
8090
|
+
m3uPlaylistContext,
|
|
8091
|
+
structure,
|
|
8092
|
+
mayUsePrecomputed: false
|
|
8093
|
+
});
|
|
7778
8094
|
const allTracks = [
|
|
7779
8095
|
...tracks2.videoTracks,
|
|
7780
8096
|
...tracks2.audioTracks,
|
|
7781
8097
|
...tracks2.otherTracks
|
|
7782
8098
|
];
|
|
7783
8099
|
const hasMoov = Boolean(getMoovBoxFromState({
|
|
7784
|
-
mp4HeaderSegment,
|
|
7785
8100
|
structureState: structure,
|
|
7786
8101
|
isoState,
|
|
7787
|
-
mayUsePrecomputed: false
|
|
8102
|
+
mayUsePrecomputed: false,
|
|
8103
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null
|
|
7788
8104
|
}));
|
|
7789
8105
|
if (!hasMoov) {
|
|
7790
8106
|
Log.trace(logLevel, "No moov box found, must wait");
|
|
7791
|
-
return {
|
|
8107
|
+
return Promise.resolve({
|
|
7792
8108
|
type: "valid-but-must-wait"
|
|
7793
|
-
};
|
|
7794
|
-
}
|
|
7795
|
-
const firstVideoTrack = allTracks.find((t) => t.type === "video");
|
|
7796
|
-
if (!firstVideoTrack) {
|
|
7797
|
-
throw new Error("No video track found");
|
|
8109
|
+
});
|
|
7798
8110
|
}
|
|
7799
|
-
const { timescale } = firstVideoTrack;
|
|
7800
8111
|
if (info.moofBoxes.length > 0) {
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
});
|
|
7810
|
-
Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
|
|
7811
|
-
for (const positions of samplePositionsArray) {
|
|
7812
|
-
const { min, max } = getSamplePositionBounds(positions, timescale);
|
|
7813
|
-
if (min <= time && time <= max) {
|
|
7814
|
-
Log.trace(logLevel, `Fragmented MP4 - Found that we have seeking info for this time range: ${min} <= ${time} <= ${max}`);
|
|
7815
|
-
const kf = findKeyframeBeforeTime({
|
|
7816
|
-
samplePositions: positions,
|
|
7817
|
-
time,
|
|
7818
|
-
timescale,
|
|
7819
|
-
logLevel,
|
|
7820
|
-
mediaSections: info.mediaSections
|
|
7821
|
-
});
|
|
7822
|
-
if (kf) {
|
|
7823
|
-
return {
|
|
7824
|
-
type: "do-seek",
|
|
7825
|
-
byte: kf
|
|
7826
|
-
};
|
|
7827
|
-
}
|
|
7828
|
-
}
|
|
7829
|
-
}
|
|
7830
|
-
const atom = await (info.mfraAlreadyLoaded ? Promise.resolve(info.mfraAlreadyLoaded) : isoState.mfra.triggerLoad());
|
|
7831
|
-
if (atom) {
|
|
7832
|
-
const moofOffset = findBestSegmentFromTfra({
|
|
7833
|
-
mfra: atom,
|
|
7834
|
-
time,
|
|
7835
|
-
firstVideoTrack,
|
|
7836
|
-
timescale
|
|
7837
|
-
});
|
|
7838
|
-
if (moofOffset !== null && !(moofOffset.start <= currentPosition && currentPosition < moofOffset.end)) {
|
|
7839
|
-
Log.verbose(logLevel, `Fragmented MP4 - Found based on mfra information that we should seek to: ${moofOffset.start} ${moofOffset.end}`);
|
|
7840
|
-
return {
|
|
7841
|
-
type: "intermediary-seek",
|
|
7842
|
-
byte: moofOffset.start
|
|
7843
|
-
};
|
|
7844
|
-
}
|
|
7845
|
-
}
|
|
7846
|
-
Log.trace(logLevel, "Fragmented MP4 - No seeking info found for this time range.");
|
|
7847
|
-
if (isByteInMediaSection({
|
|
7848
|
-
position: currentPosition,
|
|
7849
|
-
mediaSections: info.mediaSections
|
|
7850
|
-
}) !== "in-section") {
|
|
7851
|
-
return {
|
|
7852
|
-
type: "valid-but-must-wait"
|
|
7853
|
-
};
|
|
7854
|
-
}
|
|
7855
|
-
Log.trace(logLevel, "Fragmented MP4 - Inside the wrong video section, skipping to the end of the section");
|
|
7856
|
-
const mediaSection = getCurrentMediaSection({
|
|
7857
|
-
offset: currentPosition,
|
|
7858
|
-
mediaSections: info.mediaSections
|
|
8112
|
+
return getSeekingByteFromFragmentedMp4({
|
|
8113
|
+
info,
|
|
8114
|
+
time,
|
|
8115
|
+
logLevel,
|
|
8116
|
+
currentPosition,
|
|
8117
|
+
isoState,
|
|
8118
|
+
allTracks,
|
|
8119
|
+
isLastChunkInPlaylist: m3uPlaylistContext?.isLastChunkInPlaylist ?? false
|
|
7859
8120
|
});
|
|
7860
|
-
if (!mediaSection) {
|
|
7861
|
-
throw new Error("No video section defined");
|
|
7862
|
-
}
|
|
7863
|
-
return {
|
|
7864
|
-
type: "intermediary-seek",
|
|
7865
|
-
byte: mediaSection.start + mediaSection.size
|
|
7866
|
-
};
|
|
7867
8121
|
}
|
|
7868
|
-
const
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
if (!isComplete) {
|
|
7874
|
-
throw new Error("Incomplete sample positions");
|
|
8122
|
+
const trackWithSamplePositions = findTrackToSeek(allTracks, structure);
|
|
8123
|
+
if (!trackWithSamplePositions) {
|
|
8124
|
+
return Promise.resolve({
|
|
8125
|
+
type: "valid-but-must-wait"
|
|
8126
|
+
});
|
|
7875
8127
|
}
|
|
8128
|
+
const { track, samplePositions } = trackWithSamplePositions;
|
|
7876
8129
|
const keyframe = findKeyframeBeforeTime({
|
|
7877
8130
|
samplePositions,
|
|
7878
8131
|
time,
|
|
7879
|
-
timescale,
|
|
8132
|
+
timescale: track.timescale,
|
|
7880
8133
|
logLevel,
|
|
7881
8134
|
mediaSections: info.mediaSections
|
|
7882
8135
|
});
|
|
7883
8136
|
if (keyframe) {
|
|
7884
|
-
return {
|
|
8137
|
+
return Promise.resolve({
|
|
7885
8138
|
type: "do-seek",
|
|
7886
8139
|
byte: keyframe
|
|
7887
|
-
};
|
|
8140
|
+
});
|
|
7888
8141
|
}
|
|
7889
|
-
return {
|
|
8142
|
+
return Promise.resolve({
|
|
7890
8143
|
type: "invalid"
|
|
8144
|
+
});
|
|
8145
|
+
};
|
|
8146
|
+
|
|
8147
|
+
// src/containers/m3u/get-seeking-byte.ts
|
|
8148
|
+
var clearM3uStateInPrepareForSeek = ({
|
|
8149
|
+
m3uState,
|
|
8150
|
+
logLevel
|
|
8151
|
+
}) => {
|
|
8152
|
+
const selectedPlaylists = m3uState.getSelectedPlaylists();
|
|
8153
|
+
for (const playlistUrl of selectedPlaylists) {
|
|
8154
|
+
const streamRun = m3uState.getM3uStreamRun(playlistUrl);
|
|
8155
|
+
if (streamRun) {
|
|
8156
|
+
streamRun.abort();
|
|
8157
|
+
}
|
|
8158
|
+
Log.trace(logLevel, "Clearing M3U stream run for", playlistUrl);
|
|
8159
|
+
m3uState.setM3uStreamRun(playlistUrl, null);
|
|
8160
|
+
}
|
|
8161
|
+
m3uState.clearAllChunksProcessed();
|
|
8162
|
+
m3uState.sampleSorter.clearSamples();
|
|
8163
|
+
};
|
|
8164
|
+
var getSeekingByteForM3u8 = ({
|
|
8165
|
+
time,
|
|
8166
|
+
currentPosition,
|
|
8167
|
+
m3uState,
|
|
8168
|
+
logLevel
|
|
8169
|
+
}) => {
|
|
8170
|
+
clearM3uStateInPrepareForSeek({ m3uState, logLevel });
|
|
8171
|
+
const selectedPlaylists = m3uState.getSelectedPlaylists();
|
|
8172
|
+
for (const playlistUrl of selectedPlaylists) {
|
|
8173
|
+
m3uState.setSeekToSecondsToProcess(playlistUrl, {
|
|
8174
|
+
targetTime: time
|
|
8175
|
+
});
|
|
8176
|
+
}
|
|
8177
|
+
return {
|
|
8178
|
+
type: "do-seek",
|
|
8179
|
+
byte: currentPosition
|
|
7891
8180
|
};
|
|
7892
8181
|
};
|
|
7893
8182
|
|
|
@@ -8525,9 +8814,10 @@ var getSeekingByte = ({
|
|
|
8525
8814
|
transportStream,
|
|
8526
8815
|
webmState,
|
|
8527
8816
|
mediaSection,
|
|
8528
|
-
|
|
8817
|
+
m3uPlaylistContext,
|
|
8529
8818
|
structure,
|
|
8530
|
-
riffState
|
|
8819
|
+
riffState,
|
|
8820
|
+
m3uState
|
|
8531
8821
|
}) => {
|
|
8532
8822
|
if (info.type === "iso-base-media-seeking-hints") {
|
|
8533
8823
|
return getSeekingByteFromIsoBaseMedia({
|
|
@@ -8536,8 +8826,8 @@ var getSeekingByte = ({
|
|
|
8536
8826
|
logLevel,
|
|
8537
8827
|
currentPosition,
|
|
8538
8828
|
isoState,
|
|
8539
|
-
|
|
8540
|
-
|
|
8829
|
+
structure,
|
|
8830
|
+
m3uPlaylistContext
|
|
8541
8831
|
});
|
|
8542
8832
|
}
|
|
8543
8833
|
if (info.type === "wav-seeking-hints") {
|
|
@@ -8602,6 +8892,14 @@ var getSeekingByte = ({
|
|
|
8602
8892
|
seekingHints: info
|
|
8603
8893
|
}));
|
|
8604
8894
|
}
|
|
8895
|
+
if (info.type === "m3u8-seeking-hints") {
|
|
8896
|
+
return Promise.resolve(getSeekingByteForM3u8({
|
|
8897
|
+
time,
|
|
8898
|
+
currentPosition,
|
|
8899
|
+
m3uState,
|
|
8900
|
+
logLevel
|
|
8901
|
+
}));
|
|
8902
|
+
}
|
|
8605
8903
|
throw new Error(`Unknown seeking info type: ${info}`);
|
|
8606
8904
|
};
|
|
8607
8905
|
|
|
@@ -8690,6 +8988,13 @@ var getSeekingHintsFromMp4 = ({
|
|
|
8690
8988
|
};
|
|
8691
8989
|
var setSeekingHintsForMp4 = ({}) => {};
|
|
8692
8990
|
|
|
8991
|
+
// src/containers/m3u/seeking-hints.ts
|
|
8992
|
+
var getSeekingHintsForM3u = () => {
|
|
8993
|
+
return {
|
|
8994
|
+
type: "m3u8-seeking-hints"
|
|
8995
|
+
};
|
|
8996
|
+
};
|
|
8997
|
+
|
|
8693
8998
|
// src/containers/mp3/seeking-hints.ts
|
|
8694
8999
|
var getSeekingHintsForMp3 = ({
|
|
8695
9000
|
mp3State,
|
|
@@ -8836,7 +9141,7 @@ var setSeekingHintsForWebm = ({
|
|
|
8836
9141
|
// src/get-seeking-hints.ts
|
|
8837
9142
|
var getSeekingHints = ({
|
|
8838
9143
|
structureState,
|
|
8839
|
-
|
|
9144
|
+
m3uPlaylistContext,
|
|
8840
9145
|
mediaSectionState: mediaSectionState2,
|
|
8841
9146
|
isoState,
|
|
8842
9147
|
transportStream,
|
|
@@ -8858,7 +9163,7 @@ var getSeekingHints = ({
|
|
|
8858
9163
|
return getSeekingHintsFromMp4({
|
|
8859
9164
|
structureState,
|
|
8860
9165
|
isoState,
|
|
8861
|
-
mp4HeaderSegment,
|
|
9166
|
+
mp4HeaderSegment: m3uPlaylistContext?.mp4HeaderSegment ?? null,
|
|
8862
9167
|
mediaSectionState: mediaSectionState2
|
|
8863
9168
|
});
|
|
8864
9169
|
}
|
|
@@ -8901,7 +9206,10 @@ var getSeekingHints = ({
|
|
|
8901
9206
|
samplesObserved
|
|
8902
9207
|
});
|
|
8903
9208
|
}
|
|
8904
|
-
|
|
9209
|
+
if (structure.type === "m3u") {
|
|
9210
|
+
return getSeekingHintsForM3u();
|
|
9211
|
+
}
|
|
9212
|
+
throw new Error(`Seeking is not supported for this format: ${structure}`);
|
|
8905
9213
|
};
|
|
8906
9214
|
|
|
8907
9215
|
// src/seek-backwards.ts
|
|
@@ -8912,10 +9220,12 @@ var seekBackwards = async ({
|
|
|
8912
9220
|
src,
|
|
8913
9221
|
controller,
|
|
8914
9222
|
logLevel,
|
|
8915
|
-
currentReader
|
|
9223
|
+
currentReader,
|
|
9224
|
+
prefetchCache
|
|
8916
9225
|
}) => {
|
|
8917
9226
|
const howManyBytesWeCanGoBack = iterator.counter.getDiscardedOffset();
|
|
8918
9227
|
if (iterator.counter.getOffset() - howManyBytesWeCanGoBack <= seekTo) {
|
|
9228
|
+
Log.verbose(logLevel, `Seeking back to ${seekTo}`);
|
|
8919
9229
|
iterator.skipTo(seekTo);
|
|
8920
9230
|
return;
|
|
8921
9231
|
}
|
|
@@ -8924,7 +9234,9 @@ var seekBackwards = async ({
|
|
|
8924
9234
|
const { reader: newReader } = await readerInterface.read({
|
|
8925
9235
|
src,
|
|
8926
9236
|
range: seekTo,
|
|
8927
|
-
controller
|
|
9237
|
+
controller,
|
|
9238
|
+
logLevel,
|
|
9239
|
+
prefetchCache
|
|
8928
9240
|
});
|
|
8929
9241
|
iterator.replaceData(new Uint8Array([]), seekTo);
|
|
8930
9242
|
Log.verbose(logLevel, `Re-reading took ${Date.now() - time}ms. New position: ${iterator.counter.getOffset()}`);
|
|
@@ -8994,7 +9306,8 @@ var seekForward = async ({
|
|
|
8994
9306
|
readerInterface,
|
|
8995
9307
|
src,
|
|
8996
9308
|
controller,
|
|
8997
|
-
discardReadBytes
|
|
9309
|
+
discardReadBytes,
|
|
9310
|
+
prefetchCache
|
|
8998
9311
|
}) => {
|
|
8999
9312
|
if (userInitiated) {
|
|
9000
9313
|
disallowForwardSeekIfSamplesAreNeeded({
|
|
@@ -9015,7 +9328,9 @@ var seekForward = async ({
|
|
|
9015
9328
|
const { reader: newReader } = await readerInterface.read({
|
|
9016
9329
|
src,
|
|
9017
9330
|
range: seekTo,
|
|
9018
|
-
controller
|
|
9331
|
+
controller,
|
|
9332
|
+
logLevel,
|
|
9333
|
+
prefetchCache
|
|
9019
9334
|
});
|
|
9020
9335
|
iterator.skipTo(seekTo);
|
|
9021
9336
|
await discardReadBytes(true);
|
|
@@ -9038,7 +9353,8 @@ var performSeek = async ({
|
|
|
9038
9353
|
readerInterface,
|
|
9039
9354
|
src,
|
|
9040
9355
|
discardReadBytes,
|
|
9041
|
-
fields
|
|
9356
|
+
fields,
|
|
9357
|
+
prefetchCache
|
|
9042
9358
|
}) => {
|
|
9043
9359
|
const byteInMediaSection = isByteInMediaSection({
|
|
9044
9360
|
position: seekTo,
|
|
@@ -9087,7 +9403,8 @@ var performSeek = async ({
|
|
|
9087
9403
|
readerInterface,
|
|
9088
9404
|
src,
|
|
9089
9405
|
controller,
|
|
9090
|
-
discardReadBytes
|
|
9406
|
+
discardReadBytes,
|
|
9407
|
+
prefetchCache
|
|
9091
9408
|
});
|
|
9092
9409
|
} else {
|
|
9093
9410
|
await seekBackwards({
|
|
@@ -9097,7 +9414,8 @@ var performSeek = async ({
|
|
|
9097
9414
|
logLevel,
|
|
9098
9415
|
currentReader,
|
|
9099
9416
|
readerInterface,
|
|
9100
|
-
src
|
|
9417
|
+
src,
|
|
9418
|
+
prefetchCache
|
|
9101
9419
|
});
|
|
9102
9420
|
}
|
|
9103
9421
|
await controller._internals.checkForAbortAndPause();
|
|
@@ -9110,7 +9428,7 @@ var turnSeekIntoByte = async ({
|
|
|
9110
9428
|
logLevel,
|
|
9111
9429
|
iterator,
|
|
9112
9430
|
structureState,
|
|
9113
|
-
|
|
9431
|
+
m3uPlaylistContext,
|
|
9114
9432
|
isoState,
|
|
9115
9433
|
transportStream,
|
|
9116
9434
|
tracksState,
|
|
@@ -9121,7 +9439,8 @@ var turnSeekIntoByte = async ({
|
|
|
9121
9439
|
riffState,
|
|
9122
9440
|
mp3State,
|
|
9123
9441
|
contentLength,
|
|
9124
|
-
aacState
|
|
9442
|
+
aacState,
|
|
9443
|
+
m3uState
|
|
9125
9444
|
}) => {
|
|
9126
9445
|
const mediaSections = mediaSectionState2.getMediaSections();
|
|
9127
9446
|
if (mediaSections.length === 0) {
|
|
@@ -9138,7 +9457,6 @@ var turnSeekIntoByte = async ({
|
|
|
9138
9457
|
riffState,
|
|
9139
9458
|
samplesObserved,
|
|
9140
9459
|
structureState,
|
|
9141
|
-
mp4HeaderSegment,
|
|
9142
9460
|
mediaSectionState: mediaSectionState2,
|
|
9143
9461
|
isoState,
|
|
9144
9462
|
transportStream,
|
|
@@ -9148,7 +9466,8 @@ var turnSeekIntoByte = async ({
|
|
|
9148
9466
|
flacState,
|
|
9149
9467
|
mp3State,
|
|
9150
9468
|
contentLength,
|
|
9151
|
-
aacState
|
|
9469
|
+
aacState,
|
|
9470
|
+
m3uPlaylistContext
|
|
9152
9471
|
});
|
|
9153
9472
|
if (!seekingHints) {
|
|
9154
9473
|
Log.trace(logLevel, "No seeking info, cannot seek yet");
|
|
@@ -9165,18 +9484,13 @@ var turnSeekIntoByte = async ({
|
|
|
9165
9484
|
transportStream,
|
|
9166
9485
|
webmState,
|
|
9167
9486
|
mediaSection: mediaSectionState2,
|
|
9168
|
-
|
|
9487
|
+
m3uPlaylistContext,
|
|
9169
9488
|
structure: structureState,
|
|
9170
|
-
riffState
|
|
9489
|
+
riffState,
|
|
9490
|
+
m3uState
|
|
9171
9491
|
});
|
|
9172
9492
|
return seekingByte;
|
|
9173
9493
|
}
|
|
9174
|
-
if (seek2.type === "byte") {
|
|
9175
|
-
return {
|
|
9176
|
-
type: "do-seek",
|
|
9177
|
-
byte: seek2.byte
|
|
9178
|
-
};
|
|
9179
|
-
}
|
|
9180
9494
|
throw new Error(`Cannot process seek request for ${seek2}: ${JSON.stringify(seek2)}`);
|
|
9181
9495
|
};
|
|
9182
9496
|
var getWorkOnSeekRequestOptions = (state) => {
|
|
@@ -9190,7 +9504,7 @@ var getWorkOnSeekRequestOptions = (state) => {
|
|
|
9190
9504
|
contentLength: state.contentLength,
|
|
9191
9505
|
readerInterface: state.readerInterface,
|
|
9192
9506
|
mediaSection: state.mediaSection,
|
|
9193
|
-
|
|
9507
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
9194
9508
|
mode: state.mode,
|
|
9195
9509
|
seekInfiniteLoop: state.seekInfiniteLoop,
|
|
9196
9510
|
currentReader: state.currentReader,
|
|
@@ -9204,7 +9518,9 @@ var getWorkOnSeekRequestOptions = (state) => {
|
|
|
9204
9518
|
samplesObserved: state.samplesObserved,
|
|
9205
9519
|
riffState: state.riff,
|
|
9206
9520
|
mp3State: state.mp3,
|
|
9207
|
-
aacState: state.aac
|
|
9521
|
+
aacState: state.aac,
|
|
9522
|
+
m3uState: state.m3u,
|
|
9523
|
+
prefetchCache: state.prefetchCache
|
|
9208
9524
|
};
|
|
9209
9525
|
};
|
|
9210
9526
|
var workOnSeekRequest = async (options) => {
|
|
@@ -9212,7 +9528,7 @@ var workOnSeekRequest = async (options) => {
|
|
|
9212
9528
|
logLevel,
|
|
9213
9529
|
controller,
|
|
9214
9530
|
mediaSection,
|
|
9215
|
-
|
|
9531
|
+
m3uPlaylistContext,
|
|
9216
9532
|
isoState,
|
|
9217
9533
|
iterator,
|
|
9218
9534
|
structureState,
|
|
@@ -9232,20 +9548,22 @@ var workOnSeekRequest = async (options) => {
|
|
|
9232
9548
|
samplesObserved,
|
|
9233
9549
|
riffState,
|
|
9234
9550
|
mp3State,
|
|
9235
|
-
aacState
|
|
9551
|
+
aacState,
|
|
9552
|
+
prefetchCache,
|
|
9553
|
+
m3uState
|
|
9236
9554
|
} = options;
|
|
9237
9555
|
const seek2 = controller._internals.seekSignal.getSeek();
|
|
9238
9556
|
if (!seek2) {
|
|
9239
9557
|
return;
|
|
9240
9558
|
}
|
|
9241
|
-
Log.trace(logLevel, `Has seek request: ${JSON.stringify(seek2)}`);
|
|
9559
|
+
Log.trace(logLevel, `Has seek request for ${src}: ${JSON.stringify(seek2)}`);
|
|
9242
9560
|
const resolution = await turnSeekIntoByte({
|
|
9243
9561
|
seek: seek2,
|
|
9244
9562
|
mediaSectionState: mediaSection,
|
|
9245
9563
|
logLevel,
|
|
9246
9564
|
iterator,
|
|
9247
9565
|
structureState,
|
|
9248
|
-
|
|
9566
|
+
m3uPlaylistContext,
|
|
9249
9567
|
isoState,
|
|
9250
9568
|
transportStream,
|
|
9251
9569
|
tracksState,
|
|
@@ -9256,7 +9574,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
9256
9574
|
riffState,
|
|
9257
9575
|
mp3State,
|
|
9258
9576
|
contentLength,
|
|
9259
|
-
aacState
|
|
9577
|
+
aacState,
|
|
9578
|
+
m3uState
|
|
9260
9579
|
});
|
|
9261
9580
|
Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
|
|
9262
9581
|
if (resolution.type === "intermediary-seek") {
|
|
@@ -9274,7 +9593,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
9274
9593
|
readerInterface,
|
|
9275
9594
|
src,
|
|
9276
9595
|
discardReadBytes,
|
|
9277
|
-
fields
|
|
9596
|
+
fields,
|
|
9597
|
+
prefetchCache
|
|
9278
9598
|
});
|
|
9279
9599
|
return;
|
|
9280
9600
|
}
|
|
@@ -9293,7 +9613,8 @@ var workOnSeekRequest = async (options) => {
|
|
|
9293
9613
|
readerInterface,
|
|
9294
9614
|
src,
|
|
9295
9615
|
discardReadBytes,
|
|
9296
|
-
fields
|
|
9616
|
+
fields,
|
|
9617
|
+
prefetchCache
|
|
9297
9618
|
});
|
|
9298
9619
|
const { hasChanged } = controller._internals.seekSignal.clearSeekIfStillSame(seek2);
|
|
9299
9620
|
if (hasChanged) {
|
|
@@ -9914,12 +10235,6 @@ var parseAac = async (state) => {
|
|
|
9914
10235
|
return Promise.resolve(null);
|
|
9915
10236
|
};
|
|
9916
10237
|
|
|
9917
|
-
// src/skip.ts
|
|
9918
|
-
var makeSkip = (skipTo) => ({
|
|
9919
|
-
action: "skip",
|
|
9920
|
-
skipTo
|
|
9921
|
-
});
|
|
9922
|
-
|
|
9923
10238
|
// src/containers/flac/get-block-size.ts
|
|
9924
10239
|
var getBlockSize = (iterator) => {
|
|
9925
10240
|
const bits = iterator.getBits(4);
|
|
@@ -10373,11 +10688,12 @@ var calculateFlatSamples = (state) => {
|
|
|
10373
10688
|
samplePosition
|
|
10374
10689
|
};
|
|
10375
10690
|
});
|
|
10376
|
-
})
|
|
10691
|
+
});
|
|
10377
10692
|
return flatSamples;
|
|
10378
10693
|
};
|
|
10379
10694
|
var cachedSamplePositionsState = () => {
|
|
10380
10695
|
const cachedForMdatStart = {};
|
|
10696
|
+
const jumpMarksForMdatStart = {};
|
|
10381
10697
|
return {
|
|
10382
10698
|
getSamples: (mdatStart) => {
|
|
10383
10699
|
if (cachedForMdatStart[mdatStart]) {
|
|
@@ -10387,6 +10703,12 @@ var cachedSamplePositionsState = () => {
|
|
|
10387
10703
|
},
|
|
10388
10704
|
setSamples: (mdatStart, samples) => {
|
|
10389
10705
|
cachedForMdatStart[mdatStart] = samples;
|
|
10706
|
+
},
|
|
10707
|
+
setJumpMarks: (mdatStart, marks) => {
|
|
10708
|
+
jumpMarksForMdatStart[mdatStart] = marks;
|
|
10709
|
+
},
|
|
10710
|
+
getJumpMarks: (mdatStart) => {
|
|
10711
|
+
return jumpMarksForMdatStart[mdatStart];
|
|
10390
10712
|
}
|
|
10391
10713
|
};
|
|
10392
10714
|
};
|
|
@@ -10416,17 +10738,21 @@ var makeCanSkipTracksState = ({
|
|
|
10416
10738
|
hasVideoTrackHandlers,
|
|
10417
10739
|
structure
|
|
10418
10740
|
}) => {
|
|
10741
|
+
const doFieldsNeedTracks = () => {
|
|
10742
|
+
const keys = Object.keys(fields ?? {});
|
|
10743
|
+
const selectedKeys = keys.filter((k) => fields[k]);
|
|
10744
|
+
return selectedKeys.some((k) => needsTracksForField({
|
|
10745
|
+
field: k,
|
|
10746
|
+
structure: structure.getStructureOrNull()
|
|
10747
|
+
}));
|
|
10748
|
+
};
|
|
10419
10749
|
return {
|
|
10750
|
+
doFieldsNeedTracks,
|
|
10420
10751
|
canSkipTracks: () => {
|
|
10421
10752
|
if (hasAudioTrackHandlers || hasVideoTrackHandlers) {
|
|
10422
10753
|
return false;
|
|
10423
10754
|
}
|
|
10424
|
-
|
|
10425
|
-
const selectedKeys = keys.filter((k) => fields[k]);
|
|
10426
|
-
return !selectedKeys.some((k) => needsTracksForField({
|
|
10427
|
-
field: k,
|
|
10428
|
-
structure: structure.getStructureOrNull()
|
|
10429
|
-
}));
|
|
10755
|
+
return !doFieldsNeedTracks();
|
|
10430
10756
|
}
|
|
10431
10757
|
};
|
|
10432
10758
|
};
|
|
@@ -10546,7 +10872,7 @@ var getMoovAtom = async ({
|
|
|
10546
10872
|
endOfMdat,
|
|
10547
10873
|
state
|
|
10548
10874
|
}) => {
|
|
10549
|
-
const headerSegment = state.mp4HeaderSegment;
|
|
10875
|
+
const headerSegment = state.m3uPlaylistContext?.mp4HeaderSegment;
|
|
10550
10876
|
if (headerSegment) {
|
|
10551
10877
|
const segment = getMoovFromFromIsoStructure(headerSegment);
|
|
10552
10878
|
if (!segment) {
|
|
@@ -10559,7 +10885,9 @@ var getMoovAtom = async ({
|
|
|
10559
10885
|
const { reader } = await state.readerInterface.read({
|
|
10560
10886
|
src: state.src,
|
|
10561
10887
|
range: endOfMdat,
|
|
10562
|
-
controller: state.controller
|
|
10888
|
+
controller: state.controller,
|
|
10889
|
+
logLevel: state.logLevel,
|
|
10890
|
+
prefetchCache: state.prefetchCache
|
|
10563
10891
|
});
|
|
10564
10892
|
const onAudioTrack = state.onAudioTrack ? async ({ track, container }) => {
|
|
10565
10893
|
await registerAudioTrack({
|
|
@@ -10616,8 +10944,8 @@ var getMoovAtom = async ({
|
|
|
10616
10944
|
onlyIfMdatAtomExpected: null,
|
|
10617
10945
|
contentLength: state.contentLength - endOfMdat
|
|
10618
10946
|
});
|
|
10619
|
-
if (box) {
|
|
10620
|
-
boxes.push(box);
|
|
10947
|
+
if (box.type === "box") {
|
|
10948
|
+
boxes.push(box.box);
|
|
10621
10949
|
}
|
|
10622
10950
|
if (iterator.counter.getOffset() + endOfMdat > state.contentLength) {
|
|
10623
10951
|
throw new Error("Read past end of file");
|
|
@@ -10634,6 +10962,121 @@ var getMoovAtom = async ({
|
|
|
10634
10962
|
return moov;
|
|
10635
10963
|
};
|
|
10636
10964
|
|
|
10965
|
+
// src/containers/iso-base-media/mdat/calculate-jump-marks.ts
|
|
10966
|
+
var MAX_SPREAD_IN_SECONDS = 8;
|
|
10967
|
+
var getKey = (samplePositionTrack) => {
|
|
10968
|
+
return `${samplePositionTrack.track.trackId}-${samplePositionTrack.samplePosition.dts}`;
|
|
10969
|
+
};
|
|
10970
|
+
var findBestJump = ({
|
|
10971
|
+
allSamplesSortedByOffset,
|
|
10972
|
+
visited,
|
|
10973
|
+
progresses
|
|
10974
|
+
}) => {
|
|
10975
|
+
const minProgress = Math.min(...Object.values(progresses));
|
|
10976
|
+
const trackNumberWithLowestProgress = Object.entries(progresses).find(([, progress]) => progress === minProgress)?.[0];
|
|
10977
|
+
const firstSampleAboveMinProgress = allSamplesSortedByOffset.findIndex((sample) => sample.track.trackId === Number(trackNumberWithLowestProgress) && !visited.has(getKey(sample)));
|
|
10978
|
+
return firstSampleAboveMinProgress;
|
|
10979
|
+
};
|
|
10980
|
+
var calculateJumpMarks = (samplePositionTracks, endOfMdat) => {
|
|
10981
|
+
const progresses = {};
|
|
10982
|
+
for (const track of samplePositionTracks) {
|
|
10983
|
+
progresses[track[0].track.trackId] = 0;
|
|
10984
|
+
}
|
|
10985
|
+
const jumpMarks = [];
|
|
10986
|
+
const allSamplesSortedByOffset = samplePositionTracks.flat(1).sort((a, b) => a.samplePosition.offset - b.samplePosition.offset);
|
|
10987
|
+
let indexToVisit = 0;
|
|
10988
|
+
const visited = new Set;
|
|
10989
|
+
let rollOverToProcess = false;
|
|
10990
|
+
const increaseIndex = () => {
|
|
10991
|
+
indexToVisit++;
|
|
10992
|
+
if (indexToVisit >= allSamplesSortedByOffset.length) {
|
|
10993
|
+
rollOverToProcess = true;
|
|
10994
|
+
indexToVisit = 0;
|
|
10995
|
+
}
|
|
10996
|
+
};
|
|
10997
|
+
let lastVisitedSample = null;
|
|
10998
|
+
const addJumpMark = ({
|
|
10999
|
+
firstSampleAboveMinProgress
|
|
11000
|
+
}) => {
|
|
11001
|
+
if (!lastVisitedSample) {
|
|
11002
|
+
throw new Error("no last visited sample");
|
|
11003
|
+
}
|
|
11004
|
+
const jumpMark = {
|
|
11005
|
+
afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
|
|
11006
|
+
jumpToOffset: allSamplesSortedByOffset[firstSampleAboveMinProgress].samplePosition.offset
|
|
11007
|
+
};
|
|
11008
|
+
indexToVisit = firstSampleAboveMinProgress;
|
|
11009
|
+
jumpMarks.push(jumpMark);
|
|
11010
|
+
};
|
|
11011
|
+
const addFinalJumpIfNecessary = () => {
|
|
11012
|
+
if (indexToVisit === allSamplesSortedByOffset.length - 1) {
|
|
11013
|
+
return;
|
|
11014
|
+
}
|
|
11015
|
+
jumpMarks.push({
|
|
11016
|
+
afterSampleWithOffset: allSamplesSortedByOffset[indexToVisit].samplePosition.offset,
|
|
11017
|
+
jumpToOffset: endOfMdat
|
|
11018
|
+
});
|
|
11019
|
+
};
|
|
11020
|
+
const considerJump = () => {
|
|
11021
|
+
const firstSampleAboveMinProgress = findBestJump({
|
|
11022
|
+
allSamplesSortedByOffset,
|
|
11023
|
+
visited,
|
|
11024
|
+
progresses
|
|
11025
|
+
});
|
|
11026
|
+
if (firstSampleAboveMinProgress > -1 && firstSampleAboveMinProgress !== indexToVisit + 1) {
|
|
11027
|
+
addJumpMark({ firstSampleAboveMinProgress });
|
|
11028
|
+
indexToVisit = firstSampleAboveMinProgress;
|
|
11029
|
+
} else {
|
|
11030
|
+
while (true) {
|
|
11031
|
+
increaseIndex();
|
|
11032
|
+
if (!visited.has(getKey(allSamplesSortedByOffset[indexToVisit]))) {
|
|
11033
|
+
break;
|
|
11034
|
+
}
|
|
11035
|
+
}
|
|
11036
|
+
}
|
|
11037
|
+
};
|
|
11038
|
+
while (true) {
|
|
11039
|
+
const currentSamplePosition = allSamplesSortedByOffset[indexToVisit];
|
|
11040
|
+
const sampleKey = getKey(currentSamplePosition);
|
|
11041
|
+
if (visited.has(sampleKey)) {
|
|
11042
|
+
considerJump();
|
|
11043
|
+
continue;
|
|
11044
|
+
}
|
|
11045
|
+
visited.add(sampleKey);
|
|
11046
|
+
if (rollOverToProcess) {
|
|
11047
|
+
if (!lastVisitedSample) {
|
|
11048
|
+
throw new Error("no last visited sample");
|
|
11049
|
+
}
|
|
11050
|
+
jumpMarks.push({
|
|
11051
|
+
afterSampleWithOffset: lastVisitedSample.samplePosition.offset,
|
|
11052
|
+
jumpToOffset: currentSamplePosition.samplePosition.offset
|
|
11053
|
+
});
|
|
11054
|
+
rollOverToProcess = false;
|
|
11055
|
+
}
|
|
11056
|
+
lastVisitedSample = currentSamplePosition;
|
|
11057
|
+
if (visited.size === allSamplesSortedByOffset.length) {
|
|
11058
|
+
addFinalJumpIfNecessary();
|
|
11059
|
+
break;
|
|
11060
|
+
}
|
|
11061
|
+
const timestamp = currentSamplePosition.samplePosition.dts / currentSamplePosition.track.timescale;
|
|
11062
|
+
progresses[currentSamplePosition.track.trackId] = timestamp;
|
|
11063
|
+
const progressValues = Object.values(progresses);
|
|
11064
|
+
const maxProgress = Math.max(...progressValues);
|
|
11065
|
+
const minProgress = Math.min(...progressValues);
|
|
11066
|
+
const spread = maxProgress - minProgress;
|
|
11067
|
+
if (visited.size === allSamplesSortedByOffset.length) {
|
|
11068
|
+
addFinalJumpIfNecessary();
|
|
11069
|
+
break;
|
|
11070
|
+
}
|
|
11071
|
+
if (spread > MAX_SPREAD_IN_SECONDS) {
|
|
11072
|
+
considerJump();
|
|
11073
|
+
} else {
|
|
11074
|
+
increaseIndex();
|
|
11075
|
+
}
|
|
11076
|
+
}
|
|
11077
|
+
return jumpMarks;
|
|
11078
|
+
};
|
|
11079
|
+
|
|
10637
11080
|
// src/containers/iso-base-media/mdat/postprocess-bytes.ts
|
|
10638
11081
|
var postprocessBytes = ({
|
|
10639
11082
|
bytes,
|
|
@@ -10683,9 +11126,13 @@ var parseMdatSection = async (state) => {
|
|
|
10683
11126
|
return parseMdatSection(state);
|
|
10684
11127
|
}
|
|
10685
11128
|
if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
|
|
10686
|
-
|
|
11129
|
+
const flattedSamples = calculateFlatSamples(state);
|
|
11130
|
+
const calcedJumpMarks = calculateJumpMarks(flattedSamples, endOfMdat);
|
|
11131
|
+
state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
|
|
11132
|
+
state.iso.flatSamples.setSamples(mediaSection.start, flattedSamples.flat(1));
|
|
10687
11133
|
}
|
|
10688
11134
|
const flatSamples = state.iso.flatSamples.getSamples(mediaSection.start);
|
|
11135
|
+
const jumpMarks = state.iso.flatSamples.getJumpMarks(mediaSection.start);
|
|
10689
11136
|
const { iterator } = state;
|
|
10690
11137
|
const samplesWithIndex = flatSamples.find((sample) => {
|
|
10691
11138
|
return sample.samplePosition.offset === iterator.counter.getOffset();
|
|
@@ -10698,8 +11145,11 @@ var parseMdatSection = async (state) => {
|
|
|
10698
11145
|
}
|
|
10699
11146
|
return makeSkip(endOfMdat);
|
|
10700
11147
|
}
|
|
11148
|
+
if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
|
|
11149
|
+
return makeSkip(endOfMdat);
|
|
11150
|
+
}
|
|
10701
11151
|
if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
|
|
10702
|
-
return
|
|
11152
|
+
return makeFetchMoreData(samplesWithIndex.samplePosition.size - iterator.bytesRemaining());
|
|
10703
11153
|
}
|
|
10704
11154
|
const { cts, dts, duration: duration2, isKeyframe, offset, bigEndian, chunkSize } = samplesWithIndex.samplePosition;
|
|
10705
11155
|
const bytes = postprocessBytes({
|
|
@@ -10747,6 +11197,10 @@ var parseMdatSection = async (state) => {
|
|
|
10747
11197
|
});
|
|
10748
11198
|
await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, videoSample);
|
|
10749
11199
|
}
|
|
11200
|
+
const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
|
|
11201
|
+
if (jump) {
|
|
11202
|
+
return makeSkip(jump.jumpToOffset);
|
|
11203
|
+
}
|
|
10750
11204
|
return null;
|
|
10751
11205
|
};
|
|
10752
11206
|
|
|
@@ -10773,8 +11227,11 @@ var parseIsoBaseMedia = async (state) => {
|
|
|
10773
11227
|
},
|
|
10774
11228
|
contentLength: state.contentLength
|
|
10775
11229
|
});
|
|
10776
|
-
if (result) {
|
|
10777
|
-
|
|
11230
|
+
if (result.type === "fetch-more-data") {
|
|
11231
|
+
return result.bytesNeeded;
|
|
11232
|
+
}
|
|
11233
|
+
if (result.type === "box") {
|
|
11234
|
+
state.structure.getIsoStructure().boxes.push(result.box);
|
|
10778
11235
|
}
|
|
10779
11236
|
return null;
|
|
10780
11237
|
};
|
|
@@ -10853,7 +11310,8 @@ var parseM3uMediaDirective = (str) => {
|
|
|
10853
11310
|
groupId: map["GROUP-ID"],
|
|
10854
11311
|
language: map.LANGUAGE || null,
|
|
10855
11312
|
name: map.NAME || null,
|
|
10856
|
-
uri: map.URI
|
|
11313
|
+
uri: map.URI,
|
|
11314
|
+
mediaType: map.TYPE || null
|
|
10857
11315
|
};
|
|
10858
11316
|
};
|
|
10859
11317
|
|
|
@@ -11008,7 +11466,8 @@ var fetchM3u8Stream = async ({
|
|
|
11008
11466
|
// src/containers/m3u/select-stream.ts
|
|
11009
11467
|
var selectAssociatedPlaylists = async ({
|
|
11010
11468
|
playlists,
|
|
11011
|
-
fn
|
|
11469
|
+
fn,
|
|
11470
|
+
skipAudioTracks
|
|
11012
11471
|
}) => {
|
|
11013
11472
|
if (playlists.length < 1) {
|
|
11014
11473
|
return Promise.resolve([]);
|
|
@@ -11017,12 +11476,17 @@ var selectAssociatedPlaylists = async ({
|
|
|
11017
11476
|
if (!Array.isArray(streams)) {
|
|
11018
11477
|
throw new Error("Expected an array of associated playlists");
|
|
11019
11478
|
}
|
|
11479
|
+
const selectedStreams = [];
|
|
11020
11480
|
for (const stream of streams) {
|
|
11481
|
+
if (stream.isAudio && skipAudioTracks) {
|
|
11482
|
+
continue;
|
|
11483
|
+
}
|
|
11021
11484
|
if (!playlists.find((playlist) => playlist.src === stream.src)) {
|
|
11022
11485
|
throw new Error(`The associated playlist ${JSON.stringify(streams)} cannot be selected because it was not in the list of selectable playlists`);
|
|
11023
11486
|
}
|
|
11487
|
+
selectedStreams.push(stream);
|
|
11024
11488
|
}
|
|
11025
|
-
return
|
|
11489
|
+
return selectedStreams;
|
|
11026
11490
|
};
|
|
11027
11491
|
var defaultSelectM3uAssociatedPlaylists = ({ associatedPlaylists }) => {
|
|
11028
11492
|
if (associatedPlaylists.length === 1) {
|
|
@@ -11056,7 +11520,9 @@ var afterManifestFetch = async ({
|
|
|
11056
11520
|
selectM3uStreamFn,
|
|
11057
11521
|
logLevel,
|
|
11058
11522
|
selectAssociatedPlaylistsFn,
|
|
11059
|
-
readerInterface
|
|
11523
|
+
readerInterface,
|
|
11524
|
+
onAudioTrack,
|
|
11525
|
+
canSkipTracks
|
|
11060
11526
|
}) => {
|
|
11061
11527
|
const independentSegments = isIndependentSegments(structure);
|
|
11062
11528
|
if (!independentSegments) {
|
|
@@ -11081,9 +11547,11 @@ var afterManifestFetch = async ({
|
|
|
11081
11547
|
type: "selected-stream",
|
|
11082
11548
|
stream: selectedPlaylist
|
|
11083
11549
|
});
|
|
11550
|
+
const skipAudioTracks = onAudioTrack === null && canSkipTracks.doFieldsNeedTracks() === false;
|
|
11084
11551
|
const associatedPlaylists = await selectAssociatedPlaylists({
|
|
11085
11552
|
playlists: selectedPlaylist.associatedPlaylists,
|
|
11086
|
-
fn: selectAssociatedPlaylistsFn
|
|
11553
|
+
fn: selectAssociatedPlaylistsFn,
|
|
11554
|
+
skipAudioTracks
|
|
11087
11555
|
});
|
|
11088
11556
|
m3uState.setAssociatedPlaylists(associatedPlaylists);
|
|
11089
11557
|
const playlistUrls = [
|
|
@@ -11160,10 +11628,22 @@ var getLengthAndReader = async ({
|
|
|
11160
11628
|
if (requestedWithoutRange || canLiveWithoutContentLength && contentLength === null) {
|
|
11161
11629
|
const buffer = await res.arrayBuffer();
|
|
11162
11630
|
const encoded = new Uint8Array(buffer);
|
|
11631
|
+
let streamCancelled = false;
|
|
11163
11632
|
const stream = new ReadableStream({
|
|
11164
11633
|
start(controller) {
|
|
11165
|
-
|
|
11166
|
-
|
|
11634
|
+
if (ownController.signal.aborted) {
|
|
11635
|
+
return;
|
|
11636
|
+
}
|
|
11637
|
+
if (streamCancelled) {
|
|
11638
|
+
return;
|
|
11639
|
+
}
|
|
11640
|
+
try {
|
|
11641
|
+
controller.enqueue(encoded);
|
|
11642
|
+
controller.close();
|
|
11643
|
+
} catch {}
|
|
11644
|
+
},
|
|
11645
|
+
cancel() {
|
|
11646
|
+
streamCancelled = true;
|
|
11167
11647
|
}
|
|
11168
11648
|
});
|
|
11169
11649
|
return {
|
|
@@ -11239,14 +11719,11 @@ var validateContentRangeAndDetectIfSupported = ({
|
|
|
11239
11719
|
}
|
|
11240
11720
|
return { supportsContentRange: true };
|
|
11241
11721
|
};
|
|
11242
|
-
var
|
|
11243
|
-
src,
|
|
11722
|
+
var makeFetchRequest = async ({
|
|
11244
11723
|
range: range2,
|
|
11724
|
+
src,
|
|
11245
11725
|
controller
|
|
11246
11726
|
}) => {
|
|
11247
|
-
if (typeof src !== "string" && src instanceof URL === false) {
|
|
11248
|
-
throw new Error("src must be a string when using `fetchReader`");
|
|
11249
|
-
}
|
|
11250
11727
|
const resolvedUrl = resolveUrl(src);
|
|
11251
11728
|
const resolvedUrlString = resolvedUrl.toString();
|
|
11252
11729
|
if (!resolvedUrlString.startsWith("https://") && !resolvedUrlString.startsWith("blob:") && !resolvedUrlString.startsWith("http://")) {
|
|
@@ -11275,21 +11752,83 @@ var fetchReadContent = async ({
|
|
|
11275
11752
|
parsedContentRange,
|
|
11276
11753
|
statusCode: res.status
|
|
11277
11754
|
});
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11755
|
+
if (controller) {
|
|
11756
|
+
controller._internals.signal.addEventListener("abort", () => {
|
|
11757
|
+
ownController.abort(new MediaParserAbortError("Aborted by user"));
|
|
11758
|
+
}, { once: true });
|
|
11759
|
+
}
|
|
11281
11760
|
if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
|
|
11282
|
-
throw new Error(`Server returned status code ${res.status} for ${
|
|
11761
|
+
throw new Error(`Server returned status code ${res.status} for ${resolvedUrl} and range ${requestedRange}`);
|
|
11762
|
+
}
|
|
11763
|
+
const contentDisposition = res.headers.get("content-disposition");
|
|
11764
|
+
const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
|
|
11765
|
+
const { contentLength, needsContentRange, reader } = await getLengthAndReader({
|
|
11766
|
+
canLiveWithoutContentLength,
|
|
11767
|
+
res,
|
|
11768
|
+
ownController,
|
|
11769
|
+
requestedWithoutRange: requestWithoutRange
|
|
11770
|
+
});
|
|
11771
|
+
const contentType = res.headers.get("content-type");
|
|
11772
|
+
return {
|
|
11773
|
+
contentLength,
|
|
11774
|
+
needsContentRange,
|
|
11775
|
+
reader,
|
|
11776
|
+
name,
|
|
11777
|
+
contentType,
|
|
11778
|
+
supportsContentRange
|
|
11779
|
+
};
|
|
11780
|
+
};
|
|
11781
|
+
var cacheKey = ({
|
|
11782
|
+
src,
|
|
11783
|
+
range: range2
|
|
11784
|
+
}) => {
|
|
11785
|
+
return `${src}-${JSON.stringify(range2)}`;
|
|
11786
|
+
};
|
|
11787
|
+
var makeFetchRequestOrGetCached = ({
|
|
11788
|
+
range: range2,
|
|
11789
|
+
src,
|
|
11790
|
+
controller,
|
|
11791
|
+
logLevel,
|
|
11792
|
+
prefetchCache
|
|
11793
|
+
}) => {
|
|
11794
|
+
const key = cacheKey({ src, range: range2 });
|
|
11795
|
+
const cached = prefetchCache.get(key);
|
|
11796
|
+
if (cached) {
|
|
11797
|
+
Log.verbose(logLevel, `Reading from preload cache for ${key}`);
|
|
11798
|
+
return cached;
|
|
11799
|
+
}
|
|
11800
|
+
Log.verbose(logLevel, `Fetching ${key}`);
|
|
11801
|
+
const result = makeFetchRequest({ range: range2, src, controller });
|
|
11802
|
+
prefetchCache.set(key, result);
|
|
11803
|
+
return result;
|
|
11804
|
+
};
|
|
11805
|
+
var fetchReadContent = async ({
|
|
11806
|
+
src,
|
|
11807
|
+
range: range2,
|
|
11808
|
+
controller,
|
|
11809
|
+
logLevel,
|
|
11810
|
+
prefetchCache
|
|
11811
|
+
}) => {
|
|
11812
|
+
if (typeof src !== "string" && src instanceof URL === false) {
|
|
11813
|
+
throw new Error("src must be a string when using `fetchReader`");
|
|
11283
11814
|
}
|
|
11284
|
-
const contentDisposition = res.headers.get("content-disposition");
|
|
11285
|
-
const name = contentDisposition?.match(/filename="([^"]+)"/)?.[1];
|
|
11286
11815
|
const fallbackName = src.toString().split("/").pop();
|
|
11287
|
-
const {
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11816
|
+
const {
|
|
11817
|
+
reader,
|
|
11818
|
+
contentLength,
|
|
11819
|
+
needsContentRange,
|
|
11820
|
+
name,
|
|
11821
|
+
supportsContentRange,
|
|
11822
|
+
contentType
|
|
11823
|
+
} = await makeFetchRequestOrGetCached({
|
|
11824
|
+
range: range2,
|
|
11825
|
+
src,
|
|
11826
|
+
controller,
|
|
11827
|
+
logLevel,
|
|
11828
|
+
prefetchCache
|
|
11292
11829
|
});
|
|
11830
|
+
const key = cacheKey({ src, range: range2 });
|
|
11831
|
+
prefetchCache.delete(key);
|
|
11293
11832
|
if (controller) {
|
|
11294
11833
|
controller._internals.signal.addEventListener("abort", () => {
|
|
11295
11834
|
reader.reader.cancel().catch(() => {});
|
|
@@ -11298,12 +11837,33 @@ var fetchReadContent = async ({
|
|
|
11298
11837
|
return {
|
|
11299
11838
|
reader,
|
|
11300
11839
|
contentLength,
|
|
11301
|
-
contentType
|
|
11840
|
+
contentType,
|
|
11302
11841
|
name: name ?? fallbackName,
|
|
11303
11842
|
supportsContentRange,
|
|
11304
11843
|
needsContentRange
|
|
11305
11844
|
};
|
|
11306
11845
|
};
|
|
11846
|
+
var fetchPreload = ({
|
|
11847
|
+
src,
|
|
11848
|
+
range: range2,
|
|
11849
|
+
logLevel,
|
|
11850
|
+
prefetchCache
|
|
11851
|
+
}) => {
|
|
11852
|
+
if (typeof src !== "string" && src instanceof URL === false) {
|
|
11853
|
+
throw new Error("src must be a string when using `fetchReader`");
|
|
11854
|
+
}
|
|
11855
|
+
const key = cacheKey({ src, range: range2 });
|
|
11856
|
+
if (prefetchCache.has(key)) {
|
|
11857
|
+
return prefetchCache.get(key);
|
|
11858
|
+
}
|
|
11859
|
+
makeFetchRequestOrGetCached({
|
|
11860
|
+
range: range2,
|
|
11861
|
+
src,
|
|
11862
|
+
controller: null,
|
|
11863
|
+
logLevel,
|
|
11864
|
+
prefetchCache
|
|
11865
|
+
});
|
|
11866
|
+
};
|
|
11307
11867
|
var fetchReadWholeAsText = async (src) => {
|
|
11308
11868
|
if (typeof src !== "string" && src instanceof URL === false) {
|
|
11309
11869
|
throw new Error("src must be a string when using `fetchReader`");
|
|
@@ -11390,6 +11950,12 @@ var webReader = {
|
|
|
11390
11950
|
return webFileReadWholeAsText(src);
|
|
11391
11951
|
}
|
|
11392
11952
|
return fetchReadWholeAsText(src);
|
|
11953
|
+
},
|
|
11954
|
+
preload: ({ range: range2, src, logLevel, prefetchCache }) => {
|
|
11955
|
+
if (src instanceof Blob) {
|
|
11956
|
+
return;
|
|
11957
|
+
}
|
|
11958
|
+
return fetchPreload({ range: range2, src, logLevel, prefetchCache });
|
|
11393
11959
|
}
|
|
11394
11960
|
};
|
|
11395
11961
|
// src/parse-media.ts
|
|
@@ -11433,7 +11999,7 @@ var parseMedia = (options) => {
|
|
|
11433
11999
|
controller: options.controller ?? undefined,
|
|
11434
12000
|
selectM3uStream: options.selectM3uStream ?? defaultSelectM3uStreamFn,
|
|
11435
12001
|
selectM3uAssociatedPlaylists: options.selectM3uAssociatedPlaylists ?? defaultSelectM3uAssociatedPlaylists,
|
|
11436
|
-
|
|
12002
|
+
m3uPlaylistContext: options.m3uPlaylistContext ?? null,
|
|
11437
12003
|
src: options.src,
|
|
11438
12004
|
mode: "query",
|
|
11439
12005
|
onDiscardedData: null,
|
|
@@ -11445,6 +12011,39 @@ var parseMedia = (options) => {
|
|
|
11445
12011
|
});
|
|
11446
12012
|
};
|
|
11447
12013
|
|
|
12014
|
+
// src/containers/m3u/first-sample-in-m3u-chunk.ts
|
|
12015
|
+
var considerSeekBasedOnChunk = async ({
|
|
12016
|
+
sample,
|
|
12017
|
+
parentController,
|
|
12018
|
+
childController,
|
|
12019
|
+
callback,
|
|
12020
|
+
m3uState,
|
|
12021
|
+
playlistUrl,
|
|
12022
|
+
subtractChunks,
|
|
12023
|
+
chunkIndex
|
|
12024
|
+
}) => {
|
|
12025
|
+
const pendingSeek = m3uState.getSeekToSecondsToProcess(playlistUrl);
|
|
12026
|
+
if (pendingSeek === null) {
|
|
12027
|
+
await callback(sample);
|
|
12028
|
+
return;
|
|
12029
|
+
}
|
|
12030
|
+
const timestamp = Math.min(sample.dts / sample.timescale, sample.cts / sample.timescale);
|
|
12031
|
+
if (timestamp > pendingSeek.targetTime && chunkIndex !== null && chunkIndex > 0) {
|
|
12032
|
+
m3uState.setNextSeekShouldSubtractChunks(playlistUrl, subtractChunks + 1);
|
|
12033
|
+
parentController.seek({
|
|
12034
|
+
type: "keyframe-before-time",
|
|
12035
|
+
timeInSeconds: pendingSeek.targetTime
|
|
12036
|
+
});
|
|
12037
|
+
return;
|
|
12038
|
+
}
|
|
12039
|
+
childController.seek({
|
|
12040
|
+
type: "keyframe-before-time",
|
|
12041
|
+
timeInSeconds: pendingSeek.targetTime
|
|
12042
|
+
});
|
|
12043
|
+
m3uState.setNextSeekShouldSubtractChunks(playlistUrl, 0);
|
|
12044
|
+
m3uState.setSeekToSecondsToProcess(playlistUrl, null);
|
|
12045
|
+
};
|
|
12046
|
+
|
|
11448
12047
|
// src/containers/m3u/get-chunks.ts
|
|
11449
12048
|
var getChunks = (playlist) => {
|
|
11450
12049
|
const chunks = [];
|
|
@@ -11467,122 +12066,277 @@ var getChunks = (playlist) => {
|
|
|
11467
12066
|
return chunks;
|
|
11468
12067
|
};
|
|
11469
12068
|
|
|
11470
|
-
// src/containers/m3u/
|
|
11471
|
-
var
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
12069
|
+
// src/containers/m3u/seek/get-chunk-to-seek-to.ts
|
|
12070
|
+
var getChunkToSeekTo = ({
|
|
12071
|
+
chunks,
|
|
12072
|
+
seekToSecondsToProcess
|
|
12073
|
+
}) => {
|
|
12074
|
+
let duration2 = 0;
|
|
12075
|
+
for (let i = 0;i < chunks.length; i++) {
|
|
12076
|
+
if (duration2 >= seekToSecondsToProcess) {
|
|
12077
|
+
return Math.max(0, i - 1);
|
|
12078
|
+
}
|
|
12079
|
+
duration2 += chunks[i].duration;
|
|
12080
|
+
}
|
|
12081
|
+
return Math.max(0, chunks.length - 1);
|
|
12082
|
+
};
|
|
12083
|
+
|
|
12084
|
+
// src/containers/m3u/process-m3u-chunk.ts
|
|
12085
|
+
var processM3uChunk = ({
|
|
11477
12086
|
playlistUrl,
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
12087
|
+
state,
|
|
12088
|
+
structure,
|
|
12089
|
+
audioDone,
|
|
12090
|
+
videoDone
|
|
11482
12091
|
}) => {
|
|
11483
|
-
const
|
|
11484
|
-
const
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
const
|
|
11491
|
-
|
|
11492
|
-
|
|
11493
|
-
|
|
12092
|
+
const { promise, reject, resolve } = withResolvers();
|
|
12093
|
+
const onGlobalAudioTrack = audioDone ? null : async (track) => {
|
|
12094
|
+
const existingTracks = state.callbacks.tracks.getTracks();
|
|
12095
|
+
let { trackId } = track;
|
|
12096
|
+
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
12097
|
+
trackId++;
|
|
12098
|
+
}
|
|
12099
|
+
const onAudioSample = await registerAudioTrack({
|
|
12100
|
+
container: "m3u8",
|
|
12101
|
+
track: {
|
|
12102
|
+
...track,
|
|
12103
|
+
trackId
|
|
12104
|
+
},
|
|
12105
|
+
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
12106
|
+
tracks: state.callbacks.tracks,
|
|
12107
|
+
logLevel: state.logLevel,
|
|
12108
|
+
onAudioTrack: state.onAudioTrack
|
|
11494
12109
|
});
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
return promise;
|
|
11503
|
-
},
|
|
11504
|
-
abort() {
|
|
11505
|
-
childController.abort();
|
|
11506
|
-
}
|
|
11507
|
-
};
|
|
12110
|
+
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
12111
|
+
if (onAudioSample === null) {
|
|
12112
|
+
return null;
|
|
12113
|
+
}
|
|
12114
|
+
state.m3u.sampleSorter.addAudioStreamToConsider(playlistUrl, onAudioSample);
|
|
12115
|
+
return async (sample) => {
|
|
12116
|
+
await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
|
|
11508
12117
|
};
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
const
|
|
11512
|
-
|
|
11513
|
-
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11519
|
-
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
11527
|
-
|
|
11528
|
-
|
|
11529
|
-
|
|
12118
|
+
};
|
|
12119
|
+
const onGlobalVideoTrack = videoDone ? null : async (track) => {
|
|
12120
|
+
const existingTracks = state.callbacks.tracks.getTracks();
|
|
12121
|
+
let { trackId } = track;
|
|
12122
|
+
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
12123
|
+
trackId++;
|
|
12124
|
+
}
|
|
12125
|
+
const onVideoSample = await registerVideoTrack({
|
|
12126
|
+
container: "m3u8",
|
|
12127
|
+
track: {
|
|
12128
|
+
...track,
|
|
12129
|
+
trackId
|
|
12130
|
+
},
|
|
12131
|
+
logLevel: state.logLevel,
|
|
12132
|
+
onVideoTrack: state.onVideoTrack,
|
|
12133
|
+
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
12134
|
+
tracks: state.callbacks.tracks
|
|
12135
|
+
});
|
|
12136
|
+
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
12137
|
+
if (onVideoSample === null) {
|
|
12138
|
+
return null;
|
|
12139
|
+
}
|
|
12140
|
+
state.m3u.sampleSorter.addVideoStreamToConsider(playlistUrl, onVideoSample);
|
|
12141
|
+
return async (sample) => {
|
|
12142
|
+
await state.m3u.sampleSorter.addVideoSample(playlistUrl, sample);
|
|
12143
|
+
};
|
|
12144
|
+
};
|
|
12145
|
+
const pausableIterator = async () => {
|
|
12146
|
+
const playlist = getPlaylist(structure, playlistUrl);
|
|
12147
|
+
const chunks = getChunks(playlist);
|
|
12148
|
+
const seekToSecondsToProcess = state.m3u.getSeekToSecondsToProcess(playlistUrl);
|
|
12149
|
+
const chunksToSubtract = state.m3u.getNextSeekShouldSubtractChunks(playlistUrl);
|
|
12150
|
+
let chunkIndex = null;
|
|
12151
|
+
if (seekToSecondsToProcess !== null) {
|
|
12152
|
+
chunkIndex = Math.max(0, getChunkToSeekTo({
|
|
12153
|
+
chunks,
|
|
12154
|
+
seekToSecondsToProcess: seekToSecondsToProcess.targetTime
|
|
12155
|
+
}) - chunksToSubtract);
|
|
12156
|
+
}
|
|
12157
|
+
const currentPromise = {
|
|
12158
|
+
resolver: () => {
|
|
12159
|
+
return;
|
|
12160
|
+
},
|
|
12161
|
+
rejector: reject
|
|
12162
|
+
};
|
|
12163
|
+
const requiresHeaderToBeFetched = chunks[0].isHeader;
|
|
12164
|
+
for (const chunk of chunks) {
|
|
12165
|
+
const mp4HeaderSegment = state.m3u.getMp4HeaderSegment(playlistUrl);
|
|
12166
|
+
if (requiresHeaderToBeFetched && mp4HeaderSegment && chunk.isHeader) {
|
|
12167
|
+
continue;
|
|
12168
|
+
}
|
|
12169
|
+
if (chunkIndex !== null && chunks.indexOf(chunk) < chunkIndex && !chunk.isHeader) {
|
|
12170
|
+
continue;
|
|
12171
|
+
}
|
|
12172
|
+
currentPromise.resolver = (newRun) => {
|
|
12173
|
+
state.m3u.setM3uStreamRun(playlistUrl, newRun);
|
|
12174
|
+
resolve();
|
|
12175
|
+
};
|
|
12176
|
+
currentPromise.rejector = reject;
|
|
12177
|
+
const childController = mediaParserController();
|
|
12178
|
+
const forwarded = forwardMediaParserControllerPauseResume({
|
|
12179
|
+
childController,
|
|
12180
|
+
parentController: state.controller
|
|
12181
|
+
});
|
|
12182
|
+
const nextChunk = chunks[chunks.indexOf(chunk) + 1];
|
|
12183
|
+
if (nextChunk) {
|
|
12184
|
+
const nextChunkSource = state.readerInterface.createAdjacentFileSource(nextChunk.url, playlistUrl);
|
|
12185
|
+
state.readerInterface.preload({
|
|
12186
|
+
logLevel: state.logLevel,
|
|
12187
|
+
range: null,
|
|
12188
|
+
src: nextChunkSource,
|
|
12189
|
+
prefetchCache: state.prefetchCache
|
|
12190
|
+
});
|
|
12191
|
+
}
|
|
12192
|
+
const makeContinuationFn = () => {
|
|
12193
|
+
return {
|
|
12194
|
+
continue() {
|
|
12195
|
+
const resolver = withResolvers();
|
|
12196
|
+
currentPromise.resolver = resolver.resolve;
|
|
12197
|
+
currentPromise.rejector = resolver.reject;
|
|
12198
|
+
childController.resume();
|
|
12199
|
+
return resolver.promise;
|
|
12200
|
+
},
|
|
12201
|
+
abort() {
|
|
12202
|
+
childController.abort();
|
|
11530
12203
|
}
|
|
11531
|
-
}
|
|
11532
|
-
|
|
11533
|
-
|
|
11534
|
-
|
|
11535
|
-
|
|
11536
|
-
|
|
11537
|
-
|
|
12204
|
+
};
|
|
12205
|
+
};
|
|
12206
|
+
const isLastChunk = chunk === chunks[chunks.length - 1];
|
|
12207
|
+
await childController._internals.checkForAbortAndPause();
|
|
12208
|
+
const src = state.readerInterface.createAdjacentFileSource(chunk.url, playlistUrl);
|
|
12209
|
+
try {
|
|
12210
|
+
const data = await parseMedia({
|
|
12211
|
+
src,
|
|
12212
|
+
acknowledgeRemotionLicense: true,
|
|
12213
|
+
logLevel: state.logLevel,
|
|
12214
|
+
controller: childController,
|
|
12215
|
+
progressIntervalInMs: 0,
|
|
12216
|
+
onParseProgress: () => {
|
|
12217
|
+
childController.pause();
|
|
12218
|
+
currentPromise.resolver(makeContinuationFn());
|
|
12219
|
+
},
|
|
12220
|
+
fields: chunk.isHeader ? { structure: true } : undefined,
|
|
12221
|
+
onTracks: () => {
|
|
12222
|
+
if (!state.m3u.hasEmittedDoneWithTracks(playlistUrl)) {
|
|
12223
|
+
state.m3u.setHasEmittedDoneWithTracks(playlistUrl);
|
|
12224
|
+
const allDone = state.m3u.setTracksDone(playlistUrl);
|
|
12225
|
+
if (allDone) {
|
|
12226
|
+
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
12227
|
+
}
|
|
12228
|
+
return null;
|
|
12229
|
+
}
|
|
12230
|
+
},
|
|
12231
|
+
onAudioTrack: onGlobalAudioTrack === null ? null : async ({ track }) => {
|
|
12232
|
+
const callbackOrFalse = state.m3u.hasEmittedAudioTrack(playlistUrl);
|
|
12233
|
+
if (callbackOrFalse === false) {
|
|
12234
|
+
const callback = await onGlobalAudioTrack(track);
|
|
12235
|
+
if (!callback) {
|
|
12236
|
+
state.m3u.setHasEmittedAudioTrack(playlistUrl, null);
|
|
12237
|
+
return null;
|
|
12238
|
+
}
|
|
12239
|
+
state.m3u.setHasEmittedAudioTrack(playlistUrl, callback);
|
|
12240
|
+
return async (sample) => {
|
|
12241
|
+
await considerSeekBasedOnChunk({
|
|
12242
|
+
sample,
|
|
12243
|
+
callback,
|
|
12244
|
+
parentController: state.controller,
|
|
12245
|
+
childController,
|
|
12246
|
+
m3uState: state.m3u,
|
|
12247
|
+
playlistUrl,
|
|
12248
|
+
subtractChunks: chunksToSubtract,
|
|
12249
|
+
chunkIndex
|
|
12250
|
+
});
|
|
12251
|
+
};
|
|
12252
|
+
}
|
|
12253
|
+
if (callbackOrFalse === null) {
|
|
11538
12254
|
return null;
|
|
11539
12255
|
}
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
|
|
12256
|
+
return async (sample) => {
|
|
12257
|
+
await considerSeekBasedOnChunk({
|
|
12258
|
+
sample,
|
|
12259
|
+
m3uState: state.m3u,
|
|
12260
|
+
playlistUrl,
|
|
12261
|
+
callback: callbackOrFalse,
|
|
12262
|
+
parentController: state.controller,
|
|
12263
|
+
childController,
|
|
12264
|
+
subtractChunks: chunksToSubtract,
|
|
12265
|
+
chunkIndex
|
|
12266
|
+
});
|
|
11543
12267
|
};
|
|
11544
|
-
}
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11552
|
-
|
|
11553
|
-
|
|
11554
|
-
|
|
11555
|
-
|
|
12268
|
+
},
|
|
12269
|
+
onVideoTrack: onGlobalVideoTrack === null ? null : async ({ track }) => {
|
|
12270
|
+
const callbackOrFalse = state.m3u.hasEmittedVideoTrack(playlistUrl);
|
|
12271
|
+
if (callbackOrFalse === false) {
|
|
12272
|
+
const callback = await onGlobalVideoTrack({
|
|
12273
|
+
...track,
|
|
12274
|
+
m3uStreamFormat: chunk.isHeader || mp4HeaderSegment ? "mp4" : "ts"
|
|
12275
|
+
});
|
|
12276
|
+
if (!callback) {
|
|
12277
|
+
state.m3u.setHasEmittedVideoTrack(playlistUrl, null);
|
|
12278
|
+
return null;
|
|
12279
|
+
}
|
|
12280
|
+
state.m3u.setHasEmittedVideoTrack(playlistUrl, callback);
|
|
12281
|
+
return async (sample) => {
|
|
12282
|
+
await considerSeekBasedOnChunk({
|
|
12283
|
+
sample,
|
|
12284
|
+
m3uState: state.m3u,
|
|
12285
|
+
playlistUrl,
|
|
12286
|
+
callback,
|
|
12287
|
+
parentController: state.controller,
|
|
12288
|
+
childController,
|
|
12289
|
+
subtractChunks: chunksToSubtract,
|
|
12290
|
+
chunkIndex
|
|
12291
|
+
});
|
|
12292
|
+
};
|
|
12293
|
+
}
|
|
12294
|
+
if (callbackOrFalse === null) {
|
|
11556
12295
|
return null;
|
|
11557
12296
|
}
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
12297
|
+
return async (sample) => {
|
|
12298
|
+
await considerSeekBasedOnChunk({
|
|
12299
|
+
sample,
|
|
12300
|
+
m3uState: state.m3u,
|
|
12301
|
+
playlistUrl,
|
|
12302
|
+
callback: callbackOrFalse,
|
|
12303
|
+
parentController: state.controller,
|
|
12304
|
+
childController,
|
|
12305
|
+
subtractChunks: chunksToSubtract,
|
|
12306
|
+
chunkIndex
|
|
12307
|
+
});
|
|
11561
12308
|
};
|
|
12309
|
+
},
|
|
12310
|
+
reader: state.readerInterface,
|
|
12311
|
+
makeSamplesStartAtZero: false,
|
|
12312
|
+
m3uPlaylistContext: {
|
|
12313
|
+
mp4HeaderSegment,
|
|
12314
|
+
isLastChunkInPlaylist: isLastChunk
|
|
11562
12315
|
}
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
if (chunk.isHeader) {
|
|
11570
|
-
if (data.structure.type !== "iso-base-media") {
|
|
11571
|
-
throw new Error("Expected an mp4 file");
|
|
12316
|
+
});
|
|
12317
|
+
if (chunk.isHeader) {
|
|
12318
|
+
if (data.structure.type !== "iso-base-media") {
|
|
12319
|
+
throw new Error("Expected an mp4 file");
|
|
12320
|
+
}
|
|
12321
|
+
state.m3u.setMp4HeaderSegment(playlistUrl, data.structure);
|
|
11572
12322
|
}
|
|
11573
|
-
|
|
12323
|
+
} catch (e) {
|
|
12324
|
+
currentPromise.rejector(e);
|
|
12325
|
+
throw e;
|
|
12326
|
+
}
|
|
12327
|
+
forwarded.cleanup();
|
|
12328
|
+
if (!isLastChunk) {
|
|
12329
|
+
childController.pause();
|
|
12330
|
+
currentPromise.resolver(makeContinuationFn());
|
|
11574
12331
|
}
|
|
11575
|
-
} catch (e) {
|
|
11576
|
-
rejector(e);
|
|
11577
|
-
throw e;
|
|
11578
|
-
}
|
|
11579
|
-
forwarded.cleanup();
|
|
11580
|
-
if (!isLastChunk) {
|
|
11581
|
-
childController.pause();
|
|
11582
|
-
resolver(makeContinuationFn());
|
|
11583
12332
|
}
|
|
11584
|
-
|
|
11585
|
-
|
|
12333
|
+
currentPromise.resolver(null);
|
|
12334
|
+
};
|
|
12335
|
+
const run = pausableIterator();
|
|
12336
|
+
run.catch((err) => {
|
|
12337
|
+
reject(err);
|
|
12338
|
+
});
|
|
12339
|
+
return promise;
|
|
11586
12340
|
};
|
|
11587
12341
|
|
|
11588
12342
|
// src/containers/m3u/run-over-m3u.ts
|
|
@@ -11613,80 +12367,12 @@ var runOverM3u = async ({
|
|
|
11613
12367
|
return;
|
|
11614
12368
|
}
|
|
11615
12369
|
Log.trace(logLevel, "Starting new M3U parsing process for", playlistUrl);
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
resolve();
|
|
11623
|
-
},
|
|
11624
|
-
logLevel: state.logLevel,
|
|
11625
|
-
onDoneWithTracks() {
|
|
11626
|
-
const allDone = state.m3u.setTracksDone(playlistUrl);
|
|
11627
|
-
if (allDone) {
|
|
11628
|
-
state.callbacks.tracks.setIsDone(state.logLevel);
|
|
11629
|
-
}
|
|
11630
|
-
},
|
|
11631
|
-
onAudioTrack: audioDone ? null : async (track) => {
|
|
11632
|
-
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11633
|
-
let { trackId } = track;
|
|
11634
|
-
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11635
|
-
trackId++;
|
|
11636
|
-
}
|
|
11637
|
-
const onAudioSample = await registerAudioTrack({
|
|
11638
|
-
container: "m3u8",
|
|
11639
|
-
track: {
|
|
11640
|
-
...track,
|
|
11641
|
-
trackId
|
|
11642
|
-
},
|
|
11643
|
-
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
11644
|
-
tracks: state.callbacks.tracks,
|
|
11645
|
-
logLevel: state.logLevel,
|
|
11646
|
-
onAudioTrack: state.onAudioTrack
|
|
11647
|
-
});
|
|
11648
|
-
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11649
|
-
if (onAudioSample === null) {
|
|
11650
|
-
return null;
|
|
11651
|
-
}
|
|
11652
|
-
state.m3u.sampleSorter.addAudioStreamToConsider(playlistUrl, onAudioSample);
|
|
11653
|
-
return async (sample) => {
|
|
11654
|
-
await state.m3u.sampleSorter.addAudioSample(playlistUrl, sample);
|
|
11655
|
-
};
|
|
11656
|
-
},
|
|
11657
|
-
onVideoTrack: videoDone ? null : async (track) => {
|
|
11658
|
-
const existingTracks = state.callbacks.tracks.getTracks();
|
|
11659
|
-
let { trackId } = track;
|
|
11660
|
-
while (existingTracks.find((t) => t.trackId === trackId)) {
|
|
11661
|
-
trackId++;
|
|
11662
|
-
}
|
|
11663
|
-
const onVideoSample = await registerVideoTrack({
|
|
11664
|
-
container: "m3u8",
|
|
11665
|
-
track: {
|
|
11666
|
-
...track,
|
|
11667
|
-
trackId
|
|
11668
|
-
},
|
|
11669
|
-
logLevel: state.logLevel,
|
|
11670
|
-
onVideoTrack: state.onVideoTrack,
|
|
11671
|
-
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
11672
|
-
tracks: state.callbacks.tracks
|
|
11673
|
-
});
|
|
11674
|
-
state.m3u.sampleSorter.addToStreamWithTrack(playlistUrl);
|
|
11675
|
-
if (onVideoSample === null) {
|
|
11676
|
-
return null;
|
|
11677
|
-
}
|
|
11678
|
-
state.m3u.sampleSorter.addVideoStreamToConsider(playlistUrl, onVideoSample);
|
|
11679
|
-
return async (sample) => {
|
|
11680
|
-
await state.m3u.sampleSorter.addVideoSample(playlistUrl, sample);
|
|
11681
|
-
};
|
|
11682
|
-
},
|
|
11683
|
-
m3uState: state.m3u,
|
|
11684
|
-
parentController: state.controller,
|
|
11685
|
-
readerInterface: state.readerInterface
|
|
11686
|
-
});
|
|
11687
|
-
run.catch((err) => {
|
|
11688
|
-
reject(err);
|
|
11689
|
-
});
|
|
12370
|
+
await processM3uChunk({
|
|
12371
|
+
playlistUrl,
|
|
12372
|
+
state,
|
|
12373
|
+
structure,
|
|
12374
|
+
audioDone,
|
|
12375
|
+
videoDone
|
|
11690
12376
|
});
|
|
11691
12377
|
};
|
|
11692
12378
|
|
|
@@ -11708,6 +12394,10 @@ var parseM3u = async ({ state }) => {
|
|
|
11708
12394
|
if (typeof state.src !== "string" && !(state.src instanceof URL)) {
|
|
11709
12395
|
throw new Error("Expected src to be a string");
|
|
11710
12396
|
}
|
|
12397
|
+
state.mediaSection.addMediaSection({
|
|
12398
|
+
start: 0,
|
|
12399
|
+
size: state.contentLength + 1
|
|
12400
|
+
});
|
|
11711
12401
|
await afterManifestFetch({
|
|
11712
12402
|
structure,
|
|
11713
12403
|
m3uState: state.m3u,
|
|
@@ -11715,7 +12405,9 @@ var parseM3u = async ({ state }) => {
|
|
|
11715
12405
|
selectM3uStreamFn: state.selectM3uStreamFn,
|
|
11716
12406
|
logLevel: state.logLevel,
|
|
11717
12407
|
selectAssociatedPlaylistsFn: state.selectM3uAssociatedPlaylistsFn,
|
|
11718
|
-
readerInterface: state.readerInterface
|
|
12408
|
+
readerInterface: state.readerInterface,
|
|
12409
|
+
onAudioTrack: state.onAudioTrack,
|
|
12410
|
+
canSkipTracks: state.callbacks.canSkipTracksState
|
|
11719
12411
|
});
|
|
11720
12412
|
return null;
|
|
11721
12413
|
}
|
|
@@ -14045,9 +14737,9 @@ var initVideo = async ({ state }) => {
|
|
|
14045
14737
|
});
|
|
14046
14738
|
return;
|
|
14047
14739
|
}
|
|
14048
|
-
if (state.mp4HeaderSegment) {
|
|
14740
|
+
if (state.m3uPlaylistContext?.mp4HeaderSegment) {
|
|
14049
14741
|
Log.verbose(state.logLevel, "Detected ISO Base Media segment");
|
|
14050
|
-
const moovAtom = getMoovFromFromIsoStructure(state.mp4HeaderSegment);
|
|
14742
|
+
const moovAtom = getMoovFromFromIsoStructure(state.m3uPlaylistContext.mp4HeaderSegment);
|
|
14051
14743
|
if (!moovAtom) {
|
|
14052
14744
|
throw new Error("No moov box found");
|
|
14053
14745
|
}
|
|
@@ -14270,19 +14962,33 @@ var parseLoop = async ({
|
|
|
14270
14962
|
try {
|
|
14271
14963
|
await triggerInfoEmit(state);
|
|
14272
14964
|
await state.controller._internals.checkForAbortAndPause();
|
|
14273
|
-
const
|
|
14965
|
+
const result = await runParseIteration({
|
|
14274
14966
|
state
|
|
14275
14967
|
});
|
|
14276
|
-
if (
|
|
14277
|
-
|
|
14278
|
-
|
|
14279
|
-
|
|
14968
|
+
if (result !== null && result.action === "fetch-more-data") {
|
|
14969
|
+
Log.verbose(state.logLevel, `Need to fetch ${result.bytesNeeded} more bytes before we can continue`);
|
|
14970
|
+
const startBytesRemaining = state.iterator.bytesRemaining();
|
|
14971
|
+
while (true) {
|
|
14972
|
+
const done = await fetchMoreData(state);
|
|
14973
|
+
if (done) {
|
|
14974
|
+
break;
|
|
14975
|
+
}
|
|
14976
|
+
if (state.iterator.bytesRemaining() - startBytesRemaining >= result.bytesNeeded) {
|
|
14977
|
+
break;
|
|
14978
|
+
}
|
|
14979
|
+
}
|
|
14980
|
+
continue;
|
|
14981
|
+
}
|
|
14982
|
+
if (result !== null && result.action === "skip") {
|
|
14983
|
+
state.increaseSkippedBytes(result.skipTo - state.iterator.counter.getOffset());
|
|
14984
|
+
if (result.skipTo === state.contentLength) {
|
|
14985
|
+
state.iterator.discard(result.skipTo - state.iterator.counter.getOffset());
|
|
14280
14986
|
Log.verbose(state.logLevel, "Skipped to end of file, not fetching.");
|
|
14281
14987
|
break;
|
|
14282
14988
|
}
|
|
14283
14989
|
const seekStart = Date.now();
|
|
14284
14990
|
await performSeek({
|
|
14285
|
-
seekTo:
|
|
14991
|
+
seekTo: result.skipTo,
|
|
14286
14992
|
userInitiated: false,
|
|
14287
14993
|
controller: state.controller,
|
|
14288
14994
|
mediaSection: state.mediaSection,
|
|
@@ -14295,7 +15001,8 @@ var parseLoop = async ({
|
|
|
14295
15001
|
readerInterface: state.readerInterface,
|
|
14296
15002
|
fields: state.fields,
|
|
14297
15003
|
src: state.src,
|
|
14298
|
-
discardReadBytes: state.discardReadBytes
|
|
15004
|
+
discardReadBytes: state.discardReadBytes,
|
|
15005
|
+
prefetchCache: state.prefetchCache
|
|
14299
15006
|
});
|
|
14300
15007
|
state.timings.timeSeeking += Date.now() - seekStart;
|
|
14301
15008
|
}
|
|
@@ -14402,6 +15109,9 @@ var setSeekingHints = ({
|
|
|
14402
15109
|
setSeekingHintsForAac();
|
|
14403
15110
|
return;
|
|
14404
15111
|
}
|
|
15112
|
+
if (hints.type === "m3u8-seeking-hints") {
|
|
15113
|
+
return;
|
|
15114
|
+
}
|
|
14405
15115
|
throw new Error(`Unknown seeking hints type: ${hints}`);
|
|
14406
15116
|
};
|
|
14407
15117
|
|
|
@@ -14557,12 +15267,16 @@ var getMfraAtom = async ({
|
|
|
14557
15267
|
contentLength,
|
|
14558
15268
|
readerInterface,
|
|
14559
15269
|
controller,
|
|
14560
|
-
parentSize
|
|
15270
|
+
parentSize,
|
|
15271
|
+
logLevel,
|
|
15272
|
+
prefetchCache
|
|
14561
15273
|
}) => {
|
|
14562
15274
|
const result = await readerInterface.read({
|
|
14563
15275
|
controller,
|
|
14564
15276
|
range: [contentLength - parentSize, contentLength - 1],
|
|
14565
|
-
src
|
|
15277
|
+
src,
|
|
15278
|
+
logLevel,
|
|
15279
|
+
prefetchCache
|
|
14566
15280
|
});
|
|
14567
15281
|
const iterator = getArrayBufferIterator(new Uint8Array, parentSize);
|
|
14568
15282
|
while (true) {
|
|
@@ -14582,12 +15296,16 @@ var getMfroAtom = async ({
|
|
|
14582
15296
|
src,
|
|
14583
15297
|
contentLength,
|
|
14584
15298
|
readerInterface,
|
|
14585
|
-
controller
|
|
15299
|
+
controller,
|
|
15300
|
+
logLevel,
|
|
15301
|
+
prefetchCache
|
|
14586
15302
|
}) => {
|
|
14587
15303
|
const result = await readerInterface.read({
|
|
14588
15304
|
controller,
|
|
14589
15305
|
range: [contentLength - 16, contentLength - 1],
|
|
14590
|
-
src
|
|
15306
|
+
src,
|
|
15307
|
+
logLevel,
|
|
15308
|
+
prefetchCache
|
|
14591
15309
|
});
|
|
14592
15310
|
const { value } = await result.reader.reader.read();
|
|
14593
15311
|
if (!value) {
|
|
@@ -14622,13 +15340,16 @@ var getMfraSeekingBox = async ({
|
|
|
14622
15340
|
controller,
|
|
14623
15341
|
readerInterface,
|
|
14624
15342
|
src,
|
|
14625
|
-
logLevel
|
|
15343
|
+
logLevel,
|
|
15344
|
+
prefetchCache
|
|
14626
15345
|
}) => {
|
|
14627
15346
|
const parentSize = await getMfroAtom({
|
|
14628
15347
|
contentLength,
|
|
14629
15348
|
controller,
|
|
14630
15349
|
readerInterface,
|
|
14631
|
-
src
|
|
15350
|
+
src,
|
|
15351
|
+
logLevel,
|
|
15352
|
+
prefetchCache
|
|
14632
15353
|
});
|
|
14633
15354
|
if (!parentSize) {
|
|
14634
15355
|
return null;
|
|
@@ -14638,7 +15359,9 @@ var getMfraSeekingBox = async ({
|
|
|
14638
15359
|
controller,
|
|
14639
15360
|
readerInterface,
|
|
14640
15361
|
src,
|
|
14641
|
-
parentSize
|
|
15362
|
+
parentSize,
|
|
15363
|
+
logLevel,
|
|
15364
|
+
prefetchCache
|
|
14642
15365
|
});
|
|
14643
15366
|
mfraAtom.discard(8);
|
|
14644
15367
|
return getIsoBaseMediaChildren({
|
|
@@ -14656,7 +15379,8 @@ var lazyMfraLoad = ({
|
|
|
14656
15379
|
controller,
|
|
14657
15380
|
readerInterface,
|
|
14658
15381
|
src,
|
|
14659
|
-
logLevel
|
|
15382
|
+
logLevel,
|
|
15383
|
+
prefetchCache
|
|
14660
15384
|
}) => {
|
|
14661
15385
|
let prom = null;
|
|
14662
15386
|
let result = null;
|
|
@@ -14670,7 +15394,8 @@ var lazyMfraLoad = ({
|
|
|
14670
15394
|
controller,
|
|
14671
15395
|
readerInterface,
|
|
14672
15396
|
src,
|
|
14673
|
-
logLevel
|
|
15397
|
+
logLevel,
|
|
15398
|
+
prefetchCache
|
|
14674
15399
|
}).then((boxes) => {
|
|
14675
15400
|
Log.verbose(logLevel, "Lazily found mfra atom.");
|
|
14676
15401
|
result = boxes;
|
|
@@ -14711,7 +15436,8 @@ var isoBaseMediaState = ({
|
|
|
14711
15436
|
controller,
|
|
14712
15437
|
readerInterface,
|
|
14713
15438
|
src,
|
|
14714
|
-
logLevel
|
|
15439
|
+
logLevel,
|
|
15440
|
+
prefetchCache
|
|
14715
15441
|
}) => {
|
|
14716
15442
|
return {
|
|
14717
15443
|
flatSamples: cachedSamplePositionsState(),
|
|
@@ -14721,7 +15447,8 @@ var isoBaseMediaState = ({
|
|
|
14721
15447
|
controller,
|
|
14722
15448
|
readerInterface,
|
|
14723
15449
|
src,
|
|
14724
|
-
logLevel
|
|
15450
|
+
logLevel,
|
|
15451
|
+
prefetchCache
|
|
14725
15452
|
}),
|
|
14726
15453
|
moof: precomputedMoofState(),
|
|
14727
15454
|
tfra: precomputedTfraState()
|
|
@@ -14738,6 +15465,7 @@ var keyframesState = () => {
|
|
|
14738
15465
|
keyframes.push(keyframe);
|
|
14739
15466
|
};
|
|
14740
15467
|
const getKeyframes2 = () => {
|
|
15468
|
+
keyframes.sort((a, b) => a.positionInBytes - b.positionInBytes);
|
|
14741
15469
|
return keyframes;
|
|
14742
15470
|
};
|
|
14743
15471
|
const setFromSeekingHints = (keyframesFromHints) => {
|
|
@@ -14760,8 +15488,11 @@ var sampleSorter = ({
|
|
|
14760
15488
|
const streamsWithTracks = [];
|
|
14761
15489
|
const audioCallbacks = {};
|
|
14762
15490
|
const videoCallbacks = {};
|
|
14763
|
-
|
|
15491
|
+
let latestSample = {};
|
|
14764
15492
|
return {
|
|
15493
|
+
clearSamples: () => {
|
|
15494
|
+
latestSample = {};
|
|
15495
|
+
},
|
|
14765
15496
|
addToStreamWithTrack: (src) => {
|
|
14766
15497
|
streamsWithTracks.push(src);
|
|
14767
15498
|
},
|
|
@@ -14834,6 +15565,8 @@ var m3uState = (logLevel) => {
|
|
|
14834
15565
|
const hasEmittedAudioTrack = {};
|
|
14835
15566
|
const hasEmittedDoneWithTracks = {};
|
|
14836
15567
|
let hasFinishedManifest = false;
|
|
15568
|
+
const seekToSecondsToProcess = {};
|
|
15569
|
+
const nextSeekShouldSubtractChunks = {};
|
|
14837
15570
|
let readyToIterateOverM3u = false;
|
|
14838
15571
|
const allChunksProcessed = {};
|
|
14839
15572
|
const m3uStreamRuns = {};
|
|
@@ -14895,6 +15628,11 @@ var m3uState = (logLevel) => {
|
|
|
14895
15628
|
setAllChunksProcessed: (src) => {
|
|
14896
15629
|
allChunksProcessed[src] = true;
|
|
14897
15630
|
},
|
|
15631
|
+
clearAllChunksProcessed: () => {
|
|
15632
|
+
Object.keys(allChunksProcessed).forEach((key) => {
|
|
15633
|
+
delete allChunksProcessed[key];
|
|
15634
|
+
});
|
|
15635
|
+
},
|
|
14898
15636
|
getAllChunksProcessedForPlaylist,
|
|
14899
15637
|
getAllChunksProcessedOverall: () => {
|
|
14900
15638
|
if (!selectedMainPlaylist) {
|
|
@@ -14922,6 +15660,11 @@ var m3uState = (logLevel) => {
|
|
|
14922
15660
|
getTrackDone: (playlistUrl) => {
|
|
14923
15661
|
return tracksDone[playlistUrl];
|
|
14924
15662
|
},
|
|
15663
|
+
clearTracksDone: () => {
|
|
15664
|
+
Object.keys(tracksDone).forEach((key) => {
|
|
15665
|
+
delete tracksDone[key];
|
|
15666
|
+
});
|
|
15667
|
+
},
|
|
14925
15668
|
getM3uStreamRun: (playlistUrl) => m3uStreamRuns[playlistUrl] ?? null,
|
|
14926
15669
|
abortM3UStreamRuns: () => {
|
|
14927
15670
|
const values = Object.values(m3uStreamRuns);
|
|
@@ -14940,7 +15683,15 @@ var m3uState = (logLevel) => {
|
|
|
14940
15683
|
getSelectedPlaylists,
|
|
14941
15684
|
sampleSorter: sampleSorter({ logLevel, getAllChunksProcessedForPlaylist }),
|
|
14942
15685
|
setMp4HeaderSegment,
|
|
14943
|
-
getMp4HeaderSegment
|
|
15686
|
+
getMp4HeaderSegment,
|
|
15687
|
+
setSeekToSecondsToProcess: (playlistUrl, m3uSeek) => {
|
|
15688
|
+
seekToSecondsToProcess[playlistUrl] = m3uSeek;
|
|
15689
|
+
},
|
|
15690
|
+
getSeekToSecondsToProcess: (playlistUrl) => seekToSecondsToProcess[playlistUrl] ?? null,
|
|
15691
|
+
setNextSeekShouldSubtractChunks: (playlistUrl, chunks) => {
|
|
15692
|
+
nextSeekShouldSubtractChunks[playlistUrl] = chunks;
|
|
15693
|
+
},
|
|
15694
|
+
getNextSeekShouldSubtractChunks: (playlistUrl) => nextSeekShouldSubtractChunks[playlistUrl] ?? 0
|
|
14944
15695
|
};
|
|
14945
15696
|
};
|
|
14946
15697
|
|
|
@@ -14989,12 +15740,15 @@ var fetchWebmCues = async ({
|
|
|
14989
15740
|
readerInterface,
|
|
14990
15741
|
controller,
|
|
14991
15742
|
position,
|
|
14992
|
-
logLevel
|
|
15743
|
+
logLevel,
|
|
15744
|
+
prefetchCache
|
|
14993
15745
|
}) => {
|
|
14994
15746
|
const result = await readerInterface.read({
|
|
14995
15747
|
controller,
|
|
14996
15748
|
range: position,
|
|
14997
|
-
src
|
|
15749
|
+
src,
|
|
15750
|
+
logLevel,
|
|
15751
|
+
prefetchCache
|
|
14998
15752
|
});
|
|
14999
15753
|
const { value } = await result.reader.reader.read();
|
|
15000
15754
|
if (!value) {
|
|
@@ -15021,7 +15775,8 @@ var lazyCuesFetch = ({
|
|
|
15021
15775
|
controller,
|
|
15022
15776
|
logLevel,
|
|
15023
15777
|
readerInterface,
|
|
15024
|
-
src
|
|
15778
|
+
src,
|
|
15779
|
+
prefetchCache
|
|
15025
15780
|
}) => {
|
|
15026
15781
|
let prom = null;
|
|
15027
15782
|
let sOffset = null;
|
|
@@ -15043,7 +15798,8 @@ var lazyCuesFetch = ({
|
|
|
15043
15798
|
logLevel,
|
|
15044
15799
|
position,
|
|
15045
15800
|
readerInterface,
|
|
15046
|
-
src
|
|
15801
|
+
src,
|
|
15802
|
+
prefetchCache
|
|
15047
15803
|
}).then((cues) => {
|
|
15048
15804
|
Log.verbose(logLevel, "Cues loaded");
|
|
15049
15805
|
result = cues;
|
|
@@ -15105,7 +15861,8 @@ var webmState = ({
|
|
|
15105
15861
|
controller,
|
|
15106
15862
|
logLevel,
|
|
15107
15863
|
readerInterface,
|
|
15108
|
-
src
|
|
15864
|
+
src,
|
|
15865
|
+
prefetchCache
|
|
15109
15866
|
}) => {
|
|
15110
15867
|
const trackEntries = {};
|
|
15111
15868
|
const onTrackEntrySegment = (trackEntry2) => {
|
|
@@ -15166,7 +15923,8 @@ var webmState = ({
|
|
|
15166
15923
|
controller,
|
|
15167
15924
|
logLevel,
|
|
15168
15925
|
readerInterface,
|
|
15169
|
-
src
|
|
15926
|
+
src,
|
|
15927
|
+
prefetchCache
|
|
15170
15928
|
});
|
|
15171
15929
|
const getTimeStampMapForSeekingHints = () => {
|
|
15172
15930
|
return timestampMap;
|
|
@@ -15247,13 +16005,16 @@ var fetchIdx1 = async ({
|
|
|
15247
16005
|
readerInterface,
|
|
15248
16006
|
controller,
|
|
15249
16007
|
position,
|
|
15250
|
-
logLevel
|
|
16008
|
+
logLevel,
|
|
16009
|
+
prefetchCache
|
|
15251
16010
|
}) => {
|
|
15252
16011
|
Log.verbose(logLevel, "Making request to fetch idx1 from ", src, "position", position);
|
|
15253
16012
|
const result = await readerInterface.read({
|
|
15254
16013
|
controller,
|
|
15255
16014
|
range: position,
|
|
15256
|
-
src
|
|
16015
|
+
src,
|
|
16016
|
+
logLevel,
|
|
16017
|
+
prefetchCache
|
|
15257
16018
|
});
|
|
15258
16019
|
const iterator = getArrayBufferIterator(new Uint8Array, Infinity);
|
|
15259
16020
|
while (true) {
|
|
@@ -15284,7 +16045,8 @@ var lazyIdx1Fetch = ({
|
|
|
15284
16045
|
controller,
|
|
15285
16046
|
logLevel,
|
|
15286
16047
|
readerInterface,
|
|
15287
|
-
src
|
|
16048
|
+
src,
|
|
16049
|
+
prefetchCache
|
|
15288
16050
|
}) => {
|
|
15289
16051
|
let prom = null;
|
|
15290
16052
|
let result = null;
|
|
@@ -15300,7 +16062,8 @@ var lazyIdx1Fetch = ({
|
|
|
15300
16062
|
logLevel,
|
|
15301
16063
|
position,
|
|
15302
16064
|
readerInterface,
|
|
15303
|
-
src
|
|
16065
|
+
src,
|
|
16066
|
+
prefetchCache
|
|
15304
16067
|
}).then((entries) => {
|
|
15305
16068
|
prom = null;
|
|
15306
16069
|
result = entries;
|
|
@@ -15421,7 +16184,8 @@ var riffSpecificState = ({
|
|
|
15421
16184
|
controller,
|
|
15422
16185
|
logLevel,
|
|
15423
16186
|
readerInterface,
|
|
15424
|
-
src
|
|
16187
|
+
src,
|
|
16188
|
+
prefetchCache
|
|
15425
16189
|
}) => {
|
|
15426
16190
|
let avcProfile = null;
|
|
15427
16191
|
let nextTrackIndex = 0;
|
|
@@ -15440,7 +16204,8 @@ var riffSpecificState = ({
|
|
|
15440
16204
|
controller,
|
|
15441
16205
|
logLevel,
|
|
15442
16206
|
readerInterface,
|
|
15443
|
-
src
|
|
16207
|
+
src,
|
|
16208
|
+
prefetchCache
|
|
15444
16209
|
});
|
|
15445
16210
|
const sampleCounter = riffSampleCounter();
|
|
15446
16211
|
return {
|
|
@@ -15461,7 +16226,7 @@ var riffSpecificState = ({
|
|
|
15461
16226
|
};
|
|
15462
16227
|
|
|
15463
16228
|
// src/state/sample-callbacks.ts
|
|
15464
|
-
var
|
|
16229
|
+
var callbacksState = ({
|
|
15465
16230
|
controller,
|
|
15466
16231
|
hasAudioTrackHandlers,
|
|
15467
16232
|
hasVideoTrackHandlers,
|
|
@@ -15768,14 +16533,15 @@ var makeParserState = ({
|
|
|
15768
16533
|
onDiscardedData,
|
|
15769
16534
|
selectM3uStreamFn,
|
|
15770
16535
|
selectM3uAssociatedPlaylistsFn,
|
|
15771
|
-
|
|
16536
|
+
m3uPlaylistContext,
|
|
15772
16537
|
contentType,
|
|
15773
16538
|
name,
|
|
15774
16539
|
callbacks,
|
|
15775
16540
|
fieldsInReturnValue,
|
|
15776
16541
|
mimeType,
|
|
15777
16542
|
initialReaderInstance,
|
|
15778
|
-
makeSamplesStartAtZero
|
|
16543
|
+
makeSamplesStartAtZero,
|
|
16544
|
+
prefetchCache
|
|
15779
16545
|
}) => {
|
|
15780
16546
|
let skippedBytes = 0;
|
|
15781
16547
|
const returnValue = {};
|
|
@@ -15807,22 +16573,35 @@ var makeParserState = ({
|
|
|
15807
16573
|
callbacks
|
|
15808
16574
|
});
|
|
15809
16575
|
return {
|
|
15810
|
-
riff: riffSpecificState({
|
|
16576
|
+
riff: riffSpecificState({
|
|
16577
|
+
controller,
|
|
16578
|
+
logLevel,
|
|
16579
|
+
readerInterface,
|
|
16580
|
+
src,
|
|
16581
|
+
prefetchCache
|
|
16582
|
+
}),
|
|
15811
16583
|
transportStream: transportStreamState(),
|
|
15812
|
-
webm: webmState({
|
|
16584
|
+
webm: webmState({
|
|
16585
|
+
controller,
|
|
16586
|
+
logLevel,
|
|
16587
|
+
readerInterface,
|
|
16588
|
+
src,
|
|
16589
|
+
prefetchCache
|
|
16590
|
+
}),
|
|
15813
16591
|
iso: isoBaseMediaState({
|
|
15814
16592
|
contentLength,
|
|
15815
16593
|
controller,
|
|
15816
16594
|
readerInterface,
|
|
15817
16595
|
src,
|
|
15818
|
-
logLevel
|
|
16596
|
+
logLevel,
|
|
16597
|
+
prefetchCache
|
|
15819
16598
|
}),
|
|
15820
16599
|
mp3,
|
|
15821
16600
|
aac: aacState(),
|
|
15822
16601
|
flac: flacState(),
|
|
15823
16602
|
m3u: m3uState(logLevel),
|
|
15824
16603
|
timings,
|
|
15825
|
-
callbacks:
|
|
16604
|
+
callbacks: callbacksState({
|
|
15826
16605
|
controller,
|
|
15827
16606
|
hasAudioTrackHandlers,
|
|
15828
16607
|
hasVideoTrackHandlers,
|
|
@@ -15860,7 +16639,7 @@ var makeParserState = ({
|
|
|
15860
16639
|
discardReadBytes,
|
|
15861
16640
|
selectM3uStreamFn,
|
|
15862
16641
|
selectM3uAssociatedPlaylistsFn,
|
|
15863
|
-
|
|
16642
|
+
m3uPlaylistContext,
|
|
15864
16643
|
contentType,
|
|
15865
16644
|
name,
|
|
15866
16645
|
returnValue,
|
|
@@ -15870,7 +16649,8 @@ var makeParserState = ({
|
|
|
15870
16649
|
errored,
|
|
15871
16650
|
currentReader: currentReaderState,
|
|
15872
16651
|
seekInfiniteLoop,
|
|
15873
|
-
makeSamplesStartAtZero
|
|
16652
|
+
makeSamplesStartAtZero,
|
|
16653
|
+
prefetchCache
|
|
15874
16654
|
};
|
|
15875
16655
|
};
|
|
15876
16656
|
|
|
@@ -15949,7 +16729,7 @@ var internalParseMedia = async function({
|
|
|
15949
16729
|
apiName,
|
|
15950
16730
|
selectM3uStream: selectM3uStreamFn,
|
|
15951
16731
|
selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylistsFn,
|
|
15952
|
-
|
|
16732
|
+
m3uPlaylistContext,
|
|
15953
16733
|
makeSamplesStartAtZero,
|
|
15954
16734
|
seekingHints,
|
|
15955
16735
|
...more
|
|
@@ -15961,6 +16741,7 @@ var internalParseMedia = async function({
|
|
|
15961
16741
|
apiName
|
|
15962
16742
|
});
|
|
15963
16743
|
Log.verbose(logLevel, `Reading ${typeof src === "string" ? src : src instanceof URL ? src.toString() : src instanceof File ? src.name : src.toString()}`);
|
|
16744
|
+
const prefetchCache = new Map;
|
|
15964
16745
|
const {
|
|
15965
16746
|
reader: readerInstance,
|
|
15966
16747
|
contentLength,
|
|
@@ -15968,7 +16749,13 @@ var internalParseMedia = async function({
|
|
|
15968
16749
|
contentType,
|
|
15969
16750
|
supportsContentRange,
|
|
15970
16751
|
needsContentRange
|
|
15971
|
-
} = await readerInterface.read({
|
|
16752
|
+
} = await readerInterface.read({
|
|
16753
|
+
src,
|
|
16754
|
+
range: null,
|
|
16755
|
+
controller,
|
|
16756
|
+
logLevel,
|
|
16757
|
+
prefetchCache
|
|
16758
|
+
});
|
|
15972
16759
|
if (contentLength === null) {
|
|
15973
16760
|
throw new Error(`Cannot read media ${src} without a content length. This is currently not supported. Ensure the media has a "Content-Length" HTTP header.`);
|
|
15974
16761
|
}
|
|
@@ -15991,14 +16778,15 @@ var internalParseMedia = async function({
|
|
|
15991
16778
|
onDiscardedData,
|
|
15992
16779
|
selectM3uStreamFn,
|
|
15993
16780
|
selectM3uAssociatedPlaylistsFn,
|
|
15994
|
-
|
|
16781
|
+
m3uPlaylistContext,
|
|
15995
16782
|
contentType,
|
|
15996
16783
|
name,
|
|
15997
16784
|
callbacks: more,
|
|
15998
16785
|
fieldsInReturnValue: _fieldsInReturnValue ?? {},
|
|
15999
16786
|
mimeType: contentType,
|
|
16000
16787
|
initialReaderInstance: readerInstance,
|
|
16001
|
-
makeSamplesStartAtZero
|
|
16788
|
+
makeSamplesStartAtZero,
|
|
16789
|
+
prefetchCache
|
|
16002
16790
|
});
|
|
16003
16791
|
if (seekingHints) {
|
|
16004
16792
|
setSeekingHints({ hints: seekingHints, state });
|
|
@@ -16008,7 +16796,7 @@ var internalParseMedia = async function({
|
|
|
16008
16796
|
keyframesState: state.keyframes,
|
|
16009
16797
|
webmState: state.webm,
|
|
16010
16798
|
structureState: state.structure,
|
|
16011
|
-
|
|
16799
|
+
m3uPlaylistContext: state.m3uPlaylistContext,
|
|
16012
16800
|
mediaSectionState: state.mediaSection,
|
|
16013
16801
|
isoState: state.iso,
|
|
16014
16802
|
transportStream: state.transportStream,
|
|
@@ -16037,6 +16825,7 @@ var internalParseMedia = async function({
|
|
|
16037
16825
|
state.iterator?.destroy();
|
|
16038
16826
|
state.callbacks.tracks.ensureHasTracksAtEnd(state.fields);
|
|
16039
16827
|
state.m3u.abortM3UStreamRuns();
|
|
16828
|
+
prefetchCache.clear();
|
|
16040
16829
|
if (state.errored) {
|
|
16041
16830
|
throw state.errored;
|
|
16042
16831
|
}
|
|
@@ -16063,7 +16852,7 @@ var downloadAndParseMedia = async (options) => {
|
|
|
16063
16852
|
onDimensions: options.onDimensions ?? null,
|
|
16064
16853
|
selectM3uStream: options.selectM3uStream ?? defaultSelectM3uStreamFn,
|
|
16065
16854
|
selectM3uAssociatedPlaylists: options.selectM3uAssociatedPlaylists ?? defaultSelectM3uAssociatedPlaylists,
|
|
16066
|
-
|
|
16855
|
+
m3uPlaylistContext: options.m3uPlaylistContext ?? null,
|
|
16067
16856
|
onDiscardedData: async (data) => {
|
|
16068
16857
|
await content.write(data);
|
|
16069
16858
|
},
|
|
@@ -16116,7 +16905,7 @@ var downloadAndParseMedia = async (options) => {
|
|
|
16116
16905
|
return returnValue;
|
|
16117
16906
|
};
|
|
16118
16907
|
// src/version.ts
|
|
16119
|
-
var VERSION = "4.0.
|
|
16908
|
+
var VERSION = "4.0.291";
|
|
16120
16909
|
|
|
16121
16910
|
// src/index.ts
|
|
16122
16911
|
var MediaParserInternals = {
|