@remotion/media-parser 4.0.311 → 4.0.312

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 (33) 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/find-keyframe-before-time.d.ts +1 -1
  5. package/dist/containers/iso-base-media/find-keyframe-before-time.js +1 -1
  6. package/dist/containers/iso-base-media/get-seeking-byte-from-fragmented-mp4.js +3 -1
  7. package/dist/containers/iso-base-media/get-seeking-byte.js +3 -1
  8. package/dist/containers/m3u/get-seeking-byte.js +2 -0
  9. package/dist/containers/mp3/get-seeking-byte.js +4 -1
  10. package/dist/containers/riff/get-seeking-byte.js +3 -0
  11. package/dist/containers/wav/get-seeking-byte.js +1 -0
  12. package/dist/containers/wav/parse-list.js +4 -3
  13. package/dist/containers/webm/seek/get-seeking-byte.js +21 -6
  14. package/dist/controller/media-parser-controller.d.ts +3 -0
  15. package/dist/controller/media-parser-controller.js +15 -0
  16. package/dist/esm/index.mjs +226 -131
  17. package/dist/esm/server-worker.mjs +17 -0
  18. package/dist/esm/worker-server-entry.mjs +240 -130
  19. package/dist/esm/worker-web-entry.mjs +240 -130
  20. package/dist/esm/worker.mjs +28 -0
  21. package/dist/get-seeking-byte.js +13 -2
  22. package/dist/index.cjs +54 -0
  23. package/dist/index.d.ts +1 -0
  24. package/dist/internal-parse-media.js +25 -0
  25. package/dist/parse-media-on-worker-entry.js +17 -0
  26. package/dist/version.d.ts +1 -1
  27. package/dist/version.js +1 -1
  28. package/dist/webcodec-sample-types.d.ts +2 -2
  29. package/dist/work-on-seek-request.d.ts +22 -0
  30. package/dist/work-on-seek-request.js +3 -2
  31. package/dist/worker/forward-controller-to-worker.js +18 -0
  32. package/dist/worker/worker-types.d.ts +13 -2
  33. 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
  };
@@ -5844,7 +5859,11 @@ var getSeekingByteForAac = ({
5844
5859
  }
5845
5860
  }
5846
5861
  if (bestAudioSample) {
5847
- return { type: "do-seek", byte: bestAudioSample.offset };
5862
+ return {
5863
+ type: "do-seek",
5864
+ byte: bestAudioSample.offset,
5865
+ timeInSeconds: bestAudioSample.timeInSeconds
5866
+ };
5848
5867
  }
5849
5868
  return { type: "valid-but-must-wait" };
5850
5869
  };
@@ -5871,7 +5890,7 @@ var getSeekingByteForFlac = ({
5871
5890
  }
5872
5891
  }
5873
5892
  if (bestAudioSample) {
5874
- return bestAudioSample.offset;
5893
+ return bestAudioSample;
5875
5894
  }
5876
5895
  return null;
5877
5896
  };
@@ -5909,7 +5928,7 @@ var findKeyframeBeforeTime = ({
5909
5928
  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
5929
  return null;
5911
5930
  }
5912
- return videoSample.offset;
5931
+ return videoSample;
5913
5932
  };
5914
5933
 
5915
5934
  // src/containers/iso-base-media/find-track-to-seek.ts
