@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
@@ -647,24 +647,38 @@ var mediaParserController = () => {
647
647
  await pauseSignal.waitUntilResume();
648
648
  };
649
649
  let seekingHintResolution = null;
650
+ let simulateSeekResolution = null;
650
651
  const getSeekingHints = () => {
651
652
  if (!seekingHintResolution) {
652
653
  throw new Error("The mediaParserController() was not yet used in a parseMedia() call");
653
654
  }
654
655
  return seekingHintResolution();
655
656
  };
657
+ const simulateSeek = (seekInSeconds) => {
658
+ if (!simulateSeekResolution) {
659
+ throw new Error("The mediaParserController() was not yet used in a parseMedia() call");
660
+ }
661
+ return simulateSeekResolution(seekInSeconds);
662
+ };
656
663
  const attachSeekingHintResolution = (callback) => {
657
664
  if (seekingHintResolution) {
658
665
  throw new Error("The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.");
659
666
  }
660
667
  seekingHintResolution = callback;
661
668
  };
669
+ const attachSimulateSeekResolution = (callback) => {
670
+ if (simulateSeekResolution) {
671
+ throw new Error("The mediaParserController() was used in multiple parseMedia() calls. Create a separate controller for each call.");
672
+ }
673
+ simulateSeekResolution = callback;
674
+ };
662
675
  return {
663
676
  abort: (reason) => {
664
677
  abortController.abort(reason);
665
678
  emitter.dispatchAbort(reason);
666
679
  },
667
680
  seek: seekSignal.seek,
681
+ simulateSeek,
668
682
  pause: pauseSignal.pause,
669
683
  resume: pauseSignal.resume,
670
684
  addEventListener: emitter.addEventListener,
@@ -676,7 +690,8 @@ var mediaParserController = () => {
676
690
  seekSignal,
677
691
  markAsReadyToEmitEvents: emitter.markAsReady,
678
692
  performedSeeksSignal,
679
- attachSeekingHintResolution
693
+ attachSeekingHintResolution,
694
+ attachSimulateSeekResolution
680
695
  }
681
696
  };
682
697
  };
@@ -950,6 +965,21 @@ var getTrunBoxes = (segment) => {
950
965
  const trunBoxes = segment.children.filter((c) => c.type === "trun-box");
951
966
  return trunBoxes;
952
967
  };
