WindowsアプリでLGPLなFFmpegを利用したかった!
私のWindowsアプリでは動画の取り込みからONNX推論までをゼロコピーで実現したいと考えていて、NVENC、AMF、QSV、D3D11VAを含むFFmpegが必要でした。また他の独自ライセンスとの競合も回避する必要があったので、LGPLなsharedなビルドが必要でした。
FFmpegのビルドは以前に一度実施したことがあったような気がするのですが、確かなんだかとてもめんどくさかったので、できれば配布してあるビルド済みを利用したいところ。
FFmpeg公式からもリンクしてあるWindows向けビルドは、gyan.devさんかBtbnさんのところになるのですが、
- gyan.devさん:FFmpeg全部入り。なんでも使える。でも当然GPL
- Btbnさん:複数パターンのビルドがあって、shared、LGPLなビルドもあり
ということで、Btbnさん一択だな!と考えていたのですが。
こちらのビルドには、NVENCやAMF、QSVといったハードウェアエンコーダはサポートされているものの、WindowsのD3D11VAやD3D12VAはサポートされていませんでした。
仕方がないのでFFmpegのビルドに再挑戦することになりました。(数年ぶり2回目)
Windows向けFFmpegのビルドでいい感じにまとめてある投稿を見つけた!
やったー!
記事も新しいので手順通り従って行けば間違いないはず!
で、実際記事通り進めて、スムーズにconfigureもできてビルドも成功!やったね!!
で最後に掲載されているスクリプトで依存関係のあるDLLを集めてる、と。どれどれ・・・
ズラズラズラズラー
物凄い数のdllが並びました。
できるだけ少ない数のdllにまとめられないか?
動けばいいとは思うものの、あまりに多いのはちょっと考えもの。公式ビルドは数が少ないので何か設定があるのだろう?とWindows Copilotなどに相談してみると、
- 公式ビルドは
--pkg-config-flags="--static"で、依存ライブラリを静的リンクするようにしている - 静的ビルドをするには、MSYS2 MINGW64(青いアイコン)でビルドする
MSYS2の黄色っぽいアイコン(UCRT64)だと、できるだけUCRT64にあるDLLを利用する形でビルドする(というか静的ライブラリを持ってない?)ようで依存関係が静的リンクにならないのだとか。
また最初からになりますが、できるだけすっきりさせたかったので、MSYS2 MINGW64でやり直し!
私のLGPL、NVENC、AMF、QSV、D3D11VA、できるだけ静的リンクを満たすconfigureは次のようなものになりました。
../configure \
--prefix=/usr/local \
--enable-shared \
--disable-static \
--disable-debug \
--disable-doc \
--disable-ffplay \
--enable-ffmpeg \
--enable-ffprobe \
--disable-avdevice \
--enable-runtime-cpudetect \
--enable-small \
--enable-avfilter \
--enable-libzimg \
--enable-nvenc \
--enable-amf \
--enable-libvpl \
--enable-d3d11va \
--pkg-config-flags="--static" \
--extra-cflags="-I/mingw64/include" \
--extra-ldflags="-L/mingw64/lib -static-libgcc -static-libstdc++ -lpthread"
不足しているライブラリはpacmanで導入するのですが、MSYS2 Packagesで探すと、導入コードもコピペできて便利ですね。
D3D11VAは標準でリンクされるらしく特に何もせずともconfigure通りました。
ビルドした結果!

ちょっと少なくなったかな?
本当はgyan.devさんやBtbnさんのように本当にffmpegのdllだけにしたいところですが、あんまり頑張っても仕方がないので、この辺でいいだろうと妥協しました。
もし、こうやったら簡単に公式と同じくらい少なくビルドできるよ!というやり方があればぜひ教えてください!
2026/8/14追記:まとめようと頑張った結果
ここまで頑張れました。

