2013/01/25(金)C#からDirectShowを使って動画のビットマップのポインタを得てDirect3Dでムービーテクスチャにもできる動画再生ライブラリを作ったのでNYSLで公開しました。

はてブ数 2013/01/25 23:36 プログラミング::C#つーさ

本日(じゃないけど)のアウトプット。
動画プレーヤーつくりました。

今更DirectShowのSampleGrabberを使えるようになってみたり。
再生するというよりは、ビットマップのポインタを得てぐりぐり加工する向けですな。

    /// 
    /// DirectShowのSampleGrabberGraph を使ってメディアファイルを再生するサンプル。
    /// SampleGrabberを使うメリットは、ビデオもオーディオもデコード後のデータのポインタが得られることで、
    /// Marshal.Copyなどでbyte[]にコピーするなり、unsafeコンテキストを使うなりで手軽に加工することができる。
    /// ゲームアプリなどではDynamicTextureに転送することで簡単にムービーテクスチャを作ることもできる。
    /// VMR9を使った方がパフォーマンスが出るが、Device LostがOSのバージョンごとに挙動が違ったりで対応しきれない。
    /// カスタムレンダラを作るのが最良の方法なのだろうけれど、C#のみでカスタムレンダラを作るのは至難の業。
    /// Enter:開く, Space:再生/一時停止, Escape:停止 ←/→:5秒シーク
    /// 

例によってソースをNYSLで公開してます。
https://github.com/ttsuki/ttsuki-csmix/tree/master/WindowsUtil/DirectShow/

例によって、このコードをあなたのプログラムにコピペすると、
特にアセンブリを追加することなくEXE単体で動画再生ができます。
DirectShow.net とか使ってない。

C#の動画再生あれこれと言えば……。

たとえば、Managed DirectXには AudioVideoPlayback というクラスがあって、
実はManaged Direct3Dのテクスチャに転送する機能もついていることにはいるんですが、
強制的に、画面のFPSが動画のFPSに合わせられてしまったりするので、
(ただ再生するならそれでいいですが、ゲーム中のテクスチャとして使うには)非常に扱いが難しいです。

VMR9を使うと動画のフレームを描画したテクスチャを直接受け取ることができなくもないんですが、
これまた動画のレンダリング中(テクスチャを投入してから、次のフレーム時刻になって、テクスチャ描画されて戻ってくるまで)は、
描画スレッド側でDirect3DのAPIが呼べないため、60FPSを維持しながら動画再生するのはなかなか至難の業っぽく。
動画に1FPSの区間があったりすると、ゲームアプリ側も巻き込まれて1FPSになるんですよね、はい。

また、VMR9はDevice Lostしたとき、Pinを切ってDirect3DをResetしてPinをつなぐとWinXPでは動いていたんですが、
Win8にしたらそのコードではCOMExceptionが出るようなので、結局Graphをいったん破棄してとか。
当時はDirectShowに対する知識も浅かったので(未だに浅いですが)使い方間違ってたかもなぁ……。

という感じで一周してきて、結局頼れるのはSampleGrabberですね!

Media Foundation API とか使うとmp4とかも開けるようになるみたいで、そっちも使えてみたいなぁ。
APIのネーミングとかをさらっと見た感じでは、
DirectShowで言うグラフのようにトポロジを構成してデータを流すっぽいんですが。