the glue

やってみたことで忘れそうなこと、役立ちそうなことなどをまとめています。たまに何気ない日常の話もします。

3.5万円のミニPCでハードウェアエンコードして6倍時間短縮した話

経緯

動画が沢山あるけどストレージの容量は限られてる!
H.265でエンコードしたかったわけですが、4コア8スレッドとかだと0.7倍速くらいでしかエンコードできない... これではいつまで経っても終わらない!!
ということで、ハードウェアエンコードしまくればいいじゃないか!と思い立ったわけです。

環境

PC

Lenovo M75q-1 tiny
CPU: Ryzen 5 PRO 3400GE 4C8T
RAM: 16GB DDR4
GPU: Radeon Vega 11
OS : Ubuntu 18.04.4 LTS Desktop

Lenovo M75q-1 tinyについて

今回の隠れたテーマはこの激安Ryzen搭載小型デスクトップです。
週末特価を狙うとおよそ3.5万円で NVMeのSSD, 8GB RAM, Ryzen 5 PRO 3400GEの小型デスクトップが手に入って最高なシロモノですね。
なんとWindows 10 Proも入っています。※ 今回は吹き飛ばしてOSはUbuntuを入れてます。

あまりに安くそこそこの性能でめちゃくちゃ静かなので、我が家ではテレビのそばに付けっぱなしで設置して、NAS, VPNサーバー, リモート開発サーバーなどとして使ってます。
多少手間はかかりますが、そのへんの激安NASキットよりも100倍いいです。(当社比です)   

Ryzen 5 PRO 3400GEは性能としてはまったくRyzen 5 3400GEと同じで、Ryzen 5 3400Gの35W版です。
RyzenシリーズのG付きモデルは所謂APUというやつで、内蔵グラフィックスとしてRadeon Vegaが載っているものになります。

このPCに付属するACアダプタが65Wなので問題なさそうなのですが、さすがにカツカツらしく、より大容量のACアダプタに交換すると主にGPU性能が爆アゲするらしいです(未確認)

ヤフオクで本物かわからない135WのACアダプタを買ったので、届いたら交換してレビューします。
Amazonで買うなら↓がよさそう。

本当はM75q-1 tinyのレビュー記事も書きたかったのですが、面倒なので↓を参考に。 little-beans.net

調査

ffmpegを利用したLinuxでのハードウェアエンコード事情

今回のキモは「Linuxでの」というところになります。
Windowsで使う場合は、Linux上でクロスコンパイルしたffmpegのバイナリをWindowsに持ってきて使ったりするらしいです。
参考: AMD VCE 対応の ffmpeg をつくる | ニコラボ

Linux上では、VA-API経由でのハードウェアエンコードにしか対応していないみたいなので、こいつを使います。
HWAccelIntro – FFmpeg

手順

1. ffmpeg 4系を入れる

ちょっと古いですが↓の資料をみると、VA-APIを使ったハードウェアエンコードffmpeg 4.0で大幅な最適化が入ったそうです。
今時のLinuxにおけるGPUエンコード事情2018

ところがUbuntu 18.04.4 LTSで標準で入るffmpegは本記事の執筆時点で 3.4.6 です。
そのため、まずは野良aptリポジトリを使って4系を入れます。

野良リポジトリ追加

sudo add-apt-repository ppa:savoury1/ffmpeg4
sudo add-apt-repository ppa:savoury1/graphics
sudo add-apt-repository ppa:savoury1/multimedia

sudo apt-get update

ffmpegインストール

sudo apt-get install ffmpeg
ffmpeg -version
$ ffmpeg -version
ffmpeg version 4.2.2-1ubuntu1~18.04.sav0 Copyright (c) 2000-2019 the FFmpeg developers
built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
configuration: --prefix=/usr --extra-version='1ubuntu1~18.04.sav0' --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
libavutil      56. 31.100 / 56. 31.100
libavcodec     58. 54.100 / 58. 54.100
libavformat    58. 29.100 / 58. 29.100
libavdevice    58.  8.100 / 58.  8.100
libavfilter     7. 57.100 /  7. 57.100
libavresample   4.  0.  0 /  4.  0.  0
libswscale      5.  5.100 /  5.  5.100
libswresample   3.  5.100 /  3.  5.100
libpostproc    55.  5.100 / 55.  5.100

