@remotion/media-parser 4.0.206 → 4.0.208

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 (143) hide show
  1. package/dist/av1-codec-string.d.ts +3 -0
  2. package/dist/av1-codec-string.js +91 -0
  3. package/dist/boxes/iso-base-media/ftype.d.ts +9 -0
  4. package/dist/boxes/iso-base-media/ftype.js +31 -0
  5. package/dist/boxes/iso-base-media/stsd/avcc-hvcc.d.ts +20 -0
  6. package/dist/boxes/iso-base-media/stsd/avcc-hvcc.js +73 -0
  7. package/dist/boxes/iso-base-media/stsd/ctts.js +8 -1
  8. package/dist/boxes/iso-base-media/stsd/samples.d.ts +6 -3
  9. package/dist/boxes/iso-base-media/stsd/samples.js +6 -6
  10. package/dist/boxes/iso-base-media/stts/stts.d.ts +15 -0
  11. package/dist/boxes/iso-base-media/stts/stts.js +35 -0
  12. package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.d.ts +14 -0
  13. package/dist/boxes/webm/bitstream/av1/bitstream-frame-header.js +67 -0
  14. package/dist/boxes/webm/bitstream/av1/bitstream-frame.d.ts +11 -0
  15. package/dist/boxes/webm/bitstream/av1/bitstream-frame.js +14 -0
  16. package/dist/boxes/webm/bitstream/av1/chroma-sample-position.d.ts +6 -0
  17. package/dist/boxes/webm/bitstream/av1/chroma-sample-position.js +9 -0
  18. package/dist/boxes/webm/bitstream/av1/color-config.d.ts +16 -0
  19. package/dist/boxes/webm/bitstream/av1/color-config.js +103 -0
  20. package/dist/boxes/webm/bitstream/av1/color-primaries.d.ts +14 -0
  21. package/dist/boxes/webm/bitstream/av1/color-primaries.js +17 -0
  22. package/dist/boxes/webm/bitstream/av1/decoder-model-info.d.ts +9 -0
  23. package/dist/boxes/webm/bitstream/av1/decoder-model-info.js +17 -0
  24. package/dist/boxes/webm/bitstream/av1/frame.d.ts +0 -0
  25. package/dist/boxes/webm/bitstream/av1/frame.js +1 -0
  26. package/dist/boxes/webm/bitstream/av1/header-segment.d.ts +51 -0
  27. package/dist/boxes/webm/bitstream/av1/header-segment.js +183 -0
  28. package/dist/boxes/webm/bitstream/av1/matrix-coefficients.d.ts +17 -0
  29. package/dist/boxes/webm/bitstream/av1/matrix-coefficients.js +20 -0
  30. package/dist/boxes/webm/bitstream/av1/operating-parameters-info.d.ts +10 -0
  31. package/dist/boxes/webm/bitstream/av1/operating-parameters-info.js +15 -0
  32. package/dist/boxes/webm/bitstream/av1/temporal-point-info.d.ts +5 -0
  33. package/dist/boxes/webm/bitstream/av1/temporal-point-info.js +8 -0
  34. package/dist/boxes/webm/bitstream/av1/timing-info.d.ts +8 -0
  35. package/dist/boxes/webm/bitstream/av1/timing-info.js +20 -0
  36. package/dist/boxes/webm/bitstream/av1/transfer-characteristics.d.ts +21 -0
  37. package/dist/boxes/webm/bitstream/av1/transfer-characteristics.js +24 -0
  38. package/dist/boxes/webm/bitstream/av1/uvlc.d.ts +2 -0
  39. package/dist/boxes/webm/bitstream/av1/uvlc.js +20 -0
  40. package/dist/boxes/webm/bitstream/av1.d.ts +20 -0
  41. package/dist/boxes/webm/bitstream/av1.js +118 -0
  42. package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.d.ts +0 -0
  43. package/dist/boxes/webm/bitstream/h264/get-h264-descriptor.js +1 -0
  44. package/dist/boxes/webm/make-header.d.ts +6 -2
  45. package/dist/boxes/webm/make-header.js +102 -18
  46. package/dist/boxes/webm/parse-ebml.js +3 -1
  47. package/dist/boxes/webm/segments/all-segments.d.ts +70 -12
  48. package/dist/boxes/webm/segments/all-segments.js +43 -5
  49. package/dist/boxes/webm/segments/duration.d.ts +6 -0
  50. package/dist/boxes/webm/segments/duration.js +19 -0
  51. package/dist/boxes/webm/segments/info.d.ts +9 -0
  52. package/dist/boxes/webm/segments/info.js +22 -0
  53. package/dist/boxes/webm/segments/main.d.ts +5 -0
  54. package/dist/boxes/webm/segments/main.js +2 -0
  55. package/dist/boxes/webm/segments/muxing.d.ts +6 -0
  56. package/dist/boxes/webm/segments/muxing.js +11 -0
  57. package/dist/boxes/webm/segments/seek-head.d.ts +9 -0
  58. package/dist/boxes/webm/segments/seek-head.js +22 -0
  59. package/dist/boxes/webm/segments/seek-position.d.ts +6 -0
  60. package/dist/boxes/webm/segments/seek-position.js +11 -0
  61. package/dist/boxes/webm/segments/seek.d.ts +13 -0
  62. package/dist/boxes/webm/segments/seek.js +35 -0
  63. package/dist/boxes/webm/segments/timestamp-scale.d.ts +6 -0
  64. package/dist/boxes/webm/segments/timestamp-scale.js +11 -0
  65. package/dist/boxes/webm/segments/tracks.d.ts +8 -0
  66. package/dist/boxes/webm/segments/tracks.js +21 -0
  67. package/dist/boxes/webm/segments/unknown.d.ts +6 -0
  68. package/dist/boxes/webm/segments/unknown.js +11 -0
  69. package/dist/boxes/webm/segments/void.d.ts +6 -0
  70. package/dist/boxes/webm/segments/void.js +11 -0
  71. package/dist/boxes/webm/segments/writing.d.ts +6 -0
  72. package/dist/boxes/webm/segments/writing.js +11 -0
  73. package/dist/boxes/webm/tracks.d.ts +8 -0
  74. package/dist/boxes/webm/tracks.js +21 -0
  75. package/dist/combine-uint8array.d.ts +1 -0
  76. package/dist/combine-uint8array.js +13 -0
  77. package/dist/create/cluster-segment.d.ts +10 -0
  78. package/dist/create/cluster-segment.js +41 -0
  79. package/dist/create/create-media.d.ts +13 -0
  80. package/dist/create/create-media.js +108 -0
  81. package/dist/create/matroska-header.d.ts +1 -0
  82. package/dist/create/matroska-header.js +66 -0
  83. package/dist/create/matroska-info.d.ts +4 -0
  84. package/dist/create/matroska-info.js +41 -0
  85. package/dist/create/matroska-segment.d.ts +2 -0
  86. package/dist/create/matroska-segment.js +12 -0
  87. package/dist/create/matroska-trackentry.d.ts +32 -0
  88. package/dist/create/matroska-trackentry.js +266 -0
  89. package/dist/from-web.d.ts +2 -0
  90. package/dist/from-web.js +45 -0
  91. package/dist/get-video-metadata.d.ts +2 -0
  92. package/dist/get-video-metadata.js +44 -0
  93. package/dist/index.d.ts +5 -0
  94. package/dist/index.js +5 -1
  95. package/dist/options.d.ts +1 -1
  96. package/dist/parse-media.js +1 -1
  97. package/dist/read-and-increment-offset.d.ts +28 -0
  98. package/dist/read-and-increment-offset.js +177 -0
  99. package/dist/readers/from-fetch.d.ts +2 -0
  100. package/dist/readers/from-fetch.js +64 -0
  101. package/dist/readers/from-node.d.ts +2 -0
  102. package/dist/readers/from-node.js +40 -0
  103. package/dist/readers/from-web-file.d.ts +2 -0
  104. package/dist/readers/from-web-file.js +39 -0
  105. package/dist/readers/reader.d.ts +11 -0
  106. package/dist/readers/reader.js +2 -0
  107. package/dist/traversal.d.ts +1 -1
  108. package/dist/understand-vorbis.d.ts +1 -0
  109. package/dist/understand-vorbis.js +12 -0
  110. package/dist/writers/web-fs.d.ts +2 -0
  111. package/dist/writers/web-fs.js +44 -0
  112. package/dist/writers/writer.d.ts +11 -0
  113. package/dist/writers/writer.js +2 -0
  114. package/package.json +13 -8
  115. package/src/boxes/iso-base-media/stsd/ctts.ts +10 -1
  116. package/src/boxes/iso-base-media/stsd/samples.ts +12 -9
  117. package/src/boxes/webm/make-header.ts +132 -24
  118. package/src/boxes/webm/parse-ebml.ts +4 -1
  119. package/src/boxes/webm/segments/all-segments.ts +67 -7
  120. package/src/create/cluster-segment.ts +62 -0
  121. package/src/create/create-media.ts +172 -0
  122. package/src/create/matroska-header.ts +63 -0
  123. package/src/create/matroska-info.ts +46 -0
  124. package/src/create/matroska-segment.ts +10 -0
  125. package/src/create/matroska-trackentry.ts +325 -0
  126. package/src/index.ts +9 -0
  127. package/src/options.ts +1 -1
  128. package/src/parse-media.ts +1 -1
  129. package/src/test/av1.test.ts +1 -1
  130. package/src/test/create-matroska.test.ts +31 -6
  131. package/src/test/duration.test.ts +1 -1
  132. package/src/test/matroska.test.ts +35 -5
  133. package/src/test/parse-video.test.ts +1 -1
  134. package/src/test/parse-webm.test.ts +1 -1
  135. package/src/test/stream-local.test.ts +1 -1
  136. package/src/test/stream-samples.test.ts +1 -1
  137. package/src/writers/web-fs.ts +50 -0
  138. package/src/writers/writer.ts +12 -0
  139. package/tsconfig.tsbuildinfo +1 -1
  140. /package/src/{from-fetch.ts → readers/from-fetch.ts} +0 -0
  141. /package/src/{from-node.ts → readers/from-node.ts} +0 -0
  142. /package/src/{from-web-file.ts → readers/from-web-file.ts} +0 -0
  143. /package/src/{reader.ts → readers/reader.ts} +0 -0
@@ -0,0 +1,2 @@
1
+ import type { ReaderInterface } from './reader';
2
+ export declare const nodeReader: ReaderInterface;
@@ -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 @@
1
+ declare const understand: (src: string) => Promise<void>;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ const understand = async (src) => {
3
+ const content = await Bun.file(src).arrayBuffer();
4
+ const firstBit = new DataView(content).getUint8(0);
5
+ const offset = new DataView(content).getUint8(1);
6
+ const offset2 = new DataView(content).getUint8(2);
7
+ const globalOffset = firstBit + 1;
8
+ const header = new TextDecoder().decode(content.slice(globalOffset, globalOffset + offset));
9
+ const comment = new TextDecoder().decode(content.slice(globalOffset + offset, globalOffset + offset2));
10
+ const rest = new TextDecoder().decode(content.slice(globalOffset + offset2 + offset, globalOffset + offset2 + offset + 50));
11
+ console.log({ firstBit, offset, offset2, header, comment, rest });
12
+ };
@@ -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.208",
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.208"
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,