IMediaEventEx::SetNotifyWindowを使った再生終了通知
先ほどの例では、RenderFile()を使ってMFCで作成したウィンドウでMPEGファイルを再生する方法を解説しました。 しかし、先ほどの例では、映像再生終了までWaitForCompletion()でブロックしてしまっていました。 ここでは、再生の終了などのイベントをウィンドウメッセージとして受け取る方法を説明します。 (注意)ここの例では、サンプルを簡潔にするためにエラー処理を書いていません。
とりあえず、コードを書いてみる
まず、何も考えずに以下のコードを書いてみましょう。 先ほどを同じく、MFCを使って「C:\DXSDK\Samples\media\water.mpg」というMPEGファイルを再生します。
#include <afxwin.h>
#include <dshow.h>
#define FILENAME L"c:\\DXSDK\\Samples\\Media\\butterfly.mpg"
#define WM_GRAPH_NOTIFY (WM_APP + 1)
class CMainWin : public CFrameWnd
{
public:
CMainWin();
~CMainWin();
DECLARE_MESSAGE_MAP()
private:
IGraphBuilder *pGraphBuilder;
IMediaControl *pMediaControl;
IMediaEventEx *pMediaEventEx;
IVideoWindow *pVideoWindow;
bool bRunning;
protected:
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
LRESULT OnGraphNotify(WPARAM wParam, LPARAM lParam);
};
CMainWin::CMainWin()
{
Create(NULL, "Sample");
bRunning = false;
CoInitialize(NULL);
}
CMainWin::~CMainWin()
{
if (pMediaEventEx != NULL) {
pMediaEventEx->Release();
}
if (pMediaControl != NULL) {
pMediaControl->Release();
}
if (pVideoWindow != NULL) {
pVideoWindow->Release();
}
if (pGraphBuilder != NULL) {
pGraphBuilder->Release();
}
CoUninitialize();
}
void
CMainWin::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (bRunning == false) {
CoCreateInstance(CLSID_FilterGraph,
NULL,
CLSCTX_INPROC,
IID_IGraphBuilder,
(LPVOID *)&pGraphBuilder);
pGraphBuilder->QueryInterface(IID_IMediaControl,
(LPVOID *)&pMediaControl);
pGraphBuilder->QueryInterface(IID_IMediaEventEx,
(LPVOID *)&pMediaEventEx);
pMediaEventEx->SetNotifyWindow((OAHWND)GetSafeHwnd(),
WM_GRAPH_NOTIFY, NULL);
pMediaControl->RenderFile(FILENAME);
pGraphBuilder->QueryInterface(IID_IVideoWindow,
(LPVOID *)&pVideoWindow);
pVideoWindow->put_Owner((OAHWND)GetSafeHwnd());
pVideoWindow->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS);
RECT rect;
GetClientRect(&rect);
pVideoWindow->SetWindowPosition(0, 0,
rect.right - rect.left,
rect.bottom - rect.top);
pVideoWindow->put_Visible(OATRUE);
pVideoWindow->SetWindowForeground(OATRUE);
pMediaControl->Run();
bRunning = true;
}
}
// イベントが発生すると呼び出される
LRESULT
CMainWin::OnGraphNotify(WPARAM wParam, LPARAM lParam)
{
long evCode;
LONG param1, param2;
// イベントを全て取得
while (SUCCEEDED(pMediaEventEx->GetEvent(&evCode,
¶m1, ¶m2, 0))) {
pMediaEventEx->FreeEventParams(evCode, param1, param2);
switch (evCode) {
case EC_COMPLETE:
// 再生終了
MessageBox("EC_COMPLETE");
break;
}
}
return NOERROR;
}
class CApp : public CWinApp
{
public:
BOOL InitInstance();
};
BOOL CApp::InitInstance()
{
m_pMainWnd = new CMainWin;
m_pMainWnd->ShowWindow(m_nCmdShow);
m_pMainWnd->UpdateWindow();
return true;
}
BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd)
ON_WM_CHAR()
ON_MESSAGE(WM_GRAPH_NOTIFY, OnGraphNotify)
END_MESSAGE_MAP()
CApp App;
上記コードは、まず、最初にウィンドウを表示します。 表示されたウィンドウで何らかのキーボードをたたくと、MPEGファイルの再生が始まります。 MPEGファイルの再生が終了すると、OnGraphNotify()が呼び出されます。 OnGraphNotify()は、MessageBoxで「EC_COMPLETE」と表示します。 それ以上は何も動かないので、ウィンドウ右上の×をクリックして終了してください。
このプログラムのポイントを以下に示します。
- IMediaEventExインターフェースへのポインタを取得します。
- ウィンドウイベントの値を定義します。上記例では、WM_GRAPH_NOTIFYというdefineをしました。
- Notificationを送信するウィンドウ(OAHWND)をSetNotifyWindow()で設定します。
- ON_MESSAGE()を使ってイベントハンドラを設定します。
- IMediaEventEx::GetEvent()でイベントを取得します。
IMediaEventExはIMediaEventインターフェースを継承しています。 そのため、上記サンプルではIMediaEvent::GetEvent()をIMediaEventEx *pMediaEventExから使っています。
上記コードは、SetNotifyWindow()の利用例を示すために色々省いて書いているので、全く実用性がありません。 用途に応じて、Run()や各種ポインタの保持方法を変えてください。(^_^;)