この記事は mstdn.maud .io Advent Calendar 2019の13日目の記事です。

昨日はGirAFFE Beerさんの2019年に作ったものなどでした。うなしマシュマロがかわいい。

前置き

こんにちは、おたかんだよ。アドベントカレンダー初参加です。よろしくおねがいします。

さて、Ubuntu18.04で録画サーバーを構築したで紹介した録画サーバーも、運用開始からそろそろ1年となります。1年間の運用の中で、録画失敗や動画ファイル破損などの問題が発生しましたが、現在ではそういった問題も解決し(少なくとも表面上は)正常に稼働しています。

1年経つと6TBのストレージも空き領域が1TBを切りそうになり、いい加減録画データの保存方法について真剣に考える必要が出てきました。実は考える前に8TBのHDDを用意してしまったのですが。

現状とか

今はm2tsファイルと、VA-API(Video Acceleration API)でH.264にエンコードしたmp4ファイルの両方を残す運用をしています。基本的にはエンコード済みファイルをEPGStationのWebUIで視聴し、録画データ破損などでエンコード時に音ズレが発生してしまった番組のみ、m2tsファイルをVLCで視聴しています。最近は録画データ破損も少なくなり、m2tsファイルで視聴することも減りました。

エンコード済みファイルのみを残して、m2tsファイルは録画から一定期間の後に自動削除する運用に切り替えることを考えましたが、できればエンコード後のファイルは少しでも綺麗かつ小さなファイルサイズで保存したいものです。

私の使用している録画サーバーは、KabyLake世代のCeleronが搭載されているFujitsu PRIMERGY TX1310 M3 Celeron G3930です。KabyLake世代のVA-APIエンコードはH.264以外にもH.265やVP8、VP9に対応しています。今回はVP9を使用したエンコードで、H.264と比較してどれだけ差が出るのか見てみることにしました。

環境確認とか

VA-APIを使用したときの対応コーデックについての情報は vainfoを実行すると確認できます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ vainfo
error: can't connect to X server!
libva info: VA-API version 1.4.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'iHD'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_4
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.4 (libva 2.1.0)
vainfo: Driver version: Intel iHD driver - 2.0.0
vainfo: Supported profile and entrypoints
VAProfileNone : VAEntrypointVideoProc
VAProfileNone : VAEntrypointStats
VAProfileMPEG2Simple : VAEntrypointVLD
VAProfileMPEG2Simple : VAEntrypointEncSlice
VAProfileMPEG2Main : VAEntrypointVLD
VAProfileMPEG2Main : VAEntrypointEncSlice
VAProfileH264Main : VAEntrypointVLD
VAProfileH264Main : VAEntrypointEncSlice
VAProfileH264Main : VAEntrypointFEI
VAProfileH264Main : VAEntrypointEncSliceLP
VAProfileH264High : VAEntrypointVLD
VAProfileH264High : VAEntrypointEncSlice
VAProfileH264High : VAEntrypointFEI
VAProfileH264High : VAEntrypointEncSliceLP
VAProfileVC1Simple : VAEntrypointVLD
VAProfileVC1Main : VAEntrypointVLD
VAProfileVC1Advanced : VAEntrypointVLD
VAProfileJPEGBaseline : VAEntrypointVLD
VAProfileJPEGBaseline : VAEntrypointEncPicture
VAProfileH264ConstrainedBaseline: VAEntrypointVLD
VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
VAProfileH264ConstrainedBaseline: VAEntrypointFEI
VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP
VAProfileVP8Version0_3 : VAEntrypointVLD
VAProfileVP8Version0_3 : VAEntrypointEncSlice
VAProfileHEVCMain : VAEntrypointVLD
VAProfileHEVCMain : VAEntrypointEncSlice
VAProfileHEVCMain : VAEntrypointFEI
VAProfileHEVCMain10 : VAEntrypointVLD
VAProfileHEVCMain10 : VAEntrypointEncSlice
VAProfileVP9Profile0 : VAEntrypointVLD
VAProfileVP9Profile2 : VAEntrypointVLD

VAEntrypointVLDがVA-APIでデコードできるコーディックを示し、VAEntrypointEncSliceがエンコードできるコーディックを示しています。

