@remotion/media-parser 4.0.214 → 4.0.216
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/webm/ebml.d.ts +1 -1
- package/dist/boxes/webm/get-track.d.ts +6 -0
- package/dist/boxes/webm/get-track.js +184 -0
- package/dist/esm/from-node.mjs +3 -3
- package/dist/esm/index.mjs +51 -51
- package/dist/from-fetch.d.ts +2 -0
- package/dist/from-fetch.js +64 -0
- package/dist/from-node.d.ts +2 -0
- package/dist/from-node.js +40 -0
- package/dist/from-web-file.d.ts +2 -0
- package/dist/from-web-file.js +39 -0
- package/dist/reader.d.ts +11 -0
- package/dist/reader.js +2 -0
- package/dist/traversal.d.ts +65 -0
- package/dist/traversal.js +368 -0
- package/package.json +2 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const measureEBMLVarInt: (value: number) => 1 | 2 |
|
|
1
|
+
export declare const measureEBMLVarInt: (value: number) => 1 | 2 | 5 | 3 | 6 | 4;
|
|
2
2
|
export declare const getVariableInt: (value: number, minWidth: number | null) => Uint8Array;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTrack = void 0;
|
|
4
|
+
const buffer_iterator_1 = require("../../buffer-iterator");
|
|
5
|
+
const make_hvc1_codec_strings_1 = require("../../make-hvc1-codec-strings");
|
|
6
|
+
const traversal_1 = require("../../traversal");
|
|
7
|
+
const av1_codec_private_1 = require("./av1-codec-private");
|
|
8
|
+
const description_1 = require("./description");
|
|
9
|
+
const track_entry_1 = require("./segments/track-entry");
|
|
10
|
+
const getDescription = (track) => {
|
|
11
|
+
const codec = (0, traversal_1.getCodecSegment)(track);
|
|
12
|
+
if (!codec) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (codec.value === 'V_MPEG4/ISO/AVC' || codec.value === 'V_MPEGH/ISO/HEVC') {
|
|
16
|
+
const priv = (0, traversal_1.getPrivateData)(track);
|
|
17
|
+
if (priv) {
|
|
18
|
+
return priv;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
};
|
|
23
|
+
const getMatroskaVideoCodecString = ({ track, codecSegment: codec, }) => {
|
|
24
|
+
if (codec.value === 'V_VP8') {
|
|
25
|
+
return 'vp8';
|
|
26
|
+
}
|
|
27
|
+
if (codec.value === 'V_VP9') {
|
|
28
|
+
const priv = (0, traversal_1.getPrivateData)(track);
|
|
29
|
+
if (priv) {
|
|
30
|
+
throw new Error('@remotion/media-parser cannot handle the private data for VP9. Do you have an example file you could send so we can implement it?');
|
|
31
|
+
}
|
|
32
|
+
return 'vp09.00.10.08';
|
|
33
|
+
}
|
|
34
|
+
if (codec.value === 'V_MPEG4/ISO/AVC') {
|
|
35
|
+
const priv = (0, traversal_1.getPrivateData)(track);
|
|
36
|
+
if (priv) {
|
|
37
|
+
return `avc1.${priv[1].toString(16).padStart(2, '0')}${priv[2].toString(16).padStart(2, '0')}${priv[3].toString(16).padStart(2, '0')}`;
|
|
38
|
+
}
|
|
39
|
+
throw new Error('Could not find a CodecPrivate field in TrackEntry');
|
|
40
|
+
}
|
|
41
|
+
if (codec.value === 'V_AV1') {
|
|
42
|
+
const priv = (0, traversal_1.getPrivateData)(track);
|
|
43
|
+
if (!priv) {
|
|
44
|
+
throw new Error('Expected private data in AV1 track');
|
|
45
|
+
}
|
|
46
|
+
return (0, av1_codec_private_1.parseAv1PrivateData)(priv, null);
|
|
47
|
+
}
|
|
48
|
+
if (codec.value === 'V_MPEGH/ISO/HEVC') {
|
|
49
|
+
const priv = (0, traversal_1.getPrivateData)(track);
|
|
50
|
+
const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(priv, priv.length);
|
|
51
|
+
return 'hvc1.' + (0, make_hvc1_codec_strings_1.getHvc1CodecString)(iterator);
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Unknown codec: ${codec.value}`);
|
|
54
|
+
};
|
|
55
|
+
const getMatroskaAudioCodecString = (track) => {
|
|
56
|
+
const codec = (0, traversal_1.getCodecSegment)(track);
|
|
57
|
+
if (!codec) {
|
|
58
|
+
throw new Error('Expected codec segment');
|
|
59
|
+
}
|
|
60
|
+
if (codec.value === 'A_OPUS') {
|
|
61
|
+
return 'opus';
|
|
62
|
+
}
|
|
63
|
+
if (codec.value === 'A_VORBIS') {
|
|
64
|
+
return 'vorbis';
|
|
65
|
+
}
|
|
66
|
+
if (codec.value === 'A_PCM/INT/LIT') {
|
|
67
|
+
// https://github.com/ietf-wg-cellar/matroska-specification/issues/142#issuecomment-330004950
|
|
68
|
+
// Audio samples MUST be considered as signed values, except if the audio bit depth is 8 which MUST be interpreted as unsigned values.
|
|
69
|
+
const bitDepth = (0, traversal_1.getBitDepth)(track);
|
|
70
|
+
if (bitDepth === null) {
|
|
71
|
+
throw new Error('Expected bit depth');
|
|
72
|
+
}
|
|
73
|
+
if (bitDepth === 8) {
|
|
74
|
+
return 'pcm-u8';
|
|
75
|
+
}
|
|
76
|
+
return 'pcm-s' + bitDepth;
|
|
77
|
+
}
|
|
78
|
+
if (codec.value === 'A_AAC') {
|
|
79
|
+
const priv = (0, traversal_1.getPrivateData)(track);
|
|
80
|
+
const iterator = (0, buffer_iterator_1.getArrayBufferIterator)(priv, priv.length);
|
|
81
|
+
iterator.startReadingBits();
|
|
82
|
+
/**
|
|
83
|
+
* ChatGPT
|
|
84
|
+
* ▪ The first 5 bits represent the AOT.
|
|
85
|
+
▪ Common values:
|
|
86
|
+
◦ 1 for AAC Main
|
|
87
|
+
◦ 2 for AAC LC (Low Complexity)
|
|
88
|
+
◦ 3 for AAC SSR (Scalable Sample Rate)
|
|
89
|
+
◦ 4 for AAC LTP (Long Term Prediction)
|
|
90
|
+
◦ 5 for SBR (Spectral Band Replication)
|
|
91
|
+
◦ 29 for HE-AAC (which uses SBR with AAC LC)
|
|
92
|
+
*/
|
|
93
|
+
/**
|
|
94
|
+
* Fully qualified codec:
|
|
95
|
+
* This codec has multiple possible codec strings:
|
|
96
|
+
"mp4a.40.2" — MPEG-4 AAC LC
|
|
97
|
+
"mp4a.40.02" — MPEG-4 AAC LC, leading 0 for Aud-OTI compatibility
|
|
98
|
+
"mp4a.40.5" — MPEG-4 HE-AAC v1 (AAC LC + SBR)
|
|
99
|
+
"mp4a.40.05" — MPEG-4 HE-AAC v1 (AAC LC + SBR), leading 0 for Aud-OTI compatibility
|
|
100
|
+
"mp4a.40.29" — MPEG-4 HE-AAC v2 (AAC LC + SBR + PS)
|
|
101
|
+
"mp4a.67" — MPEG-2 AAC LC
|
|
102
|
+
*/
|
|
103
|
+
const profile = iterator.getBits(5);
|
|
104
|
+
iterator.stopReadingBits();
|
|
105
|
+
iterator.destroy();
|
|
106
|
+
return `mp4a.40.${profile.toString().padStart(2, '0')}`;
|
|
107
|
+
}
|
|
108
|
+
if (codec.value === 'A_MPEG/L3') {
|
|
109
|
+
return 'mp3';
|
|
110
|
+
}
|
|
111
|
+
throw new Error(`Unknown codec: ${codec.value}`);
|
|
112
|
+
};
|
|
113
|
+
const getTrack = ({ timescale, track, }) => {
|
|
114
|
+
const trackType = (0, traversal_1.getTrackTypeSegment)(track);
|
|
115
|
+
if (!trackType) {
|
|
116
|
+
throw new Error('Expected track type segment');
|
|
117
|
+
}
|
|
118
|
+
const trackId = (0, traversal_1.getTrackId)(track);
|
|
119
|
+
if ((0, track_entry_1.trackTypeToString)(trackType.value.value) === 'video') {
|
|
120
|
+
const width = (0, traversal_1.getWidthSegment)(track);
|
|
121
|
+
if (width === null) {
|
|
122
|
+
throw new Error('Expected width segment');
|
|
123
|
+
}
|
|
124
|
+
const height = (0, traversal_1.getHeightSegment)(track);
|
|
125
|
+
if (height === null) {
|
|
126
|
+
throw new Error('Expected height segment');
|
|
127
|
+
}
|
|
128
|
+
const displayHeight = (0, traversal_1.getDisplayHeightSegment)(track);
|
|
129
|
+
const displayWidth = (0, traversal_1.getDisplayWidthSegment)(track);
|
|
130
|
+
const codec = (0, traversal_1.getCodecSegment)(track);
|
|
131
|
+
if (!codec) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const codecString = getMatroskaVideoCodecString({
|
|
135
|
+
track,
|
|
136
|
+
codecSegment: codec,
|
|
137
|
+
});
|
|
138
|
+
if (!codecString) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
type: 'video',
|
|
143
|
+
trackId,
|
|
144
|
+
codec: codecString,
|
|
145
|
+
description: getDescription(track),
|
|
146
|
+
height: displayHeight ? displayHeight.value.value : height.value.value,
|
|
147
|
+
width: displayWidth ? displayWidth.value.value : width.value.value,
|
|
148
|
+
sampleAspectRatio: {
|
|
149
|
+
numerator: 1,
|
|
150
|
+
denominator: 1,
|
|
151
|
+
},
|
|
152
|
+
timescale,
|
|
153
|
+
codedHeight: height.value.value,
|
|
154
|
+
codedWidth: width.value.value,
|
|
155
|
+
displayAspectHeight: displayHeight
|
|
156
|
+
? displayHeight.value.value
|
|
157
|
+
: height.value.value,
|
|
158
|
+
displayAspectWidth: displayWidth
|
|
159
|
+
? displayWidth.value.value
|
|
160
|
+
: width.value.value,
|
|
161
|
+
rotation: 0,
|
|
162
|
+
trakBox: null,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
if ((0, track_entry_1.trackTypeToString)(trackType.value.value) === 'audio') {
|
|
166
|
+
const sampleRate = (0, traversal_1.getSampleRate)(track);
|
|
167
|
+
const numberOfChannels = (0, traversal_1.getNumberOfChannels)(track);
|
|
168
|
+
if (sampleRate === null) {
|
|
169
|
+
throw new Error('Could not find sample rate or number of channels');
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
type: 'audio',
|
|
173
|
+
trackId,
|
|
174
|
+
codec: getMatroskaAudioCodecString(track),
|
|
175
|
+
timescale,
|
|
176
|
+
numberOfChannels,
|
|
177
|
+
sampleRate,
|
|
178
|
+
description: (0, description_1.getAudioDescription)(track),
|
|
179
|
+
trakBox: null,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
};
|
|
184
|
+
exports.getTrack = getTrack;
|
package/dist/esm/from-node.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/readers/from-node.ts
|
|
2
|
-
import {createReadStream} from "fs";
|
|
3
|
-
import {stat} from "node:fs/promises";
|
|
4
|
-
import {Readable} from "stream";
|
|
2
|
+
import { createReadStream } from "fs";
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import { Readable } from "stream";
|
|
5
5
|
var nodeReader = {
|
|
6
6
|
read: async (src, range, signal) => {
|
|
7
7
|
if (typeof src !== "string") {
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1233,14 +1233,14 @@ var makeMatroskaHeader = () => {
|
|
|
1233
1233
|
};
|
|
1234
1234
|
|
|
1235
1235
|
// src/create/matroska-info.ts
|
|
1236
|
-
var makeMatroskaInfo = ({ timescale
|
|
1236
|
+
var makeMatroskaInfo = ({ timescale }) => {
|
|
1237
1237
|
return makeMatroskaBytes({
|
|
1238
1238
|
type: "Info",
|
|
1239
1239
|
value: [
|
|
1240
1240
|
{
|
|
1241
1241
|
type: "TimestampScale",
|
|
1242
1242
|
value: {
|
|
1243
|
-
value:
|
|
1243
|
+
value: timescale,
|
|
1244
1244
|
byteLength: null
|
|
1245
1245
|
},
|
|
1246
1246
|
minVintWidth: null
|
|
@@ -1569,7 +1569,7 @@ var makeMatroskaColorBytes = ({
|
|
|
1569
1569
|
|
|
1570
1570
|
// src/create/matroska-trackentry.ts
|
|
1571
1571
|
var makeMatroskaVideoBytes = ({
|
|
1572
|
-
color:
|
|
1572
|
+
color: color2,
|
|
1573
1573
|
width,
|
|
1574
1574
|
height
|
|
1575
1575
|
}) => {
|
|
@@ -1600,7 +1600,7 @@ var makeMatroskaVideoBytes = ({
|
|
|
1600
1600
|
},
|
|
1601
1601
|
minVintWidth: null
|
|
1602
1602
|
},
|
|
1603
|
-
makeMatroskaColorBytes(
|
|
1603
|
+
makeMatroskaColorBytes(color2)
|
|
1604
1604
|
],
|
|
1605
1605
|
minVintWidth: null
|
|
1606
1606
|
});
|
|
@@ -1735,7 +1735,7 @@ var makeMatroskaAudioTrackEntryBytes = ({
|
|
|
1735
1735
|
});
|
|
1736
1736
|
};
|
|
1737
1737
|
var makeMatroskaVideoTrackEntryBytes = ({
|
|
1738
|
-
color:
|
|
1738
|
+
color: color2,
|
|
1739
1739
|
width,
|
|
1740
1740
|
height,
|
|
1741
1741
|
trackNumber: trackNumber2,
|
|
@@ -1794,7 +1794,7 @@ var makeMatroskaVideoTrackEntryBytes = ({
|
|
|
1794
1794
|
minVintWidth: null
|
|
1795
1795
|
},
|
|
1796
1796
|
makeMatroskaVideoBytes({
|
|
1797
|
-
color:
|
|
1797
|
+
color: color2,
|
|
1798
1798
|
width,
|
|
1799
1799
|
height
|
|
1800
1800
|
}),
|
|
@@ -1890,13 +1890,13 @@ var createMedia = async (writer) => {
|
|
|
1890
1890
|
};
|
|
1891
1891
|
const addSample = async (chunk, trackNumber2, isVideo) => {
|
|
1892
1892
|
trackNumberProgresses[trackNumber2] = chunk.timestamp;
|
|
1893
|
-
const { cluster
|
|
1893
|
+
const { cluster, isNew, smallestProgress } = await getClusterOrMakeNew({
|
|
1894
1894
|
chunk,
|
|
1895
1895
|
isVideo
|
|
1896
1896
|
});
|
|
1897
1897
|
const newDuration = Math.round((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
1898
1898
|
await updateDuration(newDuration);
|
|
1899
|
-
const { timecodeRelativeToCluster } = await
|
|
1899
|
+
const { timecodeRelativeToCluster } = await cluster.addSample(chunk, trackNumber2);
|
|
1900
1900
|
if (isNew) {
|
|
1901
1901
|
const newCluster = w.getWrittenByteCount();
|
|
1902
1902
|
cues.push({
|
|
@@ -3474,7 +3474,7 @@ var getMatroskaAudioCodecString = (track) => {
|
|
|
3474
3474
|
throw new Error(`Unknown codec: ${codec.value}`);
|
|
3475
3475
|
};
|
|
3476
3476
|
var getTrack = ({
|
|
3477
|
-
timescale
|
|
3477
|
+
timescale,
|
|
3478
3478
|
track
|
|
3479
3479
|
}) => {
|
|
3480
3480
|
const trackType2 = getTrackTypeSegment(track);
|
|
@@ -3517,7 +3517,7 @@ var getTrack = ({
|
|
|
3517
3517
|
numerator: 1,
|
|
3518
3518
|
denominator: 1
|
|
3519
3519
|
},
|
|
3520
|
-
timescale
|
|
3520
|
+
timescale,
|
|
3521
3521
|
codedHeight: height.value.value,
|
|
3522
3522
|
codedWidth: width.value.value,
|
|
3523
3523
|
displayAspectHeight: displayHeight2 ? displayHeight2.value.value : height.value.value,
|
|
@@ -3547,7 +3547,7 @@ var getTrack = ({
|
|
|
3547
3547
|
type: "audio",
|
|
3548
3548
|
trackId,
|
|
3549
3549
|
codec: getMatroskaAudioCodecString(track),
|
|
3550
|
-
timescale
|
|
3550
|
+
timescale,
|
|
3551
3551
|
numberOfChannels,
|
|
3552
3552
|
sampleRate,
|
|
3553
3553
|
description: getAudioDescription(track),
|
|
@@ -3562,7 +3562,7 @@ var getTrack = ({
|
|
|
3562
3562
|
};
|
|
3563
3563
|
|
|
3564
3564
|
// src/boxes/webm/get-ready-tracks.ts
|
|
3565
|
-
var getTracksFromMatroska = (segment,
|
|
3565
|
+
var getTracksFromMatroska = (segment, timescale) => {
|
|
3566
3566
|
const tracksSegment = getTracksSegment(segment);
|
|
3567
3567
|
if (!tracksSegment) {
|
|
3568
3568
|
throw new Error("No tracks segment");
|
|
@@ -3577,7 +3577,7 @@ var getTracksFromMatroska = (segment, timescale3) => {
|
|
|
3577
3577
|
}
|
|
3578
3578
|
const track = getTrack({
|
|
3579
3579
|
track: trackEntrySegment,
|
|
3580
|
-
timescale
|
|
3580
|
+
timescale
|
|
3581
3581
|
});
|
|
3582
3582
|
if (track) {
|
|
3583
3583
|
tracks2.push(track);
|
|
@@ -4383,7 +4383,7 @@ var parseMdhd = ({
|
|
|
4383
4383
|
data.discard(3);
|
|
4384
4384
|
const creationTime = version === 1 ? Number(data.getUint64()) : data.getUint32();
|
|
4385
4385
|
const modificationTime = version === 1 ? Number(data.getUint64()) : data.getUint32();
|
|
4386
|
-
const
|
|
4386
|
+
const timescale = data.getUint32();
|
|
4387
4387
|
const duration2 = version === 1 ? data.getUint64() : data.getUint32();
|
|
4388
4388
|
const language2 = data.getUint16();
|
|
4389
4389
|
const quality = data.getUint16();
|
|
@@ -4394,7 +4394,7 @@ var parseMdhd = ({
|
|
|
4394
4394
|
return {
|
|
4395
4395
|
type: "mdhd-box",
|
|
4396
4396
|
duration: Number(duration2),
|
|
4397
|
-
timescale
|
|
4397
|
+
timescale,
|
|
4398
4398
|
version,
|
|
4399
4399
|
language: language2,
|
|
4400
4400
|
quality,
|
|
@@ -5133,13 +5133,13 @@ var parseStsz = ({
|
|
|
5133
5133
|
sampleSize
|
|
5134
5134
|
};
|
|
5135
5135
|
}
|
|
5136
|
-
const
|
|
5136
|
+
const samples = [];
|
|
5137
5137
|
for (let i = 0;i < sampleCount; i++) {
|
|
5138
5138
|
const bytesRemaining = size - (iterator.counter.getOffset() - offset);
|
|
5139
5139
|
if (bytesRemaining < 4) {
|
|
5140
5140
|
break;
|
|
5141
5141
|
}
|
|
5142
|
-
|
|
5142
|
+
samples.push(iterator.getUint32());
|
|
5143
5143
|
}
|
|
5144
5144
|
iterator.discard(size - (iterator.counter.getOffset() - offset));
|
|
5145
5145
|
return {
|
|
@@ -5150,7 +5150,7 @@ var parseStsz = ({
|
|
|
5150
5150
|
flags: [...flags],
|
|
5151
5151
|
sampleCount,
|
|
5152
5152
|
countType: "variable",
|
|
5153
|
-
entries:
|
|
5153
|
+
entries: samples
|
|
5154
5154
|
};
|
|
5155
5155
|
};
|
|
5156
5156
|
|
|
@@ -5371,13 +5371,13 @@ var parseTrun = ({
|
|
|
5371
5371
|
const sampleCount = iterator.getUint32();
|
|
5372
5372
|
const dataOffset = flags & 1 ? iterator.getInt32() : null;
|
|
5373
5373
|
const firstSampleFlags = flags & 4 ? iterator.getUint32() : null;
|
|
5374
|
-
const
|
|
5374
|
+
const samples = [];
|
|
5375
5375
|
for (let i = 0;i < sampleCount; i++) {
|
|
5376
5376
|
const sampleDuration = flags & 256 ? iterator.getUint32() : null;
|
|
5377
5377
|
const sampleSize = flags & 512 ? iterator.getUint32() : null;
|
|
5378
5378
|
const sampleFlags = flags & 1024 ? iterator.getUint32() : null;
|
|
5379
5379
|
const sampleCompositionTimeOffset = flags & 2048 ? version === 0 ? iterator.getUint32() : iterator.getInt32Le() : null;
|
|
5380
|
-
|
|
5380
|
+
samples.push({
|
|
5381
5381
|
sampleDuration,
|
|
5382
5382
|
sampleSize,
|
|
5383
5383
|
sampleFlags,
|
|
@@ -5395,7 +5395,7 @@ var parseTrun = ({
|
|
|
5395
5395
|
sampleCount,
|
|
5396
5396
|
dataOffset,
|
|
5397
5397
|
firstSampleFlags,
|
|
5398
|
-
samples
|
|
5398
|
+
samples
|
|
5399
5399
|
};
|
|
5400
5400
|
};
|
|
5401
5401
|
|
|
@@ -6075,26 +6075,26 @@ var parseBlockFlags = (iterator, type) => {
|
|
|
6075
6075
|
};
|
|
6076
6076
|
|
|
6077
6077
|
// src/boxes/webm/get-sample-from-block.ts
|
|
6078
|
-
var getSampleFromBlock = (
|
|
6079
|
-
const iterator = getArrayBufferIterator(
|
|
6078
|
+
var getSampleFromBlock = (ebml, parserContext, offset) => {
|
|
6079
|
+
const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
|
|
6080
6080
|
const trackNumber2 = iterator.getVint();
|
|
6081
6081
|
if (trackNumber2 === null) {
|
|
6082
6082
|
throw new Error("Not enough data to get track number, should not happen");
|
|
6083
6083
|
}
|
|
6084
6084
|
const timecodeRelativeToCluster = iterator.getInt16();
|
|
6085
|
-
const { keyframe } = parseBlockFlags(iterator,
|
|
6085
|
+
const { keyframe } = parseBlockFlags(iterator, ebml.type === "SimpleBlock" ? matroskaElements.SimpleBlock : matroskaElements.Block);
|
|
6086
6086
|
const { codec, trackTimescale } = parserContext.parserState.getTrackInfoByNumber(trackNumber2);
|
|
6087
6087
|
const clusterOffset = parserContext.parserState.getTimestampOffsetForByteOffset(offset);
|
|
6088
|
-
const
|
|
6088
|
+
const timescale = parserContext.parserState.getTimescale();
|
|
6089
6089
|
if (clusterOffset === undefined) {
|
|
6090
6090
|
throw new Error("Could not find offset for byte offset " + offset);
|
|
6091
6091
|
}
|
|
6092
|
-
const timecodeInNanoSeconds = (timecodeRelativeToCluster + clusterOffset) *
|
|
6092
|
+
const timecodeInNanoSeconds = (timecodeRelativeToCluster + clusterOffset) * timescale * (trackTimescale ?? 1);
|
|
6093
6093
|
const timecodeInMicroseconds = timecodeInNanoSeconds / 1000;
|
|
6094
6094
|
if (!codec) {
|
|
6095
6095
|
throw new Error(`Could not find codec for track ${trackNumber2}`);
|
|
6096
6096
|
}
|
|
6097
|
-
const remainingNow =
|
|
6097
|
+
const remainingNow = ebml.value.length - (iterator.counter.getOffset() - 0);
|
|
6098
6098
|
if (codec.startsWith("V_")) {
|
|
6099
6099
|
const partialVideoSample = {
|
|
6100
6100
|
data: iterator.getSlice(remainingNow),
|
|
@@ -6231,16 +6231,16 @@ var parseEbml = async (iterator, parserContext) => {
|
|
|
6231
6231
|
};
|
|
6232
6232
|
var postprocessEbml = async ({
|
|
6233
6233
|
offset,
|
|
6234
|
-
ebml
|
|
6234
|
+
ebml,
|
|
6235
6235
|
parserContext
|
|
6236
6236
|
}) => {
|
|
6237
|
-
if (
|
|
6238
|
-
parserContext.parserState.setTimescale(
|
|
6237
|
+
if (ebml.type === "TimestampScale") {
|
|
6238
|
+
parserContext.parserState.setTimescale(ebml.value.value);
|
|
6239
6239
|
}
|
|
6240
|
-
if (
|
|
6241
|
-
parserContext.parserState.onTrackEntrySegment(
|
|
6240
|
+
if (ebml.type === "TrackEntry") {
|
|
6241
|
+
parserContext.parserState.onTrackEntrySegment(ebml);
|
|
6242
6242
|
const track = getTrack({
|
|
6243
|
-
track:
|
|
6243
|
+
track: ebml,
|
|
6244
6244
|
timescale: parserContext.parserState.getTimescale()
|
|
6245
6245
|
});
|
|
6246
6246
|
if (track) {
|
|
@@ -6251,17 +6251,17 @@ var postprocessEbml = async ({
|
|
|
6251
6251
|
});
|
|
6252
6252
|
}
|
|
6253
6253
|
}
|
|
6254
|
-
if (
|
|
6255
|
-
parserContext.parserState.setTimestampOffset(offset,
|
|
6254
|
+
if (ebml.type === "Timestamp") {
|
|
6255
|
+
parserContext.parserState.setTimestampOffset(offset, ebml.value.value);
|
|
6256
6256
|
}
|
|
6257
|
-
if (
|
|
6258
|
-
const sample = getSampleFromBlock(
|
|
6257
|
+
if (ebml.type === "Block" || ebml.type === "SimpleBlock") {
|
|
6258
|
+
const sample = getSampleFromBlock(ebml, parserContext, offset);
|
|
6259
6259
|
if (sample.type === "video-sample" && parserContext.nullifySamples) {
|
|
6260
6260
|
await parserContext.parserState.onVideoSample(sample.videoSample.trackId, sample.videoSample);
|
|
6261
6261
|
return {
|
|
6262
6262
|
type: "Block",
|
|
6263
6263
|
value: new Uint8Array([]),
|
|
6264
|
-
minVintWidth:
|
|
6264
|
+
minVintWidth: ebml.minVintWidth
|
|
6265
6265
|
};
|
|
6266
6266
|
}
|
|
6267
6267
|
if (sample.type === "audio-sample" && parserContext.nullifySamples) {
|
|
@@ -6269,23 +6269,23 @@ var postprocessEbml = async ({
|
|
|
6269
6269
|
return {
|
|
6270
6270
|
type: "Block",
|
|
6271
6271
|
value: new Uint8Array([]),
|
|
6272
|
-
minVintWidth:
|
|
6272
|
+
minVintWidth: ebml.minVintWidth
|
|
6273
6273
|
};
|
|
6274
6274
|
}
|
|
6275
6275
|
if (sample.type === "no-sample" && parserContext.nullifySamples) {
|
|
6276
6276
|
return {
|
|
6277
6277
|
type: "Block",
|
|
6278
6278
|
value: new Uint8Array([]),
|
|
6279
|
-
minVintWidth:
|
|
6279
|
+
minVintWidth: ebml.minVintWidth
|
|
6280
6280
|
};
|
|
6281
6281
|
}
|
|
6282
6282
|
}
|
|
6283
|
-
if (
|
|
6284
|
-
const block2 =
|
|
6283
|
+
if (ebml.type === "BlockGroup") {
|
|
6284
|
+
const block2 = ebml.value.find((c) => c.type === "SimpleBlock" || c.type === "Block");
|
|
6285
6285
|
if (!block2 || block2.type !== "SimpleBlock" && block2.type !== "Block") {
|
|
6286
6286
|
throw new Error("Expected block segment");
|
|
6287
6287
|
}
|
|
6288
|
-
const hasReferenceBlock =
|
|
6288
|
+
const hasReferenceBlock = ebml.value.find((c) => c.type === "ReferenceBlock");
|
|
6289
6289
|
const sample = block2.value.length === 0 ? null : getSampleFromBlock(block2, parserContext, offset);
|
|
6290
6290
|
if (sample && sample.type === "partial-video-sample") {
|
|
6291
6291
|
const completeFrame = {
|
|
@@ -6298,11 +6298,11 @@ var postprocessEbml = async ({
|
|
|
6298
6298
|
return {
|
|
6299
6299
|
type: "BlockGroup",
|
|
6300
6300
|
value: [],
|
|
6301
|
-
minVintWidth:
|
|
6301
|
+
minVintWidth: ebml.minVintWidth
|
|
6302
6302
|
};
|
|
6303
6303
|
}
|
|
6304
6304
|
}
|
|
6305
|
-
return
|
|
6305
|
+
return ebml;
|
|
6306
6306
|
};
|
|
6307
6307
|
|
|
6308
6308
|
// src/boxes/webm/segments.ts
|
|
@@ -6318,8 +6318,8 @@ var parseSegment = async ({
|
|
|
6318
6318
|
}
|
|
6319
6319
|
iterator.counter.decrement(headerReadSoFar);
|
|
6320
6320
|
const offset = iterator.counter.getOffset();
|
|
6321
|
-
const
|
|
6322
|
-
const remapped = await postprocessEbml({ offset, ebml
|
|
6321
|
+
const ebml = await parseEbml(iterator, parserContext);
|
|
6322
|
+
const remapped = await postprocessEbml({ offset, ebml, parserContext });
|
|
6323
6323
|
return remapped;
|
|
6324
6324
|
};
|
|
6325
6325
|
var expectSegment = async (iterator, parserContext) => {
|
|
@@ -6612,15 +6612,15 @@ var makeParserState = ({
|
|
|
6612
6612
|
const queuedAudioSamples = {};
|
|
6613
6613
|
const queuedVideoSamples = {};
|
|
6614
6614
|
const declinedTrackNumbers = [];
|
|
6615
|
-
let
|
|
6615
|
+
let timescale = null;
|
|
6616
6616
|
const getTimescale = () => {
|
|
6617
|
-
if (
|
|
6617
|
+
if (timescale === null) {
|
|
6618
6618
|
return 1e6;
|
|
6619
6619
|
}
|
|
6620
|
-
return
|
|
6620
|
+
return timescale;
|
|
6621
6621
|
};
|
|
6622
6622
|
const setTimescale = (newTimescale) => {
|
|
6623
|
-
|
|
6623
|
+
timescale = newTimescale;
|
|
6624
6624
|
};
|
|
6625
6625
|
const timestampMap = new Map;
|
|
6626
6626
|
const setTimestampOffset = (byteOffset, timestamp) => {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchReader = void 0;
|
|
4
|
+
exports.fetchReader = {
|
|
5
|
+
read: async (src, range, signal) => {
|
|
6
|
+
if (typeof src !== 'string') {
|
|
7
|
+
throw new Error('src must be a string when using `fetchReader`');
|
|
8
|
+
}
|
|
9
|
+
const resolvedUrl = typeof window !== 'undefined' && typeof window.location !== 'undefined'
|
|
10
|
+
? new URL(src, window.location.origin).toString()
|
|
11
|
+
: src;
|
|
12
|
+
if (!resolvedUrl.startsWith('https://') &&
|
|
13
|
+
!resolvedUrl.startsWith('http://')) {
|
|
14
|
+
return Promise.reject(new Error(resolvedUrl +
|
|
15
|
+
' is not a URL - needs to start with http:// or https://. If you want to read a local file, pass `nodeReader` to parseMedia().'));
|
|
16
|
+
}
|
|
17
|
+
const res = await fetch(resolvedUrl, {
|
|
18
|
+
headers: range === null
|
|
19
|
+
? {}
|
|
20
|
+
: typeof range === 'number'
|
|
21
|
+
? {
|
|
22
|
+
Range: `bytes=${range}`,
|
|
23
|
+
}
|
|
24
|
+
: {
|
|
25
|
+
Range: `bytes=${`${range[0]}-${range[1]}`}`,
|
|
26
|
+
},
|
|
27
|
+
signal,
|
|
28
|
+
// Disable Next.js caching
|
|
29
|
+
cache: 'no-store',
|
|
30
|
+
});
|
|
31
|
+
if (res.status.toString().startsWith('4') ||
|
|
32
|
+
res.status.toString().startsWith('5')) {
|
|
33
|
+
throw new Error(`Server returned status code ${res.status} for ${src}`);
|
|
34
|
+
}
|
|
35
|
+
if (!res.body) {
|
|
36
|
+
throw new Error('No body');
|
|
37
|
+
}
|
|
38
|
+
const length = res.headers.get('content-length');
|
|
39
|
+
const contentLength = length === null ? null : parseInt(length, 10);
|
|
40
|
+
const reader = res.body.getReader();
|
|
41
|
+
if (signal) {
|
|
42
|
+
signal.addEventListener('abort', () => {
|
|
43
|
+
reader.cancel();
|
|
44
|
+
}, { once: true });
|
|
45
|
+
}
|
|
46
|
+
return { reader, contentLength };
|
|
47
|
+
},
|
|
48
|
+
getLength: async (src) => {
|
|
49
|
+
if (typeof src !== 'string') {
|
|
50
|
+
throw new Error('src must be a string when using `fetchReader`');
|
|
51
|
+
}
|
|
52
|
+
const res = await fetch(src, {
|
|
53
|
+
method: 'HEAD',
|
|
54
|
+
});
|
|
55
|
+
if (!res.body) {
|
|
56
|
+
throw new Error('No body');
|
|
57
|
+
}
|
|
58
|
+
const length = res.headers.get('content-length');
|
|
59
|
+
if (!length) {
|
|
60
|
+
throw new Error('No content-length');
|
|
61
|
+
}
|
|
62
|
+
return parseInt(length, 10);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
@@ -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
|
+
};
|
package/dist/reader.d.ts
ADDED
|
@@ -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/reader.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { FtypBox } from './boxes/iso-base-media/ftyp';
|
|
2
|
+
import type { MdhdBox } from './boxes/iso-base-media/mdhd';
|
|
3
|
+
import type { MoovBox } from './boxes/iso-base-media/moov/moov';
|
|
4
|
+
import type { MvhdBox } from './boxes/iso-base-media/mvhd';
|
|
5
|
+
import type { CttsBox } from './boxes/iso-base-media/stsd/ctts';
|
|
6
|
+
import type { StcoBox } from './boxes/iso-base-media/stsd/stco';
|
|
7
|
+
import type { StscBox } from './boxes/iso-base-media/stsd/stsc';
|
|
8
|
+
import type { StsdBox } from './boxes/iso-base-media/stsd/stsd';
|
|
9
|
+
import type { StssBox } from './boxes/iso-base-media/stsd/stss';
|
|
10
|
+
import type { StszBox } from './boxes/iso-base-media/stsd/stsz';
|
|
11
|
+
import type { SttsBox } from './boxes/iso-base-media/stsd/stts';
|
|
12
|
+
import type { TfdtBox } from './boxes/iso-base-media/tfdt';
|
|
13
|
+
import type { TfhdBox } from './boxes/iso-base-media/tfhd';
|
|
14
|
+
import type { TkhdBox } from './boxes/iso-base-media/tkhd';
|
|
15
|
+
import type { TrakBox } from './boxes/iso-base-media/trak/trak';
|
|
16
|
+
import type { TrunBox } from './boxes/iso-base-media/trun';
|
|
17
|
+
import type { AudioSegment, ClusterSegment, CodecIdSegment, DisplayHeightSegment, DisplayWidthSegment, HeightSegment, MainSegment, TimestampScaleSegment, TrackEntry, TrackTypeSegment, VideoSegment, WidthSegment } from './boxes/webm/segments/all-segments';
|
|
18
|
+
import type { AnySegment, IsoBaseMediaBox, RegularBox } from './parse-result';
|
|
19
|
+
export declare const getFtypBox: (segments: AnySegment[]) => FtypBox | null;
|
|
20
|
+
export declare const getMoovBox: (segments: AnySegment[]) => MoovBox | null;
|
|
21
|
+
export declare const getMoofBox: (main: AnySegment[]) => IsoBaseMediaBox | null;
|
|
22
|
+
export declare const getMvhdBox: (moovBox: MoovBox) => MvhdBox | null;
|
|
23
|
+
export declare const getTraks: (moovBox: MoovBox) => TrakBox[];
|
|
24
|
+
export declare const getTkhdBox: (trakBox: TrakBox) => TkhdBox | null;
|
|
25
|
+
export declare const getMdiaBox: (trakBox: TrakBox) => RegularBox | null;
|
|
26
|
+
export declare const getMdhdBox: (trakBox: TrakBox) => MdhdBox | null;
|
|
27
|
+
export declare const getStblBox: (trakBox: TrakBox) => RegularBox | null;
|
|
28
|
+
export declare const getStsdBox: (trakBox: TrakBox) => StsdBox | null;
|
|
29
|
+
export declare const getVideoDescriptors: (trakBox: TrakBox) => Uint8Array | null;
|
|
30
|
+
export declare const getStcoBox: (trakBox: TrakBox) => StcoBox | null;
|
|
31
|
+
export declare const getSttsBox: (trakBox: TrakBox) => SttsBox | null;
|
|
32
|
+
export declare const getCttsBox: (trakBox: TrakBox) => CttsBox | null;
|
|
33
|
+
export declare const getStszBox: (trakBox: TrakBox) => StszBox | null;
|
|
34
|
+
export declare const getStscBox: (trakBox: TrakBox) => StscBox | null;
|
|
35
|
+
export declare const getStssBox: (trakBox: TrakBox) => StssBox | null;
|
|
36
|
+
export declare const getTfdtBox: (segment: IsoBaseMediaBox) => TfdtBox | null;
|
|
37
|
+
export declare const getTfhdBox: (segment: IsoBaseMediaBox) => TfhdBox | null;
|
|
38
|
+
export declare const getTrunBoxes: (segment: IsoBaseMediaBox) => TrunBox[];
|
|
39
|
+
export declare const getClusterSegment: (segment: MainSegment) => ClusterSegment | null;
|
|
40
|
+
export declare const getTracksSegment: (segment: MainSegment) => {
|
|
41
|
+
type: "Tracks";
|
|
42
|
+
value: import("./boxes/webm/segments/all-segments").PossibleEbml[];
|
|
43
|
+
minVintWidth: number | null;
|
|
44
|
+
} | null;
|
|
45
|
+
export declare const getTimescaleSegment: (segment: MainSegment) => TimestampScaleSegment | null;
|
|
46
|
+
export declare const getVideoSegment: (track: TrackEntry) => VideoSegment | null;
|
|
47
|
+
export declare const getAudioSegment: (track: TrackEntry) => AudioSegment | null;
|
|
48
|
+
export declare const getSampleRate: (track: TrackEntry) => number | null;
|
|
49
|
+
export declare const getNumberOfChannels: (track: TrackEntry) => number;
|
|
50
|
+
export declare const getBitDepth: (track: TrackEntry) => number | null;
|
|
51
|
+
export declare const getPrivateData: (track: TrackEntry) => Uint8Array | null;
|
|
52
|
+
export declare const getWidthSegment: (track: TrackEntry) => WidthSegment | null;
|
|
53
|
+
export declare const getHeightSegment: (track: TrackEntry) => HeightSegment | null;
|
|
54
|
+
export declare const getDisplayWidthSegment: (track: TrackEntry) => DisplayWidthSegment | null;
|
|
55
|
+
export declare const getDisplayHeightSegment: (track: TrackEntry) => DisplayHeightSegment | null;
|
|
56
|
+
export declare const getTrackTypeSegment: (track: TrackEntry) => TrackTypeSegment | null;
|
|
57
|
+
export declare const getTrackId: (track: TrackEntry) => number;
|
|
58
|
+
export declare const getCodecSegment: (track: TrackEntry) => CodecIdSegment | null;
|
|
59
|
+
export declare const hasSkippedMdatProcessing: (anySegment: AnySegment[]) => {
|
|
60
|
+
skipped: false;
|
|
61
|
+
fileOffset?: undefined;
|
|
62
|
+
} | {
|
|
63
|
+
skipped: boolean;
|
|
64
|
+
fileOffset: number;
|
|
65
|
+
};
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hasSkippedMdatProcessing = exports.getCodecSegment = exports.getTrackId = exports.getTrackTypeSegment = exports.getDisplayHeightSegment = exports.getDisplayWidthSegment = exports.getHeightSegment = exports.getWidthSegment = exports.getPrivateData = exports.getBitDepth = exports.getNumberOfChannels = exports.getSampleRate = exports.getAudioSegment = exports.getVideoSegment = exports.getTimescaleSegment = exports.getTracksSegment = exports.getClusterSegment = exports.getTrunBoxes = exports.getTfhdBox = exports.getTfdtBox = exports.getStssBox = exports.getStscBox = exports.getStszBox = exports.getCttsBox = exports.getSttsBox = exports.getStcoBox = exports.getVideoDescriptors = exports.getStsdBox = exports.getStblBox = exports.getMdhdBox = exports.getMdiaBox = exports.getTkhdBox = exports.getTraks = exports.getMvhdBox = exports.getMoofBox = exports.getMoovBox = exports.getFtypBox = void 0;
|
|
4
|
+
const getFtypBox = (segments) => {
|
|
5
|
+
const ftypBox = segments.find((s) => s.type === 'ftyp-box');
|
|
6
|
+
if (!ftypBox || ftypBox.type !== 'ftyp-box') {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
return ftypBox;
|
|
10
|
+
};
|
|
11
|
+
exports.getFtypBox = getFtypBox;
|
|
12
|
+
const getMoovBox = (segments) => {
|
|
13
|
+
const moovBox = segments.find((s) => s.type === 'moov-box');
|
|
14
|
+
if (!moovBox || moovBox.type !== 'moov-box') {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return moovBox;
|
|
18
|
+
};
|
|
19
|
+
exports.getMoovBox = getMoovBox;
|
|
20
|
+
const getMoofBox = (main) => {
|
|
21
|
+
const moofBox = main.find((s) => s.type === 'regular-box' && s.boxType === 'moof');
|
|
22
|
+
if (!moofBox || moofBox.type !== 'regular-box') {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return moofBox;
|
|
26
|
+
};
|
|
27
|
+
exports.getMoofBox = getMoofBox;
|
|
28
|
+
const getMvhdBox = (moovBox) => {
|
|
29
|
+
const mvHdBox = moovBox.children.find((s) => s.type === 'mvhd-box');
|
|
30
|
+
if (!mvHdBox || mvHdBox.type !== 'mvhd-box') {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return mvHdBox;
|
|
34
|
+
};
|
|
35
|
+
exports.getMvhdBox = getMvhdBox;
|
|
36
|
+
const getTraks = (moovBox) => {
|
|
37
|
+
return moovBox.children.filter((s) => s.type === 'trak-box');
|
|
38
|
+
};
|
|
39
|
+
exports.getTraks = getTraks;
|
|
40
|
+
const getTkhdBox = (trakBox) => {
|
|
41
|
+
const tkhdBox = trakBox.children.find((s) => s.type === 'tkhd-box');
|
|
42
|
+
return tkhdBox;
|
|
43
|
+
};
|
|
44
|
+
exports.getTkhdBox = getTkhdBox;
|
|
45
|
+
const getMdiaBox = (trakBox) => {
|
|
46
|
+
const mdiaBox = trakBox.children.find((s) => s.type === 'regular-box' && s.boxType === 'mdia');
|
|
47
|
+
if (!mdiaBox || mdiaBox.type !== 'regular-box') {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return mdiaBox;
|
|
51
|
+
};
|
|
52
|
+
exports.getMdiaBox = getMdiaBox;
|
|
53
|
+
const getMdhdBox = (trakBox) => {
|
|
54
|
+
const mdiaBox = (0, exports.getMdiaBox)(trakBox);
|
|
55
|
+
if (!mdiaBox) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const mdhdBox = mdiaBox.children.find((c) => c.type === 'mdhd-box');
|
|
59
|
+
return mdhdBox;
|
|
60
|
+
};
|
|
61
|
+
exports.getMdhdBox = getMdhdBox;
|
|
62
|
+
const getStblBox = (trakBox) => {
|
|
63
|
+
const mdiaBox = (0, exports.getMdiaBox)(trakBox);
|
|
64
|
+
if (!mdiaBox) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const minfBox = mdiaBox.children.find((s) => s.type === 'regular-box' && s.boxType === 'minf');
|
|
68
|
+
if (!minfBox || minfBox.type !== 'regular-box') {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const stblBox = minfBox.children.find((s) => s.type === 'regular-box' && s.boxType === 'stbl');
|
|
72
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return stblBox;
|
|
76
|
+
};
|
|
77
|
+
exports.getStblBox = getStblBox;
|
|
78
|
+
const getStsdBox = (trakBox) => {
|
|
79
|
+
const stblBox = (0, exports.getStblBox)(trakBox);
|
|
80
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const stsdBox = stblBox.children.find((s) => s.type === 'stsd-box');
|
|
84
|
+
return stsdBox;
|
|
85
|
+
};
|
|
86
|
+
exports.getStsdBox = getStsdBox;
|
|
87
|
+
const getVideoDescriptors = (trakBox) => {
|
|
88
|
+
var _a;
|
|
89
|
+
const stsdBox = (0, exports.getStsdBox)(trakBox);
|
|
90
|
+
if (!stsdBox) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const descriptors = stsdBox.samples.map((s) => {
|
|
94
|
+
return s.type === 'video'
|
|
95
|
+
? s.descriptors.map((d) => {
|
|
96
|
+
return d.type === 'avcc-box'
|
|
97
|
+
? d.description
|
|
98
|
+
: d.type === 'hvcc-box'
|
|
99
|
+
? d.data
|
|
100
|
+
: null;
|
|
101
|
+
})
|
|
102
|
+
: [];
|
|
103
|
+
});
|
|
104
|
+
return (_a = descriptors.flat(1).filter(Boolean)[0]) !== null && _a !== void 0 ? _a : null;
|
|
105
|
+
};
|
|
106
|
+
exports.getVideoDescriptors = getVideoDescriptors;
|
|
107
|
+
const getStcoBox = (trakBox) => {
|
|
108
|
+
const stblBox = (0, exports.getStblBox)(trakBox);
|
|
109
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const stcoBox = stblBox.children.find((s) => s.type === 'stco-box');
|
|
113
|
+
return stcoBox;
|
|
114
|
+
};
|
|
115
|
+
exports.getStcoBox = getStcoBox;
|
|
116
|
+
const getSttsBox = (trakBox) => {
|
|
117
|
+
const stblBox = (0, exports.getStblBox)(trakBox);
|
|
118
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const sttsBox = stblBox.children.find((s) => s.type === 'stts-box');
|
|
122
|
+
return sttsBox;
|
|
123
|
+
};
|
|
124
|
+
exports.getSttsBox = getSttsBox;
|
|
125
|
+
const getCttsBox = (trakBox) => {
|
|
126
|
+
const stblBox = (0, exports.getStblBox)(trakBox);
|
|
127
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const cttsBox = stblBox.children.find((s) => s.type === 'ctts-box');
|
|
131
|
+
return cttsBox;
|
|
132
|
+
};
|
|
133
|
+
exports.getCttsBox = getCttsBox;
|
|
134
|
+
const getStszBox = (trakBox) => {
|
|
135
|
+
const stblBox = (0, exports.getStblBox)(trakBox);
|
|
136
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
const stszBox = stblBox.children.find((s) => s.type === 'stsz-box');
|
|
140
|
+
return stszBox;
|
|
141
|
+
};
|
|
142
|
+
exports.getStszBox = getStszBox;
|
|
143
|
+
const getStscBox = (trakBox) => {
|
|
144
|
+
const stblBox = (0, exports.getStblBox)(trakBox);
|
|
145
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
const stcoBox = stblBox.children.find((b) => b.type === 'stsc-box');
|
|
149
|
+
return stcoBox;
|
|
150
|
+
};
|
|
151
|
+
exports.getStscBox = getStscBox;
|
|
152
|
+
const getStssBox = (trakBox) => {
|
|
153
|
+
const stblBox = (0, exports.getStblBox)(trakBox);
|
|
154
|
+
if (!stblBox || stblBox.type !== 'regular-box') {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const stssBox = stblBox.children.find((b) => b.type === 'stss-box');
|
|
158
|
+
return stssBox;
|
|
159
|
+
};
|
|
160
|
+
exports.getStssBox = getStssBox;
|
|
161
|
+
const getTfdtBox = (segment) => {
|
|
162
|
+
if (segment.type !== 'regular-box' || segment.boxType !== 'traf') {
|
|
163
|
+
throw new Error('Expected traf-box');
|
|
164
|
+
}
|
|
165
|
+
const tfhdBox = segment.children.find((c) => c.type === 'tfdt-box');
|
|
166
|
+
if (!tfhdBox || tfhdBox.type !== 'tfdt-box') {
|
|
167
|
+
throw new Error('Expected tfhd-box');
|
|
168
|
+
}
|
|
169
|
+
return tfhdBox;
|
|
170
|
+
};
|
|
171
|
+
exports.getTfdtBox = getTfdtBox;
|
|
172
|
+
const getTfhdBox = (segment) => {
|
|
173
|
+
if (segment.type !== 'regular-box' || segment.boxType !== 'traf') {
|
|
174
|
+
throw new Error('Expected traf-box');
|
|
175
|
+
}
|
|
176
|
+
const tfhdBox = segment.children.find((c) => c.type === 'tfhd-box');
|
|
177
|
+
if (!tfhdBox || tfhdBox.type !== 'tfhd-box') {
|
|
178
|
+
throw new Error('Expected tfhd-box');
|
|
179
|
+
}
|
|
180
|
+
return tfhdBox;
|
|
181
|
+
};
|
|
182
|
+
exports.getTfhdBox = getTfhdBox;
|
|
183
|
+
const getTrunBoxes = (segment) => {
|
|
184
|
+
if (segment.type !== 'regular-box' || segment.boxType !== 'traf') {
|
|
185
|
+
throw new Error('Expected traf-box');
|
|
186
|
+
}
|
|
187
|
+
const trunBoxes = segment.children.filter((c) => c.type === 'trun-box');
|
|
188
|
+
return trunBoxes;
|
|
189
|
+
};
|
|
190
|
+
exports.getTrunBoxes = getTrunBoxes;
|
|
191
|
+
const getClusterSegment = (segment) => {
|
|
192
|
+
const clusterSegment = segment.value.find((b) => b.type === 'Cluster');
|
|
193
|
+
return clusterSegment !== null && clusterSegment !== void 0 ? clusterSegment : null;
|
|
194
|
+
};
|
|
195
|
+
exports.getClusterSegment = getClusterSegment;
|
|
196
|
+
const getTracksSegment = (segment) => {
|
|
197
|
+
const tracksSegment = segment.value.find((b) => b.type === 'Tracks');
|
|
198
|
+
if (!tracksSegment || tracksSegment.type !== 'Tracks') {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
return tracksSegment;
|
|
202
|
+
};
|
|
203
|
+
exports.getTracksSegment = getTracksSegment;
|
|
204
|
+
const getTimescaleSegment = (segment) => {
|
|
205
|
+
const infoSegment = segment.value.find((b) => b.type === 'Info');
|
|
206
|
+
if (!infoSegment || infoSegment.type !== 'Info') {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const timescale = infoSegment.value.find((b) => b.type === 'TimestampScale');
|
|
210
|
+
if (!timescale || timescale.type !== 'TimestampScale') {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return timescale;
|
|
214
|
+
};
|
|
215
|
+
exports.getTimescaleSegment = getTimescaleSegment;
|
|
216
|
+
const getVideoSegment = (track) => {
|
|
217
|
+
const videoSegment = track.value.find((b) => b.type === 'Video');
|
|
218
|
+
if (!videoSegment || videoSegment.type !== 'Video') {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
return videoSegment !== null && videoSegment !== void 0 ? videoSegment : null;
|
|
222
|
+
};
|
|
223
|
+
exports.getVideoSegment = getVideoSegment;
|
|
224
|
+
const getAudioSegment = (track) => {
|
|
225
|
+
const audioSegment = track.value.find((b) => b.type === 'Audio');
|
|
226
|
+
if (!audioSegment || audioSegment.type !== 'Audio') {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
return audioSegment !== null && audioSegment !== void 0 ? audioSegment : null;
|
|
230
|
+
};
|
|
231
|
+
exports.getAudioSegment = getAudioSegment;
|
|
232
|
+
const getSampleRate = (track) => {
|
|
233
|
+
const audioSegment = (0, exports.getAudioSegment)(track);
|
|
234
|
+
if (!audioSegment) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
const samplingFrequency = audioSegment.value.find((b) => b.type === 'SamplingFrequency');
|
|
238
|
+
if (!samplingFrequency || samplingFrequency.type !== 'SamplingFrequency') {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
return samplingFrequency.value.value;
|
|
242
|
+
};
|
|
243
|
+
exports.getSampleRate = getSampleRate;
|
|
244
|
+
const getNumberOfChannels = (track) => {
|
|
245
|
+
const audioSegment = (0, exports.getAudioSegment)(track);
|
|
246
|
+
if (!audioSegment) {
|
|
247
|
+
throw new Error('Could not find audio segment');
|
|
248
|
+
}
|
|
249
|
+
const channels = audioSegment.value.find((b) => b.type === 'Channels');
|
|
250
|
+
if (!channels || channels.type !== 'Channels') {
|
|
251
|
+
return 1;
|
|
252
|
+
}
|
|
253
|
+
return channels.value.value;
|
|
254
|
+
};
|
|
255
|
+
exports.getNumberOfChannels = getNumberOfChannels;
|
|
256
|
+
const getBitDepth = (track) => {
|
|
257
|
+
const audioSegment = (0, exports.getAudioSegment)(track);
|
|
258
|
+
if (!audioSegment) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const bitDepth = audioSegment.value.find((b) => b.type === 'BitDepth');
|
|
262
|
+
if (!bitDepth || bitDepth.type !== 'BitDepth') {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
return bitDepth.value.value;
|
|
266
|
+
};
|
|
267
|
+
exports.getBitDepth = getBitDepth;
|
|
268
|
+
const getPrivateData = (track) => {
|
|
269
|
+
const privateData = track.value.find((b) => b.type === 'CodecPrivate');
|
|
270
|
+
if (!privateData || privateData.type !== 'CodecPrivate') {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
return privateData.value;
|
|
274
|
+
};
|
|
275
|
+
exports.getPrivateData = getPrivateData;
|
|
276
|
+
const getWidthSegment = (track) => {
|
|
277
|
+
const videoSegment = (0, exports.getVideoSegment)(track);
|
|
278
|
+
if (!videoSegment) {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
const width = videoSegment.value.find((b) => b.type === 'PixelWidth');
|
|
282
|
+
if (!width || width.type !== 'PixelWidth') {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
return width;
|
|
286
|
+
};
|
|
287
|
+
exports.getWidthSegment = getWidthSegment;
|
|
288
|
+
const getHeightSegment = (track) => {
|
|
289
|
+
const videoSegment = (0, exports.getVideoSegment)(track);
|
|
290
|
+
if (!videoSegment) {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
const height = videoSegment.value.find((b) => b.type === 'PixelHeight');
|
|
294
|
+
if (!height || height.type !== 'PixelHeight') {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
return height;
|
|
298
|
+
};
|
|
299
|
+
exports.getHeightSegment = getHeightSegment;
|
|
300
|
+
const getDisplayWidthSegment = (track) => {
|
|
301
|
+
const videoSegment = (0, exports.getVideoSegment)(track);
|
|
302
|
+
if (!videoSegment) {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
const displayWidth = videoSegment.value.find((b) => b.type === 'DisplayWidth');
|
|
306
|
+
if (!displayWidth || displayWidth.type !== 'DisplayWidth') {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
return displayWidth;
|
|
310
|
+
};
|
|
311
|
+
exports.getDisplayWidthSegment = getDisplayWidthSegment;
|
|
312
|
+
const getDisplayHeightSegment = (track) => {
|
|
313
|
+
const videoSegment = (0, exports.getVideoSegment)(track);
|
|
314
|
+
if (!videoSegment) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
const displayHeight = videoSegment.value.find((b) => b.type === 'DisplayHeight');
|
|
318
|
+
if (!displayHeight || displayHeight.type !== 'DisplayHeight') {
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
return displayHeight;
|
|
322
|
+
};
|
|
323
|
+
exports.getDisplayHeightSegment = getDisplayHeightSegment;
|
|
324
|
+
const getTrackTypeSegment = (track) => {
|
|
325
|
+
const trackType = track.value.find((b) => b.type === 'TrackType');
|
|
326
|
+
if (!trackType || trackType.type !== 'TrackType') {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
return trackType;
|
|
330
|
+
};
|
|
331
|
+
exports.getTrackTypeSegment = getTrackTypeSegment;
|
|
332
|
+
const getTrackId = (track) => {
|
|
333
|
+
const trackId = track.value.find((b) => b.type === 'TrackNumber');
|
|
334
|
+
if (!trackId || trackId.type !== 'TrackNumber') {
|
|
335
|
+
throw new Error('Expected track number segment');
|
|
336
|
+
}
|
|
337
|
+
return trackId.value.value;
|
|
338
|
+
};
|
|
339
|
+
exports.getTrackId = getTrackId;
|
|
340
|
+
const getCodecSegment = (track) => {
|
|
341
|
+
const codec = track.value.find((b) => b.type === 'CodecID');
|
|
342
|
+
if (!codec || codec.type !== 'CodecID') {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
return codec;
|
|
346
|
+
};
|
|
347
|
+
exports.getCodecSegment = getCodecSegment;
|
|
348
|
+
const hasSkippedMdatProcessing = (anySegment) => {
|
|
349
|
+
const mdat = anySegment.find((b) => b.type === 'mdat-box');
|
|
350
|
+
if (!mdat) {
|
|
351
|
+
return {
|
|
352
|
+
skipped: false,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
if (mdat.type !== 'mdat-box') {
|
|
356
|
+
throw new Error('Expected mdat-box');
|
|
357
|
+
}
|
|
358
|
+
if (mdat.samplesProcessed) {
|
|
359
|
+
return {
|
|
360
|
+
skipped: false,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
skipped: true,
|
|
365
|
+
fileOffset: mdat.fileOffset,
|
|
366
|
+
};
|
|
367
|
+
};
|
|
368
|
+
exports.hasSkippedMdatProcessing = hasSkippedMdatProcessing;
|
package/package.json
CHANGED
|
@@ -3,12 +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.216",
|
|
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.
|
|
11
|
+
"@remotion/renderer": "4.0.216"
|
|
12
12
|
},
|
|
13
13
|
"publishConfig": {
|
|
14
14
|
"access": "public"
|