@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.
Files changed (111) 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/process-box.d.ts +4 -2
  16. package/dist/boxes/iso-base-media/process-box.js +56 -40
  17. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
  18. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
  19. package/dist/boxes/iso-base-media/stsd/samples.js +3 -0
  20. package/dist/boxes/iso-base-media/stsd/stco.d.ts +3 -2
  21. package/dist/boxes/iso-base-media/stsd/stco.js +2 -2
  22. package/dist/boxes/iso-base-media/trak/trak.js +1 -0
  23. package/dist/boxes/webm/bitstream/av1.js +10 -1
  24. package/dist/boxes/webm/ebml.d.ts +1 -1
  25. package/dist/boxes/webm/make-header.d.ts +8 -1
  26. package/dist/boxes/webm/make-header.js +65 -30
  27. package/dist/boxes/webm/parse-ebml.d.ts +7 -0
  28. package/dist/boxes/webm/parse-ebml.js +66 -0
  29. package/dist/boxes/webm/parse-webm-header.js +8 -9
  30. package/dist/boxes/webm/segments/all-segments.d.ts +258 -1
  31. package/dist/boxes/webm/segments/all-segments.js +126 -2
  32. package/dist/boxes/webm/segments/seek-position.js +1 -1
  33. package/dist/boxes/webm/segments/seek.d.ts +1 -1
  34. package/dist/boxes/webm/segments/seek.js +8 -2
  35. package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
  36. package/dist/boxes/webm/segments/track-entry.d.ts +5 -1
  37. package/dist/boxes/webm/segments/track-entry.js +19 -20
  38. package/dist/boxes/webm/segments.d.ts +2 -2
  39. package/dist/boxes/webm/segments.js +30 -25
  40. package/dist/boxes/webm/traversal.d.ts +1 -0
  41. package/dist/boxes/webm/traversal.js +12 -1
  42. package/dist/buffer-iterator.d.ts +9 -6
  43. package/dist/buffer-iterator.js +83 -7
  44. package/dist/from-fetch.js +13 -3
  45. package/dist/from-input-type-file.d.ts +2 -0
  46. package/dist/from-input-type-file.js +37 -0
  47. package/dist/from-node.js +9 -2
  48. package/dist/from-web-file.js +6 -1
  49. package/dist/from-web.js +15 -6
  50. package/dist/get-audio-codec.d.ts +1 -1
  51. package/dist/get-codec.d.ts +4 -0
  52. package/dist/get-codec.js +22 -0
  53. package/dist/get-sample-positions.js +1 -1
  54. package/dist/has-all-info.js +1 -1
  55. package/dist/options.d.ts +3 -2
  56. package/dist/parse-media.js +13 -9
  57. package/dist/parse-video.js +16 -0
  58. package/dist/parser-state.d.ts +4 -3
  59. package/dist/parser-state.js +15 -3
  60. package/dist/reader.d.ts +1 -1
  61. package/dist/web-file.d.ts +2 -0
  62. package/dist/web-file.js +37 -0
  63. package/package.json +2 -2
  64. package/src/boxes/iso-base-media/mdat/mdat.ts +2 -1
  65. package/src/boxes/iso-base-media/moov/moov.ts +1 -0
  66. package/src/boxes/iso-base-media/process-box.ts +70 -40
  67. package/src/boxes/iso-base-media/stsd/mebx.ts +3 -0
  68. package/src/boxes/iso-base-media/stsd/samples.ts +3 -0
  69. package/src/boxes/iso-base-media/stsd/stco.ts +5 -3
  70. package/src/boxes/iso-base-media/trak/trak.ts +1 -0
  71. package/src/boxes/webm/make-header.ts +122 -32
  72. package/src/boxes/webm/parse-ebml.ts +93 -0
  73. package/src/boxes/webm/parse-webm-header.ts +8 -12
  74. package/src/boxes/webm/segments/all-segments.ts +222 -1
  75. package/src/boxes/webm/segments/seek-position.ts +1 -1
  76. package/src/boxes/webm/segments/seek.ts +12 -2
  77. package/src/boxes/webm/segments/timestamp-scale.ts +1 -1
  78. package/src/boxes/webm/segments/track-entry.ts +31 -26
  79. package/src/boxes/webm/segments.ts +37 -32
  80. package/src/boxes/webm/traversal.ts +13 -0
  81. package/src/buffer-iterator.ts +102 -9
  82. package/src/from-fetch.ts +22 -3
  83. package/src/from-node.ts +18 -4
  84. package/src/from-web-file.ts +11 -1
  85. package/src/get-sample-positions.ts +1 -1
  86. package/src/has-all-info.ts +1 -1
  87. package/src/options.ts +3 -2
  88. package/src/parse-media.ts +14 -8
  89. package/src/parse-video.ts +17 -0
  90. package/src/parser-state.ts +22 -5
  91. package/src/reader.ts +1 -0
  92. package/src/test/create-matroska.test.ts +36 -2
  93. package/src/test/matroska.test.ts +69 -27
  94. package/src/test/parse-stco.test.ts +2 -0
  95. package/src/test/stream-local.test.ts +23 -9
  96. package/src/test/stream-remote.test.ts +23 -19
  97. package/src/test/stsd.test.ts +2 -0
  98. package/tsconfig.tsbuildinfo +1 -1
  99. package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
  100. package/dist/boxes/iso-base-media/ftype.js +0 -31
  101. package/dist/get-video-metadata.d.ts +0 -2
  102. package/dist/get-video-metadata.js +0 -44
  103. package/dist/read-and-increment-offset.d.ts +0 -28
  104. package/dist/read-and-increment-offset.js +0 -177
  105. package/dist/understand-vorbis.d.ts +0 -1
  106. package/dist/understand-vorbis.js +0 -12
  107. package/src/boxes/webm/segments/unknown.ts +0 -19
  108. /package/dist/{boxes/webm/bitstream/av1/frame.d.ts → get-samples.d.ts} +0 -0
  109. /package/dist/{boxes/webm/bitstream/av1/frame.js → get-samples.js} +0 -0
  110. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.d.ts → sample-aspect-ratio.d.ts} +0 -0
  111. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.js → sample-aspect-ratio.js} +0 -0
