ARMBIANでffmpegをビルドする

 ffmpegソースコードに手を加えて実験してみたい事があったので、自前でビルドすることにしました。
 普段使っているWindowsマシンでビルド環境を整えるのは面倒な感じがしたので、シングルボードコンピュータ*1のOrangePiで運用中のARMBIAN(ARMBIAN 5.38 stable Ubuntu 16.04.4 LTS 3.4.113-sun8i)でffmpegをソースからビルドしてみました。

 ffmpegの公式サイトにビルド手順は掲載されており、基本的にはその通り実行するだけですが、いくつか嵌ったので備忘のために記載します。
 

公式のビルド手順

 以下のURLにLinux(Ubuntu, Debian, Mint)用のビルド手順が掲載されています。
CompilationGuide/Ubuntu – FFmpeg

 ARMBIANもUbuntuなのでこの手順に従ってビルドすれば問題ないはずだ!ということで、作業を進めます。
 ※以下にはトライアンドエラーの過程も記載しているため、同様の環境でビルドしたい方は私が試行錯誤した部分まで再現する必要はありません。
 

作業手順

依存パッケージを導入

 まずは公式のビルド手順通り、依存するパッケージを導入します。
 なお、私がOrangePiで運用しているARMBIANはGUIのないServer版なので、 不要なlibsdl2-dev, libva-dev, libvdpau-dev, libxcb1-dev, libxcb-shm0-dev, libxcb-xfixes0-devを除外して、以下のコマンドを叩きます。

sudo apt-get update -qq && sudo apt-get -y install \
  autoconf \
  automake \
  build-essential \
  cmake \
  git \
  libass-dev \
  libfreetype6-dev \
  libtool \
  libvorbis-dev \
  pkg-config \
  texinfo \
  wget \
  zlib1g-dev

 これは特に問題無く完了するはずです。
 

ディレクトリ作成

 ソースコードとビルド後のバイナリを格納するディレクトリを作成します。
 それぞれ任意のパスおよび名称で問題無いと思いますが、ここでは公式のビルド手順の記載通り作業しています。

mkdir -p ~/ffmpeg_sources ~/bin

 

NASMをインストール

 公式のビルド手順に記載のコマンドと同様ですが、OrangePiはQuad-coreなのでmakeのオプションにj4を指定して4スレッドで実行してmakeの高速化を図っています。

cd ~/ffmpeg_sources && \
wget https://www.nasm.us/pub/nasm/releasebuilds/2.13.03/nasm-2.13.03.tar.bz2 && \
tar xjvf nasm-2.13.03.tar.bz2 && \
cd nasm-2.13.03 && \
./autogen.sh && \
PATH="$HOME/bin:$PATH" ./configure --prefix="$HOME/ffmpeg_build" --bindir="$HOME/bin" && \
make -j4 && \
make install

 これも特に問題無く完了するはずです。
 

Yasmをインストール

 公式のビルド手順にはYasmのversion 1.2.0以降がリポジトリから取得できるならそれを使えばよい、そうでなければソースを取得して自前でコンパイルすべしと記載されています。
 とりあえず、無邪気にリポジトリからYasmをインストールしてみます。

sudo apt-get install yasm

 すると、コンソールには以下の出力が含まれていることが確認できます。

Preparing to unpack .../yasm_1.3.0-2_armhf.deb ...
Unpacking yasm (1.3.0-2) ...
Setting up yasm (1.3.0-2) ...

 1.3.0-2なのでバージョン要件は満たしてますのでYasmのインストールはこれで完了です。
 

libx264をインストール

 公式のビルド手順にはlibx264-devのversion 118以降がリポジトリから取得できるならそれを使えばよい、そうでなければソースを取得して自前でコンパイルすべしと記載されています。
 Yasm同様に、とりあえずリポジトリからインストールしてみます。

sudo apt-get install libx264-dev

 すると、コンソールには以下の出力が含まれていることが確認できます。

Preparing to unpack .../libx264-dev_2%3a0.148.2643+git5c65704-1_armhf.deb ...
Unpacking libx264-dev:armhf (2:0.148.2643+git5c65704-1) ...
Setting up libx264-dev:armhf (2:0.148.2643+git5c65704-1) ...

 2:0.148.2643+git5c65704-1のどこがバージョン番号なのかよく判りません…とりあえず148と見做すことにして、バージョン要件は満たしてるものとして先へ進めます(適当)。
 

