@remotion/media-parser 4.0.206 → 4.0.207

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 (69) hide show
  1. package/dist/boxes/iso-base-media/stsd/ctts.js +8 -1
  2. package/dist/boxes/iso-base-media/stsd/samples.d.ts +6 -3
  3. package/dist/boxes/iso-base-media/stsd/samples.js +6 -6
  4. package/dist/boxes/webm/ebml.d.ts +1 -1
  5. package/dist/boxes/webm/make-header.d.ts +6 -2
  6. package/dist/boxes/webm/make-header.js +102 -18
  7. package/dist/boxes/webm/parse-ebml.js +3 -1
  8. package/dist/boxes/webm/segments/all-segments.d.ts +70 -12
  9. package/dist/boxes/webm/segments/all-segments.js +43 -5
  10. package/dist/create/cluster-segment.d.ts +10 -0
  11. package/dist/create/cluster-segment.js +41 -0
  12. package/dist/create/create-media.d.ts +13 -0
  13. package/dist/create/create-media.js +108 -0
  14. package/dist/create/matroska-header.d.ts +1 -0
  15. package/dist/create/matroska-header.js +66 -0
  16. package/dist/create/matroska-info.d.ts +4 -0
  17. package/dist/create/matroska-info.js +41 -0
  18. package/dist/create/matroska-segment.d.ts +2 -0
  19. package/dist/create/matroska-segment.js +12 -0
  20. package/dist/create/matroska-trackentry.d.ts +32 -0
  21. package/dist/create/matroska-trackentry.js +266 -0
  22. package/dist/get-audio-codec.d.ts +1 -1
  23. package/dist/index.d.ts +5 -0
  24. package/dist/index.js +5 -1
  25. package/dist/options.d.ts +1 -1
  26. package/dist/parse-media.js +1 -1
  27. package/dist/readers/from-fetch.d.ts +2 -0
  28. package/dist/readers/from-fetch.js +64 -0
  29. package/dist/readers/from-node.d.ts +2 -0
  30. package/dist/readers/from-node.js +40 -0
  31. package/dist/readers/from-web-file.d.ts +2 -0
  32. package/dist/readers/from-web-file.js +39 -0
  33. package/dist/readers/reader.d.ts +11 -0
  34. package/dist/readers/reader.js +2 -0
  35. package/dist/traversal.d.ts +1 -1
  36. package/dist/writers/web-fs.d.ts +2 -0
  37. package/dist/writers/web-fs.js +44 -0
  38. package/dist/writers/writer.d.ts +11 -0
  39. package/dist/writers/writer.js +2 -0
  40. package/package.json +13 -8
  41. package/src/boxes/iso-base-media/stsd/ctts.ts +10 -1
  42. package/src/boxes/iso-base-media/stsd/samples.ts +12 -9
  43. package/src/boxes/webm/make-header.ts +132 -24
  44. package/src/boxes/webm/parse-ebml.ts +4 -1
  45. package/src/boxes/webm/segments/all-segments.ts +67 -7
  46. package/src/create/cluster-segment.ts +62 -0
  47. package/src/create/create-media.ts +172 -0
  48. package/src/create/matroska-header.ts +63 -0
  49. package/src/create/matroska-info.ts +46 -0
  50. package/src/create/matroska-segment.ts +10 -0
  51. package/src/create/matroska-trackentry.ts +325 -0
  52. package/src/index.ts +9 -0
  53. package/src/options.ts +1 -1
  54. package/src/parse-media.ts +1 -1
  55. package/src/test/av1.test.ts +1 -1
  56. package/src/test/create-matroska.test.ts +31 -6
  57. package/src/test/duration.test.ts +1 -1
  58. package/src/test/matroska.test.ts +35 -5
  59. package/src/test/parse-video.test.ts +1 -1
  60. package/src/test/parse-webm.test.ts +1 -1
  61. package/src/test/stream-local.test.ts +1 -1
  62. package/src/test/stream-samples.test.ts +1 -1
  63. package/src/writers/web-fs.ts +50 -0
  64. package/src/writers/writer.ts +12 -0
  65. package/tsconfig.tsbuildinfo +1 -1
  66. /package/src/{from-fetch.ts → readers/from-fetch.ts} +0 -0
  67. /package/src/{from-node.ts → readers/from-node.ts} +0 -0
  68. /package/src/{from-web-file.ts → readers/from-web-file.ts} +0 -0
  69. /package/src/{reader.ts → readers/reader.ts} +0 -0
