@remotion/media 4.0.363 → 4.0.365
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 +12 -22
- package/dist/audio/audio-iterator.d.ts +11 -0
- package/dist/audio/audio-iterator.js +24 -0
- package/dist/audio/audio-preview-iterator.d.ts +31 -0
- package/dist/audio/audio-preview-iterator.js +168 -0
- package/dist/debug-overlay/preview-overlay.d.ts +19 -0
- package/dist/debug-overlay/preview-overlay.js +37 -0
- package/dist/esm/index.mjs +786 -542
- package/dist/helpers/round-to-4-digits.d.ts +1 -0
- package/dist/helpers/round-to-4-digits.js +4 -0
- package/dist/media-player.d.ts +87 -0
- package/dist/media-player.js +475 -0
- package/dist/video/props.d.ts +1 -0
- package/dist/video/video-for-preview.d.ts +3 -2
- package/dist/video/video-for-preview.js +30 -40
- package/dist/video/video-preview-iterator.d.ts +14 -0
- package/dist/video/video-preview-iterator.js +122 -0
- package/dist/video/video.js +4 -4
- package/dist/video-extraction/keyframe-bank.js +1 -4
- package/package.json +4 -4
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
3
3
|
import { Html5Video, Internals, useBufferState, useCurrentFrame } from 'remotion';
|
|
4
|
+
import { MediaPlayer } from '../media-player';
|
|
4
5
|
import { useLoopDisplay } from '../show-in-timeline';
|
|
5
6
|
import { useMediaInTimeline } from '../use-media-in-timeline';
|
|
6
|
-
import { MediaPlayer } from './media-player';
|
|
7
7
|
const { useUnsafeVideoConfig, Timeline, SharedAudioContext, useMediaMutedState, useMediaVolumeState, useFrameForVolumeProp, evaluateVolume, warnAboutTooHighVolume, usePreload, SequenceContext, SequenceVisibilityToggleContext, } = Internals;
|
|
8
|
-
export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logLevel, className, muted, volume, loopVolumeCurveBehavior, onVideoFrame, showInTimeline, loop, name, trimAfter, trimBefore, stack, disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps, audioStreamIndex, }) => {
|
|
8
|
+
export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logLevel, className, muted, volume, loopVolumeCurveBehavior, onVideoFrame, showInTimeline, loop, name, trimAfter, trimBefore, stack, disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps, audioStreamIndex, debugOverlay, }) => {
|
|
9
9
|
const src = usePreload(unpreloadedSrc);
|
|
10
10
|
const canvasRef = useRef(null);
|
|
11
11
|
const videoConfig = useUnsafeVideoConfig();
|
|
@@ -56,13 +56,15 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
56
56
|
if (!videoConfig) {
|
|
57
57
|
throw new Error('No video config found');
|
|
58
58
|
}
|
|
59
|
-
if (!src) {
|
|
60
|
-
throw new TypeError('No `src` was passed to <NewVideoForPreview>.');
|
|
61
|
-
}
|
|
62
59
|
const currentTime = frame / videoConfig.fps;
|
|
63
60
|
const currentTimeRef = useRef(currentTime);
|
|
64
61
|
currentTimeRef.current = currentTime;
|
|
65
62
|
const preloadedSrc = usePreload(src);
|
|
63
|
+
const buffering = useContext(Internals.BufferingContextReact);
|
|
64
|
+
if (!buffering) {
|
|
65
|
+
throw new Error('useMediaPlayback must be used inside a <BufferingContext>');
|
|
66
|
+
}
|
|
67
|
+
const isPlayerBuffering = Internals.useIsPlayerBuffering(buffering);
|
|
66
68
|
useEffect(() => {
|
|
67
69
|
if (!canvasRef.current)
|
|
68
70
|
return;
|
|
@@ -82,11 +84,16 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
82
84
|
fps: videoConfig.fps,
|
|
83
85
|
playbackRate,
|
|
84
86
|
audioStreamIndex,
|
|
87
|
+
debugOverlay,
|
|
88
|
+
bufferState: buffer,
|
|
85
89
|
});
|
|
86
90
|
mediaPlayerRef.current = player;
|
|
87
91
|
player
|
|
88
92
|
.initialize(currentTimeRef.current)
|
|
89
93
|
.then((result) => {
|
|
94
|
+
if (result.type === 'disposed') {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
90
97
|
if (result.type === 'unknown-container-format') {
|
|
91
98
|
if (disallowFallbackToOffthreadVideo) {
|
|
92
99
|
throw new Error(`Unknown container format ${preloadedSrc}, and 'disallowFallbackToOffthreadVideo' was set.`);
|
|
@@ -125,17 +132,17 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
125
132
|
}
|
|
126
133
|
})
|
|
127
134
|
.catch((error) => {
|
|
128
|
-
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[
|
|
135
|
+
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[VideoForPreview] Failed to initialize MediaPlayer', error);
|
|
129
136
|
setShouldFallbackToNativeVideo(true);
|
|
130
137
|
});
|
|
131
138
|
}
|
|
132
139
|
catch (error) {
|
|
133
|
-
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[
|
|
140
|
+
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[VideoForPreview] MediaPlayer initialization failed', error);
|
|
134
141
|
setShouldFallbackToNativeVideo(true);
|
|
135
142
|
}
|
|
136
143
|
return () => {
|
|
137
144
|
if (mediaPlayerRef.current) {
|
|
138
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[
|
|
145
|
+
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[VideoForPreview] Disposing MediaPlayer`);
|
|
139
146
|
mediaPlayerRef.current.dispose();
|
|
140
147
|
mediaPlayerRef.current = null;
|
|
141
148
|
}
|
|
@@ -153,6 +160,8 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
153
160
|
playbackRate,
|
|
154
161
|
disallowFallbackToOffthreadVideo,
|
|
155
162
|
audioStreamIndex,
|
|
163
|
+
debugOverlay,
|
|
164
|
+
buffer,
|
|
156
165
|
]);
|
|
157
166
|
const classNameValue = useMemo(() => {
|
|
158
167
|
return [Internals.OBJECTFIT_CONTAIN_CLASS_NAME, className]
|
|
@@ -163,46 +172,20 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
163
172
|
const mediaPlayer = mediaPlayerRef.current;
|
|
164
173
|
if (!mediaPlayer)
|
|
165
174
|
return;
|
|
166
|
-
if (playing) {
|
|
167
|
-
mediaPlayer.play(
|
|
168
|
-
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[NewVideoForPreview] Failed to play', error);
|
|
169
|
-
});
|
|
175
|
+
if (playing && !isPlayerBuffering) {
|
|
176
|
+
mediaPlayer.play(currentTimeRef.current);
|
|
170
177
|
}
|
|
171
178
|
else {
|
|
172
179
|
mediaPlayer.pause();
|
|
173
180
|
}
|
|
174
|
-
}, [playing, logLevel, mediaPlayerReady]);
|
|
175
|
-
|
|
181
|
+
}, [isPlayerBuffering, playing, logLevel, mediaPlayerReady]);
|
|
182
|
+
useLayoutEffect(() => {
|
|
176
183
|
const mediaPlayer = mediaPlayerRef.current;
|
|
177
184
|
if (!mediaPlayer || !mediaPlayerReady)
|
|
178
185
|
return;
|
|
179
186
|
mediaPlayer.seekTo(currentTime);
|
|
180
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[
|
|
187
|
+
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[VideoForPreview] Updating target time to ${currentTime.toFixed(3)}s`);
|
|
181
188
|
}, [currentTime, logLevel, mediaPlayerReady]);
|
|
182
|
-
useEffect(() => {
|
|
183
|
-
const mediaPlayer = mediaPlayerRef.current;
|
|
184
|
-
if (!mediaPlayer || !mediaPlayerReady)
|
|
185
|
-
return;
|
|
186
|
-
let currentBlock = null;
|
|
187
|
-
const unsubscribe = mediaPlayer.onBufferingChange((newBufferingState) => {
|
|
188
|
-
if (newBufferingState && !currentBlock) {
|
|
189
|
-
currentBlock = buffer.delayPlayback();
|
|
190
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, '[NewVideoForPreview] MediaPlayer buffering - blocking Remotion playback');
|
|
191
|
-
}
|
|
192
|
-
else if (!newBufferingState && currentBlock) {
|
|
193
|
-
currentBlock.unblock();
|
|
194
|
-
currentBlock = null;
|
|
195
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, '[NewVideoForPreview] MediaPlayer unbuffering - unblocking Remotion playback');
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
return () => {
|
|
199
|
-
unsubscribe();
|
|
200
|
-
if (currentBlock) {
|
|
201
|
-
currentBlock.unblock();
|
|
202
|
-
currentBlock = null;
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
}, [mediaPlayerReady, buffer, logLevel]);
|
|
206
189
|
const effectiveMuted = isSequenceHidden || muted || mediaMuted || userPreferredVolume <= 0;
|
|
207
190
|
useEffect(() => {
|
|
208
191
|
const mediaPlayer = mediaPlayerRef.current;
|
|
@@ -217,6 +200,13 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
217
200
|
}
|
|
218
201
|
mediaPlayer.setVolume(userPreferredVolume);
|
|
219
202
|
}, [userPreferredVolume, mediaPlayerReady]);
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
const mediaPlayer = mediaPlayerRef.current;
|
|
205
|
+
if (!mediaPlayer || !mediaPlayerReady) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
mediaPlayer.setDebugOverlay(debugOverlay);
|
|
209
|
+
}, [debugOverlay, mediaPlayerReady]);
|
|
220
210
|
const effectivePlaybackRate = useMemo(() => playbackRate * globalPlaybackRate, [playbackRate, globalPlaybackRate]);
|
|
221
211
|
useEffect(() => {
|
|
222
212
|
const mediaPlayer = mediaPlayerRef.current;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CanvasSink, WrappedCanvas } from 'mediabunny';
|
|
2
|
+
export declare const createVideoIterator: (timeToSeek: number, videoSink: CanvasSink) => {
|
|
3
|
+
destroy: () => void;
|
|
4
|
+
getNext: () => Promise<IteratorResult<WrappedCanvas, void>>;
|
|
5
|
+
isDestroyed: () => boolean;
|
|
6
|
+
tryToSatisfySeek: (time: number) => Promise<{
|
|
7
|
+
type: "not-satisfied";
|
|
8
|
+
reason: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: "satisfied";
|
|
11
|
+
frame: WrappedCanvas;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
export type VideoIterator = ReturnType<typeof createVideoIterator>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { roundTo4Digits } from '../helpers/round-to-4-digits';
|
|
2
|
+
export const createVideoIterator = (timeToSeek, videoSink) => {
|
|
3
|
+
let destroyed = false;
|
|
4
|
+
const iterator = videoSink.canvases(timeToSeek);
|
|
5
|
+
let lastReturnedFrame = null;
|
|
6
|
+
let iteratorEnded = false;
|
|
7
|
+
const getNextOrNullIfNotAvailable = async () => {
|
|
8
|
+
const next = iterator.next();
|
|
9
|
+
const result = await Promise.race([
|
|
10
|
+
next,
|
|
11
|
+
new Promise((resolve) => {
|
|
12
|
+
Promise.resolve().then(() => resolve());
|
|
13
|
+
}),
|
|
14
|
+
]);
|
|
15
|
+
if (!result) {
|
|
16
|
+
return {
|
|
17
|
+
type: 'need-to-wait-for-it',
|
|
18
|
+
waitPromise: async () => {
|
|
19
|
+
const res = await next;
|
|
20
|
+
if (res.value) {
|
|
21
|
+
lastReturnedFrame = res.value;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
iteratorEnded = true;
|
|
25
|
+
}
|
|
26
|
+
return res.value;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (result.value) {
|
|
31
|
+
lastReturnedFrame = result.value;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
iteratorEnded = true;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
type: 'got-frame-or-end',
|
|
38
|
+
frame: result.value ?? null,
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const destroy = () => {
|
|
42
|
+
destroyed = true;
|
|
43
|
+
lastReturnedFrame = null;
|
|
44
|
+
iterator.return().catch(() => undefined);
|
|
45
|
+
};
|
|
46
|
+
const tryToSatisfySeek = async (time) => {
|
|
47
|
+
if (lastReturnedFrame) {
|
|
48
|
+
const frameTimestamp = roundTo4Digits(lastReturnedFrame.timestamp);
|
|
49
|
+
if (roundTo4Digits(time) < frameTimestamp) {
|
|
50
|
+
return {
|
|
51
|
+
type: 'not-satisfied',
|
|
52
|
+
reason: `iterator is too far, most recently returned ${frameTimestamp}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const frameEndTimestamp = roundTo4Digits(lastReturnedFrame.timestamp + lastReturnedFrame.duration);
|
|
56
|
+
const timestamp = roundTo4Digits(time);
|
|
57
|
+
if (frameTimestamp <= timestamp && frameEndTimestamp > timestamp) {
|
|
58
|
+
return {
|
|
59
|
+
type: 'satisfied',
|
|
60
|
+
frame: lastReturnedFrame,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (iteratorEnded) {
|
|
65
|
+
if (lastReturnedFrame) {
|
|
66
|
+
return {
|
|
67
|
+
type: 'satisfied',
|
|
68
|
+
frame: lastReturnedFrame,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
type: 'not-satisfied',
|
|
73
|
+
reason: 'iterator ended',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
while (true) {
|
|
77
|
+
const frame = await getNextOrNullIfNotAvailable();
|
|
78
|
+
if (frame.type === 'need-to-wait-for-it') {
|
|
79
|
+
return {
|
|
80
|
+
type: 'not-satisfied',
|
|
81
|
+
reason: 'iterator did not have frame ready',
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (frame.type === 'got-frame-or-end') {
|
|
85
|
+
if (frame.frame === null) {
|
|
86
|
+
iteratorEnded = true;
|
|
87
|
+
if (lastReturnedFrame) {
|
|
88
|
+
return {
|
|
89
|
+
type: 'satisfied',
|
|
90
|
+
frame: lastReturnedFrame,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
type: 'not-satisfied',
|
|
95
|
+
reason: 'iterator ended and did not have frame ready',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const frameTimestamp = roundTo4Digits(frame.frame.timestamp);
|
|
99
|
+
const frameEndTimestamp = roundTo4Digits(frame.frame.timestamp + frame.frame.duration);
|
|
100
|
+
const timestamp = roundTo4Digits(time);
|
|
101
|
+
if (frameTimestamp <= timestamp && frameEndTimestamp > timestamp) {
|
|
102
|
+
return {
|
|
103
|
+
type: 'satisfied',
|
|
104
|
+
frame: frame.frame,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
throw new Error('Unreachable');
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
destroy,
|
|
114
|
+
getNext: () => {
|
|
115
|
+
return iterator.next();
|
|
116
|
+
},
|
|
117
|
+
isDestroyed: () => {
|
|
118
|
+
return destroyed;
|
|
119
|
+
},
|
|
120
|
+
tryToSatisfySeek,
|
|
121
|
+
};
|
|
122
|
+
};
|
package/dist/video/video.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Internals, useRemotionEnvironment } from 'remotion';
|
|
|
3
3
|
import { VideoForPreview } from './video-for-preview';
|
|
4
4
|
import { VideoForRendering } from './video-for-rendering';
|
|
5
5
|
const { validateMediaTrimProps, resolveTrimProps, validateMediaProps } = Internals;
|
|
6
|
-
const InnerVideo = ({ src, audioStreamIndex, className, delayRenderRetries, delayRenderTimeoutInMilliseconds, disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps, logLevel, loop, loopVolumeCurveBehavior, muted, name, onVideoFrame, playbackRate, style, trimAfter, trimBefore, volume, stack, toneFrequency, showInTimeline, }) => {
|
|
6
|
+
const InnerVideo = ({ src, audioStreamIndex, className, delayRenderRetries, delayRenderTimeoutInMilliseconds, disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps, logLevel, loop, loopVolumeCurveBehavior, muted, name, onVideoFrame, playbackRate, style, trimAfter, trimBefore, volume, stack, toneFrequency, showInTimeline, debugOverlay, }) => {
|
|
7
7
|
const environment = useRemotionEnvironment();
|
|
8
8
|
if (typeof src !== 'string') {
|
|
9
9
|
throw new TypeError(`The \`<Video>\` tag requires a string for \`src\`, but got ${JSON.stringify(src)} instead.`);
|
|
@@ -24,10 +24,10 @@ const InnerVideo = ({ src, audioStreamIndex, className, delayRenderRetries, dela
|
|
|
24
24
|
if (environment.isRendering) {
|
|
25
25
|
return (_jsx(VideoForRendering, { audioStreamIndex: audioStreamIndex ?? 0, className: className, delayRenderRetries: delayRenderRetries ?? null, delayRenderTimeoutInMilliseconds: delayRenderTimeoutInMilliseconds ?? null, disallowFallbackToOffthreadVideo: disallowFallbackToOffthreadVideo ?? false, name: name, fallbackOffthreadVideoProps: fallbackOffthreadVideoProps, logLevel: logLevel, loop: loop, loopVolumeCurveBehavior: loopVolumeCurveBehavior, muted: muted, onVideoFrame: onVideoFrame, playbackRate: playbackRate, src: src, stack: stack, style: style, volume: volume, toneFrequency: toneFrequency, trimAfterValue: trimAfterValue, trimBeforeValue: trimBeforeValue }));
|
|
26
26
|
}
|
|
27
|
-
return (_jsx(VideoForPreview, { audioStreamIndex: audioStreamIndex ?? 0, className: className, name: name, logLevel: logLevel, loop: loop, loopVolumeCurveBehavior: loopVolumeCurveBehavior, muted: muted, onVideoFrame: onVideoFrame, playbackRate: playbackRate, src: src, style: style, volume: volume, showInTimeline: showInTimeline, trimAfter: trimAfterValue, trimBefore: trimBeforeValue, stack: stack ?? null, disallowFallbackToOffthreadVideo: disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps: fallbackOffthreadVideoProps }));
|
|
27
|
+
return (_jsx(VideoForPreview, { audioStreamIndex: audioStreamIndex ?? 0, className: className, name: name, logLevel: logLevel, loop: loop, loopVolumeCurveBehavior: loopVolumeCurveBehavior, muted: muted, onVideoFrame: onVideoFrame, playbackRate: playbackRate, src: src, style: style, volume: volume, showInTimeline: showInTimeline, trimAfter: trimAfterValue, trimBefore: trimBeforeValue, stack: stack ?? null, disallowFallbackToOffthreadVideo: disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps: fallbackOffthreadVideoProps, debugOverlay: debugOverlay ?? false }));
|
|
28
28
|
};
|
|
29
|
-
export const Video = ({ src, audioStreamIndex, className, delayRenderRetries, delayRenderTimeoutInMilliseconds, disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps, logLevel, loop, loopVolumeCurveBehavior, muted, name, onVideoFrame, playbackRate, showInTimeline, style, trimAfter, trimBefore, volume, stack, toneFrequency, }) => {
|
|
29
|
+
export const Video = ({ src, audioStreamIndex, className, delayRenderRetries, delayRenderTimeoutInMilliseconds, disallowFallbackToOffthreadVideo, fallbackOffthreadVideoProps, logLevel, loop, loopVolumeCurveBehavior, muted, name, onVideoFrame, playbackRate, showInTimeline, style, trimAfter, trimBefore, volume, stack, toneFrequency, debugOverlay, }) => {
|
|
30
30
|
return (_jsx(InnerVideo, { audioStreamIndex: audioStreamIndex ?? 0, className: className, delayRenderRetries: delayRenderRetries ?? null, delayRenderTimeoutInMilliseconds: delayRenderTimeoutInMilliseconds ?? null, disallowFallbackToOffthreadVideo: disallowFallbackToOffthreadVideo ?? false, fallbackOffthreadVideoProps: fallbackOffthreadVideoProps ?? {}, logLevel: logLevel ??
|
|
31
|
-
(typeof window !== 'undefined' ? window.remotion_logLevel : 'info'), loop: loop ?? false, loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? 'repeat', muted: muted ?? false, name: name, onVideoFrame: onVideoFrame, playbackRate: playbackRate ?? 1, showInTimeline: showInTimeline ?? true, src: src, style: style ?? {}, trimAfter: trimAfter, trimBefore: trimBefore, volume: volume ?? 1, toneFrequency: toneFrequency ?? 1, stack: stack }));
|
|
31
|
+
(typeof window !== 'undefined' ? window.remotion_logLevel : 'info'), loop: loop ?? false, loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? 'repeat', muted: muted ?? false, name: name, onVideoFrame: onVideoFrame, playbackRate: playbackRate ?? 1, showInTimeline: showInTimeline ?? true, src: src, style: style ?? {}, trimAfter: trimAfter, trimBefore: trimBefore, volume: volume ?? 1, toneFrequency: toneFrequency ?? 1, stack: stack, debugOverlay: debugOverlay ?? false }));
|
|
32
32
|
};
|
|
33
33
|
Internals.addSequenceStackTraces(Video);
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { Internals } from 'remotion';
|
|
2
2
|
import { SAFE_BACK_WINDOW_IN_SECONDS } from '../caches';
|
|
3
|
+
import { roundTo4Digits } from '../helpers/round-to-4-digits';
|
|
3
4
|
import { renderTimestampRange } from '../render-timestamp-range';
|
|
4
|
-
// Round to only 4 digits, because WebM has a timescale of 1_000, e.g. framer.webm
|
|
5
|
-
const roundTo4Digits = (timestamp) => {
|
|
6
|
-
return Math.round(timestamp * 1000) / 1000;
|
|
7
|
-
};
|
|
8
5
|
export const makeKeyframeBank = ({ startTimestampInSeconds, endTimestampInSeconds, sampleIterator, logLevel: parentLogLevel, src, }) => {
|
|
9
6
|
Internals.Log.verbose({ logLevel: parentLogLevel, tag: '@remotion/media' }, `Creating keyframe bank from ${startTimestampInSeconds}sec to ${endTimestampInSeconds}sec`);
|
|
10
7
|
const frames = {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/media",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.365",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"make": "tsc -d && bun --env-file=../.env.bundle bundle.ts"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"mediabunny": "1.
|
|
25
|
-
"remotion": "4.0.
|
|
24
|
+
"mediabunny": "1.24.2",
|
|
25
|
+
"remotion": "4.0.365",
|
|
26
26
|
"webdriverio": "9.19.2"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"react-dom": ">=16.8.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
33
|
+
"@remotion/eslint-config-internal": "4.0.365",
|
|
34
34
|
"@vitest/browser": "^3.2.4",
|
|
35
35
|
"eslint": "9.19.0",
|
|
36
36
|
"react": "19.0.0",
|