@remotion/media-parser 4.0.206 → 4.0.207

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 (69) hide show
  1. package/dist/boxes/iso-base-media/stsd/ctts.js +8 -1
  2. package/dist/boxes/iso-base-media/stsd/samples.d.ts +6 -3
  3. package/dist/boxes/iso-base-media/stsd/samples.js +6 -6
  4. package/dist/boxes/webm/ebml.d.ts +1 -1
  5. package/dist/boxes/webm/make-header.d.ts +6 -2
  6. package/dist/boxes/webm/make-header.js +102 -18
  7. package/dist/boxes/webm/parse-ebml.js +3 -1
  8. package/dist/boxes/webm/segments/all-segments.d.ts +70 -12
  9. package/dist/boxes/webm/segments/all-segments.js +43 -5
  10. package/dist/create/cluster-segment.d.ts +10 -0
  11. package/dist/create/cluster-segment.js +41 -0
  12. package/dist/create/create-media.d.ts +13 -0
  13. package/dist/create/create-media.js +108 -0
  14. package/dist/create/matroska-header.d.ts +1 -0
  15. package/dist/create/matroska-header.js +66 -0
  16. package/dist/create/matroska-info.d.ts +4 -0
  17. package/dist/create/matroska-info.js +41 -0
  18. package/dist/create/matroska-segment.d.ts +2 -0
  19. package/dist/create/matroska-segment.js +12 -0
  20. package/dist/create/matroska-trackentry.d.ts +32 -0
  21. package/dist/create/matroska-trackentry.js +266 -0
  22. package/dist/get-audio-codec.d.ts +1 -1
  23. package/dist/index.d.ts +5 -0
  24. package/dist/index.js +5 -1
  25. package/dist/options.d.ts +1 -1
  26. package/dist/parse-media.js +1 -1
  27. package/dist/readers/from-fetch.d.ts +2 -0
  28. package/dist/readers/from-fetch.js +64 -0
  29. package/dist/readers/from-node.d.ts +2 -0
  30. package/dist/readers/from-node.js +40 -0
  31. package/dist/readers/from-web-file.d.ts +2 -0
  32. package/dist/readers/from-web-file.js +39 -0
  33. package/dist/readers/reader.d.ts +11 -0
  34. package/dist/readers/reader.js +2 -0
  35. package/dist/traversal.d.ts +1 -1
  36. package/dist/writers/web-fs.d.ts +2 -0
  37. package/dist/writers/web-fs.js +44 -0
  38. package/dist/writers/writer.d.ts +11 -0
  39. package/dist/writers/writer.js +2 -0
  40. package/package.json +13 -8
  41. package/src/boxes/iso-base-media/stsd/ctts.ts +10 -1
  42. package/src/boxes/iso-base-media/stsd/samples.ts +12 -9
  43. package/src/boxes/webm/make-header.ts +132 -24
  44. package/src/boxes/webm/parse-ebml.ts +4 -1
  45. package/src/boxes/webm/segments/all-segments.ts +67 -7
  46. package/src/create/cluster-segment.ts +62 -0
  47. package/src/create/create-media.ts +172 -0
  48. package/src/create/matroska-header.ts +63 -0
  49. package/src/create/matroska-info.ts +46 -0
  50. package/src/create/matroska-segment.ts +10 -0
  51. package/src/create/matroska-trackentry.ts +325 -0
  52. package/src/index.ts +9 -0
  53. package/src/options.ts +1 -1
  54. package/src/parse-media.ts +1 -1
  55. package/src/test/av1.test.ts +1 -1
  56. package/src/test/create-matroska.test.ts +31 -6
  57. package/src/test/duration.test.ts +1 -1
  58. package/src/test/matroska.test.ts +35 -5
  59. package/src/test/parse-video.test.ts +1 -1
  60. package/src/test/parse-webm.test.ts +1 -1
  61. package/src/test/stream-local.test.ts +1 -1
  62. package/src/test/stream-samples.test.ts +1 -1
  63. package/src/writers/web-fs.ts +50 -0
  64. package/src/writers/writer.ts +12 -0
  65. package/tsconfig.tsbuildinfo +1 -1
  66. /package/src/{from-fetch.ts → readers/from-fetch.ts} +0 -0
  67. /package/src/{from-node.ts → readers/from-node.ts} +0 -0
  68. /package/src/{from-web-file.ts → readers/from-web-file.ts} +0 -0
  69. /package/src/{reader.ts → readers/reader.ts} +0 -0
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nodeReader = void 0;
4
+ const fs_1 = require("fs");
5
+ const promises_1 = require("node:fs/promises");
6
+ const stream_1 = require("stream");
7
+ exports.nodeReader = {
8
+ read: async (src, range, signal) => {
9
+ if (typeof src !== 'string') {
10
+ throw new Error('src must be a string when using `nodeReader`');
11
+ }
12
+ const stream = (0, fs_1.createReadStream)(src, {
13
+ start: range === null ? 0 : typeof range === 'number' ? range : range[0],
14
+ end: range === null
15
+ ? Infinity
16
+ : typeof range === 'number'
17
+ ? Infinity
18
+ : range[1],
19
+ signal,
20
+ });
21
+ const stats = await (0, promises_1.stat)(src);
22
+ const reader = stream_1.Readable.toWeb(stream).getReader();
23
+ if (signal) {
24
+ signal.addEventListener('abort', () => {
25
+ reader.cancel();
26
+ }, { once: true });
27
+ }
28
+ return {
29
+ reader,
30
+ contentLength: stats.size,
31
+ };
32
+ },
33
+ getLength: async (src) => {
34
+ if (typeof src !== 'string') {
35
+ throw new Error('src must be a string when using `nodeReader`');
36
+ }
37
+ const stats = await (0, promises_1.stat)(src);
38
+ return stats.size;
39
+ },
40
+ };
@@ -0,0 +1,2 @@
1
+ import type { ReaderInterface } from './reader';
2
+ export declare const webFileReader: ReaderInterface;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.webFileReader = void 0;
4
+ exports.webFileReader = {
5
+ read: (file, range, signal) => {
6
+ if (typeof file === 'string') {
7
+ throw new Error('`inputTypeFileReader` only supports `File` objects');
8
+ }
9
+ const part = range === null
10
+ ? file
11
+ : typeof range === 'number'
12
+ ? file.slice(range)
13
+ : file.slice(range[0], range[1]);
14
+ const reader = new FileReader();
15
+ reader.readAsArrayBuffer(file);
16
+ if (signal) {
17
+ signal.addEventListener('abort', () => {
18
+ reader.abort();
19
+ }, { once: true });
20
+ }
21
+ return new Promise((resolve, reject) => {
22
+ reader.onload = () => {
23
+ resolve({
24
+ reader: part.stream().getReader(),
25
+ contentLength: file.size,
26
+ });
27
+ };
28
+ reader.onerror = (error) => {
29
+ reject(error);
30
+ };
31
+ });
32
+ },
33
+ getLength: (src) => {
34
+ if (typeof src === 'string') {
35
+ throw new Error('`inputTypeFileReader` only supports `File` objects');
36
+ }
37
+ return Promise.resolve(src.size);
38
+ },
39
+ };
@@ -0,0 +1,11 @@
1
+ type ReadResult = {
2
+ reader: ReadableStreamDefaultReader<Uint8Array>;
3
+ contentLength: number | null;
4
+ };
5
+ type ReadContent = (src: string | File, range: [number, number] | number | null, signal: AbortSignal | undefined) => Promise<ReadResult>;
6
+ type GetLength = (src: string | File) => Promise<number>;
7
+ export type ReaderInterface = {
8
+ read: ReadContent;
9
+ getLength: GetLength;
10
+ };
11
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -40,7 +40,7 @@ export declare const getClusterSegment: (segment: MainSegment) => ClusterSegment
40
40
  export declare const getTracksSegment: (segment: MainSegment) => {
41
41
  type: "Tracks";
42
42
  value: import("./boxes/webm/segments/all-segments").PossibleEbml[];
43
- minVintWidth: number;
43
+ minVintWidth: number | null;
44
44
  } | null;
