隨時間動態加速影片
學習如何在 Remotion 中讓影片的播放速度隨時間動態變化,透過累加播放率的方式正確計算每一幀應播放的影片位置
隨時間動態加速影片
有時你會想讓影片的播放速度隨時間變化——例如從正常速度開始,然後逐漸加速。本文說明正確的實作方式,以及為何直接插值 playbackRate 不可行。
注意: 此方法目前尚不支援
@remotion/media中的<Video>元件。
為何不能直接插值 playbackRate
你可能會直觉地想這樣寫:
// 錯誤做法
<OffthreadVideo
playbackRate={interpolate(frame, [0, 100], [1, 5])}
src="https://remotion.media/BigBuckBunny.mp4#disable"
/>;這樣做是錯的。 原因在於 Remotion 的渲染機制:每一幀都是獨立計算的,不依賴前一幀的狀態。
以第 100 幀為例:
playbackRate插值結果為5- Remotion 會播放影片的第
100 * 5 = 500幀 - 但實際上,速度是從 1 漸增到 5,真正應播放的影片位置遠不到第 500 幀
這種做法沒有把「之前所有幀的速度累積」考慮進去。
正確做法:累加播放率
正確的思路是:計算從第 0 幀到當前幀為止,所有幀的播放率加總,這樣就能得出影片實際應該播放到哪個位置。
import React from 'react';
import {interpolate, Sequence, useCurrentFrame, OffthreadVideo} from 'remotion';
/**
* 計算到第 frame 幀為止,實際應播放的影片位置(以幀為單位)
* @param frame 當前合成幀號
* @param speed 速度函式:輸入幀號,輸出該幀的播放速度
*/
const remapSpeed = (frame: number, speed: (fr: number) => number) => {
let framesPassed = 0;
for (let i = 0; i <= frame; i++) {
framesPassed += speed(i);
}
return framesPassed;
};
export const AcceleratedVideo: React.FC = () => {
const frame = useCurrentFrame();
// 速度函式:從第 0 幀的 1 倍速,線性增加到第 500 幀的 5 倍速
const speedFunction = (f: number) => interpolate(f, [0, 500], [1, 5]);
// 計算到目前為止實際播放的影片幀數
const remappedFrame = remapSpeed(frame, speedFunction);
return (
<Sequence from={frame}>
<OffthreadVideo
trimBefore={Math.round(remappedFrame)}
playbackRate={speedFunction(frame)}
src="https://remotion.media/BigBuckBunny.mp4#disable"
/>
</Sequence>
);
};程式碼深度解析
remapSpeed 函式
這個輔助函式透過迴圈累加每一幀的播放速度:
const remapSpeed = (frame: number, speed: (fr: number) => number) => {
let framesPassed = 0;
for (let i = 0; i <= frame; i++) {
framesPassed += speed(i);
}
return framesPassed;
};- 從第 0 幀迭代到當前幀
- 每次將該幀的速度值加入累計總量
- 回傳值代表「到目前為止,影片實際前進了多少幀」
範例計算(假設速度函式為線性 1→5,共 500 幀):
| 合成幀 | 該幀速度 | 累計影片幀 |
|---|---|---|
| 0 | 1.0 | 1 |
| 100 | 1.8 | ~140 |
| 250 | 3.0 | ~500 |
| 500 | 5.0 | ~1500 |
Sequence from={frame} 的作用
<Sequence from={frame}>
<OffthreadVideo trimBefore={Math.round(remappedFrame)} ... />
</Sequence><Sequence from={frame}>讓 Sequence 的起始點跟隨當前幀移動- 搭配
trimBefore,確保影片從正確的位置開始播放 - 在 Remotion Studio 中,你會看到時間軸隨播放移動——這是正常現象,只要計算是冪等的就沒問題
#disable 片段提示
src="https://remotion.media/BigBuckBunny.mp4#disable"通常 Remotion 會自動在 URL 後面加上媒體片段提示(如 #t=10,20),告訴瀏覽器只需載入哪段影片。加上 #disable 可以停用這個行為,因為我們是透過 trimBefore 手動控制播放位置的。
不同速度模式
固定倍速(簡單情況)
若只需固定速度播放,直接使用 playbackRate 即可:
<OffthreadVideo
playbackRate={2}
src={staticFile('video.mp4')}
/>分段速度(不同片段不同速度)
可以結合跳切技術,讓不同片段以不同速度播放。詳見 影片跳切。
自定義速度曲線
speedFunction 可以是任意函式,不僅限於線性插值:
// 先慢後快(緩入加速)
const speedFunction = (f: number) =>
interpolate(f, [0, 100], [0.5, 3], {
easing: Easing.in(Easing.quad),
});
// 固定三段速度
const speedFunction = (f: number) => {
if (f < 100) return 1;
if (f < 200) return 2;
return 4;
};效能考量
remapSpeed 中的迴圈對於幀號較大時會有線性時間複雜度。若合成幀數很多,可考慮使用積分近似或預先計算速度表來優化效能。