@remotion/media-parser 4.0.311 → 4.0.313

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 (57) hide show
  1. package/dist/containers/aac/get-seeking-byte.js +5 -1
  2. package/dist/containers/flac/get-seeking-byte.d.ts +2 -1
  3. package/dist/containers/flac/get-seeking-byte.js +1 -1
  4. package/dist/containers/iso-base-media/base-media-box.d.ts +3 -2
  5. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.d.ts +3 -1
  6. package/dist/containers/iso-base-media/collect-sample-positions-from-moof-boxes.js +2 -1
  7. package/dist/containers/iso-base-media/find-keyframe-before-time.d.ts +1 -1
  8. package/dist/containers/iso-base-media/find-keyframe-before-time.js +1 -1
  9. package/dist/containers/iso-base-media/find-track-to-seek.js +2 -0
  10. package/dist/containers/iso-base-media/get-keyframes.js +1 -0
  11. package/dist/containers/iso-base-media/get-sample-positions-from-track.d.ts +3 -1
  12. package/dist/containers/iso-base-media/get-sample-positions-from-track.js +2 -1
  13. package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +4 -1
  14. package/dist/containers/iso-base-media/get-seeking-byte.js +3 -1
  15. package/dist/containers/iso-base-media/moov/mvhd.d.ts +30 -0
  16. package/dist/containers/iso-base-media/moov/mvhd.js +65 -0
  17. package/dist/containers/iso-base-media/moov/trex.d.ts +16 -0
  18. package/dist/containers/iso-base-media/moov/trex.js +27 -0
  19. package/dist/containers/iso-base-media/process-box.js +10 -1
  20. package/dist/containers/iso-base-media/tkhd.d.ts +1 -1
  21. package/dist/containers/iso-base-media/traversal.d.ts +4 -1
  22. package/dist/containers/iso-base-media/traversal.js +18 -1
  23. package/dist/containers/m3u/get-seeking-byte.js +2 -0
  24. package/dist/containers/mp3/get-seeking-byte.js +4 -1
  25. package/dist/containers/riff/get-seeking-byte.js +3 -0
  26. package/dist/containers/wav/get-seeking-byte.js +1 -0
  27. package/dist/containers/wav/parse-list.js +4 -3
  28. package/dist/containers/webm/seek/get-seeking-byte.js +21 -6
  29. package/dist/controller/media-parser-controller.d.ts +3 -0
  30. package/dist/controller/media-parser-controller.js +15 -0
  31. package/dist/esm/index.mjs +327 -156
  32. package/dist/esm/server-worker.mjs +17 -0
  33. package/dist/esm/worker-server-entry.mjs +341 -155
  34. package/dist/esm/worker-web-entry.mjs +341 -155
  35. package/dist/esm/worker.mjs +28 -0
  36. package/dist/get-duration.js +1 -0
  37. package/dist/get-seeking-byte.js +13 -2
  38. package/dist/index.cjs +54 -0
  39. package/dist/index.d.ts +3 -2
  40. package/dist/index.js +1 -1
  41. package/dist/internal-parse-media.js +25 -0
  42. package/dist/iterator/buffer-iterator.d.ts +1 -1
  43. package/dist/iterator/buffer-manager.d.ts +1 -1
  44. package/dist/iterator/buffer-manager.js +19 -5
  45. package/dist/parse-media-on-worker-entry.js +17 -0
  46. package/dist/samples-from-moof.d.ts +3 -1
  47. package/dist/samples-from-moof.js +15 -12
  48. package/dist/state/iso-base-media/cached-sample-positions.js +1 -0
  49. package/dist/state/iso-base-media/lazy-mfra-load.js +1 -1
  50. package/dist/version.d.ts +1 -1
  51. package/dist/version.js +1 -1
  52. package/dist/webcodec-sample-types.d.ts +2 -2
  53. package/dist/work-on-seek-request.d.ts +22 -0
  54. package/dist/work-on-seek-request.js +3 -2
  55. package/dist/worker/forward-controller-to-worker.js +18 -0
  56. package/dist/worker/worker-types.d.ts +13 -2
  57. package/package.json +3 -3
@@ -750,24 +750,38 @@ var mediaParserController = () => {
750
750
  await pauseSignal.waitUntilResume();
751
751
  };
752
752
  let seekingHintResolution = null;
753
+ let simulateSeekResolution = null;
753
754
  const getSeekingHints = () => {
754
755
  if (!seekingHintResolution) {
755
756
  throw new Error("The mediaParserController() was not yet used in a parseMedia() call");
756
757
  }
757
758
  return seekingHintResolution();
758
759
  };
760
+ const simulateSeek = (seekInSeconds) => {
761
+ if (!simulateSeekResolution) {
762
+ throw new Error("The mediaParserController() was not yet used in a parseMedia() call");
763
+ }
764
+ return simulateSeekResolution(seekInSeconds);
765
+ };
759
766
  const attachSeekingHintResolution = (callback) => {
760
767
  if (seekingHintResolution) {
761
768
  throw new Error("The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.");
762
769
  }
763
770
  seekingHintResolution = callback;
764
771
  };
