標準プレゼンタのカスタマイズ
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を使ってみるところから始めてみてはいかがでしょうか。