@remotion/media 4.0.506 → 4.0.508

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.
@@ -40,7 +40,7 @@ var __callDispose = (stack, error, hasError) => {
40
40
  import { useMemo as useMemo3, useState as useState3 } from "react";
41
41
  import {
42
42
  Freeze,
43
- Internals as Internals17,
43
+ Internals as Internals18,
44
44
  Interactive,
45
45
  Sequence,
46
46
  useRemotionEnvironment as useRemotionEnvironment2,
@@ -78,7 +78,7 @@ var getLoopDisplay = ({
78
78
  // src/audio/audio-for-preview.tsx
79
79
  import { useContext as useContext2, useEffect, useMemo, useRef, useState } from "react";
80
80
  import {
81
- Internals as Internals7,
81
+ Internals as Internals8,
82
82
  Audio as RemotionAudio,
83
83
  useBufferState,
84
84
  useCurrentFrame,
@@ -137,7 +137,7 @@ var calculateEndTime = ({
137
137
  };
138
138
 
139
139
  // src/media-player.ts
140
- import { Internals as Internals5 } from "remotion";
140
+ import { Internals as Internals6 } from "remotion";
141
141
 
142
142
  // src/audio-iterator-manager.ts
143
143
  import {
@@ -868,6 +868,51 @@ var getDurationOrCompute = async (input) => {
868
868
  // src/get-shared-input.ts
869
869
  import { ALL_FORMATS, Input, UrlSource } from "mediabunny";
870
870
 
871
+ // src/max-cache-size.ts
872
+ import { cancelRender, Internals as Internals4 } from "remotion";
873
+ var getUncachedMaxCacheSize = (logLevel) => {
874
+ if (typeof window !== "undefined" && window.remotion_mediaCacheSizeInBytes !== undefined && window.remotion_mediaCacheSizeInBytes !== null) {
875
+ if (window.remotion_mediaCacheSizeInBytes < 240 * 1024 * 1024) {
876
+ cancelRender(new Error(`The minimum value for the "mediaCacheSizeInBytes" prop is 240MB (${240 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
877
+ }
878
+ if (window.remotion_mediaCacheSizeInBytes > 20000 * 1024 * 1024) {
879
+ cancelRender(new Error(`The maximum value for the "mediaCacheSizeInBytes" prop is 20GB (${20000 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
880
+ }
881
+ Internals4.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
882
+ return window.remotion_mediaCacheSizeInBytes;
883
+ }
884
+ if (typeof window !== "undefined" && window.remotion_initialMemoryAvailable !== undefined && window.remotion_initialMemoryAvailable !== null) {
885
+ const value = window.remotion_initialMemoryAvailable / 2;
886
+ if (value < 500 * 1024 * 1024) {
887
+ Internals4.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
888
+ return 500 * 1024 * 1024;
889
+ }
890
+ if (value > 20000 * 1024 * 1024) {
891
+ Internals4.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
892
+ return 20000 * 1024 * 1024;
893
+ }
894
+ Internals4.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
895
+ return value;
896
+ }
897
+ return 1000 * 1000 * 1000;
898
+ };
899
+ var cachedMaxCacheSize = null;
900
+ var getMaxVideoCacheSize = (logLevel) => {
901
+ if (cachedMaxCacheSize !== null) {
902
+ return cachedMaxCacheSize;
903
+ }
904
+ cachedMaxCacheSize = getUncachedMaxCacheSize(logLevel);
905
+ return cachedMaxCacheSize;
906
+ };
907
+ var MIN_SOURCE_CACHE_SIZE = 8 * 1024 * 1024;
908
+ var MAX_SOURCE_CACHE_SIZE = 64 * 1024 * 1024;
909
+ var getMaxSourceCacheSizeFromBudget = (budget) => {
910
+ return Math.min(MAX_SOURCE_CACHE_SIZE, Math.max(MIN_SOURCE_CACHE_SIZE, Math.floor(budget / 16)));
911
+ };
912
+ var getMaxSourceCacheSize = (logLevel) => {
913
+ return getMaxSourceCacheSizeFromBudget(getMaxVideoCacheSize(logLevel));
914
+ };
915
+
871
916
  // src/request-init.ts
872
917
  var normalizeMediaHeaders = (headers) => {
873
918
  if (!headers) {
@@ -950,7 +995,8 @@ var getSharedInputCacheKey = ({
950
995
  var acquireSharedInput = ({
951
996
  src,
952
997
  credentials,
953
- requestInit
998
+ requestInit,
999
+ logLevel
954
1000
  }) => {
955
1001
  const normalizedRequestInit = normalizeMediaRequestInit(requestInit);
956
1002
  const cacheKey = getSharedInputCacheKey({
@@ -968,7 +1014,10 @@ var acquireSharedInput = ({
968
1014
  requestInit: normalizedRequestInit
969
1015
  });
970
1016
  const input = new Input({
971
- source: new UrlSource(src, resolvedRequestInit ? { requestInit: resolvedRequestInit } : undefined),
1017
+ source: new UrlSource(src, {
1018
+ maxCacheSize: getMaxSourceCacheSize(logLevel),
1019
+ ...resolvedRequestInit ? { requestInit: resolvedRequestInit } : undefined
1020
+ }),
972
1021
  formats: ALL_FORMATS
973
1022
  });
974
1023
  sharedInputs[cacheKey] = { input, refCount: 1 };
@@ -1107,7 +1156,7 @@ class PremountAwareDelayPlayback {
1107
1156
 
1108
1157
  // src/video-iterator-manager.ts
1109
1158
  import { CanvasSink } from "mediabunny";
1110
- import { Internals as Internals4 } from "remotion";
1159
+ import { Internals as Internals5 } from "remotion";
1111
1160
 
1112
1161
  // src/helpers/round-to-4-digits.ts
1113
1162
  var roundTo4Digits = (timestamp) => {
@@ -1517,7 +1566,7 @@ var createVideoIterator = async (timeToSeek, cache) => {
1517
1566
  };
1518
1567
 
1519
1568
  // src/video-iterator-manager.ts
1520
- var { runEffectChain } = Internals4;
1569
+ var { runEffectChain } = Internals5;
1521
1570
  var isSequentialMediaTimeAdvance = ({
1522
1571
  previousTime,
1523
1572
  newTime,
@@ -1596,7 +1645,7 @@ var videoIteratorManager = async ({
1596
1645
  if (callback) {
1597
1646
  callback(frame.canvas);
1598
1647
  }
1599
- Internals4.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Drew frame ${frame.timestamp.toFixed(3)}s`);
1648
+ Internals5.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Drew frame ${frame.timestamp.toFixed(3)}s`);
1600
1649
  };
1601
1650
  const redrawCurrentFrame = async () => {
1602
1651
  if (!lastDrawnFrame) {
@@ -1608,7 +1657,7 @@ var videoIteratorManager = async ({
1608
1657
  if (callback) {
1609
1658
  callback(lastDrawnFrame.canvas);
1610
1659
  }
1611
- Internals4.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Redrew frame ${lastDrawnFrame.timestamp.toFixed(3)}s with updated effects`);
1660
+ Internals5.Log.trace({ logLevel, tag: "@remotion/media" }, `[MediaPlayer] Redrew frame ${lastDrawnFrame.timestamp.toFixed(3)}s with updated effects`);
1612
1661
  };
1613
1662
  const startVideoIterator = async (timeToSeek, nonce) => {
1614
1663
  let __stack = [];
@@ -1786,7 +1835,8 @@ class MediaPlayer {
1786
1835
  const { input, cacheKey } = acquireSharedInput({
1787
1836
  src: this.src,
1788
1837
  credentials,
1789
- requestInit
1838
+ requestInit,
1839
+ logLevel
1790
1840
  });
1791
1841
  this.input = input;
1792
1842
  this.inputCacheKey = cacheKey;
@@ -1858,7 +1908,7 @@ class MediaPlayer {
1858
1908
  if (isNetworkError(err)) {
1859
1909
  throw error;
1860
1910
  }
1861
- Internals5.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Failed to recognize format for ${this.src}`, error);
1911
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Failed to recognize format for ${this.src}`, error);
1862
1912
  return { type: "unknown-container-format" };
1863
1913
  }
1864
1914
  const [durationInSeconds, videoTrack, audioTracks] = await Promise.all([
@@ -1968,16 +2018,16 @@ class MediaPlayer {
1968
2018
  if (this.isDisposalError()) {
1969
2019
  return { type: "disposed" };
1970
2020
  }
1971
- Internals5.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to start audio and video iterators", error);
2021
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to start audio and video iterators", error);
1972
2022
  }
1973
2023
  return { type: "success", durationInSeconds };
1974
2024
  } catch (error) {
1975
2025
  const err = error;
1976
2026
  if (isNetworkError(err)) {
1977
- Internals5.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Network/CORS error for ${this.src}`, err);
2027
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, `[MediaPlayer] Network/CORS error for ${this.src}`, err);
1978
2028
  return { type: "network-error" };
1979
2029
  }
1980
- Internals5.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to initialize", error);
2030
+ Internals6.Log.error({ logLevel: this.logLevel, tag: "@remotion/media" }, "[MediaPlayer] Failed to initialize", error);
1981
2031
  throw error;
1982
2032
  }
1983
2033
  } catch (_catch) {
@@ -2273,7 +2323,7 @@ var callOnErrorAndResolve = ({
2273
2323
 
2274
2324
  // src/use-common-effects.ts
2275
2325
  import { useContext, useLayoutEffect } from "react";
2276
- import { Internals as Internals6 } from "remotion";
2326
+ import { Internals as Internals7 } from "remotion";
2277
2327
  var useCommonEffects = ({
2278
2328
  mediaPlayerRef,
2279
2329
  mediaPlayerReady,
@@ -2297,7 +2347,7 @@ var useCommonEffects = ({
2297
2347
  logLevel,
2298
2348
  label
2299
2349
  }) => {
2300
- const sharedAudioContext = useContext(Internals6.SharedAudioContext);
2350
+ const sharedAudioContext = useContext(Internals7.SharedAudioContext);
2301
2351
  useLayoutEffect(() => {
2302
2352
  const mediaPlayer = mediaPlayerRef.current;
2303
2353
  if (!mediaPlayer)
@@ -2415,7 +2465,7 @@ var useCommonEffects = ({
2415
2465
  if (!mediaPlayer || !mediaPlayerReady)
2416
2466
  return;
2417
2467
  mediaPlayer.seekTo(currentTime).catch(() => {});
2418
- Internals6.Log.trace({ logLevel, tag: "@remotion/media" }, `[${label}] Updating target time to ${currentTime.toFixed(3)}s`);
2468
+ Internals7.Log.trace({ logLevel, tag: "@remotion/media" }, `[${label}] Updating target time to ${currentTime.toFixed(3)}s`);
2419
2469
  }, [currentTime, logLevel, mediaPlayerReady, label, mediaPlayerRef]);
2420
2470
  };
2421
2471
 
@@ -2432,7 +2482,7 @@ var {
2432
2482
  warnAboutTooHighVolume,
2433
2483
  usePreload,
2434
2484
  SequenceContext
2435
- } = Internals7;
2485
+ } = Internals8;
2436
2486
  var AudioForPreviewAssertedShowing = ({
2437
2487
  src,
2438
2488
  playbackRate,
@@ -2465,7 +2515,7 @@ var AudioForPreviewAssertedShowing = ({
2465
2515
  const [mediaPlayerReady, setMediaPlayerReady] = useState(false);
2466
2516
  const [shouldFallbackToNativeAudio, setShouldFallbackToNativeAudio] = useState(false);
2467
2517
  const [playing] = Timeline.usePlayingState();
2468
- const { playbackRate: globalPlaybackRate } = Internals7.usePlaybackRate();
2518
+ const { playbackRate: globalPlaybackRate } = Internals8.usePlaybackRate();
2469
2519
  const sharedAudioContext = useContext2(SharedAudioContext);
2470
2520
  const buffer = useBufferState();
2471
2521
  const [playerMuted] = usePlayerMutedState();
@@ -2491,12 +2541,12 @@ var AudioForPreviewAssertedShowing = ({
2491
2541
  const isPremounting = Boolean(parentSequence?.premounting);
2492
2542
  const isPostmounting = Boolean(parentSequence?.postmounting);
2493
2543
  const sequenceOffset = (parentSequence?.absoluteFrom ?? 0) / videoConfig.fps;
2494
- const bufferingContext = useContext2(Internals7.BufferingContextReact);
2544
+ const bufferingContext = useContext2(Internals8.BufferingContextReact);
2495
2545
  if (!bufferingContext) {
2496
2546
  throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
2497
2547
  }
2498
2548
  const effectiveMuted = muted || playerMuted || userPreferredVolume <= 0;
2499
- const isPlayerBuffering = Internals7.useIsPlayerBuffering(bufferingContext);
2549
+ const isPlayerBuffering = Internals8.useIsPlayerBuffering(bufferingContext);
2500
2550
  const initialPlaying = useRef(playing && !isPlayerBuffering);
2501
2551
  const initialIsPremounting = useRef(isPremounting);
2502
2552
  const initialIsPostmounting = useRef(isPostmounting);
@@ -2592,7 +2642,7 @@ var AudioForPreviewAssertedShowing = ({
2592
2642
  if (action === "fail") {
2593
2643
  throw errorToUse;
2594
2644
  } else {
2595
- Internals7.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
2645
+ Internals8.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
2596
2646
  setShouldFallbackToNativeAudio(true);
2597
2647
  }
2598
2648
  };
@@ -2618,7 +2668,7 @@ var AudioForPreviewAssertedShowing = ({
2618
2668
  if (result.type === "success") {
2619
2669
  setMediaPlayerReady(true);
2620
2670
  setMediaDurationInSeconds(result.durationInSeconds);
2621
- Internals7.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] MediaPlayer initialized successfully`);
2671
+ Internals8.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] MediaPlayer initialized successfully`);
2622
2672
  }
2623
2673
  }).catch((error) => {
2624
2674
  const [action, errorToUse] = callOnErrorAndResolve({
@@ -2631,7 +2681,7 @@ var AudioForPreviewAssertedShowing = ({
2631
2681
  if (action === "fail") {
2632
2682
  throw errorToUse;
2633
2683
  } else {
2634
- Internals7.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] Failed to initialize MediaPlayer", error);
2684
+ Internals8.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] Failed to initialize MediaPlayer", error);
2635
2685
  setShouldFallbackToNativeAudio(true);
2636
2686
  }
2637
2687
  });
@@ -2646,12 +2696,12 @@ var AudioForPreviewAssertedShowing = ({
2646
2696
  if (action === "fail") {
2647
2697
  throw errorToUse;
2648
2698
  }
2649
- Internals7.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] MediaPlayer initialization failed", errorToUse);
2699
+ Internals8.Log.error({ logLevel, tag: "@remotion/media" }, "[AudioForPreview] MediaPlayer initialization failed", errorToUse);
2650
2700
  setShouldFallbackToNativeAudio(true);
2651
2701
  }
2652
2702
  return () => {
2653
2703
  if (mediaPlayerRef.current) {
2654
- Internals7.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Disposing MediaPlayer`);
2704
+ Internals8.Log.trace({ logLevel, tag: "@remotion/media" }, `[AudioForPreview] Disposing MediaPlayer`);
2655
2705
  mediaPlayerRef.current.dispose();
2656
2706
  mediaPlayerRef.current = null;
2657
2707
  }
@@ -2719,7 +2769,7 @@ var AudioForPreview = ({
2719
2769
  style
2720
2770
  }) => {
2721
2771
  const preloadedSrc = usePreload(src);
2722
- const defaultLogLevel = Internals7.useLogLevel();
2772
+ const defaultLogLevel = Internals8.useLogLevel();
2723
2773
  const frame = useCurrentFrame();
2724
2774
  const videoConfig = useVideoConfig();
2725
2775
  const currentTime = frame / videoConfig.fps;
@@ -2780,7 +2830,7 @@ import { useContext as useContext3, useLayoutEffect as useLayoutEffect2, useMemo
2780
2830
  import {
2781
2831
  cancelRender as cancelRender2,
2782
2832
  Html5Audio,
2783
- Internals as Internals16,
2833
+ Internals as Internals17,
2784
2834
  random,
2785
2835
  useCurrentFrame as useCurrentFrame2,
2786
2836
  useDelayRender,
@@ -2789,15 +2839,28 @@ import {
2789
2839
 
2790
2840
  // src/caches.ts
2791
2841
  import React2 from "react";
2792
- import { cancelRender, Internals as Internals12 } from "remotion";
2842
+ import { Internals as Internals15 } from "remotion";
2793
2843
 
2794
2844
  // src/audio-extraction/audio-manager.ts
2795
- import { Internals as Internals9 } from "remotion";
2845
+ import { Internals as Internals10 } from "remotion";
2796
2846
 
2797
2847
  // src/audio-extraction/audio-iterator.ts
2798
- import { Internals as Internals8 } from "remotion";
2848
+ import { Internals as Internals9 } from "remotion";
2799
2849
 
2800
2850
  // src/audio-extraction/audio-cache.ts
2851
+ var BYTES_PER_SAMPLE = {
2852
+ u8: 1,
2853
+ s16: 2,
2854
+ s32: 4,
2855
+ f32: 4,
2856
+ "u8-planar": 1,
2857
+ "s16-planar": 2,
2858
+ "s32-planar": 4,
2859
+ "f32-planar": 4
2860
+ };
2861
+ var getAudioSampleByteSize = (sample) => {
2862
+ return sample.numberOfFrames * sample.numberOfChannels * BYTES_PER_SAMPLE[sample.format];
2863
+ };
2801
2864
  var makeAudioCache = () => {
2802
2865
  const timestamps = [];
2803
2866
  const samples = {};
@@ -2844,6 +2907,13 @@ var makeAudioCache = () => {
2844
2907
  const getOpenTimestamps = () => {
2845
2908
  return timestamps;
2846
2909
  };
2910
+ const getTotalSize = () => {
2911
+ let total = 0;
2912
+ for (const timestamp of timestamps) {
2913
+ total += getAudioSampleByteSize(samples[timestamp]);
2914
+ }
2915
+ return total;
2916
+ };
2847
2917
  const getOldestTimestamp = () => {
2848
2918
  return timestamps[0];
2849
2919
  };
@@ -2861,7 +2931,8 @@ var makeAudioCache = () => {
2861
2931
  getSamples,
2862
2932
  getOldestTimestamp,
2863
2933
  getNewestTimestamp,
2864
- getOpenTimestamps
2934
+ getOpenTimestamps,
2935
+ getTotalSize
2865
2936
  };
2866
2937
  };
2867
2938
 
@@ -2874,7 +2945,7 @@ var warnAboutMatroskaOnce = (src, logLevel) => {
2874
2945
  return;
2875
2946
  }
2876
2947
  warned[src] = true;
2877
- Internals8.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio from ${src} will need to be read from the beginning. https://www.remotion.dev/docs/media/support#matroska-limitation`);
2948
+ Internals9.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio from ${src} will need to be read from the beginning. https://www.remotion.dev/docs/media/support#matroska-limitation`);
2878
2949
  };
2879
2950
  var makeAudioIterator2 = ({
2880
2951
  audioSampleSink,
@@ -2942,13 +3013,13 @@ var makeAudioIterator2 = ({
2942
3013
  if (openTimestamps.length > 0) {
2943
3014
  const first = openTimestamps[0];
2944
3015
  const last = openTimestamps[openTimestamps.length - 1];
2945
- Internals8.Log.verbose({ logLevel, tag: "@remotion/media" }, "Open audio samples for src", src, `${first.toFixed(3)}...${last.toFixed(3)}`);
3016
+ Internals9.Log.verbose({ logLevel, tag: "@remotion/media" }, "Open audio samples for src", src, `${first.toFixed(3)}...${last.toFixed(3)}`);
2946
3017
  }
2947
3018
  };
2948
3019
  const getCacheStats = () => {
2949
3020
  return {
2950
3021
  count: cache.getOpenTimestamps().length,
2951
- size: cache.getOpenTimestamps().reduce((acc, t) => acc + t, 0)
3022
+ size: cache.getTotalSize()
2952
3023
  };
2953
3024
  };
2954
3025
  const canSatisfyRequestedTime = (timestamp) => {
@@ -2991,8 +3062,11 @@ var makeAudioIterator2 = ({
2991
3062
  };
2992
3063
 
2993
3064
  // src/audio-extraction/audio-manager.ts
2994
- var makeAudioManager = () => {
3065
+ var makeAudioManager = ({
3066
+ getTotalCacheStats
3067
+ }) => {
2995
3068
  const iterators = [];
3069
+ let disposed = false;
2996
3070
  const makeIterator = ({
2997
3071
  timeInSeconds,
2998
3072
  src,
@@ -3039,7 +3113,7 @@ var makeAudioManager = () => {
3039
3113
  if (seenKeys.has(key)) {
3040
3114
  iterator.prepareForDeletion();
3041
3115
  iterators.splice(iterators.indexOf(iterator), 1);
3042
- Internals9.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted duplicate iterator for ${iterator.src}`);
3116
+ Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted duplicate iterator for ${iterator.src}`);
3043
3117
  }
3044
3118
  seenKeys.add(key);
3045
3119
  }
@@ -3053,6 +3127,9 @@ var makeAudioManager = () => {
3053
3127
  logLevel,
3054
3128
  maxCacheSize
3055
3129
  }) => {
3130
+ if (disposed) {
3131
+ throw new Error("Media cache has already been disposed");
3132
+ }
3056
3133
  let attempts = 0;
3057
3134
  const maxAttempts = 3;
3058
3135
  while ((await getTotalCacheStats()).totalSize > maxCacheSize && attempts < maxAttempts) {
@@ -3060,7 +3137,7 @@ var makeAudioManager = () => {
3060
3137
  attempts++;
3061
3138
  }
3062
3139
  if ((await getTotalCacheStats()).totalSize > maxCacheSize && attempts >= maxAttempts) {
3063
- Internals9.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
3140
+ Internals10.Log.warn({ logLevel, tag: "@remotion/media" }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
3064
3141
  }
3065
3142
  for (const iterator of iterators) {
3066
3143
  if (iterator.src === src && await iterator.waitForCompletion() && iterator.canSatisfyRequestedTime(timeInSeconds)) {
@@ -3075,6 +3152,9 @@ var makeAudioManager = () => {
3075
3152
  }
3076
3153
  }
3077
3154
  deleteDuplicateIterators(logLevel);
3155
+ if (disposed) {
3156
+ throw new Error("Media cache has already been disposed");
3157
+ }
3078
3158
  return makeIterator({
3079
3159
  src,
3080
3160
  timeInSeconds,
@@ -3099,6 +3179,19 @@ var makeAudioManager = () => {
3099
3179
  iterator.logOpenFrames();
3100
3180
  }
3101
3181
  };
3182
+ const clearAll = () => {
3183
+ for (const iterator of iterators) {
3184
+ iterator.prepareForDeletion();
3185
+ }
3186
+ iterators.length = 0;
3187
+ };
3188
+ const dispose = () => {
3189
+ if (disposed) {
3190
+ return;
3191
+ }
3192
+ disposed = true;
3193
+ clearAll();
3194
+ };
3102
3195
  let queue = Promise.resolve(undefined);
3103
3196
  return {
3104
3197
  getIterator: ({
@@ -3124,13 +3217,252 @@ var makeAudioManager = () => {
3124
3217
  getCacheStats,
3125
3218
  getIteratorMostInThePast,
3126
3219
  logOpenFrames,
3127
- deleteDuplicateIterators
3220
+ deleteDuplicateIterators,
3221
+ clearAll,
3222
+ dispose
3128
3223
  };
3129
3224
  };
3130
3225
 
3131
- // src/video-extraction/keyframe-manager.ts
3226
+ // src/get-sink.ts
3227
+ import { Internals as Internals12 } from "remotion";
3228
+
3229
+ // src/video-extraction/get-frames-since-keyframe.ts
3230
+ import {
3231
+ ALL_FORMATS as ALL_FORMATS2,
3232
+ AudioSampleSink,
3233
+ EncodedPacketSink,
3234
+ Input as Input2,
3235
+ MATROSKA,
3236
+ UrlSource as UrlSource2,
3237
+ VideoSampleSink,
3238
+ WEBM
3239
+ } from "mediabunny";
3132
3240
  import { Internals as Internals11 } from "remotion";
3133
3241
 
3242
+ // src/browser-can-use-webgl2.ts
3243
+ var browserCanUseWebGl2 = null;
3244
+ var browserCanUseWebGl2Uncached = () => {
3245
+ const canvas = new OffscreenCanvas(1, 1);
3246
+ const context = canvas.getContext("webgl2");
3247
+ return context !== null;
3248
+ };
3249
+ var canBrowserUseWebGl2 = () => {
3250
+ if (browserCanUseWebGl2 !== null) {
3251
+ return browserCanUseWebGl2;
3252
+ }
3253
+ browserCanUseWebGl2 = browserCanUseWebGl2Uncached();
3254
+ return browserCanUseWebGl2;
3255
+ };
3256
+
3257
+ // src/video-extraction/remember-actual-matroska-timestamps.ts
3258
+ var rememberActualMatroskaTimestamps = (isMatroska) => {
3259
+ const observations = [];
3260
+ const observeTimestamp = (startTime) => {
3261
+ if (!isMatroska) {
3262
+ return;
3263
+ }
3264
+ observations.push(startTime);
3265
+ };
3266
+ const getRealTimestamp = (observedTimestamp) => {
3267
+ if (!isMatroska) {
3268
+ return observedTimestamp;
3269
+ }
3270
+ return observations.find((observation) => Math.abs(observedTimestamp - observation) < 0.001) ?? null;
3271
+ };
3272
+ return {
3273
+ observeTimestamp,
3274
+ getRealTimestamp
3275
+ };
3276
+ };
3277
+
3278
+ // src/video-extraction/get-frames-since-keyframe.ts
3279
+ var getRetryDelay = () => {
3280
+ return null;
3281
+ };
3282
+ var getFormatOrNullOrNetworkError = async (input) => {
3283
+ try {
3284
+ return await input.getFormat();
3285
+ } catch (err) {
3286
+ if (isNetworkError(err)) {
3287
+ return "network-error";
3288
+ }
3289
+ return null;
3290
+ }
3291
+ };
3292
+ var makeSinks = (src, logLevel, credentials, requestInit) => {
3293
+ const resolvedRequestInit = resolveRequestInit({ credentials, requestInit });
3294
+ const input = new Input2({
3295
+ formats: ALL_FORMATS2,
3296
+ source: new UrlSource2(src, {
3297
+ getRetryDelay,
3298
+ maxCacheSize: getMaxSourceCacheSize(logLevel),
3299
+ ...resolvedRequestInit ? { requestInit: resolvedRequestInit } : undefined
3300
+ })
3301
+ });
3302
+ const getSinks = async () => {
3303
+ const format = await getFormatOrNullOrNetworkError(input);
3304
+ const isMatroska = format === MATROSKA || format === WEBM;
3305
+ const getVideoSinks = async () => {
3306
+ if (format === "network-error") {
3307
+ return "network-error";
3308
+ }
3309
+ if (format === null) {
3310
+ return "unknown-container-format";
3311
+ }
3312
+ const videoTrack = await input.getPrimaryVideoTrack();
3313
+ if (!videoTrack) {
3314
+ return "no-video-track";
3315
+ }
3316
+ if (await videoTrack.isLive()) {
3317
+ throw new Error("Live streams are not currently supported by Remotion. Sorry! Source: " + src);
3318
+ }
3319
+ if (await videoTrack.isRelativeToUnixEpoch()) {
3320
+ throw new Error("Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: " + src);
3321
+ }
3322
+ const canDecode = await videoTrack.canDecode();
3323
+ if (!canDecode) {
3324
+ if (videoTrack.codec === "prores") {
3325
+ return "cannot-decode-prores";
3326
+ }
3327
+ return "cannot-decode";
3328
+ }
3329
+ const sampleSink = new VideoSampleSink(videoTrack);
3330
+ const packetSink = new EncodedPacketSink(videoTrack);
3331
+ const startPacket = await packetSink.getFirstPacket({
3332
+ verifyKeyPackets: true
3333
+ });
3334
+ const hasAlpha = startPacket?.sideData.alpha;
3335
+ if (hasAlpha && !canBrowserUseWebGl2()) {
3336
+ Internals11.Log.warn({ logLevel, tag: "@remotion/media" }, `WebGL2 is not available, using the non-fast CPU path to decode alpha for ${src}.`);
3337
+ }
3338
+ return {
3339
+ sampleSink
3340
+ };
3341
+ };
3342
+ let videoSinksPromise = null;
3343
+ const getVideoSinksPromise = () => {
3344
+ if (videoSinksPromise) {
3345
+ return videoSinksPromise;
3346
+ }
3347
+ videoSinksPromise = getVideoSinks();
3348
+ return videoSinksPromise;
3349
+ };
3350
+ const audioSinksPromise = {};
3351
+ const getAudioSinks = async (index) => {
3352
+ if (format === null) {
3353
+ return "unknown-container-format";
3354
+ }
3355
+ if (format === "network-error") {
3356
+ return "network-error";
3357
+ }
3358
+ const [videoTrack, audioTracks] = await Promise.all([
3359
+ input.getPrimaryVideoTrack(),
3360
+ input.getAudioTracks()
3361
+ ]);
3362
+ const audioTrack = await resolveAudioTrack({
3363
+ videoTrack,
3364
+ audioTracks,
3365
+ audioStreamIndex: index
3366
+ });
3367
+ if (!audioTrack) {
3368
+ return "no-audio-track";
3369
+ }
3370
+ const canDecode = await audioTrack.canDecode();
3371
+ if (!canDecode) {
3372
+ return "cannot-decode-audio";
3373
+ }
3374
+ return {
3375
+ sampleSink: new AudioSampleSink(audioTrack)
3376
+ };
3377
+ };
3378
+ const getAudioSinksPromise = (index) => {
3379
+ const keyIndex = index === null ? -1 : index;
3380
+ if (audioSinksPromise[keyIndex]) {
3381
+ return audioSinksPromise[keyIndex];
3382
+ }
3383
+ audioSinksPromise[keyIndex] = getAudioSinks(index);
3384
+ return audioSinksPromise[keyIndex];
3385
+ };
3386
+ return {
3387
+ getVideo: () => getVideoSinksPromise(),
3388
+ getAudio: (index) => getAudioSinksPromise(index),
3389
+ actualMatroskaTimestamps: rememberActualMatroskaTimestamps(isMatroska),
3390
+ isMatroska,
3391
+ getDuration: () => {
3392
+ return getDurationOrCompute(input);
3393
+ }
3394
+ };
3395
+ };
3396
+ return {
3397
+ promise: getSinks(),
3398
+ dispose: () => input.dispose()
3399
+ };
3400
+ };
3401
+
3402
+ // src/get-sink.ts
3403
+ var getSinkCacheKey = ({
3404
+ src,
3405
+ credentials,
3406
+ requestInit
3407
+ }) => JSON.stringify([
3408
+ src,
3409
+ credentials,
3410
+ getMediaRequestInitFingerprint(requestInit)
3411
+ ]);
3412
+ var makeSinkManager = () => {
3413
+ const sinkPromises = {};
3414
+ const inputDisposers = {};
3415
+ let disposed = false;
3416
+ return {
3417
+ getSink: (src, logLevel, credentials, requestInit) => {
3418
+ if (disposed) {
3419
+ return Promise.reject(new Error("Media cache has already been disposed"));
3420
+ }
3421
+ const normalizedRequestInit = normalizeMediaRequestInit(requestInit);
3422
+ const cacheKey = getSinkCacheKey({
3423
+ src,
3424
+ credentials,
3425
+ requestInit: normalizedRequestInit
3426
+ });
3427
+ let promise = sinkPromises[cacheKey];
3428
+ if (!promise) {
3429
+ Internals12.Log.verbose({
3430
+ logLevel,
3431
+ tag: "@remotion/media"
3432
+ }, `Sink for ${src} was not found, creating new sink`);
3433
+ const sinks = makeSinks(src, logLevel, credentials, normalizedRequestInit);
3434
+ promise = sinks.promise;
3435
+ sinkPromises[cacheKey] = promise;
3436
+ inputDisposers[cacheKey] = sinks.dispose;
3437
+ }
3438
+ return promise;
3439
+ },
3440
+ dispose: () => {
3441
+ if (disposed) {
3442
+ return;
3443
+ }
3444
+ disposed = true;
3445
+ let firstError = null;
3446
+ for (const cacheKey of Object.keys(inputDisposers)) {
3447
+ try {
3448
+ inputDisposers[cacheKey]();
3449
+ } catch (error) {
3450
+ firstError ??= error;
3451
+ } finally {
3452
+ delete inputDisposers[cacheKey];
3453
+ delete sinkPromises[cacheKey];
3454
+ }
3455
+ }
3456
+ if (firstError !== null) {
3457
+ throw firstError;
3458
+ }
3459
+ }
3460
+ };
3461
+ };
3462
+
3463
+ // src/video-extraction/keyframe-manager.ts
3464
+ import { Internals as Internals14 } from "remotion";
3465
+
3134
3466
  // src/render-timestamp-range.ts
3135
3467
  var renderTimestampRange = (timestamps) => {
3136
3468
  if (timestamps.length === 0) {
@@ -3143,12 +3475,13 @@ var renderTimestampRange = (timestamps) => {
3143
3475
  };
3144
3476
 
3145
3477
  // src/video-extraction/keyframe-bank.ts
3146
- import { Internals as Internals10 } from "remotion";
3478
+ import { Internals as Internals13 } from "remotion";
3147
3479
 
3148
3480
  // src/video-extraction/get-allocation-size.ts
3481
+ var BYTES_PER_PIXEL_FOR_OPAQUE_FRAME = 3;
3149
3482
  var getAllocationSize = (sample) => {
3150
3483
  if (sample.format === null) {
3151
- return sample.codedHeight * sample.codedWidth * 4;
3484
+ return sample.codedHeight * sample.codedWidth * BYTES_PER_PIXEL_FOR_OPAQUE_FRAME;
3152
3485
  }
3153
3486
  return sample.allocationSize();
3154
3487
  };
@@ -3167,6 +3500,7 @@ var makeKeyframeBank = async ({
3167
3500
  let hasReachedEndOfVideo = false;
3168
3501
  let lastUsed = Date.now();
3169
3502
  let allocationSize = 0;
3503
+ let pendingOperations = 0;
3170
3504
  const getMeasuredDurationOfFrame = (timestamp) => {
3171
3505
  const index = frameTimestamps.indexOf(timestamp);
3172
3506
  if (index === -1) {
@@ -3222,7 +3556,7 @@ var makeKeyframeBank = async ({
3222
3556
  }
3223
3557
  }
3224
3558
  if (deletedTimestamps.length > 0) {
3225
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
3559
+ Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
3226
3560
  }
3227
3561
  };
3228
3562
  const hasDecodedEnoughForTimestamp = (timestamp) => {
@@ -3251,7 +3585,7 @@ var makeKeyframeBank = async ({
3251
3585
  frameTimestamps.push(frame.timestamp);
3252
3586
  allocationSize += getAllocationSize(frame);
3253
3587
  lastUsed = Date.now();
3254
- Internals10.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
3588
+ Internals13.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
3255
3589
  };
3256
3590
  const ensureEnoughFramesForTimestamp = async (timestampInSeconds, logLevel, fps) => {
3257
3591
  while (!hasDecodedEnoughForTimestamp(timestampInSeconds)) {
@@ -3306,7 +3640,7 @@ var makeKeyframeBank = async ({
3306
3640
  throw new Error("No first frame found");
3307
3641
  }
3308
3642
  const startTimestampInSeconds = firstFrame.value.timestamp;
3309
- Internals10.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
3643
+ Internals13.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
3310
3644
  addFrame(firstFrame.value, parentLogLevel);
3311
3645
  const getRangeOfTimestamps = () => {
3312
3646
  if (frameTimestamps.length === 0) {
@@ -3323,7 +3657,7 @@ var makeKeyframeBank = async ({
3323
3657
  const prepareForDeletion = (logLevel, reason) => {
3324
3658
  const range = getRangeOfTimestamps();
3325
3659
  if (range) {
3326
- Internals10.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
3660
+ Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
3327
3661
  }
3328
3662
  let framesDeleted = 0;
3329
3663
  for (const frameTimestamp of frameTimestamps.slice()) {
@@ -3364,12 +3698,18 @@ var makeKeyframeBank = async ({
3364
3698
  };
3365
3699
  const keyframeBank = {
3366
3700
  getFrameFromTimestamp: (timestamp, fps) => {
3367
- queue = queue.then(() => getFrameFromTimestamp(timestamp, fps));
3701
+ pendingOperations++;
3702
+ queue = queue.then(() => getFrameFromTimestamp(timestamp, fps)).finally(() => {
3703
+ pendingOperations--;
3704
+ });
3368
3705
  return queue;
3369
3706
  },
3370
3707
  prepareForDeletion,
3371
3708
  hasTimestampInSecond: (timestamp, fps) => {
3372
- queue = queue.then(() => hasTimestampInSecond(timestamp, fps));
3709
+ pendingOperations++;
3710
+ queue = queue.then(() => hasTimestampInSecond(timestamp, fps)).finally(() => {
3711
+ pendingOperations--;
3712
+ });
3373
3713
  return queue;
3374
3714
  },
3375
3715
  addFrame,
@@ -3377,6 +3717,7 @@ var makeKeyframeBank = async ({
3377
3717
  src,
3378
3718
  getOpenFrameCount,
3379
3719
  getLastUsed,
3720
+ isBusy: () => pendingOperations > 0,
3380
3721
  canSatisfyTimestamp,
3381
3722
  getRangeOfTimestamps
3382
3723
  };
@@ -3384,11 +3725,26 @@ var makeKeyframeBank = async ({
3384
3725
  };
3385
3726
 
3386
3727
  // src/video-extraction/keyframe-manager.ts
3387
- var makeKeyframeManager = () => {
3728
+ var RECENTLY_USED_REQUEST_COUNT = 50;
3729
+ var makeKeyframeManager = ({
3730
+ getTotalCacheStats
3731
+ }) => {
3388
3732
  let sources = {};
3389
- const addKeyframeBank = ({ src, bank }) => {
3733
+ let disposed = false;
3734
+ let requestCountForSrc = {};
3735
+ const lastRequestForBank = new WeakMap;
3736
+ const addKeyframeBank = ({
3737
+ src,
3738
+ bank,
3739
+ logLevel
3740
+ }) => {
3741
+ if (disposed) {
3742
+ bank.prepareForDeletion(logLevel, "media cache was disposed");
3743
+ return false;
3744
+ }
3390
3745
  sources[src] = sources[src] ?? [];
3391
3746
  sources[src].push(bank);
3747
+ return true;
3392
3748
  };
3393
3749
  const logCacheStats = (logLevel) => {
3394
3750
  let count = 0;
@@ -3401,10 +3757,10 @@ var makeKeyframeManager = () => {
3401
3757
  if (size === 0) {
3402
3758
  continue;
3403
3759
  }
3404
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
3760
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
3405
3761
  }
3406
3762
  }
3407
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
3763
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
3408
3764
  };
3409
3765
  const getCacheStats = () => {
3410
3766
  let count = 0;
@@ -3427,39 +3783,34 @@ var makeKeyframeManager = () => {
3427
3783
  let numberOfBanks = 0;
3428
3784
  for (const src in sources) {
3429
3785
  for (const bank of sources[src]) {
3786
+ numberOfBanks++;
3787
+ if (bank.isBusy()) {
3788
+ continue;
3789
+ }
3430
3790
  const index = sources[src].indexOf(bank);
3431
3791
  const lastUsed = bank.getLastUsed();
3432
3792
  if (mostInThePast === null || lastUsed < mostInThePast) {
3433
3793
  mostInThePast = lastUsed;
3434
3794
  mostInThePastBank = { src, bank, index };
3435
3795
  }
3436
- numberOfBanks++;
3437
3796
  }
3438
3797
  }
3439
3798
  if (!mostInThePastBank) {
3440
- throw new Error("No keyframe bank found");
3799
+ return { mostInThePastBank: null, numberOfBanks };
3441
3800
  }
3442
3801
  return { mostInThePastBank, numberOfBanks };
3443
3802
  };
3444
3803
  const deleteOldestKeyframeBank = (logLevel) => {
3445
- const {
3446
- mostInThePastBank: {
3447
- bank: mostInThePastBank,
3448
- src: mostInThePastSrc,
3449
- index: mostInThePastIndex
3450
- },
3451
- numberOfBanks
3452
- } = getTheKeyframeBankMostInThePast();
3453
- if (numberOfBanks < 2) {
3804
+ const { mostInThePastBank, numberOfBanks } = getTheKeyframeBankMostInThePast();
3805
+ if (numberOfBanks < 2 || mostInThePastBank === null) {
3454
3806
  return { finish: true };
3455
3807
  }
3456
- if (mostInThePastBank) {
3457
- const range = mostInThePastBank.getRangeOfTimestamps();
3458
- const { framesDeleted } = mostInThePastBank.prepareForDeletion(logLevel, "deleted oldest keyframe bank to stay under max cache size");
3459
- sources[mostInThePastSrc].splice(mostInThePastIndex, 1);
3460
- if (range) {
3461
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${mostInThePastSrc} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
3462
- }
3808
+ const { bank, src, index } = mostInThePastBank;
3809
+ const range = bank.getRangeOfTimestamps();
3810
+ const { framesDeleted } = bank.prepareForDeletion(logLevel, "deleted oldest keyframe bank to stay under max cache size");
3811
+ sources[src].splice(index, 1);
3812
+ if (range) {
3813
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${src} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
3463
3814
  }
3464
3815
  return { finish: false };
3465
3816
  };
@@ -3472,12 +3823,12 @@ var makeKeyframeManager = () => {
3472
3823
  if (finish) {
3473
3824
  break;
3474
3825
  }
3475
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
3826
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
3476
3827
  cacheStats = getTotalCacheStats();
3477
3828
  attempts++;
3478
3829
  }
3479
3830
  if (cacheStats.totalSize > maxCacheSize && attempts >= maxAttempts) {
3480
- Internals11.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
3831
+ Internals14.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
3481
3832
  }
3482
3833
  };
3483
3834
  const clearKeyframeBanksBeforeTime = ({
@@ -3491,14 +3842,22 @@ var makeKeyframeManager = () => {
3491
3842
  return;
3492
3843
  }
3493
3844
  const banks = sources[src];
3845
+ const currentRequest = requestCountForSrc[src] ?? 0;
3494
3846
  for (const bank of banks) {
3847
+ if (bank.isBusy()) {
3848
+ continue;
3849
+ }
3495
3850
  const range = bank.getRangeOfTimestamps();
3496
3851
  if (!range) {
3497
3852
  continue;
3498
3853
  }
3854
+ const lastRequest = lastRequestForBank.get(bank);
3855
+ if (lastRequest !== undefined && currentRequest - lastRequest < RECENTLY_USED_REQUEST_COUNT) {
3856
+ continue;
3857
+ }
3499
3858
  if (range.lastTimestamp < threshold) {
3500
3859
  bank.prepareForDeletion(logLevel, "cleared before threshold " + threshold);
3501
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
3860
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
3502
3861
  const bankIndex = banks.indexOf(bank);
3503
3862
  delete sources[src][bankIndex];
3504
3863
  } else {
@@ -3520,21 +3879,23 @@ var makeKeyframeManager = () => {
3520
3879
  const existingBanks = sources[src] ?? [];
3521
3880
  const existingBank = existingBanks?.find((bank) => bank.canSatisfyTimestamp(timestamp));
3522
3881
  if (!existingBank) {
3523
- Internals11.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
3882
+ Internals14.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
3524
3883
  const newKeyframeBank = await makeKeyframeBank({
3525
3884
  videoSampleSink,
3526
3885
  logLevel,
3527
3886
  src,
3528
3887
  initialTimestampRequest: timestamp
3529
3888
  });
3530
- addKeyframeBank({ src, bank: newKeyframeBank });
3889
+ if (!addKeyframeBank({ src, bank: newKeyframeBank, logLevel })) {
3890
+ return null;
3891
+ }
3531
3892
  return newKeyframeBank;
3532
3893
  }
3533
3894
  if (existingBank.canSatisfyTimestamp(timestamp)) {
3534
- Internals11.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
3895
+ Internals14.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
3535
3896
  return existingBank;
3536
3897
  }
3537
- Internals11.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
3898
+ Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
3538
3899
  existingBank.prepareForDeletion(logLevel, "already existed but evicted");
3539
3900
  sources[src] = sources[src].filter((bank) => bank !== existingBank);
3540
3901
  const replacementKeybank = await makeKeyframeBank({
@@ -3543,7 +3904,9 @@ var makeKeyframeManager = () => {
3543
3904
  logLevel,
3544
3905
  src
3545
3906
  });
3546
- addKeyframeBank({ src, bank: replacementKeybank });
3907
+ if (!addKeyframeBank({ src, bank: replacementKeybank, logLevel })) {
3908
+ return null;
3909
+ }
3547
3910
  return replacementKeybank;
3548
3911
  };
3549
3912
  const requestKeyframeBank = async ({
@@ -3554,6 +3917,10 @@ var makeKeyframeManager = () => {
3554
3917
  maxCacheSize,
3555
3918
  fps
3556
3919
  }) => {
3920
+ if (disposed) {
3921
+ return null;
3922
+ }
3923
+ requestCountForSrc[src] = (requestCountForSrc[src] ?? 0) + 1;
3557
3924
  ensureToStayUnderMaxCacheSize(logLevel, maxCacheSize);
3558
3925
  clearKeyframeBanksBeforeTime({
3559
3926
  timestampInSeconds: timestamp,
@@ -3567,6 +3934,9 @@ var makeKeyframeManager = () => {
3567
3934
  src,
3568
3935
  logLevel
3569
3936
  });
3937
+ if (keyframeBank) {
3938
+ lastRequestForBank.set(keyframeBank, requestCountForSrc[src]);
3939
+ }
3570
3940
  return keyframeBank;
3571
3941
  };
3572
3942
  const clearAll = (logLevel) => {
@@ -3579,6 +3949,14 @@ var makeKeyframeManager = () => {
3579
3949
  sources[src] = [];
3580
3950
  }
3581
3951
  sources = {};
3952
+ requestCountForSrc = {};
3953
+ };
3954
+ const dispose = (logLevel) => {
3955
+ if (disposed) {
3956
+ return;
3957
+ }
3958
+ disposed = true;
3959
+ clearAll(logLevel);
3582
3960
  };
3583
3961
  let queue = Promise.resolve(undefined);
3584
3962
  return {
@@ -3601,58 +3979,98 @@ var makeKeyframeManager = () => {
3601
3979
  return queue;
3602
3980
  },
3603
3981
  getCacheStats,
3604
- clearAll
3982
+ clearAll,
3983
+ dispose
3605
3984
  };
3606
3985
  };
3607
3986
 
3608
3987
  // src/caches.ts
3609
3988
  var getSafeWindowOfMonotonicity = (fps) => 0.2 * 30 / fps;
3610
- var keyframeManager = makeKeyframeManager();
3611
- var audioManager = makeAudioManager();
3612
- var getTotalCacheStats = () => {
3613
- const keyframeManagerCacheStats = keyframeManager.getCacheStats();
3614
- const audioManagerCacheStats = audioManager.getCacheStats();
3615
- return {
3616
- count: keyframeManagerCacheStats.count + audioManagerCacheStats.count,
3617
- totalSize: keyframeManagerCacheStats.totalSize + audioManagerCacheStats.totalSize
3989
+ var makeMediaCache = () => {
3990
+ const sinkManager = makeSinkManager();
3991
+ const managerInstances = {
3992
+ keyframe: null,
3993
+ audio: null
3618
3994
  };
3619
- };
3620
- var getUncachedMaxCacheSize = (logLevel) => {
3621
- if (typeof window !== "undefined" && window.remotion_mediaCacheSizeInBytes !== undefined && window.remotion_mediaCacheSizeInBytes !== null) {
3622
- if (window.remotion_mediaCacheSizeInBytes < 240 * 1024 * 1024) {
3623
- cancelRender(new Error(`The minimum value for the "mediaCacheSizeInBytes" prop is 240MB (${240 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
3624
- }
3625
- if (window.remotion_mediaCacheSizeInBytes > 20000 * 1024 * 1024) {
3626
- cancelRender(new Error(`The maximum value for the "mediaCacheSizeInBytes" prop is 20GB (${20000 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
3627
- }
3628
- Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
3629
- return window.remotion_mediaCacheSizeInBytes;
3630
- }
3631
- if (typeof window !== "undefined" && window.remotion_initialMemoryAvailable !== undefined && window.remotion_initialMemoryAvailable !== null) {
3632
- const value = window.remotion_initialMemoryAvailable / 2;
3633
- if (value < 500 * 1024 * 1024) {
3634
- Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
3635
- return 500 * 1024 * 1024;
3995
+ const getCacheStats = () => {
3996
+ const { keyframe: currentKeyframeManager, audio: currentAudioManager } = managerInstances;
3997
+ if (currentKeyframeManager === null || currentAudioManager === null) {
3998
+ throw new Error("Media cache managers have not been initialized");
3636
3999
  }
3637
- if (value > 20000 * 1024 * 1024) {
3638
- Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
3639
- return 20000 * 1024 * 1024;
4000
+ const keyframeManagerCacheStats = currentKeyframeManager.getCacheStats();
4001
+ const audioManagerCacheStats = currentAudioManager.getCacheStats();
4002
+ return {
4003
+ count: keyframeManagerCacheStats.count + audioManagerCacheStats.count,
4004
+ totalSize: keyframeManagerCacheStats.totalSize + audioManagerCacheStats.totalSize
4005
+ };
4006
+ };
4007
+ const keyframeManagerInstance = makeKeyframeManager({
4008
+ getTotalCacheStats: getCacheStats
4009
+ });
4010
+ const audioManagerInstance = makeAudioManager({
4011
+ getTotalCacheStats: getCacheStats
4012
+ });
4013
+ managerInstances.keyframe = keyframeManagerInstance;
4014
+ managerInstances.audio = audioManagerInstance;
4015
+ let frameExtractionQueue = Promise.resolve(undefined);
4016
+ let audioExtractionQueue = Promise.resolve(undefined);
4017
+ let disposed = false;
4018
+ return {
4019
+ sinkManager,
4020
+ keyframeManager: keyframeManagerInstance,
4021
+ audioManager: audioManagerInstance,
4022
+ getTotalCacheStats: getCacheStats,
4023
+ isDisposed: () => disposed,
4024
+ queueFrameExtraction: (extract) => {
4025
+ const extraction = frameExtractionQueue.then(extract);
4026
+ frameExtractionQueue = extraction.catch(() => {
4027
+ return;
4028
+ });
4029
+ return extraction;
4030
+ },
4031
+ queueAudioExtraction: (extract) => {
4032
+ const extraction = audioExtractionQueue.then(extract);
4033
+ audioExtractionQueue = extraction.catch(() => {
4034
+ return;
4035
+ });
4036
+ return extraction;
4037
+ },
4038
+ dispose: (logLevel) => {
4039
+ if (disposed) {
4040
+ return;
4041
+ }
4042
+ disposed = true;
4043
+ try {
4044
+ keyframeManagerInstance.dispose(logLevel);
4045
+ } finally {
4046
+ try {
4047
+ audioManagerInstance.dispose();
4048
+ } finally {
4049
+ sinkManager.dispose();
4050
+ }
4051
+ }
3640
4052
  }
3641
- Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
3642
- return value;
3643
- }
3644
- return 1000 * 1000 * 1000;
4053
+ };
3645
4054
  };
3646
- var cachedMaxCacheSize = null;
3647
- var getMaxVideoCacheSize = (logLevel) => {
3648
- if (cachedMaxCacheSize !== null) {
3649
- return cachedMaxCacheSize;
3650
- }
3651
- cachedMaxCacheSize = getUncachedMaxCacheSize(logLevel);
3652
- return cachedMaxCacheSize;
4055
+ var globalMediaCache = makeMediaCache();
4056
+ var useRenderMediaCache = (logLevel) => {
4057
+ const renderResourceManager = React2.useContext(Internals15.RenderResourceManagerContext);
4058
+ if (renderResourceManager === null) {
4059
+ return globalMediaCache;
4060
+ }
4061
+ return renderResourceManager.getOrCreateResource({
4062
+ key: "@remotion/media/cache",
4063
+ create: () => {
4064
+ const resource = makeMediaCache();
4065
+ return {
4066
+ resource,
4067
+ dispose: () => resource.dispose(logLevel)
4068
+ };
4069
+ }
4070
+ });
3653
4071
  };
3654
4072
  var useMaxMediaCacheSize = (logLevel) => {
3655
- const context = React2.useContext(Internals12.MaxMediaCacheSizeContext);
4073
+ const context = React2.useContext(Internals15.MaxMediaCacheSizeContext);
3656
4074
  if (context === null) {
3657
4075
  return getMaxVideoCacheSize(logLevel);
3658
4076
  }
@@ -3905,205 +4323,6 @@ var combineAudioDataAndClosePrevious = (audioDataArray) => {
3905
4323
  };
3906
4324
  };
3907
4325
 
3908
- // src/get-sink.ts
3909
- import { Internals as Internals14 } from "remotion";
3910
-
3911
- // src/video-extraction/get-frames-since-keyframe.ts
3912
- import {
3913
- ALL_FORMATS as ALL_FORMATS2,
3914
- AudioSampleSink,
3915
- EncodedPacketSink,
3916
- Input as Input2,
3917
- MATROSKA,
3918
- UrlSource as UrlSource2,
3919
- VideoSampleSink,
3920
- WEBM
3921
- } from "mediabunny";
3922
- import { Internals as Internals13 } from "remotion";
3923
-
3924
- // src/browser-can-use-webgl2.ts
3925
- var browserCanUseWebGl2 = null;
3926
- var browserCanUseWebGl2Uncached = () => {
3927
- const canvas = new OffscreenCanvas(1, 1);
3928
- const context = canvas.getContext("webgl2");
3929
- return context !== null;
3930
- };
3931
- var canBrowserUseWebGl2 = () => {
3932
- if (browserCanUseWebGl2 !== null) {
3933
- return browserCanUseWebGl2;
3934
- }
3935
- browserCanUseWebGl2 = browserCanUseWebGl2Uncached();
3936
- return browserCanUseWebGl2;
3937
- };
3938
-
3939
- // src/video-extraction/remember-actual-matroska-timestamps.ts
3940
- var rememberActualMatroskaTimestamps = (isMatroska) => {
3941
- const observations = [];
3942
- const observeTimestamp = (startTime) => {
3943
- if (!isMatroska) {
3944
- return;
3945
- }
3946
- observations.push(startTime);
3947
- };
3948
- const getRealTimestamp = (observedTimestamp) => {
3949
- if (!isMatroska) {
3950
- return observedTimestamp;
3951
- }
3952
- return observations.find((observation) => Math.abs(observedTimestamp - observation) < 0.001) ?? null;
3953
- };
3954
- return {
3955
- observeTimestamp,
3956
- getRealTimestamp
3957
- };
3958
- };
3959
-
3960
- // src/video-extraction/get-frames-since-keyframe.ts
3961
- var getRetryDelay = () => {
3962
- return null;
3963
- };
3964
- var getFormatOrNullOrNetworkError = async (input) => {
3965
- try {
3966
- return await input.getFormat();
3967
- } catch (err) {
3968
- if (isNetworkError(err)) {
3969
- return "network-error";
3970
- }
3971
- return null;
3972
- }
3973
- };
3974
- var getSinks = async (src, logLevel, credentials, requestInit) => {
3975
- const resolvedRequestInit = resolveRequestInit({ credentials, requestInit });
3976
- const input = new Input2({
3977
- formats: ALL_FORMATS2,
3978
- source: new UrlSource2(src, {
3979
- getRetryDelay,
3980
- ...resolvedRequestInit ? { requestInit: resolvedRequestInit } : undefined
3981
- })
3982
- });
3983
- const format = await getFormatOrNullOrNetworkError(input);
3984
- const isMatroska = format === MATROSKA || format === WEBM;
3985
- const getVideoSinks = async () => {
3986
- if (format === "network-error") {
3987
- return "network-error";
3988
- }
3989
- if (format === null) {
3990
- return "unknown-container-format";
3991
- }
3992
- const videoTrack = await input.getPrimaryVideoTrack();
3993
- if (!videoTrack) {
3994
- return "no-video-track";
3995
- }
3996
- if (await videoTrack.isLive()) {
3997
- throw new Error("Live streams are not currently supported by Remotion. Sorry! Source: " + src);
3998
- }
3999
- if (await videoTrack.isRelativeToUnixEpoch()) {
4000
- throw new Error("Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: " + src);
4001
- }
4002
- const canDecode = await videoTrack.canDecode();
4003
- if (!canDecode) {
4004
- if (videoTrack.codec === "prores") {
4005
- return "cannot-decode-prores";
4006
- }
4007
- return "cannot-decode";
4008
- }
4009
- const sampleSink = new VideoSampleSink(videoTrack);
4010
- const packetSink = new EncodedPacketSink(videoTrack);
4011
- const startPacket = await packetSink.getFirstPacket({
4012
- verifyKeyPackets: true
4013
- });
4014
- const hasAlpha = startPacket?.sideData.alpha;
4015
- if (hasAlpha && !canBrowserUseWebGl2()) {
4016
- Internals13.Log.warn({ logLevel, tag: "@remotion/media" }, `WebGL2 is not available, using the non-fast CPU path to decode alpha for ${src}.`);
4017
- }
4018
- return {
4019
- sampleSink
4020
- };
4021
- };
4022
- let videoSinksPromise = null;
4023
- const getVideoSinksPromise = () => {
4024
- if (videoSinksPromise) {
4025
- return videoSinksPromise;
4026
- }
4027
- videoSinksPromise = getVideoSinks();
4028
- return videoSinksPromise;
4029
- };
4030
- const audioSinksPromise = {};
4031
- const getAudioSinks = async (index) => {
4032
- if (format === null) {
4033
- return "unknown-container-format";
4034
- }
4035
- if (format === "network-error") {
4036
- return "network-error";
4037
- }
4038
- const [videoTrack, audioTracks] = await Promise.all([
4039
- input.getPrimaryVideoTrack(),
4040
- input.getAudioTracks()
4041
- ]);
4042
- const audioTrack = await resolveAudioTrack({
4043
- videoTrack,
4044
- audioTracks,
4045
- audioStreamIndex: index
4046
- });
4047
- if (!audioTrack) {
4048
- return "no-audio-track";
4049
- }
4050
- const canDecode = await audioTrack.canDecode();
4051
- if (!canDecode) {
4052
- return "cannot-decode-audio";
4053
- }
4054
- return {
4055
- sampleSink: new AudioSampleSink(audioTrack)
4056
- };
4057
- };
4058
- const getAudioSinksPromise = (index) => {
4059
- const keyIndex = index === null ? -1 : index;
4060
- if (audioSinksPromise[keyIndex]) {
4061
- return audioSinksPromise[keyIndex];
4062
- }
4063
- audioSinksPromise[keyIndex] = getAudioSinks(index);
4064
- return audioSinksPromise[keyIndex];
4065
- };
4066
- return {
4067
- getVideo: () => getVideoSinksPromise(),
4068
- getAudio: (index) => getAudioSinksPromise(index),
4069
- actualMatroskaTimestamps: rememberActualMatroskaTimestamps(isMatroska),
4070
- isMatroska,
4071
- getDuration: () => {
4072
- return getDurationOrCompute(input);
4073
- }
4074
- };
4075
- };
4076
-
4077
- // src/get-sink.ts
4078
- var sinkPromises = {};
4079
- var getSinkCacheKey = ({
4080
- src,
4081
- credentials,
4082
- requestInit
4083
- }) => JSON.stringify([
4084
- src,
4085
- credentials,
4086
- getMediaRequestInitFingerprint(requestInit)
4087
- ]);
4088
- var getSink = (src, logLevel, credentials, requestInit) => {
4089
- const normalizedRequestInit = normalizeMediaRequestInit(requestInit);
4090
- const cacheKey = getSinkCacheKey({
4091
- src,
4092
- credentials,
4093
- requestInit: normalizedRequestInit
4094
- });
4095
- let promise = sinkPromises[cacheKey];
4096
- if (!promise) {
4097
- Internals14.Log.verbose({
4098
- logLevel,
4099
- tag: "@remotion/media"
4100
- }, `Sink for ${src} was not found, creating new sink`);
4101
- promise = getSinks(src, logLevel, credentials, normalizedRequestInit);
4102
- sinkPromises[cacheKey] = promise;
4103
- }
4104
- return promise;
4105
- };
4106
-
4107
4326
  // src/audio-extraction/extract-audio.ts
4108
4327
  var extractAudioInternal = async ({
4109
4328
  src,
@@ -4118,9 +4337,10 @@ var extractAudioInternal = async ({
4118
4337
  fps,
4119
4338
  maxCacheSize,
4120
4339
  credentials,
4121
- requestInit
4340
+ requestInit,
4341
+ mediaCache
4122
4342
  }) => {
4123
- const { getAudio, actualMatroskaTimestamps, isMatroska, getDuration } = await getSink(src, logLevel, credentials, requestInit);
4343
+ const { getAudio, actualMatroskaTimestamps, isMatroska, getDuration } = await mediaCache.sinkManager.getSink(src, logLevel, credentials, requestInit);
4124
4344
  let mediaDurationInSeconds = null;
4125
4345
  if (loop) {
4126
4346
  mediaDurationInSeconds = await getDuration();
@@ -4153,7 +4373,7 @@ var extractAudioInternal = async ({
4153
4373
  return { data: null, durationInSeconds: mediaDurationInSeconds };
4154
4374
  }
4155
4375
  try {
4156
- const sampleIterator = await audioManager.getIterator({
4376
+ const sampleIterator = await mediaCache.audioManager.getIterator({
4157
4377
  src,
4158
4378
  timeInSeconds,
4159
4379
  audioSampleSink: audio.sampleSink,
@@ -4164,7 +4384,7 @@ var extractAudioInternal = async ({
4164
4384
  });
4165
4385
  const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
4166
4386
  const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
4167
- audioManager.logOpenFrames();
4387
+ mediaCache.audioManager.logOpenFrames();
4168
4388
  const audioDataArray = [];
4169
4389
  for (let i = 0;i < samples.length; i++) {
4170
4390
  const sample = samples[i];
@@ -4229,14 +4449,12 @@ var extractAudioInternal = async ({
4229
4449
  throw err;
4230
4450
  }
4231
4451
  };
4232
- var queue = Promise.resolve(undefined);
4233
4452
  var extractAudio = (params) => {
4234
- queue = queue.then(() => extractAudioInternal(params));
4235
- return queue;
4453
+ return params.mediaCache.queueAudioExtraction(() => extractAudioInternal(params));
4236
4454
  };
4237
4455
 
4238
4456
  // src/video-extraction/extract-frame.ts
4239
- import { Internals as Internals15 } from "remotion";
4457
+ import { Internals as Internals16 } from "remotion";
4240
4458
  var extractFrameInternal = async ({
4241
4459
  src,
4242
4460
  timeInSeconds: unloopedTimeInSeconds,
@@ -4248,9 +4466,10 @@ var extractFrameInternal = async ({
4248
4466
  fps,
4249
4467
  maxCacheSize,
4250
4468
  credentials,
4251
- requestInit
4469
+ requestInit,
4470
+ mediaCache
4252
4471
  }) => {
4253
- const sink = await getSink(src, logLevel, credentials, requestInit);
4472
+ const sink = await mediaCache.sinkManager.getSink(src, logLevel, credentials, requestInit);
4254
4473
  const [video, mediaDurationInSecondsRaw] = await Promise.all([
4255
4474
  sink.getVideo(),
4256
4475
  loop ? sink.getDuration() : Promise.resolve(null)
@@ -4300,7 +4519,7 @@ var extractFrameInternal = async ({
4300
4519
  };
4301
4520
  }
4302
4521
  try {
4303
- const keyframeBank = await keyframeManager.requestKeyframeBank({
4522
+ const keyframeBank = await mediaCache.keyframeManager.requestKeyframeBank({
4304
4523
  videoSampleSink: video.sampleSink,
4305
4524
  timestamp: timeInSeconds,
4306
4525
  src,
@@ -4325,14 +4544,12 @@ var extractFrameInternal = async ({
4325
4544
  durationInSeconds: await sink.getDuration()
4326
4545
  };
4327
4546
  } catch (err) {
4328
- Internals15.Log.info({ logLevel, tag: "@remotion/media" }, `Error decoding ${src} at time ${timeInSeconds}: ${err}`, err);
4547
+ Internals16.Log.info({ logLevel, tag: "@remotion/media" }, `Error decoding ${src} at time ${timeInSeconds}: ${err}`, err);
4329
4548
  return { type: "cannot-decode", durationInSeconds: mediaDurationInSeconds };
4330
4549
  }
4331
4550
  };
4332
- var queue2 = Promise.resolve(undefined);
4333
4551
  var extractFrame = (params) => {
4334
- queue2 = queue2.then(() => extractFrameInternal(params));
4335
- return queue2;
4552
+ return params.mediaCache.queueFrameExtraction(() => extractFrameInternal(params));
4336
4553
  };
4337
4554
 
4338
4555
  // src/video-extraction/rotate-frame.ts
@@ -4384,7 +4601,8 @@ var extractFrameAndAudio = async ({
4384
4601
  fps,
4385
4602
  maxCacheSize,
4386
4603
  credentials,
4387
- requestInit
4604
+ requestInit,
4605
+ mediaCache
4388
4606
  }) => {
4389
4607
  try {
4390
4608
  const [video, audio] = await Promise.all([
@@ -4399,7 +4617,8 @@ var extractFrameAndAudio = async ({
4399
4617
  fps,
4400
4618
  maxCacheSize,
4401
4619
  credentials,
4402
- requestInit
4620
+ requestInit,
4621
+ mediaCache
4403
4622
  }) : null,
4404
4623
  includeAudio ? extractAudio({
4405
4624
  src,
@@ -4414,7 +4633,8 @@ var extractFrameAndAudio = async ({
4414
4633
  trimBefore,
4415
4634
  maxCacheSize,
4416
4635
  credentials,
4417
- requestInit
4636
+ requestInit,
4637
+ mediaCache
4418
4638
  }) : null
4419
4639
  ]);
4420
4640
  if (video?.type === "cannot-decode") {
@@ -4505,7 +4725,8 @@ var addBroadcastChannelListener = () => {
4505
4725
  fps: data.fps,
4506
4726
  maxCacheSize: data.maxCacheSize,
4507
4727
  credentials: data.credentials,
4508
- requestInit: data.requestInit
4728
+ requestInit: data.requestInit,
4729
+ mediaCache: globalMediaCache
4509
4730
  });
4510
4731
  if (result.type === "cannot-decode") {
4511
4732
  const cannotDecodeResponse = {
@@ -4613,7 +4834,8 @@ var extractFrameViaBroadcastChannel = async ({
4613
4834
  fps,
4614
4835
  maxCacheSize,
4615
4836
  credentials,
4616
- requestInit
4837
+ requestInit,
4838
+ mediaCache
4617
4839
  }) => {
4618
4840
  if (isClientSideRendering || window.remotion_isMainTab) {
4619
4841
  return extractFrameAndAudio({
@@ -4631,7 +4853,8 @@ var extractFrameViaBroadcastChannel = async ({
4631
4853
  fps,
4632
4854
  maxCacheSize,
4633
4855
  credentials,
4634
- requestInit
4856
+ requestInit,
4857
+ mediaCache
4635
4858
  });
4636
4859
  }
4637
4860
  await waitForMainTabToBeReady(window.remotion_broadcastChannel);
@@ -4760,13 +4983,13 @@ var AudioForRendering = ({
4760
4983
  credentials,
4761
4984
  requestInit
4762
4985
  }) => {
4763
- const defaultLogLevel = Internals16.useLogLevel();
4986
+ const defaultLogLevel = Internals17.useLogLevel();
4764
4987
  const logLevel = overriddenLogLevel ?? defaultLogLevel;
4765
4988
  const frame = useCurrentFrame2();
4766
- const absoluteFrame = Internals16.useTimelinePosition();
4767
- const videoConfig = Internals16.useUnsafeVideoConfig();
4768
- const { registerRenderAsset, unregisterRenderAsset } = useContext3(Internals16.RenderAssetManager);
4769
- const startsAt = Internals16.useMediaStartsAt();
4989
+ const absoluteFrame = Internals17.useTimelinePosition();
4990
+ const videoConfig = Internals17.useUnsafeVideoConfig();
4991
+ const { registerRenderAsset, unregisterRenderAsset } = useContext3(Internals17.RenderAssetManager);
4992
+ const startsAt = Internals17.useMediaStartsAt();
4770
4993
  const environment = useRemotionEnvironment();
4771
4994
  if (!videoConfig) {
4772
4995
  throw new Error("No video config found");
@@ -4778,7 +5001,7 @@ var AudioForRendering = ({
4778
5001
  const { delayRender, continueRender } = useDelayRender();
4779
5002
  const [replaceWithHtml5Audio, setReplaceWithHtml5Audio] = useState2(false);
4780
5003
  const [initialRequestInit] = useState2(requestInit);
4781
- const sequenceContext = useContext3(Internals16.SequenceContext);
5004
+ const sequenceContext = useContext3(Internals17.SequenceContext);
4782
5005
  const id = useMemo2(() => `media-audio-${random(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
4783
5006
  src,
4784
5007
  sequenceContext?.cumulatedFrom,
@@ -4786,7 +5009,8 @@ var AudioForRendering = ({
4786
5009
  sequenceContext?.durationInFrames
4787
5010
  ]);
4788
5011
  const maxCacheSize = useMaxMediaCacheSize(logLevel);
4789
- const audioEnabled = Internals16.useAudioEnabled();
5012
+ const mediaCache = useRenderMediaCache(logLevel);
5013
+ const audioEnabled = Internals17.useAudioEnabled();
4790
5014
  useLayoutEffect2(() => {
4791
5015
  const timestamp = frame / fps;
4792
5016
  const durationInSeconds = 1 / fps;
@@ -4825,8 +5049,12 @@ var AudioForRendering = ({
4825
5049
  fps,
4826
5050
  maxCacheSize,
4827
5051
  credentials,
4828
- requestInit: initialRequestInit
5052
+ requestInit: initialRequestInit,
5053
+ mediaCache
4829
5054
  }).then((result) => {
5055
+ if (mediaCache.isDisposed()) {
5056
+ return;
5057
+ }
4830
5058
  const handleError = (error, clientSideError, fallbackMessage) => {
4831
5059
  const [action, errorToUse] = callOnErrorAndResolve({
4832
5060
  onError,
@@ -4838,7 +5066,7 @@ var AudioForRendering = ({
4838
5066
  if (action === "fail") {
4839
5067
  cancelRender2(errorToUse);
4840
5068
  }
4841
- Internals16.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
5069
+ Internals17.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
4842
5070
  setReplaceWithHtml5Audio(true);
4843
5071
  };
4844
5072
  if (result.type === "unknown-container-format") {
@@ -4868,12 +5096,12 @@ var AudioForRendering = ({
4868
5096
  frame,
4869
5097
  startsAt
4870
5098
  });
4871
- const volume = Internals16.evaluateVolume({
5099
+ const volume = Internals17.evaluateVolume({
4872
5100
  volume: volumeProp,
4873
5101
  frame: volumePropsFrame,
4874
5102
  mediaVolume: 1
4875
5103
  });
4876
- Internals16.warnAboutTooHighVolume(volume);
5104
+ Internals17.warnAboutTooHighVolume(volume);
4877
5105
  if (audio && volume > 0) {
4878
5106
  applyVolume(audio.data, volume);
4879
5107
  registerRenderAsset({
@@ -4888,6 +5116,9 @@ var AudioForRendering = ({
4888
5116
  }
4889
5117
  continueRender(newHandle);
4890
5118
  }).catch((error) => {
5119
+ if (mediaCache.isDisposed()) {
5120
+ return;
5121
+ }
4891
5122
  cancelRender2(error);
4892
5123
  });
4893
5124
  return () => {
@@ -4924,7 +5155,8 @@ var AudioForRendering = ({
4924
5155
  audioEnabled,
4925
5156
  onError,
4926
5157
  credentials,
4927
- initialRequestInit
5158
+ initialRequestInit,
5159
+ mediaCache
4928
5160
  ]);
4929
5161
  if (replaceWithHtml5Audio) {
4930
5162
  return /* @__PURE__ */ jsx2(Html5Audio, {
@@ -4952,7 +5184,7 @@ var AudioForRendering = ({
4952
5184
 
4953
5185
  // src/audio/audio.tsx
4954
5186
  import { jsx as jsx3 } from "react/jsx-runtime";
4955
- var { validateMediaProps } = Internals17;
5187
+ var { validateMediaProps } = Internals18;
4956
5188
  var audioSchema = {
4957
5189
  src: {
4958
5190
  type: "asset",
@@ -4960,8 +5192,8 @@ var audioSchema = {
4960
5192
  description: "Source",
4961
5193
  keyframable: false
4962
5194
  },
4963
- ...Internals17.baseSchema,
4964
- ...Internals17.premountSchema,
5195
+ ...Internals18.baseSchema,
5196
+ ...Internals18.premountSchema,
4965
5197
  volume: {
4966
5198
  type: "number",
4967
5199
  min: 0,
@@ -4997,12 +5229,12 @@ var AudioInner = (props) => {
4997
5229
  ...otherProps
4998
5230
  } = props;
4999
5231
  const environment = useRemotionEnvironment2();
5000
- const sourceStack = controls ? Internals17.getStackForControls(controls) : null;
5001
- const [mediaVolume] = Internals17.useMediaVolumeState();
5002
- const mediaStartsAt = Internals17.useMediaStartsAt();
5232
+ const sourceStack = controls ? Internals18.getStackForControls(controls) : null;
5233
+ const [mediaVolume] = Internals18.useMediaVolumeState();
5234
+ const mediaStartsAt = Internals18.useMediaStartsAt();
5003
5235
  const videoConfig = useVideoConfig2();
5004
5236
  const sequenceDurationInFrames = Math.min(durationInFrames ?? Infinity, Math.max(0, videoConfig.durationInFrames - (from ?? 0)));
5005
- const basicInfo = Internals17.useBasicMediaInTimeline({
5237
+ const basicInfo = Internals18.useBasicMediaInTimeline({
5006
5238
  src: props.src,
5007
5239
  volume: props.volume,
5008
5240
  playbackRate: props.playbackRate ?? 1,
@@ -5045,7 +5277,7 @@ var AudioInner = (props) => {
5045
5277
  postmountingActive,
5046
5278
  premountingActive,
5047
5279
  premountingStyle
5048
- } = Internals17.usePremounting({
5280
+ } = Internals18.usePremounting({
5049
5281
  from: from ?? 0,
5050
5282
  durationInFrames: basicInfo.duration,
5051
5283
  premountFor: premountFor ?? null,
@@ -5106,7 +5338,7 @@ var Audio = Interactive.withSchema({
5106
5338
  import React6, { useMemo as useMemo6, useState as useState6 } from "react";
5107
5339
  import {
5108
5340
  Freeze as Freeze2,
5109
- Internals as Internals22,
5341
+ Internals as Internals23,
5110
5342
  Interactive as Interactive2,
5111
5343
  Sequence as Sequence2,
5112
5344
  useRemotionEnvironment as useRemotionEnvironment4,
@@ -5114,7 +5346,7 @@ import {
5114
5346
  } from "remotion";
5115
5347
 
5116
5348
  // src/video/get-video-sequence-duration.ts
5117
- import { Internals as Internals18 } from "remotion";
5349
+ import { Internals as Internals19 } from "remotion";
5118
5350
  var getVideoSequenceDuration = ({
5119
5351
  durationInFrames,
5120
5352
  loop,
@@ -5125,7 +5357,7 @@ var getVideoSequenceDuration = ({
5125
5357
  if (loop || trimAfter === undefined) {
5126
5358
  return durationInFrames;
5127
5359
  }
5128
- const trimmedDuration = Internals18.calculateMediaDuration({
5360
+ const trimmedDuration = Internals19.calculateMediaDuration({
5129
5361
  trimAfter,
5130
5362
  trimBefore,
5131
5363
  playbackRate,
@@ -5146,7 +5378,7 @@ import {
5146
5378
  } from "react";
5147
5379
  import {
5148
5380
  Html5Video,
5149
- Internals as Internals20,
5381
+ Internals as Internals21,
5150
5382
  useBufferState as useBufferState2,
5151
5383
  useCurrentFrame as useCurrentFrame3,
5152
5384
  useVideoConfig as useVideoConfig3
@@ -5189,7 +5421,7 @@ var getCachedVideoFrame = (src) => {
5189
5421
  };
5190
5422
 
5191
5423
  // src/video/warn-object-fit-css.ts
5192
- import { Internals as Internals19 } from "remotion";
5424
+ import { Internals as Internals20 } from "remotion";
5193
5425
  var OBJECT_FIT_CLASS_PATTERN = /\bobject-(contain|cover|fill|none|scale-down)\b/;
5194
5426
  var warnedStyle = false;
5195
5427
  var warnedClassName = false;
@@ -5200,11 +5432,11 @@ var warnAboutObjectFitInStyleOrClassName = ({
5200
5432
  }) => {
5201
5433
  if (!warnedStyle && style?.objectFit) {
5202
5434
  warnedStyle = true;
5203
- Internals19.Log.warn({ logLevel, tag: "@remotion/media" }, "Use the `objectFit` prop instead of the `style` prop.");
5435
+ Internals20.Log.warn({ logLevel, tag: "@remotion/media" }, "Use the `objectFit` prop instead of the `style` prop.");
5204
5436
  }
5205
5437
  if (!warnedClassName && className && OBJECT_FIT_CLASS_PATTERN.test(className)) {
5206
5438
  warnedClassName = true;
5207
- Internals19.Log.warn({ logLevel, tag: "@remotion/media" }, "Use the `objectFit` prop instead of `object-*` CSS class names.");
5439
+ Internals20.Log.warn({ logLevel, tag: "@remotion/media" }, "Use the `objectFit` prop instead of `object-*` CSS class names.");
5208
5440
  }
5209
5441
  };
5210
5442
 
@@ -5222,7 +5454,7 @@ var {
5222
5454
  usePreload: usePreload2,
5223
5455
  SequenceContext: SequenceContext2,
5224
5456
  useEffectChainState
5225
- } = Internals20;
5457
+ } = Internals21;
5226
5458
  var VideoForPreviewAssertedShowing = ({
5227
5459
  src: unpreloadedSrc,
5228
5460
  style,
@@ -5265,7 +5497,7 @@ var VideoForPreviewAssertedShowing = ({
5265
5497
  const [mediaPlayerReady, setMediaPlayerReady] = useState4(false);
5266
5498
  const [shouldFallbackToNativeVideo, setShouldFallbackToNativeVideo] = useState4(false);
5267
5499
  const [playing] = Timeline2.usePlayingState();
5268
- const { playbackRate: globalPlaybackRate } = Internals20.usePlaybackRate();
5500
+ const { playbackRate: globalPlaybackRate } = Internals21.usePlaybackRate();
5269
5501
  const sharedAudioContext = useContext4(SharedAudioContext2);
5270
5502
  const buffer = useBufferState2();
5271
5503
  const canvasRefCallback = useCallback((canvas) => {
@@ -5302,12 +5534,12 @@ var VideoForPreviewAssertedShowing = ({
5302
5534
  const currentTimeRef = useRef2(currentTime);
5303
5535
  currentTimeRef.current = currentTime;
5304
5536
  const preloadedSrc = usePreload2(src);
5305
- const buffering = useContext4(Internals20.BufferingContextReact);
5537
+ const buffering = useContext4(Internals21.BufferingContextReact);
5306
5538
  if (!buffering) {
5307
5539
  throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
5308
5540
  }
5309
5541
  const effectiveMuted = muted || playerMuted || userPreferredVolume <= 0;
5310
- const isPlayerBuffering = Internals20.useIsPlayerBuffering(buffering);
5542
+ const isPlayerBuffering = Internals21.useIsPlayerBuffering(buffering);
5311
5543
  const initialPlaying = useRef2(playing && !isPlayerBuffering);
5312
5544
  const initialIsPremounting = useRef2(isPremounting);
5313
5545
  const initialIsPostmounting = useRef2(isPostmounting);
@@ -5405,7 +5637,7 @@ var VideoForPreviewAssertedShowing = ({
5405
5637
  if (action === "fail") {
5406
5638
  throw errorToUse;
5407
5639
  }
5408
- Internals20.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
5640
+ Internals21.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
5409
5641
  setShouldFallbackToNativeVideo(true);
5410
5642
  };
5411
5643
  if (result.type === "unknown-container-format") {
@@ -5447,7 +5679,7 @@ var VideoForPreviewAssertedShowing = ({
5447
5679
  if (action === "fail") {
5448
5680
  throw errorToUse;
5449
5681
  }
5450
- Internals20.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] Failed to initialize MediaPlayer", errorToUse);
5682
+ Internals21.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] Failed to initialize MediaPlayer", errorToUse);
5451
5683
  setShouldFallbackToNativeVideo(true);
5452
5684
  });
5453
5685
  } catch (error) {
@@ -5461,12 +5693,12 @@ var VideoForPreviewAssertedShowing = ({
5461
5693
  if (action === "fail") {
5462
5694
  throw errorToUse;
5463
5695
  }
5464
- Internals20.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] MediaPlayer initialization failed", errorToUse);
5696
+ Internals21.Log.error({ logLevel, tag: "@remotion/media" }, "[VideoForPreview] MediaPlayer initialization failed", errorToUse);
5465
5697
  setShouldFallbackToNativeVideo(true);
5466
5698
  }
5467
5699
  return () => {
5468
5700
  if (mediaPlayerRef.current) {
5469
- Internals20.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Disposing MediaPlayer`);
5701
+ Internals21.Log.trace({ logLevel, tag: "@remotion/media" }, `[VideoForPreview] Disposing MediaPlayer`);
5470
5702
  mediaPlayerRef.current.dispose();
5471
5703
  mediaPlayerRef.current = null;
5472
5704
  }
@@ -5490,7 +5722,7 @@ var VideoForPreviewAssertedShowing = ({
5490
5722
  ]);
5491
5723
  warnAboutObjectFitInStyleOrClassName({ style, className, logLevel });
5492
5724
  const classNameValue = useMemo4(() => {
5493
- return [Internals20.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals20.truthy).join(" ");
5725
+ return [Internals21.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals21.truthy).join(" ");
5494
5726
  }, [className]);
5495
5727
  useCommonEffects({
5496
5728
  mediaPlayerRef,
@@ -5614,7 +5846,7 @@ import {
5614
5846
  useState as useState5
5615
5847
  } from "react";
5616
5848
  import {
5617
- Internals as Internals21,
5849
+ Internals as Internals22,
5618
5850
  Loop,
5619
5851
  random as random2,
5620
5852
  useCurrentFrame as useCurrentFrame4,
@@ -5655,11 +5887,11 @@ var VideoForRendering = ({
5655
5887
  throw new TypeError("No `src` was passed to <Video>.");
5656
5888
  }
5657
5889
  const frame = useCurrentFrame4();
5658
- const absoluteFrame = Internals21.useTimelinePosition();
5890
+ const absoluteFrame = Internals22.useTimelinePosition();
5659
5891
  const { fps } = useVideoConfig4();
5660
- const { registerRenderAsset, unregisterRenderAsset } = useContext5(Internals21.RenderAssetManager);
5661
- const startsAt = Internals21.useMediaStartsAt();
5662
- const sequenceContext = useContext5(Internals21.SequenceContext);
5892
+ const { registerRenderAsset, unregisterRenderAsset } = useContext5(Internals22.RenderAssetManager);
5893
+ const startsAt = Internals22.useMediaStartsAt();
5894
+ const sequenceContext = useContext5(Internals22.SequenceContext);
5663
5895
  const id = useMemo5(() => `media-video-${random2(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
5664
5896
  src,
5665
5897
  sequenceContext?.cumulatedFrom,
@@ -5671,10 +5903,11 @@ var VideoForRendering = ({
5671
5903
  const canvasRef = useRef3(null);
5672
5904
  const [replaceWithOffthreadVideo, setReplaceWithOffthreadVideo] = useState5(false);
5673
5905
  const [initialRequestInit] = useState5(requestInit);
5674
- const audioEnabled = Internals21.useAudioEnabled();
5675
- const videoEnabled = Internals21.useVideoEnabled();
5906
+ const audioEnabled = Internals22.useAudioEnabled();
5907
+ const videoEnabled = Internals22.useVideoEnabled();
5676
5908
  const maxCacheSize = useMaxMediaCacheSize(logLevel);
5677
- const effectChainState = Internals21.useEffectChainState();
5909
+ const mediaCache = useRenderMediaCache(logLevel);
5910
+ const effectChainState = Internals22.useEffectChainState();
5678
5911
  const [error, setError] = useState5(null);
5679
5912
  if (error) {
5680
5913
  throw error;
@@ -5720,8 +5953,15 @@ var VideoForRendering = ({
5720
5953
  fps,
5721
5954
  maxCacheSize,
5722
5955
  credentials,
5723
- requestInit: initialRequestInit
5956
+ requestInit: initialRequestInit,
5957
+ mediaCache
5724
5958
  }).then(async (result) => {
5959
+ if (mediaCache.isDisposed()) {
5960
+ if (result.type === "success") {
5961
+ result.frame?.close();
5962
+ }
5963
+ return;
5964
+ }
5725
5965
  const handleError = (err, clientSideError, fallbackMessage, mediaDurationInSeconds) => {
5726
5966
  if (environment.isClientSideRendering) {
5727
5967
  cancelRender3(clientSideError);
@@ -5739,7 +5979,7 @@ var VideoForRendering = ({
5739
5979
  return;
5740
5980
  }
5741
5981
  if (window.remotion_isMainTab) {
5742
- Internals21.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
5982
+ Internals22.Log.warn({ logLevel, tag: "@remotion/media" }, fallbackMessage);
5743
5983
  }
5744
5984
  setReplaceWithOffthreadVideo({
5745
5985
  durationInSeconds: mediaDurationInSeconds
@@ -5783,7 +6023,7 @@ var VideoForRendering = ({
5783
6023
  context.canvas.style.aspectRatio = `${context.canvas.width} / ${context.canvas.height}`;
5784
6024
  context.drawImage(imageBitmap, 0, 0);
5785
6025
  if (effects.length > 0) {
5786
- const completed = await Internals21.runEffectChain({
6026
+ const completed = await Internals22.runEffectChain({
5787
6027
  state: effectChainState.get(imageBitmap.width, imageBitmap.height),
5788
6028
  source: context.canvas,
5789
6029
  effects,
@@ -5791,7 +6031,7 @@ var VideoForRendering = ({
5791
6031
  width: imageBitmap.width,
5792
6032
  height: imageBitmap.height
5793
6033
  });
5794
- if (!completed) {
6034
+ if (!completed || mediaCache.isDisposed()) {
5795
6035
  imageBitmap.close();
5796
6036
  return;
5797
6037
  }
@@ -5814,12 +6054,12 @@ var VideoForRendering = ({
5814
6054
  frame,
5815
6055
  startsAt
5816
6056
  });
5817
- const volume = Internals21.evaluateVolume({
6057
+ const volume = Internals22.evaluateVolume({
5818
6058
  volume: volumeProp,
5819
6059
  frame: volumePropsFrame,
5820
6060
  mediaVolume: 1
5821
6061
  });
5822
- Internals21.warnAboutTooHighVolume(volume);
6062
+ Internals22.warnAboutTooHighVolume(volume);
5823
6063
  if (audio && volume > 0) {
5824
6064
  applyVolume(audio.data, volume);
5825
6065
  registerRenderAsset({
@@ -5834,6 +6074,9 @@ var VideoForRendering = ({
5834
6074
  }
5835
6075
  continueRender(newHandle);
5836
6076
  }).catch((err) => {
6077
+ if (mediaCache.isDisposed()) {
6078
+ return;
6079
+ }
5837
6080
  cancelRender3(err);
5838
6081
  });
5839
6082
  return () => {
@@ -5876,11 +6119,12 @@ var VideoForRendering = ({
5876
6119
  credentials,
5877
6120
  effectChainState,
5878
6121
  effects,
5879
- initialRequestInit
6122
+ initialRequestInit,
6123
+ mediaCache
5880
6124
  ]);
5881
6125
  warnAboutObjectFitInStyleOrClassName({ style, className, logLevel });
5882
6126
  const classNameValue = useMemo5(() => {
5883
- return [Internals21.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals21.truthy).join(" ");
6127
+ return [Internals22.OBJECTFIT_CONTAIN_CLASS_NAME, className].filter(Internals22.truthy).join(" ");
5884
6128
  }, [className]);
5885
6129
  const styleWithObjectFit = useMemo5(() => {
5886
6130
  return {
@@ -5889,7 +6133,7 @@ var VideoForRendering = ({
5889
6133
  };
5890
6134
  }, [objectFitProp, style]);
5891
6135
  if (replaceWithOffthreadVideo) {
5892
- const fallback = /* @__PURE__ */ jsx5(Internals21.InnerOffthreadVideo, {
6136
+ const fallback = /* @__PURE__ */ jsx5(Internals22.InnerOffthreadVideo, {
5893
6137
  ...props,
5894
6138
  src,
5895
6139
  playbackRate: playbackRate ?? 1,
@@ -5931,7 +6175,7 @@ var VideoForRendering = ({
5931
6175
  }
5932
6176
  return /* @__PURE__ */ jsx5(Loop, {
5933
6177
  layout: "none",
5934
- durationInFrames: Internals21.calculateMediaDuration({
6178
+ durationInFrames: Internals22.calculateMediaDuration({
5935
6179
  trimAfter: trimAfterValue,
5936
6180
  mediaDurationInFrames: replaceWithOffthreadVideo.durationInSeconds * fps,
5937
6181
  playbackRate,
@@ -5960,7 +6204,7 @@ var {
5960
6204
  resolveTrimProps,
5961
6205
  validateMediaProps: validateMediaProps2,
5962
6206
  useCropStyle
5963
- } = Internals22;
6207
+ } = Internals23;
5964
6208
  var videoSchema = {
5965
6209
  src: {
5966
6210
  type: "asset",
@@ -5968,8 +6212,8 @@ var videoSchema = {
5968
6212
  description: "Source",
5969
6213
  keyframable: false
5970
6214
  },
5971
- ...Internals22.baseSchema,
5972
- ...Internals22.premountSchema,
6215
+ ...Internals23.baseSchema,
6216
+ ...Internals23.premountSchema,
5973
6217
  volume: {
5974
6218
  type: "number",
5975
6219
  min: 0,
@@ -5990,7 +6234,7 @@ var videoSchema = {
5990
6234
  },
5991
6235
  muted: { type: "boolean", default: false, description: "Muted" },
5992
6236
  loop: { type: "boolean", default: false, description: "Loop" },
5993
- ...Internals22.transformSchema,
6237
+ ...Internals23.transformSchema,
5994
6238
  ...Interactive2.backgroundSchema,
5995
6239
  ...Interactive2.borderSchema,
5996
6240
  ...Interactive2.borderRadiusSchema,
@@ -6153,10 +6397,10 @@ var VideoInner = ({
6153
6397
  cropBottom,
6154
6398
  ...props
6155
6399
  }) => {
6156
- const sourceStack = controls ? Internals22.getStackForControls(controls) ?? undefined : undefined;
6157
- const fallbackLogLevel = Internals22.useLogLevel();
6158
- const [mediaVolume] = Internals22.useMediaVolumeState();
6159
- const mediaStartsAt = Internals22.useMediaStartsAt();
6400
+ const sourceStack = controls ? Internals23.getStackForControls(controls) ?? undefined : undefined;
6401
+ const fallbackLogLevel = Internals23.useLogLevel();
6402
+ const [mediaVolume] = Internals23.useMediaVolumeState();
6403
+ const mediaStartsAt = Internals23.useMediaStartsAt();
6160
6404
  const videoConfig = useVideoConfig5();
6161
6405
  const sequenceDurationInFrames = Math.min(durationInFrames ?? Infinity, Math.max(0, videoConfig.durationInFrames - (from ?? 0)));
6162
6406
  const videoSequenceDuration = getVideoSequenceDuration({
@@ -6166,7 +6410,7 @@ var VideoInner = ({
6166
6410
  trimAfter,
6167
6411
  trimBefore
6168
6412
  });
6169
- const basicInfo = Internals22.useBasicMediaInTimeline({
6413
+ const basicInfo = Internals23.useBasicMediaInTimeline({
6170
6414
  src,
6171
6415
  volume,
6172
6416
  playbackRate: playbackRate ?? 1,
@@ -6201,11 +6445,11 @@ var VideoInner = ({
6201
6445
  type: "video",
6202
6446
  data: basicInfo
6203
6447
  }), [basicInfo]);
6204
- const memoizedEffects = Internals22.useMemoizedEffects({
6448
+ const memoizedEffects = Internals23.useMemoizedEffects({
6205
6449
  effects: effects ?? [],
6206
6450
  overrideId: controls?.overrideId ?? null
6207
6451
  });
6208
- const memoizedEffectDefinitions = Internals22.useMemoizedEffectDefinitions(effects ?? []);
6452
+ const memoizedEffectDefinitions = Internals23.useMemoizedEffectDefinitions(effects ?? []);
6209
6453
  const refForOutline = React6.useRef(null);
6210
6454
  const {
6211
6455
  effectivePostmountFor,
@@ -6215,7 +6459,7 @@ var VideoInner = ({
6215
6459
  postmountingActive,
6216
6460
  premountingActive,
6217
6461
  premountingStyle
6218
- } = Internals22.usePremounting({
6462
+ } = Internals23.usePremounting({
6219
6463
  from: from ?? 0,
6220
6464
  durationInFrames: videoSequenceDuration ?? Infinity,
6221
6465
  premountFor: premountFor ?? null,