@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.
- package/dist/av1-codec-string.d.ts +5 -0
- package/dist/av1-codec-string.js +18 -1
- package/dist/bitstream/av1.d.ts +2 -0
- package/dist/bitstream/av1.js +12 -0
- package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +20 -0
- package/dist/boxes/iso-base-media/avcc-hvcc.js +73 -0
- package/dist/boxes/iso-base-media/avcc.d.ts +18 -0
- package/dist/boxes/iso-base-media/avcc.js +27 -0
- package/dist/boxes/iso-base-media/esds-descriptors.d.ts +21 -0
- package/dist/boxes/iso-base-media/esds-descriptors.js +62 -0
- package/dist/boxes/iso-base-media/esds.d.ts +15 -0
- package/dist/boxes/iso-base-media/esds.js +27 -0
- package/dist/boxes/iso-base-media/mdat/mdat.js +2 -1
- package/dist/boxes/iso-base-media/moov/moov.js +1 -0
- package/dist/boxes/iso-base-media/process-box.d.ts +4 -2
- package/dist/boxes/iso-base-media/process-box.js +56 -40
- package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
- package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
- package/dist/boxes/iso-base-media/stsd/samples.js +3 -0
- package/dist/boxes/iso-base-media/stsd/stco.d.ts +3 -2
- package/dist/boxes/iso-base-media/stsd/stco.js +2 -2
- package/dist/boxes/iso-base-media/trak/trak.js +1 -0
- package/dist/boxes/webm/bitstream/av1.js +10 -1
- package/dist/boxes/webm/ebml.d.ts +1 -1
- package/dist/boxes/webm/make-header.d.ts +8 -1
- package/dist/boxes/webm/make-header.js +65 -30
- package/dist/boxes/webm/parse-ebml.d.ts +7 -0
- package/dist/boxes/webm/parse-ebml.js +66 -0
- package/dist/boxes/webm/parse-webm-header.js +8 -9
- package/dist/boxes/webm/segments/all-segments.d.ts +258 -1
- package/dist/boxes/webm/segments/all-segments.js +126 -2
- package/dist/boxes/webm/segments/seek-position.js +1 -1
- package/dist/boxes/webm/segments/seek.d.ts +1 -1
- package/dist/boxes/webm/segments/seek.js +8 -2
- package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
- package/dist/boxes/webm/segments/track-entry.d.ts +5 -1
- package/dist/boxes/webm/segments/track-entry.js +19 -20
- package/dist/boxes/webm/segments.d.ts +2 -2
- package/dist/boxes/webm/segments.js +30 -25
- package/dist/boxes/webm/traversal.d.ts +1 -0
- package/dist/boxes/webm/traversal.js +12 -1
- package/dist/buffer-iterator.d.ts +9 -6
- package/dist/buffer-iterator.js +83 -7
- package/dist/from-fetch.js +13 -3
- package/dist/from-input-type-file.d.ts +2 -0
- package/dist/from-input-type-file.js +37 -0
- package/dist/from-node.js +9 -2
- package/dist/from-web-file.js +6 -1
- package/dist/from-web.js +15 -6
- package/dist/get-audio-codec.d.ts +1 -1
- package/dist/get-codec.d.ts +4 -0
- package/dist/get-codec.js +22 -0
- package/dist/get-sample-positions.js +1 -1
- package/dist/has-all-info.js +1 -1
- package/dist/options.d.ts +3 -2
- package/dist/parse-media.js +13 -9
- package/dist/parse-video.js +16 -0
- package/dist/parser-state.d.ts +4 -3
- package/dist/parser-state.js +15 -3
- package/dist/reader.d.ts +1 -1
- package/dist/web-file.d.ts +2 -0
- package/dist/web-file.js +37 -0
- package/package.json +2 -2
- package/src/boxes/iso-base-media/mdat/mdat.ts +2 -1
- package/src/boxes/iso-base-media/moov/moov.ts +1 -0
- package/src/boxes/iso-base-media/process-box.ts +70 -40
- package/src/boxes/iso-base-media/stsd/mebx.ts +3 -0
- package/src/boxes/iso-base-media/stsd/samples.ts +3 -0
- package/src/boxes/iso-base-media/stsd/stco.ts +5 -3
- package/src/boxes/iso-base-media/trak/trak.ts +1 -0
- package/src/boxes/webm/make-header.ts +122 -32
- package/src/boxes/webm/parse-ebml.ts +93 -0
- package/src/boxes/webm/parse-webm-header.ts +8 -12
- package/src/boxes/webm/segments/all-segments.ts +222 -1
- package/src/boxes/webm/segments/seek-position.ts +1 -1
- package/src/boxes/webm/segments/seek.ts +12 -2
- package/src/boxes/webm/segments/timestamp-scale.ts +1 -1
- package/src/boxes/webm/segments/track-entry.ts +31 -26
- package/src/boxes/webm/segments.ts +37 -32
- package/src/boxes/webm/traversal.ts +13 -0
- package/src/buffer-iterator.ts +102 -9
- package/src/from-fetch.ts +22 -3
- package/src/from-node.ts +18 -4
- package/src/from-web-file.ts +11 -1
- package/src/get-sample-positions.ts +1 -1
- package/src/has-all-info.ts +1 -1
- package/src/options.ts +3 -2
- package/src/parse-media.ts +14 -8
- package/src/parse-video.ts +17 -0
- package/src/parser-state.ts +22 -5
- package/src/reader.ts +1 -0
- package/src/test/create-matroska.test.ts +36 -2
- package/src/test/matroska.test.ts +69 -27
- package/src/test/parse-stco.test.ts +2 -0
- package/src/test/stream-local.test.ts +23 -9
- package/src/test/stream-remote.test.ts +23 -19
- package/src/test/stsd.test.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
- package/dist/boxes/iso-base-media/ftype.js +0 -31
- package/dist/get-video-metadata.d.ts +0 -2
- package/dist/get-video-metadata.js +0 -44
- package/dist/read-and-increment-offset.d.ts +0 -28
- package/dist/read-and-increment-offset.js +0 -177
- package/dist/understand-vorbis.d.ts +0 -1
- package/dist/understand-vorbis.js +0 -12
- package/src/boxes/webm/segments/unknown.ts +0 -19
- /package/dist/{boxes/webm/bitstream/av1/frame.d.ts → get-samples.d.ts} +0 -0
- /package/dist/{boxes/webm/bitstream/av1/frame.js → get-samples.js} +0 -0
- /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.d.ts → sample-aspect-ratio.d.ts} +0 -0
- /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.js → sample-aspect-ratio.js} +0 -0
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import type {BufferIterator} from '../../buffer-iterator';
|
|
2
2
|
import type {ParseResult} from '../../parse-result';
|
|
3
3
|
import type {ParserContext} from '../../parser-context';
|
|
4
|
-
import {
|
|
4
|
+
import {expectChildren} from './segments/parse-children';
|
|
5
5
|
|
|
6
6
|
// Parsing according to https://darkcoding.net/software/reading-mediarecorders-webm-opus-output/
|
|
7
7
|
export const parseWebm = (
|
|
8
8
|
counter: BufferIterator,
|
|
9
9
|
parserContext: ParserContext,
|
|
10
10
|
): Promise<ParseResult> => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// Discard header for now
|
|
19
|
-
counter.discard(length);
|
|
20
|
-
|
|
21
|
-
return expectSegment(counter, parserContext);
|
|
11
|
+
return expectChildren({
|
|
12
|
+
iterator: counter,
|
|
13
|
+
length: Infinity,
|
|
14
|
+
initialChildren: [],
|
|
15
|
+
wrap: null,
|
|
16
|
+
parserContext,
|
|
17
|
+
});
|
|
22
18
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export const matroskaElements = {
|
|
2
|
+
Header: '0x1a45dfa3',
|
|
2
3
|
EBMLMaxIDLength: '0x42f2',
|
|
3
4
|
EBMLVersion: '0x4286',
|
|
4
|
-
EBMLReadVersion: '
|
|
5
|
+
EBMLReadVersion: '0x42f7',
|
|
5
6
|
EBMLMaxSizeLength: '0x42f3',
|
|
6
7
|
DocType: '0x4282',
|
|
7
8
|
DocTypeVersion: '0x4287',
|
|
@@ -288,3 +289,223 @@ export const getSegmentName = (id: string) => {
|
|
|
288
289
|
([, value]) => value === id,
|
|
289
290
|
)?.[0];
|
|
290
291
|
};
|
|
292
|
+
|
|
293
|
+
export const getIdForName = (name: string) => {
|
|
294
|
+
const value = Object.entries(matroskaElements).find(
|
|
295
|
+
([key]) => key === name,
|
|
296
|
+
)?.[1];
|
|
297
|
+
if (!value) {
|
|
298
|
+
throw new Error(`Could not find id for name ${name}`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return value;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export type MatroskaKey = keyof typeof matroskaElements;
|
|
305
|
+
|
|
306
|
+
export type MatroskaElement = (typeof matroskaElements)[MatroskaKey];
|
|
307
|
+
|
|
308
|
+
type EbmlType = 'string';
|
|
309
|
+
|
|
310
|
+
export type EbmlWithChildren = {
|
|
311
|
+
name: MatroskaKey;
|
|
312
|
+
type: 'children';
|
|
313
|
+
children: HeaderStructure;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export type EbmlWithUint8 = {
|
|
317
|
+
name: MatroskaKey;
|
|
318
|
+
type: 'uint';
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
export type EbmlWithHexString = {
|
|
322
|
+
name: MatroskaKey;
|
|
323
|
+
type: 'hex-string';
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
export type EbmlWithString = {
|
|
327
|
+
name: MatroskaKey;
|
|
328
|
+
type: EbmlType;
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
export type EbmlWithVoid = {
|
|
332
|
+
name: MatroskaKey;
|
|
333
|
+
type: 'void';
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
export type EbmlWithFloat = {
|
|
337
|
+
name: MatroskaKey;
|
|
338
|
+
type: 'float';
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export type Ebml =
|
|
342
|
+
| EbmlWithString
|
|
343
|
+
| EbmlWithUint8
|
|
344
|
+
| EbmlWithChildren
|
|
345
|
+
| EbmlWithVoid
|
|
346
|
+
| EbmlWithFloat
|
|
347
|
+
| EbmlWithHexString;
|
|
348
|
+
|
|
349
|
+
export const ebmlVersion = {
|
|
350
|
+
name: 'EBMLVersion',
|
|
351
|
+
type: 'uint',
|
|
352
|
+
} satisfies Ebml;
|
|
353
|
+
|
|
354
|
+
export const ebmlReadVersion = {
|
|
355
|
+
name: 'EBMLReadVersion',
|
|
356
|
+
type: 'uint',
|
|
357
|
+
} satisfies Ebml;
|
|
358
|
+
|
|
359
|
+
export const ebmlMaxIdLength = {
|
|
360
|
+
name: 'EBMLMaxIDLength',
|
|
361
|
+
type: 'uint',
|
|
362
|
+
} satisfies Ebml;
|
|
363
|
+
|
|
364
|
+
export const ebmlMaxSizeLength = {
|
|
365
|
+
name: 'EBMLMaxSizeLength',
|
|
366
|
+
type: 'uint',
|
|
367
|
+
} satisfies Ebml;
|
|
368
|
+
|
|
369
|
+
export const docType = {
|
|
370
|
+
name: 'DocType',
|
|
371
|
+
type: 'string',
|
|
372
|
+
} satisfies Ebml;
|
|
373
|
+
|
|
374
|
+
export const docTypeVersion = {
|
|
375
|
+
name: 'DocTypeVersion',
|
|
376
|
+
type: 'uint',
|
|
377
|
+
} satisfies Ebml;
|
|
378
|
+
|
|
379
|
+
export const docTypeReadVersion = {
|
|
380
|
+
name: 'DocTypeReadVersion',
|
|
381
|
+
type: 'uint',
|
|
382
|
+
} satisfies Ebml;
|
|
383
|
+
|
|
384
|
+
export const voidEbml = {
|
|
385
|
+
name: 'Void',
|
|
386
|
+
type: 'void',
|
|
387
|
+
} satisfies Ebml;
|
|
388
|
+
|
|
389
|
+
export type EmblTypes = {
|
|
390
|
+
uint: number;
|
|
391
|
+
float: number;
|
|
392
|
+
string: string;
|
|
393
|
+
children: HeaderStructure;
|
|
394
|
+
void: undefined;
|
|
395
|
+
'hex-string': string;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
export type HeaderStructure = Ebml[];
|
|
399
|
+
|
|
400
|
+
export const matroskaHeaderStructure = [
|
|
401
|
+
ebmlVersion,
|
|
402
|
+
ebmlReadVersion,
|
|
403
|
+
ebmlMaxIdLength,
|
|
404
|
+
ebmlMaxSizeLength,
|
|
405
|
+
docType,
|
|
406
|
+
docTypeVersion,
|
|
407
|
+
docTypeReadVersion,
|
|
408
|
+
] as const satisfies HeaderStructure;
|
|
409
|
+
|
|
410
|
+
export const matroskaHeader = {
|
|
411
|
+
name: 'Header',
|
|
412
|
+
type: 'children',
|
|
413
|
+
children: matroskaHeaderStructure,
|
|
414
|
+
} as const satisfies Ebml;
|
|
415
|
+
|
|
416
|
+
export const seekId = {
|
|
417
|
+
name: 'SeekID',
|
|
418
|
+
type: 'hex-string',
|
|
419
|
+
} as const satisfies Ebml;
|
|
420
|
+
|
|
421
|
+
export const seekPosition = {
|
|
422
|
+
name: 'SeekPosition',
|
|
423
|
+
type: 'uint',
|
|
424
|
+
} as const satisfies Ebml;
|
|
425
|
+
|
|
426
|
+
export const seek = {
|
|
427
|
+
name: 'Seek',
|
|
428
|
+
type: 'children',
|
|
429
|
+
children: [seekId, seekPosition],
|
|
430
|
+
} as const satisfies Ebml;
|
|
431
|
+
|
|
432
|
+
export const voidHeader = {
|
|
433
|
+
name: 'Void',
|
|
434
|
+
type: 'void',
|
|
435
|
+
} as const satisfies Ebml;
|
|
436
|
+
|
|
437
|
+
export type EbmlValue<T extends Ebml> = T extends EbmlWithUint8
|
|
438
|
+
? number
|
|
439
|
+
: T extends EbmlWithVoid
|
|
440
|
+
? undefined
|
|
441
|
+
: T extends EbmlWithString
|
|
442
|
+
? string
|
|
443
|
+
: T extends EbmlWithFloat
|
|
444
|
+
? number
|
|
445
|
+
: EbmlParsed<Ebml>[];
|
|
446
|
+
|
|
447
|
+
export type EbmlParsed<T extends Ebml> = {
|
|
448
|
+
type: T['name'];
|
|
449
|
+
value: EbmlValue<T>;
|
|
450
|
+
hex: string;
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
export const ebmlMap = {
|
|
454
|
+
[matroskaElements.Header]: matroskaHeader,
|
|
455
|
+
[matroskaElements.DocType]: docType,
|
|
456
|
+
[matroskaElements.DocTypeVersion]: docTypeVersion,
|
|
457
|
+
[matroskaElements.DocTypeReadVersion]: docTypeReadVersion,
|
|
458
|
+
[matroskaElements.EBMLVersion]: ebmlVersion,
|
|
459
|
+
[matroskaElements.EBMLReadVersion]: ebmlReadVersion,
|
|
460
|
+
[matroskaElements.EBMLMaxIDLength]: ebmlMaxIdLength,
|
|
461
|
+
[matroskaElements.EBMLMaxSizeLength]: ebmlMaxSizeLength,
|
|
462
|
+
[matroskaElements.Void]: voidEbml,
|
|
463
|
+
[matroskaElements.Cues]: {
|
|
464
|
+
name: 'Cues',
|
|
465
|
+
type: 'void',
|
|
466
|
+
},
|
|
467
|
+
[matroskaElements.DateUTC]: {
|
|
468
|
+
name: 'DateUTC',
|
|
469
|
+
type: 'void',
|
|
470
|
+
},
|
|
471
|
+
[matroskaElements.TrackTimestampScale]: {
|
|
472
|
+
name: 'TrackTimestampScale',
|
|
473
|
+
type: 'float',
|
|
474
|
+
},
|
|
475
|
+
[matroskaElements.CodecDelay]: {
|
|
476
|
+
name: 'CodecDelay',
|
|
477
|
+
type: 'void',
|
|
478
|
+
},
|
|
479
|
+
[matroskaElements.SeekPreRoll]: {
|
|
480
|
+
name: 'SeekPreRoll',
|
|
481
|
+
type: 'void',
|
|
482
|
+
},
|
|
483
|
+
[matroskaElements.DiscardPadding]: {
|
|
484
|
+
name: 'DiscardPadding',
|
|
485
|
+
type: 'void',
|
|
486
|
+
},
|
|
487
|
+
[matroskaElements.OutputSamplingFrequency]: {
|
|
488
|
+
name: 'OutputSamplingFrequency',
|
|
489
|
+
type: 'void',
|
|
490
|
+
},
|
|
491
|
+
[matroskaElements.CodecName]: {
|
|
492
|
+
name: 'CodecName',
|
|
493
|
+
type: 'void',
|
|
494
|
+
},
|
|
495
|
+
[matroskaElements.Position]: {
|
|
496
|
+
name: 'Position',
|
|
497
|
+
type: 'void',
|
|
498
|
+
},
|
|
499
|
+
[matroskaElements.SliceDuration]: {
|
|
500
|
+
name: 'SliceDuration',
|
|
501
|
+
type: 'void',
|
|
502
|
+
},
|
|
503
|
+
} as const satisfies Partial<Record<MatroskaElement, Ebml>>;
|
|
504
|
+
|
|
505
|
+
export type PossibleEbml = {
|
|
506
|
+
[key in keyof typeof ebmlMap]: {
|
|
507
|
+
type: (typeof ebmlMap)[key]['name'];
|
|
508
|
+
value: EbmlValue<(typeof ebmlMap)[key]>;
|
|
509
|
+
hex: string;
|
|
510
|
+
};
|
|
511
|
+
}[keyof typeof ebmlMap];
|
|
@@ -9,7 +9,7 @@ export const parseSeekPositionSegment = (
|
|
|
9
9
|
iterator: BufferIterator,
|
|
10
10
|
length: number,
|
|
11
11
|
): SeekPositionSegment => {
|
|
12
|
-
const seekPosition = iterator.
|
|
12
|
+
const seekPosition = iterator.getUint(length);
|
|
13
13
|
|
|
14
14
|
return {
|
|
15
15
|
type: 'seek-position-segment',
|
|
@@ -35,8 +35,18 @@ export type SeekIdSegment = {
|
|
|
35
35
|
seekId: string;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
export const parseSeekIdSegment = (
|
|
39
|
-
|
|
38
|
+
export const parseSeekIdSegment = (
|
|
39
|
+
iterator: BufferIterator,
|
|
40
|
+
length: number,
|
|
41
|
+
): SeekIdSegment => {
|
|
42
|
+
const seekId =
|
|
43
|
+
'0x' +
|
|
44
|
+
[...iterator.getSlice(length)]
|
|
45
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
46
|
+
.join('');
|
|
47
|
+
if (seekId === null) {
|
|
48
|
+
throw new Error('Not enough bytes to parse seek id');
|
|
49
|
+
}
|
|
40
50
|
|
|
41
51
|
return {
|
|
42
52
|
type: 'seek-id-segment',
|
|
@@ -8,7 +8,7 @@ export type TimestampScaleSegment = {
|
|
|
8
8
|
export const parseTimestampScaleSegment = (
|
|
9
9
|
iterator: BufferIterator,
|
|
10
10
|
): TimestampScaleSegment => {
|
|
11
|
-
const timestampScale = iterator.
|
|
11
|
+
const timestampScale = iterator.getUint(3);
|
|
12
12
|
|
|
13
13
|
return {
|
|
14
14
|
type: 'timestamp-scale-segment',
|
|
@@ -109,6 +109,11 @@ export type CodecSegment = {
|
|
|
109
109
|
codec: string;
|
|
110
110
|
};
|
|
111
111
|
|
|
112
|
+
export type TrackInfo = {
|
|
113
|
+
codec: string;
|
|
114
|
+
trackTimescale: number | null;
|
|
115
|
+
};
|
|
116
|
+
|
|
112
117
|
export const parseCodecSegment = (
|
|
113
118
|
iterator: BufferIterator,
|
|
114
119
|
length: number,
|
|
@@ -195,7 +200,7 @@ export const parseDefaultDurationSegment = (
|
|
|
195
200
|
iterator: BufferIterator,
|
|
196
201
|
length: number,
|
|
197
202
|
): DefaultDurationSegment => {
|
|
198
|
-
const defaultDuration = iterator.
|
|
203
|
+
const defaultDuration = iterator.getUint(length);
|
|
199
204
|
|
|
200
205
|
return {
|
|
201
206
|
type: 'default-duration-segment',
|
|
@@ -569,25 +574,9 @@ export const parseTimestampSegment = (
|
|
|
569
574
|
iterator: BufferIterator,
|
|
570
575
|
length: number,
|
|
571
576
|
): TimestampSegment => {
|
|
572
|
-
if (length > 3) {
|
|
573
|
-
throw new Error(
|
|
574
|
-
'Expected timestamp segment to be 1 byte or 2 bytes, but is ' + length,
|
|
575
|
-
);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
if (length === 3) {
|
|
579
|
-
const val = iterator.getUint24();
|
|
580
|
-
return {
|
|
581
|
-
type: 'timestamp-segment',
|
|
582
|
-
timestamp: val,
|
|
583
|
-
};
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
const value = length === 2 ? iterator.getUint16() : iterator.getUint8();
|
|
587
|
-
|
|
588
577
|
return {
|
|
589
578
|
type: 'timestamp-segment',
|
|
590
|
-
timestamp:
|
|
579
|
+
timestamp: iterator.getUint(length),
|
|
591
580
|
};
|
|
592
581
|
};
|
|
593
582
|
|
|
@@ -595,7 +584,7 @@ export type SimpleBlockOrBlockSegment = {
|
|
|
595
584
|
type: 'simple-block-or-block-segment';
|
|
596
585
|
length: number;
|
|
597
586
|
trackNumber: number;
|
|
598
|
-
|
|
587
|
+
timecodeInMicroseconds: number;
|
|
599
588
|
keyframe: boolean | null;
|
|
600
589
|
lacing: number;
|
|
601
590
|
invisible: boolean;
|
|
@@ -619,23 +608,39 @@ export const parseSimpleBlockOrBlockSegment = async ({
|
|
|
619
608
|
}): Promise<SimpleBlockOrBlockSegment> => {
|
|
620
609
|
const start = iterator.counter.getOffset();
|
|
621
610
|
const trackNumber = iterator.getVint();
|
|
611
|
+
if (trackNumber === null) {
|
|
612
|
+
throw new Error('Not enough data to get track number, should not happen');
|
|
613
|
+
}
|
|
614
|
+
|
|
622
615
|
const timecodeRelativeToCluster = iterator.getUint16();
|
|
623
616
|
|
|
624
617
|
const {invisible, lacing, keyframe} = parseBlockFlags(iterator, type);
|
|
625
618
|
|
|
626
|
-
const codec =
|
|
619
|
+
const {codec, trackTimescale} =
|
|
620
|
+
parserContext.parserState.getTrackInfoByNumber(trackNumber);
|
|
621
|
+
|
|
627
622
|
const clusterOffset =
|
|
628
623
|
parserContext.parserState.getTimestampOffsetForByteOffset(
|
|
629
624
|
iterator.counter.getOffset(),
|
|
630
625
|
);
|
|
631
626
|
|
|
627
|
+
const timescale = parserContext.parserState.getTimescale();
|
|
628
|
+
|
|
632
629
|
if (clusterOffset === undefined) {
|
|
633
630
|
throw new Error(
|
|
634
631
|
'Could not find offset for byte offset ' + iterator.counter.getOffset(),
|
|
635
632
|
);
|
|
636
633
|
}
|
|
637
634
|
|
|
638
|
-
|
|
635
|
+
// https://github.com/hubblec4/Matroska-Chapters-Specs/blob/master/notes.md/#timestampscale
|
|
636
|
+
// The TimestampScale Element is used to calculate the Raw Timestamp of a Block. The timestamp is obtained by adding the Block's timestamp to the Cluster's Timestamp Element, and then multiplying that result by the TimestampScale. The result will be the Block's Raw Timestamp in nanoseconds.
|
|
637
|
+
const timecodeInNanoSeconds =
|
|
638
|
+
(timecodeRelativeToCluster + clusterOffset) *
|
|
639
|
+
timescale *
|
|
640
|
+
(trackTimescale ?? 1);
|
|
641
|
+
|
|
642
|
+
// Timecode should be in microseconds
|
|
643
|
+
const timecodeInMicroseconds = timecodeInNanoSeconds / 1000;
|
|
639
644
|
|
|
640
645
|
if (!codec) {
|
|
641
646
|
throw new Error('Could not find codec for track ' + trackNumber);
|
|
@@ -645,14 +650,14 @@ export const parseSimpleBlockOrBlockSegment = async ({
|
|
|
645
650
|
|
|
646
651
|
let videoSample: Omit<VideoSample, 'type'> | null = null;
|
|
647
652
|
|
|
648
|
-
if (codec.
|
|
653
|
+
if (codec.startsWith('V_')) {
|
|
649
654
|
const partialVideoSample: Omit<VideoSample, 'type'> = {
|
|
650
655
|
data: iterator.getSlice(remainingNow),
|
|
651
656
|
cts: null,
|
|
652
657
|
dts: null,
|
|
653
658
|
duration: undefined,
|
|
654
659
|
trackId: trackNumber,
|
|
655
|
-
timestamp:
|
|
660
|
+
timestamp: timecodeInMicroseconds,
|
|
656
661
|
};
|
|
657
662
|
|
|
658
663
|
if (keyframe === null) {
|
|
@@ -668,11 +673,11 @@ export const parseSimpleBlockOrBlockSegment = async ({
|
|
|
668
673
|
}
|
|
669
674
|
}
|
|
670
675
|
|
|
671
|
-
if (codec.
|
|
676
|
+
if (codec.startsWith('A_')) {
|
|
672
677
|
await parserContext.parserState.onAudioSample(trackNumber, {
|
|
673
678
|
data: iterator.getSlice(remainingNow),
|
|
674
679
|
trackId: trackNumber,
|
|
675
|
-
timestamp:
|
|
680
|
+
timestamp: timecodeInMicroseconds,
|
|
676
681
|
type: 'key',
|
|
677
682
|
});
|
|
678
683
|
}
|
|
@@ -686,7 +691,7 @@ export const parseSimpleBlockOrBlockSegment = async ({
|
|
|
686
691
|
type: 'simple-block-or-block-segment',
|
|
687
692
|
length,
|
|
688
693
|
trackNumber,
|
|
689
|
-
|
|
694
|
+
timecodeInMicroseconds,
|
|
690
695
|
keyframe,
|
|
691
696
|
lacing,
|
|
692
697
|
invisible,
|
|
@@ -4,6 +4,8 @@ import type {ParseResult} from '../../parse-result';
|
|
|
4
4
|
import type {ParserContext} from '../../parser-context';
|
|
5
5
|
import type {VideoSample} from '../../webcodec-sample-types';
|
|
6
6
|
import {getTrack} from './get-track';
|
|
7
|
+
import {parseEbml} from './parse-ebml';
|
|
8
|
+
import type {PossibleEbml} from './segments/all-segments';
|
|
7
9
|
import {matroskaElements} from './segments/all-segments';
|
|
8
10
|
import type {DurationSegment} from './segments/duration';
|
|
9
11
|
import {parseDurationSegment} from './segments/duration';
|
|
@@ -101,8 +103,6 @@ import {
|
|
|
101
103
|
} from './segments/track-entry';
|
|
102
104
|
import type {TracksSegment} from './segments/tracks';
|
|
103
105
|
import {parseTracksSegment} from './segments/tracks';
|
|
104
|
-
import type {UnknownSegment} from './segments/unknown';
|
|
105
|
-
import {parseUnknownSegment} from './segments/unknown';
|
|
106
106
|
import type {VoidSegment} from './segments/void';
|
|
107
107
|
import {parseVoidSegment} from './segments/void';
|
|
108
108
|
import type {WritingAppSegment} from './segments/writing';
|
|
@@ -110,7 +110,6 @@ import {parseWritingSegment} from './segments/writing';
|
|
|
110
110
|
|
|
111
111
|
export type MatroskaSegment =
|
|
112
112
|
| MainSegment
|
|
113
|
-
| UnknownSegment
|
|
114
113
|
| SeekHeadSegment
|
|
115
114
|
| SeekSegment
|
|
116
115
|
| SeekPositionSegment
|
|
@@ -156,7 +155,8 @@ export type MatroskaSegment =
|
|
|
156
155
|
| ChannelsSegment
|
|
157
156
|
| BitDepthSegment
|
|
158
157
|
| ReferenceBlockSegment
|
|
159
|
-
| BlockAdditionsSegment
|
|
158
|
+
| BlockAdditionsSegment
|
|
159
|
+
| PossibleEbml;
|
|
160
160
|
|
|
161
161
|
export type OnTrackEntrySegment = (trackEntry: TrackEntrySegment) => void;
|
|
162
162
|
|
|
@@ -165,39 +165,24 @@ const parseSegment = async ({
|
|
|
165
165
|
iterator,
|
|
166
166
|
length,
|
|
167
167
|
parserContext,
|
|
168
|
+
headerReadSoFar,
|
|
168
169
|
}: {
|
|
169
170
|
segmentId: string;
|
|
170
171
|
iterator: BufferIterator;
|
|
171
172
|
length: number;
|
|
172
173
|
parserContext: ParserContext;
|
|
174
|
+
headerReadSoFar: number;
|
|
173
175
|
}): Promise<Promise<MatroskaSegment> | MatroskaSegment> => {
|
|
174
176
|
if (length === 0) {
|
|
175
177
|
throw new Error(`Expected length of ${segmentId} to be greater than 0`);
|
|
176
178
|
}
|
|
177
179
|
|
|
178
|
-
if (segmentId === '0x') {
|
|
179
|
-
return {
|
|
180
|
-
type: 'unknown-segment',
|
|
181
|
-
id: segmentId,
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Log this to debug
|
|
186
|
-
/*
|
|
187
|
-
console.log(
|
|
188
|
-
'segmentId',
|
|
189
|
-
segmentId,
|
|
190
|
-
getSegmentName(segmentId),
|
|
191
|
-
iterator.counter.getOffset(),
|
|
192
|
-
);
|
|
193
|
-
*/
|
|
194
|
-
|
|
195
180
|
if (segmentId === '0x114d9b74') {
|
|
196
181
|
return parseSeekHeadSegment(iterator, length, parserContext);
|
|
197
182
|
}
|
|
198
183
|
|
|
199
184
|
if (segmentId === '0x53ab') {
|
|
200
|
-
return parseSeekIdSegment(iterator);
|
|
185
|
+
return parseSeekIdSegment(iterator, length);
|
|
201
186
|
}
|
|
202
187
|
|
|
203
188
|
if (segmentId === '0x4dbb') {
|
|
@@ -442,22 +427,17 @@ const parseSegment = async ({
|
|
|
442
427
|
return parseBlockElementSegment(iterator, length);
|
|
443
428
|
}
|
|
444
429
|
|
|
445
|
-
|
|
446
|
-
const toDiscard = Math.min(
|
|
447
|
-
bytesRemaining,
|
|
448
|
-
length > 0 ? length : bytesRemaining,
|
|
449
|
-
);
|
|
430
|
+
iterator.counter.decrement(headerReadSoFar);
|
|
450
431
|
|
|
451
|
-
|
|
452
|
-
return child;
|
|
432
|
+
return parseEbml(iterator);
|
|
453
433
|
};
|
|
454
434
|
|
|
455
435
|
export const expectSegment = async (
|
|
456
436
|
iterator: BufferIterator,
|
|
457
437
|
parserContext: ParserContext,
|
|
458
438
|
): Promise<ParseResult> => {
|
|
459
|
-
const
|
|
460
|
-
if (
|
|
439
|
+
const offset = iterator.counter.getOffset();
|
|
440
|
+
if (iterator.bytesRemaining() === 0) {
|
|
461
441
|
return {
|
|
462
442
|
status: 'incomplete',
|
|
463
443
|
segments: [],
|
|
@@ -468,9 +448,33 @@ export const expectSegment = async (
|
|
|
468
448
|
};
|
|
469
449
|
}
|
|
470
450
|
|
|
471
|
-
const offset = iterator.counter.getOffset();
|
|
472
451
|
const segmentId = iterator.getMatroskaSegmentId();
|
|
452
|
+
|
|
453
|
+
if (segmentId === null) {
|
|
454
|
+
iterator.counter.decrement(iterator.counter.getOffset() - offset);
|
|
455
|
+
return {
|
|
456
|
+
status: 'incomplete',
|
|
457
|
+
segments: [],
|
|
458
|
+
continueParsing: () => {
|
|
459
|
+
return Promise.resolve(expectSegment(iterator, parserContext));
|
|
460
|
+
},
|
|
461
|
+
skipTo: null,
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
473
465
|
const length = iterator.getVint();
|
|
466
|
+
if (length === null) {
|
|
467
|
+
iterator.counter.decrement(iterator.counter.getOffset() - offset);
|
|
468
|
+
return {
|
|
469
|
+
status: 'incomplete',
|
|
470
|
+
segments: [],
|
|
471
|
+
continueParsing: () => {
|
|
472
|
+
return Promise.resolve(expectSegment(iterator, parserContext));
|
|
473
|
+
},
|
|
474
|
+
skipTo: null,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
|
|
474
478
|
const bytesRemainingNow =
|
|
475
479
|
iterator.byteLength() - iterator.counter.getOffset();
|
|
476
480
|
|
|
@@ -525,6 +529,7 @@ export const expectSegment = async (
|
|
|
525
529
|
iterator,
|
|
526
530
|
length,
|
|
527
531
|
parserContext,
|
|
532
|
+
headerReadSoFar: iterator.counter.getOffset() - offset,
|
|
528
533
|
});
|
|
529
534
|
|
|
530
535
|
return {
|
|
@@ -24,6 +24,19 @@ export const getTrackCodec = (track: TrackEntrySegment) => {
|
|
|
24
24
|
return child ?? null;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
export const getTrackTimestampScale = (track: TrackEntrySegment) => {
|
|
28
|
+
const child = track.children.find((b) => b.type === 'TrackTimestampScale');
|
|
29
|
+
if (!child) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (child.type !== 'TrackTimestampScale') {
|
|
34
|
+
throw new Error('Expected TrackTimestampScale');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return child.value;
|
|
38
|
+
};
|
|
39
|
+
|
|
27
40
|
export const getTrackByNumber = (tracks: TrackEntrySegment[], id: number) => {
|
|
28
41
|
return tracks.find((track) => {
|
|
29
42
|
const trackNumber = getTrackNumber(track);
|