• FFmpegでVP9エンコード

    2017年09月21日 20時25分
    時々ゲームプレイを録画して残していまして、
    CODECをh.264、色空間はYUV420にしていました。

    ただ、ゲーム画面だと隣り合うピクセルの色が全然違ったり彩度の高いピクセルが多かったりで
    YUV420にすると全体的に色が薄く見えるのが不満でした。

    これを解決すべく色空間をYUV444に変更し
    ついでにCODECも高圧縮なVP9に変更しようというのが今回の話の始まり。


    今時高圧縮なCODECというとh.265かVP9で迷います。

    h.265はハードウェアエンコード対応が多く
    VP9はだいたいのブラウザで再生できるのがそれぞれの利点でしょうか。

    画質と圧縮率はだいたい同じくらいのようで
    私には良し悪しが判断出来ません。

    今回は大量にエンコードするわけではないので再生環境が多いVP9を採用することにしました。


    VP9のエンコーダというと、最初はlibvpxに付いているvpxencを使おうと思ったのですが
    録画したaviファイルをy4mに変換する必要があり
    y4mの変換にffmpegを使うことになったので、それならもう全部ffmpegでいいかとffmpegを採用。


    それでいざffmpegでエンコードしようとすると
    オプション大量すぎてわけわからんで苦労したので調べた情報を書いておこうと思います。


    私はffmpegについて詳しいわけではないので
    不確かなことを書くのもどうかとは思ったのですが
    あまりに情報が少なかったので全く無いよりはいいかと書いておくことにしました。

    調べる時のとっかかり程度の情報と思って見ていただきたい。


    参考情報




    CODEC


    動画CODECにVP9を指定。
    -c:v libvpx-vp9


    WebMの音声CODECはOpusまたはVorbisになりますが、後発のOpusを使えばいいと思います。(性能もいいらしい)
    音声CODECにOpusを指定。
    -c:a libopus


    コンテナは出力ファイルの拡張子から判断してくれるようですが、一応指定しておけば確実かなと思います。
    -f webm



    RGB → YUV444変換


    エンコーダに渡すピクセルの色空間指定はpix_fmtで行います。
    -pix_fmt yuv444p


    カラーマトリクスは全然別のオプションでこうです。
    -vf "scale=out_color_matrix=bt709:out_range=full"


    ffmpegのログを見ると、-vfでscaleを指定しない場合auto_scalerというのが挿入され、こいつが色空間の変換処理をしているようです。
    「-vf "scale=out_color_matrix=bt709:out_range=full"」のように明示的に指定してやるとauto_scalerが自動挿入されなくなり、指定したscalerが入ります。


    ビットレート


    VP9にはビットレートのモードが4つ。

    • Constant Quantizer (Q)
    • Constrained Quality (CQ)
    • Variable Bitrate (VBR)
    • Constant Bitrate (CBR)

    ストリーミングで配信するわけでもなく
    自分用にアーカイブするのが主な目的なので
    品質固定のConstant Quantizer (Q)を採用しました。

    Constant Quantizer (Q)の指定。
    -crf 30 -b:v 0


    crfは0-63の範囲で指定し、0に近づくほど画質がよくなりデータサイズが大きくなるので
    結果のファイルサイズと画質のバランスで決めることになると思います。

    思ったより数字を大きくしても画質は良いと感じました。
    目安としていくらか試した感じだと1080p 30fpsで30-35あたりが良いのではないかと。

    「-b:v 0」は必須です。というかこの指定がConstant Quantizer (Q)の意味。


    Opusのビットレートの指定は簡単。
    -b:a 160k

    Youtubeが160kでエンコードしているらしいのでその辺りが良さそうです。


    エンコード品質と速度


    -speed 1


    0-4の間で指定し、0に近い程エンコード速度が遅くなり画質が良くなる。
    基本的には0を指定したいところですが、ただでさえ遅いVP9のエンコードがさらに遅くなるので
    エンコード時間を考慮して決めることになります。


    カラーマトリクス


    YUVからRGBに戻す時のカラーマトリクスを指定します。
    RGB → YUVの変換で指定したものを指定すればいいと思うのですが
    なぜ3個もあるのかよくわかりません。

    ffmpegのログを見ると3つとも同じにしておけばひとまとめにして認識してくれているようなのでこれで合っている気がします。
    -colorspace bt709 -color_primaries bt709 -color_trc bt709



    デコード用オプション


    公式のエンコードガイドに、画面を分割して並列デコードできるようになるみたいなオプションがエンコード例に記載してあります。
    -tile-columns 6 -frame-parallel 1


    効果はイマイチわかりませんが今のところ特に害はないです。
  • libvpxのVisual Studio用ファイルをLinux上で作る

    2015年06月11日 20時38分
    libvpxをWindows用にビルドしたいけどMinGWをインストールするのが嫌でLinuxはある人向けという
    隙間産業的な記事。


    VP9のエンコードはそろそろ早くなったりしないかなあと思いつつlibvpxの中身を眺めていたら、
    なんか行けそうな気がしてやってみたら出来たのでメモっておきます。

    ちなみに私はlibvpxの中身を熟知しているわけではなく、
    部分部分をちょいちょいとつまんで解釈し
    なんとなく合ってそうというものであるとご理解ください。


    きっかけは、libvpxの中身を見ていたら「gen_msvs_sln.sh」とか「gen_msvs_vcxproj.sh」とかが有るのに気づいたことで、
    同時に「これをLinux上で動かしてslnとかvcxprojとか作れればそれを持ってきてVSでビルド出来るんじゃね?」と閃きました。

    これらのスクリプトはconfigureでtargetにvsを選択すると使われるようになっています。

    例えば、VS12で64bit用にビルドしたい場合はtargetにx86_64-win64-vs12を指定します
    # ./configure --target=x86_64-win64-vs12

    ※targetの一覧はconfigureのhelpに出てきます。


    これでmakeすると、指定したVS向けファイルが作成されます。

    configureの中のヘッダチェックとかも気になったのですが、主にtargetを確認する処理になっていて、
    実際そのヘッダが有るかないかとかは見てないので大丈夫そうです。


    細かい手順や注意点は以下になります。

    gitのcloneを取る
    # git clone https://chromium.googlesource.com/webm/libvpx
    # cd libvpx


    試した時のrevisionはこれでした
    # git rev-parse HEAD
    44afbbb72d8a5fa0528f8a571a5023a843d02f33


    作業用にまるっとコピーします
    # mkdir ../export
    # git archive --format=tar HEAD | tar -x -C ../export
    # cd ../export


    VSプロジェクトファイル内のincludeディレクトリ指定に、configureした時のLinux上のフルパスが現れないように書き換えます
    # sed -i -e 's/SRC_PATH_BARE=$source_path/SRC_PATH_BARE=./' build/make/configure.sh
    # sed -i -e 's/CFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT) -I$(SRC_PATH)/CFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT)/' -e 's/CXXFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT) -I$(SRC_PATH)/CXXFLAGS+=-I$(BUILD_PFX)$(BUILD_ROOT)/' build/make/Makefile


    vpxenc以外コンパイルしたくないんじゃあという場合は、examplesの対象をvpxencだけに書き換えます
    # sed -i -e 's/ALL_EXAMPLES    = $(UTILS) $(EXAMPLES)/ALL_EXAMPLES    = vpxenc.c/' examples.mk


    お好みのオプションを選択してconfigure
    # ./configure --log=no --target=x86_64-win64-vs12 --enable-static-msvcrt --disable-vp8 --disable-unit-tests

    vp9のdecoderも要らないのでOFFにしようと思ったのですが
    decoderが一個も無くなると一部ソースがコンパイルエラーになるのでやめました。

    makeするとVS用のプロジェクトファイルとかソリューションファイルが作成されます
    # make


    後はこのソースツリーをまるごとWindowsに持ってきてvpx.slnをVSで開けばビルドできます。
    ※yasmのインストールも必要です



    さて、VP9のエンコードは今どのくらいの速度なのでしょうか。
    1920 * 1080 FPS30の動画をエンコードしてみました。
    CPUはCore i7 3770です。

    オプションがまだ完全に把握出来ていないのですが、
    まずはおそらく最速の設定であろう「good cpu-used=8」を試しました
    vpxenc --output=output.webm --threads=4 --good --cpu-used=8 --passes=1 --codec=vp9 --webm --end-usage=cq --cq-level=10 --i420 --color-space=bt709 --width=1920 --height=1080 input.y4m


    思ったより早い!11FPSくらい出ました。
    そこそこ使えなくもない早さな気がします。
    でも、どうせなら遅くても品質を取りたいので、次は「best」を設定してみました。
    vpxenc --output=output.webm --threads=4 --best --passes=1 --codec=vp9 --webm --end-usage=cq --cq-level=10 --i420 --color-space=bt709 --width=1920 --height=1080 input.y4m


    結果は14FPMでした。
    FPSじゃないです。FPMです。
    最初表示がバグったかと思いました。
    こんな表示が用意してあるあたり開発側もまだ遅いと思っているのでしょう。

    品質についてはbestのエンコード終了を待てなかったので比較していません。