@remotion/media-parser 4.0.292 → 4.0.294

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
@@ -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,
@@ -402,42 +404,29 @@ var webFileReadContent = ({ src, range, controller }) => {
402
404
  if (typeof src === "string" || src instanceof URL) {
403
405
  throw new Error("`inputTypeFileReader` only supports `File` objects");
404
406
  }
405
- const part = range === null ? src : typeof range === "number" ? src.slice(range) : src.slice(range[0], range[1]);
406
- const reader = new FileReader;
407
- reader.readAsArrayBuffer(src);
408
- const ownController = new AbortController;
409
- if (ownController) {
410
- ownController.signal.addEventListener("abort", () => {
411
- reader.abort();
412
- }, { once: true });
413
- }
407
+ const part = range === null ? src : typeof range === "number" ? src.slice(range) : src.slice(range[0], range[1] + 1);
408
+ const stream = part.stream();
409
+ const streamReader = stream.getReader();
414
410
  if (controller) {
415
411
  controller._internals.signal.addEventListener("abort", () => {
416
- ownController.abort();
412
+ streamReader.cancel();
417
413
  }, { once: true });
418
414
  }
419
- return new Promise((resolve, reject) => {
420
- reader.onload = () => {
421
- const stream = part.stream();
422
- const streamReader = stream.getReader();
423
- resolve({
424
- reader: {
425
- reader: streamReader,
426
- abort() {
427
- streamReader.cancel();
428
- ownController.abort();
429
- }
430
- },
431
- contentLength: src.size,
432
- name: src instanceof File ? src.name : src.toString(),
433
- supportsContentRange: true,
434
- contentType: src.type,
435
- needsContentRange: true
436
- });
437
- };
438
- reader.onerror = () => {
439
- reject(reader.error);
440
- };
415
+ return Promise.resolve({
416
+ reader: {
417
+ reader: streamReader,
418
+ async abort() {
419
+ try {
420
+ await streamReader.cancel();
421
+ } catch {}
422
+ return Promise.resolve();
423
+ }
424
+ },
425
+ contentLength: src.size,
426
+ name: src instanceof File ? src.name : src.toString(),
427
+ supportsContentRange: true,
428
+ contentType: src.type,
429
+ needsContentRange: true
441
430
  });
442
431
  };
443
432
  var webFileReadWholeAsText = () => {
@@ -807,7 +796,8 @@ var toMoofBox = (box) => {
807
796
  }
808
797
  return {
809
798
  offset: box.offset,
810
- trafBoxes: box.children.filter((c) => c.type === "regular-box" && c.boxType === "traf")
799
+ trafBoxes: box.children.filter((c) => c.type === "regular-box" && c.boxType === "traf"),
800
+ size: box.boxSize
811
801
  };
812
802
  };
813
803
  var deduplicateMoofBoxesByOffset = (moofBoxes) => {
@@ -981,13 +971,16 @@ var getTrunBoxes = (segment) => {
981
971
  const trunBoxes = segment.children.filter((c) => c.type === "trun-box");
982
972
  return trunBoxes;
983
973
  };
974
+ var getTfraBoxesFromMfraBoxChildren = (mfraBoxChildren) => {
975
+ const tfraBoxes = mfraBoxChildren.filter((b) => b.type === "tfra-box");
976
+ return tfraBoxes;
977
+ };
984
978
  var getTfraBoxes = (structure) => {
985
- const mfraBox = structure.boxes.find((b) => b.type === "regular-box" && b.boxType === "mfra");
979
+ const mfraBox = structure.find((b) => b.type === "regular-box" && b.boxType === "mfra");
986
980
  if (!mfraBox) {
987
981
  return [];
988
982
  }
989
- const tfraBoxes = mfraBox.children.filter((b) => b.type === "tfra-box");
990
- return tfraBoxes;
983
+ return getTfraBoxesFromMfraBoxChildren(mfraBox.children);
991
984
  };
992
985
 
993
986
  // src/containers/riff/traversal.ts
@@ -4579,6 +4572,17 @@ var getDurationFromFlac = (parserState) => {
4579
4572
  return streaminfo.totalSamples / streaminfo.sampleRate;
4580
4573
  };
4581
4574
 
4575
+ // src/containers/iso-base-media/are-samples-complete.ts
4576
+ var areSamplesComplete = ({
4577
+ moofBoxes,
4578
+ tfraBoxes
4579
+ }) => {
4580
+ if (moofBoxes.length === 0) {
4581
+ return true;
4582
+ }
4583
+ return tfraBoxes.length > 0 && tfraBoxes.every((t) => t.entries.length === moofBoxes.length);
4584
+ };
4585
+
4582
4586
  // src/samples-from-moof.ts
4583
4587
  var getSamplesFromTraf = (trafSegment, moofOffset) => {
4584
4588
  if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
@@ -4652,10 +4656,9 @@ var getSamplesFromMoof = ({
4652
4656
  // src/containers/iso-base-media/collect-sample-positions-from-moof-boxes.ts
4653
4657
  var collectSamplePositionsFromMoofBoxes = ({
4654
4658
  moofBoxes,
4655
- tfraBoxes,
4656
- tkhdBox
4659
+ tkhdBox,
4660
+ isComplete
4657
4661
  }) => {
4658
- const isComplete = tfraBoxes.length > 0 && tfraBoxes.every((t) => t.entries.length === moofBoxes.length);
4659
4662
  const samplePositions = moofBoxes.map((m, index) => {
4660
4663
  const isLastFragment = index === moofBoxes.length - 1 && isComplete;
4661
4664
  return {
@@ -4835,21 +4838,21 @@ var collectSamplePositionsFromTrak = (trakBox) => {
4835
4838
  var getSamplePositionsFromTrack = ({
4836
4839
  trakBox,
4837
4840
  moofBoxes,
4838
- tfraBoxes
4841
+ moofComplete
4839
4842
  }) => {
4840
4843
  const tkhdBox = getTkhdBox(trakBox);
4841
4844
  if (!tkhdBox) {
4842
4845
  throw new Error("Expected tkhd box in trak box");
4843
4846
  }
4844
4847
  if (moofBoxes.length > 0) {
4845
- const { isComplete, samplePositions } = collectSamplePositionsFromMoofBoxes({
4848
+ const { samplePositions } = collectSamplePositionsFromMoofBoxes({
4846
4849
  moofBoxes,
4847
- tfraBoxes,
4848
- tkhdBox
4850
+ tkhdBox,
4851
+ isComplete: moofComplete
4849
4852
  });
4850
4853
  return {
4851
4854
  samplePositions: samplePositions.map((s) => s.samples).flat(1),
4852
- isComplete
4855
+ isComplete: moofComplete
4853
4856
  };
4854
4857
  }
4855
4858
  return {
@@ -5052,6 +5055,20 @@ var getDurationFromWav = (state) => {
5052
5055
  return durationInSeconds;
5053
5056
  };
5054
5057
 
5058
+ // src/state/iso-base-media/precomputed-tfra.ts
5059
+ var precomputedTfraState = () => {
5060
+ let tfraBoxes = [];
5061
+ return {
5062
+ getTfraBoxes: () => tfraBoxes,
5063
+ setTfraBoxes: (boxes) => {
5064
+ tfraBoxes = boxes;
5065
+ }
5066
+ };
5067
+ };
5068
+ var deduplicateTfraBoxesByOffset = (tfraBoxes) => {
5069
+ return tfraBoxes.filter((m, i, arr) => i === arr.findIndex((t) => t.offset === m.offset));
5070
+ };
5071
+
5055
5072
  // src/get-duration.ts
5056
5073
  var getDurationFromMatroska = (segments) => {
5057
5074
  const mainSegment = segments.find((s) => s.type === "Segment");
@@ -5089,7 +5106,14 @@ var getDurationFromIsoBaseMedia = (parserState) => {
5089
5106
  return null;
5090
5107
  }
5091
5108
  const moofBoxes = getMoofBoxes(structure.boxes);
5092
- const tfraBoxes = getTfraBoxes(structure);
5109
+ const mfra = parserState.iso.mfra.getIfAlreadyLoaded();
5110
+ const tfraBoxes = deduplicateTfraBoxesByOffset([
5111
+ ...mfra ? getTfraBoxesFromMfraBoxChildren(mfra) : [],
5112
+ ...getTfraBoxes(structure.boxes)
5113
+ ]);
5114
+ if (!areSamplesComplete({ moofBoxes, tfraBoxes })) {
5115
+ return null;
5116
+ }
5093
5117
  const mvhdBox = getMvhdBox(moovBox);
5094
5118
  if (!mvhdBox) {
5095
5119
  return null;
@@ -5111,7 +5135,7 @@ var getDurationFromIsoBaseMedia = (parserState) => {
5111
5135
  const { samplePositions, isComplete } = getSamplePositionsFromTrack({
5112
5136
  trakBox: t.trakBox,
5113
5137
  moofBoxes,
5114
- tfraBoxes
5138
+ moofComplete: areSamplesComplete({ moofBoxes, tfraBoxes })
5115
5139
  });
5116
5140
  if (!isComplete) {
5117
5141
  return null;
@@ -5168,7 +5192,10 @@ var hasDuration = (parserState) => {
5168
5192
  };
5169
5193
  var hasSlowDuration = (parserState) => {
5170
5194
  try {
5171
- return hasDuration(parserState) && getDuration(parserState) !== null;
5195
+ if (!hasDuration(parserState)) {
5196
+ return false;
5197
+ }
5198
+ return getDuration(parserState) !== null;
5172
5199
  } catch {
5173
5200
  return false;
5174
5201
  }
@@ -5196,13 +5223,16 @@ var getKeyframesFromIsoBaseMedia = (state) => {
5196
5223
  });
5197
5224
  const structure = state.structure.getIsoStructure();
5198
5225
  const moofBoxes = getMoofBoxes(structure.boxes);
5199
- const tfraBoxes = getTfraBoxes(structure);
5226
+ const tfraBoxes = getTfraBoxes(structure.boxes);
5200
5227
  const allSamples = videoTracks.map((t) => {
5201
5228
  const { timescale: ts } = t;
5202
5229
  const { samplePositions, isComplete } = getSamplePositionsFromTrack({
5203
5230
  trakBox: t.trakBox,
5204
5231
  moofBoxes,
5205
- tfraBoxes
5232
+ moofComplete: areSamplesComplete({
5233
+ moofBoxes,
5234
+ tfraBoxes
5235
+ })
5206
5236
  });
5207
5237
  if (!isComplete) {
5208
5238
  return [];
@@ -5655,7 +5685,10 @@ var findAnyTrackWithSamplePositions = (allTracks, struc) => {
5655
5685
  const { samplePositions } = getSamplePositionsFromTrack({
5656
5686
  trakBox: track.trakBox,
5657
5687
  moofBoxes: getMoofBoxes(struc.boxes),
5658
- tfraBoxes: getTfraBoxes(struc)
5688
+ moofComplete: areSamplesComplete({
5689
+ moofBoxes: getMoofBoxes(struc.boxes),
5690
+ tfraBoxes: getTfraBoxes(struc.boxes)
5691
+ })
5659
5692
  });
5660
5693
  if (samplePositions.length === 0) {
5661
5694
  continue;
@@ -5674,7 +5707,10 @@ var findTrackToSeek = (allTracks, structure) => {
5674
5707
  const { samplePositions } = getSamplePositionsFromTrack({
5675
5708
  trakBox: firstVideoTrack.trakBox,
5676
5709
  moofBoxes: getMoofBoxes(struc.boxes),
5677
- tfraBoxes: getTfraBoxes(struc)
5710
+ moofComplete: areSamplesComplete({
5711
+ moofBoxes: getMoofBoxes(struc.boxes),
5712
+ tfraBoxes: getTfraBoxes(struc.boxes)
5713
+ })
5678
5714
  });
5679
5715
  if (samplePositions.length === 0) {
5680
5716
  return findAnyTrackWithSamplePositions(allTracks, struc);
@@ -5814,10 +5850,14 @@ var getSeekingByteFromFragmentedMp4 = async ({
5814
5850
  if (!tkhdBox) {
5815
5851
  throw new Error("Expected tkhd box in trak box");
5816
5852
  }
5853
+ const isComplete = areSamplesComplete({
5854
+ moofBoxes: info.moofBoxes,
5855
+ tfraBoxes: info.tfraBoxes
5856
+ });
5817
5857
  const { samplePositions: samplePositionsArray } = collectSamplePositionsFromMoofBoxes({
5818
5858
  moofBoxes: info.moofBoxes,
5819
- tfraBoxes: info.tfraBoxes,
5820
- tkhdBox
5859
+ tkhdBox,
5860
+ isComplete
5821
5861
  });
5822
5862
  Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
5823
5863
  for (const positions of samplePositionsArray) {
@@ -7040,20 +7080,6 @@ var setSeekingHintsForFlac = ({
7040
7080
  state.flac.audioSamples.setFromSeekingHints(hints.audioSampleMap);
7041
7081
  };
7042
7082
 
7043
- // src/state/iso-base-media/precomputed-tfra.ts
7044
- var precomputedTfraState = () => {
7045
- let tfraBoxes = [];
7046
- return {
7047
- getTfraBoxes: () => tfraBoxes,
7048
- setTfraBoxes: (boxes) => {
7049
- tfraBoxes = boxes;
7050
- }
7051
- };
7052
- };
7053
- var deduplicateTfraBoxesByOffset = (tfraBoxes) => {
7054
- return tfraBoxes.filter((m, i, arr) => i === arr.findIndex((t) => t.offset === m.offset));
7055
- };
7056
-
7057
7083
  // src/containers/iso-base-media/seeking-hints.ts
7058
7084
  var getSeekingHintsFromMp4 = ({
7059
7085
  structureState,
@@ -7074,7 +7100,7 @@ var getSeekingHintsFromMp4 = ({
7074
7100
  ]);
7075
7101
  const tfraBoxes = deduplicateTfraBoxesByOffset([
7076
7102
  ...isoState.tfra.getTfraBoxes(),
7077
- ...getTfraBoxes(structure)
7103
+ ...getTfraBoxes(structure.boxes)
7078
7104
  ]);
7079
7105
  if (!moovAtom) {
7080
7106
  return null;
@@ -7333,6 +7359,7 @@ var seekBackwards = async ({
7333
7359
  }
7334
7360
  const time = Date.now();
7335
7361
  Log.verbose(logLevel, `Seeking in video from position ${iterator.counter.getOffset()} -> ${seekTo}. Re-reading because this portion is not available.`);
7362
+ await currentReader.getCurrent().abort();
7336
7363
  const { reader: newReader } = await readerInterface.read({
7337
7364
  src,
7338
7365
  range: seekTo,
@@ -7427,6 +7454,7 @@ var seekForward = async ({
7427
7454
  }
7428
7455
  const time = Date.now();
7429
7456
  Log.verbose(logLevel, `Skipping over video data from position ${iterator.counter.getOffset()} -> ${seekTo}. Re-reading because this portion is not available`);
7457
+ await currentReader.getCurrent().abort();
7430
7458
  const { reader: newReader } = await readerInterface.read({
7431
7459
  src,
7432
7460
  range: seekTo,
@@ -7807,7 +7835,7 @@ var emitAvailableInfo = async ({
7807
7835
  }
7808
7836
  if (key === "slowFps") {
7809
7837
  if (hasInfo.slowFps && !emittedFields.slowFps) {
7810
- const slowFps = state.samplesObserved.getFps();
7838
+ const slowFps = getFps(state) ?? state.samplesObserved.getFps();
7811
7839
  await callbackFunctions.onSlowFps?.(slowFps);
7812
7840
  if (fieldsInReturnValue.slowFps) {
7813
7841
  returnValue.slowFps = slowFps;
@@ -8103,7 +8131,8 @@ var getAvailableInfo = ({
8103
8131
  return Boolean(structure && hasDuration(state));
8104
8132
  }
8105
8133
  if (key === "slowDurationInSeconds") {
8106
- return Boolean(structure && hasSlowDuration(state));
8134
+ const res = Boolean(structure && hasSlowDuration(state));
8135
+ return res;
8107
8136
  }
8108
8137
  if (key === "dimensions" || key === "rotation" || key === "unrotatedDimensions") {
8109
8138
  return Boolean(structure && hasDimensions(state));
@@ -8781,18 +8810,31 @@ var parseFlac = ({
8781
8810
  };
8782
8811
 
8783
8812
  // src/state/iso-base-media/cached-sample-positions.ts
8784
- var calculateFlatSamples = (state) => {
8813
+ var calculateFlatSamples = ({
8814
+ state,
8815
+ mediaSectionStart
8816
+ }) => {
8785
8817
  const tracks2 = getTracks(state, true);
8786
8818
  const allTracks = [
8787
8819
  ...tracks2.videoTracks,
8788
8820
  ...tracks2.audioTracks,
8789
8821
  ...tracks2.otherTracks
8790
8822
  ];
8823
+ const moofBoxes = getMoofBoxes(state.structure.getIsoStructure().boxes);
8824
+ const tfraBoxes = deduplicateTfraBoxesByOffset([
8825
+ ...state.iso.tfra.getTfraBoxes(),
8826
+ ...getTfraBoxes(state.structure.getIsoStructure().boxes)
8827
+ ]);
8828
+ const moofComplete = areSamplesComplete({ moofBoxes, tfraBoxes });
8829
+ const relevantMoofBox = moofBoxes.find((moofBox) => moofBox.offset + moofBox.size + 8 === mediaSectionStart);
8830
+ if (moofBoxes.length > 0 && !relevantMoofBox) {
8831
+ throw new Error("No relevant moof box found");
8832
+ }
8791
8833
  const flatSamples = allTracks.map((track) => {
8792
8834
  const { samplePositions } = getSamplePositionsFromTrack({
8793
8835
  trakBox: track.trakBox,
8794
- moofBoxes: getMoofBoxes(state.structure.getIsoStructure().boxes),
8795
- tfraBoxes: getTfraBoxes(state.structure.getIsoStructure())
8836
+ moofBoxes: relevantMoofBox ? [relevantMoofBox] : [],
8837
+ moofComplete
8796
8838
  });
8797
8839
  return samplePositions.map((samplePosition) => {
8798
8840
  return {
@@ -8808,10 +8850,7 @@ var cachedSamplePositionsState = () => {
8808
8850
  const jumpMarksForMdatStart = {};
8809
8851
  return {
8810
8852
  getSamples: (mdatStart) => {
8811
- if (cachedForMdatStart[mdatStart]) {
8812
- return cachedForMdatStart[mdatStart];
8813
- }
8814
- return null;
8853
+ return cachedForMdatStart[mdatStart] ?? null;
8815
8854
  },
8816
8855
  setSamples: (mdatStart, samples) => {
8817
8856
  cachedForMdatStart[mdatStart] = samples;
@@ -8825,6 +8864,24 @@ var cachedSamplePositionsState = () => {
8825
8864
  };
8826
8865
  };
8827
8866
 
8867
+ // src/state/iso-base-media/last-moof-box.ts
8868
+ var getLastMoofBox = (boxes) => {
8869
+ if (boxes) {
8870
+ const tfras = boxes.filter((b) => b.type === "tfra-box");
8871
+ const lastMoofOffsets = tfras.map((f) => {
8872
+ if (f.entries.length <= 1) {
8873
+ return null;
8874
+ }
8875
+ return f.entries[f.entries.length - 1].moofOffset;
8876
+ });
8877
+ if (lastMoofOffsets.length > 0) {
8878
+ const maxOffset = Math.max(...lastMoofOffsets.filter(truthy));
8879
+ return maxOffset;
8880
+ }
8881
+ return null;
8882
+ }
8883
+ };
8884
+
8828
8885
  // src/state/can-skip-tracks.ts
8829
8886
  var needsTracksForField = ({
8830
8887
  field,
@@ -10566,13 +10623,13 @@ var processBox = async ({
10566
10623
  if (boxType === "ftyp") {
10567
10624
  return {
10568
10625
  type: "box",
10569
- box: await parseFtyp({ iterator, size: boxSize, offset: fileOffset })
10626
+ box: parseFtyp({ iterator, size: boxSize, offset: fileOffset })
10570
10627
  };
10571
10628
  }
10572
10629
  if (boxType === "colr") {
10573
10630
  return {
10574
10631
  type: "box",
10575
- box: await parseColorParameterBox({
10632
+ box: parseColorParameterBox({
10576
10633
  iterator,
10577
10634
  size: boxSize
10578
10635
  })
@@ -10581,25 +10638,25 @@ var processBox = async ({
10581
10638
  if (boxType === "mvhd") {
10582
10639
  return {
10583
10640
  type: "box",
10584
- box: await parseMvhd({ iterator, offset: fileOffset, size: boxSize })
10641
+ box: parseMvhd({ iterator, offset: fileOffset, size: boxSize })
10585
10642
  };
10586
10643
  }
10587
10644
  if (boxType === "tkhd") {
10588
10645
  return {
10589
10646
  type: "box",
10590
- box: await parseTkhd({ iterator, offset: fileOffset, size: boxSize })
10647
+ box: parseTkhd({ iterator, offset: fileOffset, size: boxSize })
10591
10648
  };
10592
10649
  }
10593
10650
  if (boxType === "trun") {
10594
10651
  return {
10595
10652
  type: "box",
10596
- box: await parseTrun({ iterator, offset: fileOffset, size: boxSize })
10653
+ box: parseTrun({ iterator, offset: fileOffset, size: boxSize })
10597
10654
  };
10598
10655
  }
10599
10656
  if (boxType === "tfdt") {
10600
10657
  return {
10601
10658
  type: "box",
10602
- box: await parseTfdt({ iterator, size: boxSize, offset: fileOffset })
10659
+ box: parseTfdt({ iterator, size: boxSize, offset: fileOffset })
10603
10660
  };
10604
10661
  }
10605
10662
  if (boxType === "stsd") {
@@ -10848,7 +10905,7 @@ var processBox = async ({
10848
10905
  };
10849
10906
  }
10850
10907
  if (boxType === "moof") {
10851
- onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
10908
+ await onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
10852
10909
  }
10853
10910
  if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "stsb") {
10854
10911
  const children = await getIsoBaseMediaChildren({
@@ -11124,6 +11181,14 @@ var parseMdatSection = async (state) => {
11124
11181
  }
11125
11182
  const endOfMdat = mediaSection.size + mediaSection.start;
11126
11183
  if (maySkipVideoData({ state })) {
11184
+ const mfra = state.iso.mfra.getIfAlreadyLoaded();
11185
+ if (mfra) {
11186
+ const lastMoof = getLastMoofBox(mfra);
11187
+ if (lastMoof && lastMoof > endOfMdat) {
11188
+ Log.verbose(state.logLevel, "Skipping to last moof", lastMoof, "end of mdat", endOfMdat);
11189
+ return makeSkip(lastMoof);
11190
+ }
11191
+ }
11127
11192
  return makeSkip(endOfMdat);
11128
11193
  }
11129
11194
  const alreadyHasMoov = getHasTracks(state, true);
@@ -11141,7 +11206,10 @@ var parseMdatSection = async (state) => {
11141
11206
  return parseMdatSection(state);
11142
11207
  }
11143
11208
  if (!state.iso.flatSamples.getSamples(mediaSection.start)) {
11144
- const flattedSamples = calculateFlatSamples(state);
11209
+ const flattedSamples = calculateFlatSamples({
11210
+ state,
11211
+ mediaSectionStart: mediaSection.start
11212
+ });
11145
11213
  const calcedJumpMarks = calculateJumpMarks(flattedSamples, endOfMdat);
11146
11214
  state.iso.flatSamples.setJumpMarks(mediaSection.start, calcedJumpMarks);
11147
11215
  state.iso.flatSamples.setSamples(mediaSection.start, flattedSamples.flat(1));
@@ -11158,9 +11226,11 @@ var parseMdatSection = async (state) => {
11158
11226
  iterator.discard(nextSample_.samplePosition.offset - iterator.counter.getOffset());
11159
11227
  return null;
11160
11228
  }
11229
+ Log.verbose(state.logLevel, "Could not find sample at offset", iterator.counter.getOffset(), "skipping to end of mdat");
11161
11230
  return makeSkip(endOfMdat);
11162
11231
  }
11163
11232
  if (samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size > state.contentLength) {
11233
+ Log.verbose(state.logLevel, "Sample is beyond the end of the file. Don't process it.", samplesWithIndex.samplePosition.offset + samplesWithIndex.samplePosition.size, endOfMdat);
11164
11234
  return makeSkip(endOfMdat);
11165
11235
  }
11166
11236
  if (iterator.bytesRemaining() < samplesWithIndex.samplePosition.size) {
@@ -11214,6 +11284,7 @@ var parseMdatSection = async (state) => {
11214
11284
  }
11215
11285
  const jump = jumpMarks.find((j) => j.afterSampleWithOffset === offset);
11216
11286
  if (jump) {
11287
+ Log.verbose(state.logLevel, "Found jump mark", jump.jumpToOffset, "skipping to jump mark");
11217
11288
  return makeSkip(jump.jumpToOffset);
11218
11289
  }
11219
11290
  return null;
@@ -16569,6 +16640,7 @@ var makeParserState = ({
16569
16640
  fields: fieldsInReturnValue,
16570
16641
  callbacks
16571
16642
  });
16643
+ const mediaSection = mediaSectionState();
16572
16644
  return {
16573
16645
  riff: riffSpecificState({
16574
16646
  controller,
@@ -16626,7 +16698,7 @@ var makeParserState = ({
16626
16698
  samplesObserved,
16627
16699
  contentLength,
16628
16700
  images,
16629
- mediaSection: mediaSectionState(),
16701
+ mediaSection,
16630
16702
  logLevel,
16631
16703
  iterator,
16632
16704
  controller,
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.hasSlowDuration = exports.hasDuration = exports.getDuration = exports.isMatroska = void 0;
4
4
  const get_duration_from_flac_1 = require("./containers/flac/get-duration-from-flac");
5
+ const are_samples_complete_1 = require("./containers/iso-base-media/are-samples-complete");
5
6
  const get_sample_positions_from_track_1 = require("./containers/iso-base-media/get-sample-positions-from-track");
6
7
  const traversal_1 = require("./containers/iso-base-media/traversal");
7
8
  const get_duration_from_m3u_1 = require("./containers/m3u/get-duration-from-m3u");
@@ -9,6 +10,7 @@ const get_duration_1 = require("./containers/mp3/get-duration");
9
10
  const get_duration_2 = require("./containers/riff/get-duration");
10
11
  const get_duration_from_wav_1 = require("./containers/wav/get-duration-from-wav");
11
12
  const get_tracks_1 = require("./get-tracks");
13
+ const precomputed_tfra_1 = require("./state/iso-base-media/precomputed-tfra");
12
14
  const getDurationFromMatroska = (segments) => {
13
15
  const mainSegment = segments.find((s) => s.type === 'Segment');
14
16
  if (!mainSegment || mainSegment.type !== 'Segment') {
@@ -51,7 +53,14 @@ const getDurationFromIsoBaseMedia = (parserState) => {
51
53
  return null;
52
54
  }
53
55
  const moofBoxes = (0, traversal_1.getMoofBoxes)(structure.boxes);
54
- const tfraBoxes = (0, traversal_1.getTfraBoxes)(structure);
56
+ const mfra = parserState.iso.mfra.getIfAlreadyLoaded();
57
+ const tfraBoxes = (0, precomputed_tfra_1.deduplicateTfraBoxesByOffset)([
58
+ ...(mfra ? (0, traversal_1.getTfraBoxesFromMfraBoxChildren)(mfra) : []),
59
+ ...(0, traversal_1.getTfraBoxes)(structure.boxes),
60
+ ]);
61
+ if (!(0, are_samples_complete_1.areSamplesComplete)({ moofBoxes, tfraBoxes })) {
62
+ return null;
63
+ }
55
64
  const mvhdBox = (0, traversal_1.getMvhdBox)(moovBox);
56
65
  if (!mvhdBox) {
57
66
  return null;
@@ -73,7 +82,7 @@ const getDurationFromIsoBaseMedia = (parserState) => {
73
82
  const { samplePositions, isComplete } = (0, get_sample_positions_from_track_1.getSamplePositionsFromTrack)({
74
83
  trakBox: t.trakBox,
75
84
  moofBoxes,
76
- tfraBoxes,
85
+ moofComplete: (0, are_samples_complete_1.areSamplesComplete)({ moofBoxes, tfraBoxes }),
77
86
  });
78
87
  if (!isComplete) {
79
88
  return null;
@@ -136,7 +145,10 @@ exports.hasDuration = hasDuration;
136
145
  // Unless it it somewhere in the metadata and is non-null
137
146
  const hasSlowDuration = (parserState) => {
138
147
  try {
139
- return (0, exports.hasDuration)(parserState) && (0, exports.getDuration)(parserState) !== null;
148
+ if (!(0, exports.hasDuration)(parserState)) {
149
+ return false;
150
+ }
151
+ return (0, exports.getDuration)(parserState) !== null;
140
152
  }
141
153
  catch (_a) {
142
154
  return false;
@@ -27,7 +27,8 @@ const getAvailableInfo = ({ state, }) => {
27
27
  return Boolean(structure && (0, get_duration_1.hasDuration)(state));
28
28
  }
29
29
  if (key === 'slowDurationInSeconds') {
30
- return Boolean(structure && (0, get_duration_1.hasSlowDuration)(state));
30
+ const res = Boolean(structure && (0, get_duration_1.hasSlowDuration)(state));
31
+ return res;
31
32
  }
32
33
  if (key === 'dimensions' ||
33
34
  key === 'rotation' ||
package/dist/index.d.ts CHANGED
@@ -858,7 +858,7 @@ export declare const MediaParserInternals: {
858
858
  };
859
859
  iso: {
860
860
  flatSamples: {
861
- getSamples: (mdatStart: number) => import("./state/iso-base-media/cached-sample-positions").FlatSample[] | null;
861
+ getSamples: (mdatStart: number) => import("./state/iso-base-media/cached-sample-positions").FlatSample[];
862
862
  setSamples: (mdatStart: number, samples: import("./state/iso-base-media/cached-sample-positions").FlatSample[]) => void;
863
863
  setJumpMarks: (mdatStart: number, marks: import("./containers/iso-base-media/mdat/calculate-jump-marks").JumpMark[]) => void;
864
864
  getJumpMarks: (mdatStart: number) => import("./containers/iso-base-media/mdat/calculate-jump-marks").JumpMark[];
@@ -33,8 +33,9 @@ const getLengthAndReader = async ({ canLiveWithoutContentLength, res, ownControl
33
33
  contentLength: encoded.byteLength,
34
34
  reader: {
35
35
  reader: stream.getReader(),
36
- abort() {
36
+ abort: () => {
37
37
  ownController.abort();
38
+ return Promise.resolve();
38
39
  },
39
40
  },
40
41
  needsContentRange: false,
@@ -49,6 +50,7 @@ const getLengthAndReader = async ({ canLiveWithoutContentLength, res, ownControl
49
50
  reader,
50
51
  abort: () => {
51
52
  ownController.abort();
53
+ return Promise.resolve();
52
54
  },
53
55
  },
54
56
  contentLength,
@@ -15,7 +15,6 @@ const nodeReadContent = ({ src, range, controller }) => {
15
15
  : typeof range === 'number'
16
16
  ? Infinity
17
17
  : range[1],
18
- signal: ownController.signal,
19
18
  });
20
19
  controller._internals.signal.addEventListener('abort', () => {
21
20
  ownController.abort();
@@ -50,8 +49,13 @@ const nodeReadContent = ({ src, range, controller }) => {
50
49
  return Promise.resolve({
51
50
  reader: {
52
51
  reader,
53
- abort: () => {
54
- ownController.abort();
52
+ abort: async () => {
53
+ try {
54
+ stream.destroy();
55
+ ownController.abort();
56
+ await reader.cancel();
57
+ }
58
+ catch (_a) { }
55
59
  },
56
60
  },
57
61
  contentLength: stats.size,