@@ -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 !== null && maxBytes !== void 0 ? maxBytes : 1000000000,
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 getFourByteNumber = () => {
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
- discardFirstBytes: removeBytesRead,
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
- getDecimalBytes(length) {
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);
@@ -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 `webReader`');
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 `webReader`');
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,2 @@
1
+ import type { ReaderInterface } from './reader';
2
+ export declare const inputTypeFileReader: ReaderInterface;
@@ -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: stream_1.Readable.toWeb(stream).getReader(),
29
+ reader,
23
30
  contentLength: stats.size,
24
31
  };
25
32
  },
@@ -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
- Range: `bytes=${`${range[0]}-${range[1]}`}`,
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) => "vorbis" | "opus" | "mp3" | "aac" | "pcm" | null;
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,4 @@
1
+ import type { KnownVideoCodecs } from './options';
2
+ import type { AnySegment } from './parse-result';
3
+ export declare const hasVideoCodec: (boxes: AnySegment[]) => boolean;
4
+ export declare const getVideoCodec: (boxes: AnySegment[]) => KnownVideoCodecs | null;
@@ -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,
@@ -20,7 +20,7 @@ const hasAllInfo = (options, parseResult, state) => {
20
20
  }
21
21
  if (key === 'dimensions' ||
22
22
  key === 'rotation' ||
23
- key === 'unrotatedDimension') {
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
- unrotatedDimension?: EnableUnrotatedDimensions;
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
- unrotatedDimension: Dimensions;
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>>;
@@ -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.unrotatedDimension) {
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.unrotatedDimension = {
90
+ returnValue.unrotatedDimensions = {
87
91
  width: dimensions.unrotatedWidth,
88
92
  height: dimensions.unrotatedHeight,
89
93
  };
@@ -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()) {
@@ -1,13 +1,14 @@
1
1
  import type { OnTrackEntrySegment } from './boxes/webm/segments';
2
- import type { CodecSegment } from './boxes/webm/segments/track-entry';
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) => CodecSegment;
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;
@@ -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
- trackEntries[trackId] = codec;
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
- throw new Error('Timescale not set');
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;
@@ -0,0 +1,2 @@
1
+ import type { ReaderInterface } from './reader';
2
+ export declare const inputTypeFileReader: ReaderInterface;