はじめに
H.264 エンコードもすっかり普及して久しい感のある今日この頃。
画質ではソフトウェアエンコードに及ばないものの、速度や負荷の面で有利なハードウェアエンコードは用途によってはとても有用です。
今回は、バージョン 3.1 で VAAPI によるエンコードに対応した FFmpeg を使って QSV 対応 CPU による H.264 のハードウェアエンコードを試します。
Intel QSV
Intel QSV (Quick Sync Video) は、最近 (Sandy Bridge 以降) の Intel の CPU に搭載されているハードウェアエンコーダ/デコーダです。
CPU の世代によっては MPEG2 や H.264 だけでなく H.265 や VP8 のエンコード/デコードにも対応しています。
QSV を利用するには対応したアプリケーションが必要です。
Intel Media Server Studio
Linux 上で QSV を利用するには Intel Media Server Studio (以下 MSS) をインストールし、QSV 対応アプリ (FFmpeg 等) から利用するという方法があるようです。1 2 3 4
MSS に含まれている Intel Media SDK を使用することで QSV を利用できるようになるのですが、MSS は対応する CPU の世代が限定されていたり5、特定のディストリビューション・カーネルバージョンが推奨されていたり6、カーネルのビルドが必要だったり7、と気軽に利用するには少しハードルが高い感じがします。
VAAPI
VAAPI (Video Acceleration API) とは、Linux 上で動画のエンコード/デコードにハードウェアアクセラレーションを利用するためのオープンソースな API で、Intel の Graphics for Linux* というプロジェクトの一環として開発されています。
クローズドソースな Intel Media SDK を使用する場合に比べてパフォーマンスは劣るようですが8、MSS のように CPU の世代やディストリビューションに縛られることなく QSV が利用できるので、手軽に試してみるには良さそうです。
インストール
さっそく自宅サーバとして稼働中の PRIMERGY TX1310 M1 で VAAPI を試してみました。
スペックは以下の通りです
CPU : Xeon E3-1246v3 (Haswell Refresh / Intel HD Graphics P4600)
RAM : 32GB (DDR3-1600 non-ECC)
Chipset : Intel C226
OS : CentOS 7.2
VAAPI / Intel ドライバ
CentOS で VAAPI を利用するためには libva
と libva-intel-driver
が必要です。
(Ubuntu では libva1
と i965-va-driver
がそれらしい?)
今回は該当パッケージが含まれている Simone Caronni さんのリポジトリ を利用します。
野良リポジトリの利用が気になる場合は VAAPI の公式 からソースをダウンロードしてビルドするのが良いでしょう。
まず epel
リポジトリを追加します。
ついでに yum-config-manager
を使うために yum-utils
も入れておきます。
$ sudo yum install epel-release yum-utils
Caronni さんの epel-handbrake
リポジトリを追加します。
$ sudo yum-config-manager --add-repo=http://negativo17.org/repos/epel-handbrake.repo
追加したリポジトリをデフォルトでは不使用にしておきます。
$ sudo yum-config-manager --disable epel epel-HandBrake
必要なパッケージをインストールします。
libva-devel
は後ほど ffmpeg のビルド時に必要となります。
libva-utils
に含まれる vainfo
は VAAPI の状況を確認するのに便利です。
$ sudo yum --enablerepo=epel,epel-HandBrake libva libva-devel libva-intel-driver libva-utils
VAAPI を使用できるように、自ユーザを video
グループに追加します。
( /etc/udev/rules.d/
に適当なルールを作成して /dev/dri/renderD128
のパーミッションを 666 等にしても良いと思います)
$ sudo usermod -aG video ユーザ名
ログインし直して id
コマンド等で video
グループに属していることを確認したら vainfo
コマンドで VAAPI が利用できることを確認します。
$ vainfo
error: can't connect to X server!
libva info: VA-API version 0.38.1
libva info: va_getDriverName() returns 0
libva info: Trying to open /usr/lib64/dri/i965_drv_video.so
libva info: Found init function __vaDriverInit_0_38
libva info: va_openDriver() returns 0
vainfo: VA-API version: 0.38 (libva 1.6.2)
vainfo: Driver version: Intel i965 driver for Intel(R) Haswell Server - 1.6.2
vainfo: Supported profile and entrypoints
VAProfileMPEG2Simple : VAEntrypointVLD
VAProfileMPEG2Simple : VAEntrypointEncSlice
VAProfileMPEG2Main : VAEntrypointVLD
VAProfileMPEG2Main : VAEntrypointEncSlice
VAProfileH264ConstrainedBaseline: VAEntrypointVLD
VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
VAProfileH264Main : VAEntrypointVLD
VAProfileH264Main : VAEntrypointEncSlice
VAProfileH264High : VAEntrypointVLD
VAProfileH264High : VAEntrypointEncSlice
VAProfileH264MultiviewHigh : VAEntrypointVLD
VAProfileH264MultiviewHigh : VAEntrypointEncSlice
VAProfileH264StereoHigh : VAEntrypointVLD
VAProfileH264StereoHigh : VAEntrypointEncSlice
VAProfileVC1Simple : VAEntrypointVLD
VAProfileVC1Main : VAEntrypointVLD
VAProfileVC1Advanced : VAEntrypointVLD
VAProfileNone : VAEntrypointVideoProc
VAProfileJPEGBaseline : VAEntrypointVLD
VAProfileH264MultiviewHigh : VAEntrypointVLD
VAProfileH264MultiviewHigh : VAEntrypointEncSlice
VAProfileH264StereoHigh : VAEntrypointVLD
VAProfileH264StereoHigh : VAEntrypointEncSlice
利用可能なプロファイル一覧が出てくれば成功です。
X を起動していないので X と接続できない旨のエラーが出ていますが特に問題ありません。
ここで VAEntrypointVLD
の項目はハードウェアデコード可能、VAEntrypointEncSlice
の項目はハードウェアエンコード可能です。
これで VAAPI を利用する準備が整いました。
FFmpeg
前項で利用した epel-HandBrake
リポジトリからも ffmpeg
は入手できるのですが、現時点でバージョンが 2.8.8 と少し古いため、以下の公式手順に従って最新版の FFmpeg をビルドします。
https://trac.ffmpeg.org/wiki/CompilationGuide/Centos
この手順ではホームディレクトリ以下に必要なライブラリを展開してビルドするので OS 環境に影響を与えません。
libva-devel
が正しくインストールされていれば自動的に VAAPI に対応した ffmpeg
がビルドされますが、念のため ffmpeg
の configure
を実行した際の出力の中で
-
External libraries providing hardware acceleration:
の項目にvaapi
が含まれていること -
Enabled hwaccels:
の項目にh264_vaapi
等の利用したいコーデックが含まれていること
を確認しておきましょう。
ビルドに成功したら改めて VAAPI への対応を確認します。
$ ~/bin/ffmpeg -hwaccels 2>/dev/null
Hardware acceleration methods:
vaapi
$ ~/bin/ffmpeg -encoders 2>/dev/null |fgrep vaapi
V..... h264_vaapi H.264/AVC (VAAPI) (codec h264)
V..... hevc_vaapi H.265/HEVC (VAAPI) (codec hevc)
V..... mjpeg_vaapi MJPEG (VAAPI) (codec mjpeg)
エンコード
それでは実際にエンコードしてみましょう。
今回はアニメ 1 話 30 分の TS ファイルをエンコードしてみます。
ffmpeg
実行時はオプションの順番にも気をつけましょう。
$ ~/bin/ffmpeg -vaapi_device /dev/dri/renderD128 \
> -hwaccel vaapi -hwaccel_output_format vaapi \
> -i anime.ts \
> -vf 'format=nv12|vaapi,hwupload,scale_vaapi=w=1280:h=720' \
> -c:v h264_vaapi -profile 100 -level 40 -qp 23 -aspect 16:9 \
> -c:a copy \
> anime.mp4
(略)
frame=53848 fps=343 q=-0.0 Lsize= 711827kB time=00:29:56.66 bitrate=3245.6kbits/s dup=24 drop=0 speed=11.4x
$
2分38秒でエンコードが完了しました!速いですね!
top
で確認すると ffmpeg
プロセスのCPU 使用率は終始 12% 程度でした。
オリジナル | エンコード後 | |
---|---|---|
長さ | 29:56 | 29:56 (ノーカット) |
ファイルサイズ | 2,030 MB | 695 MB |
解像度 | 1440x1080 | 1280x720 |
フレームレート | 29.97 (60i) | 29.97 (30p) |
映像コーデック | MPEG2 | H.264 |
音声コーデック | AAC | AAC (無変換) |
オプション
ffmpeg
で VAAPI を使用するときのオプションは以下のような感じです。
- -vaapi_device
- 使用する VAAPI デバイスを指定します。QSV 対応 CPU を利用する場合は
/dev/dri/renderD128
の模様。 - -hwaccel
- デコードに使用するハードウェア機能を指定します。今回はデコードも QSV を利用したため
vaapi
を指定しました。デコードをソフトウェアで行う場合はこのオプションは不要です。 - -hwaccel_output_format
-
-hwaccel
と一緒に使用し、ハードウェアデコード後の形式を指定します。デコードもエンコードも VAAPI で行う場合、ここでvaapi
を指定するとデコード結果が直接エンコーダに渡され、処理がより高速になります。ただしエンコードの前にffmpeg
のデインターレース等のソフトウェアフィルタを利用したい場合、デコード結果を一旦デコーダからffmepg
側に渡す必要があるのでyuv420p
等を指定します。 - -i
- 入力ファイルを指定します。ハードウェアデコードを使用する場合はこれより先に上記のオプションを記述しておきます。
- -vf
- フィルタを指定します。複数のフィルタは
,
で区切って記述します。VAAPI を利用する場合は基本的にformat=nv12|vaapi,hwupload
を指定しておけば大丈夫だと思います。今回はscale_vaapi
フィルタを加えてリサイズにもハードウェアを使用してみました。 - -c:v
- 映像コーデックを指定します。
h264_vaapi
を指定すると VAAPI を使用して H.264 のエンコードが行われます。 - -profile
- H.264 のプロファイルです。デフォルト値は 100 (High) です。Baseline は 66、Main は 77 を指定するようです。
- -level
- H.264 のレベルです。実際のレベルを 10 倍した値を指定します (Level 4.1 なら 41)。解像度・フレームレートや再生デバイスによって選択しましょう。デフォルト値は 51 (Level 5.1) です。今回は Level 4.0 としました。
- -qp
- P フレームの品質を指定します。1 (最良) ~ 51 (最悪) で設定します。デフォルトは 20 です。数値が小さいほど高品質・高ビットレートになり、大きいほど低品質・低ビットレートになります。
ffmpeg
で VAAPI を使用する場合、デフォルトではこの値を元にした CQP エンコードとなるようです。 - -b
- ビットレートを指定します。このオプションでビットレートが指定された場合
-qp
オプションは無視され、CBR エンコードとなるようです。今回は CQP でのエンコードを試したためこのオプションは指定しませんでした。 - -aspect
- 今回はエンコード前後で PAR が異なるため DAR を明示的に指定しています。
その他にもいくつか VAAPI 関連のオプションがありますが、詳細は以下が参考になります。
https://wiki.libav.org/Hardware/vaapi
https://gist.github.com/Brainiarc7/95c9338a737aa36d9bb2931bed379219
比較
-qp
オプションの値をいくつか変えてエンコードしてみました。
またソフトウェアエンコード (x264) とも比較してみました。
x264 で使用したオプションは以下です。
$ ~/bin/ffmpeg -i anime.ts \
> -codec:v libx264 -profile:v high -level 4.0 -preset medium -qp XX -s 1280x720 \
> -c:a copy \
> anime_x264_qpXX.mp4
x264 では qp は 0~69 だったため、((VAAPI の qp) * 69 / 51) を指定してみました。
ついでに x264 では qp よりも crf 指定の方が一般的と思われるため crf 23 も比較してみました。
オプションは上記の -qp XX
を -crf 23
に変えて実行しました。
No | 形式 | ファイルサイズ | エンコード時間 |
---|---|---|---|
0 | オリジナル | 2,030 MB | - |
1 | VAAPI / qp 20 | 1,027 MB | 2:39 |
2 | VAAPI / qp 23 | 695 MB | 2:38 |
3 | VAAPI / qp 26 | 501 MB | 2:38 |
4 | x264 / qp 27 | 321 MB | 7:21 |
5 | x264 / qp 31 | 219 MB | 6:52 |
6 | x264 / qp 35 | 161 MB | 6:18 |
7 | x264 / crf 23 | 349 MB | 8:22 |
結果は上記の通りです。
- 画質
- 1,4,7 ではブロックノイズが目立つこともなくまずまずの感じでした。2,5 になると動きのある部分で少しノイズが目につき出し、3,6 ではさらにノイズがのり一部で輪郭もぼやけています。また VAAPI では他の QSV 検証記事などでも書かれているように、グラデーション表現でノイズが出やすい気がしました。
- 速度
- VAAPI 使用時が速いです。さすがハードウェアエンコードというところですね。VAAPI では qp 値はエンコード速度にあまり影響しないようです。対して x264 では qp 値に比例して速度が上がっています。Xeon をぶん回したので x264 でもそれなりの速度が出ました。
- 負荷
- VAAPI では
ffmpeg
プロセスのCPU 使用率は 12% 程度でした。一方 x264 では 700% 前後とほぼフル稼働、ファンの回転数も上がって非エコな感じでした。自宅サーバはエンコード専用マシンではないのでエンコード時に高負荷になり他プロセスに影響が出るのは避けたいところです。 - 圧縮率
- こちらはさすが x264、VAAPI の 2 倍以上の圧縮率となっています。ディスクの節約が最優先の場合は x264 一択ですね。
これらを踏まえてどれを選択するかは完全に個人の感覚次第ですが、録画して見終わったら消すようなものであれば、画質・速度・負荷・圧縮率を考えると VAAPI / qp 23 でも十分ありかなと個人的には思います。
おわりに
ハードウェアエンコードは保存用途には向きませんが、見たら消す予定の ts ファイルを小さくしておき HDD を節約する用途としては有用ではないかと思います。
今回は 3.5GHz 4C/8T の Xeon を使用したため x264 と比べてそこまで大きな時間差はありませんでしたが、動作クロックの低い Pentium や Celeron の場合はさらに大きな差がつくでしょう。
現状 ffmpeg
から VAAPI を利用する場合、QSV のデインターレース・デノイズ・シャープネス等の機能は使えないようですが、gstreamer
の VAAPI プラグインではこれらも利用できるようなので VAAPI を極めたい方は gstreamer
も試してみると良いと思います。
また FFmpeg 3.1 では Raspberry Pi に載っている H.264 エンコーダにも対応したようなので、これも試してみたいところです。
今さらですが、動画についても FFmpeg についてもそれほど詳しいわけではないので間違いがあったらすみません…。
とはいえ少しでも参考になればうれしいです。
期待作が目白押しの秋アニメにむけて、万全の環境で臨みましょう!
脚注
-
LinuxでIntel QSVを使ったH.264ハードウェアエンコード(CentOS7+ffmpeg) | Kung Noi Blog (MSS 2015r6 使用例) ↩
-
クリスマスなのでLinuxでQSVエンコードする - 犬アイコンのみっきー (MSS 2015r6 使用例) ↩
-
Linux (CentOS 7.1) と FFmpeg 3.0.1 で QSV (Quick Sync Video) | hirooka.pro (MSS 2016 使用例) ↩
-
Linux (CentOS 7.2 1511) と FFmpeg で QSV (Quick Sync Video) | hirooka.pro (MSS 2017 使用例) ↩ ↩2
-
MSS 2017 は Broadwell/Skylake のみに対応 ↩
-
MSS 2017 では CentOS 7.2 が推奨されている ↩
-
Comparison of performance between SDK and only VAAPI based Application ↩