DirectShow提供两种窗口模式:Windowed Mode 和 Windowless Mode。
Windowed Mode:DS创建一个属于自己的窗口,在自己创建的窗口上显示视频。通过IVideoWindow接口来管理这个窗口,适用于Video Renderer filter。
Windowless Mode:DS不提供自己创建的窗口,而是要应用程序提供窗口,用户可以将视频显示在自己指定的任意的窗口上。通过IVMRFilterConfig和 IVMRWindowlessControl来控制显示属性,适用于Video Mixing Renderer Filter 7 (VMR-7) 和 Video Mixing Renderer Filter 9 (VMR-9)。
上一篇文章属于Windowed Mode,只需要再QueryInterface出IVideoWindow接口的指针,即可通过IVideoWindow的各种功能函数设置窗口的属性。
Windowless Mode复杂一点,需要先指定窗口。下面的程序摘自MSDN(MSDN中的原始代码有一点点小错误,这里已经修改过来)
指定窗口函数:
HRESULT InitWindowlessVMR(
HWND hwndApp, // 指定窗口的句柄,输入参数
IGraphBuilder* pGraph, // Filter Graph Manager指针,输入参数.
IVMRWindowlessControl** ppWc // 输出参数.
)
{
if (!pGraph || !ppWc) return E_POINTER;
IBaseFilter* pVmr = NULL;
IVMRWindowlessControl* pWc = NULL;
// Create the VMR.
HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
if (FAILED(hr))
{
return hr;
}
// Add the VMR to the filter graph.
hr = pGraph->AddFilter(pVmr, L"Video Mixing Renderer");
if (FAILED(hr))
{
pVmr->Release();
return hr;
}
// Set the rendering mode.
IVMRFilterConfig* pConfig;
hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
if (SUCCEEDED(hr))
{
hr = pConfig->SetRenderingMode(VMRMode_Windowless);
pConfig->Release();
}
if (SUCCEEDED(hr))
{
// Set the window.
hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);
if( SUCCEEDED(hr))
{
hr = pWc->SetVideoClippingWindow(hwndApp);
if (SUCCEEDED(hr))
{
*ppWc = pWc; // Return this as an AddRef'd pointer.
}
else
{
// An error occurred, so release the interface.
pWc->Release();
}
}
}
pVmr->Release();
return hr;
}
调用此函数播放视频文件的完整代码:
pGraph = NULL;
pControl = NULL;
pEvent = NULL;
pWLC = NULL;
HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
printf("ERROR - Could not initialize COM library");
return 0;
}
// Create the filter graph manager and query for interfaces.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void **)&pGraph);
if (FAILED(hr))
{
printf("ERROR - Could not create the Filter Graph Manager.");
return 0;
}
pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);
InitWindowlessVMR(hWnd,pGraph,&pWLC); //创建一个窗体,hWnd表示这个窗体
pWLC->GetNativeVideoSize(&lWidth,&lHeight,NULL,NULL);//获得视频的大小
pWLC->SetVideoPosition(rcSrc,rcClient);//通过lWidth和lHeight获得源视频的区域,rcSrc表示希望显示的视频区域,rcClient表示在窗口的哪个区域显示视频。
//播放视频
HRESULT hr = pGraph->RenderFile(L"D://Program//DXSDK//Samples//Media//chicken.wmv", NULL);
if (SUCCEEDED(hr))
{
// Run the graph.
hr = pControl->Run();
if (SUCCEEDED(hr))
{
// Wait for completion.
long evCode;
pEvent->WaitForCompletion(INFINITE, &evCode);
// Note: Do not use INFINITE in a real application, because it
// can block indefinitely.
}
}
pWLC->Release();
pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();
如果不希望这个窗口被阻塞,将播放视频的代码放到一个工作线程中执行。