2018年06月23日

どんな解像度・縦横比の動画も一発で指定のサイズにするffmpegコマンド

ffmpegで、4:3の動画の左右に黒帯(サイドパネル)を付けて1920x1080(16:9)の動画を作りたいと思っても、-s 1920x1080 と単純に指定するだけだと横に引き伸ばされた動画になってしまう。
これに限らず、不定な解像度・縦横比の動画を、適切にレターボックス化またはサイドパネル化するのは結構難しく、以下のようなコマンドが必要になる。
ffmpeg -i "input.mp4" -vf "yadif=deint=interlaced, scale=w=trunc(ih*dar/2)*2:h=trunc(ih/2)*2, setsar=1/1, scale=w=1920:h=1080:force_original_aspect_ratio=1, pad=w=1920:h=1080:x=(ow-iw)/2:y=(oh-ih)/2:color=#000000" -pix_fmt yuv420p "output.mp4"

このコマンドを使うことで、入力動画のサイズを気にすることなく指定のサイズにして出力できる。出力サイズ(解像度)はw=1920:h=1080となっているところ(2箇所)で指定する。
color=#000000 となっているところで別のカラーコードを指定すれば、上下左右に付ける帯の色を黒以外にすることができる。

海外の質問サイトにあった回答を元にしているけれど、この回答にあるコマンドでは正方ピクセルの動画しか対応できないので、フィルタ処理の前段に scale=w=trunc(ih*dar/2)*2:h=trunc(ih/2)*2, setsar=1/1 を入れて、正方ピクセルでない動画も正方ピクセルに直している。(基本的なことだが、ffmpegのフィルタは書いた順に実行される。)scaleで/2とか*2しているのは、サイズを偶数にしないと一部の出力形式にするときにエラーが出るため。
この追加の処理により、解像度が720x480固定でありながら表示は16:9や4:3になるDVDの映像(VOBファイル)などにも対応することができる。

また、フィルタの最初にある yadif=deint=interlaced はインタレース解除フィルタ。出力はプログレッシブになるので、たとえ入力動画がインタレースでも対応できるようにしている。deint=interlaced を付けることで、インタレースだとマークされている部分だけをインタレース解除するように働いてくれるので、プログレッシブな入力動画も同一コマンドで処理できる。(プログレッシブな動画にyadifフィルタが適用されてしまうと、輪郭に縞模様が出ることがある。)しかし、これは万能ではなく、元動画を作成したエンコーダによっては、たとえインタレース動画でもインタレースの部分にマークを付けないことがあり、この場合はインタレースが解除されない。確実にインタレースが解除されるようにするには、ffprobeとかffmpegのidetフィルタとかで入力動画がインタレースであるか調べて、適切にyadifフィルタを適用するようにバッチなりプログラムなりを組む必要がある。Windowsのバッチファイルなら、この記事に書いたような方法で条件分岐することになる。


出力をインタレースの動画にする場合、入力がプログレッシブだったら単に -flags +ilme+ildct オプションを付ければ良いが、入力がインタレースだった場合はインタレ保持するようにコマンドを考えないといけない。困ったことにffmpegは昔から(2018年現在最新のver4.0でも)動画の高さ(height)が変わるとインタレースを保持できない、という問題を抱えている。なので、一旦yadifフィルタの片フィールド補完を使って「インタレース → fpsが2倍のプログレッシブ」に変換し、サイズを変更した後、tinterlaceフィルタで「fpsが2倍のプログレッシブ → 元のfpsのインタレース」に戻す。そのコマンドは以下のようになる。(以下のコマンドはインタレースの入力動画専用なので注意!)
ffmpeg -i "input.mp4" -vf "yadif=mode=send_field, scale=w=trunc(ih*dar/2)*2:h=trunc(ih/2)*2, setsar=1/1, scale=w=1920:h=1080:force_original_aspect_ratio=1, pad=w=1920:h=1080:x=(ow-iw)/2:y=(oh-ih)/2:color=#000000, tinterlace=4" -pix_fmt yuv420p -flags +ilme+ildct "output.mp4"
タグ:FFmpeg
posted by 十河大瑛 at 2018年06月23日 15:14 | Comment(3) | 作ったもの
この記事へのコメント
scaleを2回、記述しなくても'scale=trunc(oh*dar/2)*2:1080'で'scale=w=trunc(ih*dar/2)*2:h=trunc(ih/2)*2,こscale=w=1920:h=1080:force_original_aspect_ratio=1'と全く同じ挙動をすると思います。
Posted by at 2018年12月08日 07:46
Preview example
ffplay -i "input.mp4" -vf "yadif=deint=interlaced,scale=trunc(oh*dar/2)*2:1080, setsar=1/1,pad=ih*16/9:ih:(ow-iw)/2:0:color=#000000"

失礼しました。
Posted by at 2018年12月09日 07:37
ご指摘ありがとうございます。確かに、4:3などの動画をサイドパネル化する場合は、書いていただいたコマンドの方がスマートです。その代わり、シネスコサイズの動画を同一コマンドでレターボックス化することは出来なくなってしまいます。タイトルで「どんな解像度・縦横比の動画も」と標榜しているため、記事の方はそのままにしておこうと思います。
Posted by 十河大瑛 at 2018年12月16日 21:26
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。