標準プレゼンタのカスタマイズ
EVRをアプリケーションで作成したウィンドウに表示するようにします。そのために、EVRの標準プレゼンタのインターフェイスを取得し、ウィンドウハンドルを設定します。
まず、EVRからIMFGetServiceインターフェイスを取得します。そして、IMFGetService::GetServiceを使って標準プレゼンタのIMFVideoDisplayControlインターフェイスを取得します。IMFVideoDisplayControl::SetVideoWindowでウィンドウハンドルを指定します。
次に、IMFVideoDisplayControl::SetVideoPositionを使って転送元矩形と転送先矩形を指定します。転送元矩形はMFVideoNormalizedRect構造体で指定するのですが、ピクセル単位ではなく、左上が(0,0)、右下が(1,1)となることに注意して下さい。
CComPtr<IMFVideoDisplayControl> m_Vdc;
CComQIPtr<IMFGetService> service(m_Evr);
hr=service->GetService(MR_VIDEO_RENDER_SERVICE,
IID_IMFVideoDisplayControl, (void**)&m_Vdc);
hr=m_Vdc->SetVideoWindow(m_hWnd);
MFVideoNormalizedRect mvnr={0, 0, 1, 1};
RECT rect;
GetClientRect(&rect);
hr=m_Vdc->SetVideoPosition(&mvnr, &rect);
ウォーターマークの作成と適用
動画をウィンドウに表示できるようになったので、続いてウォーターマークを作成し、適用しましょう。
ウォーターマークはGDIのビットマップまたはDirect3D9サーフェイスを用意しておき、それをビデオフレームに合成することによって実現します。今回はGDIのビットマップを用意し、TextOut Win32 APIで「Use EVR with WaterMark」という文字列を描画したウォーターマークをEVRに割り当てます。
まず、IMFGetService::GetServiceを使ってIMFVideoMixerBitmapインターフェイスを取得します。
hr=service->GetService(MR_VIDEO_MIXER_SERVICE, IID_IMFVideoMixerBitmap, (void**)&m_MixerBitmap);
次に、用意したビットマップをEVRに割り当てます。そのためにMFVideoAlphaBitmap構造体でどのように合成するか指定し、IMFVideoMixerBitmap::SetAlphaBitmapを呼び出します。MFVideoAlphaBitmapはMFVideoAlphaBitmapParamを包含しています(表1、表2)。
| 型 | メンバ変数名 | 内容 |
| BOOL | GetBitmapFromDC | TRUEであればhdcメンバが有効。FALSEであればpDDsメンバが有効。つまりウォーターマークとしてGDIビットマップを使うかDirect3D9サーフェイスを使うか。 |
| HDC | hdc | ウォーターマークとなるGDIビットマップのデバイスコンテキスト。 |
| IDirect3DSurface9 | pDDs | ウォーターマークとなるDirect3D9サーフェイス。 |
| MFVideoAlphaBitmapParams | params | MFVideoAlphaBitmapParams構造体。 |
| 型 | メンバ変数名 | 内容 |
| DWORD | dwFlags | MFVideoAlphaBitmapFlagsの組み合わせで、どの構造体メンバが有効かを示す。 |
| COLORREF | clrSrcKey | ソースカラーキー。 |
| RECT | rcSrc | 転送元矩形。 |
| MFVideoNormalizedRect | nrcDest | 転送先矩形。 |
| FLOAT | fAlpha | 透明度。0で完全に透明。1.0で不透明。 |
| DWORD | dwFilterMode | Direct3Dのフィルタリングモード。D3DTEXTUREFILTERTYPEで指定する。 |
// HDC hdcBmp ウォーターマークを描くためのデバイスコンテキスト
// HBITMAP m_WaterMarkBmp ウォーターマークが描かれるビットマップハンドル
MFVideoAlphaBitmap bmpInfo={0};
ZeroMemory(&bmpInfo, sizeof(bmpInfo));
bmpInfo.GetBitmapFromDC=TRUE;
bmpInfo.bitmap.hdc=hdcBmp;
bmpInfo.params.clrSrcKey=0;
bmpInfo.params.dwFlags=
MFVideoAlphaBitmap_Alpha | MFVideoAlphaBitmap_DestRect |
MFVideoAlphaBitmap_SrcColorKey;
bmpInfo.params.fAlpha=0.8f;
MFVideoNormalizedRect dst={0, 0, 1.0f, 0.25f};
bmpInfo.params.nrcDest=dst;
BITMAP bm;
GetObject(m_WaterMarkBmp, sizeof(BITMAP), &bm);
SetRect(&bmpInfo.params.rcSrc, 0, 0, bm.bmWidth, bm.bmHeight);
hr=m_MixerBitmap->SetAlphaBitmap(&bmpInfo);
再描画とリサイズの処理
ウィンドウが再描画されたり、リサイズされたりしたときは、それをEVRのプレゼンタに伝える必要があります。再描画のときはRepaintVideo、リサイズのときはSetVideoPositionを呼び出します。
LRESULT CMyWindow::OnPaint(UINT, WPARAM, LPARAM, BOOL&) {
m_Vdc->RepaintVideo();
return DefWindowProc();
}
LRESULT CMyWindow::OnSize(UINT, WPARAM, LPARAM, BOOL&) {
MFVideoNormalizedRect mvnr={0, 0, 1, 1};
RECT rect;
GetClientRect(&rect);
m_Vdc->SetVideoPosition(&mvnr, &rect);
return 0;
}
動作確認
それでは動作を確認してみましょう。適当な動画ファイルを用意して再生してみます。サンプルコードでは、USE_EVR1.cppに直接ファイル名を指定しているので適当に書き換えてください。
アプリケーションを実行すると、ウィンドウが表示され、半透明のウォーターマークとともに動画が表示されます(図2)。

まとめ
本稿では、EVRの概要について説明し、動画を再生するアプリケーションを作成しました。また、GDIビットマップを用意し、ウォーターマークとして合成しました。
「EVRの概要」でも述べたように、EVRはMedia FoundationとDirectShow両方で使うことができます。Media FoundationはWindows 7で機能強化され、DirectShowに代わるマルチメディアプラットフォームとなっていくと思われますが、ゼロからMedia Foundationを始めると覚えることが多くて大変です。まずはEVRを使ってみるところから始めてみてはいかがでしょうか。
