@remotion/media-parser 4.0.199 → 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 (117) 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 -2
  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 +2 -0
  25. package/dist/boxes/webm/ebml.js +72 -0
  26. package/dist/boxes/webm/make-header.d.ts +9 -0
  27. package/dist/boxes/webm/make-header.js +79 -0
  28. package/dist/boxes/webm/parse-ebml.d.ts +7 -0
  29. package/dist/boxes/webm/parse-ebml.js +66 -0
  30. package/dist/boxes/webm/parse-webm-header.js +8 -9
  31. package/dist/boxes/webm/segments/all-segments.d.ts +262 -0
  32. package/dist/boxes/webm/segments/all-segments.js +130 -1
  33. package/dist/boxes/webm/segments/block-simple-block-flags.d.ts +9 -0
  34. package/dist/boxes/webm/segments/block-simple-block-flags.js +38 -0
  35. package/dist/boxes/webm/segments/seek-position.js +1 -1
  36. package/dist/boxes/webm/segments/seek.d.ts +1 -1
  37. package/dist/boxes/webm/segments/seek.js +8 -2
  38. package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
  39. package/dist/boxes/webm/segments/track-entry.d.ts +25 -9
  40. package/dist/boxes/webm/segments/track-entry.js +73 -33
  41. package/dist/boxes/webm/segments.d.ts +3 -3
  42. package/dist/boxes/webm/segments.js +64 -30
  43. package/dist/boxes/webm/traversal.d.ts +1 -0
  44. package/dist/boxes/webm/traversal.js +12 -1
  45. package/dist/buffer-iterator.d.ts +10 -6
  46. package/dist/buffer-iterator.js +92 -9
  47. package/dist/from-fetch.js +13 -3
  48. package/dist/from-input-type-file.d.ts +2 -0
  49. package/dist/from-input-type-file.js +37 -0
  50. package/dist/from-node.js +9 -2
  51. package/dist/from-web-file.js +6 -1
  52. package/dist/from-web.js +15 -6
  53. package/dist/get-codec.d.ts +4 -0
  54. package/dist/get-codec.js +22 -0
  55. package/dist/get-sample-positions.js +1 -1
  56. package/dist/has-all-info.js +1 -1
  57. package/dist/options.d.ts +3 -2
  58. package/dist/parse-media.js +13 -9
  59. package/dist/parse-video.js +16 -0
  60. package/dist/parser-state.d.ts +8 -9
  61. package/dist/parser-state.js +39 -19
  62. package/dist/reader.d.ts +1 -1
  63. package/dist/web-file.d.ts +2 -0
  64. package/dist/web-file.js +37 -0
  65. package/dist/webcodec-sample-types.d.ts +0 -1
  66. package/package.json +2 -2
  67. package/src/boxes/iso-base-media/mdat/mdat.ts +2 -2
  68. package/src/boxes/iso-base-media/moov/moov.ts +1 -0
  69. package/src/boxes/iso-base-media/process-box.ts +70 -40
  70. package/src/boxes/iso-base-media/stsd/mebx.ts +3 -0
  71. package/src/boxes/iso-base-media/stsd/samples.ts +3 -0
  72. package/src/boxes/iso-base-media/stsd/stco.ts +5 -3
  73. package/src/boxes/iso-base-media/trak/trak.ts +1 -0
  74. package/src/boxes/webm/ebml.ts +78 -0
  75. package/src/boxes/webm/make-header.ts +138 -0
  76. package/src/boxes/webm/parse-ebml.ts +93 -0
  77. package/src/boxes/webm/parse-webm-header.ts +8 -12
  78. package/src/boxes/webm/segments/all-segments.ts +226 -0
  79. package/src/boxes/webm/segments/block-simple-block-flags.ts +52 -0
  80. package/src/boxes/webm/segments/seek-position.ts +1 -1
  81. package/src/boxes/webm/segments/seek.ts +12 -2
  82. package/src/boxes/webm/segments/timestamp-scale.ts +1 -1
  83. package/src/boxes/webm/segments/track-entry.ts +125 -41
  84. package/src/boxes/webm/segments.ts +107 -40
  85. package/src/boxes/webm/traversal.ts +13 -0
  86. package/src/buffer-iterator.ts +110 -10
  87. package/src/from-fetch.ts +22 -3
  88. package/src/from-node.ts +18 -4
  89. package/src/from-web-file.ts +11 -1
  90. package/src/get-sample-positions.ts +1 -1
  91. package/src/has-all-info.ts +1 -1
  92. package/src/options.ts +3 -2
  93. package/src/parse-media.ts +14 -8
  94. package/src/parse-video.ts +17 -0
  95. package/src/parser-state.ts +52 -25
  96. package/src/reader.ts +1 -0
  97. package/src/test/create-matroska.test.ts +48 -0
  98. package/src/test/matroska.test.ts +144 -127
  99. package/src/test/parse-stco.test.ts +2 -0
  100. package/src/test/stream-local.test.ts +70 -14
  101. package/src/test/stream-remote.test.ts +23 -19
  102. package/src/test/stsd.test.ts +2 -0
  103. package/src/webcodec-sample-types.ts +0 -1
  104. package/tsconfig.tsbuildinfo +1 -1
  105. package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
  106. package/dist/boxes/iso-base-media/ftype.js +0 -31
  107. package/dist/get-video-metadata.d.ts +0 -2
  108. package/dist/get-video-metadata.js +0 -44
  109. package/dist/read-and-increment-offset.d.ts +0 -28
  110. package/dist/read-and-increment-offset.js +0 -177
  111. package/dist/understand-vorbis.d.ts +0 -1
  112. package/dist/understand-vorbis.js +0 -12
  113. package/src/boxes/webm/segments/unknown.ts +0 -19
  114. /package/dist/{boxes/webm/bitstream/av1/frame.d.ts → get-samples.d.ts} +0 -0
  115. /package/dist/{boxes/webm/bitstream/av1/frame.js → get-samples.js} +0 -0
  116. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.d.ts → sample-aspect-ratio.d.ts} +0 -0
  117. /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.js → sample-aspect-ratio.js} +0 -0
