ホーム < ゲームつくろー! < DirectX技術編 < とにもかくにもムービー再生!


その1 とにもかくにもムービー再生!


 DirectShowは音楽やムービーなどを再生するためのコンポーネントを提供してくれます。しかし、音に関してはDirectSoundがありますから、DirectShowはもっぱらムービーの再生のために使います。非常に細かな設定、デコードなどをサポートしており、全容を把握するのは容易ではないのですが、ゲームでは再生用として使用することが殆どです。この章では、DirectShowを用いて兎にも角にもムービーを再生する最低限の方法を示してみます。ここで説明する内容は、DirectX9のDirectShowのマニュアルと殆ど同じですから、そちらも参照してみてください。



@ フィルタとフィルタグラフ

 DirectShowの理解には「フィルタ」と「フィルタグラフ」を知る必要があります。フィルタとは「ろ過器」の事ですが、言うならデータの変換コードの事です。ファイルに格納されているデータを画面に出すまでには、データを色々と加工する必要があります。その加工の節々にあるのがフィルタです。このフィルタがいくつか連なって最終的な出力まで到達するのですが、その繋がりを表したのがフィルタグラフです。各フィルタを様々に組み合わせれば、多種多様なフィルタグラフができるわけです。DirectShowではフィルタとフィルタグラフという言葉が頻発しますので、イメージをつかんでおいて下さい。



A 各種インターフェイスの取得

 DirectShowのインターフェイスとして最初に取得するのはIGraphBuilderインターフェイスです。このインターフェイスによってフィルタグラフが作成できます。ただ、Direct3Dのように便利なヘルパー関数が無いので、COMに従ったお作法でインターフェイスを取得する必要があります。

 最初にCOMを初期化します。

COMの初期化
HRESULT hRes = CoInitialize(NULL);
if(FAILED(hRes)){
   // COM初期化失敗
}

これはCOMコンポーネントを扱う上でのお作法でして、これに失敗するとCOMが扱えません。これによって内部で初期化に必要な諸々が整理されています。

 次にIGraphBuilderインターフェイスを取得するためにCoCreateInstance関数を呼び出します。この関数はCOMインターフェイスを作成するグローバルなファクトリ関数です。

IGraphBuilderインターフェイスの取得
// IGraphBuilderインターフェイスの取得
hRes = CoCreateInstance(
      CLSID_FilterGraph,
      NULL,
      CLSCTX_INPROC_SERVER,
      IID_IGraphBuilder,
      (void **)(m_cpGraph.ToCreator())
      );

     if(FAILED(hRes))
        return hRes;

クラスIDやインターフェイスIDなどは上のように設定します。このIDはDirectX9のライブラリファイルであるStrmiids.libの中に定義されています。関数が成功するとm_cpGraphにIGraphBuilerインターフェイスへのポインタが取得できます(m_cpGraphはComポインタ。Comポインタについてはこちら)。

 続いてメディアコントロールおよびメディアイベントを管理するインターフェイスを取得します。メディアコントロールインターフェイスIMediaControlは、フィルタグラフの流れをストリーミングによって管理してくれます。メディアイベントインターフェイスIMediaEventは再生や停止の際にその乗法をイベントとして通知してくれます。

メディアインターフェイスの取得
// メディアコントロールインターフェイスの取得
hRes = m_cpGraph->QueryInterface(IID_IMediaControl, (void**)(m_cpControl.ToCreator()));
if(FAILED( hRes )
   return hRes;

// メディアイベントインターフェイスの取得
hRes = m_cpGraph->QueryInterface(IID_IMediaEvent, (void **)(m_cpEvent.ToCreator()));
if(FAILED( hRes )
   return hRes;
;

 これで最低限のメディア再生は確保できました。



B メディアの再生

 再生の手始めはIGraphBuilder::ReadFile関数でファイルを読み込むことです。

メディアファイルの読み込み
hRes = m_cpGraph->RenderFile(L"Test.avi", NULL);
if(FAILED( hRes ))
   return hRes;

第1引数にはファイル名を渡すのですが、ここは「2バイト文字」という制約がありまして、L"  "という形で渡します。第2引数は予約なのでNULLで固定です。IGraphBuilderインターフェイスはこのファイルを解析して再生できるように自動的にフィルタグラフを作成してくれます。

 正しくファイルが読み込めたら、後はメディアコントロールインターフェイスで再生するだけです。

メディアファイルの読み込み
// メディア再生
if( FAILED(hRes=m_cpControl->Run()) )
   return hRes;

 これを実行するとウィンドウが作成されて、自動的に再生が始まります。始まるんですが、ループ待機をしていなければあっという間にアプリケーションが閉じてしまいます。そのために、再生中に待機する関数があります。IMediaEvent::WaitForCompletion関数です。この関数を使って例えば5秒待つには次のようにします。

再生を5秒待つ
// 待機時間の設定
long pEvCode;
hRes = m_cpEvent->WaitForCompletion(5000, &pEvCode);

第1引数に待ち時間をミリ秒で指定して、第2引数に関数が終了した時のイベントコードを取得します。この関数はメディアの再生が終わると自動的に戻ってくるので、メディアが3秒しかなかったら、3秒後には関数を抜けてくれます。

 これでメディアは再生されます。ただし、再生が終わってもフィルタグラフ自体は終了しておらず、データさえあればそれを直ちにレンダリングする状態になっています。終了処理もしっかりしないと、アプリケーションが暴走します。



C 終了処理

 再生が終了したらIMediaControl::Stop関数を呼び出します。この呼び出しによってグラフフィルタの動作が止まります。

グラフフィルタを停止
m_cpControl->Stop();

 停止後必要の無くなったオブジェクトは廃棄します。通常は各インターフェイスのRelease関数を呼び出します。ただし、Comポインタを用いている場合は、これを自動的に行ってくれるので何もしなくて結構です。最後にCOMコンポーネントの終了宣言をします。

COMコンポーネントの終了宣言
CoUninitialize();


 これできれいさっぱり終了です。



 さて、このようにとてもあっさりとムービーが再生できます。しかも、aviだけでなくmpegやwmvなどもこれで再生できるのですから驚き。ただ、この状態では駄々流れなのでゲームに使用するにはあまりに厳しすぎます。次の章からはゲームで使用するために色々と工夫をしていきます。