無事 4.2.2 が入ったようです。

$ ffmpeg -h encoder=hevc_vaapi                                                                                                                                                                                      (0)[~]
ffmpeg version 4.2.2-1ubuntu1~18.04.sav0 Copyright (c) 2000-2019 the FFmpeg developers
  built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
  configuration: --prefix=/usr --extra-version='1ubuntu1~18.04.sav0' --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-nvenc --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
  libavutil      56. 31.100 / 56. 31.100
  libavcodec     58. 54.100 / 58. 54.100
  libavformat    58. 29.100 / 58. 29.100
  libavdevice    58.  8.100 / 58.  8.100
  libavfilter     7. 57.100 /  7. 57.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  5.100 /  5.  5.100
  libswresample   3.  5.100 /  3.  5.100
  libpostproc    55.  5.100 / 55.  5.100
Encoder hevc_vaapi [H.265/HEVC (VAAPI)]:
    General capabilities: delay hardware
    Threading capabilities: none
    Supported pixel formats: vaapi_vld
h265_vaapi AVOptions:
  -low_power         <boolean>    E..V..... Use low-power encoding mode (only available on some platforms; may not support all encoding features) (default false)
  -idr_interval      <int>        E..V..... Distance (in I-frames) between IDR frames (from 0 to INT_MAX) (default 0)
  -b_depth           <int>        E..V..... Maximum B-frame reference depth (from 1 to INT_MAX) (default 1)
  -rc_mode           <int>        E..V..... Set rate control mode (from 0 to 6) (default auto)
     auto                         E..V..... Choose mode automatically based on other parameters
     CQP                          E..V..... Constant-quality
     CBR                          E..V..... Constant-bitrate
     VBR                          E..V..... Variable-bitrate
     ICQ                          E..V..... Intelligent constant-quality
     QVBR                         E..V..... Quality-defined variable-bitrate
     AVBR                         E..V..... Average variable-bitrate
  -qp                <int>        E..V..... Constant QP (for P-frames; scaled by qfactor/qoffset for I/B) (from 0 to 52) (default 0)
  -aud               <boolean>    E..V..... Include AUD (default false)
  -profile           <int>        E..V..... Set profile (general_profile_idc) (from -99 to 255) (default -99)
     main                         E..V.....
     main10                       E..V.....
     rext                         E..V.....
  -tier              <int>        E..V..... Set tier (general_tier_flag) (from 0 to 1) (default main)
     main                         E..V.....
     high                         E..V.....
  -level             <int>        E..V..... Set level (general_level_idc) (from -99 to 255) (default -99)
     1                            E..V.....
     2                            E..V.....
     2.1                          E..V.....
     3                            E..V.....
     3.1                          E..V.....
     4                            E..V.....
     4.1                          E..V.....
     5                            E..V.....
     5.1                          E..V.....
     5.2                          E..V.....
     6                            E..V.....
     6.1                          E..V.....
     6.2                          E..V.....
  -sei               <flags>      E..V..... Set SEI to include (default hdr)
     hdr                          E..V..... Include HDR metadata for mastering display colour volume and content light level information

よくわからないけどどうやら使えそうです。()

2. VA-APIの準備

確認ツールのインストール

VA-APIの対応状況を確認しておくため、確認ツールを入れます。

