イベントが発生した場合の学習
[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayer、IMFMediaEngine、Audio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]
DirectShow イベントを処理するには、アプリケーションでイベントがキュー内で待機しているタイミングを確認する方法が必要です。 フィルター グラフ マネージャーには、次の 2 つの方法があります。
- ウィンドウ通知: フィルター グラフ マネージャーは、新しいイベントが発生するたびに、ユーザー定義の Windows メッセージをアプリケーション ウィンドウに送信します。
- イベント シグナリング: フィルター グラフ マネージャーは、キューに DirectShow イベントがある場合は Windows イベントを通知し、キューが空の場合はイベントをリセットします。
アプリケーションでは、どちらの手法も使用できます。 通常、ウィンドウ通知の方が簡単です。
ウィンドウ通知
ウィンドウ通知を設定するには、 IMediaEventEx::SetNotifyWindow メソッドを呼び出し、プライベート メッセージを指定します。 アプリケーションでは、WM_APPから0xBFFFまでの範囲のメッセージ番号をプライベート メッセージとして使用できます。 フィルター グラフ マネージャーは、キューに新しいイベント通知を送信するたびに、このメッセージを指定されたウィンドウに投稿します。 アプリケーションは、ウィンドウのメッセージ ループ内からメッセージに応答します。
次のコード例は、通知ウィンドウを設定する方法を示しています。
#define WM_GRAPHNOTIFY WM_APP + 1 // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
メッセージは通常の Windows メッセージであり、DirectShow イベント通知キューとは別に投稿されます。 この方法の利点は、ほとんどのアプリケーションが既にメッセージ ループを実装していることです。 そのため、DirectShow イベント処理を追加作業なしで組み込むことができます。
次のコード例は、通知メッセージに応答する方法の概要を示しています。 完全な例については、「 イベントへの応答」を参照してください。
LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
switch (msg)
{
case WM_GRAPHNOTIFY:
HandleEvent(); // Application-defined function.
break;
// Handle other Windows messages here too.
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
イベント通知とメッセージ ループはどちらも非同期であるため、アプリケーションがメッセージに応答する時点までにキューに複数のイベントが含まれる場合があります。 また、イベントが無効になった場合は、キューからクリアされることがあります。 そのため、イベント処理コードでは、キューが空であることを示すエラー コードが返されるまで IAMMediaEvent::GetEvent を呼び出します。
IMediaEventEx ポインターを解放する前に、NULL ポインターで SetNotifyWindow を呼び出してイベント通知を取り消します。 イベント処理コードで、GetEvent を呼び出す前に IMediaEventEx ポインターが有効かどうかをチェックします。 これらの手順では、 IMediaEventEx ポインターを解放した後にアプリケーションがイベント通知を受け取る可能性のあるエラーを防ぎます。
イベント シグナリング
Filter Graph Manager は、イベント キューの状態を反映する手動リセット イベントを保持します。 キューに保留中のイベント通知が含まれている場合、フィルター グラフ マネージャーは手動リセット イベントを通知します。 キューが空の場合、 IMediaEvent::GetEvent メソッドを呼び出すとイベントがリセットされます。 アプリケーションは、このイベントを使用してキューの状態を判断できます。
注意
この用語は、ここでは混乱を招く可能性があります。 手動リセット イベントは、Windows CreateEvent 関数によって作成されたイベントの種類です。DirectShow によって定義されたイベントとは関係ありません。
IMediaEvent::GetEventHandle メソッドを呼び出して、手動リセット イベントのハンドルを取得します。 WaitForMultipleObjects などの関数を呼び出して、イベントが通知されるまで待ちます。 イベントが通知されたら、 IMediaEvent::GetEvent を呼び出して DirectShow イベントを取得します。
この方法を次のコード例に示します イベント ハンドルを取得し、イベントが通知されるまで 100 ミリ秒間隔で待機します。 イベントが通知されると、 GetEvent が呼び出され、イベント コードとイベント パラメーターがコンソール ウィンドウに出力されます。 EC_COMPLETE イベントが発生すると、ループは終了し、再生が完了したことを示します。
HANDLE hEvent;
long evCode, param1, param2;
BOOLEAN bDone = FALSE;
HRESULT hr = S_OK;
hr = pEvent->GetEventHandle((OAEVENT*)&hEvent);
if (FAILED(hr))
{
/* Insert failure-handling code here. */
}
while(!bDone)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
{
while (S_OK == pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0))
{
printf("Event code: %#04x\n Params: %d, %d\n", evCode, param1, param2);
pEvent->FreeEventParams(evCode, param1, param2);
bDone = (EC_COMPLETE == evCode);
}
}
}
フィルター グラフでは、必要に応じてイベントが自動的に設定またはリセットされるため、アプリケーションでは設定しないでください。 また、フィルター グラフを解放すると、フィルター グラフはイベント ハンドルを閉じるので、その後にイベント ハンドルを使用しないでください。