libx265をインストール

 公式のビルド手順にはlibx265-devのversion 68以降がリポジトリから取得できるならそれを使えばよい、そうでなければソースを取得して自前でコンパイルすべしと記載されています。
 同様に、とりあえずリポジトリからインストールしてみます。

sudo apt-get install libx265-dev

 すると、コンソールには以下の出力が含まれていることが確認できます。

Preparing to unpack .../libx265-dev_1.9-3_armhf.deb ...
Unpacking libx265-dev:armhf (1.9-3) ...
Setting up libx265-dev:armhf (1.9-3) ...

 1.9-3という表記なので68以降なのかどうか判りません。OrangePiでH.265のエンコード・デコードをする予定も無いので、ffmpegのビルド時の障害になればlibx265のサポートを外せばいいかと考え、とりあえず先に進めます(相変わらず適当)。
 

libvpxをインストール

 公式のビルド手順にはlibvpx-devのversion 1.4.0以降がリポジトリから取得できるならそれを使えばよい、そうでなければソースを取得して自前でコンパイルすべしと記載されています。
 同様に、とりあえずリポジトリからインストールしてみます。

sudo apt-get install libvpx-dev

 すると、コンソールには以下の出力が含まれていることが確認できます。

Preparing to unpack .../libvpx-dev_1.5.0-2ubuntu1_armhf.deb ...
Unpacking libvpx-dev:armhf (1.5.0-2ubuntu1) ...
Setting up libvpx-dev:armhf (1.5.0-2ubuntu1) ...

 1.5.0なのでバージョン要件は満たしてますのでlibvpxのインストールはこれで完了です。
 

libfdk-aacをインストール

 ※あまり説明をよく読まずに作業を進めたため、ここでlibfdk-aac-devをインストールしましたが、後続のffmpegのビルド時にenable-nonfreeオプションを指定したくなかったため、結果的には使用していません。

 公式のビルド手順ではlibfdk-aac-devがリポジトリから取得できればそれを使えばよい、そうでなければソースを取得して自前でコンパイルすべしと記載されています。
 同様に、とりあえずリポジトリからインストールしてみます。

sudo apt-get install libfdk-aac-dev

 すると、コンソールにはlibfdk-aac0パッケージも必要だから追加でインストールしていいか確認を求められるのでYを押します。最終的に、コンソールには以下の出力が含まれていることが確認できます。
>|txt|
Preparing to unpack .../libfdk-aac0_0.1.3+20140816-2_armhf.deb ...
Unpacking libfdk-aac0:armhf (0.1.3+20140816-2) ...
Preparing to unpack .../libfdk-aac-dev_0.1.3+20140816-2_armhf.deb ...
Unpacking libfdk-aac-dev:armhf (0.1.3+20140816-2) ...
Setting up libfdk-aac0:armhf (0.1.3+20140816-2) ...
Setting up libfdk-aac-dev:armhf (0.1.3+20140816-2) ...
|

 libfdk-aacについてはバージョン要件が特に示されていないので、特に確認することも無くlibfdk-aacのインストールは完了です。
 ※前述の通り、enable-nonfreeオプションを指定しないでffmpegをビルドする場合には不要です。
 

libmp3lameをインストール

 公式のビルド手順にはlibvpx-devのversion 3.98.3以降がリポジトリから取得できるならそれを使えばよい、そうでなければソースを取得して自前でコンパイルすべしと記載されています。
 同様に、とりあえずリポジトリからインストールしてみます。

sudo apt-get install libmp3lame-dev

 すると、コンソールには以下の出力が含まれていることが確認できます。

Preparing to unpack .../libmp3lame-dev_3.99.5+repack1-9build1_armhf.deb ...
Unpacking libmp3lame-dev:armhf (3.99.5+repack1-9build1) ...
Setting up libmp3lame-dev:armhf (3.99.5+repack1-9build1) ...

 3.99.5なのでバージョン要件は満たしてますのでlibmp3lameのインストールはこれで完了です。
 

