@remotion/media-parser 4.0.200 → 4.0.202
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/mvhd.js +2 -2
- 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/keys.js +1 -1
- 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/av1-codec-private.js +1 -1
- package/dist/boxes/webm/bitstream/av1.js +10 -1
- package/dist/boxes/webm/description.d.ts +2 -2
- package/dist/boxes/webm/description.js +2 -2
- package/dist/boxes/webm/ebml.d.ts +2 -2
- package/dist/boxes/webm/ebml.js +23 -1
- package/dist/boxes/webm/get-ready-tracks.d.ts +1 -1
- package/dist/boxes/webm/get-ready-tracks.js +3 -3
- package/dist/boxes/webm/get-sample-from-block.d.ts +17 -0
- package/dist/boxes/webm/get-sample-from-block.js +78 -0
- package/dist/boxes/webm/get-track.d.ts +2 -2
- package/dist/boxes/webm/get-track.js +26 -25
- package/dist/boxes/webm/make-header.d.ts +3 -1
- package/dist/boxes/webm/make-header.js +90 -32
- package/dist/boxes/webm/parse-ebml.d.ts +12 -0
- package/dist/boxes/webm/parse-ebml.js +175 -0
- package/dist/boxes/webm/parse-webm-header.js +8 -9
- package/dist/boxes/webm/segments/all-segments.d.ts +572 -1
- package/dist/boxes/webm/segments/all-segments.js +353 -2
- package/dist/boxes/webm/segments/track-entry.d.ts +5 -189
- package/dist/boxes/webm/segments/track-entry.js +2 -457
- package/dist/boxes/webm/segments.d.ts +3 -16
- package/dist/boxes/webm/segments.js +40 -219
- package/dist/boxes/webm/traversal.d.ts +5 -5
- package/dist/boxes/webm/traversal.js +17 -6
- package/dist/buffer-iterator.d.ts +10 -7
- package/dist/buffer-iterator.js +83 -7
- package/dist/create/create-media.d.ts +2 -0
- package/dist/create/create-media.js +36 -0
- package/dist/create/matroska-header.d.ts +1 -0
- package/dist/create/matroska-header.js +66 -0
- package/dist/create/matroska-info.d.ts +4 -0
- package/dist/create/matroska-info.js +39 -0
- package/dist/create/matroska-segment.d.ts +1 -0
- package/dist/create/matroska-segment.js +12 -0
- package/dist/create/matroska-trackentry.d.ts +21 -0
- package/dist/create/matroska-trackentry.js +191 -0
- package/dist/create-media.d.ts +1 -0
- package/dist/create-media.js +78 -0
- 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 +2 -2
- package/dist/get-audio-codec.js +13 -13
- package/dist/get-codec.d.ts +4 -0
- package/dist/get-codec.js +22 -0
- package/dist/get-duration.js +12 -14
- package/dist/get-sample-positions.js +1 -1
- package/dist/get-tracks.js +2 -2
- package/dist/get-video-codec.js +13 -13
- package/dist/has-all-info.js +1 -1
- package/dist/options.d.ts +3 -2
- package/dist/parse-media.js +17 -10
- package/dist/parse-video.js +16 -0
- package/dist/parser-context.d.ts +1 -0
- package/dist/parser-state.d.ts +4 -3
- package/dist/parser-state.js +16 -3
- package/dist/reader.d.ts +1 -1
- package/dist/readers/from-fetch.d.ts +2 -0
- package/dist/readers/from-fetch.js +64 -0
- package/dist/readers/from-node.d.ts +2 -0
- package/dist/readers/from-node.js +40 -0
- package/dist/readers/from-web-file.d.ts +2 -0
- package/dist/readers/from-web-file.js +39 -0
- package/dist/readers/reader.d.ts +11 -0
- package/dist/readers/reader.js +2 -0
- package/dist/traversal.d.ts +19 -17
- package/dist/traversal.js +38 -39
- package/dist/web-file.d.ts +2 -0
- package/dist/web-file.js +37 -0
- package/dist/writers/web-fs.d.ts +2 -0
- package/dist/writers/web-fs.js +28 -0
- package/dist/writers/writer.d.ts +9 -0
- package/dist/writers/writer.js +2 -0
- package/input.webm +0 -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/mvhd.ts +2 -2
- package/src/boxes/iso-base-media/process-box.ts +70 -40
- package/src/boxes/iso-base-media/stsd/keys.ts +1 -1
- 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/av1-codec-private.ts +1 -1
- package/src/boxes/webm/description.ts +7 -4
- package/src/boxes/webm/ebml.ts +24 -4
- package/src/boxes/webm/get-ready-tracks.ts +4 -4
- package/src/boxes/webm/get-sample-from-block.ts +125 -0
- package/src/boxes/webm/get-track.ts +38 -31
- package/src/boxes/webm/make-header.ts +129 -32
- package/src/boxes/webm/parse-ebml.ts +247 -0
- package/src/boxes/webm/parse-webm-header.ts +8 -12
- package/src/boxes/webm/segments/all-segments.ts +539 -1
- package/src/boxes/webm/segments/track-entry.ts +5 -843
- package/src/boxes/webm/segments.ts +48 -435
- package/src/boxes/webm/traversal.ts +28 -15
- package/src/buffer-iterator.ts +104 -10
- 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-audio-codec.ts +14 -16
- package/src/get-duration.ts +15 -16
- package/src/get-sample-positions.ts +1 -1
- package/src/get-tracks.ts +2 -2
- package/src/get-video-codec.ts +13 -15
- package/src/has-all-info.ts +1 -1
- package/src/options.ts +3 -2
- package/src/parse-media.ts +20 -9
- package/src/parse-video.ts +17 -0
- package/src/parser-context.ts +1 -0
- package/src/parser-state.ts +22 -5
- package/src/reader.ts +1 -0
- package/src/test/create-matroska.test.ts +255 -7
- package/src/test/matroska.test.ts +311 -334
- package/src/test/mvhd.test.ts +1 -1
- package/src/test/parse-esds.test.ts +2 -2
- package/src/test/parse-stco.test.ts +4 -2
- package/src/test/parse-stsc.test.ts +2 -2
- package/src/test/parse-stsz.test.ts +2 -2
- package/src/test/parse-stts.test.ts +1 -1
- package/src/test/stream-local.test.ts +23 -9
- package/src/test/stream-remote.test.ts +23 -19
- package/src/test/stsd.test.ts +6 -2
- package/src/test/tkhd.test.ts +1 -1
- package/src/traversal.ts +62 -85
- 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/duration.ts +0 -29
- package/src/boxes/webm/segments/info.ts +0 -34
- package/src/boxes/webm/segments/main.ts +0 -6
- package/src/boxes/webm/segments/muxing.ts +0 -18
- package/src/boxes/webm/segments/seek-head.ts +0 -34
- package/src/boxes/webm/segments/seek-position.ts +0 -18
- package/src/boxes/webm/segments/seek.ts +0 -45
- package/src/boxes/webm/segments/timestamp-scale.ts +0 -17
- package/src/boxes/webm/segments/tracks.ts +0 -32
- package/src/boxes/webm/segments/unknown.ts +0 -19
- package/src/boxes/webm/segments/void.ts +0 -18
- package/src/boxes/webm/segments/writing.ts +0 -18
- package/src/combine-uint8array.ts +0 -13
- /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/src/buffer-iterator.ts
CHANGED
|
@@ -48,6 +48,7 @@ export class OffsetCounter {
|
|
|
48
48
|
|
|
49
49
|
const isoBaseMediaMp4Pattern = new TextEncoder().encode('ftyp');
|
|
50
50
|
const mpegPattern = new Uint8Array([0xff, 0xf3, 0xe4, 0x64]);
|
|
51
|
+
const riffPattern = new Uint8Array([0x52, 0x49, 0x46, 0x46]);
|
|
51
52
|
|
|
52
53
|
const matchesPattern = (pattern: Uint8Array) => {
|
|
53
54
|
return (data: Uint8Array) => {
|
|
@@ -61,10 +62,13 @@ const makeOffsetCounter = (): OffsetCounter => {
|
|
|
61
62
|
|
|
62
63
|
export const getArrayBufferIterator = (
|
|
63
64
|
initialData: Uint8Array,
|
|
64
|
-
maxBytes
|
|
65
|
+
maxBytes: number | null,
|
|
65
66
|
) => {
|
|
66
67
|
const buf = new ArrayBuffer(initialData.byteLength, {
|
|
67
|
-
maxByteLength:
|
|
68
|
+
maxByteLength:
|
|
69
|
+
maxBytes === null
|
|
70
|
+
? initialData.byteLength
|
|
71
|
+
: Math.min(maxBytes as number, 2 ** 32),
|
|
68
72
|
});
|
|
69
73
|
if (!buf.resize) {
|
|
70
74
|
throw new Error(
|
|
@@ -95,7 +99,61 @@ export const getArrayBufferIterator = (
|
|
|
95
99
|
return val;
|
|
96
100
|
};
|
|
97
101
|
|
|
98
|
-
const
|
|
102
|
+
const getEightByteNumber = (littleEndian = false) => {
|
|
103
|
+
if (littleEndian) {
|
|
104
|
+
const one = getUint8();
|
|
105
|
+
const two = getUint8();
|
|
106
|
+
const three = getUint8();
|
|
107
|
+
const four = getUint8();
|
|
108
|
+
const five = getUint8();
|
|
109
|
+
const six = getUint8();
|
|
110
|
+
const seven = getUint8();
|
|
111
|
+
const eight = getUint8();
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
(eight << 56) |
|
|
115
|
+
(seven << 48) |
|
|
116
|
+
(six << 40) |
|
|
117
|
+
(five << 32) |
|
|
118
|
+
(four << 24) |
|
|
119
|
+
(three << 16) |
|
|
120
|
+
(two << 8) |
|
|
121
|
+
one
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function byteArrayToBigInt(byteArray: number[]): BigInt {
|
|
126
|
+
let result = BigInt(0);
|
|
127
|
+
for (let i = 0; i < byteArray.length; i++) {
|
|
128
|
+
result = (result << BigInt(8)) + BigInt(byteArray[i]);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const bigInt = byteArrayToBigInt([
|
|
135
|
+
getUint8(),
|
|
136
|
+
getUint8(),
|
|
137
|
+
getUint8(),
|
|
138
|
+
getUint8(),
|
|
139
|
+
getUint8(),
|
|
140
|
+
getUint8(),
|
|
141
|
+
getUint8(),
|
|
142
|
+
getUint8(),
|
|
143
|
+
]);
|
|
144
|
+
|
|
145
|
+
return Number(bigInt);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const getFourByteNumber = (littleEndian = false) => {
|
|
149
|
+
if (littleEndian) {
|
|
150
|
+
const one = getUint8();
|
|
151
|
+
const two = getUint8();
|
|
152
|
+
const three = getUint8();
|
|
153
|
+
const four = getUint8();
|
|
154
|
+
return (four << 24) | (three << 16) | (two << 8) | one;
|
|
155
|
+
}
|
|
156
|
+
|
|
99
157
|
return (
|
|
100
158
|
(getUint8() << 24) | (getUint8() << 16) | (getUint8() << 8) | getUint8()
|
|
101
159
|
);
|
|
@@ -110,12 +168,18 @@ export const getArrayBufferIterator = (
|
|
|
110
168
|
return lastInt;
|
|
111
169
|
};
|
|
112
170
|
|
|
113
|
-
const getUint32 = () => {
|
|
114
|
-
const val = view.getUint32(counter.getDiscardedOffset());
|
|
171
|
+
const getUint32 = (littleEndian = false) => {
|
|
172
|
+
const val = view.getUint32(counter.getDiscardedOffset(), littleEndian);
|
|
115
173
|
counter.increment(4);
|
|
116
174
|
return val;
|
|
117
175
|
};
|
|
118
176
|
|
|
177
|
+
const getUint64 = (littleEndian = false) => {
|
|
178
|
+
const val = view.getBigUint64(counter.getDiscardedOffset(), littleEndian);
|
|
179
|
+
counter.increment(8);
|
|
180
|
+
return val;
|
|
181
|
+
};
|
|
182
|
+
|
|
119
183
|
const getUint32Le = () => {
|
|
120
184
|
const val = view.getUint32(counter.getDiscardedOffset(), true);
|
|
121
185
|
counter.increment(4);
|
|
@@ -156,6 +220,10 @@ export const getArrayBufferIterator = (
|
|
|
156
220
|
return matchesPattern(isoBaseMediaMp4Pattern)(data.subarray(4, 8));
|
|
157
221
|
};
|
|
158
222
|
|
|
223
|
+
const isRiff = () => {
|
|
224
|
+
return matchesPattern(riffPattern)(data.subarray(0, 4));
|
|
225
|
+
};
|
|
226
|
+
|
|
159
227
|
const isWebm = () => {
|
|
160
228
|
return matchesPattern(webmPattern)(data.subarray(0, 4));
|
|
161
229
|
};
|
|
@@ -186,7 +254,6 @@ export const getArrayBufferIterator = (
|
|
|
186
254
|
counter.decrement(counter.getOffset() - offset);
|
|
187
255
|
counter.setDiscardedOffset(offset);
|
|
188
256
|
} else {
|
|
189
|
-
buf.resize(offset);
|
|
190
257
|
const currentOffset = counter.getOffset();
|
|
191
258
|
counter.increment(offset - currentOffset);
|
|
192
259
|
removeBytesRead();
|
|
@@ -276,19 +343,25 @@ export const getArrayBufferIterator = (
|
|
|
276
343
|
bytesRemaining,
|
|
277
344
|
isIsoBaseMedia,
|
|
278
345
|
leb128,
|
|
279
|
-
|
|
346
|
+
removeBytesRead,
|
|
280
347
|
isWebm,
|
|
281
348
|
discard: (length: number) => {
|
|
282
349
|
counter.increment(length);
|
|
283
350
|
},
|
|
351
|
+
getEightByteNumber,
|
|
284
352
|
getFourByteNumber,
|
|
285
353
|
getSlice,
|
|
286
354
|
getAtom: () => {
|
|
287
355
|
const atom = getSlice(4);
|
|
288
356
|
return new TextDecoder().decode(atom);
|
|
289
357
|
},
|
|
358
|
+
isRiff,
|
|
290
359
|
getPaddedFourByteNumber,
|
|
291
|
-
getMatroskaSegmentId: () => {
|
|
360
|
+
getMatroskaSegmentId: (): string | null => {
|
|
361
|
+
if (bytesRemaining() === 0) {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
|
|
292
365
|
const first = getSlice(1);
|
|
293
366
|
const firstOneString = `0x${Array.from(new Uint8Array(first))
|
|
294
367
|
.map((b) => {
|
|
@@ -303,6 +376,10 @@ export const getArrayBufferIterator = (
|
|
|
303
376
|
return firstOneString;
|
|
304
377
|
}
|
|
305
378
|
|
|
379
|
+
if (bytesRemaining() === 0) {
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
|
|
306
383
|
const firstTwo = getSlice(1);
|
|
307
384
|
|
|
308
385
|
const firstTwoString = `${firstOneString}${Array.from(
|
|
@@ -317,6 +394,10 @@ export const getArrayBufferIterator = (
|
|
|
317
394
|
return firstTwoString;
|
|
318
395
|
}
|
|
319
396
|
|
|
397
|
+
if (bytesRemaining() === 0) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
|
|
320
401
|
const firstThree = getSlice(1);
|
|
321
402
|
|
|
322
403
|
const firstThreeString = `${firstTwoString}${Array.from(
|
|
@@ -331,6 +412,10 @@ export const getArrayBufferIterator = (
|
|
|
331
412
|
return firstThreeString;
|
|
332
413
|
}
|
|
333
414
|
|
|
415
|
+
if (bytesRemaining() === 0) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
|
|
334
419
|
const segmentId = getSlice(1);
|
|
335
420
|
|
|
336
421
|
return `${firstThreeString}${Array.from(new Uint8Array(segmentId))
|
|
@@ -339,7 +424,11 @@ export const getArrayBufferIterator = (
|
|
|
339
424
|
})
|
|
340
425
|
.join('')}`;
|
|
341
426
|
},
|
|
342
|
-
getVint: () => {
|
|
427
|
+
getVint: (): number | null => {
|
|
428
|
+
if (bytesRemaining() === 0) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
|
|
343
432
|
const firstByte = getUint8();
|
|
344
433
|
const totalLength = firstByte;
|
|
345
434
|
|
|
@@ -353,6 +442,10 @@ export const getArrayBufferIterator = (
|
|
|
353
442
|
actualLength++;
|
|
354
443
|
}
|
|
355
444
|
|
|
445
|
+
if (bytesRemaining() < actualLength) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
|
|
356
449
|
const slice = getSlice(actualLength);
|
|
357
450
|
const d = [firstByte, ...Array.from(new Uint8Array(slice))];
|
|
358
451
|
|
|
@@ -402,6 +495,7 @@ export const getArrayBufferIterator = (
|
|
|
402
495
|
return val;
|
|
403
496
|
},
|
|
404
497
|
getUint32,
|
|
498
|
+
getUint64,
|
|
405
499
|
// https://developer.apple.com/documentation/quicktime-file-format/sound_sample_description_version_1
|
|
406
500
|
// A 32-bit unsigned fixed-point number (16.16) that indicates the rate at which the sound samples were obtained.
|
|
407
501
|
getFixedPointUnsigned1616Number: () => {
|
|
@@ -420,7 +514,7 @@ export const getArrayBufferIterator = (
|
|
|
420
514
|
const val = getSlice(32);
|
|
421
515
|
return [...Array.from(new Uint8Array(val))];
|
|
422
516
|
},
|
|
423
|
-
|
|
517
|
+
getUint(length: number): number {
|
|
424
518
|
const bytes = getSlice(length);
|
|
425
519
|
const numbers = [...Array.from(new Uint8Array(bytes))];
|
|
426
520
|
return numbers.reduce(
|
package/src/from-fetch.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type {ReaderInterface} from './reader';
|
|
2
2
|
|
|
3
3
|
export const fetchReader: ReaderInterface = {
|
|
4
|
-
read: async (src, range) => {
|
|
4
|
+
read: async (src, range, signal) => {
|
|
5
5
|
if (typeof src !== 'string') {
|
|
6
|
-
throw new Error('src must be a string when using `
|
|
6
|
+
throw new Error('src must be a string when using `fetchReader`');
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const resolvedUrl =
|
|
@@ -34,9 +34,18 @@ export const fetchReader: ReaderInterface = {
|
|
|
34
34
|
: {
|
|
35
35
|
Range: `bytes=${`${range[0]}-${range[1]}`}`,
|
|
36
36
|
},
|
|
37
|
+
signal,
|
|
37
38
|
// Disable Next.js caching
|
|
38
39
|
cache: 'no-store',
|
|
39
40
|
});
|
|
41
|
+
|
|
42
|
+
if (
|
|
43
|
+
res.status.toString().startsWith('4') ||
|
|
44
|
+
res.status.toString().startsWith('5')
|
|
45
|
+
) {
|
|
46
|
+
throw new Error(`Server returned status code ${res.status} for ${src}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
40
49
|
if (!res.body) {
|
|
41
50
|
throw new Error('No body');
|
|
42
51
|
}
|
|
@@ -47,11 +56,21 @@ export const fetchReader: ReaderInterface = {
|
|
|
47
56
|
|
|
48
57
|
const reader = res.body.getReader();
|
|
49
58
|
|
|
59
|
+
if (signal) {
|
|
60
|
+
signal.addEventListener(
|
|
61
|
+
'abort',
|
|
62
|
+
() => {
|
|
63
|
+
reader.cancel();
|
|
64
|
+
},
|
|
65
|
+
{once: true},
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
50
69
|
return {reader, contentLength};
|
|
51
70
|
},
|
|
52
71
|
getLength: async (src) => {
|
|
53
72
|
if (typeof src !== 'string') {
|
|
54
|
-
throw new Error('src must be a string when using `
|
|
73
|
+
throw new Error('src must be a string when using `fetchReader`');
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
const res = await fetch(src, {
|
package/src/from-node.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {Readable} from 'stream';
|
|
|
4
4
|
import type {ReaderInterface} from './reader';
|
|
5
5
|
|
|
6
6
|
export const nodeReader: ReaderInterface = {
|
|
7
|
-
read: async (src, range) => {
|
|
7
|
+
read: async (src, range, signal) => {
|
|
8
8
|
if (typeof src !== 'string') {
|
|
9
9
|
throw new Error('src must be a string when using `nodeReader`');
|
|
10
10
|
}
|
|
@@ -17,12 +17,26 @@ export const nodeReader: ReaderInterface = {
|
|
|
17
17
|
: typeof range === 'number'
|
|
18
18
|
? Infinity
|
|
19
19
|
: range[1],
|
|
20
|
+
signal,
|
|
20
21
|
});
|
|
21
22
|
const stats = await stat(src);
|
|
23
|
+
|
|
24
|
+
const reader = Readable.toWeb(
|
|
25
|
+
stream,
|
|
26
|
+
).getReader() as ReadableStreamDefaultReader<Uint8Array>;
|
|
27
|
+
|
|
28
|
+
if (signal) {
|
|
29
|
+
signal.addEventListener(
|
|
30
|
+
'abort',
|
|
31
|
+
() => {
|
|
32
|
+
reader.cancel();
|
|
33
|
+
},
|
|
34
|
+
{once: true},
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
return {
|
|
23
|
-
reader
|
|
24
|
-
stream,
|
|
25
|
-
).getReader() as ReadableStreamDefaultReader<Uint8Array>,
|
|
39
|
+
reader,
|
|
26
40
|
contentLength: stats.size,
|
|
27
41
|
};
|
|
28
42
|
},
|
package/src/from-web-file.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {ReaderInterface} from './reader';
|
|
2
2
|
|
|
3
3
|
export const webFileReader: ReaderInterface = {
|
|
4
|
-
read: (file, range) => {
|
|
4
|
+
read: (file, range, signal) => {
|
|
5
5
|
if (typeof file === 'string') {
|
|
6
6
|
throw new Error('`inputTypeFileReader` only supports `File` objects');
|
|
7
7
|
}
|
|
@@ -16,6 +16,16 @@ export const webFileReader: ReaderInterface = {
|
|
|
16
16
|
const reader = new FileReader();
|
|
17
17
|
reader.readAsArrayBuffer(file);
|
|
18
18
|
|
|
19
|
+
if (signal) {
|
|
20
|
+
signal.addEventListener(
|
|
21
|
+
'abort',
|
|
22
|
+
() => {
|
|
23
|
+
reader.abort();
|
|
24
|
+
},
|
|
25
|
+
{once: true},
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
19
29
|
return new Promise((resolve, reject) => {
|
|
20
30
|
reader.onload = () => {
|
|
21
31
|
resolve({
|
package/src/get-audio-codec.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type {EsdsBox} from './boxes/iso-base-media/esds/esds';
|
|
|
3
3
|
import type {MoovBox} from './boxes/iso-base-media/moov/moov';
|
|
4
4
|
import type {AudioSample} from './boxes/iso-base-media/stsd/samples';
|
|
5
5
|
import type {TrakBox} from './boxes/iso-base-media/trak/trak';
|
|
6
|
-
import type {MainSegment} from './boxes/webm/segments/
|
|
6
|
+
import type {MainSegment} from './boxes/webm/segments/all-segments';
|
|
7
7
|
import {trakBoxContainsAudio} from './get-fps';
|
|
8
8
|
import type {KnownAudioCodecs} from './options';
|
|
9
9
|
import type {AnySegment} from './parse-result';
|
|
@@ -163,34 +163,32 @@ export const getAudioCodecFromIso = (moov: MoovBox) => {
|
|
|
163
163
|
};
|
|
164
164
|
|
|
165
165
|
export const getAudioCodecFromMatroska = (mainSegment: MainSegment) => {
|
|
166
|
-
const tracksSegment = mainSegment.
|
|
167
|
-
|
|
168
|
-
);
|
|
169
|
-
if (!tracksSegment || tracksSegment.type !== 'tracks-segment') {
|
|
166
|
+
const tracksSegment = mainSegment.value.find((b) => b.type === 'Tracks');
|
|
167
|
+
if (!tracksSegment || tracksSegment.type !== 'Tracks') {
|
|
170
168
|
return null;
|
|
171
169
|
}
|
|
172
170
|
|
|
173
|
-
for (const track of tracksSegment.
|
|
174
|
-
if (track.type === '
|
|
175
|
-
const trackType = track.
|
|
176
|
-
if (trackType && trackType.type === '
|
|
177
|
-
if (trackType.
|
|
171
|
+
for (const track of tracksSegment.value) {
|
|
172
|
+
if (track.type === 'TrackEntry') {
|
|
173
|
+
const trackType = track.value.find((b) => b.type === 'CodecID');
|
|
174
|
+
if (trackType && trackType.type === 'CodecID') {
|
|
175
|
+
if (trackType.value === 'A_OPUS') {
|
|
178
176
|
return 'opus';
|
|
179
177
|
}
|
|
180
178
|
|
|
181
|
-
if (trackType.
|
|
179
|
+
if (trackType.value === 'A_VORBIS') {
|
|
182
180
|
return 'vorbis';
|
|
183
181
|
}
|
|
184
182
|
|
|
185
|
-
if (trackType.
|
|
183
|
+
if (trackType.value === 'A_PCM/INT/LIT') {
|
|
186
184
|
return 'pcm';
|
|
187
185
|
}
|
|
188
186
|
|
|
189
|
-
if (trackType.
|
|
187
|
+
if (trackType.value === 'A_AAC') {
|
|
190
188
|
return 'aac';
|
|
191
189
|
}
|
|
192
190
|
|
|
193
|
-
if (trackType.
|
|
191
|
+
if (trackType.value === 'A_MPEG/L3') {
|
|
194
192
|
return 'mp3';
|
|
195
193
|
}
|
|
196
194
|
}
|
|
@@ -263,8 +261,8 @@ export const getAudioCodec = (boxes: AnySegment[]): KnownAudioCodecs | null => {
|
|
|
263
261
|
throw new Error('Unknown audio format: ' + codec.format);
|
|
264
262
|
}
|
|
265
263
|
|
|
266
|
-
const mainSegment = boxes.find((b) => b.type === '
|
|
267
|
-
if (!mainSegment || mainSegment.type !== '
|
|
264
|
+
const mainSegment = boxes.find((b) => b.type === 'Segment');
|
|
265
|
+
if (!mainSegment || mainSegment.type !== 'Segment') {
|
|
268
266
|
return null;
|
|
269
267
|
}
|
|
270
268
|
|
package/src/get-duration.ts
CHANGED
|
@@ -1,43 +1,42 @@
|
|
|
1
|
+
import type {DurationSegment} from './boxes/webm/segments/all-segments';
|
|
1
2
|
import type {AnySegment} from './parse-result';
|
|
2
3
|
import {getMoovBox, getMvhdBox} from './traversal';
|
|
3
4
|
|
|
4
5
|
const getDurationFromMatroska = (segments: AnySegment[]): number | null => {
|
|
5
|
-
const mainSegment = segments.find((s) => s.type === '
|
|
6
|
-
if (!mainSegment || mainSegment.type !== '
|
|
6
|
+
const mainSegment = segments.find((s) => s.type === 'Segment');
|
|
7
|
+
if (!mainSegment || mainSegment.type !== 'Segment') {
|
|
7
8
|
return null;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
const {children} = mainSegment;
|
|
11
|
+
const {value: children} = mainSegment;
|
|
11
12
|
if (!children) {
|
|
12
13
|
return null;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
const infoSegment = children.find((s) => s.type === '
|
|
16
|
+
const infoSegment = children.find((s) => s.type === 'Info');
|
|
16
17
|
|
|
17
18
|
const relevantBoxes = [
|
|
18
|
-
...mainSegment.
|
|
19
|
-
...(infoSegment && infoSegment.type === '
|
|
20
|
-
? infoSegment.children
|
|
21
|
-
: []),
|
|
19
|
+
...mainSegment.value,
|
|
20
|
+
...(infoSegment && infoSegment.type === 'Info' ? infoSegment.value : []),
|
|
22
21
|
];
|
|
23
22
|
|
|
24
|
-
const timestampScale = relevantBoxes.find(
|
|
25
|
-
|
|
26
|
-
);
|
|
27
|
-
if (!timestampScale || timestampScale.type !== 'timestamp-scale-segment') {
|
|
23
|
+
const timestampScale = relevantBoxes.find((s) => s.type === 'TimestampScale');
|
|
24
|
+
if (!timestampScale || timestampScale.type !== 'TimestampScale') {
|
|
28
25
|
return null;
|
|
29
26
|
}
|
|
30
27
|
|
|
31
|
-
const duration = relevantBoxes.find(
|
|
32
|
-
|
|
28
|
+
const duration = relevantBoxes.find(
|
|
29
|
+
(s) => s.type === 'Duration',
|
|
30
|
+
) as DurationSegment;
|
|
31
|
+
if (!duration || duration.type !== 'Duration') {
|
|
33
32
|
return null;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
return (duration.
|
|
35
|
+
return (duration.value.value / timestampScale.value.value) * 1000;
|
|
37
36
|
};
|
|
38
37
|
|
|
39
38
|
export const getDuration = (boxes: AnySegment[]): number | null => {
|
|
40
|
-
const matroskaBox = boxes.find((b) => b.type === '
|
|
39
|
+
const matroskaBox = boxes.find((b) => b.type === 'Segment');
|
|
41
40
|
if (matroskaBox) {
|
|
42
41
|
return getDurationFromMatroska(boxes);
|
|
43
42
|
}
|
package/src/get-tracks.ts
CHANGED
|
@@ -89,8 +89,8 @@ export const getTracks = (
|
|
|
89
89
|
const audioTracks: AudioTrack[] = [];
|
|
90
90
|
const otherTracks: OtherTrack[] = [];
|
|
91
91
|
|
|
92
|
-
const mainSegment = segments.find((s) => s.type === '
|
|
93
|
-
if (mainSegment && mainSegment.type === '
|
|
92
|
+
const mainSegment = segments.find((s) => s.type === 'Segment');
|
|
93
|
+
if (mainSegment && mainSegment.type === 'Segment') {
|
|
94
94
|
const matroskaTracks = getTracksFromMatroska(
|
|
95
95
|
mainSegment,
|
|
96
96
|
state.getTimescale(),
|
package/src/get-video-codec.ts
CHANGED
|
@@ -76,39 +76,37 @@ export const getVideoCodec = (boxes: AnySegment[]): KnownVideoCodecs | null => {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
const mainSegment = boxes.find((b) => b.type === '
|
|
80
|
-
if (!mainSegment || mainSegment.type !== '
|
|
79
|
+
const mainSegment = boxes.find((b) => b.type === 'Segment');
|
|
80
|
+
if (!mainSegment || mainSegment.type !== 'Segment') {
|
|
81
81
|
return null;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const tracksSegment = mainSegment.
|
|
85
|
-
|
|
86
|
-
);
|
|
87
|
-
if (!tracksSegment || tracksSegment.type !== 'tracks-segment') {
|
|
84
|
+
const tracksSegment = mainSegment.value.find((b) => b.type === 'Tracks');
|
|
85
|
+
if (!tracksSegment || tracksSegment.type !== 'Tracks') {
|
|
88
86
|
return null;
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
for (const track of tracksSegment.
|
|
92
|
-
if (track.type === '
|
|
93
|
-
const trackType = track.
|
|
94
|
-
if (trackType && trackType.type === '
|
|
95
|
-
if (trackType.
|
|
89
|
+
for (const track of tracksSegment.value) {
|
|
90
|
+
if (track.type === 'TrackEntry') {
|
|
91
|
+
const trackType = track.value.find((b) => b.type === 'CodecID');
|
|
92
|
+
if (trackType && trackType.type === 'CodecID') {
|
|
93
|
+
if (trackType.value === 'V_VP8') {
|
|
96
94
|
return 'vp8';
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
if (trackType.
|
|
97
|
+
if (trackType.value === 'V_VP9') {
|
|
100
98
|
return 'vp9';
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
if (trackType.
|
|
101
|
+
if (trackType.value === 'V_AV1') {
|
|
104
102
|
return 'av1';
|
|
105
103
|
}
|
|
106
104
|
|
|
107
|
-
if (trackType.
|
|
105
|
+
if (trackType.value === 'V_MPEG4/ISO/AVC') {
|
|
108
106
|
return 'h264';
|
|
109
107
|
}
|
|
110
108
|
|
|
111
|
-
if (trackType.
|
|
109
|
+
if (trackType.value === 'V_MPEGH/ISO/HEVC') {
|
|
112
110
|
return 'h265';
|
|
113
111
|
}
|
|
114
112
|
}
|
package/src/has-all-info.ts
CHANGED
package/src/options.ts
CHANGED
|
@@ -43,7 +43,7 @@ export type Options<
|
|
|
43
43
|
audioCodec?: EnableAudioCodec;
|
|
44
44
|
tracks?: EnableTracks;
|
|
45
45
|
rotation?: EnableRotation;
|
|
46
|
-
|
|
46
|
+
unrotatedDimensions?: EnableUnrotatedDimensions;
|
|
47
47
|
internalStats?: EnableInternalStats;
|
|
48
48
|
};
|
|
49
49
|
|
|
@@ -69,7 +69,7 @@ export type Metadata<
|
|
|
69
69
|
: {}) &
|
|
70
70
|
(EnableRotation extends true ? {rotation: number | null} : {}) &
|
|
71
71
|
(EnableUnrotatedDimensions extends true
|
|
72
|
-
? {
|
|
72
|
+
? {unrotatedDimensions: Dimensions}
|
|
73
73
|
: {}) &
|
|
74
74
|
(EnableInternalStats extends true ? {internalStats: InternalStats} : {});
|
|
75
75
|
|
|
@@ -101,6 +101,7 @@ export type ParseMedia = <
|
|
|
101
101
|
reader?: ReaderInterface;
|
|
102
102
|
onAudioTrack?: OnAudioTrack;
|
|
103
103
|
onVideoTrack?: OnVideoTrack;
|
|
104
|
+
signal?: AbortSignal;
|
|
104
105
|
}) => Promise<
|
|
105
106
|
Metadata<
|
|
106
107
|
EnableDimensions,
|
package/src/parse-media.ts
CHANGED
|
@@ -21,8 +21,14 @@ export const parseMedia: ParseMedia = async ({
|
|
|
21
21
|
reader: readerInterface = fetchReader,
|
|
22
22
|
onAudioTrack,
|
|
23
23
|
onVideoTrack,
|
|
24
|
+
signal,
|
|
24
25
|
}) => {
|
|
25
|
-
const
|
|
26
|
+
const state = makeParserState({
|
|
27
|
+
hasAudioCallbacks: onAudioTrack !== null,
|
|
28
|
+
hasVideoCallbacks: onVideoTrack !== null,
|
|
29
|
+
signal,
|
|
30
|
+
});
|
|
31
|
+
const {reader, contentLength} = await readerInterface.read(src, null, signal);
|
|
26
32
|
let currentReader = reader;
|
|
27
33
|
|
|
28
34
|
const returnValue = {} as Metadata<
|
|
@@ -41,19 +47,23 @@ export const parseMedia: ParseMedia = async ({
|
|
|
41
47
|
let iterator: BufferIterator | null = null;
|
|
42
48
|
let parseResult: ParseResult | null = null;
|
|
43
49
|
|
|
44
|
-
const state = makeParserState({
|
|
45
|
-
hasAudioCallbacks: onAudioTrack !== null,
|
|
46
|
-
hasVideoCallbacks: onVideoTrack !== null,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
50
|
const options: ParserContext = {
|
|
50
51
|
canSkipVideoData: !(onAudioTrack || onVideoTrack),
|
|
51
52
|
onAudioTrack: onAudioTrack ?? null,
|
|
52
53
|
onVideoTrack: onVideoTrack ?? null,
|
|
53
54
|
parserState: state,
|
|
55
|
+
nullifySamples: !(
|
|
56
|
+
typeof process !== 'undefined' &&
|
|
57
|
+
typeof process.env !== 'undefined' &&
|
|
58
|
+
process.env.KEEP_SAMPLES === 'true'
|
|
59
|
+
),
|
|
54
60
|
};
|
|
55
61
|
|
|
56
62
|
while (parseResult === null || parseResult.status === 'incomplete') {
|
|
63
|
+
if (signal?.aborted) {
|
|
64
|
+
throw new Error('Aborted');
|
|
65
|
+
}
|
|
66
|
+
|
|
57
67
|
const result = await currentReader.read();
|
|
58
68
|
|
|
59
69
|
if (iterator) {
|
|
@@ -67,7 +77,7 @@ export const parseMedia: ParseMedia = async ({
|
|
|
67
77
|
|
|
68
78
|
iterator = getArrayBufferIterator(
|
|
69
79
|
result.value,
|
|
70
|
-
contentLength ??
|
|
80
|
+
contentLength ?? 1_000_000_000,
|
|
71
81
|
);
|
|
72
82
|
}
|
|
73
83
|
|
|
@@ -106,6 +116,7 @@ export const parseMedia: ParseMedia = async ({
|
|
|
106
116
|
const {reader: newReader} = await readerInterface.read(
|
|
107
117
|
src,
|
|
108
118
|
parseResult.skipTo,
|
|
119
|
+
signal,
|
|
109
120
|
);
|
|
110
121
|
currentReader = newReader;
|
|
111
122
|
iterator.skipTo(parseResult.skipTo);
|
|
@@ -124,9 +135,9 @@ export const parseMedia: ParseMedia = async ({
|
|
|
124
135
|
};
|
|
125
136
|
}
|
|
126
137
|
|
|
127
|
-
if (fields?.
|
|
138
|
+
if (fields?.unrotatedDimensions) {
|
|
128
139
|
const dimensions = getDimensions(parseResult.segments, state);
|
|
129
|
-
returnValue.
|
|
140
|
+
returnValue.unrotatedDimensions = {
|
|
130
141
|
width: dimensions.unrotatedWidth,
|
|
131
142
|
height: dimensions.unrotatedHeight,
|
|
132
143
|
};
|
package/src/parse-video.ts
CHANGED
|
@@ -43,6 +43,22 @@ export const parseVideo = ({
|
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
if (iterator.isRiff()) {
|
|
47
|
+
throw new Error('AVI files are not yet supported');
|
|
48
|
+
/*
|
|
49
|
+
iterator.discard(4);
|
|
50
|
+
return parseBoxes({
|
|
51
|
+
iterator,
|
|
52
|
+
maxBytes: Infinity,
|
|
53
|
+
allowIncompleteBoxes: true,
|
|
54
|
+
initialBoxes: [],
|
|
55
|
+
options,
|
|
56
|
+
continueMdat: false,
|
|
57
|
+
littleEndian: true,
|
|
58
|
+
});
|
|
59
|
+
*/
|
|
60
|
+
}
|
|
61
|
+
|
|
46
62
|
if (iterator.isIsoBaseMedia()) {
|
|
47
63
|
return parseBoxes({
|
|
48
64
|
iterator,
|
|
@@ -51,6 +67,7 @@ export const parseVideo = ({
|
|
|
51
67
|
initialBoxes: [],
|
|
52
68
|
options,
|
|
53
69
|
continueMdat: false,
|
|
70
|
+
littleEndian: false,
|
|
54
71
|
});
|
|
55
72
|
}
|
|
56
73
|
|