DVDを再生する(MFC)

前述したDVD再生サンプルでは、自作のウィンドウではなくDefaultのウィンドウを利用しての再生でした。 ここでは、MFCの自作ウィンドウを使ってDVDを再生する方法を説明したいと思います。 (注意)ここの例では、サンプルを簡潔にするためにエラー処理を書いていません。

MFCを使ったウィンドウでのDVD再生サンプル

このサンプルのMFC部分は、「MPEGファイルを再生する3」で説明した内容とほぼ同じです。 違いはDVD graphを作成する部分と、RenderFileをしていないという2点だけです。

このコードは、DVDドライブに入っているDVDをはじめから再生します。 DVDの再生開始は、ウィンドウ内で何らかのキーを押した後に行われます。 ウィンドウ内でキーを押した時にDVDがドライブに入っていない場合には動作しません。 また、私の環境では何故かVisual Studioから起動すると画面が現れませんでした。 もし、動かない場合にはコマンドプロンプトから実行してみてください。


#include <afxwin.h>

#include <dshow.h>

#define	WM_GRAPH_NOTIFY		(WM_APP + 1)

class CMainWin : public CFrameWnd
{
public:
	CMainWin();
	~CMainWin();
	DECLARE_MESSAGE_MAP()

private:
	IDvdGraphBuilder *pDvdGraphBuilder;
	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_DvdGraphBuilder,
       NULL,
       CLSCTX_INPROC_SERVER,
       IID_IDvdGraphBuilder,
       (LPVOID *)&pDvdGraphBuilder);

   AM_DVD_RENDERSTATUS stat;
   pDvdGraphBuilder->RenderDvdVideoVolume(NULL,
       AM_DVD_HWDEC_PREFER, &stat);

   pDvdGraphBuilder->GetFiltergraph(&pGraphBuilder);

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

   pGraphBuilder->QueryInterface(IID_IMediaEventEx,
       (LPVOID *)&pMediaEventEx);
   pMediaEventEx->SetNotifyWindow((OAHWND)GetSafeHwnd(),
       WM_GRAPH_NOTIFY, NULL);

   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,
				&param1, &param2, 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;