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
効果はイマイチわかりませんが今のところ特に害はないです。
FFmpegでVP9エンコード 補足