なぜfrei0r C++フィルターDLLはffmpegにロードされないのにCフィルターはロードされるのか

なぜfrei0r C++フィルターDLLはffmpegにロードされないのにCフィルターはロードされるのか

私は、Windows 10 の frei0r サポートを使用して ffmpeg をクロスコンパイルしようとしています。Linux (Ubuntu 18.04) では、すべて問題なく動作します。Windows (Ubuntu 上の Mingw-w64 7.3.0) では、ビルドは正常に動作します。ただし、Windows で次のコマンド ラインを使用して実行すると、次のようになります。

ffmpeg -i http://lb.streaming.sk/fashiontv/stream/playlist.m3u8 -vf frei0r=pixeliz0r -loglevel debug -f mpegts pipe:play | ffplay -loglevel quiet -i pipe:play

正しい行動をとっているが、

ffmpeg -i http://lb.streaming.sk/fashiontv/stream/playlist.m3u8 -vf frei0r=vignette -loglevel debug -f mpegts pipe:play | ffplay -loglevel quiet -i pipe:play

dll が見つからないというエラーが発生します。

[Parsed_frei0r_0 @ 000000000347ef00] Could not find module 'vignette'.
[AVFilterGraph @ 00000000029074c0] Error initializing filter 'frei0r' with args 'vignette'
Error reinitializing filters!
Failed to inject frame into filter network: Invalid argument
Error while processing the decoded data for stream #0:1
[AVIOContext @ 00000000028d8f40] Statistics: 0 seeks, 0 writeouts
[AVIOContext @ 00000000028c5480] Statistics: 133422 bytes read, 0 seeks
[AVIOContext @ 00000000028d1b00] Statistics: 0 bytes read, 0 seeks
[AVIOContext @ 00000000006ccd80] Statistics: 201 bytes read, 0 seeks
[AVIOContext @ 00000000028a8100] Statistics: 137 bytes read, 0 seeks

Windows でも同じ動作が一貫しており、C++ dll プラグインが見つからない場合でも、すべての C プラグインが動作します。Linux ビルドでは、すべて問題なく動作します。

これは ffmpeg のビルド構成です:

./configure --arch=x86_64 --target-os=mingw32 --cross-prefix=x86_64-w64-mingw32- --disable-doc --enable-nonfree --enable-gpl --enable-version3 --enable-static --disable-shared --enable-frei0r --extra-cflags='-I../frei0r/include -I/usr/local/include -I/usr/share/mingw-w64/include' --extra-ldflags="-static -static-libstdc++ -static-libgcc" --extra-libs='-lstdc++ /usr/local/lib/libdl.dll.a'

問題を追跡しようとしたところ、何らかの理由で ffmpeg フィルター vf_frei0r がそれらの dll を開くことができないことがわかりました。より正確には、dlopen は dll のパス/名前で呼び出した後、null ハンドラーを返します。繰り返しますが、これは C++ の場合のみです。

これは C++ での名前マングリングに関連するものではないかと疑っていますが、私が見たところ、frei0r hpp は dlopen によって呼び出されるすべての C 関数を外部としてエクスポートします。

この問題に関して何かヒントやアイデアはありますか? ありがとうございます。

答え1

私自身の質問に答えます。

生成されたバイナリを確認した後、何らかの理由で、mingw32-w64 g++ コンパイラが frei0r.h インクルードを囲む「外部 C」を無視していることが分かりました。このため、エクスポートされたシンボルの名前は、C++ コンパイラの指示に従ってマングルされ、ffmpeg の C コードから呼び出されたときに見つかりません

アップデート: さらに調べてみると、C コンパイラでもシンボル名の装飾が行われることがわかりました。これを防ぐ 1 つの方法は、関数のエクスポート名を定義する .def ファイル (Visual Studio 用) を使用することです。

関連情報