moviepy(Python 影片合成)
最適合簡短、腳本化的影片,以及將精確文字疊加在素材上。若需要長時間、設計密集、可重複使用的影片,則建議使用 Remotion。
| 使用 moviepy 時機 | 使用 Remotion 時機 |
|---|---|
| 專案是單一 Python 腳本 | 需要 React 元件與設計系統 |
| 在現有或 AI 生成的片段上疊加文字 | 複雜的動畫圖形與圖表 |
| 對多個檔案進行批次編輯 | 需仰賴熱重載預覽 |
| 沒有 Node 工具鏈可用 | 長時間、範本化的影片 |
設定
pip install "moviepy>=2" pillow
# 或:uv add moviepy pillow
此技能以 moviepy 2.x 為目標。其 API 與 1.x 不同:import 直接來自 moviepy,方法為 with_*/subclipped/resized,而非 set_*/subclip/resize。
基本用法
from moviepy import (VideoFileClip, AudioFileClip, ImageClip, TextClip,
CompositeVideoClip, CompositeAudioClip, concatenate_videoclips, vfx, afx)
clip = VideoFileClip("in.mp4").subclipped(5, 20) # 15 秒片段
clip = clip.resized(height=1080) # 保持比例
clip = clip.with_effects([vfx.FadeIn(0.5), vfx.FadeOut(0.5)])
joined = concatenate_videoclips([clip, VideoFileClip("b.mp4")], method="compose")
joined.write_videofile("out/result.mp4", fps=30, codec="libx264", audio_codec="aac")
在長腳本中,請務必對 clip 呼叫 .close(),或將其用在 with 區塊內,以釋放檔案控制代碼。
文字疊加(素材上的確定性文字)
title = (TextClip(font="C:/Windows/Fonts/arial.ttf", # 真實字型檔案路徑
text="Dr. Jane Doe\nChief Scientist",
font_size=56, color="white",
stroke_color="black", stroke_width=2,
method="caption", size=(900, None))
.with_start(1.0).with_duration(4.0)
.with_position(("left", 860))
.with_effects([vfx.CrossFadeIn(0.3), vfx.CrossFadeOut(0.3)]))
final = CompositeVideoClip([clip, title])
注意事項:
TextClip需要字型檔案路徑(TTF/OTF)。請將品牌字型一併放入專案中。- 片段時間單位為秒,相對於複合片段的起始點。
- 如需樣式豐富的文字(圓角藥丸、漸層),請用 Pillow 渲染 PNG 後改為使用
ImageClip。 - 文字請保持在安全區域內:距離各邊緣至少 5%。
音訊
voice = AudioFileClip("voiceover.mp3")
music = AudioFileClip("music.mp3").with_effects([afx.MultiplyVolume(0.12), afx.AudioFadeOut(2)])
music = music.with_duration(voice.duration + 1)
final = clip.with_audio(CompositeAudioClip([music, voice.with_start(0.5)]))
讓旁白決定時間軸:將片段長度設為 voice.duration + padding,而非反過來做。
音訊錨定模式
scenes = [("scene1.mp3", "intro.png"), ("scene2.mp3", "chart.png")]
parts = []
for audio_path, image_path in scenes:
a = AudioFileClip(audio_path)
v = ImageClip(image_path).with_duration(a.duration + 0.6).with_audio(a)
parts.append(v)
concatenate_videoclips(parts).write_videofile("out/explainer.mp4", fps=30)
靜態畫面的 Ken Burns 效果
img = ImageClip("photo.jpg").with_duration(6)
img = img.resized(lambda t: 1.0 + 0.04 * t).with_position("center")
CompositeVideoClip([img], size=(1920, 1080)).write_videofile("out/kb.mp4", fps=30)
效能
- 預覽時使用
fps=12與preset="ultrafast";最終輸出時使用 30 fps。 write_videofile(..., threads=4)。- 避免在長片段中使用逐幀 Python lambda。盡可能先透過 FFmpeg 進行預處理。
常見問題
| 問題 | 原因與解決方法 |
|---|---|
ImportError: cannot import name 'editor' | moviepy 2 已移除 moviepy.editor;請從 moviepy 直接匯入 |
AttributeError: set_duration | 請改用 with_duration;with_start、with_position 同樣適用 |
| 文字片段崩潰 | 請傳入真實字型檔案路徑 |
| 拼接後音訊不同步 | 確保所有片段共用相同 fps;音訊請在串接後才套用 |
| 渲染緩慢 | 草稿時降低解析度;避免使用大型 resized lambda |