@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.
- package/dist/audio-extraction/audio-cache.d.ts +1 -0
- package/dist/audio-extraction/audio-manager.d.ts +8 -1
- package/dist/audio-extraction/extract-audio.d.ts +2 -0
- package/dist/caches.d.ts +291 -6
- package/dist/esm/index.mjs +649 -405
- package/dist/extract-frame-and-audio.d.ts +95 -1
- package/dist/get-shared-input.d.ts +2 -1
- package/dist/get-sink.d.ts +14 -12
- package/dist/max-cache-size.d.ts +3 -0
- package/dist/video-extraction/extract-frame-via-broadcast-channel.d.ts +95 -1
- package/dist/video-extraction/extract-frame.d.ts +2 -0
- package/dist/video-extraction/get-frames-since-keyframe.d.ts +14 -11
- package/dist/video-extraction/keyframe-bank.d.ts +1 -0
- package/dist/video-extraction/keyframe-manager.d.ts +8 -2
- package/package.json +4 -4
package/dist/esm/index.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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 } =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
} =
|
|
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 } =
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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 {
|
|
2842
|
+
import { Internals as Internals15 } from "remotion";
|
|
2793
2843
|
|
|
2794
2844
|
// src/audio-extraction/audio-manager.ts
|
|
2795
|
-
import { Internals as
|
|
2845
|
+
import { Internals as Internals10 } from "remotion";
|
|
2796
2846
|
|
|
2797
2847
|
// src/audio-extraction/audio-iterator.ts
|
|
2798
|
-
import { Internals as
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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
|
|
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 *
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3728
|
+
var RECENTLY_USED_REQUEST_COUNT = 50;
|
|
3729
|
+
var makeKeyframeManager = ({
|
|
3730
|
+
getTotalCacheStats
|
|
3731
|
+
}) => {
|
|
3388
3732
|
let sources = {};
|
|
3389
|
-
|
|
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
|
-
|
|
3760
|
+
Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
|
|
3405
3761
|
}
|
|
3406
3762
|
}
|
|
3407
|
-
|
|
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
|
-
|
|
3799
|
+
return { mostInThePastBank: null, numberOfBanks };
|
|
3441
3800
|
}
|
|
3442
3801
|
return { mostInThePastBank, numberOfBanks };
|
|
3443
3802
|
};
|
|
3444
3803
|
const deleteOldestKeyframeBank = (logLevel) => {
|
|
3445
|
-
const {
|
|
3446
|
-
|
|
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
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3895
|
+
Internals14.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
|
|
3535
3896
|
return existingBank;
|
|
3536
3897
|
}
|
|
3537
|
-
|
|
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
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
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
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
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
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
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
|
-
|
|
3642
|
-
return value;
|
|
3643
|
-
}
|
|
3644
|
-
return 1000 * 1000 * 1000;
|
|
4053
|
+
};
|
|
3645
4054
|
};
|
|
3646
|
-
var
|
|
3647
|
-
var
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
return
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
4986
|
+
const defaultLogLevel = Internals17.useLogLevel();
|
|
4764
4987
|
const logLevel = overriddenLogLevel ?? defaultLogLevel;
|
|
4765
4988
|
const frame = useCurrentFrame2();
|
|
4766
|
-
const absoluteFrame =
|
|
4767
|
-
const videoConfig =
|
|
4768
|
-
const { registerRenderAsset, unregisterRenderAsset } = useContext3(
|
|
4769
|
-
const startsAt =
|
|
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(
|
|
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
|
|
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
|
-
|
|
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 =
|
|
5099
|
+
const volume = Internals17.evaluateVolume({
|
|
4872
5100
|
volume: volumeProp,
|
|
4873
5101
|
frame: volumePropsFrame,
|
|
4874
5102
|
mediaVolume: 1
|
|
4875
5103
|
});
|
|
4876
|
-
|
|
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 } =
|
|
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
|
-
...
|
|
4964
|
-
...
|
|
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 ?
|
|
5001
|
-
const [mediaVolume] =
|
|
5002
|
-
const mediaStartsAt =
|
|
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 =
|
|
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
|
-
} =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
} =
|
|
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 } =
|
|
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(
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 [
|
|
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
|
|
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 =
|
|
5890
|
+
const absoluteFrame = Internals22.useTimelinePosition();
|
|
5659
5891
|
const { fps } = useVideoConfig4();
|
|
5660
|
-
const { registerRenderAsset, unregisterRenderAsset } = useContext5(
|
|
5661
|
-
const startsAt =
|
|
5662
|
-
const sequenceContext = useContext5(
|
|
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 =
|
|
5675
|
-
const videoEnabled =
|
|
5906
|
+
const audioEnabled = Internals22.useAudioEnabled();
|
|
5907
|
+
const videoEnabled = Internals22.useVideoEnabled();
|
|
5676
5908
|
const maxCacheSize = useMaxMediaCacheSize(logLevel);
|
|
5677
|
-
const
|
|
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
|
-
|
|
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
|
|
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 =
|
|
6057
|
+
const volume = Internals22.evaluateVolume({
|
|
5818
6058
|
volume: volumeProp,
|
|
5819
6059
|
frame: volumePropsFrame,
|
|
5820
6060
|
mediaVolume: 1
|
|
5821
6061
|
});
|
|
5822
|
-
|
|
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 [
|
|
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(
|
|
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:
|
|
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
|
-
} =
|
|
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
|
-
...
|
|
5972
|
-
...
|
|
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
|
-
...
|
|
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 ?
|
|
6157
|
-
const fallbackLogLevel =
|
|
6158
|
-
const [mediaVolume] =
|
|
6159
|
-
const mediaStartsAt =
|
|
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 =
|
|
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 =
|
|
6448
|
+
const memoizedEffects = Internals23.useMemoizedEffects({
|
|
6205
6449
|
effects: effects ?? [],
|
|
6206
6450
|
overrideId: controls?.overrideId ?? null
|
|
6207
6451
|
});
|
|
6208
|
-
const memoizedEffectDefinitions =
|
|
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
|
-
} =
|
|
6462
|
+
} = Internals23.usePremounting({
|
|
6219
6463
|
from: from ?? 0,
|
|
6220
6464
|
durationInFrames: videoSequenceDuration ?? Infinity,
|
|
6221
6465
|
premountFor: premountFor ?? null,
|