エンコード

[VAAPI/ffmpeg] 2021年版 Linux録画環境構築 その3 [Chinachu/EPGStation]

投稿日:

前回構築した Chinachu/EPGStation においてハードウェアエンコードをやりたくなったので、
まずはハードウェアエンコードについて煮詰める。
Chinachu, EPGStation それぞれへの適用は次の記事の予定。


 

環境

OS は Ubuntu Server 20.04 LTS。
CPU は Intel Pentium Gold G5420 (CoffeeLake-R)。
GPU は 内蔵GPU のみ、グラフィックカードは搭載していない。

ハードウェアエンコードとしては、 VAAPI, QSV, NVENC, VCE などがあるが、
それぞれオープンソース, Intel, NVIDIA, AMD に対応。
今回のマシンは discrete なグラフィックカードが無いので、NVENC, VCE は対象外。
Intel の内蔵GPU(iGPU) を用いるなら、VAAPI か QSV かということになるが、
今回は比較的導入が容易な VAAPI を利用することにする。
例えば Ubuntu の場合、公式レポジトリにある ffmpeg には、
VAAPI は組み込まれているが、QSV は含まれていないので、
QSV を使いたい場合は、QSV対応 ffmpeg を自分でビルドするか、カスタムレポジトリを追加する必要がある。

エンコードは ffmpeg で行うことにする。

Google Adsense

VAAPI を使う方法

詳細は以下を参照のこと。
https://wiki.archlinux.jp/index.php/ハードウェアビデオアクセラレーション

  • intel-media-va-driver(-non-free):
    負荷, 処理速度, 圧縮率いずれも下記 i965 よりも基本的に優れる。
    ハードウェアサポート状況, 後述するソフトフィルタとの併用に難あり。
    (i965 と比較して) iHD と呼ばれる。 基本的にこちらの利用を推奨。
  • i965-va-driver:
    仕様に従順でソフトフィルタ類との併用も可能, ハードウェアが早い(古い)世代から対応などメリットもあるが、
    基本性能は上記 iHD に劣る印象。

これらを導入, 選択/指定して、ffmpeg から扱うのが容易で一般的と思われる。
 

セットアップ

この辺は distribution やその ver に強く依存すると思われる。
Ubuntu と Debian でも異なるし、Ubuntu 18.04 と 20.04 でも異なる。
繰り返しになるが私の環境は Ubuntu Server 20.04 である。

セットアップ後は、環境変数 LIBVA_DRIVER_NAME で使用するドライバ名を指定する。
- iHD (推奨): 負荷, 処理速度, 圧縮率いずれも下記 i965 よりも基本的に優れる
- i965: 仕様に従順, ハードウェアサポート状況などが iHD より優れるが、基本性能は iHD に劣る印象
 

Ubuntu 20.04 の場合

前述の通り、ffmpeg に vaapi 関連は含まれているが、
それを使える環境が最初から整っている訳ではないので、環境を用意する。

レポジトリで multiverse を有効化する。
apt などから i965-va-driver, intel-media-va-driver-non-free, vainfo などは全て導入可能。

LIBVA_DRIVER_NAME を指定した上で、vainfo を実行すると、
i965/iHD のいずれか、ハードウェア, コーデック, encode/decode の対応状況などが確認できる。
これは以下についても同様。

Google Adsense

Debian 10 (EPGStationコンテナのベース) の場合

 

Ubuntu 18.04 で外部レポジトリを認める場合

標準のレポジトリの ffmpeg は v3.4系とかなり古く、h264_vaapi 周りのオプションが異なるため、
vaapi に対応した v4系を導入する。

削除する場合

http://ubuntuhandbook.org/index.php/2019/08/install-ffmpeg-4-2-ubuntu-18-04/
 

codec に寄らない共通部

codec に寄らない共通部は以下のようになる。

以下で ffmpeg の個別のオプションについて説明する。
説明は私の解釈によるものであり、正確性・厳密性を保証するものではありません。

Google Adsense

-hwaccel vaapi

ハードウェア "デコード" の設定。デコードに vaapi を用いる。
-hwaccels で利用可能なオプション一覧が表示される。
(ほか cuda, qsv, opencl, vdpau など)
 

-hwaccel_output_format vaapi

デコード後(エンコード前)の 出力形式の指定。
vaapi を指定するとデコード後は、ハード形式でハード上のメモリに保持される。

(ソフトの) ビデオフィルタを通したい場合は yuv420p を指定する。
この後さらにハードウェア・エンコードに回したい場合は、
ソフトでの処理を終えた後 (-vf) format=nv12,hwupload でハード上に転送する(後述)。
 

-vaapi_device /dev/dri/renderD128

vaapi に用いるデバイスファイルの指定。
他に /dev/dri/card0 の場合もあるらしい。
各自の環境で /dev/dri 以下のデバイスファイルを確認すること。
intel の内蔵GPUのみなら、/dev/dri/renderD128 であることが多いのかな?