@@ -1,6 +1,9 @@
1
1
  import type {BufferIterator} from '../../../buffer-iterator';
2
2
  import type {ParserContext} from '../../../parser-context';
3
+ import type {VideoSample} from '../../../webcodec-sample-types';
3
4
  import type {MatroskaSegment} from '../segments';
5
+ import type {matroskaElements} from './all-segments';
6
+ import {parseBlockFlags} from './block-simple-block-flags';
4
7
  import {expectChildren} from './parse-children';
5
8
 
6
9
  export type TrackEntrySegment = {
@@ -106,6 +109,11 @@ export type CodecSegment = {
106
109
  codec: string;
107
110
  };
108
111
 
112
+ export type TrackInfo = {
113
+ codec: string;
114
+ trackTimescale: number | null;
115
+ };
116
+
109
117
  export const parseCodecSegment = (
110
118
  iterator: BufferIterator,
111
119
  length: number,
@@ -192,7 +200,7 @@ export const parseDefaultDurationSegment = (
192
200
  iterator: BufferIterator,
193
201
  length: number,
194
202
  ): DefaultDurationSegment => {
195
- const defaultDuration = iterator.getDecimalBytes(length);
203
+ const defaultDuration = iterator.getUint(length);
196
204
 
197
205
  return {
198
206
  type: 'default-duration-segment',
@@ -566,80 +574,110 @@ export const parseTimestampSegment = (
566
574
  iterator: BufferIterator,
567
575
  length: number,
568
576
  ): TimestampSegment => {
569
- if (length > 2) {
570
- throw new Error('Expected timestamp segment to be 1 byte or 2 bytes');
571
- }
572
-
573
- const value = length === 2 ? iterator.getUint16() : iterator.getUint8();
574
-
575
577
  return {
576
578
  type: 'timestamp-segment',
577
- timestamp: value,
579
+ timestamp: iterator.getUint(length),
578
580
  };
579
581
  };
580
582
 
581
- export type SimpleBlockSegment = {
582
- type: 'simple-block-segment';
583
+ export type SimpleBlockOrBlockSegment = {
584
+ type: 'simple-block-or-block-segment';
583
585
  length: number;
584
586
  trackNumber: number;
585
- timecode: number;
586
- headerFlags: number;
587
- keyframe: boolean;
588
- lacing: [number, number];
587
+ timecodeInMicroseconds: number;
588
+ keyframe: boolean | null;
589
+ lacing: number;
589
590
  invisible: boolean;
590
- children: MatroskaSegment[];
591
+ videoSample: Omit<VideoSample, 'type'> | null;
591
592
  };
592
593
 
593
594
  export type GetTracks = () => TrackEntrySegment[];
594
595
 
595
- export const parseSimpleBlockSegment = async ({
596
+ export const parseSimpleBlockOrBlockSegment = async ({
596
597
  iterator,
597
598
  length,
598
599
  parserContext,
600
+ type,
599
601
  }: {
600
602
  iterator: BufferIterator;
601
603
  length: number;
602
604
  parserContext: ParserContext;
603
- }): Promise<SimpleBlockSegment> => {
605
+ type:
606
+ | (typeof matroskaElements)['Block']
607
+ | (typeof matroskaElements)['SimpleBlock'];
608
+ }): Promise<SimpleBlockOrBlockSegment> => {
604
609
  const start = iterator.counter.getOffset();
605
610
  const trackNumber = iterator.getVint();
606
- const timecode = iterator.getUint16();
607
- const headerFlags = iterator.getUint8();
611
+ if (trackNumber === null) {
612
+ throw new Error('Not enough data to get track number, should not happen');
613
+ }
614
+
615
+ const timecodeRelativeToCluster = iterator.getUint16();
616
+
617
+ const {invisible, lacing, keyframe} = parseBlockFlags(iterator, type);
618
+
619
+ const {codec, trackTimescale} =
620
+ parserContext.parserState.getTrackInfoByNumber(trackNumber);
608
621
 
609
- const invisible = Boolean((headerFlags >> 5) & 1);
610
- const pos6 = (headerFlags >> 6) & 1;
611
- const pos7 = (headerFlags >> 6) & 1;
612
- const keyframe = Boolean((headerFlags >> 7) & 1);
622
+ const clusterOffset =
623
+ parserContext.parserState.getTimestampOffsetForByteOffset(
624
+ iterator.counter.getOffset(),
625
+ );
626
+
627
+ const timescale = parserContext.parserState.getTimescale();
628
+
629
+ if (clusterOffset === undefined) {
630
+ throw new Error(
631
+ 'Could not find offset for byte offset ' + iterator.counter.getOffset(),
632
+ );
633
+ }
613
634
 
614
- const codec = parserContext.parserState.getTrackInfoByNumber(trackNumber);
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;
615
644
 
616
645
  if (!codec) {
617
646
  throw new Error('Could not find codec for track ' + trackNumber);
618
647
  }
619
648
 
620
- const children: MatroskaSegment[] = [];
649
+ const remainingNow = length - (iterator.counter.getOffset() - start);
621
650
 
622
- if (codec.codec.startsWith('V_')) {
623
- const remainingNow = length - (iterator.counter.getOffset() - start);
651
+ let videoSample: Omit<VideoSample, 'type'> | null = null;
624
652
 
625
- await parserContext.parserState.onVideoSample(trackNumber, {
653
+ if (codec.startsWith('V_')) {
654
+ const partialVideoSample: Omit<VideoSample, 'type'> = {
626
655
  data: iterator.getSlice(remainingNow),
627
656
  cts: null,
628
657
  dts: null,
629
658
  duration: undefined,
630
- type: keyframe ? 'key' : 'delta',
631
659
  trackId: trackNumber,
632
- timestamp: timecode,
633
- });
660
+ timestamp: timecodeInMicroseconds,
661
+ };
662
+
663
+ if (keyframe === null) {
664
+ // If we don't know if this is a keyframe, we know after we emit the BlockGroup
665
+ videoSample = partialVideoSample;
666
+ } else {
667
+ const sample: VideoSample = {
668
+ ...partialVideoSample,
669
+ type: keyframe ? 'key' : 'delta',
670
+ };
671
+
672
+ await parserContext.parserState.onVideoSample(trackNumber, sample);
673
+ }
634
674
  }
635
675
 
636
- if (codec.codec.startsWith('A_')) {
637
- const vorbisRemaining = length - (iterator.counter.getOffset() - start);
676
+ if (codec.startsWith('A_')) {
638
677
  await parserContext.parserState.onAudioSample(trackNumber, {
639
- data: iterator.getSlice(vorbisRemaining),
640
- offset: timecode,
678
+ data: iterator.getSlice(remainingNow),
641
679
  trackId: trackNumber,
642
- timestamp: timecode,
680
+ timestamp: timecodeInMicroseconds,
643
681
  type: 'key',
644
682
  });
645
683
  }
@@ -650,15 +688,14 @@ export const parseSimpleBlockSegment = async ({
650
688
  }
651
689
 
652
690
  return {
653
- type: 'simple-block-segment',
691
+ type: 'simple-block-or-block-segment',
654
692
  length,
655
693
  trackNumber,
656
- timecode,
657
- headerFlags,
694
+ timecodeInMicroseconds,
658
695
  keyframe,
659
- lacing: [pos6, pos7],
696
+ lacing,
660
697
  invisible,
661
- children,
698
+ videoSample,
662
699
  };
663
700
  };
664
701
 
@@ -705,6 +742,53 @@ export const parseBlockGroupSegment = async (
705
742
  };
706
743
  };
707
744
 
745
+ export type ReferenceBlockSegment = {
746
+ type: 'reference-block-segment';
747
+ referenceBlock: number;
748
+ };
749
+
750
+ export const parseReferenceBlockSegment = (
751
+ iterator: BufferIterator,
752
+ length: number,
753
+ ): ReferenceBlockSegment => {
754
+ if (length > 4) {
755
+ throw new Error(
756
+ `Expected reference block segment to be 4 bytes, but got ${length}`,
757
+ );
758
+ }
759
+
760
+ const referenceBlock =
761
+ length === 4
762
+ ? iterator.getUint32()
763
+ : length === 3
764
+ ? iterator.getUint24()
765
+ : length === 2
766
+ ? iterator.getUint16()
767
+ : iterator.getUint8();
768
+
769
+ return {
770
+ type: 'reference-block-segment',
771
+ referenceBlock,
772
+ };
773
+ };
774
+
775
+ export type BlockAdditionsSegment = {
776
+ type: 'block-additions-segment';
777
+ blockAdditions: Uint8Array;
778
+ };
779
+
780
+ export const parseBlockAdditionsSegment = (
781
+ iterator: BufferIterator,
782
+ length: number,
783
+ ): BlockAdditionsSegment => {
784
+ const blockAdditions = iterator.getSlice(length);
785
+
786
+ return {
787
+ type: 'block-additions-segment',
788
+ blockAdditions,
789
+ };
790
+ };
791
+
708
792
  export type BlockElement = {
709
793
  type: 'block-element-segment';
710
794
  length: number;
@@ -2,7 +2,10 @@ import {registerTrack} from '../../add-new-matroska-tracks';
2
2
  import type {BufferIterator} from '../../buffer-iterator';
3
3
  import type {ParseResult} from '../../parse-result';
4
4
  import type {ParserContext} from '../../parser-context';
5
+ import type {VideoSample} from '../../webcodec-sample-types';
5
6
  import {getTrack} from './get-track';
7
+ import {parseEbml} from './parse-ebml';
8
+ import type {PossibleEbml} from './segments/all-segments';
6
9
  import {matroskaElements} from './segments/all-segments';
7
10
  import type {DurationSegment} from './segments/duration';
8
11
  import {parseDurationSegment} from './segments/duration';
@@ -29,6 +32,7 @@ import type {
29
32
  AlphaModeSegment,
30
33
  AudioSegment,
31
34
  BitDepthSegment,
35
+ BlockAdditionsSegment,
32
36
  BlockElement,
33
37
  BlockGroupSegment,
34
38
  ChannelsSegment,
@@ -46,9 +50,10 @@ import type {
46
50
  InterlacedSegment,
47
51
  LanguageSegment,
48
52
  MaxBlockAdditionId,
53
+ ReferenceBlockSegment,
49
54
  SamplingFrequencySegment,
50
55
  SegmentUUIDSegment,
51
- SimpleBlockSegment,
56
+ SimpleBlockOrBlockSegment,
52
57
  TagSegment,
53
58
  TagsSegment,
54
59
  TimestampSegment,
@@ -64,6 +69,7 @@ import {
64
69
  parseAlphaModeSegment,
65
70
  parseAudioSegment,
66
71
  parseBitDepthSegment,
72
+ parseBlockAdditionsSegment,
67
73
  parseBlockElementSegment,
68
74
  parseBlockGroupSegment,
69
75
  parseChannelsSegment,
@@ -80,9 +86,10 @@ import {
80
86
  parseInterlacedSegment,
81
87
  parseLanguageSegment,
82
88
  parseMaxBlockAdditionId,
89
+ parseReferenceBlockSegment,
83
90
  parseSamplingFrequencySegment,
84
91
  parseSegmentUUIDSegment,
85
- parseSimpleBlockSegment,
92
+ parseSimpleBlockOrBlockSegment,
86
93
  parseTagSegment,
87
94
  parseTagsSegment,
88
95
  parseTimestampSegment,
@@ -96,8 +103,6 @@ import {
96
103
  } from './segments/track-entry';
97
104
  import type {TracksSegment} from './segments/tracks';
98
105
  import {parseTracksSegment} from './segments/tracks';
99
- import type {UnknownSegment} from './segments/unknown';
100
- import {parseUnknownSegment} from './segments/unknown';
101
106
  import type {VoidSegment} from './segments/void';
102
107
  import {parseVoidSegment} from './segments/void';
103
108
  import type {WritingAppSegment} from './segments/writing';
@@ -105,7 +110,6 @@ import {parseWritingSegment} from './segments/writing';
105
110
 
106
111
  export type MatroskaSegment =
107
112
  | MainSegment
108
- | UnknownSegment
109
113
  | SeekHeadSegment
110
114
  | SeekSegment
111
115
  | SeekPositionSegment
@@ -142,14 +146,17 @@ export type MatroskaSegment =
142
146
  | TagSegment
143
147
  | ClusterSegment
144
148
  | TimestampSegment
145
- | SimpleBlockSegment
149
+ | SimpleBlockOrBlockSegment
146
150
  | BlockGroupSegment
147
151
  | BlockElement
148
152
  | SeekIdSegment
149
153
  | AudioSegment
150
154
  | SamplingFrequencySegment
151
155
  | ChannelsSegment
152
- | BitDepthSegment;
156
+ | BitDepthSegment
157
+ | ReferenceBlockSegment
158
+ | BlockAdditionsSegment
159
+ | PossibleEbml;
153
160
 
154
161
  export type OnTrackEntrySegment = (trackEntry: TrackEntrySegment) => void;
155
162
 
@@ -158,39 +165,24 @@ const parseSegment = async ({
158
165
  iterator,
159
166
  length,
160
167
  parserContext,
168
+ headerReadSoFar,
161
169
  }: {
162
170
  segmentId: string;
163
171
  iterator: BufferIterator;
164
172
  length: number;
165
173
  parserContext: ParserContext;
174
+ headerReadSoFar: number;
166
175
  }): Promise<Promise<MatroskaSegment> | MatroskaSegment> => {
167
176
  if (length === 0) {
168
177
  throw new Error(`Expected length of ${segmentId} to be greater than 0`);
169
178
  }
170
179
 
171
- if (segmentId === '0x') {
172
- return {
173
- type: 'unknown-segment',
174
- id: segmentId,
175
- };
176
- }
177
-
178
- // Log this to debug
179
- /*
180
- console.log(
181
- 'segmentId',
182
- segmentId,
183
- getSegmentName(segmentId),
184
- iterator.counter.getOffset(),
185
- );
186
- */
187
-
188
180
  if (segmentId === '0x114d9b74') {
189
181
  return parseSeekHeadSegment(iterator, length, parserContext);
190
182
  }
191
183
 
192
184
  if (segmentId === '0x53ab') {
193
- return parseSeekIdSegment(iterator);
185
+ return parseSeekIdSegment(iterator, length);
194
186
  }
195
187
 
196
188
  if (segmentId === '0x4dbb') {
@@ -360,42 +352,92 @@ const parseSegment = async ({
360
352
  return parseBitDepthSegment(iterator, length);
361
353
  }
362
354
 
363
- if (segmentId === '0xe7') {
364
- return parseTimestampSegment(iterator, length);
355
+ if (segmentId === matroskaElements.Timestamp) {
356
+ const offset = iterator.counter.getOffset();
357
+ const timestampSegment = parseTimestampSegment(iterator, length);
358
+
359
+ parserContext.parserState.setTimestampOffset(
360
+ offset,
361
+ timestampSegment.timestamp,
362
+ );
363
+
364
+ return timestampSegment;
365
365
  }
366
366
 
367
- if (segmentId === '0xa3') {
368
- return parseSimpleBlockSegment({
367
+ if (
368
+ segmentId === matroskaElements.SimpleBlock ||
369
+ segmentId === matroskaElements.Block
370
+ ) {
371
+ return parseSimpleBlockOrBlockSegment({
369
372
  iterator,
370
373
  length,
371
374
  parserContext,
375
+ type: segmentId,
372
376
  });
373
377
  }
374
378
 
379
+ if (segmentId === matroskaElements.ReferenceBlock) {
380
+ return parseReferenceBlockSegment(iterator, length);
381
+ }
382
+
383
+ if (segmentId === matroskaElements.BlockAdditions) {
384
+ return parseBlockAdditionsSegment(iterator, length);
385
+ }
386
+
375
387
  if (segmentId === '0xa0') {
376
- return parseBlockGroupSegment(iterator, length, parserContext);
388
+ const blockGroup = await parseBlockGroupSegment(
389
+ iterator,
390
+ length,
391
+ parserContext,
392
+ );
393
+
394
+ // Blocks don't have information about keyframes.
395
+ // https://ffmpeg.org/pipermail/ffmpeg-devel/2015-June/173825.html
396
+ // "For Blocks, keyframes is
397
+ // inferred by the absence of ReferenceBlock element (as done by matroskadec).""
398
+
399
+ const block = blockGroup.children.find(
400
+ (c) => c.type === 'simple-block-or-block-segment',
401
+ );
402
+ if (!block || block.type !== 'simple-block-or-block-segment') {
403
+ throw new Error('Expected block segment');
404
+ }
405
+
406
+ const hasReferenceBlock = blockGroup.children.find(
407
+ (c) => c.type === 'reference-block-segment',
408
+ );
409
+
410
+ const partialVideoSample = block.videoSample;
411
+
412
+ if (partialVideoSample) {
413
+ const completeFrame: VideoSample = {
414
+ ...partialVideoSample,
415
+ type: hasReferenceBlock ? 'delta' : 'key',
416
+ };
417
+ await parserContext.parserState.onVideoSample(
418
+ partialVideoSample.trackId,
419
+ completeFrame,
420
+ );
421
+ }
422
+
423
+ return blockGroup;
377
424
  }
378
425
 
379
426
  if (segmentId === '0xa1') {
380
427
  return parseBlockElementSegment(iterator, length);
381
428
  }
382
429
 
383
- const bytesRemaining = iterator.byteLength() - iterator.counter.getOffset();
384
- const toDiscard = Math.min(
385
- bytesRemaining,
386
- length > 0 ? length : bytesRemaining,
387
- );
430
+ iterator.counter.decrement(headerReadSoFar);
388
431
 
389
- const child = parseUnknownSegment(iterator, segmentId, toDiscard);
390
- return child;
432
+ return parseEbml(iterator);
391
433
  };
392
434
 
393
435
  export const expectSegment = async (
394
436
  iterator: BufferIterator,
395
437
  parserContext: ParserContext,
396
438
  ): Promise<ParseResult> => {
397
- const bytesRemaining_ = iterator.bytesRemaining();
398
- if (bytesRemaining_ === 0) {
439
+ const offset = iterator.counter.getOffset();
440
+ if (iterator.bytesRemaining() === 0) {
399
441
  return {
400
442
  status: 'incomplete',
401
443
  segments: [],
@@ -406,9 +448,33 @@ export const expectSegment = async (
406
448
  };
407
449
  }
408
450
 
409
- const offset = iterator.counter.getOffset();
410
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
+
411
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
+
412
478
  const bytesRemainingNow =
413
479
  iterator.byteLength() - iterator.counter.getOffset();
414
480
 
@@ -463,6 +529,7 @@ export const expectSegment = async (
463
529
  iterator,
464
530
  length,
465
531
  parserContext,
532
+ headerReadSoFar: iterator.counter.getOffset() - offset,
466
533
  });
467
534
 
468
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);