…見ての通りVP9にはVAEntrypointEncSliceがありません。理由はドライバーにありました。vainfo: Driver version: Intel iHD driver - 2.0.0と書かれている通り、今まではiHDドライバーを使っていましたが、ArchWikiを見るとiHDドライバー(intel-media-driver)でVP9のエンコードが可能なのはIceLake以降らしい。KabyLakeでVP9エンコードを使用するにはi965ドライバー(libva-intel-driver)が必要とのこと。品質はi965よりもiHDのほうが上らしいですが、対応していないのであればi965を使うしかありません。

使用するドライバーは環境変数で設定します。i965ドライバーは既に入っていたので、下記のように実行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
$ export LIBVA_DRIVER_NAME=i965
$ vainfo
error: can't connect to X server!
libva info: VA-API version 1.4.0
libva info: va_getDriverName() returns 0
libva info: User requested driver 'i965'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/i965_drv_video.so
libva info: Found init function __vaDriverInit_1_1
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.4 (libva 2.1.0)
vainfo: Driver version: Intel i965 driver for Intel(R) Kaby Lake - 2.1.0
vainfo: Supported profile and entrypoints
VAProfileMPEG2Simple : VAEntrypointVLD
VAProfileMPEG2Simple : VAEntrypointEncSlice
VAProfileMPEG2Main : VAEntrypointVLD
VAProfileMPEG2Main : VAEntrypointEncSlice
VAProfileH264ConstrainedBaseline: VAEntrypointVLD
VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
VAProfileH264ConstrainedBaseline: VAEntrypointEncSliceLP
VAProfileH264Main : VAEntrypointVLD
VAProfileH264Main : VAEntrypointEncSlice
VAProfileH264Main : VAEntrypointEncSliceLP
VAProfileH264High : VAEntrypointVLD
VAProfileH264High : VAEntrypointEncSlice
VAProfileH264High : VAEntrypointEncSliceLP
VAProfileH264MultiviewHigh : VAEntrypointVLD
VAProfileH264MultiviewHigh : VAEntrypointEncSlice
VAProfileH264StereoHigh : VAEntrypointVLD
VAProfileH264StereoHigh : VAEntrypointEncSlice
VAProfileVC1Simple : VAEntrypointVLD
VAProfileVC1Main : VAEntrypointVLD
VAProfileVC1Advanced : VAEntrypointVLD
VAProfileNone : VAEntrypointVideoProc
VAProfileJPEGBaseline : VAEntrypointVLD
VAProfileJPEGBaseline : VAEntrypointEncPicture
VAProfileVP8Version0_3 : VAEntrypointVLD
VAProfileVP8Version0_3 : VAEntrypointEncSlice
VAProfileHEVCMain : VAEntrypointVLD
VAProfileHEVCMain : VAEntrypointEncSlice
VAProfileHEVCMain10 : VAEntrypointVLD
VAProfileHEVCMain10 : VAEntrypointEncSlice
VAProfileVP9Profile0 : VAEntrypointVLD
VAProfileVP9Profile0 : VAEntrypointEncSlice
VAProfileVP9Profile2 : VAEntrypointVLD

ドライバーにi965が使われるようになり、VAProfileVP9Profile0 : VAEntrypointEncSliceが表示されるようになりましたね。

エンコード設定

ISDB向けFFmpegのisdb-4.2をビルドしてエンコードしました。音声のコーディックにはOpusを使用。FFmegのVA-APIを使用したVP9エンコードは、ソフトウェアエンコードと比べてエンコードオプションが少なく、あまり設定を詰めることができません。とりあえず以下のようにしました。

