@remotion/media-parser 4.0.201 → 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 (113) hide show
  1. package/dist/boxes/iso-base-media/mvhd.js +2 -2
  2. package/dist/boxes/iso-base-media/stsd/keys.js +1 -1
  3. package/dist/boxes/webm/av1-codec-private.js +1 -1
  4. package/dist/boxes/webm/description.d.ts +2 -2
  5. package/dist/boxes/webm/description.js +2 -2
  6. package/dist/boxes/webm/ebml.d.ts +2 -2
  7. package/dist/boxes/webm/ebml.js +23 -1
  8. package/dist/boxes/webm/get-ready-tracks.d.ts +1 -1
  9. package/dist/boxes/webm/get-ready-tracks.js +3 -3
  10. package/dist/boxes/webm/get-sample-from-block.d.ts +17 -0
  11. package/dist/boxes/webm/get-sample-from-block.js +78 -0
  12. package/dist/boxes/webm/get-track.d.ts +2 -2
  13. package/dist/boxes/webm/get-track.js +26 -25
  14. package/dist/boxes/webm/make-header.d.ts +3 -8
  15. package/dist/boxes/webm/make-header.js +43 -20
  16. package/dist/boxes/webm/parse-ebml.d.ts +9 -4
  17. package/dist/boxes/webm/parse-ebml.js +122 -13
  18. package/dist/boxes/webm/segments/all-segments.d.ts +421 -107
  19. package/dist/boxes/webm/segments/all-segments.js +260 -33
  20. package/dist/boxes/webm/segments/seek-position.js +1 -1
  21. package/dist/boxes/webm/segments/seek.d.ts +1 -1
  22. package/dist/boxes/webm/segments/seek.js +2 -8
  23. package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
  24. package/dist/boxes/webm/segments/track-entry.d.ts +3 -191
  25. package/dist/boxes/webm/segments/track-entry.js +2 -456
  26. package/dist/boxes/webm/segments.d.ts +3 -16
  27. package/dist/boxes/webm/segments.js +12 -196
  28. package/dist/boxes/webm/traversal.d.ts +5 -6
  29. package/dist/boxes/webm/traversal.js +6 -6
  30. package/dist/buffer-iterator.d.ts +1 -1
  31. package/dist/buffer-iterator.js +3 -3
  32. package/dist/create/create-media.d.ts +2 -0
  33. package/dist/create/create-media.js +36 -0
  34. package/dist/create/matroska-header.d.ts +1 -0
  35. package/dist/create/matroska-header.js +66 -0
  36. package/dist/create/matroska-info.d.ts +4 -0
  37. package/dist/create/matroska-info.js +39 -0
  38. package/dist/create/matroska-segment.d.ts +1 -0
  39. package/dist/create/matroska-segment.js +12 -0
  40. package/dist/create/matroska-trackentry.d.ts +21 -0
  41. package/dist/create/matroska-trackentry.js +191 -0
  42. package/dist/create-media.d.ts +1 -0
  43. package/dist/create-media.js +78 -0
  44. package/dist/get-audio-codec.d.ts +1 -1
  45. package/dist/get-audio-codec.js +13 -13
  46. package/dist/get-duration.js +12 -14
  47. package/dist/get-tracks.js +2 -2
  48. package/dist/get-video-codec.js +13 -13
  49. package/dist/parse-media.js +4 -1
  50. package/dist/parser-context.d.ts +1 -0
  51. package/dist/parser-state.js +3 -2
  52. package/dist/readers/from-fetch.d.ts +2 -0
  53. package/dist/readers/from-fetch.js +64 -0
  54. package/dist/readers/from-node.d.ts +2 -0
  55. package/dist/readers/from-node.js +40 -0
  56. package/dist/readers/from-web-file.d.ts +2 -0
  57. package/dist/readers/from-web-file.js +39 -0
  58. package/dist/readers/reader.d.ts +11 -0
  59. package/dist/readers/reader.js +2 -0
  60. package/dist/traversal.d.ts +19 -17
  61. package/dist/traversal.js +38 -39
  62. package/dist/writers/web-fs.d.ts +2 -0
  63. package/dist/writers/web-fs.js +28 -0
  64. package/dist/writers/writer.d.ts +9 -0
  65. package/dist/writers/writer.js +2 -0
  66. package/input.webm +0 -0
  67. package/package.json +2 -2
  68. package/src/boxes/iso-base-media/mvhd.ts +2 -2
  69. package/src/boxes/iso-base-media/stsd/keys.ts +1 -1
  70. package/src/boxes/webm/av1-codec-private.ts +1 -1
  71. package/src/boxes/webm/description.ts +7 -4
  72. package/src/boxes/webm/ebml.ts +24 -4
  73. package/src/boxes/webm/get-ready-tracks.ts +4 -4
  74. package/src/boxes/webm/get-sample-from-block.ts +125 -0
  75. package/src/boxes/webm/get-track.ts +38 -31
  76. package/src/boxes/webm/make-header.ts +58 -51
  77. package/src/boxes/webm/parse-ebml.ts +170 -16
  78. package/src/boxes/webm/segments/all-segments.ts +379 -62
  79. package/src/boxes/webm/segments/track-entry.ts +3 -846
  80. package/src/boxes/webm/segments.ts +18 -410
  81. package/src/boxes/webm/traversal.ts +17 -17
  82. package/src/buffer-iterator.ts +5 -4
  83. package/src/get-audio-codec.ts +14 -16
  84. package/src/get-duration.ts +15 -16
  85. package/src/get-tracks.ts +2 -2
  86. package/src/get-video-codec.ts +13 -15
  87. package/src/parse-media.ts +6 -1
  88. package/src/parser-context.ts +1 -0
  89. package/src/parser-state.ts +2 -2
  90. package/src/test/create-matroska.test.ts +237 -23
  91. package/src/test/matroska.test.ts +283 -348
  92. package/src/test/mvhd.test.ts +1 -1
  93. package/src/test/parse-esds.test.ts +2 -2
  94. package/src/test/parse-stco.test.ts +2 -2
  95. package/src/test/parse-stsc.test.ts +2 -2
  96. package/src/test/parse-stsz.test.ts +2 -2
  97. package/src/test/parse-stts.test.ts +1 -1
  98. package/src/test/stsd.test.ts +4 -2
  99. package/src/test/tkhd.test.ts +1 -1
  100. package/src/traversal.ts +62 -85
  101. package/tsconfig.tsbuildinfo +1 -1
  102. package/src/boxes/webm/segments/duration.ts +0 -29
  103. package/src/boxes/webm/segments/info.ts +0 -34
  104. package/src/boxes/webm/segments/main.ts +0 -6
  105. package/src/boxes/webm/segments/muxing.ts +0 -18
  106. package/src/boxes/webm/segments/seek-head.ts +0 -34
  107. package/src/boxes/webm/segments/seek-position.ts +0 -18
  108. package/src/boxes/webm/segments/seek.ts +0 -55
  109. package/src/boxes/webm/segments/timestamp-scale.ts +0 -17
  110. package/src/boxes/webm/segments/tracks.ts +0 -32
  111. package/src/boxes/webm/segments/void.ts +0 -18
  112. package/src/boxes/webm/segments/writing.ts +0 -18
  113. package/src/combine-uint8array.ts +0 -13
