@remotion/media-parser 4.0.230 → 4.0.231

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 (41) hide show
  1. package/dist/boxes/webm/parse-webm-header.js +23 -4
  2. package/dist/boxes/webm/segments/parse-children.d.ts +12 -7
  3. package/dist/boxes/webm/segments/parse-children.js +67 -57
  4. package/dist/boxes/webm/segments.d.ts +8 -3
  5. package/dist/boxes/webm/segments.js +70 -39
  6. package/dist/create/iso-base-media/create-iso-base-media.d.ts +1 -1
  7. package/dist/create/iso-base-media/create-iso-base-media.js +4 -5
  8. package/dist/create/matroska/cluster.d.ts +7 -1
  9. package/dist/create/matroska/cluster.js +8 -5
  10. package/dist/create/matroska/create-matroska-media.d.ts +1 -1
  11. package/dist/create/matroska/create-matroska-media.js +27 -10
  12. package/dist/create/media-fn.d.ts +1 -0
  13. package/dist/emit-available-info.d.ts +1 -1
  14. package/dist/emit-available-info.js +23 -10
  15. package/dist/esm/buffer.mjs +2 -2
  16. package/dist/esm/index.mjs +591 -465
  17. package/dist/esm/web-fs.mjs +2 -2
  18. package/dist/get-audio-codec.d.ts +1 -1
  19. package/dist/get-audio-codec.js +2 -7
  20. package/dist/get-duration.d.ts +5 -0
  21. package/dist/get-duration.js +7 -3
  22. package/dist/get-fps.js +7 -0
  23. package/dist/get-video-codec.d.ts +2 -2
  24. package/dist/get-video-codec.js +2 -6
  25. package/dist/has-all-info.d.ts +1 -1
  26. package/dist/has-all-info.js +8 -8
  27. package/dist/index.d.ts +4 -3
  28. package/dist/index.js +3 -1
  29. package/dist/options.d.ts +8 -1
  30. package/dist/parse-media.js +41 -14
  31. package/dist/parse-result.d.ts +15 -0
  32. package/dist/parse-video.d.ts +1 -1
  33. package/dist/parse-video.js +3 -0
  34. package/dist/readers/reader.d.ts +2 -2
  35. package/dist/version.d.ts +1 -0
  36. package/dist/version.js +5 -0
  37. package/dist/writers/buffer-implementation/writer.d.ts +2 -2
  38. package/dist/writers/buffer-implementation/writer.js +2 -2
  39. package/dist/writers/web-fs.js +2 -3
  40. package/dist/writers/writer.d.ts +5 -3
  41. package/package.json +3 -3
