FFmpegをCMakeで探す

# はじめに
Kawa_です。C言語のプロジェクトでFFmpegを利用しようとしたところ、日本語の記事が少ないなどで環境構築やらに時間がかかってしまったので記事に残しておきます。C言語で、FFmpegという限定的すぎる記事ですが、誰かのお役に立てれば幸いです。(ほぼ備忘録ですが)

## 記事の内容
::: note warn
C++ではなく、Cを対象にした記事です。
:::
C言語でFFmpegを使うにあたっての環境構築、CMakeLists.txtについて書いておきます。
筆者はMac上で構築したのでWindowsを使用している方にはあまり参考にならないかもしれません。
なお、参考資料は記事最下部を参照ください。

## この記事の想定読者層
想定読者層です。なお、この記事にたどり着いた方はもれなく下記いずれかに当てはまると思われます。
- ~~HandyVideoの利用者~~(準備中)
- FFmpegをC言語で利用したい人
- CMakeでFFmpegを探そうとしている人
- CMakeのfind_package()でライブラリが見つからなかった人
:::note warn
FFmpegを利用したC言語のソースコードなどを求めている方は別の記事を参照されることをおすすめします。
:::

# FFmpegとCMakeをインストールする
この記事の目玉でもあるFFmpeg、CMakeのインストールからです。なお、インストール自体は他の記事でも取り上げられており、この記事の目玉ではないため簡潔に済ませています。

## Homebrew
今回、筆者はFFmpegのインストールにHomebrewを使用しました。
パッケージマネージャーにはこれのほかにもvcpkgなどがあります。
(筆者はvcpkgではうまくいかなかったのでHomebrewに逃げました。)
以下、この記事はHomebrewで構築された環境を前提として進めます。

ここでは、インストールの方法をひとつ提示します。
ターミナルを起動して、次のコマンドを実行。
```bash:bash
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
出力が一通り終わったら次のコマンドを実行し、同じように返ってきたらインストールできています。（4.1.24の部分はそれぞれのバージョンが表示されます）
```bash:bash
$ brew -v
Homebrew 4.1.24
```
::: note
インストールの詳細については[Homebrewの公式ページ（日本語）](https://brew.sh/ja/ "Homebrew")を参照してください。
:::
## FFmpeg
さきほどインストールしたHomebrewを使い、FFmpegをインストールします。
```bash:bash
$ brew install ffmpeg
```
成功すると「Installation successful！」が表示されます。

もし失敗した場合は、
```bash:bash
$ brew uninstall ffmpeg
```
でアンインストールして、先ほどのコマンドで再度インストールを試してください。
他のパッケージマネージャーを利用していた場合はそちらも確認してみてください。

## CMake
FFmpegと同様にHomebrewでインストールします。
```bash:bash
$ brew install cmake
```

最後に、以下のコマンドで今回インストールしたライブラリが確認出来れば問題ありません
```bash:bash
$ brew list
==> Formulae
aom				flac		harfbuzz	libevent		libtiff			libxrender		openjpeg		rubberband		utf8proc
apr				fontconfig	highway		libidn2			libunibreak		little-cms2		openssl@3		sdl2			webp
apr-util		freetype	icu4c		libmicrohttpd	libunistring	lz4				opus			snappy			x264
aribb24			frei0r		imath		libnghttp2		libvidstab		lzo				p11-kit			speex			x265
autoconf		fribidi		jpeg-turbo	libogg			libvmaf			m4				pango			sqlite			xorgproto
brotli			gettext		jpeg-xl		libpng			libvorbis		mbedtls			pcre2			srt				xvid
ca-certificates	giflib		lame		librist			libvpx			mpdecimal		pixman			subversion		xz
cairo			git-lfs		leptonica	libsamplerate	libx11			mpg123			pkg-config		svt-av1			zeromq
cjson			glib		libarchive	libsndfile		libxau			nettle			pyenv			tesseract		zimg
cmake			gmp			libass		libsodium		libxcb			ninja			python@3.11		theora			zstd
dav1d			gnutls		libb2		libsoxr			libxdmcp		opencore-amr	rav1e			tree
ffmpeg			graphite2	libbluray	libtasn1		libxext			openexr			readline		unbound
```
私と読者の皆様の環境とでは出力結果は違うかもしれませんが、探してもらえれば`ffmpeg`と`cmake`のどちらもあることが確認できると思います。

# FFmpegをCMakeで探す
本題です。おそらくここで詰まっている人がこの記事を読んでいることでしょう。
筆者はさっさと結論が欲しい人なので、最終的なCMakeLists.txtをここに貼っておきます。
```CMakeLists:CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
project(HandyVideo)

# コンパイラの指定
set(CMAKE_C_COMPILER hgcc)
set(CMAKE_C_STANDARD 11)

# 使用しているライブラリのパスを指定
find_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)
find_library(AVCODEC_LIBRARY avcodec)

find_path(AVFORMAT_INCLUDE_DIR libavformat/avformat.h)
find_library(AVFORMAT_LIBRARY avformat)

find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h)
find_library(AVUTIL_LIBRARY avutil)

find_path(SWSCALE_INCLUDE_DIR libswscale/swscale.h)
find_library(SWSCALE_LIBRARY swscale)

# ビルド対象のソースファイルの指定
add_executable(HandyVideo src/main.c src/videoInput.c)

# インクルードディレクトリの追加
target_include_directories(HandyVideo PRIVATE ${AVCODEC_INCLUDE_DIR} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR} ${SWSCALE_INCLUDE_DIR})

