OpenH264+FFmpeg+OpenCV4をソースビルドしてH.264を使う

# はじめに

FFmpegは、H.264・MotionJPEGなど様々な動画圧縮規格の映像を変換・再生してくれるのみならず、WebカメラをRTSP（Read Time Streaming Protocol）で制御して映像を配信・受信できる大変便利なソフトウェアです。もしFFmpegがなければ、映像をエンコード・デコードする処理や、カメラと通信する処理を自分で作らなければならず、広い範囲の専門知識も必要になります。

一方で、本家が配布しているFFmpegのモジュールはGPLライセンスのため、自作ソフトウェアに組み込んで使う場合はGPL汚染が発生する問題があります。

https://www.wdic.org/w/TECH/GPL%E6%B1%9A%E6%9F%93


この問題は、FFmpegをGPLライセンスなライブラリを取り除いてビルドすることで解決できます。具体的には、FFmpegのビルド時に`--disable-gpl`オプションをつけることでGPLのライブラリを含めずビルドしてくれます。この場合、FFmpegがLGPLライセンスになります。ただし、H.264のデコードをしてくれるGPLのライブラリx264がビルドからはずれるため、FFmpegでH.264のエンコード・デコードできなくなってしまいます。

そこで、GPLでないH.264を扱える有名なライブラリとしてCisco社が提供しているOpenH264がありますので、これを使います。

https://github.com/cisco/openh264

まとめると、

- H.264のエンコーダ・デコーダとしてOpenH264を使う
- OpenH264を組み込んだLGPLなFFmpegをビルドする

となり、今回はその手順をまとめます。ついでに、FFmpegをOpenCVのVideoCaptureでも使いたいので、OpenCVのビルド手順も示します。

# （補足）H.264のライセンス使用料について

H.264の技術には様々な特許が含まれており、使用にあたってはパテントプールであるMPEG LAにライセンス使用料を支払わなければなりません。

https://www.mpegla.com/programs/avc-h-264/faq/

しかし、ありがたいことにCiscoが配布しているOpenH264のバイナリはライセンス使用料を払ってくれているので、このバイナリを使用するに限ってはライセンス使用料を個人で支払う必要がなくなります。

https://www.openh264.org/

ただし、「Ciscoが配布しているバイナリに限って」というところが重要で、自前でソースビルドした場合は個人でライセンス使用料を支払う必要があるので注意が必要です。以下の手順ではOpneH264のビルド手順も載せていますが、ライセンス使用料の支払いを回避したい場合はビルドせず、OpenH264のGitHubからバイナリを入手してください。

https://github.com/cisco/openh264/releases/tag/v2.3.1

## バージョン

- Ubuntu 20.04
- OpenCV 3.4.9 / 4.6.0
- FFmpeg 4.3.5
- Python 3.8.10
- gcc 9.4.0
- cmake 3.16.3

# 手順

## 関連パッケージのインストール
```sh
sudo apt install gcc g++ make cmake git nasm python3-venv libpython3.8-dev
```

## OpenH264のビルドインストール

:::note warn
Ciscoが公開しているバイナリを使用する場合はこの手順は不要です。入手したバイナリを`/usr/local/lib`などビルド時に認識できる場所に保存しておきます。
:::

```sh
cd ~
git clone -b v2.3.1 https://github.com/cisco/openh264
cd openh264
make -j4
sudo make install
ls /usr/local/lib
# libopenh264.a  libopenh264.so  libopenh264.so.2.3.1  libopenh264.so.7  pkgconfig  python3.8
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
ls ${PKG_CONFIG_PATH}
# openh264.pc
```

## FFmpegビルドインストール
```sh
cd ~
git clone -b n4.3.5 https://github.com/FFmpeg/FFmpeg ffmpeg-n4.3.5
cd ffmpeg-n4.3.5
./configure \
    --enable-libopenh264 \
    --enable-optimizations \
    --enable-static \
    --enable-version3 \
    --enable-shared \
    --disable-gpl \
    --disable-logging \
    --disable-doc \
    --disable-htmlpages \
    --disable-manpages \
    --disable-podpages \
    --disable-txtpages \
    --disable-avdevice \
    --disable-postproc \
    --disable-bzlib \
    --disable-iconv \
    --disable-cuda \
    --disable-cuvid \
    --disable-debug \
    --extra-ldflags="-static-libgcc -static-libstdc++"
make -j4
sudo make install
sudo ldconfig
ffmpeg -version
# ffmpeg version n4.3.5 Copyright (c) 2000-2022 the FFmpeg developers
# built with gcc 9 (Ubuntu 9.4.0-1ubuntu1~20.04.1)
# （略）
ls ${PKG_CONFIG_PATH}
# libavcodec.pc  libavfilter.pc  libavformat.pc  libavutil.pc  libswresample.pc  libswscale.pc  openh264.pc
```

## Pythonのvenv作成

```sh
cd ~
python3 -m venv venv
source venv/bin/activate
pip install numpy==1.18.5
```

