@remotion/media 4.0.401 → 4.0.403
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/audio-for-preview.js +2 -4
- package/dist/audio/audio-for-rendering.js +8 -6
- package/dist/audio-extraction/audio-iterator.js +3 -3
- package/dist/audio-extraction/audio-manager.js +9 -1
- package/dist/caches.d.ts +6 -7
- package/dist/caches.js +2 -2
- package/dist/debug-overlay/preview-overlay.d.ts +2 -2
- package/dist/debug-overlay/preview-overlay.js +5 -3
- package/dist/esm/index.mjs +376 -355
- package/dist/extract-frame-and-audio.js +14 -29
- package/dist/media-player.d.ts +3 -3
- package/dist/media-player.js +38 -24
- package/dist/video/video-for-preview.js +0 -2
- package/dist/video/video.js +2 -4
- package/dist/video-extraction/extract-frame.d.ts +1 -1
- package/dist/video-extraction/extract-frame.js +9 -10
- package/dist/video-extraction/get-frames-since-keyframe.d.ts +2 -12
- package/dist/video-extraction/get-frames-since-keyframe.js +14 -17
- package/dist/video-extraction/keyframe-bank.d.ts +12 -10
- package/dist/video-extraction/keyframe-bank.js +93 -52
- package/dist/video-extraction/keyframe-manager.d.ts +6 -7
- package/dist/video-extraction/keyframe-manager.js +72 -77
- package/package.json +3 -3
|
@@ -270,6 +270,7 @@ const AudioForPreviewAssertedShowing = ({ src, playbackRate, logLevel, muted, vo
|
|
|
270
270
|
};
|
|
271
271
|
export const AudioForPreview = ({ loop, src, logLevel, muted, name, volume, loopVolumeCurveBehavior, playbackRate, trimAfter, trimBefore, showInTimeline, stack, disallowFallbackToHtml5Audio, toneFrequency, audioStreamIndex, fallbackHtml5AudioProps, }) => {
|
|
272
272
|
const preloadedSrc = usePreload(src);
|
|
273
|
+
const defaultLogLevel = Internals.useLogLevel();
|
|
273
274
|
const frame = useCurrentFrame();
|
|
274
275
|
const videoConfig = useVideoConfig();
|
|
275
276
|
const currentTime = frame / videoConfig.fps;
|
|
@@ -297,8 +298,5 @@ export const AudioForPreview = ({ loop, src, logLevel, muted, name, volume, loop
|
|
|
297
298
|
if (!showShow) {
|
|
298
299
|
return null;
|
|
299
300
|
}
|
|
300
|
-
return (_jsx(AudioForPreviewAssertedShowing, { audioStreamIndex: audioStreamIndex ?? 0, src: preloadedSrc, playbackRate: playbackRate ?? 1, logLevel: logLevel ??
|
|
301
|
-
(typeof window !== 'undefined'
|
|
302
|
-
? (window.remotion_logLevel ?? 'info')
|
|
303
|
-
: 'info'), muted: muted ?? false, volume: volume ?? 1, loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? 'repeat', loop: loop ?? false, trimAfter: trimAfter, trimBefore: trimBefore, name: name, showInTimeline: showInTimeline ?? true, stack: stack, disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false, toneFrequency: toneFrequency, fallbackHtml5AudioProps: fallbackHtml5AudioProps }));
|
|
301
|
+
return (_jsx(AudioForPreviewAssertedShowing, { audioStreamIndex: audioStreamIndex ?? 0, src: preloadedSrc, playbackRate: playbackRate ?? 1, logLevel: logLevel ?? defaultLogLevel, muted: muted ?? false, volume: volume ?? 1, loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? 'repeat', loop: loop ?? false, trimAfter: trimAfter, trimBefore: trimBefore, name: name, showInTimeline: showInTimeline ?? true, stack: stack, disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false, toneFrequency: toneFrequency, fallbackHtml5AudioProps: fallbackHtml5AudioProps }));
|
|
304
302
|
};
|
|
@@ -6,7 +6,9 @@ import { applyVolume } from '../convert-audiodata/apply-volume';
|
|
|
6
6
|
import { TARGET_SAMPLE_RATE } from '../convert-audiodata/resample-audiodata';
|
|
7
7
|
import { frameForVolumeProp } from '../looped-frame';
|
|
8
8
|
import { extractFrameViaBroadcastChannel } from '../video-extraction/extract-frame-via-broadcast-channel';
|
|
9
|
-
export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted, loopVolumeCurveBehavior, delayRenderRetries, delayRenderTimeoutInMilliseconds, logLevel
|
|
9
|
+
export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted, loopVolumeCurveBehavior, delayRenderRetries, delayRenderTimeoutInMilliseconds, logLevel: overriddenLogLevel, loop, fallbackHtml5AudioProps, audioStreamIndex, showInTimeline, style, name, disallowFallbackToHtml5Audio, toneFrequency, trimAfter, trimBefore, }) => {
|
|
10
|
+
const defaultLogLevel = Internals.useLogLevel();
|
|
11
|
+
const logLevel = overriddenLogLevel ?? defaultLogLevel;
|
|
10
12
|
const frame = useCurrentFrame();
|
|
11
13
|
const absoluteFrame = Internals.useTimelinePosition();
|
|
12
14
|
const videoConfig = Internals.useUnsafeVideoConfig();
|
|
@@ -31,7 +33,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
31
33
|
sequenceContext?.relativeFrom,
|
|
32
34
|
sequenceContext?.durationInFrames,
|
|
33
35
|
]);
|
|
34
|
-
const maxCacheSize = useMaxMediaCacheSize(logLevel
|
|
36
|
+
const maxCacheSize = useMaxMediaCacheSize(logLevel);
|
|
35
37
|
const audioEnabled = Internals.useAudioEnabled();
|
|
36
38
|
useLayoutEffect(() => {
|
|
37
39
|
const timestamp = frame / fps;
|
|
@@ -60,7 +62,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
60
62
|
timeInSeconds: timestamp,
|
|
61
63
|
durationInSeconds,
|
|
62
64
|
playbackRate: playbackRate ?? 1,
|
|
63
|
-
logLevel
|
|
65
|
+
logLevel,
|
|
64
66
|
includeAudio: shouldRenderAudio,
|
|
65
67
|
includeVideo: false,
|
|
66
68
|
isClientSideRendering: environment.isClientSideRendering,
|
|
@@ -81,7 +83,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
81
83
|
cancelRender(new Error(`Unknown container format ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
|
|
82
84
|
}
|
|
83
85
|
Internals.Log.warn({
|
|
84
|
-
logLevel
|
|
86
|
+
logLevel,
|
|
85
87
|
tag: '@remotion/media',
|
|
86
88
|
}, `Unknown container format for ${src} (Supported formats: https://www.remotion.dev/docs/mediabunny/formats), falling back to <Html5Audio>`);
|
|
87
89
|
setReplaceWithHtml5Audio(true);
|
|
@@ -96,7 +98,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
96
98
|
cancelRender(new Error(`Cannot decode ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
|
|
97
99
|
}
|
|
98
100
|
Internals.Log.warn({
|
|
99
|
-
logLevel
|
|
101
|
+
logLevel,
|
|
100
102
|
tag: '@remotion/media',
|
|
101
103
|
}, `Cannot decode ${src}, falling back to <Html5Audio>`);
|
|
102
104
|
setReplaceWithHtml5Audio(true);
|
|
@@ -114,7 +116,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
114
116
|
cancelRender(new Error(`Cannot decode ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
|
|
115
117
|
}
|
|
116
118
|
Internals.Log.warn({
|
|
117
|
-
logLevel
|
|
119
|
+
logLevel,
|
|
118
120
|
tag: '@remotion/media',
|
|
119
121
|
}, `Network error fetching ${src}, falling back to <Html5Audio>`);
|
|
120
122
|
setReplaceWithHtml5Audio(true);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Internals } from 'remotion';
|
|
2
|
-
import {
|
|
2
|
+
import { SAFE_WINDOW_OF_MONOTONICITY } from '../caches';
|
|
3
3
|
import { makeAudioCache } from './audio-cache';
|
|
4
4
|
// https://discord.com/channels/@me/1409810025844838481/1415028953093111870
|
|
5
5
|
// Audio frames might have dependencies on previous and next frames so we need to decode a bit more
|
|
@@ -47,7 +47,7 @@ export const makeAudioIterator = ({ audioSampleSink, isMatroska, startTimestamp,
|
|
|
47
47
|
if (fullDuration !== null && timestamp > fullDuration) {
|
|
48
48
|
// Clear all samples before the timestamp
|
|
49
49
|
// Do this in the while loop because samples might start from 0
|
|
50
|
-
cache.clearBeforeThreshold(fullDuration -
|
|
50
|
+
cache.clearBeforeThreshold(fullDuration - SAFE_WINDOW_OF_MONOTONICITY);
|
|
51
51
|
return [];
|
|
52
52
|
}
|
|
53
53
|
const samples = cache.getSamples(timestamp, durationInSeconds);
|
|
@@ -64,7 +64,7 @@ export const makeAudioIterator = ({ audioSampleSink, isMatroska, startTimestamp,
|
|
|
64
64
|
// Also do this after a sample has just been added, if it was the last sample we now have the duration
|
|
65
65
|
// and can prevent deleting the last sample
|
|
66
66
|
const deleteBefore = fullDuration === null ? timestamp : Math.min(timestamp, fullDuration);
|
|
67
|
-
cache.clearBeforeThreshold(deleteBefore -
|
|
67
|
+
cache.clearBeforeThreshold(deleteBefore - SAFE_WINDOW_OF_MONOTONICITY);
|
|
68
68
|
if (sample === null) {
|
|
69
69
|
break;
|
|
70
70
|
}
|
|
@@ -48,8 +48,16 @@ export const makeAudioManager = () => {
|
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
50
|
const getIterator = async ({ src, timeInSeconds, audioSampleSink, isMatroska, actualMatroskaTimestamps, logLevel, maxCacheSize, }) => {
|
|
51
|
-
|
|
51
|
+
let attempts = 0;
|
|
52
|
+
const maxAttempts = 3;
|
|
53
|
+
while ((await getTotalCacheStats()).totalSize > maxCacheSize &&
|
|
54
|
+
attempts < maxAttempts) {
|
|
52
55
|
deleteOldestIterator();
|
|
56
|
+
attempts++;
|
|
57
|
+
}
|
|
58
|
+
if ((await getTotalCacheStats()).totalSize > maxCacheSize &&
|
|
59
|
+
attempts >= maxAttempts) {
|
|
60
|
+
Internals.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.`);
|
|
53
61
|
}
|
|
54
62
|
for (const iterator of iterators) {
|
|
55
63
|
if (iterator.src === src &&
|
package/dist/caches.d.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { type LogLevel } from 'remotion';
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const SAFE_WINDOW_OF_MONOTONICITY = 0.2;
|
|
3
3
|
export declare const keyframeManager: {
|
|
4
|
-
requestKeyframeBank: ({
|
|
5
|
-
packetSink: import("mediabunny").EncodedPacketSink;
|
|
4
|
+
requestKeyframeBank: ({ timestamp, videoSampleSink, src, logLevel, maxCacheSize, }: {
|
|
6
5
|
timestamp: number;
|
|
7
6
|
videoSampleSink: import("mediabunny").VideoSampleSink;
|
|
8
7
|
src: string;
|
|
9
8
|
logLevel: LogLevel;
|
|
10
9
|
maxCacheSize: number;
|
|
11
|
-
}) => Promise<import("./video-extraction/keyframe-bank").KeyframeBank
|
|
12
|
-
getCacheStats: () =>
|
|
10
|
+
}) => Promise<import("./video-extraction/keyframe-bank").KeyframeBank>;
|
|
11
|
+
getCacheStats: () => {
|
|
13
12
|
count: number;
|
|
14
13
|
totalSize: number;
|
|
15
|
-
}
|
|
16
|
-
clearAll: (logLevel: LogLevel) =>
|
|
14
|
+
};
|
|
15
|
+
clearAll: (logLevel: LogLevel) => void;
|
|
17
16
|
};
|
|
18
17
|
export declare const audioManager: {
|
|
19
18
|
getIterator: ({ src, timeInSeconds, audioSampleSink, isMatroska, actualMatroskaTimestamps, logLevel, maxCacheSize, }: {
|
package/dist/caches.js
CHANGED
|
@@ -2,8 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { cancelRender, Internals } from 'remotion';
|
|
3
3
|
import { makeAudioManager } from './audio-extraction/audio-manager';
|
|
4
4
|
import { makeKeyframeManager } from './video-extraction/keyframe-manager';
|
|
5
|
-
//
|
|
6
|
-
export const
|
|
5
|
+
// Frames can be out of order, but we don't expect them to be more than 1 second out of order
|
|
6
|
+
export const SAFE_WINDOW_OF_MONOTONICITY = 0.2;
|
|
7
7
|
export const keyframeManager = makeKeyframeManager();
|
|
8
8
|
export const audioManager = makeAudioManager();
|
|
9
9
|
export const getTotalCacheStats = async () => {
|
|
@@ -2,8 +2,8 @@ import type { AudioIteratorManager } from '../audio-iterator-manager';
|
|
|
2
2
|
import type { VideoIteratorManager } from '../video-iterator-manager';
|
|
3
3
|
export declare const drawPreviewOverlay: ({ context, audioTime, audioContextState, audioSyncAnchor, playing, audioIteratorManager, videoIteratorManager, }: {
|
|
4
4
|
context: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;
|
|
5
|
-
audioTime: number;
|
|
6
|
-
audioContextState: AudioContextState;
|
|
5
|
+
audioTime: number | null;
|
|
6
|
+
audioContextState: AudioContextState | null;
|
|
7
7
|
audioSyncAnchor: number;
|
|
8
8
|
playing: boolean;
|
|
9
9
|
audioIteratorManager: AudioIteratorManager | null;
|
|
@@ -6,8 +6,10 @@ export const drawPreviewOverlay = ({ context, audioTime, audioContextState, audi
|
|
|
6
6
|
`Audio iterators created: ${audioIteratorManager?.getAudioIteratorsCreated()}`,
|
|
7
7
|
`Frames rendered: ${videoIteratorManager?.getFramesRendered()}`,
|
|
8
8
|
`Audio context state: ${audioContextState}`,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
audioTime
|
|
10
|
+
? `Audio time: ${(audioTime - audioSyncAnchor).toFixed(3)}s`
|
|
11
|
+
: null,
|
|
12
|
+
].filter(Boolean);
|
|
11
13
|
if (audioIteratorManager) {
|
|
12
14
|
const queuedPeriod = audioIteratorManager
|
|
13
15
|
.getAudioBufferIterator()
|
|
@@ -15,7 +17,7 @@ export const drawPreviewOverlay = ({ context, audioTime, audioContextState, audi
|
|
|
15
17
|
const numberOfChunksAfterResuming = audioIteratorManager
|
|
16
18
|
?.getAudioBufferIterator()
|
|
17
19
|
?.getNumberOfChunksAfterResuming();
|
|
18
|
-
if (queuedPeriod) {
|
|
20
|
+
if (queuedPeriod && audioTime) {
|
|
19
21
|
lines.push(`Audio queued until: ${(queuedPeriod.until - (audioTime - audioSyncAnchor)).toFixed(3)}s`);
|
|
20
22
|
}
|
|
21
23
|
else if (numberOfChunksAfterResuming) {
|