Introduction
OpenH264 を使いたくて FFMPEG をカスタムビルドしたが、どうやっても OpenCV が FFMPEG を検出してくれない問題にぶつかった。
FFMPEG に OpenH264 をリンクさせるのは自分も 開発メモ その316 FFMPEG で libopenh264 を Windows で使う その2 とかで実施していたが、FFMPEG を単独で利用したケースで、ライブラリとして他と組み合わせたことがなかった。
What’s problem?
問題点の原因は、OpenCV に OpenH264 の情報を伝えていなかったことにあった。
結論は OPENCV_EXTRA_EXE_LINKER_FLAGS にあるが、なぜそうなったか、詳細を理解しないと意味がないので書き記しておく。
検証環境は下記。
- Ubuntu
- 22.04
- CMake
- 4.0.3
- gcx
- 11.4.0
- OpenCV
- 4.13.0
- FFMPEG
- n8.1
- OpenH264
- 2.6.0
1. 普通にビルドした FFMPEG をリンク
まず、普通に FFMPEG をビルドする。この時点では OpenH264 は有効にしない。
イメージは下記。
1 | $ /path/to/ffmpeg/configure \ |
次に OpenCV をビルドする。
当然、システムに ffmpeg や libavcodec-dev がインストールされていないものとする。WITH_FFMPEG=ON を追加し、それ以外は極力無効にしてミニマムな状態にした。
1 | $ cmake -D CMAKE_INSTALL_PREFIX=/path/to/install/opencv \ |
上記でコンソールを見ると途中で
1 | -- Checking for modules 'libavcodec;libavformat;libavutil;libswscale' |
のように表示され FFMPEG が使えないことが示される。
1 | -- Video I/O: |
この時点では FFMPEG の情報を指定していないので予定通り。
次に FFMPEG の情報を指定してみる。
FFMPEG は CMake に対応していないので、PkgConfig を使う必要がある。
1 | $ export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/path/to/ffmpeg/lib/pkgconfig |
これにより先ほどの出力が
1 | -- Checking for modules 'libavcodec;libavformat;libavutil;libswscale' |
や
1 | -- Video I/O: |
となる。
ここまでが 前提。
2. OpenH264 を有効にした FFMPEG をリンク
次に OpenH264 を有効化して FFMPEG をビルドする。
イメージは下記。
1 | $ PKG_CONFIG_PATH="/path/to/libopenh264/lib/pkgconfig:/usr/local/lib/pkgconfig" \ |
同様に OpenCV をビルドする。
1 | $ export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/path/to/ffmpeg/lib/pkgconfig |
ここで先ほどと違った挙動を見せる
1 | -- Checking for modules 'libavcodec;libavformat;libavutil;libswscale' |
警告が見える。
1 | -- Video I/O: |
libavcodec 等のコンポーネントは有効なのに FFMPEG 自体が無効になっている…
3. PKGCONFIG に OpenH264 を足す
単純に環境変数ないしはシェル変数 PKGCONFIG に OpenH264 の PkgConfig までのパスを追加すれば治るでしょう?、と思った。
違いは OpenH264 の有無だけだし。
1 | $ export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/path/to/ffmpeg/lib/pkgconfig:/path/to/libopenh264/lib/pkgconfig |
が、何一つ変わらない。
なんで?
4. Can’t build ffmpeg test code、って何?
どう考えてもこのエラーが怪しい。
OpenCV のソースを見ると該当するのはここ。
opencv/modules/videoio/cmake/detect_ffmpeg.cmake#L89
1 | if(HAVE_FFMPEG AND NOT HAVE_FFMPEG_WRAPPER AND NOT OPENCV_FFMPEG_SKIP_BUILD_CHECK) |
どうも、try_compile で失敗しているというのは読める。
CMake の公式 try_compile を見ると、読んで字のごとく、「実行可能または静的ライブラリをソースからビルドしてみる」、とある。${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp を見ても、まぁ、すごい簡単なソースがあって、単純に FFMPEG を使ってビルドできるかどうかを事前確認している模様。
で、これが失敗しているから cmake の設定でエラーになっているのだが、肝心の理由が出力されていない。
それもそのはずで、上の公式にこのような一文がある。
CMake automatically generates, for each try_compile operation, a unique directory under ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeScratch with an unspecified name. These directories are cleaned automatically unless –debug-trycompile is passed to cmake. Such directories from previous runs are also unconditionally cleaned at the beginning of any cmake execution.
CMakeは、各try_compile操作に対して、${CMAKE_BINARY_DIR}/CMakeFiles/CMakeScratch 配下に、名前が未指定の一意なディレクトリを自動的に生成します。これらのディレクトリは、cmakeに–debug-trycompileが指定されない限り、自動的に削除されます。また、以前の実行で生成されたこのようなディレクトリも、cmakeの実行開始時に無条件に削除されます。
勝手に消えるけど、cmake に --debug-trycompile を付与すれば消えないと読める。
そして、 ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeScratch に何か出力される、と。
実際、 ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeScratch には何も存在しないことは確認できた。
なので、さっきの CMake のコマンドを
1 | $ export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/path/to/ffmpeg/lib/pkgconfig:/path/to/libopenh264/lib/pkgconfig |
と --debug-trycompile を付与してみた。
すると再び出力が変化した。
1 | -- No package 'gtk+-2.0' found |
…あれ ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeScratch じゃないの?…思ったら公式の説明には続きがあり
In this version, try_compile will use
/CMakeFiles/CMakeTmp for its operation, and all such files will be cleaned automatically.
とある。In this version が何時からなのかは不明だが、少なくとも 3.0 にはこの記述がある。
CMakeFiles/CMakeTmp を見ると、CMakeError.log みたいなのはないが、一つずつ眺めていると、Makefile があることに気づいた。
中を見ると、ffmpeg_test.cpp の記述があり、これが問題のテストプロジェクトだとわかった。
なので、手動で make を実行する。
1 | $ cd ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp |
原因がわかった。libopenh264.so.8 が必要だが、それがリンカーにわたっていない、と。
5. リンカーに外から指示
そもそも PkgConfig で OpenH264 を指定しているのに、なんでリンカーは解釈してくれないの?、と思う。libavcodec は解決できているし。
それでいろいろググっていたら build script for opencv using a custom ffmpeg installation という gist を見つける。
1 |
|
OPENCV_EXTRA_EXE_LINKER_FLAGS なる見慣れないオプションがあり、リンカーに指示を与えていた。
素直に上をまねて OpenH264 のライブラリディレクトリを指定してみる。
1 | $ export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/path/to/ffmpeg/lib/pkgconfig:/path/to/libopenh264/lib/pkgconfig |
これで無事に警告が消えて、FFMPEG が有効になった。
ちなみに、PKG_CONFIG_PATH から OpenH264 のパスは外しても問題はなかったし、OPENCV_EXTRA_EXE_LINKER_FLAGS も OpenH264 だけでよかった。
最終的には下記。
1 | $ export PKG_CONFIG_PATH=${PKG_CONFIG_PATH}:/path/to/ffmpeg/lib/pkgconfig |
6. まとめ
OPENCV_EXTRA_EXE_LINKER_FLAGS なる初見のオプションで解決するなど、OpenCV はまだまだ闇が深い。
ちなみに、このオプション、検索すると、少なくとも Configure and Build OpenCV to Custom FFMPEG Install という 2012 年という古い記事で見つかった。
今日も先人に感謝。