libwinpthreadが手ごわい。もういいです・・・
ちなみにbuildしているのは、たぶんFFmpeg 9.0.1です。あまり深く考えずgit cloneしました。
なんか初心者お断りな感じで、たぶん次ビルドする時はまた違う手順かもしれません。
次の記事がまず参考になりました。
(実はストックにも入れてたけど気づいていませんでした。前回はこれを参考にしてたのかも?)
上記の記事を参考にしつつも、それではうまくいかなかったので。
Grokにconfigureとビルド後の依存関係を見てもらいながら、あーでもないこーでもないとやってました。
誰かに参考になるとは思えませんが、自分用の記録として残しておきます。
1.dll.aを退避する
dllにリンクさせない強い気持ち(物理)
mkdir -p ~/dll_a_backup
# 退避
for f in \
/mingw64/lib/libz.dll.a \
/mingw64/lib/libbz2.dll.a \
/mingw64/lib/liblzma.dll.a \
/mingw64/lib/libiconv.dll.a \
/mingw64/lib/libzimg.dll.a \
/mingw64/lib/libvpl.dll.a \
/mingw64/lib/libwinpthread.dll.a \
/mingw64/lib/libstdc++.dll.a \
/mingw64/lib/libgcc_s.a 2>/dev/null
do
[ -f "$f" ] && mv "$f" ~/dll_a_backup/
done
mkdir -p ~/dll_a_backup
[ -f /mingw64/lib/libiconv.dll.a ] && mv /mingw64/lib/libiconv.dll.a ~/dll_a_backup/
[ -f /mingw64/lib/libwinpthread.dll.a ] && mv /mingw64/lib/libwinpthread.dll.a ~/dll_a_backup/
# 念のため名前のバリエーションも
[ -f /mingw64/lib/libgcc_s_seh-1.dll.a ] && mv /mingw64/lib/libgcc_s_seh-1.dll.a ~/dll_a_backup/
# zlib は名前が違う場合あり
[ -f /mingw64/lib/libz.dll.a ] && mv /mingw64/lib/libz.dll.a ~/dll_a_backup/
1.5. 確認、環境変数設定
# まず .dll.a を退避した状態を確認
ls /mingw64/lib/libz.dll.a 2>/dev/null && echo "まだ dll.a がある" || echo "退避OK"
# 環境変数で強制
export LDFLAGS="-L/mingw64/lib -static-libgcc -static-libstdc++ -Wl,-Bstatic -lzimg -lvpl -lstdc++ -lz -lbz2 -llzma -liconv -lwinpthread -Wl,-Bdynamic"
export EXTRA_LIBS="-lzimg -lvpl -lstdc++ -lz -lbz2 -llzma -liconv -lwinpthread"
2.クリーンして再configure
make distclean 2>/dev/null || true
# buildディレクトリを空にする場合
# rm -rf *
export PKG_CONFIG_PATH="/mingw64/lib/pkgconfig"
../configure \
--prefix=/usr/local \
--target-os=mingw32 \
--arch=x86_64 \
--enable-shared \
--disable-static \
--disable-debug \
--disable-doc \
--disable-ffplay \
--enable-ffmpeg \
--enable-ffprobe \
--disable-avdevice \
--enable-runtime-cpudetect \
--enable-small \
--enable-avfilter \
--enable-libzimg \
--enable-nvenc \
--enable-amf \
--enable-libvpl \
--enable-d3d11va \
--extra-cflags="-I/mingw64/include" \
--extra-ldflags="-L/mingw64/lib -static-libgcc -static-libstdc++" \
--extra-libs="-Wl,-Bstatic -lzimg -lvpl -lstdc++ -lz -lbz2 -llzma -liconv -lwinpthread -Wl,-Bdynamic -lws2_32 -luser32 -lole32 -lgdi32 -lbcrypt -lncrypt -lsecur32 -luuid"
3.configure 後に生成される ffbuild/config.mak を直接修正します。
sed -i 's/-lz /-Wl,-Bstatic -lz -Wl,-Bdynamic /g' ffbuild/config.mak
sed -i 's/-lbz2 /-Wl,-Bstatic -lbz2 -Wl,-Bdynamic /g' ffbuild/config.mak
sed -i 's/-llzma /-Wl,-Bstatic -llzma -Wl,-Bdynamic /g' ffbuild/config.mak
sed -i 's/-lzimg /-Wl,-Bstatic -lzimg -Wl,-Bdynamic /g' ffbuild/config.mak
sed -i 's/-lvpl /-Wl,-Bstatic -lvpl -lstdc++ -Wl,-Bdynamic /g' ffbuild/config.mak
sed -i 's/-lwinpthread /-Wl,-Bstatic -lwinpthread -Wl,-Bdynamic /g' ffbuild/config.mak
# iconv と winpthread を強制静的に
sed -i 's/-liconv/-Wl,-Bstatic -liconv -Wl,-Bdynamic/g' ffbuild/config.mak
sed -i 's/-lwinpthread/-Wl,-Bstatic -lwinpthread -Wl,-Bdynamic/g' ffbuild/config.mak
4.ビルド、ffmpegの依存関係確認
make -j$(nproc)
make install
ldd /usr/local/bin/ffmpeg.exe
$ ldd /usr/local/bin/ffmpeg.exe
ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffa14be0000)
KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ffa13a90000)
KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE.dll (0x7ffa121b0000)
msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ffa13e60000)
SHELL32.dll => /c/WINDOWS/System32/SHELL32.dll (0x7ffa12970000)
msvcp_win.dll => /c/WINDOWS/System32/msvcp_win.dll (0x7ffa12100000)
ucrtbase.dll => /c/WINDOWS/System32/ucrtbase.dll (0x7ffa127b0000)
USER32.dll => /c/WINDOWS/System32/USER32.dll (0x7ffa14890000)
win32u.dll => /c/WINDOWS/System32/win32u.dll (0x7ffa120d0000)
GDI32.dll => /c/WINDOWS/System32/GDI32.dll (0x7ffa14600000)
gdi32full.dll => /c/WINDOWS/System32/gdi32full.dll (0x7ffa125c0000)
avutil-60.dll => /usr/local/bin/avutil-60.dll (0x7ff9dee50000)
avformat-62.dll => /usr/local/bin/avformat-62.dll (0x7ff9eaa30000)
ADVAPI32.dll => /c/WINDOWS/System32/ADVAPI32.dll (0x7ffa133c0000)
avfilter-11.dll => /usr/local/bin/avfilter-11.dll (0x7ff986520000)
CRYPT32.dll => /c/WINDOWS/System32/CRYPT32.dll (0x7ffa11f40000)
avcodec-62.dll => /usr/local/bin/avcodec-62.dll (0x7ff8b0120000)
ole32.dll => /c/WINDOWS/System32/ole32.dll (0x7ffa146f0000)
sechost.dll => /c/WINDOWS/System32/sechost.dll (0x7ffa13590000)
WS2_32.dll => /c/WINDOWS/System32/WS2_32.dll (0x7ffa13670000)
combase.dll => /c/WINDOWS/System32/combase.dll (0x7ffa13700000)
RPCRT4.dll => /c/WINDOWS/System32/RPCRT4.dll (0x7ffa13d40000)
swresample-6.dll => /usr/local/bin/swresample-6.dll (0x7ffa0cba0000)
swscale-9.dll => /usr/local/bin/swscale-9.dll (0x7ff9f1d70000)
Secur32.dll => /c/WINDOWS/SYSTEM32/Secur32.dll (0x7ffa0edf0000)
ncrypt.dll => /c/WINDOWS/SYSTEM32/ncrypt.dll (0x7ffa115c0000)
libwinpthread-1.dll => /mingw64/bin/libwinpthread-1.dll (0x7ff9f9430000)
bcrypt.dll => /c/WINDOWS/SYSTEM32/bcrypt.dll (0x7ffa11ce0000)
SSPICLI.DLL => /c/WINDOWS/SYSTEM32/SSPICLI.DLL (0x7ffa10d50000)
5.dll.aを元に戻す
mv ~/dll_a_backup/*.dll.a /mingw64/lib/ 2>/dev/null || true
もしlibwinpthreadが消せたら、また追記します。