@remotion/media-parser 4.0.248 → 4.0.249
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/boxes/avc/key.d.ts +1 -1
- package/dist/boxes/iso-base-media/get-children.d.ts +14 -0
- package/dist/boxes/iso-base-media/get-children.js +39 -0
- package/dist/boxes/iso-base-media/mdat/mdat.d.ts +2 -1
- package/dist/boxes/iso-base-media/mdat/mdat.js +10 -1
- package/dist/boxes/iso-base-media/moov/moov.js +2 -3
- package/dist/boxes/iso-base-media/parse-boxes.d.ts +15 -0
- package/dist/boxes/iso-base-media/parse-boxes.js +129 -0
- package/dist/boxes/iso-base-media/parse-mdat-partially.d.ts +12 -0
- package/dist/boxes/iso-base-media/parse-mdat-partially.js +33 -0
- package/dist/boxes/iso-base-media/process-box.d.ts +2 -21
- package/dist/boxes/iso-base-media/process-box.js +53 -270
- package/dist/boxes/iso-base-media/stsd/mebx.js +2 -3
- package/dist/boxes/iso-base-media/stsd/samples.js +5 -9
- package/dist/boxes/iso-base-media/trak/trak.js +2 -3
- package/dist/boxes/mp3/get-duration.d.ts +2 -0
- package/dist/boxes/mp3/get-duration.js +30 -0
- package/dist/boxes/mp3/get-frame-length.d.ts +13 -0
- package/dist/boxes/mp3/get-frame-length.js +33 -0
- package/dist/boxes/mp3/get-metadata-from-mp3.d.ts +3 -0
- package/dist/boxes/mp3/get-metadata-from-mp3.js +8 -0
- package/dist/boxes/mp3/get-tracks-from-mp3.d.ts +4 -0
- package/dist/boxes/mp3/get-tracks-from-mp3.js +25 -0
- package/dist/boxes/mp3/id3-v1.d.ts +2 -0
- package/dist/boxes/mp3/id3-v1.js +12 -0
- package/dist/boxes/mp3/id3-v2.d.ts +0 -0
- package/dist/boxes/mp3/id3-v2.js +1 -0
- package/dist/boxes/mp3/id3.d.ts +8 -0
- package/dist/boxes/mp3/id3.js +78 -0
- package/dist/boxes/mp3/parse-mp3.d.ts +8 -0
- package/dist/boxes/mp3/parse-mp3.js +57 -0
- package/dist/boxes/mp3/parse-mpeg-header.d.ts +6 -0
- package/dist/boxes/mp3/parse-mpeg-header.js +274 -0
- package/dist/boxes/mp3/samples-per-mpeg-file.d.ts +4 -0
- package/dist/boxes/mp3/samples-per-mpeg-file.js +26 -0
- package/dist/boxes/riff/continue-after-riff-result.d.ts +13 -0
- package/dist/boxes/riff/continue-after-riff-result.js +34 -0
- package/dist/boxes/riff/expect-riff-box.d.ts +3 -1
- package/dist/boxes/riff/expect-riff-box.js +4 -3
- package/dist/boxes/riff/parse-box.d.ts +1 -7
- package/dist/boxes/riff/parse-box.js +4 -120
- package/dist/boxes/riff/parse-list-box.d.ts +3 -1
- package/dist/boxes/riff/parse-list-box.js +4 -3
- package/dist/boxes/riff/parse-riff-body.d.ts +11 -0
- package/dist/boxes/riff/parse-riff-body.js +105 -0
- package/dist/boxes/riff/parse-riff-box.d.ts +3 -1
- package/dist/boxes/riff/parse-riff-box.js +2 -2
- package/dist/boxes/transport-stream/parse-transport-stream.js +30 -41
- package/dist/buffer-iterator.d.ts +6 -0
- package/dist/buffer-iterator.js +21 -0
- package/dist/continue-mdat-routine.d.ts +17 -0
- package/dist/continue-mdat-routine.js +92 -0
- package/dist/emit-available-info.js +38 -24
- package/dist/esm/index.mjs +1820 -1046
- package/dist/file-types/detect-file-type.js +4 -2
- package/dist/get-audio-codec.js +1 -1
- package/dist/get-container.js +5 -1
- package/dist/get-dimensions.d.ts +1 -1
- package/dist/get-dimensions.js +3 -0
- package/dist/get-duration.js +5 -1
- package/dist/get-fields-from-callbacks.js +1 -0
- package/dist/get-fps.js +3 -0
- package/dist/get-is-hdr.js +1 -1
- package/dist/get-keyframes.js +1 -1
- package/dist/get-tracks.d.ts +1 -1
- package/dist/get-tracks.js +10 -3
- package/dist/get-video-codec.js +1 -1
- package/dist/has-all-info.js +4 -3
- package/dist/index.d.ts +20 -2
- package/dist/may-skip-video-data/need-samples-for-fields.js +1 -0
- package/dist/metadata/get-metadata.d.ts +1 -0
- package/dist/metadata/get-metadata.js +16 -1
- package/dist/options.d.ts +12 -5
- package/dist/parse-media.js +48 -43
- package/dist/parse-result.d.ts +16 -1
- package/dist/parse-video.js +9 -10
- package/dist/state/can-skip-tracks.js +1 -0
- package/dist/state/emitted-fields.js +1 -0
- package/dist/state/images.d.ts +9 -0
- package/dist/state/images.js +14 -0
- package/dist/state/mp3.d.ts +11 -0
- package/dist/state/mp3.js +13 -0
- package/dist/state/parser-state.d.ts +13 -2
- package/dist/state/parser-state.js +8 -1
- package/dist/state/sample-callbacks.js +4 -1
- package/dist/state/slow-duration-fps.d.ts +2 -1
- package/dist/state/slow-duration-fps.js +52 -18
- package/dist/throttled-progress.d.ts +14 -0
- package/dist/throttled-progress.js +44 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/esm/index.mjs
CHANGED
|
@@ -996,9 +996,10 @@ var isTransportStream = (data) => {
|
|
|
996
996
|
};
|
|
997
997
|
var isMp3 = (data) => {
|
|
998
998
|
const mpegPattern = new Uint8Array([255, 243, 228, 100]);
|
|
999
|
-
const
|
|
999
|
+
const id3v3Pattern = new Uint8Array([73, 68, 51, 3]);
|
|
1000
|
+
const id3v2Pattern = new Uint8Array([73, 68, 51, 2]);
|
|
1000
1001
|
const subarray = data.subarray(0, 4);
|
|
1001
|
-
return matchesPattern(mpegPattern)(subarray) || matchesPattern(
|
|
1002
|
+
return matchesPattern(mpegPattern)(subarray) || matchesPattern(id3v3Pattern)(subarray) || matchesPattern(id3v2Pattern)(subarray);
|
|
1002
1003
|
};
|
|
1003
1004
|
var isGif = (data) => {
|
|
1004
1005
|
const gifPattern = new Uint8Array([71, 73, 70, 56]);
|
|
@@ -1241,6 +1242,14 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
1241
1242
|
let view = new DataView(data.buffer);
|
|
1242
1243
|
const counter = makeOffsetCounter();
|
|
1243
1244
|
let discardAllowed = true;
|
|
1245
|
+
const startCheckpoint = () => {
|
|
1246
|
+
const checkpoint = counter.getOffset();
|
|
1247
|
+
return {
|
|
1248
|
+
returnToCheckpoint: () => {
|
|
1249
|
+
counter.decrement(counter.getOffset() - checkpoint);
|
|
1250
|
+
}
|
|
1251
|
+
};
|
|
1252
|
+
};
|
|
1244
1253
|
const getSlice = (amount) => {
|
|
1245
1254
|
const value = data.slice(counter.getDiscardedOffset(), counter.getDiscardedOffset() + amount);
|
|
1246
1255
|
counter.increment(amount);
|
|
@@ -1633,6 +1642,18 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
1633
1642
|
}
|
|
1634
1643
|
return new TextDecoder().decode(bytes).trim();
|
|
1635
1644
|
},
|
|
1645
|
+
planBytes: (size) => {
|
|
1646
|
+
const currentOffset = counter.getOffset();
|
|
1647
|
+
return {
|
|
1648
|
+
discardRest: () => {
|
|
1649
|
+
const toDiscard = size - (counter.getOffset() - currentOffset);
|
|
1650
|
+
if (toDiscard < 0) {
|
|
1651
|
+
throw new Error("read too many bytes");
|
|
1652
|
+
}
|
|
1653
|
+
return getSlice(toDiscard);
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
},
|
|
1636
1657
|
getFloat64: () => {
|
|
1637
1658
|
const val = view.getFloat64(counter.getDiscardedOffset());
|
|
1638
1659
|
counter.increment(8);
|
|
@@ -1651,7 +1672,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
1651
1672
|
disallowDiscard,
|
|
1652
1673
|
allowDiscard,
|
|
1653
1674
|
startBox,
|
|
1654
|
-
readExpGolomb
|
|
1675
|
+
readExpGolomb,
|
|
1676
|
+
startCheckpoint
|
|
1655
1677
|
};
|
|
1656
1678
|
};
|
|
1657
1679
|
|
|
@@ -1720,6 +1742,22 @@ var parseMvhd = ({
|
|
|
1720
1742
|
};
|
|
1721
1743
|
};
|
|
1722
1744
|
|
|
1745
|
+
// src/convert-audio-or-video-sample.ts
|
|
1746
|
+
var convertAudioOrVideoSampleToWebCodecsTimestamps = (sample, timescale) => {
|
|
1747
|
+
const { cts, dts, timestamp } = sample;
|
|
1748
|
+
return {
|
|
1749
|
+
cts: cts * 1e6 / timescale,
|
|
1750
|
+
dts: dts * 1e6 / timescale,
|
|
1751
|
+
timestamp: timestamp * 1e6 / timescale,
|
|
1752
|
+
duration: sample.duration === undefined ? undefined : sample.duration * 1e6 / timescale,
|
|
1753
|
+
data: sample.data,
|
|
1754
|
+
trackId: sample.trackId,
|
|
1755
|
+
type: sample.type,
|
|
1756
|
+
offset: sample.offset,
|
|
1757
|
+
timescale: 1e6
|
|
1758
|
+
};
|
|
1759
|
+
};
|
|
1760
|
+
|
|
1723
1761
|
// src/boxes/iso-base-media/traversal.ts
|
|
1724
1762
|
var getMoovBox = (segments) => {
|
|
1725
1763
|
const moovBox = segments.find((s) => s.type === "moov-box");
|
|
@@ -2010,6 +2048,9 @@ var getFps = (segments) => {
|
|
|
2010
2048
|
if (segments.type === "transport-stream") {
|
|
2011
2049
|
return null;
|
|
2012
2050
|
}
|
|
2051
|
+
if (segments.type === "mp3") {
|
|
2052
|
+
return null;
|
|
2053
|
+
}
|
|
2013
2054
|
throw new Error("Cannot get fps, not implemented");
|
|
2014
2055
|
};
|
|
2015
2056
|
var hasFpsSuitedForSlowFps = (boxes) => {
|
|
@@ -2046,7 +2087,7 @@ var getAudioCodec = (boxes, parserState) => {
|
|
|
2046
2087
|
return null;
|
|
2047
2088
|
};
|
|
2048
2089
|
var hasAudioCodec = (boxes, state) => {
|
|
2049
|
-
return
|
|
2090
|
+
return getHasTracks(boxes, state);
|
|
2050
2091
|
};
|
|
2051
2092
|
var getCodecSpecificatorFromEsdsBox = ({
|
|
2052
2093
|
child
|
|
@@ -2429,7 +2470,7 @@ var getVideoCodec = (boxes, state) => {
|
|
|
2429
2470
|
return track.videoTracks[0]?.codecWithoutConfig ?? null;
|
|
2430
2471
|
};
|
|
2431
2472
|
var hasVideoCodec = (boxes, state) => {
|
|
2432
|
-
return
|
|
2473
|
+
return getHasTracks(boxes, state);
|
|
2433
2474
|
};
|
|
2434
2475
|
var getVideoPrivateData = (trakBox) => {
|
|
2435
2476
|
const videoSample = getStsdVideoConfig(trakBox);
|
|
@@ -2652,6 +2693,19 @@ var makeBaseMediaTrack = (trakBox) => {
|
|
|
2652
2693
|
return track;
|
|
2653
2694
|
};
|
|
2654
2695
|
|
|
2696
|
+
// src/boxes/mp3/get-tracks-from-mp3.ts
|
|
2697
|
+
var getTracksFromMp3 = (parserState) => {
|
|
2698
|
+
const tracks2 = parserState.callbacks.tracks.getTracks();
|
|
2699
|
+
if (tracks2.length === 0) {
|
|
2700
|
+
throw new Error("No tracks found");
|
|
2701
|
+
}
|
|
2702
|
+
return {
|
|
2703
|
+
audioTracks: tracks2.filter((t) => t.type === "audio"),
|
|
2704
|
+
otherTracks: [],
|
|
2705
|
+
videoTracks: []
|
|
2706
|
+
};
|
|
2707
|
+
};
|
|
2708
|
+
|
|
2655
2709
|
// src/boxes/avc/codec-string.ts
|
|
2656
2710
|
var getCodecStringFromSpsAndPps = (sps) => {
|
|
2657
2711
|
return `avc1.${sps.spsData.profile.toString(16).padStart(2, "0")}${sps.spsData.compatibility.toString(16).padStart(2, "0")}${sps.spsData.level.toString(16).padStart(2, "0")}`;
|
|
@@ -3492,7 +3546,7 @@ var isoBaseMediaHasTracks = (structure) => {
|
|
|
3492
3546
|
const tracks2 = getTraks(moovBox);
|
|
3493
3547
|
return tracks2.length === numberOfTracks;
|
|
3494
3548
|
};
|
|
3495
|
-
var
|
|
3549
|
+
var getHasTracks = (structure, state) => {
|
|
3496
3550
|
if (structure.type === "matroska") {
|
|
3497
3551
|
const mainSegment = getMainSegment(structure.boxes);
|
|
3498
3552
|
if (!mainSegment) {
|
|
@@ -3509,6 +3563,9 @@ var hasTracks = (structure, state) => {
|
|
|
3509
3563
|
if (structure.type === "transport-stream") {
|
|
3510
3564
|
return hasAllTracksFromTransportStream(structure, state);
|
|
3511
3565
|
}
|
|
3566
|
+
if (structure.type === "mp3") {
|
|
3567
|
+
return state.callbacks.tracks.getTracks().length > 0;
|
|
3568
|
+
}
|
|
3512
3569
|
throw new Error("Unknown container " + structure);
|
|
3513
3570
|
};
|
|
3514
3571
|
var getTracksFromMa = (segments, state) => {
|
|
@@ -3580,56 +3637,10 @@ var getTracks = (segments, state) => {
|
|
|
3580
3637
|
if (segments.type === "transport-stream") {
|
|
3581
3638
|
return getTracksFromTransportStream(segments, state);
|
|
3582
3639
|
}
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
// src/get-container.ts
|
|
3587
|
-
var getContainer = (segments) => {
|
|
3588
|
-
if (segments.type === "iso-base-media") {
|
|
3589
|
-
return "mp4";
|
|
3590
|
-
}
|
|
3591
|
-
if (segments.type === "matroska") {
|
|
3592
|
-
return "webm";
|
|
3593
|
-
}
|
|
3594
|
-
if (segments.type === "transport-stream") {
|
|
3595
|
-
return "transport-stream";
|
|
3596
|
-
}
|
|
3597
|
-
if (segments.type === "riff") {
|
|
3598
|
-
if (isRiffAvi2(segments)) {
|
|
3599
|
-
return "avi";
|
|
3600
|
-
}
|
|
3601
|
-
}
|
|
3602
|
-
throw new Error("Unknown container");
|
|
3603
|
-
};
|
|
3604
|
-
var hasContainer = (boxes) => {
|
|
3605
|
-
try {
|
|
3606
|
-
return getContainer(boxes) !== null;
|
|
3607
|
-
} catch {
|
|
3608
|
-
return false;
|
|
3609
|
-
}
|
|
3610
|
-
};
|
|
3611
|
-
|
|
3612
|
-
// src/get-dimensions.ts
|
|
3613
|
-
var getDimensions = (boxes, state) => {
|
|
3614
|
-
const { videoTracks } = getTracks(boxes, state);
|
|
3615
|
-
if (!videoTracks.length) {
|
|
3616
|
-
throw new Error("Expected video track");
|
|
3617
|
-
}
|
|
3618
|
-
const firstVideoTrack = videoTracks[0];
|
|
3619
|
-
return {
|
|
3620
|
-
width: firstVideoTrack.width,
|
|
3621
|
-
height: firstVideoTrack.height,
|
|
3622
|
-
rotation: firstVideoTrack.rotation,
|
|
3623
|
-
unrotatedHeight: firstVideoTrack.displayAspectHeight,
|
|
3624
|
-
unrotatedWidth: firstVideoTrack.displayAspectWidth
|
|
3625
|
-
};
|
|
3626
|
-
};
|
|
3627
|
-
var hasDimensions = (boxes, state) => {
|
|
3628
|
-
try {
|
|
3629
|
-
return getDimensions(boxes, state) !== null;
|
|
3630
|
-
} catch {
|
|
3631
|
-
return false;
|
|
3640
|
+
if (segments.type === "mp3") {
|
|
3641
|
+
return getTracksFromMp3(state);
|
|
3632
3642
|
}
|
|
3643
|
+
throw new Error(`Unknown container${segments}`);
|
|
3633
3644
|
};
|
|
3634
3645
|
|
|
3635
3646
|
// src/get-sample-positions.ts
|
|
@@ -3842,153 +3853,476 @@ var getSamplePositionsFromTrack = (trakBox, moofBox) => {
|
|
|
3842
3853
|
return samplePositions;
|
|
3843
3854
|
};
|
|
3844
3855
|
|
|
3845
|
-
// src/
|
|
3846
|
-
var
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
const
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
|
|
3877
|
-
if (!mvhdBox) {
|
|
3878
|
-
return null;
|
|
3879
|
-
}
|
|
3880
|
-
if (mvhdBox.type !== "mvhd-box") {
|
|
3881
|
-
throw new Error("Expected mvhd-box");
|
|
3882
|
-
}
|
|
3883
|
-
if (mvhdBox.durationInSeconds > 0) {
|
|
3884
|
-
return mvhdBox.durationInSeconds;
|
|
3856
|
+
// src/boxes/iso-base-media/mdat/mdat.ts
|
|
3857
|
+
var parseMdat = async ({
|
|
3858
|
+
data,
|
|
3859
|
+
size,
|
|
3860
|
+
fileOffset,
|
|
3861
|
+
existingBoxes,
|
|
3862
|
+
state,
|
|
3863
|
+
signal,
|
|
3864
|
+
maySkipSampleProcessing
|
|
3865
|
+
}) => {
|
|
3866
|
+
const alreadyHas = getHasTracks({
|
|
3867
|
+
type: "iso-base-media",
|
|
3868
|
+
boxes: existingBoxes
|
|
3869
|
+
}, state);
|
|
3870
|
+
if (!alreadyHas) {
|
|
3871
|
+
if (maySkipSampleProcessing) {
|
|
3872
|
+
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
3873
|
+
return Promise.resolve({
|
|
3874
|
+
type: "mdat-box",
|
|
3875
|
+
boxSize: size,
|
|
3876
|
+
status: "samples-skipped",
|
|
3877
|
+
fileOffset
|
|
3878
|
+
});
|
|
3879
|
+
}
|
|
3880
|
+
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
3881
|
+
data.disallowDiscard();
|
|
3882
|
+
return Promise.resolve({
|
|
3883
|
+
type: "mdat-box",
|
|
3884
|
+
boxSize: size,
|
|
3885
|
+
status: "samples-buffered",
|
|
3886
|
+
fileOffset
|
|
3887
|
+
});
|
|
3885
3888
|
}
|
|
3886
|
-
const tracks2 = getTracks(
|
|
3889
|
+
const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, state);
|
|
3887
3890
|
const allTracks = [
|
|
3888
3891
|
...tracks2.videoTracks,
|
|
3889
3892
|
...tracks2.audioTracks,
|
|
3890
3893
|
...tracks2.otherTracks
|
|
3891
3894
|
];
|
|
3892
|
-
const
|
|
3893
|
-
const
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
return highest ?? 0;
|
|
3897
|
-
});
|
|
3898
|
-
const highestTimestamp = Math.max(...allSamples);
|
|
3899
|
-
return highestTimestamp;
|
|
3900
|
-
};
|
|
3901
|
-
var getDurationFromAvi = (structure) => {
|
|
3902
|
-
const strl = getStrlBoxes(structure);
|
|
3903
|
-
const lengths = [];
|
|
3904
|
-
for (const s of strl) {
|
|
3905
|
-
const strh = getStrhBox(s.children);
|
|
3906
|
-
if (!strh) {
|
|
3907
|
-
throw new Error("No strh box");
|
|
3895
|
+
const flatSamples = allTracks.map((track) => {
|
|
3896
|
+
const samplePositions = getSamplePositionsFromTrack(track.trakBox, getMoofBox(existingBoxes));
|
|
3897
|
+
if (!samplePositions) {
|
|
3898
|
+
throw new Error("No sample positions");
|
|
3908
3899
|
}
|
|
3909
|
-
|
|
3910
|
-
const streamLength = strh.length / samplesPerSecond;
|
|
3911
|
-
lengths.push(streamLength);
|
|
3912
|
-
}
|
|
3913
|
-
return Math.max(...lengths);
|
|
3914
|
-
};
|
|
3915
|
-
var getDuration = (structure, parserState) => {
|
|
3916
|
-
if (structure.type === "matroska") {
|
|
3917
|
-
return getDurationFromMatroska(structure.boxes);
|
|
3918
|
-
}
|
|
3919
|
-
if (structure.type === "iso-base-media") {
|
|
3920
|
-
return getDurationFromIsoBaseMedia(structure, parserState);
|
|
3921
|
-
}
|
|
3922
|
-
if (structure.type === "riff") {
|
|
3923
|
-
return getDurationFromAvi(structure);
|
|
3924
|
-
}
|
|
3925
|
-
if (structure.type === "transport-stream") {
|
|
3926
|
-
return null;
|
|
3927
|
-
}
|
|
3928
|
-
throw new Error("Has no duration " + structure);
|
|
3929
|
-
};
|
|
3930
|
-
var hasDuration = (structure, parserState) => {
|
|
3931
|
-
return hasTracks(structure, parserState);
|
|
3932
|
-
};
|
|
3933
|
-
var hasSlowDuration = (structure, parserState) => {
|
|
3934
|
-
try {
|
|
3935
|
-
return getDuration(structure, parserState) !== null;
|
|
3936
|
-
} catch {
|
|
3937
|
-
return false;
|
|
3938
|
-
}
|
|
3939
|
-
};
|
|
3940
|
-
|
|
3941
|
-
// src/get-is-hdr.ts
|
|
3942
|
-
var isVideoTrackHdr = (track) => {
|
|
3943
|
-
return track.color.matrixCoefficients === "bt2020" && track.color.transferCharacteristics === "arib-std-b67" && track.color.primaries === "bt2020";
|
|
3944
|
-
};
|
|
3945
|
-
var getIsHdr = (boxes, state) => {
|
|
3946
|
-
const { videoTracks } = getTracks(boxes, state);
|
|
3947
|
-
return videoTracks.some((track) => isVideoTrackHdr(track));
|
|
3948
|
-
};
|
|
3949
|
-
var hasHdr = (boxes, state) => {
|
|
3950
|
-
return hasTracks(boxes, state);
|
|
3951
|
-
};
|
|
3952
|
-
|
|
3953
|
-
// src/boxes/iso-base-media/get-keyframes.ts
|
|
3954
|
-
var getKeyframesFromIsoBaseMedia = (structure) => {
|
|
3955
|
-
const { videoTracks } = getTracksFromIsoBaseMedia(structure.boxes);
|
|
3956
|
-
const moofBox = getMoofBox(structure.boxes);
|
|
3957
|
-
const allSamples = videoTracks.map((t) => {
|
|
3958
|
-
const { timescale: ts } = t;
|
|
3959
|
-
const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
|
|
3960
|
-
const keyframes = samplePositions.filter((k) => {
|
|
3961
|
-
return k.isKeyframe;
|
|
3962
|
-
}).map((k) => {
|
|
3900
|
+
return samplePositions.map((samplePosition) => {
|
|
3963
3901
|
return {
|
|
3964
|
-
|
|
3965
|
-
|
|
3966
|
-
decodingTimeInSeconds: k.dts / ts,
|
|
3967
|
-
positionInBytes: k.offset,
|
|
3968
|
-
sizeInBytes: k.size
|
|
3902
|
+
track: { ...track },
|
|
3903
|
+
samplePosition
|
|
3969
3904
|
};
|
|
3970
3905
|
});
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
}
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3906
|
+
}).flat(1);
|
|
3907
|
+
while (true) {
|
|
3908
|
+
if (signal && signal.aborted) {
|
|
3909
|
+
break;
|
|
3910
|
+
}
|
|
3911
|
+
const samplesWithIndex = flatSamples.find((sample) => {
|
|
3912
|
+
return sample.samplePosition.offset === data.counter.getOffset();
|
|
3913
|
+
});
|
|
3914
|
+
if (!samplesWithIndex) {
|
|
3915
|
+
const nextSample_ = flatSamples.filter((s) => s.samplePosition.offset > data.counter.getOffset()).sort((a, b) => a.samplePosition.offset - b.samplePosition.offset)[0];
|
|
3916
|
+
if (nextSample_) {
|
|
3917
|
+
data.discard(nextSample_.samplePosition.offset - data.counter.getOffset());
|
|
3918
|
+
continue;
|
|
3919
|
+
} else {
|
|
3920
|
+
const bytesRemaining = size + fileOffset - data.counter.getOffset();
|
|
3921
|
+
data.discard(bytesRemaining);
|
|
3922
|
+
break;
|
|
3923
|
+
}
|
|
3924
|
+
}
|
|
3925
|
+
if (data.bytesRemaining() < samplesWithIndex.samplePosition.size) {
|
|
3926
|
+
break;
|
|
3927
|
+
}
|
|
3928
|
+
const bytes = data.getSlice(samplesWithIndex.samplePosition.size);
|
|
3929
|
+
const { cts, dts, duration: duration2, isKeyframe, offset } = samplesWithIndex.samplePosition;
|
|
3930
|
+
if (samplesWithIndex.track.type === "audio") {
|
|
3931
|
+
await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
|
|
3932
|
+
data: bytes,
|
|
3933
|
+
timestamp: cts,
|
|
3934
|
+
duration: duration2,
|
|
3935
|
+
cts,
|
|
3936
|
+
dts,
|
|
3937
|
+
trackId: samplesWithIndex.track.trackId,
|
|
3938
|
+
type: isKeyframe ? "key" : "delta",
|
|
3939
|
+
offset,
|
|
3940
|
+
timescale: samplesWithIndex.track.timescale
|
|
3941
|
+
}, samplesWithIndex.track.timescale));
|
|
3942
|
+
}
|
|
3943
|
+
if (samplesWithIndex.track.type === "video") {
|
|
3944
|
+
const nalUnitType = bytes[4] & 31;
|
|
3945
|
+
let isRecoveryPoint = false;
|
|
3946
|
+
if (nalUnitType === 6) {
|
|
3947
|
+
const seiType = bytes[5];
|
|
3948
|
+
isRecoveryPoint = seiType === 6;
|
|
3949
|
+
}
|
|
3950
|
+
await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
|
|
3951
|
+
data: bytes,
|
|
3952
|
+
timestamp: cts,
|
|
3953
|
+
duration: duration2,
|
|
3954
|
+
cts,
|
|
3955
|
+
dts,
|
|
3956
|
+
trackId: samplesWithIndex.track.trackId,
|
|
3957
|
+
type: isKeyframe && !isRecoveryPoint ? "key" : "delta",
|
|
3958
|
+
offset,
|
|
3959
|
+
timescale: samplesWithIndex.track.timescale
|
|
3960
|
+
}, samplesWithIndex.track.timescale));
|
|
3961
|
+
}
|
|
3962
|
+
const remaining = size - (data.counter.getOffset() - fileOffset);
|
|
3963
|
+
data.removeBytesRead();
|
|
3964
|
+
if (remaining === 0) {
|
|
3965
|
+
break;
|
|
3966
|
+
}
|
|
3967
|
+
}
|
|
3968
|
+
const expectedOffsetNow = size + fileOffset;
|
|
3969
|
+
const actualOffsetNow = data.counter.getOffset();
|
|
3970
|
+
if (expectedOffsetNow !== actualOffsetNow) {
|
|
3971
|
+
return Promise.resolve({
|
|
3972
|
+
type: "partial-mdat-box",
|
|
3973
|
+
boxSize: size,
|
|
3974
|
+
fileOffset
|
|
3975
|
+
});
|
|
3976
|
+
}
|
|
3977
|
+
return Promise.resolve({
|
|
3978
|
+
type: "mdat-box",
|
|
3979
|
+
boxSize: size,
|
|
3980
|
+
status: "samples-processed",
|
|
3981
|
+
fileOffset
|
|
3982
|
+
});
|
|
3983
|
+
};
|
|
3984
|
+
|
|
3985
|
+
// src/boxes/iso-base-media/parse-mdat-partially.ts
|
|
3986
|
+
var parseMdatPartially = async ({
|
|
3987
|
+
iterator,
|
|
3988
|
+
boxSize,
|
|
3989
|
+
fileOffset,
|
|
3990
|
+
parsedBoxes,
|
|
3991
|
+
state,
|
|
3992
|
+
signal
|
|
3993
|
+
}) => {
|
|
3994
|
+
const box = await parseMdat({
|
|
3995
|
+
data: iterator,
|
|
3996
|
+
size: boxSize,
|
|
3997
|
+
fileOffset,
|
|
3998
|
+
existingBoxes: parsedBoxes,
|
|
3999
|
+
state,
|
|
4000
|
+
signal,
|
|
4001
|
+
maySkipSampleProcessing: state.supportsContentRange
|
|
4002
|
+
});
|
|
4003
|
+
if (box.type === "partial-mdat-box") {
|
|
4004
|
+
return box;
|
|
4005
|
+
}
|
|
4006
|
+
if ((box.status === "samples-processed" || box.status === "samples-buffered") && box.fileOffset + boxSize === iterator.counter.getOffset()) {
|
|
4007
|
+
return {
|
|
4008
|
+
type: "complete",
|
|
4009
|
+
box,
|
|
4010
|
+
size: boxSize,
|
|
4011
|
+
skipTo: null
|
|
4012
|
+
};
|
|
4013
|
+
}
|
|
4014
|
+
return {
|
|
4015
|
+
type: "partial-mdat-box",
|
|
4016
|
+
boxSize,
|
|
4017
|
+
fileOffset
|
|
4018
|
+
};
|
|
4019
|
+
};
|
|
4020
|
+
|
|
4021
|
+
// src/get-container.ts
|
|
4022
|
+
var getContainer = (segments) => {
|
|
4023
|
+
if (segments.type === "iso-base-media") {
|
|
4024
|
+
return "mp4";
|
|
4025
|
+
}
|
|
4026
|
+
if (segments.type === "matroska") {
|
|
4027
|
+
return "webm";
|
|
4028
|
+
}
|
|
4029
|
+
if (segments.type === "transport-stream") {
|
|
4030
|
+
return "transport-stream";
|
|
4031
|
+
}
|
|
4032
|
+
if (segments.type === "mp3") {
|
|
4033
|
+
return "mp3";
|
|
4034
|
+
}
|
|
4035
|
+
if (segments.type === "riff") {
|
|
4036
|
+
if (isRiffAvi2(segments)) {
|
|
4037
|
+
return "avi";
|
|
4038
|
+
}
|
|
4039
|
+
throw new Error("Unknown RIFF container " + segments.type);
|
|
4040
|
+
}
|
|
4041
|
+
throw new Error("Unknown container " + segments);
|
|
4042
|
+
};
|
|
4043
|
+
var hasContainer = (boxes) => {
|
|
4044
|
+
try {
|
|
4045
|
+
return getContainer(boxes) !== null;
|
|
4046
|
+
} catch {
|
|
4047
|
+
return false;
|
|
4048
|
+
}
|
|
4049
|
+
};
|
|
4050
|
+
|
|
4051
|
+
// src/get-dimensions.ts
|
|
4052
|
+
var getDimensions = (boxes, state) => {
|
|
4053
|
+
const { videoTracks } = getTracks(boxes, state);
|
|
4054
|
+
if (!videoTracks.length) {
|
|
4055
|
+
if (boxes.type === "mp3") {
|
|
4056
|
+
return null;
|
|
4057
|
+
}
|
|
4058
|
+
throw new Error("Expected video track");
|
|
4059
|
+
}
|
|
4060
|
+
const firstVideoTrack = videoTracks[0];
|
|
4061
|
+
return {
|
|
4062
|
+
width: firstVideoTrack.width,
|
|
4063
|
+
height: firstVideoTrack.height,
|
|
4064
|
+
rotation: firstVideoTrack.rotation,
|
|
4065
|
+
unrotatedHeight: firstVideoTrack.displayAspectHeight,
|
|
4066
|
+
unrotatedWidth: firstVideoTrack.displayAspectWidth
|
|
4067
|
+
};
|
|
4068
|
+
};
|
|
4069
|
+
var hasDimensions = (boxes, state) => {
|
|
4070
|
+
try {
|
|
4071
|
+
return getDimensions(boxes, state) !== null;
|
|
4072
|
+
} catch {
|
|
4073
|
+
return false;
|
|
4074
|
+
}
|
|
4075
|
+
};
|
|
4076
|
+
|
|
4077
|
+
// src/boxes/mp3/get-frame-length.ts
|
|
4078
|
+
var getUnroundedMpegFrameLength = ({
|
|
4079
|
+
samplesPerFrame,
|
|
4080
|
+
bitrateKbit,
|
|
4081
|
+
samplingFrequency: samplingFrequency2,
|
|
4082
|
+
padding,
|
|
4083
|
+
layer
|
|
4084
|
+
}) => {
|
|
4085
|
+
if (layer === 1) {
|
|
4086
|
+
throw new Error("MPEG Layer I is not supported");
|
|
4087
|
+
}
|
|
4088
|
+
return samplesPerFrame / 8 * bitrateKbit / samplingFrequency2 * 1000 + (padding ? layer === 1 ? 4 : 1 : 0);
|
|
4089
|
+
};
|
|
4090
|
+
var getAverageMpegFrameLength = ({
|
|
4091
|
+
samplesPerFrame,
|
|
4092
|
+
bitrateKbit,
|
|
4093
|
+
samplingFrequency: samplingFrequency2,
|
|
4094
|
+
layer
|
|
4095
|
+
}) => {
|
|
4096
|
+
const withoutPadding = getUnroundedMpegFrameLength({
|
|
4097
|
+
bitrateKbit,
|
|
4098
|
+
layer,
|
|
4099
|
+
padding: false,
|
|
4100
|
+
samplesPerFrame,
|
|
4101
|
+
samplingFrequency: samplingFrequency2
|
|
4102
|
+
});
|
|
4103
|
+
const rounded = Math.floor(withoutPadding);
|
|
4104
|
+
const rest = withoutPadding % 1;
|
|
4105
|
+
return rest * (rounded + 1) + (1 - rest) * rounded;
|
|
4106
|
+
};
|
|
4107
|
+
var getMpegFrameLength = ({
|
|
4108
|
+
samplesPerFrame,
|
|
4109
|
+
bitrateKbit,
|
|
4110
|
+
samplingFrequency: samplingFrequency2,
|
|
4111
|
+
padding,
|
|
4112
|
+
layer
|
|
4113
|
+
}) => {
|
|
4114
|
+
return Math.floor(getUnroundedMpegFrameLength({
|
|
4115
|
+
bitrateKbit,
|
|
4116
|
+
layer,
|
|
4117
|
+
padding,
|
|
4118
|
+
samplesPerFrame,
|
|
4119
|
+
samplingFrequency: samplingFrequency2
|
|
4120
|
+
}));
|
|
4121
|
+
};
|
|
4122
|
+
|
|
4123
|
+
// src/boxes/mp3/samples-per-mpeg-file.ts
|
|
4124
|
+
var getSamplesPerMpegFrame = ({
|
|
4125
|
+
mpegVersion,
|
|
4126
|
+
layer
|
|
4127
|
+
}) => {
|
|
4128
|
+
if (mpegVersion === 1) {
|
|
4129
|
+
if (layer === 1) {
|
|
4130
|
+
return 384;
|
|
4131
|
+
}
|
|
4132
|
+
if (layer === 2 || layer === 3) {
|
|
4133
|
+
return 1152;
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
if (mpegVersion === 2) {
|
|
4137
|
+
if (layer === 1) {
|
|
4138
|
+
return 384;
|
|
4139
|
+
}
|
|
4140
|
+
if (layer === 2) {
|
|
4141
|
+
return 1152;
|
|
4142
|
+
}
|
|
4143
|
+
if (layer === 3) {
|
|
4144
|
+
return 576;
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
throw new Error("Invalid MPEG layer");
|
|
4148
|
+
};
|
|
4149
|
+
|
|
4150
|
+
// src/boxes/mp3/get-duration.ts
|
|
4151
|
+
var getDurationFromMp3 = (state) => {
|
|
4152
|
+
if (state.contentLength === null) {
|
|
4153
|
+
return null;
|
|
4154
|
+
}
|
|
4155
|
+
const mp3Info = state.mp3Info.getMp3Info();
|
|
4156
|
+
if (!mp3Info) {
|
|
4157
|
+
throw new Error("No mp3 info");
|
|
4158
|
+
}
|
|
4159
|
+
const samplesPerFrame = getSamplesPerMpegFrame({
|
|
4160
|
+
layer: mp3Info.layer,
|
|
4161
|
+
mpegVersion: mp3Info.mpegVersion
|
|
4162
|
+
});
|
|
4163
|
+
const frameLengthInBytes = getMpegFrameLength({
|
|
4164
|
+
bitrateKbit: mp3Info.bitrateKbit,
|
|
4165
|
+
padding: false,
|
|
4166
|
+
samplesPerFrame,
|
|
4167
|
+
samplingFrequency: mp3Info.sampleRate,
|
|
4168
|
+
layer: mp3Info.layer
|
|
4169
|
+
});
|
|
4170
|
+
const frames = Math.floor((state.contentLength - mp3Info.startOfMpegStream) / frameLengthInBytes);
|
|
4171
|
+
const samples = frames * samplesPerFrame;
|
|
4172
|
+
const durationInSeconds = samples / mp3Info.sampleRate;
|
|
4173
|
+
return durationInSeconds;
|
|
4174
|
+
};
|
|
4175
|
+
|
|
4176
|
+
// src/get-duration.ts
|
|
4177
|
+
var getDurationFromMatroska = (segments) => {
|
|
4178
|
+
const mainSegment = segments.find((s) => s.type === "Segment");
|
|
4179
|
+
if (!mainSegment || mainSegment.type !== "Segment") {
|
|
4180
|
+
return null;
|
|
4181
|
+
}
|
|
4182
|
+
const { value: children } = mainSegment;
|
|
4183
|
+
if (!children) {
|
|
4184
|
+
return null;
|
|
4185
|
+
}
|
|
4186
|
+
const infoSegment = children.find((s) => s.type === "Info");
|
|
4187
|
+
const relevantBoxes = [
|
|
4188
|
+
...mainSegment.value,
|
|
4189
|
+
...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
|
|
4190
|
+
];
|
|
4191
|
+
const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
|
|
4192
|
+
if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
|
|
4193
|
+
return null;
|
|
4194
|
+
}
|
|
4195
|
+
const duration2 = relevantBoxes.find((s) => s.type === "Duration");
|
|
4196
|
+
if (!duration2 || duration2.type !== "Duration") {
|
|
4197
|
+
return null;
|
|
4198
|
+
}
|
|
4199
|
+
return duration2.value.value / timestampScale2.value.value * 1000;
|
|
4200
|
+
};
|
|
4201
|
+
var getDurationFromIsoBaseMedia = (structure, parserState) => {
|
|
4202
|
+
const moovBox = getMoovBox(structure.boxes);
|
|
4203
|
+
if (!moovBox) {
|
|
4204
|
+
return null;
|
|
4205
|
+
}
|
|
4206
|
+
const moofBox = getMoofBox(structure.boxes);
|
|
4207
|
+
const mvhdBox = getMvhdBox(moovBox);
|
|
4208
|
+
if (!mvhdBox) {
|
|
4209
|
+
return null;
|
|
4210
|
+
}
|
|
4211
|
+
if (mvhdBox.type !== "mvhd-box") {
|
|
4212
|
+
throw new Error("Expected mvhd-box");
|
|
4213
|
+
}
|
|
4214
|
+
if (mvhdBox.durationInSeconds > 0) {
|
|
4215
|
+
return mvhdBox.durationInSeconds;
|
|
4216
|
+
}
|
|
4217
|
+
const tracks2 = getTracks(structure, parserState);
|
|
4218
|
+
const allTracks = [
|
|
4219
|
+
...tracks2.videoTracks,
|
|
4220
|
+
...tracks2.audioTracks,
|
|
4221
|
+
...tracks2.otherTracks
|
|
4222
|
+
];
|
|
4223
|
+
const allSamples = allTracks.map((t) => {
|
|
4224
|
+
const { timescale: ts } = t;
|
|
4225
|
+
const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
|
|
4226
|
+
const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
|
|
4227
|
+
return highest ?? 0;
|
|
4228
|
+
});
|
|
4229
|
+
const highestTimestamp = Math.max(...allSamples);
|
|
4230
|
+
return highestTimestamp;
|
|
4231
|
+
};
|
|
4232
|
+
var getDurationFromAvi = (structure) => {
|
|
4233
|
+
const strl = getStrlBoxes(structure);
|
|
4234
|
+
const lengths = [];
|
|
4235
|
+
for (const s of strl) {
|
|
4236
|
+
const strh = getStrhBox(s.children);
|
|
4237
|
+
if (!strh) {
|
|
4238
|
+
throw new Error("No strh box");
|
|
4239
|
+
}
|
|
4240
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
4241
|
+
const streamLength = strh.length / samplesPerSecond;
|
|
4242
|
+
lengths.push(streamLength);
|
|
4243
|
+
}
|
|
4244
|
+
return Math.max(...lengths);
|
|
4245
|
+
};
|
|
4246
|
+
var getDuration = (structure, parserState) => {
|
|
4247
|
+
if (structure.type === "matroska") {
|
|
4248
|
+
return getDurationFromMatroska(structure.boxes);
|
|
4249
|
+
}
|
|
4250
|
+
if (structure.type === "iso-base-media") {
|
|
4251
|
+
return getDurationFromIsoBaseMedia(structure, parserState);
|
|
4252
|
+
}
|
|
4253
|
+
if (structure.type === "riff") {
|
|
4254
|
+
return getDurationFromAvi(structure);
|
|
4255
|
+
}
|
|
4256
|
+
if (structure.type === "transport-stream") {
|
|
4257
|
+
return null;
|
|
4258
|
+
}
|
|
4259
|
+
if (structure.type === "mp3") {
|
|
4260
|
+
return getDurationFromMp3(parserState);
|
|
4261
|
+
}
|
|
4262
|
+
throw new Error("Has no duration " + structure);
|
|
4263
|
+
};
|
|
4264
|
+
var hasDuration = (structure, parserState) => {
|
|
4265
|
+
return getHasTracks(structure, parserState);
|
|
4266
|
+
};
|
|
4267
|
+
var hasSlowDuration = (structure, parserState) => {
|
|
4268
|
+
try {
|
|
4269
|
+
return getDuration(structure, parserState) !== null;
|
|
4270
|
+
} catch {
|
|
4271
|
+
return false;
|
|
4272
|
+
}
|
|
4273
|
+
};
|
|
4274
|
+
|
|
4275
|
+
// src/get-is-hdr.ts
|
|
4276
|
+
var isVideoTrackHdr = (track) => {
|
|
4277
|
+
return track.color.matrixCoefficients === "bt2020" && track.color.transferCharacteristics === "arib-std-b67" && track.color.primaries === "bt2020";
|
|
4278
|
+
};
|
|
4279
|
+
var getIsHdr = (boxes, state) => {
|
|
4280
|
+
const { videoTracks } = getTracks(boxes, state);
|
|
4281
|
+
return videoTracks.some((track) => isVideoTrackHdr(track));
|
|
4282
|
+
};
|
|
4283
|
+
var hasHdr = (boxes, state) => {
|
|
4284
|
+
return getHasTracks(boxes, state);
|
|
4285
|
+
};
|
|
4286
|
+
|
|
4287
|
+
// src/boxes/iso-base-media/get-keyframes.ts
|
|
4288
|
+
var getKeyframesFromIsoBaseMedia = (structure) => {
|
|
4289
|
+
const { videoTracks } = getTracksFromIsoBaseMedia(structure.boxes);
|
|
4290
|
+
const moofBox = getMoofBox(structure.boxes);
|
|
4291
|
+
const allSamples = videoTracks.map((t) => {
|
|
4292
|
+
const { timescale: ts } = t;
|
|
4293
|
+
const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
|
|
4294
|
+
const keyframes = samplePositions.filter((k) => {
|
|
4295
|
+
return k.isKeyframe;
|
|
4296
|
+
}).map((k) => {
|
|
4297
|
+
return {
|
|
4298
|
+
trackId: t.trackId,
|
|
4299
|
+
presentationTimeInSeconds: k.cts / ts,
|
|
4300
|
+
decodingTimeInSeconds: k.dts / ts,
|
|
4301
|
+
positionInBytes: k.offset,
|
|
4302
|
+
sizeInBytes: k.size
|
|
4303
|
+
};
|
|
4304
|
+
});
|
|
4305
|
+
return keyframes;
|
|
4306
|
+
});
|
|
4307
|
+
return allSamples.flat();
|
|
4308
|
+
};
|
|
4309
|
+
|
|
4310
|
+
// src/get-keyframes.ts
|
|
4311
|
+
var getKeyframes = (structure) => {
|
|
4312
|
+
if (structure.type === "iso-base-media") {
|
|
4313
|
+
return getKeyframesFromIsoBaseMedia(structure);
|
|
4314
|
+
}
|
|
4315
|
+
return null;
|
|
4316
|
+
};
|
|
4317
|
+
var hasKeyframes = (structure, parserState) => {
|
|
4318
|
+
if (structure.type === "iso-base-media") {
|
|
4319
|
+
return getHasTracks(structure, parserState);
|
|
4320
|
+
}
|
|
4321
|
+
return true;
|
|
4322
|
+
};
|
|
4323
|
+
|
|
4324
|
+
// src/may-skip-video-data/need-samples-for-fields.ts
|
|
4325
|
+
var needsSamples = {
|
|
3992
4326
|
slowDurationInSeconds: true,
|
|
3993
4327
|
slowFps: true,
|
|
3994
4328
|
slowKeyframes: true,
|
|
@@ -4010,7 +4344,8 @@ var needsSamples = {
|
|
|
4010
4344
|
metadata: false,
|
|
4011
4345
|
location: false,
|
|
4012
4346
|
mimeType: false,
|
|
4013
|
-
keyframes: false
|
|
4347
|
+
keyframes: false,
|
|
4348
|
+
images: false
|
|
4014
4349
|
};
|
|
4015
4350
|
var needsToIterateOverSamples = ({
|
|
4016
4351
|
fields,
|
|
@@ -4029,6 +4364,216 @@ var maySkipVideoData = ({ state }) => {
|
|
|
4029
4364
|
});
|
|
4030
4365
|
};
|
|
4031
4366
|
|
|
4367
|
+
// src/boxes/mp3/get-metadata-from-mp3.ts
|
|
4368
|
+
var getMetadataFromMp3 = (mp3Structure) => {
|
|
4369
|
+
const findHeader = mp3Structure.boxes.find((b) => b.type === "id3-header");
|
|
4370
|
+
return findHeader ? findHeader.metatags : null;
|
|
4371
|
+
};
|
|
4372
|
+
|
|
4373
|
+
// src/metadata/metadata-from-iso.ts
|
|
4374
|
+
var mapToKey = (index) => {
|
|
4375
|
+
if (index === 2839630420) {
|
|
4376
|
+
return "artist";
|
|
4377
|
+
}
|
|
4378
|
+
if (index === 2841734242) {
|
|
4379
|
+
return "album";
|
|
4380
|
+
}
|
|
4381
|
+
if (index === 2841865588) {
|
|
4382
|
+
return "comment";
|
|
4383
|
+
}
|
|
4384
|
+
if (index === 2841928057) {
|
|
4385
|
+
return "releaseDate";
|
|
4386
|
+
}
|
|
4387
|
+
if (index === 2842125678) {
|
|
4388
|
+
return "genre";
|
|
4389
|
+
}
|
|
4390
|
+
if (index === 2842583405) {
|
|
4391
|
+
return "title";
|
|
4392
|
+
}
|
|
4393
|
+
if (index === 2842980207) {
|
|
4394
|
+
return "encoder";
|
|
4395
|
+
}
|
|
4396
|
+
if (index === 2843177588) {
|
|
4397
|
+
return "writer";
|
|
4398
|
+
}
|
|
4399
|
+
if (index === 2841866361) {
|
|
4400
|
+
return "copyright";
|
|
4401
|
+
}
|
|
4402
|
+
if (index === 2841930098) {
|
|
4403
|
+
return "director";
|
|
4404
|
+
}
|
|
4405
|
+
if (index === 2842718820) {
|
|
4406
|
+
return "producer";
|
|
4407
|
+
}
|
|
4408
|
+
if (index === 2841929075) {
|
|
4409
|
+
return "description";
|
|
4410
|
+
}
|
|
4411
|
+
return null;
|
|
4412
|
+
};
|
|
4413
|
+
var parseIlstBoxWithoutKeys = (ilstBox) => {
|
|
4414
|
+
return ilstBox.entries.map((entry) => {
|
|
4415
|
+
const key = mapToKey(entry.index);
|
|
4416
|
+
if (!key) {
|
|
4417
|
+
return null;
|
|
4418
|
+
}
|
|
4419
|
+
if (entry.value.type === "unknown") {
|
|
4420
|
+
return null;
|
|
4421
|
+
}
|
|
4422
|
+
return {
|
|
4423
|
+
trackId: null,
|
|
4424
|
+
key,
|
|
4425
|
+
value: entry.value.value
|
|
4426
|
+
};
|
|
4427
|
+
}).filter(truthy);
|
|
4428
|
+
};
|
|
4429
|
+
var parseIsoMetaBox = (meta, trackId) => {
|
|
4430
|
+
const ilstBox = meta.children.find((b) => b.type === "ilst-box");
|
|
4431
|
+
const keysBox = meta.children.find((b) => b.type === "keys-box");
|
|
4432
|
+
if (!ilstBox || !keysBox) {
|
|
4433
|
+
if (ilstBox) {
|
|
4434
|
+
return parseIlstBoxWithoutKeys(ilstBox);
|
|
4435
|
+
}
|
|
4436
|
+
return [];
|
|
4437
|
+
}
|
|
4438
|
+
const entries = [];
|
|
4439
|
+
for (let i = 0;i < ilstBox.entries.length; i++) {
|
|
4440
|
+
const ilstEntry = ilstBox.entries[i];
|
|
4441
|
+
const keysEntry = keysBox.entries[i];
|
|
4442
|
+
if (ilstEntry.value.type !== "unknown") {
|
|
4443
|
+
const value = typeof ilstEntry.value.value === "string" && ilstEntry.value.value.endsWith("\x00") ? ilstEntry.value.value.slice(0, -1) : ilstEntry.value.value;
|
|
4444
|
+
entries.push({
|
|
4445
|
+
key: keysEntry.value,
|
|
4446
|
+
value,
|
|
4447
|
+
trackId
|
|
4448
|
+
});
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
return entries;
|
|
4452
|
+
};
|
|
4453
|
+
var getMetadataFromIsoBase = (isoBase) => {
|
|
4454
|
+
const moov = getMoovBox(isoBase.boxes);
|
|
4455
|
+
if (!moov) {
|
|
4456
|
+
return [];
|
|
4457
|
+
}
|
|
4458
|
+
const traks = getTraks(moov);
|
|
4459
|
+
const meta = moov.children.find((b) => b.type === "regular-box" && b.boxType === "meta");
|
|
4460
|
+
const udta = moov.children.find((b) => b.type === "regular-box" && b.boxType === "udta");
|
|
4461
|
+
const metaInUdta = udta?.children.find((b) => {
|
|
4462
|
+
return b.type === "regular-box" && b.boxType === "meta";
|
|
4463
|
+
});
|
|
4464
|
+
const metaInTracks = traks.map((t) => {
|
|
4465
|
+
const metaBox = t.children.find((child) => child.type === "regular-box" && child.boxType === "meta");
|
|
4466
|
+
if (metaBox) {
|
|
4467
|
+
const tkhd = getTkhdBox(t);
|
|
4468
|
+
if (!tkhd) {
|
|
4469
|
+
throw new Error("No tkhd box found");
|
|
4470
|
+
}
|
|
4471
|
+
return parseIsoMetaBox(metaBox, tkhd.trackId);
|
|
4472
|
+
}
|
|
4473
|
+
return null;
|
|
4474
|
+
}).filter(truthy);
|
|
4475
|
+
return [
|
|
4476
|
+
...meta ? parseIsoMetaBox(meta, null) : [],
|
|
4477
|
+
...metaInUdta ? parseIsoMetaBox(metaInUdta, null) : [],
|
|
4478
|
+
...metaInTracks.flat(1)
|
|
4479
|
+
];
|
|
4480
|
+
};
|
|
4481
|
+
|
|
4482
|
+
// src/metadata/metadata-from-matroska.ts
|
|
4483
|
+
var removeEndZeroes = (value) => {
|
|
4484
|
+
return value.endsWith("\x00") ? removeEndZeroes(value.slice(0, -1)) : value;
|
|
4485
|
+
};
|
|
4486
|
+
var parseSimpleTagIntoEbml = (children, trackId) => {
|
|
4487
|
+
const tagName = children.find((c) => c.type === "TagName");
|
|
4488
|
+
const tagString = children.find((c) => c.type === "TagString");
|
|
4489
|
+
if (!tagName || !tagString) {
|
|
4490
|
+
return null;
|
|
4491
|
+
}
|
|
4492
|
+
return {
|
|
4493
|
+
trackId,
|
|
4494
|
+
key: tagName.value.toLowerCase(),
|
|
4495
|
+
value: removeEndZeroes(tagString.value)
|
|
4496
|
+
};
|
|
4497
|
+
};
|
|
4498
|
+
var getMetadataFromMatroska = (structure) => {
|
|
4499
|
+
const entries = [];
|
|
4500
|
+
for (const segment of structure.boxes) {
|
|
4501
|
+
if (segment.type !== "Segment") {
|
|
4502
|
+
continue;
|
|
4503
|
+
}
|
|
4504
|
+
const tags2 = segment.value.filter((s) => s.type === "Tags");
|
|
4505
|
+
for (const tag of tags2) {
|
|
4506
|
+
for (const child of tag.value) {
|
|
4507
|
+
if (child.type !== "Tag") {
|
|
4508
|
+
continue;
|
|
4509
|
+
}
|
|
4510
|
+
let trackId = null;
|
|
4511
|
+
const target = child.value.find((c) => c.type === "Targets");
|
|
4512
|
+
if (target) {
|
|
4513
|
+
const tagTrackId = target.value.find((c) => c.type === "TagTrackUID")?.value;
|
|
4514
|
+
if (tagTrackId) {
|
|
4515
|
+
trackId = getTrackWithUid(segment, tagTrackId);
|
|
4516
|
+
}
|
|
4517
|
+
}
|
|
4518
|
+
const simpleTags = child.value.filter((s) => s.type === "SimpleTag");
|
|
4519
|
+
for (const simpleTag of simpleTags) {
|
|
4520
|
+
const parsed = parseSimpleTagIntoEbml(simpleTag.value, trackId);
|
|
4521
|
+
if (parsed) {
|
|
4522
|
+
entries.push(parsed);
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
return entries;
|
|
4529
|
+
};
|
|
4530
|
+
|
|
4531
|
+
// src/metadata/metadata-from-riff.ts
|
|
4532
|
+
var getMetadataFromRiff = (structure) => {
|
|
4533
|
+
const boxes = structure.boxes.find((b) => b.type === "list-box" && b.listType === "INFO");
|
|
4534
|
+
if (!boxes) {
|
|
4535
|
+
return [];
|
|
4536
|
+
}
|
|
4537
|
+
const { children } = boxes;
|
|
4538
|
+
return children.map((child) => {
|
|
4539
|
+
if (child.type !== "isft-box") {
|
|
4540
|
+
return null;
|
|
4541
|
+
}
|
|
4542
|
+
return {
|
|
4543
|
+
trackId: null,
|
|
4544
|
+
key: "encoder",
|
|
4545
|
+
value: child.software
|
|
4546
|
+
};
|
|
4547
|
+
}).filter(truthy);
|
|
4548
|
+
};
|
|
4549
|
+
|
|
4550
|
+
// src/metadata/get-metadata.ts
|
|
4551
|
+
var getMetadata = (structure) => {
|
|
4552
|
+
if (structure.type === "matroska") {
|
|
4553
|
+
return getMetadataFromMatroska(structure);
|
|
4554
|
+
}
|
|
4555
|
+
if (structure.type === "riff") {
|
|
4556
|
+
return getMetadataFromRiff(structure);
|
|
4557
|
+
}
|
|
4558
|
+
if (structure.type === "transport-stream") {
|
|
4559
|
+
return [];
|
|
4560
|
+
}
|
|
4561
|
+
if (structure.type === "mp3") {
|
|
4562
|
+
const tags2 = getMetadataFromMp3(structure);
|
|
4563
|
+
if (tags2 === null) {
|
|
4564
|
+
throw new Error("Failed to get metadata from mp3");
|
|
4565
|
+
}
|
|
4566
|
+
return tags2;
|
|
4567
|
+
}
|
|
4568
|
+
return getMetadataFromIsoBase(structure);
|
|
4569
|
+
};
|
|
4570
|
+
var hasMetadata = (structure) => {
|
|
4571
|
+
if (structure.type === "mp3") {
|
|
4572
|
+
return getMetadataFromMp3(structure) !== null;
|
|
4573
|
+
}
|
|
4574
|
+
return false;
|
|
4575
|
+
};
|
|
4576
|
+
|
|
4032
4577
|
// src/has-all-info.ts
|
|
4033
4578
|
var getAvailableInfo = ({
|
|
4034
4579
|
fieldsToFetch,
|
|
@@ -4066,7 +4611,7 @@ var getAvailableInfo = ({
|
|
|
4066
4611
|
return Boolean(structure && hasAudioCodec(structure, state));
|
|
4067
4612
|
}
|
|
4068
4613
|
if (key === "tracks") {
|
|
4069
|
-
return Boolean(structure &&
|
|
4614
|
+
return Boolean(structure && getHasTracks(structure, state));
|
|
4070
4615
|
}
|
|
4071
4616
|
if (key === "keyframes") {
|
|
4072
4617
|
return Boolean(structure && hasKeyframes(structure, state));
|
|
@@ -4086,33 +4631,122 @@ var getAvailableInfo = ({
|
|
|
4086
4631
|
if (key === "container") {
|
|
4087
4632
|
return Boolean(structure && hasContainer(structure));
|
|
4088
4633
|
}
|
|
4089
|
-
if (key === "metadata" || key === "location") {
|
|
4090
|
-
return
|
|
4634
|
+
if (key === "metadata" || key === "location" || key === "images") {
|
|
4635
|
+
return Boolean(structure && hasMetadata(structure));
|
|
4091
4636
|
}
|
|
4092
4637
|
if (key === "slowKeyframes") {
|
|
4093
4638
|
return false;
|
|
4094
4639
|
}
|
|
4095
|
-
if (key === "slowNumberOfFrames") {
|
|
4096
|
-
return false;
|
|
4640
|
+
if (key === "slowNumberOfFrames") {
|
|
4641
|
+
return false;
|
|
4642
|
+
}
|
|
4643
|
+
throw new Error(`Unknown key: ${key}`);
|
|
4644
|
+
});
|
|
4645
|
+
const entries = [];
|
|
4646
|
+
let i = 0;
|
|
4647
|
+
for (const [key] of keys) {
|
|
4648
|
+
entries.push([key, infos[i++]]);
|
|
4649
|
+
}
|
|
4650
|
+
return Object.fromEntries(entries);
|
|
4651
|
+
};
|
|
4652
|
+
var hasAllInfo = ({
|
|
4653
|
+
fields,
|
|
4654
|
+
state
|
|
4655
|
+
}) => {
|
|
4656
|
+
const availableInfo = getAvailableInfo({
|
|
4657
|
+
fieldsToFetch: fields ?? {},
|
|
4658
|
+
state
|
|
4659
|
+
});
|
|
4660
|
+
return Object.values(availableInfo).every(Boolean) && (maySkipVideoData({ state }) || state.callbacks.canSkipTracksState.canSkipTracks());
|
|
4661
|
+
};
|
|
4662
|
+
|
|
4663
|
+
// src/continue-mdat-routine.ts
|
|
4664
|
+
var continueMdatRoutine = async ({
|
|
4665
|
+
iterator,
|
|
4666
|
+
maxBytes,
|
|
4667
|
+
allowIncompleteBoxes,
|
|
4668
|
+
initialBoxes,
|
|
4669
|
+
state,
|
|
4670
|
+
continueMdat,
|
|
4671
|
+
signal,
|
|
4672
|
+
logLevel,
|
|
4673
|
+
fields
|
|
4674
|
+
}) => {
|
|
4675
|
+
const initialOffset = iterator.counter.getOffset();
|
|
4676
|
+
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
|
|
4677
|
+
const result = await parseMdatPartially({
|
|
4678
|
+
iterator,
|
|
4679
|
+
boxSize: continueMdat.boxSize,
|
|
4680
|
+
fileOffset: continueMdat.fileOffset,
|
|
4681
|
+
parsedBoxes: initialBoxes,
|
|
4682
|
+
state,
|
|
4683
|
+
signal
|
|
4684
|
+
});
|
|
4685
|
+
if (result.type === "incomplete") {
|
|
4686
|
+
throw new Error("Incomplete boxes are not allowed in this routine");
|
|
4687
|
+
}
|
|
4688
|
+
if (result.type === "partial-mdat-box") {
|
|
4689
|
+
return {
|
|
4690
|
+
status: "incomplete",
|
|
4691
|
+
continueParsing: () => {
|
|
4692
|
+
return Promise.resolve(continueMdatRoutine({
|
|
4693
|
+
iterator,
|
|
4694
|
+
maxBytes,
|
|
4695
|
+
allowIncompleteBoxes,
|
|
4696
|
+
initialBoxes,
|
|
4697
|
+
state,
|
|
4698
|
+
continueMdat: result,
|
|
4699
|
+
signal,
|
|
4700
|
+
logLevel,
|
|
4701
|
+
fields
|
|
4702
|
+
}));
|
|
4703
|
+
},
|
|
4704
|
+
skipTo: null
|
|
4705
|
+
};
|
|
4706
|
+
}
|
|
4707
|
+
const alreadyHasMdat = state.structure.getStructureOrNull()?.boxes.find((b) => b.type === "mdat-box");
|
|
4708
|
+
if (result.box.type === "mdat-box" && alreadyHasMdat) {
|
|
4709
|
+
initialBoxes = initialBoxes.filter((b) => b.type !== "mdat-box");
|
|
4710
|
+
initialBoxes.push(result.box);
|
|
4711
|
+
iterator.allowDiscard();
|
|
4712
|
+
break;
|
|
4713
|
+
} else {
|
|
4714
|
+
initialBoxes.push(result.box);
|
|
4715
|
+
if (hasAllInfo({ fields, state })) {
|
|
4716
|
+
return {
|
|
4717
|
+
status: "done"
|
|
4718
|
+
};
|
|
4719
|
+
}
|
|
4097
4720
|
}
|
|
4098
|
-
|
|
4099
|
-
});
|
|
4100
|
-
const entries = [];
|
|
4101
|
-
let i = 0;
|
|
4102
|
-
for (const [key] of keys) {
|
|
4103
|
-
entries.push([key, infos[i++]]);
|
|
4721
|
+
iterator.removeBytesRead();
|
|
4104
4722
|
}
|
|
4105
|
-
|
|
4106
|
-
};
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4723
|
+
const mdatState = getMdatBox(initialBoxes);
|
|
4724
|
+
const skipped = mdatState?.status === "samples-skipped" && !maySkipVideoData({ state }) && state.supportsContentRange;
|
|
4725
|
+
const buffered = mdatState?.status === "samples-buffered" && !maySkipVideoData({ state });
|
|
4726
|
+
if (skipped || buffered) {
|
|
4727
|
+
return {
|
|
4728
|
+
status: "incomplete",
|
|
4729
|
+
continueParsing: () => {
|
|
4730
|
+
if (buffered) {
|
|
4731
|
+
iterator.skipTo(mdatState.fileOffset, false);
|
|
4732
|
+
}
|
|
4733
|
+
return parseIsoBaseMediaBoxes({
|
|
4734
|
+
iterator,
|
|
4735
|
+
maxBytes,
|
|
4736
|
+
allowIncompleteBoxes: false,
|
|
4737
|
+
initialBoxes,
|
|
4738
|
+
state,
|
|
4739
|
+
signal,
|
|
4740
|
+
logLevel,
|
|
4741
|
+
fields
|
|
4742
|
+
});
|
|
4743
|
+
},
|
|
4744
|
+
skipTo: skipped ? mdatState.fileOffset : null
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
return {
|
|
4748
|
+
status: "done"
|
|
4749
|
+
};
|
|
4116
4750
|
};
|
|
4117
4751
|
|
|
4118
4752
|
// src/register-track.ts
|
|
@@ -4225,199 +4859,98 @@ var processDescriptor = ({
|
|
|
4225
4859
|
upStream,
|
|
4226
4860
|
avgBitrate,
|
|
4227
4861
|
maxBitrate,
|
|
4228
|
-
decoderSpecificConfigs
|
|
4229
|
-
}
|
|
4230
|
-
};
|
|
4231
|
-
}
|
|
4232
|
-
if (tag === 6) {
|
|
4233
|
-
const size = iterator.getPaddedFourByteNumber();
|
|
4234
|
-
iterator.discard(size);
|
|
4235
|
-
return {
|
|
4236
|
-
descriptor: {
|
|
4237
|
-
type: "sl-config-descriptor"
|
|
4238
|
-
}
|
|
4239
|
-
};
|
|
4240
|
-
}
|
|
4241
|
-
return {
|
|
4242
|
-
descriptor: null
|
|
4243
|
-
};
|
|
4244
|
-
};
|
|
4245
|
-
var parseDescriptors = (iterator, maxBytes) => {
|
|
4246
|
-
const descriptors = [];
|
|
4247
|
-
const initialOffset = iterator.counter.getOffset();
|
|
4248
|
-
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
|
|
4249
|
-
const { descriptor } = processDescriptor({
|
|
4250
|
-
iterator
|
|
4251
|
-
});
|
|
4252
|
-
if (descriptor) {
|
|
4253
|
-
descriptors.push(descriptor);
|
|
4254
|
-
} else {
|
|
4255
|
-
break;
|
|
4256
|
-
}
|
|
4257
|
-
}
|
|
4258
|
-
return descriptors;
|
|
4259
|
-
};
|
|
4260
|
-
|
|
4261
|
-
// src/boxes/iso-base-media/esds/esds.ts
|
|
4262
|
-
var parseEsds = ({
|
|
4263
|
-
data,
|
|
4264
|
-
size,
|
|
4265
|
-
fileOffset
|
|
4266
|
-
}) => {
|
|
4267
|
-
const version = data.getUint8();
|
|
4268
|
-
data.discard(3);
|
|
4269
|
-
const tag = data.getUint8();
|
|
4270
|
-
const sizeOfInstance = data.getPaddedFourByteNumber();
|
|
4271
|
-
const esId = data.getUint16();
|
|
4272
|
-
data.discard(1);
|
|
4273
|
-
const remaining = size - (data.counter.getOffset() - fileOffset);
|
|
4274
|
-
const descriptors = parseDescriptors(data, remaining);
|
|
4275
|
-
const remainingNow = size - (data.counter.getOffset() - fileOffset);
|
|
4276
|
-
data.discard(remainingNow);
|
|
4277
|
-
return {
|
|
4278
|
-
type: "esds-box",
|
|
4279
|
-
version,
|
|
4280
|
-
tag,
|
|
4281
|
-
sizeOfInstance,
|
|
4282
|
-
esId,
|
|
4283
|
-
descriptors
|
|
4284
|
-
};
|
|
4285
|
-
};
|
|
4286
|
-
|
|
4287
|
-
// src/convert-audio-or-video-sample.ts
|
|
4288
|
-
var convertAudioOrVideoSampleToWebCodecsTimestamps = (sample, timescale) => {
|
|
4289
|
-
const { cts, dts, timestamp } = sample;
|
|
4290
|
-
return {
|
|
4291
|
-
cts: cts * 1e6 / timescale,
|
|
4292
|
-
dts: dts * 1e6 / timescale,
|
|
4293
|
-
timestamp: timestamp * 1e6 / timescale,
|
|
4294
|
-
duration: sample.duration === undefined ? undefined : sample.duration * 1e6 / timescale,
|
|
4295
|
-
data: sample.data,
|
|
4296
|
-
trackId: sample.trackId,
|
|
4297
|
-
type: sample.type,
|
|
4298
|
-
offset: sample.offset,
|
|
4299
|
-
timescale: 1e6
|
|
4300
|
-
};
|
|
4301
|
-
};
|
|
4302
|
-
|
|
4303
|
-
// src/boxes/iso-base-media/mdat/mdat.ts
|
|
4304
|
-
var parseMdat = async ({
|
|
4305
|
-
data,
|
|
4306
|
-
size,
|
|
4307
|
-
fileOffset,
|
|
4308
|
-
existingBoxes,
|
|
4309
|
-
state,
|
|
4310
|
-
signal,
|
|
4311
|
-
maySkipSampleProcessing
|
|
4312
|
-
}) => {
|
|
4313
|
-
const alreadyHas = hasTracks({
|
|
4314
|
-
type: "iso-base-media",
|
|
4315
|
-
boxes: existingBoxes
|
|
4316
|
-
}, state);
|
|
4317
|
-
if (!alreadyHas) {
|
|
4318
|
-
if (maySkipSampleProcessing) {
|
|
4319
|
-
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
4320
|
-
return Promise.resolve({
|
|
4321
|
-
type: "mdat-box",
|
|
4322
|
-
boxSize: size,
|
|
4323
|
-
status: "samples-skipped",
|
|
4324
|
-
fileOffset
|
|
4325
|
-
});
|
|
4326
|
-
}
|
|
4327
|
-
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
4328
|
-
data.disallowDiscard();
|
|
4329
|
-
return Promise.resolve({
|
|
4330
|
-
type: "mdat-box",
|
|
4331
|
-
boxSize: size,
|
|
4332
|
-
status: "samples-buffered",
|
|
4333
|
-
fileOffset
|
|
4334
|
-
});
|
|
4335
|
-
}
|
|
4336
|
-
const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, state);
|
|
4337
|
-
const allTracks = [
|
|
4338
|
-
...tracks2.videoTracks,
|
|
4339
|
-
...tracks2.audioTracks,
|
|
4340
|
-
...tracks2.otherTracks
|
|
4341
|
-
];
|
|
4342
|
-
const flatSamples = allTracks.map((track) => {
|
|
4343
|
-
const samplePositions = getSamplePositionsFromTrack(track.trakBox, getMoofBox(existingBoxes));
|
|
4344
|
-
if (!samplePositions) {
|
|
4345
|
-
throw new Error("No sample positions");
|
|
4346
|
-
}
|
|
4347
|
-
return samplePositions.map((samplePosition) => {
|
|
4348
|
-
return {
|
|
4349
|
-
track: { ...track },
|
|
4350
|
-
samplePosition
|
|
4351
|
-
};
|
|
4352
|
-
});
|
|
4353
|
-
}).flat(1);
|
|
4354
|
-
while (true) {
|
|
4355
|
-
if (signal && signal.aborted) {
|
|
4356
|
-
break;
|
|
4357
|
-
}
|
|
4358
|
-
const samplesWithIndex = flatSamples.find((sample) => {
|
|
4359
|
-
return sample.samplePosition.offset === data.counter.getOffset();
|
|
4360
|
-
});
|
|
4361
|
-
if (!samplesWithIndex) {
|
|
4362
|
-
const nextSample_ = flatSamples.filter((s) => s.samplePosition.offset > data.counter.getOffset()).sort((a, b) => a.samplePosition.offset - b.samplePosition.offset)[0];
|
|
4363
|
-
if (nextSample_) {
|
|
4364
|
-
data.discard(nextSample_.samplePosition.offset - data.counter.getOffset());
|
|
4365
|
-
continue;
|
|
4366
|
-
} else {
|
|
4367
|
-
const bytesRemaining = size + fileOffset - data.counter.getOffset();
|
|
4368
|
-
data.discard(bytesRemaining);
|
|
4369
|
-
break;
|
|
4370
|
-
}
|
|
4371
|
-
}
|
|
4372
|
-
if (data.bytesRemaining() < samplesWithIndex.samplePosition.size) {
|
|
4373
|
-
break;
|
|
4374
|
-
}
|
|
4375
|
-
const bytes = data.getSlice(samplesWithIndex.samplePosition.size);
|
|
4376
|
-
const { cts, dts, duration: duration2, isKeyframe, offset } = samplesWithIndex.samplePosition;
|
|
4377
|
-
if (samplesWithIndex.track.type === "audio") {
|
|
4378
|
-
await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
|
|
4379
|
-
data: bytes,
|
|
4380
|
-
timestamp: cts,
|
|
4381
|
-
duration: duration2,
|
|
4382
|
-
cts,
|
|
4383
|
-
dts,
|
|
4384
|
-
trackId: samplesWithIndex.track.trackId,
|
|
4385
|
-
type: isKeyframe ? "key" : "delta",
|
|
4386
|
-
offset,
|
|
4387
|
-
timescale: samplesWithIndex.track.timescale
|
|
4388
|
-
}, samplesWithIndex.track.timescale));
|
|
4389
|
-
}
|
|
4390
|
-
if (samplesWithIndex.track.type === "video") {
|
|
4391
|
-
const nalUnitType = bytes[4] & 31;
|
|
4392
|
-
let isRecoveryPoint = false;
|
|
4393
|
-
if (nalUnitType === 6) {
|
|
4394
|
-
const seiType = bytes[5];
|
|
4395
|
-
isRecoveryPoint = seiType === 6;
|
|
4396
|
-
}
|
|
4397
|
-
await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
|
|
4398
|
-
data: bytes,
|
|
4399
|
-
timestamp: cts,
|
|
4400
|
-
duration: duration2,
|
|
4401
|
-
cts,
|
|
4402
|
-
dts,
|
|
4403
|
-
trackId: samplesWithIndex.track.trackId,
|
|
4404
|
-
type: isKeyframe && !isRecoveryPoint ? "key" : "delta",
|
|
4405
|
-
offset,
|
|
4406
|
-
timescale: samplesWithIndex.track.timescale
|
|
4407
|
-
}, samplesWithIndex.track.timescale));
|
|
4408
|
-
}
|
|
4409
|
-
const remaining = size - (data.counter.getOffset() - fileOffset);
|
|
4410
|
-
data.removeBytesRead();
|
|
4411
|
-
if (remaining === 0) {
|
|
4862
|
+
decoderSpecificConfigs
|
|
4863
|
+
}
|
|
4864
|
+
};
|
|
4865
|
+
}
|
|
4866
|
+
if (tag === 6) {
|
|
4867
|
+
const size = iterator.getPaddedFourByteNumber();
|
|
4868
|
+
iterator.discard(size);
|
|
4869
|
+
return {
|
|
4870
|
+
descriptor: {
|
|
4871
|
+
type: "sl-config-descriptor"
|
|
4872
|
+
}
|
|
4873
|
+
};
|
|
4874
|
+
}
|
|
4875
|
+
return {
|
|
4876
|
+
descriptor: null
|
|
4877
|
+
};
|
|
4878
|
+
};
|
|
4879
|
+
var parseDescriptors = (iterator, maxBytes) => {
|
|
4880
|
+
const descriptors = [];
|
|
4881
|
+
const initialOffset = iterator.counter.getOffset();
|
|
4882
|
+
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
|
|
4883
|
+
const { descriptor } = processDescriptor({
|
|
4884
|
+
iterator
|
|
4885
|
+
});
|
|
4886
|
+
if (descriptor) {
|
|
4887
|
+
descriptors.push(descriptor);
|
|
4888
|
+
} else {
|
|
4412
4889
|
break;
|
|
4413
4890
|
}
|
|
4414
4891
|
}
|
|
4415
|
-
return
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4892
|
+
return descriptors;
|
|
4893
|
+
};
|
|
4894
|
+
|
|
4895
|
+
// src/boxes/iso-base-media/esds/esds.ts
|
|
4896
|
+
var parseEsds = ({
|
|
4897
|
+
data,
|
|
4898
|
+
size,
|
|
4899
|
+
fileOffset
|
|
4900
|
+
}) => {
|
|
4901
|
+
const version = data.getUint8();
|
|
4902
|
+
data.discard(3);
|
|
4903
|
+
const tag = data.getUint8();
|
|
4904
|
+
const sizeOfInstance = data.getPaddedFourByteNumber();
|
|
4905
|
+
const esId = data.getUint16();
|
|
4906
|
+
data.discard(1);
|
|
4907
|
+
const remaining = size - (data.counter.getOffset() - fileOffset);
|
|
4908
|
+
const descriptors = parseDescriptors(data, remaining);
|
|
4909
|
+
const remainingNow = size - (data.counter.getOffset() - fileOffset);
|
|
4910
|
+
data.discard(remainingNow);
|
|
4911
|
+
return {
|
|
4912
|
+
type: "esds-box",
|
|
4913
|
+
version,
|
|
4914
|
+
tag,
|
|
4915
|
+
sizeOfInstance,
|
|
4916
|
+
esId,
|
|
4917
|
+
descriptors
|
|
4918
|
+
};
|
|
4919
|
+
};
|
|
4920
|
+
|
|
4921
|
+
// src/boxes/iso-base-media/get-children.ts
|
|
4922
|
+
var getChildren = async ({
|
|
4923
|
+
boxType,
|
|
4924
|
+
iterator,
|
|
4925
|
+
bytesRemainingInBox,
|
|
4926
|
+
state,
|
|
4927
|
+
signal,
|
|
4928
|
+
logLevel,
|
|
4929
|
+
fields
|
|
4930
|
+
}) => {
|
|
4931
|
+
const parseChildren = boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "stsb";
|
|
4932
|
+
if (parseChildren) {
|
|
4933
|
+
const boxes = [];
|
|
4934
|
+
const parsed = await parseIsoBaseMediaBoxes({
|
|
4935
|
+
iterator,
|
|
4936
|
+
maxBytes: bytesRemainingInBox,
|
|
4937
|
+
allowIncompleteBoxes: false,
|
|
4938
|
+
initialBoxes: boxes,
|
|
4939
|
+
state,
|
|
4940
|
+
signal,
|
|
4941
|
+
logLevel,
|
|
4942
|
+
fields
|
|
4943
|
+
});
|
|
4944
|
+
if (parsed.status === "incomplete") {
|
|
4945
|
+
throw new Error("Incomplete boxes are not allowed");
|
|
4946
|
+
}
|
|
4947
|
+
return boxes;
|
|
4948
|
+
}
|
|
4949
|
+
if (bytesRemainingInBox < 0) {
|
|
4950
|
+
throw new Error("Box size is too big " + JSON.stringify({ boxType }));
|
|
4951
|
+
}
|
|
4952
|
+
iterator.discard(bytesRemainingInBox);
|
|
4953
|
+
return [];
|
|
4421
4954
|
};
|
|
4422
4955
|
|
|
4423
4956
|
// src/boxes/iso-base-media/mdhd.ts
|
|
@@ -4580,7 +5113,6 @@ var parseMoov = async ({
|
|
|
4580
5113
|
allowIncompleteBoxes: false,
|
|
4581
5114
|
initialBoxes: boxes,
|
|
4582
5115
|
state,
|
|
4583
|
-
continueMdat: false,
|
|
4584
5116
|
signal,
|
|
4585
5117
|
logLevel,
|
|
4586
5118
|
fields
|
|
@@ -4882,7 +5414,6 @@ var parseMebx = async ({
|
|
|
4882
5414
|
allowIncompleteBoxes: false,
|
|
4883
5415
|
initialBoxes: boxes,
|
|
4884
5416
|
state,
|
|
4885
|
-
continueMdat: false,
|
|
4886
5417
|
signal,
|
|
4887
5418
|
logLevel: "info",
|
|
4888
5419
|
fields
|
|
@@ -5291,7 +5822,6 @@ var parseTrak = async ({
|
|
|
5291
5822
|
allowIncompleteBoxes: false,
|
|
5292
5823
|
initialBoxes,
|
|
5293
5824
|
state: options,
|
|
5294
|
-
continueMdat: false,
|
|
5295
5825
|
signal,
|
|
5296
5826
|
logLevel,
|
|
5297
5827
|
fields
|
|
@@ -5350,71 +5880,6 @@ var parseTrun = ({
|
|
|
5350
5880
|
};
|
|
5351
5881
|
|
|
5352
5882
|
// src/boxes/iso-base-media/process-box.ts
|
|
5353
|
-
var getChildren = async ({
|
|
5354
|
-
boxType,
|
|
5355
|
-
iterator,
|
|
5356
|
-
bytesRemainingInBox,
|
|
5357
|
-
state,
|
|
5358
|
-
signal,
|
|
5359
|
-
logLevel,
|
|
5360
|
-
fields
|
|
5361
|
-
}) => {
|
|
5362
|
-
const parseChildren = boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "stsb";
|
|
5363
|
-
if (parseChildren) {
|
|
5364
|
-
const boxes = [];
|
|
5365
|
-
const parsed = await parseIsoBaseMediaBoxes({
|
|
5366
|
-
iterator,
|
|
5367
|
-
maxBytes: bytesRemainingInBox,
|
|
5368
|
-
allowIncompleteBoxes: false,
|
|
5369
|
-
initialBoxes: boxes,
|
|
5370
|
-
state,
|
|
5371
|
-
continueMdat: false,
|
|
5372
|
-
signal,
|
|
5373
|
-
logLevel,
|
|
5374
|
-
fields
|
|
5375
|
-
});
|
|
5376
|
-
if (parsed.status === "incomplete") {
|
|
5377
|
-
throw new Error("Incomplete boxes are not allowed");
|
|
5378
|
-
}
|
|
5379
|
-
return boxes;
|
|
5380
|
-
}
|
|
5381
|
-
if (bytesRemainingInBox < 0) {
|
|
5382
|
-
throw new Error("Box size is too big " + JSON.stringify({ boxType }));
|
|
5383
|
-
}
|
|
5384
|
-
iterator.discard(bytesRemainingInBox);
|
|
5385
|
-
return [];
|
|
5386
|
-
};
|
|
5387
|
-
var parseMdatPartially = async ({
|
|
5388
|
-
iterator,
|
|
5389
|
-
boxSize,
|
|
5390
|
-
fileOffset,
|
|
5391
|
-
parsedBoxes,
|
|
5392
|
-
state,
|
|
5393
|
-
signal
|
|
5394
|
-
}) => {
|
|
5395
|
-
const box = await parseMdat({
|
|
5396
|
-
data: iterator,
|
|
5397
|
-
size: boxSize,
|
|
5398
|
-
fileOffset,
|
|
5399
|
-
existingBoxes: parsedBoxes,
|
|
5400
|
-
state,
|
|
5401
|
-
signal,
|
|
5402
|
-
maySkipSampleProcessing: state.supportsContentRange
|
|
5403
|
-
});
|
|
5404
|
-
if ((box.status === "samples-processed" || box.status === "samples-buffered") && box.fileOffset + boxSize === iterator.counter.getOffset()) {
|
|
5405
|
-
return {
|
|
5406
|
-
type: "complete",
|
|
5407
|
-
box,
|
|
5408
|
-
size: boxSize,
|
|
5409
|
-
skipTo: null
|
|
5410
|
-
};
|
|
5411
|
-
}
|
|
5412
|
-
return {
|
|
5413
|
-
type: "partial-mdat-box",
|
|
5414
|
-
boxSize,
|
|
5415
|
-
fileOffset
|
|
5416
|
-
};
|
|
5417
|
-
};
|
|
5418
5883
|
var processBox = async ({
|
|
5419
5884
|
iterator,
|
|
5420
5885
|
allowIncompleteBoxes,
|
|
@@ -5427,15 +5892,6 @@ var processBox = async ({
|
|
|
5427
5892
|
const fileOffset = iterator.counter.getOffset();
|
|
5428
5893
|
const bytesRemaining = iterator.bytesRemaining();
|
|
5429
5894
|
const boxSizeRaw = iterator.getFourByteNumber();
|
|
5430
|
-
if (boxSizeRaw === 1 && iterator.bytesRemaining() < 12 || iterator.bytesRemaining() < 4) {
|
|
5431
|
-
iterator.counter.decrement(iterator.counter.getOffset() - fileOffset);
|
|
5432
|
-
if (allowIncompleteBoxes) {
|
|
5433
|
-
return {
|
|
5434
|
-
type: "incomplete"
|
|
5435
|
-
};
|
|
5436
|
-
}
|
|
5437
|
-
throw new Error(`Expected box size of ${bytesRemaining}, got ${boxSizeRaw}. Incomplete boxes are not allowed.`);
|
|
5438
|
-
}
|
|
5439
5895
|
if (boxSizeRaw === 0) {
|
|
5440
5896
|
return {
|
|
5441
5897
|
type: "complete",
|
|
@@ -5447,45 +5903,54 @@ var processBox = async ({
|
|
|
5447
5903
|
skipTo: null
|
|
5448
5904
|
};
|
|
5449
5905
|
}
|
|
5906
|
+
if (boxSizeRaw === 1 && iterator.bytesRemaining() < 12 || iterator.bytesRemaining() < 4) {
|
|
5907
|
+
iterator.counter.decrement(iterator.counter.getOffset() - fileOffset);
|
|
5908
|
+
if (!allowIncompleteBoxes) {
|
|
5909
|
+
throw new Error(`Expected box size of ${bytesRemaining}, got ${boxSizeRaw}. Incomplete boxes are not allowed.`);
|
|
5910
|
+
}
|
|
5911
|
+
return {
|
|
5912
|
+
type: "incomplete"
|
|
5913
|
+
};
|
|
5914
|
+
}
|
|
5450
5915
|
const boxType = iterator.getByteString(4, false);
|
|
5451
5916
|
const boxSize = boxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw;
|
|
5452
5917
|
if (bytesRemaining < boxSize) {
|
|
5453
|
-
if (boxType
|
|
5454
|
-
|
|
5455
|
-
if (
|
|
5456
|
-
|
|
5457
|
-
const bytesToSkip = skipTo - iterator.counter.getOffset();
|
|
5458
|
-
if (bytesToSkip > 1e6) {
|
|
5459
|
-
return {
|
|
5460
|
-
type: "complete",
|
|
5461
|
-
box: {
|
|
5462
|
-
type: "mdat-box",
|
|
5463
|
-
boxSize,
|
|
5464
|
-
fileOffset,
|
|
5465
|
-
status: "samples-skipped"
|
|
5466
|
-
},
|
|
5467
|
-
size: boxSize,
|
|
5468
|
-
skipTo: fileOffset + boxSize
|
|
5469
|
-
};
|
|
5470
|
-
}
|
|
5471
|
-
} else {
|
|
5472
|
-
return parseMdatPartially({
|
|
5473
|
-
iterator,
|
|
5474
|
-
boxSize,
|
|
5475
|
-
fileOffset,
|
|
5476
|
-
parsedBoxes,
|
|
5477
|
-
state,
|
|
5478
|
-
signal
|
|
5479
|
-
});
|
|
5918
|
+
if (boxType !== "mdat") {
|
|
5919
|
+
iterator.counter.decrement(iterator.counter.getOffset() - fileOffset);
|
|
5920
|
+
if (!allowIncompleteBoxes) {
|
|
5921
|
+
throw new Error(`Expected box size of ${bytesRemaining}, got ${boxSize}. Incomplete boxes are not allowed.`);
|
|
5480
5922
|
}
|
|
5481
|
-
}
|
|
5482
|
-
iterator.counter.decrement(iterator.counter.getOffset() - fileOffset);
|
|
5483
|
-
if (allowIncompleteBoxes) {
|
|
5484
5923
|
return {
|
|
5485
5924
|
type: "incomplete"
|
|
5486
5925
|
};
|
|
5487
5926
|
}
|
|
5488
|
-
|
|
5927
|
+
const shouldSkip = maySkipVideoData({ state }) || !getHasTracks({ type: "iso-base-media", boxes: parsedBoxes }, state) && state.supportsContentRange;
|
|
5928
|
+
if (shouldSkip) {
|
|
5929
|
+
const skipTo = fileOffset + boxSize;
|
|
5930
|
+
const bytesToSkip = skipTo - iterator.counter.getOffset();
|
|
5931
|
+
if (bytesToSkip > 1e6) {
|
|
5932
|
+
return {
|
|
5933
|
+
type: "complete",
|
|
5934
|
+
box: {
|
|
5935
|
+
type: "mdat-box",
|
|
5936
|
+
boxSize,
|
|
5937
|
+
fileOffset,
|
|
5938
|
+
status: "samples-skipped"
|
|
5939
|
+
},
|
|
5940
|
+
size: boxSize,
|
|
5941
|
+
skipTo: fileOffset + boxSize
|
|
5942
|
+
};
|
|
5943
|
+
}
|
|
5944
|
+
} else {
|
|
5945
|
+
return parseMdatPartially({
|
|
5946
|
+
iterator,
|
|
5947
|
+
boxSize,
|
|
5948
|
+
fileOffset,
|
|
5949
|
+
parsedBoxes,
|
|
5950
|
+
state,
|
|
5951
|
+
signal
|
|
5952
|
+
});
|
|
5953
|
+
}
|
|
5489
5954
|
}
|
|
5490
5955
|
if (boxType === "ftyp") {
|
|
5491
5956
|
const box = parseFtyp({ iterator, size: boxSize, offset: fileOffset });
|
|
@@ -5828,8 +6293,8 @@ var processBox = async ({
|
|
|
5828
6293
|
signal,
|
|
5829
6294
|
maySkipSampleProcessing: state.supportsContentRange
|
|
5830
6295
|
});
|
|
5831
|
-
if (box ===
|
|
5832
|
-
|
|
6296
|
+
if (box.type === "partial-mdat-box") {
|
|
6297
|
+
return box;
|
|
5833
6298
|
}
|
|
5834
6299
|
return {
|
|
5835
6300
|
type: "complete",
|
|
@@ -5861,28 +6326,34 @@ var processBox = async ({
|
|
|
5861
6326
|
skipTo: null
|
|
5862
6327
|
};
|
|
5863
6328
|
};
|
|
6329
|
+
|
|
6330
|
+
// src/boxes/iso-base-media/parse-boxes.ts
|
|
5864
6331
|
var parseIsoBaseMediaBoxes = async ({
|
|
5865
6332
|
iterator,
|
|
5866
6333
|
maxBytes,
|
|
5867
6334
|
allowIncompleteBoxes,
|
|
5868
6335
|
initialBoxes,
|
|
5869
6336
|
state,
|
|
5870
|
-
continueMdat,
|
|
5871
6337
|
signal,
|
|
5872
6338
|
logLevel,
|
|
5873
6339
|
fields
|
|
5874
6340
|
}) => {
|
|
5875
6341
|
const initialOffset = iterator.counter.getOffset();
|
|
5876
|
-
const
|
|
5877
|
-
|
|
5878
|
-
const result = continueMdat ? await parseMdatPartially({
|
|
6342
|
+
const continueParsing = () => {
|
|
6343
|
+
return parseIsoBaseMediaBoxes({
|
|
5879
6344
|
iterator,
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
6345
|
+
maxBytes,
|
|
6346
|
+
allowIncompleteBoxes,
|
|
6347
|
+
initialBoxes,
|
|
5883
6348
|
state,
|
|
5884
|
-
signal
|
|
5885
|
-
|
|
6349
|
+
signal,
|
|
6350
|
+
logLevel,
|
|
6351
|
+
fields
|
|
6352
|
+
});
|
|
6353
|
+
};
|
|
6354
|
+
const alreadyHasMdat = state.structure.getStructureOrNull()?.boxes.find((b) => b.type === "mdat-box");
|
|
6355
|
+
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
|
|
6356
|
+
const result = await processBox({
|
|
5886
6357
|
iterator,
|
|
5887
6358
|
allowIncompleteBoxes,
|
|
5888
6359
|
parsedBoxes: initialBoxes,
|
|
@@ -5897,19 +6368,7 @@ var parseIsoBaseMediaBoxes = async ({
|
|
|
5897
6368
|
}
|
|
5898
6369
|
return {
|
|
5899
6370
|
status: "incomplete",
|
|
5900
|
-
continueParsing
|
|
5901
|
-
return parseIsoBaseMediaBoxes({
|
|
5902
|
-
iterator,
|
|
5903
|
-
maxBytes,
|
|
5904
|
-
allowIncompleteBoxes,
|
|
5905
|
-
initialBoxes,
|
|
5906
|
-
state,
|
|
5907
|
-
continueMdat: false,
|
|
5908
|
-
signal,
|
|
5909
|
-
logLevel,
|
|
5910
|
-
fields
|
|
5911
|
-
});
|
|
5912
|
-
},
|
|
6371
|
+
continueParsing,
|
|
5913
6372
|
skipTo: null
|
|
5914
6373
|
};
|
|
5915
6374
|
}
|
|
@@ -5917,7 +6376,7 @@ var parseIsoBaseMediaBoxes = async ({
|
|
|
5917
6376
|
return {
|
|
5918
6377
|
status: "incomplete",
|
|
5919
6378
|
continueParsing: () => {
|
|
5920
|
-
return Promise.resolve(
|
|
6379
|
+
return Promise.resolve(continueMdatRoutine({
|
|
5921
6380
|
iterator,
|
|
5922
6381
|
maxBytes,
|
|
5923
6382
|
allowIncompleteBoxes,
|
|
@@ -5951,38 +6410,14 @@ var parseIsoBaseMediaBoxes = async ({
|
|
|
5951
6410
|
}
|
|
5952
6411
|
return {
|
|
5953
6412
|
status: "incomplete",
|
|
5954
|
-
continueParsing
|
|
5955
|
-
return parseIsoBaseMediaBoxes({
|
|
5956
|
-
iterator,
|
|
5957
|
-
maxBytes,
|
|
5958
|
-
allowIncompleteBoxes,
|
|
5959
|
-
initialBoxes,
|
|
5960
|
-
state,
|
|
5961
|
-
continueMdat: false,
|
|
5962
|
-
signal,
|
|
5963
|
-
logLevel,
|
|
5964
|
-
fields
|
|
5965
|
-
});
|
|
5966
|
-
},
|
|
6413
|
+
continueParsing,
|
|
5967
6414
|
skipTo: result.skipTo
|
|
5968
6415
|
};
|
|
5969
6416
|
}
|
|
5970
6417
|
if (iterator.bytesRemaining() < 0) {
|
|
5971
6418
|
return {
|
|
5972
6419
|
status: "incomplete",
|
|
5973
|
-
continueParsing
|
|
5974
|
-
return parseIsoBaseMediaBoxes({
|
|
5975
|
-
iterator,
|
|
5976
|
-
maxBytes,
|
|
5977
|
-
allowIncompleteBoxes,
|
|
5978
|
-
initialBoxes,
|
|
5979
|
-
state,
|
|
5980
|
-
continueMdat: false,
|
|
5981
|
-
signal,
|
|
5982
|
-
logLevel,
|
|
5983
|
-
fields
|
|
5984
|
-
});
|
|
5985
|
-
},
|
|
6420
|
+
continueParsing,
|
|
5986
6421
|
skipTo: null
|
|
5987
6422
|
};
|
|
5988
6423
|
}
|
|
@@ -6004,7 +6439,6 @@ var parseIsoBaseMediaBoxes = async ({
|
|
|
6004
6439
|
allowIncompleteBoxes: false,
|
|
6005
6440
|
initialBoxes,
|
|
6006
6441
|
state,
|
|
6007
|
-
continueMdat: false,
|
|
6008
6442
|
signal,
|
|
6009
6443
|
logLevel,
|
|
6010
6444
|
fields
|
|
@@ -6126,7 +6560,6 @@ var processSample = async ({
|
|
|
6126
6560
|
maxBytes: bytesRemainingInBox,
|
|
6127
6561
|
initialBoxes,
|
|
6128
6562
|
state: options,
|
|
6129
|
-
continueMdat: false,
|
|
6130
6563
|
signal,
|
|
6131
6564
|
logLevel,
|
|
6132
6565
|
fields
|
|
@@ -6175,7 +6608,6 @@ var processSample = async ({
|
|
|
6175
6608
|
maxBytes: bytesRemainingInBox,
|
|
6176
6609
|
initialBoxes,
|
|
6177
6610
|
state: options,
|
|
6178
|
-
continueMdat: false,
|
|
6179
6611
|
signal,
|
|
6180
6612
|
logLevel,
|
|
6181
6613
|
fields
|
|
@@ -6227,7 +6659,6 @@ var processSample = async ({
|
|
|
6227
6659
|
maxBytes: bytesRemainingInBox,
|
|
6228
6660
|
initialBoxes: [],
|
|
6229
6661
|
state: options,
|
|
6230
|
-
continueMdat: false,
|
|
6231
6662
|
signal,
|
|
6232
6663
|
logLevel,
|
|
6233
6664
|
fields
|
|
@@ -6284,7 +6715,6 @@ var processSample = async ({
|
|
|
6284
6715
|
maxBytes: bytesRemainingInBox,
|
|
6285
6716
|
initialBoxes,
|
|
6286
6717
|
state: options,
|
|
6287
|
-
continueMdat: false,
|
|
6288
6718
|
signal,
|
|
6289
6719
|
logLevel,
|
|
6290
6720
|
fields
|
|
@@ -6670,11 +7100,24 @@ var emittedState = () => {
|
|
|
6670
7100
|
slowFps: false,
|
|
6671
7101
|
slowKeyframes: false,
|
|
6672
7102
|
slowNumberOfFrames: false,
|
|
6673
|
-
keyframes: false
|
|
7103
|
+
keyframes: false,
|
|
7104
|
+
images: false
|
|
6674
7105
|
};
|
|
6675
7106
|
return emittedFields;
|
|
6676
7107
|
};
|
|
6677
7108
|
|
|
7109
|
+
// src/state/images.ts
|
|
7110
|
+
var imagesState = () => {
|
|
7111
|
+
const images = [];
|
|
7112
|
+
const addImage = (image) => {
|
|
7113
|
+
images.push(image);
|
|
7114
|
+
};
|
|
7115
|
+
return {
|
|
7116
|
+
images,
|
|
7117
|
+
addImage
|
|
7118
|
+
};
|
|
7119
|
+
};
|
|
7120
|
+
|
|
6678
7121
|
// src/state/keyframes.ts
|
|
6679
7122
|
var keyframesState = () => {
|
|
6680
7123
|
const keyframes = [];
|
|
@@ -6688,6 +7131,17 @@ var keyframesState = () => {
|
|
|
6688
7131
|
};
|
|
6689
7132
|
};
|
|
6690
7133
|
|
|
7134
|
+
// src/state/mp3.ts
|
|
7135
|
+
var makeMp3State = () => {
|
|
7136
|
+
let mp3Info = null;
|
|
7137
|
+
return {
|
|
7138
|
+
getMp3Info: () => mp3Info,
|
|
7139
|
+
setMp3Info: (info) => {
|
|
7140
|
+
mp3Info = info;
|
|
7141
|
+
}
|
|
7142
|
+
};
|
|
7143
|
+
};
|
|
7144
|
+
|
|
6691
7145
|
// src/state/riff.ts
|
|
6692
7146
|
var riffSpecificState = () => {
|
|
6693
7147
|
let avcProfile = null;
|
|
@@ -6741,7 +7195,8 @@ var needsTracksField = {
|
|
|
6741
7195
|
mimeType: false,
|
|
6742
7196
|
slowKeyframes: true,
|
|
6743
7197
|
slowNumberOfFrames: true,
|
|
6744
|
-
keyframes: true
|
|
7198
|
+
keyframes: true,
|
|
7199
|
+
images: true
|
|
6745
7200
|
};
|
|
6746
7201
|
var makeCanSkipTracksState = ({
|
|
6747
7202
|
hasAudioTrackHandlers,
|
|
@@ -6831,6 +7286,9 @@ var sampleCallback = ({
|
|
|
6831
7286
|
await callback(audioSample);
|
|
6832
7287
|
}
|
|
6833
7288
|
}
|
|
7289
|
+
if (needsToIterateOverSamples({ emittedFields, fields })) {
|
|
7290
|
+
slowDurationAndFpsState.addAudioSample(audioSample);
|
|
7291
|
+
}
|
|
6834
7292
|
},
|
|
6835
7293
|
getSamplesForTrack: (trackId) => {
|
|
6836
7294
|
return samplesForTrack[trackId] ?? 0;
|
|
@@ -6862,7 +7320,7 @@ var sampleCallback = ({
|
|
|
6862
7320
|
sizeInBytes: videoSample.data.length
|
|
6863
7321
|
});
|
|
6864
7322
|
}
|
|
6865
|
-
slowDurationAndFpsState.
|
|
7323
|
+
slowDurationAndFpsState.addVideoSample(videoSample);
|
|
6866
7324
|
}
|
|
6867
7325
|
},
|
|
6868
7326
|
canSkipTracksState,
|
|
@@ -6885,33 +7343,64 @@ var sampleCallback = ({
|
|
|
6885
7343
|
|
|
6886
7344
|
// src/state/slow-duration-fps.ts
|
|
6887
7345
|
var slowDurationAndFpsState = () => {
|
|
6888
|
-
let
|
|
6889
|
-
let
|
|
6890
|
-
let
|
|
7346
|
+
let smallestVideoSample;
|
|
7347
|
+
let largestVideoSample;
|
|
7348
|
+
let smallestAudioSample;
|
|
7349
|
+
let largestAudioSample;
|
|
7350
|
+
let videoSamples = 0;
|
|
7351
|
+
let audioSamples = 0;
|
|
7352
|
+
const getSlowVideoDurationInSeconds = () => {
|
|
7353
|
+
let videoDuration = null;
|
|
7354
|
+
if (smallestVideoSample !== undefined && largestVideoSample !== undefined) {
|
|
7355
|
+
const startingTimestampDifference = largestVideoSample - smallestVideoSample;
|
|
7356
|
+
const timeBetweenSamples = startingTimestampDifference / (videoSamples - 1);
|
|
7357
|
+
videoDuration = timeBetweenSamples * videoSamples;
|
|
7358
|
+
}
|
|
7359
|
+
return videoDuration;
|
|
7360
|
+
};
|
|
6891
7361
|
const getSlowDurationInSeconds = () => {
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
7362
|
+
const videoDuration = getSlowVideoDurationInSeconds();
|
|
7363
|
+
let audioDuration = null;
|
|
7364
|
+
if (smallestAudioSample !== undefined && largestAudioSample !== undefined) {
|
|
7365
|
+
const startingTimestampDifferenceAudio = largestAudioSample - smallestAudioSample;
|
|
7366
|
+
const timeBetweenSamplesAudio = startingTimestampDifferenceAudio / (audioSamples - 1);
|
|
7367
|
+
audioDuration = timeBetweenSamplesAudio * audioSamples;
|
|
6896
7368
|
}
|
|
6897
|
-
|
|
7369
|
+
if (videoDuration === null && audioDuration === null) {
|
|
7370
|
+
throw new Error("No samples");
|
|
7371
|
+
}
|
|
7372
|
+
return Math.max(videoDuration ?? 0, audioDuration ?? 0);
|
|
6898
7373
|
};
|
|
6899
7374
|
return {
|
|
6900
|
-
|
|
6901
|
-
|
|
7375
|
+
addVideoSample: (videoSample) => {
|
|
7376
|
+
videoSamples++;
|
|
6902
7377
|
const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
|
|
6903
|
-
if (
|
|
6904
|
-
|
|
7378
|
+
if (largestVideoSample === undefined || presentationTimeInSeconds > largestVideoSample) {
|
|
7379
|
+
largestVideoSample = presentationTimeInSeconds;
|
|
7380
|
+
}
|
|
7381
|
+
if (smallestVideoSample === undefined || presentationTimeInSeconds < smallestVideoSample) {
|
|
7382
|
+
smallestVideoSample = presentationTimeInSeconds;
|
|
6905
7383
|
}
|
|
6906
|
-
|
|
6907
|
-
|
|
7384
|
+
},
|
|
7385
|
+
addAudioSample: (audioSample) => {
|
|
7386
|
+
audioSamples++;
|
|
7387
|
+
const presentationTimeInSeconds = audioSample.cts / audioSample.timescale;
|
|
7388
|
+
if (largestAudioSample === undefined || presentationTimeInSeconds > largestAudioSample) {
|
|
7389
|
+
largestAudioSample = presentationTimeInSeconds;
|
|
7390
|
+
}
|
|
7391
|
+
if (smallestAudioSample === undefined || presentationTimeInSeconds < smallestAudioSample) {
|
|
7392
|
+
smallestAudioSample = presentationTimeInSeconds;
|
|
6908
7393
|
}
|
|
6909
7394
|
},
|
|
6910
7395
|
getSlowDurationInSeconds,
|
|
6911
7396
|
getFps: () => {
|
|
6912
|
-
|
|
7397
|
+
const videoDuration = getSlowVideoDurationInSeconds() ?? 0;
|
|
7398
|
+
if (videoDuration === 0) {
|
|
7399
|
+
return 0;
|
|
7400
|
+
}
|
|
7401
|
+
return videoSamples / videoDuration;
|
|
6913
7402
|
},
|
|
6914
|
-
getSlowNumberOfFrames: () =>
|
|
7403
|
+
getSlowNumberOfFrames: () => videoSamples
|
|
6915
7404
|
};
|
|
6916
7405
|
};
|
|
6917
7406
|
|
|
@@ -7002,7 +7491,8 @@ var makeParserState = ({
|
|
|
7002
7491
|
fields,
|
|
7003
7492
|
onAudioTrack,
|
|
7004
7493
|
onVideoTrack,
|
|
7005
|
-
supportsContentRange
|
|
7494
|
+
supportsContentRange,
|
|
7495
|
+
contentLength
|
|
7006
7496
|
}) => {
|
|
7007
7497
|
let skippedBytes = 0;
|
|
7008
7498
|
const increaseSkippedBytes = (bytes) => {
|
|
@@ -7012,6 +7502,8 @@ var makeParserState = ({
|
|
|
7012
7502
|
const keyframes = keyframesState();
|
|
7013
7503
|
const emittedFields = emittedState();
|
|
7014
7504
|
const slowDurationAndFps = slowDurationAndFpsState();
|
|
7505
|
+
const mp3Info = makeMp3State();
|
|
7506
|
+
const images = imagesState();
|
|
7015
7507
|
return {
|
|
7016
7508
|
riff: riffSpecificState(),
|
|
7017
7509
|
callbacks: sampleCallback({
|
|
@@ -7037,7 +7529,10 @@ var makeParserState = ({
|
|
|
7037
7529
|
webm: webmState(),
|
|
7038
7530
|
emittedFields,
|
|
7039
7531
|
fields,
|
|
7040
|
-
slowDurationAndFps
|
|
7532
|
+
slowDurationAndFps,
|
|
7533
|
+
mp3Info,
|
|
7534
|
+
contentLength,
|
|
7535
|
+
images
|
|
7041
7536
|
};
|
|
7042
7537
|
};
|
|
7043
7538
|
|
|
@@ -7395,299 +7890,108 @@ class IsAGifError extends Error {
|
|
|
7395
7890
|
fileName
|
|
7396
7891
|
}) {
|
|
7397
7892
|
super(message);
|
|
7398
|
-
this.fileName = "IsAGifError";
|
|
7399
|
-
this.mimeType = mimeType;
|
|
7400
|
-
this.sizeInBytes = sizeInBytes;
|
|
7401
|
-
this.fileName = fileName;
|
|
7402
|
-
if (Error.captureStackTrace) {
|
|
7403
|
-
Error.captureStackTrace(this, IsAGifError);
|
|
7404
|
-
}
|
|
7405
|
-
}
|
|
7406
|
-
}
|
|
7407
|
-
|
|
7408
|
-
class IsAnImageError extends Error {
|
|
7409
|
-
imageType;
|
|
7410
|
-
dimensions;
|
|
7411
|
-
mimeType;
|
|
7412
|
-
sizeInBytes;
|
|
7413
|
-
fileName;
|
|
7414
|
-
constructor({
|
|
7415
|
-
dimensions,
|
|
7416
|
-
imageType,
|
|
7417
|
-
message,
|
|
7418
|
-
mimeType,
|
|
7419
|
-
sizeInBytes,
|
|
7420
|
-
fileName
|
|
7421
|
-
}) {
|
|
7422
|
-
super(message);
|
|
7423
|
-
this.name = "IsAnImageError";
|
|
7424
|
-
this.imageType = imageType;
|
|
7425
|
-
this.dimensions = dimensions;
|
|
7426
|
-
this.mimeType = mimeType;
|
|
7427
|
-
this.sizeInBytes = sizeInBytes;
|
|
7428
|
-
this.fileName = fileName;
|
|
7429
|
-
if (Error.captureStackTrace) {
|
|
7430
|
-
Error.captureStackTrace(this, IsAnImageError);
|
|
7431
|
-
}
|
|
7432
|
-
}
|
|
7433
|
-
}
|
|
7434
|
-
|
|
7435
|
-
class IsAPdfError extends Error {
|
|
7436
|
-
mimeType;
|
|
7437
|
-
sizeInBytes;
|
|
7438
|
-
fileName;
|
|
7439
|
-
constructor({
|
|
7440
|
-
message,
|
|
7441
|
-
mimeType,
|
|
7442
|
-
sizeInBytes,
|
|
7443
|
-
fileName
|
|
7444
|
-
}) {
|
|
7445
|
-
super(message);
|
|
7446
|
-
this.name = "IsAPdfError";
|
|
7447
|
-
this.mimeType = mimeType;
|
|
7448
|
-
this.sizeInBytes = sizeInBytes;
|
|
7449
|
-
this.fileName = fileName;
|
|
7450
|
-
if (Error.captureStackTrace) {
|
|
7451
|
-
Error.captureStackTrace(this, IsAPdfError);
|
|
7452
|
-
}
|
|
7453
|
-
}
|
|
7454
|
-
}
|
|
7455
|
-
|
|
7456
|
-
class IsAnUnsupportedFileTypeError extends Error {
|
|
7457
|
-
mimeType;
|
|
7458
|
-
sizeInBytes;
|
|
7459
|
-
fileName;
|
|
7460
|
-
constructor({
|
|
7461
|
-
message,
|
|
7462
|
-
mimeType,
|
|
7463
|
-
sizeInBytes,
|
|
7464
|
-
fileName
|
|
7465
|
-
}) {
|
|
7466
|
-
super(message);
|
|
7467
|
-
this.name = "IsAnUnsupportedFileTypeError";
|
|
7468
|
-
this.mimeType = mimeType;
|
|
7469
|
-
this.sizeInBytes = sizeInBytes;
|
|
7470
|
-
this.fileName = fileName;
|
|
7471
|
-
if (Error.captureStackTrace) {
|
|
7472
|
-
Error.captureStackTrace(this, IsAnUnsupportedFileTypeError);
|
|
7473
|
-
}
|
|
7474
|
-
}
|
|
7475
|
-
}
|
|
7476
|
-
|
|
7477
|
-
class IsAnUnsupportedAudioTypeError extends Error {
|
|
7478
|
-
mimeType;
|
|
7479
|
-
sizeInBytes;
|
|
7480
|
-
fileName;
|
|
7481
|
-
audioType;
|
|
7482
|
-
constructor({
|
|
7483
|
-
message,
|
|
7484
|
-
mimeType,
|
|
7485
|
-
sizeInBytes,
|
|
7486
|
-
fileName,
|
|
7487
|
-
audioType
|
|
7488
|
-
}) {
|
|
7489
|
-
super(message);
|
|
7490
|
-
this.name = "IsAnUnsupportedAudioTypeError";
|
|
7491
|
-
this.mimeType = mimeType;
|
|
7492
|
-
this.sizeInBytes = sizeInBytes;
|
|
7493
|
-
this.fileName = fileName;
|
|
7494
|
-
this.audioType = audioType;
|
|
7495
|
-
if (Error.captureStackTrace) {
|
|
7496
|
-
Error.captureStackTrace(this, IsAnUnsupportedAudioTypeError);
|
|
7497
|
-
}
|
|
7498
|
-
}
|
|
7499
|
-
}
|
|
7500
|
-
// src/metadata/metadata-from-iso.ts
|
|
7501
|
-
var mapToKey = (index) => {
|
|
7502
|
-
if (index === 2839630420) {
|
|
7503
|
-
return "artist";
|
|
7504
|
-
}
|
|
7505
|
-
if (index === 2841734242) {
|
|
7506
|
-
return "album";
|
|
7507
|
-
}
|
|
7508
|
-
if (index === 2841865588) {
|
|
7509
|
-
return "comment";
|
|
7510
|
-
}
|
|
7511
|
-
if (index === 2841928057) {
|
|
7512
|
-
return "releaseDate";
|
|
7513
|
-
}
|
|
7514
|
-
if (index === 2842125678) {
|
|
7515
|
-
return "genre";
|
|
7516
|
-
}
|
|
7517
|
-
if (index === 2842583405) {
|
|
7518
|
-
return "title";
|
|
7519
|
-
}
|
|
7520
|
-
if (index === 2842980207) {
|
|
7521
|
-
return "encoder";
|
|
7522
|
-
}
|
|
7523
|
-
if (index === 2843177588) {
|
|
7524
|
-
return "writer";
|
|
7525
|
-
}
|
|
7526
|
-
if (index === 2841866361) {
|
|
7527
|
-
return "copyright";
|
|
7528
|
-
}
|
|
7529
|
-
if (index === 2841930098) {
|
|
7530
|
-
return "director";
|
|
7531
|
-
}
|
|
7532
|
-
if (index === 2842718820) {
|
|
7533
|
-
return "producer";
|
|
7534
|
-
}
|
|
7535
|
-
if (index === 2841929075) {
|
|
7536
|
-
return "description";
|
|
7537
|
-
}
|
|
7538
|
-
return null;
|
|
7539
|
-
};
|
|
7540
|
-
var parseIlstBoxWithoutKeys = (ilstBox) => {
|
|
7541
|
-
return ilstBox.entries.map((entry) => {
|
|
7542
|
-
const key = mapToKey(entry.index);
|
|
7543
|
-
if (!key) {
|
|
7544
|
-
return null;
|
|
7545
|
-
}
|
|
7546
|
-
if (entry.value.type === "unknown") {
|
|
7547
|
-
return null;
|
|
7548
|
-
}
|
|
7549
|
-
return {
|
|
7550
|
-
trackId: null,
|
|
7551
|
-
key,
|
|
7552
|
-
value: entry.value.value
|
|
7553
|
-
};
|
|
7554
|
-
}).filter(truthy);
|
|
7555
|
-
};
|
|
7556
|
-
var parseIsoMetaBox = (meta, trackId) => {
|
|
7557
|
-
const ilstBox = meta.children.find((b) => b.type === "ilst-box");
|
|
7558
|
-
const keysBox = meta.children.find((b) => b.type === "keys-box");
|
|
7559
|
-
if (!ilstBox || !keysBox) {
|
|
7560
|
-
if (ilstBox) {
|
|
7561
|
-
return parseIlstBoxWithoutKeys(ilstBox);
|
|
7562
|
-
}
|
|
7563
|
-
return [];
|
|
7564
|
-
}
|
|
7565
|
-
const entries = [];
|
|
7566
|
-
for (let i = 0;i < ilstBox.entries.length; i++) {
|
|
7567
|
-
const ilstEntry = ilstBox.entries[i];
|
|
7568
|
-
const keysEntry = keysBox.entries[i];
|
|
7569
|
-
if (ilstEntry.value.type !== "unknown") {
|
|
7570
|
-
const value = typeof ilstEntry.value.value === "string" && ilstEntry.value.value.endsWith("\x00") ? ilstEntry.value.value.slice(0, -1) : ilstEntry.value.value;
|
|
7571
|
-
entries.push({
|
|
7572
|
-
key: keysEntry.value,
|
|
7573
|
-
value,
|
|
7574
|
-
trackId
|
|
7575
|
-
});
|
|
7576
|
-
}
|
|
7577
|
-
}
|
|
7578
|
-
return entries;
|
|
7579
|
-
};
|
|
7580
|
-
var getMetadataFromIsoBase = (isoBase) => {
|
|
7581
|
-
const moov = getMoovBox(isoBase.boxes);
|
|
7582
|
-
if (!moov) {
|
|
7583
|
-
return [];
|
|
7584
|
-
}
|
|
7585
|
-
const traks = getTraks(moov);
|
|
7586
|
-
const meta = moov.children.find((b) => b.type === "regular-box" && b.boxType === "meta");
|
|
7587
|
-
const udta = moov.children.find((b) => b.type === "regular-box" && b.boxType === "udta");
|
|
7588
|
-
const metaInUdta = udta?.children.find((b) => {
|
|
7589
|
-
return b.type === "regular-box" && b.boxType === "meta";
|
|
7590
|
-
});
|
|
7591
|
-
const metaInTracks = traks.map((t) => {
|
|
7592
|
-
const metaBox = t.children.find((child) => child.type === "regular-box" && child.boxType === "meta");
|
|
7593
|
-
if (metaBox) {
|
|
7594
|
-
const tkhd = getTkhdBox(t);
|
|
7595
|
-
if (!tkhd) {
|
|
7596
|
-
throw new Error("No tkhd box found");
|
|
7597
|
-
}
|
|
7598
|
-
return parseIsoMetaBox(metaBox, tkhd.trackId);
|
|
7599
|
-
}
|
|
7600
|
-
return null;
|
|
7601
|
-
}).filter(truthy);
|
|
7602
|
-
return [
|
|
7603
|
-
...meta ? parseIsoMetaBox(meta, null) : [],
|
|
7604
|
-
...metaInUdta ? parseIsoMetaBox(metaInUdta, null) : [],
|
|
7605
|
-
...metaInTracks.flat(1)
|
|
7606
|
-
];
|
|
7607
|
-
};
|
|
7608
|
-
|
|
7609
|
-
// src/metadata/metadata-from-matroska.ts
|
|
7610
|
-
var removeEndZeroes = (value) => {
|
|
7611
|
-
return value.endsWith("\x00") ? removeEndZeroes(value.slice(0, -1)) : value;
|
|
7612
|
-
};
|
|
7613
|
-
var parseSimpleTagIntoEbml = (children, trackId) => {
|
|
7614
|
-
const tagName = children.find((c) => c.type === "TagName");
|
|
7615
|
-
const tagString = children.find((c) => c.type === "TagString");
|
|
7616
|
-
if (!tagName || !tagString) {
|
|
7617
|
-
return null;
|
|
7618
|
-
}
|
|
7619
|
-
return {
|
|
7620
|
-
trackId,
|
|
7621
|
-
key: tagName.value.toLowerCase(),
|
|
7622
|
-
value: removeEndZeroes(tagString.value)
|
|
7623
|
-
};
|
|
7624
|
-
};
|
|
7625
|
-
var getMetadataFromMatroska = (structure) => {
|
|
7626
|
-
const entries = [];
|
|
7627
|
-
for (const segment of structure.boxes) {
|
|
7628
|
-
if (segment.type !== "Segment") {
|
|
7629
|
-
continue;
|
|
7630
|
-
}
|
|
7631
|
-
const tags2 = segment.value.filter((s) => s.type === "Tags");
|
|
7632
|
-
for (const tag of tags2) {
|
|
7633
|
-
for (const child of tag.value) {
|
|
7634
|
-
if (child.type !== "Tag") {
|
|
7635
|
-
continue;
|
|
7636
|
-
}
|
|
7637
|
-
let trackId = null;
|
|
7638
|
-
const target = child.value.find((c) => c.type === "Targets");
|
|
7639
|
-
if (target) {
|
|
7640
|
-
const tagTrackId = target.value.find((c) => c.type === "TagTrackUID")?.value;
|
|
7641
|
-
if (tagTrackId) {
|
|
7642
|
-
trackId = getTrackWithUid(segment, tagTrackId);
|
|
7643
|
-
}
|
|
7644
|
-
}
|
|
7645
|
-
const simpleTags = child.value.filter((s) => s.type === "SimpleTag");
|
|
7646
|
-
for (const simpleTag of simpleTags) {
|
|
7647
|
-
const parsed = parseSimpleTagIntoEbml(simpleTag.value, trackId);
|
|
7648
|
-
if (parsed) {
|
|
7649
|
-
entries.push(parsed);
|
|
7650
|
-
}
|
|
7651
|
-
}
|
|
7652
|
-
}
|
|
7893
|
+
this.fileName = "IsAGifError";
|
|
7894
|
+
this.mimeType = mimeType;
|
|
7895
|
+
this.sizeInBytes = sizeInBytes;
|
|
7896
|
+
this.fileName = fileName;
|
|
7897
|
+
if (Error.captureStackTrace) {
|
|
7898
|
+
Error.captureStackTrace(this, IsAGifError);
|
|
7653
7899
|
}
|
|
7654
7900
|
}
|
|
7655
|
-
|
|
7656
|
-
};
|
|
7901
|
+
}
|
|
7657
7902
|
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7903
|
+
class IsAnImageError extends Error {
|
|
7904
|
+
imageType;
|
|
7905
|
+
dimensions;
|
|
7906
|
+
mimeType;
|
|
7907
|
+
sizeInBytes;
|
|
7908
|
+
fileName;
|
|
7909
|
+
constructor({
|
|
7910
|
+
dimensions,
|
|
7911
|
+
imageType,
|
|
7912
|
+
message,
|
|
7913
|
+
mimeType,
|
|
7914
|
+
sizeInBytes,
|
|
7915
|
+
fileName
|
|
7916
|
+
}) {
|
|
7917
|
+
super(message);
|
|
7918
|
+
this.name = "IsAnImageError";
|
|
7919
|
+
this.imageType = imageType;
|
|
7920
|
+
this.dimensions = dimensions;
|
|
7921
|
+
this.mimeType = mimeType;
|
|
7922
|
+
this.sizeInBytes = sizeInBytes;
|
|
7923
|
+
this.fileName = fileName;
|
|
7924
|
+
if (Error.captureStackTrace) {
|
|
7925
|
+
Error.captureStackTrace(this, IsAnImageError);
|
|
7668
7926
|
}
|
|
7669
|
-
return {
|
|
7670
|
-
trackId: null,
|
|
7671
|
-
key: "encoder",
|
|
7672
|
-
value: child.software
|
|
7673
|
-
};
|
|
7674
|
-
}).filter(truthy);
|
|
7675
|
-
};
|
|
7676
|
-
|
|
7677
|
-
// src/metadata/get-metadata.ts
|
|
7678
|
-
var getMetadata = (structure) => {
|
|
7679
|
-
if (structure.type === "matroska") {
|
|
7680
|
-
return getMetadataFromMatroska(structure);
|
|
7681
7927
|
}
|
|
7682
|
-
|
|
7683
|
-
|
|
7928
|
+
}
|
|
7929
|
+
|
|
7930
|
+
class IsAPdfError extends Error {
|
|
7931
|
+
mimeType;
|
|
7932
|
+
sizeInBytes;
|
|
7933
|
+
fileName;
|
|
7934
|
+
constructor({
|
|
7935
|
+
message,
|
|
7936
|
+
mimeType,
|
|
7937
|
+
sizeInBytes,
|
|
7938
|
+
fileName
|
|
7939
|
+
}) {
|
|
7940
|
+
super(message);
|
|
7941
|
+
this.name = "IsAPdfError";
|
|
7942
|
+
this.mimeType = mimeType;
|
|
7943
|
+
this.sizeInBytes = sizeInBytes;
|
|
7944
|
+
this.fileName = fileName;
|
|
7945
|
+
if (Error.captureStackTrace) {
|
|
7946
|
+
Error.captureStackTrace(this, IsAPdfError);
|
|
7947
|
+
}
|
|
7684
7948
|
}
|
|
7685
|
-
|
|
7686
|
-
|
|
7949
|
+
}
|
|
7950
|
+
|
|
7951
|
+
class IsAnUnsupportedFileTypeError extends Error {
|
|
7952
|
+
mimeType;
|
|
7953
|
+
sizeInBytes;
|
|
7954
|
+
fileName;
|
|
7955
|
+
constructor({
|
|
7956
|
+
message,
|
|
7957
|
+
mimeType,
|
|
7958
|
+
sizeInBytes,
|
|
7959
|
+
fileName
|
|
7960
|
+
}) {
|
|
7961
|
+
super(message);
|
|
7962
|
+
this.name = "IsAnUnsupportedFileTypeError";
|
|
7963
|
+
this.mimeType = mimeType;
|
|
7964
|
+
this.sizeInBytes = sizeInBytes;
|
|
7965
|
+
this.fileName = fileName;
|
|
7966
|
+
if (Error.captureStackTrace) {
|
|
7967
|
+
Error.captureStackTrace(this, IsAnUnsupportedFileTypeError);
|
|
7968
|
+
}
|
|
7687
7969
|
}
|
|
7688
|
-
|
|
7689
|
-
};
|
|
7970
|
+
}
|
|
7690
7971
|
|
|
7972
|
+
class IsAnUnsupportedAudioTypeError extends Error {
|
|
7973
|
+
mimeType;
|
|
7974
|
+
sizeInBytes;
|
|
7975
|
+
fileName;
|
|
7976
|
+
audioType;
|
|
7977
|
+
constructor({
|
|
7978
|
+
message,
|
|
7979
|
+
mimeType,
|
|
7980
|
+
sizeInBytes,
|
|
7981
|
+
fileName,
|
|
7982
|
+
audioType
|
|
7983
|
+
}) {
|
|
7984
|
+
super(message);
|
|
7985
|
+
this.name = "IsAnUnsupportedAudioTypeError";
|
|
7986
|
+
this.mimeType = mimeType;
|
|
7987
|
+
this.sizeInBytes = sizeInBytes;
|
|
7988
|
+
this.fileName = fileName;
|
|
7989
|
+
this.audioType = audioType;
|
|
7990
|
+
if (Error.captureStackTrace) {
|
|
7991
|
+
Error.captureStackTrace(this, IsAnUnsupportedAudioTypeError);
|
|
7992
|
+
}
|
|
7993
|
+
}
|
|
7994
|
+
}
|
|
7691
7995
|
// src/get-location.ts
|
|
7692
7996
|
function parseLocation(locationString) {
|
|
7693
7997
|
const locationPattern = /^([+-]\d{2}\.?\d{0,10})([+-]\d{3}\.?\d{0,10})([+-]\d+(\.\d+)?)?\/$/;
|
|
@@ -7808,7 +8112,7 @@ var emitAvailableInfo = ({
|
|
|
7808
8112
|
if (key === "dimensions") {
|
|
7809
8113
|
if (hasInfo.dimensions && !emittedFields.dimensions && parseResult && segments) {
|
|
7810
8114
|
const dimensionsQueried = getDimensions(segments, state);
|
|
7811
|
-
const dimensions = {
|
|
8115
|
+
const dimensions = dimensionsQueried === null ? null : {
|
|
7812
8116
|
height: dimensionsQueried.height,
|
|
7813
8117
|
width: dimensionsQueried.width
|
|
7814
8118
|
};
|
|
@@ -7823,7 +8127,7 @@ var emitAvailableInfo = ({
|
|
|
7823
8127
|
if (key === "unrotatedDimensions") {
|
|
7824
8128
|
if (hasInfo.unrotatedDimensions && !emittedFields.unrotatedDimensions && parseResult && segments) {
|
|
7825
8129
|
const dimensionsQueried = getDimensions(segments, state);
|
|
7826
|
-
const unrotatedDimensions = {
|
|
8130
|
+
const unrotatedDimensions = dimensionsQueried === null ? null : {
|
|
7827
8131
|
height: dimensionsQueried.unrotatedHeight,
|
|
7828
8132
|
width: dimensionsQueried.unrotatedWidth
|
|
7829
8133
|
};
|
|
@@ -7838,7 +8142,7 @@ var emitAvailableInfo = ({
|
|
|
7838
8142
|
if (key === "rotation") {
|
|
7839
8143
|
if (hasInfo.rotation && !emittedFields.rotation && parseResult && segments) {
|
|
7840
8144
|
const dimensionsQueried = getDimensions(segments, state);
|
|
7841
|
-
const
|
|
8145
|
+
const rotation = dimensionsQueried?.rotation ?? 0;
|
|
7842
8146
|
callbacks.onRotation?.(rotation);
|
|
7843
8147
|
if (fieldsInReturnValue.rotation) {
|
|
7844
8148
|
returnValue.rotation = rotation;
|
|
@@ -7994,41 +8298,489 @@ var emitAvailableInfo = ({
|
|
|
7994
8298
|
}
|
|
7995
8299
|
continue;
|
|
7996
8300
|
}
|
|
8301
|
+
if (key === "images") {
|
|
8302
|
+
if (!emittedFields.images && hasInfo.images && parseResult) {
|
|
8303
|
+
callbacks.onImages?.(state.images.images);
|
|
8304
|
+
if (fieldsInReturnValue.images) {
|
|
8305
|
+
returnValue.images = state.images.images;
|
|
8306
|
+
}
|
|
8307
|
+
emittedFields.images = true;
|
|
8308
|
+
}
|
|
8309
|
+
continue;
|
|
8310
|
+
}
|
|
7997
8311
|
throw new Error(`Unhandled key: ${key}`);
|
|
7998
8312
|
}
|
|
7999
8313
|
};
|
|
8000
8314
|
|
|
8001
|
-
// src/get-fields-from-callbacks.ts
|
|
8002
|
-
var getFieldsFromCallback = ({
|
|
8003
|
-
fields,
|
|
8004
|
-
callbacks
|
|
8315
|
+
// src/get-fields-from-callbacks.ts
|
|
8316
|
+
var getFieldsFromCallback = ({
|
|
8317
|
+
fields,
|
|
8318
|
+
callbacks
|
|
8319
|
+
}) => {
|
|
8320
|
+
const newFields = {
|
|
8321
|
+
audioCodec: Boolean(callbacks.onAudioCodec),
|
|
8322
|
+
container: Boolean(callbacks.onContainer),
|
|
8323
|
+
dimensions: Boolean(callbacks.onDimensions),
|
|
8324
|
+
durationInSeconds: Boolean(callbacks.onDurationInSeconds),
|
|
8325
|
+
fps: Boolean(callbacks.onFps),
|
|
8326
|
+
internalStats: Boolean(callbacks.onInternalStats),
|
|
8327
|
+
isHdr: Boolean(callbacks.onIsHdr),
|
|
8328
|
+
location: Boolean(callbacks.onLocation),
|
|
8329
|
+
metadata: Boolean(callbacks.onMetadata),
|
|
8330
|
+
mimeType: Boolean(callbacks.onMimeType),
|
|
8331
|
+
name: Boolean(callbacks.onName),
|
|
8332
|
+
rotation: Boolean(callbacks.onRotation),
|
|
8333
|
+
size: Boolean(callbacks.onSize),
|
|
8334
|
+
structure: Boolean(callbacks.onStructure),
|
|
8335
|
+
tracks: Boolean(callbacks.onTracks),
|
|
8336
|
+
unrotatedDimensions: Boolean(callbacks.onUnrotatedDimensions),
|
|
8337
|
+
videoCodec: Boolean(callbacks.onVideoCodec),
|
|
8338
|
+
slowKeyframes: Boolean(callbacks.onSlowKeyframes),
|
|
8339
|
+
slowDurationInSeconds: Boolean(callbacks.onSlowDurationInSeconds),
|
|
8340
|
+
slowFps: Boolean(callbacks.onSlowFps),
|
|
8341
|
+
slowNumberOfFrames: Boolean(callbacks.onSlowNumberOfFrames),
|
|
8342
|
+
keyframes: Boolean(callbacks.onKeyframes),
|
|
8343
|
+
images: Boolean(callbacks.onImages),
|
|
8344
|
+
...fields
|
|
8345
|
+
};
|
|
8346
|
+
return newFields;
|
|
8347
|
+
};
|
|
8348
|
+
|
|
8349
|
+
// src/boxes/mp3/id3.ts
|
|
8350
|
+
function combine28Bits(a, b, c, d) {
|
|
8351
|
+
const val1 = a & 127;
|
|
8352
|
+
const val2 = b & 127;
|
|
8353
|
+
const val3 = c & 127;
|
|
8354
|
+
const val4 = d & 127;
|
|
8355
|
+
return val1 << 21 | val2 << 14 | val3 << 7 | val4;
|
|
8356
|
+
}
|
|
8357
|
+
var parseId3 = ({
|
|
8358
|
+
iterator,
|
|
8359
|
+
structure,
|
|
8360
|
+
state
|
|
8361
|
+
}) => {
|
|
8362
|
+
if (iterator.bytesRemaining() < 9) {
|
|
8363
|
+
return;
|
|
8364
|
+
}
|
|
8365
|
+
const { returnToCheckpoint } = iterator.startCheckpoint();
|
|
8366
|
+
iterator.discard(3);
|
|
8367
|
+
const versionMajor = iterator.getUint8();
|
|
8368
|
+
const versionMinor = iterator.getUint8();
|
|
8369
|
+
const flags = iterator.getUint8();
|
|
8370
|
+
const sizeArr = iterator.getSlice(4);
|
|
8371
|
+
const size = combine28Bits(sizeArr[0], sizeArr[1], sizeArr[2], sizeArr[3]);
|
|
8372
|
+
if (iterator.bytesRemaining() < size) {
|
|
8373
|
+
returnToCheckpoint();
|
|
8374
|
+
return;
|
|
8375
|
+
}
|
|
8376
|
+
const entries = [];
|
|
8377
|
+
const initial = iterator.counter.getOffset();
|
|
8378
|
+
while (iterator.counter.getOffset() < size + initial) {
|
|
8379
|
+
const name = versionMajor === 3 ? iterator.getByteString(4, true) : iterator.getByteString(3, true);
|
|
8380
|
+
if (name === "") {
|
|
8381
|
+
iterator.discard(size + initial - iterator.counter.getOffset());
|
|
8382
|
+
break;
|
|
8383
|
+
}
|
|
8384
|
+
const s = versionMajor === 3 ? iterator.getUint32() : iterator.getUint24();
|
|
8385
|
+
if (versionMajor === 3) {
|
|
8386
|
+
iterator.getUint16();
|
|
8387
|
+
}
|
|
8388
|
+
let subtract = 0;
|
|
8389
|
+
if (!name.startsWith("W")) {
|
|
8390
|
+
iterator.getUint8();
|
|
8391
|
+
subtract += 1;
|
|
8392
|
+
}
|
|
8393
|
+
if (name === "APIC") {
|
|
8394
|
+
const { discardRest } = iterator.planBytes(s - subtract);
|
|
8395
|
+
const mimeType = iterator.readUntilNullTerminator();
|
|
8396
|
+
iterator.getUint16();
|
|
8397
|
+
const description = iterator.readUntilNullTerminator();
|
|
8398
|
+
iterator.discard(1);
|
|
8399
|
+
const data = discardRest();
|
|
8400
|
+
state.images.addImage({
|
|
8401
|
+
data,
|
|
8402
|
+
description,
|
|
8403
|
+
mimeType
|
|
8404
|
+
});
|
|
8405
|
+
} else {
|
|
8406
|
+
const information = iterator.getByteString(s - subtract, true);
|
|
8407
|
+
entries.push({
|
|
8408
|
+
key: name,
|
|
8409
|
+
value: information,
|
|
8410
|
+
trackId: null
|
|
8411
|
+
});
|
|
8412
|
+
}
|
|
8413
|
+
}
|
|
8414
|
+
structure.boxes.push({
|
|
8415
|
+
type: "id3-header",
|
|
8416
|
+
flags,
|
|
8417
|
+
size,
|
|
8418
|
+
versionMajor,
|
|
8419
|
+
versionMinor,
|
|
8420
|
+
metatags: entries
|
|
8421
|
+
});
|
|
8422
|
+
};
|
|
8423
|
+
|
|
8424
|
+
// src/boxes/mp3/id3-v1.ts
|
|
8425
|
+
var parseID3V1 = (iterator) => {
|
|
8426
|
+
if (iterator.bytesRemaining() < 128) {
|
|
8427
|
+
return;
|
|
8428
|
+
}
|
|
8429
|
+
iterator.discard(128);
|
|
8430
|
+
};
|
|
8431
|
+
|
|
8432
|
+
// src/boxes/mp3/parse-mpeg-header.ts
|
|
8433
|
+
function getSamplingFrequency({
|
|
8434
|
+
bits,
|
|
8435
|
+
mpegVersion
|
|
8436
|
+
}) {
|
|
8437
|
+
const samplingTable = {
|
|
8438
|
+
0: { MPEG1: 44100, MPEG2: 22050 },
|
|
8439
|
+
1: { MPEG1: 48000, MPEG2: 24000 },
|
|
8440
|
+
2: { MPEG1: 32000, MPEG2: 16000 },
|
|
8441
|
+
3: { MPEG1: "reserved", MPEG2: "reserved" }
|
|
8442
|
+
};
|
|
8443
|
+
const key = `MPEG${mpegVersion}`;
|
|
8444
|
+
const value = samplingTable[bits][key];
|
|
8445
|
+
if (value === "reserved") {
|
|
8446
|
+
throw new Error("Reserved sampling frequency");
|
|
8447
|
+
}
|
|
8448
|
+
if (!value) {
|
|
8449
|
+
throw new Error("Invalid sampling frequency for MPEG version: " + JSON.stringify({ bits, version: mpegVersion }));
|
|
8450
|
+
}
|
|
8451
|
+
return value;
|
|
8452
|
+
}
|
|
8453
|
+
function getBitrateKB({
|
|
8454
|
+
bits,
|
|
8455
|
+
mpegVersion,
|
|
8456
|
+
level
|
|
8457
|
+
}) {
|
|
8458
|
+
const bitrateTable = {
|
|
8459
|
+
0: {
|
|
8460
|
+
"V1,L1": "free",
|
|
8461
|
+
"V1,L2": "free",
|
|
8462
|
+
"V1,L3": "free",
|
|
8463
|
+
"V2,L1": "free",
|
|
8464
|
+
"V2,L2&L3": "free"
|
|
8465
|
+
},
|
|
8466
|
+
1: { "V1,L1": 32, "V1,L2": 32, "V1,L3": 32, "V2,L1": 32, "V2,L2&L3": 8 },
|
|
8467
|
+
2: {
|
|
8468
|
+
"V1,L1": 64,
|
|
8469
|
+
"V1,L2": 48,
|
|
8470
|
+
"V1,L3": 40,
|
|
8471
|
+
"V2,L1": 48,
|
|
8472
|
+
"V2,L2&L3": 16
|
|
8473
|
+
},
|
|
8474
|
+
3: {
|
|
8475
|
+
"V1,L1": 96,
|
|
8476
|
+
"V1,L2": 56,
|
|
8477
|
+
"V1,L3": 48,
|
|
8478
|
+
"V2,L1": 56,
|
|
8479
|
+
"V2,L2&L3": 24
|
|
8480
|
+
},
|
|
8481
|
+
4: {
|
|
8482
|
+
"V1,L1": 128,
|
|
8483
|
+
"V1,L2": 64,
|
|
8484
|
+
"V1,L3": 56,
|
|
8485
|
+
"V2,L1": 64,
|
|
8486
|
+
"V2,L2&L3": 32
|
|
8487
|
+
},
|
|
8488
|
+
5: {
|
|
8489
|
+
"V1,L1": 160,
|
|
8490
|
+
"V1,L2": 80,
|
|
8491
|
+
"V1,L3": 64,
|
|
8492
|
+
"V2,L1": 80,
|
|
8493
|
+
"V2,L2&L3": 40
|
|
8494
|
+
},
|
|
8495
|
+
6: {
|
|
8496
|
+
"V1,L1": 192,
|
|
8497
|
+
"V1,L2": 96,
|
|
8498
|
+
"V1,L3": 80,
|
|
8499
|
+
"V2,L1": 96,
|
|
8500
|
+
"V2,L2&L3": 48
|
|
8501
|
+
},
|
|
8502
|
+
7: {
|
|
8503
|
+
"V1,L1": 224,
|
|
8504
|
+
"V1,L2": 112,
|
|
8505
|
+
"V1,L3": 96,
|
|
8506
|
+
"V2,L1": 112,
|
|
8507
|
+
"V2,L2&L3": 56
|
|
8508
|
+
},
|
|
8509
|
+
8: {
|
|
8510
|
+
"V1,L1": 256,
|
|
8511
|
+
"V1,L2": 128,
|
|
8512
|
+
"V1,L3": 112,
|
|
8513
|
+
"V2,L1": 128,
|
|
8514
|
+
"V2,L2&L3": 64
|
|
8515
|
+
},
|
|
8516
|
+
9: {
|
|
8517
|
+
"V1,L1": 288,
|
|
8518
|
+
"V1,L2": 160,
|
|
8519
|
+
"V1,L3": 128,
|
|
8520
|
+
"V2,L1": 144,
|
|
8521
|
+
"V2,L2&L3": 80
|
|
8522
|
+
},
|
|
8523
|
+
10: {
|
|
8524
|
+
"V1,L1": 320,
|
|
8525
|
+
"V1,L2": 192,
|
|
8526
|
+
"V1,L3": 160,
|
|
8527
|
+
"V2,L1": 160,
|
|
8528
|
+
"V2,L2&L3": 96
|
|
8529
|
+
},
|
|
8530
|
+
11: {
|
|
8531
|
+
"V1,L1": 352,
|
|
8532
|
+
"V1,L2": 224,
|
|
8533
|
+
"V1,L3": 192,
|
|
8534
|
+
"V2,L1": 176,
|
|
8535
|
+
"V2,L2&L3": 112
|
|
8536
|
+
},
|
|
8537
|
+
12: {
|
|
8538
|
+
"V1,L1": 384,
|
|
8539
|
+
"V1,L2": 256,
|
|
8540
|
+
"V1,L3": 224,
|
|
8541
|
+
"V2,L1": 192,
|
|
8542
|
+
"V2,L2&L3": 128
|
|
8543
|
+
},
|
|
8544
|
+
13: {
|
|
8545
|
+
"V1,L1": 416,
|
|
8546
|
+
"V1,L2": 320,
|
|
8547
|
+
"V1,L3": 256,
|
|
8548
|
+
"V2,L1": 224,
|
|
8549
|
+
"V2,L2&L3": 144
|
|
8550
|
+
},
|
|
8551
|
+
14: {
|
|
8552
|
+
"V1,L1": 448,
|
|
8553
|
+
"V1,L2": 384,
|
|
8554
|
+
"V1,L3": 320,
|
|
8555
|
+
"V2,L1": 256,
|
|
8556
|
+
"V2,L2&L3": 160
|
|
8557
|
+
},
|
|
8558
|
+
15: {
|
|
8559
|
+
"V1,L1": "bad",
|
|
8560
|
+
"V1,L2": "bad",
|
|
8561
|
+
"V1,L3": "bad",
|
|
8562
|
+
"V2,L1": "bad",
|
|
8563
|
+
"V2,L2&L3": "bad"
|
|
8564
|
+
}
|
|
8565
|
+
};
|
|
8566
|
+
let key;
|
|
8567
|
+
if (mpegVersion === 2 && (level === 2 || level === 3)) {
|
|
8568
|
+
key = "V2,L2&L3";
|
|
8569
|
+
} else {
|
|
8570
|
+
key = `V${mpegVersion},L${level}`;
|
|
8571
|
+
}
|
|
8572
|
+
return bitrateTable[bits][key];
|
|
8573
|
+
}
|
|
8574
|
+
var parseMpegHeader = async ({
|
|
8575
|
+
iterator,
|
|
8576
|
+
state
|
|
8577
|
+
}) => {
|
|
8578
|
+
const initialOffset = iterator.counter.getOffset();
|
|
8579
|
+
if (iterator.bytesRemaining() < 32) {
|
|
8580
|
+
return;
|
|
8581
|
+
}
|
|
8582
|
+
iterator.startReadingBits();
|
|
8583
|
+
for (let i = 0;i < 11; i++) {
|
|
8584
|
+
const expectToBe1 = iterator.getBits(1);
|
|
8585
|
+
if (expectToBe1 !== 1) {
|
|
8586
|
+
throw new Error("Expected 1");
|
|
8587
|
+
}
|
|
8588
|
+
}
|
|
8589
|
+
const audioVersionId = iterator.getBits(2);
|
|
8590
|
+
if (audioVersionId !== 3 && audioVersionId !== 2) {
|
|
8591
|
+
throw new Error("Expected MPEG Version 1 or 2");
|
|
8592
|
+
}
|
|
8593
|
+
const mpegVersion = audioVersionId === 3 ? 1 : 2;
|
|
8594
|
+
const layerBits = iterator.getBits(2);
|
|
8595
|
+
if (layerBits === 0) {
|
|
8596
|
+
throw new Error("Expected Layer I, II or III");
|
|
8597
|
+
}
|
|
8598
|
+
const layer = layerBits === 3 ? 1 : layerBits === 2 ? 2 : 3;
|
|
8599
|
+
const protectionBit = iterator.getBits(1);
|
|
8600
|
+
if (protectionBit !== 1) {
|
|
8601
|
+
throw new Error("Does not support CRC yet");
|
|
8602
|
+
}
|
|
8603
|
+
const bitrateIndex = iterator.getBits(4);
|
|
8604
|
+
const bitrateKbit = getBitrateKB({
|
|
8605
|
+
bits: bitrateIndex,
|
|
8606
|
+
mpegVersion,
|
|
8607
|
+
level: audioVersionId
|
|
8608
|
+
});
|
|
8609
|
+
if (bitrateKbit === "bad") {
|
|
8610
|
+
throw new Error("Invalid bitrate");
|
|
8611
|
+
}
|
|
8612
|
+
if (bitrateKbit === "free") {
|
|
8613
|
+
throw new Error("Free bitrate not supported");
|
|
8614
|
+
}
|
|
8615
|
+
const samplingFrequencyIndex = iterator.getBits(2);
|
|
8616
|
+
const sampleRate = getSamplingFrequency({
|
|
8617
|
+
bits: samplingFrequencyIndex,
|
|
8618
|
+
mpegVersion
|
|
8619
|
+
});
|
|
8620
|
+
const padding = Boolean(iterator.getBits(1));
|
|
8621
|
+
iterator.getBits(1);
|
|
8622
|
+
const channelMode = iterator.getBits(2);
|
|
8623
|
+
iterator.getBits(2);
|
|
8624
|
+
iterator.getBits(1);
|
|
8625
|
+
iterator.getBits(1);
|
|
8626
|
+
iterator.getBits(2);
|
|
8627
|
+
const numberOfChannels = channelMode === 3 ? 1 : 2;
|
|
8628
|
+
const samplesPerFrame = getSamplesPerMpegFrame({ mpegVersion, layer });
|
|
8629
|
+
const frameLength = getMpegFrameLength({
|
|
8630
|
+
bitrateKbit,
|
|
8631
|
+
padding,
|
|
8632
|
+
samplesPerFrame,
|
|
8633
|
+
samplingFrequency: sampleRate,
|
|
8634
|
+
layer
|
|
8635
|
+
});
|
|
8636
|
+
iterator.stopReadingBits();
|
|
8637
|
+
const offsetNow = iterator.counter.getOffset();
|
|
8638
|
+
iterator.counter.decrement(offsetNow - initialOffset);
|
|
8639
|
+
const data = iterator.getSlice(frameLength);
|
|
8640
|
+
if (state.callbacks.tracks.getTracks().length === 0) {
|
|
8641
|
+
state.mp3Info.setMp3Info({
|
|
8642
|
+
layer,
|
|
8643
|
+
mpegVersion,
|
|
8644
|
+
sampleRate,
|
|
8645
|
+
bitrateKbit,
|
|
8646
|
+
startOfMpegStream: initialOffset
|
|
8647
|
+
});
|
|
8648
|
+
await registerTrack({
|
|
8649
|
+
container: "mp3",
|
|
8650
|
+
state,
|
|
8651
|
+
track: {
|
|
8652
|
+
type: "audio",
|
|
8653
|
+
codec: "mp3",
|
|
8654
|
+
codecPrivate: null,
|
|
8655
|
+
codecWithoutConfig: "mp3",
|
|
8656
|
+
description: undefined,
|
|
8657
|
+
numberOfChannels,
|
|
8658
|
+
sampleRate,
|
|
8659
|
+
timescale: 1e6,
|
|
8660
|
+
trackId: 0,
|
|
8661
|
+
trakBox: null
|
|
8662
|
+
}
|
|
8663
|
+
});
|
|
8664
|
+
state.callbacks.tracks.setIsDone();
|
|
8665
|
+
}
|
|
8666
|
+
const mp3Info = state.mp3Info.getMp3Info();
|
|
8667
|
+
if (!mp3Info) {
|
|
8668
|
+
throw new Error("No MP3 info by now");
|
|
8669
|
+
}
|
|
8670
|
+
const avgLength = getAverageMpegFrameLength({
|
|
8671
|
+
bitrateKbit,
|
|
8672
|
+
layer,
|
|
8673
|
+
samplesPerFrame,
|
|
8674
|
+
samplingFrequency: sampleRate
|
|
8675
|
+
});
|
|
8676
|
+
const nthFrame = Math.round((initialOffset - mp3Info.startOfMpegStream) / avgLength);
|
|
8677
|
+
const durationInSeconds = samplesPerFrame / sampleRate;
|
|
8678
|
+
const timeInSeconds = nthFrame * samplesPerFrame / sampleRate;
|
|
8679
|
+
const timestamp = Math.round(timeInSeconds * 1e6);
|
|
8680
|
+
const duration2 = Math.round(durationInSeconds * 1e6);
|
|
8681
|
+
await state.callbacks.onAudioSample(0, {
|
|
8682
|
+
data,
|
|
8683
|
+
cts: timestamp,
|
|
8684
|
+
dts: timestamp,
|
|
8685
|
+
duration: duration2,
|
|
8686
|
+
offset: initialOffset,
|
|
8687
|
+
timescale: 1e6,
|
|
8688
|
+
timestamp,
|
|
8689
|
+
trackId: 0,
|
|
8690
|
+
type: "key"
|
|
8691
|
+
});
|
|
8692
|
+
};
|
|
8693
|
+
|
|
8694
|
+
// src/boxes/mp3/parse-mp3.ts
|
|
8695
|
+
var parseMp3 = async ({
|
|
8696
|
+
iterator,
|
|
8697
|
+
structure,
|
|
8698
|
+
state
|
|
8699
|
+
}) => {
|
|
8700
|
+
const continueParsing = () => {
|
|
8701
|
+
return parseMp3({ iterator, structure, state });
|
|
8702
|
+
};
|
|
8703
|
+
if (iterator.bytesRemaining() === 0) {
|
|
8704
|
+
return Promise.resolve({
|
|
8705
|
+
status: "done"
|
|
8706
|
+
});
|
|
8707
|
+
}
|
|
8708
|
+
if (iterator.bytesRemaining() < 3) {
|
|
8709
|
+
return {
|
|
8710
|
+
status: "incomplete",
|
|
8711
|
+
skipTo: null,
|
|
8712
|
+
continueParsing
|
|
8713
|
+
};
|
|
8714
|
+
}
|
|
8715
|
+
const { returnToCheckpoint } = iterator.startCheckpoint();
|
|
8716
|
+
const bytes = iterator.getSlice(3);
|
|
8717
|
+
returnToCheckpoint();
|
|
8718
|
+
if (bytes[0] === 84 && bytes[1] === 65 && bytes[2] === 71) {
|
|
8719
|
+
parseID3V1(iterator);
|
|
8720
|
+
return {
|
|
8721
|
+
status: "incomplete",
|
|
8722
|
+
continueParsing,
|
|
8723
|
+
skipTo: null
|
|
8724
|
+
};
|
|
8725
|
+
}
|
|
8726
|
+
if (bytes[0] === 73 && bytes[1] === 68 && bytes[2] === 51) {
|
|
8727
|
+
parseId3({ iterator, structure, state });
|
|
8728
|
+
return {
|
|
8729
|
+
status: "incomplete",
|
|
8730
|
+
continueParsing,
|
|
8731
|
+
skipTo: null
|
|
8732
|
+
};
|
|
8733
|
+
}
|
|
8734
|
+
if (bytes[0] === 255) {
|
|
8735
|
+
await parseMpegHeader({
|
|
8736
|
+
iterator,
|
|
8737
|
+
state
|
|
8738
|
+
});
|
|
8739
|
+
return {
|
|
8740
|
+
status: "incomplete",
|
|
8741
|
+
continueParsing,
|
|
8742
|
+
skipTo: null
|
|
8743
|
+
};
|
|
8744
|
+
}
|
|
8745
|
+
throw new Error("Unknown MP3 header ");
|
|
8746
|
+
};
|
|
8747
|
+
|
|
8748
|
+
// src/boxes/riff/continue-after-riff-result.ts
|
|
8749
|
+
var continueAfterRiffBoxResult = ({
|
|
8750
|
+
result,
|
|
8751
|
+
structure,
|
|
8752
|
+
iterator,
|
|
8753
|
+
maxOffset,
|
|
8754
|
+
state: options,
|
|
8755
|
+
fields
|
|
8005
8756
|
}) => {
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8010
|
-
|
|
8011
|
-
|
|
8012
|
-
|
|
8013
|
-
|
|
8014
|
-
|
|
8015
|
-
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8757
|
+
if (result.type === "incomplete") {
|
|
8758
|
+
return Promise.resolve({
|
|
8759
|
+
status: "incomplete",
|
|
8760
|
+
async continueParsing() {
|
|
8761
|
+
return Promise.resolve(continueAfterRiffBoxResult({
|
|
8762
|
+
result: await result.continueParsing(),
|
|
8763
|
+
structure,
|
|
8764
|
+
iterator,
|
|
8765
|
+
maxOffset,
|
|
8766
|
+
state: options,
|
|
8767
|
+
fields
|
|
8768
|
+
}));
|
|
8769
|
+
},
|
|
8770
|
+
segments: structure,
|
|
8771
|
+
skipTo: null
|
|
8772
|
+
});
|
|
8773
|
+
}
|
|
8774
|
+
if (result.type === "complete" && result.box) {
|
|
8775
|
+
structure.boxes.push(result.box);
|
|
8776
|
+
}
|
|
8777
|
+
return parseRiffBody({
|
|
8778
|
+
iterator,
|
|
8779
|
+
maxOffset,
|
|
8780
|
+
state: options,
|
|
8781
|
+
structure,
|
|
8782
|
+
fields
|
|
8783
|
+
});
|
|
8032
8784
|
};
|
|
8033
8785
|
|
|
8034
8786
|
// src/boxes/riff/is-movi.ts
|
|
@@ -8508,7 +9260,8 @@ var parseIsft = ({
|
|
|
8508
9260
|
var parseListBox = async ({
|
|
8509
9261
|
iterator,
|
|
8510
9262
|
size,
|
|
8511
|
-
state
|
|
9263
|
+
state,
|
|
9264
|
+
fields
|
|
8512
9265
|
}) => {
|
|
8513
9266
|
const counter = iterator.counter.getOffset();
|
|
8514
9267
|
const listType = iterator.getByteString(4, false);
|
|
@@ -8523,7 +9276,8 @@ var parseListBox = async ({
|
|
|
8523
9276
|
structure,
|
|
8524
9277
|
iterator,
|
|
8525
9278
|
maxOffset: counter + size,
|
|
8526
|
-
state
|
|
9279
|
+
state,
|
|
9280
|
+
fields
|
|
8527
9281
|
});
|
|
8528
9282
|
if (result.status === "incomplete") {
|
|
8529
9283
|
throw new Error(`Should only parse complete boxes (${listType})`);
|
|
@@ -8663,13 +9417,14 @@ var parseRiffBox = ({
|
|
|
8663
9417
|
size,
|
|
8664
9418
|
id,
|
|
8665
9419
|
boxes,
|
|
8666
|
-
state
|
|
9420
|
+
state,
|
|
9421
|
+
fields
|
|
8667
9422
|
}) => {
|
|
8668
9423
|
if (id === "fmt") {
|
|
8669
9424
|
return Promise.resolve(parseFmtBox({ iterator, boxes, size }));
|
|
8670
9425
|
}
|
|
8671
9426
|
if (id === "LIST") {
|
|
8672
|
-
return parseListBox({ iterator, size, state });
|
|
9427
|
+
return parseListBox({ iterator, size, state, fields });
|
|
8673
9428
|
}
|
|
8674
9429
|
if (id === "ISFT") {
|
|
8675
9430
|
return Promise.resolve(parseIsft({ iterator, size }));
|
|
@@ -8696,13 +9451,14 @@ var parseRiffBox = ({
|
|
|
8696
9451
|
var expectRiffBox = async ({
|
|
8697
9452
|
iterator,
|
|
8698
9453
|
state,
|
|
8699
|
-
structure
|
|
9454
|
+
structure,
|
|
9455
|
+
fields
|
|
8700
9456
|
}) => {
|
|
8701
9457
|
if (iterator.bytesRemaining() < 16) {
|
|
8702
9458
|
return {
|
|
8703
9459
|
type: "incomplete",
|
|
8704
9460
|
continueParsing() {
|
|
8705
|
-
return expectRiffBox({ structure, iterator, state });
|
|
9461
|
+
return expectRiffBox({ structure, iterator, state, fields });
|
|
8706
9462
|
}
|
|
8707
9463
|
};
|
|
8708
9464
|
}
|
|
@@ -8722,7 +9478,7 @@ var expectRiffBox = async ({
|
|
|
8722
9478
|
return {
|
|
8723
9479
|
type: "incomplete",
|
|
8724
9480
|
continueParsing: () => {
|
|
8725
|
-
return expectRiffBox({ structure, iterator, state });
|
|
9481
|
+
return expectRiffBox({ structure, iterator, state, fields });
|
|
8726
9482
|
}
|
|
8727
9483
|
};
|
|
8728
9484
|
}
|
|
@@ -8733,52 +9489,27 @@ var expectRiffBox = async ({
|
|
|
8733
9489
|
iterator,
|
|
8734
9490
|
size: ckSize,
|
|
8735
9491
|
boxes: structure.boxes,
|
|
8736
|
-
state
|
|
9492
|
+
state,
|
|
9493
|
+
fields
|
|
8737
9494
|
}),
|
|
8738
9495
|
skipTo: null
|
|
8739
9496
|
};
|
|
8740
9497
|
};
|
|
8741
9498
|
|
|
8742
|
-
// src/boxes/riff/parse-
|
|
8743
|
-
var continueAfterRiffBoxResult = ({
|
|
8744
|
-
result,
|
|
8745
|
-
structure,
|
|
8746
|
-
iterator,
|
|
8747
|
-
maxOffset,
|
|
8748
|
-
state: options
|
|
8749
|
-
}) => {
|
|
8750
|
-
if (result.type === "incomplete") {
|
|
8751
|
-
return Promise.resolve({
|
|
8752
|
-
status: "incomplete",
|
|
8753
|
-
async continueParsing() {
|
|
8754
|
-
return Promise.resolve(continueAfterRiffBoxResult({
|
|
8755
|
-
result: await result.continueParsing(),
|
|
8756
|
-
structure,
|
|
8757
|
-
iterator,
|
|
8758
|
-
maxOffset,
|
|
8759
|
-
state: options
|
|
8760
|
-
}));
|
|
8761
|
-
},
|
|
8762
|
-
segments: structure,
|
|
8763
|
-
skipTo: null
|
|
8764
|
-
});
|
|
8765
|
-
}
|
|
8766
|
-
if (result.type === "complete" && result.box) {
|
|
8767
|
-
structure.boxes.push(result.box);
|
|
8768
|
-
}
|
|
8769
|
-
return parseRiffBody({ iterator, maxOffset, state: options, structure });
|
|
8770
|
-
};
|
|
9499
|
+
// src/boxes/riff/parse-riff-body.ts
|
|
8771
9500
|
var parseRiffBody = async ({
|
|
8772
9501
|
iterator,
|
|
8773
9502
|
structure,
|
|
8774
9503
|
maxOffset,
|
|
8775
|
-
state
|
|
9504
|
+
state,
|
|
9505
|
+
fields
|
|
8776
9506
|
}) => {
|
|
8777
|
-
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() < maxOffset) {
|
|
9507
|
+
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() < maxOffset && !hasAllInfo({ fields, state })) {
|
|
8778
9508
|
const result = await expectRiffBox({
|
|
8779
9509
|
iterator,
|
|
8780
9510
|
state,
|
|
8781
|
-
structure
|
|
9511
|
+
structure,
|
|
9512
|
+
fields
|
|
8782
9513
|
});
|
|
8783
9514
|
if (result.type === "complete" && result.skipTo !== null) {
|
|
8784
9515
|
return {
|
|
@@ -8790,7 +9521,8 @@ var parseRiffBody = async ({
|
|
|
8790
9521
|
maxOffset,
|
|
8791
9522
|
state,
|
|
8792
9523
|
result,
|
|
8793
|
-
structure
|
|
9524
|
+
structure,
|
|
9525
|
+
fields
|
|
8794
9526
|
}));
|
|
8795
9527
|
}
|
|
8796
9528
|
};
|
|
@@ -8804,7 +9536,8 @@ var parseRiffBody = async ({
|
|
|
8804
9536
|
maxOffset,
|
|
8805
9537
|
state,
|
|
8806
9538
|
result: await result.continueParsing(),
|
|
8807
|
-
structure
|
|
9539
|
+
structure,
|
|
9540
|
+
fields
|
|
8808
9541
|
}));
|
|
8809
9542
|
},
|
|
8810
9543
|
skipTo: null
|
|
@@ -8859,6 +9592,8 @@ var parseRiffBody = async ({
|
|
|
8859
9592
|
status: "done"
|
|
8860
9593
|
};
|
|
8861
9594
|
};
|
|
9595
|
+
|
|
9596
|
+
// src/boxes/riff/parse-box.ts
|
|
8862
9597
|
var parseRiff = ({
|
|
8863
9598
|
iterator,
|
|
8864
9599
|
state,
|
|
@@ -8888,7 +9623,8 @@ var parseRiff = ({
|
|
|
8888
9623
|
iterator,
|
|
8889
9624
|
maxOffset: Infinity,
|
|
8890
9625
|
state,
|
|
8891
|
-
structure
|
|
9626
|
+
structure,
|
|
9627
|
+
fields
|
|
8892
9628
|
});
|
|
8893
9629
|
};
|
|
8894
9630
|
|
|
@@ -9605,57 +10341,46 @@ var parseTransportStream = async ({
|
|
|
9605
10341
|
structure
|
|
9606
10342
|
});
|
|
9607
10343
|
return Promise.resolve({
|
|
9608
|
-
status: "done"
|
|
9609
|
-
segments: structure
|
|
10344
|
+
status: "done"
|
|
9610
10345
|
});
|
|
9611
10346
|
}
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
fields,
|
|
9615
|
-
state
|
|
9616
|
-
})) {
|
|
9617
|
-
break;
|
|
9618
|
-
}
|
|
9619
|
-
if (iterator.bytesRemaining() < 188) {
|
|
9620
|
-
return Promise.resolve({
|
|
9621
|
-
status: "incomplete",
|
|
9622
|
-
segments: structure,
|
|
9623
|
-
skipTo: null,
|
|
9624
|
-
continueParsing: () => {
|
|
9625
|
-
return parseTransportStream({
|
|
9626
|
-
iterator,
|
|
9627
|
-
state,
|
|
9628
|
-
streamBuffers,
|
|
9629
|
-
fields,
|
|
9630
|
-
nextPesHeaderStore
|
|
9631
|
-
});
|
|
9632
|
-
}
|
|
9633
|
-
});
|
|
9634
|
-
}
|
|
9635
|
-
const packet = await parsePacket({
|
|
10347
|
+
const continueParsing = () => {
|
|
10348
|
+
return parseTransportStream({
|
|
9636
10349
|
iterator,
|
|
9637
|
-
|
|
10350
|
+
state,
|
|
9638
10351
|
streamBuffers,
|
|
9639
|
-
|
|
10352
|
+
fields,
|
|
9640
10353
|
nextPesHeaderStore
|
|
9641
10354
|
});
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9645
|
-
|
|
10355
|
+
};
|
|
10356
|
+
if (hasAllInfo({
|
|
10357
|
+
fields,
|
|
10358
|
+
state
|
|
10359
|
+
})) {
|
|
10360
|
+
return Promise.resolve({
|
|
10361
|
+
status: "done"
|
|
10362
|
+
});
|
|
10363
|
+
}
|
|
10364
|
+
if (iterator.bytesRemaining() < 188) {
|
|
10365
|
+
return Promise.resolve({
|
|
10366
|
+
status: "incomplete",
|
|
10367
|
+
continueParsing,
|
|
10368
|
+
skipTo: null
|
|
10369
|
+
});
|
|
10370
|
+
}
|
|
10371
|
+
const packet = await parsePacket({
|
|
10372
|
+
iterator,
|
|
10373
|
+
structure,
|
|
10374
|
+
streamBuffers,
|
|
10375
|
+
parserState: state,
|
|
10376
|
+
nextPesHeaderStore
|
|
10377
|
+
});
|
|
10378
|
+
if (packet) {
|
|
10379
|
+
structure.boxes.push(packet);
|
|
9646
10380
|
}
|
|
9647
10381
|
return Promise.resolve({
|
|
9648
|
-
segments: structure,
|
|
9649
10382
|
status: "incomplete",
|
|
9650
|
-
continueParsing
|
|
9651
|
-
return parseTransportStream({
|
|
9652
|
-
iterator,
|
|
9653
|
-
state,
|
|
9654
|
-
streamBuffers,
|
|
9655
|
-
fields,
|
|
9656
|
-
nextPesHeaderStore
|
|
9657
|
-
});
|
|
9658
|
-
},
|
|
10383
|
+
continueParsing,
|
|
9659
10384
|
skipTo: null
|
|
9660
10385
|
});
|
|
9661
10386
|
};
|
|
@@ -9733,7 +10458,6 @@ var parseVideo = ({
|
|
|
9733
10458
|
allowIncompleteBoxes: true,
|
|
9734
10459
|
initialBoxes,
|
|
9735
10460
|
state,
|
|
9736
|
-
continueMdat: false,
|
|
9737
10461
|
signal,
|
|
9738
10462
|
logLevel,
|
|
9739
10463
|
fields
|
|
@@ -9762,13 +10486,12 @@ var parseVideo = ({
|
|
|
9762
10486
|
});
|
|
9763
10487
|
}
|
|
9764
10488
|
if (fileType.type === "mp3") {
|
|
9765
|
-
|
|
9766
|
-
|
|
9767
|
-
|
|
9768
|
-
|
|
9769
|
-
|
|
9770
|
-
|
|
9771
|
-
}));
|
|
10489
|
+
const structure = {
|
|
10490
|
+
boxes: [],
|
|
10491
|
+
type: "mp3"
|
|
10492
|
+
};
|
|
10493
|
+
state.structure.setStructure(structure);
|
|
10494
|
+
return parseMp3({ iterator, structure, state });
|
|
9772
10495
|
}
|
|
9773
10496
|
if (fileType.type === "wav") {
|
|
9774
10497
|
return Promise.reject(new IsAnUnsupportedAudioTypeError({
|
|
@@ -9825,6 +10548,53 @@ var parseVideo = ({
|
|
|
9825
10548
|
return Promise.reject(new Error("Unknown video format " + fileType));
|
|
9826
10549
|
};
|
|
9827
10550
|
|
|
10551
|
+
// src/throttled-progress.ts
|
|
10552
|
+
var throttledStateUpdate = ({
|
|
10553
|
+
updateFn,
|
|
10554
|
+
everyMilliseconds,
|
|
10555
|
+
signal
|
|
10556
|
+
}) => {
|
|
10557
|
+
let currentState = {
|
|
10558
|
+
bytes: 0,
|
|
10559
|
+
percentage: null,
|
|
10560
|
+
totalBytes: null
|
|
10561
|
+
};
|
|
10562
|
+
if (!updateFn) {
|
|
10563
|
+
return {
|
|
10564
|
+
get: () => currentState,
|
|
10565
|
+
update: null,
|
|
10566
|
+
stopAndGetLastProgress: () => {
|
|
10567
|
+
}
|
|
10568
|
+
};
|
|
10569
|
+
}
|
|
10570
|
+
let lastUpdated = null;
|
|
10571
|
+
const callUpdateIfChanged = () => {
|
|
10572
|
+
if (currentState === lastUpdated) {
|
|
10573
|
+
return;
|
|
10574
|
+
}
|
|
10575
|
+
updateFn(currentState);
|
|
10576
|
+
lastUpdated = currentState;
|
|
10577
|
+
};
|
|
10578
|
+
const interval = setInterval(() => {
|
|
10579
|
+
callUpdateIfChanged();
|
|
10580
|
+
}, everyMilliseconds);
|
|
10581
|
+
const onAbort = () => {
|
|
10582
|
+
clearInterval(interval);
|
|
10583
|
+
};
|
|
10584
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
10585
|
+
return {
|
|
10586
|
+
get: () => currentState,
|
|
10587
|
+
update: (fn) => {
|
|
10588
|
+
currentState = fn(currentState);
|
|
10589
|
+
},
|
|
10590
|
+
stopAndGetLastProgress: () => {
|
|
10591
|
+
clearInterval(interval);
|
|
10592
|
+
signal?.removeEventListener("abort", onAbort);
|
|
10593
|
+
return currentState;
|
|
10594
|
+
}
|
|
10595
|
+
};
|
|
10596
|
+
};
|
|
10597
|
+
|
|
9828
10598
|
// src/parse-media.ts
|
|
9829
10599
|
var parseMedia = async function({
|
|
9830
10600
|
src,
|
|
@@ -9834,10 +10604,10 @@ var parseMedia = async function({
|
|
|
9834
10604
|
onVideoTrack,
|
|
9835
10605
|
signal,
|
|
9836
10606
|
logLevel = "info",
|
|
9837
|
-
onParseProgress,
|
|
10607
|
+
onParseProgress: onParseProgressDoNotCallDirectly,
|
|
10608
|
+
progressIntervalInMs,
|
|
9838
10609
|
...more
|
|
9839
10610
|
}) {
|
|
9840
|
-
let iterator = null;
|
|
9841
10611
|
let parseResult = null;
|
|
9842
10612
|
const fieldsInReturnValue = _fieldsInReturnValue ?? {};
|
|
9843
10613
|
const fields = getFieldsFromCallback({
|
|
@@ -9851,6 +10621,7 @@ var parseMedia = async function({
|
|
|
9851
10621
|
contentType,
|
|
9852
10622
|
supportsContentRange: readerSupportsContentRange
|
|
9853
10623
|
} = await readerInterface.read(src, null, signal);
|
|
10624
|
+
const iterator = getArrayBufferIterator(new Uint8Array([]), contentLength ?? 1e9);
|
|
9854
10625
|
const supportsContentRange = readerSupportsContentRange && !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.DISABLE_CONTENT_RANGE === "true");
|
|
9855
10626
|
const state = makeParserState({
|
|
9856
10627
|
hasAudioTrackHandlers: Boolean(onAudioTrack),
|
|
@@ -9860,11 +10631,18 @@ var parseMedia = async function({
|
|
|
9860
10631
|
fields,
|
|
9861
10632
|
onAudioTrack: onAudioTrack ?? null,
|
|
9862
10633
|
onVideoTrack: onVideoTrack ?? null,
|
|
9863
|
-
supportsContentRange
|
|
10634
|
+
supportsContentRange,
|
|
10635
|
+
contentLength
|
|
9864
10636
|
});
|
|
9865
10637
|
let currentReader = reader;
|
|
9866
10638
|
const returnValue = {};
|
|
9867
10639
|
const moreFields = more;
|
|
10640
|
+
const throttledState = throttledStateUpdate({
|
|
10641
|
+
updateFn: onParseProgressDoNotCallDirectly ?? null,
|
|
10642
|
+
everyMilliseconds: progressIntervalInMs ?? 100,
|
|
10643
|
+
signal,
|
|
10644
|
+
totalBytes: contentLength
|
|
10645
|
+
});
|
|
9868
10646
|
const triggerInfoEmit = () => {
|
|
9869
10647
|
const availableInfo = getAvailableInfo({
|
|
9870
10648
|
fieldsToFetch: fields,
|
|
@@ -9882,38 +10660,44 @@ var parseMedia = async function({
|
|
|
9882
10660
|
mimeType: contentType
|
|
9883
10661
|
});
|
|
9884
10662
|
};
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
10663
|
+
const checkIfDone = () => {
|
|
10664
|
+
if (hasAllInfo({
|
|
10665
|
+
fields,
|
|
10666
|
+
state
|
|
10667
|
+
})) {
|
|
10668
|
+
Log.verbose(logLevel, "Got all info, skipping to the end.");
|
|
10669
|
+
if (contentLength !== null) {
|
|
10670
|
+
state.increaseSkippedBytes(contentLength - iterator.counter.getOffset());
|
|
9890
10671
|
}
|
|
10672
|
+
return true;
|
|
10673
|
+
}
|
|
10674
|
+
return false;
|
|
10675
|
+
};
|
|
10676
|
+
triggerInfoEmit();
|
|
10677
|
+
let didProgress = false;
|
|
10678
|
+
while (!checkIfDone() && (parseResult === null || parseResult.status === "incomplete")) {
|
|
10679
|
+
if (signal?.aborted) {
|
|
10680
|
+
throw new Error("Aborted");
|
|
10681
|
+
}
|
|
10682
|
+
const offsetBefore = iterator.counter.getOffset();
|
|
10683
|
+
const fetchMoreData = async () => {
|
|
9891
10684
|
const result = await currentReader.reader.read();
|
|
9892
|
-
if (
|
|
9893
|
-
|
|
9894
|
-
iterator.addData(result.value);
|
|
9895
|
-
}
|
|
9896
|
-
} else {
|
|
9897
|
-
if (result.done) {
|
|
9898
|
-
throw new Error("Unexpectedly reached EOF");
|
|
9899
|
-
}
|
|
9900
|
-
iterator = getArrayBufferIterator(result.value, contentLength ?? 1e9);
|
|
9901
|
-
}
|
|
9902
|
-
if (iterator.bytesRemaining() >= 0) {
|
|
9903
|
-
break;
|
|
9904
|
-
}
|
|
9905
|
-
if (result.done) {
|
|
9906
|
-
break;
|
|
10685
|
+
if (result.value) {
|
|
10686
|
+
iterator.addData(result.value);
|
|
9907
10687
|
}
|
|
10688
|
+
};
|
|
10689
|
+
while (iterator.bytesRemaining() < 0) {
|
|
10690
|
+
await fetchMoreData();
|
|
9908
10691
|
}
|
|
9909
|
-
|
|
9910
|
-
|
|
10692
|
+
const hasBigBuffer = iterator.bytesRemaining() > 1e5;
|
|
10693
|
+
if (!didProgress || !hasBigBuffer) {
|
|
10694
|
+
await fetchMoreData();
|
|
9911
10695
|
}
|
|
9912
|
-
|
|
10696
|
+
throttledState.update?.(() => ({
|
|
9913
10697
|
bytes: iterator.counter.getOffset(),
|
|
9914
10698
|
percentage: contentLength ? iterator.counter.getOffset() / contentLength : null,
|
|
9915
10699
|
totalBytes: contentLength
|
|
9916
|
-
});
|
|
10700
|
+
}));
|
|
9917
10701
|
triggerInfoEmit();
|
|
9918
10702
|
if (parseResult && parseResult.status === "incomplete") {
|
|
9919
10703
|
Log.trace(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset());
|
|
@@ -9933,16 +10717,6 @@ var parseMedia = async function({
|
|
|
9933
10717
|
if (parseResult.status === "incomplete" && parseResult.skipTo !== null) {
|
|
9934
10718
|
state.increaseSkippedBytes(parseResult.skipTo - iterator.counter.getOffset());
|
|
9935
10719
|
}
|
|
9936
|
-
if (hasAllInfo({
|
|
9937
|
-
fields,
|
|
9938
|
-
state
|
|
9939
|
-
})) {
|
|
9940
|
-
Log.verbose(logLevel, "Got all info, skipping to the end.");
|
|
9941
|
-
if (contentLength !== null) {
|
|
9942
|
-
state.increaseSkippedBytes(contentLength - iterator.counter.getOffset());
|
|
9943
|
-
}
|
|
9944
|
-
break;
|
|
9945
|
-
}
|
|
9946
10720
|
if (parseResult.status === "incomplete" && parseResult.skipTo !== null) {
|
|
9947
10721
|
if (!supportsContentRange) {
|
|
9948
10722
|
throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
|
|
@@ -9957,16 +10731,16 @@ var parseMedia = async function({
|
|
|
9957
10731
|
currentReader = newReader;
|
|
9958
10732
|
iterator.skipTo(parseResult.skipTo, true);
|
|
9959
10733
|
}
|
|
10734
|
+
didProgress = iterator.counter.getOffset() > offsetBefore;
|
|
9960
10735
|
}
|
|
9961
10736
|
Log.verbose(logLevel, "Finished parsing file");
|
|
9962
|
-
const hasInfo = Object.keys(fields).reduce((acc, key) => {
|
|
9963
|
-
if (fields?.[key]) {
|
|
9964
|
-
acc[key] = true;
|
|
9965
|
-
}
|
|
9966
|
-
return acc;
|
|
9967
|
-
}, {});
|
|
9968
10737
|
emitAvailableInfo({
|
|
9969
|
-
hasInfo,
|
|
10738
|
+
hasInfo: Object.keys(fields).reduce((acc, key) => {
|
|
10739
|
+
if (fields?.[key]) {
|
|
10740
|
+
acc[key] = true;
|
|
10741
|
+
}
|
|
10742
|
+
return acc;
|
|
10743
|
+
}, {}),
|
|
9970
10744
|
callbacks: moreFields,
|
|
9971
10745
|
fieldsInReturnValue,
|
|
9972
10746
|
parseResult,
|
|
@@ -9982,7 +10756,7 @@ var parseMedia = async function({
|
|
|
9982
10756
|
return returnValue;
|
|
9983
10757
|
};
|
|
9984
10758
|
// src/version.ts
|
|
9985
|
-
var VERSION = "4.0.
|
|
10759
|
+
var VERSION = "4.0.249";
|
|
9986
10760
|
|
|
9987
10761
|
// src/index.ts
|
|
9988
10762
|
var MediaParserInternals = {
|