772
+ const attachSimulateSeekResolution = (callback) => {
773
+ if (simulateSeekResolution) {
774
+ throw new Error("The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.");
775
+ }
776
+ simulateSeekResolution = callback;
777
+ };
765
778
  return {
766
779
  abort: (reason) => {
767
780
  abortController.abort(reason);
768
781
  emitter.dispatchAbort(reason);
769
782
  },
770
783
  seek: seekSignal.seek,
784
+ simulateSeek,
771
785
  pause: pauseSignal.pause,
772
786
  resume: pauseSignal.resume,
773
787
  addEventListener: emitter.addEventListener,
@@ -779,7 +793,8 @@ var mediaParserController = () => {
779
793
  seekSignal,
780
794
  markAsReadyToEmitEvents: emitter.markAsReady,
781
795
  performedSeeksSignal,
782
- attachSeekingHintResolution
796
+ attachSeekingHintResolution,
797
+ attachSimulateSeekResolution
783
798
  }
784
799
  };
785
800
  };
@@ -1053,6 +1068,21 @@ var getTrunBoxes = (segment) => {
1053
1068
  const trunBoxes = segment.children.filter((c) => c.type === "trun-box");
1054
1069
  return trunBoxes;
1055
1070
  };
1071
+ var getMvexBox = (moovAtom) => {
1072
+ const mvexBox = moovAtom.children.find((s) => s.type === "regular-box" && s.boxType === "mvex");
1073
+ if (!mvexBox || mvexBox.type !== "regular-box") {
1074
+ return null;
1075
+ }
1076
+ return mvexBox;
1077
+ };
1078
+ var getTrexBoxes = (moovAtom) => {
1079
+ const mvexBox = getMvexBox(moovAtom);
1080
+ if (!mvexBox) {
1081
+ return [];
1082
+ }
1083
+ const trexBoxes = mvexBox.children.filter((c) => c.type === "trex-box");
1084
+ return trexBoxes;
1085
+ };
1056
1086
  var getTfraBoxesFromMfraBoxChildren = (mfraBoxChildren) => {
1057
1087
  const tfraBoxes = mfraBoxChildren.filter((b) => b.type === "tfra-box");
1058
1088
  return tfraBoxes;
@@ -2425,14 +2455,28 @@ var detectFileType = (data) => {
2425
2455
  };
2426
2456
 
2427
2457
  // src/iterator/buffer-manager.ts
2458
+ var makeBufferWithMaxBytes = (initialData, maxBytes) => {
2459
+ const maxByteLength = Math.min(maxBytes, 2 ** 31);
2460
+ try {
2461
+ const buf = new ArrayBuffer(initialData.byteLength, {
2462
+ maxByteLength
2463
+ });
2464
+ return buf;
2465
+ } catch (e) {
2466
+ if (e instanceof RangeError && maxBytes > 2 ** 27) {
2467
+ return new ArrayBuffer(initialData.byteLength, {
2468
+ maxByteLength: 2 ** 27
2469
+ });
2470
+ }
2471
+ throw e;
2472
+ }
2473
+ };
2428
2474
  var bufferManager = ({
2429
2475
  initialData,
2430
2476
  maxBytes,
2431
2477
  counter
2432
2478
  }) => {
2433
- const buf = new ArrayBuffer(initialData.byteLength, {
2434
- maxByteLength: maxBytes === null ? initialData.byteLength : Math.min(maxBytes, 2 ** 31)
2435
- });
2479
+ const buf = makeBufferWithMaxBytes(initialData, maxBytes);
2436
2480
  if (!buf.resize) {
2437
2481
  throw new Error("`ArrayBuffer.resize` is not supported in this Runtime. On the server: Use at least Node.js 20 or Bun. In the browser: Chrome 111, Edge 111, Safari 16.4, Firefox 128, Opera 111");
2438
2482
  }
@@ -4812,14 +4856,15 @@ var areSamplesComplete = ({
4812
4856
  };
4813
4857
 
4814
4858
  // src/samples-from-moof.ts
4815
- var getSamplesFromTraf = (trafSegment, moofOffset) => {
4859
+ var getSamplesFromTraf = (trafSegment, moofOffset, trexBoxes) => {
4816
4860
  if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
4817
4861
  throw new Error("Expected traf-box");
4818
4862
  }
4819
4863
  const tfhdBox = getTfhdBox(trafSegment);
4820
- const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
4821
- const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
4822
- const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
4864
+ const trexBox = trexBoxes.find((t) => t.trackId === tfhdBox?.trackId) ?? null;
4865
+ const defaultTrackSampleDuration = tfhdBox?.defaultSampleDuration || trexBox?.defaultSampleDuration || null;
4866
+ const defaultTrackSampleSize = tfhdBox?.defaultSampleSize || trexBox?.defaultSampleSize || null;
4867
+ const defaultTrackSampleFlags = tfhdBox?.defaultSampleFlags ?? trexBox?.defaultSampleFlags ?? null;
4823
4868
  const tfdtBox = getTfdtBox(trafSegment);
4824
4869
  const trunBoxes = getTrunBoxes(trafSegment);
4825
4870
  let time = 0;
@@ -4834,16 +4879,16 @@ var getSamplesFromTraf = (trafSegment, moofOffset) => {
4834
4879
  }
4835
4880
  for (const sample of trunBox.samples) {
4836
4881
  i++;
4837
- const duration2 = sample.sampleDuration ?? defaultSampleDuration;
4882
+ const duration2 = sample.sampleDuration || defaultTrackSampleDuration;
4838
4883
  if (duration2 === null) {
4839
4884
  throw new Error("Expected duration");
4840
4885
  }
4841
- const size = sample.sampleSize ?? defaultSampleSize;
4886
+ const size = sample.sampleSize ?? defaultTrackSampleSize;
4842
4887
  if (size === null) {
4843
4888
  throw new Error("Expected size");
4844
4889
  }
4845
4890
  const isFirstSample = i === 0;
4846
- const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
4891
+ const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultTrackSampleFlags;
4847
4892
  if (sampleFlags === null) {
4848
4893
  throw new Error("Expected sample flags");
4849
4894
  }
@@ -4869,14 +4914,15 @@ var getSamplesFromTraf = (trafSegment, moofOffset) => {
4869
4914
  };
4870
4915
  var getSamplesFromMoof = ({
4871
4916
  moofBox,
4872
- trackId
4917
+ trackId,
4918
+ trexBoxes
4873
4919
  }) => {
4874
4920
  const mapped = moofBox.trafBoxes.map((traf) => {
4875
4921
  const tfhdBox = getTfhdBox(traf);
4876
4922
  if (!tfhdBox || tfhdBox.trackId !== trackId) {
4877
4923
  return [];
4878
4924
  }
4879
- return getSamplesFromTraf(traf, moofBox.offset);
4925
+ return getSamplesFromTraf(traf, moofBox.offset, trexBoxes);
4880
4926
  });
4881
4927
  return mapped.flat(1);
4882
4928
  };
@@ -4885,7 +4931,8 @@ var getSamplesFromMoof = ({
4885
4931
  var collectSamplePositionsFromMoofBoxes = ({
4886
4932
  moofBoxes,
4887
4933
  tkhdBox,
4888
- isComplete
4934
+ isComplete,
4935
+ trexBoxes
4889
4936
  }) => {
4890
4937
  const samplePositions = moofBoxes.map((m, index) => {
4891
4938
  const isLastFragment = index === moofBoxes.length - 1 && isComplete;
@@ -4893,7 +4940,8 @@ var collectSamplePositionsFromMoofBoxes = ({
4893
4940
  isLastFragment,
4894
4941
  samples: getSamplesFromMoof({
4895
4942
  moofBox: m,
4896
- trackId: tkhdBox.trackId
4943
+ trackId: tkhdBox.trackId,
4944
+ trexBoxes
4897
4945
  })
4898
4946
  };
4899
4947
  });
@@ -5066,7 +5114,8 @@ var collectSamplePositionsFromTrak = (trakBox) => {
5066
5114
  var getSamplePositionsFromTrack = ({
5067
5115
  trakBox,
5068
5116
  moofBoxes,
5069
- moofComplete
5117
+ moofComplete,
5118
+ trexBoxes
5070
5119
  }) => {
5071
5120
  const tkhdBox = getTkhdBox(trakBox);
5072
5121
  if (!tkhdBox) {
@@ -5076,7 +5125,8 @@ var getSamplePositionsFromTrack = ({
5076
5125
  const { samplePositions } = collectSamplePositionsFromMoofBoxes({
5077
5126
  moofBoxes,
5078
5127
  tkhdBox,
5079
- isComplete: moofComplete
5128
+ isComplete: moofComplete,
5129
+ trexBoxes
5080
5130
  });
5081
5131
  return {
5082
5132
  samplePositions: samplePositions.map((s) => s.samples).flat(1),
@@ -5362,7 +5412,8 @@ var getDurationFromIsoBaseMedia = (parserState) => {
5362
5412
  const { samplePositions, isComplete } = getSamplePositionsFromTrack({
5363
5413
  trakBox,
5364
5414
  moofBoxes,
5365
- moofComplete: areSamplesComplete({ moofBoxes, tfraBoxes })
5415
+ moofComplete: areSamplesComplete({ moofBoxes, tfraBoxes }),
5416
+ trexBoxes: getTrexBoxes(moovBox)
5366
5417
  });
5367
5418
  if (!isComplete) {
5368
5419
  return null;
@@ -5468,7 +5519,8 @@ var getKeyframesFromIsoBaseMedia = (state) => {
5468
5519
  moofComplete: areSamplesComplete({
5469
5520
  moofBoxes,
5470
5521
  tfraBoxes
5471
- })
5522
+ }),
5523
+ trexBoxes: getTrexBoxes(moov)
5472
5524
  });
5473
5525
  if (!isComplete) {
5474
5526
  return [];
@@ -5844,7 +5896,11 @@ var getSeekingByteForAac = ({
5844
5896
  }
5845
5897
  }
5846
5898
  if (bestAudioSample) {
5847
- return { type: "do-seek", byte: bestAudioSample.offset };
5899
+ return {
5900
+ type: "do-seek",
5901
+ byte: bestAudioSample.offset,
5902
+ timeInSeconds: bestAudioSample.timeInSeconds
5903
+ };
5848
5904
  }
5849
5905
  return { type: "valid-but-must-wait" };
5850
5906
  };
@@ -5871,7 +5927,7 @@ var getSeekingByteForFlac = ({
5871
5927
  }
5872
5928
  }
5873
5929
  if (bestAudioSample) {
5874
- return bestAudioSample.offset;
5930
+ return bestAudioSample;
5875
5931
  }
5876
5932
  return null;
5877
5933
  };
@@ -5909,7 +5965,7 @@ var findKeyframeBeforeTime = ({
5909
5965
  Log.trace(logLevel, "Found a sample, but the offset has not yet been marked as a video section yet. Not yet able to seek, but probably once we have started reading the next box.", videoSample);
5910
5966
  return null;
5911
5967
  }
5912
- return videoSample.offset;
5968
+ return videoSample;
5913
5969
  };
5914
5970
 
5915
5971
  // src/containers/iso-base-media/find-track-to-seek.ts
@@ -5930,7 +5986,8 @@ var findAnyTrackWithSamplePositions = (allTracks, struc) => {
5930
5986
  moofComplete: areSamplesComplete({
5931
5987
  moofBoxes: getMoofBoxes(struc.boxes),
5932
5988
  tfraBoxes: getTfraBoxes(struc.boxes)
5933
- })
5989
+ }),
5990
+ trexBoxes: getTrexBoxes(moov)
5934
5991
  });
5935
5992
  if (samplePositions.length === 0) {
5936
5993
  continue;
@@ -5960,7 +6017,8 @@ var findTrackToSeek = (allTracks, structure) => {
5960
6017
  moofComplete: areSamplesComplete({
5961
6018
  moofBoxes: getMoofBoxes(struc.boxes),
5962
6019
  tfraBoxes: getTfraBoxes(struc.boxes)
5963
- })
6020
+ }),
6021
+ trexBoxes: getTrexBoxes(moov)
5964
6022
  });
5965
6023
  if (samplePositions.length === 0) {
5966
6024
  return findAnyTrackWithSamplePositions(allTracks, struc);
@@ -6122,7 +6180,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
6122
6180
  const { samplePositions: samplePositionsArray } = collectSamplePositionsFromMoofBoxes({
6123
6181
  moofBoxes: info.moofBoxes,
6124
6182
  tkhdBox,
6125
- isComplete
6183
+ isComplete,
6184
+ trexBoxes: getTrexBoxes(moov)
6126
6185
  });
6127
6186
  Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
6128
6187
  for (const positions of samplePositionsArray) {
@@ -6140,7 +6199,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
6140
6199
  if (kf) {
6141
6200
  return {
6142
6201
  type: "do-seek",
6143
- byte: kf
6202
+ byte: kf.offset,
6203
+ timeInSeconds: Math.min(kf.decodingTimestamp, kf.timestamp) / firstTrack.originalTimescale
6144
6204
  };
6145
6205
  }
6146
6206
  }
@@ -6243,7 +6303,8 @@ var getSeekingByteFromIsoBaseMedia = ({
6243
6303
  if (keyframe) {
6244
6304
  return Promise.resolve({
6245
6305
  type: "do-seek",
6246
- byte: keyframe
6306
+ byte: keyframe.offset,
6307
+ timeInSeconds: Math.min(keyframe.decodingTimestamp, keyframe.timestamp) / track.originalTimescale
6247
6308
  });
6248
6309
  }
6249
6310
  return Promise.resolve({
@@ -6283,7 +6344,8 @@ var getSeekingByteForM3u8 = ({
6283
6344
  }
6284
6345
  return {
6285
6346
  type: "do-seek",
6286
- byte: currentPosition
6347
+ byte: currentPosition,
6348
+ timeInSeconds: time
6287
6349
  };
6288
6350
  };
6289
6351
 
@@ -6517,9 +6579,12 @@ var getSeekingByteForMp3 = ({
6517
6579
  type: "valid-but-must-wait"
6518
6580
  };
6519
6581
  }
6582
+ const byte = Math.max(...candidates);
6583
+ const timeInSeconds = byte === bestAudioSample?.offset ? bestAudioSample.timeInSeconds : time;
6520
6584
  return {
6521
6585
  type: "do-seek",
6522
- byte: Math.max(...candidates)
6586
+ byte,
6587
+ timeInSeconds
6523
6588
  };
6524
6589
  };
6525
6590
 
@@ -6563,7 +6628,8 @@ var getSeekingByteForRiff = async ({
6563
6628
  avcState.clear();
6564
6629
  return {
6565
6630
  type: "do-seek",
6566
- byte: lastKeyframe.positionInBytes
6631
+ byte: lastKeyframe.positionInBytes,
6632
+ timeInSeconds: Math.min(lastKeyframe.decodingTimeInSeconds, lastKeyframe.presentationTimeInSeconds)
6567
6633
  };
6568
6634
  }
6569
6635
  if (idx1Entries.videoTrackIndex === null) {
@@ -6594,121 +6660,8 @@ var getSeekingByteForRiff = async ({
6594
6660
  avcState.clear();
6595
6661
  return {
6596
6662
  type: "do-seek",
6597
- byte: bestEntry.offset + info.moviOffset - 4
6598
- };
6599
- };
6600
-
6601
- // src/containers/wav/get-seeking-byte.ts
6602
- var WAVE_SAMPLES_PER_SECOND = 25;
6603
- var getSeekingByteFromWav = ({
6604
- info,
6605
- time
6606
- }) => {
6607
- const bytesPerSecond = info.sampleRate * info.blockAlign;
6608
- const durationInSeconds = info.mediaSection.size / bytesPerSecond;
6609
- const timeRoundedDown = Math.floor(Math.min(time, durationInSeconds - 0.0000001) * WAVE_SAMPLES_PER_SECOND) / WAVE_SAMPLES_PER_SECOND;
6610
- const byteOffset = bytesPerSecond * timeRoundedDown;
6611
- return Promise.resolve({
6612
- type: "do-seek",
6613
- byte: byteOffset + info.mediaSection.start
6614
- });
6615
- };
6616
-
6617
- // src/containers/webm/seek/get-seeking-byte.ts
6618
- var toSeconds = (timeInTimescale, track) => {
6619
- return timeInTimescale / track.timescale * 1000;
6620
- };
6621
- var findBiggestCueBeforeTime = ({
6622
- cues,
6623
- time,
6624
- track
6625
- }) => {
6626
- let biggestCueBeforeTime;
6627
- for (const cue of cues) {
6628
- const cueTimeInSeconds = toSeconds(cue.timeInTimescale, track);
6629
- if (cueTimeInSeconds < time && (!biggestCueBeforeTime || cueTimeInSeconds > toSeconds(biggestCueBeforeTime.timeInTimescale, track))) {
6630
- biggestCueBeforeTime = cue;
6631
- }
6632
- }
6633
- return biggestCueBeforeTime;
6634
- };
6635
- var findKeyframeBeforeTime2 = ({
6636
- keyframes,
6637
- time
6638
- }) => {
6639
- let keyframeBeforeTime;
6640
- for (const keyframe of keyframes) {
6641
- if (keyframe.decodingTimeInSeconds < time && (!keyframeBeforeTime || keyframe.decodingTimeInSeconds > keyframeBeforeTime.decodingTimeInSeconds)) {
6642
- keyframeBeforeTime = keyframe;
6643
- }
6644
- }
6645
- return keyframeBeforeTime?.positionInBytes ?? null;
6646
- };
6647
- var getByteFromCues = ({
6648
- cuesResponse,
6649
- time,
6650
- info,
6651
- logLevel
6652
- }) => {
6653
- if (!cuesResponse) {
6654
- Log.trace(logLevel, "Has no Matroska cues at the moment, cannot use them");
6655
- return null;
6656
- }
6657
- const { cues, segmentOffset } = cuesResponse;
6658
- Log.trace(logLevel, "Has Matroska cues. Will use them to perform a seek.");
6659
- const biggestCueBeforeTime = findBiggestCueBeforeTime({
6660
- cues,
6661
- time,
6662
- track: info.track
6663
- });
6664
- if (!biggestCueBeforeTime) {
6665
- return null;
6666
- }
6667
- return biggestCueBeforeTime.clusterPositionInSegment + segmentOffset;
6668
- };
6669
- var getSeekingByteFromMatroska = async ({
6670
- time,
6671
- webmState,
6672
- info,
6673
- logLevel,
6674
- mediaSection
6675
- }) => {
6676
- if (!info.track) {
6677
- Log.trace(logLevel, "No video track found, cannot seek yet");
6678
- return {
6679
- type: "valid-but-must-wait"
6680
- };
6681
- }
6682
- const cuesResponse = info.loadedCues ?? await webmState.cues.getLoadedCues();
6683
- const byteFromObservedKeyframe = findKeyframeBeforeTime2({
6684
- keyframes: info.keyframes,
6685
- time
6686
- });
6687
- const byteFromCues = getByteFromCues({
6688
- cuesResponse,
6689
- time,
6690
- info,
6691
- logLevel
6692
- });
6693
- const byteFromFirstMediaSection = webmState.getFirstCluster()?.start ?? null;
6694
- const seekPossibilities = [
6695
- byteFromCues,
6696
- byteFromObservedKeyframe,
6697
- byteFromFirstMediaSection
6698
- ].filter((n) => n !== null);
6699
- const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
6700
- if (byteToSeekTo === null) {
6701
- return {
6702
- type: "invalid"
6703
- };
6704
- }
6705
- mediaSection.addMediaSection({
6706
- start: byteToSeekTo,
6707
- size: 1
6708
- });
6709
- return {
6710
- type: "do-seek",
6711
- byte: byteToSeekTo
6663
+ byte: bestEntry.offset + info.moviOffset - 4,
6664
+ timeInSeconds: bestEntry.sampleCounts[idx1Entries.videoTrackIndex] / info.samplesPerSecond
6712
6665
  };
6713
6666
  };
6714
6667
 
@@ -7250,6 +7203,137 @@ var handleAvcPacket = async ({
7250
7203
  transportStream.lastEmittedSample.setLastEmittedSample(sample);
7251
7204
  };
7252
7205
 
7206
+ // src/containers/wav/get-seeking-byte.ts
7207
+ var WAVE_SAMPLES_PER_SECOND = 25;
7208
+ var getSeekingByteFromWav = ({
7209
+ info,
7210
+ time
7211
+ }) => {
7212
+ const bytesPerSecond = info.sampleRate * info.blockAlign;
7213
+ const durationInSeconds = info.mediaSection.size / bytesPerSecond;
7214
+ const timeRoundedDown = Math.floor(Math.min(time, durationInSeconds - 0.0000001) * WAVE_SAMPLES_PER_SECOND) / WAVE_SAMPLES_PER_SECOND;
7215
+ const byteOffset = bytesPerSecond * timeRoundedDown;
7216
+ return Promise.resolve({
7217
+ type: "do-seek",
7218
+ byte: byteOffset + info.mediaSection.start,
7219
+ timeInSeconds: timeRoundedDown
7220
+ });
7221
+ };
7222
+
7223
+ // src/containers/webm/seek/get-seeking-byte.ts
7224
+ var toSeconds = (timeInTimescale, track) => {
7225
+ return timeInTimescale / track.timescale * 1000;
7226
+ };
7227
+ var findBiggestCueBeforeTime = ({
7228
+ cues,
7229
+ time,
7230
+ track
7231
+ }) => {
7232
+ let biggestCueBeforeTime;
7233
+ for (const cue of cues) {
7234
+ const cueTimeInSeconds = toSeconds(cue.timeInTimescale, track);
7235
+ if (cueTimeInSeconds < time && (!biggestCueBeforeTime || cueTimeInSeconds > toSeconds(biggestCueBeforeTime.timeInTimescale, track))) {
7236
+ biggestCueBeforeTime = cue;
7237
+ }
7238
+ }
7239
+ return biggestCueBeforeTime;
7240
+ };
7241
+ var findKeyframeBeforeTime2 = ({
7242
+ keyframes,
7243
+ time
7244
+ }) => {
7245
+ let keyframeBeforeTime;
7246
+ for (const keyframe of keyframes) {
7247
+ if (keyframe.decodingTimeInSeconds < time && (!keyframeBeforeTime || keyframe.decodingTimeInSeconds > keyframeBeforeTime.decodingTimeInSeconds)) {
7248
+ keyframeBeforeTime = keyframe;
7249
+ }
7250
+ }
7251
+ return keyframeBeforeTime ?? null;
7252
+ };
7253
+ var getByteFromCues = ({
7254
+ cuesResponse,
7255
+ time,
7256
+ info,
7257
+ logLevel
7258
+ }) => {
7259
+ if (!cuesResponse) {
7260
+ Log.trace(logLevel, "Has no Matroska cues at the moment, cannot use them");
7261
+ return null;
7262
+ }
7263
+ const { cues, segmentOffset } = cuesResponse;
7264
+ Log.trace(logLevel, "Has Matroska cues. Will use them to perform a seek.");
7265
+ const biggestCueBeforeTime = findBiggestCueBeforeTime({
7266
+ cues,
7267
+ time,
7268
+ track: info.track
7269
+ });
7270
+ if (!biggestCueBeforeTime) {
7271
+ return null;
7272
+ }
7273
+ return {
7274
+ byte: biggestCueBeforeTime.clusterPositionInSegment + segmentOffset,
7275
+ timeInSeconds: toSeconds(biggestCueBeforeTime.timeInTimescale, info.track)
7276
+ };
7277
+ };
7278
+ var getSeekingByteFromMatroska = async ({
7279
+ time,
7280
+ webmState,
7281
+ info,
7282
+ logLevel,
7283
+ mediaSection
7284
+ }) => {
7285
+ if (!info.track) {
7286
+ Log.trace(logLevel, "No video track found, cannot seek yet");
7287
+ return {
7288
+ type: "valid-but-must-wait"
7289
+ };
7290
+ }
7291
+ const cuesResponse = info.loadedCues ?? await webmState.cues.getLoadedCues();
7292
+ const byteFromObservedKeyframe = findKeyframeBeforeTime2({
7293
+ keyframes: info.keyframes,
7294
+ time
7295
+ });
7296
+ const byteFromCues = getByteFromCues({
7297
+ cuesResponse,
7298
+ time,
7299
+ info,
7300
+ logLevel
7301
+ });
7302
+ const byteFromFirstMediaSection = webmState.getFirstCluster()?.start ?? null;
7303
+ const seekPossibilities = [
7304
+ byteFromCues?.byte ?? null,
7305
+ byteFromObservedKeyframe?.positionInBytes ?? null,
7306
+ byteFromFirstMediaSection
7307
+ ].filter((n) => n !== null);
7308
+ const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
7309
+ if (byteToSeekTo === null) {
7310
+ return {
7311
+ type: "invalid"
7312
+ };
7313
+ }
7314
+ mediaSection.addMediaSection({
7315
+ start: byteToSeekTo,
7316
+ size: 1
7317
+ });
7318
+ const timeInSeconds = (() => {
7319
+ if (byteToSeekTo === byteFromObservedKeyframe?.positionInBytes) {
7320
+ return Math.min(byteFromObservedKeyframe.decodingTimeInSeconds, byteFromObservedKeyframe.presentationTimeInSeconds);
7321
+ }
7322
+ if (byteToSeekTo === byteFromCues?.byte) {
7323
+ return byteFromCues.timeInSeconds;
7324
+ }
7325
+ if (byteToSeekTo === byteFromFirstMediaSection) {
7326
+ return 0;
7327
+ }
7328
+ throw new Error("Should not happen");
7329
+ })();
7330
+ return {
7331
+ type: "do-seek",
7332
+ byte: byteToSeekTo,
7333
+ timeInSeconds
7334
+ };
7335
+ };
7336
+
7253
7337
  // src/state/transport-stream/observed-pes-header.ts
7254
7338
  var makeObservedPesHeader = () => {
7255
7339
  const pesHeaders = [];
@@ -7339,7 +7423,8 @@ var getSeekingByte = ({
7339
7423
  if (byte) {
7340
7424
  return Promise.resolve({
7341
7425
  type: "do-seek",
7342
- byte
7426
+ byte: byte.offset,
7427
+ timeInSeconds: byte.timeInSeconds
7343
7428
  });
7344
7429
  }
7345
7430
  return Promise.resolve({
@@ -7352,11 +7437,20 @@ var getSeekingByte = ({
7352
7437
  timeInSeconds: time,
7353
7438
  ptsStartOffset: info.ptsStartOffset
7354
7439
  });
7355
- const byte = lastKeyframeBeforeTimeInSeconds?.offset ?? 0;
7440
+ if (!lastKeyframeBeforeTimeInSeconds) {
7441
+ transportStream.resetBeforeSeek();
7442
+ return Promise.resolve({
7443
+ type: "do-seek",
7444
+ byte: 0,
7445
+ timeInSeconds: 0
7446
+ });
7447
+ }
7448
+ const byte = lastKeyframeBeforeTimeInSeconds.offset;
7356
7449
  transportStream.resetBeforeSeek();
7357
7450
  return Promise.resolve({
7358
7451
  type: "do-seek",
7359
- byte
7452
+ byte,
7453
+ timeInSeconds: Math.min(lastKeyframeBeforeTimeInSeconds.pts, lastKeyframeBeforeTimeInSeconds.dts ?? Infinity) / MPEG_TIMESCALE
7360
7454
  });
7361
7455
  }
7362
7456
  if (info.type === "riff-seeking-hints") {
@@ -9239,7 +9333,8 @@ var calculateFlatSamples = ({
9239
9333
  const { samplePositions } = getSamplePositionsFromTrack({
9240
9334
  trakBox,
9241
9335
  moofBoxes: relevantMoofBox ? [relevantMoofBox] : [],
9242
- moofComplete
9336
+ moofComplete,
9337
+ trexBoxes: getTrexBoxes(moov)
9243
9338
  });
9244
9339
  return samplePositions.map((samplePosition) => {
9245
9340
  return {
@@ -9955,7 +10050,7 @@ var toUnixTimestamp = (value) => {
9955
10050
  return Math.floor(value + baseDate.getTime() / 1000) * 1000;
9956
10051
  };
9957
10052
 
9958
- // src/containers/iso-base-media/mvhd.ts
10053
+ // src/containers/iso-base-media/moov/mvhd.ts
9959
10054
  var parseMvhd = ({
9960
10055
  iterator,
9961
10056
  offset,
@@ -10011,6 +10106,34 @@ var parseMvhd = ({
10011
10106
  };
10012
10107
  };
10013
10108
 
10109
+ // src/containers/iso-base-media/moov/trex.ts
10110
+ var parseTrex = ({
10111
+ iterator,
10112
+ offset,
10113
+ size
10114
+ }) => {
10115
+ const box = iterator.startBox(size - 8);
10116
+ const version = iterator.getUint8();
10117
+ iterator.discard(3);
10118
+ const trackId = iterator.getUint32();
10119
+ const defaultSampleDescriptionIndex = iterator.getUint32();
10120
+ const defaultSampleDuration = iterator.getUint32();
10121
+ const defaultSampleSize = iterator.getUint32();
10122
+ const defaultSampleFlags = iterator.getUint32();
10123
+ box.expectNoMoreBytes();
10124
+ return {
10125
+ type: "trex-box",
10126
+ boxSize: size,
10127
+ offset,
10128
+ trackId,
10129
+ version,
10130
+ defaultSampleDescriptionIndex,
10131
+ defaultSampleDuration,
10132
+ defaultSampleSize,
10133
+ defaultSampleFlags
10134
+ };
10135
+ };
10136
+
10014
10137
  // src/containers/iso-base-media/stsd/av1c.ts
10015
10138
  var parseAv1C = ({
10016
10139
  data,
@@ -11383,10 +11506,16 @@ var processBox = async ({
11383
11506
  })
11384
11507
  };
11385
11508
  }
11509
+ if (boxType === "trex") {
11510
+ return {
11511
+ type: "box",
11512
+ box: await parseTrex({ iterator, offset: fileOffset, size: boxSize })
11513
+ };
11514
+ }
11386
11515
  if (boxType === "moof") {
11387
11516
  await onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
11388
11517
  }
11389
- if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "edts" || boxType === "stsb") {
11518
+ if (boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "mfra" || boxType === "edts" || boxType === "mvex" || boxType === "stsb") {
11390
11519
  const children = await getIsoBaseMediaChildren({
11391
11520
  iterator,
11392
11521
  size: boxSize - 8,
@@ -11406,6 +11535,7 @@ var processBox = async ({
11406
11535
  };
11407
11536
  }
11408
11537
  iterator.discard(boxSize - 8);
11538
+ Log.verbose(logLevel, "Unknown ISO Base Media Box:", boxType);
11409
11539
  return {
11410
11540
  type: "box",
11411
11541
  box: {
@@ -14778,10 +14908,11 @@ var parseList = ({
14778
14908
  const metadata = [];
14779
14909
  const remainingBytes = () => ckSize - (iterator.counter.getOffset() - startOffset);
14780
14910
  while (remainingBytes() > 0) {
14781
- if (remainingBytes() < 4) {
14782
- iterator.discard(remainingBytes());
14783
- break;
14911
+ const byte = iterator.getUint8();
14912
+ if (byte === 0) {
14913
+ continue;
14784
14914
  }
14915
+ iterator.counter.decrement(1);
14785
14916
  const key = iterator.getByteString(4, false);
14786
14917
  const size = iterator.getUint32Le();
14787
14918
  const value = iterator.getByteString(size, true);
@@ -16199,7 +16330,7 @@ var lazyMfraLoad = ({
16199
16330
  logLevel,
16200
16331
  prefetchCache
16201
16332
  }).then((boxes) => {
16202
- Log.verbose(logLevel, "Lazily found mfra atom.");
16333
+ Log.verbose(logLevel, boxes ? "Lazily found mfra atom." : "No mfra atom found.");
16203
16334
  result = boxes;
16204
16335
  return boxes;
16205
16336
  });
@@ -17726,6 +17857,46 @@ var internalParseMedia = async function({
17726
17857
  contentLength: state.contentLength,
17727
17858
  aacState: state.aac
17728
17859
  })));
17860
+ controller._internals.attachSimulateSeekResolution((seek2) => {
17861
+ const {
17862
+ aacState: aacState2,
17863
+ avcState: avcState2,
17864
+ flacState: flacState2,
17865
+ isoState,
17866
+ iterator,
17867
+ keyframes,
17868
+ m3uState: m3uState2,
17869
+ mediaSection,
17870
+ mp3State,
17871
+ riffState,
17872
+ samplesObserved,
17873
+ structureState: structureState2,
17874
+ tracksState,
17875
+ transportStream,
17876
+ webmState: webmState2
17877
+ } = getWorkOnSeekRequestOptions(state);
17878
+ return turnSeekIntoByte({
17879
+ aacState: aacState2,
17880
+ seek: seek2,
17881
+ avcState: avcState2,
17882
+ contentLength,
17883
+ flacState: flacState2,
17884
+ isoState,
17885
+ iterator,
17886
+ keyframes,
17887
+ logLevel,
17888
+ m3uPlaylistContext,
17889
+ m3uState: m3uState2,
17890
+ mediaSectionState: mediaSection,
17891
+ mp3State,
17892
+ riffState,
17893
+ samplesObserved,
17894
+ structureState: structureState2,
17895
+ tracksState,
17896
+ transportStream,
17897
+ webmState: webmState2
17898
+ });
17899
+ });
17729
17900
  if (!hasAudioTrackHandlers && !hasVideoTrackHandlers && Object.values(state.fields).every((v) => !v) && mode === "query") {
17730
17901
  Log.warn(logLevel, new Error("Warning - No `fields` and no `on*` callbacks were passed to `parseMedia()`. Specify the data you would like to retrieve."));
17731
17902
  }
@@ -17779,6 +17950,21 @@ var forwardMediaParserControllerToWorker = (controller) => {
17779
17950
  });
17780
17951
  return;
17781
17952
  }
17953
+ if (message.type === "request-simulate-seek") {
17954
+ controller.simulateSeek(message.payload).then((resolution) => {
17955
+ postMessage({
17956
+ type: "response-simulate-seek",
17957
+ nonce: message.nonce,
17958
+ payload: resolution
17959
+ });
17960
+ }).catch((err) => {
17961
+ postMessage({
17962
+ type: "response-error",
17963
+ payload: err
17964
+ });
17965
+ });
17966
+ return;
17967
+ }
17782
17968
  if (message.type === "request-resume") {
17783
17969
  controller.resume();
17784
17970
  return;