@remotion/media-parser 4.0.201 → 4.0.202
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/mvhd.js +2 -2
- package/dist/boxes/iso-base-media/stsd/keys.js +1 -1
- package/dist/boxes/webm/av1-codec-private.js +1 -1
- package/dist/boxes/webm/description.d.ts +2 -2
- package/dist/boxes/webm/description.js +2 -2
- package/dist/boxes/webm/ebml.d.ts +2 -2
- package/dist/boxes/webm/ebml.js +23 -1
- package/dist/boxes/webm/get-ready-tracks.d.ts +1 -1
- package/dist/boxes/webm/get-ready-tracks.js +3 -3
- package/dist/boxes/webm/get-sample-from-block.d.ts +17 -0
- package/dist/boxes/webm/get-sample-from-block.js +78 -0
- package/dist/boxes/webm/get-track.d.ts +2 -2
- package/dist/boxes/webm/get-track.js +26 -25
- package/dist/boxes/webm/make-header.d.ts +3 -8
- package/dist/boxes/webm/make-header.js +43 -20
- package/dist/boxes/webm/parse-ebml.d.ts +9 -4
- package/dist/boxes/webm/parse-ebml.js +122 -13
- package/dist/boxes/webm/segments/all-segments.d.ts +421 -107
- package/dist/boxes/webm/segments/all-segments.js +260 -33
- 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 +2 -8
- package/dist/boxes/webm/segments/timestamp-scale.js +1 -1
- package/dist/boxes/webm/segments/track-entry.d.ts +3 -191
- package/dist/boxes/webm/segments/track-entry.js +2 -456
- package/dist/boxes/webm/segments.d.ts +3 -16
- package/dist/boxes/webm/segments.js +12 -196
- package/dist/boxes/webm/traversal.d.ts +5 -6
- package/dist/boxes/webm/traversal.js +6 -6
- package/dist/buffer-iterator.d.ts +1 -1
- package/dist/buffer-iterator.js +3 -3
- package/dist/create/create-media.d.ts +2 -0
- package/dist/create/create-media.js +36 -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 +39 -0
- package/dist/create/matroska-segment.d.ts +1 -0
- package/dist/create/matroska-segment.js +12 -0
- package/dist/create/matroska-trackentry.d.ts +21 -0
- package/dist/create/matroska-trackentry.js +191 -0
- package/dist/create-media.d.ts +1 -0
- package/dist/create-media.js +78 -0
- package/dist/get-audio-codec.d.ts +1 -1
- package/dist/get-audio-codec.js +13 -13
- package/dist/get-duration.js +12 -14
- package/dist/get-tracks.js +2 -2
- package/dist/get-video-codec.js +13 -13
- package/dist/parse-media.js +4 -1
- package/dist/parser-context.d.ts +1 -0
- package/dist/parser-state.js +3 -2
- 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 +19 -17
- package/dist/traversal.js +38 -39
- package/dist/writers/web-fs.d.ts +2 -0
- package/dist/writers/web-fs.js +28 -0
- package/dist/writers/writer.d.ts +9 -0
- package/dist/writers/writer.js +2 -0
- package/input.webm +0 -0
- package/package.json +2 -2
- package/src/boxes/iso-base-media/mvhd.ts +2 -2
- package/src/boxes/iso-base-media/stsd/keys.ts +1 -1
- package/src/boxes/webm/av1-codec-private.ts +1 -1
- package/src/boxes/webm/description.ts +7 -4
- package/src/boxes/webm/ebml.ts +24 -4
- package/src/boxes/webm/get-ready-tracks.ts +4 -4
- package/src/boxes/webm/get-sample-from-block.ts +125 -0
- package/src/boxes/webm/get-track.ts +38 -31
- package/src/boxes/webm/make-header.ts +58 -51
- package/src/boxes/webm/parse-ebml.ts +170 -16
- package/src/boxes/webm/segments/all-segments.ts +379 -62
- package/src/boxes/webm/segments/track-entry.ts +3 -846
- package/src/boxes/webm/segments.ts +18 -410
- package/src/boxes/webm/traversal.ts +17 -17
- package/src/buffer-iterator.ts +5 -4
- package/src/get-audio-codec.ts +14 -16
- package/src/get-duration.ts +15 -16
- package/src/get-tracks.ts +2 -2
- package/src/get-video-codec.ts +13 -15
- package/src/parse-media.ts +6 -1
- package/src/parser-context.ts +1 -0
- package/src/parser-state.ts +2 -2
- package/src/test/create-matroska.test.ts +237 -23
- package/src/test/matroska.test.ts +283 -348
- package/src/test/mvhd.test.ts +1 -1
- package/src/test/parse-esds.test.ts +2 -2
- package/src/test/parse-stco.test.ts +2 -2
- package/src/test/parse-stsc.test.ts +2 -2
- package/src/test/parse-stsz.test.ts +2 -2
- package/src/test/parse-stts.test.ts +1 -1
- package/src/test/stsd.test.ts +4 -2
- package/src/test/tkhd.test.ts +1 -1
- package/src/traversal.ts +62 -85
- package/tsconfig.tsbuildinfo +1 -1
- package/src/boxes/webm/segments/duration.ts +0 -29
- package/src/boxes/webm/segments/info.ts +0 -34
- package/src/boxes/webm/segments/main.ts +0 -6
- package/src/boxes/webm/segments/muxing.ts +0 -18
- package/src/boxes/webm/segments/seek-head.ts +0 -34
- package/src/boxes/webm/segments/seek-position.ts +0 -18
- package/src/boxes/webm/segments/seek.ts +0 -55
- package/src/boxes/webm/segments/timestamp-scale.ts +0 -17
- package/src/boxes/webm/segments/tracks.ts +0 -32
- package/src/boxes/webm/segments/void.ts +0 -18
- package/src/boxes/webm/segments/writing.ts +0 -18
- package/src/combine-uint8array.ts +0 -13
|
@@ -16,15 +16,16 @@ import {
|
|
|
16
16
|
} from '../../traversal';
|
|
17
17
|
import {parseAv1PrivateData} from './av1-codec-private';
|
|
18
18
|
import {getAudioDescription} from './description';
|
|
19
|
-
import type {
|
|
19
|
+
import type {CodecIdSegment, TrackEntry} from './segments/all-segments';
|
|
20
|
+
import {trackTypeToString} from './segments/track-entry';
|
|
20
21
|
|
|
21
|
-
const getDescription = (track:
|
|
22
|
+
const getDescription = (track: TrackEntry): undefined | Uint8Array => {
|
|
22
23
|
const codec = getCodecSegment(track);
|
|
23
24
|
if (!codec) {
|
|
24
25
|
return undefined;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
if (codec.
|
|
28
|
+
if (codec.value === 'V_MPEG4/ISO/AVC' || codec.value === 'V_MPEGH/ISO/HEVC') {
|
|
28
29
|
const priv = getPrivateData(track);
|
|
29
30
|
if (priv) {
|
|
30
31
|
return priv;
|
|
@@ -38,14 +39,14 @@ const getMatroskaVideoCodecString = ({
|
|
|
38
39
|
track,
|
|
39
40
|
codecSegment: codec,
|
|
40
41
|
}: {
|
|
41
|
-
track:
|
|
42
|
-
codecSegment:
|
|
42
|
+
track: TrackEntry;
|
|
43
|
+
codecSegment: CodecIdSegment;
|
|
43
44
|
}): string | null => {
|
|
44
|
-
if (codec.
|
|
45
|
+
if (codec.value === 'V_VP8') {
|
|
45
46
|
return 'vp8';
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
if (codec.
|
|
49
|
+
if (codec.value === 'V_VP9') {
|
|
49
50
|
const priv = getPrivateData(track);
|
|
50
51
|
if (priv) {
|
|
51
52
|
throw new Error(
|
|
@@ -56,7 +57,7 @@ const getMatroskaVideoCodecString = ({
|
|
|
56
57
|
return 'vp09.00.10.08';
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
if (codec.
|
|
60
|
+
if (codec.value === 'V_MPEG4/ISO/AVC') {
|
|
60
61
|
const priv = getPrivateData(track);
|
|
61
62
|
if (priv) {
|
|
62
63
|
return `avc1.${priv[1].toString(16).padStart(2, '0')}${priv[2].toString(16).padStart(2, '0')}${priv[3].toString(16).padStart(2, '0')}`;
|
|
@@ -65,7 +66,7 @@ const getMatroskaVideoCodecString = ({
|
|
|
65
66
|
throw new Error('Could not find a CodecPrivate field in TrackEntry');
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
if (codec.
|
|
69
|
+
if (codec.value === 'V_AV1') {
|
|
69
70
|
const priv = getPrivateData(track);
|
|
70
71
|
|
|
71
72
|
if (!priv) {
|
|
@@ -75,31 +76,34 @@ const getMatroskaVideoCodecString = ({
|
|
|
75
76
|
return parseAv1PrivateData(priv, null);
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
if (codec.
|
|
79
|
+
if (codec.value === 'V_MPEGH/ISO/HEVC') {
|
|
79
80
|
const priv = getPrivateData(track);
|
|
80
|
-
const iterator = getArrayBufferIterator(
|
|
81
|
+
const iterator = getArrayBufferIterator(
|
|
82
|
+
priv as Uint8Array,
|
|
83
|
+
(priv as Uint8Array).length,
|
|
84
|
+
);
|
|
81
85
|
|
|
82
86
|
return 'hvc1.' + getHvc1CodecString(iterator);
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
throw new Error(`Unknown codec: ${codec.
|
|
89
|
+
throw new Error(`Unknown codec: ${codec.value}`);
|
|
86
90
|
};
|
|
87
91
|
|
|
88
|
-
const getMatroskaAudioCodecString = (track:
|
|
92
|
+
const getMatroskaAudioCodecString = (track: TrackEntry): string => {
|
|
89
93
|
const codec = getCodecSegment(track);
|
|
90
94
|
if (!codec) {
|
|
91
95
|
throw new Error('Expected codec segment');
|
|
92
96
|
}
|
|
93
97
|
|
|
94
|
-
if (codec.
|
|
98
|
+
if (codec.value === 'A_OPUS') {
|
|
95
99
|
return 'opus';
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
if (codec.
|
|
102
|
+
if (codec.value === 'A_VORBIS') {
|
|
99
103
|
return 'vorbis';
|
|
100
104
|
}
|
|
101
105
|
|
|
102
|
-
if (codec.
|
|
106
|
+
if (codec.value === 'A_PCM/INT/LIT') {
|
|
103
107
|
// https://github.com/ietf-wg-cellar/matroska-specification/issues/142#issuecomment-330004950
|
|
104
108
|
// Audio samples MUST be considered as signed values, except if the audio bit depth is 8 which MUST be interpreted as unsigned values.
|
|
105
109
|
|
|
@@ -115,10 +119,13 @@ const getMatroskaAudioCodecString = (track: TrackEntrySegment): string => {
|
|
|
115
119
|
return 'pcm-s' + bitDepth;
|
|
116
120
|
}
|
|
117
121
|
|
|
118
|
-
if (codec.
|
|
122
|
+
if (codec.value === 'A_AAC') {
|
|
119
123
|
const priv = getPrivateData(track);
|
|
120
124
|
|
|
121
|
-
const iterator = getArrayBufferIterator(
|
|
125
|
+
const iterator = getArrayBufferIterator(
|
|
126
|
+
priv as Uint8Array,
|
|
127
|
+
(priv as Uint8Array).length,
|
|
128
|
+
);
|
|
122
129
|
|
|
123
130
|
iterator.startReadingBits();
|
|
124
131
|
/**
|
|
@@ -150,11 +157,11 @@ const getMatroskaAudioCodecString = (track: TrackEntrySegment): string => {
|
|
|
150
157
|
return `mp4a.40.${profile.toString().padStart(2, '0')}`;
|
|
151
158
|
}
|
|
152
159
|
|
|
153
|
-
if (codec.
|
|
160
|
+
if (codec.value === 'A_MPEG/L3') {
|
|
154
161
|
return 'mp3';
|
|
155
162
|
}
|
|
156
163
|
|
|
157
|
-
throw new Error(`Unknown codec: ${codec.
|
|
164
|
+
throw new Error(`Unknown codec: ${codec.value}`);
|
|
158
165
|
};
|
|
159
166
|
|
|
160
167
|
export const getTrack = ({
|
|
@@ -162,7 +169,7 @@ export const getTrack = ({
|
|
|
162
169
|
track,
|
|
163
170
|
}: {
|
|
164
171
|
timescale: number;
|
|
165
|
-
track:
|
|
172
|
+
track: TrackEntry;
|
|
166
173
|
}): VideoTrack | AudioTrack | null => {
|
|
167
174
|
const trackType = getTrackTypeSegment(track);
|
|
168
175
|
|
|
@@ -172,7 +179,7 @@ export const getTrack = ({
|
|
|
172
179
|
|
|
173
180
|
const trackId = getTrackId(track);
|
|
174
181
|
|
|
175
|
-
if (trackType.
|
|
182
|
+
if (trackTypeToString(trackType.value.value) === 'video') {
|
|
176
183
|
const width = getWidthSegment(track);
|
|
177
184
|
|
|
178
185
|
if (width === null) {
|
|
@@ -207,27 +214,27 @@ export const getTrack = ({
|
|
|
207
214
|
trackId,
|
|
208
215
|
codec: codecString,
|
|
209
216
|
description: getDescription(track),
|
|
210
|
-
height: displayHeight ? displayHeight.
|
|
211
|
-
width: displayWidth ? displayWidth.
|
|
217
|
+
height: displayHeight ? displayHeight.value.value : height.value.value,
|
|
218
|
+
width: displayWidth ? displayWidth.value.value : width.value.value,
|
|
212
219
|
sampleAspectRatio: {
|
|
213
220
|
numerator: 1,
|
|
214
221
|
denominator: 1,
|
|
215
222
|
},
|
|
216
223
|
timescale,
|
|
217
224
|
samplePositions: [],
|
|
218
|
-
codedHeight: height.
|
|
219
|
-
codedWidth: width.
|
|
225
|
+
codedHeight: height.value.value,
|
|
226
|
+
codedWidth: width.value.value,
|
|
220
227
|
displayAspectHeight: displayHeight
|
|
221
|
-
? displayHeight.
|
|
222
|
-
: height.
|
|
228
|
+
? displayHeight.value.value
|
|
229
|
+
: height.value.value,
|
|
223
230
|
displayAspectWidth: displayWidth
|
|
224
|
-
? displayWidth.
|
|
225
|
-
: width.
|
|
231
|
+
? displayWidth.value.value
|
|
232
|
+
: width.value.value,
|
|
226
233
|
rotation: 0,
|
|
227
234
|
};
|
|
228
235
|
}
|
|
229
236
|
|
|
230
|
-
if (trackType.
|
|
237
|
+
if (trackTypeToString(trackType.value.value) === 'audio') {
|
|
231
238
|
const sampleRate = getSampleRate(track);
|
|
232
239
|
const numberOfChannels = getNumberOfChannels(track);
|
|
233
240
|
if (sampleRate === null) {
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import {getVariableInt} from './ebml';
|
|
2
2
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
EbmlWithUint8,
|
|
8
|
-
EmblTypes,
|
|
9
|
-
HeaderStructure,
|
|
3
|
+
FloatWithSize,
|
|
4
|
+
PossibleEbml,
|
|
5
|
+
PossibleEbmlOrUint8Array,
|
|
6
|
+
UintWithSize,
|
|
10
7
|
matroskaElements,
|
|
11
8
|
} from './segments/all-segments';
|
|
12
|
-
import {getIdForName} from './segments/all-segments';
|
|
9
|
+
import {ebmlMap, getIdForName} from './segments/all-segments';
|
|
13
10
|
|
|
14
11
|
export const webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
|
|
15
12
|
|
|
@@ -26,24 +23,7 @@ const matroskaToHex = (
|
|
|
26
23
|
return numbers;
|
|
27
24
|
};
|
|
28
25
|
|
|
29
|
-
|
|
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) {
|
|
26
|
+
function putUintDynamic(number: number, minimumLength: number | null) {
|
|
47
27
|
if (number < 0) {
|
|
48
28
|
throw new Error(
|
|
49
29
|
'This function is designed for non-negative integers only.',
|
|
@@ -51,7 +31,10 @@ function putUintDynamic(number: number) {
|
|
|
51
31
|
}
|
|
52
32
|
|
|
53
33
|
// Calculate the minimum number of bytes needed to store the integer
|
|
54
|
-
const length = Math.
|
|
34
|
+
const length = Math.max(
|
|
35
|
+
minimumLength ?? 0,
|
|
36
|
+
Math.ceil(Math.log2(number + 1) / 8),
|
|
37
|
+
);
|
|
55
38
|
const bytes = new Uint8Array(length);
|
|
56
39
|
|
|
57
40
|
for (let i = 0; i < length; i++) {
|
|
@@ -62,36 +45,42 @@ function putUintDynamic(number: number) {
|
|
|
62
45
|
return bytes;
|
|
63
46
|
}
|
|
64
47
|
|
|
65
|
-
const makeFromHeaderStructure =
|
|
66
|
-
|
|
67
|
-
fields: SerializeValue<Struct>,
|
|
48
|
+
const makeFromHeaderStructure = (
|
|
49
|
+
fields: PossibleEbmlOrUint8Array,
|
|
68
50
|
): Uint8Array => {
|
|
51
|
+
if (fields instanceof Uint8Array) {
|
|
52
|
+
return fields;
|
|
53
|
+
}
|
|
54
|
+
|
|
69
55
|
const arrays: Uint8Array[] = [];
|
|
70
56
|
|
|
57
|
+
const struct = ebmlMap[getIdForName(fields.type)];
|
|
58
|
+
|
|
59
|
+
if (struct.type === 'uint8array') {
|
|
60
|
+
return fields.value as Uint8Array;
|
|
61
|
+
}
|
|
62
|
+
|
|
71
63
|
if (struct.type === 'children') {
|
|
72
|
-
for (const item of
|
|
73
|
-
arrays.push(
|
|
74
|
-
makeMatroskaHeader(
|
|
75
|
-
item,
|
|
76
|
-
// @ts-expect-error
|
|
77
|
-
fields[item.name],
|
|
78
|
-
),
|
|
79
|
-
);
|
|
64
|
+
for (const item of fields.value as PossibleEbml[]) {
|
|
65
|
+
arrays.push(makeMatroskaBytes(item));
|
|
80
66
|
}
|
|
81
67
|
|
|
82
68
|
return combineUint8Arrays(arrays);
|
|
83
69
|
}
|
|
84
70
|
|
|
85
71
|
if (struct.type === 'string') {
|
|
86
|
-
return new TextEncoder().encode(fields as string);
|
|
72
|
+
return new TextEncoder().encode(fields.value as string);
|
|
87
73
|
}
|
|
88
74
|
|
|
89
75
|
if (struct.type === 'uint') {
|
|
90
|
-
return putUintDynamic(
|
|
76
|
+
return putUintDynamic(
|
|
77
|
+
(fields.value as UintWithSize).value,
|
|
78
|
+
(fields.value as UintWithSize).byteLength,
|
|
79
|
+
);
|
|
91
80
|
}
|
|
92
81
|
|
|
93
82
|
if (struct.type === 'hex-string') {
|
|
94
|
-
const hex = (fields as string).substring(2);
|
|
83
|
+
const hex = (fields.value as string).substring(2);
|
|
95
84
|
const arr = new Uint8Array(hex.length / 2);
|
|
96
85
|
for (let i = 0; i < hex.length; i += 2) {
|
|
97
86
|
const byte = parseInt(hex.substring(i, i + 2), 16);
|
|
@@ -101,27 +90,45 @@ const makeFromHeaderStructure = <Struct extends Ebml>(
|
|
|
101
90
|
return arr;
|
|
102
91
|
}
|
|
103
92
|
|
|
104
|
-
if (struct.type === '
|
|
105
|
-
|
|
93
|
+
if (struct.type === 'float') {
|
|
94
|
+
const value = fields.value as FloatWithSize;
|
|
95
|
+
if (value.size === '32') {
|
|
96
|
+
const dataView = new DataView(new ArrayBuffer(4));
|
|
97
|
+
dataView.setFloat32(0, value.value);
|
|
98
|
+
return new Uint8Array(dataView.buffer);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const dataView2 = new DataView(new ArrayBuffer(8));
|
|
102
|
+
dataView2.setFloat64(0, value.value);
|
|
103
|
+
return new Uint8Array(dataView2.buffer);
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
throw new Error('Unexpected type');
|
|
109
107
|
};
|
|
110
108
|
|
|
111
|
-
export const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
109
|
+
export const makeMatroskaBytes = (fields: PossibleEbmlOrUint8Array) => {
|
|
110
|
+
if (fields instanceof Uint8Array) {
|
|
111
|
+
return fields;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const value = makeFromHeaderStructure(fields);
|
|
116
115
|
|
|
117
116
|
return combineUint8Arrays([
|
|
118
|
-
matroskaToHex(getIdForName(
|
|
119
|
-
getVariableInt(value.length),
|
|
117
|
+
matroskaToHex(getIdForName(fields.type)),
|
|
118
|
+
getVariableInt(value.length, fields.minVintWidth),
|
|
120
119
|
value,
|
|
121
120
|
]);
|
|
122
121
|
};
|
|
123
122
|
|
|
124
|
-
const combineUint8Arrays = (arrays: Uint8Array[]) => {
|
|
123
|
+
export const combineUint8Arrays = (arrays: Uint8Array[]) => {
|
|
124
|
+
if (arrays.length === 0) {
|
|
125
|
+
return new Uint8Array([]);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (arrays.length === 1) {
|
|
129
|
+
return arrays[0];
|
|
130
|
+
}
|
|
131
|
+
|
|
125
132
|
let totalLength = 0;
|
|
126
133
|
for (const array of arrays) {
|
|
127
134
|
totalLength += array.length;
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {registerTrack} from '../../add-new-matroska-tracks';
|
|
2
|
+
import {type BufferIterator} from '../../buffer-iterator';
|
|
3
|
+
import type {ParserContext} from '../../parser-context';
|
|
4
|
+
import type {VideoSample} from '../../webcodec-sample-types';
|
|
5
|
+
import {getSampleFromBlock} from './get-sample-from-block';
|
|
6
|
+
import {getTrack} from './get-track';
|
|
2
7
|
import type {PossibleEbml} from './segments/all-segments';
|
|
3
|
-
import {ebmlMap
|
|
8
|
+
import {ebmlMap} from './segments/all-segments';
|
|
4
9
|
|
|
5
|
-
type Prettify<T> = {
|
|
10
|
+
export type Prettify<T> = {
|
|
6
11
|
[K in keyof T]: T[K];
|
|
7
12
|
} & {};
|
|
8
13
|
|
|
9
|
-
export const parseEbml = (
|
|
14
|
+
export const parseEbml = async (
|
|
15
|
+
iterator: BufferIterator,
|
|
16
|
+
parserContext: ParserContext,
|
|
17
|
+
): Promise<Prettify<PossibleEbml>> => {
|
|
10
18
|
const hex = iterator.getMatroskaSegmentId();
|
|
11
19
|
if (hex === null) {
|
|
12
20
|
throw new Error(
|
|
@@ -21,7 +29,10 @@ export const parseEbml = (iterator: BufferIterator): Prettify<PossibleEbml> => {
|
|
|
21
29
|
);
|
|
22
30
|
}
|
|
23
31
|
|
|
32
|
+
const off = iterator.counter.getOffset();
|
|
24
33
|
const size = iterator.getVint();
|
|
34
|
+
const minVintWidth = iterator.counter.getOffset() - off;
|
|
35
|
+
|
|
25
36
|
if (size === null) {
|
|
26
37
|
throw new Error(
|
|
27
38
|
'Not enough bytes left to parse EBML - this should not happen',
|
|
@@ -29,9 +40,17 @@ export const parseEbml = (iterator: BufferIterator): Prettify<PossibleEbml> => {
|
|
|
29
40
|
}
|
|
30
41
|
|
|
31
42
|
if (hasInMap.type === 'uint') {
|
|
43
|
+
const beforeUintOffset = iterator.counter.getOffset();
|
|
32
44
|
const value = iterator.getUint(size);
|
|
33
45
|
|
|
34
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
type: hasInMap.name,
|
|
48
|
+
value: {
|
|
49
|
+
value,
|
|
50
|
+
byteLength: iterator.counter.getOffset() - beforeUintOffset,
|
|
51
|
+
},
|
|
52
|
+
minVintWidth,
|
|
53
|
+
};
|
|
35
54
|
}
|
|
36
55
|
|
|
37
56
|
if (hasInMap.type === 'string') {
|
|
@@ -40,7 +59,7 @@ export const parseEbml = (iterator: BufferIterator): Prettify<PossibleEbml> => {
|
|
|
40
59
|
return {
|
|
41
60
|
type: hasInMap.name,
|
|
42
61
|
value,
|
|
43
|
-
|
|
62
|
+
minVintWidth,
|
|
44
63
|
};
|
|
45
64
|
}
|
|
46
65
|
|
|
@@ -49,29 +68,49 @@ export const parseEbml = (iterator: BufferIterator): Prettify<PossibleEbml> => {
|
|
|
49
68
|
|
|
50
69
|
return {
|
|
51
70
|
type: hasInMap.name,
|
|
52
|
-
value
|
|
53
|
-
|
|
71
|
+
value: {
|
|
72
|
+
value,
|
|
73
|
+
size: size === 4 ? '32' : '64',
|
|
74
|
+
},
|
|
75
|
+
minVintWidth,
|
|
54
76
|
};
|
|
55
77
|
}
|
|
56
78
|
|
|
57
|
-
if (hasInMap.type === '
|
|
58
|
-
|
|
79
|
+
if (hasInMap.type === 'hex-string') {
|
|
80
|
+
return {
|
|
81
|
+
type: hasInMap.name,
|
|
82
|
+
value:
|
|
83
|
+
'0x' +
|
|
84
|
+
[...iterator.getSlice(size)]
|
|
85
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
86
|
+
.join(''),
|
|
87
|
+
minVintWidth,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
59
90
|
|
|
91
|
+
if (hasInMap.type === 'uint8array') {
|
|
60
92
|
return {
|
|
61
93
|
type: hasInMap.name,
|
|
62
|
-
value:
|
|
63
|
-
|
|
94
|
+
value: iterator.getSlice(size),
|
|
95
|
+
minVintWidth,
|
|
64
96
|
};
|
|
65
97
|
}
|
|
66
98
|
|
|
67
99
|
if (hasInMap.type === 'children') {
|
|
68
|
-
const children:
|
|
100
|
+
const children: PossibleEbml[] = [];
|
|
69
101
|
const startOffset = iterator.counter.getOffset();
|
|
70
102
|
|
|
71
103
|
// eslint-disable-next-line no-constant-condition
|
|
72
104
|
while (true) {
|
|
73
|
-
const
|
|
74
|
-
|
|
105
|
+
const offset = iterator.counter.getOffset();
|
|
106
|
+
const value = await parseEbml(iterator, parserContext);
|
|
107
|
+
const remapped = await postprocessEbml({
|
|
108
|
+
offset,
|
|
109
|
+
ebml: value,
|
|
110
|
+
parserContext,
|
|
111
|
+
});
|
|
112
|
+
children.push(remapped);
|
|
113
|
+
|
|
75
114
|
const offsetNow = iterator.counter.getOffset();
|
|
76
115
|
|
|
77
116
|
if (offsetNow - startOffset > size) {
|
|
@@ -85,9 +124,124 @@ export const parseEbml = (iterator: BufferIterator): Prettify<PossibleEbml> => {
|
|
|
85
124
|
}
|
|
86
125
|
}
|
|
87
126
|
|
|
88
|
-
return {type: hasInMap.name, value: children
|
|
127
|
+
return {type: hasInMap.name, value: children, minVintWidth};
|
|
89
128
|
}
|
|
90
129
|
|
|
91
130
|
// @ts-expect-error
|
|
92
131
|
throw new Error(`Unknown segment type ${hasInMap.type}`);
|
|
93
132
|
};
|
|
133
|
+
|
|
134
|
+
export const postprocessEbml = async ({
|
|
135
|
+
offset,
|
|
136
|
+
ebml,
|
|
137
|
+
parserContext,
|
|
138
|
+
}: {
|
|
139
|
+
offset: number;
|
|
140
|
+
ebml: Prettify<PossibleEbml>;
|
|
141
|
+
parserContext: ParserContext;
|
|
142
|
+
}): Promise<Prettify<PossibleEbml>> => {
|
|
143
|
+
if (ebml.type === 'TimestampScale') {
|
|
144
|
+
parserContext.parserState.setTimescale(ebml.value.value);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (ebml.type === 'TrackEntry') {
|
|
148
|
+
parserContext.parserState.onTrackEntrySegment(ebml);
|
|
149
|
+
|
|
150
|
+
const track = getTrack({
|
|
151
|
+
track: ebml,
|
|
152
|
+
timescale: parserContext.parserState.getTimescale(),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
if (track) {
|
|
156
|
+
await registerTrack({
|
|
157
|
+
state: parserContext.parserState,
|
|
158
|
+
options: parserContext,
|
|
159
|
+
track,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (ebml.type === 'Timestamp') {
|
|
165
|
+
parserContext.parserState.setTimestampOffset(offset, ebml.value.value);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (ebml.type === 'Block' || ebml.type === 'SimpleBlock') {
|
|
169
|
+
const sample = getSampleFromBlock(ebml, parserContext, offset);
|
|
170
|
+
|
|
171
|
+
if (sample.type === 'video-sample' && parserContext.nullifySamples) {
|
|
172
|
+
await parserContext.parserState.onVideoSample(
|
|
173
|
+
sample.videoSample.trackId,
|
|
174
|
+
sample.videoSample,
|
|
175
|
+
);
|
|
176
|
+
return {
|
|
177
|
+
type: 'Block',
|
|
178
|
+
value: new Uint8Array([]),
|
|
179
|
+
minVintWidth: ebml.minVintWidth,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (sample.type === 'audio-sample' && parserContext.nullifySamples) {
|
|
184
|
+
await parserContext.parserState.onAudioSample(
|
|
185
|
+
sample.audioSample.trackId,
|
|
186
|
+
sample.audioSample,
|
|
187
|
+
);
|
|
188
|
+
return {
|
|
189
|
+
type: 'Block',
|
|
190
|
+
value: new Uint8Array([]),
|
|
191
|
+
minVintWidth: ebml.minVintWidth,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (sample.type === 'no-sample' && parserContext.nullifySamples) {
|
|
196
|
+
return {
|
|
197
|
+
type: 'Block',
|
|
198
|
+
value: new Uint8Array([]),
|
|
199
|
+
minVintWidth: ebml.minVintWidth,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (ebml.type === 'BlockGroup') {
|
|
205
|
+
// Blocks don't have information about keyframes.
|
|
206
|
+
// https://ffmpeg.org/pipermail/ffmpeg-devel/2015-June/173825.html
|
|
207
|
+
// "For Blocks, keyframes is
|
|
208
|
+
// inferred by the absence of ReferenceBlock element (as done by matroskadec).""
|
|
209
|
+
|
|
210
|
+
const block = ebml.value.find(
|
|
211
|
+
(c) => c.type === 'SimpleBlock' || c.type === 'Block',
|
|
212
|
+
);
|
|
213
|
+
if (!block || (block.type !== 'SimpleBlock' && block.type !== 'Block')) {
|
|
214
|
+
throw new Error('Expected block segment');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const hasReferenceBlock = ebml.value.find(
|
|
218
|
+
(c) => c.type === 'ReferenceBlock',
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const sample =
|
|
222
|
+
block.value.length === 0
|
|
223
|
+
? null
|
|
224
|
+
: getSampleFromBlock(block, parserContext, offset);
|
|
225
|
+
|
|
226
|
+
if (sample && sample.type === 'partial-video-sample') {
|
|
227
|
+
const completeFrame: VideoSample = {
|
|
228
|
+
...sample.partialVideoSample,
|
|
229
|
+
type: hasReferenceBlock ? 'delta' : 'key',
|
|
230
|
+
};
|
|
231
|
+
await parserContext.parserState.onVideoSample(
|
|
232
|
+
sample.partialVideoSample.trackId,
|
|
233
|
+
completeFrame,
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (parserContext.nullifySamples) {
|
|
238
|
+
return {
|
|
239
|
+
type: 'BlockGroup',
|
|
240
|
+
value: [],
|
|
241
|
+
minVintWidth: ebml.minVintWidth,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return ebml;
|
|
247
|
+
};
|