DirectShow 提供了如下过滤器来显C频:
l Video Renderer qo?font face="Times New Roman">. 该过滤器可用于所有的支持DirectX的^収ͼ它对q_没有其它Ҏ的要求。可以是它,?font face="Times New Roman">GDI来显C频。它是在WindowsXP之前操作pȝ的默认视频显C滤器?/font>
l Video Mixing Renderer Filter 7 (VMR-7). VMR-7可用?font face="Times New Roman">WindowsXP操作pȝQƈ且是该系l下的默认视频显C滤器。与老的视频昄qo器相比,它具有一些更强大的性能Q包括采用插件模式来控制DirectShow昄?/font>
l Video Mixing Renderer Filter 9 (VMR-9). VMR-9是一个更新的视频混合昄qo器,它采用了Direct3D来显C。它可用于所有的支持DirectX的^台。它不是默认的显C滤器Q因为它与其它的昄qo器相比,对系l要求更高?/font>
一般来_在视频显C应用上Q?font face="Times New Roman">VMR-9是首选。因为,它用了最新的囑փAPIQƈ且提供了最好的性能?/font>
H体模式和非H体模式
DirectShow视频昄可以选择在窗体模式或者非H体模式下进行?/font>
l 在窗体模式下Q视频将创徏一个它自己的窗体来昄?/font>
l 在非H体模式下,视频可以自己在你E序的一个窗口上昄Q而不让视频自己区创徏H体来显C?/font>
Video Rendererqo器只支持H体模式Q?font face="Times New Roman">VMR-7?font face="Times New Roman">VMR-9支持q两U模式。它们默认状态是H体模式?/font>
在窗体模式下Q视频将创徏一个窗口,然后在该H口上显C频。大多数情况下,你可能想要把该窗口绑定到你的应用E序中。通过使用IVideoWindow接口Q可以设|视频窗口的cd和位|?/font>
在开始播攑։Q在qo器图表管理器中去查找IVideoWindow接口Q?/font>
IVideoWindow *pVidWin = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void **)&g_pVidWin);
调用IVideoWindow::put_OwnerҎd理你应用E序的窗体。该Ҏ提供了一?strong>OAHWNDcd的变量,所以要把句柄{换ؓ该类型:
pVidWin->put_Owner((OAHWND)hwnd);
调用IVideoWindow::Put_WindowStyle来改变视频窗体的cdQ?/font>
pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
WS_CHILD标志讄视频H体Z个子H体Q?font face="Times New Roman">WS_CLIPSIBLINGS标志可以防止视频H体在另一个子H体的客户区内显C频?/font>
调用IVideoWindow::SetWindowPositionҎ可以视频H口的相对于你应用程序的客户区的位置。该Ҏ的参数带了一?font face="Times New Roman">RECT参数Q用它去指定视频H口的位|。下例,让视频窗口和它父H体的客户区惛_配?/font>
RECT grc;
GetClientRect(hwnd, &grc);
pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);
通过在过滤器图表理器上调用IBaseicVide:GetVideoSizeҎ可以得到视频本n的尺寸大。你可以通过q些信息让视频保持正的U|比例?
在应用程序退出前Q停止图表ƈ重置视频H口?font face="Times New Roman">NULL。否则,H口消息可能被错误的发送给错误的窗口,从而导致错误发生,
pControl->Stop();
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);
视频混合昄qo器(VMR-7?font face="Times New Roman"> VMR-9Q都支持非窗体模式。这里将描述H体模式和非H体模式之间的不同,以及如何使用非模式窗体?
Z向后兼容已经在用的应用E序Q?font face="Times New Roman">VMR默认的显C模式ؓH体模式。在H体模式中,视频创徏一个它自己的窗体去昄视频。应用程序设|这个视频窗体ؓ它的一个子H体。这个单?a title=PPSp癄-存在 target=_blank>存在的窗体会D如下问题Q?
l 最严重的是Q?a title=PPSp癄-如果 target=_blank>如果H体的消息在U程间发送可能导致消息死锁?font face="Times New Roman">
l qo器图表管理器必须传递某?font face="Times New Roman">window消息Q比?font face="Times New Roman">WM_PAINTQ给视频昄?font face="Times New Roman">(Video Renderer)。这些对IvideoWIndow的操作必Lp滤器图表理器来完成Q而不是视频显C器来完成,所以要靠过滤器图表理器来U正内部状态?/font>
l 要视频窗体的鼠标或者键盘事Ӟ应用E序必须建立一?#8220;消息通道”Q让视频H口把消息传递给应用E序?font face="Times New Roman">
l Z防止剪接的情况,视频H体q必L有正的H口状态?font face="Times New Roman">
非窗体模式通过使用VMR直接在应用程序的客户Zd来避免了上述的问题。它使用DirectDrawd接视频矩形。非H体模式极大E度减少了死锁的偶然发生。同P应用E序不必去设|视频自w创建的H口和窗口的状态。事实上Q当VRM使用H体模式Ӟ它也不?strong>IVideoWindow接口?/font>
要用非H体模式Q你必须明确地去配置VMR。你会发现配|工作非常灵zdƈ且比H体模式更容易?/font>
在配|?font face="Times New Roman">VMR 前应建立qo器图?font face="Times New Roman">(Filter graph):
现在调用IGraphBuilder::RenderFile完成qo器图表余下的工作。过滤器图表理器将自动使用q个你添加到qo器图表中?font face="Times New Roman">VMR实例?/font>
下面代码昄了这些工作:
HRESULT InitWindowlessVMR(
HWND hwndApp, // 视频H体
IGraphBuilder* pGraph, // qo器图表指?font face="Times New Roman">
IVMRWindowlessControl** ppWc, // 接收VMR指针
)
{
if (!pGraph || !ppWc) return E_POINTER;
IBaseFilter* pVmr = NULL;
IVMRWindowlessControl* pWc = NULL;
// 创徏VMR
HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
if (FAILED(hr))
{
return hr;
}
// ?font face="Times New Roman">VMRd到过滤器图表?
hr = pGraph->AddFilter(pVmr, L"Video Mixing Renderer");
if (FAILED(hr))
{
pVmr->Release();
return hr;
}
// 讄昄模式
IVMRFilterConfig* pConfig;
hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
if (SUCCEEDED(hr))
{
hr = pConfig->SetRenderingMode(VMRMode_Windowless);
pConfig->Release();
}
if (SUCCEEDED(hr))
{
// 讄H体
hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);
if( SUCCEEDED(hr))
{
hr = pWc->SetVideoClippingWindow(hwndApp);
if (SUCCEEDED(hr))
{
*ppWc = pWc; //q回AddRef指针
}
else
{
pWc->Release();
}
}
}
pVmr->Release();
return hr;
}
该函数假设正在显CZ个视频流q没有合的静态位图。你看到按如下调用该函敎ͼ
IVMRWindowlessControl *pWc = NULL;
hr = InitWindowlessVMR(hwnd, pGraph, &g_pWc);
if (SUCCEEDED(hr))
{
// 建立图表
pGraph->RenderFile(wszMyFileName, 0);
//完成后释?font face="Times New Roman">VMR接口
pWc->Release();
}
视频定位
配置?font face="Times New Roman">VMR后,下一个步骤就是去讄视频昄的位|。有两个矩Ş位置要考虑Q一个是Source矩Ş位置Q一个是desitnation矩Ş位置?font face="Times New Roman">Source定义视频昄的位|?font face="Times New Roman">Destination指定包含视频的窗体的客户区的位置?font face="Times New Roman">VMR?font face="Times New Roman">source把图像按destination的尺寸匹配后昄出来?/font>
调用IVMRWindowlessControl::SetVideoPositionL定这个两个矩形位|?font face="Times New Roman">Source矩Ş的大必ȝ于或于视频本n的尺寸大;你可以?strong>IVMRWindowlessControl::GetNativeVideoSize去获得视频本w的寸?/font>
下面的实例,设|?font face="Times New Roman">Source{于视频寸1/4Q左上角的位|相{)Qƈ讄destination矩Ş{于H体客户区的大小1/Q左上角的位|相{)Q?/font>
// 获得视频自n寸大小
long lWidth, lHeight;
HRESULT hr = g_pWc->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
if (SUCCEEDED(hr))
{
RECT rcSrc, rcDest;
// 讄Source寸
SetRect(&rcSrc, 0, 0, lWidth/2, lHeight/2);
// 获得昄H体的客户区寸
GetClientRect(hwnd, &rcDest);
//讄destination寸
SetRect(&rcDest, 0, 0, rcDest.right/2, rcDest.bottom/2);
// 视频定位
hr = g_pWc->SetVideoPosition(&rcSrc, &rcDest);
}
处理H体消息
因ؓVMR没有自己的窗体,当视频需要重L者尺寸要改变是,你必要通知H体来适应?/font>
l 当接收到一?font face="Times New Roman">WM_PAINT消息Q可调用IVMRWindowlessControl::RepaintVideo 来重d像?font face="Times New Roman">
l 当接收到一?font face="Times New Roman">WM_DISPLAYCHANGE 消息, 可调?font face="Times New Roman"> IVMRWindowlessControl::DisplayModeChanged消息?font face="Times New Roman">VMR可以获得如下行为比如改变分辨率或者色深?font face="Times New Roman">
l 当接收到一?font face="Times New Roman">WM_SIZE 消息, 可以重新调用SetVideoPosition 来改变视频的昄位置?font face="Times New Roman">
下面昄如何处理WM_PAINT消息。它在H体的客户区重绘Q但是不会对视频昄的区域进行重l。不对视频显C的区域q行重绘Q是因ؓVMR会对该区域显C频,如果你的E序再对该区域重l会引v屏幕闪烁。也是应个原因,所有不要在你窗体类中去讄背景列?/font>
void OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc;
RECT rcClient;
GetClientRect(hwnd, &rcClient);
hdc = BeginPaint(hwnd, &ps);
if (g_pWc != NULL)
{
// 查找H体需要重l的客户区,该区域应该减去视频显C的区域
// (q里假设g_rcDest 是已l计好了的区域)
HRGN rgnClient = CreateRectRgnIndirect(&rcClient);
HRGN rgnVideo = CreateRectRgnIndirect(&g_rcDest);
CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF);
// 重绘H体
HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);
FillRgn(hdc, rgnClient, hbr);
// 释放对象
DeleteObject(hbr);
DeleteObject(rgnClient);
DeleteObject(rgnVideo);
// hVMR to 重绘视频
HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc);
}
else // 没有视频昄Q重l整个客户区
{
FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1));
}
EndPaint(hwnd, &ps);
}
1.接口不再使用XXXXX2/4/7,而是使用l一?/span>XXXXX, ?/span>:
LPDIRECTDRAW g_pDD = NULL;(?/span>)
LPDIRECTDRAW4 g_pDD = NULL;(?/span>)
新版?/span>不兼Ҏ版本.
2.在初始化LPDIRECTDRAW g_pDD的时候不再需?/span>QueryInterface,而是直接?/span> DirectDrawCreate(NULL, &g_pDD, NULL);完成.
3.DDCAPSl构改变,很多成员不再使用ddcaps.dwCaps&DDSCAP_XXX判断是否有这个功?/span>.而是Ҏ直接提供?/span>ddcaps.dwXXXCpas的成员是否ؓ0来判?/span>.q有很多的成员的改变Q这个看新的PB6.0的文?/span>
4. DDSURFACEDESC ddsd改动(只对?/span>Overlay)
不再使用 ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP | DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
中的DDSCAPS_COMPLEX | DDSCAPS_VIDEOMEMORY;
5.Overlay?/span>Alpha讄问题:
要Overlay有透明效果只要讄DDOVERLAYFX 中的 dwAlphaConst,dwAlphaConstBitDepth到合适的值就可以?br>