MP4 轉 GIF 教學:FFmpeg 兩階段演算法與畫質最佳化
把 MP4 轉成 GIF 很簡單,但要做出畫質好的 GIF 很難。很多人跑 ffmpeg -i input.mp4 output.gif 得到一個充滿色塊雜訊的 GIF。問題出在 GIF 只支援 256 色。這篇教學解析 FFmpeg 的 palettegen/paletteuse 兩階段演算法,從 GIF 原理到最佳化全包。
為什麼 GIF 轉換很難
GIF 格式的限制:
- 只有 256 色:MP4 有數百萬色,GIF 只能存 256 色
- 無壓縮:沒有 H.264 那種幀間壓縮,檔案巨大
- 沒聲音:只有動態圖片
- 1 位元透明度:沒有半透明,只有完全透明或完全不透明
核心挑戰: 怎麼把 MP4 的數百萬色縮減成 256 色。這就是色彩量化(Color Quantization),GIF 畫質好壞的關鍵。
方法 1:基本轉換(不推薦)
bash
ffmpeg -i input.mp4 output.gif這能跑,但畫質差:FFmpeg 會取影片前幾幀生成預設調色盤,套用到整部影片。色彩偏移的影片會在其他場景色彩失真。
方法 2:兩階段演算法(推薦)
原理
兩階段演算法的核心:
- 產生調色盤(palettegen):分析整部影片,提取最佳 256 色調色盤
- 使用調色盤(paletteuse):用產生的調色盤把每個像素最佳對應
這樣 FFmpeg 會考慮所有場景選出最佳 256 色。
指令
bash
# 步驟 1:產生調色盤
ffmpeg -i input.mp4 -vf "palettegen" palette.png
# 步驟 2:用調色盤轉成 GIF
ffmpeg -i input.mp4 -i palette.png -filter_complex "paletteuse" output.gif一步指令
bash
ffmpeg -i input.mp4 -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif不產生調色盤檔案,全部在記憶體完成。
畫質最佳化技巧
1. 統計模式選擇
bash
# 考慮所有場景(預設,畫質更好)
ffmpeg -i input.mp4 -vf "palettegen=stats_mode=full" palette.png
# 只考慮每幀差異(快,調色盤小)
ffmpeg -i input.mp4 -vf "palettegen=stats_mode=diff" palette.png
# 單幀(最快,畫質最差)
ffmpeg -i input.mp4 -vf "palettegen=stats_mode=single" palette.pngstats_mode=full 畫質最好但最慢。
2. 抖動演算法
bash
# 可用抖動模式
# bayer: 規則抖動,交叉網紋圖案
# heckbert: 誤差擴散(預設)
# floyd_steinberg: 最高畫質誤差擴散
# sierra2: Sierra-2-4A 誤差擴散
# none: 無抖動,色帶瑕疵
ffmpeg -i input.mp4 -i palette.png -filter_complex "paletteuse=dither=floyd_steinberg" output.giffloyd_steinberg 最自然,但檔案較大。
3. 解析度和幀率調整
bash
# 480p、15fps(縮小)
ffmpeg -i input.mp4 -vf "scale=480:-1:flags=lanczos,fps=15" -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif
# 640p、10fps(更小)
ffmpeg -i input.mp4 -vf "scale=640:-1:flags=lanczos,fps=10" -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif4. 長度剪輯
bash
# 只取 5 秒片段
ffmpeg -t 5 -i input.mp4 -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif
# 從第 10 秒取 5 秒
ffmpeg -ss 10 -t 5 -i input.mp4 -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif透明背景 GIF
去背處理
bash
# 綠幕去背
ffmpeg -i input.mp4 -filter_complex "[0:v] colorkey=0x00FF00:0.3:0.2 [greenless]; [greenless] palettegen=reserve_transparent=1 [p]; [greenless][p] paletteuse=alpha_threshold=128" output.gif參數:
0x00FF00:綠色鍵值0.3:相似度(0.3 = 容許 30% 色差)0.2:混合(邊緣混合程度)
黑色背景透明
bash
ffmpeg -i input.mp4 -filter_complex "[0:v] colorkey=0x000000:0.1:0.0 [bgless]; [bgless] palettegen=reserve_transparent=1 [p]; [bgless][p] paletteuse=alpha_threshold=128" output.gif檔案大小最佳化
1. 降解析度
bash
# 720p → 480p(檔案約縮小 50%)
ffmpeg -i input.mp4 -vf "scale=480:-1:flags=lanczos" -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif2. 降幀率
bash
# 30fps → 15fps(檔案約縮小 50%)
ffmpeg -i input.mp4 -vf "fps=15" -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif3. 剪掉不必要的動作
bash
# 只取前 5 秒
ffmpeg -t 5 -i input.mp4 -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif4. 用 gifsicle 後處理
bash
# gifsicle 最佳化
gifsicle -O3 --lossy=80 -o output.gif input.gif
# 移除透明度縮小
gifsicle --no-extensions -o output.gif input.gifgifsicle -O3 --lossy=80 通常能縮小 30-50% 檔案,畫質降低不明顯。
實用範本
高畫質 GIF
bash
ffmpeg -i input.mp4 \
-vf "scale=720:-1:flags=lanczos,fps=24" \
-filter_complex "[0:v] palettegen=stats_mode=full [p]; [0:v][p] paletteuse=dither=floyd_steinberg" \
output.gif網頁用 GIF
bash
ffmpeg -i input.mp4 \
-vf "scale=480:-1:flags=lanczos,fps=15" \
-filter_complex "[0:v] palettegen=stats_mode=full [p]; [0:v][p] paletteuse=dither=floyd_steinberg" \
output.gif小型 GIF
bash
ffmpeg -t 5 -i input.mp4 \
-vf "scale=320:-1:flags=lanczos,fps=10" \
-filter_complex "[0:v] palettegen=stats_mode=full [p]; [0:v][p] paletteuse=dither=sierra2" \
output.gif
# 再用 gifsicle 最佳化
gifsicle -O3 --lossy=80 -o output-final.gif output.gif常見問題
| 問題 | 原因 | 解決方案 |
|---|---|---|
| GIF 充滿色塊雜訊 | 用預設調色盤 | 用兩階段演算法 |
| GIF 巨大 | 無壓縮格式 | 降解析度和幀率 |
| 色彩不準 | 調色盤不適合 | 用 stats_mode=full |
| 色帶瑕疵 | 抖動不足 | 用 dither=floyd_steinberg |
| GIF 卡頓 | 幀率太低 | 用 fps=15 以上 |
| 透明背景有瑕疵 | 1 位元透明度 | 調整 alpha_threshold |
| 轉換慢 | stats_mode=full 慢 | 用 stats_mode=diff |
總結
GIF 轉換的核心是兩階段演算法:palettegen 產生調色盤、paletteuse 套用調色盤。基本範本:
bash
ffmpeg -i input.mp4 -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif高畫質加 stats_mode=full 和 dither=floyd_steinberg。要縮小檔案就降解析度和幀率。GIF 只適合短動畫,長影片用 MP4 或 WebM。
快速參考:
- 基本指令:
ffmpeg -i input.mp4 -filter_complex "[0:v] palettegen [p]; [0:v][p] paletteuse" output.gif - 高畫質: 加
stats_mode=full和dither=floyd_steinberg - 縮小檔案: 降解析度和幀率
- 後處理:
gifsicle -O3 --lossy=80再縮 30-50%