@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
@@ -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 {expectSegment} from './segments';
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
- counter.discard(4);
12
- const length = counter.getVint();
13
-
14
- if (length !== 31 && length !== 35) {
15
- throw new Error(`Expected header length 31 or 25, got ${length}`);
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: '0x42F7',
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.getDecimalBytes(length);
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 = (iterator: BufferIterator): SeekIdSegment => {
39
- const seekId = iterator.getMatroskaSegmentId();
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.getDecimalBytes(3);
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.getDecimalBytes(length);
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: value,
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
- timecode: number;
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 = parserContext.parserState.getTrackInfoByNumber(trackNumber);
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
- const timecode = timecodeRelativeToCluster + clusterOffset;
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.codec.startsWith('V_')) {
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: timecode,
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.codec.startsWith('A_')) {
676
+ if (codec.startsWith('A_')) {
672
677
  await parserContext.parserState.onAudioSample(trackNumber, {
673
678
  data: iterator.getSlice(remainingNow),
674
679
  trackId: trackNumber,
675
- timestamp: timecode,
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
- timecode,
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
- const bytesRemaining = iterator.byteLength() - iterator.counter.getOffset();
446
- const toDiscard = Math.min(
447
- bytesRemaining,
448
- length > 0 ? length : bytesRemaining,
449
- );
430
+ iterator.counter.decrement(headerReadSoFar);
450
431
 
451
- const child = parseUnknownSegment(iterator, segmentId, toDiscard);
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 bytesRemaining_ = iterator.bytesRemaining();
460
- if (bytesRemaining_ === 0) {
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);