影片剪輯:裁切、拼接、配樂——把多段素材做成一支完整影片
用 Remotion 做剪輯:多段影片拼接、跳剪、凍結畫面、配樂淡入淡出、播放速度調整。學完能把原本要進剪映/Premiere 的工作搬進 React 程式碼裡。
成品預覽
這就是你跟著教學能做出來的成品——一支 15 秒的科技 YouTuber 頻道 intro/剪輯示範。開場 talking head、跳接到 SaaS 縮圖、2× 加速 coding 蒙太奇、凍結戲劇性瞬間、Subscribe 收尾,五個剪輯技巧都用 React + interpolate 做出來,完全沒有任何外部影音檔案。
這篇會做出什麼
一支 30 秒的影片剪輯示範,把四段原始素材做成一支有節奏的片子:
- 0~6 秒:Clip A 開場(原始影片的 10~16 秒段落)
- 6~12 秒:Clip B 接上(另一段 0~6 秒,加速 1.5 倍)
- 12~18 秒:Clip C 慢動作(0.5 倍速)
- 18~24 秒:Clip D 凍結最後一幀做「定格結尾」
- 全程:背景音樂淡入 → 中間降 ducking → 結尾淡出
做完你會發現:剪輯 = 切片 + 時間控制 + 音訊混音,三件事用 React 就能搞定。
前置知識
- T3 YouTube 片頭動畫 — 熟悉
<Sequence> - T8 Podcast 音波視覺化 — 熟悉
<Audio>
素材準備:
- 四段
.mp4影片(各自 10 秒以上就好) - 一首
.mp3背景音樂 - 放在
public/clips/和public/music/
Step 1:載入第一段影片
Claude Code:
新增 Composition "VideoEditingDemo":
- 1920x1080
- fps 30
- durationInFrames 900(30 秒)
- 新建 src/compositions/VideoEditingDemo.tsx
- 在 src/Root.tsx 註冊
元件內先:
1. 從 remotion import OffthreadVideo, staticFile
2. 用 <OffthreadVideo src={staticFile("clips/a.mp4")} /> 播第一段
3. 全螢幕填滿
為什麼用 <OffthreadVideo> 而不是 <Video>?
<Video> 會用瀏覽器的 <video> 元素,渲染時容易被 Chromium 限制同時開啟的 video 數量卡住。<OffthreadVideo> 在 worker thread 解碼,渲染速度更快,尤其是多段影片拼接。
💡
<OffthreadVideo>vs<Video>完整差異在 /docs/offthreadvideo 和 /docs/video-and-audio。
Step 2:只播影片的特定段落(裁切)
A 段影片原本 30 秒,但我們只要第 10~16 秒。用 startFrom / endAt:
把第一段影片改成只播第 10~16 秒:
1. <OffthreadVideo> 加 startFrom={10 * 30}
2. 加 endAt={16 * 30}
3. 用 <Sequence from={0} durationInFrames={180}> 包住
(從 0 秒開始播 6 秒)
startFrom 的單位:是原始影片的幀數,不是 composition 的幀數。這個常搞混。假設影片是 30fps,第 10 秒就是 startFrom={300}。
💡 影片裁切、
startFrom、endAt的細節在 /docs/video-sequence。
Step 3:拼接第二段(跳剪)
在 A 段結束後接上 B 段:
1. 新增 <Sequence from={180} durationInFrames={180}>
2. 裡面放 <OffthreadVideo src={staticFile("clips/b.mp4")}
startFrom={0}
endAt={180}
playbackRate={1.5} />
3. playbackRate 1.5 = 播放速度 1.5 倍(6 秒原片壓成 4 秒)
4. 但是我們 Sequence 只給 6 秒,4 秒的內容會剛好填滿(因為加速)
注意:playbackRate > 1 時,startFrom 和 endAt 還是原片的時間座標。加速只影響播放速度,不影響裁切位置。
💡
playbackRate的數學與陷阱在 /docs/video-playback-rate。跳剪範式在 /docs/video-jumpcuts。
Step 4:慢動作 C 段
接上 C 段(慢動作):
1. <Sequence from={360} durationInFrames={180}>
2. <OffthreadVideo src={staticFile("clips/c.mp4")}
startFrom={0}
endAt={90}
playbackRate={0.5} />
3. 原片 3 秒 ÷ 0.5 = 6 秒,剛好填滿
慢動作的品質:如果原片是 30fps,慢到 0.5 倍後實際上每個「動作」會被重複 2 幀。要真的滑順需要源片是 60fps 以上。
Step 5:D 段定格結尾
最後一段最酷——影片播 4 秒後凍結最後一幀再多停 2 秒:
接上 D 段 + 凍結結尾:
1. <Sequence from={540} durationInFrames={180}>
2. 前 4 秒正常播放:
用 <Freeze frame={119}> 外層包住
3. <Freeze frame={X}> 會在指定 frame 凍結裡面的時間
0~120 frame 正常播(4 秒),120~180 frame 凍結在第 119 幀
寫法:
<Sequence from={540} durationInFrames={180}>
<VideoWithFreeze
src={staticFile("clips/d.mp4")}
freezeAfterFrame={120}
/>
</Sequence>
VideoWithFreeze 元件:
- 如果 useCurrentFrame() < freezeAfterFrame → 正常播
- 否則 → 用 <Freeze frame={freezeAfterFrame}> 包 OffthreadVideo
<Freeze> 的用途:做「定格」(關鍵動作停住)或「時間暫停」特效。比自己用 CSS paused hack 乾淨太多。
💡
<Freeze>與video-align-duration的完整用法在 /docs/video-freeze 和 /docs/video-align-duration。
Step 6:加背景音樂
在 VideoEditingDemo 根層加背景音樂:
1. <Audio src={staticFile("music/bgm.mp3")} />
2. 讓它播整個 30 秒
3. 用 volume prop 做淡入淡出:
volume={(frame) => {
// 0~30 淡入
if (frame < 30) return interpolate(frame, [0, 30], [0, 0.7]);
// 最後 1 秒淡出
if (frame > 870) return interpolate(frame, [870, 900], [0.7, 0]);
// 中間 Clip B 時 ducking 到 0.3
if (frame > 180 && frame < 360) return 0.3;
return 0.7;
}}
為什麼 volume 用 function?
<Audio volume> 可以傳數字(固定音量)或函式(每幀不同音量)。用函式就能做淡入淡出、ducking、節拍同步的音量起伏。
💡
<Audio volume>函式簽名、動態音量、audio-muting、audio-trimming等進階技巧在 /docs/audio-volume、/docs/audio-muting、/docs/audio-trimming。
Step 7:讓影片素材原本的聲音也保留
到目前為止 <OffthreadVideo> 的原聲是預設播放的。但第二段加速了,聲音會變調——Chipmunk 效果。用 muted 關掉:
把 B 段和 C 段的原聲關掉(保留 A、D 段原聲):
1. B 段 <OffthreadVideo muted />
2. C 段 <OffthreadVideo muted />
3. A、D 段保留原聲但用 volume={0.4}
避免蓋過背景音樂
加速 / 慢速時的音訊處理:
playbackRate會改變音高(像轉盤機)- 想要「視訊變速但音訊保持」得用
@remotion/media-parser分離處理,進階題
Step 8:加一個過場黑幀
段落之間加個 3 幀的純黑 frame 當分隔(像紀錄片那樣):
在每個 Sequence 之間加黑幀分隔:
1. 用 <Sequence from={177} durationInFrames={3}>
<AbsoluteFill style={{ backgroundColor: "black" }} />
2. 類似做 from={357, 537, 717}
3. 這樣段落切換時有 0.1 秒純黑,節奏更明顯
比起 cross-fade,硬切 + 黑幀在紀錄片、訪談片最常見。
Step 9:渲染
渲染 VideoEditingDemo:
- 1920x1080 H.264
- CRF 20
- 輸出 out/video-editing-demo.mp4
- concurrency 4(多段影片拼接吃 CPU)
如果渲染很慢或出現 media-playback-error,看 /docs/media-playback-error 和 /docs/non-seekable-media。
完成!回顧學到的概念
| 概念 | 用在哪 |
|---|---|
<OffthreadVideo> 多段影片拼接 | Step 1~5 |
startFrom / endAt 裁切 | Step 2 |
playbackRate 加速 / 慢動作 | Step 3、4 |
<Freeze> 凍結畫面 | Step 5 |
<Audio volume> 動態函式 | Step 6 |
原片音訊 muted 控制 | Step 7 |
| 黑幀分隔段落 | Step 8 |
本篇涵蓋的官方文件
- /docs/offthreadvideo —
<OffthreadVideo>效能與用法 - /docs/video-and-audio — 影片與音訊總覽
- /docs/video-details — 影片進階細節
- /docs/video-sequence — Sequence 包影片
- /docs/video-jumpcuts — 跳剪範式
- /docs/video-align-duration — 對齊影片時長
- /docs/video-freeze — 凍結畫面
- /docs/video-playback-rate — 播放速度
- /docs/audio-volume — 動態音量
- /docs/audio-muting — 靜音
- /docs/audio-trimming — 音訊裁切
- /docs/audio-playback-rate — 音訊播放速度
- /docs/non-seekable-media — 不可 seek 的媒體
- /docs/media-playback-error — 媒體錯誤處理
常見問題
Q:為什麼渲染時 Remotion 抱怨「video took too long to load」?
A:通常是 <OffthreadVideo> 的檔案太大或格式太刁鑽。解法:用 ffmpeg 先轉成 H.264 yuv420p 30fps 的「標準 MP4」。Remotion 對這種格式最順。
Q:playbackRate < 1 時聲音會走音?
A:會。這是 <OffthreadVideo> 的已知行為——playbackRate 會同時影響音訊播放速度跟音高。想保持音高就 muted,另外放一軌正常速度的 <Audio>。
Q:我想在影片上疊字幕,要怎麼做?
A:直接在 <OffthreadVideo> 外面用 <AbsoluteFill> 疊一層文字。因為都是 React,疊層就是寫 JSX。看 T12 短影音自動上字幕。
Q:從影片抽出音訊當配音?
A:可以。用 <Audio src={staticFile("clips/a.mp4")} />——Remotion 會自動只取音訊軌。見 /docs/audio-from-video。
下一步
- T10:YouTube 縮圖產生器 — 用 Stills 批量產縮圖
- T11:音效設計——混音、音高、音效庫 — 進階音訊處理
- T14:參數化影片模板 — 把剪輯流程做成模板讀 JSON 批量產影片
有問題歡迎到 FB 社群 討論!