UbuntuでのQSVエンコードは他の記事でも何度か扱ってきたので、繰り返しの部分も多いが復習も兼ねてまとめておく。まずドライバが2種類あり、Intel公式のIntel Media Server Studioのものを使うか、OSSのmedia-driverを使うか。前者はkernel patchの形を取るためkernelが限定されてしまう。後者はその必要はないが、エンコードの性能が倍くらい劣化する。どちらを取るかは人それぞれだが硬直的なシステムは歪みが歪みを招き続けるので、性能が劣化してでも後者を選択する。ドライバの構築方法は以下。
apt update
apt install -y autoconf automake cmake g++ libtool pkg-config libva-dev libdrm-dev libpciaccess-dev libx11-dev vainfo
vainfo
mkdir -p ~/vaapi
cd ~/vaapi
git clone https://github.com/01org/libva
cd libva
./autogen.sh --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu
make
make install
ldconfig
mkdir -p ~/vaapi/workspace
cd ~/vaapi/workspace
git clone https://github.com/intel/gmmlib
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE= Release -DARCH=64 ../gmmlib
make
cd ~/vaapi/workspace
git clone https://github.com/intel/media-driver
cd media-driver
git submodule init
git pull
mkdir -p ~/vaapi/workspace/build_media
cd ~/vaapi/workspace/build_media
cmake ../media-driver \
-DMEDIA_VERSION="2.0.0" \
-DBS_DIR_GMMLIB=$PWD/../gmmlib/Source/GmmLib/ \
-DBS_DIR_COMMON=$PWD/../gmmlib/Source/Common/ \
-DBS_DIR_INC=$PWD/../gmmlib/Source/inc/ \
-DBS_DIR_MEDIA=$PWD/../media-driver \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_INSTALL_LIBDIR=/usr/lib/x86_64-linux-gnu \
-DINSTALL_DRIVER_SYSCONF=OFF \
-DLIBVA_DRIVERS_PATH=/usr/lib/x86_64-linux-gnu/dri
make
make install
export LIBVA_DRIVER_NAME=iHD
echo LIBVA_DRIVER_NAME=iHD >> /etc/environment
vainfo
ちょっと長いですが頑張って下さい。vainfoでi965のドライバがiHDに切り替わっていれば成功。このドライバを使ってQSVエンコードを行うようにffmpegを作り直す。CentOSのときはIntel配布のrpmを利用してrpmbuildでパッケージごと作り変えられたんだけど、Ubuntuには関連パッケージが配布されておらず、debuildがうまくいかないので大人しくmakeする。手順は以下。
cd ~/vaapi
git clone https://github.com/Intel-Media-SDK/MediaSDK msdk
cd msdk
git submodule init
git pull
apt install -y libx11-xcb-dev libxcb-dri3-dev libxcb-present-dev
mkdir -p ~/vaapi/build_msdk
cd ~/vaapi/build_msdk
cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_WAYLAND=ON -DENABLE_X11_DRI3=ON -DENABLE_OPENCL=ON ../msdk
make
make install
echo '/opt/intel/mediasdk/lib' > /etc/ld.so.conf.d/imsdk.conf
ldconfig
apt install -y libfdk-aac-dev libvorbis-dev libvpx-dev libx264-dev libx265-dev ocl-icd-opencl-dev pkg-config yasm
cd /usr/local/src
git clone https://github.com/FFmpeg/FFmpeg
cd FFmpeg
PKG_CONFIG_PATH=/opt/intel/mediasdk/lib/pkgconfig ./configure \
--prefix=/usr/local/ffmpeg \
--extra-cflags="-I/opt/intel/mediasdk/include" \
--extra-ldflags="-L/opt/intel/mediasdk/lib" \
--extra-ldflags="-L/opt/intel/mediasdk/plugins" \
--enable-libmfx \
--enable-vaapi \
--enable-opencl \
--disable-debug \
--enable-libvorbis \
--enable-libvpx \
--enable-libdrm \
--enable-gpl \
--cpu=native \
--enable-libfdk-aac \
--enable-libx264 \
--enable-libx265 \
--extra-libs=-lpthread \
--enable-nonfree
make
make install
パッケージ版のffmpegと棲み分けるように /usr/local
にインストールしているので注意。ffmpeg -encoders
でh264_qsvやhevc_qsvが追加されていればOK。これで必要な作業が終わったように思いがちなんだけど、実はまだcomskipがある。comskipだけ構築し忘れていつまでもチャプターが入らなかったなんてのは録画サーバあるある。CentOSのときはこれもパッケージでインストール出来たんだけど、Ubuntuではソースからmakeする。ここまでくると手順は楽なもので以下。あとちょっと頑張って。
apt install -y libargtable2-dev libavutil-dev libavformat-dev libavcodec-dev libtool-bin
git clone git://github.com/erikkaashoek/Comskip /usr/local/src/Comskip
cd /usr/local/src/Comskip
./autogen.sh
./configure
make
make install
comskip.iniはネットに転がっているものを適当に書き換えて使っています。あとはこれらをEPGStationに組み込んで録画完了後に圧縮とCMチャプターが入るようにする。冒頭にも触れたが、media-driverのQSVは性能が悪く、よくて倍速程度しか出ないので、録画後に圧縮を始めると60分番組なら30分待つことになってしまう。だらだらと録画してる時間の方がアイドルしてて、録画後に内蔵GPUがフル回転というのもバランスが悪くて気に食わない。という訳で、録画開始直後からリアルタイムエンコーディングを行うように設定する。
方法は幾つかあるが、EPGStationには録画開始直後に実行するコマンドを『recordedStartCommand』としてconfig.jsonに指定できる。例えばそこに以下のようなコマンドが実行されるように追加する。
timeout $duration tail +0f "$src" | /usr/local/ffmpeg/bin/ffmpeg -y -nostdin -v error -dual_mono_mode $mode -hwaccel qsv -vcodec mpeg2_qsv -i pipe:0 -vcodec hevc_qsv -preset medium -tune film -vb 4M -vf deinterlace_qsv,scale_qsv=1280:720 -acodec copy -threads 0 "$enc" &
自分の場合はスクリプトを介して実行しているので、その中で上記のパラメータたちを適宜書き換えている。$durationには環境変数ENDATから現在時刻を引いた秒数を入れている。お気付きかもしれないが、この設計だと録画が終わる時間に強制的にエンコードを終了してしまうので、エンコードが追いついていない場合は途中で切れてしまうことになる。運用上ほとんど起きることはないが、何らかの事情で稀に起きてるようなので、TSファイルとmp4ファイルを比較して数分の差がある場合は破棄するようにしている。
録画後のencode処理もEPGStationのconfig.jsonでencode配列にh264やh265を用意して、そのcmdにコマンドを指定してやればよい。ここでも自作したスクリプトを指定して、mp4ファイルがあればcomskipのみ、なければ圧縮とcomskipを行うような構造にしている。これで今のところは問題なく動作している。scriptはやっつけで作ったもので、お見せするほどのものではないので、config.jsonのイメージだけ共有しておく。以下のような感じ。
vi EPGStation/config/config.json
:
"recorded": "/glusterfs/rec",
"recordedFormat": "%SHORTYEAR%%MONTH%%DAY%-%TITLE%",
"ffmpeg": "/usr/local/ffmpeg/bin/ffmpeg",
"ffprobe": "/usr/local/ffmpeg/bin/ffprobe",
"maxEncode": 4,
"encode": [
{
"name": "H265",
"cmd": "/usr/local/bin/enc.pl",
"suffix": ".mp4",
"default": true
},
{
"name": "H264",
"cmd": "/usr/local/bin/enc.pl -c h264",
"suffix": ".mp4"
},
{
"name": "H265-sub",
"cmd": "/usr/local/bin/enc.pl -m sub",
"suffix": "-sub.mp4"
},
{
"name": "H264-sub",
"cmd": "/usr/local/bin/enc.pl -c h264 -m sub",
"suffix": "-sub.mp4"
}
],
"recordedStartCommand": "/usr/local/bin/enc.pl -r",
"delts": true,
ubuntu 19.04 でエラーが発生した場合以下が参考になりそうだったのでメモしておきます
https://github.com/Intel-Media-SDK/MediaSDK/wiki/Build-and-use-ffmpeg-with-MediaSDK
情報提供ありがとうございます。
しばらくはLTS版を使うつもりですが、時が来たら参考にさせて頂きます。