@@ -1965,14 +1965,15 @@ var createIsoBaseMedia = async ({
1965
1965
  writer,
1966
1966
  onBytesProgress,
1967
1967
  onMillisecondsProgress,
1968
- logLevel
1968
+ logLevel,
1969
+ filename
1969
1970
  }) => {
1970
1971
  const header = createIsoBaseMediaFtyp({
1971
1972
  compatibleBrands: ["isom", "iso2", "avc1", "mp42"],
1972
1973
  majorBrand: "isom",
1973
1974
  minorBrand: 512
1974
1975
  });
1975
- const w = await writer.createContent();
1976
+ const w = await writer.createContent({ filename, mimeType: "video/mp4" });
1976
1977
  await w.write(header);
1977
1978
  let durationInUnits = 0;
1978
1979
  const currentTracks = [];
@@ -2072,9 +2073,8 @@ var createIsoBaseMedia = async ({
2072
2073
  };
2073
2074
  const waitForFinishPromises = [];
2074
2075
  return {
2075
- save: async () => {
2076
- const file = await w.save();
2077
- return file;
2076
+ save: () => {
2077
+ return w.save();
2078
2078
  },
2079
2079
  remove: async () => {
2080
2080
  await w.remove();
@@ -2182,11 +2182,17 @@ var canFitInCluster = ({
2182
2182
  }
2183
2183
  return timecodeRelativeToCluster <= maxClusterTimestamp;
2184
2184
  };
2185
- var makeCluster = async (w, clusterStartTimestamp, timescale) => {
2185
+ var makeCluster = async ({
2186
+ writer,
2187
+ clusterStartTimestamp,
2188
+ timescale,
2189
+ logLevel
2190
+ }) => {
2191
+ Log.verbose(logLevel, `Making new Matroska cluster with timestamp ${clusterStartTimestamp}`);
2186
2192
  const cluster = createClusterSegment(timestampToClusterTimestamp(clusterStartTimestamp, timescale));
2187
- const clusterVIntPosition = w.getWrittenByteCount() + cluster.offsets.offset + matroskaToHex(matroskaElements.Cluster).byteLength;
2193
+ const clusterVIntPosition = writer.getWrittenByteCount() + cluster.offsets.offset + matroskaToHex(matroskaElements.Cluster).byteLength;
2188
2194
  let clusterSize = cluster.bytes.byteLength - matroskaToHex(matroskaElements.Cluster).byteLength - CLUSTER_MIN_VINT_WIDTH;
2189
- await w.write(cluster.bytes);
2195
+ await writer.write(cluster.bytes);
2190
2196
  const addSample = async (chunk, trackNumber2) => {
2191
2197
  const timecodeRelativeToCluster = timestampToClusterTimestamp(chunk.timestamp, timescale) - timestampToClusterTimestamp(clusterStartTimestamp, timescale);
2192
2198
  if (!canFitInCluster({ clusterStartTimestamp, chunk, timescale })) {
@@ -2202,8 +2208,8 @@ var makeCluster = async (w, clusterStartTimestamp, timescale) => {
2202
2208
  timecodeRelativeToCluster
2203
2209
  });
2204
2210
  clusterSize += simpleBlock2.byteLength;
2205
- await w.updateDataAt(clusterVIntPosition, getVariableInt(clusterSize, CLUSTER_MIN_VINT_WIDTH));
2206
- await w.write(simpleBlock2);
2211
+ await writer.updateDataAt(clusterVIntPosition, getVariableInt(clusterSize, CLUSTER_MIN_VINT_WIDTH));
2212
+ await writer.write(simpleBlock2);
2207
2213
  return { timecodeRelativeToCluster };
2208
2214
  };
2209
2215
  const shouldMakeNewCluster = ({
@@ -2219,6 +2225,7 @@ var makeCluster = async (w, clusterStartTimestamp, timescale) => {
2219
2225
  timescale
2220
2226
  });
2221
2227
  if (!canFit) {
2228
+ Log.verbose(logLevel, `Cannot fit ${chunk.timestamp} in cluster ${clusterStartTimestamp}. Creating new cluster`);
2222
2229
  return true;
2223
2230
  }
2224
2231
  const keyframe = chunk.type === "key";
@@ -2938,10 +2945,12 @@ var timescale = 1e6;
2938
2945
  var createMatroskaMedia = async ({
2939
2946
  writer,
2940
2947
  onBytesProgress,
2941
- onMillisecondsProgress
2948
+ onMillisecondsProgress,
2949
+ filename,
2950
+ logLevel
2942
2951
  }) => {
2943
2952
  const header = makeMatroskaHeader();
2944
- const w = await writer.createContent();
2953
+ const w = await writer.createContent({ filename, mimeType: "video/webm" });
2945
2954
  await w.write(header.bytes);
2946
2955
  const matroskaInfo = makeMatroskaInfo({
2947
2956
  timescale
@@ -2993,7 +3002,12 @@ var createMatroskaMedia = async ({
2993
3002
  };
2994
3003
  await w.write(matroskaSegment.bytes);
2995
3004
  const clusterOffset = w.getWrittenByteCount();
2996
- let currentCluster = await makeCluster(w, 0, timescale);
3005
+ let currentCluster = await makeCluster({
3006
+ writer: w,
3007
+ clusterStartTimestamp: 0,
3008
+ timescale,
3009
+ logLevel
3010
+ });
2997
3011
  seeks.push({
2998
3012
  hexString: matroskaElements.Cluster,
2999
3013
  byte: clusterOffset - seekHeadOffset
@@ -3001,9 +3015,14 @@ var createMatroskaMedia = async ({
3001
3015
  const trackNumberProgresses = {};
3002
3016
  const getClusterOrMakeNew = async ({
3003
3017
  chunk,
3004
- isVideo
3018
+ isVideo,
3019
+ trackNumber: trackNumber2
3005
3020
  }) => {
3006
- const smallestProgress = Math.min(...Object.values(trackNumberProgresses));
3021
+ const trackProgressValues = Object.values(trackNumberProgresses);
3022
+ const smallestProgress = trackProgressValues.length === 0 ? 0 : Math.min(...trackProgressValues);
3023
+ if (chunk.type === "key") {
3024
+ trackNumberProgresses[trackNumber2] = chunk.timestamp;
3025
+ }
3007
3026
  if (!currentCluster.shouldMakeNewCluster({
3008
3027
  newT: smallestProgress,
3009
3028
  isVideo,
@@ -3011,7 +3030,12 @@ var createMatroskaMedia = async ({
3011
3030
  })) {
3012
3031
  return { cluster: currentCluster, isNew: false, smallestProgress };
3013
3032
  }
3014
- currentCluster = await makeCluster(w, smallestProgress, timescale);
3033
+ currentCluster = await makeCluster({
3034
+ writer: w,
3035
+ clusterStartTimestamp: smallestProgress,
3036
+ timescale,
3037
+ logLevel
3038
+ });
3015
3039
  return { cluster: currentCluster, isNew: true, smallestProgress };
3016
3040
  };
3017
3041
  const updateDuration = async (newDuration) => {
@@ -3024,10 +3048,10 @@ var createMatroskaMedia = async ({
3024
3048
  trackNumber: trackNumber2,
3025
3049
  isVideo
3026
3050
  }) => {
3027
- trackNumberProgresses[trackNumber2] = chunk.timestamp;
3028
3051
  const { cluster, isNew, smallestProgress } = await getClusterOrMakeNew({
3029
3052
  chunk,
3030
- isVideo
3053
+ isVideo,
3054
+ trackNumber: trackNumber2
3031
3055
  });
3032
3056
  const newDuration = Math.round((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
3033
3057
  await updateDuration(newDuration);
@@ -3061,9 +3085,8 @@ var createMatroskaMedia = async ({
3061
3085
  }
3062
3086
  });
3063
3087
  },
3064
- save: async () => {
3065
- const file = await w.save();
3066
- return file;
3088
+ save: () => {
3089
+ return w.save();
3067
3090
  },
3068
3091
  remove: async () => {
3069
3092
  await w.remove();
@@ -3266,6 +3289,244 @@ var getMdatBox = (anySegment) => {
3266
3289
  return mdat;
3267
3290
  };
3268
3291
 
3292
+ // src/get-sample-positions.ts
3293
+ var getSamplePositions = ({
3294
+ stcoBox,
3295
+ stszBox,
3296
+ stscBox,
3297
+ stssBox,
3298
+ sttsBox,
3299
+ cttsBox
3300
+ }) => {
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
+ }
3306
+ }
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
+ }
3314
+ }
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
+ }
3343
+ }
3344
+ return samples;
3345
+ };
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");
3351
+ }
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
+ }
3398
+ }
3399
+ return samples;
3400
+ };
3401
+ var getSamplesFromMoof = ({
3402
+ moofBox,
3403
+ trackId
3404
+ }) => {
3405
+ if (moofBox.type !== "regular-box") {
3406
+ throw new Error("Expected moof-box");
3407
+ }
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);
3414
+ };
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);
3425
+ 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");
3437
+ }
3438
+ 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");
3443
+ }
3444
+ let samplePositions = getSamplePositions({
3445
+ stcoBox,
3446
+ stscBox,
3447
+ stszBox,
3448
+ stssBox,
3449
+ sttsBox,
3450
+ cttsBox
3451
+ });
3452
+ if (samplePositions.length === 0 && moofBox) {
3453
+ samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
3454
+ }
3455
+ return samplePositions;
3456
+ };
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") {
3462
+ return null;
3463
+ }
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) {
3498
+ return null;
3499
+ }
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
+
3269
3530
  // src/get-fps.ts
3270
3531
  var calculateFps = ({
3271
3532
  sttsBox,
@@ -3338,6 +3599,9 @@ var getFps = (segments) => {
3338
3599
  };
3339
3600
  var hasFps = (boxes) => {
3340
3601
  try {
3602
+ if (isMatroska(boxes)) {
3603
+ return true;
3604
+ }
3341
3605
  return getFps(boxes) !== null;
3342
3606
  } catch {
3343
3607
  return false;
@@ -3360,13 +3624,9 @@ var getAudioCodec = (boxes, parserState) => {
3360
3624
  }
3361
3625
  return null;
3362
3626
  };
3363
- var hasAudioCodec = (boxes, state) => {
3364
- try {
3365
- return getAudioCodec(boxes, state) !== null;
3366
- } catch {
3367
- return false;
3368
- }
3369
- };
3627
+ var hasAudioCodec = (boxes) => {
3628
+ return hasTracks(boxes);
3629
+ };
3370
3630
  var getCodecSpecificatorFromEsdsBox = ({
3371
3631
  child
3372
3632
  }) => {
@@ -4226,11 +4486,7 @@ var getVideoCodec = (boxes) => {
4226
4486
  return null;
4227
4487
  };
4228
4488
  var hasVideoCodec = (boxes) => {
4229
- try {
4230
- return getVideoCodec(boxes) !== null;
4231
- } catch {
4232
- return false;
4233
- }
4489
+ return hasTracks(boxes);
4234
4490
  };
4235
4491
  var getVideoPrivateData = (trakBox) => {
4236
4492
  const videoSample = getStsdVideoConfig(trakBox);
@@ -4800,303 +5056,68 @@ var getTracks = (segments, state) => {
4800
5056
  return {
4801
5057
  videoTracks,
4802
5058
  audioTracks,
4803
- otherTracks
4804
- };
4805
- }
4806
- const tracks2 = getTraks(moovBox);
4807
- for (const trakBox of tracks2) {
4808
- const track = makeBaseMediaTrack(trakBox);
4809
- if (!track) {
4810
- continue;
4811
- }
4812
- if (track.type === "video") {
4813
- videoTracks.push(track);
4814
- } else if (track.type === "audio") {
4815
- audioTracks.push(track);
4816
- } else if (track.type === "other") {
4817
- otherTracks.push(track);
4818
- }
4819
- }
4820
- return {
4821
- videoTracks,
4822
- audioTracks,
4823
- otherTracks
4824
- };
4825
- };
4826
-
4827
- // src/get-container.ts
4828
- var getContainer = (segments) => {
4829
- const moovBox = getMoovBox(segments);
4830
- if (moovBox) {
4831
- return "mp4";
4832
- }
4833
- const mainSegment = getMainSegment(segments);
4834
- if (mainSegment) {
4835
- return "webm";
4836
- }
4837
- return null;
4838
- };
4839
- var hasContainer = (boxes) => {
4840
- try {
4841
- return getContainer(boxes) !== null;
4842
- } catch {
4843
- return false;
4844
- }
4845
- };
4846
-
4847
- // src/get-dimensions.ts
4848
- var getDimensions = (boxes, state) => {
4849
- const { videoTracks } = getTracks(boxes, state);
4850
- if (!videoTracks.length) {
4851
- throw new Error("Expected video track");
4852
- }
4853
- const firstVideoTrack = videoTracks[0];
4854
- return {
4855
- width: firstVideoTrack.width,
4856
- height: firstVideoTrack.height,
4857
- rotation: firstVideoTrack.rotation,
4858
- unrotatedHeight: firstVideoTrack.displayAspectHeight,
4859
- unrotatedWidth: firstVideoTrack.displayAspectWidth
4860
- };
4861
- };
4862
- var hasDimensions = (boxes, state) => {
4863
- try {
4864
- return getDimensions(boxes, state) !== null;
4865
- } catch {
4866
- return false;
4867
- }
4868
- };
4869
-
4870
- // src/get-sample-positions.ts
4871
- var getSamplePositions = ({
4872
- stcoBox,
4873
- stszBox,
4874
- stscBox,
4875
- stssBox,
4876
- sttsBox,
4877
- cttsBox
4878
- }) => {
4879
- const sttsDeltas = [];
4880
- for (const distribution of sttsBox.sampleDistribution) {
4881
- for (let i = 0;i < distribution.sampleCount; i++) {
4882
- sttsDeltas.push(distribution.sampleDelta);
4883
- }
4884
- }
4885
- const cttsEntries = [];
4886
- for (const entry of cttsBox?.entries ?? [
4887
- { sampleCount: sttsDeltas.length, sampleOffset: 0 }
4888
- ]) {
4889
- for (let i = 0;i < entry.sampleCount; i++) {
4890
- cttsEntries.push(entry.sampleOffset);
4891
- }
4892
- }
4893
- let dts = 0;
4894
- const chunks = stcoBox.entries;
4895
- const samples = [];
4896
- let samplesPerChunk = 1;
4897
- for (let i = 0;i < chunks.length; i++) {
4898
- const hasEntry = stscBox.entries.find((entry) => entry.firstChunk === i + 1);
4899
- if (hasEntry) {
4900
- samplesPerChunk = hasEntry.samplesPerChunk;
4901
- }
4902
- let offsetInThisChunk = 0;
4903
- for (let j = 0;j < samplesPerChunk; j++) {
4904
- const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
4905
- const isKeyframe = stssBox ? stssBox.sampleNumber.includes(samples.length + 1) : true;
4906
- const delta = sttsDeltas[samples.length];
4907
- const ctsOffset = cttsEntries[samples.length];
4908
- const cts = dts + ctsOffset;
4909
- samples.push({
4910
- offset: Number(chunks[i]) + offsetInThisChunk,
4911
- size,
4912
- isKeyframe,
4913
- dts,
4914
- cts,
4915
- duration: delta,
4916
- chunk: i
4917
- });
4918
- dts += delta;
4919
- offsetInThisChunk += size;
4920
- }
4921
- }
4922
- return samples;
4923
- };
4924
-
4925
- // src/samples-from-moof.ts
4926
- var getSamplesFromTraf = (trafSegment, moofOffset) => {
4927
- if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
4928
- throw new Error("Expected traf-box");
4929
- }
4930
- const tfhdBox = getTfhdBox(trafSegment);
4931
- const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
4932
- const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
4933
- const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
4934
- const tfdtBox = getTfdtBox(trafSegment);
4935
- const trunBoxes = getTrunBoxes(trafSegment);
4936
- let time = 0;
4937
- let offset = 0;
4938
- let dataOffset = 0;
4939
- const samples = [];
4940
- for (const trunBox of trunBoxes) {
4941
- let i = -1;
4942
- if (trunBox.dataOffset) {
4943
- dataOffset = trunBox.dataOffset;
4944
- offset = 0;
4945
- }
4946
- for (const sample of trunBox.samples) {
4947
- i++;
4948
- const duration2 = sample.sampleDuration ?? defaultSampleDuration;
4949
- if (duration2 === null) {
4950
- throw new Error("Expected duration");
4951
- }
4952
- const size = sample.sampleSize ?? defaultSampleSize;
4953
- if (size === null) {
4954
- throw new Error("Expected size");
4955
- }
4956
- const isFirstSample = i === 0;
4957
- const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
4958
- if (sampleFlags === null) {
4959
- throw new Error("Expected sample flags");
4960
- }
4961
- const keyframe = !(sampleFlags >> 16 & 1);
4962
- const dts = time + (tfdtBox?.baseMediaDecodeTime ?? 0);
4963
- const samplePosition = {
4964
- offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
4965
- dts,
4966
- cts: dts,
4967
- duration: duration2,
4968
- isKeyframe: keyframe,
4969
- size,
4970
- chunk: 0
4971
- };
4972
- samples.push(samplePosition);
4973
- offset += size;
4974
- time += duration2;
4975
- }
4976
- }
4977
- return samples;
4978
- };
4979
- var getSamplesFromMoof = ({
4980
- moofBox,
4981
- trackId
4982
- }) => {
4983
- if (moofBox.type !== "regular-box") {
4984
- throw new Error("Expected moof-box");
4985
- }
4986
- const trafs = moofBox.children.filter((c) => c.type === "regular-box" && c.boxType === "traf");
4987
- const mapped = trafs.map((traf) => {
4988
- const tfhdBox = getTfhdBox(traf);
4989
- return tfhdBox?.trackId === trackId ? getSamplesFromTraf(traf, moofBox.offset) : [];
4990
- });
4991
- return mapped.flat(1);
4992
- };
4993
-
4994
- // src/boxes/iso-base-media/get-sample-positions-from-track.ts
4995
- var getSamplePositionsFromTrack = (trakBox, moofBox) => {
4996
- const stszBox = getStszBox(trakBox);
4997
- const stcoBox = getStcoBox(trakBox);
4998
- const stscBox = getStscBox(trakBox);
4999
- const stssBox = getStssBox(trakBox);
5000
- const sttsBox = getSttsBox(trakBox);
5001
- const tkhdBox = getTkhdBox(trakBox);
5002
- const cttsBox = getCttsBox(trakBox);
5003
- const timescaleAndDuration = getTimescaleAndDuration(trakBox);
5004
- if (!tkhdBox) {
5005
- throw new Error("Expected tkhd box in trak box");
5006
- }
5007
- if (!stszBox) {
5008
- throw new Error("Expected stsz box in trak box");
5009
- }
5010
- if (!stcoBox) {
5011
- throw new Error("Expected stco box in trak box");
5012
- }
5013
- if (!stscBox) {
5014
- throw new Error("Expected stsc box in trak box");
5015
- }
5016
- if (!sttsBox) {
5017
- throw new Error("Expected stts box in trak box");
5018
- }
5019
- if (!timescaleAndDuration) {
5020
- throw new Error("Expected timescale and duration in trak box");
5021
- }
5022
- let samplePositions = getSamplePositions({
5023
- stcoBox,
5024
- stscBox,
5025
- stszBox,
5026
- stssBox,
5027
- sttsBox,
5028
- cttsBox
5029
- });
5030
- if (samplePositions.length === 0 && moofBox) {
5031
- samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
5032
- }
5033
- return samplePositions;
5034
- };
5035
-
5036
- // src/get-duration.ts
5037
- var getDurationFromMatroska = (segments) => {
5038
- const mainSegment = segments.find((s) => s.type === "Segment");
5039
- if (!mainSegment || mainSegment.type !== "Segment") {
5040
- return null;
5041
- }
5042
- const { value: children } = mainSegment;
5043
- if (!children) {
5044
- return null;
5045
- }
5046
- const infoSegment = children.find((s) => s.type === "Info");
5047
- const relevantBoxes = [
5048
- ...mainSegment.value,
5049
- ...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
5050
- ];
5051
- const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
5052
- if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
5053
- return null;
5059
+ otherTracks
5060
+ };
5054
5061
  }
5055
- const duration2 = relevantBoxes.find((s) => s.type === "Duration");
5056
- if (!duration2 || duration2.type !== "Duration") {
5057
- return null;
5062
+ const tracks2 = getTraks(moovBox);
5063
+ for (const trakBox of tracks2) {
5064
+ const track = makeBaseMediaTrack(trakBox);
5065
+ if (!track) {
5066
+ continue;
5067
+ }
5068
+ if (track.type === "video") {
5069
+ videoTracks.push(track);
5070
+ } else if (track.type === "audio") {
5071
+ audioTracks.push(track);
5072
+ } else if (track.type === "other") {
5073
+ otherTracks.push(track);
5074
+ }
5058
5075
  }
5059
- return duration2.value.value / timestampScale2.value.value * 1000;
5076
+ return {
5077
+ videoTracks,
5078
+ audioTracks,
5079
+ otherTracks
5080
+ };
5060
5081
  };
5061
- var getDuration = (boxes, parserState) => {
5062
- const matroskaBox = boxes.find((b) => b.type === "Segment");
5063
- if (matroskaBox) {
5064
- return getDurationFromMatroska(boxes);
5065
- }
5066
- const moovBox = getMoovBox(boxes);
5067
- if (!moovBox) {
5068
- return null;
5082
+
5083
+ // src/get-container.ts
5084
+ var getContainer = (segments) => {
5085
+ const moovBox = getMoovBox(segments);
5086
+ if (moovBox) {
5087
+ return "mp4";
5069
5088
  }
5070
- const moofBox = getMoofBox(boxes);
5071
- const mvhdBox = getMvhdBox(moovBox);
5072
- if (!mvhdBox) {
5073
- return null;
5089
+ const mainSegment = getMainSegment(segments);
5090
+ if (mainSegment) {
5091
+ return "webm";
5074
5092
  }
5075
- if (mvhdBox.type !== "mvhd-box") {
5076
- throw new Error("Expected mvhd-box");
5093
+ return null;
5094
+ };
5095
+ var hasContainer = (boxes) => {
5096
+ try {
5097
+ return getContainer(boxes) !== null;
5098
+ } catch {
5099
+ return false;
5077
5100
  }
5078
- if (mvhdBox.durationInSeconds > 0) {
5079
- return mvhdBox.durationInSeconds;
5101
+ };
5102
+
5103
+ // src/get-dimensions.ts
5104
+ var getDimensions = (boxes, state) => {
5105
+ const { videoTracks } = getTracks(boxes, state);
5106
+ if (!videoTracks.length) {
5107
+ throw new Error("Expected video track");
5080
5108
  }
5081
- const tracks2 = getTracks(boxes, parserState);
5082
- const allTracks = [
5083
- ...tracks2.videoTracks,
5084
- ...tracks2.audioTracks,
5085
- ...tracks2.otherTracks
5086
- ];
5087
- const allSamples = allTracks.map((t) => {
5088
- const { timescale: ts } = t;
5089
- const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
5090
- const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
5091
- return highest ?? 0;
5092
- });
5093
- const highestTimestamp = Math.max(...allSamples);
5094
- return highestTimestamp;
5109
+ const firstVideoTrack = videoTracks[0];
5110
+ return {
5111
+ width: firstVideoTrack.width,
5112
+ height: firstVideoTrack.height,
5113
+ rotation: firstVideoTrack.rotation,
5114
+ unrotatedHeight: firstVideoTrack.displayAspectHeight,
5115
+ unrotatedWidth: firstVideoTrack.displayAspectWidth
5116
+ };
5095
5117
  };
5096
- var hasDuration = (boxes, parserState) => {
5118
+ var hasDimensions = (boxes, state) => {
5097
5119
  try {
5098
- const duration2 = getDuration(boxes, parserState);
5099
- return getDuration(boxes, parserState) !== null && duration2 !== 0;
5120
+ return getDimensions(boxes, state) !== null;
5100
5121
  } catch {
5101
5122
  return false;
5102
5123
  }
@@ -5115,14 +5136,14 @@ var emitAvailableInfo = ({
5115
5136
  const keys = Object.keys(hasInfo);
5116
5137
  for (const key of keys) {
5117
5138
  if (key === "boxes") {
5118
- if (hasInfo.boxes && returnValue.boxes === undefined) {
5139
+ if (parseResult && hasInfo.boxes && returnValue.boxes === undefined) {
5119
5140
  moreFields.onBoxes?.(parseResult.segments);
5120
5141
  returnValue.boxes = parseResult.segments;
5121
5142
  }
5122
5143
  continue;
5123
5144
  }
5124
5145
  if (key === "durationInSeconds") {
5125
- if (hasInfo.durationInSeconds && returnValue.durationInSeconds === undefined) {
5146
+ if (hasInfo.durationInSeconds && returnValue.durationInSeconds === undefined && parseResult) {
5126
5147
  const durationInSeconds = getDuration(parseResult.segments, state);
5127
5148
  moreFields.onDurationInSeconds?.(durationInSeconds);
5128
5149
  returnValue.durationInSeconds = durationInSeconds;
@@ -5130,7 +5151,7 @@ var emitAvailableInfo = ({
5130
5151
  continue;
5131
5152
  }
5132
5153
  if (key === "dimensions") {
5133
- if (hasInfo.dimensions && returnValue.dimensions === undefined) {
5154
+ if (hasInfo.dimensions && returnValue.dimensions === undefined && parseResult) {
5134
5155
  const dimensionsQueried = getDimensions(parseResult.segments, state);
5135
5156
  const dimensions = {
5136
5157
  height: dimensionsQueried.height,
@@ -5142,7 +5163,7 @@ var emitAvailableInfo = ({
5142
5163
  continue;
5143
5164
  }
5144
5165
  if (key === "unrotatedDimensions") {
5145
- if (returnValue.unrotatedDimensions === undefined && hasInfo.unrotatedDimensions) {
5166
+ if (returnValue.unrotatedDimensions === undefined && hasInfo.unrotatedDimensions && parseResult) {
5146
5167
  const dimensionsQueried = getDimensions(parseResult.segments, state);
5147
5168
  const unrotatedDimensions = {
5148
5169
  height: dimensionsQueried.unrotatedHeight,
@@ -5154,7 +5175,7 @@ var emitAvailableInfo = ({
5154
5175
  continue;
5155
5176
  }
5156
5177
  if (key === "rotation") {
5157
- if (returnValue.rotation === undefined && hasInfo.rotation) {
5178
+ if (returnValue.rotation === undefined && hasInfo.rotation && parseResult) {
5158
5179
  const dimensionsQueried = getDimensions(parseResult.segments, state);
5159
5180
  const { rotation } = dimensionsQueried;
5160
5181
  moreFields.onRotation?.(rotation);
@@ -5163,7 +5184,7 @@ var emitAvailableInfo = ({
5163
5184
  continue;
5164
5185
  }
5165
5186
  if (key === "fps") {
5166
- if (returnValue.fps === undefined && hasInfo.fps) {
5187
+ if (returnValue.fps === undefined && hasInfo.fps && parseResult) {
5167
5188
  const fps = getFps(parseResult.segments);
5168
5189
  moreFields.onFps?.(fps);
5169
5190
  returnValue.fps = fps;
@@ -5171,7 +5192,7 @@ var emitAvailableInfo = ({
5171
5192
  continue;
5172
5193
  }
5173
5194
  if (key === "videoCodec") {
5174
- if (returnValue.videoCodec === undefined && hasInfo.videoCodec) {
5195
+ if (returnValue.videoCodec === undefined && hasInfo.videoCodec && parseResult) {
5175
5196
  const videoCodec = getVideoCodec(parseResult.segments);
5176
5197
  moreFields.onVideoCodec?.(videoCodec);
5177
5198
  returnValue.videoCodec = videoCodec;
@@ -5179,7 +5200,7 @@ var emitAvailableInfo = ({
5179
5200
  continue;
5180
5201
  }
5181
5202
  if (key === "audioCodec") {
5182
- if (returnValue.audioCodec === undefined && hasInfo.audioCodec) {
5203
+ if (returnValue.audioCodec === undefined && hasInfo.audioCodec && parseResult) {
5183
5204
  const audioCodec = getAudioCodec(parseResult.segments, state);
5184
5205
  moreFields.onAudioCodec?.(audioCodec);
5185
5206
  returnValue.audioCodec = audioCodec;
@@ -5187,7 +5208,7 @@ var emitAvailableInfo = ({
5187
5208
  continue;
5188
5209
  }
5189
5210
  if (key === "tracks") {
5190
- if (hasInfo.tracks && returnValue.videoTracks === undefined && returnValue.audioTracks === undefined) {
5211
+ if (hasInfo.tracks && returnValue.videoTracks === undefined && returnValue.audioTracks === undefined && parseResult) {
5191
5212
  const { videoTracks, audioTracks } = getTracks(parseResult.segments, state);
5192
5213
  moreFields.onTracks?.({ videoTracks, audioTracks });
5193
5214
  returnValue.videoTracks = videoTracks;
@@ -5218,7 +5239,7 @@ var emitAvailableInfo = ({
5218
5239
  continue;
5219
5240
  }
5220
5241
  if (key === "container") {
5221
- if (returnValue.container === undefined && hasInfo.container) {
5242
+ if (returnValue.container === undefined && hasInfo.container && parseResult) {
5222
5243
  const container = getContainer(parseResult.segments);
5223
5244
  moreFields.onContainer?.(container);
5224
5245
  returnValue.container = container;
@@ -5234,25 +5255,25 @@ var getAvailableInfo = (options, parseResult, state) => {
5234
5255
  const keys = Object.entries(options).filter(([, value]) => value);
5235
5256
  const infos = keys.map(([key]) => {
5236
5257
  if (key === "boxes") {
5237
- return parseResult.status === "done";
5258
+ return Boolean(parseResult && parseResult.status === "done");
5238
5259
  }
5239
5260
  if (key === "durationInSeconds") {
5240
- return hasDuration(parseResult.segments, state);
5261
+ return Boolean(parseResult && hasDuration(parseResult.segments, state));
5241
5262
  }
5242
5263
  if (key === "dimensions" || key === "rotation" || key === "unrotatedDimensions") {
5243
- return hasDimensions(parseResult.segments, state);
5264
+ return Boolean(parseResult && hasDimensions(parseResult.segments, state));
5244
5265
  }
5245
5266
  if (key === "fps") {
5246
- return hasFps(parseResult.segments);
5267
+ return Boolean(parseResult && hasFps(parseResult.segments));
5247
5268
  }
5248
5269
  if (key === "videoCodec") {
5249
- return hasVideoCodec(parseResult.segments);
5270
+ return Boolean(parseResult && hasVideoCodec(parseResult.segments));
5250
5271
  }
5251
5272
  if (key === "audioCodec") {
5252
- return hasAudioCodec(parseResult.segments, state);
5273
+ return Boolean(parseResult && hasAudioCodec(parseResult.segments));
5253
5274
  }
5254
5275
  if (key === "tracks") {
5255
- return hasTracks(parseResult.segments);
5276
+ return Boolean(parseResult && hasTracks(parseResult.segments));
5256
5277
  }
5257
5278
  if (key === "internalStats") {
5258
5279
  return false;
@@ -5264,7 +5285,7 @@ var getAvailableInfo = (options, parseResult, state) => {
5264
5285
  return true;
5265
5286
  }
5266
5287
  if (key === "container") {
5267
- return hasContainer(parseResult.segments);
5288
+ return Boolean(parseResult && hasContainer(parseResult.segments));
5268
5289
  }
5269
5290
  throw new Error(`Unknown key: ${key}`);
5270
5291
  });
@@ -7605,32 +7626,54 @@ var postprocessEbml = async ({
7605
7626
  };
7606
7627
 
7607
7628
  // src/boxes/webm/segments.ts
7608
- var parseSegment = async ({
7609
- segmentId,
7629
+ var continueAfterMatroskaParseResult = async ({
7630
+ result,
7610
7631
  iterator,
7611
- length,
7612
7632
  parserContext,
7613
- headerReadSoFar
7633
+ segment
7614
7634
  }) => {
7615
- if (length < 0) {
7616
- throw new Error(`Expected length of ${segmentId} to be greater or equal 0`);
7635
+ if (result.status === "done") {
7636
+ throw new Error("Should not continue after done");
7617
7637
  }
7618
- iterator.counter.decrement(headerReadSoFar);
7619
- const offset = iterator.counter.getOffset();
7620
- const ebml = await parseEbml(iterator, parserContext);
7621
- const remapped = await postprocessEbml({ offset, ebml, parserContext });
7622
- return remapped;
7638
+ const proceeded = await result.continueParsing();
7639
+ if (proceeded.status === "done") {
7640
+ return {
7641
+ status: "done",
7642
+ segment
7643
+ };
7644
+ }
7645
+ return {
7646
+ continueParsing() {
7647
+ return continueAfterMatroskaParseResult({
7648
+ result: proceeded,
7649
+ iterator,
7650
+ parserContext,
7651
+ segment
7652
+ });
7653
+ },
7654
+ segment: null,
7655
+ status: "incomplete"
7656
+ };
7623
7657
  };
7624
- var expectSegment = async (iterator, parserContext) => {
7625
- const offset = iterator.counter.getOffset();
7658
+ var expectSegment = async ({
7659
+ iterator,
7660
+ parserContext,
7661
+ offset,
7662
+ children
7663
+ }) => {
7664
+ iterator.counter.decrement(iterator.counter.getOffset() - offset);
7626
7665
  if (iterator.bytesRemaining() === 0) {
7627
7666
  return {
7628
7667
  status: "incomplete",
7629
- segments: [],
7630
7668
  continueParsing: () => {
7631
- return Promise.resolve(expectSegment(iterator, parserContext));
7669
+ return expectAndProcessSegment({
7670
+ iterator,
7671
+ parserContext,
7672
+ offset,
7673
+ children
7674
+ });
7632
7675
  },
7633
- skipTo: null
7676
+ segment: null
7634
7677
  };
7635
7678
  }
7636
7679
  const segmentId = iterator.getMatroskaSegmentId();
@@ -7638,11 +7681,15 @@ var expectSegment = async (iterator, parserContext) => {
7638
7681
  iterator.counter.decrement(iterator.counter.getOffset() - offset);
7639
7682
  return {
7640
7683
  status: "incomplete",
7641
- segments: [],
7642
7684
  continueParsing: () => {
7643
- return Promise.resolve(expectSegment(iterator, parserContext));
7685
+ return expectAndProcessSegment({
7686
+ iterator,
7687
+ parserContext,
7688
+ offset,
7689
+ children
7690
+ });
7644
7691
  },
7645
- skipTo: null
7692
+ segment: null
7646
7693
  };
7647
7694
  }
7648
7695
  const offsetBeforeVInt = iterator.counter.getOffset();
@@ -7652,41 +7699,43 @@ var expectSegment = async (iterator, parserContext) => {
7652
7699
  iterator.counter.decrement(iterator.counter.getOffset() - offset);
7653
7700
  return {
7654
7701
  status: "incomplete",
7655
- segments: [],
7656
7702
  continueParsing: () => {
7657
- return Promise.resolve(expectSegment(iterator, parserContext));
7703
+ return expectSegment({ iterator, parserContext, offset, children });
7658
7704
  },
7659
- skipTo: null
7705
+ segment: null
7660
7706
  };
7661
7707
  }
7662
7708
  const bytesRemainingNow = iterator.byteLength() - iterator.counter.getOffset();
7663
7709
  if (segmentId === "0x18538067" || segmentId === "0x1f43b675") {
7710
+ const newSegment = {
7711
+ type: segmentId === "0x18538067" ? "Segment" : "Cluster",
7712
+ minVintWidth: offsetAfterVInt - offsetBeforeVInt,
7713
+ value: []
7714
+ };
7664
7715
  const main = await expectChildren({
7665
7716
  iterator,
7666
7717
  length,
7667
- initialChildren: [],
7668
- wrap: segmentId === "0x18538067" ? (s) => ({
7669
- type: "Segment",
7670
- value: s,
7671
- minVintWidth: offsetAfterVInt - offsetBeforeVInt
7672
- }) : (s) => ({
7673
- type: "Cluster",
7674
- value: s,
7675
- minVintWidth: offsetAfterVInt - offsetBeforeVInt
7676
- }),
7677
- parserContext
7718
+ children: newSegment.value,
7719
+ parserContext,
7720
+ startOffset: iterator.counter.getOffset()
7678
7721
  });
7679
7722
  if (main.status === "incomplete") {
7680
7723
  return {
7681
7724
  status: "incomplete",
7682
- segments: main.segments,
7683
- skipTo: null,
7684
- continueParsing: main.continueParsing
7725
+ continueParsing: () => {
7726
+ return continueAfterMatroskaParseResult({
7727
+ iterator,
7728
+ parserContext,
7729
+ result: main,
7730
+ segment: newSegment
7731
+ });
7732
+ },
7733
+ segment: newSegment
7685
7734
  };
7686
7735
  }
7687
7736
  return {
7688
7737
  status: "done",
7689
- segments: main.segments
7738
+ segment: newSegment
7690
7739
  };
7691
7740
  }
7692
7741
  if (bytesRemainingNow < length) {
@@ -7694,11 +7743,10 @@ var expectSegment = async (iterator, parserContext) => {
7694
7743
  iterator.counter.decrement(bytesRead);
7695
7744
  return {
7696
7745
  status: "incomplete",
7697
- segments: [],
7746
+ segment: null,
7698
7747
  continueParsing: () => {
7699
- return Promise.resolve(expectSegment(iterator, parserContext));
7700
- },
7701
- skipTo: null
7748
+ return expectSegment({ iterator, parserContext, offset, children });
7749
+ }
7702
7750
  };
7703
7751
  }
7704
7752
  const segment = await parseSegment({
@@ -7710,131 +7758,179 @@ var expectSegment = async (iterator, parserContext) => {
7710
7758
  });
7711
7759
  return {
7712
7760
  status: "done",
7713
- segments: [segment]
7761
+ segment
7714
7762
  };
7715
7763
  };
7764
+ var parseSegment = async ({
7765
+ segmentId,
7766
+ iterator,
7767
+ length,
7768
+ parserContext,
7769
+ headerReadSoFar
7770
+ }) => {
7771
+ if (length < 0) {
7772
+ throw new Error(`Expected length of ${segmentId} to be greater or equal 0`);
7773
+ }
7774
+ iterator.counter.decrement(headerReadSoFar);
7775
+ const offset = iterator.counter.getOffset();
7776
+ const ebml = await parseEbml(iterator, parserContext);
7777
+ const remapped = await postprocessEbml({ offset, ebml, parserContext });
7778
+ return remapped;
7779
+ };
7716
7780
 
7717
7781
  // src/boxes/webm/segments/parse-children.ts
7718
7782
  var processParseResult = ({
7719
7783
  parseResult,
7720
- children,
7721
- wrap
7784
+ children
7722
7785
  }) => {
7786
+ if (parseResult.segment && !children.includes(parseResult.segment)) {
7787
+ children.push(parseResult.segment);
7788
+ }
7723
7789
  if (parseResult.status === "incomplete") {
7724
7790
  return {
7725
7791
  status: "incomplete",
7726
- segments: [],
7792
+ segment: parseResult.segment,
7727
7793
  continueParsing: async () => {
7728
7794
  const newParseResult = await parseResult.continueParsing();
7729
7795
  return processParseResult({
7730
7796
  children,
7731
- parseResult: newParseResult,
7732
- wrap
7797
+ parseResult: newParseResult
7733
7798
  });
7734
- },
7735
- skipTo: null
7799
+ }
7736
7800
  };
7737
7801
  }
7738
- for (const segment of parseResult.segments) {
7739
- children.push(segment);
7740
- }
7741
7802
  return {
7742
7803
  status: "done",
7743
- segments: wrap ? [wrap(children)] : children
7804
+ segment: parseResult.segment
7744
7805
  };
7745
7806
  };
7746
- var continueParsingfunction = ({
7747
- result,
7807
+ var expectAndProcessSegment = async ({
7748
7808
  iterator,
7809
+ parserContext,
7810
+ offset,
7811
+ children
7812
+ }) => {
7813
+ const segment = await expectSegment({
7814
+ iterator,
7815
+ parserContext,
7816
+ offset,
7817
+ children
7818
+ });
7819
+ return processParseResult({
7820
+ children,
7821
+ parseResult: segment
7822
+ });
7823
+ };
7824
+ var continueAfterSegmentResult = async ({
7825
+ result,
7826
+ length,
7749
7827
  children,
7750
- wrap,
7751
7828
  parserContext,
7752
- length
7753
- }) => async () => {
7754
- if (result.status !== "incomplete") {
7755
- throw new Error("expected incomplete");
7829
+ iterator,
7830
+ startOffset
7831
+ }) => {
7832
+ if (result.status === "done") {
7833
+ throw new Error("Should not continue after done");
7756
7834
  }
7757
- const offset = iterator.counter.getOffset();
7758
- const continued = await result.continueParsing();
7759
- if (continued.status === "incomplete") {
7760
- if (!parserContext.supportsContentRange) {
7761
- throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
7762
- }
7835
+ const segmentResult = await result.continueParsing();
7836
+ if (segmentResult.status === "done") {
7763
7837
  return {
7764
7838
  status: "incomplete",
7765
- continueParsing: continueParsingfunction({
7766
- result: continued,
7767
- iterator,
7768
- children,
7769
- wrap,
7770
- parserContext,
7771
- length: length - (iterator.counter.getOffset() - offset)
7772
- }),
7773
- skipTo: continued.skipTo,
7774
- segments: wrap ? [wrap(children)] : children
7839
+ continueParsing: () => {
7840
+ return expectChildren({
7841
+ children,
7842
+ iterator,
7843
+ length,
7844
+ parserContext,
7845
+ startOffset
7846
+ });
7847
+ },
7848
+ skipTo: null
7775
7849
  };
7776
7850
  }
7777
- return expectChildren({
7778
- iterator,
7779
- length: length - (iterator.counter.getOffset() - offset),
7780
- initialChildren: children,
7781
- wrap,
7782
- parserContext
7783
- });
7851
+ return {
7852
+ status: "incomplete",
7853
+ continueParsing: () => {
7854
+ return continueAfterSegmentResult({
7855
+ result: segmentResult,
7856
+ children,
7857
+ iterator,
7858
+ length,
7859
+ parserContext,
7860
+ startOffset
7861
+ });
7862
+ },
7863
+ skipTo: null
7864
+ };
7784
7865
  };
7785
7866
  var expectChildren = async ({
7786
7867
  iterator,
7787
7868
  length,
7788
- initialChildren,
7789
- wrap,
7790
- parserContext
7869
+ children,
7870
+ parserContext,
7871
+ startOffset
7791
7872
  }) => {
7792
- const children = [...initialChildren];
7793
- const startOffset = iterator.counter.getOffset();
7794
7873
  while (iterator.counter.getOffset() < startOffset + length) {
7795
7874
  if (iterator.bytesRemaining() === 0) {
7796
7875
  break;
7797
7876
  }
7798
- const parseResult = await expectSegment(iterator, parserContext);
7799
- const child = processParseResult({
7800
- children,
7801
- parseResult,
7802
- wrap
7877
+ const currentOffset = iterator.counter.getOffset();
7878
+ const child = await expectAndProcessSegment({
7879
+ iterator,
7880
+ parserContext,
7881
+ offset: currentOffset,
7882
+ children
7803
7883
  });
7804
7884
  if (child.status === "incomplete") {
7805
- if (!parserContext.supportsContentRange) {
7806
- throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
7807
- }
7808
7885
  return {
7809
7886
  status: "incomplete",
7810
- continueParsing: continueParsingfunction({
7811
- result: child,
7812
- iterator,
7813
- children,
7814
- wrap,
7815
- parserContext,
7816
- length: length - (iterator.counter.getOffset() - startOffset)
7817
- }),
7818
- skipTo: child.skipTo,
7819
- segments: wrap ? [wrap(children)] : children
7887
+ continueParsing: () => {
7888
+ return continueAfterSegmentResult({
7889
+ result: child,
7890
+ children,
7891
+ iterator,
7892
+ length: length - (currentOffset - startOffset),
7893
+ parserContext,
7894
+ startOffset: currentOffset
7895
+ });
7896
+ },
7897
+ skipTo: null
7820
7898
  };
7821
7899
  }
7822
7900
  }
7823
7901
  return {
7824
- status: "done",
7825
- segments: wrap ? [wrap(children)] : children
7902
+ status: "done"
7826
7903
  };
7827
7904
  };
7828
7905
 
7829
7906
  // src/boxes/webm/parse-webm-header.ts
7830
- var parseWebm = (counter, parserContext) => {
7831
- return expectChildren({
7907
+ var continueAfterMatroskaResult = (result, children) => {
7908
+ if (result.status === "done") {
7909
+ return {
7910
+ status: "done",
7911
+ segments: children
7912
+ };
7913
+ }
7914
+ return {
7915
+ status: "incomplete",
7916
+ segments: children,
7917
+ continueParsing: async () => {
7918
+ const newResult = await result.continueParsing();
7919
+ return continueAfterMatroskaResult(newResult, children);
7920
+ },
7921
+ skipTo: null
7922
+ };
7923
+ };
7924
+ var parseWebm = async (counter, parserContext) => {
7925
+ const children = [];
7926
+ const results = await expectChildren({
7832
7927
  iterator: counter,
7833
7928
  length: Infinity,
7834
- initialChildren: [],
7835
- wrap: null,
7836
- parserContext
7929
+ children,
7930
+ parserContext,
7931
+ startOffset: counter.counter.getOffset()
7837
7932
  });
7933
+ return continueAfterMatroskaResult(results, children);
7838
7934
  };
7839
7935
 
7840
7936
  // src/parse-video.ts
@@ -7863,6 +7959,7 @@ var parseVideo = ({
7863
7959
  throw new Error("AVI files are not yet supported");
7864
7960
  }
7865
7961
  if (iterator.isIsoBaseMedia()) {
7962
+ Log.verbose(logLevel, "Detected ISO Base Media container");
7866
7963
  return parseBoxes({
7867
7964
  iterator,
7868
7965
  maxBytes: Infinity,
@@ -7875,6 +7972,7 @@ var parseVideo = ({
7875
7972
  });
7876
7973
  }
7877
7974
  if (iterator.isWebm()) {
7975
+ Log.verbose(logLevel, "Detected Matroska container");
7878
7976
  return Promise.resolve(parseWebm(iterator, options));
7879
7977
  }
7880
7978
  if (iterator.isMp3()) {
@@ -8016,6 +8114,7 @@ var parseMedia = async ({
8016
8114
  onVideoTrack,
8017
8115
  signal,
8018
8116
  logLevel = "info",
8117
+ onParseProgress,
8019
8118
  ...more
8020
8119
  }) => {
8021
8120
  const state = makeParserState({
@@ -8035,14 +8134,40 @@ var parseMedia = async ({
8035
8134
  const moreFields = more;
8036
8135
  let iterator = null;
8037
8136
  let parseResult = null;
8137
+ const canSkipVideoData = !onVideoTrack && !onAudioTrack;
8138
+ if (canSkipVideoData) {
8139
+ Log.verbose(logLevel, "Only parsing metadata, because no onVideoTrack and onAudioTrack callbacks were passed.");
8140
+ } else {
8141
+ Log.verbose(logLevel, "Parsing video data, because onVideoTrack/onAudioTrack callbacks were passed.");
8142
+ }
8038
8143
  const options = {
8039
- canSkipVideoData: !(onAudioTrack || onVideoTrack),
8144
+ canSkipVideoData,
8040
8145
  onAudioTrack: onAudioTrack ?? null,
8041
8146
  onVideoTrack: onVideoTrack ?? null,
8042
8147
  parserState: state,
8043
8148
  nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true"),
8044
8149
  supportsContentRange
8045
8150
  };
8151
+ const hasAllInfo = () => {
8152
+ if (parseResult === null) {
8153
+ return false;
8154
+ }
8155
+ const availableInfo = getAvailableInfo(fields ?? {}, parseResult, state);
8156
+ return Object.values(availableInfo).every(Boolean);
8157
+ };
8158
+ const triggerInfoEmit = () => {
8159
+ const availableInfo = getAvailableInfo(fields ?? {}, parseResult, state);
8160
+ emitAvailableInfo({
8161
+ hasInfo: availableInfo,
8162
+ moreFields,
8163
+ parseResult,
8164
+ state,
8165
+ returnValue,
8166
+ contentLength,
8167
+ name
8168
+ });
8169
+ };
8170
+ triggerInfoEmit();
8046
8171
  while (parseResult === null || parseResult.status === "incomplete") {
8047
8172
  if (signal?.aborted) {
8048
8173
  throw new Error("Aborted");
@@ -8069,7 +8194,14 @@ var parseMedia = async ({
8069
8194
  if (!iterator) {
8070
8195
  throw new Error("Unexpected null");
8071
8196
  }
8197
+ await onParseProgress?.({
8198
+ bytes: iterator.counter.getOffset(),
8199
+ percentage: contentLength ? iterator.counter.getOffset() / contentLength : null,
8200
+ totalBytes: contentLength
8201
+ });
8202
+ triggerInfoEmit();
8072
8203
  if (parseResult && parseResult.status === "incomplete") {
8204
+ Log.verbose(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset(), getAvailableInfo(fields ?? {}, parseResult, state));
8073
8205
  parseResult = await parseResult.continueParsing();
8074
8206
  } else {
8075
8207
  parseResult = await parseVideo({
@@ -8079,18 +8211,7 @@ var parseMedia = async ({
8079
8211
  logLevel
8080
8212
  });
8081
8213
  }
8082
- const availableInfo = getAvailableInfo(fields ?? {}, parseResult, state);
8083
- const hasAllInfo = Object.values(availableInfo).every(Boolean);
8084
- emitAvailableInfo({
8085
- hasInfo: availableInfo,
8086
- moreFields,
8087
- parseResult,
8088
- state,
8089
- returnValue,
8090
- contentLength,
8091
- name
8092
- });
8093
- if (hasAllInfo && !onVideoTrack && !onAudioTrack) {
8214
+ if (hasAllInfo() && !onVideoTrack && !onAudioTrack) {
8094
8215
  break;
8095
8216
  }
8096
8217
  if (parseResult && parseResult.status === "incomplete" && parseResult.skipTo !== null) {
@@ -8103,6 +8224,7 @@ var parseMedia = async ({
8103
8224
  iterator.skipTo(parseResult.skipTo, true);
8104
8225
  }
8105
8226
  }
8227
+ Log.verbose(logLevel, "Finished parsing file");
8106
8228
  emitAvailableInfo({
8107
8229
  hasInfo: Object.keys(fields ?? {}).reduce((acc, key) => {
8108
8230
  acc[key] = true;
@@ -8119,6 +8241,9 @@ var parseMedia = async ({
8119
8241
  iterator?.destroy();
8120
8242
  return returnValue;
8121
8243
  };
8244
+ // src/version.ts
8245
+ var VERSION = "4.0.231";
8246
+
8122
8247
  // src/index.ts
8123
8248
  var MediaParserInternals = {
8124
8249
  createMatroskaMedia,
@@ -8127,5 +8252,6 @@ var MediaParserInternals = {
8127
8252
  };
8128
8253
  export {
8129
8254
  parseMedia,
8255
+ VERSION,
8130
8256
  MediaParserInternals
8131
8257
  };