@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.
Files changed (95) hide show
  1. package/dist/add-avc-profile-to-track.d.ts +3 -0
  2. package/dist/add-avc-profile-to-track.js +35 -0
  3. package/dist/add-new-matroska-tracks.d.ts +6 -1
  4. package/dist/add-new-matroska-tracks.js +16 -1
  5. package/dist/boxes/avc/parse-avc.d.ts +18 -0
  6. package/dist/boxes/avc/parse-avc.js +96 -0
  7. package/dist/boxes/iso-base-media/make-track.js +3 -3
  8. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +2 -2
  9. package/dist/boxes/iso-base-media/mdat/mdat.js +5 -2
  10. package/dist/boxes/iso-base-media/moov/moov.js +2 -2
  11. package/dist/boxes/iso-base-media/process-box.d.ts +5 -5
  12. package/dist/boxes/iso-base-media/process-box.js +38 -37
  13. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -2
  14. package/dist/boxes/iso-base-media/stsd/samples.d.ts +2 -2
  15. package/dist/boxes/iso-base-media/stsd/samples.js +9 -9
  16. package/dist/boxes/iso-base-media/trak/trak.js +2 -2
  17. package/dist/boxes/iso-base-media/traversal.d.ts +1 -1
  18. package/dist/boxes/riff/expect-riff-box.d.ts +16 -0
  19. package/dist/boxes/riff/expect-riff-box.js +49 -0
  20. package/dist/boxes/riff/get-tracks-from-avi.d.ts +21 -0
  21. package/dist/boxes/riff/get-tracks-from-avi.js +108 -0
  22. package/dist/boxes/riff/is-movi.d.ts +2 -0
  23. package/dist/boxes/riff/is-movi.js +12 -0
  24. package/dist/boxes/riff/parse-avih.d.ts +6 -0
  25. package/dist/boxes/riff/parse-avih.js +32 -0
  26. package/dist/boxes/riff/parse-box.d.ts +13 -0
  27. package/dist/boxes/riff/parse-box.js +113 -0
  28. package/dist/boxes/riff/parse-fmt-box.d.ts +7 -0
  29. package/dist/boxes/riff/parse-fmt-box.js +33 -0
  30. package/dist/boxes/riff/parse-list-box.d.ts +8 -0
  31. package/dist/boxes/riff/parse-list-box.js +30 -0
  32. package/dist/boxes/riff/parse-movi.d.ts +17 -0
  33. package/dist/boxes/riff/parse-movi.js +122 -0
  34. package/dist/boxes/riff/parse-riff-box.d.ts +10 -0
  35. package/dist/boxes/riff/parse-riff-box.js +33 -0
  36. package/dist/boxes/riff/parse-strf.d.ts +7 -0
  37. package/dist/boxes/riff/parse-strf.js +67 -0
  38. package/dist/boxes/riff/parse-strh.d.ts +6 -0
  39. package/dist/boxes/riff/parse-strh.js +46 -0
  40. package/dist/boxes/riff/riff-box.d.ts +81 -0
  41. package/dist/boxes/riff/riff-box.js +2 -0
  42. package/dist/boxes/riff/strf.d.ts +7 -0
  43. package/dist/boxes/riff/strf.js +67 -0
  44. package/dist/boxes/riff/timescale.d.ts +1 -0
  45. package/dist/boxes/riff/timescale.js +4 -0
  46. package/dist/boxes/riff/traversal.d.ts +8 -0
  47. package/dist/boxes/riff/traversal.js +36 -0
  48. package/dist/boxes/webm/parse-ebml.js +2 -2
  49. package/dist/boxes/webm/parse-webm-header.d.ts +2 -2
  50. package/dist/boxes/webm/parse-webm-header.js +7 -7
  51. package/dist/boxes/webm/traversal.d.ts +2 -2
  52. package/dist/buffer-iterator.d.ts +6 -1
  53. package/dist/buffer-iterator.js +24 -5
  54. package/dist/create/iso-base-media/create-iso-base-media.js +0 -4
  55. package/dist/create/matroska/create-matroska-media.js +0 -4
  56. package/dist/create/media-fn.d.ts +0 -1
  57. package/dist/create/mp3/create-mp3.d.ts +2 -0
  58. package/dist/create/mp3/create-mp3.js +49 -0
  59. package/dist/create/wav/create-wav.d.ts +2 -0
  60. package/dist/create/wav/create-wav.js +108 -0
  61. package/dist/emit-available-info.d.ts +2 -2
  62. package/dist/emit-available-info.js +6 -4
  63. package/dist/esm/from-node.mjs +2 -1
  64. package/dist/esm/index.mjs +1487 -431
  65. package/dist/get-audio-codec.d.ts +3 -3
  66. package/dist/get-audio-codec.js +2 -2
  67. package/dist/get-container.d.ts +3 -3
  68. package/dist/get-container.js +9 -7
  69. package/dist/get-dimensions.d.ts +3 -3
  70. package/dist/get-duration.d.ts +3 -3
  71. package/dist/get-duration.js +32 -14
  72. package/dist/get-fps.d.ts +3 -3
  73. package/dist/get-fps.js +31 -4
  74. package/dist/get-tracks.d.ts +4 -7
  75. package/dist/get-tracks.js +55 -27
  76. package/dist/get-video-codec.d.ts +5 -4
  77. package/dist/get-video-codec.js +38 -10
  78. package/dist/has-all-info.d.ts +2 -2
  79. package/dist/has-all-info.js +4 -4
  80. package/dist/index.d.ts +1 -0
  81. package/dist/index.js +2 -0
  82. package/dist/options.d.ts +9 -9
  83. package/dist/parse-media.js +2 -0
  84. package/dist/parse-result.d.ts +20 -6
  85. package/dist/parse-video.d.ts +2 -2
  86. package/dist/parse-video.js +5 -16
  87. package/dist/parser-context.d.ts +1 -0
  88. package/dist/parser-state.d.ts +11 -0
  89. package/dist/parser-state.js +30 -0
  90. package/dist/readers/from-node.js +2 -1
  91. package/dist/register-track.d.ts +13 -0
  92. package/dist/register-track.js +25 -0
  93. package/dist/version.d.ts +1 -1
  94. package/dist/version.js +1 -1
  95. package/package.json +3 -3
