@remotion/media-parser 4.0.198 → 4.0.200

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 (34) hide show
  1. package/dist/boxes/iso-base-media/mdat/mdat.js +0 -1
  2. package/dist/boxes/webm/ebml.d.ts +2 -0
  3. package/dist/boxes/webm/ebml.js +72 -0
  4. package/dist/boxes/webm/make-header.d.ts +2 -0
  5. package/dist/boxes/webm/make-header.js +44 -0
  6. package/dist/boxes/webm/segments/all-segments.d.ts +5 -0
  7. package/dist/boxes/webm/segments/all-segments.js +5 -0
  8. package/dist/boxes/webm/segments/block-simple-block-flags.d.ts +9 -0
  9. package/dist/boxes/webm/segments/block-simple-block-flags.js +38 -0
  10. package/dist/boxes/webm/segments/track-entry.d.ts +20 -8
  11. package/dist/boxes/webm/segments/track-entry.js +64 -23
  12. package/dist/boxes/webm/segments.d.ts +2 -2
  13. package/dist/boxes/webm/segments.js +35 -6
  14. package/dist/buffer-iterator.d.ts +1 -0
  15. package/dist/buffer-iterator.js +9 -2
  16. package/dist/get-audio-codec.d.ts +1 -1
  17. package/dist/parser-state.d.ts +4 -6
  18. package/dist/parser-state.js +24 -16
  19. package/dist/webcodec-sample-types.d.ts +0 -1
  20. package/package.json +2 -2
  21. package/src/boxes/iso-base-media/mdat/mdat.ts +0 -1
  22. package/src/boxes/webm/ebml.ts +78 -0
  23. package/src/boxes/webm/make-header.ts +48 -0
  24. package/src/boxes/webm/segments/all-segments.ts +5 -0
  25. package/src/boxes/webm/segments/block-simple-block-flags.ts +52 -0
  26. package/src/boxes/webm/segments/track-entry.ts +108 -29
  27. package/src/boxes/webm/segments.ts +71 -9
  28. package/src/buffer-iterator.ts +8 -1
  29. package/src/parser-state.ts +30 -20
  30. package/src/test/create-matroska.test.ts +14 -0
  31. package/src/test/matroska.test.ts +75 -100
  32. package/src/test/stream-local.test.ts +47 -5
  33. package/src/webcodec-sample-types.ts +0 -1
  34. package/tsconfig.tsbuildinfo +1 -1
@@ -62,7 +62,6 @@ const parseMdat = async ({ data, size, fileOffset, existingBoxes, options, }) =>
62
62
  await options.parserState.onAudioSample(sampleWithIndex.track.trackId, {
63
63
  data: bytes,
64
64
  timestamp: sampleWithIndex.samplePosition.offset,
65
- offset: data.counter.getOffset(),
66
65
  trackId: sampleWithIndex.track.trackId,
67
66
  type: sampleWithIndex.samplePosition.isKeyframe ? 'key' : 'delta',
68
67
  });
