この記事でわかること
- CRFモードと2パスビットレートモードの違い
- 2パスパイプラインの実行方法:分析パスとエンコードパス
- ビットレート計算で特定のファイルサイズをターゲットにする方法
- カスタムログファイルの場所を指定する
-passlogfileオプション - H.264とH.265の2パスの例
テスト済みバージョン: FFmpeg 6.1(ubuntu-latest / CI検証済み)
対象 OS: Windows / macOS / Linux
⚠️ 実行前に必ず確認してください(passlogファイル汚染のリスク)
- 古い passlog ファイルが残っていると、パス2が誤ったデータを参照してエンコードが静かに破壊されます
- 複数ファイルをバッチ処理する場合、
-passlogfileにファイルごとのユニークな名前を必ず指定してください - エンコード完了後は
passlogfileを削除してください - パス1とパス2は必ず同じディレクトリで実行するか、両方に同じ
-passlogfileパスを指定してください
CRFモードと2パスビットレートモードの違い
FFmpegのlibx264・libx265エンコーダーには2つの主要な品質/ビットレート制御モードがあります:
| モード | オプション | 使い所 |
|---|---|---|
| CRF(固定レートファクター) | -crf 18〜28 | 品質を一定にしたい、ファイルサイズは変動してよい |
| 2パスビットレート | -b:v N -pass 1/2 | 特定のファイルサイズやビットレートを達成する必要がある |
CRFはシンプルで、アーカイブやストリーミングに多く使われます。2パスは特定のサイズ制限(メール添付ファイルの上限、ディスク容量など)に収める必要がある場合に適しています。
2パスの仕組み
パス1(分析): FFmpegが動画を高速にエンコードし、各フレームの複雑さを記録したログファイルを書き出します。出力動画は生成されません — ログファイルだけが重要です。
パス2(エンコード): FFmpegがログファイルを読み込んでどのシーンにより多くのビットが必要かを理解し、分析に基づいてビットレートを配分しながら最終出力をエンコードします。
デフォルトでは ffmpeg2pass-0.log(H.264ではffmpeg2pass-0.log.mbtreeも)が作業ディレクトリに生成されます。バッチ処理では必ず -passlogfile でユニークな名前を指定してください。
基本的な2パスH.264の例
推奨:エンコードごとにユニークな passlogfile を使う
パス1 — 分析のみ、出力なし:
ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 1 \
-passlogfile /tmp/passlog_myproject -an -f null /dev/null
パス2 — 分析データを使った実際のエンコード:
ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 2 \
-passlogfile /tmp/passlog_myproject -c:a aac -b:a 128k output.mp4
エンコード完了後に passlog を削除:
rm -f /tmp/passlog_myproject.log /tmp/passlog_myproject.log.mbtree
-pass 1/-pass 2で1パス目・2パス目を指定-passlogfileでログファイルのパスを明示(デフォルトのffmpeg2pass-0.logはバッチ処理で衝突するため非推奨)-anでパス1の音声エンコードをスキップ(ログには映像データのみ必要)-f null /dev/nullで出力を破棄(ログファイルのみ重要)
パス1とパス2で同じ -passlogfile パスを必ず指定してください。 異なるパスにすると No such file or directory エラーでパス2が失敗します。
特定のファイルサイズをターゲットにする
目標ファイルサイズからビットレートを計算する方法:
合計ビットレート_kbps = (目標サイズ_MB × 8192) ÷ 動画時間_秒
映像ビットレート_kbps = 合計ビットレート_kbps − 音声ビットレート_kbps
例: 4分(240秒)の動画を128kbps音声込みで50MBに収める場合:
合計 = (50 × 8192) ÷ 240 ≈ 1707 kbps
映像 = 1707 − 128 = 1579 kbps ≈ 1.5M
パス1:
ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -pass 1 \
-passlogfile /tmp/passlog_target -an -f null /dev/null
パス2:
ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -pass 2 \
-passlogfile /tmp/passlog_target -c:a aac -b:a 128k output.mp4
クリーンアップ:
rm -f /tmp/passlog_target.log /tmp/passlog_target.log.mbtree
バッチ処理での安全な passlogfile 管理
複数ファイルをバッチエンコードする場合、デフォルトのログ名 ffmpeg2pass-0.log を使うと、各ファイルのパス1がログを上書きし合い、パス2が誤ったデータを参照します。タイムスタンプやファイル名ベースのユニーク名を必ず使ってください:
for f in *.mp4; do
base="${f%.mp4}"
# タイムスタンプ付きのユニークな passlogfile 名
passlog="/tmp/passlog_${base}_$(date +%s)"
# パス1
ffmpeg -i "$f" -c:v libx264 -b:v 1M -pass 1 \
-passlogfile "$passlog" -an -f null /dev/null
# パス2
ffmpeg -i "$f" -c:v libx264 -b:v 1M -pass 2 \
-passlogfile "$passlog" -c:a aac "${base}_out.mp4"
# 必ずクリーンアップ
rm -f "${passlog}.log" "${passlog}.log.mbtree"
done
エンコード後の整合性確認
2パスエンコード後に出力の尺が正しいか確認する手順:
# 入力の尺(秒)
in_dur=$(ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 input.mp4)
# 出力の尺(秒)
out_dur=$(ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 output.mp4)
echo "入力: ${in_dur}秒 / 出力: ${out_dur}秒"
# 差が 0.5 秒以上あれば要確認
カスタムログファイルの場所(旧来の方法との対比)
デフォルトでは FFmpeg はログを ./ffmpeg2pass-0.log に書き込みます。-passlogfile で別のパスを指定できます:
ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 1 -passlogfile /tmp/mylog -an -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 2 -passlogfile /tmp/mylog -c:a aac output.mp4
クリーンアップ:
rm -f /tmp/mylog.log /tmp/mylog.log.mbtree
2パスH.265(libx265)
H.265での2パスエンコードも同様の構造です:
ffmpeg -i input.mp4 -c:v libx265 -b:v 800k \
-x265-params "pass=1:stats=/tmp/passlog_h265.log" -an -f null /dev/null
ffmpeg -i input.mp4 -c:v libx265 -b:v 800k \
-x265-params "pass=2:stats=/tmp/passlog_h265.log" -c:a aac output.mp4
クリーンアップ:
rm -f /tmp/passlog_h265.log /tmp/passlog_h265.log.cutree
注意:libx265は-x265-params pass=1 / stats=パスの書式を使います。H.264の-passlogfileとは異なります。
エンコーダープリセットの追加
2パスにエンコーダープリセットを組み合わせられます:
ffmpeg -i input.mp4 -c:v libx264 -preset slow -b:v 1M -pass 1 \
-passlogfile /tmp/passlog_slow -an -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -preset slow -b:v 1M -pass 2 \
-passlogfile /tmp/passlog_slow -c:a aac -b:a 128k output.mp4
rm -f /tmp/passlog_slow.log /tmp/passlog_slow.log.mbtree
ログファイルとパス2の分析が一致するよう、両パスで同じプリセットを使用してください。
2パスを使うべき場面
| シナリオ | 推奨 |
|---|---|
| 一定の映像品質でアーカイブ | CRFモード(-crf 23)を使用 |
| 特定のサイズ制限に収める必要がある | 2パスビットレートモードを使用 |
| 保証されたビットレートでストリーミング配信 | 2パス(または-maxrateによる制約付きビットレート) |
| クイックトランスコードやプレビュー | CRFモード(シングルパス) |
よくある問題
パス2でログファイルが見つからない
パス2がパス1と異なるディレクトリで実行されると、ffmpeg2pass-0.logを見つけられません。両パスを同じディレクトリで実行するか、両パスで-passlogfile /path/to/logを使用してください。
パス1での音声エンコード
-anでパス1の音声エンコードをスキップするのは正しい対応です — ログには映像の複雑さデータのみ必要です。
両パスで同じ-b:vを使用する
両パスで必ず同じ-b:v値を使用してください。異なる値を使うと、パス1のログが別のビットレートをターゲットにしてしまい、信頼性の低い結果になります。
関連記事
テスト環境: ffmpeg 6.1.1 / Ubuntu 24.04(GitHub Actions)
一次ソース: trac.ffmpeg.org/wiki/Encode/H.264 / ffmpeg.org/ffmpeg.html
よくある質問
2-pass と CRF、どっちを使うべき?
出力サイズを正確に決めたいなら 2-pass、画質優先なら CRF。Web アップロード用途では CRF が現代的なベストプラクティス(YouTube も推奨)。Discord 容量制限などサイズ縛りには 2-pass。
2-pass はなぜ 2 回エンコードする?
1 回目で動画全体のシーン複雑度を分析、2 回目でその情報を元にビットレートを動的配分するため。複雑なシーンに多く、静的シーンに少なく割り当てることで同サイズで高画質を実現。
エンコード時間はどれくらい増える?
CRF 1 回と比べてだいたい 1.8〜2.2 倍。1 回目は分析のみで映像出力は破棄するため、2 回目より少し速い。
1 回目のログファイルは残しておく?
不要です — ffmpeg が ffmpeg2pass-0.log を 2 回目で読んだ後、自動的に削除する設計(オプション -passlogfile で名前変更可能)。CI では明示的に削除しておく方が安全。
2-pass でも -c:a copy で音声無劣化にできる?
はい。2-pass は映像の最適化なので、音声は通常通りコピーまたは AAC 等で再エンコード可能。音声込みのジョブなら 2 回目だけ -c:a aac -b:a 128k を指定。