# ライブラリを実行ファイルにリンクする
target_link_libraries(HandyVideo PRIVATE ${AVCODEC_LIBRARY} ${AVFORMAT_LIBRARY} ${AVUTIL_LIBRARY} ${SWSCALE_LIBRARY})
```
このCMakeについては次のトピックから簡単に解説します。が、筆者自身がCMakeについて理解が浅いため、詳しくは参考資料・サイトを参照していただくか、検索していただくようお願いします。

## 簡単な解説
::: note warn
上記の通り、理解が深いわけではありません。調べてはいますが、正確でない可能性もあるため必ず複数のサイト、記事を参照してください
:::
- １~２行目
バージョンの指定とプロジェクトの名前を設定します。
```text:CMakeの設定
cmake_minimum_required(VERSION 3.25)
project(HandyVideo)
```
- ４~６行目
今回のプロジェクトではHandyGraphcというライブラリを使用しなければいけなかったので、そのコンパイラを使用するようにしています。ここは関係ない方が多いかもしれないです。
```text:コンパイラの指定
# コンパイラの指定
set(CMAKE_C_COMPILER hgcc)
set(CMAKE_C_STANDARD 11)
```
- 8~19行目
ここが今回もっとも重要な部分です。後述しますが、find_pathを使って読み込みたいライブラリの含まれるディレクトリとパスを探し、保存しています。
```text:パスの指定
# 使用しているライブラリのパスを指定
find_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)
find_library(AVCODEC_LIBRARY avcodec)

find_path(AVFORMAT_INCLUDE_DIR libavformat/avformat.h)
find_library(AVFORMAT_LIBRARY avformat)

find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h)
find_library(AVUTIL_LIBRARY avutil)

find_path(SWSCALE_INCLUDE_DIR libswscale/swscale.h)
find_library(SWSCALE_LIBRARY swscale)
```
- 21~22行目
ビルドする際の対象となるソースファイルを指定しています。
```text:ビルド対象のソースファイルを指定
# ビルド対象のソースファイルの指定
add_executable(HandyVideo src/main.c src/videoInput.c)
```
- 2４~2８行目
インクルードディレクトリに先ほど取得したパスを指定し、実行ファイルに先ほど取得したライブラリのパスをリンクしています。
```text:リンクする
# インクルードディレクトリの指定
target_include_directories(HandyVideo PRIVATE ${AVCODEC_INCLUDE_DIR} ${AVFORMAT_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR} ${SWSCALE_INCLUDE_DIR})

# ライブラリを実行ファイルにリンクする
target_link_libraries(HandyVideo PRIVATE ${AVCODEC_LIBRARY} ${AVFORMAT_LIBRARY} ${AVUTIL_LIBRARY} ${SWSCALE_LIBRARY})
```

## find_packageではいけない理由
CMakeでライブラリを探そうとした時、多くの人はfind_packageに辿り着いたことでしょう。
しかし、HomebrewでインストールしたffmpegにはCMakeがサポートされておらず、find_packageには引っかからないようです。find_packageで見つけることができるように、ファイルを作成することも可能ですが、今回の筆者のように使用するライブラリが少ないならゴリ押し気味に使用するライブラリのパスを全て書くのも良いです。

## find_pathを使う
上記の理由から、CMakeでFFmpeg探して使うのにはfind_pathで探すことになります。
```text:例
find_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)
```
この例では`AVCODEC_INCLUDE_DIR`という変数に`livavcodec/avcodec.h`が含まれるディレクトリまでのパスを代入します。私の環境では、`AVCODEC_INCLUDE_DIR`の変数を表示させると
```text:AVCODEC_INCLUDE_DIRの中身
 /usr/local/include
```
と出力されます。これで、`avcodec.h`がどこにあるのか分かりますね。

::: note info
find_libraryでもやっていることは同様ですので説明は省きます。
:::

最終的に、これで取得したディレクトリを次のように
```text:例
target_include_directories(HandyVideo PRIVATE ${AVCODEC_INCLUDE_DIR})
```
`target_include_directories`に渡すことで、`HandyVideo`というターゲットにディレクトリを追加します。これによって、find_packageで見つからなかったライブラリをfind_pathで見つけ、利用することができるようになります。（PRAIVATEの説明は省きます。参考資料・サイトを参照してください）

## ChatGPTを過信してはいけない
これは当然のことではありますが、ChatGPTに丸投げしてもうまくいくコードが一発で返ってくることはなかなかありません。また、FFmpegに関してはデータの更新が追いついていないところもあるように感じたのであまり過信せず、疑問点をうまく検索にかけることをお勧めします。古い記事や情報が多いですので、[FFmpeg公式ページ](https://ffmpeg.org/ "FFmpeg")から最新の情報を入手することなどもおすすめです。

# 最後に
最後まで読んでいただきありがとうございました。至らぬ点も多々ありましたでしょうが、それでもこの記事の内容が誰かの助けになればと思います。
これと関連して、HandyVideoというプロジェクトを学校の最終課題での提出作品としてC言語で作成中です。そこにはFFmpegを使っている部分もありますので、また触れた内容を記事にして投稿したいと思います。その際はまた立ち寄っていいただけますと嬉しいです。それでは、よきC言語、FFmpegライフを。


# 参考資料・サイト
参考にさせていただいた資料・サイトのまとめです。
ありがとうございました。

https://stackoverflow.com/questions/50760024/cmake-configuration-for-ffmpeg-in-c-project

https://qiita.com/mitsuruk9999/items/b8a4094f558a9c36e208

https://noqisofon.hatenablog.com/entry/20120730/1343631914

https://kamino.hatenablog.com/entry/cmake_tutorial2

https://github.com/Microsoft/vcpkg/issues/1379

https://qiita.com/shohirose/items/45fb49c6b429e8b204ac

https://cmake.org/cmake/help/latest/command/find_path.html

https://chat.openai.com