@@ -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
  }
@@ -52,6 +52,11 @@ export const parseMedia: ParseMedia = async ({
52
52
  onAudioTrack: onAudioTrack ?? null,
53
53
  onVideoTrack: onVideoTrack ?? null,
54
54
  parserState: state,
55
+ nullifySamples: !(
56
+ typeof process !== 'undefined' &&
57
+ typeof process.env !== 'undefined' &&
58
+ process.env.KEEP_SAMPLES === 'true'
59
+ ),
55
60
  };
56
61
 
57
62
  while (parseResult === null || parseResult.status === 'incomplete') {
@@ -72,7 +77,7 @@ export const parseMedia: ParseMedia = async ({
72
77
 
73
78
  iterator = getArrayBufferIterator(
74
79
  result.value,
75
- contentLength ?? undefined,
80
+ contentLength ?? 1_000_000_000,
76
81
  );
77
82
  }
78
83
 
@@ -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
  };
@@ -40,8 +40,8 @@ export const makeParserState = ({
40
40
  const trackTimescale = getTrackTimestampScale(trackEntry);
41
41
 
42
42
  trackEntries[trackId] = {
43
- codec: codec.codec,
44
- trackTimescale,
43
+ codec: codec.value,
44
+ trackTimescale: trackTimescale?.value ?? null,
45
45
  };
46
46
  };
47
47
 
@@ -1,29 +1,121 @@
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 {
5
- matroskaHeader,
6
- seek,
7
- seekId,
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,
8
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';
9
17
 
10
- test('Should make Matroska header that is same as input', async () => {
11
- const exampleVideo = RenderInternals.exampleVideos.matroskaMp3;
12
- const file = await Bun.file(exampleVideo).arrayBuffer();
18
+ const state = makeParserState({
19
+ hasAudioCallbacks: false,
20
+ hasVideoCallbacks: false,
21
+ signal: undefined,
22
+ });
13
23
 
14
- const headerInput = new Uint8Array(file.slice(0, 0x28));
24
+ const options: ParserContext = {
25
+ canSkipVideoData: true,
26
+ onAudioTrack: null,
27
+ onVideoTrack: null,
28
+ parserState: state,
29
+ nullifySamples: false,
30
+ };
15
31
 
16
- const headerOutput = makeMatroskaHeader(matroskaHeader, {
17
- DocType: 'matroska',
18
- DocTypeVersion: 4,
19
- DocTypeReadVersion: 2,
20
- EBMLMaxIDLength: 4,
21
- EBMLMaxSizeLength: 8,
22
- EBMLReadVersion: 1,
23
- EBMLVersion: 1,
32
+ test('Should make Matroska header that is same as input', async () => {
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
+ ],
24
73
  });
25
74
 
26
- expect(headerInput).toEqual(headerOutput);
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
+ });
27
119
  });
28
120
 
29
121
  test('Should be able to create SeekIdBox', async () => {
@@ -31,7 +123,11 @@ test('Should be able to create SeekIdBox', async () => {
31
123
  await Bun.file('vp8-segments/56-0x53ab').arrayBuffer(),
32
124
  );
33
125
 
34
- const custom = makeMatroskaHeader(seekId, '0x1549a966');
126
+ const custom = makeMatroskaBytes({
127
+ type: 'SeekID',
128
+ value: '0x1549a966',
129
+ minVintWidth: 1,
130
+ });
35
131
  expect(custom).toEqual(file);
36
132
  });
37
133
 
@@ -39,10 +135,128 @@ test('Should be able to create Seek', async () => {
39
135
  const file = new Uint8Array(
40
136
  await Bun.file('vp8-segments/53-0x4dbb').arrayBuffer(),
41
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
+ });
42
170
 
43
- const custom = makeMatroskaHeader(seek, {
44
- SeekID: '0x1549a966',
45
- SeekPosition: 0x40,
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,
46
188
  });
47
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';
238
+
239
+ const parsed = await parseWebm('input.webm');
240
+
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
+ }
256
+
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';
48
262
  });