またこれらのデバイスファイルの権限にも注意が必要。
私の環境では、これらはパーミッション: 660 で、
所有者が root, グループがそれぞれ render, video になっている。
必要に応じて、これらのグループにユーザーを追加するなどする。
 

-vf deintelace_vaapi,scale_vaapi=h=720:w=-2

ビデオフィルタの指定。
*_vaapi となっているものはハードウェア処理される。
-filters | grep vaapi などで他のオプションが調べられる。

Google Adsense

scale_vaapi は 720p などにスケールする場合に使用。
地上波などでは、1440x1080(4:3) を 16:9 に伸長して 1920x1080 にしている。
h=720:w=-2 とすることで、入力が 1920x1080(16:9) でも 1440x1080(4:3) でも、
元の比率を活かして 1280x720(16:9), 960x720(4:3, 再生時は 1280x720) のように等倍に圧縮できる。

ts などを圧縮する際に、解像度は変えず 1080p を維持したい場合は、scale_vaapi フィルタは外すこと。
deintarace_vaapi の出力が 1080p で、例えその後何もする必要がなくても、
scale_vaapi を指定すると、回路を通るようで処理が遅くなるし、処理も結構重いようだ。
(chinachu は出力解像度に寄らずこのフィルタを通すようなスクリプトになっている。)

例えば以下のような綺麗で重めのソフトによるスケールと比較しても、
手元では scale_vaapi を用いる下段のほうが遅かった。
(ここではいずれもビデオフィルタ前は yuv420p形式, この後ハードウェアエンコード・レディな状態。)

 

-vf format=nv12|vaapi,hwupload,... の指定について

"ffmpeg vaapi" でググると、このような記述が山のように出てくる。
これは良く言うと色々な入力, 状況に対応しやすいオールマイティーな書き方、
悪く言うとハードウェアデコードできない状態でも、とりあえず動いて気づかせない書き方です。

このフィルタを書き下すと、ハードウェアデコードできて vaapi 形式の場合はそのまま、
ハードデコードができずソフトデコードした場合は、nv12 に整形して (i)GPU にアップロードという意味です。

今回の私の目的は tsファイルのハードウェアエンコードなので、
このような冗長な書き方は不要で、-hwaccel_output_format vaapi から *_vaapi 系フィルタに直結でOKです。

この "定型句" を単なるおまじないではなく、
正しく理解するとソフトフィルタとハードエンコードの併用が可能です。
 

ソフトウェアフィルタとの併用について

上で「ソフトフィルタとハードエンコードの併用が可能」と書きましたが、
それはあくまでも技術的には可能であるという意味です。
データを (i)GPU と メモリ間で往復させる操作はそれだけでオーバーヘッドが大きく、
さらに(ハードウェアと比べて)格段に遅いCPUのソフト処理が入ることにより、
ハードウェアエンコードの唯一と言っていいメリット:処理速度が損なわれるため、私見としてはお勧めしません。
# 画質を上げるなどキレイにしたい場合は、ソフトウェアエンコードのほうに歩があります。

実際、iHD を用いた場合にこのような使い方を想定していないのか、或いはあまりテストされていないのか、
-hwaccel_output_format yuv420p-vf hwdownlaod,format=yuv420p などメモリに戻す操作は正しく動かない。
(i965 では期待通りに動く)

Google Adsense

codec 毎の設定

ffmpeg の codecsdドキュメントを参照。
大きく3種類に分類できる。

  • libavcodec の標準オプション(の一部)
  • vaapi に共通のオプション
  • codec_vaapi 毎の独自オプション

とは言っても、上記2つであっても、vaapiコーデックによって、
無視されたり挙動がおかしかったり様々のようだ。
あまり実用的でまとまったドキュメントや記録が見つからなかったため、
それなりに色々試して下記の形に落ち着いているが、まだ煮詰めきれていない印象。
その vaapi_コーデックによる違いなどを考慮した設定を以下に紹介する。

本当は -rc_mode で ICQ(Intelligent constant-quality, 4?) を指定して使いたいのだが、
どのコーデックで、他にどんなオプションと合わせて設定すればまともに動くのか、どなたかご存知ないだろうか。。。

以下の説明は私の解釈によるものであり、正確性・厳密性を保証するものではありません。
 

h264_vaapi

1行目:コーデックとクォリティの指定。-crf ではなく、-qp での指定が必要。

2行目:-g 300 は x264 の keyint のことだいう理解。30fps で10秒毎ということで 300 を指定。
-idr_interval はIフレーム間に準Iフレームがいくつか入るかの指定?
入れるドライバのバージョンによってはサポートしていないかも。
(EPGStation 用 docker内では指定できなかった)
-bf は最大連続Bフレーム数。

