皆さん、FFmpegコンパイルしてますか?
誰しも人生のうち一度はFFmpegをコンパイルしたいと思う時があると思います。
今回、ついに私もパッケージマネージャのバイナリでは不満な事例がでてきてしまい、さらに先日FFmpeg 5.0がリリースされましたので、いい機会と思いコンパイルしてみようと思った次第です。
想定環境
CPUはCeleron J4105(Gemini Lake)、OSはUbuntu Server 20.04 LTS。
Gemini LakeはIntel Atom系列のブランドの一つです。超低価格ノートにありがちなCeleron N4000がまさにこれとか、iGPUだけでいうとKaby Lakeなどと一緒の世代とか、でなんとなく分るでしょうか。
そしてUbuntuは20.04 LTSです。22.04 LTSはあと2か月あります。
……なんでこんなことわざわざ書いてるのかは後述。
目標
動画ファイルのエンコードをしたい、けど画質よりも変換スピードを重視したい。使用するCPUが高速とは言えない。
そのために、想定環境において(主要な映像コーデックの)ハードウェアアクセラレーションでのデコードおよびエンコード対応のffmpegがほしい。
ffmpeg本体のコンパイル以外はなるべく楽をしたいのでインストールできるパッケージがあればそちらで済ませる。
ヘッドレスサーバで動作させるのでX11関連のパッケージをなるべくインストールしたくない。
ドキュメントを読む
ffmpegのコンパイル方法などインターネット上に数え切れないほどありますが、基本的には公式方面からドキュメントを集めていきます。
https://www.ffmpeg.org/documentation.html
他を読んでどうしても分からないときは結局ここ
HWAccelIntro – FFmpeg
ffmpegで使えるハードウェアアクセラレーションの確認。一応目を通す
CompilationGuide/Ubuntu – FFmpeg
Ubuntu等における一般的なffmpegコンパイルのガイド。3回読む
Hardware/QuickSync – FFmpeg
Intel CPUの世代とそれぞれで対応する映像コーデックのリスト、QSV対応バイナリのコンパイルオプションおよび実際のffmpegのコマンド例。3回読む
GitHub - intel/media-driver
Intel Media Driver(iHD driver)のビルド方法はREADMEに全部書いてある
Build FFmpeg QSV · Intel-Media-SDK/MediaSDK Wiki · GitHub
Intel Media SDK(MSDK)(libmfx)のドキュメント内にもffmpegのコンパイル方法が書いてある。ふたつ上のとすこしかぶるけど
以上より
あたりが肝、というのが分かります。
それでは、主にCompilationGuide/Ubuntuを見つつ始めていきます。
FFmpeg依存パッケージのインストールとか下準備とか
コンパイルに必須のパッケージ。ただし、ガイドにあるようにffplayが必要ない場合それらの依存パッケージはインストールしなくてよいのと、Ubuntu 20.04に限り追加でlibunistring-devがインストールが必要のようですね。
sudo apt install \ autoconf \ automake \ build-essential \ cmake \ git-core \ libass-dev \ libfreetype6-dev \ libgnutls28-dev \ libmp3lame-dev \ libtool \ libvorbis-dev \ pkg-config \ texinfo \ wget \ yasm \ zlib1g-dev \ libunistring-dev
sudo apt install \ nasm \ libx264-dev \ libx265-dev \ libnuma-dev \ libvpx-dev \ libfdk-aac-dev \ libopus-dev
上記のガイドではH.265やVP9、AV1など新しめの映像フォーマットにも対応するようにパッケージのインストールをしています。今回の主目的とずれるこれらの(ソフトウェア)コーデックは必要性は無いのですが、まあまあ汎用的に使えるバイナリを作ったほうがいいだろうという思いでほぼガイド通りにインストールします。
ただしAV1およびVMAF(これはコーデックではなく映像の定量的な評価システム)に関しては今回は除外しました。現代のハイパワーなCPUならともかくGemini Lakeには荷が重すぎると判断したためです。とはいえH.265とかOpusとかいつ使うかな......
mkdir -p ~/ffmpeg_sources ~/bin
ffmpegのコンパイル済ファイルを置くディレクトリを用意します。
echo -e "/usr/local/lib\n/opt/intel/mediasdk/lib" | sudo tee -a /etc/ld.so.conf.d/locallib.conf sudo ldconfig -v
この後自分でビルドした諸々がインストールされる場所をライブラリ検索パスに追加します。後ででもいいかも。
Intel Media Driver(iHD driver)
自分でビルドします。
ドキュメントにはUbuntu19.04以降ならaptでインストールできると書いてあるのですが罠です。
Ubuntu20.04でaptでインストールできるMedia Driverのパッケージを使ってビルドしたFFmpegはGemini Lakeでだけ使用できないという問題があるのです。
[Issue] KO hardware decode/encode with Gemini lake family · Issue #930 · intel/media-driver · GitHub
このissueが建てられたのは2020年5月で後にちゃんと修正されていますが、Ubuntu 20.04のaptでインストールできるバージョンは今も相変わらず2020Q1。
Ubuntu 22.04リリース後とか、Gemini Lake以外のCPUを使ってるとか、そういう場合はわざわざビルドする必要は無いと思われます......
sudo apt install \ libdrm-dev \ libgl1-mesa-glx \ libgl1-mesa-dev
media-driverの依存パッケージ、ただしX11関連のパッケージはインストールしません
libva
media-driverのREADMEに従ってビルドします。
cd ~/ wget https://github.com/intel/libva/archive/refs/tags/2.13.0.tar.gz tar xzvf 2.13.0.tar.gz cd libva-2.13.0/ ./autogen.sh make -j"$(nproc)" sudo make install
gmmlib
同じくビルドします
cd ~/ wget https://github.com/intel/gmmlib/archive/refs/tags/intel-gmmlib-22.0.2.tar.gz tar xzvf intel-gmmlib-22.0.2.tar.gz cd gmmlib-intel-gmmlib-22.0.2 mkdir build cd build cmake -DCMAKE_BUILD_TYPE=Release -DARCH=64 .. make -j"$(nproc)" sudo make install
Media Driver
cd ~/ wget https://github.com/intel/media-driver/archive/refs/tags/intel-media-22.1.1.tar.gz tar xzvf intel-media-22.1.1.tar.gz mkdir build_media cd build_media cmake ../media-driver-intel-media-22.1.1 make -j"$(nproc)" sudo make install
Media SDK(libmfx)
既に依存関係にあるパッケージのインストールやlibvaのビルドは終わってるので、ドキュメント前半をすっ飛ばしていきなりビルドできます。
cd ~/ wget https://github.com/Intel-Media-SDK/MediaSDK/archive/refs/tags/intel-mediasdk-22.1.0.tar.gz tar xzvf intel-mediasdk-22.1.0.tar.gz cd MediaSDK-intel-mediasdk-22.1.0 mkdir build && cd build cmake .. make -j"$(nproc)" sudo make install
FFmpeg
さてメインディッシュです。
AV1関連オプションを外し、libmfxを有効、パッケージコンフィグパスをmsdkがインストールされている場所に指定しなおしています。
cd ~/ffmpeg_sources wget https://www.ffmpeg.org/releases/ffmpeg-5.0.tar.gz tar xzvf ffmpeg-5.0.tar.gz cd ffmpeg-5.0 PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="/opt/intel/mediasdk/lib/pkgconfig" ./configure \ --prefix="$HOME/ffmpeg_build" \ --pkg-config-flags="--static" \ --extra-cflags="-I$HOME/ffmpeg_build/include" \ --extra-ldflags="-L$HOME/ffmpeg_build/lib" \ --extra-libs="-lpthread -lm" \ --ld="g++" \ --bindir="$HOME/bin" \ --disable-ffplay \ --enable-gpl \ --enable-gnutls \ --enable-libass \ --enable-libfdk-aac \ --enable-libfreetype \ --enable-libmp3lame \ --enable-libopus \ --enable-libvorbis \ --enable-libvpx \ --enable-libx264 \ --enable-libx265 \ --enable-nonfree \ --enable-libmfx PATH="$HOME/bin:$PATH" make -j$(nproc) make install hash -r
これで、~/binにffmpegが生えてるはずです。
エンコードテスト
Big Buck Bunnyを変換してみましょう。
Big Buck Bunny
なお素の状態だとパーミッションで怒られるので、sudoなしでエンコードしたい場合は
sudo gpasswd -a $USER render
ユーザーをrenderグループに追加して再起動、あたりが楽でしょうか? udevをいじる方法もありますが。
以下の2つのコマンドを試してみます。
ffmpeg -hwaccel qsv -c:v h264_qsv -i bbb_sunflower_1080p_30fps_normal.mp4 -vf 'scale_qsv=1280:720' -c:v h264_qsv -look_ahead 1 -global_quality:v 36 -c:a aac -b:a 128k -ac 2 output.mp4
画質とサイズのバランスをとって720p。
ffmpeg -hwaccel qsv -c:v h264_qsv -i bbb_sunflower_1080p_30fps_normal.mp4 -vf 'scale_qsv=720:480' -aspect 16:9 -c:v h264_qsv -look_ahead 1 -global_quality:v 44 -c:a libfdk_aac -b:a 48k -ac 2 -profile:a aac_he_v2 output.mp4
小さな画面サイズでの再生を想定してギリギリまでビットレートを落として480p。
global_qualityで画質の調整をしています。数値を小さくするほど画質が良くなる代わりにビットレートは高くなります。
私の場合は720pでglobal_qualityを36、480pで44という数値にしてみました。ついでに480pでは音声のビットレートも馬鹿にならないくらい映像のビットレートが落ちているので、HE-AAC V2の48kbps、つまりradikoと同じコーデック・ビットレートにしてみました。
見てわかる通り、画質を犠牲にかなりファイルサイズを抑えています。
以上のそれぞれのコマンドでの実行結果は以下の通り。