この記事でわかること
ffmpeg -i input.mp4 output.gifのナイーブな変換がなぜ品質が悪いのか- 最適化GIF用の
palettegen→paletteuse2パスパイプライン - フレームレート・解像度・ディザリングの制御方法
- 見た目の品質を保ちながらファイルサイズを削減するテクニック
テスト済みバージョン: FFmpeg 6.1(ubuntu-latest / CI検証済み)
対象 OS: Windows / macOS / Linux
GIFに2パス方式が必要な理由
GIFフォーマットはフレームごとに256色パレットという制限があります。カスタムパレットなしに動画を直接変換すると、FFmpegは汎用のWebセーフパレットにフォールバックし、色が薄くなったりバンディング(色の帯状のノイズ)が発生します。
解決策は2パス方式です:
- パス1 — palettegen: 動画を分析し、そのコンテンツに最適化された256色パレットを生成する
- パス2 — paletteuse: 生成したカスタムパレットを各フレームに適用する(オプションでディザリング)
クイックスタート — 1コマンド版(lavfi使用)
シンプルなケースでは、lavfiデバイスとフィルターグラフの分岐を使って両パスを1つのコマンドで実行できます:
ffmpeg -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" output.gif
このコマンドでは:
- フレームレートを15fpsに設定(ファイルサイズ削減)
- Lanczosリサンプリングで幅480pxにスケール(
-1でアスペクト比保持) - フィルター済みストリームを分岐:一方が
palettegenへ、もう一方がpaletteuseへ [p]経由でパレットをpaletteuseにマージ
2ファイル2パス方式(精度重視の場合に推奨)
1コマンド版は1プロセス内で動画を2回処理します。長い動画やパレットオプションを個別に調整したい場合は、明示的な2ステップを使います:
ステップ1 — パレット生成:
ffmpeg -i input.mp4 -vf "fps=15,scale=320:-1:flags=lanczos,palettegen" /tmp/palette.png
palettegenは256色の最適化カラーを含む16×16のPNGを出力します。
ステップ2 — パレット適用:
ffmpeg -i input.mp4 -i /tmp/palette.png -lavfi "fps=15,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse" output.gif
ポイント:
- 2つの入力をフィルターグラフで参照するため、
-vfの代わりに-lavfiを使用 [1:v]は2番目の入力(パレットPNG)を指す- パレットと一致させるため、パス2でも
fpsとscaleを同じ値で再適用する必要がある
フレームレートとサイズの制御
GIFのファイルサイズは解像度とフレーム数に比例して増大します。主な調整パラメータは:
| パラメータ | 効果 | 例 |
|---|---|---|
fps=N | フレームレートを下げる | fps=10(小さいループGIF向け) |
scale=W:-1 | 幅をWにスケール、高さ自動 | scale=320:-1 |
scale=-1:H | 幅自動、高さをHにスケール | scale=-1:240 |
最高品質のダウンスケールにはflags=lanczosを使います。プレビュー用に速度優先ならflags=bilinearが高速です。
ディザリングオプション
paletteuseフィルターはditherオプションで複数のディザリングアルゴリズムをサポートします:
ffmpeg -i input.mp4 -i /tmp/palette.png -lavfi "fps=15,scale=320:-1:flags=lanczos[x];[x][1:v]paletteuse=dither=bayer:bayer_scale=5" output.gif
| ディザーモード | 説明 |
|---|---|
bayer(デフォルト) | 整列ディザ — 規則的なパターンが出るが圧縮に有利 |
floyd_steinberg | 誤差拡散 — グラデーションが滑らか、ファイルはやや大きい |
sierra2 | バランス型の誤差拡散 |
none | ディザリングなし — フラットなグラフィックに最適、写真には不向き |
bayer_scale(1〜5)はbayerディザリング使用時のパターンサイズを制御します。値が大きいほどパターンが目立たなくなりますが、圧縮効率が下がります。
ループ制御
GIFはほとんどのブラウザでデフォルトでループ再生されます。-loopでループを制御できます:
ffmpeg -i input.mp4 -vf "fps=15,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -loop 0 output.gif
-loopの値 | 動作 |
|---|---|
0 | 永久ループ(多くのプレーヤーのデフォルト) |
-1 | ループなし(1回再生で終了) |
N(N ≥ 1) | N回ループして停止 |
変換前のトリミング
動画の一部だけをGIFに変換するには、-ssと-tをGIFフィルターと組み合わせます:
ffmpeg -ss 00:00:05 -i input.mp4 -t 3 -vf "fps=12,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" output.gif
これは5秒地点から3秒間を変換します。
よくある問題
出力ファイルが非常に大きい
- fpsを下げる(スローモーションは10〜12、通常コンテンツは15)
- スケールを小さくする(幅320pxが一般的な出発点)
floyd_steinbergより圧縮効率の良いdither=bayerを使用
色が薄く見える
- 完全な2パスパイプラインを実行しているか確認(
ffmpeg -i input.mp4 output.gifだけでは不可) palettegenが対象フレームを正しく分析しているか(パス2と同じfps/scaleか)確認
パス2でパレットPNGが見つからない
パス1と2で/tmp/palette.pngのパスが一致しているか確認してください。WindowsではC:/tmp/palette.pngのようにフルパスを使用してください。
関連記事
テスト環境: ffmpeg 6.1.1 / Ubuntu 24.04(GitHub Actions)
一次ソース: ffmpeg.org/ffmpeg-filters.html#palettegen / ffmpeg.org/ffmpeg-filters.html#paletteuse