@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.
- package/dist/boxes/iso-base-media/stsd/ctts.js +8 -1
- package/dist/boxes/iso-base-media/stsd/samples.d.ts +6 -3
- package/dist/boxes/iso-base-media/stsd/samples.js +6 -6
- package/dist/boxes/webm/ebml.d.ts +1 -1
- package/dist/boxes/webm/make-header.d.ts +6 -2
- package/dist/boxes/webm/make-header.js +102 -18
- package/dist/boxes/webm/parse-ebml.js +3 -1
- package/dist/boxes/webm/segments/all-segments.d.ts +70 -12
- package/dist/boxes/webm/segments/all-segments.js +43 -5
- package/dist/create/cluster-segment.d.ts +10 -0
- package/dist/create/cluster-segment.js +41 -0
- package/dist/create/create-media.d.ts +13 -0
- package/dist/create/create-media.js +108 -0
- package/dist/create/matroska-header.d.ts +1 -0
- package/dist/create/matroska-header.js +66 -0
- package/dist/create/matroska-info.d.ts +4 -0
- package/dist/create/matroska-info.js +41 -0
- package/dist/create/matroska-segment.d.ts +2 -0
- package/dist/create/matroska-segment.js +12 -0
- package/dist/create/matroska-trackentry.d.ts +32 -0
- package/dist/create/matroska-trackentry.js +266 -0
- package/dist/get-audio-codec.d.ts +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -1
- package/dist/options.d.ts +1 -1
- package/dist/parse-media.js +1 -1
- package/dist/readers/from-fetch.d.ts +2 -0
- package/dist/readers/from-fetch.js +64 -0
- package/dist/readers/from-node.d.ts +2 -0
- package/dist/readers/from-node.js +40 -0
- package/dist/readers/from-web-file.d.ts +2 -0
- package/dist/readers/from-web-file.js +39 -0
- package/dist/readers/reader.d.ts +11 -0
- package/dist/readers/reader.js +2 -0
- package/dist/traversal.d.ts +1 -1
- package/dist/writers/web-fs.d.ts +2 -0
- package/dist/writers/web-fs.js +44 -0
- package/dist/writers/writer.d.ts +11 -0
- package/dist/writers/writer.js +2 -0
- package/package.json +13 -8
- package/src/boxes/iso-base-media/stsd/ctts.ts +10 -1
- package/src/boxes/iso-base-media/stsd/samples.ts +12 -9
- package/src/boxes/webm/make-header.ts +132 -24
- package/src/boxes/webm/parse-ebml.ts +4 -1
- package/src/boxes/webm/segments/all-segments.ts +67 -7
- package/src/create/cluster-segment.ts +62 -0
- package/src/create/create-media.ts +172 -0
- package/src/create/matroska-header.ts +63 -0
- package/src/create/matroska-info.ts +46 -0
- package/src/create/matroska-segment.ts +10 -0
- package/src/create/matroska-trackentry.ts +325 -0
- package/src/index.ts +9 -0
- package/src/options.ts +1 -1
- package/src/parse-media.ts +1 -1
- package/src/test/av1.test.ts +1 -1
- package/src/test/create-matroska.test.ts +31 -6
- package/src/test/duration.test.ts +1 -1
- package/src/test/matroska.test.ts +35 -5
- package/src/test/parse-video.test.ts +1 -1
- package/src/test/parse-webm.test.ts +1 -1
- package/src/test/stream-local.test.ts +1 -1
- package/src/test/stream-samples.test.ts +1 -1
- package/src/writers/web-fs.ts +50 -0
- package/src/writers/writer.ts +12 -0
- package/tsconfig.tsbuildinfo +1 -1
- /package/src/{from-fetch.ts → readers/from-fetch.ts} +0 -0
- /package/src/{from-node.ts → readers/from-node.ts} +0 -0
- /package/src/{from-web-file.ts → readers/from-web-file.ts} +0 -0
- /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,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 {};
|
package/dist/traversal.d.ts
CHANGED
|
@@ -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,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 {};
|
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.
|
|
6
|
+
"version": "4.0.207",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"devDependencies": {
|
|
10
|
-
"@
|
|
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
|
|
54
|
+
const makeFromStructure = (
|
|
49
55
|
fields: PossibleEbmlOrUint8Array,
|
|
50
|
-
):
|
|
51
|
-
if (
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
77
|
-
(
|
|
78
|
-
|
|
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
|
|
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
|
|
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
|
|
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 = (
|
|
110
|
-
|
|
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 =
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
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: '
|
|
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: '
|
|
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
|
-
|
|
|
886
|
+
| BytesAndOffset;
|
|
827
887
|
|
|
828
888
|
export type EbmlMapKey = keyof typeof ebmlMap;
|