Intel Media SDKとIntel QSVに対応したffmpegをビルドして爆速H.264エンコード(Ubuntu 16.04)

DTVLinux, DTV, Ubuntu, ffmpeg, エンコード

前回までの記事で、Intel Media Driverをインストールし、無事にドライバの読み込みまでは完了したところである。
これでVAAPIを用いたエンコードは出来るのだが、ffmpegのバージョンがあがり、この状態からQSVを使ったエンコードまでできるようになった。

ご承知の通り、VAAPIを使ったエンコードはエンコードオプションが非常に少なく、使い勝手が良いとは言えない。対照的に、Intel QSVを用いると、オプションは豊富となり、さらに少しだけ「ファイルが重たくなってしまう」というような事象にも対応出来るようだ。

Intel Media SDKをインストールする

まずはじめに、Intel Media SDKをインストールしておかなければ、QSVに対応することができない。ただし、インストール自体は非常に簡単である。
基本的には、公式サイトの通り。ただし最新版のLibvaが入っていれば、タグをcheckoutする必要はない。

$ wget https://github.com/intel/compute-runtime/releases/download/18.24.10921/intel-opencl_18.24.10921_amd64.deb
$ sudo dpkg -i intel-opencl_18.24.10921_amd64.deb
$ git clone https://github.com/Intel-Media-SDK/MediaSDK msdk
$ cd msdk
$ mkdir build
$ cd build
$ cmake ..
$ time make -j8
$ sudo make install
$ export PKG_CONFIG_PATH=/opt/intel/mediasdk/lib/pkgconfig:$PKG_CONFIG_PATH

なお、当方の環境ではビルド中にOpenCL環境が少し欠けている点があり(具体的には「cl.app」と「cl_va_api_media_sharing_intel.h」)、それぞれを別々に調達し/usr/include/CL/配下に配置してあげた。この方法が正しいのかどうかは不明であるが、とにかくmakeは通った。

最後の行は、/opt/intel/mediasdk/lib/pkgconfig配下にMedia SDKのpkg-configファイルが格納されているので、ここにpkg-configが参照できるよう環境変数に追加をしている次第。

ffmpegをビルドする

今回は、Intel QSVやその他諸々に対応したffmpegを一からビルドしていく。バージョンもffmpeg4となり、機能は相当に強化されているらしい。
基本的には、リポジトリに登録されているx264等は少し機能が遅れていることから、これらに関してもソースからコンパイルをしていく。
実際には、公式サイトをみながら進めていくと良い。

依存関係のあるコンポーネントのインストール

依存関係がいくつかあるので、これだけ注意しておきたい。x264等個別のエンコーダーのインストールは、上記の公式サイトを参考としていただければ幸いである。

$ sudo apt-get update -qq && sudo apt-get -y install autoconf automake build-essential cmake git-core libass-dev libfreetype6-dev libsdl2-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texinfo wget zlib1g-devnasm yasm libgtk-3-0 libgdk-pixbuf2.0

QSV対応のffmpegをコンパイル&インストールする

ようやくFFMpegのインストールとなる。忘れてはならないのは、Intel QSVを有効にしておくこと。その他、現在のffmpegのエンコードオプションはffmpegを実行すると出てくるので、それを参考にすると良い。
また、デフォルトではPKG_CONFIG_PATHが別に設定されることを想定していないため、この部分は少しだけ修正。

$ cd ~/ffmpeg_sources
$ git clone https://github.com/FFmpeg/FFmpeg ffmpeg
$ cd ffmpeg
$ PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig:$PKG_CONFIG_PATH" ./configure \
  --prefix="$HOME/ffmpeg_build" \
  --pkg-config-flags="--static" \
  --extra-cflags="-I$HOME/ffmpeg_build/include" \
  --extra-ldflags="-L$HOME/ffmpeg_build/lib" \
  --extra-cflags="-I/opt/intel/mediasdk/include" \
  --extra-ldflags="-L/opt/intel/mediasdk/lib" \
  --extra-ldflags="-L/opt/intel/mediasdk/plugins" \
  --extra-libs="-lpthread -lm" \
  --bindir="$HOME/bin" \
  --enable-vaapi \
  --enable-libdrm \
  --enable-libtheora \
  --enable-opencl \
  --enable-gpl \
  --enable-libmfx \
  --enable-libaom \
  --enable-libass \
  --enable-libfdk-aac \
  --enable-libfreetype \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvorbis \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265 \
  --enable-nonfree