libopusをインストール

 公式のビルド手順にはlibopus-devのversion 1.1以降がリポジトリから取得できるならそれを使えばよい、そうでなければソースを取得して自前でコンパイルすべしと記載されています。
 同様に、とりあえずリポジトリからインストールしてみます。

sudo apt-get install libopus-dev

 すると、コンソールには以下の出力が含まれていることが確認できます。

Preparing to unpack .../libopus-dev_1.1.2-1ubuntu1_armhf.deb ...
Unpacking libopus-dev:armhf (1.1.2-1ubuntu1) ...
Setting up libopus-dev:armhf (1.1.2-1ubuntu1) ...

 1.1.2-1なのでバージョン要件は満たしてますのでlibopusのインストールはこれで完了です。
 

libaomをインストール

 aomって何だと思ったら、GoogleのVP8/VP9後継のVP10がキャンセルされて、その他各社も合流してロイヤリティーフリーなコーデックとして開発されているAV1のライブラリのようです。Alliance for Open Mediaの略でAOMみたいですね。

 公式のビルド手順に記載のコマンドと同様ですが、NASMのインストール時と同様に、makeのオプションにj4を指定して4スレッドで実行してmakeの高速化を図っています。

cd ~/ffmpeg_sources && \
git -C aom pull 2> /dev/null || git clone --depth 1 https://aomedia.googlesource.com/aom && \
mkdir aom_build && \
cd aom_build && \
PATH="$HOME/bin:$PATH" cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$HOME/ffmpeg_build" -DENABLE_SHARED=off -DENABLE_NASM=on ../aom && \
PATH="$HOME/bin:$PATH" make -j4 && \
make install

 これを実行すると、コンソールには以下のエラーメッセージが表示されました。cmakeでエラーが起きたようです。

-- Configuring incomplete, errors occurred!
See also "/home/user/ffmpeg_sources/aom_build/CMakeFiles/CMakeOutput.log".
See also "/home/user/ffmpeg_sources/aom_build/CMakeFiles/CMakeError.log".
<<
 CMakeError.logを確認すると、以下のエラーが出力されていました。
>|txt|
/usr/bin/ld: cannot find -lpthreads

 OrangePi内を探してみると、libpthread.so.0なら/lib/arm-linux-gnueabihf/にあるので、とりあえず環境変数LD_LIBRARY_PATHを追記します。

LD_LIBRARY_PATH=/lib/arm-linux-gnueabihf:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH

 libpthreadが見えてることを確認します。

$ ldconfig -p | grep pthread
        libpthread.so.0 (libc6,hard-float, OS ABI: Linux 3.2.0) => /lib/arm-linux-gnueabihf/libpthread.so.0

 エラーが発生したcmakeを単独で再実行してみます。

PATH="$HOME/bin:$PATH" cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$HOME/ffmpeg_build" -DENABLE_SHARED=off -DENABLE_NASM=on ../aom

 すると、再度エラーが発生します。コンソール出力をよく確認すると、以下の出力がされています。

--- aom_configure: Detected CPU: armv7l
CMake Error at build/cmake/aom_configure.cmake:125 (message):
  No RTCD support for armv7l.  Create it, or add -DAOM_TARGET_CPU=generic to
  your cmake command line for a generic build of libaom and tools.
Call Stack (most recent call first):
  CMakeLists.txt:75 (include)

 「armv7lアーキテクチャではRTCDサポートしてないんで、(自前で?)RTCDを創るか、cmakeに-DAOM_TARGET_CPU=genericオプションを指定しなよ!」的な内容です。
 ここで言うRTCDが何を指しているのか正直なところ判っていませんが、それを調べるよりcmakeにオプション指定すればいいのだろうという判断で、以下のコマンドを実行します。

PATH="$HOME/bin:$PATH" cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$HOME/ffmpeg_build" -DENABLE_SHARED=off -DAOM_TARGET_CPU=generic -DENABLE_NASM=on ../aom

 今度は無事にcmakeはエラーメッセージを吐かずに完了しました。戻り値も0ですので、引き続きmakeします。

PATH="$HOME/bin:$PATH" make -j4

 すると、以下のようなエラーメッセージがコンソール出力に吐かれます。

