libx264 で動画をエンコードしようとすると、height not divisible by 2(または width not divisible by 2)というエラーで止まり、出力ファイルが作られません。FFmpegで最も多いエラーの1つです。原因は1つです。ピクセルフォーマットが yuv420p のとき、libx264 は幅と高さの両方に偶数を要求しますが、スケールやクロップの結果、動画の幅か高さが奇数になっています。直し方は3つあり、どれもそのまま貼り付けて使えます。

エラーメッセージはエンコーダを指していますが、直す場所はその手前です。エンコーダに渡すフレームの幅と高さを両方とも偶数にします。このエラーはどの形でも、フィルタを1行変えれば解決できます。

なぜ H.264 の yuv420p は偶数サイズが必要なのか

FFmpeg は、libx264 が対応していれば入力のピクセルフォーマットをそのまま使います。そのため yuv420p の素材は yuv420p で出力されます。鍵は 420 の部分です。これは クロマサブサンプリング 4:2:0 を意味し、色(クロマ)情報を、明るさ(ルマ)に対して水平・垂直それぞれ半分の解像度で保存します。言い換えると、1つのクロマサンプルがルマの 2×2 ブロックを受け持ちます。

幅または高さが奇数だと、この 2×2 のグリッドがフレームをきれいに敷き詰められず、半端な行または列が1つ残ります。libx264 は 4:2:0 でこれを受け付けず、処理を拒否して width not divisible by 2 または height not divisible by 2 と報告します。

# 失敗時の表示例
[libx264 @ ...] height not divisible by 2 (1280x721)
[vost#0:0/libx264 ...] Error while opening encoder - maybe incorrect
parameters such as bit_rate, rate, width or height.
Conversion failed!

括弧内のサイズ(上の例では 1280x721)を見れば、どちらの辺が問題かがわかります。ここでは高さ 721 が奇数です。

奇数サイズが生まれる最も多い原因は、比率指定によるスケールです。たとえば 1280x722 の素材を半分にすると 640x361 になり、エンコーダは奇数の高さを拒否します。PNG画像などのRGBの素材を奇数サイズでクロップし(crop=641:480)、yuv420p で出力する場合も同じです。

解決法1: trunc で偶数に切り下げる

入力サイズが何であっても効く、最も汎用的な解決法です。trunc を使って両方のサイズを最も近い偶数に強制します。trunc(iw/2)*2 は、幅を2で割って小数部を捨て、再び2を掛けます。これで、元の値以下の偶数が必ず得られます。

ffmpeg -i input.mp4 -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" -c:a copy output.mp4
  • iw / ih — 入力の幅と高さ
  • trunc(iw/2)*2 — 幅を偶数に切り下げる
  • trunc(ih/2)*2 — 高さを偶数に切り下げる
  • -c:a copy — 音声はそのまま(再エンコードしない)

奇数だった辺が1ピクセル小さくなります。scale は絵全体を新しいサイズに縮めるもので、行や列を切り取るわけではありません。フレームを拡大することはないため、「とにかくエンコードを通したい」「特定の解像度を厳密に守る必要はない」という場合の安全な既定値です。

解決法2: scale=-2 でアスペクト比を保つ

意図的にリサイズするとき(たとえば「高さを720pにして比率は保つ」)は、もう一方のサイズをFFmpegに計算させ、結果を偶数にするよう指示します。それが scale フィルタの -2 の意味です。「この辺はアスペクト比を保つように計算し、2の倍数に丸める」という指定になります。

ffmpeg -i input.mp4 -vf "scale=-2:720" output.mp4

ここでは高さを 720 に固定し、幅は素材のアスペクト比から計算され、自動的に偶数に丸められます。-1 ではなく -2 を使うのは、-1 だと幅が奇数になり、同じエラーが再発することがあるためです。幅のほうを固定する場合も同じ書き方です。

ffmpeg -i input.mp4 -vf "scale=1280:-2" output.mp4

720pや1080pへダウンスケールするときは、この解決法を選びます。片方のサイズを指定すれば、-2 がもう一方を比率どおりの偶数にします。

解決法3: pad で次の偶数まで余白を足す

絵を1ピクセルも失いたくない場合は、縮めるのではなくキャンバスを広げます。pad フィルタは細い余白を足してサイズを偶数にし、元のフレームはそのまま残します。

ffmpeg -i input.mp4 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" output.mp4
  • ceil(iw/2)*2 — 幅を次の偶数へ 切り上げる
  • ceil(ih/2)*2 — 高さを次の偶数へ 切り上げる

奇数の辺には、ちょうど1行または1列の余白(既定では黒)が足されます。元の画像は丸ごと残り、奇数だった辺に1ピクセルの縁が増えるだけです。素材が貴重な場合(たとえばアーカイブ映像や画面録画など)にこれを選びます。

どの解決法を選ぶべきか

解決法 フィルタ サイズへの影響 向いている場面
切り下げ scale=trunc(iw/2)*2:trunc(ih/2)*2 奇数の辺ごとに最大1px縮む 汎用「とにかく通したい」
比率保持 scale=-2:720(または scale=1280:-2) 目標サイズに偶数でリサイズ 720p/1080pへのダウンスケール
余白追加 pad=ceil(iw/2)*2:ceil(ih/2)*2 奇数の辺ごとに最大1px増える 全ピクセルを保持したい

3つとも幅と高さが偶数になり、エンコーダの要件を満たします。あとは「少し縮める」「リサイズする」「少し縁を足す」のどれが合うかで選びます。

よくある質問

scale の -1 と -2 の違いは何ですか?

どちらもアスペクト比からそのサイズを計算させる指定です。-1 は数学的に正確な値を出すため奇数になり得て、height not divisible by 2 を再発させることがあります。-2 は同じ計算をしたうえで結果を2の倍数に丸めるので、yuv420p で常に安全です。H.264出力では -2 を選んでください。

クロップがこのエラーを起こすのはなぜですか?

yuv420p の素材なら、crop は奇数のサイズを偶数に切り下げます。crop=641:480 は 640x480 になり、そのままエンコードできます。奇数のサイズがエンコーダに届くのは、PNG画像などのRGBのフレームをクロップして yuv420p で出力する場合(たとえば -pix_fmt yuv420p を付けたとき)や、exact=1 を付けた場合です。偶数の目標値を使うか、crop=trunc(iw/2)*2:trunc(ih/2)*2 で自動的に計算してください。

ピクセルフォーマットを変えるだけでもいいですか?

-pix_fmt yuv444p(色の間引きなし)に切り替えれば、偶数サイズの要件はなくなります。4:2:2(yuv422p)では、幅は偶数のままにする必要があります。ただし多くのプレーヤーやデバイスは yuv420p しか確実に再生できないため、できたファイルを再生できない環境があります。サイズを直すほうが互換性の高い解決策です。

エラーは width と言っているのに、高さしか変えていません。なぜですか?

scale や crop は両方の辺を同時に変えられ、エンコーダは最初にぶつかった辺を報告します。trunc や ceil で 両方 のサイズを偶数に丸めればすべてのケースをカバーできるので、どちらが実際に奇数なのかを突き止める必要はありません。

libx264 以外のコーデックでも起きますか?

H.265/HEVC では起きます。libx265 も yuv420p で奇数の幅や高さを拒否します。一方、VP8・VP9・AV1 のエンコーダ(libvpx、libvpx-vp9、libaom-av1、libsvtav1)と mpeg4 は奇数サイズを受け付けます。つまり制限は yuv420p そのものではなく、libx264 と libx265 によるものです。libx265 でも同じ scale/pad の解決法が使えます。

関連記事