Linux的ビデオのハードウェアエンコーディング
video
- TOP
- Old Archives
- Linux的ビデオのハードウェアエンコーディング
ネットで検索するとかなりいい加減な情報が溢れているので、 そこまで分かっているわけではないけれどまとめてみた。
「エンコード」
まずencodeとdecodeがわからない記事がいくつか出てくるのでそこから。
- データを映像/音声にするのがデコード
- 映像/音声をデータにするのがエンコード
エンコードは動画編集をしているのでなければ、基本的に動画変換のお話。
ハードウェア
ハードウェアでやる、というのはCPUに頼らず、ハードウェア側に搭載された専用のチップを使用してエンコーディングする話をしている。
これにより
- CPUにかかる負荷が低減できる
- 速度が向上する(かもしれない)
というメリットがある。
遅いGPUと速いCPUの組み合わせだと速度向上には必ずしもつながらないが。 だが、GPUは非常に速いので高速化する可能性は高い。
最近の盛り上がり
動画処理というか、変換というかではなくて、 「ゲームしながらゲームを録画するため」 だと思う。
ゲームはリソースをいっぱい近く使うので、録画するのは難しい。 処理落ちなどの原因になる。 そんなことがあったら多分ガチなゲーマーは許さない。
録画時はそのまま映像データを収録しているとあまりに巨大ファイルになる。 ゲームのプレイ時間は長い可能性が高いし、これはこれできつい。 というわけで、これをハードウェアにオフロードしてCPUや描画用グラフィックスに負担をかけることなく録画/変換して保存しようということだと思う。
ただ、IntelのQSVは恐らく趣旨が違う。 というのは、こちらは「CPUやメモリにも負担をかける」からだ。 VP9エンコードにもKaby Lakeにも対応していたりするので、もしかしたら動画編集を意識しているのかもしれない。
VA-APIとVDPAU
VA-APIはIntelが、VDPAUはNvidiaが作ったLinux用のハードウェアビデオアクセラレーション用のAPIだ。
それぞれサポートされているのだが、そのサポートに注意がいる。
libva-vdpau-driver
はVA-APIをラップしてVDPAUに投げるlibvdpau-va-gl
はVDPAUをラップしてVA-APIに投げる
このため
- NVIDIAはVA-APIは使えるけれど実際はVDPAUを使用する
- IntelはVDPAUは使えるけれど実際はVA-APIを使用する
ちなみに、AMDのオープンソースドライバ(ATIあるいはamdgpu)はVA-APIドライバとしてlibva-mesa-driver
(とmesa)と、libva-vdpau-driver
の2種類の方法がある。
前者であればVA-APIを直接取り扱う。後者であればVDPAUに流す。
そして、重要な点
- VDPAUはハードウェアデコード用
- VA-APIはハードウェアエンコード/デコード用
つまり
- NvidiaのカードはVA-APIをサポートしていないのでこの方法でのエンコードは無理
- AMDのカードは
libva-mesa-driver
を使わないとハードウェアエンコードできない
ハードウェア側機能
IntelにはQSV, NvidiaにはNVEnc, AMDにはVCEがある。
QSV (Quick Sync Video)
デコードだけじゃなかったんだぁ…と思ってしまったけれど、 実はIntelのビデオアクセラレーションは割とLinuxに手厚い。
QSVの利用はIntel Media Server Studioを要求されるけれども、色々と条件が厳しいし、フリーではない(無料ではあるけれど)。
性能的には劣るもののVA-APIから叩けるらしい。
VCE (Video Coding Engine)
デコード用のUVD(Unified Video Decoder)とセットのAMDの機能。
VA-API経由で叩ける。
NVEnc
Nvidiaのエンコード用ビデオアクセラレーション。 Pascal世代になってとっても速くなったらしい。
Maxwell Gen2でもHEVC 720p高画質で300fpsとか言っているのでGPUすごい。
QSVのほうが速いとか言っている人がいるけれども、多分そんな環境まずない。
画質が割と腐っているけれど、H265がH264とほぼ同じ速度で変換できるので、H265にすればだいぶよろしくなる。 H265エンコードはMaxwellからのサポート。
エンコーダと画質のお話
ハードウェアエンコードを行う場合、実際のデータ変換処理を行う「エンコーダ」としてハードウェアへのアダプタを指定する。
つまり、NVEncを使う場合、libx264の代わりにnvenc_h264を使うことになる。
なのでエンコーダオプション(-crf
とか)も変わる。
結果的に変換のされ方が変わる。 同一のクオリティを要求しても同じデータにはならない。
そして、ハードウェアエンコードを行った場合の画質、あまりよくない。
H.264でq=30
くらいまで落とすとものすごくわかりやすいことになる。
q=28
でも厳しい。
画質が悪いのだからできれば「保存したい」よりも「消すのはちょっと…」くらいのモチベーションの動画で使いたいところなのだが、 そういう動画こそサイズを小さくしたい。 ところが、ハードウェアエンコーダでサイズを小さくすると画質が目立って悪い。 だいぶ悩ましい話だ。
ffmpegでエンコード
Linuxの動画はffmpegで変換するものでしょう?
というわけで、QSVとVCEはVA-APIに対応しているのでVA-APIで。
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 -vf 'format=nv12,hwupload' -c:v h264_vaapi output.mp4
エンコードもハードウェアでやればより軽い。
ffmpeg -init_hw_device vaapi=foo:/dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device foo -i input.mp4 -filter_hw_device foo -vf 'format=nv12|vaapi,hwupload' -c:v h264_vaapi output.mp4
-q
オプションは指定できるみたい。
ffmpeg -init_hw_device vaapi=foo:/dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device foo -i input.mp4 -filter_hw_device foo -vf 'format=nv12|vaapi,hwupload' -c:v h264_vaapi -q 28 output.mp4
Nvidiaがひとり独自路線なのはちょっと気になるけれども、使いやすいのはnvencのほう。
ffmpeg -i input.mp4 -c:v nvenc_h264 -q 28 output.mp4
qの値など実際は探り探りやっていくしかない感じ。
あなたのビデオカード、眠ってませんか
GPUは基本的に積極的に働かせないと動かない子なので、 結構なリソースを眠らせている可能性は結構ある。
Linux環境だとCinnamonとKDE Plasmaがハードウェアアクセラレーションに対応しているため、 割と最近のIntel CPUやAMD APUを搭載しているコンピュータだとCPU的にはXFceやMATE、LXDEなんかよりよっぽど軽かったりもする。
そういうのがあればある程度は働いてくれるのだが、これもビデオカードの機能のごく一部を使っているだけ。 ちなみに、OpenGL用のアクセラレータを使っている。
この状態でもデコーダやエンコーダは遊んでいるので、せっかくのリソース活用してあげてください。
ハードウェアエンコーダの画質はちょっと微妙だけども。