@@ -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/get-sample-positions.ts
3293
- var getSamplePositions = ({
3294
- stcoBox,
3295
- stszBox,
3296
- stscBox,
3297
- stssBox,
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
- cttsBox
3428
+ timeScale,
3429
+ durationInSamples
3300
3430
  }) => {
3301
- const sttsDeltas = [];
3302
- for (const distribution of sttsBox.sampleDistribution) {
3303
- for (let i = 0;i < distribution.sampleCount; i++) {
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 cttsEntries = [];
3308
- for (const entry of cttsBox?.entries ?? [
3309
- { sampleCount: sttsDeltas.length, sampleOffset: 0 }
3310
- ]) {
3311
- for (let i = 0;i < entry.sampleCount; i++) {
3312
- cttsEntries.push(entry.sampleOffset);
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
- let dts = 0;
3316
- const chunks = stcoBox.entries;
3317
- const samples = [];
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 samples;
3448
+ return true;
3345
3449
  };
3346
-
3347
- // src/samples-from-moof.ts
3348
- var getSamplesFromTraf = (trafSegment, moofOffset) => {
3349
- if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
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 tfhdBox = getTfhdBox(trafSegment);
3353
- const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
3354
- const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
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 samples;
3459
+ return true;
3400
3460
  };
3401
- var getSamplesFromMoof = ({
3402
- moofBox,
3403
- trackId
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
- const trafs = moofBox.children.filter((c) => c.type === "regular-box" && c.boxType === "traf");
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 (!tkhdBox) {
3427
- throw new Error("Expected tkhd box in trak box");
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
- throw new Error("Expected stts box in trak box");
3440
- }
3441
- if (!timescaleAndDuration) {
3442
- throw new Error("Expected timescale and duration in trak box");
3475
+ return null;
3443
3476
  }
3444
- let samplePositions = getSamplePositions({
3445
- stcoBox,
3446
- stscBox,
3447
- stszBox,
3448
- stssBox,
3477
+ return calculateFps({
3449
3478
  sttsBox,
3450
- cttsBox
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
- // src/get-duration.ts
3459
- var getDurationFromMatroska = (segments) => {
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 { value: children } = mainSegment;
3465
- if (!children) {
3466
- return null;
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
- if (mvhdBox.type !== "mvhd-box") {
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 getTimescaleAndDuration = (trakBox) => {
3567
- const mdhdBox = getMdhdBox(trakBox);
3568
- if (mdhdBox) {
3569
- return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
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
- const moovBox = getMoovBox(segments);
3590
- if (!moovBox) {
3591
- return null;
3510
+ if (segments.type === "iso-base-media") {
3511
+ return getFpsFromIsoMaseMedia(segments);
3592
3512
  }
3593
- const trackBoxes = getTraks(moovBox);
3594
- const trackBox = trackBoxes.find(trakBoxContainsVideo);
3595
- if (!trackBox) {
3513
+ if (segments.type === "riff") {
3514
+ return getFpsFromAvi(segments);
3515
+ }
3516
+ if (segments.type === "matroska") {
3596
3517
  return null;
3597
3518
  }
3598
- return getFpsFromMp4TrakBox(trackBox);
3519
+ throw new Error("Cannot get fps, not implemented");
3599
3520
  };
3600
3521
  var hasFps = (boxes) => {
3601
3522
  try {
3602
- if (isMatroska(boxes)) {
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 = (littleEndian = false) => {
4036
- const val = view.getUint32(counter.getDiscardedOffset(), littleEndian);
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: (length) => {
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 getVideoCodec = (boxes) => {
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 getNumberOfTracks = (moovBox) => {
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 = (segments) => {
5020
- const mainSegment = getMainSegment(segments);
5021
- if (mainSegment) {
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
- const moovBox = getMoovBox(segments);
5025
- if (!moovBox) {
5026
- return false;
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
- const numberOfTracks = getNumberOfTracks(moovBox);
5029
- const tracks2 = getTraks(moovBox);
5030
- return tracks2.length === numberOfTracks;
5132
+ if (structure.type === "riff") {
5133
+ return hasAllTracksFromAvi(structure, state);
5134
+ }
5135
+ throw new Error("Unknown container");
5031
5136
  };
5032
- var getTracks = (segments, state) => {
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 && mainSegment.type === "Segment") {
5038
- const matroskaTracks = getTracksFromMatroska(mainSegment, state.getTimescale());
5039
- for (const track of matroskaTracks) {
5040
- if (track.type === "video") {
5041
- videoTracks.push(track);
5042
- } else if (track.type === "audio") {
5043
- audioTracks.push(track);
5044
- } else if (track.type === "other") {
5045
- otherTracks.push(track);
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
- const moovBox = getMoovBox(segments);
5086
- if (moovBox) {
5208
+ if (segments.type === "iso-base-media") {
5087
5209
  return "mp4";
5088
5210
  }
5089
- const mainSegment = getMainSegment(segments);
5090
- if (mainSegment) {
5211
+ if (segments.type === "matroska") {
5091
5212
  return "webm";
5092
5213
  }
5093
- return null;
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 === "boxes") {
5139
- if (parseResult && hasInfo.boxes && returnValue.boxes === undefined) {
5140
- moreFields.onBoxes?.(parseResult.segments);
5141
- returnValue.boxes = parseResult.segments;
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 === "boxes") {
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(existingBoxes);
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 parseBoxes({
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 parseBoxes({
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 parseBoxes({
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 parseBoxes({
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 parseBoxes({
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 parseBoxes({
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 parseBoxes({
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 parseBoxes({
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
- if (transformedTrack.type === "audio") {
7044
- const callback = await options.onAudioTrack?.(transformedTrack);
7045
- await options.parserState.registerAudioSampleCallback(transformedTrack.trackId, callback ?? null);
7046
- }
7047
- if (transformedTrack.type === "video") {
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 parseBoxes = async ({
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
- let boxes = initialBoxes;
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: boxes,
7636
+ segments: structure,
7227
7637
  continueParsing: () => {
7228
- return parseBoxes({
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: boxes,
7655
+ segments: structure,
7246
7656
  continueParsing: () => {
7247
- return Promise.resolve(parseBoxes({
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: boxes,
7688
+ segments: structure,
7279
7689
  continueParsing: () => {
7280
- return parseBoxes({
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: boxes,
7707
+ segments: structure,
7298
7708
  continueParsing: () => {
7299
- return parseBoxes({
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: boxes,
7731
+ segments: structure,
7322
7732
  continueParsing: () => {
7323
7733
  if (buffered) {
7324
7734
  iterator.skipTo(mdatState.fileOffset, false);
7325
7735
  }
7326
- return parseBoxes({
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: boxes
7752
+ segments: structure
7343
7753
  };
7344
7754
  };
7345
7755
 
7346
- // src/add-new-matroska-tracks.ts
7347
- var registerTrack = async ({
7348
- state,
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
- track
7874
+ structure,
7875
+ ckId,
7876
+ ckSize
7351
7877
  }) => {
7352
- if (track.type === "video" && options.onVideoTrack) {
7353
- const callback = await options.onVideoTrack(track);
7354
- await state.registerVideoSampleCallback(track.trackId, callback ?? null);
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
- if (track.type === "audio" && options.onAudioTrack) {
7357
- const callback = await options.onAudioTrack(track);
7358
- await state.registerAudioSampleCallback(track.trackId, callback ?? null);
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, children) => {
8944
+ var continueAfterMatroskaResult = (result, structure) => {
7908
8945
  if (result.status === "done") {
7909
8946
  return {
7910
8947
  status: "done",
7911
- segments: children
8948
+ segments: structure
7912
8949
  };
7913
8950
  }
7914
8951
  return {
7915
8952
  status: "incomplete",
7916
- segments: children,
8953
+ segments: structure,
7917
8954
  continueParsing: async () => {
7918
8955
  const newResult = await result.continueParsing();
7919
- return continueAfterMatroskaResult(newResult, children);
8956
+ return continueAfterMatroskaResult(newResult, structure);
7920
8957
  },
7921
8958
  skipTo: null
7922
8959
  };
7923
8960
  };
7924
8961
  var parseWebm = async (counter, parserContext) => {
7925
- const children = [];
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, children);
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.resolve({
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
- throw new Error("AVI files are not yet supported");
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 parseBoxes({
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 Promise.resolve(parseWebm(iterator, options));
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.231";
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 {