$ make -j8
$ make install

これで、%HOME/binディレクトリの中にffmpegができあがる。$HOME/binにパスを通してこのまま使うことも可能なのだが(というか、ffmpegの推奨はこれである)、少し気持ちが悪いのでコピーしたりコンパイルオプションを変えたりしておこう。

インストールされると、ffmpegのエンコーダーにh264_qsvが追加されているのが分かる。

$ ffmpeg -encoder s | grep qsv
 V..... h264_qsv             H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration) (codec h264)
 V..... hevc_qsv             HEVC (Intel Quick Sync Video acceleration) (codec hevc)
 V..... mjpeg_qsv            MJPEG (Intel Quick Sync Video acceleration) (codec mjpeg)
 V..... mpeg2_qsv            MPEG-2 video (Intel Quick Sync Video acceleration) (codec mpeg2video)

QSV対応ffmpegの使い方やオプション

さて、これでIntel Media SDKを使ってffmpegからQSVエンコードをする準備が整った。

使用するコーデックはh264_qsv。使用出来るOptionは、やはり公式サイトが詳しい。

また、非常に充実しているのが下記のサイトで、非常に詳しい使い方が手に入る。

機能上VAAPIと大きな違いは、インタレースの解除オプションがあるところだろうか(deinterlace_qsv)。QSVを使用する際に利用出来るオプションの詳細は、ffmpeg -h encoder=h264_qsvを実行することで確認可能だ。

$ ffmpeg -h encoder=h264_qsv
  -async_depth       <int>        E..V...... Maximum processing parallelism (from 1 to INT_MAX) (default 4)
  -avbr_accuracy     <int>        E..V...... Accuracy of the AVBR ratecontrol (from 0 to INT_MAX) (default 0)
  -avbr_convergence  <int>        E..V...... Convergence of the AVBR ratecontrol (from 0 to INT_MAX) (default 0)
  -preset            <int>        E..V...... (from 1 to 7) (default medium)
     veryfast        7            E..V......
     faster          6            E..V......
     fast            5            E..V......
     medium          4            E..V......
     slow            3            E..V......
     slower          2            E..V......
     veryslow        1            E..V......
  -rdo               <int>        E..V...... Enable rate distortion optimization (from -1 to 1) (default -1)
  -max_frame_size    <int>        E..V...... Maximum encoded frame size in bytes (from -1 to 65535) (default -1)
  -max_slice_size    <int>        E..V...... Maximum encoded slice size in bytes (from -1 to 65535) (default -1)
  -bitrate_limit     <int>        E..V...... Toggle bitrate limitations (from -1 to 1) (default -1)
  -mbbrc             <int>        E..V...... MB level bitrate control (from -1 to 1) (default -1)
  -extbrc            <int>        E..V...... Extended bitrate control (from -1 to 1) (default -1)
  -adaptive_i        <int>        E..V...... Adaptive I-frame placement (from -1 to 1) (default -1)
  -adaptive_b        <int>        E..V...... Adaptive B-frame placement (from -1 to 1) (default -1)
  -b_strategy        <int>        E..V...... Strategy to choose between I/P/B-frames (from -1 to 1) (default -1)
  -forced_idr        <boolean>    E..V...... Forcing I frames as IDR frames (default false)
  -low_power         <boolean>    E..V...... enable low power mode(experimental: many limitations by mfx version, BRC modes, etc.) (default false)
  -cavlc             <int>        E..V...... Enable CAVLC (from 0 to 1) (default 0)
  -idr_interval      <int>        E..V...... Distance (in I-frames) between IDR frames (from 0 to INT_MAX) (default 0)
  -pic_timing_sei    <int>        E..V...... Insert picture timing SEI with pic_struct_syntax element (from 0 to 1) (default 1)
  -single_sei_nal_unit <int>        E..V...... Put all the SEI messages into one NALU (from -1 to 1) (default -1)
  -max_dec_frame_buffering <int>        E..V...... Maximum number of frames buffered in the DPB (from 0 to 65535) (default 0)
  -look_ahead        <int>        E..V...... Use VBR algorithm with look ahead (from 0 to 1) (default 0)
  -look_ahead_depth  <int>        E..V...... Depth of look ahead in number frames (from 0 to 100) (default 0)
  -look_ahead_downsampling <int>        E..V...... Downscaling factor for the frames saved for the lookahead analysis (from 0 to 3) (default unknown)
     unknown         0            E..V......
     auto            0            E..V......
     off             1            E..V......
     2x              2            E..V......
     4x              3            E..V......
  -int_ref_type      <int>        E..V...... Intra refresh type (from -1 to 65535) (default -1)
     none            0            E..V......
     vertical        1            E..V......
  -int_ref_cycle_size <int>        E..V...... Number of frames in the intra refresh cycle (from -1 to 65535) (default -1)
  -int_ref_qp_delta  <int>        E..V...... QP difference for the refresh MBs (from -32768 to 32767) (default -32768)
  -recovery_point_sei <int>        E..V...... Insert recovery point SEI messages (from -1 to 1) (default -1)
  -profile           <int>        E..V...... (from 0 to INT_MAX) (default unknown)
     unknown         0            E..V......
     baseline        66           E..V......
     main            77           E..V......
     high            100          E..V......
  -a53cc             <int>        E..V...... Use A53 Closed Captions (if available) (from 0 to 1) (default 1)
  -aud               <int>        E..V...... Insert the Access Unit Delimiter NAL (from 0 to 1) (default 0)
  -mfmode            <int>        E..V...... Multi-Frame Mode (from 0 to 2) (default auto)
     off             1            E..V......
     auto            2            E..V......
  -repeat_pps        <boolean>    E..V...... repeat pps for every frame (default false)