45
45
  export declare const getTimescaleSegment: (segment: MainSegment) => TimestampScaleSegment | null;
46
46
  export declare const getVideoSegment: (track: TrackEntry) => VideoSegment | null;
@@ -0,0 +1,2 @@
1
+ import type { WriterInterface } from './writer';
2
+ export declare const webFsWriter: WriterInterface;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.webFsWriter = void 0;
4
+ const createContent = async () => {
5
+ const directoryHandle = await navigator.storage.getDirectory();
6
+ const filename = `media-parser-${Math.random().toString().replace('0.', '')}.webm`;
7
+ const fileHandle = await directoryHandle.getFileHandle(filename, {
8
+ create: true,
9
+ });
10
+ const writable = await fileHandle.createWritable();
11
+ let written = 0;
12
+ const writer = {
13
+ write: async (arr) => {
14
+ await writable.write(arr);
15
+ written += arr.byteLength;
16
+ },
17
+ save: async () => {
18
+ await writable.close();
19
+ const picker = await window.showSaveFilePicker({
20
+ suggestedName: `${Math.random().toString().replace('.', '')}.webm`,
21
+ });
22
+ const newHandle = await directoryHandle.getFileHandle(filename, {
23
+ create: true,
24
+ });
25
+ const newFile = await newHandle.getFile();
26
+ const pickerWriteable = await picker.createWritable();
27
+ const stream = newFile.stream();
28
+ await stream.pipeTo(pickerWriteable);
29
+ await directoryHandle.removeEntry(filename, {
30
+ recursive: true,
31
+ });
32
+ },
33
+ getWrittenByteCount: () => written,
34
+ updateDataAt: async (position, vint) => {
35
+ await writable.seek(position);
36
+ await writable.write(vint);
37
+ await writable.seek(written);
38
+ },
39
+ };
40
+ return writer;
41
+ };
42
+ exports.webFsWriter = {
43
+ createContent,
44
+ };
@@ -0,0 +1,11 @@
1
+ export type Writer = {
2
+ write: (arr: Uint8Array) => Promise<void>;
3
+ save: () => Promise<void>;
4
+ getWrittenByteCount: () => number;
5
+ updateDataAt: (position: number, vint: Uint8Array) => Promise<void>;
6
+ };
7
+ type CreateContent = () => Promise<Writer>;
8
+ export type WriterInterface = {
9
+ createContent: CreateContent;
10
+ };
11
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -3,11 +3,12 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/media-parser"
4
4
  },