@@ -0,0 +1,62 @@
1
+ import {getVariableInt} from '../boxes/webm/ebml';
2
+ import {
3
+ combineUint8Arrays,
4
+ makeMatroskaBytes,
5
+ matroskaToHex,
6
+ serializeUint16,
7
+ } from '../boxes/webm/make-header';
8
+
9
+ export const CLUSTER_MIN_VINT_WIDTH = 8;
10
+
11
+ export const createClusterSegment = () => {
12
+ return makeMatroskaBytes({
13
+ type: 'Cluster',
14
+ value: [
15
+ {
16
+ type: 'Timestamp',
17
+ minVintWidth: 4,
18
+ value: {
19
+ value: 0,
20
+ byteLength: null,
21
+ },
22
+ },
23
+ ],
24
+ minVintWidth: CLUSTER_MIN_VINT_WIDTH,
25
+ });
26
+ };
27
+
28
+ export const makeSimpleBlock = ({
29
+ bytes,
30
+ trackNumber,
31
+ timecodeRelativeToCluster,
32
+ keyframe,
33
+ invisible,
34
+ lacing,
35
+ }: {
36
+ bytes: Uint8Array;
37
+ trackNumber: number;
38
+ timecodeRelativeToCluster: number;
39
+ keyframe: boolean;
40
+ invisible: boolean;
41
+ lacing: number;
42
+ }) => {
43
+ const simpleBlockHeader = matroskaToHex('0xa3');
44
+
45
+ const headerByte =
46
+ (Number(keyframe) << 7) | (Number(invisible) << 3) | (lacing << 1);
47
+
48
+ const body = combineUint8Arrays([
49
+ getVariableInt(trackNumber, null),
50
+ // TODO: Cannot encode long videos because of uint16 overflow
51
+ // need to make new cluster
52
+ serializeUint16(timecodeRelativeToCluster),
53
+ new Uint8Array([headerByte]),
54
+ bytes,
55
+ ]);
56
+
57
+ return combineUint8Arrays([
58
+ simpleBlockHeader,
59
+ getVariableInt(body.length, null),
60
+ body,
61
+ ]);
62
+ };
@@ -0,0 +1,172 @@
1
+ import {getVariableInt} from '../boxes/webm/ebml';
2
+ import {
3
+ combineUint8Arrays,
4
+ matroskaToHex,
5
+ padMatroskaBytes,
6
+ } from '../boxes/webm/make-header';
7
+ import type {BytesAndOffset} from '../boxes/webm/segments/all-segments';
8
+ import {matroskaElements} from '../boxes/webm/segments/all-segments';
9
+ import type {WriterInterface} from '../writers/writer';
10
+ import {
11
+ CLUSTER_MIN_VINT_WIDTH,
12
+ createClusterSegment,
13
+ makeSimpleBlock,
14
+ } from './cluster-segment';
15
+ import {makeMatroskaHeader} from './matroska-header';
16
+ import {makeMatroskaInfo} from './matroska-info';
17
+ import {createMatroskaSegment} from './matroska-segment';
18
+ import type {MakeTrackAudio, MakeTrackVideo} from './matroska-trackentry';
19
+ import {
20
+ makeMatroskaAudioTrackEntryBytes,
21
+ makeMatroskaTracks,
22
+ makeMatroskaVideoTrackEntryBytes,
23
+ } from './matroska-trackentry';
24
+
25
+ export type MediaFn = {
26
+ save: () => Promise<void>;
27
+ addSample: (chunk: EncodedVideoChunk, trackNumber: number) => Promise<void>;
28
+ updateDuration: (duration: number) => Promise<void>;
29
+ addTrack: (
30
+ track:
31
+ | Omit<MakeTrackAudio, 'trackNumber'>
32
+ | Omit<MakeTrackVideo, 'trackNumber'>,
33
+ ) => Promise<{trackNumber: number}>;
34
+ addWaitForFinishPromise: (promise: () => Promise<void>) => void;
35
+ waitForFinish: () => Promise<void>;
36
+ };
37
+
38
+ export const createMedia = async (
39
+ writer: WriterInterface,
40
+ ): Promise<MediaFn> => {
41
+ const header = makeMatroskaHeader();
42
+
43
+ const w = await writer.createContent();
44
+ await w.write(header.bytes);
45
+ const matroskaInfo = makeMatroskaInfo({
46
+ timescale: 1_000_000,
47
+ // TODO: Hardcoded
48
+ duration: 2658,
49
+ });
50
+
51
+ const currentTracks: BytesAndOffset[] = [];
52
+
53
+ const matroskaTracks = makeMatroskaTracks(currentTracks);
54
+ const matroskaSegment = createMatroskaSegment([
55
+ matroskaInfo,
56
+ ...matroskaTracks,
57
+ ]);
58
+
59
+ const durationOffset =
60
+ (matroskaSegment.offsets.children[0].children.find(
61
+ (c) => c.field === 'Duration',
62
+ )?.offset ?? 0) + w.getWrittenByteCount();
63
+ const tracksOffset =
64
+ (matroskaSegment.offsets.children.find((o) => o.field === 'Tracks')
65
+ ?.offset ?? 0) + w.getWrittenByteCount();
66
+
67
+ if (!durationOffset) {
68
+ throw new Error('could not get duration offset');
69
+ }
70
+
71
+ if (!tracksOffset) {
72
+ throw new Error('could not get tracks offset');
73
+ }
74
+
75
+ await w.write(matroskaSegment.bytes);
76
+
77
+ const cluster = createClusterSegment();
78
+ const clusterVIntPosition =
79
+ w.getWrittenByteCount() +
80
+ cluster.offsets.offset +
81
+ matroskaToHex(matroskaElements.Cluster).byteLength;
82
+
83
+ let clusterSize = cluster.bytes.byteLength;
84
+ await w.write(cluster.bytes);
85
+
86
+ const addSample = async (chunk: EncodedVideoChunk, trackNumber: number) => {
87
+ const arr = new Uint8Array(chunk.byteLength);
88
+ chunk.copyTo(arr);
89
+ const simpleBlock = makeSimpleBlock({
90
+ bytes: arr,
91
+ invisible: false,
92
+ keyframe: chunk.type === 'key',
93
+ lacing: 0,
94
+ trackNumber,
95
+ // TODO: Maybe this is bad, because it's in microseconds, but should be in timescale
96
+ // Maybe it only works by coincidence
97
+ timecodeRelativeToCluster: Math.round(chunk.timestamp / 1000),
98
+ });
99
+
100
+ clusterSize += simpleBlock.byteLength;
101
+ await w.updateDataAt(
102
+ clusterVIntPosition,
103
+ getVariableInt(clusterSize, CLUSTER_MIN_VINT_WIDTH),
104
+ );
105
+ await w.write(simpleBlock);
106
+ };
107
+
108
+ const updateDuration = async (newDuration: number) => {
109
+ const blocks = padMatroskaBytes(
110
+ {
111
+ type: 'Duration',
112
+ value: {
113
+ value: newDuration,
114
+ size: '64',
115
+ },
116
+ minVintWidth: null,
117
+ },
118
+ // TODO: That's too much padding
119
+ 1000,
120
+ );
121
+ await w.updateDataAt(
122
+ durationOffset,
123
+ combineUint8Arrays(blocks.map((b) => b.bytes)),
124
+ );
125
+ };
126
+
127
+ const addTrack = async (track: BytesAndOffset) => {
128
+ currentTracks.push(track);
129
+ const newTracks = makeMatroskaTracks(currentTracks);
130
+
131
+ await w.updateDataAt(
132
+ tracksOffset,
133
+ combineUint8Arrays(newTracks.map((b) => b.bytes)),
134
+ );
135
+ };
136
+
137
+ let operationProm = Promise.resolve();
138
+
139
+ const waitForFinishPromises: (() => Promise<void>)[] = [];
140
+
141
+ return {
142
+ save: async () => {
143
+ await w.save();
144
+ },
145
+ addSample: (chunk, trackNumber) => {
146
+ operationProm = operationProm.then(() => addSample(chunk, trackNumber));
147
+ return operationProm;
148
+ },
149
+ updateDuration: (duration) => {
150
+ operationProm = operationProm.then(() => updateDuration(duration));
151
+ return operationProm;
152
+ },
153
+ addTrack: (track) => {
154
+ const trackNumber = currentTracks.length + 1;
155
+
156
+ const bytes =
157
+ track.type === 'video'
158
+ ? makeMatroskaVideoTrackEntryBytes({...track, trackNumber})
159
+ : makeMatroskaAudioTrackEntryBytes({...track, trackNumber});
160
+
161
+ operationProm = operationProm.then(() => addTrack(bytes));
162
+
163
+ return operationProm.then(() => ({trackNumber}));
164
+ },
165
+ addWaitForFinishPromise: (promise) => {
166
+ waitForFinishPromises.push(promise);
167
+ },
168
+ async waitForFinish() {
169
+ await Promise.all(waitForFinishPromises.map((p) => p()));
170
+ },
171
+ };
172
+ };
@@ -0,0 +1,63 @@
1
+ import {makeMatroskaBytes} from '../boxes/webm/make-header';
2
+
3
+ export const makeMatroskaHeader = () => {
4
+ return makeMatroskaBytes({
5
+ type: 'Header',
6
+ value: [
7
+ {
8
+ minVintWidth: null,
9
+ type: 'EBMLVersion',
10
+ value: {
11
+ value: 1,
12
+ byteLength: null,
13
+ },
14
+ },
15
+ {
16
+ minVintWidth: null,
17
+ type: 'EBMLReadVersion',
18
+ value: {
19
+ value: 1,
20
+ byteLength: null,
21
+ },
22
+ },
23
+ {
24
+ type: 'EBMLMaxIDLength',
25
+ value: {
26
+ byteLength: null,
27
+ value: 4,
28
+ },
29
+ minVintWidth: null,
30
+ },
31
+ {
32
+ type: 'EBMLMaxSizeLength',
33
+ value: {
34
+ byteLength: null,
35
+ value: 8,
36
+ },
37
+ minVintWidth: null,
38
+ },
39
+ {
40
+ type: 'DocType',
41
+ value: 'webm',
42
+ minVintWidth: null,
43
+ },
44
+ {
45
+ type: 'DocTypeVersion',
46
+ value: {
47
+ byteLength: null,
48
+ value: 4,
49
+ },
50
+ minVintWidth: null,
51
+ },
52
+ {
53
+ type: 'DocTypeReadVersion',
54
+ value: {
55
+ byteLength: null,
56
+ value: 2,
57
+ },
58
+ minVintWidth: null,
59
+ },
60
+ ],
61
+ minVintWidth: null,
62
+ });
63
+ };
@@ -0,0 +1,46 @@
1
+ import {makeMatroskaBytes, padMatroskaBytes} from '../boxes/webm/make-header';
2
+
3
+ export const makeMatroskaInfo = ({
4
+ timescale,
5
+ duration,
6
+ }: {
7
+ timescale: number;
8
+ duration: number;
9
+ }) => {
10
+ return makeMatroskaBytes({
11
+ type: 'Info',
12
+ value: [
13
+ {
14
+ type: 'TimestampScale',
15
+ value: {
16
+ value: timescale,
17
+ byteLength: null,
18
+ },
19
+ minVintWidth: null,
20
+ },
21
+ {
22
+ type: 'MuxingApp',
23
+ value: '@remotion/media-parser',
24
+ minVintWidth: null,
25
+ },
26
+ {
27
+ type: 'WritingApp',
28
+ value: '@remotion/media-parser',
29
+ minVintWidth: null,
30
+ },
31
+ ...padMatroskaBytes(
32
+ {
33
+ type: 'Duration',
34
+ value: {
35
+ value: duration,
36
+ size: '64',
37
+ },
38
+ minVintWidth: null,
39
+ },
40
+ // TODO: That's too much padding
41
+ 1000,
42
+ ),
43
+ ],
44
+ minVintWidth: null,
45
+ });
46
+ };
@@ -0,0 +1,10 @@
1
+ import {makeMatroskaBytes} from '../boxes/webm/make-header';
2
+ import type {BytesAndOffset} from '../boxes/webm/segments/all-segments';
3
+
4
+ export const createMatroskaSegment = (children: BytesAndOffset[]) => {
5
+ return makeMatroskaBytes({
6
+ type: 'Segment',
7
+ value: children,
8
+ minVintWidth: 8,
9
+ });
10
+ };
@@ -0,0 +1,325 @@
1
+ import {makeMatroskaBytes, padMatroskaBytes} from '../boxes/webm/make-header';
2
+ import type {BytesAndOffset} from '../boxes/webm/segments/all-segments';
3
+
4
+ export type MatroskaColorParams = {
5
+ transferChracteristics: 'bt709' | 'smpte170m' | 'iec61966-2-1' | null;
6
+ matrixCoefficients: 'bt709' | 'bt470bg' | 'rgb' | 'smpte170m' | null;
7
+ primaries: 'bt709' | 'smpte170m' | 'bt470bg' | null;
8
+ fullRange: boolean | null;
9
+ };
10
+
11
+ export const makeMatroskaColorBytes = ({
12
+ transferChracteristics,
13
+ matrixCoefficients,
14
+ primaries,
15
+ fullRange,
16
+ }: MatroskaColorParams) => {
17
+ const rangeValue =
18
+ transferChracteristics && matrixCoefficients
19
+ ? 3
20
+ : fullRange === true
21
+ ? 2
22
+ : fullRange === false
23
+ ? 1
24
+ : 0;
25
+
26
+ // https://datatracker.ietf.org/doc/draft-ietf-cellar-matroska/
27
+ // 5.1.4.1.28.27
28
+ const primariesValue =
29
+ primaries === 'bt709'
30
+ ? 1
31
+ : primaries === 'smpte170m'
32
+ ? 6
33
+ : primaries === 'bt470bg'
34
+ ? 5
35
+ : 2;
36
+
37
+ const transferChracteristicsValue =
38
+ transferChracteristics === 'bt709'
39
+ ? 1
40
+ : transferChracteristics === 'smpte170m'
41
+ ? 6
42
+ : transferChracteristics === 'iec61966-2-1'
43
+ ? 13
44
+ : 2;
45
+
46
+ if (matrixCoefficients === 'rgb') {
47
+ throw new Error('Cannot encode Matroska in RGB');
48
+ }
49
+
50
+ const matrixCoefficientsValue =
51
+ matrixCoefficients === 'bt709'
52
+ ? 1
53
+ : matrixCoefficients === 'bt470bg'
54
+ ? 5
55
+ : matrixCoefficients === 'smpte170m'
56
+ ? 6
57
+ : 2;
58
+
59
+ return makeMatroskaBytes({
60
+ type: 'Colour',
61
+ minVintWidth: null,
62
+ value: [
63
+ {
64
+ type: 'TransferCharacteristics',
65
+ value: {
66
+ value: transferChracteristicsValue,
67
+ byteLength: null,
68
+ },
69
+ minVintWidth: null,
70
+ },
71
+ {
72
+ type: 'MatrixCoefficients',
73
+ value: {
74
+ value: matrixCoefficientsValue,
75
+ byteLength: null,
76
+ },
77
+ minVintWidth: null,
78
+ },
79
+ {
80
+ type: 'Primaries',
81
+ value: {
82
+ value: primariesValue,
83
+ byteLength: null,
84
+ },
85
+ minVintWidth: null,
86
+ },
87
+ {
88
+ type: 'Range',
89
+ value: {
90
+ value: rangeValue,
91
+ byteLength: null,
92
+ },
93
+ minVintWidth: null,
94
+ },
95
+ ],
96
+ });
97
+ };
98
+
99
+ export const makeMatroskaVideoBytes = ({
100
+ color,
101
+ width,
102
+ height,
103
+ }: {
104
+ color: MatroskaColorParams;
105
+ width: number;
106
+ height: number;
107
+ }) => {
108
+ return makeMatroskaBytes({
109
+ type: 'Video',
110
+ value: [
111
+ {
112
+ type: 'PixelWidth',
113
+ value: {
114
+ value: width,
115
+ byteLength: null,
116
+ },
117
+ minVintWidth: null,
118
+ },
119
+ {
120
+ type: 'PixelHeight',
121
+ value: {
122
+ value: height,
123
+ byteLength: null,
124
+ },
125
+ minVintWidth: null,
126
+ },
127
+ {
128
+ type: 'FlagInterlaced',
129
+ value: {
130
+ // https://datatracker.ietf.org/doc/draft-ietf-cellar-matroska/
131
+ // 5.1.4.1.28.1.
132
+ value: 2, // 2 - progressive, no interlaced
133
+ byteLength: null,
134
+ },
135
+ minVintWidth: null,
136
+ },
137
+ makeMatroskaColorBytes(color),
138
+ ],
139
+ minVintWidth: null,
140
+ });
141
+ };
142
+
143
+ export type MakeTrackAudio = {
144
+ trackNumber: number;
145
+ codecId: string;
146
+ numberOfChannels: number;
147
+ sampleRate: number;
148
+ type: 'audio';
149
+ };
150
+
151
+ export type MakeTrackVideo = {
152
+ color: MatroskaColorParams;
153
+ width: number;
154
+ height: number;
155
+ defaultDuration: number;
156
+ trackNumber: number;
157
+ codecId: string;
158
+ type: 'video';
159
+ };
160
+
161
+ export const makeMatroskaAudioTrackEntryBytes = ({
162
+ trackNumber,
163
+ codecId,
164
+ numberOfChannels: audioChannels,
165
+ sampleRate,
166
+ }: MakeTrackAudio) => {
167
+ return makeMatroskaBytes({
168
+ type: 'TrackEntry',
169
+ minVintWidth: null,
170
+ value: [
171
+ {
172
+ type: 'TrackNumber',
173
+ value: {
174
+ value: trackNumber,
175
+ byteLength: null,
176
+ },
177
+ minVintWidth: null,
178
+ },
179
+ {
180
+ type: 'TrackUID',
181
+ value: '0x188FEB95C8EFABA',
182
+ minVintWidth: null,
183
+ },
184
+ {
185
+ type: 'TrackType',
186
+ value: {
187
+ value: 2,
188
+ byteLength: null,
189
+ },
190
+ minVintWidth: null,
191
+ },
192
+ {
193
+ type: 'TrackTimestampScale',
194
+ value: {
195
+ value: 1,
196
+ size: '64',
197
+ },
198
+ minVintWidth: null,
199
+ },
200
+ {
201
+ type: 'CodecID',
202
+ value: codecId,
203
+ minVintWidth: null,
204
+ },
205
+ {
206
+ type: 'Audio',
207
+ value: [
208
+ {
209
+ type: 'Channels',
210
+ minVintWidth: null,
211
+ value: {
212
+ value: audioChannels,
213
+ byteLength: null,
214
+ },
215
+ },
216
+ {
217
+ type: 'SamplingFrequency',
218
+ minVintWidth: null,
219
+ value: {
220
+ value: sampleRate,
221
+ size: '64',
222
+ },
223
+ },
224
+ {
225
+ type: 'BitDepth',
226
+ minVintWidth: null,
227
+ value: {
228
+ value: 32,
229
+ byteLength: null,
230
+ },
231
+ },
232
+ ],
233
+ minVintWidth: null,
234
+ },
235
+ ],
236
+ });
237
+ };
238
+
239
+ export const makeMatroskaVideoTrackEntryBytes = ({
240
+ color,
241
+ width,
242
+ height,
243
+ defaultDuration,
244
+ trackNumber,
245
+ codecId,
246
+ }: MakeTrackVideo) => {
247
+ return makeMatroskaBytes({
248
+ type: 'TrackEntry',
249
+ minVintWidth: null,
250
+ value: [
251
+ {
252
+ type: 'TrackNumber',
253
+ value: {
254
+ value: trackNumber,
255
+ byteLength: null,
256
+ },
257
+ minVintWidth: null,
258
+ },
259
+ {
260
+ type: 'TrackUID',
261
+ value: '0xab2171012bb9020a',
262
+ minVintWidth: null,
263
+ },
264
+ {
265
+ type: 'FlagLacing',
266
+ value: {
267
+ value: 0,
268
+ byteLength: null,
269
+ },
270
+ minVintWidth: null,
271
+ },
272
+ {
273
+ type: 'Language',
274
+ value: 'und',
275
+ minVintWidth: null,
276
+ },
277
+ {
278
+ type: 'FlagDefault',
279
+ value: {
280
+ value: 0,
281
+ byteLength: null,
282
+ },
283
+ minVintWidth: null,
284
+ },
285
+ {
286
+ type: 'CodecID',
287
+ value: codecId,
288
+ minVintWidth: null,
289
+ },
290
+ {
291
+ type: 'TrackType',
292
+ value: {
293
+ value: 1, // 'video'
294
+ byteLength: null,
295
+ },
296
+ minVintWidth: null,
297
+ },
298
+ {
299
+ type: 'DefaultDuration',
300
+ value: {
301
+ value: defaultDuration,
302
+ byteLength: null,
303
+ },
304
+ minVintWidth: null,
305
+ },
306
+ makeMatroskaVideoBytes({
307
+ color,
308
+ width,
309
+ height,
310
+ }),
311
+ ],
312
+ });
313
+ };
314
+
315
+ export const makeMatroskaTracks = (tracks: BytesAndOffset[]) => {
316
+ return padMatroskaBytes(
317
+ makeMatroskaBytes({
318
+ type: 'Tracks',
319
+ value: tracks,
320
+ minVintWidth: null,
321
+ }),
322
+ // TODO: That's too much padding
323
+ 1000,
324
+ );
325
+ };
package/src/index.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import {createMedia} from './create/create-media';
2
+
3
+ export {AudioTrack, OtherTrack, Track, VideoTrack} from './get-tracks';
1
4
  export {parseMedia} from './parse-media';
