DirectShowからアプリケーションへのメッセージ

複数のフィルタから構成されるグラフで,すべてのフレームのレンダリングが終わったとき,エラーが起きたときなど,DirectShow側からそのイベントが起きたタイミングを知ることができれば,便利である.コールバックで実装することも可能であるが,DirectShowでは,これをWindows のメッセージを機能を利用し,アプリケーション側にメッセージを送信することができる.そのプログラミングについて説明する.

メッセージ送信の設定

まず,IMediaEventExのインタフェースのポインタをグラフビルダから取得する.

hResult = m_pGraph->QueryInterface(IID_IMediaEventEx, (void **) &m_pMediaEvent);
if (hResult != S_OK)return FALSE;

このインタフェースを利用し,イベントを処理する.IMediaEventExのメソッド,SetNotifyWindowを使い,ビルダがメッセージを送信するウィンドウを指定する.指定にはウィンドウハンドルを利用する.具体的には以下のように設定する.

hResult = m_pMediaEvent->SetNotifyWindow((OAHWND)this->m_hWnd, WM_DSHOW,0);
if (hResult != S_OK)return FALSE;

第1引数がメッセージの送信先のウィンドウハンドル,第2引数がメッセージの識別子となる.第3引数がメッセージを受け取るときのパラメータWPARAMとなる.第2引数は,他のメッセージと重複することはあってはならないため,ユーザ用の未定義値を利用する.これには,WM_APPを利用する.

#define    WM_DSHOW    WM_APP+1

このウィンドウメッセージを処理する.

受信側のコーディング

SDKのAPIを利用する場合は,WM_PAINTなどと並んで,WM_DSHOWを処理する.MFCの場合には,以下のようにオリジナルのメッセージハンドラを実装する.

BEGIN_MESSAGE_MAP(CDirectShowSkeltonMFCExView, CView)
//\{\{AFX_MSG_MAP(CDirectShowSkeltonMFCExView)
ON_WM_SIZE()
ON_MESSAGE(WM_DSHOW,CDirectShowSkeltonMFCExView::OnWMDSHOW ) // 追加
//\}\}AFX_MSG_MAP
END_MESSAGE_MAP()

これで,MFCを利用する場合,メッセージ受信時にOnWMDSHOWが呼び出されることとなる.しかし,受信しても,グラフビルダで何が行ったかはこのままではわからない.DirectShowで発生するイベントは,すべてがそのまま送信されるのではない.DirectShow側の細かいイベントは,IMediaEventExインタフェースを通して,取り出すことになる.WM_DSHOWメッセージ受信時にIMediaEventExからDirectShowイベントを取得する.
このイベント処理は,EventHandleで実装する.

void HandleEvent(void){
long evCode, param1, param2;
HRESULT hResult;
// イベントキューからイベントを取り出す
while (hResult = m_pMediaEvent->GetEvent(&evCode, ¶m1, ¶m2, 0), SUCCEEDED(hResult)){
// 上で取り出したイベントを消去する
hResult = m_pMediaEvent->FreeEventParams(evCode, param1, param2);
if ((EC_USER == evCode)){
if( param1 == PARAM_MESSAGE_FROM_FILTER && param2==PARAM_MESSAGE_FROM_FILTER){
this->MessageBox("フィルタからメッセージを受け取りました.","DirectShowSkeltonMFCEx",MB_OK);
break;
〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
}

 まず,IMediaEventExのGetEventメソッドでメッセージを取得する.取得したメッセージは,FreeEventParamsで消去する.DirectShowのメッセージは処理されるまで,バッファに残るため,このように処理したメッセージは明示的に消去する必要がある.取得した情報は,ここで自由に処理することができる.

送信側のコーディング

DirectShowのメッセージは,フィルタからも送信することができる.これは,NotifyEventメソッドで送信することができる.

NotifyEvent( EC_USER, wParam, lParam );

 ここでの第1引数が,DirectShowメッセージの識別子であり,第2,3引数がDirectShowメッセージのパラメータとなる.
 DirectShowのビルダグラフもメッセージを送信する.たとえば,EC_COMPLETEは,すべてのストリームが再生が終わった場合に送信される.他にもデバイスを失ったときなどメッセージが送信されるタイミングがある.これは,ヘルプに記載されている.MSDNを参考にされたい.
http://code.google.com/p/sonson-code/source/browse/#svn/trunk/win/DirectShow/ThroughEx