## OpenCV4ビルドインストール
```sh
cd ~
wget https://github.com/opencv/opencv/archive/4.6.0.zip -O opencv-4.6.0.zip
unzip opencv-4.6.0.zip
cd opencv-4.6.0
mkdir build
cd build
export INSTALL_DIR=/home/vboxuser/opencv4
cmake \
    -DCMAKE_BUILD_TYPE=RELEASE \
    -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}/build \
    -DOPENCV_PYTHON_INSTALL_PATH=${INSTALL_DIR} \
    -DHAVE_opencv_python2=OFF \
    -DHAVE_opencv_python3=ON \
    -DBUILD_opencv_python2=OFF \
    -DBUILD_opencv_python3=ON \
    -DPYTHON3_EXECUTABLE=$(which python) \
    -DPYTHON_DEFAULT_EXECUTABLE=$(which python) \
    -DPYTHON3_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
    -DPYTHON3_PACKAGES_PATH=$(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \
    -DOPENCV_FFMPEG_USE_FIND_PACKAGE=ON \
    -DBUILD_DOCS=OFF \
    -DBUILD_TESTS=OFF \
    -DBUILD_EXAMPLES=OFF \
    -DBUILD_JAVA=OFF \
    -DWITH_1394=OFF \
    -DWITH_CUDA=OFF \
    -DWITH_CUFFT=OFF \
    -DWITH_FFMPEG=ON \
    -DWITH_GSTREAMERE=OFF \
    -DWITH_GTK=OFF \
    -DWITH_IPP=OFF \
    -DWITH_JASPERE=OFF \
    -DWITH_JPEG=ON \
    -DWITH_OPENEXR=OFF \
    -DWITH_PNG=ON \
    -DWITH_TIFF=ON \
    -DWITH_V4L=OFF \
    -DWITH_GPHOTO2=OFF \
    -DWITH_CUBLAS=OFF \
    -DWITH_VTK=OFF \
    -DWITH_NVCUVID=OFF \
    ..
# 以下のログが出力され、FFmpegを認識していることが確認できる
# --   Video I/O:
# --     FFMPEG:                      YES (find_package)
# --       avcodec:                   YES (58.91.100)
# --       avformat:                  YES (58.45.100)
# --       avutil:                    YES (56.51.100)
# --       swscale:                   YES (5.7.100)
# --       avresample:                NO
# --     GStreamer:                   NO
make -j4
make install
echo ${INSTALL_DIR}/build/lib | sudo tee /etc/ld.so.conf.d/opencv.conf
sudo ldconfig
export PYTHONPATH=${INSTALL_DIR}/cv2/python-3.8
python -c "import cv2; cap = cv2.VideoCapture('bunny.mp4'); print(cap.isOpened())"
# True
```

お疲れ様でした。

# （蛇足）OpenCV3でFFmpegを認識してくれない問題

https://qiita.com/JuvenileTalk9/questions/d5c44e21407454432647

上記Q&Aにも記載しましたが、OpenCV3で同じ手順を実施すると、何故かFFmpegを認識してくれない問題があります。cmakeのオプションが足りないのか……。cmakeについての理解不足が大きいと思うので、もう少し勉強してから再トライしてみます。

```sh
cd ~
wget https://github.com/opencv/opencv/archive/3.4.9.zip -O opencv-3.4.9.zip
unzip opencv-3.4.9.zip
cd opencv-3.4.9
mkdir build
cd build
export INSTALL_DIR=/home/vboxuser/opencv3
cmake \
    -DCMAKE_BUILD_TYPE=RELEASE \
    -DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}/build \
    -DOPENCV_PYTHON_INSTALL_PATH=${INSTALL_DIR} \
    -DHAVE_opencv_python2=OFF \
    -DHAVE_opencv_python3=ON \
    -DBUILD_opencv_python2=OFF \
    -DBUILD_opencv_python3=ON \
    -DPYTHON3_EXECUTABLE=$(which python) \
    -DPYTHON_DEFAULT_EXECUTABLE=$(which python) \
    -DPYTHON3_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
    -DPYTHON3_PACKAGES_PATH=$(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \
    -DOPENCV_FFMPEG_USE_FIND_PACKAGE=ON \
    -DBUILD_DOCS=OFF \
    -DBUILD_TESTS=OFF \
    -DBUILD_EXAMPLES=OFF \
    -DBUILD_JAVA=OFF \
    -DWITH_1394=OFF \
    -DWITH_CUDA=OFF \
    -DWITH_CUFFT=OFF \
    -DWITH_FFMPEG=ON \
    -DWITH_GSTREAMERE=OFF \
    -DWITH_GTK=OFF \
    -DWITH_IPP=OFF \
    -DWITH_JASPERE=OFF \
    -DWITH_JPEG=ON \
    -DWITH_OPENEXR=OFF \
    -DWITH_PNG=ON \
    -DWITH_TIFF=ON \
    -DWITH_V4L=OFF \
    -DWITH_GPHOTO2=OFF \
    -DWITH_CUBLAS=OFF \
    -DWITH_VTK=OFF \
    -DWITH_NVCUVID=OFF \
    ..
# 以下のログが出力され、FFmpegを認識していないことが確認できる
# --   Video I/O:
# --     FFMPEG:                      NO (find_package)
# --       avcodec:                   NO
# --       avformat:                  NO
# --       avutil:                    NO
# --       swscale:                   NO
# --       avresample:                NO
# --     GStreamer:                   NO
make -j4
make install
echo ${INSTALL_DIR}/build/lib | sudo tee /etc/ld.so.conf.d/opencv.conf
sudo ldconfig
export PYTHONPATH=${INSTALL_DIR}/cv2/python-3.8
python -c "import cv2; cap = cv2.VideoCapture('bunny.mp4'); print(cap.isOpened())"
# False
```

# 参考

- https://qiita.com/engineer/items/54e33bdacc173c84cc8a
- https://take-the-risk.com/2019/11/09/ffmpeg-lgpl-build-ubuntu/
- https://qiita.com/dandelion1124/items/4b0b134694abe65ed39f