@remotion/media-parser 4.0.293 → 4.0.295

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 (42) hide show
  1. package/dist/containers/iso-base-media/are-samples-complete.d.ts +6 -0
  2. package/dist/containers/iso-base-media/are-samples-complete.js +11 -0
  3. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.d.ts +2 -3
  4. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.js +1 -3
  5. package/dist/containers/iso-base-media/find-track-to-seek.js +9 -2
  6. package/dist/containers/iso-base-media/get-keyframes.js +6 -2
  7. package/dist/containers/iso-base-media/get-sample-positions-from-track.d.ts +2 -3
  8. package/dist/containers/iso-base-media/get-sample-positions-from-track.js +4 -4
  9. package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +6 -1
  10. package/dist/containers/iso-base-media/mdat/mdat.js +18 -1
  11. package/dist/containers/iso-base-media/process-box.js +7 -7
  12. package/dist/containers/iso-base-media/seeking-hints.js +1 -1
  13. package/dist/containers/iso-base-media/traversal.d.ts +2 -1
  14. package/dist/containers/iso-base-media/traversal.js +8 -4
  15. package/dist/emit-available-info.js +26 -26
  16. package/dist/esm/index.mjs +160 -88
  17. package/dist/esm/node.mjs +7 -4
  18. package/dist/esm/universal.mjs +29 -37
  19. package/dist/esm/web.mjs +22 -33
  20. package/dist/esm/worker-server-entry.mjs +166 -91
  21. package/dist/esm/worker-web-entry.mjs +159 -87
  22. package/dist/get-duration.js +15 -3
  23. package/dist/has-all-info.js +2 -1
  24. package/dist/index.d.ts +1 -1
  25. package/dist/readers/fetch/get-body-and-reader.js +3 -1
  26. package/dist/readers/from-node.js +7 -3
  27. package/dist/readers/from-web-file.js +20 -32
  28. package/dist/readers/reader.d.ts +1 -1
  29. package/dist/seek-backwards.js +1 -0
  30. package/dist/seek-forwards.js +1 -0
  31. package/dist/state/iso-base-media/cached-sample-positions.d.ts +5 -2
  32. package/dist/state/iso-base-media/cached-sample-positions.js +17 -7
  33. package/dist/state/iso-base-media/iso-state.d.ts +1 -1
  34. package/dist/state/iso-base-media/last-moof-box.d.ts +2 -0
  35. package/dist/state/iso-base-media/last-moof-box.js +21 -0
  36. package/dist/state/iso-base-media/precomputed-moof.d.ts +1 -0
  37. package/dist/state/iso-base-media/precomputed-moof.js +1 -0
  38. package/dist/state/parser-state.d.ts +1 -1
  39. package/dist/state/parser-state.js +2 -1
  40. package/dist/version.d.ts +1 -1
  41. package/dist/version.js +1 -1
  42. package/package.json +3 -3
