ffmpeg 完整教學 2026:影片壓縮、轉檔、字幕與批次處理實戰

ffmpeg 是幾乎所有影音工具背後那支命令列程式。本文在同一台機器實測 H.264/H.265/AV1/VP9 的檔案大小與編碼耗時,整理 12 組可直接複製的指令:網頁壓縮、HEVC 轉檔、音軌抽取、字幕燒錄與軟字幕、兩段式 GIF、concat 合併、直式 Reels 補邊、loudnorm 音量正規化、批次轉檔與聯絡表縮圖,並附上實測遇到的錯誤訊息對照表。

  • Dennis
  • 10 分鐘閱讀
ffmpeg 完整教學 2026:影片壓縮、轉檔、字幕與批次處理實戰

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 MB100%—
H.264 1080p CRF 23 medium7.48 MB29.8%8.4 秒
H.264 1080p CRF 28 medium3.49 MB13.9%7.3 秒
H.264 720p CRF 23 slow1.95 MB7.8%6.1 秒
H.265(HEVC)1080p CRF 28 medium5.89 MB23.5%17.6 秒
AV1(SVT-AV1)1080p CRF 35 preset 86.40 MB25.5%26.1 秒
VP9 1080p CRF 35 row-mt7.04 MB28.1%66.1 秒
換容器 -c copy(不重新編碼)25.06 MB100%0.14 秒

三個反直覺的結論,一定要先講清楚:

  1. AV1 和 VP9 在這組測試裡沒有比較小。 合成測試畫面是高細節、高熵的內容,屬於壓縮器最不擅長的極端情境;真實拍攝素材(尤其有淺景深、慢動作)才會出現「AV1 比 H.264 小 30–50%」的宣傳效果。而且 CRF 35 的 AV1 與 CRF 28 的 H.264 本來就不是同一品質點,跨編碼器比 CRF 數字是沒有意義的。
  2. VP9 慢到會讓人放棄。 同一支 10 秒片,VP9 花了 66 秒,是 AV1 的 2.5 倍、H.264 的 8 倍。除非你有大量時間或硬體加速,2026 年還在做 CPU-only VP9 轉檔的性價比非常差。
  3. -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 舊機都能播
上傳 YouTubeH.264 1080p CRF 18–20平台會再壓一次,餵高品質少一層損失
手機儲存空間H.265 CRF 28 + hvc1體積明顯小,蘋果生態原生支援
長期封存母帶別重壓,只做 -c copy 換容器每次重壓都是世代損失
網站動圖直接給 <video> 播 MP4/WebMGIF 在同樣畫質下通常大好幾倍
監視器/NVR 取證H.264、固定 GOP、不開 B-frame隨機存取與相容性優先於體積

站內延伸閱讀

原始來源

  • 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

📬 訂閱 most.tw 電子報

每週精選 AI 工具教學與技術乾貨,直接送到你的信箱。免費、隨時可退訂。

訂閱即表示同意收到 most.tw 電子報,隨時可一鍵退訂。

💬 有問題想討論?加 LINE 聯絡我

歡迎透過 LINE 官方帳號直接留言,我會盡快回覆你的問題。

加入 LINE 好友