[ 24%] Building C object CMakeFiles/aom_av1_encoder.dir/av1/encoder/av1_quantize.c.o
/home/user/ffmpeg_sources/aom/av1/decoder/obu.c: In function ‘read_sequence_header_obu’:
/home/user/ffmpeg_sources/aom/av1/decoder/obu.c:188:37: error: ‘AV1_COMMON {aka struct AV1Common}’ has no member named ‘enhancement_layers_cnt’
       operating_point >= pbi->common.enhancement_layers_cnt)
                                     ^
CMakeFiles/aom_av1_decoder.dir/build.make:206: recipe for target 'CMakeFiles/aom_av1_decoder.dir/av1/decoder/obu.c.o' failed
make[2]: *** [CMakeFiles/aom_av1_decoder.dir/av1/decoder/obu.c.o] Error 1
CMakeFiles/Makefile2:2127: recipe for target 'CMakeFiles/aom_av1_decoder.dir/all' failed
make[1]: *** [CMakeFiles/aom_av1_decoder.dir/all] Error 2

 enhancement_layers_cntなんか無いと言われても、gitから取得したコードそのもので自分で何か変更したコードじゃないし…。
 もしかしてmakeを4スレッドで実行したから、依存関係のあるリソースが処理される前に参照しちゃって怒られてるのか?
 と、妄想しmakeを-j4オプション未指定で実行してみました。

make clean
PATH="$HOME/bin:$PATH" make

 すると、先ほどと同内容のエラーが吐かれました。makeのマルチスレッド指定オプションのせいではないことは確定しました。

[  6%] Building C object CMakeFiles/aom_av1_decoder.dir/av1/decoder/obu.c.o
/home/user/ffmpeg_sources/aom/av1/decoder/obu.c: In function ‘read_sequence_header_obu’:
/home/user/ffmpeg_sources/aom/av1/decoder/obu.c:188:37: error: ‘AV1_COMMON {aka struct AV1Common}’ has no member named ‘enhancement_layers_cnt’
       operating_point >= pbi->common.enhancement_layers_cnt)
                                     ^
CMakeFiles/aom_av1_decoder.dir/build.make:206: recipe for target 'CMakeFiles/aom_av1_decoder.dir/av1/decoder/obu.c.o' failed
make[2]: *** [CMakeFiles/aom_av1_decoder.dir/av1/decoder/obu.c.o] Error 1
CMakeFiles/Makefile2:2127: recipe for target 'CMakeFiles/aom_av1_decoder.dir/all' failed
make[1]: *** [CMakeFiles/aom_av1_decoder.dir/all] Error 2

 仕方ないので真面目にソースを調べることにします。
 エラーが発生しているobu.cの当該行のpbiはdecoder.hに定義された構造体AV1Decoderで、そのメンバのcommonはonyxc_int.hに定義された構造体AV1Commonのようです。
 で、onyxc_int.hのAV1Commonを確認すると、確かにenhancement_layers_cntというメンバはありません。
 え?コンパイル通らないソースがチェックインされてる???
 Google gitのコミット履歴を追うと、以下のcommitで不整合が発生したようです。
d2f317c33564da8b4b54a98dfa6726e572dd6d66 - aom - Git at Google
 このcommitではonyxc_int.hもobu.cも(その他のリソースも)変更されておりenhancement_layers_cntはnumber_spatial_layersに変わって、名前だけではなくロジックも変わっているようです。
 が、エラー発生行は何故か修正されておらず、そんなメンバは無いと怒られているというのが本エラーの原因のように見えます。
 と言うわけで、このcommitの前の断面のリソースであればこのエラーは発生せず、ビルドできるはずです。
 これまでに実行したgit -cloneで取得したリソース群を削除し、改めてこのcommit前の断面のソースコードを配置し、ビルドします。