package/dist/esm/web.mjs CHANGED
@@ -75,8 +75,9 @@ var getLengthAndReader = async ({
75
75
  contentLength: encoded.byteLength,
76
76
  reader: {
77
77
  reader: stream.getReader(),
78
- abort() {
78
+ abort: () => {
79
79
  ownController.abort();
80
+ return Promise.resolve();
80
81
  }
81
82
  },
82
83
  needsContentRange: false
@@ -91,6 +92,7 @@ var getLengthAndReader = async ({
91
92
  reader,
92
93
  abort: () => {
93
94
  ownController.abort();
95
+ return Promise.resolve();
94
96
  }
95
97
  },
96
98
  contentLength,
@@ -311,42 +313,29 @@ var webFileReadContent = ({ src, range, controller }) => {
311
313
  if (typeof src === "string" || src instanceof URL) {
312
314
  throw new Error("`inputTypeFileReader` only supports `File` objects");
313
315
  }
314
- const part = range === null ? src : typeof range === "number" ? src.slice(range) : src.slice(range[0], range[1]);
315
- const reader = new FileReader;
316
- reader.readAsArrayBuffer(src);
317
- const ownController = new AbortController;
318
- if (ownController) {
319
- ownController.signal.addEventListener("abort", () => {
320
- reader.abort();
321
- }, { once: true });
322
- }
316
+ const part = range === null ? src : typeof range === "number" ? src.slice(range) : src.slice(range[0], range[1] + 1);
317
+ const stream = part.stream();
318
+ const streamReader = stream.getReader();
323
319
  if (controller) {
324
320
  controller._internals.signal.addEventListener("abort", () => {
325
- ownController.abort();
321
+ streamReader.cancel();
326
322
  }, { once: true });
327
323
  }
328
- return new Promise((resolve, reject) => {
329
- reader.onload = () => {
330
- const stream = part.stream();
331
- const streamReader = stream.getReader();
332
- resolve({
333
- reader: {
334
- reader: streamReader,
335
- abort() {
336
- streamReader.cancel();
337
- ownController.abort();
338
- }
339
- },
340
- contentLength: src.size,
341
- name: src instanceof File ? src.name : src.toString(),
342
- supportsContentRange: true,
343
- contentType: src.type,
344
- needsContentRange: true
345
- });
346
- };
347
- reader.onerror = () => {
348
- reject(reader.error);
349
- };
324
+ return Promise.resolve({
325
+ reader: {
326
+ reader: streamReader,
327
+ async abort() {
328
+ try {
329
+ await streamReader.cancel();
330
+ } catch {}
331
+ return Promise.resolve();
332
+ }
333
+ },
334
+ contentLength: src.size,
335
+ name: src instanceof File ? src.name : src.toString(),
336
+ supportsContentRange: true,
337
+ contentType: src.type,
338
+ needsContentRange: true
350
339
  });
351
340
  };
352
341
  var webFileReadWholeAsText = () => {
@@ -166,8 +166,9 @@ var getLengthAndReader = async ({
166
166
  contentLength: encoded.byteLength,
167
167
  reader: {
168
168
  reader: stream.getReader(),
169
- abort() {
169
+ abort: () => {
170
170
  ownController.abort();
171
+ return Promise.resolve();
171
172
  }
172
173
  },
173
174
  needsContentRange: false
@@ -182,6 +183,7 @@ var getLengthAndReader = async ({
182
183
  reader,
183
184
  abort: () => {
184
185
  ownController.abort();
186
+ return Promise.resolve();
185
187
  }
186
188
  },
187
189
  contentLength,
@@ -407,8 +409,7 @@ var nodeReadContent = ({ src, range, controller }) => {
407
409
  const ownController = new AbortController;
408
410
  const stream = createReadStream(src, {
409
411
  start: range === null ? 0 : typeof range === "number" ? range : range[0],
410
- end: range === null ? Infinity : typeof range === "number" ? Infinity : range[1],
411
- signal: ownController.signal
412
+ end: range === null ? Infinity : typeof range === "number" ? Infinity : range[1]
412
413
  });
413
414
  controller._internals.signal.addEventListener("abort", () => {
414
415
  ownController.abort();
@@ -443,8 +444,12 @@ var nodeReadContent = ({ src, range, controller }) => {
443
444
  return Promise.resolve({
444
445
  reader: {
445
446
  reader,
446
- abort: () => {
447
- ownController.abort();
447
+ abort: async () => {
448
+ try {
449
+ stream.destroy();
450
+ ownController.abort();
451
+ await reader.cancel();
452
+ } catch {}
448
453
  }
449
454
  },
450
455
  contentLength: stats.size,
@@ -477,42 +482,29 @@ var webFileReadContent = ({ src, range, controller }) => {
477
482
  if (typeof src === "string" || src instanceof URL) {
478
483
  throw new Error("`inputTypeFileReader` only supports `File` objects");
479
484
  }
480
- const part = range === null ? src : typeof range === "number" ? src.slice(range) : src.slice(range[0], range[1]);
481
- const reader = new FileReader;
482
- reader.readAsArrayBuffer(src);
483
- const ownController = new AbortController;
484
- if (ownController) {
485
- ownController.signal.addEventListener("abort", () => {
486
- reader.abort();
487
- }, { once: true });
488
- }
485
+ const part = range === null ? src : typeof range === "number" ? src.slice(range) : src.slice(range[0], range[1] + 1);
486
+ const stream = part.stream();
487
+ const streamReader = stream.getReader();
489
488
  if (controller) {
490
489
  controller._internals.signal.addEventListener("abort", () => {
491
- ownController.abort();
490
+ streamReader.cancel();
492
491
  }, { once: true });
493
492
  }
494
- return new Promise((resolve, reject) => {
495
- reader.onload = () => {
496
- const stream = part.stream();
497
- const streamReader = stream.getReader();
498
- resolve({
499
- reader: {
500
- reader: streamReader,
501
- abort() {
502
- streamReader.cancel();
503
- ownController.abort();
504
- }
505
- },
506
- contentLength: src.size,
507
- name: src instanceof File ? src.name : src.toString(),
508
- supportsContentRange: true,
509
- contentType: src.type,
510
- needsContentRange: true
511
- });
512
- };
513
- reader.onerror = () => {
514
- reject(reader.error);
515
- };
493
+ return Promise.resolve({
494
+ reader: {
495
+ reader: streamReader,
496
+ async abort() {
497
+ try {
498
+ await streamReader.cancel();
499
+ } catch {}
500
+ return Promise.resolve();
501
+ }
502
+ },
503
+ contentLength: src.size,
504
+ name: src instanceof File ? src.name : src.toString(),
505
+ supportsContentRange: true,
506
+ contentType: src.type,
507
+ needsContentRange: true
516
508
  });
517
509
  };
518
510
  var webFileReadWholeAsText = () => {
@@ -892,7 +884,8 @@ var toMoofBox = (box) => {
892
884
  }
893
885
  return {
894
886
  offset: box.offset,
895
- trafBoxes: box.children.filter((c) => c.type === "regular-box" && c.boxType === "traf")
887
+ trafBoxes: box.children.filter((c) => c.type === "regular-box" && c.boxType === "traf"),
888
+ size: box.boxSize
896
889
  };
897
890
  };
898
891
  var deduplicateMoofBoxesByOffset = (moofBoxes) => {
@@ -1066,13 +1059,16 @@ var getTrunBoxes = (segment) => {
1066
1059
  const trunBoxes = segment.children.filter((c) => c.type === "trun-box");
1067
1060
  return trunBoxes;
1068
1061
  };
1062
+ var getTfraBoxesFromMfraBoxChildren = (mfraBoxChildren) => {
1063
+ const tfraBoxes = mfraBoxChildren.filter((b) => b.type === "tfra-box");
1064
+ return tfraBoxes;
1065
+ };
1069
1066
  var getTfraBoxes = (structure) => {
1070
- const mfraBox = structure.boxes.find((b) => b.type === "regular-box" && b.boxType === "mfra");
1067
+ const mfraBox = structure.find((b) => b.type === "regular-box" && b.boxType === "mfra");
1071
1068
  if (!mfraBox) {
1072
1069
  return [];
1073
1070
  }
1074
- const tfraBoxes = mfraBox.children.filter((b) => b.type === "tfra-box");
1075
- return tfraBoxes;
1071
+ return getTfraBoxesFromMfraBoxChildren(mfraBox.children);
1076
1072
  };
1077
1073
 
1078
1074
  // src/containers/riff/traversal.ts
@@ -4664,6 +4660,17 @@ var getDurationFromFlac = (parserState) => {
4664
4660
  return streaminfo.totalSamples / streaminfo.sampleRate;
4665
4661
  };
4666
4662
 
4663
+ // src/containers/iso-base-media/are-samples-complete.ts
4664
+ var areSamplesComplete = ({
4665
+ moofBoxes,
4666
+ tfraBoxes
4667
+ }) => {
4668
+ if (moofBoxes.length === 0) {
4669
+ return true;
4670
+ }
4671
+ return tfraBoxes.length > 0 && tfraBoxes.every((t) => t.entries.length === moofBoxes.length);
4672
+ };
4673
+
4667
4674
  // src/samples-from-moof.ts
4668
4675
  var getSamplesFromTraf = (trafSegment, moofOffset) => {
4669
4676
  if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
@@ -4737,10 +4744,9 @@ var getSamplesFromMoof = ({
4737
4744
  // src/containers/iso-base-media/collect-sample-positions-from-moof-boxes.ts
4738
4745
  var collectSamplePositionsFromMoofBoxes = ({
4739
4746
  moofBoxes,
4740
- tfraBoxes,
4741
- tkhdBox
4747
+ tkhdBox,
4748
+ isComplete
4742
4749
  }) => {
4743
- const isComplete = tfraBoxes.length > 0 && tfraBoxes.every((t) => t.entries.length === moofBoxes.length);
4744
4750
  const samplePositions = moofBoxes.map((m, index) => {
4745
4751
  const isLastFragment = index === moofBoxes.length - 1 && isComplete;
4746
4752
  return {
@@ -4920,21 +4926,21 @@ var collectSamplePositionsFromTrak = (trakBox) => {
4920
4926
  var getSamplePositionsFromTrack = ({
4921
4927
  trakBox,
4922
4928
  moofBoxes,
4923
- tfraBoxes
4929
+ moofComplete
4924
4930
  }) => {
4925
4931
  const tkhdBox = getTkhdBox(trakBox);
4926
4932
  if (!tkhdBox) {
4927
4933
  throw new Error("Expected tkhd box in trak box");
4928
4934
  }
4929
4935
  if (moofBoxes.length > 0) {
4930
- const { isComplete, samplePositions } = collectSamplePositionsFromMoofBoxes({
4936
+ const { samplePositions } = collectSamplePositionsFromMoofBoxes({
4931
4937
  moofBoxes,
4932
- tfraBoxes,
4933
- tkhdBox
4938
+ tkhdBox,
4939
+ isComplete: moofComplete
4934
4940
  });
4935
4941
  return {
4936
4942
  samplePositions: samplePositions.map((s) => s.samples).flat(1),
4937
- isComplete
4943
+ isComplete: moofComplete
4938
4944
  };
4939
4945
  }
4940
4946
  return {
@@ -5137,6 +5143,20 @@ var getDurationFromWav = (state) => {
5137
5143
  return durationInSeconds;
5138
5144
  };
5139
5145
 
5146
+ // src/state/iso-base-media/precomputed-tfra.ts
5147
+ var precomputedTfraState = () => {
5148
+ let tfraBoxes = [];
5149
+ return {
5150
+ getTfraBoxes: () => tfraBoxes,
5151
+ setTfraBoxes: (boxes) => {
5152
+ tfraBoxes = boxes;
5153
+ }
5154
+ };
5155
+ };
5156
+ var deduplicateTfraBoxesByOffset = (tfraBoxes) => {
5157
+ return tfraBoxes.filter((m, i, arr) => i === arr.findIndex((t) => t.offset === m.offset));
5158
+ };
5159
+
5140
5160
  // src/get-duration.ts
5141
5161
  var getDurationFromMatroska = (segments) => {
5142
5162
  const mainSegment = segments.find((s) => s.type === "Segment");
@@ -5174,7 +5194,14 @@ var getDurationFromIsoBaseMedia = (parserState) => {
5174
5194
  return null;
5175
5195
  }
5176
5196
  const moofBoxes = getMoofBoxes(structure.boxes);
5177
- const tfraBoxes = getTfraBoxes(structure);
5197
+ const mfra = parserState.iso.mfra.getIfAlreadyLoaded();
5198
+ const tfraBoxes = deduplicateTfraBoxesByOffset([
5199
+ ...mfra ? getTfraBoxesFromMfraBoxChildren(mfra) : [],
5200
+ ...getTfraBoxes(structure.boxes)
5201
+ ]);
5202
+ if (!areSamplesComplete({ moofBoxes, tfraBoxes })) {
5203
+ return null;
5204
+ }
5178
5205
  const mvhdBox = getMvhdBox(moovBox);
5179
5206
  if (!mvhdBox) {
5180
5207
  return null;
@@ -5196,7 +5223,7 @@ var getDurationFromIsoBaseMedia = (parserState) => {
5196
5223
  const { samplePositions, isComplete } = getSamplePositionsFromTrack({
5197
5224
  trakBox: t.trakBox,
5198
5225
  moofBoxes,
5199
- tfraBoxes
5226
+ moofComplete: areSamplesComplete({ moofBoxes, tfraBoxes })
5200
5227
  });
5201
5228
  if (!isComplete) {
5202
5229
  return null;
@@ -5253,7 +5280,10 @@ var hasDuration = (parserState) => {
5253
5280
  };
5254
5281
  var hasSlowDuration = (parserState) => {
5255
5282
  try {
5256
- return hasDuration(parserState) && getDuration(parserState) !== null;
5283
+ if (!hasDuration(parserState)) {
5284
+ return false;
5285
+ }
5286
+ return getDuration(parserState) !== null;
5257
5287
  } catch {
5258
5288
  return false;
5259
5289
  }
@@ -5281,13 +5311,16 @@ var getKeyframesFromIsoBaseMedia = (state) => {
5281
5311
  });
5282
5312
  const structure = state.structure.getIsoStructure();
5283
5313
  const moofBoxes = getMoofBoxes(structure.boxes);
5284
- const tfraBoxes = getTfraBoxes(structure);
5314
+ const tfraBoxes = getTfraBoxes(structure.boxes);
5285
5315
  const allSamples = videoTracks.map((t) => {
5286
5316
  const { timescale: ts } = t;
5287
5317
  const { samplePositions, isComplete } = getSamplePositionsFromTrack({
5288
5318
  trakBox: t.trakBox,
5289
5319
  moofBoxes,
5290
- tfraBoxes
5320
+ moofComplete: areSamplesComplete({
5321
+ moofBoxes,
5322
+ tfraBoxes
5323
+ })
5291
5324
  });
5292
5325
  if (!isComplete) {
5293
5326
  return [];
@@ -5740,7 +5773,10 @@ var findAnyTrackWithSamplePositions = (allTracks, struc) => {
5740
5773
  const { samplePositions } = getSamplePositionsFromTrack({
5741
5774
  trakBox: track.trakBox,
5742
5775
  moofBoxes: getMoofBoxes(struc.boxes),
5743
- tfraBoxes: getTfraBoxes(struc)
5776
+ moofComplete: areSamplesComplete({
5777
+ moofBoxes: getMoofBoxes(struc.boxes),
5778
+ tfraBoxes: getTfraBoxes(struc.boxes)
5779
+ })
5744
5780
  });
5745
5781
  if (samplePositions.length === 0) {
5746
5782
  continue;
@@ -5759,7 +5795,10 @@ var findTrackToSeek = (allTracks, structure) => {
5759
5795
  const { samplePositions } = getSamplePositionsFromTrack({
5760
5796
  trakBox: firstVideoTrack.trakBox,
5761
5797
  moofBoxes: getMoofBoxes(struc.boxes),
5762
- tfraBoxes: getTfraBoxes(struc)
5798
+ moofComplete: areSamplesComplete({
5799
+ moofBoxes: getMoofBoxes(struc.boxes),
5800
+ tfraBoxes: getTfraBoxes(struc.boxes)
5801
+ })
5763
5802
  });
5764
5803
  if (samplePositions.length === 0) {
5765
5804
  return findAnyTrackWithSamplePositions(allTracks, struc);
@@ -5899,10 +5938,14 @@ var getSeekingByteFromFragmentedMp4 = async ({
5899
5938
  if (!tkhdBox) {
5900
5939
  throw new Error("Expected tkhd box in trak box");
5901
5940
  }
5941
+ const isComplete = areSamplesComplete({
5942
+ moofBoxes: info.moofBoxes,
5943
+ tfraBoxes: info.tfraBoxes
5944
+ });
5902
5945
  const { samplePositions: samplePositionsArray } = collectSamplePositionsFromMoofBoxes({
5903
5946
  moofBoxes: info.moofBoxes,
5904
- tfraBoxes: info.tfraBoxes,
5905
- tkhdBox
5947
+ tkhdBox,
5948
+ isComplete
5906
5949
  });
5907
5950
  Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
5908
5951
  for (const positions of samplePositionsArray) {
@@ -7125,20 +7168,6 @@ var setSeekingHintsForFlac = ({
7125
7168
  state.flac.audioSamples.setFromSeekingHints(hints.audioSampleMap);
7126
7169
  };
7127
7170
 
7128
- // src/state/iso-base-media/precomputed-tfra.ts
7129
- var precomputedTfraState = () => {
7130
- let tfraBoxes = [];
7131
- return {
7132
- getTfraBoxes: () => tfraBoxes,
7133
- setTfraBoxes: (boxes) => {
7134
- tfraBoxes = boxes;
7135
- }
7136
- };
7137
- };
7138
- var deduplicateTfraBoxesByOffset = (tfraBoxes) => {
7139
- return tfraBoxes.filter((m, i, arr) => i === arr.findIndex((t) => t.offset === m.offset));
7140
- };
7141
-
7142
7171
  // src/containers/iso-base-media/seeking-hints.ts
7143
7172
  var getSeekingHintsFromMp4 = ({
7144
7173
  structureState,
@@ -7159,7 +7188,7 @@ var getSeekingHintsFromMp4 = ({
7159
7188
  ]);
7160
7189
  const tfraBoxes = deduplicateTfraBoxesByOffset([
7161
7190
  ...isoState.tfra.getTfraBoxes(),
7162
- ...getTfraBoxes(structure)
7191
+ ...getTfraBoxes(structure.boxes)
7163
7192
  ]);
7164
7193
  if (!moovAtom) {
7165
7194
  return null;
@@ -7418,6 +7447,7 @@ var seekBackwards = async ({
7418
7447
  }
7419
7448
  const time = Date.now();
7420
7449
  Log.verbose(logLevel, `Seeking in video from position ${iterator.counter.getOffset()} -> ${seekTo}. Re-reading because this portion is not available.`);
7450
+ await currentReader.getCurrent().abort();
7421
7451
  const { reader: newReader } = await readerInterface.read({
7422
7452
  src,
7423
7453
  range: seekTo,
@@ -7512,6 +7542,7 @@ var seekForward = async ({
7512
7542
  }
7513
7543
  const time = Date.now();
7514
7544
  Log.verbose(logLevel, `Skipping over video data from position ${iterator.counter.getOffset()} -> ${seekTo}. Re-reading because this portion is not available`);
7545
+ await currentReader.getCurrent().abort();
7515
7546
  const { reader: newReader } = await readerInterface.read({
7516
7547
  src,
7517
7548
  range: seekTo,
@@ -7892,7 +7923,7 @@ var emitAvailableInfo = async ({
7892
7923
  }
7893
7924
  if (key === "slowFps") {
7894
7925
  if (hasInfo.slowFps && !emittedFields.slowFps) {
7895
- const slowFps = state.samplesObserved.getFps();
7926
+ const slowFps = getFps(state) ?? state.samplesObserved.getFps();
7896
7927
  await callbackFunctions.onSlowFps?.(slowFps);
7897
7928
  if (fieldsInReturnValue.slowFps) {
7898
7929
  returnValue.slowFps = slowFps;
@@ -8188,7 +8219,8 @@ var getAvailableInfo = ({
8188
8219
  return Boolean(structure && hasDuration(state));
8189
8220
  }
8190
8221
  if (key === "slowDurationInSeconds") {
8191
- return Boolean(structure && hasSlowDuration(state));
8222
+ const res = Boolean(structure && hasSlowDuration(state));
8223
+ return res;
8192
8224
  }
8193
8225
  if (key === "dimensions" || key === "rotation" || key === "unrotatedDimensions") {
8194
8226
  return Boolean(structure && hasDimensions(state));
@@ -8866,18 +8898,31 @@ var parseFlac = ({
8866
8898
  };
8867
8899
 
8868
8900
  // src/state/iso-base-media/cached-sample-positions.ts
8869
- var calculateFlatSamples = (state) => {
8901
+ var calculateFlatSamples = ({
8902
+ state,
8903
+ mediaSectionStart
8904
+ }) => {
8870
8905
  const tracks2 = getTracks(state, true);
8871
8906
  const allTracks = [
8872
8907
  ...tracks2.videoTracks,
8873
8908
  ...tracks2.audioTracks,
8874
8909
  ...tracks2.otherTracks
8875
8910
  ];
8911
+ const moofBoxes = getMoofBoxes(state.structure.getIsoStructure().boxes);
8912
+ const tfraBoxes = deduplicateTfraBoxesByOffset([
8913
+ ...state.iso.tfra.getTfraBoxes(),
8914
+ ...getTfraBoxes(state.structure.getIsoStructure().boxes)
8915
+ ]);
8916
+ const moofComplete = areSamplesComplete({ moofBoxes, tfraBoxes });
8917
+ const relevantMoofBox = moofBoxes.find((moofBox) => moofBox.offset + moofBox.size + 8 === mediaSectionStart);
8918
+ if (moofBoxes.length > 0 && !relevantMoofBox) {
8919
+ throw new Error("No relevant moof box found");
8920
+ }
8876
8921
  const flatSamples = allTracks.map((track) => {
8877
8922
  const { samplePositions } = getSamplePositionsFromTrack({
8878
8923
  trakBox: track.trakBox,
8879
- moofBoxes: getMoofBoxes(state.structure.getIsoStructure().boxes),
8880
- tfraBoxes: getTfraBoxes(state.structure.getIsoStructure())
8924
+ moofBoxes: relevantMoofBox ? [relevantMoofBox] : [],
8925
+ moofComplete
8881
8926
  });
8882
8927
  return samplePositions.map((samplePosition) => {
8883
8928
  return {
@@ -8893,10 +8938,7 @@ var cachedSamplePositionsState = () => {
8893
8938
  const jumpMarksForMdatStart = {};
8894
8939
  return {
8895
8940
  getSamples: (mdatStart) => {
8896
- if (cachedForMdatStart[mdatStart]) {
8897
- return cachedForMdatStart[mdatStart];
8898
- }
8899
- return null;
8941
+ return cachedForMdatStart[mdatStart] ?? null;
8900
8942
  },
8901
8943
  setSamples: (mdatStart, samples) => {
8902
8944
  cachedForMdatStart[mdatStart] = samples;
@@ -8910,6 +8952,24 @@ var cachedSamplePositionsState = () => {
8910
8952
  };
8911
8953
  };
8912
8954
 
8955
+ // src/state/iso-base-media/last-moof-box.ts
8956
+ var getLastMoofBox = (boxes) => {
8957
+ if (boxes) {
8958
+ const tfras = boxes.filter((b) => b.type === "tfra-box");
8959
+ const lastMoofOffsets = tfras.map((f) => {
8960
+ if (f.entries.length <= 1) {
8961
+ return null;
8962
+ }
8963
+ return f.entries[f.entries.length - 1].moofOffset;
8964
+ });
8965
+ if (lastMoofOffsets.length > 0) {
8966
+ const maxOffset = Math.max(...lastMoofOffsets.filter(truthy));
8967
+ return maxOffset;
8968
+ }
8969
+ return null;
8970
+ }
8971
+ };
8972
+
8913
8973
  // src/state/can-skip-tracks.ts
8914
8974
  var needsTracksForField = ({
8915
8975
  field,
@@ -10651,13 +10711,13 @@ var processBox = async ({
10651
10711
  if (boxType === "ftyp") {
10652
10712
  return {
10653
10713
  type: "box",
10654
- box: await parseFtyp({ iterator, size: boxSize, offset: fileOffset })
10714
+ box: parseFtyp({ iterator, size: boxSize, offset: fileOffset })
10655
10715
  };
10656
10716
  }
10657
10717
  if (boxType === "colr") {
10658
10718
  return {
10659
10719
  type: "box",
10660
- box: await parseColorParameterBox({
10720
+ box: parseColorParameterBox({
10661
10721
  iterator,
10662
10722
  size: boxSize
10663
10723
  })
@@ -10666,25 +10726,25 @@ var processBox = async ({
10666
10726
  if (boxType === "mvhd") {
10667
10727
  return {
10668
10728
  type: "box",
10669
- box: await parseMvhd({ iterator, offset: fileOffset, size: boxSize })
10729
+ box: parseMvhd({ iterator, offset: fileOffset, size: boxSize })
10670
10730
  };
10671
10731
  }
10672
10732
  if (boxType === "tkhd") {
10673
10733
  return {
10674
10734
  type: "box",
10675
- box: await parseTkhd({ iterator, offset: fileOffset, size: boxSize })
10735
+ box: parseTkhd({ iterator, offset: fileOffset, size: boxSize })
10676
10736
  };
10677
10737
  }
10678
10738
  if (boxType === "trun") {
10679
10739
  return {
10680
10740
  type: "box",
10681
- box: await parseTrun({ iterator, offset: fileOffset, size: boxSize })
10741
+ box: parseTrun({ iterator, offset: fileOffset, size: boxSize })
10682
10742
  };
10683
10743
  }
10684
10744
  if (boxType === "tfdt") {
10685
10745
  return {
10686
10746
  type: "box",
10687
- box: await parseTfdt({ iterator, size: boxSize, offset: fileOffset })
10747
+ box: parseTfdt({ iterator, size: boxSize, offset: fileOffset })
10688
10748
  };
10689
10749
  }
10690
10750
  if (boxType === "stsd") {
@@ -10933,7 +10993,7 @@ var processBox = async ({
10933
10993
  };
10934
10994
  }
10935
10995
  if (boxType === "moof") {
10936
- onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
10996
+ await onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
10937
10997
  }
10938
10998
  if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "stsb") {
10939
10999
  const children = await getIsoBaseMediaChildren({
@@ -11209,6 +11269,14 @@ var parseMdatSection = async (state) => {
11209
11269
  }
11210
11270
  const endOfMdat = mediaSection.size + mediaSection.start;
11211
11271
  if (maySkipVideoData({ state })) {
11272
+ const mfra = state.iso.mfra.getIfAlreadyLoaded();
11273
+ if (mfra) {
11274
+ const lastMoof = getLastMoofBox(mfra);
11275
+ if (lastMoof && lastMoof > endOfMdat) {
11276
+ Log.verbose(state.logLevel, "Skipping to last moof", lastMoof, "end of mdat", endOfMdat);
11277
+ return makeSkip(lastMoof);
11278
+ }
11279
+ }
11212
11280
  return makeSkip(endOfMdat);
11213
11281
  }
11214
11282
  const alreadyHasMoov = getHasTracks(state, true);
@@ -11226,7 +11294,10 @@ var parseMdatSection = async (state) => {
11226
11294
  return parseMdatSection(state);
11227
11295
  }
11228
11296
  if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
11229
- const flattedSamples = calculateFlatSamples(state);
11297
+ const flattedSamples = calculateFlatSamples({
11298
+ state,
11299
+ mediaSectionStart: mediaSection.start
11300
+ });
11230
11301
  const calcedJumpMarks = calculateJumpMarks(flattedSamples, endOfMdat);
11231
11302
  state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
11232
11303
  state.iso.flatSamples.setSamples(mediaSection.start, flattedSamples.flat(1));
@@ -11243,9 +11314,11 @@ var parseMdatSection = async (state) => {
11243
11314
  iterator.discard(nextSample_.samplePosition.offset - iterator.counter.getOffset());
11244
11315
  return null;
11245
11316
  }
11317
+ Log.verbose(state.logLevel, "Could not find sample at offset", iterator.counter.getOffset(), "skipping to end of mdat");
11246
11318
  return makeSkip(endOfMdat);
11247
11319
  }
11248
11320
  if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
11321
+ Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size, endOfMdat);
11249
11322
  return makeSkip(endOfMdat);
11250
11323
  }
11251
11324
  if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
@@ -11299,6 +11372,7 @@ var parseMdatSection = async (state) => {
11299
11372
  }
11300
11373
  const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
11301
11374
  if (jump) {
11375
+ Log.verbose(state.logLevel, "Found jump mark", jump.jumpToOffset, "skipping to jump mark");
11302
11376
  return makeSkip(jump.jumpToOffset);
11303
11377
  }
11304
11378
  return null;
@@ -16682,6 +16756,7 @@ var makeParserState = ({
16682
16756
  fields: fieldsInReturnValue,
16683
16757
  callbacks
16684
16758
  });
16759
+ const mediaSection = mediaSectionState();
16685
16760
  return {
16686
16761
  riff: riffSpecificState({
16687
16762
  controller,
@@ -16739,7 +16814,7 @@ var makeParserState = ({
16739
16814
  samplesObserved,
16740
16815
  contentLength,
16741
16816
  images,
16742
- mediaSection: mediaSectionState(),
16817
+ mediaSection,
16743
16818
  logLevel,
16744
16819
  iterator,
16745
16820
  controller,