@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,9 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSegmentName = exports.knownIdsWithThreeLength = exports.knownIdsWithTwoLength = exports.knownIdsWithOneLength = exports.matroskaElements = void 0;
3
+ exports.ebmlMap = exports.voidHeader = exports.seek = exports.seekPosition = exports.seekId = exports.matroskaHeader = exports.matroskaHeaderStructure = exports.voidEbml = exports.docTypeReadVersion = exports.docTypeVersion = exports.docType = exports.ebmlMaxSizeLength = exports.ebmlMaxIdLength = exports.ebmlReadVersion = exports.ebmlVersion = exports.getIdForName = exports.getSegmentName = exports.knownIdsWithThreeLength = exports.knownIdsWithTwoLength = exports.knownIdsWithOneLength = exports.matroskaElements = void 0;
4
4
  exports.matroskaElements = {
5
+ Header: '0x1a45dfa3',
5
6
  EBMLMaxIDLength: '0x42f2',
7
+ EBMLVersion: '0x4286',
8
+ EBMLReadVersion: '0x42f7',
6
9
  EBMLMaxSizeLength: '0x42f3',
10
+ DocType: '0x4282',
11
+ DocTypeVersion: '0x4287',
12
+ DocTypeReadVersion: '0x4285',
7
13
  Segment: '0x18538067',
8
14
  SeekHead: '0x114d9b74',
9
15
  Seek: '0x4dbb',
@@ -275,3 +281,126 @@ const getSegmentName = (id) => {
275
281
  return (_a = Object.entries(exports.matroskaElements).find(([, value]) => value === id)) === null || _a === void 0 ? void 0 : _a[0];
276
282
  };
277
283
  exports.getSegmentName = getSegmentName;
284
+ const getIdForName = (name) => {
285
+ var _a;
286
+ const value = (_a = Object.entries(exports.matroskaElements).find(([key]) => key === name)) === null || _a === void 0 ? void 0 : _a[1];
287
+ if (!value) {
288
+ throw new Error(`Could not find id for name ${name}`);
289
+ }
290
+ return value;
291
+ };
292
+ exports.getIdForName = getIdForName;
293
+ exports.ebmlVersion = {
294
+ name: 'EBMLVersion',
295
+ type: 'uint',
296
+ };
297
+ exports.ebmlReadVersion = {
298
+ name: 'EBMLReadVersion',
299
+ type: 'uint',
300
+ };
301
+ exports.ebmlMaxIdLength = {
302
+ name: 'EBMLMaxIDLength',
303
+ type: 'uint',
304
+ };
305
+ exports.ebmlMaxSizeLength = {
306
+ name: 'EBMLMaxSizeLength',
307
+ type: 'uint',
308
+ };
309
+ exports.docType = {
310
+ name: 'DocType',
311
+ type: 'string',
312
+ };
313
+ exports.docTypeVersion = {
314
+ name: 'DocTypeVersion',
315
+ type: 'uint',
316
+ };
317
+ exports.docTypeReadVersion = {
318
+ name: 'DocTypeReadVersion',
319
+ type: 'uint',
320
+ };
321
+ exports.voidEbml = {
322
+ name: 'Void',
323
+ type: 'void',
324
+ };
325
+ exports.matroskaHeaderStructure = [
326
+ exports.ebmlVersion,
327
+ exports.ebmlReadVersion,
328
+ exports.ebmlMaxIdLength,
329
+ exports.ebmlMaxSizeLength,
330
+ exports.docType,
331
+ exports.docTypeVersion,
332
+ exports.docTypeReadVersion,
333
+ ];
334
+ exports.matroskaHeader = {
335
+ name: 'Header',
336
+ type: 'children',
337
+ children: exports.matroskaHeaderStructure,
338
+ };
339
+ exports.seekId = {
340
+ name: 'SeekID',
341
+ type: 'hex-string',
342
+ };
343
+ exports.seekPosition = {
344
+ name: 'SeekPosition',
345
+ type: 'uint',
346
+ };
347
+ exports.seek = {
348
+ name: 'Seek',
349
+ type: 'children',
350
+ children: [exports.seekId, exports.seekPosition],
351
+ };
352
+ exports.voidHeader = {
353
+ name: 'Void',
354
+ type: 'void',
355
+ };
356
+ exports.ebmlMap = {
357
+ [exports.matroskaElements.Header]: exports.matroskaHeader,
358
+ [exports.matroskaElements.DocType]: exports.docType,
359
+ [exports.matroskaElements.DocTypeVersion]: exports.docTypeVersion,
360
+ [exports.matroskaElements.DocTypeReadVersion]: exports.docTypeReadVersion,
361
+ [exports.matroskaElements.EBMLVersion]: exports.ebmlVersion,
362
+ [exports.matroskaElements.EBMLReadVersion]: exports.ebmlReadVersion,
363
+ [exports.matroskaElements.EBMLMaxIDLength]: exports.ebmlMaxIdLength,
364
+ [exports.matroskaElements.EBMLMaxSizeLength]: exports.ebmlMaxSizeLength,
365
+ [exports.matroskaElements.Void]: exports.voidEbml,
366
+ [exports.matroskaElements.Cues]: {
367
+ name: 'Cues',
368
+ type: 'void',
369
+ },
370
+ [exports.matroskaElements.DateUTC]: {
371
+ name: 'DateUTC',
372
+ type: 'void',
373
+ },
374
+ [exports.matroskaElements.TrackTimestampScale]: {
375
+ name: 'TrackTimestampScale',
376
+ type: 'float',
377
+ },
378
+ [exports.matroskaElements.CodecDelay]: {
379
+ name: 'CodecDelay',
380
+ type: 'void',
381
+ },
382
+ [exports.matroskaElements.SeekPreRoll]: {
383
+ name: 'SeekPreRoll',
384
+ type: 'void',
385
+ },
386
+ [exports.matroskaElements.DiscardPadding]: {
387
+ name: 'DiscardPadding',
388
+ type: 'void',
389
+ },
390
+ [exports.matroskaElements.OutputSamplingFrequency]: {
391
+ name: 'OutputSamplingFrequency',
392
+ type: 'void',
393
+ },
394
+ [exports.matroskaElements.CodecName]: {
395
+ name: 'CodecName',
396
+ type: 'void',
397
+ },
398
+ [exports.matroskaElements.Position]: {
399
+ name: 'Position',
400
+ type: 'void',
401
+ },
402
+ [exports.matroskaElements.SliceDuration]: {
403
+ name: 'SliceDuration',
404
+ type: 'void',
405
+ },
406
+ };
@@ -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;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseSeekPositionSegment = void 0;
4
4
  const parseSeekPositionSegment = (iterator, length) => {
5
- const seekPosition = iterator.getDecimalBytes(length);
5
+ const seekPosition = iterator.getUint(length);
6
6
  return {
7
7
  type: 'seek-position-segment',
8
8
  seekPosition,
@@ -10,4 +10,4 @@ export type SeekIdSegment = {
10
10
  type: 'seek-id-segment';
11
11
  seekId: string;
12
12
  };
13
- export declare const parseSeekIdSegment: (iterator: BufferIterator) => SeekIdSegment;
13
+ export declare const parseSeekIdSegment: (iterator: BufferIterator, length: number) => SeekIdSegment;
@@ -19,8 +19,14 @@ const parseSeekSegment = async (iterator, length, parserContext) => {
19
19
  };
20
20
  };
21
21
  exports.parseSeekSegment = parseSeekSegment;
22
- const parseSeekIdSegment = (iterator) => {
23
- const seekId = iterator.getMatroskaSegmentId();
22
+ const parseSeekIdSegment = (iterator, length) => {
23
+ const seekId = '0x' +
24
+ [...iterator.getSlice(length)]
25
+ .map((b) => b.toString(16).padStart(2, '0'))
26
+ .join('');
27
+ if (seekId === null) {
28
+ throw new Error('Not enough bytes to parse seek id');
29
+ }
24
30
  return {
25
31
  type: 'seek-id-segment',
26
32
  seekId,
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseTimestampScaleSegment = void 0;
4
4
  const parseTimestampScaleSegment = (iterator) => {
5
- const timestampScale = iterator.getDecimalBytes(3);
5
+ const timestampScale = iterator.getUint(3);
6
6
  return {
7
7
  type: 'timestamp-scale-segment',
8
8
  timestampScale,
@@ -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[];
@@ -29,6 +31,10 @@ export type CodecSegment = {
29
31
  type: 'codec-segment';
30
32
  codec: string;
31
33
  };
34
+ export type TrackInfo = {
35
+ codec: string;
36
+ trackTimescale: number | null;
37
+ };
32
38
  export declare const parseCodecSegment: (iterator: BufferIterator, length: number) => CodecSegment;
33
39
  type TrackType = 'video' | 'audio' | 'complex' | 'subtitle' | 'button' | 'control' | 'metadata';
34
40
  export type TrackTypeSegment = {
@@ -135,29 +141,39 @@ export type TimestampSegment = {
135
141
  timestamp: number;
136
142
  };
137
143
  export declare const parseTimestampSegment: (iterator: BufferIterator, length: number) => TimestampSegment;
138
- export type SimpleBlockSegment = {
139
- type: 'simple-block-segment';
144
+ export type SimpleBlockOrBlockSegment = {
145
+ type: 'simple-block-or-block-segment';
140
146
  length: number;
141
147
  trackNumber: number;
142
- timecode: number;
143
- headerFlags: number;
144
- keyframe: boolean;
145
- lacing: [number, number];
148
+ timecodeInMicroseconds: number;
149
+ keyframe: boolean | null;
150
+ lacing: number;
146
151
  invisible: boolean;
147
- children: MatroskaSegment[];
152
+ videoSample: Omit<VideoSample, 'type'> | null;
148
153
  };
149
154
  export type GetTracks = () => TrackEntrySegment[];
150
- export declare const parseSimpleBlockSegment: ({ iterator, length, parserContext, }: {
155
+ export declare const parseSimpleBlockOrBlockSegment: ({ iterator, length, parserContext, type, }: {
151
156
  iterator: BufferIterator;
152
157
  length: number;
153
158
  parserContext: ParserContext;
154
- }) => Promise<SimpleBlockSegment>;
159
+ type: (typeof matroskaElements)['Block'] | (typeof matroskaElements)['SimpleBlock'];
160
+ }) => Promise<SimpleBlockOrBlockSegment>;
155
161
  export declare const parseTrackNumber: (iterator: BufferIterator, length: number) => TrackNumberSegment;
156
162
  export type BlockGroupSegment = {
157
163
  type: 'block-group-segment';
158
164
  children: MatroskaSegment[];
159
165
  };
160
166
  export declare const parseBlockGroupSegment: (iterator: BufferIterator, length: number, parserContext: ParserContext) => Promise<BlockGroupSegment>;
167
+ export type ReferenceBlockSegment = {
168
+ type: 'reference-block-segment';
169
+ referenceBlock: number;
170
+ };
171
+ export declare const parseReferenceBlockSegment: (iterator: BufferIterator, length: number) => ReferenceBlockSegment;
172
+ export type BlockAdditionsSegment = {
173
+ type: 'block-additions-segment';
174
+ blockAdditions: Uint8Array;
175
+ };
176
+ export declare const parseBlockAdditionsSegment: (iterator: BufferIterator, length: number) => BlockAdditionsSegment;
161
177
  export type BlockElement = {
162
178
  type: 'block-element-segment';
163
179
  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)({
@@ -108,7 +109,7 @@ const parseTrackTypeSegment = (iterator, length) => {
108
109
  };
109
110
  exports.parseTrackTypeSegment = parseTrackTypeSegment;
110
111
  const parseDefaultDurationSegment = (iterator, length) => {
111
- const defaultDuration = iterator.getDecimalBytes(length);
112
+ const defaultDuration = iterator.getUint(length);
112
113
  return {
113
114
  type: 'default-duration-segment',
114
115
  defaultDuration,
@@ -299,49 +300,64 @@ 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');
304
- }
305
- const value = length === 2 ? iterator.getUint16() : iterator.getUint8();
306
303
  return {
307
304
  type: 'timestamp-segment',
308
- timestamp: value,
305
+ timestamp: iterator.getUint(length),
309
306
  };
310
307
  };
311
308
  exports.parseTimestampSegment = parseTimestampSegment;
312
- const parseSimpleBlockSegment = async ({ iterator, length, parserContext, }) => {
309
+ const parseSimpleBlockOrBlockSegment = async ({ iterator, length, parserContext, type, }) => {
313
310
  const start = iterator.counter.getOffset();
314
311
  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);
321
- const codec = parserContext.parserState.getTrackInfoByNumber(trackNumber);
312
+ if (trackNumber === null) {
313
+ throw new Error('Not enough data to get track number, should not happen');
314
+ }
315
+ const timecodeRelativeToCluster = iterator.getUint16();
316
+ const { invisible, lacing, keyframe } = (0, block_simple_block_flags_1.parseBlockFlags)(iterator, type);
317
+ const { codec, trackTimescale } = parserContext.parserState.getTrackInfoByNumber(trackNumber);
318
+ const clusterOffset = parserContext.parserState.getTimestampOffsetForByteOffset(iterator.counter.getOffset());
319
+ const timescale = parserContext.parserState.getTimescale();
320
+ if (clusterOffset === undefined) {
321
+ throw new Error('Could not find offset for byte offset ' + iterator.counter.getOffset());
322
+ }
323
+ // https://github.com/hubblec4/Matroska-Chapters-Specs/blob/master/notes.md/#timestampscale
324
+ // 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.
325
+ const timecodeInNanoSeconds = (timecodeRelativeToCluster + clusterOffset) *
326
+ timescale *
327
+ (trackTimescale !== null && trackTimescale !== void 0 ? trackTimescale : 1);
328
+ // Timecode should be in microseconds
329
+ const timecodeInMicroseconds = timecodeInNanoSeconds / 1000;
322
330
  if (!codec) {
323
331
  throw new Error('Could not find codec for track ' + trackNumber);
324
332
  }
325
- const children = [];
326
- if (codec.codec.startsWith('V_')) {
327
- const remainingNow = length - (iterator.counter.getOffset() - start);
328
- await parserContext.parserState.onVideoSample(trackNumber, {
333
+ const remainingNow = length - (iterator.counter.getOffset() - start);
334
+ let videoSample = null;
335
+ if (codec.startsWith('V_')) {
336
+ const partialVideoSample = {
329
337
  data: iterator.getSlice(remainingNow),
330
338
  cts: null,
331
339
  dts: null,
332
340
  duration: undefined,
333
- type: keyframe ? 'key' : 'delta',
334
341
  trackId: trackNumber,
335
- timestamp: timecode,
336
- });
342
+ timestamp: timecodeInMicroseconds,
343
+ };
344
+ if (keyframe === null) {
345
+ // If we don't know if this is a keyframe, we know after we emit the BlockGroup
346
+ videoSample = partialVideoSample;
347
+ }
348
+ else {
349
+ const sample = {
350
+ ...partialVideoSample,
351
+ type: keyframe ? 'key' : 'delta',
352
+ };
353
+ await parserContext.parserState.onVideoSample(trackNumber, sample);
354
+ }
337
355
  }
338
- if (codec.codec.startsWith('A_')) {
339
- const vorbisRemaining = length - (iterator.counter.getOffset() - start);
356
+ if (codec.startsWith('A_')) {
340
357
  await parserContext.parserState.onAudioSample(trackNumber, {
341
- data: iterator.getSlice(vorbisRemaining),
342
- offset: timecode,
358
+ data: iterator.getSlice(remainingNow),
343
359
  trackId: trackNumber,
344
- timestamp: timecode,
360
+ timestamp: timecodeInMicroseconds,
345
361
  type: 'key',
346
362
  });
347
363
  }
@@ -350,18 +366,17 @@ const parseSimpleBlockSegment = async ({ iterator, length, parserContext, }) =>
350
366
  iterator.discard(remainingNowAfter);
351
367
  }
352
368
  return {
353
- type: 'simple-block-segment',
369
+ type: 'simple-block-or-block-segment',
354
370
  length,
355
371
  trackNumber,
356
- timecode,
357
- headerFlags,
372
+ timecodeInMicroseconds,
358
373
  keyframe,
359
- lacing: [pos6, pos7],
374
+ lacing,
360
375
  invisible,
361
- children,
376
+ videoSample,
362
377
  };
363
378
  };
364
- exports.parseSimpleBlockSegment = parseSimpleBlockSegment;
379
+ exports.parseSimpleBlockOrBlockSegment = parseSimpleBlockOrBlockSegment;
365
380
  const parseTrackNumber = (iterator, length) => {
366
381
  if (length !== 1) {
367
382
  throw new Error('Expected track number to be 1 byte');
@@ -390,6 +405,31 @@ const parseBlockGroupSegment = async (iterator, length, parserContext) => {
390
405
  };
391
406
  };
392
407
  exports.parseBlockGroupSegment = parseBlockGroupSegment;
408
+ const parseReferenceBlockSegment = (iterator, length) => {
409
+ if (length > 4) {
410
+ throw new Error(`Expected reference block segment to be 4 bytes, but got ${length}`);
411
+ }
412
+ const referenceBlock = length === 4
413
+ ? iterator.getUint32()
414
+ : length === 3
415
+ ? iterator.getUint24()
416
+ : length === 2
417
+ ? iterator.getUint16()
418
+ : iterator.getUint8();
419
+ return {
420
+ type: 'reference-block-segment',
421
+ referenceBlock,
422
+ };
423
+ };
424
+ exports.parseReferenceBlockSegment = parseReferenceBlockSegment;
425
+ const parseBlockAdditionsSegment = (iterator, length) => {
426
+ const blockAdditions = iterator.getSlice(length);
427
+ return {
428
+ type: 'block-additions-segment',
429
+ blockAdditions,
430
+ };
431
+ };
432
+ exports.parseBlockAdditionsSegment = parseBlockAdditionsSegment;
393
433
  const parseBlockElementSegment = (iterator, length) => {
394
434
  iterator.discard(length);
395
435
  return {
@@ -1,6 +1,7 @@
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 type { PossibleEbml } from './segments/all-segments';
4
5
  import type { DurationSegment } from './segments/duration';
5
6
  import type { InfoSegment } from './segments/info';
6
7
  import { type MainSegment } from './segments/main';
@@ -10,11 +11,10 @@ import { type SeekSegment } from './segments/seek';
10
11
  import type { SeekHeadSegment } from './segments/seek-head';
11
12
  import { type SeekPositionSegment } from './segments/seek-position';
12
13
  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';
14
+ 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
15
  import type { TracksSegment } from './segments/tracks';
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 | 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 | PossibleEbml;
19
19
  export type OnTrackEntrySegment = (trackEntry: TrackEntrySegment) => void;
20
20
  export declare const expectSegment: (iterator: BufferIterator, parserContext: ParserContext) => Promise<ParseResult>;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.expectSegment = void 0;
4
4
  const add_new_matroska_tracks_1 = require("../../add-new-matroska-tracks");
5
5
  const get_track_1 = require("./get-track");
6
+ const parse_ebml_1 = require("./parse-ebml");
6
7
  const all_segments_1 = require("./segments/all-segments");
7
8
  const duration_1 = require("./segments/duration");
8
9
  const info_1 = require("./segments/info");
@@ -14,33 +15,17 @@ const seek_position_1 = require("./segments/seek-position");
14
15
  const timestamp_scale_1 = require("./segments/timestamp-scale");
15
16
  const track_entry_1 = require("./segments/track-entry");
16
17
  const tracks_1 = require("./segments/tracks");
17
- const unknown_1 = require("./segments/unknown");
18
18
  const void_1 = require("./segments/void");
19
19
  const writing_1 = require("./segments/writing");
20
- const parseSegment = async ({ segmentId, iterator, length, parserContext, }) => {
20
+ const parseSegment = async ({ segmentId, iterator, length, parserContext, headerReadSoFar, }) => {
21
21
  if (length === 0) {
22
22
  throw new Error(`Expected length of ${segmentId} to be greater than 0`);
23
23
  }
24
- if (segmentId === '0x') {
25
- return {
26
- type: 'unknown-segment',
27
- id: segmentId,
28
- };
29
- }
30
- // Log this to debug
31
- /*
32
- console.log(
33
- 'segmentId',
34
- segmentId,
35
- getSegmentName(segmentId),
36
- iterator.counter.getOffset(),
37
- );
38
- */
39
24
  if (segmentId === '0x114d9b74') {
40
25
  return (0, seek_head_1.parseSeekHeadSegment)(iterator, length, parserContext);
41
26
  }
42
27
  if (segmentId === '0x53ab') {
43
- return (0, seek_1.parseSeekIdSegment)(iterator);
28
+ return (0, seek_1.parseSeekIdSegment)(iterator, length);
44
29
  }
45
30
  if (segmentId === '0x4dbb') {
46
31
  return (0, seek_1.parseSeekSegment)(iterator, length, parserContext);
@@ -168,30 +153,57 @@ const parseSegment = async ({ segmentId, iterator, length, parserContext, }) =>
168
153
  if (segmentId === all_segments_1.matroskaElements.BitDepth) {
169
154
  return (0, track_entry_1.parseBitDepthSegment)(iterator, length);
170
155
  }
171
- if (segmentId === '0xe7') {
172
- return (0, track_entry_1.parseTimestampSegment)(iterator, length);
156
+ if (segmentId === all_segments_1.matroskaElements.Timestamp) {
157
+ const offset = iterator.counter.getOffset();
158
+ const timestampSegment = (0, track_entry_1.parseTimestampSegment)(iterator, length);
159
+ parserContext.parserState.setTimestampOffset(offset, timestampSegment.timestamp);
160
+ return timestampSegment;
173
161
  }
174
- if (segmentId === '0xa3') {
175
- return (0, track_entry_1.parseSimpleBlockSegment)({
162
+ if (segmentId === all_segments_1.matroskaElements.SimpleBlock ||
163
+ segmentId === all_segments_1.matroskaElements.Block) {
164
+ return (0, track_entry_1.parseSimpleBlockOrBlockSegment)({
176
165
  iterator,
177
166
  length,
178
167
  parserContext,
168
+ type: segmentId,
179
169
  });
180
170
  }
171
+ if (segmentId === all_segments_1.matroskaElements.ReferenceBlock) {
172
+ return (0, track_entry_1.parseReferenceBlockSegment)(iterator, length);
173
+ }
174
+ if (segmentId === all_segments_1.matroskaElements.BlockAdditions) {
175
+ return (0, track_entry_1.parseBlockAdditionsSegment)(iterator, length);
176
+ }
181
177
  if (segmentId === '0xa0') {
182
- return (0, track_entry_1.parseBlockGroupSegment)(iterator, length, parserContext);
178
+ const blockGroup = await (0, track_entry_1.parseBlockGroupSegment)(iterator, length, parserContext);
179
+ // Blocks don't have information about keyframes.
180
+ // https://ffmpeg.org/pipermail/ffmpeg-devel/2015-June/173825.html
181
+ // "For Blocks, keyframes is
182
+ // inferred by the absence of ReferenceBlock element (as done by matroskadec).""
183
+ const block = blockGroup.children.find((c) => c.type === 'simple-block-or-block-segment');
184
+ if (!block || block.type !== 'simple-block-or-block-segment') {
185
+ throw new Error('Expected block segment');
186
+ }
187
+ const hasReferenceBlock = blockGroup.children.find((c) => c.type === 'reference-block-segment');
188
+ const partialVideoSample = block.videoSample;
189
+ if (partialVideoSample) {
190
+ const completeFrame = {
191
+ ...partialVideoSample,
192
+ type: hasReferenceBlock ? 'delta' : 'key',
193
+ };
194
+ await parserContext.parserState.onVideoSample(partialVideoSample.trackId, completeFrame);
195
+ }
196
+ return blockGroup;
183
197
  }
184
198
  if (segmentId === '0xa1') {
185
199
  return (0, track_entry_1.parseBlockElementSegment)(iterator, length);
186
200
  }
187
- const bytesRemaining = iterator.byteLength() - iterator.counter.getOffset();
188
- const toDiscard = Math.min(bytesRemaining, length > 0 ? length : bytesRemaining);
189
- const child = (0, unknown_1.parseUnknownSegment)(iterator, segmentId, toDiscard);
190
- return child;
201
+ iterator.counter.decrement(headerReadSoFar);
202
+ return (0, parse_ebml_1.parseEbml)(iterator);
191
203
  };
192
204
  const expectSegment = async (iterator, parserContext) => {
193
- const bytesRemaining_ = iterator.bytesRemaining();
194
- if (bytesRemaining_ === 0) {
205
+ const offset = iterator.counter.getOffset();
206
+ if (iterator.bytesRemaining() === 0) {
195
207
  return {
196
208
  status: 'incomplete',
197
209
  segments: [],
@@ -201,9 +213,30 @@ const expectSegment = async (iterator, parserContext) => {
201
213
  skipTo: null,
202
214
  };
203
215
  }
204
- const offset = iterator.counter.getOffset();
205
216
  const segmentId = iterator.getMatroskaSegmentId();
217
+ if (segmentId === null) {
218
+ iterator.counter.decrement(iterator.counter.getOffset() - offset);
219
+ return {
220
+ status: 'incomplete',
221
+ segments: [],
222
+ continueParsing: () => {
223
+ return Promise.resolve((0, exports.expectSegment)(iterator, parserContext));
224
+ },
225
+ skipTo: null,
226
+ };
227
+ }
206
228
  const length = iterator.getVint();
229
+ if (length === null) {
230
+ iterator.counter.decrement(iterator.counter.getOffset() - offset);
231
+ return {
232
+ status: 'incomplete',
233
+ segments: [],
234
+ continueParsing: () => {
235
+ return Promise.resolve((0, exports.expectSegment)(iterator, parserContext));
236
+ },
237
+ skipTo: null,
238
+ };
239
+ }
207
240
  const bytesRemainingNow = iterator.byteLength() - iterator.counter.getOffset();
208
241
  if (segmentId === '0x18538067' || segmentId === '0x1f43b675') {
209
242
  const main = await (0, parse_children_1.expectChildren)({
@@ -251,6 +284,7 @@ const expectSegment = async (iterator, parserContext) => {
251
284
  iterator,
252
285
  length,
253
286
  parserContext,
287
+ headerReadSoFar: iterator.counter.getOffset() - offset,
254
288
  });
255
289
  return {
256
290
  status: 'done',
@@ -4,4 +4,5 @@ import type { CodecSegment, TrackEntrySegment } from './segments/track-entry';
4
4
  export declare const getMainSegment: (segments: AnySegment[]) => MainSegment | null;
5
5
  export declare const getTrackNumber: (track: TrackEntrySegment) => number | null;
6
6
  export declare const getTrackCodec: (track: TrackEntrySegment) => CodecSegment | null;
7
+ export declare const getTrackTimestampScale: (track: TrackEntrySegment) => number | null;
7
8
  export declare const getTrackByNumber: (tracks: TrackEntrySegment[], id: number) => TrackEntrySegment | undefined;