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 の解決法が使えます。