5
5
  "name": "@remotion/media-parser",
6
- "version": "4.0.206",
6
+ "version": "4.0.207",
7
7
  "main": "dist/index.js",
8
8
  "sideEffects": false,
9
9
  "devDependencies": {
10
- "@remotion/renderer": "4.0.206"
10
+ "@types/wicg-file-system-access": "2023.10.5",
11
+ "@remotion/renderer": "4.0.207"
11
12
  },
12
13
  "publishConfig": {
13
14
  "access": "public"
@@ -17,21 +18,25 @@
17
18
  },
18
19
  "exports": {
19
20
  ".": "./dist/index.js",
20
- "./node": "./dist/from-node.js",
21
- "./fetch": "./dist/from-fetch.js",
22
- "./web-file": "./dist/from-web-file.js",
21
+ "./node": "./dist/readers/from-node.js",
22
+ "./fetch": "./dist/readers/from-fetch.js",
23
+ "./web-file": "./dist/readers/from-web-file.js",
24
+ "./web-fs": "./dist/writers/web-fs.js",
23
25
  "./package.json": "./package.json"
24
26
  },
25
27
  "typesVersions": {
26
28
  ">=1.0": {
27
29
  "node": [
28
- "dist/from-node.d.ts"
30
+ "dist/readers/from-node.d.ts"
29
31
  ],
30
32
  "fetch": [
31
- "dist/from-fetch.d.ts"
33
+ "dist/readers/from-fetch.d.ts"
32
34
  ],
33
35
  "web-file": [
34
- "dist/from-web-file.d.ts"
36
+ "dist/readers/from-web-file.d.ts"
37
+ ],
38
+ "web-fs": [
39
+ "dist/writers/web-fs.d.ts"
35
40
  ]
36
41
  }
37
42
  },
