@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.
Files changed (180) hide show
  1. package/dist/av1-codec-string.d.ts +5 -0
  2. package/dist/av1-codec-string.js +18 -1
  3. package/dist/bitstream/av1.d.ts +2 -0
  4. package/dist/bitstream/av1.js +12 -0
  5. package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +20 -0
  6. package/dist/boxes/iso-base-media/avcc-hvcc.js +73 -0
  7. package/dist/boxes/iso-base-media/avcc.d.ts +18 -0
  8. package/dist/boxes/iso-base-media/avcc.js +27 -0
  9. package/dist/boxes/iso-base-media/esds-descriptors.d.ts +21 -0
  10. package/dist/boxes/iso-base-media/esds-descriptors.js +62 -0
  11. package/dist/boxes/iso-base-media/esds.d.ts +15 -0
  12. package/dist/boxes/iso-base-media/esds.js +27 -0
  13. package/dist/boxes/iso-base-media/mdat/mdat.js +2 -1
  14. package/dist/boxes/iso-base-media/moov/moov.js +1 -0
  15. package/dist/boxes/iso-base-media/mvhd.js +2 -2
  16. package/dist/boxes/iso-base-media/process-box.d.ts +4 -2
  17. package/dist/boxes/iso-base-media/process-box.js +56 -40
  18. package/dist/boxes/iso-base-media/stsd/keys.js +1 -1
  19. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
  20. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
  21. package/dist/boxes/iso-base-media/stsd/samples.js +3 -0
  22. package/dist/boxes/iso-base-media/stsd/stco.d.ts +3 -2
  23. package/dist/boxes/iso-base-media/stsd/stco.js +2 -2
  24. package/dist/boxes/iso-base-media/trak/trak.js +1 -0
  25. package/dist/boxes/webm/av1-codec-private.js +1 -1
  26. package/dist/boxes/webm/bitstream/av1.js +10 -1
  27. package/dist/boxes/webm/description.d.ts +2 -2
  28. package/dist/boxes/webm/description.js +2 -2
  29. package/dist/boxes/webm/ebml.d.ts +2 -2
  30. package/dist/boxes/webm/ebml.js +23 -1
  31. package/dist/boxes/webm/get-ready-tracks.d.ts +1 -1
  32. package/dist/boxes/webm/get-ready-tracks.js +3 -3
  33. package/dist/boxes/webm/get-sample-from-block.d.ts +17 -0
  34. package/dist/boxes/webm/get-sample-from-block.js +78 -0
  35. package/dist/boxes/webm/get-track.d.ts +2 -2
  36. package/dist/boxes/webm/get-track.js +26 -25
  37. package/dist/boxes/webm/make-header.d.ts +3 -1
  38. package/dist/boxes/webm/make-header.js +90 -32
  39. package/dist/boxes/webm/parse-ebml.d.ts +12 -0
  40. package/dist/boxes/webm/parse-ebml.js +175 -0
  41. package/dist/boxes/webm/parse-webm-header.js +8 -9
  42. package/dist/boxes/webm/segments/all-segments.d.ts +572 -1
  43. package/dist/boxes/webm/segments/all-segments.js +353 -2
  44. package/dist/boxes/webm/segments/track-entry.d.ts +5 -189
  45. package/dist/boxes/webm/segments/track-entry.js +2 -457
  46. package/dist/boxes/webm/segments.d.ts +3 -16
  47. package/dist/boxes/webm/segments.js +40 -219
  48. package/dist/boxes/webm/traversal.d.ts +5 -5
  49. package/dist/boxes/webm/traversal.js +17 -6
  50. package/dist/buffer-iterator.d.ts +10 -7
  51. package/dist/buffer-iterator.js +83 -7
  52. package/dist/create/create-media.d.ts +2 -0
  53. package/dist/create/create-media.js +36 -0
  54. package/dist/create/matroska-header.d.ts +1 -0
  55. package/dist/create/matroska-header.js +66 -0
  56. package/dist/create/matroska-info.d.ts +4 -0
  57. package/dist/create/matroska-info.js +39 -0
  58. package/dist/create/matroska-segment.d.ts +1 -0
  59. package/dist/create/matroska-segment.js +12 -0
  60. package/dist/create/matroska-trackentry.d.ts +21 -0
  61. package/dist/create/matroska-trackentry.js +191 -0
  62. package/dist/create-media.d.ts +1 -0
  63. package/dist/create-media.js +78 -0
  64. package/dist/from-fetch.js +13 -3
  65. package/dist/from-input-type-file.d.ts +2 -0
  66. package/dist/from-input-type-file.js +37 -0
  67. package/dist/from-node.js +9 -2
  68. package/dist/from-web-file.js +6 -1
  69. package/dist/from-web.js +15 -6
  70. package/dist/get-audio-codec.d.ts +2 -2
  71. package/dist/get-audio-codec.js +13 -13
  72. package/dist/get-codec.d.ts +4 -0
  73. package/dist/get-codec.js +22 -0
  74. package/dist/get-duration.js +12 -14
  75. package/dist/get-sample-positions.js +1 -1
  76. package/dist/get-tracks.js +2 -2
  77. package/dist/get-video-codec.js +13 -13
  78. package/dist/has-all-info.js +1 -1
  79. package/dist/options.d.ts +3 -2
  80. package/dist/parse-media.js +17 -10
  81. package/dist/parse-video.js +16 -0
  82. package/dist/parser-context.d.ts +1 -0
  83. package/dist/parser-state.d.ts +4 -3
  84. package/dist/parser-state.js +16 -3
  85. package/dist/reader.d.ts +1 -1
  86. package/dist/readers/from-fetch.d.ts +2 -0
  87. package/dist/readers/from-fetch.js +64 -0
  88. package/dist/readers/from-node.d.ts +2 -0
  89. package/dist/readers/from-node.js +40 -0
  90. package/dist/readers/from-web-file.d.ts +2 -0
  91. package/dist/readers/from-web-file.js +39 -0
  92. package/dist/readers/reader.d.ts +11 -0
  93. package/dist/readers/reader.js +2 -0
  94. package/dist/traversal.d.ts +19 -17
  95. package/dist/traversal.js +38 -39
  96. package/dist/web-file.d.ts +2 -0
  97. package/dist/web-file.js +37 -0
  98. package/dist/writers/web-fs.d.ts +2 -0
  99. package/dist/writers/web-fs.js +28 -0
  100. package/dist/writers/writer.d.ts +9 -0
  101. package/dist/writers/writer.js +2 -0
  102. package/input.webm +0 -0
  103. package/package.json +2 -2
  104. package/src/boxes/iso-base-media/mdat/mdat.ts +2 -1
  105. package/src/boxes/iso-base-media/moov/moov.ts +1 -0
  106. package/src/boxes/iso-base-media/mvhd.ts +2 -2
  107. package/src/boxes/iso-base-media/process-box.ts +70 -40
  108. package/src/boxes/iso-base-media/stsd/keys.ts +1 -1
  109. package/src/boxes/iso-base-media/stsd/mebx.ts +3 -0
  110. package/src/boxes/iso-base-media/stsd/samples.ts +3 -0
  111. package/src/boxes/iso-base-media/stsd/stco.ts +5 -3
  112. package/src/boxes/iso-base-media/trak/trak.ts +1 -0
  113. package/src/boxes/webm/av1-codec-private.ts +1 -1
  114. package/src/boxes/webm/description.ts +7 -4
  115. package/src/boxes/webm/ebml.ts +24 -4
  116. package/src/boxes/webm/get-ready-tracks.ts +4 -4
  117. package/src/boxes/webm/get-sample-from-block.ts +125 -0
  118. package/src/boxes/webm/get-track.ts +38 -31
  119. package/src/boxes/webm/make-header.ts +129 -32
  120. package/src/boxes/webm/parse-ebml.ts +247 -0
  121. package/src/boxes/webm/parse-webm-header.ts +8 -12
  122. package/src/boxes/webm/segments/all-segments.ts +539 -1
  123. package/src/boxes/webm/segments/track-entry.ts +5 -843
  124. package/src/boxes/webm/segments.ts +48 -435
  125. package/src/boxes/webm/traversal.ts +28 -15
  126. package/src/buffer-iterator.ts +104 -10
  127. package/src/from-fetch.ts +22 -3
  128. package/src/from-node.ts +18 -4
  129. package/src/from-web-file.ts +11 -1
  130. package/src/get-audio-codec.ts +14 -16
  131. package/src/get-duration.ts +15 -16
  132. package/src/get-sample-positions.ts +1 -1
  133. package/src/get-tracks.ts +2 -2
  134. package/src/get-video-codec.ts +13 -15
  135. package/src/has-all-info.ts +1 -1
  136. package/src/options.ts +3 -2
  137. package/src/parse-media.ts +20 -9
  138. package/src/parse-video.ts +17 -0
  139. package/src/parser-context.ts +1 -0
  140. package/src/parser-state.ts +22 -5
  141. package/src/reader.ts +1 -0
  142. package/src/test/create-matroska.test.ts +255 -7
  143. package/src/test/matroska.test.ts +311 -334
  144. package/src/test/mvhd.test.ts +1 -1
  145. package/src/test/parse-esds.test.ts +2 -2
  146. package/src/test/parse-stco.test.ts +4 -2
  147. package/src/test/parse-stsc.test.ts +2 -2
  148. package/src/test/parse-stsz.test.ts +2 -2
  149. package/src/test/parse-stts.test.ts +1 -1
  150. package/src/test/stream-local.test.ts +23 -9
  151. package/src/test/stream-remote.test.ts +23 -19
  152. package/src/test/stsd.test.ts +6 -2
  153. package/src/test/tkhd.test.ts +1 -1
  154. package/src/traversal.ts +62 -85
  155. package/tsconfig.tsbuildinfo +1 -1
  156. package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
  157. package/dist/boxes/iso-base-media/ftype.js +0 -31
  158. package/dist/get-video-metadata.d.ts +0 -2
  159. package/dist/get-video-metadata.js +0 -44
  160. package/dist/read-and-increment-offset.d.ts +0 -28
  161. package/dist/read-and-increment-offset.js +0 -177
  162. package/dist/understand-vorbis.d.ts +0 -1
  163. package/dist/understand-vorbis.js +0 -12
  164. package/src/boxes/webm/segments/duration.ts +0 -29
  165. package/src/boxes/webm/segments/info.ts +0 -34
  166. package/src/boxes/webm/segments/main.ts +0 -6
  167. package/src/boxes/webm/segments/muxing.ts +0 -18
  168. package/src/boxes/webm/segments/seek-head.ts +0 -34
  169. package/src/boxes/webm/segments/seek-position.ts +0 -18
  170. package/src/boxes/webm/segments/seek.ts +0 -45
  171. package/src/boxes/webm/segments/timestamp-scale.ts +0 -17
  172. package/src/boxes/webm/segments/tracks.ts +0 -32
  173. package/src/boxes/webm/segments/unknown.ts +0 -19
  174. package/src/boxes/webm/segments/void.ts +0 -18
  175. package/src/boxes/webm/segments/writing.ts +0 -18
  176. package/src/combine-uint8array.ts +0 -13
  177. /package/dist/{boxes/webm/bitstream/av1/frame.d.ts → get-samples.d.ts} +0 -0
  178. /package/dist/{boxes/webm/bitstream/av1/frame.js → get-samples.js} +0 -0
  179. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.d.ts → sample-aspect-ratio.d.ts} +0 -0
  180. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.js → sample-aspect-ratio.js} +0 -0
