@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
@@ -1,6 +1,6 @@
1
1
  import type {OnTrackEntrySegment} from './boxes/webm/segments';
2
- import type {CodecSegment} from './boxes/webm/segments/track-entry';
3
- import {getTrackCodec} from './boxes/webm/traversal';
2
+ import type {TrackInfo} from './boxes/webm/segments/track-entry';
3
+ import {getTrackCodec, getTrackTimestampScale} from './boxes/webm/traversal';
4
4
  import {getTrackId} from './traversal';
5
5
  import type {
6
6
  AudioSample,
@@ -14,11 +14,13 @@ export type InternalStats = {};
14
14
  export const makeParserState = ({
15
15
  hasAudioCallbacks,
16
16
  hasVideoCallbacks,
17
+ signal,
17
18
  }: {
18
19
  hasAudioCallbacks: boolean;
19
20
  hasVideoCallbacks: boolean;
21
+ signal: AbortSignal | undefined;
20
22
  }) => {
21
- const trackEntries: Record<number, CodecSegment> = {};
23
+ const trackEntries: Record<number, TrackInfo> = {};
22
24
 
23
25
  const onTrackEntrySegment: OnTrackEntrySegment = (trackEntry) => {
24
26
  const trackId = getTrackId(trackEntry);
@@ -35,7 +37,12 @@ export const makeParserState = ({
35
37
  throw new Error('Expected codec');
36
38
  }
37
39
 
38
- trackEntries[trackId] = codec;
40
+ const trackTimescale = getTrackTimestampScale(trackEntry);
41
+
42
+ trackEntries[trackId] = {
43
+ codec: codec.value,
44
+ trackTimescale: trackTimescale?.value ?? null,
45
+ };
39
46
  };
40
47
 
41
48
  const videoSampleCallbacks: Record<number, OnVideoSample> = {};
@@ -49,8 +56,10 @@ export const makeParserState = ({
49
56
  let timescale: number | null = null;
50
57
 
51
58
  const getTimescale = () => {
59
+ // https://www.matroska.org/technical/notes.html
60
+ // When using the default value of TimestampScale of “1,000,000”, one Segment Tick represents one millisecond.
52
61
  if (timescale === null) {
53
- throw new Error('Timescale not set');
62
+ return 1_000_000;
54
63
  }
55
64
 
56
65
  return timescale;
@@ -125,6 +134,10 @@ export const makeParserState = ({
125
134
  queuedAudioSamples[id] = [];
126
135
  },
127
136
  onAudioSample: async (trackId: number, audioSample: AudioSample) => {
137
+ if (signal?.aborted) {
138
+ throw new Error('Aborted');
139
+ }
140
+
128
141
  const callback = audioSampleCallbacks[trackId];
129
142
  if (callback) {
130
143
  await callback(audioSample);
@@ -139,6 +152,10 @@ export const makeParserState = ({
139
152
  }
140
153
  },
141
154
  onVideoSample: async (trackId: number, videoSample: VideoSample) => {
155
+ if (signal?.aborted) {
156
+ throw new Error('Aborted');
157
+ }
158
+
142
159
  const callback = videoSampleCallbacks[trackId];
143
160
  if (callback) {
144
161
  await callback(videoSample);
package/src/reader.ts CHANGED
@@ -5,6 +5,7 @@ type ReadResult = {
5
5
  type ReadContent = (
6
6
  src: string | File,
7
7
  range: [number, number] | number | null,
8
+ signal: AbortSignal | undefined,
8
9
  ) => Promise<ReadResult>;
9
10
  type GetLength = (src: string | File) => Promise<number>;
10
11
 
@@ -1,14 +1,262 @@
1
- import {RenderInternals} from '@remotion/renderer';
1
+ /* eslint-disable padding-line-between-statements */
2
+ /* eslint-disable max-depth */
2
3
  import {expect, test} from 'bun:test';
3
- import {makeMatroskaHeader} from '../boxes/webm/make-header';
4
+ import {combineUint8Arrays, makeMatroskaBytes} from '../boxes/webm/make-header';
5
+ import {parseEbml} from '../boxes/webm/parse-ebml';
6
+ import type {MatroskaSegment} from '../boxes/webm/segments';
7
+ import type {
8
+ MainSegment,
9
+ TrackEntry,
10
+ } from '../boxes/webm/segments/all-segments';
11
+ import {getArrayBufferIterator} from '../buffer-iterator';
12
+ import {nodeReader} from '../from-node';
13
+ import {parseMedia} from '../parse-media';
14
+ import type {AnySegment} from '../parse-result';
15
+ import type {ParserContext} from '../parser-context';
16
+ import {makeParserState} from '../parser-state';
17
+
18
+ const state = makeParserState({
19
+ hasAudioCallbacks: false,
20
+ hasVideoCallbacks: false,
21
+ signal: undefined,
22
+ });
23
+
24
+ const options: ParserContext = {
25
+ canSkipVideoData: true,
26
+ onAudioTrack: null,
27
+ onVideoTrack: null,
28
+ parserState: state,
29
+ nullifySamples: false,
30
+ };
4
31
 
5
32
  test('Should make Matroska header that is same as input', async () => {
6
- const exampleVideo = RenderInternals.exampleVideos.matroskaMp3;
7
- const file = await Bun.file(exampleVideo).arrayBuffer();
33
+ const headerOutput = makeMatroskaBytes({
34
+ type: 'Header',
35
+ minVintWidth: 1,
36
+ value: [
37
+ {
38
+ type: 'EBMLVersion',
39
+ value: {value: 1, byteLength: 1},
40
+ minVintWidth: 1,
41
+ },
42
+ {
43
+ type: 'EBMLReadVersion',
44
+ value: {value: 1, byteLength: 1},
45
+ minVintWidth: 1,
46
+ },
47
+ {
48
+ type: 'EBMLMaxIDLength',
49
+ value: {value: 4, byteLength: 1},
50
+ minVintWidth: 1,
51
+ },
52
+ {
53
+ type: 'EBMLMaxSizeLength',
54
+ value: {value: 8, byteLength: 1},
55
+ minVintWidth: 1,
56
+ },
57
+ {
58
+ type: 'DocType',
59
+ value: 'webm',
60
+ minVintWidth: 1,
61
+ },
62
+ {
63
+ type: 'DocTypeVersion',
64
+ value: {value: 4, byteLength: 1},
65
+ minVintWidth: 1,
66
+ },
67
+ {
68
+ type: 'DocTypeReadVersion',
69
+ value: {value: 2, byteLength: 1},
70
+ minVintWidth: 1,
71
+ },
72
+ ],
73
+ });
74
+
75
+ const iterator = getArrayBufferIterator(headerOutput, headerOutput.length);
76
+ const parsed = await parseEbml(iterator, options);
77
+
78
+ expect(parsed).toEqual({
79
+ type: 'Header',
80
+ minVintWidth: 1,
81
+ value: [
82
+ {
83
+ type: 'EBMLVersion',
84
+ value: {value: 1, byteLength: 1},
85
+ minVintWidth: 1,
86
+ },
87
+ {
88
+ type: 'EBMLReadVersion',
89
+ value: {value: 1, byteLength: 1},
90
+ minVintWidth: 1,
91
+ },
92
+ {
93
+ type: 'EBMLMaxIDLength',
94
+ value: {value: 4, byteLength: 1},
95
+ minVintWidth: 1,
96
+ },
97
+ {
98
+ type: 'EBMLMaxSizeLength',
99
+ value: {value: 8, byteLength: 1},
100
+ minVintWidth: 1,
101
+ },
102
+ {
103
+ type: 'DocType',
104
+ value: 'webm',
105
+ minVintWidth: 1,
106
+ },
107
+ {
108
+ type: 'DocTypeVersion',
109
+ value: {value: 4, byteLength: 1},
110
+ minVintWidth: 1,
111
+ },
112
+ {
113
+ type: 'DocTypeReadVersion',
114
+ value: {value: 2, byteLength: 1},
115
+ minVintWidth: 1,
116
+ },
117
+ ],
118
+ });
119
+ });
120
+
121
+ test('Should be able to create SeekIdBox', async () => {
122
+ const file = new Uint8Array(
123
+ await Bun.file('vp8-segments/56-0x53ab').arrayBuffer(),
124
+ );
125
+
126
+ const custom = makeMatroskaBytes({
127
+ type: 'SeekID',
128
+ value: '0x1549a966',
129
+ minVintWidth: 1,
130
+ });
131
+ expect(custom).toEqual(file);
132
+ });
133
+
134
+ test('Should be able to create Seek', async () => {
135
+ const file = new Uint8Array(
136
+ await Bun.file('vp8-segments/53-0x4dbb').arrayBuffer(),
137
+ );
138
+ const parsed = await parseEbml(getArrayBufferIterator(file, null), options);
139
+ expect(parsed).toEqual({
140
+ type: 'Seek',
141
+ value: [
142
+ {
143
+ type: 'SeekID',
144
+ value: '0x1549a966',
145
+ minVintWidth: 1,
146
+ },
147
+ {
148
+ type: 'SeekPosition',
149
+ value: {value: 0x40, byteLength: 1},
150
+ minVintWidth: 1,
151
+ },
152
+ ],
153
+ minVintWidth: 1,
154
+ });
155
+
156
+ const custom = makeMatroskaBytes(parsed);
157
+ expect(custom).toEqual(file);
158
+ });
159
+
160
+ test('Should parse seekHead', async () => {
161
+ const file = new Uint8Array(
162
+ await Bun.file('vp8-segments/2165155-0x114d9b74').arrayBuffer(),
163
+ );
164
+
165
+ const seekPosition = makeMatroskaBytes({
166
+ type: 'SeekPosition',
167
+ value: {value: 3911, byteLength: 2},
168
+ minVintWidth: 1,
169
+ });
170
+
171
+ const custom = makeMatroskaBytes({
172
+ type: 'SeekHead',
173
+ value: [
174
+ {
175
+ type: 'Seek',
176
+ value: [
177
+ {
178
+ type: 'SeekID',
179
+ value: '0x1f43b675',
180
+ minVintWidth: 1,
181
+ },
182
+ seekPosition,
183
+ ],
184
+ minVintWidth: 1,
185
+ },
186
+ ],
187
+ minVintWidth: 1,
188
+ });
189
+ expect(custom).toEqual(file);
190
+
191
+ const iterator = getArrayBufferIterator(file, file.length);
192
+ const parsed = await parseEbml(iterator, options);
193
+
194
+ expect(parsed).toEqual({
195
+ minVintWidth: 1,
196
+ type: 'SeekHead',
197
+ value: [
198
+ {
199
+ minVintWidth: 1,
200
+ type: 'Seek',
201
+ value: [
202
+ {minVintWidth: 1, type: 'SeekID', value: '0x1f43b675'},
203
+ {
204
+ minVintWidth: 1,
205
+ type: 'SeekPosition',
206
+ value: {value: 3911, byteLength: 2},
207
+ },
208
+ ],
209
+ },
210
+ ],
211
+ });
212
+ });
213
+
214
+ const parseWebm = async (str: string) => {
215
+ const {boxes} = await parseMedia({
216
+ src: str,
217
+ fields: {
218
+ boxes: true,
219
+ },
220
+ reader: nodeReader,
221
+ });
222
+ return boxes;
223
+ };
224
+
225
+ const stringifyWebm = (boxes: AnySegment[]) => {
226
+ const buffers: Uint8Array[] = [];
227
+ for (const box of boxes) {
228
+ const bytes = makeMatroskaBytes(box as MatroskaSegment);
229
+ buffers.push(bytes);
230
+ }
231
+
232
+ const combined = combineUint8Arrays(buffers);
233
+ return combined;
234
+ };
235
+
236
+ test('Can we disassemble a Matroska file and assembled it again', async () => {
237
+ process.env.KEEP_SAMPLES = 'true';
8
238
 
9
- const headerInput = new Uint8Array(file.slice(0, 0x23 + 5));
239
+ const parsed = await parseWebm('input.webm');
10
240
 
11
- const headerOutput = makeMatroskaHeader();
241
+ const segment = parsed.find((s) => s.type === 'Segment') as MainSegment;
242
+ const tracks = segment.value.flatMap((s) =>
243
+ s.type === 'Tracks' ? s.value.filter((a) => a.type === 'TrackEntry') : [],
244
+ );
245
+ for (const track of tracks as TrackEntry[]) {
246
+ for (const child of track.value) {
247
+ if (child.type === 'Video') {
248
+ for (const attribute of child.value) {
249
+ if (attribute.type === 'DisplayHeight') {
250
+ attribute.value.value *= 2;
251
+ }
252
+ }
253
+ }
254
+ }
255
+ }
12
256
 
13
- expect(headerInput).toEqual(headerOutput);
257
+ const bytes = await Bun.file('input.webm').arrayBuffer();
258
+ expect(stringifyWebm(parsed).byteLength).toEqual(
259
+ new Uint8Array(bytes).byteLength,
260
+ );
261
+ process.env.KEEP_SAMPLES = 'false';
14
262
  });