また、-vfオプションの中で指定できる項目(フィルター)は、以下の3つとなっている。

  • vpp_qsv
  • scale_qsv
  • overlay_qsv
  • deinterlace_qsv

それぞれのフィルタの詳細は、ffmpeg -h filter=vpp_qsv等と指定することでで確認出来る。

QSVでMPEG2をH.264にトランスコードしてみる

基本的にMPEG2からH.264へ変換する場合の例は次のような形になる。MPEG2のデコードからQSVへ明示的に流してあげる形をとらないと、デコードがソフトウェアで行われてしまう。

ffmpeg -hwaccel qsv -c:v mpeg2_qsv -i [input] -c:v h264_qsv -vf 'scale_qsv=1280:720' -q:v 23 -c:a copy output.mp4

q:v 23は品質固定のCQPモード。数字が低いほど画質は高くなる(VAAPIでいう、qpである)。こちらのサイトによれば、QSV対応ffmpegでは概ね23程度に設定をすると支障がないとのこと。

format=nv12等は、先述のサイトによればffmpeg4からは原則として廃止されているとのことで、今回は外している。

あとは実際にやってみるのみ。先の設定で、15Mbpsほどある1080iのMPEG2(地デジ)の番組は17倍速程度、500fpsほどで処理され、3-4Mbpsまで縮んでいた。

ちなみに、同じ素材をVAAPIを用いて行うと、qp20の設定で11-12倍、360fpsくらい。速度は申し分なく、また(欲を言えばもう少しファイルサイズが小さくなって欲しいが)簡易なエンコード用途であれば十分だ。

Intel Media SDKを用いると、H265のエンコードも可能である。何日か使ってみて、おかしなところが出てこないか確かめておこうと思う。

執筆者紹介

Thir

購入したガジェットの紹介やサーバーの構築方法、スマートホーム化等、そのときハマっていたもののメモ書き・趣味の備忘録ではありますが、お役に立つ情報があれば幸いです。最近はYouTubeでもレビュー動画やVlogをあげています。サイト紹介・プロフィールはこちら。依頼・お問い合わせはこちらから。