ffmpeg 是一支命令列影音處理程式,能轉檔、壓縮、剪裁、抽音軌、燒字幕、產縮圖與批次處理;YouTube 下載器、剪輯軟體、監視器 NVR 背後幾乎都在呼叫它。本文在一台 2 核心機器上實測四種編碼器的真實大小與耗時,並給出 12 組可直接複製的指令。
為什麼要學命令列,而不是找一套 GUI
| 痛點 | GUI 轉檔器的現實 | ffmpeg 的做法 |
|---|---|---|
| 批次處理 | 一次拖一個檔,20 個檔點 20 次 | 一行 for 迴圈跑完整個資料夾 |
| 參數不透明 | 只有「高/中/低品質」三顆按鈕,不知道 bitrate 實際是多少 | -crf 23 就是 23,可重現、可版控 |
| 伺服器上跑 | 沒有桌面環境就沒得用 | 純 CLI,SSH 進去就能跑,cron 排程可自動化 |
| 特定需求 | 「只抽第二條音軌的第 30 到 45 秒」通常找不到選項 | -map 0:a:1 -ss 30 -to 45 一行解決 |
| 一致性 | 每次匯出設定都可能不同 | 指令存成腳本,永遠同一套參數 |
反過來說,如果你一年只轉一次檔,GUI 比較快。ffmpeg 的價值在「重複」與「自動化」。
先弄懂五個概念,指令就不用背
| 概念 | 意思 | 常見誤解 |
|---|---|---|
| 容器(container) | .mp4、.mkv、.webm 是「盒子」,決定能裝哪些東西 | 改副檔名不會改變編碼,只會讓播放器困惑 |
| 編碼(codec) | 盒子裡的內容怎麼壓:H.264、H.265、AV1、VP9 | 「MP4 檔」不代表編碼是 H.264,也可能是 H.265 |
| CRF | 品質控制模式,數字越小品質越好、檔案越大 | CRF 不是跨編碼器可比的單位,H.264 的 23 與 AV1 的 23 完全不等價 |
| preset | 壓縮「努力程度」,ultrafast 最快、veryslow 最慢但同品質檔案最小 | preset 不影響畫質目標,只影響「花多少 CPU 換空間」 |
-map | 指定要拿哪條影音流 | 不加 -map 時 ffmpeg 只會挑「每種類型預設一條」,多音軌/多字幕會被丟掉 |
一個實務判準:要「畫質盡量好、不管檔案大小」用 CRF 18–20;要「上傳網站、控制流量」用 CRF 23–28。 短影音平台會再壓一次,餵給它 CRF 18 是浪費。
實測:同一支影片,四種編碼器的真實差距
測試方法與環境(2026-11-02 實測):ffmpeg 6.1.1(Ubuntu 內建)、2 邏輯核心、來源為 10 秒 1920×1080 30fps 合成畫面(testsrc2)加 440 Hz 正弦波音軌,原始檔 25.07 MB(20.05 Mbps)。所有輸出都帶 AAC 128 kbps 音軌。
| 輸出設定 | 檔案大小 | 相對原始 | 編碼耗時 |
|---|---|---|---|
| 原始檔(H.264 CRF 18 ultrafast) | 25.07 MB | 100% | — |
H.264 1080p CRF 23 medium | 7.48 MB | 29.8% | 8.4 秒 |
H.264 1080p CRF 28 medium | 3.49 MB | 13.9% | 7.3 秒 |
H.264 720p CRF 23 slow | 1.95 MB | 7.8% | 6.1 秒 |
H.265(HEVC)1080p CRF 28 medium | 5.89 MB | 23.5% | 17.6 秒 |
| AV1(SVT-AV1)1080p CRF 35 preset 8 | 6.40 MB | 25.5% | 26.1 秒 |
VP9 1080p CRF 35 row-mt | 7.04 MB | 28.1% | 66.1 秒 |
換容器 -c copy(不重新編碼) | 25.06 MB | 100% | 0.14 秒 |
三個反直覺的結論,一定要先講清楚:
- AV1 和 VP9 在這組測試裡沒有比較小。 合成測試畫面是高細節、高熵的內容,屬於壓縮器最不擅長的極端情境;真實拍攝素材(尤其有淺景深、慢動作)才會出現「AV1 比 H.264 小 30–50%」的宣傳效果。而且 CRF 35 的 AV1 與 CRF 28 的 H.264 本來就不是同一品質點,跨編碼器比 CRF 數字是沒有意義的。
- VP9 慢到會讓人放棄。 同一支 10 秒片,VP9 花了 66 秒,是 AV1 的 2.5 倍、H.264 的 8 倍。除非你有大量時間或硬體加速,2026 年還在做 CPU-only VP9 轉檔的性價比非常差。
-c copy幾乎不花時間。 只是換容器(.mp4→.mkv)時用它,0.14 秒完成、檔案大小一模一樣。很多人不知道這招,結果重壓一次導致畫質白白掉一級。
這組數字是「同一支影片、同一台機器」的相對比較,不是絕對效能指標。你的 CPU 核心數、素材複雜度都會改變絕對值;真正要選參數時,拿你自己的素材跑一次 10 秒樣本最準。
12 組可以直接複製的指令
以下每一條都在同一台機器實際跑過,錯誤訊息也是真的貼上來的。
1. 先看清楚檔案裡有什麼
ffprobe -v error -show_entries format=duration,size,bit_rate \
-show_entries stream=index,codec_name,codec_type,width,height,r_frame_rate \
-of default=noprint_wrappers=1 input.mp4
轉檔失敗九成是「你以為它是 A,其實它是 B」。先跑 ffprobe,確認編碼、解析度、音軌數量,再決定參數。
2. 網頁用:1080p → 720p,CRF 23
ffmpeg -i input.mp4 -vf scale=1280:-2 -c:v libx264 -crf 23 -preset slow \
-c:a aac -b:a 128k -movflags +faststart output.mp4
-vf scale=1280:-2:寬度固定 1280,高度自動按比例算,-2保證是偶數(H.264 要求長寬都是 2 的倍數)。-movflags +faststart:把索引移到檔案開頭,讓瀏覽器可以邊下載邊播放。少了這個,使用者要等整支下載完才開始播。- 實測這條把 25.07 MB 壓到 1.95 MB,耗時 6.1 秒。
3. H.265 轉檔給蘋果裝置:記得加 -tag:v hvc1
ffmpeg -i input.mp4 -c:v libx265 -crf 28 -preset medium -tag:v hvc1 \
-c:a aac -b:a 128k output_hevc.mp4
-tag:v hvc1 是必要欄位,不是可選項。少了它,QuickTime 與 Safari 有機會把檔案當成不支援的格式。-c copy 換容器時如果原本沒有這個 tag,也可以用同一招補上(實測可行)。
4. AV1:慢,但值得排程跑
ffmpeg -i input.mp4 -c:v libsvtav1 -crf 35 -preset 8 -c:a libopus -b:a 96k output.mkv
SVT-AV1 的 -preset 是 0–13,數字越大越快。實測 preset 8 在這台機器是 26 秒/10 秒素材。適合「放著跑整晚」的批次壓縮,不適合互動使用。
5. 只抽音軌
ffmpeg -i input.mp4 -vn -c:a libmp3lame -q:a 2 audio.mp3
ffmpeg -i input.mp4 -vn -c:a libopus -b:a 64k audio.opus
-vn 是「不要影像」。實測 10 秒音軌:MP3 -q:a 2 輸出 48,617 bytes;Opus 64k 輸出 98,359 bytes。
第二個數字看起來很怪——Opus 通常比 MP3 有效率,為什麼反而大了一倍?因為測試音源是純正弦波,這種極度規律的訊號在 VBR 模式下會拿到很高的碼率。這正好說明一件事:所有「壓縮率」評測都高度依賴素材。 用真實人聲或音樂測試才有參考價值。
6. 抓縮圖與聯絡表
# 單張:第 5 秒的畫面
ffmpeg -ss 5 -i input.mp4 -frames:v 1 -q:v 2 thumbnail.jpg
# 聯絡表:每 2 秒一張,排成 3×2 格
ffmpeg -i input.mp4 -vf "fps=1/2,scale=320:-1,tile=3x2" contact.jpg
實測:1920×1080 的 JPEG(-q:v 2)為 124,157 bytes;聯絡表輸出 960×360、27,240 bytes。上架影片時用聯絡表當預覽,比單張截圖有資訊量。
7. -ss 放前面還是後面,差 8 倍速度
ffmpeg -ss 9 -i input.mp4 -frames:v 1 fast.jpg # 放 -i 之前:0.157 秒
ffmpeg -i input.mp4 -ss 9 -frames:v 1 slow.jpg # 放 -i 之後:1.332 秒
同一支 10 秒影片、同一個位置,實測差了 8.5 倍。原理是放前面時 ffmpeg 直接 seek 到最近關鍵幀再解碼,放後面則要從頭解碼到尾。大量截圖或切片時,把 -ss 放前面是最高性價比的一行改動。
8. 兩段式 GIF —— 但它不一定比較小
# 第一段:產生專屬調色盤
ffmpeg -ss 1 -t 3 -i input.mp4 -vf "fps=12,scale=480:-1:flags=lanczos,palettegen=stats_mode=diff" palette.png
# 第二段:套用調色盤
ffmpeg -ss 1 -t 3 -i input.mp4 -i palette.png \
-lavfi "fps=12,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5" out.gif
實測結果值得記下來:同樣 3 秒、480 寬、12 fps,單段直轉是 272,044 bytes,兩段式反而是 493,163 bytes —— 兩段式大了 81%。
原因是 dither=bayer 會在每個像素加入抖動雜訊來消除色階斷層,而 GIF 是無損壓縮,雜訊愈多檔案愈大。所以兩段式的真正價值是畫質(消除漸層斷層),不是體積。要小檔案就犧牲抖動(paletteuse=dither=none),要好看就接受變大。把「兩段式一定比較小」當鐵律的人,量過就會知道不是這麼回事。
9. 字幕:燒進去,還是裝在裡面
# A. 燒進畫面(對方一定看得到,但無法關閉、且必須重壓影像)
ffmpeg -i input.mp4 -vf "subtitles=test.srt:force_style='FontSize=24'" \
-c:v libx264 -crf 23 -c:a copy out_hardsub.mp4
# B. 裝進容器(可開關,不重壓影像)
ffmpeg -i input.mp4 -i test.srt -map 0 -map 1 -c copy -c:s mov_text out_softsub.mp4
# C. 把字幕再抽出來
ffmpeg -i out_softsub.mp4 -map 0:s:0 extracted.srt
實測 B 之後 ffprobe 顯示三條流:h264/video、aac/audio、mov_text/subtitle,C 能原樣抽回 SRT。注意 -c:s mov_text 是 MP4 容器的字幕格式;MKV 請改用 srt。B 用 -c copy,所以只要 0.1 秒級的時間;A 因為要重壓影像,慢很多而且是不可逆的畫質損失。
10. 合併多段影片
printf "file 'part1.mp4'\nfile 'part2.mp4'\n" > list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy joined.mp4
實測兩支 3 秒、同參數的片段合併後是 6.0 秒、-c copy 秒完成。前提是所有片段的編碼參數、解析度、時基(timebase)都一致;只要有一支是不同解析度或不同 fps,合併出來的檔案就會在切換點破格或音畫不同步。不一致時的正解是先各自轉成同一組參數,再合併。
11. 直式短影音:補邊而不是裁切
ffmpeg -i input.mp4 -vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:color=black" \
-c:v libx264 -crf 23 -c:a aac reel.mp4
實測輸出確實是 1080×1920。force_original_aspect_ratio=decrease 先等比縮到「塞得進」目標框,再用 pad 補黑邊置中。想要裁切構圖(去掉左右黑邊)就換成 crop=608:1080:656:0 這種寫法——實測裁切後輸出 608×1080,主體會放大約 3.16 倍,畫質壓力大很多。
12. 音量正規化:讓每支片一樣大聲
ffmpeg -i input.mp4 -af loudnorm=I=-16:TP=-1.5:LRA=11 -c:v copy norm.mp4
實測輸出:輸入整體音量 -21.75 LUFS、真峰值 -14.46 dBTP,經過 loudnorm 後變成 -16.05 LUFS、真峰值 -8.67 dBTP,normalization_type 為 dynamic。
-16 LUFS 是串流平台常見目標值。-c:v copy 表示影像不動、只處理音訊,所以幾乎不花時間。要注意 dynamic 模式是「即時調整」而非「先掃描全片再平均」,長片若有大小聲落差,建議加 print_format=json 先量測再二次套用(two-pass loudnorm)。
批次處理:把 20 個檔變成一行
for f in input/*.mp4; do
out="output/$(basename "${f%.*}").web.mp4"
ffmpeg -y -i "$f" -vf scale=854:-2 -c:v libx264 -crf 26 -preset medium \
-movflags +faststart "$out"
done
實測 3 支 1280×720 的 4 秒片段,每支從 4.36 MB 壓到約 232 KB,總共 2.8 秒跑完。
三個實務提醒:
-y是「覆蓋既有檔不解釋」,批次時必要,但測試時最好先拿掉。- 想保留目錄結構用
rsync或find -exec;上面這條只適合扁平目錄。 - 幾百個檔時加
-loglevel error減少輸出,或改寫成xargs -P 4平行跑(核心數 2 的機器不要開到 8,會互相搶資源)。
實測踩到的錯誤訊息對照表
| 訊息 | 原因 | 解法 |
|---|---|---|
width not divisible by 2 (1281x721) | 指定了奇數寬度;H.264 要求長寬為偶數 | 用 scale=1280:-2,或明確給偶數;-2 只保證「沒指定的那一邊」是偶數 |
Invalid data found when processing input | 檔案不是影片,或下載不完整(實測餵 4 KB 隨機位元組就是這個訊息) | 先 ffprobe 確認,必要時重新下載 |
Conversion failed! | 參數組合不合法(實測指定不存在的 -profile:v 值) | 逐一簡化參數,先讓最小指令跑通再往上加 |
| 輸出檔案 0 bytes | 通常是 filter 語法錯誤或路徑不存在 | 去掉 -loglevel error 看完整訊息 |
| 合併後破格/音畫不同步 | 片段參數不一致 | 先統一轉檔再 concat |
另一個常見誤區是 hugo/自動化腳本裡用 ffmpeg ... | tail 取 exit code——拿到的是 tail 的結束碼,永遠是 0。要驗證成敗請用 ffmpeg ... > log 2>&1; echo $?,或檢查輸出檔大小。
硬體加速:編譯進去了,但沒有裝置可測
ffmpeg -hwaccels 在這台機器列出的是 vdpau cuda vaapi qsv drm opencl vulkan,-encoders 也看得到 h264_nvenc、av1_nvenc、av1_qsv、av1_vaapi——也就是說這份 binary 有把硬體編碼器編進去。但機器上沒有 /dev/dri,也沒有 nvidia-smi,所以本文的耗時數字全部是純 CPU 的結果,硬體加速路徑沒有實測。
要用的話大致是這兩種寫法(未實測,請以你的驅動與 ffmpeg 版本為準):
# NVIDIA
ffmpeg -i in.mp4 -c:v h264_nvenc -preset p5 -cq 23 out.mp4
# Intel / AMD(VAAPI)
ffmpeg -vaapi_device /dev/dri/renderD128 -i in.mp4 \
-vf 'format=nv12,hwupload' -c:v h264_vaapi -qp 23 out.mp4
實務經驗值:硬體編碼在「速度」上有壓倒性優勢,但同碼率下的畫質通常不如 libx264 preset slow;而且 -cq/-qp 的數字與 CRF 不是同一套尺度。要拿來存檔母帶,建議還是 CPU 編碼。
什麼情況該用什麼
| 場景 | 建議 | 理由 |
|---|---|---|
| 部落格嵌影片 | H.264 720p CRF 23 + +faststart | 相容性最好,Safari/Android 舊機都能播 |
| 上傳 YouTube | H.264 1080p CRF 18–20 | 平台會再壓一次,餵高品質少一層損失 |
| 手機儲存空間 | H.265 CRF 28 + hvc1 | 體積明顯小,蘋果生態原生支援 |
| 長期封存 | 母帶別重壓,只做 -c copy 換容器 | 每次重壓都是世代損失 |
| 網站動圖 | 直接給 <video> 播 MP4/WebM | GIF 在同樣畫質下通常大好幾倍 |
| 監視器/NVR 取證 | H.264、固定 GOP、不開 B-frame | 隨機存取與相容性優先於體積 |
站內延伸閱讀
- yt-dlp:功能豐富的開源 YouTube 與影片下載工具
- Frigate NVR 完整教學:把監視器變成會認人的系統
- Whisper 語音轉文字完整教學
- HyperFrames:HTML 轉 MP4 的影片框架
原始來源
- ffmpeg 官方文件(完整參數):https://ffmpeg.org/ffmpeg.html
- ffmpeg 濾鏡手冊(scale/pad/crop/subtitles/loudnorm):https://ffmpeg.org/ffmpeg-filters.html
- 編碼器清單與選項:https://ffmpeg.org/ffmpeg-codecs.html
- H.264 編碼指南(CRF 與 preset):https://trac.ffmpeg.org/wiki/Encode/H.264
- H.265/HEVC 編碼指南:https://trac.ffmpeg.org/wiki/Encode/H.265
- AV1(SVT-AV1)編碼指南:https://trac.ffmpeg.org/wiki/Encode/AV1
- VP9 編碼指南:https://trac.ffmpeg.org/wiki/Encode/VP9
- 縮放(Scaling)說明:https://trac.ffmpeg.org/wiki/Scaling
- 合併(Concatenate)說明:https://trac.ffmpeg.org/wiki/Concatenate
- 音量處理(AudioVolume/loudnorm):https://trac.ffmpeg.org/wiki/AudioVolume
