@remotion/media-parser 4.0.210 → 4.0.212
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/iso-base-media/mdat/mdat.d.ts +12 -4
- package/dist/boxes/iso-base-media/mdat/mdat.js +13 -3
- package/dist/boxes/iso-base-media/process-box.js +46 -7
- package/dist/boxes/iso-base-media/traversal.d.ts +2 -7
- package/dist/boxes/iso-base-media/traversal.js +5 -15
- package/dist/boxes/webm/color.js +29 -22
- package/dist/boxes/webm/get-track.js +1 -16
- package/dist/boxes/webm/segments/parse-children.js +6 -0
- package/dist/buffer-iterator.d.ts +4 -1
- package/dist/buffer-iterator.js +31 -5
- package/dist/create/cluster.d.ts +8 -2
- package/dist/create/cluster.js +3 -2
- package/dist/create/create-media.d.ts +1 -1
- package/dist/create/create-media.js +44 -27
- package/dist/create/matroska-cues.d.ts +1 -1
- package/dist/create/matroska-cues.js +4 -5
- package/dist/create/matroska-trackentry.js +0 -8
- package/dist/esm/from-fetch.mjs +41 -6
- package/dist/esm/from-node.mjs +2 -1
- package/dist/esm/from-web-file.mjs +2 -1
- package/dist/esm/index.mjs +239 -106
- package/dist/get-audio-codec.d.ts +1 -1
- package/dist/get-audio-codec.js +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/parse-media.js +34 -25
- package/dist/parser-context.d.ts +1 -0
- package/dist/readers/from-fetch.d.ts +12 -0
- package/dist/readers/from-fetch.js +59 -13
- package/dist/readers/from-node.js +1 -0
- package/dist/readers/from-web-file.js +1 -0
- package/dist/readers/reader.d.ts +1 -0
- package/dist/traversal.d.ts +21 -0
- package/dist/traversal.js +158 -1
- package/package.json +2 -2
- package/dist/av1-codec-string.d.ts +0 -3
- package/dist/av1-codec-string.js +0 -91
- package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
- package/dist/boxes/iso-base-media/ftype.js +0 -31
- package/dist/boxes/iso-base-media/stsd/avcc-hvcc.d.ts +0 -20
- package/dist/boxes/iso-base-media/stsd/avcc-hvcc.js +0 -73
- package/dist/boxes/iso-base-media/stts/stts.d.ts +0 -15
- package/dist/boxes/iso-base-media/stts/stts.js +0 -35
- package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.d.ts +0 -14
- package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.js +0 -67
- package/dist/boxes/webm/bitstream/av1/bitstream-frame.d.ts +0 -11
- package/dist/boxes/webm/bitstream/av1/bitstream-frame.js +0 -14
- package/dist/boxes/webm/bitstream/av1/chroma-sample-position.d.ts +0 -6
- package/dist/boxes/webm/bitstream/av1/chroma-sample-position.js +0 -9
- package/dist/boxes/webm/bitstream/av1/color-config.d.ts +0 -16
- package/dist/boxes/webm/bitstream/av1/color-config.js +0 -103
- package/dist/boxes/webm/bitstream/av1/color-primaries.d.ts +0 -14
- package/dist/boxes/webm/bitstream/av1/color-primaries.js +0 -17
- package/dist/boxes/webm/bitstream/av1/decoder-model-info.d.ts +0 -9
- package/dist/boxes/webm/bitstream/av1/decoder-model-info.js +0 -17
- package/dist/boxes/webm/bitstream/av1/frame.d.ts +0 -0
- package/dist/boxes/webm/bitstream/av1/frame.js +0 -1
- package/dist/boxes/webm/bitstream/av1/header-segment.d.ts +0 -51
- package/dist/boxes/webm/bitstream/av1/header-segment.js +0 -183
- package/dist/boxes/webm/bitstream/av1/matrix-coefficients.d.ts +0 -17
- package/dist/boxes/webm/bitstream/av1/matrix-coefficients.js +0 -20
- package/dist/boxes/webm/bitstream/av1/operating-parameters-info.d.ts +0 -10
- package/dist/boxes/webm/bitstream/av1/operating-parameters-info.js +0 -15
- package/dist/boxes/webm/bitstream/av1/temporal-point-info.d.ts +0 -5
- package/dist/boxes/webm/bitstream/av1/temporal-point-info.js +0 -8
- package/dist/boxes/webm/bitstream/av1/timing-info.d.ts +0 -8
- package/dist/boxes/webm/bitstream/av1/timing-info.js +0 -20
- package/dist/boxes/webm/bitstream/av1/transfer-characteristics.d.ts +0 -21
- package/dist/boxes/webm/bitstream/av1/transfer-characteristics.js +0 -24
- package/dist/boxes/webm/bitstream/av1/uvlc.d.ts +0 -2
- package/dist/boxes/webm/bitstream/av1/uvlc.js +0 -20
- package/dist/boxes/webm/bitstream/av1.d.ts +0 -20
- package/dist/boxes/webm/bitstream/av1.js +0 -118
- package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.d.ts +0 -0
- package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.js +0 -1
- package/dist/boxes/webm/segments/duration.d.ts +0 -6
- package/dist/boxes/webm/segments/duration.js +0 -19
- package/dist/boxes/webm/segments/info.d.ts +0 -9
- package/dist/boxes/webm/segments/info.js +0 -22
- package/dist/boxes/webm/segments/main.d.ts +0 -5
- package/dist/boxes/webm/segments/main.js +0 -2
- package/dist/boxes/webm/segments/muxing.d.ts +0 -6
- package/dist/boxes/webm/segments/muxing.js +0 -11
- package/dist/boxes/webm/segments/seek-head.d.ts +0 -9
- package/dist/boxes/webm/segments/seek-head.js +0 -22
- package/dist/boxes/webm/segments/seek-position.d.ts +0 -6
- package/dist/boxes/webm/segments/seek-position.js +0 -11
- package/dist/boxes/webm/segments/seek.d.ts +0 -13
- package/dist/boxes/webm/segments/seek.js +0 -35
- package/dist/boxes/webm/segments/timestamp-scale.d.ts +0 -6
- package/dist/boxes/webm/segments/timestamp-scale.js +0 -11
- package/dist/boxes/webm/segments/tracks.d.ts +0 -8
- package/dist/boxes/webm/segments/tracks.js +0 -21
- package/dist/boxes/webm/segments/unknown.d.ts +0 -6
- package/dist/boxes/webm/segments/unknown.js +0 -11
- package/dist/boxes/webm/segments/void.d.ts +0 -6
- package/dist/boxes/webm/segments/void.js +0 -11
- package/dist/boxes/webm/segments/writing.d.ts +0 -6
- package/dist/boxes/webm/segments/writing.js +0 -11
- package/dist/boxes/webm/tracks.d.ts +0 -8
- package/dist/boxes/webm/tracks.js +0 -21
- package/dist/combine-uint8array.d.ts +0 -1
- package/dist/combine-uint8array.js +0 -13
- package/dist/create/cues.d.ts +0 -0
- package/dist/create/cues.js +0 -1
- package/dist/from-web.d.ts +0 -2
- package/dist/from-web.js +0 -45
- package/dist/get-video-metadata.d.ts +0 -2
- package/dist/get-video-metadata.js +0 -44
- package/dist/read-and-increment-offset.d.ts +0 -28
- package/dist/read-and-increment-offset.js +0 -177
- package/dist/understand-vorbis.d.ts +0 -1
- package/dist/understand-vorbis.js +0 -12
package/dist/esm/index.mjs
CHANGED
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
// src/readers/from-fetch.ts
|
|
2
|
+
function parseContentRange(input) {
|
|
3
|
+
const matches = input.match(/^(\w+) ((\d+)-(\d+)|\*)\/(\d+|\*)$/);
|
|
4
|
+
if (!matches)
|
|
5
|
+
return null;
|
|
6
|
+
const [, unit, , start, end, size] = matches;
|
|
7
|
+
const range = {
|
|
8
|
+
unit,
|
|
9
|
+
start: start != null ? Number(start) : null,
|
|
10
|
+
end: end != null ? Number(end) : null,
|
|
11
|
+
size: size === "*" ? null : Number(size)
|
|
12
|
+
};
|
|
13
|
+
if (range.start === null && range.end === null && range.size === null) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return range;
|
|
17
|
+
}
|
|
18
|
+
var validateContentRangeAndDetectIfSupported = (actualRange, parsedContentRange) => {
|
|
19
|
+
if (typeof actualRange === "number" && parsedContentRange?.start !== actualRange) {
|
|
20
|
+
if (actualRange === 0) {
|
|
21
|
+
return { supportsContentRange: false };
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
|
|
24
|
+
}
|
|
25
|
+
if (actualRange !== null && typeof actualRange !== "number" && (parsedContentRange?.start !== actualRange[0] || parsedContentRange?.end !== actualRange[1])) {
|
|
26
|
+
throw new Error(`Range header (${actualRange}) does not match content-range header (${parsedContentRange?.start})`);
|
|
27
|
+
}
|
|
28
|
+
return { supportsContentRange: true };
|
|
29
|
+
};
|
|
2
30
|
var fetchReader = {
|
|
3
31
|
read: async (src, range, signal) => {
|
|
4
32
|
if (typeof src !== "string") {
|
|
@@ -9,20 +37,25 @@ var fetchReader = {
|
|
|
9
37
|
return Promise.reject(new Error(resolvedUrl + " is not a URL - needs to start with http:// or https:// or blob:. If you want to read a local file, pass `reader: nodeReader` to parseMedia()."));
|
|
10
38
|
}
|
|
11
39
|
const controller = new AbortController;
|
|
40
|
+
const cache = typeof navigator !== "undefined" && navigator.userAgent.includes("Cloudflare-Workers") ? undefined : "no-store";
|
|
41
|
+
const actualRange = range === null ? 0 : range;
|
|
12
42
|
const res = await fetch(resolvedUrl, {
|
|
13
|
-
headers:
|
|
14
|
-
Range: `bytes=${
|
|
43
|
+
headers: typeof actualRange === "number" ? {
|
|
44
|
+
Range: `bytes=${actualRange}-`
|
|
15
45
|
} : {
|
|
16
|
-
Range: `bytes=${`${
|
|
46
|
+
Range: `bytes=${`${actualRange[0]}-${actualRange[1]}`}`
|
|
17
47
|
},
|
|
18
48
|
signal: controller.signal,
|
|
19
|
-
cache
|
|
49
|
+
cache
|
|
20
50
|
});
|
|
51
|
+
const contentRange = res.headers.get("content-range");
|
|
52
|
+
const parsedContentRange = contentRange ? parseContentRange(contentRange) : null;
|
|
53
|
+
const { supportsContentRange } = validateContentRangeAndDetectIfSupported(actualRange, parsedContentRange);
|
|
21
54
|
signal?.addEventListener("abort", () => {
|
|
22
55
|
controller.abort();
|
|
23
56
|
}, { once: true });
|
|
24
57
|
if (res.status.toString().startsWith("4") || res.status.toString().startsWith("5")) {
|
|
25
|
-
throw new Error(`Server returned status code ${res.status} for ${src}`);
|
|
58
|
+
throw new Error(`Server returned status code ${res.status} for ${src} and range ${actualRange}`);
|
|
26
59
|
}
|
|
27
60
|
if (!res.body) {
|
|
28
61
|
throw new Error("No body");
|
|
@@ -47,7 +80,8 @@ var fetchReader = {
|
|
|
47
80
|
}
|
|
48
81
|
},
|
|
49
82
|
contentLength,
|
|
50
|
-
name: name ?? fallbackName
|
|
83
|
+
name: name ?? fallbackName,
|
|
84
|
+
supportsContentRange
|
|
51
85
|
};
|
|
52
86
|
},
|
|
53
87
|
getLength: async (src) => {
|
|
@@ -1060,11 +1094,16 @@ var makeCluster = async (w, timestamp) => {
|
|
|
1060
1094
|
clusterSize += simpleBlock2.byteLength;
|
|
1061
1095
|
await w.updateDataAt(clusterVIntPosition, getVariableInt(clusterSize, CLUSTER_MIN_VINT_WIDTH));
|
|
1062
1096
|
await w.write(simpleBlock2);
|
|
1097
|
+
return { timecodeRelativeToCluster };
|
|
1063
1098
|
};
|
|
1064
|
-
const shouldMakeNewCluster = (
|
|
1099
|
+
const shouldMakeNewCluster = ({
|
|
1100
|
+
isVideo,
|
|
1101
|
+
keyframe,
|
|
1102
|
+
newT
|
|
1103
|
+
}) => {
|
|
1065
1104
|
const newTimestamp = timestampToClusterTimestamp(newT);
|
|
1066
1105
|
const oldTimestamp = timestampToClusterTimestamp(timestamp);
|
|
1067
|
-
return newTimestamp - oldTimestamp >= 2000 && keyframe;
|
|
1106
|
+
return newTimestamp - oldTimestamp >= 2000 && keyframe && isVideo;
|
|
1068
1107
|
};
|
|
1069
1108
|
return { addSample, shouldMakeNewCluster };
|
|
1070
1109
|
};
|
|
@@ -1094,18 +1133,18 @@ var createMatroskaCues = (cues) => {
|
|
|
1094
1133
|
type: "CueTime",
|
|
1095
1134
|
minVintWidth: null,
|
|
1096
1135
|
value: {
|
|
1097
|
-
value:
|
|
1136
|
+
value: cue.time,
|
|
1098
1137
|
byteLength: null
|
|
1099
1138
|
}
|
|
1100
1139
|
},
|
|
1101
|
-
|
|
1140
|
+
{
|
|
1102
1141
|
type: "CueTrackPositions",
|
|
1103
1142
|
value: [
|
|
1104
1143
|
{
|
|
1105
1144
|
type: "CueTrack",
|
|
1106
1145
|
minVintWidth: null,
|
|
1107
1146
|
value: {
|
|
1108
|
-
value:
|
|
1147
|
+
value: cue.trackNumber,
|
|
1109
1148
|
byteLength: null
|
|
1110
1149
|
}
|
|
1111
1150
|
},
|
|
@@ -1119,7 +1158,7 @@ var createMatroskaCues = (cues) => {
|
|
|
1119
1158
|
}
|
|
1120
1159
|
],
|
|
1121
1160
|
minVintWidth: null
|
|
1122
|
-
}
|
|
1161
|
+
}
|
|
1123
1162
|
],
|
|
1124
1163
|
minVintWidth: null
|
|
1125
1164
|
};
|
|
@@ -1258,6 +1297,11 @@ var createMatroskaSegment = (children) => {
|
|
|
1258
1297
|
});
|
|
1259
1298
|
};
|
|
1260
1299
|
|
|
1300
|
+
// src/truthy.ts
|
|
1301
|
+
function truthy(value) {
|
|
1302
|
+
return Boolean(value);
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1261
1305
|
// src/boxes/webm/traversal.ts
|
|
1262
1306
|
var getMainSegment = (segments) => {
|
|
1263
1307
|
return segments.find((s) => s.type === "Segment");
|
|
@@ -1484,7 +1528,7 @@ var makeMatroskaColorBytes = ({
|
|
|
1484
1528
|
type: "Colour",
|
|
1485
1529
|
minVintWidth: null,
|
|
1486
1530
|
value: [
|
|
1487
|
-
{
|
|
1531
|
+
transferChracteristicsValue === 2 ? null : {
|
|
1488
1532
|
type: "TransferCharacteristics",
|
|
1489
1533
|
value: {
|
|
1490
1534
|
value: transferChracteristicsValue,
|
|
@@ -1492,7 +1536,7 @@ var makeMatroskaColorBytes = ({
|
|
|
1492
1536
|
},
|
|
1493
1537
|
minVintWidth: null
|
|
1494
1538
|
},
|
|
1495
|
-
{
|
|
1539
|
+
matrixCoefficientsValue === 2 ? null : {
|
|
1496
1540
|
type: "MatrixCoefficients",
|
|
1497
1541
|
value: {
|
|
1498
1542
|
value: matrixCoefficientsValue,
|
|
@@ -1500,7 +1544,7 @@ var makeMatroskaColorBytes = ({
|
|
|
1500
1544
|
},
|
|
1501
1545
|
minVintWidth: null
|
|
1502
1546
|
},
|
|
1503
|
-
{
|
|
1547
|
+
primariesValue === 2 ? null : {
|
|
1504
1548
|
type: "Primaries",
|
|
1505
1549
|
value: {
|
|
1506
1550
|
value: primariesValue,
|
|
@@ -1516,7 +1560,7 @@ var makeMatroskaColorBytes = ({
|
|
|
1516
1560
|
},
|
|
1517
1561
|
minVintWidth: null
|
|
1518
1562
|
}
|
|
1519
|
-
]
|
|
1563
|
+
].filter(truthy)
|
|
1520
1564
|
});
|
|
1521
1565
|
};
|
|
1522
1566
|
|
|
@@ -1644,14 +1688,6 @@ var makeMatroskaAudioTrackEntryBytes = ({
|
|
|
1644
1688
|
},
|
|
1645
1689
|
minVintWidth: null
|
|
1646
1690
|
},
|
|
1647
|
-
{
|
|
1648
|
-
type: "TrackTimestampScale",
|
|
1649
|
-
value: {
|
|
1650
|
-
value: 1,
|
|
1651
|
-
size: "64"
|
|
1652
|
-
},
|
|
1653
|
-
minVintWidth: null
|
|
1654
|
-
},
|
|
1655
1691
|
{
|
|
1656
1692
|
type: "CodecID",
|
|
1657
1693
|
value: makeAudioCodecId(codec),
|
|
@@ -1788,13 +1824,15 @@ var createMedia = async (writer) => {
|
|
|
1788
1824
|
const cues = [];
|
|
1789
1825
|
const trackNumbers = [];
|
|
1790
1826
|
const matroskaSegment = createMatroskaSegment([
|
|
1791
|
-
matroskaInfo,
|
|
1792
1827
|
...createMatroskaSeekHead(seeks),
|
|
1828
|
+
matroskaInfo,
|
|
1793
1829
|
...makeMatroskaTracks(currentTracks)
|
|
1794
1830
|
]);
|
|
1795
|
-
const
|
|
1831
|
+
const infoSegment = matroskaSegment.offsets.children.find((o) => o.field === "Info");
|
|
1832
|
+
const durationOffset = (infoSegment?.children.find((c) => c.field === "Duration")?.offset ?? 0) + w.getWrittenByteCount();
|
|
1796
1833
|
const tracksOffset = (matroskaSegment.offsets.children.find((o) => o.field === "Tracks")?.offset ?? 0) + w.getWrittenByteCount();
|
|
1797
1834
|
const seekHeadOffset = (matroskaSegment.offsets.children.find((o) => o.field === "SeekHead")?.offset ?? 0) + w.getWrittenByteCount();
|
|
1835
|
+
const infoOffset = (infoSegment?.offset ?? 0) + w.getWrittenByteCount();
|
|
1798
1836
|
if (!seekHeadOffset) {
|
|
1799
1837
|
throw new Error("could not get seek offset");
|
|
1800
1838
|
}
|
|
@@ -1804,6 +1842,13 @@ var createMedia = async (writer) => {
|
|
|
1804
1842
|
if (!tracksOffset) {
|
|
1805
1843
|
throw new Error("could not get tracks offset");
|
|
1806
1844
|
}
|
|
1845
|
+
if (!infoOffset) {
|
|
1846
|
+
throw new Error("could not get tracks offset");
|
|
1847
|
+
}
|
|
1848
|
+
seeks.push({
|
|
1849
|
+
hexString: matroskaElements.Info,
|
|
1850
|
+
byte: infoOffset - seekHeadOffset
|
|
1851
|
+
});
|
|
1807
1852
|
seeks.push({
|
|
1808
1853
|
hexString: matroskaElements.Tracks,
|
|
1809
1854
|
byte: tracksOffset - seekHeadOffset
|
|
@@ -1812,10 +1857,10 @@ var createMedia = async (writer) => {
|
|
|
1812
1857
|
const updatedSeek = createMatroskaSeekHead(seeks);
|
|
1813
1858
|
await w.updateDataAt(seekHeadOffset, combineUint8Arrays(updatedSeek.map((b) => b.bytes)));
|
|
1814
1859
|
};
|
|
1815
|
-
const segmentOffset = w.getWrittenByteCount()
|
|
1860
|
+
const segmentOffset = w.getWrittenByteCount();
|
|
1816
1861
|
const updateSegmentSize = async (size) => {
|
|
1817
1862
|
const data = getVariableInt(size, MATROSKA_SEGMENT_MIN_VINT_WIDTH);
|
|
1818
|
-
await w.updateDataAt(segmentOffset, data);
|
|
1863
|
+
await w.updateDataAt(segmentOffset + matroskaToHex(matroskaElements.Segment).byteLength, data);
|
|
1819
1864
|
};
|
|
1820
1865
|
await w.write(matroskaSegment.bytes);
|
|
1821
1866
|
const clusterOffset = w.getWrittenByteCount();
|
|
@@ -1824,32 +1869,39 @@ var createMedia = async (writer) => {
|
|
|
1824
1869
|
hexString: matroskaElements.Cluster,
|
|
1825
1870
|
byte: clusterOffset - seekHeadOffset
|
|
1826
1871
|
});
|
|
1827
|
-
cues.push({
|
|
1828
|
-
time: 0,
|
|
1829
|
-
clusterPosition: clusterOffset - seekHeadOffset,
|
|
1830
|
-
trackNumbers
|
|
1831
|
-
});
|
|
1832
1872
|
const trackNumberProgresses = {};
|
|
1833
|
-
const getClusterOrMakeNew = async (
|
|
1873
|
+
const getClusterOrMakeNew = async ({
|
|
1874
|
+
chunk,
|
|
1875
|
+
isVideo
|
|
1876
|
+
}) => {
|
|
1834
1877
|
const smallestProgress = Math.min(...Object.values(trackNumberProgresses));
|
|
1835
|
-
if (!currentCluster.shouldMakeNewCluster(
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
trackNumbers
|
|
1843
|
-
});
|
|
1878
|
+
if (!currentCluster.shouldMakeNewCluster({
|
|
1879
|
+
newT: smallestProgress,
|
|
1880
|
+
keyframe: chunk.type === "key",
|
|
1881
|
+
isVideo
|
|
1882
|
+
})) {
|
|
1883
|
+
return { cluster: currentCluster, isNew: false, smallestProgress };
|
|
1884
|
+
}
|
|
1844
1885
|
currentCluster = await makeCluster(w, smallestProgress);
|
|
1845
|
-
return currentCluster;
|
|
1886
|
+
return { cluster: currentCluster, isNew: true, smallestProgress };
|
|
1846
1887
|
};
|
|
1847
|
-
const addSample = async (chunk, trackNumber2) => {
|
|
1888
|
+
const addSample = async (chunk, trackNumber2, isVideo) => {
|
|
1848
1889
|
trackNumberProgresses[trackNumber2] = chunk.timestamp;
|
|
1849
|
-
const
|
|
1890
|
+
const { cluster: cluster2, isNew, smallestProgress } = await getClusterOrMakeNew({
|
|
1891
|
+
chunk,
|
|
1892
|
+
isVideo
|
|
1893
|
+
});
|
|
1850
1894
|
const newDuration = Math.round((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
1851
1895
|
await updateDuration(newDuration);
|
|
1852
|
-
|
|
1896
|
+
const { timecodeRelativeToCluster } = await cluster2.addSample(chunk, trackNumber2);
|
|
1897
|
+
if (isNew) {
|
|
1898
|
+
const newCluster = w.getWrittenByteCount();
|
|
1899
|
+
cues.push({
|
|
1900
|
+
time: timestampToClusterTimestamp(smallestProgress) + timecodeRelativeToCluster,
|
|
1901
|
+
clusterPosition: newCluster - seekHeadOffset,
|
|
1902
|
+
trackNumber: trackNumber2
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1853
1905
|
};
|
|
1854
1906
|
const updateDuration = async (newDuration) => {
|
|
1855
1907
|
const blocks = makeDurationWithPadding(newDuration);
|
|
@@ -1870,8 +1922,8 @@ var createMedia = async (writer) => {
|
|
|
1870
1922
|
remove: async () => {
|
|
1871
1923
|
await w.remove();
|
|
1872
1924
|
},
|
|
1873
|
-
addSample: (chunk, trackNumber2) => {
|
|
1874
|
-
operationProm.current = operationProm.current.then(() => addSample(chunk, trackNumber2));
|
|
1925
|
+
addSample: (chunk, trackNumber2, isVideo) => {
|
|
1926
|
+
operationProm.current = operationProm.current.then(() => addSample(chunk, trackNumber2, isVideo));
|
|
1875
1927
|
return operationProm.current;
|
|
1876
1928
|
},
|
|
1877
1929
|
updateDuration: (duration2) => {
|
|
@@ -1897,8 +1949,8 @@ var createMedia = async (writer) => {
|
|
|
1897
1949
|
});
|
|
1898
1950
|
await updateSeekWrite();
|
|
1899
1951
|
await w.write(createMatroskaCues(cues).bytes);
|
|
1900
|
-
const segmentSize = w.getWrittenByteCount() - segmentOffset;
|
|
1901
1952
|
await w.waitForFinish();
|
|
1953
|
+
const segmentSize = w.getWrittenByteCount() - segmentOffset - matroskaToHex(matroskaElements.Segment).byteLength - MATROSKA_SEGMENT_MIN_VINT_WIDTH;
|
|
1902
1954
|
await updateSegmentSize(segmentSize);
|
|
1903
1955
|
}
|
|
1904
1956
|
};
|
|
@@ -2058,25 +2110,15 @@ var getTrunBoxes = (segment) => {
|
|
|
2058
2110
|
const trunBoxes = segment.children.filter((c) => c.type === "trun-box");
|
|
2059
2111
|
return trunBoxes;
|
|
2060
2112
|
};
|
|
2061
|
-
var
|
|
2113
|
+
var getMdatBox = (anySegment) => {
|
|
2062
2114
|
const mdat = anySegment.find((b) => b.type === "mdat-box");
|
|
2063
2115
|
if (!mdat) {
|
|
2064
|
-
return
|
|
2065
|
-
skipped: false
|
|
2066
|
-
};
|
|
2116
|
+
return null;
|
|
2067
2117
|
}
|
|
2068
2118
|
if (mdat.type !== "mdat-box") {
|
|
2069
2119
|
throw new Error("Expected mdat-box");
|
|
2070
2120
|
}
|
|
2071
|
-
|
|
2072
|
-
return {
|
|
2073
|
-
skipped: false
|
|
2074
|
-
};
|
|
2075
|
-
}
|
|
2076
|
-
return {
|
|
2077
|
-
skipped: true,
|
|
2078
|
-
fileOffset: mdat.fileOffset
|
|
2079
|
-
};
|
|
2121
|
+
return mdat;
|
|
2080
2122
|
};
|
|
2081
2123
|
|
|
2082
2124
|
// src/get-fps.ts
|
|
@@ -2270,6 +2312,9 @@ var getAudioCodecStringFromTrak = (trak) => {
|
|
|
2270
2312
|
};
|
|
2271
2313
|
};
|
|
2272
2314
|
var getAudioCodecFromAudioCodecInfo = (codec) => {
|
|
2315
|
+
if (codec.format === "twos") {
|
|
2316
|
+
return "pcm-s16";
|
|
2317
|
+
}
|
|
2273
2318
|
if (codec.format === "sowt") {
|
|
2274
2319
|
return "aiff";
|
|
2275
2320
|
}
|
|
@@ -2285,7 +2330,7 @@ var getAudioCodecFromAudioCodecInfo = (codec) => {
|
|
|
2285
2330
|
}
|
|
2286
2331
|
throw new Error("Unknown mp4a codec: " + codec.primarySpecificator);
|
|
2287
2332
|
}
|
|
2288
|
-
throw new Error(
|
|
2333
|
+
throw new Error(`Unknown audio format: ${codec.format}`);
|
|
2289
2334
|
};
|
|
2290
2335
|
var getAudioCodecFromTrack = (track) => {
|
|
2291
2336
|
const audioSample = getAudioCodecFromTrak(track);
|
|
@@ -2464,6 +2509,9 @@ class OffsetCounter {
|
|
|
2464
2509
|
setDiscardedOffset(offset) {
|
|
2465
2510
|
this.#discardedBytes = offset;
|
|
2466
2511
|
}
|
|
2512
|
+
getDiscardedBytes() {
|
|
2513
|
+
return this.#discardedBytes;
|
|
2514
|
+
}
|
|
2467
2515
|
discardBytes(amount) {
|
|
2468
2516
|
this.#discardedBytes += amount;
|
|
2469
2517
|
}
|
|
@@ -2496,11 +2544,18 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2496
2544
|
data.set(initialData);
|
|
2497
2545
|
let view = new DataView(data.buffer);
|
|
2498
2546
|
const counter = makeOffsetCounter();
|
|
2547
|
+
let discardAllowed = true;
|
|
2499
2548
|
const getSlice = (amount) => {
|
|
2500
2549
|
const value = data.slice(counter.getDiscardedOffset(), counter.getDiscardedOffset() + amount);
|
|
2501
2550
|
counter.increment(amount);
|
|
2502
2551
|
return value;
|
|
2503
2552
|
};
|
|
2553
|
+
const disallowDiscard = () => {
|
|
2554
|
+
discardAllowed = false;
|
|
2555
|
+
};
|
|
2556
|
+
const allowDiscard = () => {
|
|
2557
|
+
discardAllowed = true;
|
|
2558
|
+
};
|
|
2504
2559
|
const getUint8 = () => {
|
|
2505
2560
|
const val = view.getUint8(counter.getDiscardedOffset());
|
|
2506
2561
|
counter.increment(1);
|
|
@@ -2606,6 +2661,9 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2606
2661
|
return matchesPattern(mpegPattern)(data.subarray(0, 4));
|
|
2607
2662
|
};
|
|
2608
2663
|
const removeBytesRead = () => {
|
|
2664
|
+
if (!discardAllowed) {
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2609
2667
|
const bytesToRemove = counter.getDiscardedOffset();
|
|
2610
2668
|
if (bytesToRemove < 1e5) {
|
|
2611
2669
|
return;
|
|
@@ -2616,12 +2674,22 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2616
2674
|
buf.resize(newData.byteLength);
|
|
2617
2675
|
view = new DataView(data.buffer);
|
|
2618
2676
|
};
|
|
2619
|
-
const skipTo = (offset) => {
|
|
2677
|
+
const skipTo = (offset, reset) => {
|
|
2620
2678
|
const becomesSmaller = offset < counter.getOffset();
|
|
2621
2679
|
if (becomesSmaller) {
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2680
|
+
if (reset) {
|
|
2681
|
+
buf.resize(0);
|
|
2682
|
+
counter.decrement(counter.getOffset() - offset);
|
|
2683
|
+
counter.setDiscardedOffset(offset);
|
|
2684
|
+
} else {
|
|
2685
|
+
const toDecrement = counter.getOffset() - offset;
|
|
2686
|
+
const newOffset = counter.getOffset() - toDecrement;
|
|
2687
|
+
counter.decrement(toDecrement);
|
|
2688
|
+
const c = counter.getDiscardedBytes();
|
|
2689
|
+
if (c > newOffset) {
|
|
2690
|
+
throw new Error("already discarded too many bytes");
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2625
2693
|
} else {
|
|
2626
2694
|
const currentOffset = counter.getOffset();
|
|
2627
2695
|
counter.increment(offset - currentOffset);
|
|
@@ -2842,7 +2910,9 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
2842
2910
|
getInt32Le,
|
|
2843
2911
|
getInt32,
|
|
2844
2912
|
destroy,
|
|
2845
|
-
isMp3
|
|
2913
|
+
isMp3,
|
|
2914
|
+
disallowDiscard,
|
|
2915
|
+
allowDiscard
|
|
2846
2916
|
};
|
|
2847
2917
|
};
|
|
2848
2918
|
|
|
@@ -4201,15 +4271,26 @@ var parseMdat = async ({
|
|
|
4201
4271
|
fileOffset,
|
|
4202
4272
|
existingBoxes,
|
|
4203
4273
|
options,
|
|
4204
|
-
signal
|
|
4274
|
+
signal,
|
|
4275
|
+
maySkipSampleProcessing
|
|
4205
4276
|
}) => {
|
|
4206
4277
|
const alreadyHas = hasTracks(existingBoxes);
|
|
4207
4278
|
if (!alreadyHas) {
|
|
4279
|
+
if (maySkipSampleProcessing) {
|
|
4280
|
+
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
4281
|
+
return Promise.resolve({
|
|
4282
|
+
type: "mdat-box",
|
|
4283
|
+
boxSize: size,
|
|
4284
|
+
status: "samples-skipped",
|
|
4285
|
+
fileOffset
|
|
4286
|
+
});
|
|
4287
|
+
}
|
|
4208
4288
|
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
4289
|
+
data.disallowDiscard();
|
|
4209
4290
|
return Promise.resolve({
|
|
4210
4291
|
type: "mdat-box",
|
|
4211
4292
|
boxSize: size,
|
|
4212
|
-
|
|
4293
|
+
status: "samples-buffered",
|
|
4213
4294
|
fileOffset
|
|
4214
4295
|
});
|
|
4215
4296
|
}
|
|
@@ -4284,7 +4365,7 @@ var parseMdat = async ({
|
|
|
4284
4365
|
return Promise.resolve({
|
|
4285
4366
|
type: "mdat-box",
|
|
4286
4367
|
boxSize: size,
|
|
4287
|
-
|
|
4368
|
+
status: "samples-processed",
|
|
4288
4369
|
fileOffset
|
|
4289
4370
|
});
|
|
4290
4371
|
};
|
|
@@ -5361,9 +5442,10 @@ var parseMdatPartially = async ({
|
|
|
5361
5442
|
fileOffset,
|
|
5362
5443
|
existingBoxes: parsedBoxes,
|
|
5363
5444
|
options,
|
|
5364
|
-
signal
|
|
5445
|
+
signal,
|
|
5446
|
+
maySkipSampleProcessing: options.supportsContentRange
|
|
5365
5447
|
});
|
|
5366
|
-
if (box.
|
|
5448
|
+
if ((box.status === "samples-processed" || box.status === "samples-buffered") && box.fileOffset + boxSize === iterator.counter.getOffset()) {
|
|
5367
5449
|
return {
|
|
5368
5450
|
type: "complete",
|
|
5369
5451
|
box,
|
|
@@ -5412,7 +5494,7 @@ var processBox = async ({
|
|
|
5412
5494
|
const boxSize = boxSizeRaw === 1 ? iterator.getEightByteNumber(littleEndian) : boxSizeRaw;
|
|
5413
5495
|
if (bytesRemaining < boxSize) {
|
|
5414
5496
|
if (boxType === "mdat") {
|
|
5415
|
-
const shouldSkip = options.canSkipVideoData || !hasTracks(parsedBoxes);
|
|
5497
|
+
const shouldSkip = (options.canSkipVideoData || !hasTracks(parsedBoxes)) && options.supportsContentRange;
|
|
5416
5498
|
if (shouldSkip) {
|
|
5417
5499
|
const skipTo = fileOffset + boxSize;
|
|
5418
5500
|
const bytesToSkip = skipTo - iterator.counter.getOffset();
|
|
@@ -5423,7 +5505,7 @@ var processBox = async ({
|
|
|
5423
5505
|
type: "mdat-box",
|
|
5424
5506
|
boxSize,
|
|
5425
5507
|
fileOffset,
|
|
5426
|
-
|
|
5508
|
+
status: "samples-skipped"
|
|
5427
5509
|
},
|
|
5428
5510
|
size: boxSize,
|
|
5429
5511
|
skipTo: fileOffset + boxSize
|
|
@@ -5751,8 +5833,12 @@ var processBox = async ({
|
|
|
5751
5833
|
fileOffset,
|
|
5752
5834
|
existingBoxes: parsedBoxes,
|
|
5753
5835
|
options,
|
|
5754
|
-
signal
|
|
5836
|
+
signal,
|
|
5837
|
+
maySkipSampleProcessing: options.supportsContentRange
|
|
5755
5838
|
});
|
|
5839
|
+
if (box === null) {
|
|
5840
|
+
throw new Error("Unexpected null");
|
|
5841
|
+
}
|
|
5756
5842
|
return {
|
|
5757
5843
|
type: "complete",
|
|
5758
5844
|
box,
|
|
@@ -5855,11 +5941,18 @@ var parseBoxes = async ({
|
|
|
5855
5941
|
if (result.box.type === "mdat-box" && alreadyHasMdat) {
|
|
5856
5942
|
boxes = boxes.filter((b) => b.type !== "mdat-box");
|
|
5857
5943
|
boxes.push(result.box);
|
|
5944
|
+
iterator.allowDiscard();
|
|
5945
|
+
if (result.box.status !== "samples-processed") {
|
|
5946
|
+
throw new Error("unexpected");
|
|
5947
|
+
}
|
|
5858
5948
|
break;
|
|
5859
5949
|
} else {
|
|
5860
5950
|
boxes.push(result.box);
|
|
5861
5951
|
}
|
|
5862
5952
|
if (result.skipTo !== null) {
|
|
5953
|
+
if (!options.supportsContentRange) {
|
|
5954
|
+
throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
|
|
5955
|
+
}
|
|
5863
5956
|
return {
|
|
5864
5957
|
status: "incomplete",
|
|
5865
5958
|
segments: boxes,
|
|
@@ -5878,18 +5971,42 @@ var parseBoxes = async ({
|
|
|
5878
5971
|
skipTo: result.skipTo
|
|
5879
5972
|
};
|
|
5880
5973
|
}
|
|
5974
|
+
if (iterator.bytesRemaining() < 0) {
|
|
5975
|
+
return {
|
|
5976
|
+
status: "incomplete",
|
|
5977
|
+
segments: boxes,
|
|
5978
|
+
continueParsing: () => {
|
|
5979
|
+
return parseBoxes({
|
|
5980
|
+
iterator,
|
|
5981
|
+
maxBytes,
|
|
5982
|
+
allowIncompleteBoxes,
|
|
5983
|
+
initialBoxes: boxes,
|
|
5984
|
+
options,
|
|
5985
|
+
continueMdat: false,
|
|
5986
|
+
littleEndian,
|
|
5987
|
+
signal
|
|
5988
|
+
});
|
|
5989
|
+
},
|
|
5990
|
+
skipTo: null
|
|
5991
|
+
};
|
|
5992
|
+
}
|
|
5881
5993
|
iterator.removeBytesRead();
|
|
5882
5994
|
}
|
|
5883
|
-
const mdatState =
|
|
5884
|
-
|
|
5995
|
+
const mdatState = getMdatBox(boxes);
|
|
5996
|
+
const skipped = mdatState?.status === "samples-skipped" && !options.canSkipVideoData && options.supportsContentRange;
|
|
5997
|
+
const buffered = mdatState?.status === "samples-buffered" && !options.canSkipVideoData;
|
|
5998
|
+
if (skipped || buffered) {
|
|
5885
5999
|
return {
|
|
5886
6000
|
status: "incomplete",
|
|
5887
6001
|
segments: boxes,
|
|
5888
6002
|
continueParsing: () => {
|
|
6003
|
+
if (buffered) {
|
|
6004
|
+
iterator.skipTo(mdatState.fileOffset, false);
|
|
6005
|
+
}
|
|
5889
6006
|
return parseBoxes({
|
|
5890
6007
|
iterator,
|
|
5891
6008
|
maxBytes,
|
|
5892
|
-
allowIncompleteBoxes,
|
|
6009
|
+
allowIncompleteBoxes: false,
|
|
5893
6010
|
initialBoxes: boxes,
|
|
5894
6011
|
options,
|
|
5895
6012
|
continueMdat: false,
|
|
@@ -5897,7 +6014,7 @@ var parseBoxes = async ({
|
|
|
5897
6014
|
signal
|
|
5898
6015
|
});
|
|
5899
6016
|
},
|
|
5900
|
-
skipTo: mdatState.fileOffset
|
|
6017
|
+
skipTo: skipped ? mdatState.fileOffset : null
|
|
5901
6018
|
};
|
|
5902
6019
|
}
|
|
5903
6020
|
return {
|
|
@@ -6338,6 +6455,9 @@ var continueParsingfunction = ({
|
|
|
6338
6455
|
const offset = iterator.counter.getOffset();
|
|
6339
6456
|
const continued = await result.continueParsing();
|
|
6340
6457
|
if (continued.status === "incomplete") {
|
|
6458
|
+
if (!parserContext.supportsContentRange) {
|
|
6459
|
+
throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
|
|
6460
|
+
}
|
|
6341
6461
|
return {
|
|
6342
6462
|
status: "incomplete",
|
|
6343
6463
|
continueParsing: continueParsingfunction({
|
|
@@ -6380,6 +6500,9 @@ var expectChildren = async ({
|
|
|
6380
6500
|
wrap
|
|
6381
6501
|
});
|
|
6382
6502
|
if (child.status === "incomplete") {
|
|
6503
|
+
if (!parserContext.supportsContentRange) {
|
|
6504
|
+
throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
|
|
6505
|
+
}
|
|
6383
6506
|
return {
|
|
6384
6507
|
status: "incomplete",
|
|
6385
6508
|
continueParsing: continueParsingfunction({
|
|
@@ -6595,8 +6718,14 @@ var parseMedia = async ({
|
|
|
6595
6718
|
hasVideoCallbacks: onVideoTrack !== null,
|
|
6596
6719
|
signal
|
|
6597
6720
|
});
|
|
6598
|
-
const {
|
|
6721
|
+
const {
|
|
6722
|
+
reader,
|
|
6723
|
+
contentLength,
|
|
6724
|
+
name,
|
|
6725
|
+
supportsContentRange: readerSupportsContentRange
|
|
6726
|
+
} = await readerInterface.read(src, null, signal);
|
|
6599
6727
|
let currentReader = reader;
|
|
6728
|
+
const supportsContentRange = readerSupportsContentRange && !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.DISABLE_CONTENT_RANGE === "true");
|
|
6600
6729
|
const returnValue = {};
|
|
6601
6730
|
const moreFields = more;
|
|
6602
6731
|
let iterator = null;
|
|
@@ -6606,22 +6735,34 @@ var parseMedia = async ({
|
|
|
6606
6735
|
onAudioTrack: onAudioTrack ?? null,
|
|
6607
6736
|
onVideoTrack: onVideoTrack ?? null,
|
|
6608
6737
|
parserState: state,
|
|
6609
|
-
nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true")
|
|
6738
|
+
nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true"),
|
|
6739
|
+
supportsContentRange
|
|
6610
6740
|
};
|
|
6611
6741
|
while (parseResult === null || parseResult.status === "incomplete") {
|
|
6612
6742
|
if (signal?.aborted) {
|
|
6613
6743
|
throw new Error("Aborted");
|
|
6614
6744
|
}
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
if (
|
|
6618
|
-
|
|
6745
|
+
while (true) {
|
|
6746
|
+
const result = await currentReader.reader.read();
|
|
6747
|
+
if (iterator) {
|
|
6748
|
+
if (!result.done) {
|
|
6749
|
+
iterator.addData(result.value);
|
|
6750
|
+
}
|
|
6751
|
+
} else {
|
|
6752
|
+
if (result.done) {
|
|
6753
|
+
throw new Error("Unexpectedly reached EOF");
|
|
6754
|
+
}
|
|
6755
|
+
iterator = getArrayBufferIterator(result.value, contentLength ?? 1e9);
|
|
6756
|
+
}
|
|
6757
|
+
if (iterator.bytesRemaining() >= 0) {
|
|
6758
|
+
break;
|
|
6619
6759
|
}
|
|
6620
|
-
} else {
|
|
6621
6760
|
if (result.done) {
|
|
6622
|
-
|
|
6761
|
+
break;
|
|
6623
6762
|
}
|
|
6624
|
-
|
|
6763
|
+
}
|
|
6764
|
+
if (!iterator) {
|
|
6765
|
+
throw new Error("Unexpected null");
|
|
6625
6766
|
}
|
|
6626
6767
|
if (parseResult && parseResult.status === "incomplete") {
|
|
6627
6768
|
parseResult = await parseResult.continueParsing();
|
|
@@ -6647,27 +6788,19 @@ var parseMedia = async ({
|
|
|
6647
6788
|
break;
|
|
6648
6789
|
}
|
|
6649
6790
|
if (parseResult && parseResult.status === "incomplete" && parseResult.skipTo !== null) {
|
|
6791
|
+
if (!supportsContentRange) {
|
|
6792
|
+
throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
|
|
6793
|
+
}
|
|
6650
6794
|
const { reader: newReader } = await readerInterface.read(src, parseResult.skipTo, signal);
|
|
6651
6795
|
currentReader = newReader;
|
|
6652
|
-
iterator.skipTo(parseResult.skipTo);
|
|
6796
|
+
iterator.skipTo(parseResult.skipTo, true);
|
|
6653
6797
|
}
|
|
6654
6798
|
}
|
|
6655
6799
|
emitAvailableInfo({
|
|
6656
|
-
hasInfo: {
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
fps: true,
|
|
6661
|
-
videoCodec: true,
|
|
6662
|
-
audioCodec: true,
|
|
6663
|
-
tracks: true,
|
|
6664
|
-
rotation: true,
|
|
6665
|
-
unrotatedDimensions: true,
|
|
6666
|
-
internalStats: true,
|
|
6667
|
-
size: true,
|
|
6668
|
-
name: true,
|
|
6669
|
-
container: true
|
|
6670
|
-
},
|
|
6800
|
+
hasInfo: Object.keys(fields ?? {}).reduce((acc, key) => {
|
|
6801
|
+
acc[key] = true;
|
|
6802
|
+
return acc;
|
|
6803
|
+
}, {}),
|
|
6671
6804
|
moreFields,
|
|
6672
6805
|
parseResult,
|
|
6673
6806
|
state,
|