@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.
- package/dist/av1-codec-string.d.ts +5 -0
- package/dist/av1-codec-string.js +18 -1
- package/dist/bitstream/av1.d.ts +2 -0
- package/dist/bitstream/av1.js +12 -0
- package/dist/boxes/iso-base-media/avcc-hvcc.d.ts +20 -0
- package/dist/boxes/iso-base-media/avcc-hvcc.js +73 -0
- package/dist/boxes/iso-base-media/avcc.d.ts +18 -0
- package/dist/boxes/iso-base-media/avcc.js +27 -0
- package/dist/boxes/iso-base-media/esds-descriptors.d.ts +21 -0
- package/dist/boxes/iso-base-media/esds-descriptors.js +62 -0
- package/dist/boxes/iso-base-media/esds.d.ts +15 -0
- package/dist/boxes/iso-base-media/esds.js +27 -0
- package/dist/boxes/iso-base-media/mdat/mdat.js +2 -2
- package/dist/boxes/iso-base-media/moov/moov.js +1 -0
- package/dist/boxes/iso-base-media/process-box.d.ts +4 -2
- package/dist/boxes/iso-base-media/process-box.js +56 -40
- package/dist/boxes/iso-base-media/stsd/mebx.d.ts +2 -1
- package/dist/boxes/iso-base-media/stsd/mebx.js +2 -1
- package/dist/boxes/iso-base-media/stsd/samples.js +3 -0
- package/dist/boxes/iso-base-media/stsd/stco.d.ts +3 -2
- package/dist/boxes/iso-base-media/stsd/stco.js +2 -2
- package/dist/boxes/iso-base-media/trak/trak.js +1 -0
- package/dist/boxes/webm/bitstream/av1.js +10 -1
- package/dist/boxes/webm/ebml.d.ts +2 -0
- package/dist/boxes/webm/ebml.js +72 -0
- package/dist/boxes/webm/make-header.d.ts +9 -0
- package/dist/boxes/webm/make-header.js +79 -0
- package/dist/boxes/webm/parse-ebml.d.ts +7 -0
- package/dist/boxes/webm/parse-ebml.js +66 -0
- package/dist/boxes/webm/parse-webm-header.js +8 -9
- package/dist/boxes/webm/segments/all-segments.d.ts +262 -0
- package/dist/boxes/webm/segments/all-segments.js +130 -1
- package/dist/boxes/webm/segments/block-simple-block-flags.d.ts +9 -0
- package/dist/boxes/webm/segments/block-simple-block-flags.js +38 -0
- package/dist/boxes/webm/segments/seek-position.js +1 -1
- package/dist/boxes/webm/segments/seek.d.ts +1 -1
- package/dist/boxes/webm/segments/seek.js +8 -2
- package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
- package/dist/boxes/webm/segments/track-entry.d.ts +25 -9
- package/dist/boxes/webm/segments/track-entry.js +73 -33
- package/dist/boxes/webm/segments.d.ts +3 -3
- package/dist/boxes/webm/segments.js +64 -30
- package/dist/boxes/webm/traversal.d.ts +1 -0
- package/dist/boxes/webm/traversal.js +12 -1
- package/dist/buffer-iterator.d.ts +10 -6
- package/dist/buffer-iterator.js +92 -9
- package/dist/from-fetch.js +13 -3
- package/dist/from-input-type-file.d.ts +2 -0
- package/dist/from-input-type-file.js +37 -0
- package/dist/from-node.js +9 -2
- package/dist/from-web-file.js +6 -1
- package/dist/from-web.js +15 -6
- package/dist/get-codec.d.ts +4 -0
- package/dist/get-codec.js +22 -0
- package/dist/get-sample-positions.js +1 -1
- package/dist/has-all-info.js +1 -1
- package/dist/options.d.ts +3 -2
- package/dist/parse-media.js +13 -9
- package/dist/parse-video.js +16 -0
- package/dist/parser-state.d.ts +8 -9
- package/dist/parser-state.js +39 -19
- package/dist/reader.d.ts +1 -1
- package/dist/web-file.d.ts +2 -0
- package/dist/web-file.js +37 -0
- package/dist/webcodec-sample-types.d.ts +0 -1
- package/package.json +2 -2
- package/src/boxes/iso-base-media/mdat/mdat.ts +2 -2
- package/src/boxes/iso-base-media/moov/moov.ts +1 -0
- package/src/boxes/iso-base-media/process-box.ts +70 -40
- package/src/boxes/iso-base-media/stsd/mebx.ts +3 -0
- package/src/boxes/iso-base-media/stsd/samples.ts +3 -0
- package/src/boxes/iso-base-media/stsd/stco.ts +5 -3
- package/src/boxes/iso-base-media/trak/trak.ts +1 -0
- package/src/boxes/webm/ebml.ts +78 -0
- package/src/boxes/webm/make-header.ts +138 -0
- package/src/boxes/webm/parse-ebml.ts +93 -0
- package/src/boxes/webm/parse-webm-header.ts +8 -12
- package/src/boxes/webm/segments/all-segments.ts +226 -0
- package/src/boxes/webm/segments/block-simple-block-flags.ts +52 -0
- package/src/boxes/webm/segments/seek-position.ts +1 -1
- package/src/boxes/webm/segments/seek.ts +12 -2
- package/src/boxes/webm/segments/timestamp-scale.ts +1 -1
- package/src/boxes/webm/segments/track-entry.ts +125 -41
- package/src/boxes/webm/segments.ts +107 -40
- package/src/boxes/webm/traversal.ts +13 -0
- package/src/buffer-iterator.ts +110 -10
- package/src/from-fetch.ts +22 -3
- package/src/from-node.ts +18 -4
- package/src/from-web-file.ts +11 -1
- package/src/get-sample-positions.ts +1 -1
- package/src/has-all-info.ts +1 -1
- package/src/options.ts +3 -2
- package/src/parse-media.ts +14 -8
- package/src/parse-video.ts +17 -0
- package/src/parser-state.ts +52 -25
- package/src/reader.ts +1 -0
- package/src/test/create-matroska.test.ts +48 -0
- package/src/test/matroska.test.ts +144 -127
- package/src/test/parse-stco.test.ts +2 -0
- package/src/test/stream-local.test.ts +70 -14
- package/src/test/stream-remote.test.ts +23 -19
- package/src/test/stsd.test.ts +2 -0
- package/src/webcodec-sample-types.ts +0 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/boxes/iso-base-media/ftype.d.ts +0 -9
- package/dist/boxes/iso-base-media/ftype.js +0 -31
- package/dist/get-video-metadata.d.ts +0 -2
- package/dist/get-video-metadata.js +0 -44
- package/dist/read-and-increment-offset.d.ts +0 -28
- package/dist/read-and-increment-offset.js +0 -177
- package/dist/understand-vorbis.d.ts +0 -1
- package/dist/understand-vorbis.js +0 -12
- package/src/boxes/webm/segments/unknown.ts +0 -19
- /package/dist/{boxes/webm/bitstream/av1/frame.d.ts → get-samples.d.ts} +0 -0
- /package/dist/{boxes/webm/bitstream/av1/frame.js → get-samples.js} +0 -0
- /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.d.ts → sample-aspect-ratio.d.ts} +0 -0
- /package/dist/{boxes/webm/bitstream/h264/get-h264-descriptor.js → sample-aspect-ratio.js} +0 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {getVariableInt} from './ebml';
|
|
2
|
+
import type {
|
|
3
|
+
Ebml,
|
|
4
|
+
EbmlWithChildren,
|
|
5
|
+
EbmlWithHexString,
|
|
6
|
+
EbmlWithString,
|
|
7
|
+
EbmlWithUint8,
|
|
8
|
+
EmblTypes,
|
|
9
|
+
HeaderStructure,
|
|
10
|
+
matroskaElements,
|
|
11
|
+
} from './segments/all-segments';
|
|
12
|
+
import {getIdForName} from './segments/all-segments';
|
|
13
|
+
|
|
14
|
+
export const webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
|
|
15
|
+
|
|
16
|
+
const matroskaToHex = (
|
|
17
|
+
matrId: (typeof matroskaElements)[keyof typeof matroskaElements],
|
|
18
|
+
) => {
|
|
19
|
+
const numbers: Uint8Array = new Uint8Array((matrId.length - 2) / 2);
|
|
20
|
+
|
|
21
|
+
for (let i = 2; i < matrId.length; i += 2) {
|
|
22
|
+
const hex = matrId.substring(i, i + 2);
|
|
23
|
+
numbers[(i - 2) / 2] = parseInt(hex, 16);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return numbers;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type Numbers = '0' | '1' | '2' | '3' | '4' | '5' | '6';
|
|
30
|
+
|
|
31
|
+
type ChildFields<Struct extends HeaderStructure> = {
|
|
32
|
+
[key in keyof Struct &
|
|
33
|
+
Numbers as Struct[key]['name']]: EmblTypes[Struct[key]['type']];
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type SerializeValue<Struct extends Ebml> = Struct extends EbmlWithChildren
|
|
37
|
+
? ChildFields<Struct['children']>
|
|
38
|
+
: Struct extends EbmlWithString
|
|
39
|
+
? string
|
|
40
|
+
: Struct extends EbmlWithUint8
|
|
41
|
+
? number
|
|
42
|
+
: Struct extends EbmlWithHexString
|
|
43
|
+
? string
|
|
44
|
+
: undefined;
|
|
45
|
+
|
|
46
|
+
function putUintDynamic(number: number) {
|
|
47
|
+
if (number < 0) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'This function is designed for non-negative integers only.',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Calculate the minimum number of bytes needed to store the integer
|
|
54
|
+
const length = Math.ceil(Math.log2(number + 1) / 8);
|
|
55
|
+
const bytes = new Uint8Array(length);
|
|
56
|
+
|
|
57
|
+
for (let i = 0; i < length; i++) {
|
|
58
|
+
// Extract each byte from the number
|
|
59
|
+
bytes[length - 1 - i] = (number >> (8 * i)) & 0xff;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return bytes;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const makeFromHeaderStructure = <Struct extends Ebml>(
|
|
66
|
+
struct: Struct,
|
|
67
|
+
fields: SerializeValue<Struct>,
|
|
68
|
+
): Uint8Array => {
|
|
69
|
+
const arrays: Uint8Array[] = [];
|
|
70
|
+
|
|
71
|
+
if (struct.type === 'children') {
|
|
72
|
+
for (const item of struct.children) {
|
|
73
|
+
arrays.push(
|
|
74
|
+
makeMatroskaHeader(
|
|
75
|
+
item,
|
|
76
|
+
// @ts-expect-error
|
|
77
|
+
fields[item.name],
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return combineUint8Arrays(arrays);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (struct.type === 'string') {
|
|
86
|
+
return new TextEncoder().encode(fields as string);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (struct.type === 'uint') {
|
|
90
|
+
return putUintDynamic(fields as number);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (struct.type === 'hex-string') {
|
|
94
|
+
const hex = (fields as string).substring(2);
|
|
95
|
+
const arr = new Uint8Array(hex.length / 2);
|
|
96
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
97
|
+
const byte = parseInt(hex.substring(i, i + 2), 16);
|
|
98
|
+
arr[i / 2] = byte;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return arr;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (struct.type === 'void') {
|
|
105
|
+
throw new Error('Serializing Void is not implemented');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
throw new Error('Unexpected type');
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
export const makeMatroskaHeader = <Struct extends Ebml>(
|
|
112
|
+
struct: Struct,
|
|
113
|
+
fields: SerializeValue<Struct>,
|
|
114
|
+
) => {
|
|
115
|
+
const value = makeFromHeaderStructure(struct, fields);
|
|
116
|
+
|
|
117
|
+
return combineUint8Arrays([
|
|
118
|
+
matroskaToHex(getIdForName(struct.name)),
|
|
119
|
+
getVariableInt(value.length),
|
|
120
|
+
value,
|
|
121
|
+
]);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const combineUint8Arrays = (arrays: Uint8Array[]) => {
|
|
125
|
+
let totalLength = 0;
|
|
126
|
+
for (const array of arrays) {
|
|
127
|
+
totalLength += array.length;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const result = new Uint8Array(totalLength);
|
|
131
|
+
let offset = 0;
|
|
132
|
+
for (const array of arrays) {
|
|
133
|
+
result.set(array, offset);
|
|
134
|
+
offset += array.length;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return result;
|
|
138
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type {BufferIterator} from '../../buffer-iterator';
|
|
2
|
+
import type {PossibleEbml} from './segments/all-segments';
|
|
3
|
+
import {ebmlMap, type Ebml, type EbmlParsed} from './segments/all-segments';
|
|
4
|
+
|
|
5
|
+
type Prettify<T> = {
|
|
6
|
+
[K in keyof T]: T[K];
|
|
7
|
+
} & {};
|
|
8
|
+
|
|
9
|
+
export const parseEbml = (iterator: BufferIterator): Prettify<PossibleEbml> => {
|
|
10
|
+
const hex = iterator.getMatroskaSegmentId();
|
|
11
|
+
if (hex === null) {
|
|
12
|
+
throw new Error(
|
|
13
|
+
'Not enough bytes left to parse EBML - this should not happen',
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const hasInMap = ebmlMap[hex as keyof typeof ebmlMap];
|
|
18
|
+
if (!hasInMap) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Don't know how to parse EBML hex ID ${JSON.stringify(hex)}`,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const size = iterator.getVint();
|
|
25
|
+
if (size === null) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
'Not enough bytes left to parse EBML - this should not happen',
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (hasInMap.type === 'uint') {
|
|
32
|
+
const value = iterator.getUint(size);
|
|
33
|
+
|
|
34
|
+
return {type: hasInMap.name, value, hex};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (hasInMap.type === 'string') {
|
|
38
|
+
const value = iterator.getByteString(size);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
type: hasInMap.name,
|
|
42
|
+
value,
|
|
43
|
+
hex,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (hasInMap.type === 'float') {
|
|
48
|
+
const value = size === 4 ? iterator.getFloat32() : iterator.getFloat64();
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
type: hasInMap.name,
|
|
52
|
+
value,
|
|
53
|
+
hex,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (hasInMap.type === 'void') {
|
|
58
|
+
iterator.discard(size);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
type: hasInMap.name,
|
|
62
|
+
value: undefined,
|
|
63
|
+
hex,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (hasInMap.type === 'children') {
|
|
68
|
+
const children: EbmlParsed<Ebml>[] = [];
|
|
69
|
+
const startOffset = iterator.counter.getOffset();
|
|
70
|
+
|
|
71
|
+
// eslint-disable-next-line no-constant-condition
|
|
72
|
+
while (true) {
|
|
73
|
+
const value = parseEbml(iterator);
|
|
74
|
+
children.push(value);
|
|
75
|
+
const offsetNow = iterator.counter.getOffset();
|
|
76
|
+
|
|
77
|
+
if (offsetNow - startOffset > size) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Offset ${offsetNow - startOffset} is larger than the length of the hex ${size}`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (offsetNow - startOffset === size) {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {type: hasInMap.name, value: children as EbmlParsed<Ebml>[], hex};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// @ts-expect-error
|
|
92
|
+
throw new Error(`Unknown segment type ${hasInMap.type}`);
|
|
93
|
+
};
|
|
@@ -1,22 +1,18 @@
|
|
|
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 {
|
|
4
|
+
import {expectChildren} from './segments/parse-children';
|
|
5
5
|
|
|
6
6
|
// Parsing according to https://darkcoding.net/software/reading-mediarecorders-webm-opus-output/
|
|
7
7
|
export const parseWebm = (
|
|
8
8
|
counter: BufferIterator,
|
|
9
9
|
parserContext: ParserContext,
|
|
10
10
|
): Promise<ParseResult> => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// Discard header for now
|
|
19
|
-
counter.discard(length);
|
|
20
|
-
|
|
21
|
-
return expectSegment(counter, parserContext);
|
|
11
|
+
return expectChildren({
|
|
12
|
+
iterator: counter,
|
|
13
|
+
length: Infinity,
|
|
14
|
+
initialChildren: [],
|
|
15
|
+
wrap: null,
|
|
16
|
+
parserContext,
|
|
17
|
+
});
|
|
22
18
|
};
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
export const matroskaElements = {
|
|
2
|
+
Header: '0x1a45dfa3',
|
|
2
3
|
EBMLMaxIDLength: '0x42f2',
|
|
4
|
+
EBMLVersion: '0x4286',
|
|
5
|
+
EBMLReadVersion: '0x42f7',
|
|
3
6
|
EBMLMaxSizeLength: '0x42f3',
|
|
7
|
+
DocType: '0x4282',
|
|
8
|
+
DocTypeVersion: '0x4287',
|
|
9
|
+
DocTypeReadVersion: '0x4285',
|
|
4
10
|
Segment: '0x18538067',
|
|
5
11
|
SeekHead: '0x114d9b74',
|
|
6
12
|
Seek: '0x4dbb',
|
|
@@ -283,3 +289,223 @@ export const getSegmentName = (id: string) => {
|
|
|
283
289
|
([, value]) => value === id,
|
|
284
290
|
)?.[0];
|
|
285
291
|
};
|
|
292
|
+
|
|
293
|
+
export const getIdForName = (name: string) => {
|
|
294
|
+
const value = Object.entries(matroskaElements).find(
|
|
295
|
+
([key]) => key === name,
|
|
296
|
+
)?.[1];
|
|
297
|
+
if (!value) {
|
|
298
|
+
throw new Error(`Could not find id for name ${name}`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return value;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
export type MatroskaKey = keyof typeof matroskaElements;
|
|
305
|
+
|
|
306
|
+
export type MatroskaElement = (typeof matroskaElements)[MatroskaKey];
|
|
307
|
+
|
|
308
|
+
type EbmlType = 'string';
|
|
309
|
+
|
|
310
|
+
export type EbmlWithChildren = {
|
|
311
|
+
name: MatroskaKey;
|
|
312
|
+
type: 'children';
|
|
313
|
+
children: HeaderStructure;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
export type EbmlWithUint8 = {
|
|
317
|
+
name: MatroskaKey;
|
|
318
|
+
type: 'uint';
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
export type EbmlWithHexString = {
|
|
322
|
+
name: MatroskaKey;
|
|
323
|
+
type: 'hex-string';
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
export type EbmlWithString = {
|
|
327
|
+
name: MatroskaKey;
|
|
328
|
+
type: EbmlType;
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
export type EbmlWithVoid = {
|
|
332
|
+
name: MatroskaKey;
|
|
333
|
+
type: 'void';
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
export type EbmlWithFloat = {
|
|
337
|
+
name: MatroskaKey;
|
|
338
|
+
type: 'float';
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export type Ebml =
|
|
342
|
+
| EbmlWithString
|
|
343
|
+
| EbmlWithUint8
|
|
344
|
+
| EbmlWithChildren
|
|
345
|
+
| EbmlWithVoid
|
|
346
|
+
| EbmlWithFloat
|
|
347
|
+
| EbmlWithHexString;
|
|
348
|
+
|
|
349
|
+
export const ebmlVersion = {
|
|
350
|
+
name: 'EBMLVersion',
|
|
351
|
+
type: 'uint',
|
|
352
|
+
} satisfies Ebml;
|
|
353
|
+
|
|
354
|
+
export const ebmlReadVersion = {
|
|
355
|
+
name: 'EBMLReadVersion',
|
|
356
|
+
type: 'uint',
|
|
357
|
+
} satisfies Ebml;
|
|
358
|
+
|
|
359
|
+
export const ebmlMaxIdLength = {
|
|
360
|
+
name: 'EBMLMaxIDLength',
|
|
361
|
+
type: 'uint',
|
|
362
|
+
} satisfies Ebml;
|
|
363
|
+
|
|
364
|
+
export const ebmlMaxSizeLength = {
|
|
365
|
+
name: 'EBMLMaxSizeLength',
|
|
366
|
+
type: 'uint',
|
|
367
|
+
} satisfies Ebml;
|
|
368
|
+
|
|
369
|
+
export const docType = {
|
|
370
|
+
name: 'DocType',
|
|
371
|
+
type: 'string',
|
|
372
|
+
} satisfies Ebml;
|
|
373
|
+
|
|
374
|
+
export const docTypeVersion = {
|
|
375
|
+
name: 'DocTypeVersion',
|
|
376
|
+
type: 'uint',
|
|
377
|
+
} satisfies Ebml;
|
|
378
|
+
|
|
379
|
+
export const docTypeReadVersion = {
|
|
380
|
+
name: 'DocTypeReadVersion',
|
|
381
|
+
type: 'uint',
|
|
382
|
+
} satisfies Ebml;
|
|
383
|
+
|
|
384
|
+
export const voidEbml = {
|
|
385
|
+
name: 'Void',
|
|
386
|
+
type: 'void',
|
|
387
|
+
} satisfies Ebml;
|
|
388
|
+
|
|
389
|
+
export type EmblTypes = {
|
|
390
|
+
uint: number;
|
|
391
|
+
float: number;
|
|
392
|
+
string: string;
|
|
393
|
+
children: HeaderStructure;
|
|
394
|
+
void: undefined;
|
|
395
|
+
'hex-string': string;
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
export type HeaderStructure = Ebml[];
|
|
399
|
+
|
|
400
|
+
export const matroskaHeaderStructure = [
|
|
401
|
+
ebmlVersion,
|
|
402
|
+
ebmlReadVersion,
|
|
403
|
+
ebmlMaxIdLength,
|
|
404
|
+
ebmlMaxSizeLength,
|
|
405
|
+
docType,
|
|
406
|
+
docTypeVersion,
|
|
407
|
+
docTypeReadVersion,
|
|
408
|
+
] as const satisfies HeaderStructure;
|
|
409
|
+
|
|
410
|
+
export const matroskaHeader = {
|
|
411
|
+
name: 'Header',
|
|
412
|
+
type: 'children',
|
|
413
|
+
children: matroskaHeaderStructure,
|
|
414
|
+
} as const satisfies Ebml;
|
|
415
|
+
|
|
416
|
+
export const seekId = {
|
|
417
|
+
name: 'SeekID',
|
|
418
|
+
type: 'hex-string',
|
|
419
|
+
} as const satisfies Ebml;
|
|
420
|
+
|
|
421
|
+
export const seekPosition = {
|
|
422
|
+
name: 'SeekPosition',
|
|
423
|
+
type: 'uint',
|
|
424
|
+
} as const satisfies Ebml;
|
|
425
|
+
|
|
426
|
+
export const seek = {
|
|
427
|
+
name: 'Seek',
|
|
428
|
+
type: 'children',
|
|
429
|
+
children: [seekId, seekPosition],
|
|
430
|
+
} as const satisfies Ebml;
|
|
431
|
+
|
|
432
|
+
export const voidHeader = {
|
|
433
|
+
name: 'Void',
|
|
434
|
+
type: 'void',
|
|
435
|
+
} as const satisfies Ebml;
|
|
436
|
+
|
|
437
|
+
export type EbmlValue<T extends Ebml> = T extends EbmlWithUint8
|
|
438
|
+
? number
|
|
439
|
+
: T extends EbmlWithVoid
|
|
440
|
+
? undefined
|
|
441
|
+
: T extends EbmlWithString
|
|
442
|
+
? string
|
|
443
|
+
: T extends EbmlWithFloat
|
|
444
|
+
? number
|
|
445
|
+
: EbmlParsed<Ebml>[];
|
|
446
|
+
|
|
447
|
+
export type EbmlParsed<T extends Ebml> = {
|
|
448
|
+
type: T['name'];
|
|
449
|
+
value: EbmlValue<T>;
|
|
450
|
+
hex: string;
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
export const ebmlMap = {
|
|
454
|
+
[matroskaElements.Header]: matroskaHeader,
|
|
455
|
+
[matroskaElements.DocType]: docType,
|
|
456
|
+
[matroskaElements.DocTypeVersion]: docTypeVersion,
|
|
457
|
+
[matroskaElements.DocTypeReadVersion]: docTypeReadVersion,
|
|
458
|
+
[matroskaElements.EBMLVersion]: ebmlVersion,
|
|
459
|
+
[matroskaElements.EBMLReadVersion]: ebmlReadVersion,
|
|
460
|
+
[matroskaElements.EBMLMaxIDLength]: ebmlMaxIdLength,
|
|
461
|
+
[matroskaElements.EBMLMaxSizeLength]: ebmlMaxSizeLength,
|
|
462
|
+
[matroskaElements.Void]: voidEbml,
|
|
463
|
+
[matroskaElements.Cues]: {
|
|
464
|
+
name: 'Cues',
|
|
465
|
+
type: 'void',
|
|
466
|
+
},
|
|
467
|
+
[matroskaElements.DateUTC]: {
|
|
468
|
+
name: 'DateUTC',
|
|
469
|
+
type: 'void',
|
|
470
|
+
},
|
|
471
|
+
[matroskaElements.TrackTimestampScale]: {
|
|
472
|
+
name: 'TrackTimestampScale',
|
|
473
|
+
type: 'float',
|
|
474
|
+
},
|
|
475
|
+
[matroskaElements.CodecDelay]: {
|
|
476
|
+
name: 'CodecDelay',
|
|
477
|
+
type: 'void',
|
|
478
|
+
},
|
|
479
|
+
[matroskaElements.SeekPreRoll]: {
|
|
480
|
+
name: 'SeekPreRoll',
|
|
481
|
+
type: 'void',
|
|
482
|
+
},
|
|
483
|
+
[matroskaElements.DiscardPadding]: {
|
|
484
|
+
name: 'DiscardPadding',
|
|
485
|
+
type: 'void',
|
|
486
|
+
},
|
|
487
|
+
[matroskaElements.OutputSamplingFrequency]: {
|
|
488
|
+
name: 'OutputSamplingFrequency',
|
|
489
|
+
type: 'void',
|
|
490
|
+
},
|
|
491
|
+
[matroskaElements.CodecName]: {
|
|
492
|
+
name: 'CodecName',
|
|
493
|
+
type: 'void',
|
|
494
|
+
},
|
|
495
|
+
[matroskaElements.Position]: {
|
|
496
|
+
name: 'Position',
|
|
497
|
+
type: 'void',
|
|
498
|
+
},
|
|
499
|
+
[matroskaElements.SliceDuration]: {
|
|
500
|
+
name: 'SliceDuration',
|
|
501
|
+
type: 'void',
|
|
502
|
+
},
|
|
503
|
+
} as const satisfies Partial<Record<MatroskaElement, Ebml>>;
|
|
504
|
+
|
|
505
|
+
export type PossibleEbml = {
|
|
506
|
+
[key in keyof typeof ebmlMap]: {
|
|
507
|
+
type: (typeof ebmlMap)[key]['name'];
|
|
508
|
+
value: EbmlValue<(typeof ebmlMap)[key]>;
|
|
509
|
+
hex: string;
|
|
510
|
+
};
|
|
511
|
+
}[keyof typeof ebmlMap];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type {BufferIterator} from '../../../buffer-iterator';
|
|
2
|
+
import {matroskaElements} from './all-segments';
|
|
3
|
+
|
|
4
|
+
type BlockFlags = {
|
|
5
|
+
invisible: boolean;
|
|
6
|
+
lacing: number;
|
|
7
|
+
keyframe: boolean | null;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const parseBlockFlags = (
|
|
11
|
+
iterator: BufferIterator,
|
|
12
|
+
type:
|
|
13
|
+
| (typeof matroskaElements)['Block']
|
|
14
|
+
| (typeof matroskaElements)['SimpleBlock'],
|
|
15
|
+
): BlockFlags => {
|
|
16
|
+
if (type === matroskaElements.Block) {
|
|
17
|
+
iterator.startReadingBits();
|
|
18
|
+
// Reserved
|
|
19
|
+
iterator.getBits(4);
|
|
20
|
+
const invisible = Boolean(iterator.getBits(1));
|
|
21
|
+
const lacing = iterator.getBits(2);
|
|
22
|
+
// unused
|
|
23
|
+
iterator.getBits(1);
|
|
24
|
+
iterator.stopReadingBits();
|
|
25
|
+
return {
|
|
26
|
+
invisible,
|
|
27
|
+
lacing,
|
|
28
|
+
keyframe: null,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (type === matroskaElements.SimpleBlock) {
|
|
33
|
+
iterator.startReadingBits();
|
|
34
|
+
|
|
35
|
+
const keyframe = Boolean(iterator.getBits(1));
|
|
36
|
+
// Reserved
|
|
37
|
+
iterator.getBits(3);
|
|
38
|
+
const invisible = Boolean(iterator.getBits(1));
|
|
39
|
+
const lacing = iterator.getBits(2);
|
|
40
|
+
iterator.getBits(1);
|
|
41
|
+
|
|
42
|
+
iterator.stopReadingBits();
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
invisible,
|
|
46
|
+
lacing,
|
|
47
|
+
keyframe,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
throw new Error('Unexpected type');
|
|
52
|
+
};
|
|
@@ -9,7 +9,7 @@ export const parseSeekPositionSegment = (
|
|
|
9
9
|
iterator: BufferIterator,
|
|
10
10
|
length: number,
|
|
11
11
|
): SeekPositionSegment => {
|
|
12
|
-
const seekPosition = iterator.
|
|
12
|
+
const seekPosition = iterator.getUint(length);
|
|
13
13
|
|
|
14
14
|
return {
|
|
15
15
|
type: 'seek-position-segment',
|
|
@@ -35,8 +35,18 @@ export type SeekIdSegment = {
|
|
|
35
35
|
seekId: string;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
export const parseSeekIdSegment = (
|
|
39
|
-
|
|
38
|
+
export const parseSeekIdSegment = (
|
|
39
|
+
iterator: BufferIterator,
|
|
40
|
+
length: number,
|
|
41
|
+
): SeekIdSegment => {
|
|
42
|
+
const seekId =
|
|
43
|
+
'0x' +
|
|
44
|
+
[...iterator.getSlice(length)]
|
|
45
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
46
|
+
.join('');
|
|
47
|
+
if (seekId === null) {
|
|
48
|
+
throw new Error('Not enough bytes to parse seek id');
|
|
49
|
+
}
|
|
40
50
|
|
|
41
51
|
return {
|
|
42
52
|
type: 'seek-id-segment',
|
|
@@ -8,7 +8,7 @@ export type TimestampScaleSegment = {
|
|
|
8
8
|
export const parseTimestampScaleSegment = (
|
|
9
9
|
iterator: BufferIterator,
|
|
10
10
|
): TimestampScaleSegment => {
|
|
11
|
-
const timestampScale = iterator.
|
|
11
|
+
const timestampScale = iterator.getUint(3);
|
|
12
12
|
|
|
13
13
|
return {
|
|
14
14
|
type: 'timestamp-scale-segment',
|