1
ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -sn -i input.ts  -vf 'format=nv12|vaapi,hwupload,deinterlace_vaapi,scale_vaapi=w=1920:h=1080' -c:v vp9_vaapi  -compression_level 0  -c:a libopus -b:a 128k -f webm outfile.webm
  • -vaapi_device /dev/dri/renderD128
    • VA-APIで使うデバイスの指定。私の環境では/dev/dri/renderD128だった
  • -hwaccel vaapi
    • VA-APIのハードウェアデコードを使用するように指定。
  • -hwaccel_output_format vaapi
    • HWエンコーダーに何を使用するかの指定。ここでvaapiを指定すると、HWデコーダーから直接ストリームが渡されるので早くなるらしい。
  • -sn
    • 字幕ストリームを無効化する。これが無いとエラーが発生してエンコードされないことがあったので。
  • -i input.ts
    • 入力ファイルの指定。
  • -vf
    • エンコーダーに渡すフィルタの指定
    • format=nv12|vaapi
      • よく分かっていません…。IntelのHWエンコーダーが受け付けてくれる色空間であるnv12に変換する?
    • hwupload
      • これもよく分かっていません。nv12に変換されたストリームを直接渡す(エンコーダーに?)
    • deinterlace_vaapi
      • VA-APIでインターレス解除をする設定
    • scale_vaapi=w=1920:h=1080
      • 解像度を1920*1080にスケーリングする設定
  • -c:v vp9_vaapi
    • コーディックにvp9_vaapiを指定する設定。
  • -compression_level 0
    • 圧縮の品質指定。値が0に近いほど時間が掛かるが、圧縮率は高くなる。数MB程度しか変わらなかったので、外してもいい設定かもしれない。ちなみに値の幅は0-1らしいです。
  • -c:a libopus -b:a 128k
    • 音声コーディックにlibopusを使い、ビットレートを128kbpsにする設定。
  • -f webm
    • ファイルの出力形式の設定。Webmを選びました。
  • outfile.webm
    • 出力フアイル名の指定。

ちなみにH.264のときは以下のような設定にしていました。

1
ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -sn -i input.ts  -vf 'format=nv12|vaapi,hwupload,deinterlace_vaapi,scale_vaapi=w=1920:h=1080'  -c:v h264_vaapi -qp 20 -c:a aac -b:a 192k -r:a 48000 -ac 2 -f mp4 outfile.mp4

知識が乏しいので、ガバ設定になっていそう。

エンコードしてみる

動画について詳しくないので、ファイルサイズとエンコード時間、主観的な画質についてのみ確認することにしました。

ファイルサイズ

番組名 m2ts H.264 VP9
SAO War of Underworld #8
[BS 11]
4GB 1.7GB 988.8MB
PSYCHO-PASS 3 #1
[東海テレビ]
6.4GB 2.3GB 1.4GB
ガキ使トレジャーハンター24時
[中京テレビ]
41.8GB 35.1GB 18GB

エンコードにかかった時間

番組名 録画時間 H.264 VP9
SAO War of Underworld #8
[BS 11]
30分2秒 12分55秒 13分35秒
PSYCHO-PASS 3 #1
[東海テレビ]
1時間3秒 21分32秒 23分47秒
ガキ使トレジャーハンター24時
[中京テレビ]
6時間3秒 2時間11分58秒 2時間26分29秒

普段録画することの多い30分番組と1時間番組、特番で放送時間の長い番組の3つで調べてみました。

H.264と比べて、ファイルサイズが半分以下になることはありませんでしたが、4割くらい減らすことができました。もとのm2tsファイルからは1/4になったと考えると、かなり小さくなっているのではないでしょうか。ガキ使だけはH.264にエンコしてもm2tsと比較して半分以下になりませんでしたが、VP9にすると他の番組と同様に1/4程度になりました。

VP9へのエンコードにかかった時間はH.264と比べて多少長くなりましたが、それでも録画時間の半分以下ですし、気にするレベルのことではないでしょう。-compression_level 0の値を変えたときにどれだけ早くなるのか気になりますが、時間がなかったのでしっかり検証できていません…。SAO WoU #8で値を1にしてみた限りでは数十秒の差だったので、誤差の範囲内でしょう。(値の取れる範囲は0-1です)

画質についてですが、正直違いがわかりません…。なんてこった、何も書けやしない。これだけファイルサイズが減ったのに、見た目の違いが分からないのはいいことなのですが。動画のビットレートを調節して、画質の違いがわからないギリギリのラインを探そうかと思いましたが、これも時間がなかったのでパスしました…

あとがき

たとえCPUがCeleronでも、VA-APIを使えばVP9へのエンコードが実用レベルの速度になるのは有り難いことです。H.265/HEVCと違ってVP9に対応しているブラウザは多いため、視聴時の使い勝手の面でも良さそうです。これだけの圧縮率をもつコーディックが、ロイヤリティーフリーになっているのはいいですね。

VP9の後続であるAOMedia Video 1(AV1)も登場して移行が進み始めていますし、AV1がエンコード/デコード共に低負荷になるのが楽しみです。

以上 mstdn.maud .io Advent Calendar 2019 13日目の記事でした。

明日はぴけぴけさんです。