@remotion/media-parser 4.0.200 → 4.0.201
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/av1-codec-string.d.ts +5 -0
- package/dist/av1-codec-string.js +18 -1
- package/dist/bitstream/av1.d.ts +2 -0
- package/dist/bitstream/av1.js +12 -0
- package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +20 -0
- package/dist/boxes/iso-base-media/avcc-hvcc.js +73 -0
- package/dist/boxes/iso-base-media/avcc.d.ts +18 -0
- package/dist/boxes/iso-base-media/avcc.js +27 -0
- package/dist/boxes/iso-base-media/esds-descriptors.d.ts +21 -0
- package/dist/boxes/iso-base-media/esds-descriptors.js +62 -0
- package/dist/boxes/iso-base-media/esds.d.ts +15 -0
- package/dist/boxes/iso-base-media/esds.js +27 -0
- package/dist/boxes/iso-base-media/mdat/mdat.js +2 -1
- package/dist/boxes/iso-base-media/moov/moov.js +1 -0
- package/dist/boxes/iso-base-media/process-box.d.ts +4 -2
- package/dist/boxes/iso-base-media/process-box.js +56 -40
- package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
- package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
- package/dist/boxes/iso-base-media/stsd/samples.js +3 -0
- package/dist/boxes/iso-base-media/stsd/stco.d.ts +3 -2
- package/dist/boxes/iso-base-media/stsd/stco.js +2 -2
- package/dist/boxes/iso-base-media/trak/trak.js +1 -0
- package/dist/boxes/webm/bitstream/av1.js +10 -1
- package/dist/boxes/webm/ebml.d.ts +1 -1
- package/dist/boxes/webm/make-header.d.ts +8 -1
- package/dist/boxes/webm/make-header.js +65 -30
- package/dist/boxes/webm/parse-ebml.d.ts +7 -0
- package/dist/boxes/webm/parse-ebml.js +66 -0
- package/dist/boxes/webm/parse-webm-header.js +8 -9
- package/dist/boxes/webm/segments/all-segments.d.ts +258 -1
- package/dist/boxes/webm/segments/all-segments.js +126 -2
- package/dist/boxes/webm/segments/seek-position.js +1 -1
- package/dist/boxes/webm/segments/seek.d.ts +1 -1
- package/dist/boxes/webm/segments/seek.js +8 -2
- package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
- package/dist/boxes/webm/segments/track-entry.d.ts +5 -1
- package/dist/boxes/webm/segments/track-entry.js +19 -20
- package/dist/boxes/webm/segments.d.ts +2 -2
- package/dist/boxes/webm/segments.js +30 -25
- package/dist/boxes/webm/traversal.d.ts +1 -0
- package/dist/boxes/webm/traversal.js +12 -1
- package/dist/buffer-iterator.d.ts +9 -6
- package/dist/buffer-iterator.js +83 -7
- package/dist/from-fetch.js +13 -3
- package/dist/from-input-type-file.d.ts +2 -0
- package/dist/from-input-type-file.js +37 -0
- package/dist/from-node.js +9 -2
- package/dist/from-web-file.js +6 -1
- package/dist/from-web.js +15 -6
- package/dist/get-audio-codec.d.ts +1 -1
- package/dist/get-codec.d.ts +4 -0
- package/dist/get-codec.js +22 -0
- package/dist/get-sample-positions.js +1 -1
- package/dist/has-all-info.js +1 -1
- package/dist/options.d.ts +3 -2
- package/dist/parse-media.js +13 -9
- package/dist/parse-video.js +16 -0
- package/dist/parser-state.d.ts +4 -3
- package/dist/parser-state.js +15 -3
- package/dist/reader.d.ts +1 -1
- package/dist/web-file.d.ts +2 -0
- package/dist/web-file.js +37 -0
- package/package.json +2 -2
- package/src/boxes/iso-base-media/mdat/mdat.ts +2 -1
- package/src/boxes/iso-base-media/moov/moov.ts +1 -0
- package/src/boxes/iso-base-media/process-box.ts +70 -40
- package/src/boxes/iso-base-media/stsd/mebx.ts +3 -0
- package/src/boxes/iso-base-media/stsd/samples.ts +3 -0
- package/src/boxes/iso-base-media/stsd/stco.ts +5 -3
- package/src/boxes/iso-base-media/trak/trak.ts +1 -0
- package/src/boxes/webm/make-header.ts +122 -32
- package/src/boxes/webm/parse-ebml.ts +93 -0
- package/src/boxes/webm/parse-webm-header.ts +8 -12
- package/src/boxes/webm/segments/all-segments.ts +222 -1
- package/src/boxes/webm/segments/seek-position.ts +1 -1
- package/src/boxes/webm/segments/seek.ts +12 -2
- package/src/boxes/webm/segments/timestamp-scale.ts +1 -1
- package/src/boxes/webm/segments/track-entry.ts +31 -26
- package/src/boxes/webm/segments.ts +37 -32
- package/src/boxes/webm/traversal.ts +13 -0
- package/src/buffer-iterator.ts +102 -9
- package/src/from-fetch.ts +22 -3
- package/src/from-node.ts +18 -4
- package/src/from-web-file.ts +11 -1
- package/src/get-sample-positions.ts +1 -1
- package/src/has-all-info.ts +1 -1
- package/src/options.ts +3 -2
- package/src/parse-media.ts +14 -8
- package/src/parse-video.ts +17 -0
- package/src/parser-state.ts +22 -5
- package/src/reader.ts +1 -0
- package/src/test/create-matroska.test.ts +36 -2
- package/src/test/matroska.test.ts +69 -27
- package/src/test/parse-stco.test.ts +2 -0
- package/src/test/stream-local.test.ts +23 -9
- package/src/test/stream-remote.test.ts +23 -19
- package/src/test/stsd.test.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
- package/dist/boxes/iso-base-media/ftype.js +0 -31
- 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/src/boxes/webm/segments/unknown.ts +0 -19
- /package/dist/{boxes/webm/bitstream/av1/frame.d.ts → get-samples.d.ts} +0 -0
- /package/dist/{boxes/webm/bitstream/av1/frame.js → get-samples.js} +0 -0
- /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.d.ts → sample-aspect-ratio.d.ts} +0 -0
- /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.js → sample-aspect-ratio.js} +0 -0
package/dist/buffer-iterator.js
CHANGED
|
@@ -51,6 +51,7 @@ exports.OffsetCounter = OffsetCounter;
|
|
|
51
51
|
_OffsetCounter_offset = new WeakMap(), _OffsetCounter_discardedBytes = new WeakMap();
|
|
52
52
|
const isoBaseMediaMp4Pattern = new TextEncoder().encode('ftyp');
|
|
53
53
|
const mpegPattern = new Uint8Array([0xff, 0xf3, 0xe4, 0x64]);
|
|
54
|
+
const riffPattern = new Uint8Array([0x52, 0x49, 0x46, 0x46]);
|
|
54
55
|
const matchesPattern = (pattern) => {
|
|
55
56
|
return (data) => {
|
|
56
57
|
return pattern.every((value, index) => data[index] === value);
|
|
@@ -61,7 +62,9 @@ const makeOffsetCounter = () => {
|
|
|
61
62
|
};
|
|
62
63
|
const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
63
64
|
const buf = new ArrayBuffer(initialData.byteLength, {
|
|
64
|
-
maxByteLength: maxBytes
|
|
65
|
+
maxByteLength: maxBytes
|
|
66
|
+
? Math.min(maxBytes, 2 ** 32)
|
|
67
|
+
: 1000000000,
|
|
65
68
|
});
|
|
66
69
|
if (!buf.resize) {
|
|
67
70
|
throw new Error('`ArrayBuffer.resize` is not supported in this Runtime. On the server: Use at least Node.js 20 or Bun. In the browser: Chrome 111, Edge 111, Safari 16.4, Firefox 128, Opera 111');
|
|
@@ -80,7 +83,52 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
80
83
|
counter.increment(1);
|
|
81
84
|
return val;
|
|
82
85
|
};
|
|
83
|
-
const
|
|
86
|
+
const getEightByteNumber = (littleEndian = false) => {
|
|
87
|
+
if (littleEndian) {
|
|
88
|
+
const one = getUint8();
|
|
89
|
+
const two = getUint8();
|
|
90
|
+
const three = getUint8();
|
|
91
|
+
const four = getUint8();
|
|
92
|
+
const five = getUint8();
|
|
93
|
+
const six = getUint8();
|
|
94
|
+
const seven = getUint8();
|
|
95
|
+
const eight = getUint8();
|
|
96
|
+
return ((eight << 56) |
|
|
97
|
+
(seven << 48) |
|
|
98
|
+
(six << 40) |
|
|
99
|
+
(five << 32) |
|
|
100
|
+
(four << 24) |
|
|
101
|
+
(three << 16) |
|
|
102
|
+
(two << 8) |
|
|
103
|
+
one);
|
|
104
|
+
}
|
|
105
|
+
function byteArrayToBigInt(byteArray) {
|
|
106
|
+
let result = BigInt(0);
|
|
107
|
+
for (let i = 0; i < byteArray.length; i++) {
|
|
108
|
+
result = (result << BigInt(8)) + BigInt(byteArray[i]);
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
const bigInt = byteArrayToBigInt([
|
|
113
|
+
getUint8(),
|
|
114
|
+
getUint8(),
|
|
115
|
+
getUint8(),
|
|
116
|
+
getUint8(),
|
|
117
|
+
getUint8(),
|
|
118
|
+
getUint8(),
|
|
119
|
+
getUint8(),
|
|
120
|
+
getUint8(),
|
|
121
|
+
]);
|
|
122
|
+
return Number(bigInt);
|
|
123
|
+
};
|
|
124
|
+
const getFourByteNumber = (littleEndian = false) => {
|
|
125
|
+
if (littleEndian) {
|
|
126
|
+
const one = getUint8();
|
|
127
|
+
const two = getUint8();
|
|
128
|
+
const three = getUint8();
|
|
129
|
+
const four = getUint8();
|
|
130
|
+
return (four << 24) | (three << 16) | (two << 8) | one;
|
|
131
|
+
}
|
|
84
132
|
return ((getUint8() << 24) | (getUint8() << 16) | (getUint8() << 8) | getUint8());
|
|
85
133
|
};
|
|
86
134
|
const getPaddedFourByteNumber = () => {
|
|
@@ -90,11 +138,16 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
90
138
|
}
|
|
91
139
|
return lastInt;
|
|
92
140
|
};
|
|
93
|
-
const getUint32 = () => {
|
|
94
|
-
const val = view.getUint32(counter.getDiscardedOffset());
|
|
141
|
+
const getUint32 = (littleEndian = false) => {
|
|
142
|
+
const val = view.getUint32(counter.getDiscardedOffset(), littleEndian);
|
|
95
143
|
counter.increment(4);
|
|
96
144
|
return val;
|
|
97
145
|
};
|
|
146
|
+
const getUint64 = (littleEndian = false) => {
|
|
147
|
+
const val = view.getBigUint64(counter.getDiscardedOffset(), littleEndian);
|
|
148
|
+
counter.increment(8);
|
|
149
|
+
return val;
|
|
150
|
+
};
|
|
98
151
|
const getUint32Le = () => {
|
|
99
152
|
const val = view.getUint32(counter.getDiscardedOffset(), true);
|
|
100
153
|
counter.increment(4);
|
|
@@ -128,6 +181,9 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
128
181
|
const isIsoBaseMedia = () => {
|
|
129
182
|
return matchesPattern(isoBaseMediaMp4Pattern)(data.subarray(4, 8));
|
|
130
183
|
};
|
|
184
|
+
const isRiff = () => {
|
|
185
|
+
return matchesPattern(riffPattern)(data.subarray(0, 4));
|
|
186
|
+
};
|
|
131
187
|
const isWebm = () => {
|
|
132
188
|
return matchesPattern(make_header_1.webmPattern)(data.subarray(0, 4));
|
|
133
189
|
};
|
|
@@ -154,7 +210,6 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
154
210
|
counter.setDiscardedOffset(offset);
|
|
155
211
|
}
|
|
156
212
|
else {
|
|
157
|
-
buf.resize(offset);
|
|
158
213
|
const currentOffset = counter.getOffset();
|
|
159
214
|
counter.increment(offset - currentOffset);
|
|
160
215
|
removeBytesRead();
|
|
@@ -225,19 +280,24 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
225
280
|
bytesRemaining,
|
|
226
281
|
isIsoBaseMedia,
|
|
227
282
|
leb128,
|
|
228
|
-
|
|
283
|
+
removeBytesRead,
|
|
229
284
|
isWebm,
|
|
230
285
|
discard: (length) => {
|
|
231
286
|
counter.increment(length);
|
|
232
287
|
},
|
|
288
|
+
getEightByteNumber,
|
|
233
289
|
getFourByteNumber,
|
|
234
290
|
getSlice,
|
|
235
291
|
getAtom: () => {
|
|
236
292
|
const atom = getSlice(4);
|
|
237
293
|
return new TextDecoder().decode(atom);
|
|
238
294
|
},
|
|
295
|
+
isRiff,
|
|
239
296
|
getPaddedFourByteNumber,
|
|
240
297
|
getMatroskaSegmentId: () => {
|
|
298
|
+
if (bytesRemaining() === 0) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
241
301
|
const first = getSlice(1);
|
|
242
302
|
const firstOneString = `0x${Array.from(new Uint8Array(first))
|
|
243
303
|
.map((b) => {
|
|
@@ -249,6 +309,9 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
249
309
|
if (all_segments_1.knownIdsWithOneLength.includes(firstOneString)) {
|
|
250
310
|
return firstOneString;
|
|
251
311
|
}
|
|
312
|
+
if (bytesRemaining() === 0) {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
252
315
|
const firstTwo = getSlice(1);
|
|
253
316
|
const firstTwoString = `${firstOneString}${Array.from(new Uint8Array(firstTwo))
|
|
254
317
|
.map((b) => {
|
|
@@ -258,6 +321,9 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
258
321
|
if (all_segments_1.knownIdsWithTwoLength.includes(firstTwoString)) {
|
|
259
322
|
return firstTwoString;
|
|
260
323
|
}
|
|
324
|
+
if (bytesRemaining() === 0) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
261
327
|
const firstThree = getSlice(1);
|
|
262
328
|
const firstThreeString = `${firstTwoString}${Array.from(new Uint8Array(firstThree))
|
|
263
329
|
.map((b) => {
|
|
@@ -267,6 +333,9 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
267
333
|
if (all_segments_1.knownIdsWithThreeLength.includes(firstThreeString)) {
|
|
268
334
|
return firstThreeString;
|
|
269
335
|
}
|
|
336
|
+
if (bytesRemaining() === 0) {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
270
339
|
const segmentId = getSlice(1);
|
|
271
340
|
return `${firstThreeString}${Array.from(new Uint8Array(segmentId))
|
|
272
341
|
.map((b) => {
|
|
@@ -275,6 +344,9 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
275
344
|
.join('')}`;
|
|
276
345
|
},
|
|
277
346
|
getVint: () => {
|
|
347
|
+
if (bytesRemaining() === 0) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
278
350
|
const firstByte = getUint8();
|
|
279
351
|
const totalLength = firstByte;
|
|
280
352
|
if (totalLength === 0) {
|
|
@@ -285,6 +357,9 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
285
357
|
while (((totalLength >> (7 - actualLength)) & 0x01) === 0) {
|
|
286
358
|
actualLength++;
|
|
287
359
|
}
|
|
360
|
+
if (bytesRemaining() < actualLength) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
288
363
|
const slice = getSlice(actualLength);
|
|
289
364
|
const d = [firstByte, ...Array.from(new Uint8Array(slice))];
|
|
290
365
|
actualLength += 1; // Include the first byte set as 1
|
|
@@ -328,6 +403,7 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
328
403
|
return val;
|
|
329
404
|
},
|
|
330
405
|
getUint32,
|
|
406
|
+
getUint64,
|
|
331
407
|
// https://developer.apple.com/documentation/quicktime-file-format/sound_sample_description_version_1
|
|
332
408
|
// A 32-bit unsigned fixed-point number (16.16) that indicates the rate at which the sound samples were obtained.
|
|
333
409
|
getFixedPointUnsigned1616Number: () => {
|
|
@@ -346,7 +422,7 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
346
422
|
const val = getSlice(32);
|
|
347
423
|
return [...Array.from(new Uint8Array(val))];
|
|
348
424
|
},
|
|
349
|
-
|
|
425
|
+
getUint(length) {
|
|
350
426
|
const bytes = getSlice(length);
|
|
351
427
|
const numbers = [...Array.from(new Uint8Array(bytes))];
|
|
352
428
|
return numbers.reduce((acc, byte, index) => acc + (byte << (8 * (numbers.length - index - 1))), 0);
|
package/dist/from-fetch.js
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.fetchReader = void 0;
|
|
4
4
|
exports.fetchReader = {
|
|
5
|
-
read: async (src, range) => {
|
|
5
|
+
read: async (src, range, signal) => {
|
|
6
6
|
if (typeof src !== 'string') {
|
|
7
|
-
throw new Error('src must be a string when using `
|
|
7
|
+
throw new Error('src must be a string when using `fetchReader`');
|
|
8
8
|
}
|
|
9
9
|
const resolvedUrl = typeof window !== 'undefined' && typeof window.location !== 'undefined'
|
|
10
10
|
? new URL(src, window.location.origin).toString()
|
|
@@ -24,20 +24,30 @@ exports.fetchReader = {
|
|
|
24
24
|
: {
|
|
25
25
|
Range: `bytes=${`${range[0]}-${range[1]}`}`,
|
|
26
26
|
},
|
|
27
|
+
signal,
|
|
27
28
|
// Disable Next.js caching
|
|
28
29
|
cache: 'no-store',
|
|
29
30
|
});
|
|
31
|
+
if (res.status.toString().startsWith('4') ||
|
|
32
|
+
res.status.toString().startsWith('5')) {
|
|
33
|
+
throw new Error(`Server returned status code ${res.status} for ${src}`);
|
|
34
|
+
}
|
|
30
35
|
if (!res.body) {
|
|
31
36
|
throw new Error('No body');
|
|
32
37
|
}
|
|
33
38
|
const length = res.headers.get('content-length');
|
|
34
39
|
const contentLength = length === null ? null : parseInt(length, 10);
|
|
35
40
|
const reader = res.body.getReader();
|
|
41
|
+
if (signal) {
|
|
42
|
+
signal.addEventListener('abort', () => {
|
|
43
|
+
reader.cancel();
|
|
44
|
+
}, { once: true });
|
|
45
|
+
}
|
|
36
46
|
return { reader, contentLength };
|
|
37
47
|
},
|
|
38
48
|
getLength: async (src) => {
|
|
39
49
|
if (typeof src !== 'string') {
|
|
40
|
-
throw new Error('src must be a string when using `
|
|
50
|
+
throw new Error('src must be a string when using `fetchReader`');
|
|
41
51
|
}
|
|
42
52
|
const res = await fetch(src, {
|
|
43
53
|
method: 'HEAD',
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.inputTypeFileReader = void 0;
|
|
4
|
+
exports.inputTypeFileReader = {
|
|
5
|
+
read: (file, range) => {
|
|
6
|
+
if (typeof file === 'string') {
|
|
7
|
+
throw new Error('`inputTypeFileReader` only supports `File` objects');
|
|
8
|
+
}
|
|
9
|
+
if (range !== null) {
|
|
10
|
+
throw new Error('`inputTypeFileReader` does not support `range`');
|
|
11
|
+
}
|
|
12
|
+
const part = range === null
|
|
13
|
+
? file
|
|
14
|
+
: typeof range === 'number'
|
|
15
|
+
? file.slice(range)
|
|
16
|
+
: file.slice(range[0], range[1]);
|
|
17
|
+
const reader = new FileReader();
|
|
18
|
+
reader.readAsArrayBuffer(file);
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
reader.onload = () => {
|
|
21
|
+
resolve({
|
|
22
|
+
reader: part.stream().getReader(),
|
|
23
|
+
contentLength: file.size,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
reader.onerror = (error) => {
|
|
27
|
+
reject(error);
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
getLength: (src) => {
|
|
32
|
+
if (typeof src === 'string') {
|
|
33
|
+
throw new Error('`inputTypeFileReader` only supports `File` objects');
|
|
34
|
+
}
|
|
35
|
+
return Promise.resolve(src.size);
|
|
36
|
+
},
|
|
37
|
+
};
|
package/dist/from-node.js
CHANGED
|
@@ -5,7 +5,7 @@ const fs_1 = require("fs");
|
|
|
5
5
|
const promises_1 = require("node:fs/promises");
|
|
6
6
|
const stream_1 = require("stream");
|
|
7
7
|
exports.nodeReader = {
|
|
8
|
-
read: async (src, range) => {
|
|
8
|
+
read: async (src, range, signal) => {
|
|
9
9
|
if (typeof src !== 'string') {
|
|
10
10
|
throw new Error('src must be a string when using `nodeReader`');
|
|
11
11
|
}
|
|
@@ -16,10 +16,17 @@ exports.nodeReader = {
|
|
|
16
16
|
: typeof range === 'number'
|
|
17
17
|
? Infinity
|
|
18
18
|
: range[1],
|
|
19
|
+
signal,
|
|
19
20
|
});
|
|
20
21
|
const stats = await (0, promises_1.stat)(src);
|
|
22
|
+
const reader = stream_1.Readable.toWeb(stream).getReader();
|
|
23
|
+
if (signal) {
|
|
24
|
+
signal.addEventListener('abort', () => {
|
|
25
|
+
reader.cancel();
|
|
26
|
+
}, { once: true });
|
|
27
|
+
}
|
|
21
28
|
return {
|
|
22
|
-
reader
|
|
29
|
+
reader,
|
|
23
30
|
contentLength: stats.size,
|
|
24
31
|
};
|
|
25
32
|
},
|
package/dist/from-web-file.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.webFileReader = void 0;
|
|
4
4
|
exports.webFileReader = {
|
|
5
|
-
read: (file, range) => {
|
|
5
|
+
read: (file, range, signal) => {
|
|
6
6
|
if (typeof file === 'string') {
|
|
7
7
|
throw new Error('`inputTypeFileReader` only supports `File` objects');
|
|
8
8
|
}
|
|
@@ -13,6 +13,11 @@ exports.webFileReader = {
|
|
|
13
13
|
: file.slice(range[0], range[1]);
|
|
14
14
|
const reader = new FileReader();
|
|
15
15
|
reader.readAsArrayBuffer(file);
|
|
16
|
+
if (signal) {
|
|
17
|
+
signal.addEventListener('abort', () => {
|
|
18
|
+
reader.abort();
|
|
19
|
+
}, { once: true });
|
|
20
|
+
}
|
|
16
21
|
return new Promise((resolve, reject) => {
|
|
17
22
|
reader.onload = () => {
|
|
18
23
|
resolve({
|
package/dist/from-web.js
CHANGED
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.webReader = void 0;
|
|
4
4
|
exports.webReader = {
|
|
5
5
|
read: async (src, range) => {
|
|
6
|
+
if (typeof src !== 'string') {
|
|
7
|
+
throw new Error('src must be a string when using `webReader`');
|
|
8
|
+
}
|
|
6
9
|
const resolvedUrl = typeof window !== 'undefined' && typeof window.location !== 'undefined'
|
|
7
10
|
? new URL(src, window.location.origin).toString()
|
|
8
11
|
: src;
|
|
@@ -14,22 +17,28 @@ exports.webReader = {
|
|
|
14
17
|
const res = await fetch(resolvedUrl, {
|
|
15
18
|
headers: range === null
|
|
16
19
|
? {}
|
|
17
|
-
:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
: typeof range === 'number'
|
|
21
|
+
? {
|
|
22
|
+
Range: `bytes=${range}`,
|
|
23
|
+
}
|
|
24
|
+
: {
|
|
25
|
+
Range: `bytes=${`${range[0]}-${range[1]}`}`,
|
|
26
|
+
},
|
|
27
|
+
// Disable Next.js caching
|
|
28
|
+
cache: 'no-store',
|
|
20
29
|
});
|
|
21
30
|
if (!res.body) {
|
|
22
31
|
throw new Error('No body');
|
|
23
32
|
}
|
|
24
33
|
const length = res.headers.get('content-length');
|
|
25
|
-
if (!length) {
|
|
26
|
-
throw new Error('No content-length');
|
|
27
|
-
}
|
|
28
34
|
const contentLength = length === null ? null : parseInt(length, 10);
|
|
29
35
|
const reader = res.body.getReader();
|
|
30
36
|
return { reader, contentLength };
|
|
31
37
|
},
|
|
32
38
|
getLength: async (src) => {
|
|
39
|
+
if (typeof src !== 'string') {
|
|
40
|
+
throw new Error('src must be a string when using `webReader`');
|
|
41
|
+
}
|
|
33
42
|
const res = await fetch(src, {
|
|
34
43
|
method: 'HEAD',
|
|
35
44
|
});
|
|
@@ -14,7 +14,7 @@ export declare const getNumberOfChannelsFromTrak: (trak: TrakBox) => number | nu
|
|
|
14
14
|
export declare const getSampleRate: (trak: TrakBox) => number | null;
|
|
15
15
|
export declare const getAudioCodecFromTrak: (trak: TrakBox) => AudioCodecInfo | null;
|
|
16
16
|
export declare const getAudioCodecFromIso: (moov: MoovBox) => AudioCodecInfo | null;
|
|
17
|
-
export declare const getAudioCodecFromMatroska: (mainSegment: MainSegment) => "
|
|
17
|
+
export declare const getAudioCodecFromMatroska: (mainSegment: MainSegment) => "aac" | "mp3" | "opus" | "pcm" | "vorbis" | null;
|
|
18
18
|
export declare const getAudioCodecStringFromTrak: (trak: TrakBox) => {
|
|
19
19
|
codecString: string;
|
|
20
20
|
description: Uint8Array | undefined;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getVideoCodec = exports.hasVideoCodec = void 0;
|
|
4
|
+
const hasVideoCodec = (boxes) => {
|
|
5
|
+
try {
|
|
6
|
+
return boxes.some((b) => b.type === 'ftyp-box');
|
|
7
|
+
}
|
|
8
|
+
catch (err) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
exports.hasVideoCodec = hasVideoCodec;
|
|
13
|
+
const getVideoCodec = (boxes) => {
|
|
14
|
+
const ftypBox = boxes.find((b) => b.type === 'ftyp-box');
|
|
15
|
+
if (ftypBox && ftypBox.type === 'ftyp-box') {
|
|
16
|
+
if (ftypBox.compatibleBrands.find((b) => b === 'avc1')) {
|
|
17
|
+
return 'h264';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
};
|
|
22
|
+
exports.getVideoCodec = getVideoCodec;
|
|
@@ -38,7 +38,7 @@ const getSamplePositions = ({ stcoBox, stszBox, stscBox, stssBox, sttsBox, cttsB
|
|
|
38
38
|
const ctsOffset = cttsEntries[samples.length];
|
|
39
39
|
const cts = dts + ctsOffset;
|
|
40
40
|
samples.push({
|
|
41
|
-
offset: chunks[i] + offsetInThisChunk,
|
|
41
|
+
offset: Number(chunks[i]) + offsetInThisChunk,
|
|
42
42
|
size,
|
|
43
43
|
isKeyframe,
|
|
44
44
|
dts,
|
package/dist/has-all-info.js
CHANGED
|
@@ -20,7 +20,7 @@ const hasAllInfo = (options, parseResult, state) => {
|
|
|
20
20
|
}
|
|
21
21
|
if (key === 'dimensions' ||
|
|
22
22
|
key === 'rotation' ||
|
|
23
|
-
key === '
|
|
23
|
+
key === 'unrotatedDimensions') {
|
|
24
24
|
return (0, get_dimensions_1.hasDimensions)(parseResult.segments, state);
|
|
25
25
|
}
|
|
26
26
|
if (key === 'fps') {
|
package/dist/options.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export type Options<EnableDimensions extends boolean, EnableDuration extends boo
|
|
|
15
15
|
audioCodec?: EnableAudioCodec;
|
|
16
16
|
tracks?: EnableTracks;
|
|
17
17
|
rotation?: EnableRotation;
|
|
18
|
-
|
|
18
|
+
unrotatedDimensions?: EnableUnrotatedDimensions;
|
|
19
19
|
internalStats?: EnableInternalStats;
|
|
20
20
|
};
|
|
21
21
|
export type Metadata<EnableDimensions extends boolean, EnableDuration extends boolean, EnableBoxes extends boolean, EnableFps extends boolean, EnableVideoCodec extends boolean, EnableAudioCodec extends boolean, EnableTracks extends boolean, EnableRotation extends boolean, EnableUnrotatedDimensions extends boolean, EnableInternalStats extends boolean> = (EnableDimensions extends true ? {
|
|
@@ -36,7 +36,7 @@ export type Metadata<EnableDimensions extends boolean, EnableDuration extends bo
|
|
|
36
36
|
} : {}) & (EnableRotation extends true ? {
|
|
37
37
|
rotation: number | null;
|
|
38
38
|
} : {}) & (EnableUnrotatedDimensions extends true ? {
|
|
39
|
-
|
|
39
|
+
unrotatedDimensions: Dimensions;
|
|
40
40
|
} : {}) & (EnableInternalStats extends true ? {
|
|
41
41
|
internalStats: InternalStats;
|
|
42
42
|
} : {});
|
|
@@ -46,4 +46,5 @@ export type ParseMedia = <EnableDimensions extends boolean, EnableDuration exten
|
|
|
46
46
|
reader?: ReaderInterface;
|
|
47
47
|
onAudioTrack?: OnAudioTrack;
|
|
48
48
|
onVideoTrack?: OnVideoTrack;
|
|
49
|
+
signal?: AbortSignal;
|
|
49
50
|
}) => Promise<Metadata<EnableDimensions, EnableDuration, EnableBoxes, EnableFps, EnableVideoCodec, EnableAudioCodec, EnableTracks, EnableRotation, EnableUnrotatedDimensions, EnableInternalStats>>;
|
package/dist/parse-media.js
CHANGED
|
@@ -12,16 +12,17 @@ const get_video_codec_1 = require("./get-video-codec");
|
|
|
12
12
|
const has_all_info_1 = require("./has-all-info");
|
|
13
13
|
const parse_video_1 = require("./parse-video");
|
|
14
14
|
const parser_state_1 = require("./parser-state");
|
|
15
|
-
const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.fetchReader, onAudioTrack, onVideoTrack, }) => {
|
|
16
|
-
const { reader, contentLength } = await readerInterface.read(src, null);
|
|
17
|
-
let currentReader = reader;
|
|
18
|
-
const returnValue = {};
|
|
19
|
-
let iterator = null;
|
|
20
|
-
let parseResult = null;
|
|
15
|
+
const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.fetchReader, onAudioTrack, onVideoTrack, signal, }) => {
|
|
21
16
|
const state = (0, parser_state_1.makeParserState)({
|
|
22
17
|
hasAudioCallbacks: onAudioTrack !== null,
|
|
23
18
|
hasVideoCallbacks: onVideoTrack !== null,
|
|
19
|
+
signal,
|
|
24
20
|
});
|
|
21
|
+
const { reader, contentLength } = await readerInterface.read(src, null, signal);
|
|
22
|
+
let currentReader = reader;
|
|
23
|
+
const returnValue = {};
|
|
24
|
+
let iterator = null;
|
|
25
|
+
let parseResult = null;
|
|
25
26
|
const options = {
|
|
26
27
|
canSkipVideoData: !(onAudioTrack || onVideoTrack),
|
|
27
28
|
onAudioTrack: onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : null,
|
|
@@ -29,6 +30,9 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
|
|
|
29
30
|
parserState: state,
|
|
30
31
|
};
|
|
31
32
|
while (parseResult === null || parseResult.status === 'incomplete') {
|
|
33
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
34
|
+
throw new Error('Aborted');
|
|
35
|
+
}
|
|
32
36
|
const result = await currentReader.read();
|
|
33
37
|
if (iterator) {
|
|
34
38
|
if (!result.done) {
|
|
@@ -66,7 +70,7 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
|
|
|
66
70
|
if (!currentReader.closed) {
|
|
67
71
|
currentReader.cancel(new Error('skipped ahead'));
|
|
68
72
|
}
|
|
69
|
-
const { reader: newReader } = await readerInterface.read(src, parseResult.skipTo);
|
|
73
|
+
const { reader: newReader } = await readerInterface.read(src, parseResult.skipTo, signal);
|
|
70
74
|
currentReader = newReader;
|
|
71
75
|
iterator.skipTo(parseResult.skipTo);
|
|
72
76
|
}
|
|
@@ -81,9 +85,9 @@ const parseMedia = async ({ src, fields, reader: readerInterface = from_fetch_1.
|
|
|
81
85
|
height: dimensions.height,
|
|
82
86
|
};
|
|
83
87
|
}
|
|
84
|
-
if (fields === null || fields === void 0 ? void 0 : fields.
|
|
88
|
+
if (fields === null || fields === void 0 ? void 0 : fields.unrotatedDimensions) {
|
|
85
89
|
const dimensions = (0, get_dimensions_1.getDimensions)(parseResult.segments, state);
|
|
86
|
-
returnValue.
|
|
90
|
+
returnValue.unrotatedDimensions = {
|
|
87
91
|
width: dimensions.unrotatedWidth,
|
|
88
92
|
height: dimensions.unrotatedHeight,
|
|
89
93
|
};
|
package/dist/parse-video.js
CHANGED
|
@@ -17,6 +17,21 @@ const parseVideo = ({ iterator, options, }) => {
|
|
|
17
17
|
skipTo: null,
|
|
18
18
|
});
|
|
19
19
|
}
|
|
20
|
+
if (iterator.isRiff()) {
|
|
21
|
+
throw new Error('AVI files are not yet supported');
|
|
22
|
+
/*
|
|
23
|
+
iterator.discard(4);
|
|
24
|
+
return parseBoxes({
|
|
25
|
+
iterator,
|
|
26
|
+
maxBytes: Infinity,
|
|
27
|
+
allowIncompleteBoxes: true,
|
|
28
|
+
initialBoxes: [],
|
|
29
|
+
options,
|
|
30
|
+
continueMdat: false,
|
|
31
|
+
littleEndian: true,
|
|
32
|
+
});
|
|
33
|
+
*/
|
|
34
|
+
}
|
|
20
35
|
if (iterator.isIsoBaseMedia()) {
|
|
21
36
|
return (0, process_box_1.parseBoxes)({
|
|
22
37
|
iterator,
|
|
@@ -25,6 +40,7 @@ const parseVideo = ({ iterator, options, }) => {
|
|
|
25
40
|
initialBoxes: [],
|
|
26
41
|
options,
|
|
27
42
|
continueMdat: false,
|
|
43
|
+
littleEndian: false,
|
|
28
44
|
});
|
|
29
45
|
}
|
|
30
46
|
if (iterator.isWebm()) {
|
package/dist/parser-state.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import type { OnTrackEntrySegment } from './boxes/webm/segments';
|
|
2
|
-
import type {
|
|
2
|
+
import type { TrackInfo } from './boxes/webm/segments/track-entry';
|
|
3
3
|
import type { AudioSample, OnAudioSample, OnVideoSample, VideoSample } from './webcodec-sample-types';
|
|
4
4
|
export type InternalStats = {};
|
|
5
|
-
export declare const makeParserState: ({ hasAudioCallbacks, hasVideoCallbacks, }: {
|
|
5
|
+
export declare const makeParserState: ({ hasAudioCallbacks, hasVideoCallbacks, signal, }: {
|
|
6
6
|
hasAudioCallbacks: boolean;
|
|
7
7
|
hasVideoCallbacks: boolean;
|
|
8
|
+
signal: AbortSignal | undefined;
|
|
8
9
|
}) => {
|
|
9
10
|
onTrackEntrySegment: OnTrackEntrySegment;
|
|
10
|
-
getTrackInfoByNumber: (id: number) =>
|
|
11
|
+
getTrackInfoByNumber: (id: number) => TrackInfo;
|
|
11
12
|
registerVideoSampleCallback: (id: number, callback: OnVideoSample | null) => Promise<void>;
|
|
12
13
|
setTimestampOffset: (byteOffset: number, timestamp: number) => void;
|
|
13
14
|
getTimestampOffsetForByteOffset: (byteOffset: number) => number | undefined;
|
package/dist/parser-state.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.makeParserState = void 0;
|
|
4
4
|
const traversal_1 = require("./boxes/webm/traversal");
|
|
5
5
|
const traversal_2 = require("./traversal");
|
|
6
|
-
const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, }) => {
|
|
6
|
+
const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, signal, }) => {
|
|
7
7
|
const trackEntries = {};
|
|
8
8
|
const onTrackEntrySegment = (trackEntry) => {
|
|
9
9
|
const trackId = (0, traversal_2.getTrackId)(trackEntry);
|
|
@@ -17,7 +17,11 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, }) => {
|
|
|
17
17
|
if (!codec) {
|
|
18
18
|
throw new Error('Expected codec');
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
const trackTimescale = (0, traversal_1.getTrackTimestampScale)(trackEntry);
|
|
21
|
+
trackEntries[trackId] = {
|
|
22
|
+
codec: codec.codec,
|
|
23
|
+
trackTimescale,
|
|
24
|
+
};
|
|
21
25
|
};
|
|
22
26
|
const videoSampleCallbacks = {};
|
|
23
27
|
const audioSampleCallbacks = {};
|
|
@@ -26,8 +30,10 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, }) => {
|
|
|
26
30
|
const declinedTrackNumbers = [];
|
|
27
31
|
let timescale = null;
|
|
28
32
|
const getTimescale = () => {
|
|
33
|
+
// https://www.matroska.org/technical/notes.html
|
|
34
|
+
// When using the default value of TimestampScale of “1,000,000”, one Segment Tick represents one millisecond.
|
|
29
35
|
if (timescale === null) {
|
|
30
|
-
|
|
36
|
+
return 1000000;
|
|
31
37
|
}
|
|
32
38
|
return timescale;
|
|
33
39
|
};
|
|
@@ -85,6 +91,9 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, }) => {
|
|
|
85
91
|
queuedAudioSamples[id] = [];
|
|
86
92
|
},
|
|
87
93
|
onAudioSample: async (trackId, audioSample) => {
|
|
94
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
95
|
+
throw new Error('Aborted');
|
|
96
|
+
}
|
|
88
97
|
const callback = audioSampleCallbacks[trackId];
|
|
89
98
|
if (callback) {
|
|
90
99
|
await callback(audioSample);
|
|
@@ -99,6 +108,9 @@ const makeParserState = ({ hasAudioCallbacks, hasVideoCallbacks, }) => {
|
|
|
99
108
|
}
|
|
100
109
|
},
|
|
101
110
|
onVideoSample: async (trackId, videoSample) => {
|
|
111
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
112
|
+
throw new Error('Aborted');
|
|
113
|
+
}
|
|
102
114
|
const callback = videoSampleCallbacks[trackId];
|
|
103
115
|
if (callback) {
|
|
104
116
|
await callback(videoSample);
|
package/dist/reader.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ type ReadResult = {
|
|
|
2
2
|
reader: ReadableStreamDefaultReader<Uint8Array>;
|
|
3
3
|
contentLength: number | null;
|
|
4
4
|
};
|
|
5
|
-
type ReadContent = (src: string | File, range: [number, number] | number | null) => Promise<ReadResult>;
|
|
5
|
+
type ReadContent = (src: string | File, range: [number, number] | number | null, signal: AbortSignal | undefined) => Promise<ReadResult>;
|
|
6
6
|
type GetLength = (src: string | File) => Promise<number>;
|
|
7
7
|
export type ReaderInterface = {
|
|
8
8
|
read: ReadContent;
|