OpenCVからVP6やH.264などさまざまな動画を読み込み可能にするffopencv

追記 2008-10-18

OpenCV1.1preがリリースされ、ffopencvも正式についてるようなので、そちらを使いましょうー。

以下

Windows版のOpenCVではffmpegが使えないと思っていたのですが、otherlibsの下にffopencvというそれっぽいプロジェクトがあったので、ちょっとだけいじって使えるようにしました。ffopencv100.dllというファイルをPATHの通っているところに置くと、cvCaptureFromAVIから自動的にffmpegのデコード処理が呼び出されるようになります。既存のコードの変更やリコンパイルの必要はありません。
ニコニコ動画のflvを読むためにビルドしたので、VP6とh264のflvファイルが読めたところで満足しています。
バイナリとプロジェクトファイルをダウンロード

作業メモ

MinGWでコンパイルしたffmpegのライブラリがとにかく落ちまくる

SSSE3とMMXのところで落ちていたのでこっちのプロセッサの問題かもしれないですが、gccとcl間で何かありそうな予感がしたので、ffmpegでプロセッサ依存のアセンブリをdisableにして、--enable-memalign-hackとかいう、いかにも構造体やビットフィールドのメモリアライメントをハックしてそうな怪しげなオプションをはずすとと落ちなくなりました。落ちるときに、ffmpeg的にはOKだけどコンパイラが悪いからGCC4.2以降でコンパイルしてね、とか出て、でもgcc4.2以降のMinGW版がないとかで。
あとダイナミックリンクとスタティックリンクでコーデックを探したときの挙動が違うという超絶恐ろしい現象が発生していましたが、スタティックだと問題なさそうだったのでスタティックリンクして怪しげな問題は放置しています。ここでLGPLになったのですが、もともとのffopencvもスタティックリンクするようになっていたので気にしていません。

VP6

VP6のときにavcodec_openしたあとで画面のサイズが0になるという謎の現象があったので、そのまえにサイズを保存しておいてオープン後に書き戻すというさらに怪しげなことをしています。
ニコニコ動画のflvを読むためにビルドしているので、flvからaviへ変換しまくることなくVP6とh264のflvファイルが読めたところで満足しています。

あやしげです

MinGWでコンパイルしたffmpegがあやしい。おかしい。とてもこわい。
コンパイルオプションなどの詳細はzipのなかに書いています。

追記

 --enable-shared --enable-memalign-hackでコンパイルしても動いてました。同時にいろいろ触りすぎて謎になってしまいましたが、ffopencvのコードが悪かったようです。ただ、新しいCPUに依存してしまうため、バイナリはこのままにしておきます。SSSE3など使いたい場合は、ffmpegをコンパイルしてリンクしなおしてください。

ffmpegの構造体

たぶんVC側とgcc側で構造体メンバのアラインが違うか、型サイズが違うかで構造のメンバがずれてる気がするのでそのへんを調べる……。

#ifdef __ICC
    #define DECLARE_ALIGNED(n,t,v)      t v __attribute__ ((aligned (n)))
    #define DECLARE_ASM_CONST(n,t,v)    const t __attribute__ ((aligned (n))) v
#elif defined(__GNUC__)
    #define DECLARE_ALIGNED(n,t,v)      t v __attribute__ ((aligned (n)))
    #define DECLARE_ASM_CONST(n,t,v)    static const t v attribute_used __attribute__ ((aligned (n)))
#elif defined(_MSC_VER)
    #define DECLARE_ALIGNED(n,t,v)      __declspec(align(n)) t v
    #define DECLARE_ASM_CONST(n,t,v)    __declspec(align(n)) static const t v
#elif defined(HAVE_INLINE_ASM)
    #error The asm code needs alignment, but we do not know how to do it for this compiler.
#else
    #define DECLARE_ALIGNED(n,t,v)      t v
    #define DECLARE_ASM_CONST(n,t,v)    static const t v
#endif

こうなってるけど、__attribute__*1は、VCだと#pragma packで、__declspec(align(n))とは意味が違ったような。
ググる

追記

いくつかsizeofをとったら一緒だった。上のはインターフェースとしては使われてなかった。
stdint.hが別ファイルだったけど構造体にint64_tなんかを含んでも同じサイズだった。

追記

 --enable-shared --enable-memalign-hackでコンパイルしても動くようになった。同時にいろいろ触りすぎて謎になってしまったけど、ffopencvのコードが悪かったようです。

おわり。

*1: aligned(n