@@ -6140,7 +6159,8 @@ var getSeekingByteFromFragmentedMp4 = async ({
6140
6159
  if (kf) {
6141
6160
  return {
6142
6161
  type: "do-seek",
6143
- byte: kf
6162
+ byte: kf.offset,
6163
+ timeInSeconds: Math.min(kf.decodingTimestamp, kf.timestamp) / firstTrack.originalTimescale
6144
6164
  };
6145
6165
  }
6146
6166
  }
@@ -6243,7 +6263,8 @@ var getSeekingByteFromIsoBaseMedia = ({
6243
6263
  if (keyframe) {
6244
6264
  return Promise.resolve({
6245
6265
  type: "do-seek",
6246
- byte: keyframe
6266
+ byte: keyframe.offset,
6267
+ timeInSeconds: Math.min(keyframe.decodingTimestamp, keyframe.timestamp) / track.originalTimescale
6247
6268
  });
6248
6269
  }
6249
6270
  return Promise.resolve({
@@ -6283,7 +6304,8 @@ var getSeekingByteForM3u8 = ({
6283
6304
  }
6284
6305
  return {
6285
6306
  type: "do-seek",
6286
- byte: currentPosition
6307
+ byte: currentPosition,
6308
+ timeInSeconds: time
6287
6309
  };
6288
6310
  };
6289
6311
 
@@ -6517,9 +6539,12 @@ var getSeekingByteForMp3 = ({
6517
6539
  type: "valid-but-must-wait"
6518
6540
  };
6519
6541
  }
6542
+ const byte = Math.max(...candidates);
6543
+ const timeInSeconds = byte === bestAudioSample?.offset ? bestAudioSample.timeInSeconds : time;
6520
6544
  return {
6521
6545
  type: "do-seek",
6522
- byte: Math.max(...candidates)
6546
+ byte,
6547
+ timeInSeconds
6523
6548
  };
6524
6549
  };
6525
6550
 
@@ -6563,7 +6588,8 @@ var getSeekingByteForRiff = async ({
6563
6588
  avcState.clear();
6564
6589
  return {
6565
6590
  type: "do-seek",
6566
- byte: lastKeyframe.positionInBytes
6591
+ byte: lastKeyframe.positionInBytes,
6592
+ timeInSeconds: Math.min(lastKeyframe.decodingTimeInSeconds, lastKeyframe.presentationTimeInSeconds)
6567
6593
  };
6568
6594
  }
6569
6595
  if (idx1Entries.videoTrackIndex === null) {
@@ -6594,121 +6620,8 @@ var getSeekingByteForRiff = async ({
6594
6620
  avcState.clear();
6595
6621
  return {
6596
6622
  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
6623
+ byte: bestEntry.offset + info.moviOffset - 4,
6624
+ timeInSeconds: bestEntry.sampleCounts[idx1Entries.videoTrackIndex] / info.samplesPerSecond
6712
6625
  };
6713
6626
  };
6714
6627
 
@@ -7250,6 +7163,137 @@ var handleAvcPacket = async ({
7250
7163
  transportStream.lastEmittedSample.setLastEmittedSample(sample);
7251
7164
  };
7252
7165
 
7166
+ // src/containers/wav/get-seeking-byte.ts
7167
+ var WAVE_SAMPLES_PER_SECOND = 25;
7168
+ var getSeekingByteFromWav = ({
7169
+ info,
7170
+ time
7171
+ }) => {
7172
+ const bytesPerSecond = info.sampleRate * info.blockAlign;
7173
+ const durationInSeconds = info.mediaSection.size / bytesPerSecond;
7174
+ const timeRoundedDown = Math.floor(Math.min(time, durationInSeconds - 0.0000001) * WAVE_SAMPLES_PER_SECOND) / WAVE_SAMPLES_PER_SECOND;
7175
+ const byteOffset = bytesPerSecond * timeRoundedDown;
7176
+ return Promise.resolve({
7177
+ type: "do-seek",
7178
+ byte: byteOffset + info.mediaSection.start,
7179
+ timeInSeconds: timeRoundedDown
7180
+ });
7181
+ };
7182
+
7183
+ // src/containers/webm/seek/get-seeking-byte.ts
7184
+ var toSeconds = (timeInTimescale, track) => {
7185
+ return timeInTimescale / track.timescale * 1000;
7186
+ };
7187
+ var findBiggestCueBeforeTime = ({
7188
+ cues,
7189
+ time,
7190
+ track
7191
+ }) => {
7192
+ let biggestCueBeforeTime;
7193
+ for (const cue of cues) {
7194
+ const cueTimeInSeconds = toSeconds(cue.timeInTimescale, track);
7195
+ if (cueTimeInSeconds < time && (!biggestCueBeforeTime || cueTimeInSeconds > toSeconds(biggestCueBeforeTime.timeInTimescale, track))) {
7196
+ biggestCueBeforeTime = cue;
7197
+ }
7198
+ }
7199
+ return biggestCueBeforeTime;
7200
+ };
7201
+ var findKeyframeBeforeTime2 = ({
7202
+ keyframes,
7203
+ time
7204
+ }) => {
7205
+ let keyframeBeforeTime;
7206
+ for (const keyframe of keyframes) {
7207
+ if (keyframe.decodingTimeInSeconds < time && (!keyframeBeforeTime || keyframe.decodingTimeInSeconds > keyframeBeforeTime.decodingTimeInSeconds)) {
7208
+ keyframeBeforeTime = keyframe;
7209
+ }
7210
+ }
7211
+ return keyframeBeforeTime ?? null;
7212
+ };
7213
+ var getByteFromCues = ({
7214
+ cuesResponse,
7215
+ time,
7216
+ info,
7217
+ logLevel
7218
+ }) => {
7219
+ if (!cuesResponse) {
7220
+ Log.trace(logLevel, "Has no Matroska cues at the moment, cannot use them");
7221
+ return null;
7222
+ }
7223
+ const { cues, segmentOffset } = cuesResponse;
7224
+ Log.trace(logLevel, "Has Matroska cues. Will use them to perform a seek.");
7225
+ const biggestCueBeforeTime = findBiggestCueBeforeTime({
7226
+ cues,
7227
+ time,
7228
+ track: info.track
7229
+ });
7230
+ if (!biggestCueBeforeTime) {
7231
+ return null;
7232
+ }
7233
+ return {
7234
+ byte: biggestCueBeforeTime.clusterPositionInSegment + segmentOffset,
7235
+ timeInSeconds: toSeconds(biggestCueBeforeTime.timeInTimescale, info.track)
7236
+ };
7237
+ };
7238
+ var getSeekingByteFromMatroska = async ({
7239
+ time,
7240
+ webmState,
7241
+ info,
7242
+ logLevel,
7243
+ mediaSection
7244
+ }) => {
7245
+ if (!info.track) {
7246
+ Log.trace(logLevel, "No video track found, cannot seek yet");
7247
+ return {
7248
+ type: "valid-but-must-wait"
7249
+ };
7250
+ }
7251
+ const cuesResponse = info.loadedCues ?? await webmState.cues.getLoadedCues();
7252
+ const byteFromObservedKeyframe = findKeyframeBeforeTime2({
7253
+ keyframes: info.keyframes,
7254
+ time
7255
+ });
7256
+ const byteFromCues = getByteFromCues({
7257
+ cuesResponse,
7258
+ time,
7259
+ info,
7260
+ logLevel
7261
+ });
7262
+ const byteFromFirstMediaSection = webmState.getFirstCluster()?.start ?? null;
7263
+ const seekPossibilities = [
7264
+ byteFromCues?.byte ?? null,
7265
+ byteFromObservedKeyframe?.positionInBytes ?? null,
7266
+ byteFromFirstMediaSection
7267
+ ].filter((n) => n !== null);
7268
+ const byteToSeekTo = seekPossibilities.length === 0 ? null : Math.max(...seekPossibilities);
7269
+ if (byteToSeekTo === null) {
7270
+ return {
7271
+ type: "invalid"
7272
+ };
7273
+ }
7274
+ mediaSection.addMediaSection({
7275
+ start: byteToSeekTo,
7276
+ size: 1
7277
+ });
7278
+ const timeInSeconds = (() => {
7279
+ if (byteToSeekTo === byteFromObservedKeyframe?.positionInBytes) {
7280
+ return Math.min(byteFromObservedKeyframe.decodingTimeInSeconds, byteFromObservedKeyframe.presentationTimeInSeconds);
7281
+ }
7282
+ if (byteToSeekTo === byteFromCues?.byte) {
7283
+ return byteFromCues.timeInSeconds;
7284
+ }
7285
+ if (byteToSeekTo === byteFromFirstMediaSection) {
7286
+ return 0;
7287
+ }
7288
+ throw new Error("Should not happen");
7289
+ })();
7290
+ return {
7291
+ type: "do-seek",
7292
+ byte: byteToSeekTo,
7293
+ timeInSeconds
7294
+ };
7295
+ };
7296
+
7253
7297
  // src/state/transport-stream/observed-pes-header.ts
7254
7298
  var makeObservedPesHeader = () => {
7255
7299
  const pesHeaders = [];
@@ -7339,7 +7383,8 @@ var getSeekingByte = ({
7339
7383
  if (byte) {
7340
7384
  return Promise.resolve({
7341
7385
  type: "do-seek",
7342
- byte
7386
+ byte: byte.offset,
7387
+ timeInSeconds: byte.timeInSeconds
7343
7388
  });
7344
7389
  }
7345
7390
  return Promise.resolve({
@@ -7352,11 +7397,20 @@ var getSeekingByte = ({
7352
7397
  timeInSeconds: time,
7353
7398
  ptsStartOffset: info.ptsStartOffset
7354
7399
  });
7355
- const byte = lastKeyframeBeforeTimeInSeconds?.offset ?? 0;
7400
+ if (!lastKeyframeBeforeTimeInSeconds) {
7401
+ transportStream.resetBeforeSeek();
7402
+ return Promise.resolve({
7403
+ type: "do-seek",
7404
+ byte: 0,
7405
+ timeInSeconds: 0
7406
+ });
7407
+ }
7408
+ const byte = lastKeyframeBeforeTimeInSeconds.offset;
7356
7409
  transportStream.resetBeforeSeek();
7357
7410
  return Promise.resolve({
7358
7411
  type: "do-seek",
7359
- byte
7412
+ byte,
7413
+ timeInSeconds: Math.min(lastKeyframeBeforeTimeInSeconds.pts, lastKeyframeBeforeTimeInSeconds.dts ?? Infinity) / MPEG_TIMESCALE
7360
7414
  });
7361
7415
  }
7362
7416
  if (info.type === "riff-seeking-hints") {
@@ -14778,10 +14832,11 @@ var parseList = ({
14778
14832
  const metadata = [];
14779
14833
  const remainingBytes = () => ckSize - (iterator.counter.getOffset() - startOffset);
14780
14834
  while (remainingBytes() > 0) {
14781
- if (remainingBytes() < 4) {
14782
- iterator.discard(remainingBytes());
14783
- break;
14835
+ const byte = iterator.getUint8();
14836
+ if (byte === 0) {
14837
+ continue;
14784
14838
  }
14839
+ iterator.counter.decrement(1);
14785
14840
  const key = iterator.getByteString(4, false);
14786
14841
  const size = iterator.getUint32Le();
14787
14842
  const value = iterator.getByteString(size, true);
@@ -17726,6 +17781,46 @@ var internalParseMedia = async function({
17726
17781
  contentLength: state.contentLength,
17727
17782
  aacState: state.aac
17728
17783
  })));
17784
+ controller._internals.attachSimulateSeekResolution((seek2) => {
17785
+ const {
17786
+ aacState: aacState2,
17787
+ avcState: avcState2,
17788
+ flacState: flacState2,
17789
+ isoState,
17790
+ iterator,
17791
+ keyframes,
17792
+ m3uState: m3uState2,
17793
+ mediaSection,
17794
+ mp3State,
17795
+ riffState,
17796
+ samplesObserved,
17797
+ structureState: structureState2,
17798
+ tracksState,
17799
+ transportStream,
17800
+ webmState: webmState2
17801
+ } = getWorkOnSeekRequestOptions(state);
17802
+ return turnSeekIntoByte({
17803
+ aacState: aacState2,
17804
+ seek: seek2,
17805
+ avcState: avcState2,
17806
+ contentLength,
17807
+ flacState: flacState2,
17808
+ isoState,
17809
+ iterator,
17810
+ keyframes,
17811
+ logLevel,
17812
+ m3uPlaylistContext,
17813
+ m3uState: m3uState2,
17814
+ mediaSectionState: mediaSection,
17815
+ mp3State,
17816
+ riffState,
17817
+ samplesObserved,
17818
+ structureState: structureState2,
17819
+ tracksState,
17820
+ transportStream,
17821
+ webmState: webmState2
17822
+ });
17823
+ });
17729
17824
  if (!hasAudioTrackHandlers && !hasVideoTrackHandlers && Object.values(state.fields).every((v) => !v) && mode === "query") {
17730
17825
  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
17826
  }
@@ -17779,6 +17874,21 @@ var forwardMediaParserControllerToWorker = (controller) => {
17779
17874
  });
17780
17875
  return;
17781
17876
  }
17877
+ if (message.type === "request-simulate-seek") {
17878
+ controller.simulateSeek(message.payload).then((resolution) => {
17879
+ postMessage({
17880
+ type: "response-simulate-seek",
17881
+ nonce: message.nonce,
17882
+ payload: resolution
17883
+ });
17884
+ }).catch((err) => {
17885
+ postMessage({
17886
+ type: "response-error",
17887
+ payload: err
17888
+ });
17889
+ });
17890
+ return;
17891
+ }
17782
17892
  if (message.type === "request-resume") {
17783
17893
  controller.resume();
17784
17894
  return;