@@ -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?: number,
65
+ maxBytes: number | null,
65
66
  ) => {
66
67
  const buf = new ArrayBuffer(initialData.byteLength, {
67
- maxByteLength: maxBytes ?? 1_000_000_000,
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 getFourByteNumber = () => {
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
- discardFirstBytes: removeBytesRead,
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
- getDecimalBytes(length: number): number {
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 `webReader`');
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 `webReader`');
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: Readable.toWeb(
24
- stream,
25
- ).getReader() as ReadableStreamDefaultReader<Uint8Array>,
39
+ reader,
26
40
  contentLength: stats.size,
27
41
  };
28
42
  },
@@ -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({
@@ -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/main';
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.children.find(
167
- (b) => b.type === 'tracks-segment',
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.children) {
174
- if (track.type === 'track-entry-segment') {
175
- const trackType = track.children.find((b) => b.type === 'codec-segment');
176
- if (trackType && trackType.type === 'codec-segment') {
177
- if (trackType.codec === 'A_OPUS') {
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.codec === 'A_VORBIS') {
179
+ if (trackType.value === 'A_VORBIS') {
182
180
  return 'vorbis';
183
181
  }
184
182
 
185
- if (trackType.codec === 'A_PCM/INT/LIT') {
183
+ if (trackType.value === 'A_PCM/INT/LIT') {
186
184
  return 'pcm';
187
185
  }
188
186
 
189
- if (trackType.codec === 'A_AAC') {
187
+ if (trackType.value === 'A_AAC') {
190
188
  return 'aac';
191
189
  }
192
190
 
193
- if (trackType.codec === 'A_MPEG/L3') {
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 === 'main-segment');
267
- if (!mainSegment || mainSegment.type !== 'main-segment') {
264
+ const mainSegment = boxes.find((b) => b.type === 'Segment');
265
+ if (!mainSegment || mainSegment.type !== 'Segment') {
268
266
  return null;
269
267
  }
270
268
 
@@ -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 === 'main-segment');
6
- if (!mainSegment || mainSegment.type !== 'main-segment') {
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 === 'info-segment');
16
+ const infoSegment = children.find((s) => s.type === 'Info');
16
17
 
17
18
  const relevantBoxes = [
18
- ...mainSegment.children,
19
- ...(infoSegment && infoSegment.type === 'info-segment'
20
- ? infoSegment.children
21
- : []),
19
+ ...mainSegment.value,
20
+ ...(infoSegment && infoSegment.type === 'Info' ? infoSegment.value : []),
22
21
  ];
23
22
 
24
- const timestampScale = relevantBoxes.find(
25
- (s) => s.type === 'timestamp-scale-segment',
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((s) => s.type === 'duration-segment');
32
- if (!duration || duration.type !== 'duration-segment') {
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.duration / timestampScale.timestampScale) * 1000;
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 === 'main-segment');
39
+ const matroskaBox = boxes.find((b) => b.type === 'Segment');
41
40
  if (matroskaBox) {
42
41
  return getDurationFromMatroska(boxes);
43
42
  }
@@ -77,7 +77,7 @@ export const getSamplePositions = ({
77
77
  const cts = dts + ctsOffset;
78
78
 
79
79
  samples.push({
80
- offset: chunks[i] + offsetInThisChunk,
80
+ offset: Number(chunks[i]) + offsetInThisChunk,
81
81
  size,
82
82
  isKeyframe,
83
83
  dts,
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 === 'main-segment');
93
- if (mainSegment && mainSegment.type === 'main-segment') {
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(),
@@ -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 === 'main-segment');
80
- if (!mainSegment || mainSegment.type !== 'main-segment') {
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.children.find(
85
- (b) => b.type === 'tracks-segment',
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.children) {
92
- if (track.type === 'track-entry-segment') {
93
- const trackType = track.children.find((b) => b.type === 'codec-segment');
94
- if (trackType && trackType.type === 'codec-segment') {
95
- if (trackType.codec === 'V_VP8') {
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.codec === 'V_VP9') {
97
+ if (trackType.value === 'V_VP9') {
100
98
  return 'vp9';
101
99
  }
102
100
 
103
- if (trackType.codec === 'V_AV1') {
101
+ if (trackType.value === 'V_AV1') {
104
102
  return 'av1';
105
103
  }
106
104
 
107
- if (trackType.codec === 'V_MPEG4/ISO/AVC') {
105
+ if (trackType.value === 'V_MPEG4/ISO/AVC') {
108
106
  return 'h264';
109
107
  }
110
108
 
111
- if (trackType.codec === 'V_MPEGH/ISO/HEVC') {
109
+ if (trackType.value === 'V_MPEGH/ISO/HEVC') {
112
110
  return 'h265';
113
111
  }
114
112
  }
@@ -51,7 +51,7 @@ export const hasAllInfo = (
51
51
  if (
52
52
  key === 'dimensions' ||
53
53
  key === 'rotation' ||
54
- key === 'unrotatedDimension'
54
+ key === 'unrotatedDimensions'
55
55
  ) {
56
56
  return hasDimensions(parseResult.segments, state);
57
57
  }
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
- unrotatedDimension?: EnableUnrotatedDimensions;
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
- ? {unrotatedDimension: Dimensions}
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,
@@ -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 {reader, contentLength} = await readerInterface.read(src, null);
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 ?? undefined,
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?.unrotatedDimension) {
138
+ if (fields?.unrotatedDimensions) {
128
139
  const dimensions = getDimensions(parseResult.segments, state);
129
- returnValue.unrotatedDimension = {
140
+ returnValue.unrotatedDimensions = {
130
141
  width: dimensions.unrotatedWidth,
131
142
  height: dimensions.unrotatedHeight,
132
143
  };
@@ -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
 
@@ -6,4 +6,5 @@ export type ParserContext = {
6
6
  onVideoTrack: OnVideoTrack | null;
7
7
  canSkipVideoData: boolean;
8
8
  parserState: ParserState;
9
+ nullifySamples: boolean;
9
10
  };