@@ -0,0 +1,2 @@
1
+ export declare const measureEBMLVarInt: (value: number) => 1 | 2 | 3 | 4 | 5 | 6;
2
+ export declare const getVariableInt: (value: number, width?: number) => Uint8Array;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // https://github.com/Vanilagy/webm-muxer/blob/main/src/ebml.ts#L101
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.getVariableInt = exports.measureEBMLVarInt = void 0;
5
+ const measureEBMLVarInt = (value) => {
6
+ if (value < (1 << 7) - 1) {
7
+ /** Top bit is set, leaving 7 bits to hold the integer, but we can't store
8
+ * 127 because "all bits set to one" is a reserved value. Same thing for the
9
+ * other cases below:
10
+ */
11
+ return 1;
12
+ }
13
+ if (value < (1 << 14) - 1) {
14
+ return 2;
15
+ }
16
+ if (value < (1 << 21) - 1) {
17
+ return 3;
18
+ }
19
+ if (value < (1 << 28) - 1) {
20
+ return 4;
21
+ }
22
+ if (value < 2 ** 35 - 1) {
23
+ return 5;
24
+ }
25
+ if (value < 2 ** 42 - 1) {
26
+ return 6;
27
+ }
28
+ throw new Error('EBML VINT size not supported ' + value);
29
+ };
30
+ exports.measureEBMLVarInt = measureEBMLVarInt;
31
+ const getVariableInt = (value, width = (0, exports.measureEBMLVarInt)(value)) => {
32
+ switch (width) {
33
+ case 1:
34
+ return new Uint8Array([(1 << 7) | value]);
35
+ case 2:
36
+ return new Uint8Array([(1 << 6) | (value >> 8), value]);
37
+ case 3:
38
+ return new Uint8Array([(1 << 5) | (value >> 16), value >> 8, value]);
39
+ case 4:
40
+ return new Uint8Array([
41
+ (1 << 4) | (value >> 24),
42
+ value >> 16,
43
+ value >> 8,
44
+ value,
45
+ ]);
46
+ case 5:
47
+ /**
48
+ * JavaScript converts its doubles to 32-bit integers for bitwise
49
+ * operations, so we need to do a division by 2^32 instead of a
50
+ * right-shift of 32 to retain those top 3 bits
51
+ */
52
+ return new Uint8Array([
53
+ (1 << 3) | ((value / 2 ** 32) & 0x7),
54
+ value >> 24,
55
+ value >> 16,
56
+ value >> 8,
57
+ value,
58
+ ]);
59
+ case 6:
60
+ return new Uint8Array([
61
+ (1 << 2) | ((value / 2 ** 40) & 0x3),
62
+ (value / 2 ** 32) | 0,
63
+ value >> 24,
64
+ value >> 16,
65
+ value >> 8,
66
+ value,
67
+ ]);
68
+ default:
69
+ throw new Error('Bad EBML VINT size ' + width);
70
+ }
71
+ };
72
+ exports.getVariableInt = getVariableInt;
@@ -0,0 +1,2 @@
1
+ export declare const webmPattern: Uint8Array;
2
+ export declare const makeMatroskaHeader: () => Uint8Array;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeMatroskaHeader = exports.webmPattern = void 0;
4
+ const ebml_1 = require("./ebml");
5
+ const all_segments_1 = require("./segments/all-segments");
6
+ exports.webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
7
+ const matroskaToHex = (matrId) => {
8
+ const numbers = [];
9
+ for (let i = 2; i < matrId.length; i += 2) {
10
+ const hex = matrId.substr(i, 2);
11
+ numbers.push(parseInt(hex, 16));
12
+ }
13
+ return numbers;
14
+ };
15
+ const makeMatroskaHeader = () => {
16
+ const size = 0x23;
17
+ const array = new Uint8Array([
18
+ ...exports.webmPattern,
19
+ ...(0, ebml_1.getVariableInt)(size),
20
+ ...matroskaToHex(all_segments_1.matroskaElements.EBMLVersion),
21
+ ...(0, ebml_1.getVariableInt)(1),
22
+ 1,
23
+ ...matroskaToHex(all_segments_1.matroskaElements.EBMLReadVersion),
24
+ ...(0, ebml_1.getVariableInt)(1),
25
+ 1,
26
+ ...matroskaToHex(all_segments_1.matroskaElements.EBMLMaxIDLength),
27
+ ...(0, ebml_1.getVariableInt)(1),
28
+ 4,
29
+ ...matroskaToHex(all_segments_1.matroskaElements.EBMLMaxSizeLength),
30
+ ...(0, ebml_1.getVariableInt)(1),
31
+ 8,
32
+ ...matroskaToHex(all_segments_1.matroskaElements.DocType),
33
+ ...(0, ebml_1.getVariableInt)(8),
34
+ ...new TextEncoder().encode('matroska'),
35
+ ...matroskaToHex(all_segments_1.matroskaElements.DocTypeVersion),
36
+ ...(0, ebml_1.getVariableInt)(1),
37
+ 4,
38
+ ...matroskaToHex(all_segments_1.matroskaElements.DocTypeReadVersion),
39
+ ...(0, ebml_1.getVariableInt)(1),
40
+ 2,
41
+ ]);
42
+ return array;
43
+ };
44
+ exports.makeMatroskaHeader = makeMatroskaHeader;
@@ -1,6 +1,11 @@
1
1
  export declare const matroskaElements: {
2
2
  readonly EBMLMaxIDLength: "0x42f2";
3
+ readonly EBMLVersion: "0x4286";
4
+ readonly EBMLReadVersion: "0x42F7";
3
5
  readonly EBMLMaxSizeLength: "0x42f3";
6
+ readonly DocType: "0x4282";
7
+ readonly DocTypeVersion: "0x4287";
8
+ readonly DocTypeReadVersion: "0x4285";
4
9
  readonly Segment: "0x18538067";
5
10
  readonly SeekHead: "0x114d9b74";
6
11
  readonly Seek: "0x4dbb";
@@ -3,7 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getSegmentName = exports.knownIdsWithThreeLength = exports.knownIdsWithTwoLength = exports.knownIdsWithOneLength = exports.matroskaElements = void 0;
4
4
  exports.matroskaElements = {
5
5
  EBMLMaxIDLength: '0x42f2',
6
+ EBMLVersion: '0x4286',
7
+ EBMLReadVersion: '0x42F7',
6
8
  EBMLMaxSizeLength: '0x42f3',
9
+ DocType: '0x4282',
10
+ DocTypeVersion: '0x4287',
11
+ DocTypeReadVersion: '0x4285',
7
12
  Segment: '0x18538067',
8
13
  SeekHead: '0x114d9b74',
9
14
  Seek: '0x4dbb',
@@ -0,0 +1,9 @@
1
+ import type { BufferIterator } from '../../../buffer-iterator';
2
+ import { matroskaElements } from './all-segments';
3
+ type BlockFlags = {
4
+ invisible: boolean;
5
+ lacing: number;
6
+ keyframe: boolean | null;
7
+ };
8
+ export declare const parseBlockFlags: (iterator: BufferIterator, type: (typeof matroskaElements)['Block'] | (typeof matroskaElements)['SimpleBlock']) => BlockFlags;
9
+ export {};
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseBlockFlags = void 0;
4
+ const all_segments_1 = require("./all-segments");
5
+ const parseBlockFlags = (iterator, type) => {
6
+ if (type === all_segments_1.matroskaElements.Block) {
7
+ iterator.startReadingBits();
8
+ // Reserved
9
+ iterator.getBits(4);
10
+ const invisible = Boolean(iterator.getBits(1));
11
+ const lacing = iterator.getBits(2);
12
+ // unused
13
+ iterator.getBits(1);
14
+ iterator.stopReadingBits();
15
+ return {
16
+ invisible,
17
+ lacing,
18
+ keyframe: null,
19
+ };
20
+ }
21
+ if (type === all_segments_1.matroskaElements.SimpleBlock) {
22
+ iterator.startReadingBits();
23
+ const keyframe = Boolean(iterator.getBits(1));
24
+ // Reserved
25
+ iterator.getBits(3);
26
+ const invisible = Boolean(iterator.getBits(1));
27
+ const lacing = iterator.getBits(2);
28
+ iterator.getBits(1);
29
+ iterator.stopReadingBits();
30
+ return {
31
+ invisible,
32
+ lacing,
33
+ keyframe,
34
+ };
35
+ }
36
+ throw new Error('Unexpected type');
37
+ };
38
+ exports.parseBlockFlags = parseBlockFlags;
@@ -1,6 +1,8 @@
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';
4
6
  export type TrackEntrySegment = {
5
7
  type: 'track-entry-segment';
6
8
  children: MatroskaSegment[];
@@ -135,29 +137,39 @@ export type TimestampSegment = {
135
137
  timestamp: number;
136
138
  };
137
139
  export declare const parseTimestampSegment: (iterator: BufferIterator, length: number) => TimestampSegment;
138
- export type SimpleBlockSegment = {
139
- type: 'simple-block-segment';
140
+ export type SimpleBlockOrBlockSegment = {
141
+ type: 'simple-block-or-block-segment';
140
142
  length: number;
141
143
  trackNumber: number;
142
144
  timecode: number;
143
- headerFlags: number;
144
- keyframe: boolean;
145
- lacing: [number, number];
145
+ keyframe: boolean | null;
146
+ lacing: number;
146
147
  invisible: boolean;
147
- children: MatroskaSegment[];
148
+ videoSample: Omit<VideoSample, 'type'> | null;
148
149
  };
149
150
  export type GetTracks = () => TrackEntrySegment[];
150
- export declare const parseSimpleBlockSegment: ({ iterator, length, parserContext, }: {
151
+ export declare const parseSimpleBlockOrBlockSegment: ({ iterator, length, parserContext, type, }: {
151
152
  iterator: BufferIterator;
152
153
  length: number;
153
154
  parserContext: ParserContext;
154
- }) => Promise<SimpleBlockSegment>;
155
+ type: (typeof matroskaElements)['Block'] | (typeof matroskaElements)['SimpleBlock'];
156
+ }) => Promise<SimpleBlockOrBlockSegment>;
155
157
  export declare const parseTrackNumber: (iterator: BufferIterator, length: number) => TrackNumberSegment;
156
158
  export type BlockGroupSegment = {
157
159
  type: 'block-group-segment';
158
160
  children: MatroskaSegment[];
159
161
  };
160
162
  export declare const parseBlockGroupSegment: (iterator: BufferIterator, length: number, parserContext: ParserContext) => Promise<BlockGroupSegment>;
163
+ export type ReferenceBlockSegment = {
164
+ type: 'reference-block-segment';
165
+ referenceBlock: number;
166
+ };
167
+ export declare const parseReferenceBlockSegment: (iterator: BufferIterator, length: number) => ReferenceBlockSegment;
168
+ export type BlockAdditionsSegment = {
169
+ type: 'block-additions-segment';
170
+ blockAdditions: Uint8Array;
171
+ };
172
+ export declare const parseBlockAdditionsSegment: (iterator: BufferIterator, length: number) => BlockAdditionsSegment;
161
173
  export type BlockElement = {
162
174
  type: 'block-element-segment';
163
175
  length: number;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseBitDepthSegment = exports.parseChannelsSegment = exports.parseSamplingFrequencySegment = exports.parseBlockElementSegment = exports.parseBlockGroupSegment = exports.parseTrackNumber = exports.parseSimpleBlockSegment = exports.parseTimestampSegment = exports.parseTagSegment = exports.parseTagsSegment = exports.parseDefaultFlagSegment = exports.parseSegmentUUIDSegment = exports.parseCrc32Segment = exports.parseCodecPrivateSegment = exports.parseInterlacedSegment = exports.parseTitleSegment = exports.parseColorSegment = exports.parseMaxBlockAdditionId = exports.parseAlphaModeSegment = exports.parseDisplayHeightSegment = exports.parseDisplayWidthSegment = exports.parseHeightSegment = exports.parseWidthSegment = exports.parseAudioSegment = exports.parseVideoSegment = exports.parseDefaultDurationSegment = exports.parseTrackTypeSegment = exports.parseCodecSegment = exports.parseLanguageSegment = exports.parseFlagLacing = exports.parseTrackUID = exports.parseTrackEntry = void 0;
3
+ exports.parseBitDepthSegment = exports.parseChannelsSegment = exports.parseSamplingFrequencySegment = exports.parseBlockElementSegment = exports.parseBlockAdditionsSegment = exports.parseReferenceBlockSegment = exports.parseBlockGroupSegment = exports.parseTrackNumber = exports.parseSimpleBlockOrBlockSegment = exports.parseTimestampSegment = exports.parseTagSegment = exports.parseTagsSegment = exports.parseDefaultFlagSegment = exports.parseSegmentUUIDSegment = exports.parseCrc32Segment = exports.parseCodecPrivateSegment = exports.parseInterlacedSegment = exports.parseTitleSegment = exports.parseColorSegment = exports.parseMaxBlockAdditionId = exports.parseAlphaModeSegment = exports.parseDisplayHeightSegment = exports.parseDisplayWidthSegment = exports.parseHeightSegment = exports.parseWidthSegment = exports.parseAudioSegment = exports.parseVideoSegment = exports.parseDefaultDurationSegment = exports.parseTrackTypeSegment = exports.parseCodecSegment = exports.parseLanguageSegment = exports.parseFlagLacing = exports.parseTrackUID = exports.parseTrackEntry = void 0;
4
+ const block_simple_block_flags_1 = require("./block-simple-block-flags");
4
5
  const parse_children_1 = require("./parse-children");
5
6
  const parseTrackEntry = async (iterator, length, parserContext) => {
6
7
  const children = await (0, parse_children_1.expectChildren)({
@@ -299,8 +300,15 @@ const parseTagSegment = (iterator, length) => {
299
300
  };
300
301
  exports.parseTagSegment = parseTagSegment;
301
302
  const parseTimestampSegment = (iterator, length) => {
302
- if (length > 2) {
303
- throw new Error('Expected timestamp segment to be 1 byte or 2 bytes');
303
+ if (length > 3) {
304
+ throw new Error('Expected timestamp segment to be 1 byte or 2 bytes, but is ' + length);
305
+ }
306
+ if (length === 3) {
307
+ const val = iterator.getUint24();
308
+ return {
309
+ type: 'timestamp-segment',
310
+ timestamp: val,
311
+ };
304
312
  }
305
313
  const value = length === 2 ? iterator.getUint16() : iterator.getUint8();
306
314
  return {
@@ -309,37 +317,46 @@ const parseTimestampSegment = (iterator, length) => {
309
317
  };
310
318
  };
311
319
  exports.parseTimestampSegment = parseTimestampSegment;
312
- const parseSimpleBlockSegment = async ({ iterator, length, parserContext, }) => {
320
+ const parseSimpleBlockOrBlockSegment = async ({ iterator, length, parserContext, type, }) => {
313
321
  const start = iterator.counter.getOffset();
314
322
  const trackNumber = iterator.getVint();
315
- const timecode = iterator.getUint16();
316
- const headerFlags = iterator.getUint8();
317
- const invisible = Boolean((headerFlags >> 5) & 1);
318
- const pos6 = (headerFlags >> 6) & 1;
319
- const pos7 = (headerFlags >> 6) & 1;
320
- const keyframe = Boolean((headerFlags >> 7) & 1);
323
+ const timecodeRelativeToCluster = iterator.getUint16();
324
+ const { invisible, lacing, keyframe } = (0, block_simple_block_flags_1.parseBlockFlags)(iterator, type);
321
325
  const codec = parserContext.parserState.getTrackInfoByNumber(trackNumber);
326
+ const clusterOffset = parserContext.parserState.getTimestampOffsetForByteOffset(iterator.counter.getOffset());
327
+ if (clusterOffset === undefined) {
328
+ throw new Error('Could not find offset for byte offset ' + iterator.counter.getOffset());
329
+ }
330
+ const timecode = timecodeRelativeToCluster + clusterOffset;
322
331
  if (!codec) {
323
332
  throw new Error('Could not find codec for track ' + trackNumber);
324
333
  }
325
- const children = [];
334
+ const remainingNow = length - (iterator.counter.getOffset() - start);
335
+ let videoSample = null;
326
336
  if (codec.codec.startsWith('V_')) {
327
- const remainingNow = length - (iterator.counter.getOffset() - start);
328
- await parserContext.parserState.onVideoSample(trackNumber, {
337
+ const partialVideoSample = {
329
338
  data: iterator.getSlice(remainingNow),
330
339
  cts: null,
331
340
  dts: null,
332
341
  duration: undefined,
333
- type: keyframe ? 'key' : 'delta',
334
342
  trackId: trackNumber,
335
343
  timestamp: timecode,
336
- });
344
+ };
345
+ if (keyframe === null) {
346
+ // If we don't know if this is a keyframe, we know after we emit the BlockGroup
347
+ videoSample = partialVideoSample;
348
+ }
349
+ else {
350
+ const sample = {
351
+ ...partialVideoSample,
352
+ type: keyframe ? 'key' : 'delta',
353
+ };
354
+ await parserContext.parserState.onVideoSample(trackNumber, sample);
355
+ }
337
356
  }
338
357
  if (codec.codec.startsWith('A_')) {
339
- const vorbisRemaining = length - (iterator.counter.getOffset() - start);
340
358
  await parserContext.parserState.onAudioSample(trackNumber, {
341
- data: iterator.getSlice(vorbisRemaining),
342
- offset: timecode,
359
+ data: iterator.getSlice(remainingNow),
343
360
  trackId: trackNumber,
344
361
  timestamp: timecode,
345
362
  type: 'key',
@@ -350,18 +367,17 @@ const parseSimpleBlockSegment = async ({ iterator, length, parserContext, }) =>
350
367
  iterator.discard(remainingNowAfter);
351
368
  }
352
369
  return {
353
- type: 'simple-block-segment',
370
+ type: 'simple-block-or-block-segment',
354
371
  length,
355
372
  trackNumber,
356
373
  timecode,
357
- headerFlags,
358
374
  keyframe,
359
- lacing: [pos6, pos7],
375
+ lacing,
360
376
  invisible,
361
- children,
377
+ videoSample,
362
378
  };
363
379
  };
364
- exports.parseSimpleBlockSegment = parseSimpleBlockSegment;
380
+ exports.parseSimpleBlockOrBlockSegment = parseSimpleBlockOrBlockSegment;
365
381
  const parseTrackNumber = (iterator, length) => {
366
382
  if (length !== 1) {
367
383
  throw new Error('Expected track number to be 1 byte');
@@ -390,6 +406,31 @@ const parseBlockGroupSegment = async (iterator, length, parserContext) => {
390
406
  };
391
407
  };
392
408
  exports.parseBlockGroupSegment = parseBlockGroupSegment;
409
+ const parseReferenceBlockSegment = (iterator, length) => {
410
+ if (length > 4) {
411
+ throw new Error(`Expected reference block segment to be 4 bytes, but got ${length}`);
412
+ }
413
+ const referenceBlock = length === 4
414
+ ? iterator.getUint32()
415
+ : length === 3
416
+ ? iterator.getUint24()
417
+ : length === 2
418
+ ? iterator.getUint16()
419
+ : iterator.getUint8();
420
+ return {
421
+ type: 'reference-block-segment',
422
+ referenceBlock,
423
+ };
424
+ };
425
+ exports.parseReferenceBlockSegment = parseReferenceBlockSegment;
426
+ const parseBlockAdditionsSegment = (iterator, length) => {
427
+ const blockAdditions = iterator.getSlice(length);
428
+ return {
429
+ type: 'block-additions-segment',
430
+ blockAdditions,
431
+ };
432
+ };
433
+ exports.parseBlockAdditionsSegment = parseBlockAdditionsSegment;
393
434
  const parseBlockElementSegment = (iterator, length) => {
394
435
  iterator.discard(length);
395
436
  return {
@@ -10,11 +10,11 @@ import { type SeekSegment } from './segments/seek';
10
10
  import type { SeekHeadSegment } from './segments/seek-head';
11
11
  import { type SeekPositionSegment } from './segments/seek-position';
12
12
  import type { TimestampScaleSegment } from './segments/timestamp-scale';
13
- import type { AlphaModeSegment, AudioSegment, BitDepthSegment, BlockElement, BlockGroupSegment, ChannelsSegment, ClusterSegment, CodecPrivateSegment, CodecSegment, ColorSegment, Crc32Segment, DefaultDurationSegment, DefaultFlagSegment, DisplayHeightSegment, DisplayWidthSegment, FlagLacingSegment, HeightSegment, InterlacedSegment, LanguageSegment, MaxBlockAdditionId, SamplingFrequencySegment, SegmentUUIDSegment, SimpleBlockSegment, TagSegment, TagsSegment, TimestampSegment, TitleSegment, TrackEntrySegment, TrackNumberSegment, TrackTypeSegment, TrackUIDSegment, VideoSegment, WidthSegment } from './segments/track-entry';
13
+ import type { AlphaModeSegment, AudioSegment, BitDepthSegment, BlockAdditionsSegment, BlockElement, BlockGroupSegment, ChannelsSegment, ClusterSegment, CodecPrivateSegment, CodecSegment, ColorSegment, Crc32Segment, DefaultDurationSegment, DefaultFlagSegment, DisplayHeightSegment, DisplayWidthSegment, FlagLacingSegment, HeightSegment, InterlacedSegment, LanguageSegment, MaxBlockAdditionId, ReferenceBlockSegment, SamplingFrequencySegment, SegmentUUIDSegment, SimpleBlockOrBlockSegment, TagSegment, TagsSegment, TimestampSegment, TitleSegment, TrackEntrySegment, TrackNumberSegment, TrackTypeSegment, TrackUIDSegment, VideoSegment, WidthSegment } from './segments/track-entry';
14
14
  import type { TracksSegment } from './segments/tracks';
15
15
  import type { UnknownSegment } from './segments/unknown';
16
16
  import type { VoidSegment } from './segments/void';
17
17
  import type { WritingAppSegment } from './segments/writing';
18
- export type MatroskaSegment = MainSegment | UnknownSegment | SeekHeadSegment | SeekSegment | SeekPositionSegment | VoidSegment | InfoSegment | TimestampScaleSegment | MuxingAppSegment | WritingAppSegment | DurationSegment | TracksSegment | TrackEntrySegment | TrackNumberSegment | TrackUIDSegment | FlagLacingSegment | LanguageSegment | CodecSegment | TrackTypeSegment | DefaultDurationSegment | VideoSegment | WidthSegment | HeightSegment | DisplayWidthSegment | DisplayHeightSegment | AlphaModeSegment | MaxBlockAdditionId | ColorSegment | TitleSegment | InterlacedSegment | CodecPrivateSegment | Crc32Segment | SegmentUUIDSegment | DefaultFlagSegment | TagsSegment | TagSegment | ClusterSegment | TimestampSegment | SimpleBlockSegment | BlockGroupSegment | BlockElement | SeekIdSegment | AudioSegment | SamplingFrequencySegment | ChannelsSegment | BitDepthSegment;
18
+ export type MatroskaSegment = MainSegment | UnknownSegment | SeekHeadSegment | SeekSegment | SeekPositionSegment | VoidSegment | InfoSegment | TimestampScaleSegment | MuxingAppSegment | WritingAppSegment | DurationSegment | TracksSegment | TrackEntrySegment | TrackNumberSegment | TrackUIDSegment | FlagLacingSegment | LanguageSegment | CodecSegment | TrackTypeSegment | DefaultDurationSegment | VideoSegment | WidthSegment | HeightSegment | DisplayWidthSegment | DisplayHeightSegment | AlphaModeSegment | MaxBlockAdditionId | ColorSegment | TitleSegment | InterlacedSegment | CodecPrivateSegment | Crc32Segment | SegmentUUIDSegment | DefaultFlagSegment | TagsSegment | TagSegment | ClusterSegment | TimestampSegment | SimpleBlockOrBlockSegment | BlockGroupSegment | BlockElement | SeekIdSegment | AudioSegment | SamplingFrequencySegment | ChannelsSegment | BitDepthSegment | ReferenceBlockSegment | BlockAdditionsSegment;
19
19
  export type OnTrackEntrySegment = (trackEntry: TrackEntrySegment) => void;
20
20
  export declare const expectSegment: (iterator: BufferIterator, parserContext: ParserContext) => Promise<ParseResult>;
@@ -168,18 +168,47 @@ const parseSegment = async ({ segmentId, iterator, length, parserContext, }) =>
168
168
  if (segmentId === all_segments_1.matroskaElements.BitDepth) {
169
169
  return (0, track_entry_1.parseBitDepthSegment)(iterator, length);
170
170
  }
171
- if (segmentId === '0xe7') {
172
- return (0, track_entry_1.parseTimestampSegment)(iterator, length);
173
- }
174
- if (segmentId === '0xa3') {
175
- return (0, track_entry_1.parseSimpleBlockSegment)({
171
+ if (segmentId === all_segments_1.matroskaElements.Timestamp) {
172
+ const offset = iterator.counter.getOffset();
173
+ const timestampSegment = (0, track_entry_1.parseTimestampSegment)(iterator, length);
174
+ parserContext.parserState.setTimestampOffset(offset, timestampSegment.timestamp);
175
+ return timestampSegment;
176
+ }
177
+ if (segmentId === all_segments_1.matroskaElements.SimpleBlock ||
178
+ segmentId === all_segments_1.matroskaElements.Block) {
179
+ return (0, track_entry_1.parseSimpleBlockOrBlockSegment)({
176
180
  iterator,
177
181
  length,
178
182
  parserContext,
183
+ type: segmentId,
179
184
  });
180
185
  }
186
+ if (segmentId === all_segments_1.matroskaElements.ReferenceBlock) {
187
+ return (0, track_entry_1.parseReferenceBlockSegment)(iterator, length);
188
+ }
189
+ if (segmentId === all_segments_1.matroskaElements.BlockAdditions) {
190
+ return (0, track_entry_1.parseBlockAdditionsSegment)(iterator, length);
191
+ }
181
192
  if (segmentId === '0xa0') {
182
- return (0, track_entry_1.parseBlockGroupSegment)(iterator, length, parserContext);
193
+ const blockGroup = await (0, track_entry_1.parseBlockGroupSegment)(iterator, length, parserContext);
194
+ // Blocks don't have information about keyframes.
195
+ // https://ffmpeg.org/pipermail/ffmpeg-devel/2015-June/173825.html
196
+ // "For Blocks, keyframes is
197
+ // inferred by the absence of ReferenceBlock element (as done by matroskadec).""
198
+ const block = blockGroup.children.find((c) => c.type === 'simple-block-or-block-segment');
199
+ if (!block || block.type !== 'simple-block-or-block-segment') {
200
+ throw new Error('Expected block segment');
201
+ }
202
+ const hasReferenceBlock = blockGroup.children.find((c) => c.type === 'reference-block-segment');
203
+ const partialVideoSample = block.videoSample;
204
+ if (partialVideoSample) {
205
+ const completeFrame = {
206
+ ...partialVideoSample,
207
+ type: hasReferenceBlock ? 'delta' : 'key',
208
+ };
209
+ await parserContext.parserState.onVideoSample(partialVideoSample.trackId, completeFrame);
210
+ }
211
+ return blockGroup;
183
212
  }
184
213
  if (segmentId === '0xa1') {
185
214
  return (0, track_entry_1.parseBlockElementSegment)(iterator, length);
@@ -34,6 +34,7 @@ export declare const getArrayBufferIterator: (initialData: Uint8Array, maxBytes?
34
34
  getEBML: () => number;
35
35
  getInt8: () => number;
36
36
  getUint16: () => number;
37
+ getUint24: () => number;
37
38
  getInt16: () => number;
38
39
  getUint32: () => number;
39
40
  getFixedPointUnsigned1616Number: () => number;
@@ -13,6 +13,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
13
13
  var _OffsetCounter_offset, _OffsetCounter_discardedBytes;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.getArrayBufferIterator = exports.OffsetCounter = void 0;
16
+ const make_header_1 = require("./boxes/webm/make-header");
16
17
  const all_segments_1 = require("./boxes/webm/segments/all-segments");
17
18
  class OffsetCounter {
18
19
  constructor(initial) {
@@ -49,7 +50,6 @@ class OffsetCounter {
49
50
  exports.OffsetCounter = OffsetCounter;
50
51
  _OffsetCounter_offset = new WeakMap(), _OffsetCounter_discardedBytes = new WeakMap();
51
52
  const isoBaseMediaMp4Pattern = new TextEncoder().encode('ftyp');
52
- const webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
53
53
  const mpegPattern = new Uint8Array([0xff, 0xf3, 0xe4, 0x64]);
54
54
  const matchesPattern = (pattern) => {
55
55
  return (data) => {
@@ -129,7 +129,7 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
129
129
  return matchesPattern(isoBaseMediaMp4Pattern)(data.subarray(4, 8));
130
130
  };
131
131
  const isWebm = () => {
132
- return matchesPattern(webmPattern)(data.subarray(0, 4));
132
+ return matchesPattern(make_header_1.webmPattern)(data.subarray(0, 4));
133
133
  };
134
134
  const isMp3 = () => {
135
135
  return matchesPattern(mpegPattern)(data.subarray(0, 4));
@@ -315,6 +315,13 @@ const getArrayBufferIterator = (initialData, maxBytes) => {
315
315
  counter.increment(2);
316
316
  return val;
317
317
  },
318
+ getUint24: () => {
319
+ const val1 = view.getUint8(counter.getDiscardedOffset());
320
+ const val2 = view.getUint8(counter.getDiscardedOffset());
321
+ const val3 = view.getUint8(counter.getDiscardedOffset());
322
+ counter.increment(3);
323
+ return (val1 << 16) | (val2 << 8) | val3;
324
+ },
318
325
  getInt16: () => {
319
326
  const val = view.getInt16(counter.getDiscardedOffset());
320
327
  counter.increment(2);
@@ -14,7 +14,7 @@ export declare const getNumberOfChannelsFromTrak: (trak: TrakBox) => number | nu
14
14
  export declare const getSampleRate: (trak: TrakBox) => number | null;
15
15
  export declare const getAudioCodecFromTrak: (trak: TrakBox) => AudioCodecInfo | null;
16
16
  export declare const getAudioCodecFromIso: (moov: MoovBox) => AudioCodecInfo | null;
17
- export declare const getAudioCodecFromMatroska: (mainSegment: MainSegment) => "aac" | "mp3" | "opus" | "pcm" | "vorbis" | null;
17
+ export declare const getAudioCodecFromMatroska: (mainSegment: MainSegment) => "vorbis" | "opus" | "mp3" | "aac" | "pcm" | null;
18
18
  export declare const getAudioCodecStringFromTrak: (trak: TrakBox) => {
19
19
  codecString: string;
20
20
  description: Uint8Array | undefined;
@@ -1,9 +1,7 @@
1
1
  import type { OnTrackEntrySegment } from './boxes/webm/segments';
2
2
  import type { CodecSegment } from './boxes/webm/segments/track-entry';
3
3
  import type { AudioSample, OnAudioSample, OnVideoSample, VideoSample } from './webcodec-sample-types';
4
- export type InternalStats = {
5
- samplesThatHadToBeQueued: number;
6
- };
4
+ export type InternalStats = {};
7
5
  export declare const makeParserState: ({ hasAudioCallbacks, hasVideoCallbacks, }: {
8
6
  hasAudioCallbacks: boolean;
9
7
  hasVideoCallbacks: boolean;
@@ -11,12 +9,12 @@ export declare const makeParserState: ({ hasAudioCallbacks, hasVideoCallbacks, }
11
9
  onTrackEntrySegment: OnTrackEntrySegment;
12
10
  getTrackInfoByNumber: (id: number) => CodecSegment;
13
11
  registerVideoSampleCallback: (id: number, callback: OnVideoSample | null) => Promise<void>;
12
+ setTimestampOffset: (byteOffset: number, timestamp: number) => void;
13
+ getTimestampOffsetForByteOffset: (byteOffset: number) => number | undefined;
14
14
  registerAudioSampleCallback: (id: number, callback: OnAudioSample | null) => Promise<void>;
15
15
  onAudioSample: (trackId: number, audioSample: AudioSample) => Promise<void>;
16
16
  onVideoSample: (trackId: number, videoSample: VideoSample) => Promise<void>;
17
- getInternalStats: () => {
18
- samplesThatHadToBeQueued: number;
19
- };
17
+ getInternalStats: () => {};
20
18
  getTimescale: () => number;
21
19
  setTimescale: (newTimescale: number) => void;
22
20
  };