VAAPIとDockerでDebianでもQSVを使ったh.264エンコードを行う
Debian上でChinachuを使った録画サーバを運用しているが(構築する記事は以前書いた)、これまでエンコードは普通にCPUでやっていて、そこそこ時間がかかっていた。
最近のIntel CPUに搭載されているハードウェアエンコーダであるところのQuick Sync Video (QSV) を使うとかなり速くなるというのは知っていたものの、Linux上ではIntel Media Server Studio (MSS) の導入が必要だと思いこんでいた。これが曲者で、CentOSじゃないとダメだったりカーネルにパッチ当てないといけなかったりでつらそうだし[1]で、ホストはできるだけきれいに保ちたかったので諦めていた。VM作って行おうにも、CPUがVT-dに対応していることが必要[2]で、Haswell世代のCore i3を使っているのでダメだった[3]。
ところが、最近Video Acceleration API (VAAPI) の存在を知った。これはMSSとは異なりオープンソースで開発されているハードウェアアクセラレーション用のAPIであり、カーネルにパッチを当てなくても利用することができる[1:1]。つまりDockerでコンテナに閉じ込めてきれいに使うことができるわけである。探してみると、既にVAAPI対応FFmpegを利用するためのDockerfileを作っている方がいらっしゃった(https://github.com/pocka/docker-ffmpeg-vaapi)。これを使わないわけにはいかない...!と思って早速利用してみた。
まず、ホストにドライバを入れる[4]。
$ sudo apt-get install i965-va-driver
/dev/dri
内のデバイスファイルを確認する。
$ ls -lh /dev/dri
total 0
crw-rw---- 1 root video 226, 0 Jan 23 21:00 card0
crw-rw---- 1 root video 226, 64 Jan 23 21:00 controlD64
このどっちかが当たりらしい。続くコマンドでデバイスファイルを指定する必要があるので全部試すとどれか動くものがあるはずで、動いたものが当たりだ(雑)。自分の環境ではcard0
だった。Webで調べた感じだと/dev/dri/renderD128
の人もいるみたい?
あとは、先にあげたリポジトリのREADMEにあるコマンドを参考にして以下のコマンドでサクッとエンコードができた。
docker run \
--device=/dev/dri/card0 \
-v /dev/dri:/dev/dri \
-v /data:/data \
pocka/ffmpeg-vaapi \
-vaapi_device /dev/dri/card0 \
-hwaccel vaapi \
-hwaccel_output_format vaapi \
-i /data/test-input.ts \
-vf 'format=nv12|vaapi,hwupload,scale_vaapi=w=1280:h=720' \
-level 41 \
-c:v h264_vaapi \
-aspect 16:9 \
-qp 23 \
-c:a copy \
-movflags faststart \
-vsync 1 \
/data/test-out.mp4
--device
と-vaapi_device
には上で調べたデバイスファイルのどれかを与える(動くものを探す)。
元のコマンドから書き換えた点として、--privileged
を外して--device {デバイスファイル}
とした。前者はホスト上の全デバイスへのアクセスへのアクセス権限をコンテナに与えるが、後者は特定のデバイスにのみ与えるのでより安全だ[5]。
はまったところとして、エンコードされたファイルをroot所有にしてほしくなかったので、--u 1000:1000
と一般ユーザのPIDを渡して一般ユーザ権限で動かそうとしたところ、コンテナ内でデバイスファイルのパーミッション(660)に引っかかって動作しなかった。デバイスファイルの所有者:グループはroot:video
になっているので、この場合、グループvideo
のGIDを調べて(ぼくの環境では44だった)--group-add 44
と同時に渡してあげると良い。
FFmpegのオプションは説明しきれないので適当に調べて欲しい。
以上で一応エンコードはできるのだが、何故かMacのQuickTimeで再生できなかった。Dockerfileに記述されているソフトウェアのバージョンを最新のものにしてビルドし直したイメージを使ってエンコードすることでこの問題は解決した。本家にプルリクエストは投げてあるが、マージされるまでは僕のリポジトリのDockerfileを使うと良いかもしれない(https://github.com/mecab/docker-ffmpeg-vaapi)。
以上、VAAPIとコンテナを使って、きれいに保ちたいDebianホストでもIntel QSVを利用して高速にエンコードする方法を説明した。エンコードの効率や品質はQSVを使わずにエンコードするのに比べてあまり良くないが、とにかく早いので満足している。地上波TSを1280x720に縮小、qp=25
, qmin=13
, qmax=31
で10倍速くらい出ている。便利な時代だ。
https://ja.wikipedia.org/wiki/Intel_Core_i3 (ところでこれ調べてて知ったんですが、Skylake以降だったらi3でもVT-d対応してるんですね...。) ↩︎
今回はIntel QSVについて書いたが、VAAPIに対応しているnVidiaとかAMDのGPUでも同じ感じでいけるはずで、i965-va-driverの代わりに適切なドライバをインストールすればいいと思う。または、va-driver-allを入れれば関連するドライバが全部入るはずだ。たぶん。 ↩︎