一般步骤:
-
创建Graph Builder接口
-
创建VMR接口并加入到GraphBuiler中
-
查询IVMRFilterConfig接口设置VMR为VMRMode_Windowless模式;查询IVMWindowlessControl接口设置VMR的显示窗口为Application的窗口。
-
Render视频文件
-
SetVideoPositon设置视频显示的位置
-
查询IMedialControl接口并Run
-
相应WM_PAINT消息,注意分别重绘挖去视频窗口的背景和视频窗口(pWc->RepaintVideo)
-
清理工作(何时清理那些接口,目前还不清楚,以后再研究^_^)
还是先写注意吧,因为注意容易忘,而过程写起来比较困难些,呵呵
注意:
-
播放没有自己的窗口,是直接把视频绘制(Paint)在Application的窗口上的,所以当Application需要响应WM_PAINT消息的时候,要注意对视频的绘制(Paint)。
此时,Windowless的视频播放“窗口”(实际上是windowless的)和Application的窗口应该分开来单独重绘(相应WM_PAINT)。
首先,检测Application的窗口上windowless的视频窗口中是否有video: if (pWc). 其中pWc是创建的IVMRWindowlessControl接口。如果pWc != NULL则表示有video,此时通过创建一个CombineRgn把windowless窗口挖去,先重绘这个CombineRgn,然后再调用 pWc->RepaintVideo重绘windowless视频窗口。即
void OnPaint(HWND hwnd) { PAINTSTRUCT ps; HDC hdc; RECT rcClient; GetClientRect(hwnd, &rcClient); hdc = BeginPaint(hwnd, &ps); if(g_pWc) { HRGN rgnClient = CreateRectRgnIndirect(&rcClient); HRGN rgnVideo = CreateRectRgnIndirect(&g_rcDest); // Saved from earlier. CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF); // Paint on this region. HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE); FillRgn(hdc, rgnClient, hbr); DeleteObject(hbr); DeleteObject(rgnClient); DeleteObject(rgnVideo); // Request the VMR to paint the video. HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc); } else // No video image. Just paint the whole client area. { FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1)); } EndPaint(hwnd, &ps); }
-
VMR COM接口的类型是 IBaseFilter、 CoCreateInstance第三参数是IID_IBaseFilter
Graph Buider的是IGraphBuilder、CoCreateInstance第三参数是IID_IGraphBuilder
-
创建了VMR实例接口后,应该把该Filter加入到Graph Builder中去。
pGraph->AddFilter(pVmr, L"Video Mixing Render"); //第二个参数似乎可以随便取个名字,只是个名称而已
-
创建了VMR并加入到Graph Builder中后,应该配置VMR。这里需要先后查询两个接口:IVMRFilterConfig和IVMRWindowlessControl,设置渲染模式为windowless( pConfig->SetRenderingMode)、设置VMR的窗口为Application的窗口( pWc->SetVideoClippingWindow(hWinMain))
-
还需要指定windowless视频窗口在Application窗口中的位置:pWc->SetVideoPositon(&rcSrc, &rcDest)。这里有两个RECT,分别代表源视频的尺寸区域和要显示在窗口上的区域尺寸。可以通过pWc->GetNativeVideoSize((&lWidth, &lHeight, NULL, NULL)获得源区域尺寸,然后设定要取源画面的多少尺寸Rect:SetRect(&rcSrc, 0, 0, lWidth/2, lHeight/2)//此时只取源画面的1/2。再设定好显示的区域rcDest后用pWc->SetVideoPositon设定。
-
COLOR_BTNFACE + 1是什么意思?好像+1不+1都差不多呀?