影片編輯器 是做什麼的?
概述
AI 輔助影片工作流程,由三個引擎驅動:
- ffmpeg -- 編輯既有片段(修剪、壓縮、合併、調整大小、速度、穩定、浮水印、音訊、GIF、縮圖、轉場、字幕)
- Remotion -- 建立新的影片內容(標題卡、下三分之一、片尾卡、預告片、動態覆疊圖層)
- Whisper -- 轉錄與字幕生成
其他功能:
- 硬體加速:在 Apple Silicon 上透過
h264_videotoolbox / hevc_videotoolbox 實現
- 主題整合:可與
~/design-assets/color-palettes/ 的設計資產結合
- 平台預設:針對 YouTube、Instagram、TikTok、Twitter 等平台
- 工作區快取:Remotion 可避免重複執行
npm install
使用時機
遇到使用者的任何下列意圖時觸發:
| 類別 | 關鍵字 |
|---|
| 基本編輯 | 修剪、剪裁、剪輯、縮短、分割 |
| 壓縮 | 壓縮、減少大小、縮小、變小、最佳化 |
| 合併 | 合併、結合、串接、連接、拼接 |
| 調整大小 | 調整大小、縮放、裁剪、填補、長寬比、直式、橫式、方形 |
| 速度 | 加速、減速、慢動作、縮時、快轉、倒轉 |
| 穩定 | 穩定、晃動、平滑、消除晃動 |
| 轉場 | 淡入、淡出、溶解、擦拭、轉場 |
| 字幕 | 字幕、SRT、轉錄、語音轉文字 |
| 標題卡 | 標題卡、開場、片頭、動態文字 |
| 下三分之一 | 下三分之一、姓名標籤、字卡、姓名條 |
| 片尾卡 | 片尾卡、結尾、片尾畫面、結束 |
| 預告片 | 預告片、宣傳片、精華片段、蒙太奇 |
| 縮圖 | 縮圖、海報、畫面擷取、螢幕截圖 |
| GIF | GIF、動態圖片、循環、迷因 |
| 浮水印 | 浮水印、標誌覆疊、品牌 |
| 音訊 | 音訊、音量、標準化、響度、靜音、淡入、淡出、混合、擷取音訊 |
| 資訊 | 資訊、詳細資料、時長、解析度、編碼器、位元率、中繼資料 |
| 管線 | 管線、批次、工作流程、多步驟 |
| 平台 | YouTube、Instagram、TikTok、Twitter、Reels、Shorts |
指令參考
編輯指令 (ffmpeg)
| 指令 | 說明 | 範例 |
|---|
/trim | 從影片中剪出片段 | "修剪 video.mp4 從 0:30 到 1:45" |
/compress | 壓縮檔案大小,可控制品質 | "壓縮到 10MB 以下" |
/merge | 合併多個片段為一個 | "合併 clip1.mp4 和 clip2.mp4 並加入淡出" |
/resize | 改變尺寸、長寬比、裁剪或填補 | "調整為 1080x1080 方形" |
/speed | 加速、減速或倒轉 | "2 倍速度" 或 "0.5 倍慢動作" |
/stabilize | 消除相機晃動 (vidstab 兩遍) | "穩定 shaky.mp4" |
/watermark | 在影片上疊加圖片或文字 | "加入 logo.png 在右下角" |
/audio | 音量、標準化、混合、淡入淡出、擷取、靜音 | "標準化音訊至 -14 LUFS" |
/thumbnail | 擷取畫面為圖片 | "在 0:15 處建立縮圖" |
/gif | 從影片片段建立動態 GIF | "從 0:05 到 0:10 的 GIF,寬度 320px" |
/extract | 擷取音訊或字幕軌 | "擷取音訊為 mp3" |
/info | 顯示影片中繼資料和串流詳細資訊 | "顯示 video.mp4 資訊" |
建立指令 (Remotion)
| 指令 | 說明 | 範例 |
|---|
/title-card | 動態標題卡,支援主題 | "標題卡:Coming Soon,wad 主題,縮放動畫" |
/lower-third | 動態姓名/標題覆疊圖層 | "下三分之一:John Doe,CEO,現代風格" |
/end-card | 動態片尾卡,含行動呼籲和社群按鈕 | "片尾卡:立即訂閱!,@handle,ea 主題" |
/teaser | 多片段蒙太奇,含轉場和標題 | "從 clips/ 資料夾建立 30 秒預告片" |
轉錄指令 (Whisper)
| 指令 | 說明 | 範例 |
|---|
/transcribe | 從語音生成 SRT/VTT 字幕 | "轉錄 interview.mp4" |
/add-captions | 轉錄 + 將字幕燒錄到影片上 | "為 talk.mp4 加入字幕" |
編排
| 指令 | 說明 | 範例 |
|---|
/pipeline | 多步驟處理鏈 | "修剪、加入標題卡、壓縮成適合 Instagram 的格式" |
工作流程
步驟 1:檢查可用工具
which ffmpeg ffprobe && echo "ffmpeg: ok"
node --version && echo "node: ok"
which whisper && echo "whisper: ok" || echo "whisper: 未安裝(字幕需要手動 .srt 檔案)"
ffmpeg -encoders 2>/dev/null | grep videotoolbox && echo "hw accel: ok" || echo "hw accel: 不可用"
ffmpeg -filters 2>/dev/null | grep vidstab && echo "vidstab: ok" || echo "vidstab: 不可用(請使用 brew install ffmpeg 並加上 --with-libvidstab)"
如果缺少 ffmpeg:"請執行 brew install ffmpeg 安裝"
如果缺少 Node.js:"請從 https://nodejs.org 安裝或執行 brew install node"
如果缺少 vidstab:"請使用 vidstab 重新安裝 ffmpeg:brew install ffmpeg --with-libvidstab"
步驟 2:分類請求
| 使用者意圖 | 引擎 | 路徑 |
|---|
| 編輯既有片段 | ffmpeg | 步驟 3a |
| 建立新影片內容 | Remotion | 步驟 3b |
| 音訊操作 | ffmpeg 音訊濾鏡 | 步驟 3a |
| 資訊/檢查 | ffprobe | 步驟 3a |
| 組合管線 | 同時編排兩者 | 步驟 3c |
| 發佈至平台 | 根據預設調整大小 + 壓縮 | 步驟 3a |
| 轉錄 | Whisper + ffmpeg | 步驟 3a |
步驟 3a:ffmpeg 路徑
- 如果未提供輸入檔案,詢問使用者
- 使用 ffprobe 檢查:
ffprobe -v quiet -print_format json -show_format -show_streams "<file>"
- 硬體加速檢測(macOS Apple Silicon):
ffmpeg -encoders 2>/dev/null | grep h264_videotoolbox
- 輸出檔案衝突處理:
OUTPUT="trimmed_video.mp4"
COUNTER=2
while [ -f "$OUTPUT" ]; do
OUTPUT="trimmed_video_${COUNTER}.mp4"
COUNTER=$((COUNTER + 1))
done
- 建立 ffmpeg 指令
- 以通俗用語解釋每個旗標
- 說明輸出檔案名稱(絕不覆寫來源檔案)
- 詢問:「要執行嗎?」
- 執行,然後驗證:
if [ $? -eq 0 ]; then
echo "成功"
ffprobe -v quiet -print_format json -show_format "$OUTPUT" | grep -E '"duration"|"size"'
else
echo "錯誤 — 請檢查上方 ffmpeg 輸出"
fi
- 報告輸出路徑 + 檔案大小 + 時長
輸出命名慣例:
| 指令 | 輸出模式 |
|---|
| 修剪 | trimmed_<filename> |
| 壓縮 | compressed_<filename> |
| 合併 | merged_output.<ext> |
| 調整大小 | resized_<filename> |
| 速度 | speed_<factor>x_<filename> |
| 穩定 | stabilized_<filename> |
| 浮水印 | watermarked_<filename> |
| 字幕 | captioned_<filename> |
| 音訊擷取 | <name>.mp3 |
| 音訊修改 | audio_<filename> |
| 字幕擷取 | <name>.srt |
| 縮圖 | thumb_<name>_<timecode>.jpg |
| GIF | <name>.gif |
步驟 3b:Remotion 路徑
- 確認已安裝 Node.js
- 工作區快取 -- 重複使用現有工作區:
WORKSPACE="/tmp/remotion-workspace"
if [ -d "$WORKSPACE/node_modules" ]; then
echo "正在重複使用快取的 Remotion 工作區"
else
echo "正在建立 Remotion 工作區(首次執行)..."
mkdir -p "$WORKSPACE"
cp -r ~/project-templates/remotion-video/* "$WORKSPACE/"
cd "$WORKSPACE" && npm install
fi
- 主題載入 從
~/design-assets/color-palettes/:
- 視需要撰寫或更新 composition 原始檔
- 可用的 compositions:
TitleCard -- 動態標題,含多種動畫預設
LowerThird -- 姓名/標題覆疊圖層,含強調條
EndCard -- 片尾卡,含行動呼籲、社群按鈕、標誌
Teaser -- 多片段蒙太奇,含 TransitionSeries
- 渲染:
cd "$WORKSPACE"
npx remotion render src/index.ts <CompositionId> /path/to/output.mp4 \
--props='{"text":"Title","bg":"#09090B","fg":"#FFFFFF","accent":"#7C3AED"}'
- 將輸出複製到使用者的工作目錄
- 報告輸出路徑 + 時長
步驟 3c:組合管線
對於多步驟請求(例如:"製作一個包含標題卡、片段和片尾卡的預告片"):
- 規劃 -- 在執行前向使用者說明每個步驟
- 建立 -- 先產生任何 Remotion 內容(標題卡、片尾卡)
- 處理 -- 使用 ffmpeg 修剪/調整來源片段大小
- 組合 -- 使用 ffmpeg 合併所有片段並加上轉場
- 完成 -- 如果指定目標平台,則壓縮成適合的格式
- 在主要階段(建立 vs. 編輯 vs. 組合)之間進行確認
ffmpeg 快速參考
修剪(無損)
ffmpeg -ss <start> -to <end> -i input.mp4 -c copy trimmed_input.mp4
壓縮 -- 網頁 (CRF 23)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k compressed_input.mp4
壓縮 -- 硬體加速 (macOS)
ffmpeg -i input.mp4 -c:v h264_videotoolbox -b:v 5M -c:a aac -b:a 128k compressed_input.mp4
合併並加入淡出轉場
ffmpeg -i clip1.mp4 -i clip2.mp4 \
-filter_complex "[0][1]xfade=transition=fade:duration=1:offset=<offset>,format=yuv420p[v];[0:a][1:a]acrossfade=d=1[a]" \
-map "[v]" -map "[a]" merged_output.mp4
調整大小 / 縮放
ffmpeg -i input.mp4 -vf "scale=1920:1080" resized_input.mp4
ffmpeg -i input.mp4 -vf "scale=1080:-1" resized_input.mp4
ffmpeg -i input.mp4 -vf "crop=min(iw\,ih):min(iw\,ih)" cropped_input.mp4
ffmpeg -i input.mp4 -vf "scale=1080:1080:force_original_aspect_ratio=decrease,pad=1080:1080:(ow-iw)/2:(oh-ih)/2:black" padded_input.mp4
變更速度
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -af "atempo=2.0" speed_2x_input.mp4
ffmpeg -i input.mp4 -vf "setpts=2.0*PTS" -af "atempo=0.5" speed_0.5x_input.mp4
ffmpeg -i input.mp4 -vf "setpts=0.25*PTS" -af "atempo=2.0,atempo=2.0" speed_4x_input.mp4
ffmpeg -i input.mp4 -vf "reverse" -af "areverse" reversed_input.mp4
浮水印覆疊
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "overlay=W-w-20:H-h-20" watermarked_input.mp4
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "overlay=20:20" watermarked_input.mp4
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "[1]format=rgba,colorchannelmixer=aa=0.3[wm];[0][wm]overlay=(W-w)/2:(H-h)/2" watermarked_input.mp4
ffmpeg -i input.mp4 \
-vf "drawtext=text='My Brand':fontsize=24:[email protected]:x=W-tw-20:y=H-th-20" watermarked_input.mp4
影片穩定 (vidstab 兩遍)
ffmpeg -i shaky.mp4 -vf vidstabdetect=shakiness=10:accuracy=15 -f null -
ffmpeg -i shaky.mp4 -vf vidstabtransform=smoothing=30:input=transforms.trf stabilized_shaky.mp4
音訊操作
ffmpeg -i input.mp4 -af "volume=1.5" audio_input.mp4
ffmpeg -i input.mp4 -af "loudnorm=I=-14:TP=-1:LRA=11" audio_input.mp4
ffmpeg -i video.mp4 -i music.mp3 \
-filter_complex "[0:a]volume=1.0[a1];[1:a]volume=0.3[a2];[a1][a2]amix=inputs=2:duration=first[a]" \
-map 0:v -map "[a]" audio_input.mp4
ffmpeg -i input.mp4 -af "afade=t=in:ss=0:d=3,afade=t=out:st=<end-3>:d=3" audio_input.mp4
ffmpeg -i input.mp4 -an muted_input.mp4
ffmpeg -i input.mp4 -i newtrack.mp3 -c:v copy -map 0:v:0 -map 1:a:0 replaced_audio_input.mp4
GIF 建立(兩遍調色板以提升品質)
ffmpeg -ss <start> -t <duration> -i input.mp4 \
-vf "fps=15,scale=320:-1:flags=lanczos,palettegen" palette.png
ffmpeg -ss <start> -t <duration> -i input.mp4 -i palette.png \
-filter_complex "[0:v]fps=15,scale=320:-1:flags=lanczos[v];[v][1:v]paletteuse" output.gif
rm palette.png
縮圖擷取
ffmpeg -ss <timestamp> -i input.mp4 -frames:v 1 -q:v 2 thumb_input_<timestamp>.jpg
ffmpeg -i input.mp4 -vf "fps=1/<interval>,scale=320:-1,tile=4x4" thumb_grid_input.jpg
燒錄 .srt 字幕
ffmpeg -i input.mp4 -vf "subtitles=captions.srt:force_style='FontSize=24,PrimaryColour=&H00FFFFFF'" captioned_input.mp4
擷取音訊
ffmpeg -i input.mp4 -vn -c:a libmp3lame -q:a 2 output.mp3
影片資訊
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
Remotion 快速參考
快取工作區設定
WORKSPACE="/tmp/remotion-workspace"
if [ ! -d "$WORKSPACE/node_modules" ]; then
cp -r ~/project-templates/remotion-video/* "$WORKSPACE/"
cd "$WORKSPACE" && npm install
fi
TitleCard Composition
import { AbsoluteFill, spring, useCurrentFrame, useVideoConfig, Img } from 'remotion';
type Animation = 'fade' | 'slide-up' | 'slide-down' | 'zoom' | 'typewriter' | 'glitch' | 'blur-in';
export const TitleCard: React.FC<{
text: string;
subtitle?: string;
bg?: string;
fg?: string;
accent?: string;
animation?: Animation;
logo?: string;
}> = ({ text, subtitle, bg = '#09090B', fg = '#FFFFFF', accent = '#7C3AED', animation = 'fade', logo }) => {
const frame = useCurrent
…
[為翻譯而截斷]