@remotion/media 4.0.363 → 4.0.364
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 +4 -1
- 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 +14 -0
- package/dist/audio/audio-preview-iterator.js +43 -0
- package/dist/debug-overlay/preview-overlay.d.ts +5 -0
- package/dist/debug-overlay/preview-overlay.js +13 -0
- package/dist/esm/index.mjs +549 -378
- 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 +95 -0
- package/dist/media-player.js +496 -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 +25 -14
- 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,9 +56,6 @@ 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;
|
|
@@ -82,11 +79,16 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
82
79
|
fps: videoConfig.fps,
|
|
83
80
|
playbackRate,
|
|
84
81
|
audioStreamIndex,
|
|
82
|
+
debugOverlay,
|
|
83
|
+
bufferState: buffer,
|
|
85
84
|
});
|
|
86
85
|
mediaPlayerRef.current = player;
|
|
87
86
|
player
|
|
88
87
|
.initialize(currentTimeRef.current)
|
|
89
88
|
.then((result) => {
|
|
89
|
+
if (result.type === 'disposed') {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
90
92
|
if (result.type === 'unknown-container-format') {
|
|
91
93
|
if (disallowFallbackToOffthreadVideo) {
|
|
92
94
|
throw new Error(`Unknown container format ${preloadedSrc}, and 'disallowFallbackToOffthreadVideo' was set.`);
|
|
@@ -125,17 +127,17 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
125
127
|
}
|
|
126
128
|
})
|
|
127
129
|
.catch((error) => {
|
|
128
|
-
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[
|
|
130
|
+
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[VideoForPreview] Failed to initialize MediaPlayer', error);
|
|
129
131
|
setShouldFallbackToNativeVideo(true);
|
|
130
132
|
});
|
|
131
133
|
}
|
|
132
134
|
catch (error) {
|
|
133
|
-
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[
|
|
135
|
+
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[VideoForPreview] MediaPlayer initialization failed', error);
|
|
134
136
|
setShouldFallbackToNativeVideo(true);
|
|
135
137
|
}
|
|
136
138
|
return () => {
|
|
137
139
|
if (mediaPlayerRef.current) {
|
|
138
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[
|
|
140
|
+
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[VideoForPreview] Disposing MediaPlayer`);
|
|
139
141
|
mediaPlayerRef.current.dispose();
|
|
140
142
|
mediaPlayerRef.current = null;
|
|
141
143
|
}
|
|
@@ -153,6 +155,8 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
153
155
|
playbackRate,
|
|
154
156
|
disallowFallbackToOffthreadVideo,
|
|
155
157
|
audioStreamIndex,
|
|
158
|
+
debugOverlay,
|
|
159
|
+
buffer,
|
|
156
160
|
]);
|
|
157
161
|
const classNameValue = useMemo(() => {
|
|
158
162
|
return [Internals.OBJECTFIT_CONTAIN_CLASS_NAME, className]
|
|
@@ -165,19 +169,19 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
165
169
|
return;
|
|
166
170
|
if (playing) {
|
|
167
171
|
mediaPlayer.play().catch((error) => {
|
|
168
|
-
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[
|
|
172
|
+
Internals.Log.error({ logLevel, tag: '@remotion/media' }, '[VideoForPreview] Failed to play', error);
|
|
169
173
|
});
|
|
170
174
|
}
|
|
171
175
|
else {
|
|
172
176
|
mediaPlayer.pause();
|
|
173
177
|
}
|
|
174
178
|
}, [playing, logLevel, mediaPlayerReady]);
|
|
175
|
-
|
|
179
|
+
useLayoutEffect(() => {
|
|
176
180
|
const mediaPlayer = mediaPlayerRef.current;
|
|
177
181
|
if (!mediaPlayer || !mediaPlayerReady)
|
|
178
182
|
return;
|
|
179
183
|
mediaPlayer.seekTo(currentTime);
|
|
180
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[
|
|
184
|
+
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, `[VideoForPreview] Updating target time to ${currentTime.toFixed(3)}s`);
|
|
181
185
|
}, [currentTime, logLevel, mediaPlayerReady]);
|
|
182
186
|
useEffect(() => {
|
|
183
187
|
const mediaPlayer = mediaPlayerRef.current;
|
|
@@ -187,12 +191,12 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
187
191
|
const unsubscribe = mediaPlayer.onBufferingChange((newBufferingState) => {
|
|
188
192
|
if (newBufferingState && !currentBlock) {
|
|
189
193
|
currentBlock = buffer.delayPlayback();
|
|
190
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, '[
|
|
194
|
+
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, '[VideoForPreview] MediaPlayer buffering - blocking Remotion playback');
|
|
191
195
|
}
|
|
192
196
|
else if (!newBufferingState && currentBlock) {
|
|
193
197
|
currentBlock.unblock();
|
|
194
198
|
currentBlock = null;
|
|
195
|
-
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, '[
|
|
199
|
+
Internals.Log.trace({ logLevel, tag: '@remotion/media' }, '[VideoForPreview] MediaPlayer unbuffering - unblocking Remotion playback');
|
|
196
200
|
}
|
|
197
201
|
});
|
|
198
202
|
return () => {
|
|
@@ -217,6 +221,13 @@ export const VideoForPreview = ({ src: unpreloadedSrc, style, playbackRate, logL
|
|
|
217
221
|
}
|
|
218
222
|
mediaPlayer.setVolume(userPreferredVolume);
|
|
219
223
|
}, [userPreferredVolume, mediaPlayerReady]);
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
const mediaPlayer = mediaPlayerRef.current;
|
|
226
|
+
if (!mediaPlayer || !mediaPlayerReady) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
mediaPlayer.setDebugOverlay(debugOverlay);
|
|
230
|
+
}, [debugOverlay, mediaPlayerReady]);
|
|
220
231
|
const effectivePlaybackRate = useMemo(() => playbackRate * globalPlaybackRate, [playbackRate, globalPlaybackRate]);
|
|
221
232
|
useEffect(() => {
|
|
222
233
|
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.364",
|
|
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.1",
|
|
25
|
+
"remotion": "4.0.364",
|
|
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.364",
|
|
34
34
|
"@vitest/browser": "^3.2.4",
|
|
35
35
|
"eslint": "9.19.0",
|
|
36
36
|
"react": "19.0.0",
|