@remotion/media-parser 4.0.200 → 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/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 -1
- package/dist/boxes/iso-base-media/moov/moov.js +1 -0
- package/dist/boxes/iso-base-media/mvhd.js +2 -2
- 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/keys.js +1 -1
- 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/av1-codec-private.js +1 -1
- package/dist/boxes/webm/bitstream/av1.js +10 -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 -1
- package/dist/boxes/webm/make-header.js +90 -32
- package/dist/boxes/webm/parse-ebml.d.ts +12 -0
- package/dist/boxes/webm/parse-ebml.js +175 -0
- package/dist/boxes/webm/parse-webm-header.js +8 -9
- package/dist/boxes/webm/segments/all-segments.d.ts +572 -1
- package/dist/boxes/webm/segments/all-segments.js +353 -2
- package/dist/boxes/webm/segments/track-entry.d.ts +5 -189
- package/dist/boxes/webm/segments/track-entry.js +2 -457
- package/dist/boxes/webm/segments.d.ts +3 -16
- package/dist/boxes/webm/segments.js +40 -219
- package/dist/boxes/webm/traversal.d.ts +5 -5
- package/dist/boxes/webm/traversal.js +17 -6
- package/dist/buffer-iterator.d.ts +10 -7
- package/dist/buffer-iterator.js +83 -7
- 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/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-audio-codec.d.ts +2 -2
- package/dist/get-audio-codec.js +13 -13
- package/dist/get-codec.d.ts +4 -0
- package/dist/get-codec.js +22 -0
- package/dist/get-duration.js +12 -14
- package/dist/get-sample-positions.js +1 -1
- package/dist/get-tracks.js +2 -2
- package/dist/get-video-codec.js +13 -13
- package/dist/has-all-info.js +1 -1
- package/dist/options.d.ts +3 -2
- package/dist/parse-media.js +17 -10
- package/dist/parse-video.js +16 -0
- package/dist/parser-context.d.ts +1 -0
- package/dist/parser-state.d.ts +4 -3
- package/dist/parser-state.js +16 -3
- package/dist/reader.d.ts +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 +19 -17
- package/dist/traversal.js +38 -39
- package/dist/web-file.d.ts +2 -0
- package/dist/web-file.js +37 -0
- 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/mdat/mdat.ts +2 -1
- package/src/boxes/iso-base-media/moov/moov.ts +1 -0
- package/src/boxes/iso-base-media/mvhd.ts +2 -2
- package/src/boxes/iso-base-media/process-box.ts +70 -40
- package/src/boxes/iso-base-media/stsd/keys.ts +1 -1
- 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/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 +129 -32
- package/src/boxes/webm/parse-ebml.ts +247 -0
- package/src/boxes/webm/parse-webm-header.ts +8 -12
- package/src/boxes/webm/segments/all-segments.ts +539 -1
- package/src/boxes/webm/segments/track-entry.ts +5 -843
- package/src/boxes/webm/segments.ts +48 -435
- package/src/boxes/webm/traversal.ts +28 -15
- package/src/buffer-iterator.ts +104 -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-audio-codec.ts +14 -16
- package/src/get-duration.ts +15 -16
- package/src/get-sample-positions.ts +1 -1
- package/src/get-tracks.ts +2 -2
- package/src/get-video-codec.ts +13 -15
- package/src/has-all-info.ts +1 -1
- package/src/options.ts +3 -2
- package/src/parse-media.ts +20 -9
- package/src/parse-video.ts +17 -0
- package/src/parser-context.ts +1 -0
- package/src/parser-state.ts +22 -5
- package/src/reader.ts +1 -0
- package/src/test/create-matroska.test.ts +255 -7
- package/src/test/matroska.test.ts +311 -334
- package/src/test/mvhd.test.ts +1 -1
- package/src/test/parse-esds.test.ts +2 -2
- package/src/test/parse-stco.test.ts +4 -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/stream-local.test.ts +23 -9
- package/src/test/stream-remote.test.ts +23 -19
- package/src/test/stsd.test.ts +6 -2
- package/src/test/tkhd.test.ts +1 -1
- package/src/traversal.ts +62 -85
- 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/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 -45
- package/src/boxes/webm/segments/timestamp-scale.ts +0 -17
- package/src/boxes/webm/segments/tracks.ts +0 -32
- package/src/boxes/webm/segments/unknown.ts +0 -19
- 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
- /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
|
@@ -5,7 +5,7 @@ export const parseAv1PrivateData = (
|
|
|
5
5
|
data: Uint8Array,
|
|
6
6
|
colrAtom: ColorParameterBox | null,
|
|
7
7
|
) => {
|
|
8
|
-
const iterator = getArrayBufferIterator(data);
|
|
8
|
+
const iterator = getArrayBufferIterator(data, data.byteLength);
|
|
9
9
|
iterator.startReadingBits();
|
|
10
10
|
if (iterator.getBits(1) !== 1) {
|
|
11
11
|
iterator.destroy();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {getArrayBufferIterator} from '../../buffer-iterator';
|
|
2
2
|
import {getCodecSegment, getPrivateData} from '../../traversal';
|
|
3
|
-
import type {
|
|
3
|
+
import type {TrackEntry} from './segments/all-segments';
|
|
4
4
|
|
|
5
5
|
export const getAudioDescription = (
|
|
6
|
-
track:
|
|
6
|
+
track: TrackEntry,
|
|
7
7
|
): undefined | Uint8Array => {
|
|
8
8
|
const codec = getCodecSegment(track);
|
|
9
|
-
if (!codec || codec.
|
|
9
|
+
if (!codec || codec.value !== 'A_VORBIS') {
|
|
10
10
|
return undefined;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -59,7 +59,10 @@ export const getAudioDescription = (
|
|
|
59
59
|
|
|
60
60
|
const vorbisBooks = privateData.slice(offset);
|
|
61
61
|
|
|
62
|
-
const bufferIterator = getArrayBufferIterator(
|
|
62
|
+
const bufferIterator = getArrayBufferIterator(
|
|
63
|
+
vorbisInfo.slice(0),
|
|
64
|
+
vorbisInfo.length,
|
|
65
|
+
);
|
|
63
66
|
|
|
64
67
|
// type
|
|
65
68
|
bufferIterator.getUint8();
|
package/src/boxes/webm/ebml.ts
CHANGED
|
@@ -32,10 +32,9 @@ export const measureEBMLVarInt = (value: number) => {
|
|
|
32
32
|
throw new Error('EBML VINT size not supported ' + value);
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
export const getVariableInt = (
|
|
36
|
-
value
|
|
37
|
-
|
|
38
|
-
) => {
|
|
35
|
+
export const getVariableInt = (value: number, minWidth: number | null) => {
|
|
36
|
+
const width = Math.max(measureEBMLVarInt(value), minWidth ?? 0);
|
|
37
|
+
|
|
39
38
|
switch (width) {
|
|
40
39
|
case 1:
|
|
41
40
|
return new Uint8Array([(1 << 7) | value]);
|
|
@@ -72,6 +71,27 @@ export const getVariableInt = (
|
|
|
72
71
|
value >> 8,
|
|
73
72
|
value,
|
|
74
73
|
]);
|
|
74
|
+
case 7:
|
|
75
|
+
return new Uint8Array([
|
|
76
|
+
(1 << 1) | ((value / 2 ** 48) & 0x1),
|
|
77
|
+
(value / 2 ** 40) | 0,
|
|
78
|
+
(value / 2 ** 32) | 0,
|
|
79
|
+
value >> 24,
|
|
80
|
+
value >> 16,
|
|
81
|
+
value >> 8,
|
|
82
|
+
value,
|
|
83
|
+
]);
|
|
84
|
+
case 8:
|
|
85
|
+
return new Uint8Array([
|
|
86
|
+
(1 << 0) | ((value / 2 ** 56) & 0x1),
|
|
87
|
+
(value / 2 ** 48) | 0,
|
|
88
|
+
(value / 2 ** 40) | 0,
|
|
89
|
+
(value / 2 ** 32) | 0,
|
|
90
|
+
value >> 24,
|
|
91
|
+
value >> 16,
|
|
92
|
+
value >> 8,
|
|
93
|
+
value,
|
|
94
|
+
]);
|
|
75
95
|
default:
|
|
76
96
|
throw new Error('Bad EBML VINT size ' + width);
|
|
77
97
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {Track} from '../../get-tracks';
|
|
2
2
|
import {getTracksSegment} from '../../traversal';
|
|
3
3
|
import {getTrack} from './get-track';
|
|
4
|
-
import type {MainSegment} from './segments/
|
|
4
|
+
import type {MainSegment} from './segments/all-segments';
|
|
5
5
|
|
|
6
6
|
export const getTracksFromMatroska = (
|
|
7
7
|
segment: MainSegment,
|
|
@@ -14,12 +14,12 @@ export const getTracksFromMatroska = (
|
|
|
14
14
|
|
|
15
15
|
const tracks: Track[] = [];
|
|
16
16
|
|
|
17
|
-
for (const trackEntrySegment of tracksSegment.
|
|
18
|
-
if (trackEntrySegment.type === '
|
|
17
|
+
for (const trackEntrySegment of tracksSegment.value) {
|
|
18
|
+
if (trackEntrySegment.type === 'Crc32') {
|
|
19
19
|
continue;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
if (trackEntrySegment.type !== '
|
|
22
|
+
if (trackEntrySegment.type !== 'TrackEntry') {
|
|
23
23
|
throw new Error('Expected track entry segment');
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import {getArrayBufferIterator} from '../../buffer-iterator';
|
|
2
|
+
import type {ParserContext} from '../../parser-context';
|
|
3
|
+
import type {AudioSample, VideoSample} from '../../webcodec-sample-types';
|
|
4
|
+
import type {BlockSegment, SimpleBlockSegment} from './segments/all-segments';
|
|
5
|
+
import {matroskaElements} from './segments/all-segments';
|
|
6
|
+
import {parseBlockFlags} from './segments/block-simple-block-flags';
|
|
7
|
+
|
|
8
|
+
type SampleResult =
|
|
9
|
+
| {
|
|
10
|
+
type: 'video-sample';
|
|
11
|
+
videoSample: VideoSample;
|
|
12
|
+
}
|
|
13
|
+
| {
|
|
14
|
+
type: 'audio-sample';
|
|
15
|
+
audioSample: AudioSample;
|
|
16
|
+
}
|
|
17
|
+
| {
|
|
18
|
+
type: 'partial-video-sample';
|
|
19
|
+
partialVideoSample: Omit<VideoSample, 'type'>;
|
|
20
|
+
}
|
|
21
|
+
| {
|
|
22
|
+
type: 'no-sample';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const getSampleFromBlock = (
|
|
26
|
+
ebml: BlockSegment | SimpleBlockSegment,
|
|
27
|
+
parserContext: ParserContext,
|
|
28
|
+
offset: number,
|
|
29
|
+
): SampleResult => {
|
|
30
|
+
const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
|
|
31
|
+
const trackNumber = iterator.getVint();
|
|
32
|
+
if (trackNumber === null) {
|
|
33
|
+
throw new Error('Not enough data to get track number, should not happen');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const timecodeRelativeToCluster = iterator.getUint16();
|
|
37
|
+
|
|
38
|
+
const {keyframe} = parseBlockFlags(
|
|
39
|
+
iterator,
|
|
40
|
+
ebml.type === 'SimpleBlock'
|
|
41
|
+
? matroskaElements.SimpleBlock
|
|
42
|
+
: matroskaElements.Block,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const {codec, trackTimescale} =
|
|
46
|
+
parserContext.parserState.getTrackInfoByNumber(trackNumber);
|
|
47
|
+
|
|
48
|
+
const clusterOffset =
|
|
49
|
+
parserContext.parserState.getTimestampOffsetForByteOffset(offset);
|
|
50
|
+
|
|
51
|
+
const timescale = parserContext.parserState.getTimescale();
|
|
52
|
+
|
|
53
|
+
if (clusterOffset === undefined) {
|
|
54
|
+
throw new Error('Could not find offset for byte offset ' + offset);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// https://github.com/hubblec4/Matroska-Chapters-Specs/blob/master/notes.md/#timestampscale
|
|
58
|
+
// The TimestampScale Element is used to calculate the Raw Timestamp of a Block. The timestamp is obtained by adding the Block's timestamp to the Cluster's Timestamp Element, and then multiplying that result by the TimestampScale. The result will be the Block's Raw Timestamp in nanoseconds.
|
|
59
|
+
const timecodeInNanoSeconds =
|
|
60
|
+
(timecodeRelativeToCluster + clusterOffset) *
|
|
61
|
+
timescale *
|
|
62
|
+
(trackTimescale ?? 1);
|
|
63
|
+
|
|
64
|
+
// Timecode should be in microseconds
|
|
65
|
+
const timecodeInMicroseconds = timecodeInNanoSeconds / 1000;
|
|
66
|
+
|
|
67
|
+
if (!codec) {
|
|
68
|
+
throw new Error(`Could not find codec for track ${trackNumber}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const remainingNow = ebml.value.length - (iterator.counter.getOffset() - 0);
|
|
72
|
+
|
|
73
|
+
if (codec.startsWith('V_')) {
|
|
74
|
+
const partialVideoSample: Omit<VideoSample, 'type'> = {
|
|
75
|
+
data: iterator.getSlice(remainingNow),
|
|
76
|
+
cts: null,
|
|
77
|
+
dts: null,
|
|
78
|
+
duration: undefined,
|
|
79
|
+
trackId: trackNumber,
|
|
80
|
+
timestamp: timecodeInMicroseconds,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
if (keyframe === null) {
|
|
84
|
+
iterator.destroy();
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
type: 'partial-video-sample',
|
|
88
|
+
partialVideoSample,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const sample: VideoSample = {
|
|
93
|
+
...partialVideoSample,
|
|
94
|
+
type: keyframe ? 'key' : 'delta',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
iterator.destroy();
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
type: 'video-sample',
|
|
101
|
+
videoSample: sample,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (codec.startsWith('A_')) {
|
|
106
|
+
const audioSample: AudioSample = {
|
|
107
|
+
data: iterator.getSlice(remainingNow),
|
|
108
|
+
trackId: trackNumber,
|
|
109
|
+
timestamp: timecodeInMicroseconds,
|
|
110
|
+
type: 'key',
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
iterator.destroy();
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
type: 'audio-sample',
|
|
117
|
+
audioSample,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
iterator.destroy();
|
|
122
|
+
return {
|
|
123
|
+
type: 'no-sample',
|
|
124
|
+
};
|
|
125
|
+
};
|
|
@@ -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,48 +1,145 @@
|
|
|
1
1
|
import {getVariableInt} from './ebml';
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
|
+
FloatWithSize,
|
|
4
|
+
PossibleEbml,
|
|
5
|
+
PossibleEbmlOrUint8Array,
|
|
6
|
+
UintWithSize,
|
|
7
|
+
matroskaElements,
|
|
8
|
+
} from './segments/all-segments';
|
|
9
|
+
import {ebmlMap, getIdForName} from './segments/all-segments';
|
|
3
10
|
|
|
4
11
|
export const webmPattern = new Uint8Array([0x1a, 0x45, 0xdf, 0xa3]);
|
|
5
12
|
|
|
6
13
|
const matroskaToHex = (
|
|
7
14
|
matrId: (typeof matroskaElements)[keyof typeof matroskaElements],
|
|
8
15
|
) => {
|
|
9
|
-
const numbers:
|
|
16
|
+
const numbers: Uint8Array = new Uint8Array((matrId.length - 2) / 2);
|
|
17
|
+
|
|
10
18
|
for (let i = 2; i < matrId.length; i += 2) {
|
|
11
|
-
const hex = matrId.
|
|
12
|
-
numbers
|
|
19
|
+
const hex = matrId.substring(i, i + 2);
|
|
20
|
+
numbers[(i - 2) / 2] = parseInt(hex, 16);
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
return numbers;
|
|
16
24
|
};
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
26
|
+
function putUintDynamic(number: number, minimumLength: number | null) {
|
|
27
|
+
if (number < 0) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
'This function is designed for non-negative integers only.',
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Calculate the minimum number of bytes needed to store the integer
|
|
34
|
+
const length = Math.max(
|
|
35
|
+
minimumLength ?? 0,
|
|
36
|
+
Math.ceil(Math.log2(number + 1) / 8),
|
|
37
|
+
);
|
|
38
|
+
const bytes = new Uint8Array(length);
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < length; i++) {
|
|
41
|
+
// Extract each byte from the number
|
|
42
|
+
bytes[length - 1 - i] = (number >> (8 * i)) & 0xff;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return bytes;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const makeFromHeaderStructure = (
|
|
49
|
+
fields: PossibleEbmlOrUint8Array,
|
|
50
|
+
): Uint8Array => {
|
|
51
|
+
if (fields instanceof Uint8Array) {
|
|
52
|
+
return fields;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const arrays: Uint8Array[] = [];
|
|
56
|
+
|
|
57
|
+
const struct = ebmlMap[getIdForName(fields.type)];
|
|
58
|
+
|
|
59
|
+
if (struct.type === 'uint8array') {
|
|
60
|
+
return fields.value as Uint8Array;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (struct.type === 'children') {
|
|
64
|
+
for (const item of fields.value as PossibleEbml[]) {
|
|
65
|
+
arrays.push(makeMatroskaBytes(item));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return combineUint8Arrays(arrays);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (struct.type === 'string') {
|
|
72
|
+
return new TextEncoder().encode(fields.value as string);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (struct.type === 'uint') {
|
|
76
|
+
return putUintDynamic(
|
|
77
|
+
(fields.value as UintWithSize).value,
|
|
78
|
+
(fields.value as UintWithSize).byteLength,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (struct.type === 'hex-string') {
|
|
83
|
+
const hex = (fields.value as string).substring(2);
|
|
84
|
+
const arr = new Uint8Array(hex.length / 2);
|
|
85
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
86
|
+
const byte = parseInt(hex.substring(i, i + 2), 16);
|
|
87
|
+
arr[i / 2] = byte;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return arr;
|
|
91
|
+
}
|
|
92
|
+
|
|
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);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
throw new Error('Unexpected type');
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const makeMatroskaBytes = (fields: PossibleEbmlOrUint8Array) => {
|
|
110
|
+
if (fields instanceof Uint8Array) {
|
|
111
|
+
return fields;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const value = makeFromHeaderStructure(fields);
|
|
115
|
+
|
|
116
|
+
return combineUint8Arrays([
|
|
117
|
+
matroskaToHex(getIdForName(fields.type)),
|
|
118
|
+
getVariableInt(value.length, fields.minVintWidth),
|
|
119
|
+
value,
|
|
45
120
|
]);
|
|
121
|
+
};
|
|
122
|
+
|
|
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
|
+
|
|
132
|
+
let totalLength = 0;
|
|
133
|
+
for (const array of arrays) {
|
|
134
|
+
totalLength += array.length;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const result = new Uint8Array(totalLength);
|
|
138
|
+
let offset = 0;
|
|
139
|
+
for (const array of arrays) {
|
|
140
|
+
result.set(array, offset);
|
|
141
|
+
offset += array.length;
|
|
142
|
+
}
|
|
46
143
|
|
|
47
|
-
return
|
|
144
|
+
return result;
|
|
48
145
|
};
|