@@ -24,7 +24,7 @@ export const parseCtts = ({
24
24
  size: number;
25
25
  }): CttsBox => {
26
26
  const version = iterator.getUint8();
27
- if (version !== 0) {
27
+ if (version !== 0 && version !== 1) {
28
28
  throw new Error(`Unsupported CTTS version ${version}`);
29
29
  }
30
30
 
@@ -35,7 +35,16 @@ export const parseCtts = ({
35
35
 
36
36
  for (let i = 0; i < entryCount; i++) {
37
37
  const sampleCount = iterator.getUint32();
38
+
39
+ // V1 = signed, V0 = unsigned
40
+ // however some files are buggy
41
+
42
+ // Let's do the same thing as mp4box but uint32, based on our test set of videos
43
+ // https://github.com/gpac/mp4box.js/blob/c6cc468145bc5b031b866446111f29c8b620dbe6/src/parsing/ctts.js#L2
38
44
  const sampleOffset = iterator.getUint32();
45
+ if (sampleOffset < 0) {
46
+ throw new Error('ctts box uses negative values without using version 1');
47
+ }
39
48
 
40
49
  entries.push({
41
50
  sampleCount,
@@ -7,9 +7,6 @@ type SampleBase = {
7
7
  format: string;
8
8
  offset: number;
9
9
  dataReferenceIndex: number;
10
- version: number;
11
- revisionLevel: number;
12
- vendor: number[];
13
10
  size: number;
14
11
  };
15
12
 
@@ -25,6 +22,9 @@ export type AudioSample = SampleBase & {
25
22
  bytesPerFrame: number | null;
26
23
  bitsPerSample: number | null;
27
24
  children: AnySegment[];
25
+ version: number;
26
+ revisionLevel: number;
27
+ vendor: number[];
28
28
  };
29
29
 
30
30
  export type VideoSample = SampleBase & {
@@ -41,6 +41,9 @@ export type VideoSample = SampleBase & {
41
41
  depth: number;
42
42
  colorTableId: number;
43
43
  descriptors: AnySegment[];
44
+ version: number;
45
+ revisionLevel: number;
46
+ vendor: number[];
44
47
  };
45
48
 
46
49
  type UnknownSample = SampleBase & {
@@ -139,9 +142,6 @@ export const processSample = async ({
139
142
  iterator.discard(6);
140
143
 
141
144
  const dataReferenceIndex = iterator.getUint16();
142
- const version = iterator.getUint16();
143
- const revisionLevel = iterator.getUint16();
144
- const vendor = iterator.getSlice(4);
145
145
 
146
146
  if (!isVideo && !isAudio) {
147
147
  const bytesRemainingInBox =
@@ -153,9 +153,6 @@ export const processSample = async ({
153
153
  type: 'unknown',
154
154
  offset: fileOffset,
155
155
  dataReferenceIndex,
156
- version,
157
- revisionLevel,
158
- vendor: [...Array.from(new Uint8Array(vendor))],
159
156
  size: boxSize,
160
157
  format: boxFormat,
161
158
  },
@@ -163,6 +160,9 @@ export const processSample = async ({
163
160
  }
164
161
 
165
162
  if (isAudio) {
163
+ const version = iterator.getUint16();
164
+ const revisionLevel = iterator.getUint16();
165
+ const vendor = iterator.getSlice(4);
166
166
  if (version === 0) {
167
167
  const numberOfChannels = iterator.getUint16();
168
168
  const sampleSize = iterator.getUint16();
@@ -268,6 +268,9 @@ export const processSample = async ({
268
268
  }
269
269
 
270
270
  if (isVideo) {
271
+ const version = iterator.getUint16();
272
+ const revisionLevel = iterator.getUint16();
273
+ const vendor = iterator.getSlice(4);
271
274
  const temporalQuality = iterator.getUint32();
272
275
  const spacialQuality = iterator.getUint32();
273
276
  const width = iterator.getUint16();
@@ -1,16 +1,22 @@
1
1
  import {getVariableInt} from './ebml';
2
2
  import type {
3
+ BytesAndOffset,
3
4
  FloatWithSize,
5
+ OffsetAndChildren,
4
6
  PossibleEbml,
5
7
  PossibleEbmlOrUint8Array,
6
8
  UintWithSize,
9
+ } from './segments/all-segments';
10
+ import {
11
+ ebmlMap,
12
+ getIdForName,
13
+ incrementOffsetAndChildren,
7
14
  matroskaElements,
8
15
  } from './segments/all-segments';
9
- import {ebmlMap, getIdForName} from './segments/all-segments';
10
16
 
11
17
  export const webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
12
18
 
13
- const matroskaToHex = (
19
+ export const matroskaToHex = (
14
20
  matrId: (typeof matroskaElements)[keyof typeof matroskaElements],
15
21
  ) => {
16
22
  const numbers: Uint8Array = new Uint8Array((matrId.length - 2) / 2);
@@ -45,10 +51,10 @@ function putUintDynamic(number: number, minimumLength: number | null) {
45
51
  return bytes;
46
52
  }
47
53
 
48
- const makeFromHeaderStructure = (
54
+ const makeFromStructure = (
49
55
  fields: PossibleEbmlOrUint8Array,
50
- ): Uint8Array => {
51
- if (fields instanceof Uint8Array) {
56
+ ): BytesAndOffset => {
57
+ if ('bytes' in fields) {
52
58
  return fields;
53
59
  }
54
60
 
@@ -57,26 +63,51 @@ const makeFromHeaderStructure = (
57
63
  const struct = ebmlMap[getIdForName(fields.type)];
58
64
 
59
65
  if (struct.type === 'uint8array') {
60
- return fields.value as Uint8Array;
66
+ return {
67
+ bytes: fields.value as Uint8Array,
68
+ offsets: {offset: 0, children: [], field: fields.type},
69
+ };
61
70
  }
62
71
 
63
72
  if (struct.type === 'children') {
73
+ const children: OffsetAndChildren[] = [];
74
+ let bytesWritten = 0;
64
75
  for (const item of fields.value as PossibleEbml[]) {
65
- arrays.push(makeMatroskaBytes(item));
76
+ const {bytes, offsets} = makeMatroskaBytes(item);
77
+ arrays.push(bytes);
78
+ children.push(incrementOffsetAndChildren(offsets, bytesWritten));
79
+ bytesWritten += bytes.byteLength;
66
80
  }
67
81
 
68
- return combineUint8Arrays(arrays);
82
+ return {
83
+ bytes: combineUint8Arrays(arrays),
84
+ offsets: {offset: 0, children, field: fields.type},
85
+ };
69
86
  }
70
87
 
71
88
  if (struct.type === 'string') {
72
- return new TextEncoder().encode(fields.value as string);
89
+ return {
90
+ bytes: new TextEncoder().encode(fields.value as string),
91
+ offsets: {
92
+ children: [],
93
+ offset: 0,
94
+ field: fields.type,
95
+ },
96
+ };
73
97
  }
74
98
 
75
99
  if (struct.type === 'uint') {
76
- return putUintDynamic(
77
- (fields.value as UintWithSize).value,
78
- (fields.value as UintWithSize).byteLength,
79
- );
100
+ return {
101
+ bytes: putUintDynamic(
102
+ (fields.value as UintWithSize).value,
103
+ (fields.value as UintWithSize).byteLength,
104
+ ),
105
+ offsets: {
106
+ children: [],
107
+ offset: 0,
108
+ field: fields.type,
109
+ },
110
+ };
80
111
  }
81
112
 
82
113
  if (struct.type === 'hex-string') {
@@ -87,7 +118,14 @@ const makeFromHeaderStructure = (
87
118
  arr[i / 2] = byte;
88
119
  }
89
120
 
90
- return arr;
121
+ return {
122
+ bytes: arr,
123
+ offsets: {
124
+ children: [],
125
+ offset: 0,
126
+ field: fields.type,
127
+ },
128
+ };
91
129
  }
92
130
 
93
131
  if (struct.type === 'float') {
@@ -95,29 +133,89 @@ const makeFromHeaderStructure = (
95
133
  if (value.size === '32') {
96
134
  const dataView = new DataView(new ArrayBuffer(4));
97
135
  dataView.setFloat32(0, value.value);
98
- return new Uint8Array(dataView.buffer);
136
+ return {
137
+ bytes: new Uint8Array(dataView.buffer),
138
+ offsets: {
139
+ children: [],
140
+ offset: 0,
141
+ field: fields.type,
142
+ },
143
+ };
99
144
  }
100
145
 
101
146
  const dataView2 = new DataView(new ArrayBuffer(8));
102
147
  dataView2.setFloat64(0, value.value);
103
- return new Uint8Array(dataView2.buffer);
148
+ return {
149
+ bytes: new Uint8Array(dataView2.buffer),
150
+ offsets: {
151
+ children: [],
152
+ offset: 0,
153
+ field: fields.type,
154
+ },
155
+ };
104
156
  }
105
157
 
106
158
  throw new Error('Unexpected type');
107
159
  };
108
160
 
109
- export const makeMatroskaBytes = (fields: PossibleEbmlOrUint8Array) => {
110
- if (fields instanceof Uint8Array) {
161
+ export const makeMatroskaBytes = (
162
+ fields: PossibleEbmlOrUint8Array,
163
+ ): BytesAndOffset => {
164
+ if ('bytes' in fields) {
111
165
  return fields;
112
166
  }
113
167
 
114
- const value = makeFromHeaderStructure(fields);
168
+ const value = makeFromStructure(fields);
169
+ const header = matroskaToHex(getIdForName(fields.type));
170
+ const size = getVariableInt(value.bytes.length, fields.minVintWidth);
171
+
172
+ const bytes = combineUint8Arrays([header, size, value.bytes]);
173
+
174
+ return {
175
+ bytes,
176
+ offsets: {
177
+ offset: value.offsets.offset,
178
+ field: value.offsets.field,
179
+ children: value.offsets.children.map((c) => {
180
+ return incrementOffsetAndChildren(
181
+ c,
182
+ header.byteLength + size.byteLength,
183
+ );
184
+ }),
185
+ },
186
+ };
187
+ };
188
+
189
+ export const padMatroskaBytes = (
190
+ fields: PossibleEbmlOrUint8Array,
191
+ totalLength: number,
192
+ ): BytesAndOffset[] => {
193
+ const regular = makeMatroskaBytes(fields);
194
+ const paddingLength =
195
+ totalLength -
196
+ regular.bytes.byteLength -
197
+ matroskaToHex(matroskaElements.Void).byteLength;
198
+
199
+ if (paddingLength < 0) {
200
+ throw new Error('ooops');
201
+ }
115
202
 
116
- return combineUint8Arrays([
117
- matroskaToHex(getIdForName(fields.type)),
118
- getVariableInt(value.length, fields.minVintWidth),
119
- value,
120
- ]);
203
+ const padding = makeMatroskaBytes({
204
+ type: 'Void',
205
+ value: new Uint8Array(paddingLength).fill(0),
206
+ minVintWidth: null,
207
+ });
208
+
209
+ return [
210
+ regular,
211
+ {
212
+ bytes: padding.bytes,
213
+ offsets: incrementOffsetAndChildren(
214
+ padding.offsets,
215
+ regular.bytes.length,
216
+ ),
217
+ },
218
+ ];
121
219
  };
122
220
 
123
221
  export const combineUint8Arrays = (arrays: Uint8Array[]) => {
@@ -143,3 +241,13 @@ export const combineUint8Arrays = (arrays: Uint8Array[]) => {
143
241
 
144
242
  return result;
145
243
  };
244
+
245
+ export function serializeUint16(value: number): Uint8Array {
246
+ const buffer = new ArrayBuffer(2);
247
+
248
+ const view = new DataView(buffer);
249
+
250
+ view.setUint16(0, value);
251
+
252
+ return new Uint8Array(buffer);
253
+ }
@@ -43,8 +43,11 @@ export const parseEbml = async (
43
43
  const beforeUintOffset = iterator.counter.getOffset();
44
44
  const value = size === 0 ? 0 : iterator.getUint(size);
45
45
 
46
+ const {name} = hasInMap;
47
+
46
48
  return {
47
- type: hasInMap.name,
49
+ // To work around TS limit
50
+ type: name as 'SeekPosition',
48
51
  value: {
49
52
  value,
50
53
  byteLength: iterator.counter.getOffset() - beforeUintOffset,
@@ -360,7 +360,7 @@ export const ebmlReadVersion = {
360
360
  export const ebmlMaxIdLength = {
361
361
  name: 'EBMLMaxIDLength',
362
362
  type: 'uint',
363
- } satisfies Ebml;
363
+ } as const satisfies Ebml;
364
364
 
365
365
  export const ebmlMaxSizeLength = {
366
366
  name: 'EBMLMaxSizeLength',
@@ -539,7 +539,37 @@ export const trackUID = {
539
539
 
540
540
  export const color = {
541
541
  name: 'Colour',
542
- type: 'uint8array',
542
+ type: 'children',
543
+ } as const satisfies Ebml;
544
+
545
+ export const transfer = {
546
+ name: 'TransferCharacteristics',
547
+ type: 'uint',
548
+ } as const satisfies Ebml;
549
+
550
+ export const matrix = {
551
+ name: 'MatrixCoefficients',
552
+ type: 'uint',
553
+ } as const satisfies Ebml;
554
+
555
+ export const primaries = {
556
+ name: 'Primaries',
557
+ type: 'uint',
558
+ } as const satisfies Ebml;
559
+
560
+ export const range = {
561
+ name: 'Range',
562
+ type: 'uint',
563
+ } as const satisfies Ebml;
564
+
565
+ export const ChromaSitingHorz = {
566
+ name: 'ChromaSitingHorz',
567
+ type: 'uint',
568
+ } as const satisfies Ebml;
569
+
570
+ export const ChromaSitingVert = {
571
+ name: 'ChromaSitingVert',
572
+ type: 'uint',
543
573
  } as const satisfies Ebml;
544
574
 
545
575
  export const language = {
@@ -579,7 +609,7 @@ export const videoSegment = {
579
609
 
580
610
  export const flagDefault = {
581
611
  name: 'FlagDefault',
582
- type: 'uint8array',
612
+ type: 'uint',
583
613
  } as const satisfies Ebml;
584
614
 
585
615
  export const referenceBlock = {
@@ -661,7 +691,7 @@ export type ClusterSegment = EbmlParsed<typeof cluster>;
661
691
  export type Tracks = EbmlParsed<typeof tracks>;
662
692
 
663
693
  export type FloatWithSize = {value: number; size: '32' | '64'};
664
- export type UintWithSize = {value: number; byteLength: number};
694
+ export type UintWithSize = {value: number; byteLength: number | null};
665
695
 
666
696
  export type EbmlValue<
667
697
  T extends Ebml,
@@ -687,13 +717,13 @@ export type EbmlValueOrUint8Array<T extends Ebml> =
687
717
  export type EbmlParsed<T extends Ebml> = {
688
718
  type: T['name'];
689
719
  value: EbmlValue<T>;
690
- minVintWidth: number;
720
+ minVintWidth: number | null;
691
721
  };
692
722
 
693
723
  export type EbmlParsedOrUint8Array<T extends Ebml> = {
694
724
  type: T['name'];
695
725
  value: EbmlValueOrUint8Array<T>;
696
- minVintWidth: number;
726
+ minVintWidth: number | null;
697
727
  };
698
728
 
699
729
  export const ebmlMap = {
@@ -807,6 +837,12 @@ export const ebmlMap = {
807
837
  name: 'Cluster',
808
838
  type: 'children',
809
839
  },
840
+ [matroskaElements.TransferCharacteristics]: transfer,
841
+ [matroskaElements.MatrixCoefficients]: matrix,
842
+ [matroskaElements.Primaries]: primaries,
843
+ [matroskaElements.Range]: range,
844
+ [matroskaElements.ChromaSitingHorz]: ChromaSitingHorz,
845
+ [matroskaElements.ChromaSitingVert]: ChromaSitingVert,
810
846
  } as const satisfies Partial<Record<MatroskaElement, Ebml>>;
811
847
 
812
848
  export type PossibleEbml = Prettify<
@@ -815,6 +851,30 @@ export type PossibleEbml = Prettify<
815
851
  }[keyof typeof ebmlMap]
816
852
  >;
817
853
 
854
+ export type OffsetAndChildren = {
855
+ offset: number;
856
+ children: OffsetAndChildren[];
857
+ field: keyof typeof matroskaElements;
858
+ };
859
+
860
+ export const incrementOffsetAndChildren = (
861
+ offset: OffsetAndChildren,
862
+ increment: number,
863
+ ): OffsetAndChildren => {
864
+ return {
865
+ offset: offset.offset + increment,
866
+ children: offset.children.map((c) =>
867
+ incrementOffsetAndChildren(c, increment),
868
+ ),
869
+ field: offset.field,
870
+ };
871
+ };
872
+
873
+ export type BytesAndOffset = {
874
+ bytes: Uint8Array;
875
+ offsets: OffsetAndChildren;
876
+ };
877
+
818
878
  export type PossibleEbmlOrUint8Array =
819
879
  | Prettify<
820
880
  {
@@ -823,6 +883,6 @@ export type PossibleEbmlOrUint8Array =
823
883
  >;
824
884
  }[keyof typeof ebmlMap]
825
885
  >
826
- | Uint8Array;
886
+ | BytesAndOffset;
827
887
 
828
888
  export type EbmlMapKey = keyof typeof ebmlMap;