968
+ var getMvexBox = (moovAtom) => {
969
+ const mvexBox = moovAtom.children.find((s) => s.type === "regular-box" && s.boxType === "mvex");
970
+ if (!mvexBox || mvexBox.type !== "regular-box") {
971
+ return null;
972
+ }
973
+ return mvexBox;
974
+ };
975
+ var getTrexBoxes = (moovAtom) => {
976
+ const mvexBox = getMvexBox(moovAtom);
977
+ if (!mvexBox) {
978
+ return [];
979
+ }
980
+ const trexBoxes = mvexBox.children.filter((c) => c.type === "trex-box");
981
+ return trexBoxes;
982
+ };
953
983
  var getTfraBoxesFromMfraBoxChildren = (mfraBoxChildren) => {
954
984
  const tfraBoxes = mfraBoxChildren.filter((b) => b.type === "tfra-box");
955
985
  return tfraBoxes;
@@ -2322,14 +2352,28 @@ var detectFileType = (data) => {
2322
2352
  };
2323
2353
 
2324
2354
  // src/iterator/buffer-manager.ts
2355
+ var makeBufferWithMaxBytes = (initialData, maxBytes) => {
2356
+ const maxByteLength = Math.min(maxBytes, 2 ** 31);
2357
+ try {
2358
+ const buf = new ArrayBuffer(initialData.byteLength, {
2359
+ maxByteLength
2360
+ });
2361
+ return buf;
2362
+ } catch (e) {
2363
+ if (e instanceof RangeError && maxBytes > 2 ** 27) {
2364
+ return new ArrayBuffer(initialData.byteLength, {
2365
+ maxByteLength: 2 ** 27
2366
+ });
2367
+ }
2368
+ throw e;
2369
+ }
2370
+ };
2325
2371
  var bufferManager = ({
2326
2372
  initialData,
2327
2373
  maxBytes,
2328
2374
  counter
2329
2375
  }) => {
2330
- const buf = new ArrayBuffer(initialData.byteLength, {
2331
- maxByteLength: maxBytes === null ? initialData.byteLength : Math.min(maxBytes, 2 ** 31)
2332
- });
2376
+ const buf = makeBufferWithMaxBytes(initialData, maxBytes);
2333
2377
  if (!buf.resize) {
2334
2378
  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");
2335
2379
  }
@@ -4709,14 +4753,15 @@ var areSamplesComplete = ({
4709
4753
  };
4710
4754
 
4711
4755
  // src/samples-from-moof.ts
4712
- var getSamplesFromTraf = (trafSegment, moofOffset) => {
4756
+ var getSamplesFromTraf = (trafSegment, moofOffset, trexBoxes) => {
4713
4757
  if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
4714
4758
  throw new Error("Expected traf-box");
4715
4759
  }
4716
4760
  const tfhdBox = getTfhdBox(trafSegment);
4717
- const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
4718
- const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
4719
- const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
4761
+ const trexBox = trexBoxes.find((t) => t.trackId === tfhdBox?.trackId) ?? null;
4762
+ const defaultTrackSampleDuration = tfhdBox?.defaultSampleDuration || trexBox?.defaultSampleDuration || null;
4763
+ const defaultTrackSampleSize = tfhdBox?.defaultSampleSize || trexBox?.defaultSampleSize || null;
4764
+ const defaultTrackSampleFlags = tfhdBox?.defaultSampleFlags ?? trexBox?.defaultSampleFlags ?? null;
4720
4765
  const tfdtBox = getTfdtBox(trafSegment);
4721
4766
  const trunBoxes = getTrunBoxes(trafSegment);
4722
4767
  let time = 0;
@@ -4731,16 +4776,16 @@ var getSamplesFromTraf = (trafSegment, moofOffset) => {
4731
4776
  }
4732
4777
  for (const sample of trunBox.samples) {
4733
4778
  i++;
4734
- const duration2 = sample.sampleDuration ?? defaultSampleDuration;
4779
+ const duration2 = sample.sampleDuration || defaultTrackSampleDuration;
4735
4780
  if (duration2 === null) {
4736
4781
  throw new Error("Expected duration");
4737
4782
  }
4738
- const size = sample.sampleSize ?? defaultSampleSize;
4783
+ const size = sample.sampleSize ?? defaultTrackSampleSize;
4739
4784
  if (size === null) {
4740
4785
  throw new Error("Expected size");
4741
4786
  }
4742
4787
  const isFirstSample = i === 0;
4743
- const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
4788
+ const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultTrackSampleFlags;
4744
4789
  if (sampleFlags === null) {
4745
4790
  throw new Error("Expected sample flags");
4746
4791
  }
@@ -4766,14 +4811,15 @@ var getSamplesFromTraf = (trafSegment, moofOffset) => {
4766
4811
  };
4767
4812
  var getSamplesFromMoof = ({
4768
4813
  moofBox,
4769
- trackId
4814
+ trackId,
4815
+ trexBoxes
4770
4816
  }) => {
4771
4817
  const mapped = moofBox.trafBoxes.map((traf) => {
4772
4818
  const tfhdBox = getTfhdBox(traf);
4773
4819
  if (!tfhdBox || tfhdBox.trackId !== trackId) {
4774
4820
  return [];
4775
4821
  }
4776
- return getSamplesFromTraf(traf, moofBox.offset);
4822
+ return getSamplesFromTraf(traf, moofBox.offset, trexBoxes);
4777
4823
  });
4778
4824
  return mapped.flat(1);
4779
4825
  };
@@ -4782,7 +4828,8 @@ var getSamplesFromMoof = ({
4782
4828
  var collectSamplePositionsFromMoofBoxes = ({
4783
4829
  moofBoxes,
4784
4830
  tkhdBox,
4785
- isComplete
4831
+ isComplete,
4832
+ trexBoxes
4786
4833
  }) => {
4787
4834
  const samplePositions = moofBoxes.map((m, index) => {
4788
4835
  const isLastFragment = index === moofBoxes.length - 1 && isComplete;
@@ -4790,7 +4837,8 @@ var collectSamplePositionsFromMoofBoxes = ({
4790
4837
  isLastFragment,
4791
4838
  samples: getSamplesFromMoof({
4792
4839
  moofBox: m,
4793
- trackId: tkhdBox.trackId
4840
+ trackId: tkhdBox.trackId,
4841
+ trexBoxes
4794
4842
  })
4795
4843
  };
4796
4844
  });
@@ -4963,7 +5011,8 @@ var collectSamplePositionsFromTrak = (trakBox) => {
4963
5011
  var getSamplePositionsFromTrack = ({
4964
5012
  trakBox,
4965
5013
  moofBoxes,
4966
- moofComplete
5014
+ moofComplete,
5015
+ trexBoxes
4967
5016
  }) => {
4968
5017
  const tkhdBox = getTkhdBox(trakBox);
4969
5018
  if (!tkhdBox) {
@@ -4973,7 +5022,8 @@ var getSamplePositionsFromTrack = ({
4973
5022
  const { samplePositions } = collectSamplePositionsFromMoofBoxes({
4974
5023
  moofBoxes,
4975
5024
  tkhdBox,
4976
- isComplete: moofComplete
5025
+ isComplete: moofComplete,
5026
+ trexBoxes
4977
5027
  });
4978
5028
  return {
4979
5029
  samplePositions: samplePositions.map((s) => s.samples).flat(1),
@@ -5259,7 +5309,8 @@ var getDurationFromIsoBaseMedia = (parserState) => {
5259
5309
  const { samplePositions, isComplete } = getSamplePositionsFromTrack({
5260
5310
  trakBox,
5261
5311
  moofBoxes,
5262
- moofComplete: areSamplesComplete({ moofBoxes, tfraBoxes })
5312
+ moofComplete: areSamplesComplete({ moofBoxes, tfraBoxes }),
5313
+ trexBoxes: getTrexBoxes(moovBox)
5263
5314
  });
5264
5315
  if (!isComplete) {
5265
5316
  return null;
@@ -5365,7 +5416,8 @@ var getKeyframesFromIsoBaseMedia = (state) => {
5365
5416
  moofComplete: areSamplesComplete({
5366
5417
  moofBoxes,
5367
5418
  tfraBoxes
5368
- })
5419
+ }),
5420
+ trexBoxes: getTrexBoxes(moov)
5369
5421
  });
5370
5422
  if (!isComplete) {
5371
5423
  return [];
@@ -5741,7 +5793,11 @@ var getSeekingByteForAac = ({
5741
5793
  }
5742
5794
  }
5743
5795
  if (bestAudioSample) {
5744
- return { type: "do-seek", byte: bestAudioSample.offset };
5796
+ return {
5797
+ type: "do-seek",
5798
+ byte: bestAudioSample.offset,
5799
+ timeInSeconds: bestAudioSample.timeInSeconds
5800
+ };
5745
5801
  }
5746
5802
  return { type: "valid-but-must-wait" };
5747
5803
  };
@@ -5768,7 +5824,7 @@ var getSeekingByteForFlac = ({
5768
5824
  }
5769
5825
  }
5770
5826
  if (bestAudioSample) {
5771
- return bestAudioSample.offset;
5827
+ return bestAudioSample;
5772
5828
  }
5773
5829
  return null;
5774
5830
  };
@@ -5806,7 +5862,7 @@ var findKeyframeBeforeTime = ({
5806
5862
  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);
5807
5863
  return null;
5808
5864
  }
5809
- return videoSample.offset;
5865
+ return videoSample;
5810
5866
  };
5811
5867
 
5812
5868
  // src/containers/iso-base-media/find-track-to-seek.ts
@@ -5827,7 +5883,8 @@ var findAnyTrackWithSamplePositions = (allTracks, struc) => {
5827
5883
  moofComplete: areSamplesComplete({
5828
5884
  moofBoxes: getMoofBoxes(struc.boxes),
5829
5885
  tfraBoxes: getTfraBoxes(struc.boxes)
5830
- })
5886
+ }),
5887
+ trexBoxes: getTrexBoxes(moov)
5831
5888
  });
5832
5889
  if (samplePositions.length === 0) {
5833
5890
  continue;
@@ -5857,7 +5914,8 @@ var findTrackToSeek = (allTracks, structure) => {
5857
5914
  moofComplete: areSamplesComplete({
5858
5915
  moofBoxes: getMoofBoxes(struc.boxes),
5859
5916
  tfraBoxes: getTfraBoxes(struc.boxes)
5860
- })
5917
+ }),
5918
+ trexBoxes: getTrexBoxes(moov)
5861
5919
  });
5862
5920
  if (samplePositions.length === 0) {
5863
5921
  return findAnyTrackWithSamplePositions(allTracks, struc);
@@ -6019,7 +6077,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
6019
6077
  const { samplePositions: samplePositionsArray } = collectSamplePositionsFromMoofBoxes({
6020
6078
  moofBoxes: info.moofBoxes,
6021
6079
  tkhdBox,
6022
- isComplete
6080
+ isComplete,
6081
+ trexBoxes: getTrexBoxes(moov)
6023
6082
  });
6024
6083
  Log.trace(logLevel, "Fragmented MP4 - Checking if we have seeking info for this time range");
6025
6084
  for (const positions of samplePositionsArray) {
@@ -6037,7 +6096,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
6037
6096
  if (kf) {
6038
6097
  return {
6039
6098
  type: "do-seek",
6040
- byte: kf
6099
+ byte: kf.offset,
6100
+ timeInSeconds: Math.min(kf.decodingTimestamp, kf.timestamp) / firstTrack.originalTimescale
6041
6101
  };
6042
6102
  }
6043
6103
  }
@@ -6140,7 +6200,8 @@ var getSeekingByteFromIsoBaseMedia = ({
6140
6200
  if (keyframe) {
6141
6201
  return Promise.resolve({
6142
6202
  type: "do-seek",
6143
- byte: keyframe
6203
+ byte: keyframe.offset,
6204
+ timeInSeconds: Math.min(keyframe.decodingTimestamp, keyframe.timestamp) / track.originalTimescale
6144
6205
  });
6145
6206
  }
6146
6207
  return Promise.resolve({
@@ -6180,7 +6241,8 @@ var getSeekingByteForM3u8 = ({
6180
6241
  }
6181
6242
  return {
6182
6243
  type: "do-seek",
6183
- byte: currentPosition
6244
+ byte: currentPosition,
6245
+ timeInSeconds: time
6184
6246
  };
6185
6247
  };
6186
6248
 
@@ -6414,9 +6476,12 @@ var getSeekingByteForMp3 = ({
6414
6476
  type: "valid-but-must-wait"
6415
6477
  };
6416
6478
  }
6479
+ const byte = Math.max(...candidates);
6480
+ const timeInSeconds = byte === bestAudioSample?.offset ? bestAudioSample.timeInSeconds : time;
6417
6481
  return {
6418
6482
  type: "do-seek",
6419
- byte: Math.max(...candidates)
6483
+ byte,
6484
+ timeInSeconds
6420
6485
  };
6421
6486
  };
6422
6487
 
@@ -6460,7 +6525,8 @@ var getSeekingByteForRiff = async ({
6460
6525
  avcState.clear();
6461
6526
  return {
6462
6527
  type: "do-seek",
6463
- byte: lastKeyframe.positionInBytes
6528
+ byte: lastKeyframe.positionInBytes,
6529
+ timeInSeconds: Math.min(lastKeyframe.decodingTimeInSeconds, lastKeyframe.presentationTimeInSeconds)
6464
6530
  };
6465
6531
  }
6466
6532
  if (idx1Entries.videoTrackIndex === null) {
@@ -6491,121 +6557,8 @@ var getSeekingByteForRiff = async ({
6491
6557
  avcState.clear();
6492
6558
  return {
6493
6559
  type: "do-seek",
6494
- byte: bestEntry.offset + info.moviOffset - 4
6495
- };
6496
- };
6497
-
6498
- // src/containers/wav/get-seeking-byte.ts
6499
- var WAVE_SAMPLES_PER_SECOND = 25;
6500
- var getSeekingByteFromWav = ({
6501
- info,
6502
- time
6503
- }) => {
6504
- const bytesPerSecond = info.sampleRate * info.blockAlign;
6505
- const durationInSeconds = info.mediaSection.size / bytesPerSecond;
6506
- const timeRoundedDown = Math.floor(Math.min(time, durationInSeconds - 0.0000001) * WAVE_SAMPLES_PER_SECOND) / WAVE_SAMPLES_PER_SECOND;
6507
- const byteOffset = bytesPerSecond * timeRoundedDown;
6508
- return Promise.resolve({
6509
- type: "do-seek",
6510
- byte: byteOffset + info.mediaSection.start
6511
- });
6512
- };
6513
-
6514
- // src/containers/webm/seek/get-seeking-byte.ts
6515
- var toSeconds = (timeInTimescale, track) => {
6516
- return timeInTimescale / track.timescale * 1000;
6517
- };
6518
- var findBiggestCueBeforeTime = ({
6519
- cues,
6520
- time,
6521
- track
6522
- }) => {
6523
- let biggestCueBeforeTime;
6524
- for (const cue of cues) {
6525
- const cueTimeInSeconds = toSeconds(cue.timeInTimescale, track);
6526
- if (cueTimeInSeconds < time && (!biggestCueBeforeTime || cueTimeInSeconds > toSeconds(biggestCueBeforeTime.timeInTimescale, track))) {
6527
- biggestCueBeforeTime = cue;
6528
- }
6529
- }
6530
- return biggestCueBeforeTime;
6531
- };
6532
- var findKeyframeBeforeTime2 = ({
6533
- keyframes,
6534
- time
6535
- }) => {
6536
- let keyframeBeforeTime;
6537
- for (const keyframe of keyframes) {
6538
- if (keyframe.decodingTimeInSeconds < time && (!keyframeBeforeTime || keyframe.decodingTimeInSeconds > keyframeBeforeTime.decodingTimeInSeconds)) {
6539
- keyframeBeforeTime = keyframe;
6540
- }
6541
- }
6542
- return keyframeBeforeTime?.positionInBytes ?? null;
6543
- };
6544
- var getByteFromCues = ({
6545
- cuesResponse,
6546
- time,
6547
- info,
6548
- logLevel
6549
- }) => {
6550
- if (!cuesResponse) {
6551
- Log.trace(logLevel, "Has no Matroska cues at the moment, cannot use them");
6552
- return null;
6553
- }
6554
- const { cues, segmentOffset } = cuesResponse;
6555
- Log.trace(logLevel, "Has Matroska cues. Will use them to perform a seek.");
6556
- const biggestCueBeforeTime = findBiggestCueBeforeTime({
6557
- cues,
6558
- time,
6559
- track: info.track
6560
- });
6561
- if (!biggestCueBeforeTime) {
6562
- return null;
6563
- }
6564
- return biggestCueBeforeTime.clusterPositionInSegment + segmentOffset;
6565
- };
6566
- var getSeekingByteFromMatroska = async ({
6567
- time,
6568
- webmState,
6569
- info,
6570
- logLevel,
6571
- mediaSection
6572
- }) => {
6573
- if (!info.track) {
6574
- Log.trace(logLevel, "No video track found, cannot seek yet");
6575
- return {
6576
- type: "valid-but-must-wait"
6577
- };
6578
- }
6579
- const cuesResponse = info.loadedCues ?? await webmState.cues.getLoadedCues();
6580
- const byteFromObservedKeyframe = findKeyframeBeforeTime2({
6581
- keyframes: info.keyframes,
6582
- time
6583
- });
6584
- const byteFromCues = getByteFromCues({
6585
- cuesResponse,
6586
- time,
6587
- info,
6588
- logLevel
6589
- });
6590
- const byteFromFirstMediaSection = webmState.getFirstCluster()?.start ?? null;
6591
- const seekPossibilities = [
6592
- byteFromCues,
6593
- byteFromObservedKeyframe,
6594
- byteFromFirstMediaSection
6595
- ].filter((n) => n !== null);
6596
- const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
6597
- if (byteToSeekTo === null) {
6598
- return {
6599
- type: "invalid"
6600
- };
6601
- }
6602
- mediaSection.addMediaSection({
6603
- start: byteToSeekTo,
6604
- size: 1
6605
- });
6606
- return {
6607
- type: "do-seek",
6608
- byte: byteToSeekTo
6560
+ byte: bestEntry.offset + info.moviOffset - 4,
6561
+ timeInSeconds: bestEntry.sampleCounts[idx1Entries.videoTrackIndex] / info.samplesPerSecond
6609
6562
  };
6610
6563
  };
6611
6564
 
@@ -7147,6 +7100,137 @@ var handleAvcPacket = async ({
7147
7100
  transportStream.lastEmittedSample.setLastEmittedSample(sample);
7148
7101
  };
7149
7102
 
7103
+ // src/containers/wav/get-seeking-byte.ts
7104
+ var WAVE_SAMPLES_PER_SECOND = 25;
7105
+ var getSeekingByteFromWav = ({
7106
+ info,
7107
+ time
7108
+ }) => {
7109
+ const bytesPerSecond = info.sampleRate * info.blockAlign;
7110
+ const durationInSeconds = info.mediaSection.size / bytesPerSecond;
7111
+ const timeRoundedDown = Math.floor(Math.min(time, durationInSeconds - 0.0000001) * WAVE_SAMPLES_PER_SECOND) / WAVE_SAMPLES_PER_SECOND;
7112
+ const byteOffset = bytesPerSecond * timeRoundedDown;
7113
+ return Promise.resolve({
7114
+ type: "do-seek",
7115
+ byte: byteOffset + info.mediaSection.start,
7116
+ timeInSeconds: timeRoundedDown
7117
+ });
7118
+ };
7119
+
7120
+ // src/containers/webm/seek/get-seeking-byte.ts
7121
+ var toSeconds = (timeInTimescale, track) => {
7122
+ return timeInTimescale / track.timescale * 1000;
7123
+ };
7124
+ var findBiggestCueBeforeTime = ({
7125
+ cues,
7126
+ time,
7127
+ track
7128
+ }) => {
7129
+ let biggestCueBeforeTime;
7130
+ for (const cue of cues) {
7131
+ const cueTimeInSeconds = toSeconds(cue.timeInTimescale, track);
7132
+ if (cueTimeInSeconds < time && (!biggestCueBeforeTime || cueTimeInSeconds > toSeconds(biggestCueBeforeTime.timeInTimescale, track))) {
7133
+ biggestCueBeforeTime = cue;
7134
+ }
7135
+ }
7136
+ return biggestCueBeforeTime;
7137
+ };
7138
+ var findKeyframeBeforeTime2 = ({
7139
+ keyframes,
7140
+ time
7141
+ }) => {
7142
+ let keyframeBeforeTime;
7143
+ for (const keyframe of keyframes) {
7144
+ if (keyframe.decodingTimeInSeconds < time && (!keyframeBeforeTime || keyframe.decodingTimeInSeconds > keyframeBeforeTime.decodingTimeInSeconds)) {
7145
+ keyframeBeforeTime = keyframe;
7146
+ }
7147
+ }
7148
+ return keyframeBeforeTime ?? null;
7149
+ };
7150
+ var getByteFromCues = ({
7151
+ cuesResponse,
7152
+ time,
7153
+ info,
7154
+ logLevel
7155
+ }) => {
7156
+ if (!cuesResponse) {
7157
+ Log.trace(logLevel, "Has no Matroska cues at the moment, cannot use them");
7158
+ return null;
7159
+ }
7160
+ const { cues, segmentOffset } = cuesResponse;
7161
+ Log.trace(logLevel, "Has Matroska cues. Will use them to perform a seek.");
7162
+ const biggestCueBeforeTime = findBiggestCueBeforeTime({
7163
+ cues,
7164
+ time,
7165
+ track: info.track
7166
+ });
7167
+ if (!biggestCueBeforeTime) {
7168
+ return null;
7169
+ }
7170
+ return {
7171
+ byte: biggestCueBeforeTime.clusterPositionInSegment + segmentOffset,
7172
+ timeInSeconds: toSeconds(biggestCueBeforeTime.timeInTimescale, info.track)
7173
+ };
7174
+ };
7175
+ var getSeekingByteFromMatroska = async ({
7176
+ time,
7177
+ webmState,
7178
+ info,
7179
+ logLevel,
7180
+ mediaSection
7181
+ }) => {
7182
+ if (!info.track) {
7183
+ Log.trace(logLevel, "No video track found, cannot seek yet");
7184
+ return {
7185
+ type: "valid-but-must-wait"
7186
+ };
7187
+ }
7188
+ const cuesResponse = info.loadedCues ?? await webmState.cues.getLoadedCues();
7189
+ const byteFromObservedKeyframe = findKeyframeBeforeTime2({
7190
+ keyframes: info.keyframes,
7191
+ time
7192
+ });
7193
+ const byteFromCues = getByteFromCues({
7194
+ cuesResponse,
7195
+ time,
7196
+ info,
7197
+ logLevel
7198
+ });
7199
+ const byteFromFirstMediaSection = webmState.getFirstCluster()?.start ?? null;
7200
+ const seekPossibilities = [
7201
+ byteFromCues?.byte ?? null,
7202
+ byteFromObservedKeyframe?.positionInBytes ?? null,
7203
+ byteFromFirstMediaSection
7204
+ ].filter((n) => n !== null);
7205
+ const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
7206
+ if (byteToSeekTo === null) {
7207
+ return {
7208
+ type: "invalid"
7209
+ };
7210
+ }
7211
+ mediaSection.addMediaSection({
7212
+ start: byteToSeekTo,
7213
+ size: 1
7214
+ });
7215
+ const timeInSeconds = (() => {
7216
+ if (byteToSeekTo === byteFromObservedKeyframe?.positionInBytes) {
7217
+ return Math.min(byteFromObservedKeyframe.decodingTimeInSeconds, byteFromObservedKeyframe.presentationTimeInSeconds);
7218
+ }
7219
+ if (byteToSeekTo === byteFromCues?.byte) {
7220
+ return byteFromCues.timeInSeconds;
7221
+ }
7222
+ if (byteToSeekTo === byteFromFirstMediaSection) {
7223
+ return 0;
7224
+ }
7225
+ throw new Error("Should not happen");
7226
+ })();
7227
+ return {
7228
+ type: "do-seek",
7229
+ byte: byteToSeekTo,
7230
+ timeInSeconds
7231
+ };
7232
+ };
7233
+
7150
7234
  // src/state/transport-stream/observed-pes-header.ts
7151
7235
  var makeObservedPesHeader = () => {
7152
7236
  const pesHeaders = [];
@@ -7236,7 +7320,8 @@ var getSeekingByte = ({
7236
7320
  if (byte) {
7237
7321
  return Promise.resolve({
7238
7322
  type: "do-seek",
7239
- byte
7323
+ byte: byte.offset,
7324
+ timeInSeconds: byte.timeInSeconds
7240
7325
  });
7241
7326
  }
7242
7327
  return Promise.resolve({
@@ -7249,11 +7334,20 @@ var getSeekingByte = ({
7249
7334
  timeInSeconds: time,
7250
7335
  ptsStartOffset: info.ptsStartOffset
7251
7336
  });
7252
- const byte = lastKeyframeBeforeTimeInSeconds?.offset ?? 0;
7337
+ if (!lastKeyframeBeforeTimeInSeconds) {
7338
+ transportStream.resetBeforeSeek();
7339
+ return Promise.resolve({
7340
+ type: "do-seek",
7341
+ byte: 0,
7342
+ timeInSeconds: 0
7343
+ });
7344
+ }
7345
+ const byte = lastKeyframeBeforeTimeInSeconds.offset;
7253
7346
  transportStream.resetBeforeSeek();
7254
7347
  return Promise.resolve({
7255
7348
  type: "do-seek",
7256
- byte
7349
+ byte,
7350
+ timeInSeconds: Math.min(lastKeyframeBeforeTimeInSeconds.pts, lastKeyframeBeforeTimeInSeconds.dts ?? Infinity) / MPEG_TIMESCALE
7257
7351
  });
7258
7352
  }
7259
7353
  if (info.type === "riff-seeking-hints") {
@@ -9136,7 +9230,8 @@ var calculateFlatSamples = ({
9136
9230
  const { samplePositions } = getSamplePositionsFromTrack({
9137
9231
  trakBox,
9138
9232
  moofBoxes: relevantMoofBox ? [relevantMoofBox] : [],
9139
- moofComplete
9233
+ moofComplete,
9234
+ trexBoxes: getTrexBoxes(moov)
9140
9235
  });
9141
9236
  return samplePositions.map((samplePosition) => {
9142
9237
  return {
@@ -9852,7 +9947,7 @@ var toUnixTimestamp = (value) => {
9852
9947
  return Math.floor(value + baseDate.getTime() / 1000) * 1000;
9853
9948
  };
9854
9949
 
9855
- // src/containers/iso-base-media/mvhd.ts
9950
+ // src/containers/iso-base-media/moov/mvhd.ts
9856
9951
  var parseMvhd = ({
9857
9952
  iterator,
9858
9953
  offset,
@@ -9908,6 +10003,34 @@ var parseMvhd = ({
9908
10003
  };
9909
10004
  };
9910
10005
 
10006
+ // src/containers/iso-base-media/moov/trex.ts
10007
+ var parseTrex = ({
10008
+ iterator,
10009
+ offset,
10010
+ size
10011
+ }) => {
10012
+ const box = iterator.startBox(size - 8);
10013
+ const version = iterator.getUint8();
10014
+ iterator.discard(3);
10015
+ const trackId = iterator.getUint32();
10016
+ const defaultSampleDescriptionIndex = iterator.getUint32();
10017
+ const defaultSampleDuration = iterator.getUint32();
10018
+ const defaultSampleSize = iterator.getUint32();
10019
+ const defaultSampleFlags = iterator.getUint32();
10020
+ box.expectNoMoreBytes();
10021
+ return {
10022
+ type: "trex-box",
10023
+ boxSize: size,
10024
+ offset,
10025
+ trackId,
10026
+ version,
10027
+ defaultSampleDescriptionIndex,
10028
+ defaultSampleDuration,
10029
+ defaultSampleSize,
10030
+ defaultSampleFlags
10031
+ };
10032
+ };
10033
+
9911
10034
  // src/containers/iso-base-media/stsd/av1c.ts
9912
10035
  var parseAv1C = ({
9913
10036
  data,
@@ -11280,10 +11403,16 @@ var processBox = async ({
11280
11403
  })
11281
11404
  };
11282
11405
  }
11406
+ if (boxType === "trex") {
11407
+ return {
11408
+ type: "box",
11409
+ box: await parseTrex({ iterator, offset: fileOffset, size: boxSize })
11410
+ };
11411
+ }
11283
11412
  if (boxType === "moof") {
11284
11413
  await onlyIfMoovAtomExpected?.isoState?.mfra.triggerLoad();
11285
11414
  }
11286
- 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") {
11415
+ 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") {
11287
11416
  const children = await getIsoBaseMediaChildren({
11288
11417
  iterator,
11289
11418
  size: boxSize - 8,
@@ -11303,6 +11432,7 @@ var processBox = async ({
11303
11432
  };
11304
11433
  }
11305
11434
  iterator.discard(boxSize - 8);
11435
+ Log.verbose(logLevel, "Unknown ISO Base Media Box:", boxType);
11306
11436
  return {
11307
11437
  type: "box",
11308
11438
  box: {
@@ -14647,10 +14777,11 @@ var parseList = ({
14647
14777
  const metadata = [];
14648
14778
  const remainingBytes = () => ckSize - (iterator.counter.getOffset() - startOffset);
14649
14779
  while (remainingBytes() > 0) {
14650
- if (remainingBytes() < 4) {
14651
- iterator.discard(remainingBytes());
14652
- break;
14780
+ const byte = iterator.getUint8();
14781
+ if (byte === 0) {
14782
+ continue;
14653
14783
  }
14784
+ iterator.counter.decrement(1);
14654
14785
  const key = iterator.getByteString(4, false);
14655
14786
  const size = iterator.getUint32Le();
14656
14787
  const value = iterator.getByteString(size, true);
@@ -16068,7 +16199,7 @@ var lazyMfraLoad = ({
16068
16199
  logLevel,
16069
16200
  prefetchCache
16070
16201
  }).then((boxes) => {
16071
- Log.verbose(logLevel, "Lazily found mfra atom.");
16202
+ Log.verbose(logLevel, boxes ? "Lazily found mfra atom." : "No mfra atom found.");
16072
16203
  result = boxes;
16073
16204
  return boxes;
16074
16205
  });
@@ -17595,6 +17726,46 @@ var internalParseMedia = async function({
17595
17726
  contentLength: state.contentLength,
17596
17727
  aacState: state.aac
17597
17728
  })));
17729
+ controller._internals.attachSimulateSeekResolution((seek2) => {
17730
+ const {
17731
+ aacState: aacState2,
17732
+ avcState: avcState2,
17733
+ flacState: flacState2,
17734
+ isoState,
17735
+ iterator,
17736
+ keyframes,
17737
+ m3uState: m3uState2,
17738
+ mediaSection,
17739
+ mp3State,
17740
+ riffState,
17741
+ samplesObserved,
17742
+ structureState: structureState2,
17743
+ tracksState,
17744
+ transportStream,
17745
+ webmState: webmState2
17746
+ } = getWorkOnSeekRequestOptions(state);
17747
+ return turnSeekIntoByte({
17748
+ aacState: aacState2,
17749
+ seek: seek2,
17750
+ avcState: avcState2,
17751
+ contentLength,
17752
+ flacState: flacState2,
17753
+ isoState,
17754
+ iterator,
17755
+ keyframes,
17756
+ logLevel,
17757
+ m3uPlaylistContext,
17758
+ m3uState: m3uState2,
17759
+ mediaSectionState: mediaSection,
17760
+ mp3State,
17761
+ riffState,
17762
+ samplesObserved,
17763
+ structureState: structureState2,
17764
+ tracksState,
17765
+ transportStream,
17766
+ webmState: webmState2
17767
+ });
17768
+ });
17598
17769
  if (!hasAudioTrackHandlers && !hasVideoTrackHandlers && Object.values(state.fields).every((v) => !v) && mode === "query") {
17599
17770
  Log.warn(logLevel, new Error("Warning - No `fields` and no `on*` callbacks were passed to `parseMedia()`. Specify the data you would like to retrieve."));
17600
17771
  }
@@ -17648,6 +17819,21 @@ var forwardMediaParserControllerToWorker = (controller) => {
17648
17819
  });
17649
17820
  return;
17650
17821
  }
17822
+ if (message.type === "request-simulate-seek") {
17823
+ controller.simulateSeek(message.payload).then((resolution) => {
17824
+ postMessage({
17825
+ type: "response-simulate-seek",
17826
+ nonce: message.nonce,
17827
+ payload: resolution
17828
+ });
17829
+ }).catch((err) => {
17830
+ postMessage({
17831
+ type: "response-error",
17832
+ payload: err
17833
+ });
17834
+ });
17835
+ return;
17836
+ }
17651
17837
  if (message.type === "request-resume") {
17652
17838
  controller.resume();
17653
17839
  return;