# 腐ってる最新断面のソースコードを消去
cd ~/ffmpeg_sources/aom
rm -rf ./*
# 腐る前の断面のソースコードを取得・展開する
wget https://aomedia.googlesource.com/aom/+archive/ea67540a1a3799e136dbdfa4dd140f7091e7cbf0.tar.gz
tar xvf ea67540a1a3799e136dbdfa4dd140f7091e7cbf0.tar.gz
# 腐ってる最新断面の中途半端なビルドディレクトリを消去
cd ../aom_build
rm -rf ./*
# cmake
PATH="$HOME/bin:$PATH" cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$HOME/ffmpeg_build" -DENABLE_SHARED=off -DAOM_TARGET_CPU=generic -DENABLE_NASM=on ../aom
# make
PATH="$HOME/bin:$PATH" make -j4
make install

 これで、やっと正常にlibaomをインストールできました!
 ※このGoogle gitの最新断面が腐っていたのは私が実行した時(2018/5/15)の話です。一般論として腐ったリソースのせいでビルドが通らないなんて状態は、早急に正常なリソースがコミットされるか旧リソースに戻されるかしてさっさと解消されるはずです。
 

ffmpegのビルド

 やっとffmpeg本体です。
 公式のビルド手順通りですが、nable-nonfreeオプションだけ外しています。

cd ~/ffmpeg_sources && \
wget -O ffmpeg-snapshot.tar.bz2 https://ffmpeg.org/releases/ffmpeg-snapshot.tar.bz2 && \
tar xjvf ffmpeg-snapshot.tar.bz2 && \
cd ffmpeg && \
PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/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" \
  --bindir="$HOME/bin" \
  --enable-gpl \
  --enable-libaom \
  --enable-libass \
  --enable-libfdk-aac \
  --enable-libfreetype \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvorbis \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265 && \
PATH="$HOME/bin:$PATH" make -j4 && \
make install && \
hash -r

 これを実行すると、以下のエラーメッセージが表示されます。

libfdk_aac is incompatible with the gpl and --enable-nonfree is not specified.

 libfdk_aacの項にも記載しましたが、libfdk_aacを使うならenable-nonfreeを指定しないといけないわけです(そうすると、GPLではないライセンスのffmpegが出来上がります。)。
 それは嫌なので、libfdk_aacも外した以下のコマンドを叩きます。

PATH="$HOME/bin:$PATH" PKG_CONFIG_PATH="$HOME/ffmpeg_build/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" \
  --bindir="$HOME/bin" \
  --enable-gpl \
  --enable-libaom \
  --enable-libass \
  --enable-libfreetype \
  --enable-libmp3lame \
  --enable-libopus \
  --enable-libvorbis \
  --enable-libvpx \
  --enable-libx264 \
  --enable-libx265

 今度はエラーは表示されず、GPLv2以降のライセンスが適用される旨の表示が出力メッセージ内に現れます。

License: GPL version 2 or later

 後は、makeが通れば完了です。

PATH="$HOME/bin:$PATH" make -j4 && \
make install && \
hash -r	

 ひたすら重く、時間が掛かりますのでしばらく放置した後、特にエラーメッセージが表示されていないこと*2を確認して終了です!

 なお、こうして自前でビルドしたffmpegのバイナリは、~/binに配置されています(元々導入されていたffmpegのバイナリは/usr/binにあるので上書きされないので安心)。
 .profile等の設定次第ですが、PATH指定で~/binが/usr/binより前にあればパス指定せずに単にffmpegを実行すると自前ビルド版のffmpegが実行されます。それが嫌な場合は、~/bin以外の場所にバイナリを移動するか、ffmpegではない名称(ffmpeg_dev等)にリネームしてしまえば意図せず自前ビルド版のffmpegを実行してしまうことは防げます。
 

備考

 上記手順で作成した自前ビルド版のffmpegH.264の高解像度な動画をエンコードしようとするとkillされる現象が発生しています。
 OrangePiのメモリが足りてないのか、ソースコードに問題があってメモリリークでもしてるのか、ビルド手順中で問題無しと判断した何かが問題なのか、等々、調査できていません*3*4
 とりあえず低解像度にリスケールすればエンコードできる感じなので、私のやりたい実験用途では使えなくは無さそうなので、あんまり調査するつもりも無いのですが。。。
 また、解像度に依らずエンコード中のコンソール出力の進捗状況表示の数値がしばらく表示されないという現象も発生しており、安定して使える感じでは無さそうです。
 自前ビルド版でないffmpegならOrangePiでも概ね安定して使えているのですけどね。
 



以上。

*1:所謂Raspberry Piみたいなもの。

*2:deprecated系のwarningメッセージなどが大量に出力されますがとりあえず問題ありません。

*3:loglevelをdebugに指定しても、killされるまでに特異な出力は見当たらない。

*4:コアダンプが吐かれているわけでもないのでどう調べようかというのもあります。