フレームのサイズは I >> P >> B のようになっていて、
基本はそれぞれ直前の上位のフレームからの差分のような形で表現されている。
つまり基本的にはIフレームを減らしてBフレームを増やせるようにすると圧縮率は稼ぎやすい。

Google Adsense


3行目:-i/b_qfactor は x264(encopts) でいう ip_factor, pb_factor に相当すると思われる。
x264 ではそれぞれ 1.4, 1.3 を指定していたので流用。 0.7143 は 1.4 の逆数。
-qmin/qmax は x264 の qp_min, qp_max 相当としてそれぞれ 10, 51 を指定。
# 今回は qp 指定での quality-base のエンコードなので、実は効いていないのかもしれないが。

4行目:音声圧縮の指定、AAC 128kbps。

5行目:h264+aac な mp4 の出力指定。
 

hevc_vaapi (H265)

ハードウェアレベルではまだ実装が追い込めていないのか、
h265 のハードエンコードは h264 と比べてあまりメリットがない(世代に依ってはむしろ劣る) という結果が、
各所でのレビューなどで散見するようである。

圧縮率を上げていくと、黒系の塗りつぶしがチラついたり、
グラデーションが潰れたりするが、そんな場合に10bit化は効果的であるというのは以前経験している。
この h265_vaapi は、hevc による高圧縮率そのものよりも、
"VAProfileHEVCMain10" としてサポートしている 10bit エンコードを目的として試してみた。
ffmpeg に渡すオプションの後半は以下。

1行目:hevc_vaapi に関しては format: p010 で渡す必要があるらしい。
2行目:コーデックの指定。プロファイルは Main10(2) を指定。
3−5行目は共通。

format と profile (10bit化を狙う場合) だけ意識すれば他はほとんどそのまま使いまわせるようだ。
 

H265 はブラウザ視聴に難アリ

さて hevc_vaapi の設定をある程度追い込んで、EPGStation に実装してみたところ、
エンコードは通ってファイルが出力されるも、ブラウザからは再生されない。
調べてみた所 IE11, 旧Edge(+拡張機能), Safari11+ ではサポートされているが、
Chrome(含 新Edge), Firefox ではサポートされていないようだ。
どうも特許の関連から H265 ではなく VP9, 最近では AV1 で進めたいという思惑もあり、
各種ブラウザの H265 サポート状態は芳しくないようである。
録画サーバー自体が Linux な私の環境を考えると、Chinachu, EPGStation には不向きなようだ。

それならばと試したのが、次の VP9 である。

Google Adsense

vp9_vaapi

hevc_vaapi を試した当初の動機(10bitエンコード) を忘れて挑んだ vp9_vaapi。
一応 h264 よりも圧縮率が高く、かつブラウザによるサポートも進んでいるという大義名分はある。
しかし、先に断っておくようにあまり強いメリットはない。

  • 基本的に i965のみ, iHD は IceLake以降のみ対応(予定?)
  • 10bit エンコードも今のところ非対応
  • 個人による導入例が圧倒的に少ないようで、検索しても熟れた記事が全く引っかからない
    (ドキュメント記載の仕様の抜けなど、実用上の解が得られにくい)
  • Quality-base において、ある程度以上の圧縮率で全く縮まない(が、画質はボロボロ)など挙動がおかしい(後述)

一応、試した中でマシだった設定は以下。
(ただしあまり圧縮率は上げられない)

1行目:コーデックの指定。-global_quality で qualityベースの指定ができる (0-255)。
数字を大きくするほど画質が落ちて圧縮率が上がるが、
ある程度以上あげると、画質だけ落ちるもののファイルサイズは変わらなくなる謎挙動。
-gp などは反映されないが、-b:v 1.5M などとしてビットレートベースの指定は可能。
ビットレートを指定した時は、quality で指定した時より圧縮率を上げることができるようだ。

2−3行目は共通。

4行目:VP9 でBフレームを用いると、順番がひっくり返ることがあるので(?)、
正しい順序になるようにタイムスタンプを付ける?という感じで、
正しく出力するためのおまじないらしいが、あまり詰めて検討していない。

5, 6行目:VP9 は音声: Opus と共に WebM コンテナに詰める仕様であるようだ。
 

あれこれやってみた感想

h264_vaapi, h265_vaapi, vp9_vaapi について CoffeeLake-R 上で i965/iHD を用いて試した感想としては、
VP9+10bit を試せる「IceLake以降 + iHD」環境以外では h264_vaapi を用いるのが良さそうである。
ということで、Chinachu/EPGStation でのハードウェアエンコードは h264_vaapi を用いることにする。

次回は Chinachu, EPGStation でのハードウェアエンコードについてです。
 

Google Adsense

Google Adsense

-エンコード
-, , , ,

Copyright© P-Life, 2022 All Rights Reserved.