sudo apt-get install vainfo
$ vainfo                                                                                                                                                                                                   (0)[~]
error: can't connect to X server!
libva info: VA-API version 1.7.0
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/radeonsi_drv_video.so
libva info: Found init function __vaDriverInit_1_1
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.7 (libva 2.1.0)
vainfo: Driver version: Mesa Gallium driver 19.2.8 for AMD RAVEN (DRM 3.33.0, 5.3.0-53-generic, LLVM 9.0.0)
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            : VAEntrypointVLD
      VAProfileMPEG2Main              : VAEntrypointVLD
      VAProfileVC1Simple              : VAEntrypointVLD
      VAProfileVC1Main                : VAEntrypointVLD
      VAProfileVC1Advanced            : VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointEncSlice
      VAProfileH264High               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointEncSlice
      VAProfileHEVCMain               : VAEntrypointVLD
      VAProfileHEVCMain               : VAEntrypointEncSlice
      VAProfileHEVCMain10             : VAEntrypointVLD
      VAProfileJPEGBaseline           : VAEntrypointVLD
      VAProfileVP9Profile0            : VAEntrypointVLD
      VAProfileVP9Profile2            : VAEntrypointVLD
      VAProfileNone                   : VAEntrypointVideoProc

リモートからつないでいるのでX serverにつながらん!といわれますが、 VAProfileHEVCMainVAEntrypointVLDVAEntrypointEnvcSlice があるので、対応していそうですね。 ドライバは /usr/lib/x86_64-linux-gnu/dri/radeonsi_drv_video.so となっていて、これはRadeonの標準ドライバだそうです。

利用するドライバを明示

今回はVGAバイスが一つしか無くてドライバが一つしかロードされていないので指定しなくても問題ない気がしますが、ねんのためVA-APIで利用するドライバを指定しておきます。

export LIBVA_DRIVER_NAME=radeonsi

3. エンコード実行

では実際にエンコードしていきましょう。テストとして今回はH.264の動画を、音声はそのままでH.265に変換してみます。

ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -i hoge.mp4 -vf 'format=p010|vaapi,hwupload' -c:v hevc_vaapi -qp 28 -c:a copy -tag:v hvc1 hoge_hw.mp4

詳しいオプションは説明しませんが、vaapiと書いてある部分のオプションが重要です。 動画の品質は -qp オプションで決定できます。 H.264の場合は以下のような感じです。

ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -i hoge.mp4 -vf 'format=nv12|vaapi,hwupload' -c:v h264_vaapi -qp 28 -c:a copy -tag:v hvc1 hoge_hw.mp4

4. 結論

実行したときの変換速度を比較してみます。

ソフトウェアエンコードの場合

$ ffmpeg -i hoge.mp4 -c:v libx265 -qp 28 -c:a copy -tag:v hvc1 hoge_hw.mp4

frame=  456 fps= 42 q=-0.0 size=    1280kB time=00:00:16.32 bitrate= 642.5kbits/s speed= 1.5x

ハードウェアエンコードの場合

$ ffmpeg -vaapi_device /dev/dri/renderD128 -hwaccel vaapi -hwaccel_output_format vaapi -i hoge.mp4 -vf 'format=p010|vaapi,hwupload' -c:v hevc_vaapi -qp 28 -c:a copy -tag:v hvc1 hoge_hw.mp4

frame= 1148 fps=228 q=-0.0 size=    6912kB time=00:00:39.33 bitrate=1439.4kbits/s speed=7.83x

およそ6倍くらいのスピードが出ていますね。すごい。
Ryzen 5のG付きはAPUなので、GPUもCPUも大体同じくらいの温度になるのですが、
ソフトウェアエンコードのときは80℃近く、ハードウェアエンコードのときは50℃前後で落ち着いていました。

まとめ

h.265の変換で、およそ6倍程度の変換速度の差が出ました。
ただし、実際の変換結果は載せませんが傾向としてソフトウェアエンコードのほうが画質がよく、 -qp でのクオリティ設定ではよりビットレートが低く、つまり容量が小さくなる傾向にあります。
容量をめちゃくちゃ重視するならソフトウェアエンコードでじっくり、現実的にはハードウェアエンコードで丁度いい画質設定を探してがっつりエンコードするのがよいのではないでしょうか。

参考

Ubuntu – bionic の ffmpeg パッケージに関する詳細
How to Install FFmpeg 4.2 in Ubuntu 18.04 / Linux Mint 19.x | UbuntuHandbook
www.sunmattu.net