@remotion/media-parser 4.0.284 → 4.0.286
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/aac-codecprivate.d.ts +1 -1
- package/dist/combine-uint8-arrays.d.ts +1 -1
- package/dist/containers/aac/parse-aac.js +0 -3
- package/dist/containers/avc/create-sps-pps-data.d.ts +1 -1
- package/dist/containers/flac/get-channel-count.d.ts +1 -1
- package/dist/containers/flac/parse-flac-frame.js +0 -2
- package/dist/containers/flac/parse-streaminfo.js +0 -2
- package/dist/containers/iso-base-media/collect-sample-positions-from-trak.js +4 -3
- package/dist/containers/iso-base-media/get-moov-atom.js +0 -4
- package/dist/containers/iso-base-media/mdat/mdat.js +0 -3
- package/dist/containers/iso-base-media/mfra/get-mfra-atom.d.ts +3 -3
- package/dist/containers/iso-base-media/parse-boxes.js +0 -2
- package/dist/containers/iso-base-media/process-box.d.ts +0 -2
- package/dist/containers/iso-base-media/process-box.js +1 -3
- package/dist/containers/m3u/iterate-over-segment-files.js +1 -0
- package/dist/containers/m3u/run-over-m3u.js +0 -3
- package/dist/containers/mp3/parse-mpeg-header.js +0 -3
- package/dist/containers/riff/expect-riff-box.js +0 -2
- package/dist/containers/riff/parse-movi.js +0 -3
- package/dist/containers/transport-stream/adts-header.d.ts +1 -1
- package/dist/containers/transport-stream/discard-rest-of-packet.d.ts +1 -1
- package/dist/containers/transport-stream/find-separator.d.ts +17 -1
- package/dist/containers/transport-stream/find-separator.js +6 -5
- package/dist/containers/transport-stream/get-seeking-info.d.ts +4 -0
- package/dist/containers/transport-stream/get-seeking-info.js +17 -0
- package/dist/containers/transport-stream/handle-aac-packet.d.ts +10 -3
- package/dist/containers/transport-stream/handle-aac-packet.js +21 -16
- package/dist/containers/transport-stream/handle-avc-packet.d.ts +10 -3
- package/dist/containers/transport-stream/handle-avc-packet.js +26 -17
- package/dist/containers/transport-stream/parse-packet.d.ts +8 -4
- package/dist/containers/transport-stream/parse-packet.js +15 -16
- package/dist/containers/transport-stream/parse-pes.d.ts +5 -1
- package/dist/containers/transport-stream/parse-pes.js +4 -3
- package/dist/containers/transport-stream/parse-stream-packet.d.ts +6 -6
- package/dist/containers/transport-stream/parse-stream-packet.js +10 -115
- package/dist/containers/transport-stream/parse-transport-stream.js +15 -3
- package/dist/containers/transport-stream/process-stream-buffers.d.ts +26 -6
- package/dist/containers/transport-stream/process-stream-buffers.js +77 -12
- package/dist/containers/transport-stream/traversal.d.ts +3 -1
- package/dist/containers/transport-stream/traversal.js +10 -2
- package/dist/containers/wav/parse-fmt.js +0 -2
- package/dist/containers/wav/parse-media-section.js +0 -2
- package/dist/containers/webm/cues/fetch-web-cues.d.ts +12 -0
- package/dist/containers/webm/cues/fetch-web-cues.js +32 -0
- package/dist/containers/webm/cues/format-cues.d.ts +8 -0
- package/dist/containers/webm/cues/format-cues.js +41 -0
- package/dist/containers/webm/cues/get-seeking-byte.d.ts +14 -0
- package/dist/containers/webm/cues/get-seeking-byte.js +91 -0
- package/dist/containers/webm/fetch-web-cues.d.ts +12 -0
- package/dist/containers/webm/fetch-web-cues.js +29 -0
- package/dist/containers/webm/get-byte-for-cues.d.ts +5 -0
- package/dist/containers/webm/get-byte-for-cues.js +33 -0
- package/dist/containers/webm/get-ready-tracks.d.ts +9 -4
- package/dist/containers/webm/get-ready-tracks.js +6 -6
- package/dist/containers/webm/get-sample-from-block.d.ts +3 -2
- package/dist/containers/webm/get-sample-from-block.js +9 -8
- package/dist/containers/webm/get-seeking-byte.d.ts +14 -0
- package/dist/containers/webm/get-seeking-byte.js +91 -0
- package/dist/containers/webm/get-seeking-info.d.ts +3 -0
- package/dist/containers/webm/get-seeking-info.js +17 -0
- package/dist/containers/webm/parse-ebml.d.ts +5 -4
- package/dist/containers/webm/parse-ebml.js +29 -34
- package/dist/containers/webm/parse-webm-header.js +14 -2
- package/dist/containers/webm/seek/fetch-web-cues.d.ts +12 -0
- package/dist/containers/webm/seek/fetch-web-cues.js +32 -0
- package/dist/containers/webm/seek/format-cues.d.ts +8 -0
- package/dist/containers/webm/seek/format-cues.js +42 -0
- package/dist/containers/webm/seek/get-seeking-byte.d.ts +14 -0
- package/dist/containers/webm/seek/get-seeking-byte.js +100 -0
- package/dist/containers/webm/seek/get-seeking-info.d.ts +3 -0
- package/dist/containers/webm/seek/get-seeking-info.js +17 -0
- package/dist/containers/webm/segments/all-segments.d.ts +1 -0
- package/dist/containers/webm/segments.d.ts +10 -4
- package/dist/containers/webm/segments.js +30 -12
- package/dist/containers/webm/state-for-processing.d.ts +15 -0
- package/dist/containers/webm/state-for-processing.js +14 -0
- package/dist/controller/seek-signal.d.ts +2 -2
- package/dist/download-and-parse-media.js +2 -1
- package/dist/emit-audio-sample.d.ts +2 -5
- package/dist/emit-audio-sample.js +2 -5
- package/dist/esm/index.mjs +5057 -4394
- package/dist/esm/universal.mjs +1 -1
- package/dist/esm/web.mjs +1 -1
- package/dist/esm/worker-server-entry.mjs +2327 -1664
- package/dist/esm/worker-web-entry.mjs +2327 -1664
- package/dist/file-types/detect-file-type.js +3 -1
- package/dist/get-audio-codec.d.ts +2 -1
- package/dist/get-audio-codec.js +15 -1
- package/dist/get-sample-positions-from-mp4.d.ts +3 -0
- package/dist/get-sample-positions-from-mp4.js +46 -0
- package/dist/get-seeking-byte.d.ts +19 -0
- package/dist/get-seeking-byte.js +50 -0
- package/dist/get-seeking-info.d.ts +5 -10
- package/dist/get-seeking-info.js +12 -25
- package/dist/get-tracks.js +6 -2
- package/dist/index.d.ts +44 -19
- package/dist/init-video.js +4 -3
- package/dist/internal-parse-media.js +3 -2
- package/dist/iterator/buffer-iterator.d.ts +3 -3
- package/dist/iterator/buffer-manager.d.ts +3 -3
- package/dist/log.d.ts +5 -5
- package/dist/options.d.ts +1 -0
- package/dist/parse-loop.js +0 -3
- package/dist/parse-media-on-worker-entry.d.ts +1 -1
- package/dist/parse-media.js +2 -1
- package/dist/readers/from-web-file.js +1 -1
- package/dist/register-track.d.ts +2 -5
- package/dist/register-track.js +2 -10
- package/dist/seek-backwards.js +2 -3
- package/dist/seeking-info.d.ts +14 -1
- package/dist/state/iso-base-media/cached-sample-positions.d.ts +1 -1
- package/dist/state/keyframes.js +3 -0
- package/dist/state/matroska/lazy-cues-fetch.d.ts +19 -0
- package/dist/state/matroska/lazy-cues-fetch.js +51 -0
- package/dist/state/matroska/lazy-seek-fetch.d.ts +1 -0
- package/dist/state/matroska/lazy-seek-fetch.js +5 -0
- package/dist/state/matroska/webm.d.ts +46 -0
- package/dist/state/matroska/webm.js +121 -0
- package/dist/state/matroska.d.ts +0 -0
- package/dist/state/matroska.js +1 -0
- package/dist/state/parser-state.d.ts +34 -9
- package/dist/state/parser-state.js +7 -6
- package/dist/state/sample-callbacks.d.ts +1 -1
- package/dist/state/sample-callbacks.js +9 -9
- package/dist/state/samples-observed/slow-duration-fps.d.ts +11 -0
- package/dist/state/samples-observed/slow-duration-fps.js +92 -0
- package/dist/state/seek-infinite-loop.js +12 -2
- package/dist/state/transport-stream/observed-pes-header.d.ts +13 -0
- package/dist/state/transport-stream/observed-pes-header.js +29 -0
- package/dist/state/transport-stream/pts-start-offset.d.ts +5 -0
- package/dist/state/transport-stream/pts-start-offset.js +13 -0
- package/dist/state/transport-stream/start-offset.d.ts +2 -1
- package/dist/state/transport-stream/start-offset.js +3 -3
- package/dist/state/transport-stream/transport-stream.d.ts +6 -0
- package/dist/state/transport-stream/transport-stream.js +4 -2
- package/dist/state/video-section.js +14 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/work-on-seek-request.d.ts +8 -0
- package/dist/work-on-seek-request.js +24 -6
- package/dist/worker-server.js +1 -0
- package/dist/worker.d.ts +0 -1
- package/package.json +4 -4
|
@@ -361,7 +361,7 @@ var webFileReadContent = ({ src, range, controller }) => {
|
|
|
361
361
|
}
|
|
362
362
|
},
|
|
363
363
|
contentLength: src.size,
|
|
364
|
-
name: src.name,
|
|
364
|
+
name: src instanceof File ? src.name : src.toString(),
|
|
365
365
|
supportsContentRange: true,
|
|
366
366
|
contentType: src.type,
|
|
367
367
|
needsContentRange: true
|
|
@@ -1943,12 +1943,13 @@ var isTransportStream = (data) => {
|
|
|
1943
1943
|
return data[0] === 71 && data[188] === 71;
|
|
1944
1944
|
};
|
|
1945
1945
|
var isMp3 = (data) => {
|
|
1946
|
-
const mpegPattern = new Uint8Array([255, 243
|
|
1946
|
+
const mpegPattern = new Uint8Array([255, 243]);
|
|
1947
|
+
const mpegPattern2 = new Uint8Array([255, 251]);
|
|
1947
1948
|
const id3v4Pattern = new Uint8Array([73, 68, 51, 4]);
|
|
1948
1949
|
const id3v3Pattern = new Uint8Array([73, 68, 51, 3]);
|
|
1949
1950
|
const id3v2Pattern = new Uint8Array([73, 68, 51, 2]);
|
|
1950
1951
|
const subarray = data.subarray(0, 4);
|
|
1951
|
-
return matchesPattern(mpegPattern)(subarray) || matchesPattern(id3v4Pattern)(subarray) || matchesPattern(id3v3Pattern)(subarray) || matchesPattern(id3v2Pattern)(subarray);
|
|
1952
|
+
return matchesPattern(mpegPattern)(subarray) || matchesPattern(mpegPattern2)(subarray) || matchesPattern(id3v4Pattern)(subarray) || matchesPattern(id3v3Pattern)(subarray) || matchesPattern(id3v2Pattern)(subarray);
|
|
1952
1953
|
};
|
|
1953
1954
|
var isGif = (data) => {
|
|
1954
1955
|
const gifPattern = new Uint8Array([71, 73, 70, 56]);
|
|
@@ -3326,8 +3327,15 @@ var findProgramAssociationTableOrThrow = (structure) => {
|
|
|
3326
3327
|
}
|
|
3327
3328
|
return box;
|
|
3328
3329
|
};
|
|
3329
|
-
var
|
|
3330
|
+
var findProgramMapOrNull = (structure) => {
|
|
3330
3331
|
const box = structure.boxes.find((b) => b.type === "transport-stream-pmt-box");
|
|
3332
|
+
if (!box) {
|
|
3333
|
+
return null;
|
|
3334
|
+
}
|
|
3335
|
+
return box;
|
|
3336
|
+
};
|
|
3337
|
+
var findProgramMapTableOrThrow = (structure) => {
|
|
3338
|
+
const box = findProgramMapOrNull(structure);
|
|
3331
3339
|
if (!box) {
|
|
3332
3340
|
throw new Error("No PMT box found");
|
|
3333
3341
|
}
|
|
@@ -3948,10 +3956,10 @@ var getTrack = ({
|
|
|
3948
3956
|
|
|
3949
3957
|
// src/containers/webm/get-ready-tracks.ts
|
|
3950
3958
|
var getTracksFromMatroska = ({
|
|
3951
|
-
|
|
3959
|
+
structureState,
|
|
3960
|
+
webmState
|
|
3952
3961
|
}) => {
|
|
3953
|
-
const
|
|
3954
|
-
const structure = state.structure.getMatroskaStructure();
|
|
3962
|
+
const structure = structureState.getMatroskaStructure();
|
|
3955
3963
|
const mainSegment = getMainSegment(structure.boxes);
|
|
3956
3964
|
if (!mainSegment) {
|
|
3957
3965
|
throw new Error("No main segment");
|
|
@@ -3992,14 +4000,18 @@ var getTracksFromMatroska = ({
|
|
|
3992
4000
|
}
|
|
3993
4001
|
return { missingInfo, resolved: resolvedTracks };
|
|
3994
4002
|
};
|
|
3995
|
-
var matroskaHasTracks = (
|
|
3996
|
-
|
|
4003
|
+
var matroskaHasTracks = ({
|
|
4004
|
+
structureState,
|
|
4005
|
+
webmState
|
|
4006
|
+
}) => {
|
|
4007
|
+
const structure = structureState.getMatroskaStructure();
|
|
3997
4008
|
const mainSegment = getMainSegment(structure.boxes);
|
|
3998
4009
|
if (!mainSegment) {
|
|
3999
4010
|
return false;
|
|
4000
4011
|
}
|
|
4001
4012
|
return getTracksSegment(mainSegment) !== null && getTracksFromMatroska({
|
|
4002
|
-
|
|
4013
|
+
structureState,
|
|
4014
|
+
webmState
|
|
4003
4015
|
}).missingInfo.length === 0;
|
|
4004
4016
|
};
|
|
4005
4017
|
|
|
@@ -4014,7 +4026,10 @@ var isoBaseMediaHasTracks = (state) => {
|
|
|
4014
4026
|
var getHasTracks = (state) => {
|
|
4015
4027
|
const structure = state.structure.getStructure();
|
|
4016
4028
|
if (structure.type === "matroska") {
|
|
4017
|
-
return matroskaHasTracks(
|
|
4029
|
+
return matroskaHasTracks({
|
|
4030
|
+
structureState: state.structure,
|
|
4031
|
+
webmState: state.webm
|
|
4032
|
+
});
|
|
4018
4033
|
}
|
|
4019
4034
|
if (structure.type === "iso-base-media") {
|
|
4020
4035
|
return isoBaseMediaHasTracks(state);
|
|
@@ -4047,7 +4062,8 @@ var getCategorizedTracksFromMatroska = (state) => {
|
|
|
4047
4062
|
const audioTracks = [];
|
|
4048
4063
|
const otherTracks = [];
|
|
4049
4064
|
const { resolved } = getTracksFromMatroska({
|
|
4050
|
-
state
|
|
4065
|
+
structureState: state.structure,
|
|
4066
|
+
webmState: state.webm
|
|
4051
4067
|
});
|
|
4052
4068
|
for (const track of resolved) {
|
|
4053
4069
|
if (track.type === "video") {
|
|
@@ -4270,6 +4286,9 @@ var getAudioCodecFromTrak = (trak) => {
|
|
|
4270
4286
|
var isLpcmAudioCodec = (trak) => {
|
|
4271
4287
|
return getAudioCodecFromTrak(trak)?.format === "lpcm";
|
|
4272
4288
|
};
|
|
4289
|
+
var isIn24AudioCodec = (trak) => {
|
|
4290
|
+
return getAudioCodecFromTrak(trak)?.format === "in24";
|
|
4291
|
+
};
|
|
4273
4292
|
var getAudioCodecStringFromTrak = (trak) => {
|
|
4274
4293
|
const codec = getAudioCodecFromTrak(trak);
|
|
4275
4294
|
if (!codec) {
|
|
@@ -4281,6 +4300,12 @@ var getAudioCodecStringFromTrak = (trak) => {
|
|
|
4281
4300
|
description: codec.description
|
|
4282
4301
|
};
|
|
4283
4302
|
}
|
|
4303
|
+
if (codec.format === "in24") {
|
|
4304
|
+
return {
|
|
4305
|
+
codecString: "pcm-s24",
|
|
4306
|
+
description: undefined
|
|
4307
|
+
};
|
|
4308
|
+
}
|
|
4284
4309
|
const codecStringWithoutMp3Exception = [
|
|
4285
4310
|
codec.format,
|
|
4286
4311
|
codec.primarySpecificator ? codec.primarySpecificator.toString(16) : null,
|
|
@@ -4296,6 +4321,9 @@ var getAudioCodecFromAudioCodecInfo = (codec) => {
|
|
|
4296
4321
|
if (codec.format === "twos") {
|
|
4297
4322
|
return "pcm-s16";
|
|
4298
4323
|
}
|
|
4324
|
+
if (codec.format === "in24") {
|
|
4325
|
+
return "pcm-s24";
|
|
4326
|
+
}
|
|
4299
4327
|
if (codec.format === "lpcm") {
|
|
4300
4328
|
return "pcm-s16";
|
|
4301
4329
|
}
|
|
@@ -4547,8 +4575,8 @@ var getSamplePositions = ({
|
|
|
4547
4575
|
return samples;
|
|
4548
4576
|
};
|
|
4549
4577
|
|
|
4550
|
-
// src/get-sample-positions-from-
|
|
4551
|
-
var
|
|
4578
|
+
// src/get-sample-positions-from-mp4.ts
|
|
4579
|
+
var getGroupedSamplesPositionsFromMp4 = (trakBox) => {
|
|
4552
4580
|
const stscBox = getStscBox(trakBox);
|
|
4553
4581
|
const stszBox = getStszBox(trakBox);
|
|
4554
4582
|
const stcoBox = getStcoBox(trakBox);
|
|
@@ -4591,8 +4619,9 @@ var getSamplePositionsFromLpcm = (trakBox) => {
|
|
|
4591
4619
|
var collectSamplePositionsFromTrak = (trakBox) => {
|
|
4592
4620
|
const isLpcm = isLpcmAudioCodec(trakBox);
|
|
4593
4621
|
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
4594
|
-
|
|
4595
|
-
|
|
4622
|
+
const isIn24 = isIn24AudioCodec(trakBox);
|
|
4623
|
+
if (isLpcm || isIn24) {
|
|
4624
|
+
return getGroupedSamplesPositionsFromMp4(trakBox);
|
|
4596
4625
|
}
|
|
4597
4626
|
const stszBox = getStszBox(trakBox);
|
|
4598
4627
|
const stcoBox = getStcoBox(trakBox);
|
|
@@ -5390,9 +5419,16 @@ var mediaSectionState = () => {
|
|
|
5390
5419
|
const mediaSections = [];
|
|
5391
5420
|
const addMediaSection = (section) => {
|
|
5392
5421
|
const overlaps = mediaSections.some((existingSection) => section.start < existingSection.start + existingSection.size && section.start + section.size > existingSection.start);
|
|
5393
|
-
if (
|
|
5394
|
-
|
|
5422
|
+
if (overlaps) {
|
|
5423
|
+
return;
|
|
5424
|
+
}
|
|
5425
|
+
for (let i = mediaSections.length - 1;i >= 0; i--) {
|
|
5426
|
+
const existingSection = mediaSections[i];
|
|
5427
|
+
if (section.start <= existingSection.start && section.start + section.size >= existingSection.start + existingSection.size) {
|
|
5428
|
+
mediaSections.splice(i, 1);
|
|
5429
|
+
}
|
|
5395
5430
|
}
|
|
5431
|
+
mediaSections.push(section);
|
|
5396
5432
|
};
|
|
5397
5433
|
const getMediaSections = () => {
|
|
5398
5434
|
return mediaSections;
|
|
@@ -5608,33 +5644,6 @@ var getSeekingByteFromIsoBaseMedia = async ({
|
|
|
5608
5644
|
};
|
|
5609
5645
|
};
|
|
5610
5646
|
|
|
5611
|
-
// src/containers/iso-base-media/get-seeking-info-from-mp4.ts
|
|
5612
|
-
var getSeekingInfoFromMp4 = ({
|
|
5613
|
-
structureState,
|
|
5614
|
-
isoState,
|
|
5615
|
-
mp4HeaderSegment,
|
|
5616
|
-
mediaSectionState: mediaSectionState2
|
|
5617
|
-
}) => {
|
|
5618
|
-
const structure = structureState.getIsoStructure();
|
|
5619
|
-
const moovAtom = getMoovBoxFromState({
|
|
5620
|
-
isoState,
|
|
5621
|
-
mp4HeaderSegment,
|
|
5622
|
-
structureState
|
|
5623
|
-
});
|
|
5624
|
-
const moofBoxes = getMoofBoxes(structure.boxes);
|
|
5625
|
-
const tfraBoxes = getTfraBoxes(structure);
|
|
5626
|
-
if (!moovAtom) {
|
|
5627
|
-
return null;
|
|
5628
|
-
}
|
|
5629
|
-
return {
|
|
5630
|
-
type: "iso-base-media-seeking-info",
|
|
5631
|
-
moovBox: moovAtom,
|
|
5632
|
-
moofBoxes,
|
|
5633
|
-
tfraBoxes,
|
|
5634
|
-
mediaSections: mediaSectionState2.getMediaSections()
|
|
5635
|
-
};
|
|
5636
|
-
};
|
|
5637
|
-
|
|
5638
5647
|
// src/containers/wav/get-seeking-byte.ts
|
|
5639
5648
|
var WAVE_SAMPLES_PER_SECOND = 25;
|
|
5640
5649
|
var getSeekingByteFromWav = ({
|
|
@@ -5651,482 +5660,1204 @@ var getSeekingByteFromWav = ({
|
|
|
5651
5660
|
});
|
|
5652
5661
|
};
|
|
5653
5662
|
|
|
5654
|
-
// src/containers/
|
|
5655
|
-
var
|
|
5656
|
-
|
|
5657
|
-
|
|
5663
|
+
// src/containers/webm/seek/get-seeking-byte.ts
|
|
5664
|
+
var toSeconds = (timeInTimescale, track) => {
|
|
5665
|
+
return timeInTimescale / track.timescale * 1000;
|
|
5666
|
+
};
|
|
5667
|
+
var findBiggestCueBeforeTime = ({
|
|
5668
|
+
cues,
|
|
5669
|
+
time,
|
|
5670
|
+
track
|
|
5658
5671
|
}) => {
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5672
|
+
let biggestCueBeforeTime;
|
|
5673
|
+
for (const cue of cues) {
|
|
5674
|
+
const cueTimeInSeconds = toSeconds(cue.timeInTimescale, track);
|
|
5675
|
+
if (cueTimeInSeconds < time && (!biggestCueBeforeTime || cueTimeInSeconds > toSeconds(biggestCueBeforeTime.timeInTimescale, track))) {
|
|
5676
|
+
biggestCueBeforeTime = cue;
|
|
5677
|
+
}
|
|
5662
5678
|
}
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5679
|
+
return biggestCueBeforeTime;
|
|
5680
|
+
};
|
|
5681
|
+
var findKeyframeBeforeTime2 = ({
|
|
5682
|
+
keyframes,
|
|
5683
|
+
time
|
|
5684
|
+
}) => {
|
|
5685
|
+
let keyframeBeforeTime;
|
|
5686
|
+
for (const keyframe of keyframes) {
|
|
5687
|
+
if (keyframe.decodingTimeInSeconds < time && (!keyframeBeforeTime || keyframe.decodingTimeInSeconds > keyframeBeforeTime.decodingTimeInSeconds)) {
|
|
5688
|
+
keyframeBeforeTime = keyframe;
|
|
5689
|
+
}
|
|
5666
5690
|
}
|
|
5667
|
-
return
|
|
5668
|
-
type: "wav-seeking-info",
|
|
5669
|
-
sampleRate: fmtBox.sampleRate,
|
|
5670
|
-
blockAlign: fmtBox.blockAlign,
|
|
5671
|
-
mediaSections: mediaSection[0]
|
|
5672
|
-
};
|
|
5691
|
+
return keyframeBeforeTime?.positionInBytes ?? null;
|
|
5673
5692
|
};
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
mediaSectionState: mediaSectionState2,
|
|
5680
|
-
isoState
|
|
5693
|
+
var getByteFromCues = ({
|
|
5694
|
+
cuesResponse,
|
|
5695
|
+
time,
|
|
5696
|
+
info,
|
|
5697
|
+
logLevel
|
|
5681
5698
|
}) => {
|
|
5682
|
-
|
|
5683
|
-
|
|
5699
|
+
if (!cuesResponse) {
|
|
5700
|
+
Log.trace(logLevel, "Has no Matroska cues at the moment, cannot use them");
|
|
5684
5701
|
return null;
|
|
5685
5702
|
}
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
return getSeekingInfoFromWav({
|
|
5696
|
-
structure,
|
|
5697
|
-
mediaSectionState: mediaSectionState2
|
|
5698
|
-
});
|
|
5703
|
+
const { cues, segmentOffset } = cuesResponse;
|
|
5704
|
+
Log.trace(logLevel, "Has Matroska cues. Will use them to perform a seek.");
|
|
5705
|
+
const biggestCueBeforeTime = findBiggestCueBeforeTime({
|
|
5706
|
+
cues,
|
|
5707
|
+
time,
|
|
5708
|
+
track: info.track
|
|
5709
|
+
});
|
|
5710
|
+
if (!biggestCueBeforeTime) {
|
|
5711
|
+
return null;
|
|
5699
5712
|
}
|
|
5700
|
-
|
|
5713
|
+
return biggestCueBeforeTime.clusterPositionInSegment + segmentOffset;
|
|
5701
5714
|
};
|
|
5702
|
-
var
|
|
5703
|
-
info,
|
|
5715
|
+
var getSeekingByteFromMatroska = async ({
|
|
5704
5716
|
time,
|
|
5717
|
+
webmState,
|
|
5718
|
+
info,
|
|
5705
5719
|
logLevel,
|
|
5706
|
-
|
|
5707
|
-
|
|
5720
|
+
mediaSection,
|
|
5721
|
+
keyframes
|
|
5708
5722
|
}) => {
|
|
5709
|
-
if (info.
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
currentPosition,
|
|
5715
|
-
isoState
|
|
5716
|
-
});
|
|
5723
|
+
if (!info.track) {
|
|
5724
|
+
Log.trace(logLevel, "No video track found, cannot seek yet");
|
|
5725
|
+
return {
|
|
5726
|
+
type: "valid-but-must-wait"
|
|
5727
|
+
};
|
|
5717
5728
|
}
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5729
|
+
const cuesResponse = await webmState.cues.getLoadedCues();
|
|
5730
|
+
const byteFromObservedKeyframe = findKeyframeBeforeTime2({
|
|
5731
|
+
keyframes: keyframes.getKeyframes(),
|
|
5732
|
+
time
|
|
5733
|
+
});
|
|
5734
|
+
const byteFromCues = getByteFromCues({
|
|
5735
|
+
cuesResponse,
|
|
5736
|
+
time,
|
|
5737
|
+
info,
|
|
5738
|
+
logLevel
|
|
5739
|
+
});
|
|
5740
|
+
const byteFromFirstMediaSection = webmState.getFirstCluster()?.start ?? null;
|
|
5741
|
+
const seekPossibilities = [
|
|
5742
|
+
byteFromCues,
|
|
5743
|
+
byteFromObservedKeyframe,
|
|
5744
|
+
byteFromFirstMediaSection
|
|
5745
|
+
].filter((n) => n !== null);
|
|
5746
|
+
const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
|
|
5747
|
+
if (byteToSeekTo === null) {
|
|
5748
|
+
return {
|
|
5749
|
+
type: "invalid"
|
|
5750
|
+
};
|
|
5723
5751
|
}
|
|
5724
|
-
|
|
5752
|
+
mediaSection.addMediaSection({
|
|
5753
|
+
start: byteToSeekTo,
|
|
5754
|
+
size: 1
|
|
5755
|
+
});
|
|
5756
|
+
return {
|
|
5757
|
+
type: "do-seek",
|
|
5758
|
+
byte: byteToSeekTo
|
|
5759
|
+
};
|
|
5725
5760
|
};
|
|
5726
5761
|
|
|
5727
|
-
// src/
|
|
5728
|
-
var
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5762
|
+
// src/convert-audio-or-video-sample.ts
|
|
5763
|
+
var TARGET_TIMESCALE = 1e6;
|
|
5764
|
+
var fixFloat = (value) => {
|
|
5765
|
+
if (value % 1 < 0.0000001) {
|
|
5766
|
+
return Math.floor(value);
|
|
5767
|
+
}
|
|
5768
|
+
if (value % 1 > 0.9999999) {
|
|
5769
|
+
return Math.ceil(value);
|
|
5770
|
+
}
|
|
5771
|
+
return value;
|
|
5772
|
+
};
|
|
5773
|
+
var convertAudioOrVideoSampleToWebCodecsTimestamps = ({
|
|
5774
|
+
sample,
|
|
5775
|
+
timescale
|
|
5736
5776
|
}) => {
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
if (iterator.counter.getOffset() - howManyBytesWeCanGoBack <= seekTo) {
|
|
5740
|
-
iterator.skipTo(seekTo);
|
|
5741
|
-
return;
|
|
5777
|
+
if (timescale === TARGET_TIMESCALE) {
|
|
5778
|
+
return sample;
|
|
5742
5779
|
}
|
|
5743
|
-
const
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5780
|
+
const { cts, dts, timestamp } = sample;
|
|
5781
|
+
return {
|
|
5782
|
+
cts: fixFloat(cts * (TARGET_TIMESCALE / timescale)),
|
|
5783
|
+
dts: fixFloat(dts * (TARGET_TIMESCALE / timescale)),
|
|
5784
|
+
timestamp: fixFloat(timestamp * (TARGET_TIMESCALE / timescale)),
|
|
5785
|
+
duration: sample.duration === undefined ? undefined : fixFloat(sample.duration * (TARGET_TIMESCALE / timescale)),
|
|
5786
|
+
data: sample.data,
|
|
5787
|
+
trackId: sample.trackId,
|
|
5788
|
+
type: sample.type,
|
|
5789
|
+
offset: sample.offset,
|
|
5790
|
+
timescale: TARGET_TIMESCALE
|
|
5791
|
+
};
|
|
5753
5792
|
};
|
|
5754
5793
|
|
|
5755
|
-
// src/
|
|
5756
|
-
var
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
slowNumberOfFrames: true,
|
|
5761
|
-
audioCodec: false,
|
|
5762
|
-
container: false,
|
|
5763
|
-
dimensions: false,
|
|
5764
|
-
durationInSeconds: false,
|
|
5765
|
-
fps: false,
|
|
5766
|
-
internalStats: false,
|
|
5767
|
-
isHdr: false,
|
|
5768
|
-
name: false,
|
|
5769
|
-
rotation: false,
|
|
5770
|
-
size: false,
|
|
5771
|
-
structure: false,
|
|
5772
|
-
tracks: false,
|
|
5773
|
-
unrotatedDimensions: false,
|
|
5774
|
-
videoCodec: false,
|
|
5775
|
-
metadata: false,
|
|
5776
|
-
location: false,
|
|
5777
|
-
mimeType: false,
|
|
5778
|
-
keyframes: false,
|
|
5779
|
-
images: false,
|
|
5780
|
-
numberOfAudioChannels: false,
|
|
5781
|
-
sampleRate: false,
|
|
5782
|
-
slowAudioBitrate: true,
|
|
5783
|
-
slowVideoBitrate: true,
|
|
5784
|
-
m3uStreams: false
|
|
5785
|
-
};
|
|
5786
|
-
var needsToIterateOverSamples = ({
|
|
5787
|
-
fields,
|
|
5788
|
-
emittedFields
|
|
5794
|
+
// src/emit-audio-sample.ts
|
|
5795
|
+
var emitAudioSample = async ({
|
|
5796
|
+
trackId,
|
|
5797
|
+
audioSample,
|
|
5798
|
+
callbacks
|
|
5789
5799
|
}) => {
|
|
5790
|
-
|
|
5791
|
-
const selectedKeys = keys.filter((k) => fields[k]);
|
|
5792
|
-
return selectedKeys.some((k) => fieldsNeedSamplesMap[k] && !emittedFields[k]);
|
|
5800
|
+
await callbacks.onAudioSample(trackId, audioSample);
|
|
5793
5801
|
};
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
previousPosition,
|
|
5799
|
-
fields
|
|
5802
|
+
var emitVideoSample = async ({
|
|
5803
|
+
trackId,
|
|
5804
|
+
videoSample,
|
|
5805
|
+
callbacks
|
|
5800
5806
|
}) => {
|
|
5801
|
-
|
|
5802
|
-
if (fieldsNeedingSamples.length > 0) {
|
|
5803
|
-
throw new Error(`Forward seeking is not allowed when the following fields are requested from parseMedia(): ${fieldsNeedingSamples.join(", ")}. Seek was from 0x${previousPosition.toString(16)} to 0x${seekTo.toString(16)}. Either don't seek forward, or don't request these fields.`);
|
|
5804
|
-
}
|
|
5807
|
+
await callbacks.onVideoSample(trackId, videoSample);
|
|
5805
5808
|
};
|
|
5806
5809
|
|
|
5807
|
-
// src/
|
|
5808
|
-
var
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
readerInterface,
|
|
5816
|
-
src,
|
|
5817
|
-
controller,
|
|
5818
|
-
discardReadBytes
|
|
5810
|
+
// src/register-track.ts
|
|
5811
|
+
var registerVideoTrack = async ({
|
|
5812
|
+
track,
|
|
5813
|
+
container,
|
|
5814
|
+
logLevel,
|
|
5815
|
+
onVideoTrack,
|
|
5816
|
+
registerVideoSampleCallback,
|
|
5817
|
+
tracks: tracks2
|
|
5819
5818
|
}) => {
|
|
5820
|
-
if (
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
seekTo,
|
|
5824
|
-
previousPosition: iterator.counter.getOffset()
|
|
5825
|
-
});
|
|
5819
|
+
if (tracks2.getTracks().find((t) => t.trackId === track.trackId)) {
|
|
5820
|
+
Log.trace(logLevel, `Track ${track.trackId} already registered, skipping`);
|
|
5821
|
+
return null;
|
|
5826
5822
|
}
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
if (alreadyHasBuffer) {
|
|
5830
|
-
iterator.skipTo(seekTo);
|
|
5831
|
-
Log.verbose(logLevel, `Already read ahead enough, skipping forward`);
|
|
5832
|
-
return;
|
|
5823
|
+
if (track.type !== "video") {
|
|
5824
|
+
throw new Error("Expected video track");
|
|
5833
5825
|
}
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5826
|
+
tracks2.addTrack(track);
|
|
5827
|
+
if (!onVideoTrack) {
|
|
5828
|
+
return null;
|
|
5829
|
+
}
|
|
5830
|
+
const callback = await onVideoTrack({
|
|
5831
|
+
track,
|
|
5832
|
+
container
|
|
5840
5833
|
});
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
Log.verbose(logLevel, `Re-reading took ${Date.now() - time}ms. New position: ${iterator.counter.getOffset()}`);
|
|
5844
|
-
currentReader.setCurrent(newReader);
|
|
5834
|
+
await registerVideoSampleCallback(track.trackId, callback ?? null);
|
|
5835
|
+
return callback;
|
|
5845
5836
|
};
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
userInitiated,
|
|
5851
|
-
controller,
|
|
5852
|
-
mediaSection,
|
|
5853
|
-
iterator,
|
|
5854
|
-
seekInfiniteLoop,
|
|
5837
|
+
var registerAudioTrack = async ({
|
|
5838
|
+
track,
|
|
5839
|
+
container,
|
|
5840
|
+
tracks: tracks2,
|
|
5855
5841
|
logLevel,
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
currentReader,
|
|
5859
|
-
readerInterface,
|
|
5860
|
-
src,
|
|
5861
|
-
discardReadBytes,
|
|
5862
|
-
fields
|
|
5842
|
+
onAudioTrack,
|
|
5843
|
+
registerAudioSampleCallback
|
|
5863
5844
|
}) => {
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
});
|
|
5868
|
-
if (byteInMediaSection !== "in-section" && userInitiated) {
|
|
5869
|
-
const sections = mediaSection.getMediaSections();
|
|
5870
|
-
const sectionStrings = sections.map((section) => {
|
|
5871
|
-
return `start: ${section.start}, end: ${section.size + section.start}`;
|
|
5872
|
-
});
|
|
5873
|
-
throw new Error(`Cannot seek to a byte that is not in the video section. Seeking to: ${seekTo}, sections: ${sectionStrings.join(" | ")}`);
|
|
5874
|
-
}
|
|
5875
|
-
seekInfiniteLoop.registerSeek(seekTo);
|
|
5876
|
-
if (seekTo <= iterator.counter.getOffset() && mode === "download") {
|
|
5877
|
-
throw new Error(`Seeking backwards is not supported in parseAndDownloadMedia() mode. Current position: ${iterator.counter.getOffset()}, seekTo: ${seekTo}`);
|
|
5878
|
-
}
|
|
5879
|
-
if (seekTo > contentLength) {
|
|
5880
|
-
throw new Error(`Cannot seek beyond the end of the file: ${seekTo} > ${contentLength}`);
|
|
5845
|
+
if (tracks2.getTracks().find((t) => t.trackId === track.trackId)) {
|
|
5846
|
+
Log.trace(logLevel, `Track ${track.trackId} already registered, skipping`);
|
|
5847
|
+
return null;
|
|
5881
5848
|
}
|
|
5882
|
-
if (
|
|
5883
|
-
|
|
5884
|
-
iterator.discard(seekTo - iterator.counter.getOffset());
|
|
5885
|
-
return;
|
|
5849
|
+
if (track.type !== "audio") {
|
|
5850
|
+
throw new Error("Expected audio track");
|
|
5886
5851
|
}
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
Log.verbose(logLevel, `Already at the desired position, seeking done`);
|
|
5891
|
-
controller._internals.performedSeeksSignal.markLastSeekAsUserInitiated();
|
|
5892
|
-
return;
|
|
5852
|
+
tracks2.addTrack(track);
|
|
5853
|
+
if (!onAudioTrack) {
|
|
5854
|
+
return null;
|
|
5893
5855
|
}
|
|
5894
|
-
const
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
to: seekTo,
|
|
5898
|
-
type: userInitiated ? "user-initiated" : "internal"
|
|
5856
|
+
const callback = await onAudioTrack({
|
|
5857
|
+
track,
|
|
5858
|
+
container
|
|
5899
5859
|
});
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
seekTo,
|
|
5903
|
-
userInitiated,
|
|
5904
|
-
iterator,
|
|
5905
|
-
fields,
|
|
5906
|
-
logLevel,
|
|
5907
|
-
currentReader,
|
|
5908
|
-
readerInterface,
|
|
5909
|
-
src,
|
|
5910
|
-
controller,
|
|
5911
|
-
discardReadBytes
|
|
5912
|
-
});
|
|
5913
|
-
} else {
|
|
5914
|
-
await seekBackwards({
|
|
5915
|
-
controller,
|
|
5916
|
-
seekTo,
|
|
5917
|
-
iterator,
|
|
5918
|
-
logLevel,
|
|
5919
|
-
currentReader,
|
|
5920
|
-
readerInterface,
|
|
5921
|
-
src
|
|
5922
|
-
});
|
|
5923
|
-
}
|
|
5924
|
-
await controller._internals.checkForAbortAndPause();
|
|
5860
|
+
await registerAudioSampleCallback(track.trackId, callback ?? null);
|
|
5861
|
+
return callback;
|
|
5925
5862
|
};
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
mediaSectionState: mediaSectionState2,
|
|
5931
|
-
logLevel,
|
|
5932
|
-
iterator,
|
|
5933
|
-
structureState,
|
|
5934
|
-
mp4HeaderSegment,
|
|
5935
|
-
isoState
|
|
5863
|
+
var registerVideoTrackWhenProfileIsAvailable = ({
|
|
5864
|
+
state,
|
|
5865
|
+
track,
|
|
5866
|
+
container
|
|
5936
5867
|
}) => {
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
const seekingInfo = getSeekingInfo({
|
|
5946
|
-
structureState,
|
|
5947
|
-
mp4HeaderSegment,
|
|
5948
|
-
mediaSectionState: mediaSectionState2,
|
|
5949
|
-
isoState
|
|
5950
|
-
});
|
|
5951
|
-
if (!seekingInfo) {
|
|
5952
|
-
Log.trace(logLevel, "No seeking info, cannot seek yet");
|
|
5953
|
-
return {
|
|
5954
|
-
type: "valid-but-must-wait"
|
|
5955
|
-
};
|
|
5956
|
-
}
|
|
5957
|
-
const seekingByte = await getSeekingByte({
|
|
5958
|
-
info: seekingInfo,
|
|
5959
|
-
time: seek2.time,
|
|
5960
|
-
logLevel,
|
|
5961
|
-
currentPosition: iterator.counter.getOffset(),
|
|
5962
|
-
isoState
|
|
5868
|
+
state.riff.registerOnAvcProfileCallback(async (profile) => {
|
|
5869
|
+
await registerVideoTrack({
|
|
5870
|
+
track: addAvcProfileToTrack(track, profile),
|
|
5871
|
+
container,
|
|
5872
|
+
logLevel: state.logLevel,
|
|
5873
|
+
onVideoTrack: state.onVideoTrack,
|
|
5874
|
+
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
5875
|
+
tracks: state.callbacks.tracks
|
|
5963
5876
|
});
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
|
|
5877
|
+
});
|
|
5878
|
+
};
|
|
5879
|
+
|
|
5880
|
+
// src/containers/avc/interpret-sps.ts
|
|
5881
|
+
var getDimensionsFromSps = (sps) => {
|
|
5882
|
+
const height = sps.pic_height_in_map_units_minus1;
|
|
5883
|
+
const width = sps.pic_width_in_mbs_minus1;
|
|
5884
|
+
return {
|
|
5885
|
+
height: (height + 1) * 16 - (sps.frame_crop_bottom_offset ?? 0) * 2 - (sps.frame_crop_top_offset ?? 0) * 2,
|
|
5886
|
+
width: (width + 1) * 16 - (sps.frame_crop_right_offset ?? 0) * 2 - (sps.frame_crop_left_offset ?? 0) * 2
|
|
5887
|
+
};
|
|
5888
|
+
};
|
|
5889
|
+
var getSampleAspectRatioFromSps = (sps) => {
|
|
5890
|
+
if (sps.vui_parameters?.sar_height && sps.vui_parameters.sar_width) {
|
|
5967
5891
|
return {
|
|
5968
|
-
|
|
5969
|
-
|
|
5892
|
+
width: sps.vui_parameters.sar_width,
|
|
5893
|
+
height: sps.vui_parameters.sar_height
|
|
5970
5894
|
};
|
|
5971
5895
|
}
|
|
5972
|
-
|
|
5896
|
+
return {
|
|
5897
|
+
width: 1,
|
|
5898
|
+
height: 1
|
|
5899
|
+
};
|
|
5973
5900
|
};
|
|
5974
|
-
var
|
|
5901
|
+
var getVideoColorFromSps = (sps) => {
|
|
5902
|
+
const matrixCoefficients2 = sps.vui_parameters?.matrix_coefficients;
|
|
5903
|
+
const transferCharacteristics2 = sps.vui_parameters?.transfer_characteristics;
|
|
5904
|
+
const colorPrimaries = sps.vui_parameters?.colour_primaries;
|
|
5975
5905
|
return {
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
structureState: state.structure,
|
|
5981
|
-
src: state.src,
|
|
5982
|
-
contentLength: state.contentLength,
|
|
5983
|
-
readerInterface: state.readerInterface,
|
|
5984
|
-
mediaSection: state.mediaSection,
|
|
5985
|
-
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
5986
|
-
mode: state.mode,
|
|
5987
|
-
seekInfiniteLoop: state.seekInfiniteLoop,
|
|
5988
|
-
currentReader: state.currentReader,
|
|
5989
|
-
discardReadBytes: state.discardReadBytes,
|
|
5990
|
-
fields: state.fields
|
|
5906
|
+
matrixCoefficients: matrixCoefficients2 ? getMatrixCoefficientsFromIndex(matrixCoefficients2) : null,
|
|
5907
|
+
transferCharacteristics: transferCharacteristics2 ? getTransferCharacteristicsFromIndex(transferCharacteristics2) : null,
|
|
5908
|
+
primaries: colorPrimaries ? getPrimariesFromIndex(colorPrimaries) : null,
|
|
5909
|
+
fullRange: sps.vui_parameters?.video_full_range_flag ?? null
|
|
5991
5910
|
};
|
|
5992
5911
|
};
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
isoState,
|
|
6000
|
-
iterator,
|
|
6001
|
-
structureState,
|
|
6002
|
-
src,
|
|
6003
|
-
contentLength,
|
|
6004
|
-
readerInterface,
|
|
6005
|
-
mode,
|
|
6006
|
-
seekInfiniteLoop,
|
|
6007
|
-
currentReader,
|
|
6008
|
-
discardReadBytes,
|
|
6009
|
-
fields
|
|
6010
|
-
} = options;
|
|
6011
|
-
const seek2 = controller._internals.seekSignal.getSeek();
|
|
6012
|
-
if (!seek2) {
|
|
6013
|
-
return;
|
|
6014
|
-
}
|
|
6015
|
-
Log.trace(logLevel, `Has seek request: ${JSON.stringify(seek2)}`);
|
|
6016
|
-
const resolution = await turnSeekIntoByte({
|
|
6017
|
-
seek: seek2,
|
|
6018
|
-
mediaSectionState: mediaSection,
|
|
6019
|
-
logLevel,
|
|
6020
|
-
iterator,
|
|
6021
|
-
structureState,
|
|
6022
|
-
mp4HeaderSegment,
|
|
6023
|
-
isoState
|
|
6024
|
-
});
|
|
6025
|
-
Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
|
|
6026
|
-
if (resolution.type === "intermediary-seek") {
|
|
6027
|
-
await performSeek({
|
|
6028
|
-
seekTo: resolution.byte,
|
|
6029
|
-
userInitiated: false,
|
|
6030
|
-
controller,
|
|
6031
|
-
mediaSection,
|
|
6032
|
-
iterator,
|
|
6033
|
-
logLevel,
|
|
6034
|
-
mode,
|
|
6035
|
-
contentLength,
|
|
6036
|
-
seekInfiniteLoop,
|
|
6037
|
-
currentReader,
|
|
6038
|
-
readerInterface,
|
|
6039
|
-
src,
|
|
6040
|
-
discardReadBytes,
|
|
6041
|
-
fields
|
|
6042
|
-
});
|
|
6043
|
-
return;
|
|
5912
|
+
|
|
5913
|
+
// src/containers/avc/key.ts
|
|
5914
|
+
var getKeyFrameOrDeltaFromAvcInfo = (infos) => {
|
|
5915
|
+
const keyOrDelta = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
|
|
5916
|
+
if (!keyOrDelta) {
|
|
5917
|
+
throw new Error("expected avc to contain info about key or delta");
|
|
6044
5918
|
}
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
5919
|
+
return keyOrDelta.type === "keyframe" ? "key" : "delta";
|
|
5920
|
+
};
|
|
5921
|
+
|
|
5922
|
+
// src/containers/avc/parse-avc.ts
|
|
5923
|
+
var Extended_SAR = 255;
|
|
5924
|
+
var readVuiParameters = (iterator) => {
|
|
5925
|
+
let sar_width = null;
|
|
5926
|
+
let sar_height = null;
|
|
5927
|
+
let overscan_appropriate_flag = null;
|
|
5928
|
+
let video_format = null;
|
|
5929
|
+
let video_full_range_flag = null;
|
|
5930
|
+
let colour_primaries = null;
|
|
5931
|
+
let transfer_characteristics = null;
|
|
5932
|
+
let matrix_coefficients = null;
|
|
5933
|
+
let chroma_sample_loc_type_top_field = null;
|
|
5934
|
+
let chroma_sample_loc_type_bottom_field = null;
|
|
5935
|
+
const aspect_ratio_info_present_flag = iterator.getBits(1);
|
|
5936
|
+
if (aspect_ratio_info_present_flag) {
|
|
5937
|
+
const aspect_ratio_idc = iterator.getBits(8);
|
|
5938
|
+
if (aspect_ratio_idc === Extended_SAR) {
|
|
5939
|
+
sar_width = iterator.getBits(16);
|
|
5940
|
+
sar_height = iterator.getBits(16);
|
|
6066
5941
|
}
|
|
6067
|
-
return;
|
|
6068
5942
|
}
|
|
6069
|
-
|
|
6070
|
-
|
|
5943
|
+
const overscan_info_present_flag = iterator.getBits(1);
|
|
5944
|
+
if (overscan_info_present_flag) {
|
|
5945
|
+
overscan_appropriate_flag = iterator.getBits(1);
|
|
6071
5946
|
}
|
|
6072
|
-
|
|
6073
|
-
|
|
5947
|
+
const video_signal_type_present_flag = iterator.getBits(1);
|
|
5948
|
+
if (video_signal_type_present_flag) {
|
|
5949
|
+
video_format = iterator.getBits(3);
|
|
5950
|
+
video_full_range_flag = Boolean(iterator.getBits(1));
|
|
5951
|
+
const colour_description_present_flag = iterator.getBits(1);
|
|
5952
|
+
if (colour_description_present_flag) {
|
|
5953
|
+
colour_primaries = iterator.getBits(8);
|
|
5954
|
+
transfer_characteristics = iterator.getBits(8);
|
|
5955
|
+
matrix_coefficients = iterator.getBits(8);
|
|
5956
|
+
}
|
|
5957
|
+
}
|
|
5958
|
+
const chroma_loc_info_present_flag = iterator.getBits(1);
|
|
5959
|
+
if (chroma_loc_info_present_flag) {
|
|
5960
|
+
chroma_sample_loc_type_top_field = iterator.readExpGolomb();
|
|
5961
|
+
chroma_sample_loc_type_bottom_field = iterator.readExpGolomb();
|
|
6074
5962
|
}
|
|
5963
|
+
return {
|
|
5964
|
+
sar_width,
|
|
5965
|
+
sar_height,
|
|
5966
|
+
overscan_appropriate_flag,
|
|
5967
|
+
chroma_sample_loc_type_bottom_field,
|
|
5968
|
+
chroma_sample_loc_type_top_field,
|
|
5969
|
+
colour_primaries,
|
|
5970
|
+
matrix_coefficients,
|
|
5971
|
+
transfer_characteristics,
|
|
5972
|
+
video_format,
|
|
5973
|
+
video_full_range_flag
|
|
5974
|
+
};
|
|
6075
5975
|
};
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
5976
|
+
var readSps = (iterator) => {
|
|
5977
|
+
const profile = iterator.getUint8();
|
|
5978
|
+
const compatibility = iterator.getUint8();
|
|
5979
|
+
const level = iterator.getUint8();
|
|
5980
|
+
iterator.startReadingBits();
|
|
5981
|
+
const seq_parameter_set_id = iterator.readExpGolomb();
|
|
5982
|
+
let separate_colour_plane_flag = null;
|
|
5983
|
+
let bit_depth_luma_minus8 = null;
|
|
5984
|
+
let bit_depth_chroma_minus8 = null;
|
|
5985
|
+
let qpprime_y_zero_transform_bypass_flag = null;
|
|
5986
|
+
let log2_max_frame_num_minus4 = null;
|
|
5987
|
+
let log2_max_pic_order_cnt_lsb_minus4 = null;
|
|
5988
|
+
let max_num_ref_frames = null;
|
|
5989
|
+
let gaps_in_frame_num_value_allowed_flag = null;
|
|
5990
|
+
let mb_adaptive_frame_field_flag = null;
|
|
5991
|
+
let direct_8x8_inference_flag = null;
|
|
5992
|
+
let frame_crop_left_offset = null;
|
|
5993
|
+
let frame_crop_right_offset = null;
|
|
5994
|
+
let frame_crop_top_offset = null;
|
|
5995
|
+
let frame_crop_bottom_offset = null;
|
|
5996
|
+
let vui_parameters = null;
|
|
5997
|
+
if (profile === 100 || profile === 110 || profile === 122 || profile === 244 || profile === 44 || profile === 83 || profile === 86 || profile === 118 || profile === 128 || profile === 138 || profile === 139 || profile === 134 || profile === 135) {
|
|
5998
|
+
const chromaFormat = iterator.readExpGolomb();
|
|
5999
|
+
if (chromaFormat === 3) {
|
|
6000
|
+
separate_colour_plane_flag = iterator.getBits(1);
|
|
6101
6001
|
}
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6002
|
+
bit_depth_luma_minus8 = iterator.readExpGolomb();
|
|
6003
|
+
bit_depth_chroma_minus8 = iterator.readExpGolomb();
|
|
6004
|
+
qpprime_y_zero_transform_bypass_flag = iterator.getBits(1);
|
|
6005
|
+
const seq_scaling_matrix_present_flag = iterator.getBits(1);
|
|
6006
|
+
const seq_scaling_list_present_flag = [];
|
|
6007
|
+
if (seq_scaling_matrix_present_flag) {
|
|
6008
|
+
for (let i = 0;i < (chromaFormat !== 3 ? 8 : 12); i++) {
|
|
6009
|
+
seq_scaling_list_present_flag[i] = iterator.getBits(1);
|
|
6010
|
+
if (seq_scaling_list_present_flag[i]) {
|
|
6011
|
+
if (i < 6) {
|
|
6012
|
+
throw new Error("Not implemented");
|
|
6013
|
+
} else {
|
|
6014
|
+
throw new Error("Not implemented");
|
|
6109
6015
|
}
|
|
6110
|
-
emittedFields.durationInSeconds = true;
|
|
6111
6016
|
}
|
|
6112
6017
|
}
|
|
6113
|
-
continue;
|
|
6114
6018
|
}
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6019
|
+
}
|
|
6020
|
+
log2_max_frame_num_minus4 = iterator.readExpGolomb();
|
|
6021
|
+
const pic_order_cnt_type = iterator.readExpGolomb();
|
|
6022
|
+
if (pic_order_cnt_type === 0) {
|
|
6023
|
+
log2_max_pic_order_cnt_lsb_minus4 = iterator.readExpGolomb();
|
|
6024
|
+
} else if (pic_order_cnt_type === 1) {
|
|
6025
|
+
throw new Error("pic_order_cnt_type = 1 not implemented");
|
|
6026
|
+
}
|
|
6027
|
+
max_num_ref_frames = iterator.readExpGolomb();
|
|
6028
|
+
gaps_in_frame_num_value_allowed_flag = iterator.getBits(1);
|
|
6029
|
+
const pic_width_in_mbs_minus1 = iterator.readExpGolomb();
|
|
6030
|
+
const pic_height_in_map_units_minus1 = iterator.readExpGolomb();
|
|
6031
|
+
const frame_mbs_only_flag = iterator.getBits(1);
|
|
6032
|
+
if (!frame_mbs_only_flag) {
|
|
6033
|
+
mb_adaptive_frame_field_flag = iterator.getBits(1);
|
|
6034
|
+
}
|
|
6035
|
+
direct_8x8_inference_flag = iterator.getBits(1);
|
|
6036
|
+
const frame_cropping_flag = iterator.getBits(1);
|
|
6037
|
+
if (frame_cropping_flag) {
|
|
6038
|
+
frame_crop_left_offset = iterator.readExpGolomb();
|
|
6039
|
+
frame_crop_right_offset = iterator.readExpGolomb();
|
|
6040
|
+
frame_crop_top_offset = iterator.readExpGolomb();
|
|
6041
|
+
frame_crop_bottom_offset = iterator.readExpGolomb();
|
|
6042
|
+
}
|
|
6043
|
+
const vui_parameters_present_flag = iterator.getBits(1);
|
|
6044
|
+
if (vui_parameters_present_flag) {
|
|
6045
|
+
vui_parameters = readVuiParameters(iterator);
|
|
6046
|
+
}
|
|
6047
|
+
iterator.stopReadingBits();
|
|
6048
|
+
return {
|
|
6049
|
+
profile,
|
|
6050
|
+
compatibility,
|
|
6051
|
+
level,
|
|
6052
|
+
bit_depth_chroma_minus8,
|
|
6053
|
+
bit_depth_luma_minus8,
|
|
6054
|
+
gaps_in_frame_num_value_allowed_flag,
|
|
6055
|
+
log2_max_frame_num_minus4,
|
|
6056
|
+
log2_max_pic_order_cnt_lsb_minus4,
|
|
6057
|
+
max_num_ref_frames,
|
|
6058
|
+
pic_height_in_map_units_minus1,
|
|
6059
|
+
pic_width_in_mbs_minus1,
|
|
6060
|
+
qpprime_y_zero_transform_bypass_flag,
|
|
6061
|
+
separate_colour_plane_flag,
|
|
6062
|
+
seq_parameter_set_id,
|
|
6063
|
+
direct_8x8_inference_flag,
|
|
6064
|
+
frame_crop_bottom_offset,
|
|
6065
|
+
frame_crop_left_offset,
|
|
6066
|
+
frame_crop_right_offset,
|
|
6067
|
+
frame_crop_top_offset,
|
|
6068
|
+
mb_adaptive_frame_field_flag,
|
|
6069
|
+
vui_parameters
|
|
6070
|
+
};
|
|
6071
|
+
};
|
|
6072
|
+
var findEnd = (buffer) => {
|
|
6073
|
+
let zeroesInARow = 0;
|
|
6074
|
+
for (let i = 0;i < buffer.length; i++) {
|
|
6075
|
+
const val = buffer[i];
|
|
6076
|
+
if (val === 0) {
|
|
6077
|
+
zeroesInARow++;
|
|
6124
6078
|
continue;
|
|
6125
6079
|
}
|
|
6126
|
-
if (
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6080
|
+
if (zeroesInARow >= 2 && val === 1) {
|
|
6081
|
+
return i - zeroesInARow;
|
|
6082
|
+
}
|
|
6083
|
+
zeroesInARow = 0;
|
|
6084
|
+
}
|
|
6085
|
+
return null;
|
|
6086
|
+
};
|
|
6087
|
+
var inspect = (buffer) => {
|
|
6088
|
+
const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
|
|
6089
|
+
iterator.startReadingBits();
|
|
6090
|
+
iterator.getBits(1);
|
|
6091
|
+
iterator.getBits(2);
|
|
6092
|
+
const type = iterator.getBits(5);
|
|
6093
|
+
iterator.stopReadingBits();
|
|
6094
|
+
if (type === 7) {
|
|
6095
|
+
const end = findEnd(buffer);
|
|
6096
|
+
const data = readSps(iterator);
|
|
6097
|
+
const sps = buffer.slice(0, end === null ? Infinity : end);
|
|
6098
|
+
return {
|
|
6099
|
+
spsData: data,
|
|
6100
|
+
sps,
|
|
6101
|
+
type: "avc-profile"
|
|
6102
|
+
};
|
|
6103
|
+
}
|
|
6104
|
+
if (type === 5) {
|
|
6105
|
+
return {
|
|
6106
|
+
type: "keyframe"
|
|
6107
|
+
};
|
|
6108
|
+
}
|
|
6109
|
+
if (type === 8) {
|
|
6110
|
+
const end = findEnd(buffer);
|
|
6111
|
+
const pps = buffer.slice(0, end === null ? Infinity : end);
|
|
6112
|
+
return {
|
|
6113
|
+
type: "avc-pps",
|
|
6114
|
+
pps
|
|
6115
|
+
};
|
|
6116
|
+
}
|
|
6117
|
+
if (type === 1) {
|
|
6118
|
+
return {
|
|
6119
|
+
type: "delta-frame"
|
|
6120
|
+
};
|
|
6121
|
+
}
|
|
6122
|
+
iterator.destroy();
|
|
6123
|
+
return null;
|
|
6124
|
+
};
|
|
6125
|
+
var parseAvc = (buffer) => {
|
|
6126
|
+
let zeroesInARow = 0;
|
|
6127
|
+
const infos = [];
|
|
6128
|
+
for (let i = 0;i < buffer.length; i++) {
|
|
6129
|
+
const val = buffer[i];
|
|
6130
|
+
if (val === 0) {
|
|
6131
|
+
zeroesInARow++;
|
|
6132
|
+
continue;
|
|
6133
|
+
}
|
|
6134
|
+
if (zeroesInARow >= 2 && val === 1) {
|
|
6135
|
+
zeroesInARow = 0;
|
|
6136
|
+
const info = inspect(buffer.slice(i + 1, i + 100));
|
|
6137
|
+
if (info) {
|
|
6138
|
+
infos.push(info);
|
|
6139
|
+
if (info.type === "keyframe" || info.type === "delta-frame") {
|
|
6140
|
+
break;
|
|
6141
|
+
}
|
|
6142
|
+
}
|
|
6143
|
+
}
|
|
6144
|
+
if (val !== 1) {
|
|
6145
|
+
zeroesInARow = 0;
|
|
6146
|
+
}
|
|
6147
|
+
}
|
|
6148
|
+
return infos;
|
|
6149
|
+
};
|
|
6150
|
+
|
|
6151
|
+
// src/containers/avc/sps-and-pps.ts
|
|
6152
|
+
var getSpsAndPps = (infos) => {
|
|
6153
|
+
const avcProfile = infos.find((i) => i.type === "avc-profile");
|
|
6154
|
+
const ppsProfile = infos.find((i) => i.type === "avc-pps");
|
|
6155
|
+
if (!avcProfile || !ppsProfile) {
|
|
6156
|
+
throw new Error("Expected avcProfile and ppsProfile");
|
|
6157
|
+
}
|
|
6158
|
+
return { pps: ppsProfile, sps: avcProfile };
|
|
6159
|
+
};
|
|
6160
|
+
|
|
6161
|
+
// src/containers/transport-stream/handle-avc-packet.ts
|
|
6162
|
+
var MPEG_TIMESCALE = 90000;
|
|
6163
|
+
var handleAvcPacket = async ({
|
|
6164
|
+
streamBuffer,
|
|
6165
|
+
programId,
|
|
6166
|
+
offset,
|
|
6167
|
+
sampleCallbacks,
|
|
6168
|
+
logLevel,
|
|
6169
|
+
onVideoTrack,
|
|
6170
|
+
transportStream,
|
|
6171
|
+
makeSamplesStartAtZero
|
|
6172
|
+
}) => {
|
|
6173
|
+
const avc = parseAvc(streamBuffer.getBuffer());
|
|
6174
|
+
const isTrackRegistered = sampleCallbacks.tracks.getTracks().find((t) => {
|
|
6175
|
+
return t.trackId === programId;
|
|
6176
|
+
});
|
|
6177
|
+
if (!isTrackRegistered) {
|
|
6178
|
+
const spsAndPps = getSpsAndPps(avc);
|
|
6179
|
+
const dimensions = getDimensionsFromSps(spsAndPps.sps.spsData);
|
|
6180
|
+
const sampleAspectRatio = getSampleAspectRatioFromSps(spsAndPps.sps.spsData);
|
|
6181
|
+
const startOffset = makeSamplesStartAtZero ? Math.min(streamBuffer.pesHeader.pts, streamBuffer.pesHeader.dts ?? Infinity) : 0;
|
|
6182
|
+
transportStream.startOffset.setOffset(programId, startOffset);
|
|
6183
|
+
const track = {
|
|
6184
|
+
m3uStreamFormat: null,
|
|
6185
|
+
rotation: 0,
|
|
6186
|
+
trackId: programId,
|
|
6187
|
+
type: "video",
|
|
6188
|
+
timescale: MPEG_TIMESCALE,
|
|
6189
|
+
codec: getCodecStringFromSpsAndPps(spsAndPps.sps),
|
|
6190
|
+
codecPrivate: createSpsPpsData(spsAndPps),
|
|
6191
|
+
fps: null,
|
|
6192
|
+
codedWidth: dimensions.width,
|
|
6193
|
+
codedHeight: dimensions.height,
|
|
6194
|
+
height: dimensions.height,
|
|
6195
|
+
width: dimensions.width,
|
|
6196
|
+
displayAspectWidth: dimensions.width,
|
|
6197
|
+
displayAspectHeight: dimensions.height,
|
|
6198
|
+
trakBox: null,
|
|
6199
|
+
codecWithoutConfig: "h264",
|
|
6200
|
+
description: undefined,
|
|
6201
|
+
sampleAspectRatio: {
|
|
6202
|
+
denominator: sampleAspectRatio.height,
|
|
6203
|
+
numerator: sampleAspectRatio.width
|
|
6204
|
+
},
|
|
6205
|
+
color: getVideoColorFromSps(spsAndPps.sps.spsData)
|
|
6206
|
+
};
|
|
6207
|
+
await registerVideoTrack({
|
|
6208
|
+
track,
|
|
6209
|
+
container: "transport-stream",
|
|
6210
|
+
logLevel,
|
|
6211
|
+
onVideoTrack,
|
|
6212
|
+
registerVideoSampleCallback: sampleCallbacks.registerVideoSampleCallback,
|
|
6213
|
+
tracks: sampleCallbacks.tracks
|
|
6214
|
+
});
|
|
6215
|
+
}
|
|
6216
|
+
const type = getKeyFrameOrDeltaFromAvcInfo(avc);
|
|
6217
|
+
const sample = {
|
|
6218
|
+
cts: streamBuffer.pesHeader.pts - transportStream.startOffset.getOffset(programId),
|
|
6219
|
+
dts: (streamBuffer.pesHeader.dts ?? streamBuffer.pesHeader.pts) - transportStream.startOffset.getOffset(programId),
|
|
6220
|
+
timestamp: streamBuffer.pesHeader.pts - transportStream.startOffset.getOffset(programId),
|
|
6221
|
+
duration: undefined,
|
|
6222
|
+
data: streamBuffer.getBuffer(),
|
|
6223
|
+
trackId: programId,
|
|
6224
|
+
type,
|
|
6225
|
+
offset,
|
|
6226
|
+
timescale: MPEG_TIMESCALE
|
|
6227
|
+
};
|
|
6228
|
+
if (type === "key") {
|
|
6229
|
+
transportStream.observedPesHeaders.markPtsAsKeyframe(streamBuffer.pesHeader.pts);
|
|
6230
|
+
}
|
|
6231
|
+
await emitVideoSample({
|
|
6232
|
+
trackId: programId,
|
|
6233
|
+
videoSample: convertAudioOrVideoSampleToWebCodecsTimestamps({
|
|
6234
|
+
sample,
|
|
6235
|
+
timescale: MPEG_TIMESCALE
|
|
6236
|
+
}),
|
|
6237
|
+
callbacks: sampleCallbacks
|
|
6238
|
+
});
|
|
6239
|
+
transportStream.lastEmittedSample.setLastEmittedSample(sample);
|
|
6240
|
+
};
|
|
6241
|
+
|
|
6242
|
+
// src/state/transport-stream/observed-pes-header.ts
|
|
6243
|
+
var makeObservedPesHeader = () => {
|
|
6244
|
+
const pesHeaders = [];
|
|
6245
|
+
const confirmedAsKeyframe = [];
|
|
6246
|
+
const state = {
|
|
6247
|
+
pesHeaders,
|
|
6248
|
+
addPesHeader: (pesHeader) => {
|
|
6249
|
+
if (pesHeaders.find((p) => p.offset === pesHeader.offset)) {
|
|
6250
|
+
return;
|
|
6251
|
+
}
|
|
6252
|
+
pesHeaders.push(pesHeader);
|
|
6253
|
+
},
|
|
6254
|
+
markPtsAsKeyframe: (pts) => {
|
|
6255
|
+
confirmedAsKeyframe.push(pts);
|
|
6256
|
+
},
|
|
6257
|
+
getPesKeyframeHeaders: () => {
|
|
6258
|
+
return pesHeaders.filter((p) => confirmedAsKeyframe.includes(p.pts));
|
|
6259
|
+
}
|
|
6260
|
+
};
|
|
6261
|
+
return state;
|
|
6262
|
+
};
|
|
6263
|
+
var getLastKeyFrameBeforeTimeInSeconds = ({
|
|
6264
|
+
observedPesHeaders,
|
|
6265
|
+
timeInSeconds,
|
|
6266
|
+
ptsStartOffset
|
|
6267
|
+
}) => {
|
|
6268
|
+
return observedPesHeaders.findLast((k) => (k.pts - ptsStartOffset) / MPEG_TIMESCALE <= timeInSeconds);
|
|
6269
|
+
};
|
|
6270
|
+
|
|
6271
|
+
// src/get-seeking-byte.ts
|
|
6272
|
+
var getSeekingByte = ({
|
|
6273
|
+
info,
|
|
6274
|
+
time,
|
|
6275
|
+
logLevel,
|
|
6276
|
+
currentPosition,
|
|
6277
|
+
isoState,
|
|
6278
|
+
transportStream,
|
|
6279
|
+
webmState,
|
|
6280
|
+
mediaSection,
|
|
6281
|
+
keyframes
|
|
6282
|
+
}) => {
|
|
6283
|
+
if (info.type === "iso-base-media-seeking-info") {
|
|
6284
|
+
return getSeekingByteFromIsoBaseMedia({
|
|
6285
|
+
info,
|
|
6286
|
+
time,
|
|
6287
|
+
logLevel,
|
|
6288
|
+
currentPosition,
|
|
6289
|
+
isoState
|
|
6290
|
+
});
|
|
6291
|
+
}
|
|
6292
|
+
if (info.type === "wav-seeking-info") {
|
|
6293
|
+
return getSeekingByteFromWav({
|
|
6294
|
+
info,
|
|
6295
|
+
time
|
|
6296
|
+
});
|
|
6297
|
+
}
|
|
6298
|
+
if (info.type === "webm-seeking-info") {
|
|
6299
|
+
return getSeekingByteFromMatroska({
|
|
6300
|
+
info,
|
|
6301
|
+
time,
|
|
6302
|
+
webmState,
|
|
6303
|
+
logLevel,
|
|
6304
|
+
mediaSection,
|
|
6305
|
+
keyframes
|
|
6306
|
+
});
|
|
6307
|
+
}
|
|
6308
|
+
if (info.type === "transport-stream-seeking-info") {
|
|
6309
|
+
const lastKeyframeBeforeTimeInSeconds = getLastKeyFrameBeforeTimeInSeconds({
|
|
6310
|
+
observedPesHeaders: info.observedPesHeaders,
|
|
6311
|
+
timeInSeconds: time,
|
|
6312
|
+
ptsStartOffset: info.ptsStartOffset
|
|
6313
|
+
});
|
|
6314
|
+
const byte = lastKeyframeBeforeTimeInSeconds?.offset ?? 0;
|
|
6315
|
+
transportStream.resetBeforeSeek();
|
|
6316
|
+
return Promise.resolve({
|
|
6317
|
+
type: "do-seek",
|
|
6318
|
+
byte
|
|
6319
|
+
});
|
|
6320
|
+
}
|
|
6321
|
+
throw new Error(`Unknown seeking info type: ${info}`);
|
|
6322
|
+
};
|
|
6323
|
+
|
|
6324
|
+
// src/containers/iso-base-media/get-seeking-info-from-mp4.ts
|
|
6325
|
+
var getSeekingInfoFromMp4 = ({
|
|
6326
|
+
structureState,
|
|
6327
|
+
isoState,
|
|
6328
|
+
mp4HeaderSegment,
|
|
6329
|
+
mediaSectionState: mediaSectionState2
|
|
6330
|
+
}) => {
|
|
6331
|
+
const structure = structureState.getIsoStructure();
|
|
6332
|
+
const moovAtom = getMoovBoxFromState({
|
|
6333
|
+
isoState,
|
|
6334
|
+
mp4HeaderSegment,
|
|
6335
|
+
structureState
|
|
6336
|
+
});
|
|
6337
|
+
const moofBoxes = getMoofBoxes(structure.boxes);
|
|
6338
|
+
const tfraBoxes = getTfraBoxes(structure);
|
|
6339
|
+
if (!moovAtom) {
|
|
6340
|
+
return null;
|
|
6341
|
+
}
|
|
6342
|
+
return {
|
|
6343
|
+
type: "iso-base-media-seeking-info",
|
|
6344
|
+
moovBox: moovAtom,
|
|
6345
|
+
moofBoxes,
|
|
6346
|
+
tfraBoxes,
|
|
6347
|
+
mediaSections: mediaSectionState2.getMediaSections()
|
|
6348
|
+
};
|
|
6349
|
+
};
|
|
6350
|
+
|
|
6351
|
+
// src/containers/transport-stream/get-seeking-info.ts
|
|
6352
|
+
var getSeekingInfoFromTransportStream = (transportStream, tracksState) => {
|
|
6353
|
+
const firstVideoTrack = tracksState.getTracks().find((t) => t.type === "video");
|
|
6354
|
+
if (!firstVideoTrack) {
|
|
6355
|
+
throw new Error("No video track found");
|
|
6356
|
+
}
|
|
6357
|
+
return {
|
|
6358
|
+
type: "transport-stream-seeking-info",
|
|
6359
|
+
observedPesHeaders: transportStream.observedPesHeaders.getPesKeyframeHeaders(),
|
|
6360
|
+
ptsStartOffset: transportStream.startOffset.getOffset(firstVideoTrack.trackId)
|
|
6361
|
+
};
|
|
6362
|
+
};
|
|
6363
|
+
|
|
6364
|
+
// src/containers/wav/get-seeking-info.ts
|
|
6365
|
+
var getSeekingInfoFromWav = ({
|
|
6366
|
+
structure,
|
|
6367
|
+
mediaSectionState: mediaSectionState2
|
|
6368
|
+
}) => {
|
|
6369
|
+
const fmtBox = structure.boxes.find((box) => box.type === "wav-fmt");
|
|
6370
|
+
if (!fmtBox) {
|
|
6371
|
+
return null;
|
|
6372
|
+
}
|
|
6373
|
+
const mediaSection = mediaSectionState2.getMediaSections();
|
|
6374
|
+
if (mediaSection.length !== 1) {
|
|
6375
|
+
return null;
|
|
6376
|
+
}
|
|
6377
|
+
return {
|
|
6378
|
+
type: "wav-seeking-info",
|
|
6379
|
+
sampleRate: fmtBox.sampleRate,
|
|
6380
|
+
blockAlign: fmtBox.blockAlign,
|
|
6381
|
+
mediaSections: mediaSection[0]
|
|
6382
|
+
};
|
|
6383
|
+
};
|
|
6384
|
+
|
|
6385
|
+
// src/containers/webm/seek/get-seeking-info.ts
|
|
6386
|
+
var getSeekingInfoFromMatroska = (tracksState) => {
|
|
6387
|
+
const tracks2 = tracksState.getTracks();
|
|
6388
|
+
const firstVideoTrack = tracks2.find((track) => track.type === "video");
|
|
6389
|
+
return {
|
|
6390
|
+
type: "webm-seeking-info",
|
|
6391
|
+
track: firstVideoTrack ? {
|
|
6392
|
+
timescale: firstVideoTrack.timescale,
|
|
6393
|
+
trackId: firstVideoTrack.trackId
|
|
6394
|
+
} : null
|
|
6395
|
+
};
|
|
6396
|
+
};
|
|
6397
|
+
|
|
6398
|
+
// src/get-seeking-info.ts
|
|
6399
|
+
var getSeekingInfo = ({
|
|
6400
|
+
structureState,
|
|
6401
|
+
mp4HeaderSegment,
|
|
6402
|
+
mediaSectionState: mediaSectionState2,
|
|
6403
|
+
isoState,
|
|
6404
|
+
transportStream,
|
|
6405
|
+
tracksState
|
|
6406
|
+
}) => {
|
|
6407
|
+
const structure = structureState.getStructureOrNull();
|
|
6408
|
+
if (!structure) {
|
|
6409
|
+
return null;
|
|
6410
|
+
}
|
|
6411
|
+
if (structure.type === "iso-base-media") {
|
|
6412
|
+
return getSeekingInfoFromMp4({
|
|
6413
|
+
structureState,
|
|
6414
|
+
isoState,
|
|
6415
|
+
mp4HeaderSegment,
|
|
6416
|
+
mediaSectionState: mediaSectionState2
|
|
6417
|
+
});
|
|
6418
|
+
}
|
|
6419
|
+
if (structure.type === "wav") {
|
|
6420
|
+
return getSeekingInfoFromWav({
|
|
6421
|
+
structure,
|
|
6422
|
+
mediaSectionState: mediaSectionState2
|
|
6423
|
+
});
|
|
6424
|
+
}
|
|
6425
|
+
if (structure.type === "matroska") {
|
|
6426
|
+
return getSeekingInfoFromMatroska(tracksState);
|
|
6427
|
+
}
|
|
6428
|
+
if (structure.type === "transport-stream") {
|
|
6429
|
+
return getSeekingInfoFromTransportStream(transportStream, tracksState);
|
|
6430
|
+
}
|
|
6431
|
+
throw new Error(`Seeking is not supported for this format: ${structure.type}`);
|
|
6432
|
+
};
|
|
6433
|
+
|
|
6434
|
+
// src/seek-backwards.ts
|
|
6435
|
+
var seekBackwards = async ({
|
|
6436
|
+
iterator,
|
|
6437
|
+
seekTo,
|
|
6438
|
+
readerInterface,
|
|
6439
|
+
src,
|
|
6440
|
+
controller,
|
|
6441
|
+
logLevel,
|
|
6442
|
+
currentReader
|
|
6443
|
+
}) => {
|
|
6444
|
+
const howManyBytesWeCanGoBack = iterator.counter.getDiscardedOffset();
|
|
6445
|
+
if (iterator.counter.getOffset() - howManyBytesWeCanGoBack <= seekTo) {
|
|
6446
|
+
iterator.skipTo(seekTo);
|
|
6447
|
+
return;
|
|
6448
|
+
}
|
|
6449
|
+
const time = Date.now();
|
|
6450
|
+
Log.verbose(logLevel, `Seeking in video from position ${iterator.counter.getOffset()} -> ${seekTo}. Re-reading because this portion is not available.`);
|
|
6451
|
+
const { reader: newReader } = await readerInterface.read({
|
|
6452
|
+
src,
|
|
6453
|
+
range: seekTo,
|
|
6454
|
+
controller
|
|
6455
|
+
});
|
|
6456
|
+
iterator.replaceData(new Uint8Array([]), seekTo);
|
|
6457
|
+
Log.verbose(logLevel, `Re-reading took ${Date.now() - time}ms. New position: ${iterator.counter.getOffset()}`);
|
|
6458
|
+
currentReader.setCurrent(newReader);
|
|
6459
|
+
};
|
|
6460
|
+
|
|
6461
|
+
// src/state/need-samples-for-fields.ts
|
|
6462
|
+
var fieldsNeedSamplesMap = {
|
|
6463
|
+
slowDurationInSeconds: true,
|
|
6464
|
+
slowFps: true,
|
|
6465
|
+
slowKeyframes: true,
|
|
6466
|
+
slowNumberOfFrames: true,
|
|
6467
|
+
audioCodec: false,
|
|
6468
|
+
container: false,
|
|
6469
|
+
dimensions: false,
|
|
6470
|
+
durationInSeconds: false,
|
|
6471
|
+
fps: false,
|
|
6472
|
+
internalStats: false,
|
|
6473
|
+
isHdr: false,
|
|
6474
|
+
name: false,
|
|
6475
|
+
rotation: false,
|
|
6476
|
+
size: false,
|
|
6477
|
+
structure: false,
|
|
6478
|
+
tracks: false,
|
|
6479
|
+
unrotatedDimensions: false,
|
|
6480
|
+
videoCodec: false,
|
|
6481
|
+
metadata: false,
|
|
6482
|
+
location: false,
|
|
6483
|
+
mimeType: false,
|
|
6484
|
+
keyframes: false,
|
|
6485
|
+
images: false,
|
|
6486
|
+
numberOfAudioChannels: false,
|
|
6487
|
+
sampleRate: false,
|
|
6488
|
+
slowAudioBitrate: true,
|
|
6489
|
+
slowVideoBitrate: true,
|
|
6490
|
+
m3uStreams: false
|
|
6491
|
+
};
|
|
6492
|
+
var needsToIterateOverSamples = ({
|
|
6493
|
+
fields,
|
|
6494
|
+
emittedFields
|
|
6495
|
+
}) => {
|
|
6496
|
+
const keys = Object.keys(fields ?? {});
|
|
6497
|
+
const selectedKeys = keys.filter((k) => fields[k]);
|
|
6498
|
+
return selectedKeys.some((k) => fieldsNeedSamplesMap[k] && !emittedFields[k]);
|
|
6499
|
+
};
|
|
6500
|
+
|
|
6501
|
+
// src/disallow-forward-seek-if-samples-are-needed.ts
|
|
6502
|
+
var disallowForwardSeekIfSamplesAreNeeded = ({
|
|
6503
|
+
seekTo,
|
|
6504
|
+
previousPosition,
|
|
6505
|
+
fields
|
|
6506
|
+
}) => {
|
|
6507
|
+
const fieldsNeedingSamples = Object.entries(fields).filter(([, value]) => value).map(([key]) => key).filter((key) => fieldsNeedSamplesMap[key]);
|
|
6508
|
+
if (fieldsNeedingSamples.length > 0) {
|
|
6509
|
+
throw new Error(`Forward seeking is not allowed when the following fields are requested from parseMedia(): ${fieldsNeedingSamples.join(", ")}. Seek was from 0x${previousPosition.toString(16)} to 0x${seekTo.toString(16)}. Either don't seek forward, or don't request these fields.`);
|
|
6510
|
+
}
|
|
6511
|
+
};
|
|
6512
|
+
|
|
6513
|
+
// src/seek-forwards.ts
|
|
6514
|
+
var seekForward = async ({
|
|
6515
|
+
seekTo,
|
|
6516
|
+
userInitiated,
|
|
6517
|
+
iterator,
|
|
6518
|
+
fields,
|
|
6519
|
+
logLevel,
|
|
6520
|
+
currentReader,
|
|
6521
|
+
readerInterface,
|
|
6522
|
+
src,
|
|
6523
|
+
controller,
|
|
6524
|
+
discardReadBytes
|
|
6525
|
+
}) => {
|
|
6526
|
+
if (userInitiated) {
|
|
6527
|
+
disallowForwardSeekIfSamplesAreNeeded({
|
|
6528
|
+
fields,
|
|
6529
|
+
seekTo,
|
|
6530
|
+
previousPosition: iterator.counter.getOffset()
|
|
6531
|
+
});
|
|
6532
|
+
}
|
|
6533
|
+
const alreadyHasBuffer = iterator.bytesRemaining() >= seekTo - iterator.counter.getOffset();
|
|
6534
|
+
Log.verbose(logLevel, `Performing seek from ${iterator.counter.getOffset()} to ${seekTo}`);
|
|
6535
|
+
if (alreadyHasBuffer) {
|
|
6536
|
+
iterator.skipTo(seekTo);
|
|
6537
|
+
Log.verbose(logLevel, `Already read ahead enough, skipping forward`);
|
|
6538
|
+
return;
|
|
6539
|
+
}
|
|
6540
|
+
const time = Date.now();
|
|
6541
|
+
Log.verbose(logLevel, `Skipping over video data from position ${iterator.counter.getOffset()} -> ${seekTo}. Re-reading because this portion is not available`);
|
|
6542
|
+
const { reader: newReader } = await readerInterface.read({
|
|
6543
|
+
src,
|
|
6544
|
+
range: seekTo,
|
|
6545
|
+
controller
|
|
6546
|
+
});
|
|
6547
|
+
iterator.skipTo(seekTo);
|
|
6548
|
+
await discardReadBytes(true);
|
|
6549
|
+
Log.verbose(logLevel, `Re-reading took ${Date.now() - time}ms. New position: ${iterator.counter.getOffset()}`);
|
|
6550
|
+
currentReader.setCurrent(newReader);
|
|
6551
|
+
};
|
|
6552
|
+
|
|
6553
|
+
// src/perform-seek.ts
|
|
6554
|
+
var performSeek = async ({
|
|
6555
|
+
seekTo,
|
|
6556
|
+
userInitiated,
|
|
6557
|
+
controller,
|
|
6558
|
+
mediaSection,
|
|
6559
|
+
iterator,
|
|
6560
|
+
seekInfiniteLoop,
|
|
6561
|
+
logLevel,
|
|
6562
|
+
mode,
|
|
6563
|
+
contentLength,
|
|
6564
|
+
currentReader,
|
|
6565
|
+
readerInterface,
|
|
6566
|
+
src,
|
|
6567
|
+
discardReadBytes,
|
|
6568
|
+
fields
|
|
6569
|
+
}) => {
|
|
6570
|
+
const byteInMediaSection = isByteInMediaSection({
|
|
6571
|
+
position: seekTo,
|
|
6572
|
+
mediaSections: mediaSection.getMediaSections()
|
|
6573
|
+
});
|
|
6574
|
+
if (byteInMediaSection !== "in-section" && userInitiated) {
|
|
6575
|
+
const sections = mediaSection.getMediaSections();
|
|
6576
|
+
const sectionStrings = sections.map((section) => {
|
|
6577
|
+
return `start: ${section.start}, end: ${section.size + section.start}`;
|
|
6578
|
+
});
|
|
6579
|
+
throw new Error(`Cannot seek to a byte that is not in the video section. Seeking to: ${seekTo}, sections: ${sectionStrings.join(" | ")}`);
|
|
6580
|
+
}
|
|
6581
|
+
seekInfiniteLoop.registerSeek(seekTo);
|
|
6582
|
+
if (seekTo <= iterator.counter.getOffset() && mode === "download") {
|
|
6583
|
+
throw new Error(`Seeking backwards is not supported in parseAndDownloadMedia() mode. Current position: ${iterator.counter.getOffset()}, seekTo: ${seekTo}`);
|
|
6584
|
+
}
|
|
6585
|
+
if (seekTo > contentLength) {
|
|
6586
|
+
throw new Error(`Cannot seek beyond the end of the file: ${seekTo} > ${contentLength}`);
|
|
6587
|
+
}
|
|
6588
|
+
if (mode === "download") {
|
|
6589
|
+
Log.verbose(logLevel, `Skipping over video data from position ${iterator.counter.getOffset()} -> ${seekTo}. Fetching but not reading all the data inbetween because in download mode`);
|
|
6590
|
+
iterator.discard(seekTo - iterator.counter.getOffset());
|
|
6591
|
+
return;
|
|
6592
|
+
}
|
|
6593
|
+
await controller._internals.checkForAbortAndPause();
|
|
6594
|
+
const alreadyAtByte = iterator.counter.getOffset() === seekTo;
|
|
6595
|
+
if (alreadyAtByte) {
|
|
6596
|
+
Log.verbose(logLevel, `Already at the desired position, seeking done`);
|
|
6597
|
+
controller._internals.performedSeeksSignal.markLastSeekAsUserInitiated();
|
|
6598
|
+
return;
|
|
6599
|
+
}
|
|
6600
|
+
const skippingForward = seekTo > iterator.counter.getOffset();
|
|
6601
|
+
controller._internals.performedSeeksSignal.recordSeek({
|
|
6602
|
+
from: iterator.counter.getOffset(),
|
|
6603
|
+
to: seekTo,
|
|
6604
|
+
type: userInitiated ? "user-initiated" : "internal"
|
|
6605
|
+
});
|
|
6606
|
+
if (skippingForward) {
|
|
6607
|
+
await seekForward({
|
|
6608
|
+
seekTo,
|
|
6609
|
+
userInitiated,
|
|
6610
|
+
iterator,
|
|
6611
|
+
fields,
|
|
6612
|
+
logLevel,
|
|
6613
|
+
currentReader,
|
|
6614
|
+
readerInterface,
|
|
6615
|
+
src,
|
|
6616
|
+
controller,
|
|
6617
|
+
discardReadBytes
|
|
6618
|
+
});
|
|
6619
|
+
} else {
|
|
6620
|
+
await seekBackwards({
|
|
6621
|
+
controller,
|
|
6622
|
+
seekTo,
|
|
6623
|
+
iterator,
|
|
6624
|
+
logLevel,
|
|
6625
|
+
currentReader,
|
|
6626
|
+
readerInterface,
|
|
6627
|
+
src
|
|
6628
|
+
});
|
|
6629
|
+
}
|
|
6630
|
+
await controller._internals.checkForAbortAndPause();
|
|
6631
|
+
};
|
|
6632
|
+
|
|
6633
|
+
// src/work-on-seek-request.ts
|
|
6634
|
+
var turnSeekIntoByte = async ({
|
|
6635
|
+
seek: seek2,
|
|
6636
|
+
mediaSectionState: mediaSectionState2,
|
|
6637
|
+
logLevel,
|
|
6638
|
+
iterator,
|
|
6639
|
+
structureState,
|
|
6640
|
+
mp4HeaderSegment,
|
|
6641
|
+
isoState,
|
|
6642
|
+
transportStream,
|
|
6643
|
+
tracksState,
|
|
6644
|
+
webmState,
|
|
6645
|
+
keyframes
|
|
6646
|
+
}) => {
|
|
6647
|
+
const mediaSections = mediaSectionState2.getMediaSections();
|
|
6648
|
+
if (mediaSections.length === 0) {
|
|
6649
|
+
Log.trace(logLevel, "No media sections defined, cannot seek yet");
|
|
6650
|
+
return {
|
|
6651
|
+
type: "valid-but-must-wait"
|
|
6652
|
+
};
|
|
6653
|
+
}
|
|
6654
|
+
if (seek2.type === "keyframe-before-time") {
|
|
6655
|
+
if (seek2.timeInSeconds < 0) {
|
|
6656
|
+
throw new Error(`Cannot seek to a negative time: ${JSON.stringify(seek2)}`);
|
|
6657
|
+
}
|
|
6658
|
+
const seekingInfo = getSeekingInfo({
|
|
6659
|
+
structureState,
|
|
6660
|
+
mp4HeaderSegment,
|
|
6661
|
+
mediaSectionState: mediaSectionState2,
|
|
6662
|
+
isoState,
|
|
6663
|
+
transportStream,
|
|
6664
|
+
tracksState
|
|
6665
|
+
});
|
|
6666
|
+
if (!seekingInfo) {
|
|
6667
|
+
Log.trace(logLevel, "No seeking info, cannot seek yet");
|
|
6668
|
+
return {
|
|
6669
|
+
type: "valid-but-must-wait"
|
|
6670
|
+
};
|
|
6671
|
+
}
|
|
6672
|
+
const seekingByte = await getSeekingByte({
|
|
6673
|
+
info: seekingInfo,
|
|
6674
|
+
time: seek2.timeInSeconds,
|
|
6675
|
+
logLevel,
|
|
6676
|
+
currentPosition: iterator.counter.getOffset(),
|
|
6677
|
+
isoState,
|
|
6678
|
+
transportStream,
|
|
6679
|
+
webmState,
|
|
6680
|
+
mediaSection: mediaSectionState2,
|
|
6681
|
+
keyframes
|
|
6682
|
+
});
|
|
6683
|
+
return seekingByte;
|
|
6684
|
+
}
|
|
6685
|
+
if (seek2.type === "byte") {
|
|
6686
|
+
return {
|
|
6687
|
+
type: "do-seek",
|
|
6688
|
+
byte: seek2.byte
|
|
6689
|
+
};
|
|
6690
|
+
}
|
|
6691
|
+
throw new Error(`Cannot process seek request for ${seek2}: ${JSON.stringify(seek2)}`);
|
|
6692
|
+
};
|
|
6693
|
+
var getWorkOnSeekRequestOptions = (state) => {
|
|
6694
|
+
return {
|
|
6695
|
+
logLevel: state.logLevel,
|
|
6696
|
+
controller: state.controller,
|
|
6697
|
+
isoState: state.iso,
|
|
6698
|
+
iterator: state.iterator,
|
|
6699
|
+
structureState: state.structure,
|
|
6700
|
+
src: state.src,
|
|
6701
|
+
contentLength: state.contentLength,
|
|
6702
|
+
readerInterface: state.readerInterface,
|
|
6703
|
+
mediaSection: state.mediaSection,
|
|
6704
|
+
mp4HeaderSegment: state.mp4HeaderSegment,
|
|
6705
|
+
mode: state.mode,
|
|
6706
|
+
seekInfiniteLoop: state.seekInfiniteLoop,
|
|
6707
|
+
currentReader: state.currentReader,
|
|
6708
|
+
discardReadBytes: state.discardReadBytes,
|
|
6709
|
+
fields: state.fields,
|
|
6710
|
+
transportStream: state.transportStream,
|
|
6711
|
+
tracksState: state.callbacks.tracks,
|
|
6712
|
+
webmState: state.webm,
|
|
6713
|
+
keyframes: state.keyframes
|
|
6714
|
+
};
|
|
6715
|
+
};
|
|
6716
|
+
var workOnSeekRequest = async (options) => {
|
|
6717
|
+
const {
|
|
6718
|
+
logLevel,
|
|
6719
|
+
controller,
|
|
6720
|
+
mediaSection,
|
|
6721
|
+
mp4HeaderSegment,
|
|
6722
|
+
isoState,
|
|
6723
|
+
iterator,
|
|
6724
|
+
structureState,
|
|
6725
|
+
src,
|
|
6726
|
+
contentLength,
|
|
6727
|
+
readerInterface,
|
|
6728
|
+
mode,
|
|
6729
|
+
seekInfiniteLoop,
|
|
6730
|
+
currentReader,
|
|
6731
|
+
discardReadBytes,
|
|
6732
|
+
fields,
|
|
6733
|
+
transportStream,
|
|
6734
|
+
tracksState,
|
|
6735
|
+
webmState,
|
|
6736
|
+
keyframes
|
|
6737
|
+
} = options;
|
|
6738
|
+
const seek2 = controller._internals.seekSignal.getSeek();
|
|
6739
|
+
if (!seek2) {
|
|
6740
|
+
return;
|
|
6741
|
+
}
|
|
6742
|
+
Log.trace(logLevel, `Has seek request: ${JSON.stringify(seek2)}`);
|
|
6743
|
+
const resolution = await turnSeekIntoByte({
|
|
6744
|
+
seek: seek2,
|
|
6745
|
+
mediaSectionState: mediaSection,
|
|
6746
|
+
logLevel,
|
|
6747
|
+
iterator,
|
|
6748
|
+
structureState,
|
|
6749
|
+
mp4HeaderSegment,
|
|
6750
|
+
isoState,
|
|
6751
|
+
transportStream,
|
|
6752
|
+
tracksState,
|
|
6753
|
+
webmState,
|
|
6754
|
+
keyframes
|
|
6755
|
+
});
|
|
6756
|
+
Log.trace(logLevel, `Seek action: ${JSON.stringify(resolution)}`);
|
|
6757
|
+
if (resolution.type === "intermediary-seek") {
|
|
6758
|
+
await performSeek({
|
|
6759
|
+
seekTo: resolution.byte,
|
|
6760
|
+
userInitiated: false,
|
|
6761
|
+
controller,
|
|
6762
|
+
mediaSection,
|
|
6763
|
+
iterator,
|
|
6764
|
+
logLevel,
|
|
6765
|
+
mode,
|
|
6766
|
+
contentLength,
|
|
6767
|
+
seekInfiniteLoop,
|
|
6768
|
+
currentReader,
|
|
6769
|
+
readerInterface,
|
|
6770
|
+
src,
|
|
6771
|
+
discardReadBytes,
|
|
6772
|
+
fields
|
|
6773
|
+
});
|
|
6774
|
+
return;
|
|
6775
|
+
}
|
|
6776
|
+
if (resolution.type === "do-seek") {
|
|
6777
|
+
await performSeek({
|
|
6778
|
+
seekTo: resolution.byte,
|
|
6779
|
+
userInitiated: true,
|
|
6780
|
+
controller,
|
|
6781
|
+
mediaSection,
|
|
6782
|
+
iterator,
|
|
6783
|
+
logLevel,
|
|
6784
|
+
mode,
|
|
6785
|
+
contentLength,
|
|
6786
|
+
seekInfiniteLoop,
|
|
6787
|
+
currentReader,
|
|
6788
|
+
readerInterface,
|
|
6789
|
+
src,
|
|
6790
|
+
discardReadBytes,
|
|
6791
|
+
fields
|
|
6792
|
+
});
|
|
6793
|
+
const { hasChanged } = controller._internals.seekSignal.clearSeekIfStillSame(seek2);
|
|
6794
|
+
if (hasChanged) {
|
|
6795
|
+
Log.trace(logLevel, `Seek request has changed while seeking, seeking again`);
|
|
6796
|
+
await workOnSeekRequest(options);
|
|
6797
|
+
}
|
|
6798
|
+
return;
|
|
6799
|
+
}
|
|
6800
|
+
if (resolution.type === "invalid") {
|
|
6801
|
+
throw new Error(`The seek request ${JSON.stringify(seek2)} cannot be processed`);
|
|
6802
|
+
}
|
|
6803
|
+
if (resolution.type === "valid-but-must-wait") {
|
|
6804
|
+
Log.trace(logLevel, "Seek request is valid but cannot be processed yet");
|
|
6805
|
+
}
|
|
6806
|
+
};
|
|
6807
|
+
|
|
6808
|
+
// src/emit-available-info.ts
|
|
6809
|
+
var emitAvailableInfo = async ({
|
|
6810
|
+
hasInfo,
|
|
6811
|
+
state
|
|
6812
|
+
}) => {
|
|
6813
|
+
const keys = Object.keys(hasInfo);
|
|
6814
|
+
const {
|
|
6815
|
+
emittedFields,
|
|
6816
|
+
fieldsInReturnValue,
|
|
6817
|
+
returnValue,
|
|
6818
|
+
name,
|
|
6819
|
+
callbackFunctions
|
|
6820
|
+
} = state;
|
|
6821
|
+
for (const key of keys) {
|
|
6822
|
+
await workOnSeekRequest(getWorkOnSeekRequestOptions(state));
|
|
6823
|
+
if (key === "structure") {
|
|
6824
|
+
if (hasInfo.structure && !emittedFields.structure) {
|
|
6825
|
+
await callbackFunctions.onStructure?.(state.structure.getStructure());
|
|
6826
|
+
if (fieldsInReturnValue.structure) {
|
|
6827
|
+
returnValue.structure = state.structure.getStructure();
|
|
6828
|
+
}
|
|
6829
|
+
emittedFields.structure = true;
|
|
6830
|
+
}
|
|
6831
|
+
continue;
|
|
6832
|
+
}
|
|
6833
|
+
if (key === "durationInSeconds") {
|
|
6834
|
+
if (hasInfo.durationInSeconds) {
|
|
6835
|
+
if (!emittedFields.durationInSeconds) {
|
|
6836
|
+
const durationInSeconds = getDuration(state);
|
|
6837
|
+
await callbackFunctions.onDurationInSeconds?.(durationInSeconds);
|
|
6838
|
+
if (fieldsInReturnValue.durationInSeconds) {
|
|
6839
|
+
returnValue.durationInSeconds = durationInSeconds;
|
|
6840
|
+
}
|
|
6841
|
+
emittedFields.durationInSeconds = true;
|
|
6842
|
+
}
|
|
6843
|
+
}
|
|
6844
|
+
continue;
|
|
6845
|
+
}
|
|
6846
|
+
if (key === "slowDurationInSeconds") {
|
|
6847
|
+
if (hasInfo.slowDurationInSeconds && !emittedFields.slowDurationInSeconds) {
|
|
6848
|
+
const slowDurationInSeconds = getDuration(state) ?? state.slowDurationAndFps.getSlowDurationInSeconds();
|
|
6849
|
+
await callbackFunctions.onSlowDurationInSeconds?.(slowDurationInSeconds);
|
|
6850
|
+
if (fieldsInReturnValue.slowDurationInSeconds) {
|
|
6851
|
+
returnValue.slowDurationInSeconds = slowDurationInSeconds;
|
|
6852
|
+
}
|
|
6853
|
+
emittedFields.slowDurationInSeconds = true;
|
|
6854
|
+
}
|
|
6855
|
+
continue;
|
|
6856
|
+
}
|
|
6857
|
+
if (key === "fps") {
|
|
6858
|
+
if (hasInfo.fps) {
|
|
6859
|
+
if (!emittedFields.fps) {
|
|
6860
|
+
const fps = getFps(state);
|
|
6130
6861
|
await callbackFunctions.onFps?.(fps);
|
|
6131
6862
|
if (fieldsInReturnValue.fps) {
|
|
6132
6863
|
returnValue.fps = fps;
|
|
@@ -6544,175 +7275,44 @@ var triggerInfoEmit = async (state) => {
|
|
|
6544
7275
|
});
|
|
6545
7276
|
await emitAvailableInfo({
|
|
6546
7277
|
hasInfo: availableInfo,
|
|
6547
|
-
state
|
|
6548
|
-
});
|
|
6549
|
-
};
|
|
6550
|
-
|
|
6551
|
-
// src/check-if-done.ts
|
|
6552
|
-
var checkIfDone = async (state) => {
|
|
6553
|
-
const startCheck = Date.now();
|
|
6554
|
-
const hasAll = hasAllInfo({
|
|
6555
|
-
state
|
|
6556
|
-
});
|
|
6557
|
-
state.timings.timeCheckingIfDone += Date.now() - startCheck;
|
|
6558
|
-
if (hasAll && state.mode === "query") {
|
|
6559
|
-
Log.verbose(state.logLevel, "Got all info, skipping to the end.");
|
|
6560
|
-
state.increaseSkippedBytes(state.contentLength - state.iterator.counter.getOffset());
|
|
6561
|
-
return true;
|
|
6562
|
-
}
|
|
6563
|
-
if (state.iterator.counter.getOffset() === state.contentLength) {
|
|
6564
|
-
if (state.structure.getStructure().type === "m3u" && !state.m3u.getAllChunksProcessedOverall()) {
|
|
6565
|
-
return false;
|
|
6566
|
-
}
|
|
6567
|
-
Log.verbose(state.logLevel, "Reached end of file");
|
|
6568
|
-
await state.discardReadBytes(true);
|
|
6569
|
-
return true;
|
|
6570
|
-
}
|
|
6571
|
-
if (state.iterator.counter.getOffset() + state.iterator.bytesRemaining() === state.contentLength && state.errored) {
|
|
6572
|
-
Log.verbose(state.logLevel, "Reached end of file and errorred");
|
|
6573
|
-
return true;
|
|
6574
|
-
}
|
|
6575
|
-
return false;
|
|
6576
|
-
};
|
|
6577
|
-
|
|
6578
|
-
// src/make-progress-object.ts
|
|
6579
|
-
var makeProgressObject = (state) => {
|
|
6580
|
-
return {
|
|
6581
|
-
bytes: state.iterator.counter.getOffset(),
|
|
6582
|
-
percentage: state.contentLength ? state.iterator.counter.getOffset() / state.contentLength : null,
|
|
6583
|
-
totalBytes: state.contentLength
|
|
6584
|
-
};
|
|
6585
|
-
};
|
|
6586
|
-
|
|
6587
|
-
// src/convert-audio-or-video-sample.ts
|
|
6588
|
-
var TARGET_TIMESCALE = 1e6;
|
|
6589
|
-
var fixFloat = (value) => {
|
|
6590
|
-
if (value % 1 < 0.0000001) {
|
|
6591
|
-
return Math.floor(value);
|
|
6592
|
-
}
|
|
6593
|
-
if (value % 1 > 0.9999999) {
|
|
6594
|
-
return Math.ceil(value);
|
|
6595
|
-
}
|
|
6596
|
-
return value;
|
|
6597
|
-
};
|
|
6598
|
-
var convertAudioOrVideoSampleToWebCodecsTimestamps = ({
|
|
6599
|
-
sample,
|
|
6600
|
-
timescale
|
|
6601
|
-
}) => {
|
|
6602
|
-
if (timescale === TARGET_TIMESCALE) {
|
|
6603
|
-
return sample;
|
|
6604
|
-
}
|
|
6605
|
-
const { cts, dts, timestamp } = sample;
|
|
6606
|
-
return {
|
|
6607
|
-
cts: fixFloat(cts * (TARGET_TIMESCALE / timescale)),
|
|
6608
|
-
dts: fixFloat(dts * (TARGET_TIMESCALE / timescale)),
|
|
6609
|
-
timestamp: fixFloat(timestamp * (TARGET_TIMESCALE / timescale)),
|
|
6610
|
-
duration: sample.duration === undefined ? undefined : fixFloat(sample.duration * (TARGET_TIMESCALE / timescale)),
|
|
6611
|
-
data: sample.data,
|
|
6612
|
-
trackId: sample.trackId,
|
|
6613
|
-
type: sample.type,
|
|
6614
|
-
offset: sample.offset,
|
|
6615
|
-
timescale: TARGET_TIMESCALE
|
|
6616
|
-
};
|
|
6617
|
-
};
|
|
6618
|
-
|
|
6619
|
-
// src/emit-audio-sample.ts
|
|
6620
|
-
var emitAudioSample = async ({
|
|
6621
|
-
trackId,
|
|
6622
|
-
audioSample,
|
|
6623
|
-
workOnSeekRequestOptions,
|
|
6624
|
-
callbacks
|
|
6625
|
-
}) => {
|
|
6626
|
-
await callbacks.onAudioSample(trackId, audioSample);
|
|
6627
|
-
await workOnSeekRequest(workOnSeekRequestOptions);
|
|
6628
|
-
};
|
|
6629
|
-
var emitVideoSample = async ({
|
|
6630
|
-
trackId,
|
|
6631
|
-
videoSample,
|
|
6632
|
-
workOnSeekRequestOptions,
|
|
6633
|
-
callbacks
|
|
6634
|
-
}) => {
|
|
6635
|
-
await callbacks.onVideoSample(trackId, videoSample);
|
|
6636
|
-
await workOnSeekRequest(workOnSeekRequestOptions);
|
|
6637
|
-
};
|
|
6638
|
-
|
|
6639
|
-
// src/register-track.ts
|
|
6640
|
-
var registerVideoTrack = async ({
|
|
6641
|
-
track,
|
|
6642
|
-
container,
|
|
6643
|
-
logLevel,
|
|
6644
|
-
workOnSeekRequestOptions,
|
|
6645
|
-
onVideoTrack,
|
|
6646
|
-
registerVideoSampleCallback,
|
|
6647
|
-
tracks: tracks2
|
|
6648
|
-
}) => {
|
|
6649
|
-
if (tracks2.getTracks().find((t) => t.trackId === track.trackId)) {
|
|
6650
|
-
Log.trace(logLevel, `Track ${track.trackId} already registered, skipping`);
|
|
6651
|
-
return null;
|
|
6652
|
-
}
|
|
6653
|
-
if (track.type !== "video") {
|
|
6654
|
-
throw new Error("Expected video track");
|
|
6655
|
-
}
|
|
6656
|
-
tracks2.addTrack(track);
|
|
6657
|
-
if (!onVideoTrack) {
|
|
6658
|
-
return null;
|
|
6659
|
-
}
|
|
6660
|
-
const callback = await onVideoTrack({
|
|
6661
|
-
track,
|
|
6662
|
-
container
|
|
7278
|
+
state
|
|
6663
7279
|
});
|
|
6664
|
-
await registerVideoSampleCallback(track.trackId, callback ?? null);
|
|
6665
|
-
if (workOnSeekRequestOptions) {
|
|
6666
|
-
await workOnSeekRequest(workOnSeekRequestOptions);
|
|
6667
|
-
}
|
|
6668
|
-
return callback;
|
|
6669
7280
|
};
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
return
|
|
6682
|
-
}
|
|
6683
|
-
if (track.type !== "audio") {
|
|
6684
|
-
throw new Error("Expected audio track");
|
|
7281
|
+
|
|
7282
|
+
// src/check-if-done.ts
|
|
7283
|
+
var checkIfDone = async (state) => {
|
|
7284
|
+
const startCheck = Date.now();
|
|
7285
|
+
const hasAll = hasAllInfo({
|
|
7286
|
+
state
|
|
7287
|
+
});
|
|
7288
|
+
state.timings.timeCheckingIfDone += Date.now() - startCheck;
|
|
7289
|
+
if (hasAll && state.mode === "query") {
|
|
7290
|
+
Log.verbose(state.logLevel, "Got all info, skipping to the end.");
|
|
7291
|
+
state.increaseSkippedBytes(state.contentLength - state.iterator.counter.getOffset());
|
|
7292
|
+
return true;
|
|
6685
7293
|
}
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
7294
|
+
if (state.iterator.counter.getOffset() === state.contentLength) {
|
|
7295
|
+
if (state.structure.getStructure().type === "m3u" && !state.m3u.getAllChunksProcessedOverall()) {
|
|
7296
|
+
return false;
|
|
7297
|
+
}
|
|
7298
|
+
Log.verbose(state.logLevel, "Reached end of file");
|
|
7299
|
+
await state.discardReadBytes(true);
|
|
7300
|
+
return true;
|
|
6689
7301
|
}
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
});
|
|
6694
|
-
await registerAudioSampleCallback(track.trackId, callback ?? null);
|
|
6695
|
-
if (workOnSeekRequestOptions) {
|
|
6696
|
-
await workOnSeekRequest(workOnSeekRequestOptions);
|
|
7302
|
+
if (state.iterator.counter.getOffset() + state.iterator.bytesRemaining() === state.contentLength && state.errored) {
|
|
7303
|
+
Log.verbose(state.logLevel, "Reached end of file and errorred");
|
|
7304
|
+
return true;
|
|
6697
7305
|
}
|
|
6698
|
-
return
|
|
7306
|
+
return false;
|
|
6699
7307
|
};
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
track: addAvcProfileToTrack(track, profile),
|
|
6709
|
-
container,
|
|
6710
|
-
logLevel: state.logLevel,
|
|
6711
|
-
onVideoTrack: state.onVideoTrack,
|
|
6712
|
-
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
6713
|
-
tracks: state.callbacks.tracks
|
|
6714
|
-
});
|
|
6715
|
-
});
|
|
7308
|
+
|
|
7309
|
+
// src/make-progress-object.ts
|
|
7310
|
+
var makeProgressObject = (state) => {
|
|
7311
|
+
return {
|
|
7312
|
+
bytes: state.iterator.counter.getOffset(),
|
|
7313
|
+
percentage: state.contentLength ? state.iterator.counter.getOffset() / state.contentLength : null,
|
|
7314
|
+
totalBytes: state.contentLength
|
|
7315
|
+
};
|
|
6716
7316
|
};
|
|
6717
7317
|
|
|
6718
7318
|
// src/containers/aac/parse-aac.ts
|
|
@@ -6759,7 +7359,6 @@ var parseAac = async (state) => {
|
|
|
6759
7359
|
const data = iterator.getSlice(frameLength);
|
|
6760
7360
|
if (state.callbacks.tracks.getTracks().length === 0) {
|
|
6761
7361
|
await registerAudioTrack({
|
|
6762
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
6763
7362
|
container: "aac",
|
|
6764
7363
|
track: {
|
|
6765
7364
|
codec: mapAudioObjectTypeToCodecString(audioObjectType),
|
|
@@ -6799,7 +7398,6 @@ var parseAac = async (state) => {
|
|
|
6799
7398
|
},
|
|
6800
7399
|
timescale: 1
|
|
6801
7400
|
}),
|
|
6802
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
6803
7401
|
callbacks: state.callbacks
|
|
6804
7402
|
});
|
|
6805
7403
|
return Promise.resolve(null);
|
|
@@ -7007,7 +7605,6 @@ var emitSample = async ({
|
|
|
7007
7605
|
},
|
|
7008
7606
|
timescale: 1
|
|
7009
7607
|
}),
|
|
7010
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
7011
7608
|
callbacks: state.callbacks
|
|
7012
7609
|
});
|
|
7013
7610
|
iterator.destroy();
|
|
@@ -7157,7 +7754,6 @@ var parseStreamInfo = async ({
|
|
|
7157
7754
|
state.structure.getFlacStructure().boxes.push(flacStreamInfo);
|
|
7158
7755
|
await registerAudioTrack({
|
|
7159
7756
|
container: "flac",
|
|
7160
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
7161
7757
|
track: {
|
|
7162
7758
|
codec: "flac",
|
|
7163
7759
|
type: "audio",
|
|
@@ -9108,7 +9704,7 @@ var processBox = async ({
|
|
|
9108
9704
|
if (!onlyIfMoovAtomExpected) {
|
|
9109
9705
|
throw new Error("State is required");
|
|
9110
9706
|
}
|
|
9111
|
-
const {
|
|
9707
|
+
const { tracks: tracks2, onAudioTrack, onVideoTrack } = onlyIfMoovAtomExpected;
|
|
9112
9708
|
const box = await parseTrak({
|
|
9113
9709
|
size: boxSize,
|
|
9114
9710
|
offsetAtStart: fileOffset,
|
|
@@ -9118,7 +9714,6 @@ var processBox = async ({
|
|
|
9118
9714
|
const transformedTrack = makeBaseMediaTrack(box);
|
|
9119
9715
|
if (transformedTrack && transformedTrack.type === "video") {
|
|
9120
9716
|
await registerVideoTrack({
|
|
9121
|
-
workOnSeekRequestOptions,
|
|
9122
9717
|
track: transformedTrack,
|
|
9123
9718
|
container: "mp4",
|
|
9124
9719
|
logLevel,
|
|
@@ -9129,7 +9724,6 @@ var processBox = async ({
|
|
|
9129
9724
|
}
|
|
9130
9725
|
if (transformedTrack && transformedTrack.type === "audio") {
|
|
9131
9726
|
await registerAudioTrack({
|
|
9132
|
-
workOnSeekRequestOptions,
|
|
9133
9727
|
track: transformedTrack,
|
|
9134
9728
|
container: "mp4",
|
|
9135
9729
|
registerAudioSampleCallback: onlyIfMoovAtomExpected.registerAudioSampleCallback,
|
|
@@ -9237,7 +9831,6 @@ var getMoovAtom = async ({
|
|
|
9237
9831
|
});
|
|
9238
9832
|
const onAudioTrack = state.onAudioTrack ? async ({ track, container }) => {
|
|
9239
9833
|
await registerAudioTrack({
|
|
9240
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
9241
9834
|
track,
|
|
9242
9835
|
container,
|
|
9243
9836
|
logLevel: state.logLevel,
|
|
@@ -9249,7 +9842,6 @@ var getMoovAtom = async ({
|
|
|
9249
9842
|
} : null;
|
|
9250
9843
|
const onVideoTrack = state.onVideoTrack ? async ({ track, container }) => {
|
|
9251
9844
|
await registerVideoTrack({
|
|
9252
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
9253
9845
|
track,
|
|
9254
9846
|
container,
|
|
9255
9847
|
logLevel: state.logLevel,
|
|
@@ -9284,7 +9876,6 @@ var getMoovAtom = async ({
|
|
|
9284
9876
|
onlyIfMoovAtomExpected: {
|
|
9285
9877
|
tracks: tracksState,
|
|
9286
9878
|
isoState: null,
|
|
9287
|
-
workOnSeekRequestOptions: null,
|
|
9288
9879
|
onAudioTrack,
|
|
9289
9880
|
onVideoTrack,
|
|
9290
9881
|
registerVideoSampleCallback: () => Promise.resolve(),
|
|
@@ -9372,7 +9963,6 @@ var parseMdatSection = async (state) => {
|
|
|
9372
9963
|
},
|
|
9373
9964
|
timescale: samplesWithIndex.track.timescale
|
|
9374
9965
|
}),
|
|
9375
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
9376
9966
|
callbacks: state.callbacks
|
|
9377
9967
|
});
|
|
9378
9968
|
}
|
|
@@ -9399,7 +9989,6 @@ var parseMdatSection = async (state) => {
|
|
|
9399
9989
|
},
|
|
9400
9990
|
timescale: samplesWithIndex.track.timescale
|
|
9401
9991
|
}),
|
|
9402
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
9403
9992
|
callbacks: state.callbacks
|
|
9404
9993
|
});
|
|
9405
9994
|
}
|
|
@@ -9419,7 +10008,6 @@ var parseIsoBaseMedia = async (state) => {
|
|
|
9419
10008
|
onlyIfMoovAtomExpected: {
|
|
9420
10009
|
tracks: state.callbacks.tracks,
|
|
9421
10010
|
isoState: state.iso,
|
|
9422
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
9423
10011
|
onAudioTrack: state.onAudioTrack,
|
|
9424
10012
|
onVideoTrack: state.onVideoTrack,
|
|
9425
10013
|
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
@@ -9829,7 +10417,8 @@ var parseMedia = (options) => {
|
|
|
9829
10417
|
onDiscardedData: null,
|
|
9830
10418
|
onError: () => ({ action: "fail" }),
|
|
9831
10419
|
acknowledgeRemotionLicense: Boolean(options.acknowledgeRemotionLicense),
|
|
9832
|
-
apiName: "parseMedia()"
|
|
10420
|
+
apiName: "parseMedia()",
|
|
10421
|
+
makeSamplesStartAtZero: options.makeSamplesStartAtZero ?? true
|
|
9833
10422
|
});
|
|
9834
10423
|
};
|
|
9835
10424
|
|
|
@@ -9950,7 +10539,8 @@ var iteratorOverSegmentFiles = async ({
|
|
|
9950
10539
|
return callbackOrFalse;
|
|
9951
10540
|
},
|
|
9952
10541
|
reader: readerInterface,
|
|
9953
|
-
mp4HeaderSegment
|
|
10542
|
+
mp4HeaderSegment,
|
|
10543
|
+
makeSamplesStartAtZero: false
|
|
9954
10544
|
});
|
|
9955
10545
|
if (chunk.isHeader) {
|
|
9956
10546
|
if (data.structure.type !== "iso-base-media") {
|
|
@@ -10022,7 +10612,6 @@ var runOverM3u = async ({
|
|
|
10022
10612
|
}
|
|
10023
10613
|
const onAudioSample = await registerAudioTrack({
|
|
10024
10614
|
container: "m3u8",
|
|
10025
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
10026
10615
|
track: {
|
|
10027
10616
|
...track,
|
|
10028
10617
|
trackId
|
|
@@ -10049,7 +10638,6 @@ var runOverM3u = async ({
|
|
|
10049
10638
|
}
|
|
10050
10639
|
const onVideoSample = await registerVideoTrack({
|
|
10051
10640
|
container: "m3u8",
|
|
10052
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
10053
10641
|
track: {
|
|
10054
10642
|
...track,
|
|
10055
10643
|
trackId
|
|
@@ -10429,7 +11017,6 @@ var parseMpegHeader = async ({
|
|
|
10429
11017
|
state.mp3Info.setMp3Info(info);
|
|
10430
11018
|
await registerAudioTrack({
|
|
10431
11019
|
container: "mp3",
|
|
10432
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
10433
11020
|
track: {
|
|
10434
11021
|
type: "audio",
|
|
10435
11022
|
codec: "mp3",
|
|
@@ -10479,7 +11066,6 @@ var parseMpegHeader = async ({
|
|
|
10479
11066
|
trackId: 0,
|
|
10480
11067
|
type: "key"
|
|
10481
11068
|
},
|
|
10482
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
10483
11069
|
callbacks: state.callbacks
|
|
10484
11070
|
});
|
|
10485
11071
|
}
|
|
@@ -10637,419 +11223,180 @@ var parseStrfVideo = ({
|
|
|
10637
11223
|
const compression = iterator.getByteString(4, false);
|
|
10638
11224
|
const sizeImage = iterator.getUint32Le();
|
|
10639
11225
|
const xPelsPerMeter = iterator.getInt32Le();
|
|
10640
|
-
const yPelsPerMeter = iterator.getInt32Le();
|
|
10641
|
-
const clrUsed = iterator.getUint32Le();
|
|
10642
|
-
const clrImportant = iterator.getUint32Le();
|
|
10643
|
-
box.expectNoMoreBytes();
|
|
10644
|
-
return {
|
|
10645
|
-
type: "strf-box-video",
|
|
10646
|
-
biSize,
|
|
10647
|
-
bitCount,
|
|
10648
|
-
clrImportant,
|
|
10649
|
-
clrUsed,
|
|
10650
|
-
compression,
|
|
10651
|
-
height,
|
|
10652
|
-
planes,
|
|
10653
|
-
sizeImage,
|
|
10654
|
-
width,
|
|
10655
|
-
xPelsPerMeter,
|
|
10656
|
-
yPelsPerMeter
|
|
10657
|
-
};
|
|
10658
|
-
};
|
|
10659
|
-
var parseStrf = ({
|
|
10660
|
-
iterator,
|
|
10661
|
-
size,
|
|
10662
|
-
fccType
|
|
10663
|
-
}) => {
|
|
10664
|
-
if (fccType === "vids") {
|
|
10665
|
-
return parseStrfVideo({ iterator, size });
|
|
10666
|
-
}
|
|
10667
|
-
if (fccType === "auds") {
|
|
10668
|
-
return parseStrfAudio({ iterator, size });
|
|
10669
|
-
}
|
|
10670
|
-
throw new Error(`Unsupported fccType: ${fccType}`);
|
|
10671
|
-
};
|
|
10672
|
-
|
|
10673
|
-
// src/containers/riff/parse-strh.ts
|
|
10674
|
-
var parseStrh = ({
|
|
10675
|
-
iterator,
|
|
10676
|
-
size
|
|
10677
|
-
}) => {
|
|
10678
|
-
const box = iterator.startBox(size);
|
|
10679
|
-
const fccType = iterator.getByteString(4, false);
|
|
10680
|
-
if (fccType !== "vids" && fccType !== "auds") {
|
|
10681
|
-
throw new Error("Expected AVI handler to be vids / auds");
|
|
10682
|
-
}
|
|
10683
|
-
const handler = fccType === "vids" ? iterator.getByteString(4, false) : iterator.getUint32Le();
|
|
10684
|
-
if (typeof handler === "string" && handler !== "H264") {
|
|
10685
|
-
throw new Error(`Only H264 is supported as a stream type in .avi, got ${handler}`);
|
|
10686
|
-
}
|
|
10687
|
-
if (fccType === "auds" && handler !== 1) {
|
|
10688
|
-
throw new Error(`Only "1" is supported as a stream type in .avi, got ${handler}`);
|
|
10689
|
-
}
|
|
10690
|
-
const flags = iterator.getUint32Le();
|
|
10691
|
-
const priority = iterator.getUint16Le();
|
|
10692
|
-
const language2 = iterator.getUint16Le();
|
|
10693
|
-
const initialFrames = iterator.getUint32Le();
|
|
10694
|
-
const scale = iterator.getUint32Le();
|
|
10695
|
-
const rate = iterator.getUint32Le();
|
|
10696
|
-
const start = iterator.getUint32Le();
|
|
10697
|
-
const length = iterator.getUint32Le();
|
|
10698
|
-
const suggestedBufferSize = iterator.getUint32Le();
|
|
10699
|
-
const quality = iterator.getUint32Le();
|
|
10700
|
-
const sampleSize = iterator.getUint32Le();
|
|
10701
|
-
box.discardRest();
|
|
10702
|
-
const ckId = iterator.getByteString(4, false);
|
|
10703
|
-
const ckSize = iterator.getUint32Le();
|
|
10704
|
-
if (ckId !== "strf") {
|
|
10705
|
-
throw new Error(`Expected strf, got ${JSON.stringify(ckId)}`);
|
|
10706
|
-
}
|
|
10707
|
-
if (iterator.bytesRemaining() < ckSize) {
|
|
10708
|
-
throw new Error("Expected strf to be complete");
|
|
10709
|
-
}
|
|
10710
|
-
const strf = parseStrf({ iterator, size: ckSize, fccType });
|
|
10711
|
-
return {
|
|
10712
|
-
type: "strh-box",
|
|
10713
|
-
fccType,
|
|
10714
|
-
handler,
|
|
10715
|
-
flags,
|
|
10716
|
-
priority,
|
|
10717
|
-
initialFrames,
|
|
10718
|
-
length,
|
|
10719
|
-
quality,
|
|
10720
|
-
rate,
|
|
10721
|
-
sampleSize,
|
|
10722
|
-
scale,
|
|
10723
|
-
start,
|
|
10724
|
-
suggestedBufferSize,
|
|
10725
|
-
language: language2,
|
|
10726
|
-
strf
|
|
10727
|
-
};
|
|
10728
|
-
};
|
|
10729
|
-
|
|
10730
|
-
// src/containers/riff/parse-riff-box.ts
|
|
10731
|
-
var parseRiffBox = ({
|
|
10732
|
-
size,
|
|
10733
|
-
id,
|
|
10734
|
-
state
|
|
10735
|
-
}) => {
|
|
10736
|
-
const { iterator } = state;
|
|
10737
|
-
if (id === "LIST") {
|
|
10738
|
-
return parseListBox({ size, state });
|
|
10739
|
-
}
|
|
10740
|
-
if (id === "ISFT") {
|
|
10741
|
-
return Promise.resolve(parseIsft({ iterator, size }));
|
|
10742
|
-
}
|
|
10743
|
-
if (id === "avih") {
|
|
10744
|
-
return Promise.resolve(parseAvih({ iterator, size }));
|
|
10745
|
-
}
|
|
10746
|
-
if (id === "strh") {
|
|
10747
|
-
return Promise.resolve(parseStrh({ iterator, size }));
|
|
10748
|
-
}
|
|
10749
|
-
iterator.discard(size);
|
|
10750
|
-
const box = {
|
|
10751
|
-
type: "riff-box",
|
|
10752
|
-
size,
|
|
10753
|
-
id
|
|
10754
|
-
};
|
|
10755
|
-
return Promise.resolve(box);
|
|
10756
|
-
};
|
|
10757
|
-
|
|
10758
|
-
// src/containers/riff/expect-riff-box.ts
|
|
10759
|
-
var expectRiffBox = async (state) => {
|
|
10760
|
-
const { iterator } = state;
|
|
10761
|
-
if (state.iterator.bytesRemaining() < 16) {
|
|
10762
|
-
return null;
|
|
10763
|
-
}
|
|
10764
|
-
const checkpoint = iterator.startCheckpoint();
|
|
10765
|
-
const ckId = iterator.getByteString(4, false);
|
|
10766
|
-
const ckSize = iterator.getUint32Le();
|
|
10767
|
-
if (isMoviAtom(iterator, ckId)) {
|
|
10768
|
-
iterator.discard(4);
|
|
10769
|
-
state.mediaSection.addMediaSection({
|
|
10770
|
-
start: iterator.counter.getOffset(),
|
|
10771
|
-
size: ckSize - 4
|
|
10772
|
-
});
|
|
10773
|
-
return null;
|
|
10774
|
-
}
|
|
10775
|
-
if (iterator.bytesRemaining() < ckSize) {
|
|
10776
|
-
checkpoint.returnToCheckpoint();
|
|
10777
|
-
return null;
|
|
10778
|
-
}
|
|
10779
|
-
const box = await parseRiffBox({
|
|
10780
|
-
id: ckId,
|
|
10781
|
-
size: ckSize,
|
|
10782
|
-
state
|
|
10783
|
-
});
|
|
10784
|
-
if (box.type === "strh-box") {
|
|
10785
|
-
if (box.strf.type === "strf-box-audio" && state.onAudioTrack) {
|
|
10786
|
-
const audioTrack = makeAviAudioTrack({
|
|
10787
|
-
index: state.riff.getNextTrackIndex(),
|
|
10788
|
-
strf: box.strf
|
|
10789
|
-
});
|
|
10790
|
-
await registerAudioTrack({
|
|
10791
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
10792
|
-
track: audioTrack,
|
|
10793
|
-
container: "avi",
|
|
10794
|
-
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
10795
|
-
tracks: state.callbacks.tracks,
|
|
10796
|
-
logLevel: state.logLevel,
|
|
10797
|
-
onAudioTrack: state.onAudioTrack
|
|
10798
|
-
});
|
|
10799
|
-
}
|
|
10800
|
-
if (state.onVideoTrack && box.strf.type === "strf-box-video") {
|
|
10801
|
-
const videoTrack = makeAviVideoTrack({
|
|
10802
|
-
strh: box,
|
|
10803
|
-
index: state.riff.getNextTrackIndex(),
|
|
10804
|
-
strf: box.strf
|
|
10805
|
-
});
|
|
10806
|
-
registerVideoTrackWhenProfileIsAvailable({
|
|
10807
|
-
state,
|
|
10808
|
-
track: videoTrack,
|
|
10809
|
-
container: "avi"
|
|
10810
|
-
});
|
|
10811
|
-
}
|
|
10812
|
-
state.riff.incrementNextTrackIndex();
|
|
10813
|
-
}
|
|
10814
|
-
return box;
|
|
10815
|
-
};
|
|
10816
|
-
|
|
10817
|
-
// src/containers/avc/key.ts
|
|
10818
|
-
var getKeyFrameOrDeltaFromAvcInfo = (infos) => {
|
|
10819
|
-
const keyOrDelta = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
|
|
10820
|
-
if (!keyOrDelta) {
|
|
10821
|
-
throw new Error("expected avc to contain info about key or delta");
|
|
10822
|
-
}
|
|
10823
|
-
return keyOrDelta.type === "keyframe" ? "key" : "delta";
|
|
11226
|
+
const yPelsPerMeter = iterator.getInt32Le();
|
|
11227
|
+
const clrUsed = iterator.getUint32Le();
|
|
11228
|
+
const clrImportant = iterator.getUint32Le();
|
|
11229
|
+
box.expectNoMoreBytes();
|
|
11230
|
+
return {
|
|
11231
|
+
type: "strf-box-video",
|
|
11232
|
+
biSize,
|
|
11233
|
+
bitCount,
|
|
11234
|
+
clrImportant,
|
|
11235
|
+
clrUsed,
|
|
11236
|
+
compression,
|
|
11237
|
+
height,
|
|
11238
|
+
planes,
|
|
11239
|
+
sizeImage,
|
|
11240
|
+
width,
|
|
11241
|
+
xPelsPerMeter,
|
|
11242
|
+
yPelsPerMeter
|
|
11243
|
+
};
|
|
10824
11244
|
};
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
10828
|
-
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
let video_format = null;
|
|
10833
|
-
let video_full_range_flag = null;
|
|
10834
|
-
let colour_primaries = null;
|
|
10835
|
-
let transfer_characteristics = null;
|
|
10836
|
-
let matrix_coefficients = null;
|
|
10837
|
-
let chroma_sample_loc_type_top_field = null;
|
|
10838
|
-
let chroma_sample_loc_type_bottom_field = null;
|
|
10839
|
-
const aspect_ratio_info_present_flag = iterator.getBits(1);
|
|
10840
|
-
if (aspect_ratio_info_present_flag) {
|
|
10841
|
-
const aspect_ratio_idc = iterator.getBits(8);
|
|
10842
|
-
if (aspect_ratio_idc === Extended_SAR) {
|
|
10843
|
-
sar_width = iterator.getBits(16);
|
|
10844
|
-
sar_height = iterator.getBits(16);
|
|
10845
|
-
}
|
|
10846
|
-
}
|
|
10847
|
-
const overscan_info_present_flag = iterator.getBits(1);
|
|
10848
|
-
if (overscan_info_present_flag) {
|
|
10849
|
-
overscan_appropriate_flag = iterator.getBits(1);
|
|
10850
|
-
}
|
|
10851
|
-
const video_signal_type_present_flag = iterator.getBits(1);
|
|
10852
|
-
if (video_signal_type_present_flag) {
|
|
10853
|
-
video_format = iterator.getBits(3);
|
|
10854
|
-
video_full_range_flag = Boolean(iterator.getBits(1));
|
|
10855
|
-
const colour_description_present_flag = iterator.getBits(1);
|
|
10856
|
-
if (colour_description_present_flag) {
|
|
10857
|
-
colour_primaries = iterator.getBits(8);
|
|
10858
|
-
transfer_characteristics = iterator.getBits(8);
|
|
10859
|
-
matrix_coefficients = iterator.getBits(8);
|
|
10860
|
-
}
|
|
11245
|
+
var parseStrf = ({
|
|
11246
|
+
iterator,
|
|
11247
|
+
size,
|
|
11248
|
+
fccType
|
|
11249
|
+
}) => {
|
|
11250
|
+
if (fccType === "vids") {
|
|
11251
|
+
return parseStrfVideo({ iterator, size });
|
|
10861
11252
|
}
|
|
10862
|
-
|
|
10863
|
-
|
|
10864
|
-
chroma_sample_loc_type_top_field = iterator.readExpGolomb();
|
|
10865
|
-
chroma_sample_loc_type_bottom_field = iterator.readExpGolomb();
|
|
11253
|
+
if (fccType === "auds") {
|
|
11254
|
+
return parseStrfAudio({ iterator, size });
|
|
10866
11255
|
}
|
|
10867
|
-
|
|
10868
|
-
sar_width,
|
|
10869
|
-
sar_height,
|
|
10870
|
-
overscan_appropriate_flag,
|
|
10871
|
-
chroma_sample_loc_type_bottom_field,
|
|
10872
|
-
chroma_sample_loc_type_top_field,
|
|
10873
|
-
colour_primaries,
|
|
10874
|
-
matrix_coefficients,
|
|
10875
|
-
transfer_characteristics,
|
|
10876
|
-
video_format,
|
|
10877
|
-
video_full_range_flag
|
|
10878
|
-
};
|
|
11256
|
+
throw new Error(`Unsupported fccType: ${fccType}`);
|
|
10879
11257
|
};
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
|
|
10886
|
-
|
|
10887
|
-
|
|
10888
|
-
|
|
10889
|
-
|
|
10890
|
-
let log2_max_frame_num_minus4 = null;
|
|
10891
|
-
let log2_max_pic_order_cnt_lsb_minus4 = null;
|
|
10892
|
-
let max_num_ref_frames = null;
|
|
10893
|
-
let gaps_in_frame_num_value_allowed_flag = null;
|
|
10894
|
-
let mb_adaptive_frame_field_flag = null;
|
|
10895
|
-
let direct_8x8_inference_flag = null;
|
|
10896
|
-
let frame_crop_left_offset = null;
|
|
10897
|
-
let frame_crop_right_offset = null;
|
|
10898
|
-
let frame_crop_top_offset = null;
|
|
10899
|
-
let frame_crop_bottom_offset = null;
|
|
10900
|
-
let vui_parameters = null;
|
|
10901
|
-
if (profile === 100 || profile === 110 || profile === 122 || profile === 244 || profile === 44 || profile === 83 || profile === 86 || profile === 118 || profile === 128 || profile === 138 || profile === 139 || profile === 134 || profile === 135) {
|
|
10902
|
-
const chromaFormat = iterator.readExpGolomb();
|
|
10903
|
-
if (chromaFormat === 3) {
|
|
10904
|
-
separate_colour_plane_flag = iterator.getBits(1);
|
|
10905
|
-
}
|
|
10906
|
-
bit_depth_luma_minus8 = iterator.readExpGolomb();
|
|
10907
|
-
bit_depth_chroma_minus8 = iterator.readExpGolomb();
|
|
10908
|
-
qpprime_y_zero_transform_bypass_flag = iterator.getBits(1);
|
|
10909
|
-
const seq_scaling_matrix_present_flag = iterator.getBits(1);
|
|
10910
|
-
const seq_scaling_list_present_flag = [];
|
|
10911
|
-
if (seq_scaling_matrix_present_flag) {
|
|
10912
|
-
for (let i = 0;i < (chromaFormat !== 3 ? 8 : 12); i++) {
|
|
10913
|
-
seq_scaling_list_present_flag[i] = iterator.getBits(1);
|
|
10914
|
-
if (seq_scaling_list_present_flag[i]) {
|
|
10915
|
-
if (i < 6) {
|
|
10916
|
-
throw new Error("Not implemented");
|
|
10917
|
-
} else {
|
|
10918
|
-
throw new Error("Not implemented");
|
|
10919
|
-
}
|
|
10920
|
-
}
|
|
10921
|
-
}
|
|
10922
|
-
}
|
|
11258
|
+
|
|
11259
|
+
// src/containers/riff/parse-strh.ts
|
|
11260
|
+
var parseStrh = ({
|
|
11261
|
+
iterator,
|
|
11262
|
+
size
|
|
11263
|
+
}) => {
|
|
11264
|
+
const box = iterator.startBox(size);
|
|
11265
|
+
const fccType = iterator.getByteString(4, false);
|
|
11266
|
+
if (fccType !== "vids" && fccType !== "auds") {
|
|
11267
|
+
throw new Error("Expected AVI handler to be vids / auds");
|
|
10923
11268
|
}
|
|
10924
|
-
|
|
10925
|
-
|
|
10926
|
-
|
|
10927
|
-
log2_max_pic_order_cnt_lsb_minus4 = iterator.readExpGolomb();
|
|
10928
|
-
} else if (pic_order_cnt_type === 1) {
|
|
10929
|
-
throw new Error("pic_order_cnt_type = 1 not implemented");
|
|
11269
|
+
const handler = fccType === "vids" ? iterator.getByteString(4, false) : iterator.getUint32Le();
|
|
11270
|
+
if (typeof handler === "string" && handler !== "H264") {
|
|
11271
|
+
throw new Error(`Only H264 is supported as a stream type in .avi, got ${handler}`);
|
|
10930
11272
|
}
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
const pic_width_in_mbs_minus1 = iterator.readExpGolomb();
|
|
10934
|
-
const pic_height_in_map_units_minus1 = iterator.readExpGolomb();
|
|
10935
|
-
const frame_mbs_only_flag = iterator.getBits(1);
|
|
10936
|
-
if (!frame_mbs_only_flag) {
|
|
10937
|
-
mb_adaptive_frame_field_flag = iterator.getBits(1);
|
|
11273
|
+
if (fccType === "auds" && handler !== 1) {
|
|
11274
|
+
throw new Error(`Only "1" is supported as a stream type in .avi, got ${handler}`);
|
|
10938
11275
|
}
|
|
10939
|
-
|
|
10940
|
-
const
|
|
10941
|
-
|
|
10942
|
-
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
11276
|
+
const flags = iterator.getUint32Le();
|
|
11277
|
+
const priority = iterator.getUint16Le();
|
|
11278
|
+
const language2 = iterator.getUint16Le();
|
|
11279
|
+
const initialFrames = iterator.getUint32Le();
|
|
11280
|
+
const scale = iterator.getUint32Le();
|
|
11281
|
+
const rate = iterator.getUint32Le();
|
|
11282
|
+
const start = iterator.getUint32Le();
|
|
11283
|
+
const length = iterator.getUint32Le();
|
|
11284
|
+
const suggestedBufferSize = iterator.getUint32Le();
|
|
11285
|
+
const quality = iterator.getUint32Le();
|
|
11286
|
+
const sampleSize = iterator.getUint32Le();
|
|
11287
|
+
box.discardRest();
|
|
11288
|
+
const ckId = iterator.getByteString(4, false);
|
|
11289
|
+
const ckSize = iterator.getUint32Le();
|
|
11290
|
+
if (ckId !== "strf") {
|
|
11291
|
+
throw new Error(`Expected strf, got ${JSON.stringify(ckId)}`);
|
|
10946
11292
|
}
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
vui_parameters = readVuiParameters(iterator);
|
|
11293
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
11294
|
+
throw new Error("Expected strf to be complete");
|
|
10950
11295
|
}
|
|
10951
|
-
iterator
|
|
11296
|
+
const strf = parseStrf({ iterator, size: ckSize, fccType });
|
|
10952
11297
|
return {
|
|
10953
|
-
|
|
10954
|
-
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
frame_crop_bottom_offset,
|
|
10969
|
-
frame_crop_left_offset,
|
|
10970
|
-
frame_crop_right_offset,
|
|
10971
|
-
frame_crop_top_offset,
|
|
10972
|
-
mb_adaptive_frame_field_flag,
|
|
10973
|
-
vui_parameters
|
|
11298
|
+
type: "strh-box",
|
|
11299
|
+
fccType,
|
|
11300
|
+
handler,
|
|
11301
|
+
flags,
|
|
11302
|
+
priority,
|
|
11303
|
+
initialFrames,
|
|
11304
|
+
length,
|
|
11305
|
+
quality,
|
|
11306
|
+
rate,
|
|
11307
|
+
sampleSize,
|
|
11308
|
+
scale,
|
|
11309
|
+
start,
|
|
11310
|
+
suggestedBufferSize,
|
|
11311
|
+
language: language2,
|
|
11312
|
+
strf
|
|
10974
11313
|
};
|
|
10975
11314
|
};
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
}
|
|
10987
|
-
zeroesInARow = 0;
|
|
10988
|
-
}
|
|
10989
|
-
return null;
|
|
10990
|
-
};
|
|
10991
|
-
var inspect = (buffer) => {
|
|
10992
|
-
const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
|
|
10993
|
-
iterator.startReadingBits();
|
|
10994
|
-
iterator.getBits(1);
|
|
10995
|
-
iterator.getBits(2);
|
|
10996
|
-
const type = iterator.getBits(5);
|
|
10997
|
-
iterator.stopReadingBits();
|
|
10998
|
-
if (type === 7) {
|
|
10999
|
-
const end = findEnd(buffer);
|
|
11000
|
-
const data = readSps(iterator);
|
|
11001
|
-
const sps = buffer.slice(0, end === null ? Infinity : end);
|
|
11002
|
-
return {
|
|
11003
|
-
spsData: data,
|
|
11004
|
-
sps,
|
|
11005
|
-
type: "avc-profile"
|
|
11006
|
-
};
|
|
11315
|
+
|
|
11316
|
+
// src/containers/riff/parse-riff-box.ts
|
|
11317
|
+
var parseRiffBox = ({
|
|
11318
|
+
size,
|
|
11319
|
+
id,
|
|
11320
|
+
state
|
|
11321
|
+
}) => {
|
|
11322
|
+
const { iterator } = state;
|
|
11323
|
+
if (id === "LIST") {
|
|
11324
|
+
return parseListBox({ size, state });
|
|
11007
11325
|
}
|
|
11008
|
-
if (
|
|
11009
|
-
return {
|
|
11010
|
-
type: "keyframe"
|
|
11011
|
-
};
|
|
11326
|
+
if (id === "ISFT") {
|
|
11327
|
+
return Promise.resolve(parseIsft({ iterator, size }));
|
|
11012
11328
|
}
|
|
11013
|
-
if (
|
|
11014
|
-
|
|
11015
|
-
const pps = buffer.slice(0, end === null ? Infinity : end);
|
|
11016
|
-
return {
|
|
11017
|
-
type: "avc-pps",
|
|
11018
|
-
pps
|
|
11019
|
-
};
|
|
11329
|
+
if (id === "avih") {
|
|
11330
|
+
return Promise.resolve(parseAvih({ iterator, size }));
|
|
11020
11331
|
}
|
|
11021
|
-
if (
|
|
11022
|
-
return {
|
|
11023
|
-
type: "delta-frame"
|
|
11024
|
-
};
|
|
11332
|
+
if (id === "strh") {
|
|
11333
|
+
return Promise.resolve(parseStrh({ iterator, size }));
|
|
11025
11334
|
}
|
|
11026
|
-
iterator.
|
|
11027
|
-
|
|
11335
|
+
iterator.discard(size);
|
|
11336
|
+
const box = {
|
|
11337
|
+
type: "riff-box",
|
|
11338
|
+
size,
|
|
11339
|
+
id
|
|
11340
|
+
};
|
|
11341
|
+
return Promise.resolve(box);
|
|
11028
11342
|
};
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11032
|
-
|
|
11033
|
-
|
|
11034
|
-
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11343
|
+
|
|
11344
|
+
// src/containers/riff/expect-riff-box.ts
|
|
11345
|
+
var expectRiffBox = async (state) => {
|
|
11346
|
+
const { iterator } = state;
|
|
11347
|
+
if (state.iterator.bytesRemaining() < 16) {
|
|
11348
|
+
return null;
|
|
11349
|
+
}
|
|
11350
|
+
const checkpoint = iterator.startCheckpoint();
|
|
11351
|
+
const ckId = iterator.getByteString(4, false);
|
|
11352
|
+
const ckSize = iterator.getUint32Le();
|
|
11353
|
+
if (isMoviAtom(iterator, ckId)) {
|
|
11354
|
+
iterator.discard(4);
|
|
11355
|
+
state.mediaSection.addMediaSection({
|
|
11356
|
+
start: iterator.counter.getOffset(),
|
|
11357
|
+
size: ckSize - 4
|
|
11358
|
+
});
|
|
11359
|
+
return null;
|
|
11360
|
+
}
|
|
11361
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
11362
|
+
checkpoint.returnToCheckpoint();
|
|
11363
|
+
return null;
|
|
11364
|
+
}
|
|
11365
|
+
const box = await parseRiffBox({
|
|
11366
|
+
id: ckId,
|
|
11367
|
+
size: ckSize,
|
|
11368
|
+
state
|
|
11369
|
+
});
|
|
11370
|
+
if (box.type === "strh-box") {
|
|
11371
|
+
if (box.strf.type === "strf-box-audio" && state.onAudioTrack) {
|
|
11372
|
+
const audioTrack = makeAviAudioTrack({
|
|
11373
|
+
index: state.riff.getNextTrackIndex(),
|
|
11374
|
+
strf: box.strf
|
|
11375
|
+
});
|
|
11376
|
+
await registerAudioTrack({
|
|
11377
|
+
track: audioTrack,
|
|
11378
|
+
container: "avi",
|
|
11379
|
+
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
11380
|
+
tracks: state.callbacks.tracks,
|
|
11381
|
+
logLevel: state.logLevel,
|
|
11382
|
+
onAudioTrack: state.onAudioTrack
|
|
11383
|
+
});
|
|
11047
11384
|
}
|
|
11048
|
-
if (
|
|
11049
|
-
|
|
11385
|
+
if (state.onVideoTrack && box.strf.type === "strf-box-video") {
|
|
11386
|
+
const videoTrack = makeAviVideoTrack({
|
|
11387
|
+
strh: box,
|
|
11388
|
+
index: state.riff.getNextTrackIndex(),
|
|
11389
|
+
strf: box.strf
|
|
11390
|
+
});
|
|
11391
|
+
registerVideoTrackWhenProfileIsAvailable({
|
|
11392
|
+
state,
|
|
11393
|
+
track: videoTrack,
|
|
11394
|
+
container: "avi"
|
|
11395
|
+
});
|
|
11050
11396
|
}
|
|
11397
|
+
state.riff.incrementNextTrackIndex();
|
|
11051
11398
|
}
|
|
11052
|
-
return
|
|
11399
|
+
return box;
|
|
11053
11400
|
};
|
|
11054
11401
|
|
|
11055
11402
|
// src/containers/riff/parse-movi.ts
|
|
@@ -11105,7 +11452,6 @@ var handleChunk = async ({
|
|
|
11105
11452
|
},
|
|
11106
11453
|
timescale: 1
|
|
11107
11454
|
}),
|
|
11108
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
11109
11455
|
callbacks: state.callbacks
|
|
11110
11456
|
});
|
|
11111
11457
|
return;
|
|
@@ -11135,7 +11481,6 @@ var handleChunk = async ({
|
|
|
11135
11481
|
},
|
|
11136
11482
|
timescale: 1
|
|
11137
11483
|
}),
|
|
11138
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
11139
11484
|
callbacks: state.callbacks
|
|
11140
11485
|
});
|
|
11141
11486
|
}
|
|
@@ -11296,7 +11641,10 @@ var parseSdt = (iterator) => {
|
|
|
11296
11641
|
};
|
|
11297
11642
|
|
|
11298
11643
|
// src/containers/transport-stream/parse-pes.ts
|
|
11299
|
-
var parsePes = (
|
|
11644
|
+
var parsePes = ({
|
|
11645
|
+
iterator,
|
|
11646
|
+
offset
|
|
11647
|
+
}) => {
|
|
11300
11648
|
const ident = iterator.getUint24();
|
|
11301
11649
|
if (ident !== 1) {
|
|
11302
11650
|
throw new Error(`Unexpected PES packet start code: ${ident.toString(16)}`);
|
|
@@ -11328,7 +11676,7 @@ var parsePes = (iterator) => {
|
|
|
11328
11676
|
iterator.getBits(1);
|
|
11329
11677
|
iterator.getBits(1);
|
|
11330
11678
|
const pesHeaderLength = iterator.getBits(8);
|
|
11331
|
-
const
|
|
11679
|
+
const offsetAfterHeader = iterator.counter.getOffset();
|
|
11332
11680
|
let pts = null;
|
|
11333
11681
|
if (!ptsPresent) {
|
|
11334
11682
|
throw new Error(`PTS is required`);
|
|
@@ -11359,12 +11707,13 @@ var parsePes = (iterator) => {
|
|
|
11359
11707
|
dts = dts1 << 30 | dts2 << 15 | dts3;
|
|
11360
11708
|
}
|
|
11361
11709
|
iterator.stopReadingBits();
|
|
11362
|
-
iterator.discard(pesHeaderLength - (iterator.counter.getOffset() -
|
|
11710
|
+
iterator.discard(pesHeaderLength - (iterator.counter.getOffset() - offsetAfterHeader));
|
|
11363
11711
|
const packet = {
|
|
11364
11712
|
dts,
|
|
11365
11713
|
pts,
|
|
11366
11714
|
streamId,
|
|
11367
|
-
priority
|
|
11715
|
+
priority,
|
|
11716
|
+
offset
|
|
11368
11717
|
};
|
|
11369
11718
|
return packet;
|
|
11370
11719
|
};
|
|
@@ -11434,64 +11783,19 @@ var parsePmt = (iterator) => {
|
|
|
11434
11783
|
return tables;
|
|
11435
11784
|
};
|
|
11436
11785
|
|
|
11437
|
-
// src/containers/transport-stream/adts-header.ts
|
|
11438
|
-
var readAdtsHeader = (buffer) => {
|
|
11439
|
-
if (buffer.byteLength < 9) {
|
|
11440
|
-
return null;
|
|
11441
|
-
}
|
|
11442
|
-
const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
|
|
11443
|
-
iterator.startReadingBits();
|
|
11444
|
-
const bits = iterator.getBits(12);
|
|
11445
|
-
if (bits !== 4095) {
|
|
11446
|
-
throw new Error("Invalid ADTS header ");
|
|
11447
|
-
}
|
|
11448
|
-
const id = iterator.getBits(1);
|
|
11449
|
-
if (id !== 0) {
|
|
11450
|
-
throw new Error("Only supporting MPEG-4 for .ts");
|
|
11451
|
-
}
|
|
11452
|
-
const layer = iterator.getBits(2);
|
|
11453
|
-
if (layer !== 0) {
|
|
11454
|
-
throw new Error("Only supporting layer 0 for .ts");
|
|
11455
|
-
}
|
|
11456
|
-
const protectionAbsent = iterator.getBits(1);
|
|
11457
|
-
const audioObjectType = iterator.getBits(2);
|
|
11458
|
-
const samplingFrequencyIndex = iterator.getBits(4);
|
|
11459
|
-
const sampleRate = getSampleRateFromSampleFrequencyIndex(samplingFrequencyIndex);
|
|
11460
|
-
iterator.getBits(1);
|
|
11461
|
-
const channelConfiguration = iterator.getBits(3);
|
|
11462
|
-
const codecPrivate2 = createAacCodecPrivate({
|
|
11463
|
-
audioObjectType,
|
|
11464
|
-
sampleRate,
|
|
11465
|
-
channelConfiguration,
|
|
11466
|
-
codecPrivate: null
|
|
11467
|
-
});
|
|
11468
|
-
iterator.getBits(1);
|
|
11469
|
-
iterator.getBits(1);
|
|
11470
|
-
iterator.getBits(1);
|
|
11471
|
-
iterator.getBits(1);
|
|
11472
|
-
const frameLength = iterator.getBits(13);
|
|
11473
|
-
iterator.getBits(11);
|
|
11474
|
-
iterator.getBits(2);
|
|
11475
|
-
if (!protectionAbsent) {
|
|
11476
|
-
iterator.getBits(16);
|
|
11477
|
-
}
|
|
11478
|
-
iterator.stopReadingBits();
|
|
11479
|
-
iterator.destroy();
|
|
11480
|
-
return {
|
|
11481
|
-
frameLength,
|
|
11482
|
-
codecPrivate: codecPrivate2,
|
|
11483
|
-
channelConfiguration,
|
|
11484
|
-
sampleRate,
|
|
11485
|
-
audioObjectType
|
|
11486
|
-
};
|
|
11487
|
-
};
|
|
11488
|
-
|
|
11489
11786
|
// src/containers/transport-stream/find-separator.ts
|
|
11490
|
-
function findNthSubarrayIndex(
|
|
11787
|
+
function findNthSubarrayIndex({
|
|
11788
|
+
array,
|
|
11789
|
+
subarray,
|
|
11790
|
+
n,
|
|
11791
|
+
startIndex,
|
|
11792
|
+
startCount
|
|
11793
|
+
}) {
|
|
11491
11794
|
const subarrayLength = subarray.length;
|
|
11492
11795
|
const arrayLength = array.length;
|
|
11493
|
-
let count =
|
|
11494
|
-
|
|
11796
|
+
let count = startCount;
|
|
11797
|
+
let i = startIndex;
|
|
11798
|
+
for (i;i <= arrayLength - subarrayLength; i++) {
|
|
11495
11799
|
let match = true;
|
|
11496
11800
|
for (let j = 0;j < subarrayLength; j++) {
|
|
11497
11801
|
if (array[i + j] !== subarray[j]) {
|
|
@@ -11502,144 +11806,87 @@ function findNthSubarrayIndex(array, subarray, n) {
|
|
|
11502
11806
|
if (match) {
|
|
11503
11807
|
count++;
|
|
11504
11808
|
if (count === n) {
|
|
11505
|
-
return i;
|
|
11809
|
+
return { type: "found", index: i };
|
|
11506
11810
|
}
|
|
11507
11811
|
}
|
|
11508
11812
|
}
|
|
11509
|
-
return -
|
|
11813
|
+
return { type: "not-found", index: i, count };
|
|
11510
11814
|
}
|
|
11511
11815
|
|
|
11512
|
-
// src/containers/
|
|
11513
|
-
var
|
|
11514
|
-
|
|
11515
|
-
|
|
11516
|
-
return {
|
|
11517
|
-
height: (height + 1) * 16 - (sps.frame_crop_bottom_offset ?? 0) * 2 - (sps.frame_crop_top_offset ?? 0) * 2,
|
|
11518
|
-
width: (width + 1) * 16 - (sps.frame_crop_right_offset ?? 0) * 2 - (sps.frame_crop_left_offset ?? 0) * 2
|
|
11519
|
-
};
|
|
11520
|
-
};
|
|
11521
|
-
var getSampleAspectRatioFromSps = (sps) => {
|
|
11522
|
-
if (sps.vui_parameters?.sar_height && sps.vui_parameters.sar_width) {
|
|
11523
|
-
return {
|
|
11524
|
-
width: sps.vui_parameters.sar_width,
|
|
11525
|
-
height: sps.vui_parameters.sar_height
|
|
11526
|
-
};
|
|
11527
|
-
}
|
|
11528
|
-
return {
|
|
11529
|
-
width: 1,
|
|
11530
|
-
height: 1
|
|
11531
|
-
};
|
|
11532
|
-
};
|
|
11533
|
-
var getVideoColorFromSps = (sps) => {
|
|
11534
|
-
const matrixCoefficients2 = sps.vui_parameters?.matrix_coefficients;
|
|
11535
|
-
const transferCharacteristics2 = sps.vui_parameters?.transfer_characteristics;
|
|
11536
|
-
const colorPrimaries = sps.vui_parameters?.colour_primaries;
|
|
11537
|
-
return {
|
|
11538
|
-
matrixCoefficients: matrixCoefficients2 ? getMatrixCoefficientsFromIndex(matrixCoefficients2) : null,
|
|
11539
|
-
transferCharacteristics: transferCharacteristics2 ? getTransferCharacteristicsFromIndex(transferCharacteristics2) : null,
|
|
11540
|
-
primaries: colorPrimaries ? getPrimariesFromIndex(colorPrimaries) : null,
|
|
11541
|
-
fullRange: sps.vui_parameters?.video_full_range_flag ?? null
|
|
11542
|
-
};
|
|
11543
|
-
};
|
|
11544
|
-
|
|
11545
|
-
// src/containers/avc/sps-and-pps.ts
|
|
11546
|
-
var getSpsAndPps = (infos) => {
|
|
11547
|
-
const avcProfile = infos.find((i) => i.type === "avc-profile");
|
|
11548
|
-
const ppsProfile = infos.find((i) => i.type === "avc-pps");
|
|
11549
|
-
if (!avcProfile || !ppsProfile) {
|
|
11550
|
-
throw new Error("Expected avcProfile and ppsProfile");
|
|
11551
|
-
}
|
|
11552
|
-
return { pps: ppsProfile, sps: avcProfile };
|
|
11553
|
-
};
|
|
11554
|
-
|
|
11555
|
-
// src/containers/transport-stream/handle-avc-packet.ts
|
|
11556
|
-
var MPEG_TIMESCALE = 90000;
|
|
11557
|
-
var handleAvcPacket = async ({
|
|
11558
|
-
streamBuffer,
|
|
11559
|
-
programId,
|
|
11560
|
-
state,
|
|
11561
|
-
offset
|
|
11562
|
-
}) => {
|
|
11563
|
-
const avc = parseAvc(streamBuffer.buffer);
|
|
11564
|
-
const isTrackRegistered = state.callbacks.tracks.getTracks().find((t) => {
|
|
11565
|
-
return t.trackId === programId;
|
|
11566
|
-
});
|
|
11567
|
-
if (!isTrackRegistered) {
|
|
11568
|
-
const spsAndPps = getSpsAndPps(avc);
|
|
11569
|
-
const dimensions = getDimensionsFromSps(spsAndPps.sps.spsData);
|
|
11570
|
-
const sampleAspectRatio = getSampleAspectRatioFromSps(spsAndPps.sps.spsData);
|
|
11571
|
-
const track = {
|
|
11572
|
-
m3uStreamFormat: null,
|
|
11573
|
-
rotation: 0,
|
|
11574
|
-
trackId: programId,
|
|
11575
|
-
type: "video",
|
|
11576
|
-
timescale: MPEG_TIMESCALE,
|
|
11577
|
-
codec: getCodecStringFromSpsAndPps(spsAndPps.sps),
|
|
11578
|
-
codecPrivate: createSpsPpsData(spsAndPps),
|
|
11579
|
-
fps: null,
|
|
11580
|
-
codedWidth: dimensions.width,
|
|
11581
|
-
codedHeight: dimensions.height,
|
|
11582
|
-
height: dimensions.height,
|
|
11583
|
-
width: dimensions.width,
|
|
11584
|
-
displayAspectWidth: dimensions.width,
|
|
11585
|
-
displayAspectHeight: dimensions.height,
|
|
11586
|
-
trakBox: null,
|
|
11587
|
-
codecWithoutConfig: "h264",
|
|
11588
|
-
description: undefined,
|
|
11589
|
-
sampleAspectRatio: {
|
|
11590
|
-
denominator: sampleAspectRatio.height,
|
|
11591
|
-
numerator: sampleAspectRatio.width
|
|
11592
|
-
},
|
|
11593
|
-
color: getVideoColorFromSps(spsAndPps.sps.spsData)
|
|
11594
|
-
};
|
|
11595
|
-
await registerVideoTrack({
|
|
11596
|
-
track,
|
|
11597
|
-
container: "transport-stream",
|
|
11598
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
11599
|
-
logLevel: state.logLevel,
|
|
11600
|
-
onVideoTrack: state.onVideoTrack,
|
|
11601
|
-
registerVideoSampleCallback: state.callbacks.registerVideoSampleCallback,
|
|
11602
|
-
tracks: state.callbacks.tracks
|
|
11603
|
-
});
|
|
11816
|
+
// src/containers/transport-stream/adts-header.ts
|
|
11817
|
+
var readAdtsHeader = (buffer) => {
|
|
11818
|
+
if (buffer.byteLength < 9) {
|
|
11819
|
+
return null;
|
|
11604
11820
|
}
|
|
11605
|
-
const
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
|
|
11613
|
-
|
|
11614
|
-
|
|
11615
|
-
|
|
11616
|
-
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11622
|
-
|
|
11623
|
-
|
|
11821
|
+
const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
|
|
11822
|
+
iterator.startReadingBits();
|
|
11823
|
+
const bits = iterator.getBits(12);
|
|
11824
|
+
if (bits !== 4095) {
|
|
11825
|
+
throw new Error("Invalid ADTS header ");
|
|
11826
|
+
}
|
|
11827
|
+
const id = iterator.getBits(1);
|
|
11828
|
+
if (id !== 0) {
|
|
11829
|
+
throw new Error("Only supporting MPEG-4 for .ts");
|
|
11830
|
+
}
|
|
11831
|
+
const layer = iterator.getBits(2);
|
|
11832
|
+
if (layer !== 0) {
|
|
11833
|
+
throw new Error("Only supporting layer 0 for .ts");
|
|
11834
|
+
}
|
|
11835
|
+
const protectionAbsent = iterator.getBits(1);
|
|
11836
|
+
const audioObjectType = iterator.getBits(2);
|
|
11837
|
+
const samplingFrequencyIndex = iterator.getBits(4);
|
|
11838
|
+
const sampleRate = getSampleRateFromSampleFrequencyIndex(samplingFrequencyIndex);
|
|
11839
|
+
iterator.getBits(1);
|
|
11840
|
+
const channelConfiguration = iterator.getBits(3);
|
|
11841
|
+
const codecPrivate2 = createAacCodecPrivate({
|
|
11842
|
+
audioObjectType,
|
|
11843
|
+
sampleRate,
|
|
11844
|
+
channelConfiguration,
|
|
11845
|
+
codecPrivate: null
|
|
11624
11846
|
});
|
|
11847
|
+
iterator.getBits(1);
|
|
11848
|
+
iterator.getBits(1);
|
|
11849
|
+
iterator.getBits(1);
|
|
11850
|
+
iterator.getBits(1);
|
|
11851
|
+
const frameLength = iterator.getBits(13);
|
|
11852
|
+
iterator.getBits(11);
|
|
11853
|
+
iterator.getBits(2);
|
|
11854
|
+
if (!protectionAbsent) {
|
|
11855
|
+
iterator.getBits(16);
|
|
11856
|
+
}
|
|
11857
|
+
iterator.stopReadingBits();
|
|
11858
|
+
iterator.destroy();
|
|
11859
|
+
return {
|
|
11860
|
+
frameLength,
|
|
11861
|
+
codecPrivate: codecPrivate2,
|
|
11862
|
+
channelConfiguration,
|
|
11863
|
+
sampleRate,
|
|
11864
|
+
audioObjectType
|
|
11865
|
+
};
|
|
11625
11866
|
};
|
|
11626
11867
|
|
|
11627
11868
|
// src/containers/transport-stream/handle-aac-packet.ts
|
|
11628
11869
|
var handleAacPacket = async ({
|
|
11629
11870
|
streamBuffer,
|
|
11630
|
-
state,
|
|
11631
11871
|
programId,
|
|
11632
|
-
offset
|
|
11872
|
+
offset,
|
|
11873
|
+
sampleCallbacks,
|
|
11874
|
+
logLevel,
|
|
11875
|
+
onAudioTrack,
|
|
11876
|
+
transportStream,
|
|
11877
|
+
makeSamplesStartAtZero
|
|
11633
11878
|
}) => {
|
|
11634
|
-
const adtsHeader = readAdtsHeader(streamBuffer.
|
|
11879
|
+
const adtsHeader = readAdtsHeader(streamBuffer.getBuffer());
|
|
11635
11880
|
if (!adtsHeader) {
|
|
11636
11881
|
throw new Error("Invalid ADTS header - too short");
|
|
11637
11882
|
}
|
|
11638
11883
|
const { channelConfiguration, codecPrivate: codecPrivate2, sampleRate, audioObjectType } = adtsHeader;
|
|
11639
|
-
const isTrackRegistered =
|
|
11884
|
+
const isTrackRegistered = sampleCallbacks.tracks.getTracks().find((t) => {
|
|
11640
11885
|
return t.trackId === programId;
|
|
11641
11886
|
});
|
|
11642
11887
|
if (!isTrackRegistered) {
|
|
11888
|
+
const startOffset = makeSamplesStartAtZero ? Math.min(streamBuffer.pesHeader.pts, streamBuffer.pesHeader.dts ?? Infinity) : 0;
|
|
11889
|
+
transportStream.startOffset.setOffset(programId, startOffset);
|
|
11643
11890
|
const track = {
|
|
11644
11891
|
type: "audio",
|
|
11645
11892
|
codecPrivate: codecPrivate2,
|
|
@@ -11655,19 +11902,18 @@ var handleAacPacket = async ({
|
|
|
11655
11902
|
await registerAudioTrack({
|
|
11656
11903
|
track,
|
|
11657
11904
|
container: "transport-stream",
|
|
11658
|
-
|
|
11659
|
-
|
|
11660
|
-
|
|
11661
|
-
|
|
11662
|
-
onAudioTrack: state.onAudioTrack
|
|
11905
|
+
registerAudioSampleCallback: sampleCallbacks.registerAudioSampleCallback,
|
|
11906
|
+
tracks: sampleCallbacks.tracks,
|
|
11907
|
+
logLevel,
|
|
11908
|
+
onAudioTrack
|
|
11663
11909
|
});
|
|
11664
11910
|
}
|
|
11665
11911
|
const sample = {
|
|
11666
|
-
cts: streamBuffer.pesHeader.pts,
|
|
11667
|
-
dts: streamBuffer.pesHeader.dts ?? streamBuffer.pesHeader.pts,
|
|
11668
|
-
timestamp: streamBuffer.pesHeader.pts,
|
|
11912
|
+
cts: streamBuffer.pesHeader.pts - transportStream.startOffset.getOffset(programId),
|
|
11913
|
+
dts: (streamBuffer.pesHeader.dts ?? streamBuffer.pesHeader.pts) - transportStream.startOffset.getOffset(programId),
|
|
11914
|
+
timestamp: streamBuffer.pesHeader.pts - transportStream.startOffset.getOffset(programId),
|
|
11669
11915
|
duration: undefined,
|
|
11670
|
-
data:
|
|
11916
|
+
data: streamBuffer.getBuffer(),
|
|
11671
11917
|
trackId: programId,
|
|
11672
11918
|
type: "key",
|
|
11673
11919
|
offset,
|
|
@@ -11679,196 +11925,162 @@ var handleAacPacket = async ({
|
|
|
11679
11925
|
sample,
|
|
11680
11926
|
timescale: MPEG_TIMESCALE
|
|
11681
11927
|
}),
|
|
11682
|
-
|
|
11683
|
-
callbacks: state.callbacks
|
|
11928
|
+
callbacks: sampleCallbacks
|
|
11684
11929
|
});
|
|
11930
|
+
transportStream.lastEmittedSample.setLastEmittedSample(sample);
|
|
11685
11931
|
};
|
|
11686
11932
|
|
|
11687
11933
|
// src/containers/transport-stream/process-stream-buffers.ts
|
|
11934
|
+
var makeTransportStreamPacketBuffer = ({
|
|
11935
|
+
buffers,
|
|
11936
|
+
pesHeader,
|
|
11937
|
+
offset
|
|
11938
|
+
}) => {
|
|
11939
|
+
let currentBuf = buffers ? [buffers] : [];
|
|
11940
|
+
let subarrayIndex = null;
|
|
11941
|
+
const getBuffer = () => {
|
|
11942
|
+
if (currentBuf.length === 0) {
|
|
11943
|
+
return new Uint8Array;
|
|
11944
|
+
}
|
|
11945
|
+
if (currentBuf.length === 1) {
|
|
11946
|
+
return currentBuf[0];
|
|
11947
|
+
}
|
|
11948
|
+
currentBuf = [combineUint8Arrays(currentBuf)];
|
|
11949
|
+
return currentBuf[0];
|
|
11950
|
+
};
|
|
11951
|
+
let fastFind = null;
|
|
11952
|
+
return {
|
|
11953
|
+
pesHeader,
|
|
11954
|
+
offset,
|
|
11955
|
+
getBuffer,
|
|
11956
|
+
addBuffer: (buffer) => {
|
|
11957
|
+
currentBuf.push(buffer);
|
|
11958
|
+
subarrayIndex = null;
|
|
11959
|
+
},
|
|
11960
|
+
get2ndSubArrayIndex: () => {
|
|
11961
|
+
if (subarrayIndex === null) {
|
|
11962
|
+
const result = findNthSubarrayIndex({
|
|
11963
|
+
array: getBuffer(),
|
|
11964
|
+
subarray: new Uint8Array([0, 0, 1, 9]),
|
|
11965
|
+
n: 2,
|
|
11966
|
+
startIndex: fastFind?.index ?? 0,
|
|
11967
|
+
startCount: fastFind?.count ?? 0
|
|
11968
|
+
});
|
|
11969
|
+
if (result.type === "found") {
|
|
11970
|
+
subarrayIndex = result.index;
|
|
11971
|
+
fastFind = null;
|
|
11972
|
+
} else {
|
|
11973
|
+
fastFind = result;
|
|
11974
|
+
return -1;
|
|
11975
|
+
}
|
|
11976
|
+
}
|
|
11977
|
+
return subarrayIndex;
|
|
11978
|
+
}
|
|
11979
|
+
};
|
|
11980
|
+
};
|
|
11688
11981
|
var processStreamBuffer = async ({
|
|
11689
11982
|
streamBuffer,
|
|
11690
|
-
state,
|
|
11691
11983
|
programId,
|
|
11692
|
-
structure
|
|
11984
|
+
structure,
|
|
11985
|
+
sampleCallbacks,
|
|
11986
|
+
logLevel,
|
|
11987
|
+
onAudioTrack,
|
|
11988
|
+
onVideoTrack,
|
|
11989
|
+
transportStream,
|
|
11990
|
+
makeSamplesStartAtZero
|
|
11693
11991
|
}) => {
|
|
11694
11992
|
const stream = getStreamForId(structure, programId);
|
|
11695
11993
|
if (!stream) {
|
|
11696
11994
|
throw new Error("No stream found");
|
|
11697
11995
|
}
|
|
11996
|
+
if (stream.streamType === 2) {
|
|
11997
|
+
throw new Error("H.262 video stream not supported");
|
|
11998
|
+
}
|
|
11698
11999
|
if (stream.streamType === 27) {
|
|
11699
12000
|
await handleAvcPacket({
|
|
11700
12001
|
programId,
|
|
11701
12002
|
streamBuffer,
|
|
11702
|
-
|
|
11703
|
-
|
|
12003
|
+
sampleCallbacks,
|
|
12004
|
+
logLevel,
|
|
12005
|
+
onVideoTrack,
|
|
12006
|
+
offset: streamBuffer.offset,
|
|
12007
|
+
transportStream,
|
|
12008
|
+
makeSamplesStartAtZero
|
|
11704
12009
|
});
|
|
11705
12010
|
} else if (stream.streamType === 15) {
|
|
11706
12011
|
await handleAacPacket({
|
|
11707
12012
|
streamBuffer,
|
|
11708
|
-
state,
|
|
11709
12013
|
programId,
|
|
11710
|
-
offset: streamBuffer.offset
|
|
12014
|
+
offset: streamBuffer.offset,
|
|
12015
|
+
sampleCallbacks,
|
|
12016
|
+
logLevel,
|
|
12017
|
+
onAudioTrack,
|
|
12018
|
+
transportStream,
|
|
12019
|
+
makeSamplesStartAtZero
|
|
11711
12020
|
});
|
|
11712
12021
|
}
|
|
11713
|
-
if (!
|
|
11714
|
-
const tracksRegistered =
|
|
12022
|
+
if (!sampleCallbacks.tracks.hasAllTracks()) {
|
|
12023
|
+
const tracksRegistered = sampleCallbacks.tracks.getTracks().length;
|
|
11715
12024
|
const { streams } = findProgramMapTableOrThrow(structure);
|
|
11716
12025
|
if (filterStreamsBySupportedTypes(streams).length === tracksRegistered) {
|
|
11717
|
-
|
|
12026
|
+
sampleCallbacks.tracks.setIsDone(logLevel);
|
|
11718
12027
|
}
|
|
11719
12028
|
}
|
|
11720
12029
|
};
|
|
11721
12030
|
var processFinalStreamBuffers = async ({
|
|
11722
|
-
|
|
11723
|
-
|
|
12031
|
+
structure,
|
|
12032
|
+
sampleCallbacks,
|
|
12033
|
+
logLevel,
|
|
12034
|
+
onAudioTrack,
|
|
12035
|
+
onVideoTrack,
|
|
12036
|
+
transportStream,
|
|
12037
|
+
makeSamplesStartAtZero
|
|
11724
12038
|
}) => {
|
|
11725
|
-
for (const [programId, buffer] of
|
|
11726
|
-
if (buffer.
|
|
12039
|
+
for (const [programId, buffer] of transportStream.streamBuffers) {
|
|
12040
|
+
if (buffer.getBuffer().byteLength > 0) {
|
|
11727
12041
|
await processStreamBuffer({
|
|
11728
12042
|
streamBuffer: buffer,
|
|
11729
|
-
state,
|
|
11730
12043
|
programId,
|
|
11731
|
-
structure
|
|
12044
|
+
structure,
|
|
12045
|
+
sampleCallbacks,
|
|
12046
|
+
logLevel,
|
|
12047
|
+
onAudioTrack,
|
|
12048
|
+
onVideoTrack,
|
|
12049
|
+
transportStream,
|
|
12050
|
+
makeSamplesStartAtZero
|
|
11732
12051
|
});
|
|
11733
|
-
|
|
12052
|
+
transportStream.streamBuffers.delete(programId);
|
|
11734
12053
|
}
|
|
11735
12054
|
}
|
|
11736
12055
|
};
|
|
11737
12056
|
|
|
11738
12057
|
// src/containers/transport-stream/parse-stream-packet.ts
|
|
11739
|
-
var
|
|
11740
|
-
transportStreamEntry,
|
|
11741
|
-
state,
|
|
11742
|
-
structure,
|
|
11743
|
-
offset
|
|
11744
|
-
}) => {
|
|
11745
|
-
const { streamBuffers, nextPesHeaderStore: nextPesHeader } = state.transportStream;
|
|
11746
|
-
while (true) {
|
|
11747
|
-
const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
|
|
11748
|
-
if (!streamBuffer) {
|
|
11749
|
-
throw new Error("Stream buffer not found");
|
|
11750
|
-
}
|
|
11751
|
-
const expectedLength = readAdtsHeader(streamBuffer.buffer)?.frameLength ?? null;
|
|
11752
|
-
if (expectedLength === null) {
|
|
11753
|
-
break;
|
|
11754
|
-
}
|
|
11755
|
-
if (expectedLength > streamBuffer.buffer.length) {
|
|
11756
|
-
break;
|
|
11757
|
-
}
|
|
11758
|
-
await processStreamBuffer({
|
|
11759
|
-
streamBuffer: {
|
|
11760
|
-
buffer: streamBuffer.buffer.slice(0, expectedLength),
|
|
11761
|
-
offset,
|
|
11762
|
-
pesHeader: streamBuffer.pesHeader
|
|
11763
|
-
},
|
|
11764
|
-
programId: transportStreamEntry.pid,
|
|
11765
|
-
state,
|
|
11766
|
-
structure
|
|
11767
|
-
});
|
|
11768
|
-
const rest = streamBuffer.buffer.slice(expectedLength);
|
|
11769
|
-
streamBuffers.set(transportStreamEntry.pid, {
|
|
11770
|
-
buffer: rest,
|
|
11771
|
-
pesHeader: nextPesHeader.getNextPesHeader(),
|
|
11772
|
-
offset
|
|
11773
|
-
});
|
|
11774
|
-
}
|
|
11775
|
-
};
|
|
11776
|
-
var parseAvcStream = async ({
|
|
11777
|
-
programId,
|
|
11778
|
-
state,
|
|
11779
|
-
structure,
|
|
11780
|
-
streamBuffer
|
|
11781
|
-
}) => {
|
|
11782
|
-
const indexOfSeparator = findNthSubarrayIndex(streamBuffer.buffer, new Uint8Array([0, 0, 1, 9]), 2);
|
|
11783
|
-
if (indexOfSeparator === -1 || indexOfSeparator === 0) {
|
|
11784
|
-
return null;
|
|
11785
|
-
}
|
|
11786
|
-
const packet = streamBuffer.buffer.slice(0, indexOfSeparator);
|
|
11787
|
-
const rest = streamBuffer.buffer.slice(indexOfSeparator);
|
|
11788
|
-
await processStreamBuffer({
|
|
11789
|
-
state,
|
|
11790
|
-
streamBuffer: {
|
|
11791
|
-
offset: streamBuffer.offset,
|
|
11792
|
-
pesHeader: streamBuffer.pesHeader,
|
|
11793
|
-
buffer: packet
|
|
11794
|
-
},
|
|
11795
|
-
programId,
|
|
11796
|
-
structure
|
|
11797
|
-
});
|
|
11798
|
-
return rest;
|
|
11799
|
-
};
|
|
11800
|
-
var parseStream = async ({
|
|
12058
|
+
var parseStream = ({
|
|
11801
12059
|
transportStreamEntry,
|
|
11802
|
-
state,
|
|
11803
12060
|
programId,
|
|
11804
|
-
|
|
12061
|
+
iterator,
|
|
12062
|
+
transportStream
|
|
11805
12063
|
}) => {
|
|
11806
|
-
const
|
|
11807
|
-
let restOfPacket = getRestOfPacket(iterator);
|
|
12064
|
+
const restOfPacket = getRestOfPacket(iterator);
|
|
11808
12065
|
const offset = iterator.counter.getOffset();
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
|
|
11812
|
-
|
|
11813
|
-
|
|
11814
|
-
pesHeader: nextPesHeader.getNextPesHeader(),
|
|
11815
|
-
buffer: new Uint8Array([]),
|
|
11816
|
-
offset
|
|
11817
|
-
});
|
|
11818
|
-
}
|
|
11819
|
-
const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
|
|
11820
|
-
streamBuffer.buffer = combineUint8Arrays([
|
|
11821
|
-
streamBuffer.buffer,
|
|
11822
|
-
restOfPacket
|
|
11823
|
-
]);
|
|
11824
|
-
const rest = await parseAvcStream({
|
|
11825
|
-
state,
|
|
11826
|
-
programId,
|
|
11827
|
-
structure,
|
|
11828
|
-
streamBuffer: streamBuffers.get(transportStreamEntry.pid)
|
|
11829
|
-
});
|
|
11830
|
-
if (rest !== null) {
|
|
11831
|
-
streamBuffers.delete(transportStreamEntry.pid);
|
|
11832
|
-
if (rest.length === 0) {
|
|
11833
|
-
break;
|
|
11834
|
-
}
|
|
11835
|
-
restOfPacket = rest;
|
|
11836
|
-
} else {
|
|
11837
|
-
break;
|
|
11838
|
-
}
|
|
11839
|
-
}
|
|
11840
|
-
return;
|
|
11841
|
-
}
|
|
11842
|
-
if (transportStreamEntry.streamType === 15) {
|
|
11843
|
-
const { streamBuffers, nextPesHeaderStore: nextPesHeader } = state.transportStream;
|
|
11844
|
-
const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
|
|
11845
|
-
if (!streamBuffer) {
|
|
11846
|
-
streamBuffers.set(transportStreamEntry.pid, {
|
|
11847
|
-
buffer: restOfPacket,
|
|
11848
|
-
pesHeader: nextPesHeader.getNextPesHeader(),
|
|
11849
|
-
offset
|
|
11850
|
-
});
|
|
11851
|
-
} else {
|
|
11852
|
-
streamBuffer.buffer = combineUint8Arrays([
|
|
11853
|
-
streamBuffer.buffer,
|
|
11854
|
-
restOfPacket
|
|
11855
|
-
]);
|
|
11856
|
-
}
|
|
11857
|
-
return parseAdtsStream({
|
|
11858
|
-
transportStreamEntry,
|
|
11859
|
-
state,
|
|
11860
|
-
structure,
|
|
12066
|
+
const { streamBuffers, nextPesHeaderStore: nextPesHeader } = transportStream;
|
|
12067
|
+
if (!streamBuffers.has(transportStreamEntry.pid)) {
|
|
12068
|
+
streamBuffers.set(programId, makeTransportStreamPacketBuffer({
|
|
12069
|
+
pesHeader: nextPesHeader.getNextPesHeader(),
|
|
12070
|
+
buffers: null,
|
|
11861
12071
|
offset
|
|
11862
|
-
});
|
|
12072
|
+
}));
|
|
11863
12073
|
}
|
|
11864
|
-
|
|
12074
|
+
const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
|
|
12075
|
+
streamBuffer.addBuffer(restOfPacket);
|
|
11865
12076
|
};
|
|
11866
12077
|
|
|
11867
12078
|
// src/containers/transport-stream/parse-packet.ts
|
|
11868
|
-
var parsePacket =
|
|
11869
|
-
|
|
12079
|
+
var parsePacket = ({
|
|
12080
|
+
iterator,
|
|
12081
|
+
structure,
|
|
12082
|
+
transportStream
|
|
11870
12083
|
}) => {
|
|
11871
|
-
const { iterator } = parserState;
|
|
11872
12084
|
const offset = iterator.counter.getOffset();
|
|
11873
12085
|
const syncByte = iterator.getUint8();
|
|
11874
12086
|
if (syncByte !== 71) {
|
|
@@ -11905,58 +12117,230 @@ var parsePacket = async ({
|
|
|
11905
12117
|
}
|
|
11906
12118
|
const read = iterator.counter.getOffset() - offset;
|
|
11907
12119
|
if (read === 188) {
|
|
11908
|
-
return
|
|
12120
|
+
return null;
|
|
11909
12121
|
}
|
|
11910
|
-
const structure = parserState.structure.getTsStructure();
|
|
11911
12122
|
const pat = structure.boxes.find((b) => b.type === "transport-stream-pmt-box");
|
|
11912
12123
|
const isPes = payloadUnitStartIndicator && pat?.streams.find((e) => e.pid === programId);
|
|
11913
12124
|
if (isPes) {
|
|
11914
|
-
const packetPes = parsePes(iterator);
|
|
11915
|
-
|
|
12125
|
+
const packetPes = parsePes({ iterator, offset });
|
|
12126
|
+
transportStream.nextPesHeaderStore.setNextPesHeader(packetPes);
|
|
12127
|
+
transportStream.observedPesHeaders.addPesHeader(packetPes);
|
|
11916
12128
|
} else if (payloadUnitStartIndicator === 1) {
|
|
11917
12129
|
iterator.getUint8();
|
|
11918
12130
|
}
|
|
11919
12131
|
if (programId === 0) {
|
|
11920
|
-
return
|
|
12132
|
+
return parsePat(iterator);
|
|
11921
12133
|
}
|
|
11922
12134
|
if (programId === 17) {
|
|
11923
|
-
return
|
|
12135
|
+
return parseSdt(iterator);
|
|
11924
12136
|
}
|
|
11925
12137
|
const program = programId === 17 ? null : getProgramForId(structure, programId);
|
|
11926
12138
|
if (program) {
|
|
11927
12139
|
const pmt = parsePmt(iterator);
|
|
11928
|
-
return
|
|
12140
|
+
return pmt;
|
|
11929
12141
|
}
|
|
11930
|
-
const
|
|
11931
|
-
if (
|
|
11932
|
-
|
|
11933
|
-
transportStreamEntry
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
12142
|
+
const transportStreamEntry = getStreamForId(structure, programId);
|
|
12143
|
+
if (transportStreamEntry) {
|
|
12144
|
+
parseStream({
|
|
12145
|
+
transportStreamEntry,
|
|
12146
|
+
iterator,
|
|
12147
|
+
transportStream,
|
|
12148
|
+
programId
|
|
11937
12149
|
});
|
|
11938
|
-
return
|
|
12150
|
+
return null;
|
|
12151
|
+
}
|
|
12152
|
+
throw new Error("Unknown packet identifier");
|
|
12153
|
+
};
|
|
12154
|
+
|
|
12155
|
+
// src/containers/transport-stream/process-audio.ts
|
|
12156
|
+
var canProcessAudio = ({
|
|
12157
|
+
streamBuffer
|
|
12158
|
+
}) => {
|
|
12159
|
+
const expectedLength = readAdtsHeader(streamBuffer.getBuffer())?.frameLength ?? null;
|
|
12160
|
+
if (expectedLength === null) {
|
|
12161
|
+
return false;
|
|
12162
|
+
}
|
|
12163
|
+
if (expectedLength > streamBuffer.getBuffer().length) {
|
|
12164
|
+
return false;
|
|
12165
|
+
}
|
|
12166
|
+
return true;
|
|
12167
|
+
};
|
|
12168
|
+
var processAudio = async ({
|
|
12169
|
+
transportStreamEntry,
|
|
12170
|
+
structure,
|
|
12171
|
+
offset,
|
|
12172
|
+
sampleCallbacks,
|
|
12173
|
+
logLevel,
|
|
12174
|
+
onAudioTrack,
|
|
12175
|
+
onVideoTrack,
|
|
12176
|
+
transportStream,
|
|
12177
|
+
makeSamplesStartAtZero
|
|
12178
|
+
}) => {
|
|
12179
|
+
const { streamBuffers, nextPesHeaderStore: nextPesHeader } = transportStream;
|
|
12180
|
+
const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
|
|
12181
|
+
if (!streamBuffer) {
|
|
12182
|
+
throw new Error("Stream buffer not found");
|
|
12183
|
+
}
|
|
12184
|
+
const expectedLength = readAdtsHeader(streamBuffer.getBuffer())?.frameLength ?? null;
|
|
12185
|
+
if (expectedLength === null) {
|
|
12186
|
+
throw new Error("Expected length is null");
|
|
12187
|
+
}
|
|
12188
|
+
if (expectedLength > streamBuffer.getBuffer().length) {
|
|
12189
|
+
throw new Error("Expected length is greater than stream buffer length");
|
|
12190
|
+
}
|
|
12191
|
+
await processStreamBuffer({
|
|
12192
|
+
streamBuffer: makeTransportStreamPacketBuffer({
|
|
12193
|
+
buffers: streamBuffer.getBuffer().slice(0, expectedLength),
|
|
12194
|
+
offset,
|
|
12195
|
+
pesHeader: streamBuffer.pesHeader
|
|
12196
|
+
}),
|
|
12197
|
+
programId: transportStreamEntry.pid,
|
|
12198
|
+
structure,
|
|
12199
|
+
sampleCallbacks,
|
|
12200
|
+
logLevel,
|
|
12201
|
+
onAudioTrack,
|
|
12202
|
+
onVideoTrack,
|
|
12203
|
+
transportStream,
|
|
12204
|
+
makeSamplesStartAtZero
|
|
12205
|
+
});
|
|
12206
|
+
const rest = streamBuffer.getBuffer().slice(expectedLength);
|
|
12207
|
+
streamBuffers.set(transportStreamEntry.pid, makeTransportStreamPacketBuffer({
|
|
12208
|
+
buffers: rest,
|
|
12209
|
+
pesHeader: nextPesHeader.getNextPesHeader(),
|
|
12210
|
+
offset
|
|
12211
|
+
}));
|
|
12212
|
+
};
|
|
12213
|
+
|
|
12214
|
+
// src/containers/transport-stream/process-video.ts
|
|
12215
|
+
var canProcessVideo = ({
|
|
12216
|
+
streamBuffer
|
|
12217
|
+
}) => {
|
|
12218
|
+
const indexOfSeparator = streamBuffer.get2ndSubArrayIndex();
|
|
12219
|
+
if (indexOfSeparator === -1 || indexOfSeparator === 0) {
|
|
12220
|
+
return false;
|
|
12221
|
+
}
|
|
12222
|
+
return true;
|
|
12223
|
+
};
|
|
12224
|
+
var processVideo = async ({
|
|
12225
|
+
programId,
|
|
12226
|
+
structure,
|
|
12227
|
+
streamBuffer,
|
|
12228
|
+
sampleCallbacks,
|
|
12229
|
+
logLevel,
|
|
12230
|
+
onAudioTrack,
|
|
12231
|
+
onVideoTrack,
|
|
12232
|
+
transportStream,
|
|
12233
|
+
makeSamplesStartAtZero
|
|
12234
|
+
}) => {
|
|
12235
|
+
const indexOfSeparator = streamBuffer.get2ndSubArrayIndex();
|
|
12236
|
+
if (indexOfSeparator === -1 || indexOfSeparator === 0) {
|
|
12237
|
+
throw new Error("cannot process avc stream");
|
|
12238
|
+
}
|
|
12239
|
+
const buf = streamBuffer.getBuffer();
|
|
12240
|
+
const packet = buf.slice(0, indexOfSeparator);
|
|
12241
|
+
const rest = buf.slice(indexOfSeparator);
|
|
12242
|
+
await processStreamBuffer({
|
|
12243
|
+
streamBuffer: makeTransportStreamPacketBuffer({
|
|
12244
|
+
offset: streamBuffer.offset,
|
|
12245
|
+
pesHeader: streamBuffer.pesHeader,
|
|
12246
|
+
buffers: packet
|
|
12247
|
+
}),
|
|
12248
|
+
programId,
|
|
12249
|
+
structure,
|
|
12250
|
+
sampleCallbacks,
|
|
12251
|
+
logLevel,
|
|
12252
|
+
onAudioTrack,
|
|
12253
|
+
onVideoTrack,
|
|
12254
|
+
transportStream,
|
|
12255
|
+
makeSamplesStartAtZero
|
|
12256
|
+
});
|
|
12257
|
+
return rest;
|
|
12258
|
+
};
|
|
12259
|
+
|
|
12260
|
+
// src/containers/transport-stream/process-sample-if-possible.ts
|
|
12261
|
+
var processSampleIfPossible = async (state) => {
|
|
12262
|
+
const programMap = findProgramMapOrNull(state.structure.getTsStructure());
|
|
12263
|
+
if (!programMap) {
|
|
12264
|
+
return;
|
|
12265
|
+
}
|
|
12266
|
+
let processed = false;
|
|
12267
|
+
for (const stream of programMap.streams) {
|
|
12268
|
+
const streamBuffer = state.transportStream.streamBuffers.get(stream.pid);
|
|
12269
|
+
if (!streamBuffer) {
|
|
12270
|
+
continue;
|
|
12271
|
+
}
|
|
12272
|
+
if (stream.streamType === 27) {
|
|
12273
|
+
if (canProcessVideo({ streamBuffer })) {
|
|
12274
|
+
const rest = await processVideo({
|
|
12275
|
+
programId: stream.pid,
|
|
12276
|
+
structure: state.structure.getTsStructure(),
|
|
12277
|
+
streamBuffer,
|
|
12278
|
+
sampleCallbacks: state.callbacks,
|
|
12279
|
+
logLevel: state.logLevel,
|
|
12280
|
+
onAudioTrack: state.onAudioTrack,
|
|
12281
|
+
onVideoTrack: state.onVideoTrack,
|
|
12282
|
+
transportStream: state.transportStream,
|
|
12283
|
+
makeSamplesStartAtZero: state.makeSamplesStartAtZero
|
|
12284
|
+
});
|
|
12285
|
+
state.transportStream.streamBuffers.delete(stream.pid);
|
|
12286
|
+
state.transportStream.streamBuffers.set(stream.pid, makeTransportStreamPacketBuffer({
|
|
12287
|
+
pesHeader: state.transportStream.nextPesHeaderStore.getNextPesHeader(),
|
|
12288
|
+
buffers: rest,
|
|
12289
|
+
offset: state.iterator.counter.getOffset()
|
|
12290
|
+
}));
|
|
12291
|
+
processed = true;
|
|
12292
|
+
break;
|
|
12293
|
+
}
|
|
12294
|
+
}
|
|
12295
|
+
if (stream.streamType === 15) {
|
|
12296
|
+
if (canProcessAudio({ streamBuffer })) {
|
|
12297
|
+
await processAudio({
|
|
12298
|
+
structure: state.structure.getTsStructure(),
|
|
12299
|
+
offset: state.iterator.counter.getOffset(),
|
|
12300
|
+
sampleCallbacks: state.callbacks,
|
|
12301
|
+
logLevel: state.logLevel,
|
|
12302
|
+
onAudioTrack: state.onAudioTrack,
|
|
12303
|
+
onVideoTrack: state.onVideoTrack,
|
|
12304
|
+
transportStream: state.transportStream,
|
|
12305
|
+
makeSamplesStartAtZero: state.makeSamplesStartAtZero,
|
|
12306
|
+
transportStreamEntry: stream
|
|
12307
|
+
});
|
|
12308
|
+
processed = true;
|
|
12309
|
+
break;
|
|
12310
|
+
}
|
|
12311
|
+
}
|
|
11939
12312
|
}
|
|
11940
|
-
|
|
12313
|
+
return processed;
|
|
11941
12314
|
};
|
|
11942
12315
|
|
|
11943
12316
|
// src/containers/transport-stream/parse-transport-stream.ts
|
|
11944
12317
|
var parseTransportStream = async (state) => {
|
|
11945
12318
|
const structure = state.structure.getTsStructure();
|
|
12319
|
+
const processed = await processSampleIfPossible(state);
|
|
12320
|
+
if (processed) {
|
|
12321
|
+
return Promise.resolve(null);
|
|
12322
|
+
}
|
|
11946
12323
|
const { iterator } = state;
|
|
11947
12324
|
if (iterator.bytesRemaining() < 188) {
|
|
11948
12325
|
return Promise.resolve(null);
|
|
11949
12326
|
}
|
|
11950
|
-
const packet =
|
|
11951
|
-
|
|
12327
|
+
const packet = parsePacket({
|
|
12328
|
+
iterator,
|
|
12329
|
+
structure,
|
|
12330
|
+
transportStream: state.transportStream
|
|
11952
12331
|
});
|
|
11953
12332
|
if (packet) {
|
|
11954
12333
|
structure.boxes.push(packet);
|
|
11955
12334
|
}
|
|
11956
12335
|
if (iterator.bytesRemaining() === 0) {
|
|
11957
12336
|
await processFinalStreamBuffers({
|
|
11958
|
-
state,
|
|
11959
|
-
structure
|
|
12337
|
+
transportStream: state.transportStream,
|
|
12338
|
+
structure,
|
|
12339
|
+
sampleCallbacks: state.callbacks,
|
|
12340
|
+
logLevel: state.logLevel,
|
|
12341
|
+
onAudioTrack: state.onAudioTrack,
|
|
12342
|
+
onVideoTrack: state.onVideoTrack,
|
|
12343
|
+
makeSamplesStartAtZero: state.makeSamplesStartAtZero
|
|
11960
12344
|
});
|
|
11961
12345
|
}
|
|
11962
12346
|
return Promise.resolve(null);
|
|
@@ -12014,7 +12398,6 @@ var parseFmt = async ({
|
|
|
12014
12398
|
};
|
|
12015
12399
|
state.structure.getWavStructure().boxes.push(wavHeader);
|
|
12016
12400
|
await registerAudioTrack({
|
|
12017
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
12018
12401
|
track: {
|
|
12019
12402
|
type: "audio",
|
|
12020
12403
|
codec: format,
|
|
@@ -12139,7 +12522,6 @@ var parseMediaSection2 = async ({
|
|
|
12139
12522
|
},
|
|
12140
12523
|
timescale: 1
|
|
12141
12524
|
}),
|
|
12142
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
12143
12525
|
callbacks: state.callbacks
|
|
12144
12526
|
});
|
|
12145
12527
|
return null;
|
|
@@ -12172,6 +12554,35 @@ var parseWav = (state) => {
|
|
|
12172
12554
|
throw new Error(`Unknown WAV box type ${type}`);
|
|
12173
12555
|
};
|
|
12174
12556
|
|
|
12557
|
+
// src/containers/webm/get-byte-for-cues.ts
|
|
12558
|
+
var getByteForSeek = ({
|
|
12559
|
+
seekHeadSegment,
|
|
12560
|
+
offset
|
|
12561
|
+
}) => {
|
|
12562
|
+
const value = seekHeadSegment.value.map((v) => {
|
|
12563
|
+
if (v.type !== "Seek") {
|
|
12564
|
+
return null;
|
|
12565
|
+
}
|
|
12566
|
+
const seekId2 = v.value.find((_v) => {
|
|
12567
|
+
return _v.type === "SeekID" && _v.value === matroskaElements.Cues;
|
|
12568
|
+
});
|
|
12569
|
+
if (!seekId2) {
|
|
12570
|
+
return null;
|
|
12571
|
+
}
|
|
12572
|
+
const seekPosition2 = v.value.find((_v) => {
|
|
12573
|
+
return _v.type === "SeekPosition";
|
|
12574
|
+
});
|
|
12575
|
+
if (!seekPosition2) {
|
|
12576
|
+
return false;
|
|
12577
|
+
}
|
|
12578
|
+
return seekPosition2.value;
|
|
12579
|
+
}).filter(truthy);
|
|
12580
|
+
if (value.length === 0) {
|
|
12581
|
+
return null;
|
|
12582
|
+
}
|
|
12583
|
+
return value[0].value + offset;
|
|
12584
|
+
};
|
|
12585
|
+
|
|
12175
12586
|
// src/containers/webm/segments/block-simple-block-flags.ts
|
|
12176
12587
|
var parseBlockFlags = (iterator, type) => {
|
|
12177
12588
|
if (type === matroskaElements.Block) {
|
|
@@ -12208,19 +12619,20 @@ var parseBlockFlags = (iterator, type) => {
|
|
|
12208
12619
|
var addAvcToTrackIfNecessary = ({
|
|
12209
12620
|
partialVideoSample,
|
|
12210
12621
|
codec,
|
|
12211
|
-
|
|
12622
|
+
structureState: structureState2,
|
|
12623
|
+
webmState,
|
|
12212
12624
|
trackNumber: trackNumber2
|
|
12213
12625
|
}) => {
|
|
12214
|
-
if (codec === "V_MPEG4/ISO/AVC" && getTracksFromMatroska({
|
|
12626
|
+
if (codec === "V_MPEG4/ISO/AVC" && getTracksFromMatroska({ structureState: structureState2, webmState }).missingInfo.length > 0) {
|
|
12215
12627
|
const parsed = parseAvc(partialVideoSample.data);
|
|
12216
12628
|
for (const parse of parsed) {
|
|
12217
12629
|
if (parse.type === "avc-profile") {
|
|
12218
|
-
|
|
12630
|
+
webmState.setAvcProfileForTrackNumber(trackNumber2, parse);
|
|
12219
12631
|
}
|
|
12220
12632
|
}
|
|
12221
12633
|
}
|
|
12222
12634
|
};
|
|
12223
|
-
var getSampleFromBlock = (ebml,
|
|
12635
|
+
var getSampleFromBlock = (ebml, webmState, offset, structureState2) => {
|
|
12224
12636
|
const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
|
|
12225
12637
|
const trackNumber2 = iterator.getVint();
|
|
12226
12638
|
if (trackNumber2 === null) {
|
|
@@ -12228,9 +12640,9 @@ var getSampleFromBlock = (ebml, state, offset) => {
|
|
|
12228
12640
|
}
|
|
12229
12641
|
const timecodeRelativeToCluster = iterator.getInt16();
|
|
12230
12642
|
const { keyframe } = parseBlockFlags(iterator, ebml.type === "SimpleBlock" ? matroskaElements.SimpleBlock : matroskaElements.Block);
|
|
12231
|
-
const { codec, trackTimescale } =
|
|
12232
|
-
const clusterOffset =
|
|
12233
|
-
const timescale =
|
|
12643
|
+
const { codec, trackTimescale } = webmState.getTrackInfoByNumber(trackNumber2);
|
|
12644
|
+
const clusterOffset = webmState.getTimestampOffsetForByteOffset(offset);
|
|
12645
|
+
const timescale = webmState.getTimescale();
|
|
12234
12646
|
if (clusterOffset === undefined) {
|
|
12235
12647
|
throw new Error("Could not find offset for byte offset " + offset);
|
|
12236
12648
|
}
|
|
@@ -12261,7 +12673,8 @@ var getSampleFromBlock = (ebml, state, offset) => {
|
|
|
12261
12673
|
addAvcToTrackIfNecessary({
|
|
12262
12674
|
codec,
|
|
12263
12675
|
partialVideoSample,
|
|
12264
|
-
|
|
12676
|
+
structureState: structureState2,
|
|
12677
|
+
webmState,
|
|
12265
12678
|
trackNumber: trackNumber2
|
|
12266
12679
|
});
|
|
12267
12680
|
const sample = {
|
|
@@ -12299,8 +12712,7 @@ var getSampleFromBlock = (ebml, state, offset) => {
|
|
|
12299
12712
|
};
|
|
12300
12713
|
|
|
12301
12714
|
// src/containers/webm/parse-ebml.ts
|
|
12302
|
-
var parseEbml = async (
|
|
12303
|
-
const { iterator } = state;
|
|
12715
|
+
var parseEbml = async (iterator, statesForProcessing) => {
|
|
12304
12716
|
const hex = iterator.getMatroskaSegmentId();
|
|
12305
12717
|
if (hex === null) {
|
|
12306
12718
|
throw new Error("Not enough bytes left to parse EBML - this should not happen");
|
|
@@ -12369,12 +12781,12 @@ var parseEbml = async (state) => {
|
|
|
12369
12781
|
break;
|
|
12370
12782
|
}
|
|
12371
12783
|
const offset = iterator.counter.getOffset();
|
|
12372
|
-
const value = await parseEbml(
|
|
12373
|
-
const remapped = await postprocessEbml({
|
|
12784
|
+
const value = await parseEbml(iterator, statesForProcessing);
|
|
12785
|
+
const remapped = statesForProcessing ? await postprocessEbml({
|
|
12374
12786
|
offset,
|
|
12375
12787
|
ebml: value,
|
|
12376
|
-
|
|
12377
|
-
});
|
|
12788
|
+
statesForProcessing
|
|
12789
|
+
}) : value;
|
|
12378
12790
|
children.push(remapped);
|
|
12379
12791
|
const offsetNow = iterator.counter.getOffset();
|
|
12380
12792
|
if (offsetNow - startOffset > size) {
|
|
@@ -12391,54 +12803,58 @@ var parseEbml = async (state) => {
|
|
|
12391
12803
|
var postprocessEbml = async ({
|
|
12392
12804
|
offset,
|
|
12393
12805
|
ebml,
|
|
12394
|
-
|
|
12806
|
+
statesForProcessing: {
|
|
12807
|
+
webmState,
|
|
12808
|
+
callbacks,
|
|
12809
|
+
logLevel,
|
|
12810
|
+
onAudioTrack,
|
|
12811
|
+
onVideoTrack,
|
|
12812
|
+
structureState: structureState2
|
|
12813
|
+
}
|
|
12395
12814
|
}) => {
|
|
12396
12815
|
if (ebml.type === "TimestampScale") {
|
|
12397
|
-
|
|
12816
|
+
webmState.setTimescale(ebml.value.value);
|
|
12398
12817
|
}
|
|
12399
12818
|
if (ebml.type === "Tracks") {
|
|
12400
|
-
|
|
12819
|
+
callbacks.tracks.setIsDone(logLevel);
|
|
12401
12820
|
}
|
|
12402
12821
|
if (ebml.type === "TrackEntry") {
|
|
12403
|
-
|
|
12822
|
+
webmState.onTrackEntrySegment(ebml);
|
|
12404
12823
|
const track = getTrack({
|
|
12405
12824
|
track: ebml,
|
|
12406
|
-
timescale:
|
|
12825
|
+
timescale: webmState.getTimescale()
|
|
12407
12826
|
});
|
|
12408
12827
|
if (track && track.type === "audio") {
|
|
12409
12828
|
await registerAudioTrack({
|
|
12410
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
12411
12829
|
track,
|
|
12412
12830
|
container: "webm",
|
|
12413
|
-
registerAudioSampleCallback:
|
|
12414
|
-
tracks:
|
|
12415
|
-
logLevel
|
|
12416
|
-
onAudioTrack
|
|
12831
|
+
registerAudioSampleCallback: callbacks.registerAudioSampleCallback,
|
|
12832
|
+
tracks: callbacks.tracks,
|
|
12833
|
+
logLevel,
|
|
12834
|
+
onAudioTrack
|
|
12417
12835
|
});
|
|
12418
12836
|
}
|
|
12419
12837
|
if (track && track.type === "video") {
|
|
12420
12838
|
await registerVideoTrack({
|
|
12421
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
12422
12839
|
track,
|
|
12423
12840
|
container: "webm",
|
|
12424
|
-
logLevel
|
|
12425
|
-
onVideoTrack
|
|
12426
|
-
registerVideoSampleCallback:
|
|
12427
|
-
tracks:
|
|
12841
|
+
logLevel,
|
|
12842
|
+
onVideoTrack,
|
|
12843
|
+
registerVideoSampleCallback: callbacks.registerVideoSampleCallback,
|
|
12844
|
+
tracks: callbacks.tracks
|
|
12428
12845
|
});
|
|
12429
12846
|
}
|
|
12430
12847
|
}
|
|
12431
12848
|
if (ebml.type === "Timestamp") {
|
|
12432
|
-
|
|
12849
|
+
webmState.setTimestampOffset(offset, ebml.value.value);
|
|
12433
12850
|
}
|
|
12434
12851
|
if (ebml.type === "Block" || ebml.type === "SimpleBlock") {
|
|
12435
|
-
const sample = getSampleFromBlock(ebml,
|
|
12852
|
+
const sample = getSampleFromBlock(ebml, webmState, offset, structureState2);
|
|
12436
12853
|
if (sample.type === "video-sample") {
|
|
12437
12854
|
await emitVideoSample({
|
|
12438
12855
|
trackId: sample.videoSample.trackId,
|
|
12439
12856
|
videoSample: sample.videoSample,
|
|
12440
|
-
|
|
12441
|
-
callbacks: state.callbacks
|
|
12857
|
+
callbacks
|
|
12442
12858
|
});
|
|
12443
12859
|
return {
|
|
12444
12860
|
type: "Block",
|
|
@@ -12450,8 +12866,7 @@ var postprocessEbml = async ({
|
|
|
12450
12866
|
await emitAudioSample({
|
|
12451
12867
|
trackId: sample.audioSample.trackId,
|
|
12452
12868
|
audioSample: sample.audioSample,
|
|
12453
|
-
|
|
12454
|
-
callbacks: state.callbacks
|
|
12869
|
+
callbacks
|
|
12455
12870
|
});
|
|
12456
12871
|
return {
|
|
12457
12872
|
type: "Block",
|
|
@@ -12473,7 +12888,7 @@ var postprocessEbml = async ({
|
|
|
12473
12888
|
throw new Error("Expected block segment");
|
|
12474
12889
|
}
|
|
12475
12890
|
const hasReferenceBlock = ebml.value.find((c) => c.type === "ReferenceBlock");
|
|
12476
|
-
const sample = block2.value.length === 0 ? null : getSampleFromBlock(block2,
|
|
12891
|
+
const sample = block2.value.length === 0 ? null : getSampleFromBlock(block2, webmState, offset, structureState2);
|
|
12477
12892
|
if (sample && sample.type === "partial-video-sample") {
|
|
12478
12893
|
const completeFrame = {
|
|
12479
12894
|
...sample.partialVideoSample,
|
|
@@ -12482,8 +12897,7 @@ var postprocessEbml = async ({
|
|
|
12482
12897
|
await emitVideoSample({
|
|
12483
12898
|
trackId: sample.partialVideoSample.trackId,
|
|
12484
12899
|
videoSample: completeFrame,
|
|
12485
|
-
|
|
12486
|
-
callbacks: state.callbacks
|
|
12900
|
+
callbacks
|
|
12487
12901
|
});
|
|
12488
12902
|
}
|
|
12489
12903
|
return {
|
|
@@ -12497,10 +12911,12 @@ var postprocessEbml = async ({
|
|
|
12497
12911
|
|
|
12498
12912
|
// src/containers/webm/segments.ts
|
|
12499
12913
|
var expectSegment = async ({
|
|
12500
|
-
|
|
12501
|
-
isInsideSegment
|
|
12914
|
+
statesForProcessing,
|
|
12915
|
+
isInsideSegment,
|
|
12916
|
+
iterator,
|
|
12917
|
+
logLevel,
|
|
12918
|
+
mediaSectionState: mediaSectionState2
|
|
12502
12919
|
}) => {
|
|
12503
|
-
const { iterator } = state;
|
|
12504
12920
|
if (iterator.bytesRemaining() === 0) {
|
|
12505
12921
|
throw new Error("has no bytes");
|
|
12506
12922
|
}
|
|
@@ -12519,9 +12935,12 @@ var expectSegment = async ({
|
|
|
12519
12935
|
return null;
|
|
12520
12936
|
}
|
|
12521
12937
|
const bytesRemainingNow = iterator.bytesRemaining();
|
|
12522
|
-
Log.trace(
|
|
12938
|
+
Log.trace(logLevel, "Segment ID:", ebmlMap[segmentId]?.name, "Size:" + size, bytesRemainingNow);
|
|
12523
12939
|
if (segmentId === matroskaElements.Segment) {
|
|
12524
|
-
|
|
12940
|
+
if (!statesForProcessing) {
|
|
12941
|
+
throw new Error("States for processing are required");
|
|
12942
|
+
}
|
|
12943
|
+
statesForProcessing.webmState.addSegment({
|
|
12525
12944
|
start: offset,
|
|
12526
12945
|
size
|
|
12527
12946
|
});
|
|
@@ -12536,7 +12955,16 @@ var expectSegment = async ({
|
|
|
12536
12955
|
if (isInsideSegment === null) {
|
|
12537
12956
|
throw new Error("Expected to be inside segment");
|
|
12538
12957
|
}
|
|
12539
|
-
|
|
12958
|
+
if (!statesForProcessing) {
|
|
12959
|
+
throw new Error("States for processing are required");
|
|
12960
|
+
}
|
|
12961
|
+
if (mediaSectionState2) {
|
|
12962
|
+
mediaSectionState2.addMediaSection({
|
|
12963
|
+
start: offset,
|
|
12964
|
+
size
|
|
12965
|
+
});
|
|
12966
|
+
}
|
|
12967
|
+
statesForProcessing.webmState.addCluster({
|
|
12540
12968
|
start: offset,
|
|
12541
12969
|
size,
|
|
12542
12970
|
segment: isInsideSegment.index
|
|
@@ -12555,37 +12983,75 @@ var expectSegment = async ({
|
|
|
12555
12983
|
const segment = await parseSegment({
|
|
12556
12984
|
segmentId,
|
|
12557
12985
|
length: size,
|
|
12558
|
-
|
|
12559
|
-
|
|
12986
|
+
headerReadSoFar: iterator.counter.getOffset() - offset,
|
|
12987
|
+
statesForProcessing,
|
|
12988
|
+
iterator
|
|
12560
12989
|
});
|
|
12561
12990
|
return segment;
|
|
12562
12991
|
};
|
|
12563
12992
|
var parseSegment = async ({
|
|
12564
12993
|
segmentId,
|
|
12565
12994
|
length,
|
|
12566
|
-
|
|
12567
|
-
headerReadSoFar
|
|
12995
|
+
iterator,
|
|
12996
|
+
headerReadSoFar,
|
|
12997
|
+
statesForProcessing
|
|
12568
12998
|
}) => {
|
|
12569
12999
|
if (length < 0) {
|
|
12570
13000
|
throw new Error(`Expected length of ${segmentId} to be greater or equal 0`);
|
|
12571
13001
|
}
|
|
12572
|
-
|
|
12573
|
-
const offset =
|
|
12574
|
-
const ebml = await parseEbml(
|
|
12575
|
-
|
|
13002
|
+
iterator.counter.decrement(headerReadSoFar);
|
|
13003
|
+
const offset = iterator.counter.getOffset();
|
|
13004
|
+
const ebml = await parseEbml(iterator, statesForProcessing);
|
|
13005
|
+
if (!statesForProcessing) {
|
|
13006
|
+
return ebml;
|
|
13007
|
+
}
|
|
13008
|
+
const remapped = await postprocessEbml({
|
|
13009
|
+
offset,
|
|
13010
|
+
ebml,
|
|
13011
|
+
statesForProcessing
|
|
13012
|
+
});
|
|
12576
13013
|
return remapped;
|
|
12577
13014
|
};
|
|
12578
13015
|
|
|
13016
|
+
// src/containers/webm/state-for-processing.ts
|
|
13017
|
+
var selectStatesForProcessing = ({
|
|
13018
|
+
callbacks,
|
|
13019
|
+
logLevel,
|
|
13020
|
+
onAudioTrack,
|
|
13021
|
+
onVideoTrack,
|
|
13022
|
+
structure,
|
|
13023
|
+
webm
|
|
13024
|
+
}) => {
|
|
13025
|
+
return {
|
|
13026
|
+
webmState: webm,
|
|
13027
|
+
callbacks,
|
|
13028
|
+
logLevel,
|
|
13029
|
+
onAudioTrack,
|
|
13030
|
+
onVideoTrack,
|
|
13031
|
+
structureState: structure
|
|
13032
|
+
};
|
|
13033
|
+
};
|
|
13034
|
+
|
|
12579
13035
|
// src/containers/webm/parse-webm-header.ts
|
|
12580
13036
|
var parseWebm = async (state) => {
|
|
12581
13037
|
const structure = state.structure.getMatroskaStructure();
|
|
12582
13038
|
const { iterator } = state;
|
|
13039
|
+
const offset = iterator.counter.getOffset();
|
|
12583
13040
|
const isInsideSegment = state.webm.isInsideSegment(iterator);
|
|
12584
|
-
const isInsideCluster = state.webm.isInsideCluster(
|
|
13041
|
+
const isInsideCluster = state.webm.isInsideCluster(offset);
|
|
12585
13042
|
const results = await expectSegment({
|
|
12586
|
-
|
|
12587
|
-
|
|
13043
|
+
iterator,
|
|
13044
|
+
logLevel: state.logLevel,
|
|
13045
|
+
statesForProcessing: selectStatesForProcessing(state),
|
|
13046
|
+
isInsideSegment,
|
|
13047
|
+
mediaSectionState: state.mediaSection
|
|
12588
13048
|
});
|
|
13049
|
+
if (results?.type === "SeekHead") {
|
|
13050
|
+
const position = getByteForSeek({ seekHeadSegment: results, offset });
|
|
13051
|
+
if (position !== null) {
|
|
13052
|
+
state.webm.cues.triggerLoad(position, offset);
|
|
13053
|
+
}
|
|
13054
|
+
}
|
|
12589
13055
|
if (results === null) {
|
|
12590
13056
|
return null;
|
|
12591
13057
|
}
|
|
@@ -12636,7 +13102,6 @@ var initVideo = async ({ state }) => {
|
|
|
12636
13102
|
const tracks2 = getTracksFromMoovBox(moovAtom);
|
|
12637
13103
|
for (const track of tracks2.videoTracks) {
|
|
12638
13104
|
await registerVideoTrack({
|
|
12639
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
12640
13105
|
track,
|
|
12641
13106
|
container: "mp4",
|
|
12642
13107
|
logLevel: state.logLevel,
|
|
@@ -12647,7 +13112,6 @@ var initVideo = async ({ state }) => {
|
|
|
12647
13112
|
}
|
|
12648
13113
|
for (const track of tracks2.audioTracks) {
|
|
12649
13114
|
await registerAudioTrack({
|
|
12650
|
-
workOnSeekRequestOptions: getWorkOnSeekRequestOptions(state),
|
|
12651
13115
|
track,
|
|
12652
13116
|
container: "mp4",
|
|
12653
13117
|
registerAudioSampleCallback: state.callbacks.registerAudioSampleCallback,
|
|
@@ -12681,6 +13145,10 @@ var initVideo = async ({ state }) => {
|
|
|
12681
13145
|
}
|
|
12682
13146
|
if (fileType.type === "transport-stream") {
|
|
12683
13147
|
Log.verbose(state.logLevel, "Detected MPEG-2 Transport Stream");
|
|
13148
|
+
state.mediaSection.addMediaSection({
|
|
13149
|
+
start: 0,
|
|
13150
|
+
size: contentLength
|
|
13151
|
+
});
|
|
12684
13152
|
state.structure.setStructure({
|
|
12685
13153
|
boxes: [],
|
|
12686
13154
|
type: "transport-stream"
|
|
@@ -12849,12 +13317,10 @@ var parseLoop = async ({
|
|
|
12849
13317
|
}
|
|
12850
13318
|
try {
|
|
12851
13319
|
await triggerInfoEmit(state);
|
|
12852
|
-
const start = Date.now();
|
|
12853
13320
|
await state.controller._internals.checkForAbortAndPause();
|
|
12854
13321
|
const skip = await runParseIteration({
|
|
12855
13322
|
state
|
|
12856
13323
|
});
|
|
12857
|
-
state.timings.timeIterating += Date.now() - start;
|
|
12858
13324
|
if (skip !== null) {
|
|
12859
13325
|
state.increaseSkippedBytes(skip.skipTo - state.iterator.counter.getOffset());
|
|
12860
13326
|
if (skip.skipTo === state.contentLength) {
|
|
@@ -12902,7 +13368,6 @@ var parseLoop = async ({
|
|
|
12902
13368
|
iterationWithThisOffset++;
|
|
12903
13369
|
} else {
|
|
12904
13370
|
iterationWithThisOffset = 0;
|
|
12905
|
-
state.seekInfiniteLoop.reset();
|
|
12906
13371
|
}
|
|
12907
13372
|
}
|
|
12908
13373
|
};
|
|
@@ -13223,6 +13688,9 @@ var keyframesState = () => {
|
|
|
13223
13688
|
const keyframes = [];
|
|
13224
13689
|
return {
|
|
13225
13690
|
addKeyframe: (keyframe) => {
|
|
13691
|
+
if (keyframes.find((k) => k.positionInBytes === keyframe.positionInBytes)) {
|
|
13692
|
+
return;
|
|
13693
|
+
}
|
|
13226
13694
|
keyframes.push(keyframe);
|
|
13227
13695
|
},
|
|
13228
13696
|
getKeyframes: () => {
|
|
@@ -13374,52 +13842,291 @@ var m3uState = (logLevel) => {
|
|
|
13374
13842
|
setAllChunksProcessed: (src) => {
|
|
13375
13843
|
allChunksProcessed[src] = true;
|
|
13376
13844
|
},
|
|
13377
|
-
getAllChunksProcessedForPlaylist,
|
|
13378
|
-
getAllChunksProcessedOverall: () => {
|
|
13379
|
-
if (!selectedMainPlaylist) {
|
|
13380
|
-
return false;
|
|
13845
|
+
getAllChunksProcessedForPlaylist,
|
|
13846
|
+
getAllChunksProcessedOverall: () => {
|
|
13847
|
+
if (!selectedMainPlaylist) {
|
|
13848
|
+
return false;
|
|
13849
|
+
}
|
|
13850
|
+
const selectedPlaylists = getSelectedPlaylists();
|
|
13851
|
+
return selectedPlaylists.every((url) => allChunksProcessed[url]);
|
|
13852
|
+
},
|
|
13853
|
+
setHasFinishedManifest: () => {
|
|
13854
|
+
hasFinishedManifest = true;
|
|
13855
|
+
},
|
|
13856
|
+
hasFinishedManifest: () => hasFinishedManifest,
|
|
13857
|
+
setM3uStreamRun: (playlistUrl, run) => {
|
|
13858
|
+
if (!run) {
|
|
13859
|
+
delete m3uStreamRuns[playlistUrl];
|
|
13860
|
+
return;
|
|
13861
|
+
}
|
|
13862
|
+
m3uStreamRuns[playlistUrl] = run;
|
|
13863
|
+
},
|
|
13864
|
+
setTracksDone: (playlistUrl) => {
|
|
13865
|
+
tracksDone[playlistUrl] = true;
|
|
13866
|
+
const selectedPlaylists = getSelectedPlaylists();
|
|
13867
|
+
return selectedPlaylists.every((url) => tracksDone[url]);
|
|
13868
|
+
},
|
|
13869
|
+
getTrackDone: (playlistUrl) => {
|
|
13870
|
+
return tracksDone[playlistUrl];
|
|
13871
|
+
},
|
|
13872
|
+
getM3uStreamRun: (playlistUrl) => m3uStreamRuns[playlistUrl] ?? null,
|
|
13873
|
+
abortM3UStreamRuns: () => {
|
|
13874
|
+
const values = Object.values(m3uStreamRuns);
|
|
13875
|
+
if (values.length === 0) {
|
|
13876
|
+
return;
|
|
13877
|
+
}
|
|
13878
|
+
Log.trace(logLevel, `Aborting ${values.length} M3U stream runs`);
|
|
13879
|
+
values.forEach((run) => {
|
|
13880
|
+
run.abort();
|
|
13881
|
+
});
|
|
13882
|
+
},
|
|
13883
|
+
setAssociatedPlaylists: (playlists) => {
|
|
13884
|
+
associatedPlaylists = playlists;
|
|
13885
|
+
},
|
|
13886
|
+
getAssociatedPlaylists: () => associatedPlaylists,
|
|
13887
|
+
getSelectedPlaylists,
|
|
13888
|
+
sampleSorter: sampleSorter({ logLevel, getAllChunksProcessedForPlaylist }),
|
|
13889
|
+
setMp4HeaderSegment,
|
|
13890
|
+
getMp4HeaderSegment
|
|
13891
|
+
};
|
|
13892
|
+
};
|
|
13893
|
+
|
|
13894
|
+
// src/containers/webm/seek/format-cues.ts
|
|
13895
|
+
var formatCues = (cues) => {
|
|
13896
|
+
const matroskaCues = [];
|
|
13897
|
+
for (const cue of cues) {
|
|
13898
|
+
if (cue.type === "Crc32") {
|
|
13899
|
+
continue;
|
|
13900
|
+
}
|
|
13901
|
+
if (cue.type !== "CuePoint") {
|
|
13902
|
+
throw new Error("Expected CuePoint");
|
|
13903
|
+
}
|
|
13904
|
+
const cueTime = cue.value.find((_cue) => _cue.type === "CueTime");
|
|
13905
|
+
if (!cueTime) {
|
|
13906
|
+
throw new Error("Expected CueTime");
|
|
13907
|
+
}
|
|
13908
|
+
const cueTrackPositions = cue.value.find((c) => c.type === "CueTrackPositions");
|
|
13909
|
+
if (!cueTrackPositions) {
|
|
13910
|
+
throw new Error("Expected CueTrackPositions");
|
|
13911
|
+
}
|
|
13912
|
+
const cueTimeValue = cueTime.value.value;
|
|
13913
|
+
const cueTrack = cueTrackPositions.value.find((_c) => _c.type === "CueTrack");
|
|
13914
|
+
if (!cueTrack) {
|
|
13915
|
+
throw new Error("Expected CueTrack");
|
|
13916
|
+
}
|
|
13917
|
+
const cueClusterPosition = cueTrackPositions.value.find((_c) => _c.type === "CueClusterPosition");
|
|
13918
|
+
if (!cueClusterPosition) {
|
|
13919
|
+
throw new Error("Expected CueClusterPosition");
|
|
13920
|
+
}
|
|
13921
|
+
const cueRelativePosition = cueTrackPositions.value.find((_c) => _c.type === "CueRelativePosition");
|
|
13922
|
+
const matroskaCue = {
|
|
13923
|
+
trackId: cueTrack.value.value,
|
|
13924
|
+
timeInTimescale: cueTimeValue,
|
|
13925
|
+
clusterPositionInSegment: cueClusterPosition.value.value,
|
|
13926
|
+
relativePosition: cueRelativePosition?.value.value ?? 0
|
|
13927
|
+
};
|
|
13928
|
+
matroskaCues.push(matroskaCue);
|
|
13929
|
+
}
|
|
13930
|
+
return matroskaCues;
|
|
13931
|
+
};
|
|
13932
|
+
|
|
13933
|
+
// src/containers/webm/seek/fetch-web-cues.ts
|
|
13934
|
+
var fetchWebmCues = async ({
|
|
13935
|
+
src,
|
|
13936
|
+
readerInterface,
|
|
13937
|
+
controller,
|
|
13938
|
+
position,
|
|
13939
|
+
logLevel
|
|
13940
|
+
}) => {
|
|
13941
|
+
const result = await readerInterface.read({
|
|
13942
|
+
controller,
|
|
13943
|
+
range: position,
|
|
13944
|
+
src
|
|
13945
|
+
});
|
|
13946
|
+
const { value } = await result.reader.reader.read();
|
|
13947
|
+
if (!value) {
|
|
13948
|
+
return null;
|
|
13949
|
+
}
|
|
13950
|
+
result.reader.abort();
|
|
13951
|
+
const iterator = getArrayBufferIterator(value, value.length);
|
|
13952
|
+
const segment = await expectSegment({
|
|
13953
|
+
iterator,
|
|
13954
|
+
logLevel,
|
|
13955
|
+
statesForProcessing: null,
|
|
13956
|
+
isInsideSegment: null,
|
|
13957
|
+
mediaSectionState: null
|
|
13958
|
+
});
|
|
13959
|
+
iterator.destroy();
|
|
13960
|
+
if (!segment?.value) {
|
|
13961
|
+
return null;
|
|
13962
|
+
}
|
|
13963
|
+
return formatCues(segment.value);
|
|
13964
|
+
};
|
|
13965
|
+
|
|
13966
|
+
// src/state/matroska/lazy-cues-fetch.ts
|
|
13967
|
+
var lazyCuesFetch = ({
|
|
13968
|
+
controller,
|
|
13969
|
+
logLevel,
|
|
13970
|
+
readerInterface,
|
|
13971
|
+
src
|
|
13972
|
+
}) => {
|
|
13973
|
+
let prom = null;
|
|
13974
|
+
let sOffset = null;
|
|
13975
|
+
const triggerLoad = (position, segmentOffset) => {
|
|
13976
|
+
if (prom) {
|
|
13977
|
+
return prom;
|
|
13978
|
+
}
|
|
13979
|
+
if (sOffset && sOffset !== segmentOffset) {
|
|
13980
|
+
throw new Error("Segment offset mismatch");
|
|
13981
|
+
}
|
|
13982
|
+
sOffset = segmentOffset;
|
|
13983
|
+
Log.verbose(logLevel, "Cues box found, trying to lazy load cues");
|
|
13984
|
+
prom = fetchWebmCues({
|
|
13985
|
+
controller,
|
|
13986
|
+
logLevel,
|
|
13987
|
+
position,
|
|
13988
|
+
readerInterface,
|
|
13989
|
+
src
|
|
13990
|
+
}).then((cues) => {
|
|
13991
|
+
Log.verbose(logLevel, "Cues loaded");
|
|
13992
|
+
return cues;
|
|
13993
|
+
});
|
|
13994
|
+
return prom;
|
|
13995
|
+
};
|
|
13996
|
+
const getLoadedCues = async () => {
|
|
13997
|
+
if (!prom) {
|
|
13998
|
+
return null;
|
|
13999
|
+
}
|
|
14000
|
+
const cues = await prom;
|
|
14001
|
+
if (!cues) {
|
|
14002
|
+
return null;
|
|
14003
|
+
}
|
|
14004
|
+
if (!sOffset) {
|
|
14005
|
+
throw new Error("Segment offset not set");
|
|
14006
|
+
}
|
|
14007
|
+
return {
|
|
14008
|
+
cues,
|
|
14009
|
+
segmentOffset: sOffset
|
|
14010
|
+
};
|
|
14011
|
+
};
|
|
14012
|
+
return {
|
|
14013
|
+
triggerLoad,
|
|
14014
|
+
getLoadedCues
|
|
14015
|
+
};
|
|
14016
|
+
};
|
|
14017
|
+
|
|
14018
|
+
// src/state/matroska/webm.ts
|
|
14019
|
+
var webmState = ({
|
|
14020
|
+
controller,
|
|
14021
|
+
logLevel,
|
|
14022
|
+
readerInterface,
|
|
14023
|
+
src
|
|
14024
|
+
}) => {
|
|
14025
|
+
const trackEntries = {};
|
|
14026
|
+
const onTrackEntrySegment = (trackEntry2) => {
|
|
14027
|
+
const trackId = getTrackId(trackEntry2);
|
|
14028
|
+
if (!trackId) {
|
|
14029
|
+
throw new Error("Expected track id");
|
|
14030
|
+
}
|
|
14031
|
+
if (trackEntries[trackId]) {
|
|
14032
|
+
return;
|
|
14033
|
+
}
|
|
14034
|
+
const codec = getTrackCodec(trackEntry2);
|
|
14035
|
+
if (!codec) {
|
|
14036
|
+
throw new Error("Expected codec");
|
|
14037
|
+
}
|
|
14038
|
+
const trackTimescale = getTrackTimestampScale(trackEntry2);
|
|
14039
|
+
trackEntries[trackId] = {
|
|
14040
|
+
codec: codec.value,
|
|
14041
|
+
trackTimescale: trackTimescale?.value ?? null
|
|
14042
|
+
};
|
|
14043
|
+
};
|
|
14044
|
+
const timestampMap = new Map;
|
|
14045
|
+
const getTimestampOffsetForByteOffset = (byteOffset) => {
|
|
14046
|
+
const entries = Array.from(timestampMap.entries());
|
|
14047
|
+
const sortedByByteOffset = entries.sort((a, b) => {
|
|
14048
|
+
return a[0] - b[0];
|
|
14049
|
+
}).reverse();
|
|
14050
|
+
for (const [offset, timestamp] of sortedByByteOffset) {
|
|
14051
|
+
if (offset >= byteOffset) {
|
|
14052
|
+
continue;
|
|
14053
|
+
}
|
|
14054
|
+
return timestamp;
|
|
14055
|
+
}
|
|
14056
|
+
return timestampMap.get(byteOffset);
|
|
14057
|
+
};
|
|
14058
|
+
const setTimestampOffset = (byteOffset, timestamp) => {
|
|
14059
|
+
timestampMap.set(byteOffset, timestamp);
|
|
14060
|
+
};
|
|
14061
|
+
let timescale = null;
|
|
14062
|
+
const setTimescale = (newTimescale) => {
|
|
14063
|
+
timescale = newTimescale;
|
|
14064
|
+
};
|
|
14065
|
+
const getTimescale = () => {
|
|
14066
|
+
if (timescale === null) {
|
|
14067
|
+
return 1e6;
|
|
14068
|
+
}
|
|
14069
|
+
return timescale;
|
|
14070
|
+
};
|
|
14071
|
+
const segments = [];
|
|
14072
|
+
const clusters = [];
|
|
14073
|
+
const avcProfilesMap = {};
|
|
14074
|
+
const setAvcProfileForTrackNumber = (trackNumber2, avcProfile) => {
|
|
14075
|
+
avcProfilesMap[trackNumber2] = avcProfile;
|
|
14076
|
+
};
|
|
14077
|
+
const getAvcProfileForTrackNumber = (trackNumber2) => {
|
|
14078
|
+
return avcProfilesMap[trackNumber2] ?? null;
|
|
14079
|
+
};
|
|
14080
|
+
const cues = lazyCuesFetch({
|
|
14081
|
+
controller,
|
|
14082
|
+
logLevel,
|
|
14083
|
+
readerInterface,
|
|
14084
|
+
src
|
|
14085
|
+
});
|
|
14086
|
+
return {
|
|
14087
|
+
cues,
|
|
14088
|
+
onTrackEntrySegment,
|
|
14089
|
+
getTrackInfoByNumber: (id) => trackEntries[id],
|
|
14090
|
+
setTimestampOffset,
|
|
14091
|
+
getTimestampOffsetForByteOffset,
|
|
14092
|
+
getTimescale,
|
|
14093
|
+
setTimescale,
|
|
14094
|
+
addSegment: (seg) => {
|
|
14095
|
+
const segment = {
|
|
14096
|
+
...seg,
|
|
14097
|
+
index: segments.length
|
|
14098
|
+
};
|
|
14099
|
+
segments.push(segment);
|
|
14100
|
+
},
|
|
14101
|
+
addCluster: (cluster) => {
|
|
14102
|
+
const exists = clusters.some((existingCluster) => existingCluster.start === cluster.start);
|
|
14103
|
+
if (!exists) {
|
|
14104
|
+
clusters.push(cluster);
|
|
13381
14105
|
}
|
|
13382
|
-
const selectedPlaylists = getSelectedPlaylists();
|
|
13383
|
-
return selectedPlaylists.every((url) => allChunksProcessed[url]);
|
|
13384
14106
|
},
|
|
13385
|
-
|
|
13386
|
-
|
|
14107
|
+
getFirstCluster: () => {
|
|
14108
|
+
return clusters.find((cluster) => cluster.segment === 0);
|
|
13387
14109
|
},
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
14110
|
+
isInsideSegment: (iterator) => {
|
|
14111
|
+
const offset = iterator.counter.getOffset();
|
|
14112
|
+
const insideClusters = segments.filter((cluster) => {
|
|
14113
|
+
return offset >= cluster.start && offset <= cluster.start + cluster.size;
|
|
14114
|
+
});
|
|
14115
|
+
if (insideClusters.length > 1) {
|
|
14116
|
+
throw new Error("Expected to only be inside 1 cluster");
|
|
13393
14117
|
}
|
|
13394
|
-
|
|
13395
|
-
},
|
|
13396
|
-
setTracksDone: (playlistUrl) => {
|
|
13397
|
-
tracksDone[playlistUrl] = true;
|
|
13398
|
-
const selectedPlaylists = getSelectedPlaylists();
|
|
13399
|
-
return selectedPlaylists.every((url) => tracksDone[url]);
|
|
13400
|
-
},
|
|
13401
|
-
getTrackDone: (playlistUrl) => {
|
|
13402
|
-
return tracksDone[playlistUrl];
|
|
14118
|
+
return insideClusters[0] ?? null;
|
|
13403
14119
|
},
|
|
13404
|
-
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
|
|
13408
|
-
|
|
14120
|
+
isInsideCluster: (offset) => {
|
|
14121
|
+
for (const cluster of clusters) {
|
|
14122
|
+
if (offset >= cluster.start && offset <= cluster.start + cluster.size) {
|
|
14123
|
+
return cluster;
|
|
14124
|
+
}
|
|
13409
14125
|
}
|
|
13410
|
-
|
|
13411
|
-
values.forEach((run) => {
|
|
13412
|
-
run.abort();
|
|
13413
|
-
});
|
|
13414
|
-
},
|
|
13415
|
-
setAssociatedPlaylists: (playlists) => {
|
|
13416
|
-
associatedPlaylists = playlists;
|
|
14126
|
+
return null;
|
|
13417
14127
|
},
|
|
13418
|
-
|
|
13419
|
-
|
|
13420
|
-
sampleSorter: sampleSorter({ logLevel, getAllChunksProcessedForPlaylist }),
|
|
13421
|
-
setMp4HeaderSegment,
|
|
13422
|
-
getMp4HeaderSegment
|
|
14128
|
+
setAvcProfileForTrackNumber,
|
|
14129
|
+
getAvcProfileForTrackNumber
|
|
13423
14130
|
};
|
|
13424
14131
|
};
|
|
13425
14132
|
|
|
@@ -13550,19 +14257,19 @@ var sampleCallback = ({
|
|
|
13550
14257
|
}
|
|
13551
14258
|
}
|
|
13552
14259
|
}
|
|
14260
|
+
if (videoSample.type === "key") {
|
|
14261
|
+
keyframes.addKeyframe({
|
|
14262
|
+
trackId,
|
|
14263
|
+
decodingTimeInSeconds: videoSample.dts / videoSample.timescale,
|
|
14264
|
+
positionInBytes: videoSample.offset,
|
|
14265
|
+
presentationTimeInSeconds: videoSample.cts / videoSample.timescale,
|
|
14266
|
+
sizeInBytes: videoSample.data.length
|
|
14267
|
+
});
|
|
14268
|
+
}
|
|
13553
14269
|
if (needsToIterateOverSamples({
|
|
13554
14270
|
fields,
|
|
13555
14271
|
emittedFields
|
|
13556
14272
|
})) {
|
|
13557
|
-
if (fields.slowKeyframes && videoSample.type === "key") {
|
|
13558
|
-
keyframes.addKeyframe({
|
|
13559
|
-
trackId,
|
|
13560
|
-
decodingTimeInSeconds: videoSample.dts / videoSample.timescale,
|
|
13561
|
-
positionInBytes: videoSample.offset,
|
|
13562
|
-
presentationTimeInSeconds: videoSample.cts / videoSample.timescale,
|
|
13563
|
-
sizeInBytes: videoSample.data.length
|
|
13564
|
-
});
|
|
13565
|
-
}
|
|
13566
14273
|
slowDurationAndFpsState.addVideoSample(videoSample);
|
|
13567
14274
|
}
|
|
13568
14275
|
},
|
|
@@ -13586,28 +14293,8 @@ var sampleCallback = ({
|
|
|
13586
14293
|
};
|
|
13587
14294
|
};
|
|
13588
14295
|
|
|
13589
|
-
// src/state/
|
|
13590
|
-
var
|
|
13591
|
-
let lastSeek = null;
|
|
13592
|
-
return {
|
|
13593
|
-
registerSeek: (byte) => {
|
|
13594
|
-
if (!lastSeek || lastSeek.byte !== byte) {
|
|
13595
|
-
lastSeek = { byte, numberOfTimes: 1 };
|
|
13596
|
-
return;
|
|
13597
|
-
}
|
|
13598
|
-
lastSeek.numberOfTimes++;
|
|
13599
|
-
if (lastSeek.numberOfTimes >= 10) {
|
|
13600
|
-
throw new Error(`Seeking infinite loop detected: Seeked to byte 0x${byte.toString(16)} ${lastSeek.numberOfTimes} times in a row with no position change in the file. Check your usage of .seek().`);
|
|
13601
|
-
}
|
|
13602
|
-
},
|
|
13603
|
-
reset: () => {
|
|
13604
|
-
lastSeek = null;
|
|
13605
|
-
}
|
|
13606
|
-
};
|
|
13607
|
-
};
|
|
13608
|
-
|
|
13609
|
-
// src/state/slow-duration-fps.ts
|
|
13610
|
-
var slowDurationAndFpsState = () => {
|
|
14296
|
+
// src/state/samples-observed/slow-duration-fps.ts
|
|
14297
|
+
var samplesObservedState = () => {
|
|
13611
14298
|
let smallestVideoSample;
|
|
13612
14299
|
let largestVideoSample;
|
|
13613
14300
|
let smallestAudioSample;
|
|
@@ -13636,51 +14323,85 @@ var slowDurationAndFpsState = () => {
|
|
|
13636
14323
|
}
|
|
13637
14324
|
return Math.max(videoDuration ?? 0, audioDuration ?? 0);
|
|
13638
14325
|
};
|
|
14326
|
+
const addVideoSample = (videoSample) => {
|
|
14327
|
+
videoSamples.set(videoSample.cts, videoSample.data.byteLength);
|
|
14328
|
+
const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
|
|
14329
|
+
if (largestVideoSample === undefined || presentationTimeInSeconds > largestVideoSample) {
|
|
14330
|
+
largestVideoSample = presentationTimeInSeconds;
|
|
14331
|
+
}
|
|
14332
|
+
if (smallestVideoSample === undefined || presentationTimeInSeconds < smallestVideoSample) {
|
|
14333
|
+
smallestVideoSample = presentationTimeInSeconds;
|
|
14334
|
+
}
|
|
14335
|
+
};
|
|
14336
|
+
const addAudioSample = (audioSample) => {
|
|
14337
|
+
audioSamples.set(audioSample.cts, audioSample.data.byteLength);
|
|
14338
|
+
const presentationTimeInSeconds = audioSample.cts / audioSample.timescale;
|
|
14339
|
+
if (largestAudioSample === undefined || presentationTimeInSeconds > largestAudioSample) {
|
|
14340
|
+
largestAudioSample = presentationTimeInSeconds;
|
|
14341
|
+
}
|
|
14342
|
+
if (smallestAudioSample === undefined || presentationTimeInSeconds < smallestAudioSample) {
|
|
14343
|
+
smallestAudioSample = presentationTimeInSeconds;
|
|
14344
|
+
}
|
|
14345
|
+
};
|
|
14346
|
+
const getFps2 = () => {
|
|
14347
|
+
const videoDuration = getSlowVideoDurationInSeconds() ?? 0;
|
|
14348
|
+
if (videoDuration === 0) {
|
|
14349
|
+
return 0;
|
|
14350
|
+
}
|
|
14351
|
+
return videoSamples.size / videoDuration;
|
|
14352
|
+
};
|
|
14353
|
+
const getSlowNumberOfFrames = () => videoSamples.size;
|
|
14354
|
+
const getAudioBitrate = () => {
|
|
14355
|
+
const audioDuration = getSlowDurationInSeconds();
|
|
14356
|
+
if (audioDuration === 0 || audioSamples.size === 0) {
|
|
14357
|
+
return null;
|
|
14358
|
+
}
|
|
14359
|
+
const audioSizesInBytes = Array.from(audioSamples.values()).reduce((acc, size) => acc + size, 0);
|
|
14360
|
+
return audioSizesInBytes * 8 / audioDuration;
|
|
14361
|
+
};
|
|
14362
|
+
const getVideoBitrate = () => {
|
|
14363
|
+
const videoDuration = getSlowDurationInSeconds();
|
|
14364
|
+
if (videoDuration === 0 || videoSamples.size === 0) {
|
|
14365
|
+
return null;
|
|
14366
|
+
}
|
|
14367
|
+
const videoSizesInBytes = Array.from(videoSamples.values()).reduce((acc, size) => acc + size, 0);
|
|
14368
|
+
return videoSizesInBytes * 8 / videoDuration;
|
|
14369
|
+
};
|
|
13639
14370
|
return {
|
|
13640
|
-
addVideoSample
|
|
13641
|
-
|
|
13642
|
-
const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
|
|
13643
|
-
if (largestVideoSample === undefined || presentationTimeInSeconds > largestVideoSample) {
|
|
13644
|
-
largestVideoSample = presentationTimeInSeconds;
|
|
13645
|
-
}
|
|
13646
|
-
if (smallestVideoSample === undefined || presentationTimeInSeconds < smallestVideoSample) {
|
|
13647
|
-
smallestVideoSample = presentationTimeInSeconds;
|
|
13648
|
-
}
|
|
13649
|
-
},
|
|
13650
|
-
addAudioSample: (audioSample) => {
|
|
13651
|
-
audioSamples.set(audioSample.cts, audioSample.data.byteLength);
|
|
13652
|
-
const presentationTimeInSeconds = audioSample.cts / audioSample.timescale;
|
|
13653
|
-
if (largestAudioSample === undefined || presentationTimeInSeconds > largestAudioSample) {
|
|
13654
|
-
largestAudioSample = presentationTimeInSeconds;
|
|
13655
|
-
}
|
|
13656
|
-
if (smallestAudioSample === undefined || presentationTimeInSeconds < smallestAudioSample) {
|
|
13657
|
-
smallestAudioSample = presentationTimeInSeconds;
|
|
13658
|
-
}
|
|
13659
|
-
},
|
|
14371
|
+
addVideoSample,
|
|
14372
|
+
addAudioSample,
|
|
13660
14373
|
getSlowDurationInSeconds,
|
|
13661
|
-
getFps:
|
|
13662
|
-
|
|
13663
|
-
|
|
13664
|
-
|
|
14374
|
+
getFps: getFps2,
|
|
14375
|
+
getSlowNumberOfFrames,
|
|
14376
|
+
getAudioBitrate,
|
|
14377
|
+
getVideoBitrate
|
|
14378
|
+
};
|
|
14379
|
+
};
|
|
14380
|
+
|
|
14381
|
+
// src/state/seek-infinite-loop.ts
|
|
14382
|
+
var seekInfiniteLoopDetectionState = () => {
|
|
14383
|
+
let lastSeek = null;
|
|
14384
|
+
let firstSeekTime = null;
|
|
14385
|
+
return {
|
|
14386
|
+
registerSeek: (byte) => {
|
|
14387
|
+
const now = Date.now();
|
|
14388
|
+
if (!lastSeek || lastSeek.byte !== byte) {
|
|
14389
|
+
lastSeek = { byte, numberOfTimes: 1 };
|
|
14390
|
+
firstSeekTime = now;
|
|
14391
|
+
return;
|
|
13665
14392
|
}
|
|
13666
|
-
|
|
13667
|
-
|
|
13668
|
-
|
|
13669
|
-
getAudioBitrate: () => {
|
|
13670
|
-
const audioDuration = getSlowDurationInSeconds();
|
|
13671
|
-
if (audioDuration === 0 || audioSamples.size === 0) {
|
|
13672
|
-
return null;
|
|
14393
|
+
lastSeek.numberOfTimes++;
|
|
14394
|
+
if (lastSeek.numberOfTimes >= 10 && firstSeekTime && now - firstSeekTime <= 2000) {
|
|
14395
|
+
throw new Error(`Seeking infinite loop detected: Seeked to byte 0x${byte.toString(16)} ${lastSeek.numberOfTimes} times in a row in the last 2 seconds. Check your usage of .seek().`);
|
|
13673
14396
|
}
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
getVideoBitrate: () => {
|
|
13678
|
-
const videoDuration = getSlowDurationInSeconds();
|
|
13679
|
-
if (videoDuration === 0 || videoSamples.size === 0) {
|
|
13680
|
-
return null;
|
|
14397
|
+
if (now - firstSeekTime > 2000) {
|
|
14398
|
+
lastSeek = { byte, numberOfTimes: 1 };
|
|
14399
|
+
firstSeekTime = now;
|
|
13681
14400
|
}
|
|
13682
|
-
|
|
13683
|
-
|
|
14401
|
+
},
|
|
14402
|
+
reset: () => {
|
|
14403
|
+
lastSeek = null;
|
|
14404
|
+
firstSeekTime = null;
|
|
13684
14405
|
}
|
|
13685
14406
|
};
|
|
13686
14407
|
};
|
|
@@ -13696,7 +14417,21 @@ var timingsState = () => {
|
|
|
13696
14417
|
};
|
|
13697
14418
|
};
|
|
13698
14419
|
|
|
13699
|
-
// src/
|
|
14420
|
+
// src/state/transport-stream/last-emitted-sample.ts
|
|
14421
|
+
var lastEmittedSampleState = () => {
|
|
14422
|
+
let lastEmittedSample = null;
|
|
14423
|
+
return {
|
|
14424
|
+
setLastEmittedSample: (sample) => {
|
|
14425
|
+
lastEmittedSample = sample;
|
|
14426
|
+
},
|
|
14427
|
+
getLastEmittedSample: () => lastEmittedSample,
|
|
14428
|
+
resetLastEmittedSample: () => {
|
|
14429
|
+
lastEmittedSample = null;
|
|
14430
|
+
}
|
|
14431
|
+
};
|
|
14432
|
+
};
|
|
14433
|
+
|
|
14434
|
+
// src/state/transport-stream/next-pes-header-store.ts
|
|
13700
14435
|
var makeNextPesHeaderStore = () => {
|
|
13701
14436
|
let nextPesHeader = null;
|
|
13702
14437
|
return {
|
|
@@ -13712,111 +14447,34 @@ var makeNextPesHeaderStore = () => {
|
|
|
13712
14447
|
};
|
|
13713
14448
|
};
|
|
13714
14449
|
|
|
13715
|
-
// src/state/transport-stream.ts
|
|
13716
|
-
var
|
|
14450
|
+
// src/state/transport-stream/pts-start-offset.ts
|
|
14451
|
+
var ptsStartOffsetStore = () => {
|
|
14452
|
+
const offsets = {};
|
|
13717
14453
|
return {
|
|
13718
|
-
|
|
13719
|
-
|
|
14454
|
+
getOffset: (trackId) => offsets[trackId] || 0,
|
|
14455
|
+
setOffset: (trackId, newOffset) => {
|
|
14456
|
+
offsets[trackId] = newOffset;
|
|
14457
|
+
}
|
|
13720
14458
|
};
|
|
13721
14459
|
};
|
|
13722
14460
|
|
|
13723
|
-
// src/state/
|
|
13724
|
-
var
|
|
13725
|
-
const
|
|
13726
|
-
const
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
throw new Error("Expected codec");
|
|
13737
|
-
}
|
|
13738
|
-
const trackTimescale = getTrackTimestampScale(trackEntry2);
|
|
13739
|
-
trackEntries[trackId] = {
|
|
13740
|
-
codec: codec.value,
|
|
13741
|
-
trackTimescale: trackTimescale?.value ?? null
|
|
13742
|
-
};
|
|
13743
|
-
};
|
|
13744
|
-
const timestampMap = new Map;
|
|
13745
|
-
const getTimestampOffsetForByteOffset = (byteOffset) => {
|
|
13746
|
-
const entries = Array.from(timestampMap.entries());
|
|
13747
|
-
const sortedByByteOffset = entries.sort((a, b) => {
|
|
13748
|
-
return a[0] - b[0];
|
|
13749
|
-
}).reverse();
|
|
13750
|
-
for (const [offset, timestamp] of sortedByByteOffset) {
|
|
13751
|
-
if (offset >= byteOffset) {
|
|
13752
|
-
continue;
|
|
13753
|
-
}
|
|
13754
|
-
return timestamp;
|
|
13755
|
-
}
|
|
13756
|
-
return timestampMap.get(byteOffset);
|
|
13757
|
-
};
|
|
13758
|
-
const setTimestampOffset = (byteOffset, timestamp) => {
|
|
13759
|
-
timestampMap.set(byteOffset, timestamp);
|
|
13760
|
-
};
|
|
13761
|
-
let timescale = null;
|
|
13762
|
-
const setTimescale = (newTimescale) => {
|
|
13763
|
-
timescale = newTimescale;
|
|
13764
|
-
};
|
|
13765
|
-
const getTimescale = () => {
|
|
13766
|
-
if (timescale === null) {
|
|
13767
|
-
return 1e6;
|
|
13768
|
-
}
|
|
13769
|
-
return timescale;
|
|
13770
|
-
};
|
|
13771
|
-
const segments = [];
|
|
13772
|
-
const clusters = [];
|
|
13773
|
-
const avcProfilesMap = {};
|
|
13774
|
-
const setAvcProfileForTrackNumber = (trackNumber2, avcProfile) => {
|
|
13775
|
-
avcProfilesMap[trackNumber2] = avcProfile;
|
|
13776
|
-
};
|
|
13777
|
-
const getAvcProfileForTrackNumber = (trackNumber2) => {
|
|
13778
|
-
return avcProfilesMap[trackNumber2] ?? null;
|
|
13779
|
-
};
|
|
13780
|
-
return {
|
|
13781
|
-
onTrackEntrySegment,
|
|
13782
|
-
getTrackInfoByNumber: (id) => trackEntries[id],
|
|
13783
|
-
setTimestampOffset,
|
|
13784
|
-
getTimestampOffsetForByteOffset,
|
|
13785
|
-
timescale,
|
|
13786
|
-
getTimescale,
|
|
13787
|
-
setTimescale,
|
|
13788
|
-
addSegment: (seg) => {
|
|
13789
|
-
const segment = {
|
|
13790
|
-
...seg,
|
|
13791
|
-
index: segments.length
|
|
13792
|
-
};
|
|
13793
|
-
segments.push(segment);
|
|
13794
|
-
},
|
|
13795
|
-
addCluster: (cluster) => {
|
|
13796
|
-
clusters.push(cluster);
|
|
13797
|
-
},
|
|
13798
|
-
isInsideSegment: (iterator) => {
|
|
13799
|
-
const offset = iterator.counter.getOffset();
|
|
13800
|
-
const insideClusters = segments.filter((cluster) => {
|
|
13801
|
-
return offset >= cluster.start && offset <= cluster.start + cluster.size;
|
|
13802
|
-
});
|
|
13803
|
-
if (insideClusters.length > 1) {
|
|
13804
|
-
throw new Error("Expected to only be inside 1 cluster");
|
|
13805
|
-
}
|
|
13806
|
-
return insideClusters[0] ?? null;
|
|
13807
|
-
},
|
|
13808
|
-
isInsideCluster: (iterator) => {
|
|
13809
|
-
for (const cluster of clusters) {
|
|
13810
|
-
const offset = iterator.counter.getOffset();
|
|
13811
|
-
if (offset >= cluster.start && offset <= cluster.start + cluster.size) {
|
|
13812
|
-
return cluster;
|
|
13813
|
-
}
|
|
13814
|
-
}
|
|
13815
|
-
return null;
|
|
14461
|
+
// src/state/transport-stream/transport-stream.ts
|
|
14462
|
+
var transportStreamState = () => {
|
|
14463
|
+
const streamBuffers = new Map;
|
|
14464
|
+
const startOffset = ptsStartOffsetStore();
|
|
14465
|
+
const lastEmittedSample = lastEmittedSampleState();
|
|
14466
|
+
const state = {
|
|
14467
|
+
nextPesHeaderStore: makeNextPesHeaderStore(),
|
|
14468
|
+
observedPesHeaders: makeObservedPesHeader(),
|
|
14469
|
+
streamBuffers,
|
|
14470
|
+
startOffset,
|
|
14471
|
+
resetBeforeSeek: () => {
|
|
14472
|
+
state.streamBuffers.clear();
|
|
14473
|
+
state.nextPesHeaderStore = makeNextPesHeaderStore();
|
|
13816
14474
|
},
|
|
13817
|
-
|
|
13818
|
-
getAvcProfileForTrackNumber
|
|
14475
|
+
lastEmittedSample
|
|
13819
14476
|
};
|
|
14477
|
+
return state;
|
|
13820
14478
|
};
|
|
13821
14479
|
|
|
13822
14480
|
// src/state/parser-state.ts
|
|
@@ -13840,7 +14498,8 @@ var makeParserState = ({
|
|
|
13840
14498
|
callbacks,
|
|
13841
14499
|
fieldsInReturnValue,
|
|
13842
14500
|
mimeType,
|
|
13843
|
-
initialReaderInstance
|
|
14501
|
+
initialReaderInstance,
|
|
14502
|
+
makeSamplesStartAtZero
|
|
13844
14503
|
}) => {
|
|
13845
14504
|
let skippedBytes = 0;
|
|
13846
14505
|
const returnValue = {};
|
|
@@ -13851,7 +14510,7 @@ var makeParserState = ({
|
|
|
13851
14510
|
const structure = structureState();
|
|
13852
14511
|
const keyframes = keyframesState();
|
|
13853
14512
|
const emittedFields = emittedState();
|
|
13854
|
-
const slowDurationAndFps =
|
|
14513
|
+
const slowDurationAndFps = samplesObservedState();
|
|
13855
14514
|
const mp3Info = makeMp3State();
|
|
13856
14515
|
const images = imagesState();
|
|
13857
14516
|
const timings = timingsState();
|
|
@@ -13874,7 +14533,7 @@ var makeParserState = ({
|
|
|
13874
14533
|
return {
|
|
13875
14534
|
riff: riffSpecificState(),
|
|
13876
14535
|
transportStream: transportStreamState(),
|
|
13877
|
-
webm: webmState(),
|
|
14536
|
+
webm: webmState({ controller, logLevel, readerInterface, src }),
|
|
13878
14537
|
iso: isoBaseMediaState({
|
|
13879
14538
|
contentLength,
|
|
13880
14539
|
controller,
|
|
@@ -13934,7 +14593,8 @@ var makeParserState = ({
|
|
|
13934
14593
|
mimeType,
|
|
13935
14594
|
errored,
|
|
13936
14595
|
currentReader: currentReaderState,
|
|
13937
|
-
seekInfiniteLoop
|
|
14596
|
+
seekInfiniteLoop,
|
|
14597
|
+
makeSamplesStartAtZero
|
|
13938
14598
|
};
|
|
13939
14599
|
};
|
|
13940
14600
|
|
|
@@ -14016,6 +14676,7 @@ var internalParseMedia = async function({
|
|
|
14016
14676
|
selectM3uStream: selectM3uStreamFn,
|
|
14017
14677
|
selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylistsFn,
|
|
14018
14678
|
mp4HeaderSegment,
|
|
14679
|
+
makeSamplesStartAtZero,
|
|
14019
14680
|
...more
|
|
14020
14681
|
}) {
|
|
14021
14682
|
controller._internals.markAsReadyToEmitEvents();
|
|
@@ -14024,7 +14685,7 @@ var internalParseMedia = async function({
|
|
|
14024
14685
|
logLevel,
|
|
14025
14686
|
apiName
|
|
14026
14687
|
});
|
|
14027
|
-
Log.verbose(logLevel, `Reading ${typeof src === "string" ? src : src instanceof URL ? src.toString() : src.name}`);
|
|
14688
|
+
Log.verbose(logLevel, `Reading ${typeof src === "string" ? src : src instanceof URL ? src.toString() : src instanceof File ? src.name : src.toString()}`);
|
|
14028
14689
|
const {
|
|
14029
14690
|
reader: readerInstance,
|
|
14030
14691
|
contentLength,
|
|
@@ -14061,7 +14722,8 @@ var internalParseMedia = async function({
|
|
|
14061
14722
|
callbacks: more,
|
|
14062
14723
|
fieldsInReturnValue: _fieldsInReturnValue ?? {},
|
|
14063
14724
|
mimeType: contentType,
|
|
14064
|
-
initialReaderInstance: readerInstance
|
|
14725
|
+
initialReaderInstance: readerInstance,
|
|
14726
|
+
makeSamplesStartAtZero
|
|
14065
14727
|
});
|
|
14066
14728
|
if (!hasAudioTrackHandlers && !hasVideoTrackHandlers && Object.values(state.fields).every((v) => !v) && mode === "query") {
|
|
14067
14729
|
Log.warn(logLevel, new Error("Warning - No `fields` and no `on*` callbacks were passed to `parseMedia()`. Specify the data you would like to retrieve."));
|
|
@@ -14492,7 +15154,8 @@ var startParsing = async (message, reader) => {
|
|
|
14492
15154
|
});
|
|
14493
15155
|
};
|
|
14494
15156
|
} : null,
|
|
14495
|
-
onDiscardedData: null
|
|
15157
|
+
onDiscardedData: null,
|
|
15158
|
+
makeSamplesStartAtZero: true
|
|
14496
15159
|
});
|
|
14497
15160
|
post({
|
|
14498
15161
|
type: "response-done",
|