映像再生が終わるまで待つ

DirectShowを使ってMPEGを再生する最も単純な方法は説明をしましたが、前述した方法ではMessageBoxで処理を止めているだけでした。 MessageBoxで処理を待たせるだけでは実用的ではないので、ここでは再生が終了するまで自動的に待つ方法を説明したいと思います。 (注意)ここの例では、サンプルを簡潔にするためにエラー処理を書いていません。

サンプルコード

前の例では、MessageBox()でユーザがボタンをクリックするまで再生を続けるというコードでした。 それではあんまりなので、「終わるまで待つ」という風にコードを追加してみると以下のようになります。

IMediaEventのWaitForCompletionを使うと再生が終了するまで待てます。 WaitForCompletionはブロッキングを行うメソッドです。 WaitForCompletionの第一引数はタイムアウトする時間を表しています。 例えば、第一引数に2と入れるとWaitForCompletionは2秒間返って来ません。 WaitForCompletionの第一引数を「-1」にすると再生が終了するまでブロックします。


#include <stdio.h>

#include <dshow.h>

#define	FILENAME L"c:\\DXSDK\\Samples\\Media\\butterfly.mpg"

int
main()
{
 IGraphBuilder *pGraphBuilder;
 IMediaControl *pMediaControl;
 IMediaEvent *pMediaEvent;
 long eventCode;

 CoInitialize(NULL);

 CoCreateInstance(CLSID_FilterGraph,
	NULL,
	CLSCTX_INPROC,
	IID_IGraphBuilder,
	(LPVOID *)&pGraphBuilder);

 pGraphBuilder->QueryInterface(IID_IMediaControl,
	(LPVOID *)&pMediaControl);

 pGraphBuilder->QueryInterface(IID_IMediaEvent,
	(LPVOID *)&pMediaEvent);

 pMediaControl->RenderFile(FILENAME);

 pMediaControl->Run();

 // 一つ目の引数はタイムアウトです。
 // 例えば、-1の部分を2にすると2秒でタイムアウト。
 pMediaEvent->WaitForCompletion(-1, &eventCode);
 switch (eventCode) {
 case 0:
	printf("timeout\n");
	break;
 case EC_COMPLETE:
	printf("complete\n");
	break;
 case EC_ERRORABORT:
	printf("errorabort\n");
	break;
 case EC_USERABORT:
	printf("userabort\n");
	break;
 }

 pMediaControl->Release();
 pGraphBuilder->Release();
 CoUninitialize();

 return 0;
}

WaitForCompletion()は完全にブロックしてしまうので、(Threadを使わずに)他の処理を並列して行いたい場合などには使えません。 そのような時には、IMediaEventのGetState()が利用できます。 GetState()は、Filter Graphの状態を取得できます。 GetState()で状態を取得して、再生が終わるまで監視を続けるビジーループを行えば、ノンブロッキングな再生完了待ちコードが実現可能です。

実際にはMFCなどと組み合わせて、特定のボタンやメニューが利用されたら再生を停止したり開始したりするのが最も現実的であると思われます。