2
5
  export {
3
6
  AudioSample,
@@ -7,3 +10,9 @@ export {
7
10
  OnVideoTrack,
8
11
  VideoSample,
9
12
  } from './webcodec-sample-types';
13
+
14
+ export type {MediaFn} from './create/create-media';
15
+
16
+ export const MediaParserInternals = {
17
+ createMedia,
18
+ };
package/src/options.ts CHANGED
@@ -3,7 +3,7 @@ import type {Dimensions} from './get-dimensions';
3
3
  import type {AudioTrack, VideoTrack} from './get-tracks';
4
4
  import type {AnySegment} from './parse-result';
5
5
  import type {InternalStats} from './parser-state';
6
- import type {ReaderInterface} from './reader';
6
+ import type {ReaderInterface} from './readers/reader';
7
7
  import type {OnAudioTrack, OnVideoTrack} from './webcodec-sample-types';
8
8
 
9
9
  export type KnownVideoCodecs =
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable max-depth */
2
2
  import type {BufferIterator} from './buffer-iterator';
3
3
  import {getArrayBufferIterator} from './buffer-iterator';
4
- import {fetchReader} from './from-fetch';
5
4
  import {getAudioCodec} from './get-audio-codec';
6
5
  import {getDimensions} from './get-dimensions';
7
6
  import {getDuration} from './get-duration';
@@ -14,6 +13,7 @@ import type {ParseResult} from './parse-result';
14
13
  import {parseVideo} from './parse-video';
15
14
  import type {ParserContext} from './parser-context';
16
15
  import {makeParserState} from './parser-state';
16
+ import {fetchReader} from './readers/from-fetch';
17
17
 
18
18
  export const parseMedia: ParseMedia = async ({
19
19
  src,