@remotion/media-parser 4.0.231 → 4.0.232
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/add-avc-profile-to-track.d.ts +3 -0
- package/dist/add-avc-profile-to-track.js +35 -0
- package/dist/add-new-matroska-tracks.d.ts +6 -1
- package/dist/add-new-matroska-tracks.js +16 -1
- package/dist/boxes/avc/parse-avc.d.ts +18 -0
- package/dist/boxes/avc/parse-avc.js +96 -0
- package/dist/boxes/iso-base-media/make-track.js +3 -3
- package/dist/boxes/iso-base-media/mdat/mdat.d.ts +2 -2
- package/dist/boxes/iso-base-media/mdat/mdat.js +5 -2
- package/dist/boxes/iso-base-media/moov/moov.js +2 -2
- package/dist/boxes/iso-base-media/process-box.d.ts +5 -5
- package/dist/boxes/iso-base-media/process-box.js +38 -37
- package/dist/boxes/iso-base-media/stsd/mebx.js +2 -2
- package/dist/boxes/iso-base-media/stsd/samples.d.ts +2 -2
- package/dist/boxes/iso-base-media/stsd/samples.js +9 -9
- package/dist/boxes/iso-base-media/trak/trak.js +2 -2
- package/dist/boxes/iso-base-media/traversal.d.ts +1 -1
- package/dist/boxes/riff/expect-riff-box.d.ts +16 -0
- package/dist/boxes/riff/expect-riff-box.js +49 -0
- package/dist/boxes/riff/get-tracks-from-avi.d.ts +21 -0
- package/dist/boxes/riff/get-tracks-from-avi.js +108 -0
- package/dist/boxes/riff/is-movi.d.ts +2 -0
- package/dist/boxes/riff/is-movi.js +12 -0
- package/dist/boxes/riff/parse-avih.d.ts +6 -0
- package/dist/boxes/riff/parse-avih.js +32 -0
- package/dist/boxes/riff/parse-box.d.ts +13 -0
- package/dist/boxes/riff/parse-box.js +113 -0
- package/dist/boxes/riff/parse-fmt-box.d.ts +7 -0
- package/dist/boxes/riff/parse-fmt-box.js +33 -0
- package/dist/boxes/riff/parse-list-box.d.ts +8 -0
- package/dist/boxes/riff/parse-list-box.js +30 -0
- package/dist/boxes/riff/parse-movi.d.ts +17 -0
- package/dist/boxes/riff/parse-movi.js +122 -0
- package/dist/boxes/riff/parse-riff-box.d.ts +10 -0
- package/dist/boxes/riff/parse-riff-box.js +33 -0
- package/dist/boxes/riff/parse-strf.d.ts +7 -0
- package/dist/boxes/riff/parse-strf.js +67 -0
- package/dist/boxes/riff/parse-strh.d.ts +6 -0
- package/dist/boxes/riff/parse-strh.js +46 -0
- package/dist/boxes/riff/riff-box.d.ts +81 -0
- package/dist/boxes/riff/riff-box.js +2 -0
- package/dist/boxes/riff/strf.d.ts +7 -0
- package/dist/boxes/riff/strf.js +67 -0
- package/dist/boxes/riff/timescale.d.ts +1 -0
- package/dist/boxes/riff/timescale.js +4 -0
- package/dist/boxes/riff/traversal.d.ts +8 -0
- package/dist/boxes/riff/traversal.js +36 -0
- package/dist/boxes/webm/parse-ebml.js +2 -2
- package/dist/boxes/webm/parse-webm-header.d.ts +2 -2
- package/dist/boxes/webm/parse-webm-header.js +7 -7
- package/dist/boxes/webm/traversal.d.ts +2 -2
- package/dist/buffer-iterator.d.ts +6 -1
- package/dist/buffer-iterator.js +24 -5
- package/dist/create/iso-base-media/create-iso-base-media.js +0 -4
- package/dist/create/matroska/create-matroska-media.js +0 -4
- package/dist/create/media-fn.d.ts +0 -1
- package/dist/create/mp3/create-mp3.d.ts +2 -0
- package/dist/create/mp3/create-mp3.js +49 -0
- package/dist/create/wav/create-wav.d.ts +2 -0
- package/dist/create/wav/create-wav.js +108 -0
- package/dist/emit-available-info.d.ts +2 -2
- package/dist/emit-available-info.js +6 -4
- package/dist/esm/from-node.mjs +2 -1
- package/dist/esm/index.mjs +1487 -431
- package/dist/get-audio-codec.d.ts +3 -3
- package/dist/get-audio-codec.js +2 -2
- package/dist/get-container.d.ts +3 -3
- package/dist/get-container.js +9 -7
- package/dist/get-dimensions.d.ts +3 -3
- package/dist/get-duration.d.ts +3 -3
- package/dist/get-duration.js +32 -14
- package/dist/get-fps.d.ts +3 -3
- package/dist/get-fps.js +31 -4
- package/dist/get-tracks.d.ts +4 -7
- package/dist/get-tracks.js +55 -27
- package/dist/get-video-codec.d.ts +5 -4
- package/dist/get-video-codec.js +38 -10
- package/dist/has-all-info.d.ts +2 -2
- package/dist/has-all-info.js +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/options.d.ts +9 -9
- package/dist/parse-media.js +2 -0
- package/dist/parse-result.d.ts +20 -6
- package/dist/parse-video.d.ts +2 -2
- package/dist/parse-video.js +5 -16
- package/dist/parser-context.d.ts +1 -0
- package/dist/parser-state.d.ts +11 -0
- package/dist/parser-state.js +30 -0
- package/dist/readers/from-node.js +2 -1
- package/dist/register-track.d.ts +13 -0
- package/dist/register-track.js +25 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
package/dist/esm/index.mjs
CHANGED
|
@@ -2117,10 +2117,6 @@ var createIsoBaseMedia = async ({
|
|
|
2117
2117
|
await updateMdatSize();
|
|
2118
2118
|
Log.verbose(logLevel, "All write operations done. Waiting for finish...");
|
|
2119
2119
|
await w.waitForFinish();
|
|
2120
|
-
},
|
|
2121
|
-
updateDuration: (duration2) => {
|
|
2122
|
-
operationProm.current = operationProm.current.then(() => updateDuration(duration2));
|
|
2123
|
-
return operationProm.current;
|
|
2124
2120
|
}
|
|
2125
2121
|
};
|
|
2126
2122
|
};
|
|
@@ -3095,10 +3091,6 @@ var createMatroskaMedia = async ({
|
|
|
3095
3091
|
operationProm.current = operationProm.current.then(() => addSample({ chunk, trackNumber: trackNumber2, isVideo }));
|
|
3096
3092
|
return operationProm.current;
|
|
3097
3093
|
},
|
|
3098
|
-
updateDuration: (duration2) => {
|
|
3099
|
-
operationProm.current = operationProm.current.then(() => updateDuration(duration2));
|
|
3100
|
-
return operationProm.current;
|
|
3101
|
-
},
|
|
3102
3094
|
addTrack: (track) => {
|
|
3103
3095
|
const trackNumber2 = currentTracks.length + 1;
|
|
3104
3096
|
operationProm.current = operationProm.current.then(() => addTrack({ ...track, trackNumber: trackNumber2 }));
|
|
@@ -3124,6 +3116,119 @@ var createMatroskaMedia = async ({
|
|
|
3124
3116
|
};
|
|
3125
3117
|
};
|
|
3126
3118
|
|
|
3119
|
+
// src/create/wav/create-wav.ts
|
|
3120
|
+
var numberTo32BiIntLittleEndian = (num) => {
|
|
3121
|
+
return new Uint8Array([
|
|
3122
|
+
num & 255,
|
|
3123
|
+
num >> 8 & 255,
|
|
3124
|
+
num >> 16 & 255,
|
|
3125
|
+
num >> 24 & 255
|
|
3126
|
+
]);
|
|
3127
|
+
};
|
|
3128
|
+
var numberTo16BitLittleEndian = (num) => {
|
|
3129
|
+
return new Uint8Array([num & 255, num >> 8 & 255]);
|
|
3130
|
+
};
|
|
3131
|
+
var BIT_DEPTH = 16;
|
|
3132
|
+
var BYTES_PER_SAMPLE = BIT_DEPTH / 8;
|
|
3133
|
+
var createWav = async ({
|
|
3134
|
+
filename,
|
|
3135
|
+
logLevel,
|
|
3136
|
+
onBytesProgress,
|
|
3137
|
+
onMillisecondsProgress,
|
|
3138
|
+
writer
|
|
3139
|
+
}) => {
|
|
3140
|
+
const w = await writer.createContent({ filename, mimeType: "audio/wav" });
|
|
3141
|
+
await w.write(new Uint8Array([82, 73, 70, 70]));
|
|
3142
|
+
const sizePosition = w.getWrittenByteCount();
|
|
3143
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3144
|
+
await w.write(new Uint8Array([87, 65, 86, 69]));
|
|
3145
|
+
await w.write(new Uint8Array([102, 109, 116, 32]));
|
|
3146
|
+
await w.write(new Uint8Array([16, 0, 0, 0]));
|
|
3147
|
+
await w.write(new Uint8Array([1, 0]));
|
|
3148
|
+
const channelNumPosition = w.getWrittenByteCount();
|
|
3149
|
+
await w.write(new Uint8Array([1, 0]));
|
|
3150
|
+
const sampleRatePosition = w.getWrittenByteCount();
|
|
3151
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3152
|
+
const byteRatePosition = w.getWrittenByteCount();
|
|
3153
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3154
|
+
const blockAlignPosition = w.getWrittenByteCount();
|
|
3155
|
+
await w.write(new Uint8Array([0, 0]));
|
|
3156
|
+
await w.write(numberTo16BitLittleEndian(BIT_DEPTH));
|
|
3157
|
+
await w.write(new Uint8Array([100, 97, 116, 97]));
|
|
3158
|
+
const dataSizePosition = w.getWrittenByteCount();
|
|
3159
|
+
await w.write(new Uint8Array([0, 0, 0, 0]));
|
|
3160
|
+
const operationProm = { current: Promise.resolve() };
|
|
3161
|
+
const updateSize = async () => {
|
|
3162
|
+
const size = w.getWrittenByteCount() - sizePosition - 4;
|
|
3163
|
+
await w.updateDataAt(sizePosition, numberTo32BiIntLittleEndian(size));
|
|
3164
|
+
const dataSize = w.getWrittenByteCount() - dataSizePosition - 4;
|
|
3165
|
+
await w.updateDataAt(dataSizePosition, numberTo32BiIntLittleEndian(dataSize));
|
|
3166
|
+
};
|
|
3167
|
+
const updateChannelNum = async (numberOfChannels) => {
|
|
3168
|
+
await w.updateDataAt(channelNumPosition, new Uint8Array([numberOfChannels, 0]));
|
|
3169
|
+
};
|
|
3170
|
+
const updateSampleRate = async (sampleRate) => {
|
|
3171
|
+
await w.updateDataAt(sampleRatePosition, numberTo32BiIntLittleEndian(sampleRate));
|
|
3172
|
+
};
|
|
3173
|
+
const updateByteRate = async ({
|
|
3174
|
+
sampleRate,
|
|
3175
|
+
numberOfChannels
|
|
3176
|
+
}) => {
|
|
3177
|
+
await w.updateDataAt(byteRatePosition, numberTo32BiIntLittleEndian(sampleRate * numberOfChannels + BYTES_PER_SAMPLE));
|
|
3178
|
+
};
|
|
3179
|
+
const updateBlockAlign = async (numberOfChannels) => {
|
|
3180
|
+
await w.updateDataAt(blockAlignPosition, new Uint8Array(numberTo16BitLittleEndian(numberOfChannels * BYTES_PER_SAMPLE)));
|
|
3181
|
+
};
|
|
3182
|
+
const addSample = async (chunk) => {
|
|
3183
|
+
Log.verbose(logLevel, "Adding sample", chunk);
|
|
3184
|
+
await w.write(chunk.data);
|
|
3185
|
+
onMillisecondsProgress((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
3186
|
+
onBytesProgress(w.getWrittenByteCount());
|
|
3187
|
+
};
|
|
3188
|
+
const waitForFinishPromises = [];
|
|
3189
|
+
return {
|
|
3190
|
+
save: () => {
|
|
3191
|
+
return w.save();
|
|
3192
|
+
},
|
|
3193
|
+
remove: () => {
|
|
3194
|
+
return w.remove();
|
|
3195
|
+
},
|
|
3196
|
+
addSample: ({ chunk, trackNumber: trackNumber2 }) => {
|
|
3197
|
+
if (trackNumber2 !== 1) {
|
|
3198
|
+
throw new Error("Only one track supported for WAV");
|
|
3199
|
+
}
|
|
3200
|
+
operationProm.current = operationProm.current.then(() => addSample(chunk));
|
|
3201
|
+
return operationProm.current;
|
|
3202
|
+
},
|
|
3203
|
+
updateTrackSampleRate: () => {
|
|
3204
|
+
throw new Error("updateTrackSampleRate() not implemented for WAV encoder");
|
|
3205
|
+
},
|
|
3206
|
+
addWaitForFinishPromise: (promise) => {
|
|
3207
|
+
waitForFinishPromises.push(promise);
|
|
3208
|
+
},
|
|
3209
|
+
async waitForFinish() {
|
|
3210
|
+
Log.verbose(logLevel, "All write operations queued. Waiting for finish...");
|
|
3211
|
+
await Promise.all(waitForFinishPromises.map((p) => p()));
|
|
3212
|
+
await operationProm.current;
|
|
3213
|
+
await updateSize();
|
|
3214
|
+
await w.waitForFinish();
|
|
3215
|
+
},
|
|
3216
|
+
addTrack: async (track) => {
|
|
3217
|
+
if (track.type !== "audio") {
|
|
3218
|
+
throw new Error("Only audio tracks supported for WAV");
|
|
3219
|
+
}
|
|
3220
|
+
await updateChannelNum(track.numberOfChannels);
|
|
3221
|
+
await updateSampleRate(track.sampleRate);
|
|
3222
|
+
await updateByteRate({
|
|
3223
|
+
sampleRate: track.sampleRate,
|
|
3224
|
+
numberOfChannels: track.numberOfChannels
|
|
3225
|
+
});
|
|
3226
|
+
await updateBlockAlign(track.numberOfChannels);
|
|
3227
|
+
return Promise.resolve({ trackNumber: 1 });
|
|
3228
|
+
}
|
|
3229
|
+
};
|
|
3230
|
+
};
|
|
3231
|
+
|
|
3127
3232
|
// src/boxes/iso-base-media/traversal.ts
|
|
3128
3233
|
var getMoovBox = (segments) => {
|
|
3129
3234
|
const moovBox = segments.find((s) => s.type === "moov-box");
|
|
@@ -3289,317 +3394,133 @@ var getMdatBox = (anySegment) => {
|
|
|
3289
3394
|
return mdat;
|
|
3290
3395
|
};
|
|
3291
3396
|
|
|
3292
|
-
// src/
|
|
3293
|
-
var
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3397
|
+
// src/boxes/riff/traversal.ts
|
|
3398
|
+
var isRiffAvi = (structure) => {
|
|
3399
|
+
return structure.boxes.some((box) => box.type === "riff-header" && box.fileType === "AVI");
|
|
3400
|
+
};
|
|
3401
|
+
var getHdlrBox = (structure) => {
|
|
3402
|
+
return structure.boxes.find((box) => box.type === "list-box" && box.listType === "hdrl");
|
|
3403
|
+
};
|
|
3404
|
+
var getAvihBox = (structure) => {
|
|
3405
|
+
const hdlrBox = getHdlrBox(structure);
|
|
3406
|
+
if (!hdlrBox) {
|
|
3407
|
+
return null;
|
|
3408
|
+
}
|
|
3409
|
+
return hdlrBox.children.find((box) => box.type === "avih-box");
|
|
3410
|
+
};
|
|
3411
|
+
var getStrlBoxes = (structure) => {
|
|
3412
|
+
const hdlrBox = getHdlrBox(structure);
|
|
3413
|
+
if (!hdlrBox) {
|
|
3414
|
+
return [];
|
|
3415
|
+
}
|
|
3416
|
+
return hdlrBox.children.filter((box) => box.type === "list-box" && box.listType === "strl");
|
|
3417
|
+
};
|
|
3418
|
+
var getStrhBox = (strlBoxChildren) => {
|
|
3419
|
+
return strlBoxChildren.find((box) => box.type === "strh-box");
|
|
3420
|
+
};
|
|
3421
|
+
var getStrfBox = (strlBoxChildren) => {
|
|
3422
|
+
return strlBoxChildren.find((box) => box.type === "strf-box-audio" || box.type === "strf-box-video") ?? null;
|
|
3423
|
+
};
|
|
3424
|
+
|
|
3425
|
+
// src/get-fps.ts
|
|
3426
|
+
var calculateFps = ({
|
|
3298
3427
|
sttsBox,
|
|
3299
|
-
|
|
3428
|
+
timeScale,
|
|
3429
|
+
durationInSamples
|
|
3300
3430
|
}) => {
|
|
3301
|
-
|
|
3302
|
-
for (const
|
|
3303
|
-
|
|
3304
|
-
sttsDeltas.push(distribution.sampleDelta);
|
|
3305
|
-
}
|
|
3431
|
+
let totalSamples = 0;
|
|
3432
|
+
for (const sample of sttsBox.sampleDistribution) {
|
|
3433
|
+
totalSamples += sample.sampleCount;
|
|
3306
3434
|
}
|
|
3307
|
-
const
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3435
|
+
const durationInSeconds = durationInSamples / timeScale;
|
|
3436
|
+
const fps = totalSamples / durationInSeconds;
|
|
3437
|
+
return fps;
|
|
3438
|
+
};
|
|
3439
|
+
var trakBoxContainsAudio = (trakBox) => {
|
|
3440
|
+
const stsd = getStsdBox(trakBox);
|
|
3441
|
+
if (!stsd) {
|
|
3442
|
+
return false;
|
|
3314
3443
|
}
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
let samplesPerChunk = 1;
|
|
3319
|
-
for (let i = 0;i < chunks.length; i++) {
|
|
3320
|
-
const hasEntry = stscBox.entries.find((entry) => entry.firstChunk === i + 1);
|
|
3321
|
-
if (hasEntry) {
|
|
3322
|
-
samplesPerChunk = hasEntry.samplesPerChunk;
|
|
3323
|
-
}
|
|
3324
|
-
let offsetInThisChunk = 0;
|
|
3325
|
-
for (let j = 0;j < samplesPerChunk; j++) {
|
|
3326
|
-
const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
|
|
3327
|
-
const isKeyframe = stssBox ? stssBox.sampleNumber.includes(samples.length + 1) : true;
|
|
3328
|
-
const delta = sttsDeltas[samples.length];
|
|
3329
|
-
const ctsOffset = cttsEntries[samples.length];
|
|
3330
|
-
const cts = dts + ctsOffset;
|
|
3331
|
-
samples.push({
|
|
3332
|
-
offset: Number(chunks[i]) + offsetInThisChunk,
|
|
3333
|
-
size,
|
|
3334
|
-
isKeyframe,
|
|
3335
|
-
dts,
|
|
3336
|
-
cts,
|
|
3337
|
-
duration: delta,
|
|
3338
|
-
chunk: i
|
|
3339
|
-
});
|
|
3340
|
-
dts += delta;
|
|
3341
|
-
offsetInThisChunk += size;
|
|
3342
|
-
}
|
|
3444
|
+
const videoSample = stsd.samples.find((s) => s.type === "audio");
|
|
3445
|
+
if (!videoSample || videoSample.type !== "audio") {
|
|
3446
|
+
return false;
|
|
3343
3447
|
}
|
|
3344
|
-
return
|
|
3448
|
+
return true;
|
|
3345
3449
|
};
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
throw new Error("Expected traf-box");
|
|
3450
|
+
var trakBoxContainsVideo = (trakBox) => {
|
|
3451
|
+
const stsd = getStsdBox(trakBox);
|
|
3452
|
+
if (!stsd) {
|
|
3453
|
+
return false;
|
|
3351
3454
|
}
|
|
3352
|
-
const
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
|
|
3356
|
-
const tfdtBox = getTfdtBox(trafSegment);
|
|
3357
|
-
const trunBoxes = getTrunBoxes(trafSegment);
|
|
3358
|
-
let time = 0;
|
|
3359
|
-
let offset = 0;
|
|
3360
|
-
let dataOffset = 0;
|
|
3361
|
-
const samples = [];
|
|
3362
|
-
for (const trunBox of trunBoxes) {
|
|
3363
|
-
let i = -1;
|
|
3364
|
-
if (trunBox.dataOffset) {
|
|
3365
|
-
dataOffset = trunBox.dataOffset;
|
|
3366
|
-
offset = 0;
|
|
3367
|
-
}
|
|
3368
|
-
for (const sample of trunBox.samples) {
|
|
3369
|
-
i++;
|
|
3370
|
-
const duration2 = sample.sampleDuration ?? defaultSampleDuration;
|
|
3371
|
-
if (duration2 === null) {
|
|
3372
|
-
throw new Error("Expected duration");
|
|
3373
|
-
}
|
|
3374
|
-
const size = sample.sampleSize ?? defaultSampleSize;
|
|
3375
|
-
if (size === null) {
|
|
3376
|
-
throw new Error("Expected size");
|
|
3377
|
-
}
|
|
3378
|
-
const isFirstSample = i === 0;
|
|
3379
|
-
const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
|
|
3380
|
-
if (sampleFlags === null) {
|
|
3381
|
-
throw new Error("Expected sample flags");
|
|
3382
|
-
}
|
|
3383
|
-
const keyframe = !(sampleFlags >> 16 & 1);
|
|
3384
|
-
const dts = time + (tfdtBox?.baseMediaDecodeTime ?? 0);
|
|
3385
|
-
const samplePosition = {
|
|
3386
|
-
offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
|
|
3387
|
-
dts,
|
|
3388
|
-
cts: dts,
|
|
3389
|
-
duration: duration2,
|
|
3390
|
-
isKeyframe: keyframe,
|
|
3391
|
-
size,
|
|
3392
|
-
chunk: 0
|
|
3393
|
-
};
|
|
3394
|
-
samples.push(samplePosition);
|
|
3395
|
-
offset += size;
|
|
3396
|
-
time += duration2;
|
|
3397
|
-
}
|
|
3455
|
+
const videoSample = stsd.samples.find((s) => s.type === "video");
|
|
3456
|
+
if (!videoSample || videoSample.type !== "video") {
|
|
3457
|
+
return false;
|
|
3398
3458
|
}
|
|
3399
|
-
return
|
|
3459
|
+
return true;
|
|
3400
3460
|
};
|
|
3401
|
-
var
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
if (moofBox.type !== "regular-box") {
|
|
3406
|
-
throw new Error("Expected moof-box");
|
|
3461
|
+
var getTimescaleAndDuration = (trakBox) => {
|
|
3462
|
+
const mdhdBox = getMdhdBox(trakBox);
|
|
3463
|
+
if (mdhdBox) {
|
|
3464
|
+
return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
|
|
3407
3465
|
}
|
|
3408
|
-
|
|
3409
|
-
const mapped = trafs.map((traf) => {
|
|
3410
|
-
const tfhdBox = getTfhdBox(traf);
|
|
3411
|
-
return tfhdBox?.trackId === trackId ? getSamplesFromTraf(traf, moofBox.offset) : [];
|
|
3412
|
-
});
|
|
3413
|
-
return mapped.flat(1);
|
|
3466
|
+
return null;
|
|
3414
3467
|
};
|
|
3415
|
-
|
|
3416
|
-
// src/boxes/iso-base-media/get-sample-positions-from-track.ts
|
|
3417
|
-
var getSamplePositionsFromTrack = (trakBox, moofBox) => {
|
|
3418
|
-
const stszBox = getStszBox(trakBox);
|
|
3419
|
-
const stcoBox = getStcoBox(trakBox);
|
|
3420
|
-
const stscBox = getStscBox(trakBox);
|
|
3421
|
-
const stssBox = getStssBox(trakBox);
|
|
3422
|
-
const sttsBox = getSttsBox(trakBox);
|
|
3423
|
-
const tkhdBox = getTkhdBox(trakBox);
|
|
3424
|
-
const cttsBox = getCttsBox(trakBox);
|
|
3468
|
+
var getFpsFromMp4TrakBox = (trakBox) => {
|
|
3425
3469
|
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
3426
|
-
if (!
|
|
3427
|
-
|
|
3428
|
-
}
|
|
3429
|
-
if (!stszBox) {
|
|
3430
|
-
throw new Error("Expected stsz box in trak box");
|
|
3431
|
-
}
|
|
3432
|
-
if (!stcoBox) {
|
|
3433
|
-
throw new Error("Expected stco box in trak box");
|
|
3434
|
-
}
|
|
3435
|
-
if (!stscBox) {
|
|
3436
|
-
throw new Error("Expected stsc box in trak box");
|
|
3470
|
+
if (!timescaleAndDuration) {
|
|
3471
|
+
return null;
|
|
3437
3472
|
}
|
|
3473
|
+
const sttsBox = getSttsBox(trakBox);
|
|
3438
3474
|
if (!sttsBox) {
|
|
3439
|
-
|
|
3440
|
-
}
|
|
3441
|
-
if (!timescaleAndDuration) {
|
|
3442
|
-
throw new Error("Expected timescale and duration in trak box");
|
|
3475
|
+
return null;
|
|
3443
3476
|
}
|
|
3444
|
-
|
|
3445
|
-
stcoBox,
|
|
3446
|
-
stscBox,
|
|
3447
|
-
stszBox,
|
|
3448
|
-
stssBox,
|
|
3477
|
+
return calculateFps({
|
|
3449
3478
|
sttsBox,
|
|
3450
|
-
|
|
3479
|
+
timeScale: timescaleAndDuration.timescale,
|
|
3480
|
+
durationInSamples: timescaleAndDuration.duration
|
|
3451
3481
|
});
|
|
3452
|
-
if (samplePositions.length === 0 && moofBox) {
|
|
3453
|
-
samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
|
|
3454
|
-
}
|
|
3455
|
-
return samplePositions;
|
|
3456
3482
|
};
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
const mainSegment = segments.find((s) => s.type === "Segment");
|
|
3461
|
-
if (!mainSegment || mainSegment.type !== "Segment") {
|
|
3483
|
+
var getFpsFromIsoMaseMedia = (structure) => {
|
|
3484
|
+
const moovBox = getMoovBox(structure.boxes);
|
|
3485
|
+
if (!moovBox) {
|
|
3462
3486
|
return null;
|
|
3463
3487
|
}
|
|
3464
|
-
const
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
}
|
|
3468
|
-
const infoSegment = children.find((s) => s.type === "Info");
|
|
3469
|
-
const relevantBoxes = [
|
|
3470
|
-
...mainSegment.value,
|
|
3471
|
-
...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
|
|
3472
|
-
];
|
|
3473
|
-
const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
|
|
3474
|
-
if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
|
|
3475
|
-
return null;
|
|
3476
|
-
}
|
|
3477
|
-
const duration2 = relevantBoxes.find((s) => s.type === "Duration");
|
|
3478
|
-
if (!duration2 || duration2.type !== "Duration") {
|
|
3479
|
-
return null;
|
|
3480
|
-
}
|
|
3481
|
-
return duration2.value.value / timestampScale2.value.value * 1000;
|
|
3482
|
-
};
|
|
3483
|
-
var isMatroska = (boxes) => {
|
|
3484
|
-
const matroskaBox = boxes.find((b) => b.type === "Segment");
|
|
3485
|
-
return matroskaBox;
|
|
3486
|
-
};
|
|
3487
|
-
var getDuration = (boxes, parserState) => {
|
|
3488
|
-
if (isMatroska(boxes)) {
|
|
3489
|
-
return getDurationFromMatroska(boxes);
|
|
3490
|
-
}
|
|
3491
|
-
const moovBox = getMoovBox(boxes);
|
|
3492
|
-
if (!moovBox) {
|
|
3493
|
-
return null;
|
|
3494
|
-
}
|
|
3495
|
-
const moofBox = getMoofBox(boxes);
|
|
3496
|
-
const mvhdBox = getMvhdBox(moovBox);
|
|
3497
|
-
if (!mvhdBox) {
|
|
3488
|
+
const trackBoxes = getTraks(moovBox);
|
|
3489
|
+
const trackBox = trackBoxes.find(trakBoxContainsVideo);
|
|
3490
|
+
if (!trackBox) {
|
|
3498
3491
|
return null;
|
|
3499
3492
|
}
|
|
3500
|
-
|
|
3501
|
-
throw new Error("Expected mvhd-box");
|
|
3502
|
-
}
|
|
3503
|
-
if (mvhdBox.durationInSeconds > 0) {
|
|
3504
|
-
return mvhdBox.durationInSeconds;
|
|
3505
|
-
}
|
|
3506
|
-
const tracks2 = getTracks(boxes, parserState);
|
|
3507
|
-
const allTracks = [
|
|
3508
|
-
...tracks2.videoTracks,
|
|
3509
|
-
...tracks2.audioTracks,
|
|
3510
|
-
...tracks2.otherTracks
|
|
3511
|
-
];
|
|
3512
|
-
const allSamples = allTracks.map((t) => {
|
|
3513
|
-
const { timescale: ts } = t;
|
|
3514
|
-
const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
|
|
3515
|
-
const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
|
|
3516
|
-
return highest ?? 0;
|
|
3517
|
-
});
|
|
3518
|
-
const highestTimestamp = Math.max(...allSamples);
|
|
3519
|
-
return highestTimestamp;
|
|
3520
|
-
};
|
|
3521
|
-
var hasDuration = (boxes, parserState) => {
|
|
3522
|
-
try {
|
|
3523
|
-
const duration2 = getDuration(boxes, parserState);
|
|
3524
|
-
return getDuration(boxes, parserState) !== null && duration2 !== 0;
|
|
3525
|
-
} catch {
|
|
3526
|
-
return false;
|
|
3527
|
-
}
|
|
3528
|
-
};
|
|
3529
|
-
|
|
3530
|
-
// src/get-fps.ts
|
|
3531
|
-
var calculateFps = ({
|
|
3532
|
-
sttsBox,
|
|
3533
|
-
timeScale,
|
|
3534
|
-
durationInSamples
|
|
3535
|
-
}) => {
|
|
3536
|
-
let totalSamples = 0;
|
|
3537
|
-
for (const sample of sttsBox.sampleDistribution) {
|
|
3538
|
-
totalSamples += sample.sampleCount;
|
|
3539
|
-
}
|
|
3540
|
-
const durationInSeconds = durationInSamples / timeScale;
|
|
3541
|
-
const fps = totalSamples / durationInSeconds;
|
|
3542
|
-
return fps;
|
|
3543
|
-
};
|
|
3544
|
-
var trakBoxContainsAudio = (trakBox) => {
|
|
3545
|
-
const stsd = getStsdBox(trakBox);
|
|
3546
|
-
if (!stsd) {
|
|
3547
|
-
return false;
|
|
3548
|
-
}
|
|
3549
|
-
const videoSample = stsd.samples.find((s) => s.type === "audio");
|
|
3550
|
-
if (!videoSample || videoSample.type !== "audio") {
|
|
3551
|
-
return false;
|
|
3552
|
-
}
|
|
3553
|
-
return true;
|
|
3554
|
-
};
|
|
3555
|
-
var trakBoxContainsVideo = (trakBox) => {
|
|
3556
|
-
const stsd = getStsdBox(trakBox);
|
|
3557
|
-
if (!stsd) {
|
|
3558
|
-
return false;
|
|
3559
|
-
}
|
|
3560
|
-
const videoSample = stsd.samples.find((s) => s.type === "video");
|
|
3561
|
-
if (!videoSample || videoSample.type !== "video") {
|
|
3562
|
-
return false;
|
|
3563
|
-
}
|
|
3564
|
-
return true;
|
|
3493
|
+
return getFpsFromMp4TrakBox(trackBox);
|
|
3565
3494
|
};
|
|
3566
|
-
var
|
|
3567
|
-
const
|
|
3568
|
-
|
|
3569
|
-
|
|
3495
|
+
var getFpsFromAvi = (structure) => {
|
|
3496
|
+
const strl = getStrlBoxes(structure);
|
|
3497
|
+
for (const s of strl) {
|
|
3498
|
+
const strh = getStrhBox(s.children);
|
|
3499
|
+
if (!strh) {
|
|
3500
|
+
throw new Error("No strh box");
|
|
3501
|
+
}
|
|
3502
|
+
if (strh.fccType === "auds") {
|
|
3503
|
+
continue;
|
|
3504
|
+
}
|
|
3505
|
+
return strh.rate;
|
|
3570
3506
|
}
|
|
3571
3507
|
return null;
|
|
3572
3508
|
};
|
|
3573
|
-
var getFpsFromMp4TrakBox = (trakBox) => {
|
|
3574
|
-
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
3575
|
-
if (!timescaleAndDuration) {
|
|
3576
|
-
return null;
|
|
3577
|
-
}
|
|
3578
|
-
const sttsBox = getSttsBox(trakBox);
|
|
3579
|
-
if (!sttsBox) {
|
|
3580
|
-
return null;
|
|
3581
|
-
}
|
|
3582
|
-
return calculateFps({
|
|
3583
|
-
sttsBox,
|
|
3584
|
-
timeScale: timescaleAndDuration.timescale,
|
|
3585
|
-
durationInSamples: timescaleAndDuration.duration
|
|
3586
|
-
});
|
|
3587
|
-
};
|
|
3588
3509
|
var getFps = (segments) => {
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
return null;
|
|
3510
|
+
if (segments.type === "iso-base-media") {
|
|
3511
|
+
return getFpsFromIsoMaseMedia(segments);
|
|
3592
3512
|
}
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3513
|
+
if (segments.type === "riff") {
|
|
3514
|
+
return getFpsFromAvi(segments);
|
|
3515
|
+
}
|
|
3516
|
+
if (segments.type === "matroska") {
|
|
3596
3517
|
return null;
|
|
3597
3518
|
}
|
|
3598
|
-
|
|
3519
|
+
throw new Error("Cannot get fps, not implemented");
|
|
3599
3520
|
};
|
|
3600
3521
|
var hasFps = (boxes) => {
|
|
3601
3522
|
try {
|
|
3602
|
-
if (
|
|
3523
|
+
if (boxes.type === "matroska") {
|
|
3603
3524
|
return true;
|
|
3604
3525
|
}
|
|
3605
3526
|
return getFps(boxes) !== null;
|
|
@@ -3624,8 +3545,8 @@ var getAudioCodec = (boxes, parserState) => {
|
|
|
3624
3545
|
}
|
|
3625
3546
|
return null;
|
|
3626
3547
|
};
|
|
3627
|
-
var hasAudioCodec = (boxes) => {
|
|
3628
|
-
return hasTracks(boxes);
|
|
3548
|
+
var hasAudioCodec = (boxes, state) => {
|
|
3549
|
+
return hasTracks(boxes, state);
|
|
3629
3550
|
};
|
|
3630
3551
|
var getCodecSpecificatorFromEsdsBox = ({
|
|
3631
3552
|
child
|
|
@@ -3987,6 +3908,9 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
3987
3908
|
const allowDiscard = () => {
|
|
3988
3909
|
discardAllowed = true;
|
|
3989
3910
|
};
|
|
3911
|
+
const discard = (length) => {
|
|
3912
|
+
counter.increment(length);
|
|
3913
|
+
};
|
|
3990
3914
|
const getUint8 = () => {
|
|
3991
3915
|
const val = view.getUint8(counter.getDiscardedOffset());
|
|
3992
3916
|
counter.increment(1);
|
|
@@ -4032,8 +3956,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4032
3956
|
}
|
|
4033
3957
|
return lastInt;
|
|
4034
3958
|
};
|
|
4035
|
-
const getUint32 = (
|
|
4036
|
-
const val = view.getUint32(counter.getDiscardedOffset()
|
|
3959
|
+
const getUint32 = () => {
|
|
3960
|
+
const val = view.getUint32(counter.getDiscardedOffset());
|
|
4037
3961
|
counter.increment(4);
|
|
4038
3962
|
return val;
|
|
4039
3963
|
};
|
|
@@ -4042,6 +3966,18 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4042
3966
|
counter.increment(8);
|
|
4043
3967
|
return val;
|
|
4044
3968
|
};
|
|
3969
|
+
const startBox = (size) => {
|
|
3970
|
+
const startOffset = counter.getOffset();
|
|
3971
|
+
return {
|
|
3972
|
+
discardRest: () => discard(size - (counter.getOffset() - startOffset)),
|
|
3973
|
+
expectNoMoreBytes: () => {
|
|
3974
|
+
const remaining = size - (counter.getOffset() - startOffset);
|
|
3975
|
+
if (remaining !== 0) {
|
|
3976
|
+
throw new Error("expected 0 bytes, got " + remaining);
|
|
3977
|
+
}
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3980
|
+
};
|
|
4045
3981
|
const getUint32Le = () => {
|
|
4046
3982
|
const val = view.getUint32(counter.getDiscardedOffset(), true);
|
|
4047
3983
|
counter.increment(4);
|
|
@@ -4185,9 +4121,7 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4185
4121
|
leb128,
|
|
4186
4122
|
removeBytesRead,
|
|
4187
4123
|
isWebm,
|
|
4188
|
-
discard
|
|
4189
|
-
counter.increment(length);
|
|
4190
|
-
},
|
|
4124
|
+
discard,
|
|
4191
4125
|
getEightByteNumber,
|
|
4192
4126
|
getFourByteNumber,
|
|
4193
4127
|
getSlice,
|
|
@@ -4281,6 +4215,11 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4281
4215
|
counter.increment(2);
|
|
4282
4216
|
return val;
|
|
4283
4217
|
},
|
|
4218
|
+
getUint16Le: () => {
|
|
4219
|
+
const val = view.getUint16(counter.getDiscardedOffset(), true);
|
|
4220
|
+
counter.increment(2);
|
|
4221
|
+
return val;
|
|
4222
|
+
},
|
|
4284
4223
|
getUint24: () => {
|
|
4285
4224
|
const val1 = view.getUint8(counter.getDiscardedOffset());
|
|
4286
4225
|
const val2 = view.getUint8(counter.getDiscardedOffset() + 1);
|
|
@@ -4336,7 +4275,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
|
|
|
4336
4275
|
destroy,
|
|
4337
4276
|
isMp3,
|
|
4338
4277
|
disallowDiscard,
|
|
4339
|
-
allowDiscard
|
|
4278
|
+
allowDiscard,
|
|
4279
|
+
startBox
|
|
4340
4280
|
};
|
|
4341
4281
|
};
|
|
4342
4282
|
|
|
@@ -4445,14 +4385,7 @@ var getVideoCodecFromIsoTrak = (trakBox) => {
|
|
|
4445
4385
|
}
|
|
4446
4386
|
throw new Error("Could not find video codec");
|
|
4447
4387
|
};
|
|
4448
|
-
var
|
|
4449
|
-
const moovBox = getMoovBox(boxes);
|
|
4450
|
-
if (moovBox) {
|
|
4451
|
-
const trakBox = getTraks(moovBox).filter((t) => trakBoxContainsVideo(t))[0];
|
|
4452
|
-
if (trakBox) {
|
|
4453
|
-
return getVideoCodecFromIsoTrak(trakBox);
|
|
4454
|
-
}
|
|
4455
|
-
}
|
|
4388
|
+
var getVideoCodecFromMatroska = (boxes) => {
|
|
4456
4389
|
const mainSegment = boxes.find((b) => b.type === "Segment");
|
|
4457
4390
|
if (!mainSegment || mainSegment.type !== "Segment") {
|
|
4458
4391
|
return null;
|
|
@@ -4483,10 +4416,44 @@ var getVideoCodec = (boxes) => {
|
|
|
4483
4416
|
}
|
|
4484
4417
|
}
|
|
4485
4418
|
}
|
|
4419
|
+
throw new Error("Could not find video codec");
|
|
4420
|
+
};
|
|
4421
|
+
var getVideoCodecFromAvi = (structure) => {
|
|
4422
|
+
const strl = getStrlBoxes(structure);
|
|
4423
|
+
for (const s of strl) {
|
|
4424
|
+
const strh = getStrhBox(s.children);
|
|
4425
|
+
if (!strh) {
|
|
4426
|
+
throw new Error("No strh box");
|
|
4427
|
+
}
|
|
4428
|
+
if (strh.fccType === "auds") {
|
|
4429
|
+
continue;
|
|
4430
|
+
}
|
|
4431
|
+
if (strh.handler === "H264") {
|
|
4432
|
+
return "h264";
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
throw new Error("Unsupported codec");
|
|
4436
|
+
};
|
|
4437
|
+
var getVideoCodec = (boxes) => {
|
|
4438
|
+
if (boxes.type === "iso-base-media") {
|
|
4439
|
+
const moovBox = getMoovBox(boxes.boxes);
|
|
4440
|
+
if (moovBox) {
|
|
4441
|
+
const trakBox = getTraks(moovBox).filter((t) => trakBoxContainsVideo(t))[0];
|
|
4442
|
+
if (trakBox) {
|
|
4443
|
+
return getVideoCodecFromIsoTrak(trakBox);
|
|
4444
|
+
}
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
if (boxes.type === "riff") {
|
|
4448
|
+
return getVideoCodecFromAvi(boxes);
|
|
4449
|
+
}
|
|
4450
|
+
if (boxes.type === "matroska") {
|
|
4451
|
+
return getVideoCodecFromMatroska(boxes.boxes);
|
|
4452
|
+
}
|
|
4486
4453
|
return null;
|
|
4487
4454
|
};
|
|
4488
|
-
var hasVideoCodec = (boxes) => {
|
|
4489
|
-
return hasTracks(boxes);
|
|
4455
|
+
var hasVideoCodec = (boxes, state) => {
|
|
4456
|
+
return hasTracks(boxes, state);
|
|
4490
4457
|
};
|
|
4491
4458
|
var getVideoPrivateData = (trakBox) => {
|
|
4492
4459
|
const videoSample = getStsdVideoConfig(trakBox);
|
|
@@ -4577,7 +4544,7 @@ var makeBaseMediaTrack = (trakBox) => {
|
|
|
4577
4544
|
sampleRate,
|
|
4578
4545
|
description,
|
|
4579
4546
|
trakBox,
|
|
4580
|
-
codecPrivate: getCodecPrivateFromTrak(trakBox),
|
|
4547
|
+
codecPrivate: getCodecPrivateFromTrak(trakBox) ?? description ?? null,
|
|
4581
4548
|
codecWithoutConfig: getAudioCodecFromTrack(trakBox)
|
|
4582
4549
|
};
|
|
4583
4550
|
}
|
|
@@ -4636,6 +4603,135 @@ var makeBaseMediaTrack = (trakBox) => {
|
|
|
4636
4603
|
return track;
|
|
4637
4604
|
};
|
|
4638
4605
|
|
|
4606
|
+
// src/add-avc-profile-to-track.ts
|
|
4607
|
+
var addAvcProfileToTrack = (track, avc1Profile) => {
|
|
4608
|
+
if (avc1Profile === null) {
|
|
4609
|
+
return track;
|
|
4610
|
+
}
|
|
4611
|
+
return {
|
|
4612
|
+
...track,
|
|
4613
|
+
codec: `avc1.${avc1Profile.sps.profile.toString(16).padStart(2, "0")}${avc1Profile.sps.compatibility.toString(16).padStart(2, "0")}${avc1Profile.sps.level.toString(16).padStart(2, "0")}`,
|
|
4614
|
+
codecPrivate: combineUint8Arrays([
|
|
4615
|
+
new Uint8Array([
|
|
4616
|
+
1,
|
|
4617
|
+
avc1Profile.sps.level,
|
|
4618
|
+
avc1Profile.sps.compatibility,
|
|
4619
|
+
avc1Profile.sps.profile,
|
|
4620
|
+
255,
|
|
4621
|
+
225
|
|
4622
|
+
]),
|
|
4623
|
+
serializeUint16(avc1Profile.sps.sps.length),
|
|
4624
|
+
avc1Profile.sps.sps,
|
|
4625
|
+
new Uint8Array([1]),
|
|
4626
|
+
serializeUint16(avc1Profile.pps.pps.length),
|
|
4627
|
+
avc1Profile.pps.pps
|
|
4628
|
+
])
|
|
4629
|
+
};
|
|
4630
|
+
};
|
|
4631
|
+
|
|
4632
|
+
// src/boxes/riff/timescale.ts
|
|
4633
|
+
var MEDIA_PARSER_RIFF_TIMESCALE = 1e6;
|
|
4634
|
+
|
|
4635
|
+
// src/boxes/riff/get-tracks-from-avi.ts
|
|
4636
|
+
var getNumberOfTracks = (structure) => {
|
|
4637
|
+
const avihBox = getAvihBox(structure);
|
|
4638
|
+
if (avihBox) {
|
|
4639
|
+
return avihBox.streams;
|
|
4640
|
+
}
|
|
4641
|
+
throw new Error("No avih box found");
|
|
4642
|
+
};
|
|
4643
|
+
var makeAviAudioTrack = ({
|
|
4644
|
+
strf,
|
|
4645
|
+
index
|
|
4646
|
+
}) => {
|
|
4647
|
+
if (strf.formatTag !== 255) {
|
|
4648
|
+
throw new Error(`Unsupported audio format ${strf.formatTag}`);
|
|
4649
|
+
}
|
|
4650
|
+
return {
|
|
4651
|
+
type: "audio",
|
|
4652
|
+
codec: "mp4a.40.2",
|
|
4653
|
+
codecPrivate: new Uint8Array([18, 16]),
|
|
4654
|
+
codecWithoutConfig: "aac",
|
|
4655
|
+
description: new Uint8Array([18, 16]),
|
|
4656
|
+
numberOfChannels: strf.numberOfChannels,
|
|
4657
|
+
sampleRate: strf.sampleRate,
|
|
4658
|
+
timescale: MEDIA_PARSER_RIFF_TIMESCALE,
|
|
4659
|
+
trackId: index,
|
|
4660
|
+
trakBox: null
|
|
4661
|
+
};
|
|
4662
|
+
};
|
|
4663
|
+
var makeAviVideoTrack = ({
|
|
4664
|
+
strh,
|
|
4665
|
+
strf,
|
|
4666
|
+
index
|
|
4667
|
+
}) => {
|
|
4668
|
+
if (strh.handler !== "H264") {
|
|
4669
|
+
throw new Error(`Unsupported video codec ${strh.handler}`);
|
|
4670
|
+
}
|
|
4671
|
+
return {
|
|
4672
|
+
codecPrivate: null,
|
|
4673
|
+
codec: "to-be-overriden-later",
|
|
4674
|
+
codecWithoutConfig: "h264",
|
|
4675
|
+
codedHeight: strf.height,
|
|
4676
|
+
codedWidth: strf.width,
|
|
4677
|
+
width: strf.width,
|
|
4678
|
+
height: strf.height,
|
|
4679
|
+
type: "video",
|
|
4680
|
+
displayAspectHeight: strf.height,
|
|
4681
|
+
timescale: MEDIA_PARSER_RIFF_TIMESCALE,
|
|
4682
|
+
description: undefined,
|
|
4683
|
+
trackId: index,
|
|
4684
|
+
color: {
|
|
4685
|
+
fullRange: null,
|
|
4686
|
+
matrixCoefficients: null,
|
|
4687
|
+
primaries: null,
|
|
4688
|
+
transferCharacteristics: null
|
|
4689
|
+
},
|
|
4690
|
+
displayAspectWidth: strf.width,
|
|
4691
|
+
trakBox: null,
|
|
4692
|
+
rotation: 0,
|
|
4693
|
+
sampleAspectRatio: {
|
|
4694
|
+
numerator: 1,
|
|
4695
|
+
denominator: 1
|
|
4696
|
+
},
|
|
4697
|
+
fps: strh.rate / strh.scale
|
|
4698
|
+
};
|
|
4699
|
+
};
|
|
4700
|
+
var getTracksFromAvi = (structure, state) => {
|
|
4701
|
+
if (!isRiffAvi(structure)) {
|
|
4702
|
+
throw new Error("Not an AVI file");
|
|
4703
|
+
}
|
|
4704
|
+
const videoTracks = [];
|
|
4705
|
+
const audioTracks = [];
|
|
4706
|
+
const otherTracks = [];
|
|
4707
|
+
const boxes = getStrlBoxes(structure);
|
|
4708
|
+
let i = 0;
|
|
4709
|
+
for (const box of boxes) {
|
|
4710
|
+
const strh = getStrhBox(box.children);
|
|
4711
|
+
const strf = getStrfBox(box.children);
|
|
4712
|
+
if (!strh || !strf) {
|
|
4713
|
+
continue;
|
|
4714
|
+
}
|
|
4715
|
+
if (strf.type === "strf-box-video") {
|
|
4716
|
+
videoTracks.push(addAvcProfileToTrack(makeAviVideoTrack({ strh, strf, index: i }), state.getAvcProfile()));
|
|
4717
|
+
} else if (strh.fccType === "auds") {
|
|
4718
|
+
audioTracks.push(makeAviAudioTrack({ strf, index: i }));
|
|
4719
|
+
} else {
|
|
4720
|
+
throw new Error(`Unsupported track type ${strh.fccType}`);
|
|
4721
|
+
}
|
|
4722
|
+
i++;
|
|
4723
|
+
}
|
|
4724
|
+
return { audioTracks, otherTracks, videoTracks };
|
|
4725
|
+
};
|
|
4726
|
+
var hasAllTracksFromAvi = (structure, state) => {
|
|
4727
|
+
if (!isRiffAvi(structure)) {
|
|
4728
|
+
throw new Error("Not an AVI file");
|
|
4729
|
+
}
|
|
4730
|
+
const numberOfTracks = getNumberOfTracks(structure);
|
|
4731
|
+
const tracks2 = getTracksFromAvi(structure, state);
|
|
4732
|
+
return tracks2.videoTracks.length + tracks2.audioTracks.length + tracks2.otherTracks.length === numberOfTracks;
|
|
4733
|
+
};
|
|
4734
|
+
|
|
4639
4735
|
// src/make-hvc1-codec-strings.ts
|
|
4640
4736
|
var getHvc1CodecString = (data) => {
|
|
4641
4737
|
const configurationVersion = data.getUint8();
|
|
@@ -5009,48 +5105,63 @@ var getTracksFromMatroska = (segment, timescale2) => {
|
|
|
5009
5105
|
};
|
|
5010
5106
|
|
|
5011
5107
|
// src/get-tracks.ts
|
|
5012
|
-
var
|
|
5108
|
+
var getNumberOfTracks2 = (moovBox) => {
|
|
5013
5109
|
const mvHdBox = getMvhdBox(moovBox);
|
|
5014
5110
|
if (!mvHdBox) {
|
|
5015
5111
|
return 0;
|
|
5016
5112
|
}
|
|
5017
5113
|
return mvHdBox.nextTrackId - 1;
|
|
5018
5114
|
};
|
|
5019
|
-
var hasTracks = (
|
|
5020
|
-
|
|
5021
|
-
|
|
5115
|
+
var hasTracks = (structure, state) => {
|
|
5116
|
+
if (structure.type === "matroska") {
|
|
5117
|
+
const mainSegment = getMainSegment(structure.boxes);
|
|
5118
|
+
if (!mainSegment) {
|
|
5119
|
+
throw new Error("No main segment found");
|
|
5120
|
+
}
|
|
5022
5121
|
return getTracksSegment(mainSegment) !== null;
|
|
5023
5122
|
}
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5123
|
+
if (structure.type === "iso-base-media") {
|
|
5124
|
+
const moovBox = getMoovBox(structure.boxes);
|
|
5125
|
+
if (!moovBox) {
|
|
5126
|
+
return false;
|
|
5127
|
+
}
|
|
5128
|
+
const numberOfTracks = getNumberOfTracks2(moovBox);
|
|
5129
|
+
const tracks2 = getTraks(moovBox);
|
|
5130
|
+
return tracks2.length === numberOfTracks;
|
|
5027
5131
|
}
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5132
|
+
if (structure.type === "riff") {
|
|
5133
|
+
return hasAllTracksFromAvi(structure, state);
|
|
5134
|
+
}
|
|
5135
|
+
throw new Error("Unknown container");
|
|
5031
5136
|
};
|
|
5032
|
-
var
|
|
5137
|
+
var getTracksFromMa = (segments, state) => {
|
|
5033
5138
|
const videoTracks = [];
|
|
5034
5139
|
const audioTracks = [];
|
|
5035
5140
|
const otherTracks = [];
|
|
5036
5141
|
const mainSegment = segments.find((s) => s.type === "Segment");
|
|
5037
|
-
if (mainSegment
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5142
|
+
if (!mainSegment) {
|
|
5143
|
+
throw new Error("No main segment found");
|
|
5144
|
+
}
|
|
5145
|
+
const matroskaTracks = getTracksFromMatroska(mainSegment, state.getTimescale());
|
|
5146
|
+
for (const track of matroskaTracks) {
|
|
5147
|
+
if (track.type === "video") {
|
|
5148
|
+
videoTracks.push(track);
|
|
5149
|
+
} else if (track.type === "audio") {
|
|
5150
|
+
audioTracks.push(track);
|
|
5151
|
+
} else if (track.type === "other") {
|
|
5152
|
+
otherTracks.push(track);
|
|
5047
5153
|
}
|
|
5048
|
-
return {
|
|
5049
|
-
videoTracks,
|
|
5050
|
-
audioTracks,
|
|
5051
|
-
otherTracks
|
|
5052
|
-
};
|
|
5053
5154
|
}
|
|
5155
|
+
return {
|
|
5156
|
+
videoTracks,
|
|
5157
|
+
audioTracks,
|
|
5158
|
+
otherTracks
|
|
5159
|
+
};
|
|
5160
|
+
};
|
|
5161
|
+
var getTracksFromIsoBaseMedia = (segments) => {
|
|
5162
|
+
const videoTracks = [];
|
|
5163
|
+
const audioTracks = [];
|
|
5164
|
+
const otherTracks = [];
|
|
5054
5165
|
const moovBox = getMoovBox(segments);
|
|
5055
5166
|
if (!moovBox) {
|
|
5056
5167
|
return {
|
|
@@ -5079,18 +5190,33 @@ var getTracks = (segments, state) => {
|
|
|
5079
5190
|
otherTracks
|
|
5080
5191
|
};
|
|
5081
5192
|
};
|
|
5193
|
+
var getTracks = (segments, state) => {
|
|
5194
|
+
if (segments.type === "matroska") {
|
|
5195
|
+
return getTracksFromMa(segments.boxes, state);
|
|
5196
|
+
}
|
|
5197
|
+
if (segments.type === "iso-base-media") {
|
|
5198
|
+
return getTracksFromIsoBaseMedia(segments.boxes);
|
|
5199
|
+
}
|
|
5200
|
+
if (segments.type === "riff") {
|
|
5201
|
+
return getTracksFromAvi(segments, state);
|
|
5202
|
+
}
|
|
5203
|
+
throw new Error("Unknown container");
|
|
5204
|
+
};
|
|
5082
5205
|
|
|
5083
5206
|
// src/get-container.ts
|
|
5084
5207
|
var getContainer = (segments) => {
|
|
5085
|
-
|
|
5086
|
-
if (moovBox) {
|
|
5208
|
+
if (segments.type === "iso-base-media") {
|
|
5087
5209
|
return "mp4";
|
|
5088
5210
|
}
|
|
5089
|
-
|
|
5090
|
-
if (mainSegment) {
|
|
5211
|
+
if (segments.type === "matroska") {
|
|
5091
5212
|
return "webm";
|
|
5092
5213
|
}
|
|
5093
|
-
|
|
5214
|
+
if (segments.type === "riff") {
|
|
5215
|
+
if (isRiffAvi(segments)) {
|
|
5216
|
+
return "avi";
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
throw new Error("Unknown container");
|
|
5094
5220
|
};
|
|
5095
5221
|
var hasContainer = (boxes) => {
|
|
5096
5222
|
try {
|
|
@@ -5123,6 +5249,258 @@ var hasDimensions = (boxes, state) => {
|
|
|
5123
5249
|
}
|
|
5124
5250
|
};
|
|
5125
5251
|
|
|
5252
|
+
// src/get-sample-positions.ts
|
|
5253
|
+
var getSamplePositions = ({
|
|
5254
|
+
stcoBox,
|
|
5255
|
+
stszBox,
|
|
5256
|
+
stscBox,
|
|
5257
|
+
stssBox,
|
|
5258
|
+
sttsBox,
|
|
5259
|
+
cttsBox
|
|
5260
|
+
}) => {
|
|
5261
|
+
const sttsDeltas = [];
|
|
5262
|
+
for (const distribution of sttsBox.sampleDistribution) {
|
|
5263
|
+
for (let i = 0;i < distribution.sampleCount; i++) {
|
|
5264
|
+
sttsDeltas.push(distribution.sampleDelta);
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
const cttsEntries = [];
|
|
5268
|
+
for (const entry of cttsBox?.entries ?? [
|
|
5269
|
+
{ sampleCount: sttsDeltas.length, sampleOffset: 0 }
|
|
5270
|
+
]) {
|
|
5271
|
+
for (let i = 0;i < entry.sampleCount; i++) {
|
|
5272
|
+
cttsEntries.push(entry.sampleOffset);
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
let dts = 0;
|
|
5276
|
+
const chunks = stcoBox.entries;
|
|
5277
|
+
const samples = [];
|
|
5278
|
+
let samplesPerChunk = 1;
|
|
5279
|
+
for (let i = 0;i < chunks.length; i++) {
|
|
5280
|
+
const hasEntry = stscBox.entries.find((entry) => entry.firstChunk === i + 1);
|
|
5281
|
+
if (hasEntry) {
|
|
5282
|
+
samplesPerChunk = hasEntry.samplesPerChunk;
|
|
5283
|
+
}
|
|
5284
|
+
let offsetInThisChunk = 0;
|
|
5285
|
+
for (let j = 0;j < samplesPerChunk; j++) {
|
|
5286
|
+
const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
|
|
5287
|
+
const isKeyframe = stssBox ? stssBox.sampleNumber.includes(samples.length + 1) : true;
|
|
5288
|
+
const delta = sttsDeltas[samples.length];
|
|
5289
|
+
const ctsOffset = cttsEntries[samples.length];
|
|
5290
|
+
const cts = dts + ctsOffset;
|
|
5291
|
+
samples.push({
|
|
5292
|
+
offset: Number(chunks[i]) + offsetInThisChunk,
|
|
5293
|
+
size,
|
|
5294
|
+
isKeyframe,
|
|
5295
|
+
dts,
|
|
5296
|
+
cts,
|
|
5297
|
+
duration: delta,
|
|
5298
|
+
chunk: i
|
|
5299
|
+
});
|
|
5300
|
+
dts += delta;
|
|
5301
|
+
offsetInThisChunk += size;
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
return samples;
|
|
5305
|
+
};
|
|
5306
|
+
|
|
5307
|
+
// src/samples-from-moof.ts
|
|
5308
|
+
var getSamplesFromTraf = (trafSegment, moofOffset) => {
|
|
5309
|
+
if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
|
|
5310
|
+
throw new Error("Expected traf-box");
|
|
5311
|
+
}
|
|
5312
|
+
const tfhdBox = getTfhdBox(trafSegment);
|
|
5313
|
+
const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
|
|
5314
|
+
const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
|
|
5315
|
+
const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
|
|
5316
|
+
const tfdtBox = getTfdtBox(trafSegment);
|
|
5317
|
+
const trunBoxes = getTrunBoxes(trafSegment);
|
|
5318
|
+
let time = 0;
|
|
5319
|
+
let offset = 0;
|
|
5320
|
+
let dataOffset = 0;
|
|
5321
|
+
const samples = [];
|
|
5322
|
+
for (const trunBox of trunBoxes) {
|
|
5323
|
+
let i = -1;
|
|
5324
|
+
if (trunBox.dataOffset) {
|
|
5325
|
+
dataOffset = trunBox.dataOffset;
|
|
5326
|
+
offset = 0;
|
|
5327
|
+
}
|
|
5328
|
+
for (const sample of trunBox.samples) {
|
|
5329
|
+
i++;
|
|
5330
|
+
const duration2 = sample.sampleDuration ?? defaultSampleDuration;
|
|
5331
|
+
if (duration2 === null) {
|
|
5332
|
+
throw new Error("Expected duration");
|
|
5333
|
+
}
|
|
5334
|
+
const size = sample.sampleSize ?? defaultSampleSize;
|
|
5335
|
+
if (size === null) {
|
|
5336
|
+
throw new Error("Expected size");
|
|
5337
|
+
}
|
|
5338
|
+
const isFirstSample = i === 0;
|
|
5339
|
+
const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
|
|
5340
|
+
if (sampleFlags === null) {
|
|
5341
|
+
throw new Error("Expected sample flags");
|
|
5342
|
+
}
|
|
5343
|
+
const keyframe = !(sampleFlags >> 16 & 1);
|
|
5344
|
+
const dts = time + (tfdtBox?.baseMediaDecodeTime ?? 0);
|
|
5345
|
+
const samplePosition = {
|
|
5346
|
+
offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
|
|
5347
|
+
dts,
|
|
5348
|
+
cts: dts,
|
|
5349
|
+
duration: duration2,
|
|
5350
|
+
isKeyframe: keyframe,
|
|
5351
|
+
size,
|
|
5352
|
+
chunk: 0
|
|
5353
|
+
};
|
|
5354
|
+
samples.push(samplePosition);
|
|
5355
|
+
offset += size;
|
|
5356
|
+
time += duration2;
|
|
5357
|
+
}
|
|
5358
|
+
}
|
|
5359
|
+
return samples;
|
|
5360
|
+
};
|
|
5361
|
+
var getSamplesFromMoof = ({
|
|
5362
|
+
moofBox,
|
|
5363
|
+
trackId
|
|
5364
|
+
}) => {
|
|
5365
|
+
if (moofBox.type !== "regular-box") {
|
|
5366
|
+
throw new Error("Expected moof-box");
|
|
5367
|
+
}
|
|
5368
|
+
const trafs = moofBox.children.filter((c) => c.type === "regular-box" && c.boxType === "traf");
|
|
5369
|
+
const mapped = trafs.map((traf) => {
|
|
5370
|
+
const tfhdBox = getTfhdBox(traf);
|
|
5371
|
+
return tfhdBox?.trackId === trackId ? getSamplesFromTraf(traf, moofBox.offset) : [];
|
|
5372
|
+
});
|
|
5373
|
+
return mapped.flat(1);
|
|
5374
|
+
};
|
|
5375
|
+
|
|
5376
|
+
// src/boxes/iso-base-media/get-sample-positions-from-track.ts
|
|
5377
|
+
var getSamplePositionsFromTrack = (trakBox, moofBox) => {
|
|
5378
|
+
const stszBox = getStszBox(trakBox);
|
|
5379
|
+
const stcoBox = getStcoBox(trakBox);
|
|
5380
|
+
const stscBox = getStscBox(trakBox);
|
|
5381
|
+
const stssBox = getStssBox(trakBox);
|
|
5382
|
+
const sttsBox = getSttsBox(trakBox);
|
|
5383
|
+
const tkhdBox = getTkhdBox(trakBox);
|
|
5384
|
+
const cttsBox = getCttsBox(trakBox);
|
|
5385
|
+
const timescaleAndDuration = getTimescaleAndDuration(trakBox);
|
|
5386
|
+
if (!tkhdBox) {
|
|
5387
|
+
throw new Error("Expected tkhd box in trak box");
|
|
5388
|
+
}
|
|
5389
|
+
if (!stszBox) {
|
|
5390
|
+
throw new Error("Expected stsz box in trak box");
|
|
5391
|
+
}
|
|
5392
|
+
if (!stcoBox) {
|
|
5393
|
+
throw new Error("Expected stco box in trak box");
|
|
5394
|
+
}
|
|
5395
|
+
if (!stscBox) {
|
|
5396
|
+
throw new Error("Expected stsc box in trak box");
|
|
5397
|
+
}
|
|
5398
|
+
if (!sttsBox) {
|
|
5399
|
+
throw new Error("Expected stts box in trak box");
|
|
5400
|
+
}
|
|
5401
|
+
if (!timescaleAndDuration) {
|
|
5402
|
+
throw new Error("Expected timescale and duration in trak box");
|
|
5403
|
+
}
|
|
5404
|
+
let samplePositions = getSamplePositions({
|
|
5405
|
+
stcoBox,
|
|
5406
|
+
stscBox,
|
|
5407
|
+
stszBox,
|
|
5408
|
+
stssBox,
|
|
5409
|
+
sttsBox,
|
|
5410
|
+
cttsBox
|
|
5411
|
+
});
|
|
5412
|
+
if (samplePositions.length === 0 && moofBox) {
|
|
5413
|
+
samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
|
|
5414
|
+
}
|
|
5415
|
+
return samplePositions;
|
|
5416
|
+
};
|
|
5417
|
+
|
|
5418
|
+
// src/get-duration.ts
|
|
5419
|
+
var getDurationFromMatroska = (segments) => {
|
|
5420
|
+
const mainSegment = segments.find((s) => s.type === "Segment");
|
|
5421
|
+
if (!mainSegment || mainSegment.type !== "Segment") {
|
|
5422
|
+
return null;
|
|
5423
|
+
}
|
|
5424
|
+
const { value: children } = mainSegment;
|
|
5425
|
+
if (!children) {
|
|
5426
|
+
return null;
|
|
5427
|
+
}
|
|
5428
|
+
const infoSegment = children.find((s) => s.type === "Info");
|
|
5429
|
+
const relevantBoxes = [
|
|
5430
|
+
...mainSegment.value,
|
|
5431
|
+
...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
|
|
5432
|
+
];
|
|
5433
|
+
const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
|
|
5434
|
+
if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
|
|
5435
|
+
return null;
|
|
5436
|
+
}
|
|
5437
|
+
const duration2 = relevantBoxes.find((s) => s.type === "Duration");
|
|
5438
|
+
if (!duration2 || duration2.type !== "Duration") {
|
|
5439
|
+
return null;
|
|
5440
|
+
}
|
|
5441
|
+
return duration2.value.value / timestampScale2.value.value * 1000;
|
|
5442
|
+
};
|
|
5443
|
+
var getDurationFromIsoBaseMedia = (structure, parserState) => {
|
|
5444
|
+
const moovBox = getMoovBox(structure.boxes);
|
|
5445
|
+
if (!moovBox) {
|
|
5446
|
+
return null;
|
|
5447
|
+
}
|
|
5448
|
+
const moofBox = getMoofBox(structure.boxes);
|
|
5449
|
+
const mvhdBox = getMvhdBox(moovBox);
|
|
5450
|
+
if (!mvhdBox) {
|
|
5451
|
+
return null;
|
|
5452
|
+
}
|
|
5453
|
+
if (mvhdBox.type !== "mvhd-box") {
|
|
5454
|
+
throw new Error("Expected mvhd-box");
|
|
5455
|
+
}
|
|
5456
|
+
if (mvhdBox.durationInSeconds > 0) {
|
|
5457
|
+
return mvhdBox.durationInSeconds;
|
|
5458
|
+
}
|
|
5459
|
+
const tracks2 = getTracks(structure, parserState);
|
|
5460
|
+
const allTracks = [
|
|
5461
|
+
...tracks2.videoTracks,
|
|
5462
|
+
...tracks2.audioTracks,
|
|
5463
|
+
...tracks2.otherTracks
|
|
5464
|
+
];
|
|
5465
|
+
const allSamples = allTracks.map((t) => {
|
|
5466
|
+
const { timescale: ts } = t;
|
|
5467
|
+
const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
|
|
5468
|
+
const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
|
|
5469
|
+
return highest ?? 0;
|
|
5470
|
+
});
|
|
5471
|
+
const highestTimestamp = Math.max(...allSamples);
|
|
5472
|
+
return highestTimestamp;
|
|
5473
|
+
};
|
|
5474
|
+
var getDurationFromAvi = (structure) => {
|
|
5475
|
+
const strl = getStrlBoxes(structure);
|
|
5476
|
+
const lengths = [];
|
|
5477
|
+
for (const s of strl) {
|
|
5478
|
+
const strh = getStrhBox(s.children);
|
|
5479
|
+
if (!strh) {
|
|
5480
|
+
throw new Error("No strh box");
|
|
5481
|
+
}
|
|
5482
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
5483
|
+
const streamLength = strh.length / samplesPerSecond;
|
|
5484
|
+
lengths.push(streamLength);
|
|
5485
|
+
}
|
|
5486
|
+
return Math.max(...lengths);
|
|
5487
|
+
};
|
|
5488
|
+
var getDuration = (structure, parserState) => {
|
|
5489
|
+
if (structure.type === "matroska") {
|
|
5490
|
+
return getDurationFromMatroska(structure.boxes);
|
|
5491
|
+
}
|
|
5492
|
+
if (structure.type === "iso-base-media") {
|
|
5493
|
+
return getDurationFromIsoBaseMedia(structure, parserState);
|
|
5494
|
+
}
|
|
5495
|
+
if (structure.type === "riff") {
|
|
5496
|
+
return getDurationFromAvi(structure);
|
|
5497
|
+
}
|
|
5498
|
+
throw new Error("Has no duration");
|
|
5499
|
+
};
|
|
5500
|
+
var hasDuration = (structure, parserState) => {
|
|
5501
|
+
return hasTracks(structure, parserState);
|
|
5502
|
+
};
|
|
5503
|
+
|
|
5126
5504
|
// src/emit-available-info.ts
|
|
5127
5505
|
var emitAvailableInfo = ({
|
|
5128
5506
|
hasInfo,
|
|
@@ -5135,10 +5513,10 @@ var emitAvailableInfo = ({
|
|
|
5135
5513
|
}) => {
|
|
5136
5514
|
const keys = Object.keys(hasInfo);
|
|
5137
5515
|
for (const key of keys) {
|
|
5138
|
-
if (key === "
|
|
5139
|
-
if (parseResult && hasInfo.
|
|
5140
|
-
moreFields.
|
|
5141
|
-
returnValue.
|
|
5516
|
+
if (key === "structure") {
|
|
5517
|
+
if (parseResult && hasInfo.structure && returnValue.structure === undefined) {
|
|
5518
|
+
moreFields.onStructure?.(parseResult.segments);
|
|
5519
|
+
returnValue.structure = parseResult.segments;
|
|
5142
5520
|
}
|
|
5143
5521
|
continue;
|
|
5144
5522
|
}
|
|
@@ -5254,7 +5632,7 @@ var emitAvailableInfo = ({
|
|
|
5254
5632
|
var getAvailableInfo = (options, parseResult, state) => {
|
|
5255
5633
|
const keys = Object.entries(options).filter(([, value]) => value);
|
|
5256
5634
|
const infos = keys.map(([key]) => {
|
|
5257
|
-
if (key === "
|
|
5635
|
+
if (key === "structure") {
|
|
5258
5636
|
return Boolean(parseResult && parseResult.status === "done");
|
|
5259
5637
|
}
|
|
5260
5638
|
if (key === "durationInSeconds") {
|
|
@@ -5267,13 +5645,13 @@ var getAvailableInfo = (options, parseResult, state) => {
|
|
|
5267
5645
|
return Boolean(parseResult && hasFps(parseResult.segments));
|
|
5268
5646
|
}
|
|
5269
5647
|
if (key === "videoCodec") {
|
|
5270
|
-
return Boolean(parseResult && hasVideoCodec(parseResult.segments));
|
|
5648
|
+
return Boolean(parseResult && hasVideoCodec(parseResult.segments, state));
|
|
5271
5649
|
}
|
|
5272
5650
|
if (key === "audioCodec") {
|
|
5273
|
-
return Boolean(parseResult && hasAudioCodec(parseResult.segments));
|
|
5651
|
+
return Boolean(parseResult && hasAudioCodec(parseResult.segments, state));
|
|
5274
5652
|
}
|
|
5275
5653
|
if (key === "tracks") {
|
|
5276
|
-
return Boolean(parseResult && hasTracks(parseResult.segments));
|
|
5654
|
+
return Boolean(parseResult && hasTracks(parseResult.segments, state));
|
|
5277
5655
|
}
|
|
5278
5656
|
if (key === "internalStats") {
|
|
5279
5657
|
return false;
|
|
@@ -5297,6 +5675,35 @@ var getAvailableInfo = (options, parseResult, state) => {
|
|
|
5297
5675
|
return Object.fromEntries(entries);
|
|
5298
5676
|
};
|
|
5299
5677
|
|
|
5678
|
+
// src/register-track.ts
|
|
5679
|
+
var registerTrack = async ({
|
|
5680
|
+
state,
|
|
5681
|
+
options,
|
|
5682
|
+
track
|
|
5683
|
+
}) => {
|
|
5684
|
+
if (track.type === "video" && options.onVideoTrack) {
|
|
5685
|
+
const callback = await options.onVideoTrack(track);
|
|
5686
|
+
await state.registerVideoSampleCallback(track.trackId, callback ?? null);
|
|
5687
|
+
}
|
|
5688
|
+
if (track.type === "audio" && options.onAudioTrack) {
|
|
5689
|
+
const callback = await options.onAudioTrack(track);
|
|
5690
|
+
await state.registerAudioSampleCallback(track.trackId, callback ?? null);
|
|
5691
|
+
}
|
|
5692
|
+
};
|
|
5693
|
+
var registerVideoTrackWhenProfileIsAvailable = ({
|
|
5694
|
+
options,
|
|
5695
|
+
state,
|
|
5696
|
+
track
|
|
5697
|
+
}) => {
|
|
5698
|
+
state.registerOnAvcProfileCallback(async (profile) => {
|
|
5699
|
+
await registerTrack({
|
|
5700
|
+
options,
|
|
5701
|
+
state,
|
|
5702
|
+
track: addAvcProfileToTrack(track, profile)
|
|
5703
|
+
});
|
|
5704
|
+
});
|
|
5705
|
+
};
|
|
5706
|
+
|
|
5300
5707
|
// src/boxes/iso-base-media/esds/decoder-specific-config.ts
|
|
5301
5708
|
var parseDecoderSpecificConfig = (iterator, logLevel) => {
|
|
5302
5709
|
const layerTag = iterator.getUint8();
|
|
@@ -5471,7 +5878,10 @@ var parseMdat = async ({
|
|
|
5471
5878
|
signal,
|
|
5472
5879
|
maySkipSampleProcessing
|
|
5473
5880
|
}) => {
|
|
5474
|
-
const alreadyHas = hasTracks(
|
|
5881
|
+
const alreadyHas = hasTracks({
|
|
5882
|
+
type: "iso-base-media",
|
|
5883
|
+
boxes: existingBoxes
|
|
5884
|
+
}, options.parserState);
|
|
5475
5885
|
if (!alreadyHas) {
|
|
5476
5886
|
if (maySkipSampleProcessing) {
|
|
5477
5887
|
data.discard(size - (data.counter.getOffset() - fileOffset));
|
|
@@ -5491,7 +5901,7 @@ var parseMdat = async ({
|
|
|
5491
5901
|
fileOffset
|
|
5492
5902
|
});
|
|
5493
5903
|
}
|
|
5494
|
-
const tracks2 = getTracks(existingBoxes, options.parserState);
|
|
5904
|
+
const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, options.parserState);
|
|
5495
5905
|
const allTracks = [
|
|
5496
5906
|
...tracks2.videoTracks,
|
|
5497
5907
|
...tracks2.audioTracks,
|
|
@@ -5610,7 +6020,7 @@ var parseMoov = async ({
|
|
|
5610
6020
|
signal,
|
|
5611
6021
|
logLevel
|
|
5612
6022
|
}) => {
|
|
5613
|
-
const children = await
|
|
6023
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
5614
6024
|
iterator,
|
|
5615
6025
|
maxBytes: size - (iterator.counter.getOffset() - offset),
|
|
5616
6026
|
allowIncompleteBoxes: false,
|
|
@@ -5627,7 +6037,7 @@ var parseMoov = async ({
|
|
|
5627
6037
|
offset,
|
|
5628
6038
|
boxSize: size,
|
|
5629
6039
|
type: "moov-box",
|
|
5630
|
-
children: children.segments
|
|
6040
|
+
children: children.segments.boxes
|
|
5631
6041
|
};
|
|
5632
6042
|
};
|
|
5633
6043
|
|
|
@@ -5932,7 +6342,7 @@ var parseMebx = async ({
|
|
|
5932
6342
|
}) => {
|
|
5933
6343
|
iterator.discard(6);
|
|
5934
6344
|
const dataReferenceIndex = iterator.getUint16();
|
|
5935
|
-
const children = await
|
|
6345
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
5936
6346
|
iterator,
|
|
5937
6347
|
maxBytes: iterator.counter.getOffset() - offset,
|
|
5938
6348
|
allowIncompleteBoxes: false,
|
|
@@ -5951,7 +6361,7 @@ var parseMebx = async ({
|
|
|
5951
6361
|
offset,
|
|
5952
6362
|
dataReferenceIndex,
|
|
5953
6363
|
format: "mebx",
|
|
5954
|
-
children: children.segments
|
|
6364
|
+
children: children.segments.boxes
|
|
5955
6365
|
};
|
|
5956
6366
|
};
|
|
5957
6367
|
|
|
@@ -6142,7 +6552,7 @@ var processSample = async ({
|
|
|
6142
6552
|
const packetSize = iterator.getUint16();
|
|
6143
6553
|
const sampleRate = iterator.getFixedPointUnsigned1616Number();
|
|
6144
6554
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6145
|
-
const children = await
|
|
6555
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6146
6556
|
iterator,
|
|
6147
6557
|
allowIncompleteBoxes: false,
|
|
6148
6558
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6174,7 +6584,7 @@ var processSample = async ({
|
|
|
6174
6584
|
bytesPerPacket: null,
|
|
6175
6585
|
bytesPerFrame: null,
|
|
6176
6586
|
bitsPerSample: null,
|
|
6177
|
-
children: children.segments
|
|
6587
|
+
children: children.segments.boxes
|
|
6178
6588
|
}
|
|
6179
6589
|
};
|
|
6180
6590
|
}
|
|
@@ -6189,7 +6599,7 @@ var processSample = async ({
|
|
|
6189
6599
|
const bytesPerFrame = iterator.getUint32();
|
|
6190
6600
|
const bytesPerSample = iterator.getUint32();
|
|
6191
6601
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6192
|
-
const children = await
|
|
6602
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6193
6603
|
iterator,
|
|
6194
6604
|
allowIncompleteBoxes: false,
|
|
6195
6605
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6221,7 +6631,7 @@ var processSample = async ({
|
|
|
6221
6631
|
bytesPerPacket,
|
|
6222
6632
|
bytesPerFrame,
|
|
6223
6633
|
bitsPerSample: bytesPerSample,
|
|
6224
|
-
children: children.segments
|
|
6634
|
+
children: children.segments.boxes
|
|
6225
6635
|
}
|
|
6226
6636
|
};
|
|
6227
6637
|
}
|
|
@@ -6240,7 +6650,7 @@ var processSample = async ({
|
|
|
6240
6650
|
const bytesPerFrame = iterator.getUint32();
|
|
6241
6651
|
const samplesPerPacket = iterator.getUint32();
|
|
6242
6652
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6243
|
-
const children = await
|
|
6653
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6244
6654
|
iterator,
|
|
6245
6655
|
allowIncompleteBoxes: false,
|
|
6246
6656
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6272,7 +6682,7 @@ var processSample = async ({
|
|
|
6272
6682
|
bytesPerPacket: null,
|
|
6273
6683
|
bytesPerFrame,
|
|
6274
6684
|
bitsPerSample: bitsPerCodedSample,
|
|
6275
|
-
children: children.segments
|
|
6685
|
+
children: children.segments.boxes
|
|
6276
6686
|
}
|
|
6277
6687
|
};
|
|
6278
6688
|
}
|
|
@@ -6294,7 +6704,7 @@ var processSample = async ({
|
|
|
6294
6704
|
const depth = iterator.getUint16();
|
|
6295
6705
|
const colorTableId = iterator.getInt16();
|
|
6296
6706
|
const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
|
|
6297
|
-
const children = bytesRemainingInBox > 8 ? await
|
|
6707
|
+
const children = bytesRemainingInBox > 8 ? await parseIsoBaseMediaBoxes({
|
|
6298
6708
|
iterator,
|
|
6299
6709
|
allowIncompleteBoxes: false,
|
|
6300
6710
|
maxBytes: bytesRemainingInBox,
|
|
@@ -6303,7 +6713,7 @@ var processSample = async ({
|
|
|
6303
6713
|
continueMdat: false,
|
|
6304
6714
|
signal,
|
|
6305
6715
|
logLevel
|
|
6306
|
-
}) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: [] });
|
|
6716
|
+
}) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: { boxes: [], type: "iso-base-media" } });
|
|
6307
6717
|
if (children.status === "incomplete") {
|
|
6308
6718
|
throw new Error("Incomplete boxes are not allowed");
|
|
6309
6719
|
}
|
|
@@ -6328,7 +6738,7 @@ var processSample = async ({
|
|
|
6328
6738
|
compressorName,
|
|
6329
6739
|
depth,
|
|
6330
6740
|
colorTableId,
|
|
6331
|
-
descriptors: children.segments
|
|
6741
|
+
descriptors: children.segments.boxes
|
|
6332
6742
|
}
|
|
6333
6743
|
};
|
|
6334
6744
|
}
|
|
@@ -6650,7 +7060,7 @@ var parseTrak = async ({
|
|
|
6650
7060
|
signal,
|
|
6651
7061
|
logLevel
|
|
6652
7062
|
}) => {
|
|
6653
|
-
const children = await
|
|
7063
|
+
const children = await parseIsoBaseMediaBoxes({
|
|
6654
7064
|
iterator: data,
|
|
6655
7065
|
maxBytes: size - (data.counter.getOffset() - offsetAtStart),
|
|
6656
7066
|
allowIncompleteBoxes: false,
|
|
@@ -6667,7 +7077,7 @@ var parseTrak = async ({
|
|
|
6667
7077
|
offset: offsetAtStart,
|
|
6668
7078
|
boxSize: size,
|
|
6669
7079
|
type: "trak-box",
|
|
6670
|
-
children: children.segments
|
|
7080
|
+
children: children.segments.boxes
|
|
6671
7081
|
};
|
|
6672
7082
|
};
|
|
6673
7083
|
|
|
@@ -6724,7 +7134,7 @@ var getChildren = async ({
|
|
|
6724
7134
|
}) => {
|
|
6725
7135
|
const parseChildren = boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "moof" || boxType === "dims" || boxType === "wave" || boxType === "traf" || boxType === "stsb";
|
|
6726
7136
|
if (parseChildren) {
|
|
6727
|
-
const parsed = await
|
|
7137
|
+
const parsed = await parseIsoBaseMediaBoxes({
|
|
6728
7138
|
iterator,
|
|
6729
7139
|
maxBytes: bytesRemainingInBox,
|
|
6730
7140
|
allowIncompleteBoxes: false,
|
|
@@ -6737,7 +7147,7 @@ var getChildren = async ({
|
|
|
6737
7147
|
if (parsed.status === "incomplete") {
|
|
6738
7148
|
throw new Error("Incomplete boxes are not allowed");
|
|
6739
7149
|
}
|
|
6740
|
-
return parsed.segments;
|
|
7150
|
+
return parsed.segments.boxes;
|
|
6741
7151
|
}
|
|
6742
7152
|
if (bytesRemainingInBox < 0) {
|
|
6743
7153
|
throw new Error("Box size is too big " + JSON.stringify({ boxType }));
|
|
@@ -6811,7 +7221,7 @@ var processBox = async ({
|
|
|
6811
7221
|
const boxSize = boxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw;
|
|
6812
7222
|
if (bytesRemaining < boxSize) {
|
|
6813
7223
|
if (boxType === "mdat") {
|
|
6814
|
-
const shouldSkip = (options.canSkipVideoData || !hasTracks(parsedBoxes)) && options.supportsContentRange;
|
|
7224
|
+
const shouldSkip = (options.canSkipVideoData || !hasTracks({ type: "iso-base-media", boxes: parsedBoxes }, options.parserState)) && options.supportsContentRange;
|
|
6815
7225
|
if (shouldSkip) {
|
|
6816
7226
|
const skipTo = fileOffset + boxSize;
|
|
6817
7227
|
const bytesToSkip = skipTo - iterator.counter.getOffset();
|
|
@@ -7040,14 +7450,11 @@ var processBox = async ({
|
|
|
7040
7450
|
});
|
|
7041
7451
|
const transformedTrack = makeBaseMediaTrack(box);
|
|
7042
7452
|
if (transformedTrack) {
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
const callback = await options.onVideoTrack?.(transformedTrack);
|
|
7049
|
-
await options.parserState.registerVideoSampleCallback(transformedTrack.trackId, callback ?? null);
|
|
7050
|
-
}
|
|
7453
|
+
await registerTrack({
|
|
7454
|
+
options,
|
|
7455
|
+
state: options.parserState,
|
|
7456
|
+
track: transformedTrack
|
|
7457
|
+
});
|
|
7051
7458
|
}
|
|
7052
7459
|
return {
|
|
7053
7460
|
type: "complete",
|
|
@@ -7188,7 +7595,7 @@ var processBox = async ({
|
|
|
7188
7595
|
skipTo: null
|
|
7189
7596
|
};
|
|
7190
7597
|
};
|
|
7191
|
-
var
|
|
7598
|
+
var parseIsoBaseMediaBoxes = async ({
|
|
7192
7599
|
iterator,
|
|
7193
7600
|
maxBytes,
|
|
7194
7601
|
allowIncompleteBoxes,
|
|
@@ -7198,9 +7605,12 @@ var parseBoxes = async ({
|
|
|
7198
7605
|
signal,
|
|
7199
7606
|
logLevel
|
|
7200
7607
|
}) => {
|
|
7201
|
-
|
|
7608
|
+
const structure = {
|
|
7609
|
+
type: "iso-base-media",
|
|
7610
|
+
boxes: initialBoxes
|
|
7611
|
+
};
|
|
7202
7612
|
const initialOffset = iterator.counter.getOffset();
|
|
7203
|
-
const alreadyHasMdat = boxes.find((b) => b.type === "mdat-box");
|
|
7613
|
+
const alreadyHasMdat = structure.boxes.find((b) => b.type === "mdat-box");
|
|
7204
7614
|
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
|
|
7205
7615
|
const result = continueMdat ? await parseMdatPartially({
|
|
7206
7616
|
iterator,
|
|
@@ -7223,13 +7633,13 @@ var parseBoxes = async ({
|
|
|
7223
7633
|
}
|
|
7224
7634
|
return {
|
|
7225
7635
|
status: "incomplete",
|
|
7226
|
-
segments:
|
|
7636
|
+
segments: structure,
|
|
7227
7637
|
continueParsing: () => {
|
|
7228
|
-
return
|
|
7638
|
+
return parseIsoBaseMediaBoxes({
|
|
7229
7639
|
iterator,
|
|
7230
7640
|
maxBytes,
|
|
7231
7641
|
allowIncompleteBoxes,
|
|
7232
|
-
initialBoxes: boxes,
|
|
7642
|
+
initialBoxes: structure.boxes,
|
|
7233
7643
|
options,
|
|
7234
7644
|
continueMdat: false,
|
|
7235
7645
|
signal,
|
|
@@ -7242,13 +7652,13 @@ var parseBoxes = async ({
|
|
|
7242
7652
|
if (result.type === "partial-mdat-box") {
|
|
7243
7653
|
return {
|
|
7244
7654
|
status: "incomplete",
|
|
7245
|
-
segments:
|
|
7655
|
+
segments: structure,
|
|
7246
7656
|
continueParsing: () => {
|
|
7247
|
-
return Promise.resolve(
|
|
7657
|
+
return Promise.resolve(parseIsoBaseMediaBoxes({
|
|
7248
7658
|
iterator,
|
|
7249
7659
|
maxBytes,
|
|
7250
7660
|
allowIncompleteBoxes,
|
|
7251
|
-
initialBoxes: boxes,
|
|
7661
|
+
initialBoxes: structure.boxes,
|
|
7252
7662
|
options,
|
|
7253
7663
|
continueMdat: result,
|
|
7254
7664
|
signal,
|
|
@@ -7259,15 +7669,15 @@ var parseBoxes = async ({
|
|
|
7259
7669
|
};
|
|
7260
7670
|
}
|
|
7261
7671
|
if (result.box.type === "mdat-box" && alreadyHasMdat) {
|
|
7262
|
-
boxes = boxes.filter((b) => b.type !== "mdat-box");
|
|
7263
|
-
boxes.push(result.box);
|
|
7672
|
+
structure.boxes = structure.boxes.filter((b) => b.type !== "mdat-box");
|
|
7673
|
+
structure.boxes.push(result.box);
|
|
7264
7674
|
iterator.allowDiscard();
|
|
7265
7675
|
if (result.box.status !== "samples-processed") {
|
|
7266
7676
|
throw new Error("unexpected");
|
|
7267
7677
|
}
|
|
7268
7678
|
break;
|
|
7269
7679
|
} else {
|
|
7270
|
-
boxes.push(result.box);
|
|
7680
|
+
structure.boxes.push(result.box);
|
|
7271
7681
|
}
|
|
7272
7682
|
if (result.skipTo !== null) {
|
|
7273
7683
|
if (!options.supportsContentRange) {
|
|
@@ -7275,13 +7685,13 @@ var parseBoxes = async ({
|
|
|
7275
7685
|
}
|
|
7276
7686
|
return {
|
|
7277
7687
|
status: "incomplete",
|
|
7278
|
-
segments:
|
|
7688
|
+
segments: structure,
|
|
7279
7689
|
continueParsing: () => {
|
|
7280
|
-
return
|
|
7690
|
+
return parseIsoBaseMediaBoxes({
|
|
7281
7691
|
iterator,
|
|
7282
7692
|
maxBytes,
|
|
7283
7693
|
allowIncompleteBoxes,
|
|
7284
|
-
initialBoxes: boxes,
|
|
7694
|
+
initialBoxes: structure.boxes,
|
|
7285
7695
|
options,
|
|
7286
7696
|
continueMdat: false,
|
|
7287
7697
|
signal,
|
|
@@ -7294,13 +7704,13 @@ var parseBoxes = async ({
|
|
|
7294
7704
|
if (iterator.bytesRemaining() < 0) {
|
|
7295
7705
|
return {
|
|
7296
7706
|
status: "incomplete",
|
|
7297
|
-
segments:
|
|
7707
|
+
segments: structure,
|
|
7298
7708
|
continueParsing: () => {
|
|
7299
|
-
return
|
|
7709
|
+
return parseIsoBaseMediaBoxes({
|
|
7300
7710
|
iterator,
|
|
7301
7711
|
maxBytes,
|
|
7302
7712
|
allowIncompleteBoxes,
|
|
7303
|
-
initialBoxes: boxes,
|
|
7713
|
+
initialBoxes: structure.boxes,
|
|
7304
7714
|
options,
|
|
7305
7715
|
continueMdat: false,
|
|
7306
7716
|
signal,
|
|
@@ -7312,22 +7722,22 @@ var parseBoxes = async ({
|
|
|
7312
7722
|
}
|
|
7313
7723
|
iterator.removeBytesRead();
|
|
7314
7724
|
}
|
|
7315
|
-
const mdatState = getMdatBox(boxes);
|
|
7725
|
+
const mdatState = getMdatBox(structure.boxes);
|
|
7316
7726
|
const skipped = mdatState?.status === "samples-skipped" && !options.canSkipVideoData && options.supportsContentRange;
|
|
7317
7727
|
const buffered = mdatState?.status === "samples-buffered" && !options.canSkipVideoData;
|
|
7318
7728
|
if (skipped || buffered) {
|
|
7319
7729
|
return {
|
|
7320
7730
|
status: "incomplete",
|
|
7321
|
-
segments:
|
|
7731
|
+
segments: structure,
|
|
7322
7732
|
continueParsing: () => {
|
|
7323
7733
|
if (buffered) {
|
|
7324
7734
|
iterator.skipTo(mdatState.fileOffset, false);
|
|
7325
7735
|
}
|
|
7326
|
-
return
|
|
7736
|
+
return parseIsoBaseMediaBoxes({
|
|
7327
7737
|
iterator,
|
|
7328
7738
|
maxBytes,
|
|
7329
7739
|
allowIncompleteBoxes: false,
|
|
7330
|
-
initialBoxes: boxes,
|
|
7740
|
+
initialBoxes: structure.boxes,
|
|
7331
7741
|
options,
|
|
7332
7742
|
continueMdat: false,
|
|
7333
7743
|
signal,
|
|
@@ -7339,24 +7749,651 @@ var parseBoxes = async ({
|
|
|
7339
7749
|
}
|
|
7340
7750
|
return {
|
|
7341
7751
|
status: "done",
|
|
7342
|
-
segments:
|
|
7752
|
+
segments: structure
|
|
7343
7753
|
};
|
|
7344
7754
|
};
|
|
7345
7755
|
|
|
7346
|
-
// src/
|
|
7347
|
-
var
|
|
7348
|
-
|
|
7756
|
+
// src/boxes/riff/is-movi.ts
|
|
7757
|
+
var isMoviAtom = (iterator, ckId) => {
|
|
7758
|
+
if (ckId !== "LIST") {
|
|
7759
|
+
return false;
|
|
7760
|
+
}
|
|
7761
|
+
const listType = iterator.getByteString(4);
|
|
7762
|
+
iterator.counter.decrement(4);
|
|
7763
|
+
return listType === "movi";
|
|
7764
|
+
};
|
|
7765
|
+
|
|
7766
|
+
// src/boxes/avc/parse-avc.ts
|
|
7767
|
+
var readSps = (iterator) => {
|
|
7768
|
+
const profile = iterator.getUint8();
|
|
7769
|
+
const compatibility = iterator.getUint8();
|
|
7770
|
+
const level = iterator.getUint8();
|
|
7771
|
+
return {
|
|
7772
|
+
profile,
|
|
7773
|
+
compatibility,
|
|
7774
|
+
level
|
|
7775
|
+
};
|
|
7776
|
+
};
|
|
7777
|
+
var findEnd = (buffer) => {
|
|
7778
|
+
let zeroesInARow = 0;
|
|
7779
|
+
for (let i = 0;i < buffer.length; i++) {
|
|
7780
|
+
const val = buffer[i];
|
|
7781
|
+
if (val === 0) {
|
|
7782
|
+
zeroesInARow++;
|
|
7783
|
+
continue;
|
|
7784
|
+
}
|
|
7785
|
+
if (zeroesInARow >= 2 && val === 1) {
|
|
7786
|
+
return i - zeroesInARow;
|
|
7787
|
+
}
|
|
7788
|
+
zeroesInARow = 0;
|
|
7789
|
+
}
|
|
7790
|
+
return null;
|
|
7791
|
+
};
|
|
7792
|
+
var inspect = (buffer) => {
|
|
7793
|
+
const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
|
|
7794
|
+
iterator.startReadingBits();
|
|
7795
|
+
iterator.getBits(1);
|
|
7796
|
+
iterator.getBits(2);
|
|
7797
|
+
const type = iterator.getBits(5);
|
|
7798
|
+
iterator.stopReadingBits();
|
|
7799
|
+
if (type === 7) {
|
|
7800
|
+
const end = findEnd(buffer);
|
|
7801
|
+
const data = readSps(iterator);
|
|
7802
|
+
const sps = buffer.slice(1, end === null ? Infinity : end);
|
|
7803
|
+
return {
|
|
7804
|
+
level: data.level,
|
|
7805
|
+
profile: data.profile,
|
|
7806
|
+
compatibility: data.compatibility,
|
|
7807
|
+
sps,
|
|
7808
|
+
type: "avc-profile"
|
|
7809
|
+
};
|
|
7810
|
+
}
|
|
7811
|
+
if (type === 5) {
|
|
7812
|
+
return {
|
|
7813
|
+
type: "keyframe"
|
|
7814
|
+
};
|
|
7815
|
+
}
|
|
7816
|
+
if (type === 8) {
|
|
7817
|
+
const end = findEnd(buffer);
|
|
7818
|
+
const pps = buffer.slice(0, end === null ? Infinity : end);
|
|
7819
|
+
return {
|
|
7820
|
+
type: "avc-pps",
|
|
7821
|
+
pps
|
|
7822
|
+
};
|
|
7823
|
+
}
|
|
7824
|
+
if (type === 1) {
|
|
7825
|
+
return {
|
|
7826
|
+
type: "delta-frame"
|
|
7827
|
+
};
|
|
7828
|
+
}
|
|
7829
|
+
iterator.destroy();
|
|
7830
|
+
return null;
|
|
7831
|
+
};
|
|
7832
|
+
var parseAvc = (buffer) => {
|
|
7833
|
+
let zeroesInARow = 0;
|
|
7834
|
+
const infos = [];
|
|
7835
|
+
for (let i = 0;i < buffer.length; i++) {
|
|
7836
|
+
const val = buffer[i];
|
|
7837
|
+
if (val === 0) {
|
|
7838
|
+
zeroesInARow++;
|
|
7839
|
+
continue;
|
|
7840
|
+
}
|
|
7841
|
+
if (zeroesInARow >= 2 && val === 1) {
|
|
7842
|
+
zeroesInARow = 0;
|
|
7843
|
+
const info = inspect(buffer.slice(i + 1, i + 100));
|
|
7844
|
+
if (info) {
|
|
7845
|
+
infos.push(info);
|
|
7846
|
+
if (info.type === "keyframe" || info.type === "delta-frame") {
|
|
7847
|
+
break;
|
|
7848
|
+
}
|
|
7849
|
+
}
|
|
7850
|
+
}
|
|
7851
|
+
if (val !== 1) {
|
|
7852
|
+
zeroesInARow = 0;
|
|
7853
|
+
}
|
|
7854
|
+
}
|
|
7855
|
+
return infos;
|
|
7856
|
+
};
|
|
7857
|
+
|
|
7858
|
+
// src/boxes/riff/parse-movi.ts
|
|
7859
|
+
var getStrhForIndex = (structure, trackId) => {
|
|
7860
|
+
const boxes = getStrlBoxes(structure);
|
|
7861
|
+
const box = boxes[trackId];
|
|
7862
|
+
if (!box) {
|
|
7863
|
+
throw new Error("Expected box");
|
|
7864
|
+
}
|
|
7865
|
+
const strh = getStrhBox(box.children);
|
|
7866
|
+
if (!strh) {
|
|
7867
|
+
throw new Error("strh");
|
|
7868
|
+
}
|
|
7869
|
+
return strh;
|
|
7870
|
+
};
|
|
7871
|
+
var handleChunk = async ({
|
|
7872
|
+
iterator,
|
|
7349
7873
|
options,
|
|
7350
|
-
|
|
7874
|
+
structure,
|
|
7875
|
+
ckId,
|
|
7876
|
+
ckSize
|
|
7351
7877
|
}) => {
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7878
|
+
const videoChunk = ckId.match(/^([0-9]{2})dc$/);
|
|
7879
|
+
if (videoChunk) {
|
|
7880
|
+
const trackId = parseInt(videoChunk[1], 10);
|
|
7881
|
+
const strh = getStrhForIndex(structure, trackId);
|
|
7882
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
7883
|
+
const nthSample = options.parserState.getSamplesForTrack(trackId);
|
|
7884
|
+
const timeInSec = nthSample / samplesPerSecond;
|
|
7885
|
+
const timestamp = Math.floor(timeInSec * MEDIA_PARSER_RIFF_TIMESCALE);
|
|
7886
|
+
const duration2 = Math.floor(1 / samplesPerSecond * MEDIA_PARSER_RIFF_TIMESCALE);
|
|
7887
|
+
const data = iterator.getSlice(ckSize);
|
|
7888
|
+
const infos = parseAvc(data);
|
|
7889
|
+
const keyOrDelta = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
|
|
7890
|
+
if (!keyOrDelta) {
|
|
7891
|
+
throw new Error("expected avc to contain info about key or delta");
|
|
7892
|
+
}
|
|
7893
|
+
const avcProfile = infos.find((i) => i.type === "avc-profile");
|
|
7894
|
+
const ppsProfile = infos.find((i) => i.type === "avc-pps");
|
|
7895
|
+
if (avcProfile && ppsProfile) {
|
|
7896
|
+
await options.parserState.onProfile({ pps: ppsProfile, sps: avcProfile });
|
|
7897
|
+
}
|
|
7898
|
+
await options.parserState.onVideoSample(trackId, {
|
|
7899
|
+
cts: timestamp,
|
|
7900
|
+
dts: timestamp,
|
|
7901
|
+
data,
|
|
7902
|
+
duration: duration2,
|
|
7903
|
+
timestamp,
|
|
7904
|
+
trackId,
|
|
7905
|
+
type: keyOrDelta.type === "keyframe" ? "key" : "delta"
|
|
7906
|
+
});
|
|
7907
|
+
} else {
|
|
7908
|
+
const audioChunk = ckId.match(/^([0-9]{2})wb$/);
|
|
7909
|
+
if (audioChunk) {
|
|
7910
|
+
const trackId = parseInt(audioChunk[1], 10);
|
|
7911
|
+
const strh = getStrhForIndex(structure, trackId);
|
|
7912
|
+
const samplesPerSecond = strh.rate / strh.scale;
|
|
7913
|
+
const nthSample = options.parserState.getSamplesForTrack(trackId);
|
|
7914
|
+
const timeInSec = nthSample / samplesPerSecond;
|
|
7915
|
+
const timestamp = timeInSec * MEDIA_PARSER_RIFF_TIMESCALE;
|
|
7916
|
+
const duration2 = 1 / samplesPerSecond * MEDIA_PARSER_RIFF_TIMESCALE;
|
|
7917
|
+
await options.parserState.onAudioSample(trackId, {
|
|
7918
|
+
cts: timestamp,
|
|
7919
|
+
dts: timestamp,
|
|
7920
|
+
data: iterator.getSlice(ckSize),
|
|
7921
|
+
duration: duration2,
|
|
7922
|
+
timestamp,
|
|
7923
|
+
trackId,
|
|
7924
|
+
type: "key"
|
|
7925
|
+
});
|
|
7926
|
+
}
|
|
7355
7927
|
}
|
|
7356
|
-
|
|
7357
|
-
|
|
7358
|
-
|
|
7928
|
+
};
|
|
7929
|
+
var parseMovi = async ({
|
|
7930
|
+
iterator,
|
|
7931
|
+
maxOffset,
|
|
7932
|
+
options,
|
|
7933
|
+
structure
|
|
7934
|
+
}) => {
|
|
7935
|
+
while (iterator.counter.getOffset() < maxOffset) {
|
|
7936
|
+
if (iterator.bytesRemaining() < 8) {
|
|
7937
|
+
return {
|
|
7938
|
+
type: "incomplete",
|
|
7939
|
+
continueParsing: () => {
|
|
7940
|
+
return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
|
|
7941
|
+
}
|
|
7942
|
+
};
|
|
7943
|
+
}
|
|
7944
|
+
const ckId = iterator.getByteString(4);
|
|
7945
|
+
const ckSize = iterator.getUint32Le();
|
|
7946
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
7947
|
+
iterator.counter.decrement(8);
|
|
7948
|
+
return {
|
|
7949
|
+
type: "incomplete",
|
|
7950
|
+
continueParsing: () => {
|
|
7951
|
+
return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
|
|
7952
|
+
}
|
|
7953
|
+
};
|
|
7954
|
+
}
|
|
7955
|
+
await handleChunk({ iterator, options, structure, ckId, ckSize });
|
|
7956
|
+
while (iterator.counter.getOffset() < maxOffset && iterator.bytesRemaining() > 0) {
|
|
7957
|
+
if (iterator.getUint8() !== 0) {
|
|
7958
|
+
iterator.counter.decrement(1);
|
|
7959
|
+
break;
|
|
7960
|
+
}
|
|
7961
|
+
}
|
|
7962
|
+
}
|
|
7963
|
+
if (iterator.counter.getOffset() === maxOffset) {
|
|
7964
|
+
return {
|
|
7965
|
+
type: "complete",
|
|
7966
|
+
box: {
|
|
7967
|
+
type: "movi-box"
|
|
7968
|
+
}
|
|
7969
|
+
};
|
|
7970
|
+
}
|
|
7971
|
+
if (iterator.counter.getOffset() > maxOffset) {
|
|
7972
|
+
throw new Error("Oops, this should not happen!");
|
|
7973
|
+
}
|
|
7974
|
+
return {
|
|
7975
|
+
type: "incomplete",
|
|
7976
|
+
continueParsing: () => {
|
|
7977
|
+
return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
|
|
7978
|
+
}
|
|
7979
|
+
};
|
|
7980
|
+
};
|
|
7981
|
+
|
|
7982
|
+
// src/boxes/riff/parse-avih.ts
|
|
7983
|
+
var parseAvih = ({
|
|
7984
|
+
iterator,
|
|
7985
|
+
size
|
|
7986
|
+
}) => {
|
|
7987
|
+
const { expectNoMoreBytes } = iterator.startBox(size);
|
|
7988
|
+
const dwMicroSecPerFrame = iterator.getUint32Le();
|
|
7989
|
+
const dwMaxBytesPerSec = iterator.getUint32Le();
|
|
7990
|
+
const paddingGranularity = iterator.getUint32Le();
|
|
7991
|
+
const flags = iterator.getUint32Le();
|
|
7992
|
+
const totalFrames = iterator.getUint32Le();
|
|
7993
|
+
const initialFrames = iterator.getUint32Le();
|
|
7994
|
+
const streams = iterator.getUint32Le();
|
|
7995
|
+
const suggestedBufferSize = iterator.getUint32Le();
|
|
7996
|
+
const width = iterator.getUint32Le();
|
|
7997
|
+
const height = iterator.getUint32Le();
|
|
7998
|
+
iterator.discard(16);
|
|
7999
|
+
expectNoMoreBytes();
|
|
8000
|
+
return {
|
|
8001
|
+
type: "avih-box",
|
|
8002
|
+
microSecPerFrame: dwMicroSecPerFrame,
|
|
8003
|
+
maxBytesPerSecond: dwMaxBytesPerSec,
|
|
8004
|
+
paddingGranularity,
|
|
8005
|
+
flags,
|
|
8006
|
+
totalFrames,
|
|
8007
|
+
initialFrames,
|
|
8008
|
+
streams,
|
|
8009
|
+
suggestedBufferSize,
|
|
8010
|
+
height,
|
|
8011
|
+
width
|
|
8012
|
+
};
|
|
8013
|
+
};
|
|
8014
|
+
|
|
8015
|
+
// src/boxes/riff/parse-fmt-box.ts
|
|
8016
|
+
var parseFmtBox = ({
|
|
8017
|
+
iterator,
|
|
8018
|
+
boxes,
|
|
8019
|
+
size
|
|
8020
|
+
}) => {
|
|
8021
|
+
const box = iterator.startBox(size);
|
|
8022
|
+
const header = boxes.find((b) => b.type === "riff-header");
|
|
8023
|
+
if (!header) {
|
|
8024
|
+
throw new Error("Expected RIFF header");
|
|
8025
|
+
}
|
|
8026
|
+
if (header.fileType !== "WAVE") {
|
|
8027
|
+
throw new Error("Only supporting WAVE type");
|
|
8028
|
+
}
|
|
8029
|
+
const wFormatTag = iterator.getUint16Le();
|
|
8030
|
+
if (wFormatTag !== 1) {
|
|
8031
|
+
throw new Error("Expected wFormatTag to be 1, only supporting this");
|
|
8032
|
+
}
|
|
8033
|
+
const numberOfChannels = iterator.getUint16Le();
|
|
8034
|
+
const sampleRate = iterator.getUint32Le();
|
|
8035
|
+
const byteRate = iterator.getUint32Le();
|
|
8036
|
+
const blockAlign = iterator.getUint16Le();
|
|
8037
|
+
const bitsPerSample = iterator.getUint16Le();
|
|
8038
|
+
box.expectNoMoreBytes();
|
|
8039
|
+
return {
|
|
8040
|
+
type: "wave-format-box",
|
|
8041
|
+
formatTag: wFormatTag,
|
|
8042
|
+
numberOfChannels,
|
|
8043
|
+
sampleRate,
|
|
8044
|
+
blockAlign,
|
|
8045
|
+
byteRate,
|
|
8046
|
+
bitsPerSample
|
|
8047
|
+
};
|
|
8048
|
+
};
|
|
8049
|
+
|
|
8050
|
+
// src/boxes/riff/parse-list-box.ts
|
|
8051
|
+
var parseListBox = async ({
|
|
8052
|
+
iterator,
|
|
8053
|
+
size,
|
|
8054
|
+
options
|
|
8055
|
+
}) => {
|
|
8056
|
+
const counter = iterator.counter.getOffset();
|
|
8057
|
+
const listType = iterator.getByteString(4);
|
|
8058
|
+
if (listType === "movi") {
|
|
8059
|
+
throw new Error("should not be handled here");
|
|
8060
|
+
}
|
|
8061
|
+
const structure = {
|
|
8062
|
+
type: "riff",
|
|
8063
|
+
boxes: []
|
|
8064
|
+
};
|
|
8065
|
+
const result = await parseRiffBody({
|
|
8066
|
+
structure,
|
|
8067
|
+
iterator,
|
|
8068
|
+
maxOffset: counter + size,
|
|
8069
|
+
options
|
|
8070
|
+
});
|
|
8071
|
+
if (result.status === "incomplete") {
|
|
8072
|
+
throw new Error(`Should only parse complete boxes (${listType})`);
|
|
8073
|
+
}
|
|
8074
|
+
return {
|
|
8075
|
+
type: "list-box",
|
|
8076
|
+
listType,
|
|
8077
|
+
children: structure.boxes
|
|
8078
|
+
};
|
|
8079
|
+
};
|
|
8080
|
+
|
|
8081
|
+
// src/boxes/riff/parse-strf.ts
|
|
8082
|
+
var parseStrfAudio = ({
|
|
8083
|
+
iterator,
|
|
8084
|
+
size
|
|
8085
|
+
}) => {
|
|
8086
|
+
const box = iterator.startBox(size);
|
|
8087
|
+
const formatTag = iterator.getUint16Le();
|
|
8088
|
+
const numberOfChannels = iterator.getUint16Le();
|
|
8089
|
+
const samplesPerSec = iterator.getUint32Le();
|
|
8090
|
+
const avgBytesPerSec = iterator.getUint32Le();
|
|
8091
|
+
const blockAlign = iterator.getUint16Le();
|
|
8092
|
+
const bitsPerSample = iterator.getUint16Le();
|
|
8093
|
+
const cbSize = iterator.getUint16Le();
|
|
8094
|
+
box.expectNoMoreBytes();
|
|
8095
|
+
return {
|
|
8096
|
+
type: "strf-box-audio",
|
|
8097
|
+
avgBytesPerSecond: avgBytesPerSec,
|
|
8098
|
+
bitsPerSample,
|
|
8099
|
+
blockAlign,
|
|
8100
|
+
cbSize,
|
|
8101
|
+
formatTag,
|
|
8102
|
+
numberOfChannels,
|
|
8103
|
+
sampleRate: samplesPerSec
|
|
8104
|
+
};
|
|
8105
|
+
};
|
|
8106
|
+
var parseStrfVideo = ({
|
|
8107
|
+
iterator,
|
|
8108
|
+
size
|
|
8109
|
+
}) => {
|
|
8110
|
+
const box = iterator.startBox(size);
|
|
8111
|
+
const biSize = iterator.getUint32Le();
|
|
8112
|
+
const width = iterator.getInt32Le();
|
|
8113
|
+
const height = iterator.getInt32Le();
|
|
8114
|
+
const planes = iterator.getUint16Le();
|
|
8115
|
+
const bitCount = iterator.getUint16Le();
|
|
8116
|
+
const compression = iterator.getByteString(4);
|
|
8117
|
+
const sizeImage = iterator.getUint32Le();
|
|
8118
|
+
const xPelsPerMeter = iterator.getInt32Le();
|
|
8119
|
+
const yPelsPerMeter = iterator.getInt32Le();
|
|
8120
|
+
const clrUsed = iterator.getUint32Le();
|
|
8121
|
+
const clrImportant = iterator.getUint32Le();
|
|
8122
|
+
box.expectNoMoreBytes();
|
|
8123
|
+
return {
|
|
8124
|
+
type: "strf-box-video",
|
|
8125
|
+
biSize,
|
|
8126
|
+
bitCount,
|
|
8127
|
+
clrImportant,
|
|
8128
|
+
clrUsed,
|
|
8129
|
+
compression,
|
|
8130
|
+
height,
|
|
8131
|
+
planes,
|
|
8132
|
+
sizeImage,
|
|
8133
|
+
width,
|
|
8134
|
+
xPelsPerMeter,
|
|
8135
|
+
yPelsPerMeter
|
|
8136
|
+
};
|
|
8137
|
+
};
|
|
8138
|
+
var parseStrf = ({
|
|
8139
|
+
iterator,
|
|
8140
|
+
size,
|
|
8141
|
+
boxes
|
|
8142
|
+
}) => {
|
|
8143
|
+
const strh = boxes.find((b) => b.type === "strh-box");
|
|
8144
|
+
if (!strh) {
|
|
8145
|
+
throw new Error("strh box not found");
|
|
8146
|
+
}
|
|
8147
|
+
if (strh.fccType === "vids") {
|
|
8148
|
+
return parseStrfVideo({ iterator, size });
|
|
8149
|
+
}
|
|
8150
|
+
if (strh.fccType === "auds") {
|
|
8151
|
+
return parseStrfAudio({ iterator, size });
|
|
8152
|
+
}
|
|
8153
|
+
throw new Error(`Unsupported fccType: ${strh.fccType}`);
|
|
8154
|
+
};
|
|
8155
|
+
|
|
8156
|
+
// src/boxes/riff/parse-strh.ts
|
|
8157
|
+
var parseStrh = ({
|
|
8158
|
+
iterator,
|
|
8159
|
+
size
|
|
8160
|
+
}) => {
|
|
8161
|
+
const box = iterator.startBox(size);
|
|
8162
|
+
const fccType = iterator.getByteString(4);
|
|
8163
|
+
if (fccType !== "vids" && fccType !== "auds") {
|
|
8164
|
+
throw new Error("Expected AVI handler to be vids / auds");
|
|
8165
|
+
}
|
|
8166
|
+
const handler = fccType === "vids" ? iterator.getByteString(4) : iterator.getUint32Le();
|
|
8167
|
+
if (typeof handler === "string" && handler !== "H264") {
|
|
8168
|
+
throw new Error(`Only H264 is supported as a stream type in .avi, got ${handler}`);
|
|
8169
|
+
}
|
|
8170
|
+
if (fccType === "auds" && handler !== 1) {
|
|
8171
|
+
throw new Error(`Only "1" is supported as a stream type in .avi, got ${handler}`);
|
|
8172
|
+
}
|
|
8173
|
+
const flags = iterator.getUint32Le();
|
|
8174
|
+
const priority = iterator.getUint16Le();
|
|
8175
|
+
const language2 = iterator.getUint16Le();
|
|
8176
|
+
const initialFrames = iterator.getUint32Le();
|
|
8177
|
+
const scale = iterator.getUint32Le();
|
|
8178
|
+
const rate = iterator.getUint32Le();
|
|
8179
|
+
const start = iterator.getUint32Le();
|
|
8180
|
+
const length = iterator.getUint32Le();
|
|
8181
|
+
const suggestedBufferSize = iterator.getUint32Le();
|
|
8182
|
+
const quality = iterator.getUint32Le();
|
|
8183
|
+
const sampleSize = iterator.getUint32Le();
|
|
8184
|
+
box.discardRest();
|
|
8185
|
+
return {
|
|
8186
|
+
type: "strh-box",
|
|
8187
|
+
fccType,
|
|
8188
|
+
handler,
|
|
8189
|
+
flags,
|
|
8190
|
+
priority,
|
|
8191
|
+
initialFrames,
|
|
8192
|
+
length,
|
|
8193
|
+
quality,
|
|
8194
|
+
rate,
|
|
8195
|
+
sampleSize,
|
|
8196
|
+
scale,
|
|
8197
|
+
start,
|
|
8198
|
+
suggestedBufferSize,
|
|
8199
|
+
language: language2
|
|
8200
|
+
};
|
|
8201
|
+
};
|
|
8202
|
+
|
|
8203
|
+
// src/boxes/riff/parse-riff-box.ts
|
|
8204
|
+
var parseRiffBox = ({
|
|
8205
|
+
iterator,
|
|
8206
|
+
size,
|
|
8207
|
+
id,
|
|
8208
|
+
boxes,
|
|
8209
|
+
options
|
|
8210
|
+
}) => {
|
|
8211
|
+
if (id === "fmt") {
|
|
8212
|
+
return Promise.resolve(parseFmtBox({ iterator, boxes, size }));
|
|
8213
|
+
}
|
|
8214
|
+
if (id === "LIST") {
|
|
8215
|
+
return parseListBox({ iterator, size, options });
|
|
8216
|
+
}
|
|
8217
|
+
if (id === "avih") {
|
|
8218
|
+
return Promise.resolve(parseAvih({ iterator, size }));
|
|
8219
|
+
}
|
|
8220
|
+
if (id === "strh") {
|
|
8221
|
+
return Promise.resolve(parseStrh({ iterator, size }));
|
|
8222
|
+
}
|
|
8223
|
+
if (id === "strf") {
|
|
8224
|
+
return Promise.resolve(parseStrf({ iterator, size, boxes }));
|
|
8225
|
+
}
|
|
8226
|
+
iterator.discard(size);
|
|
8227
|
+
const box = {
|
|
8228
|
+
type: "riff-box",
|
|
8229
|
+
size,
|
|
8230
|
+
id
|
|
8231
|
+
};
|
|
8232
|
+
return Promise.resolve(box);
|
|
8233
|
+
};
|
|
8234
|
+
|
|
8235
|
+
// src/boxes/riff/expect-riff-box.ts
|
|
8236
|
+
var expectRiffBox = async ({
|
|
8237
|
+
iterator,
|
|
8238
|
+
options,
|
|
8239
|
+
structure
|
|
8240
|
+
}) => {
|
|
8241
|
+
if (iterator.bytesRemaining() < 16) {
|
|
8242
|
+
return {
|
|
8243
|
+
type: "incomplete",
|
|
8244
|
+
continueParsing() {
|
|
8245
|
+
return expectRiffBox({ structure, iterator, options });
|
|
8246
|
+
}
|
|
8247
|
+
};
|
|
8248
|
+
}
|
|
8249
|
+
const ckId = iterator.getByteString(4);
|
|
8250
|
+
const ckSize = iterator.getUint32Le();
|
|
8251
|
+
if (isMoviAtom(iterator, ckId)) {
|
|
8252
|
+
iterator.discard(4);
|
|
8253
|
+
return parseMovi({
|
|
8254
|
+
iterator,
|
|
8255
|
+
maxOffset: ckSize + iterator.counter.getOffset() - 4,
|
|
8256
|
+
options,
|
|
8257
|
+
structure
|
|
8258
|
+
});
|
|
8259
|
+
}
|
|
8260
|
+
if (iterator.bytesRemaining() < ckSize) {
|
|
8261
|
+
iterator.counter.decrement(8);
|
|
8262
|
+
return {
|
|
8263
|
+
type: "incomplete",
|
|
8264
|
+
continueParsing: () => {
|
|
8265
|
+
return expectRiffBox({ structure, iterator, options });
|
|
8266
|
+
}
|
|
8267
|
+
};
|
|
8268
|
+
}
|
|
8269
|
+
return {
|
|
8270
|
+
type: "complete",
|
|
8271
|
+
box: await parseRiffBox({
|
|
8272
|
+
id: ckId,
|
|
8273
|
+
iterator,
|
|
8274
|
+
size: ckSize,
|
|
8275
|
+
boxes: structure.boxes,
|
|
8276
|
+
options
|
|
8277
|
+
})
|
|
8278
|
+
};
|
|
8279
|
+
};
|
|
8280
|
+
|
|
8281
|
+
// src/boxes/riff/parse-box.ts
|
|
8282
|
+
var continueAfterRiffBoxResult = ({
|
|
8283
|
+
result,
|
|
8284
|
+
structure,
|
|
8285
|
+
iterator,
|
|
8286
|
+
maxOffset,
|
|
8287
|
+
options
|
|
8288
|
+
}) => {
|
|
8289
|
+
if (result.type === "incomplete") {
|
|
8290
|
+
return Promise.resolve({
|
|
8291
|
+
status: "incomplete",
|
|
8292
|
+
async continueParsing() {
|
|
8293
|
+
return Promise.resolve(continueAfterRiffBoxResult({
|
|
8294
|
+
result: await result.continueParsing(),
|
|
8295
|
+
structure,
|
|
8296
|
+
iterator,
|
|
8297
|
+
maxOffset,
|
|
8298
|
+
options
|
|
8299
|
+
}));
|
|
8300
|
+
},
|
|
8301
|
+
segments: structure,
|
|
8302
|
+
skipTo: null
|
|
8303
|
+
});
|
|
8304
|
+
}
|
|
8305
|
+
if (result.type === "complete") {
|
|
8306
|
+
if (result.box) {
|
|
8307
|
+
structure.boxes.push(result.box);
|
|
8308
|
+
}
|
|
8309
|
+
}
|
|
8310
|
+
return parseRiffBody({ iterator, maxOffset, options, structure });
|
|
8311
|
+
};
|
|
8312
|
+
var parseRiffBody = async ({
|
|
8313
|
+
iterator,
|
|
8314
|
+
structure,
|
|
8315
|
+
maxOffset,
|
|
8316
|
+
options
|
|
8317
|
+
}) => {
|
|
8318
|
+
while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() < maxOffset) {
|
|
8319
|
+
const result = await expectRiffBox({
|
|
8320
|
+
iterator,
|
|
8321
|
+
options,
|
|
8322
|
+
structure
|
|
8323
|
+
});
|
|
8324
|
+
if (result.type === "incomplete") {
|
|
8325
|
+
return {
|
|
8326
|
+
status: "incomplete",
|
|
8327
|
+
async continueParsing() {
|
|
8328
|
+
return Promise.resolve(continueAfterRiffBoxResult({
|
|
8329
|
+
iterator,
|
|
8330
|
+
maxOffset,
|
|
8331
|
+
options,
|
|
8332
|
+
result: await result.continueParsing(),
|
|
8333
|
+
structure
|
|
8334
|
+
}));
|
|
8335
|
+
},
|
|
8336
|
+
segments: structure,
|
|
8337
|
+
skipTo: null
|
|
8338
|
+
};
|
|
8339
|
+
}
|
|
8340
|
+
if (result.box === null) {
|
|
8341
|
+
continue;
|
|
8342
|
+
}
|
|
8343
|
+
structure.boxes.push(result.box);
|
|
8344
|
+
if (result.box.type === "strf-box-video" || result.box.type === "strf-box-audio") {
|
|
8345
|
+
const strh = getStrhBox(structure.boxes);
|
|
8346
|
+
const strf = getStrfBox(structure.boxes);
|
|
8347
|
+
if (!strh || !strf) {
|
|
8348
|
+
throw new Error("strh or strf box missing");
|
|
8349
|
+
}
|
|
8350
|
+
if (strf.type === "strf-box-audio" && options.onAudioTrack) {
|
|
8351
|
+
const audioTrack = makeAviAudioTrack({
|
|
8352
|
+
index: options.nextTrackIndex,
|
|
8353
|
+
strf
|
|
8354
|
+
});
|
|
8355
|
+
await registerTrack({
|
|
8356
|
+
options,
|
|
8357
|
+
state: options.parserState,
|
|
8358
|
+
track: audioTrack
|
|
8359
|
+
});
|
|
8360
|
+
}
|
|
8361
|
+
if (options.onVideoTrack && strf.type === "strf-box-video") {
|
|
8362
|
+
const videoTrack = makeAviVideoTrack({
|
|
8363
|
+
strh,
|
|
8364
|
+
index: options.nextTrackIndex,
|
|
8365
|
+
strf
|
|
8366
|
+
});
|
|
8367
|
+
registerVideoTrackWhenProfileIsAvailable({
|
|
8368
|
+
options,
|
|
8369
|
+
state: options.parserState,
|
|
8370
|
+
track: videoTrack
|
|
8371
|
+
});
|
|
8372
|
+
}
|
|
8373
|
+
options.nextTrackIndex++;
|
|
8374
|
+
}
|
|
8375
|
+
}
|
|
8376
|
+
return {
|
|
8377
|
+
status: "done",
|
|
8378
|
+
segments: structure
|
|
8379
|
+
};
|
|
8380
|
+
};
|
|
8381
|
+
var parseRiff = ({
|
|
8382
|
+
iterator,
|
|
8383
|
+
options
|
|
8384
|
+
}) => {
|
|
8385
|
+
const structure = { type: "riff", boxes: [] };
|
|
8386
|
+
const riff = iterator.getByteString(4);
|
|
8387
|
+
if (riff !== "RIFF") {
|
|
8388
|
+
throw new Error("Not a RIFF file");
|
|
7359
8389
|
}
|
|
8390
|
+
const size = iterator.getUint32Le();
|
|
8391
|
+
const fileType = iterator.getByteString(4);
|
|
8392
|
+
if (fileType !== "WAVE" && fileType !== "AVI") {
|
|
8393
|
+
throw new Error(`File type ${fileType} not supported`);
|
|
8394
|
+
}
|
|
8395
|
+
structure.boxes.push({ type: "riff-header", fileSize: size, fileType });
|
|
8396
|
+
return parseRiffBody({ iterator, structure, maxOffset: Infinity, options });
|
|
7360
8397
|
};
|
|
7361
8398
|
|
|
7362
8399
|
// src/boxes/webm/segments/block-simple-block-flags.ts
|
|
@@ -7904,33 +8941,33 @@ var expectChildren = async ({
|
|
|
7904
8941
|
};
|
|
7905
8942
|
|
|
7906
8943
|
// src/boxes/webm/parse-webm-header.ts
|
|
7907
|
-
var continueAfterMatroskaResult = (result,
|
|
8944
|
+
var continueAfterMatroskaResult = (result, structure) => {
|
|
7908
8945
|
if (result.status === "done") {
|
|
7909
8946
|
return {
|
|
7910
8947
|
status: "done",
|
|
7911
|
-
segments:
|
|
8948
|
+
segments: structure
|
|
7912
8949
|
};
|
|
7913
8950
|
}
|
|
7914
8951
|
return {
|
|
7915
8952
|
status: "incomplete",
|
|
7916
|
-
segments:
|
|
8953
|
+
segments: structure,
|
|
7917
8954
|
continueParsing: async () => {
|
|
7918
8955
|
const newResult = await result.continueParsing();
|
|
7919
|
-
return continueAfterMatroskaResult(newResult,
|
|
8956
|
+
return continueAfterMatroskaResult(newResult, structure);
|
|
7920
8957
|
},
|
|
7921
8958
|
skipTo: null
|
|
7922
8959
|
};
|
|
7923
8960
|
};
|
|
7924
8961
|
var parseWebm = async (counter, parserContext) => {
|
|
7925
|
-
const
|
|
8962
|
+
const structure = { type: "matroska", boxes: [] };
|
|
7926
8963
|
const results = await expectChildren({
|
|
7927
8964
|
iterator: counter,
|
|
7928
8965
|
length: Infinity,
|
|
7929
|
-
children,
|
|
8966
|
+
children: structure.boxes,
|
|
7930
8967
|
parserContext,
|
|
7931
8968
|
startOffset: counter.counter.getOffset()
|
|
7932
8969
|
});
|
|
7933
|
-
return continueAfterMatroskaResult(results,
|
|
8970
|
+
return continueAfterMatroskaResult(results, structure);
|
|
7934
8971
|
};
|
|
7935
8972
|
|
|
7936
8973
|
// src/parse-video.ts
|
|
@@ -7941,26 +8978,14 @@ var parseVideo = ({
|
|
|
7941
8978
|
logLevel
|
|
7942
8979
|
}) => {
|
|
7943
8980
|
if (iterator.bytesRemaining() === 0) {
|
|
7944
|
-
return Promise.
|
|
7945
|
-
status: "incomplete",
|
|
7946
|
-
segments: [],
|
|
7947
|
-
continueParsing: () => {
|
|
7948
|
-
return parseVideo({
|
|
7949
|
-
iterator,
|
|
7950
|
-
options,
|
|
7951
|
-
signal,
|
|
7952
|
-
logLevel
|
|
7953
|
-
});
|
|
7954
|
-
},
|
|
7955
|
-
skipTo: null
|
|
7956
|
-
});
|
|
8981
|
+
return Promise.reject(new Error("no bytes"));
|
|
7957
8982
|
}
|
|
7958
8983
|
if (iterator.isRiff()) {
|
|
7959
|
-
|
|
8984
|
+
return Promise.resolve(parseRiff({ iterator, options }));
|
|
7960
8985
|
}
|
|
7961
8986
|
if (iterator.isIsoBaseMedia()) {
|
|
7962
8987
|
Log.verbose(logLevel, "Detected ISO Base Media container");
|
|
7963
|
-
return
|
|
8988
|
+
return parseIsoBaseMediaBoxes({
|
|
7964
8989
|
iterator,
|
|
7965
8990
|
maxBytes: Infinity,
|
|
7966
8991
|
allowIncompleteBoxes: true,
|
|
@@ -7973,7 +8998,7 @@ var parseVideo = ({
|
|
|
7973
8998
|
}
|
|
7974
8999
|
if (iterator.isWebm()) {
|
|
7975
9000
|
Log.verbose(logLevel, "Detected Matroska container");
|
|
7976
|
-
return
|
|
9001
|
+
return parseWebm(iterator, options);
|
|
7977
9002
|
}
|
|
7978
9003
|
if (iterator.isMp3()) {
|
|
7979
9004
|
return Promise.reject(new Error("MP3 files are not yet supported"));
|
|
@@ -8038,8 +9063,23 @@ var makeParserState = ({
|
|
|
8038
9063
|
}
|
|
8039
9064
|
return timestampMap.get(byteOffset);
|
|
8040
9065
|
};
|
|
9066
|
+
const samplesForTrack = {};
|
|
9067
|
+
const profileCallbacks = [];
|
|
9068
|
+
const registerOnAvcProfileCallback = (callback) => {
|
|
9069
|
+
profileCallbacks.push(callback);
|
|
9070
|
+
};
|
|
9071
|
+
let avcProfile = null;
|
|
9072
|
+
const onProfile = async (profile) => {
|
|
9073
|
+
avcProfile = profile;
|
|
9074
|
+
for (const callback of profileCallbacks) {
|
|
9075
|
+
await callback(profile);
|
|
9076
|
+
}
|
|
9077
|
+
profileCallbacks.length = 0;
|
|
9078
|
+
};
|
|
8041
9079
|
return {
|
|
8042
9080
|
onTrackEntrySegment,
|
|
9081
|
+
onProfile,
|
|
9082
|
+
registerOnAvcProfileCallback,
|
|
8043
9083
|
getTrackInfoByNumber: (id) => trackEntries[id],
|
|
8044
9084
|
registerVideoSampleCallback: async (id, callback) => {
|
|
8045
9085
|
if (callback === null) {
|
|
@@ -8071,6 +9111,10 @@ var makeParserState = ({
|
|
|
8071
9111
|
if (signal?.aborted) {
|
|
8072
9112
|
throw new Error("Aborted");
|
|
8073
9113
|
}
|
|
9114
|
+
if (typeof samplesForTrack[trackId] === "undefined") {
|
|
9115
|
+
samplesForTrack[trackId] = 0;
|
|
9116
|
+
}
|
|
9117
|
+
samplesForTrack[trackId]++;
|
|
8074
9118
|
const callback = audioSampleCallbacks[trackId];
|
|
8075
9119
|
if (callback) {
|
|
8076
9120
|
await callback(audioSample);
|
|
@@ -8087,6 +9131,10 @@ var makeParserState = ({
|
|
|
8087
9131
|
if (signal?.aborted) {
|
|
8088
9132
|
throw new Error("Aborted");
|
|
8089
9133
|
}
|
|
9134
|
+
if (typeof samplesForTrack[trackId] === "undefined") {
|
|
9135
|
+
samplesForTrack[trackId] = 0;
|
|
9136
|
+
}
|
|
9137
|
+
samplesForTrack[trackId]++;
|
|
8090
9138
|
const callback = videoSampleCallbacks[trackId];
|
|
8091
9139
|
if (callback) {
|
|
8092
9140
|
await callback(videoSample);
|
|
@@ -8101,7 +9149,13 @@ var makeParserState = ({
|
|
|
8101
9149
|
},
|
|
8102
9150
|
getInternalStats: () => ({}),
|
|
8103
9151
|
getTimescale,
|
|
8104
|
-
setTimescale
|
|
9152
|
+
setTimescale,
|
|
9153
|
+
getSamplesForTrack: (trackId) => {
|
|
9154
|
+
return samplesForTrack[trackId] ?? 0;
|
|
9155
|
+
},
|
|
9156
|
+
getAvcProfile: () => {
|
|
9157
|
+
return avcProfile;
|
|
9158
|
+
}
|
|
8105
9159
|
};
|
|
8106
9160
|
};
|
|
8107
9161
|
|
|
@@ -8146,7 +9200,8 @@ var parseMedia = async ({
|
|
|
8146
9200
|
onVideoTrack: onVideoTrack ?? null,
|
|
8147
9201
|
parserState: state,
|
|
8148
9202
|
nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true"),
|
|
8149
|
-
supportsContentRange
|
|
9203
|
+
supportsContentRange,
|
|
9204
|
+
nextTrackIndex: 0
|
|
8150
9205
|
};
|
|
8151
9206
|
const hasAllInfo = () => {
|
|
8152
9207
|
if (parseResult === null) {
|
|
@@ -8242,12 +9297,13 @@ var parseMedia = async ({
|
|
|
8242
9297
|
return returnValue;
|
|
8243
9298
|
};
|
|
8244
9299
|
// src/version.ts
|
|
8245
|
-
var VERSION = "4.0.
|
|
9300
|
+
var VERSION = "4.0.232";
|
|
8246
9301
|
|
|
8247
9302
|
// src/index.ts
|
|
8248
9303
|
var MediaParserInternals = {
|
|
8249
9304
|
createMatroskaMedia,
|
|
8250
9305
|
createIsoBaseMedia,
|
|
9306
|
+
createWav,
|
|
8251
9307
|
Log
|
|
8252
9308
|
};
|
|
8253
9309
|
export {
|