概述
概述
DirectShow提供了几种渲染视频的滤镜:
·Video Renderer filter:此过滤器适用于支持DirectX的所有平台,并且没有特定的系统要求。 Video Renderer尽可能使用DirectDraw来呈现视频; 否则,它使用GDI。 此筛选器是比Windows XP早的平台上的默认视频渲染器。
·Video Mixing Renderer Filter 7 (VMR-7):VMR-7在Windows XP上可用,它是默认的视频渲染器。 VMR-7总是使用DirectDraw 7进行渲染。 它提供了旧版Video Renderer过滤器中没有的许多强大功能,包括应用程序控制用于渲染的DirectDraw表面的插件模型。
·Video Mixing Render Filter 9 (VMR-9):VMR-9是使用Direct3D 9进行渲染的视频混合渲染器的更新版本。 它适用于支持DirectX的所有平台。 但它不是默认的渲染器,因为它比Video Renderer过滤器具有更高的系统要求。
·Overlay Mixer滤镜专为DVD播放和广播视频而设计。 它还支持视频端口扩展(VPE),使其能够与硬件MPEG-2解码器或将视频直接发送到图形卡的模拟电视调谐器。
·增强视频渲染器(EVR)过滤器在Windows Vista中可用。 与早期的视频渲染器相比,它提供了改进的视频性能,尤其是在启用Windows Vista桌面组合时
DirectShow视频渲染器可以在窗口模式或无窗口模式下运行:
·在窗口模式下,渲染器创建自己的窗口来显示视频。 通常,您将使此窗口成为应用程序窗口的子项。
·在无窗口模式下,渲染器将视频直接拖到应用程序窗口上。 它不创建它自己的窗口
Video Renderer过滤器仅支持窗口模式。 VMR-7和VMR-9过滤器支持这两种模式。 它们默认为窗口模式以实现向后兼容,但无窗口模式是首选。 EVR仅支持无窗口模式。
Choosing the Right Video Renderer
主要使用哪个渲染器取决于您需要支持哪些版本的Windows
·在Windows Vista及更高版本中,如果硬件支持,则应用程序应使用EVR。 否则,回到VMR-9或VMR-7。 EVR提供比以前的渲染器更好的性能和更好的视频质量。 此外,它旨在与桌面窗口管理器(DWM)一起使用。
·在Windows Vista之前,如果硬件支持它并且不需要视频端口功能,请使用VMR-9。 否则,请使用VMR-7。
·在较旧的系统上,您可能需要使用Overlay Mixer(用于视频端口或硬件叠加支持)或旧式Video Renderer过滤器。
IGraphBuilder :: Render和RenderFile方法默认使用VMR-7。 如果硬件不支持VMR-7,这些方法将回退到传统的Video Renderer过滤器。 EVR和VMR-9绝不是默认的渲染器。
窗口模式
在窗口模式下,视频渲染器创建自己的窗口,在该窗口绘制视频帧。 除非另有说明,否则此窗口是具有自己的边框和标题栏的顶层窗口。 但是,大多数情况下,您会将视频窗口附加到应用程序窗口,以便将视频集成到应用程序UI中。 这需要以下步骤:
1.查询IVideoWindow。
2.设置父窗口。
3.设置新的窗口样式。
4.将视频窗口放置在所有者窗口内。
5.通知WM_MOVE消息的视频窗口。
Query for IVideoWindow
在开始播放之前,请在Filter Graph Manager中查询IVideoWindow接口
IVideoWindow *pVidWin = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
Set the Parent Window
要设置父窗口,请调用带有应用程序窗口句柄的IVideoWindow :: put_Owner方法。 这个方法接受一个OAHWND类型的变量,所以把句柄转换为这种类型:
pVidWin->put_Owner((OAHWND)hwnd);
Set New Window Styles
通过调用IVideoWindow :: put_WindowStyle方法来更改视频窗口的样式:
pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
WS_CHILD标志将窗口设置为子窗口,并且WS_CLIPSIBLINGS标志防止窗口在另一个子窗口的客户区域内绘制。
Position the Video Window
要设置视频相对于应用程序窗口客户区的位置,请调用IVideoWindow :: SetWindowPosition方法。 此方法采用指定视频窗口的左边缘,顶边缘,宽度和高度的矩形。 例如,以下代码将视频窗口拉伸到适合父窗口的整个客户区:
RECT rc;
GetClientRect(hwnd, &rc);
pVidWin->SetWindowPosition(0, 0, rc.right, rc.bottom);
要获得视频的原始大小,请在Filter Graph Manager上调用IBasicVideo :: GetVideoSize方法。 您可以使用该信息来缩放视频并保持正确的宽高比。
Respond to WM_MOVE Messages
为了获得最佳性能,每当窗口在图形暂停时移动时,都应通知视频渲染器。 调用IVideoWindow :: NotifyOwnerMessage方法来转发WM_MOVE消息:
// (Inside your WindowProc)
case WM_MOVE:
pVidWin->NotifyOwnerMessage((OAHWND)hWnd, msg, wParam, lParam);
break;
如果渲染器正在使用硬件叠加层,则此通知将导致渲染器更新叠加层位置。 (VMR-9不使用叠加层,因此如果您使用VMR-9,则无需调用此方法。)
Cleap Up
在应用程序退出之前,停止图形并将视频窗口的所有者重置为NULL。 否则,窗口消息可能被发送到错误的窗口,这可能会导致错误。 此外,隐藏视频窗口,否则您可能会在屏幕上瞬间看到视频图像闪烁:
pControl->Stop();
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);
无窗口模式
Configure the VMR for Windowless Mode
·VMR-7
1.创建过滤器图形管理器。
2.创建VMR-7并将其添加到过滤器图形中。
3.使用VMRMode_Windowless标志在VMR-7上调用IVMRFilterConfig :: SetRenderingMode。
4.查询IVMRWindowlessControl接口的VMR-7。
5.在VMR-7上调用IVMRWindowlessControl :: SetVideoClippingWindow。指定视频应该出现的窗口的句柄。
·VMR-9
1.创建过滤器图形管理器。
2.创建VMR-9并将其添加到过滤器图形中。
3.使用VMR9Mode_Windowless标志调用VMR-9上的IVMRFilterConfig9 :: SetRenderingMode。
4.查询IVMRWindowlessControl9界面的VMR-9。
5.在VMR-9上调用IVMRWindowlessControl9 :: SetVideoClippingWindow。 指定视频应该出现的窗口的句柄。
以下代码显示了一个辅助函数,它可以创建VMR-7,将其添加到图形中,并设置无窗口模式。
HRESULT InitWindowlessVMR(
HWND hwndApp, // Window to hold the video.
IGraphBuilder* pGraph, // Pointer to the Filter Graph Manager.
IVMRWindowlessControl** ppWc // Receives a pointer to the VMR.
)
{
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;
}
此功能假定仅显示一个视频流,而不是在视频上混合静态位图。你可以这样调用这个函数:
IVMRWindowlessControl *pWc = NULL;
hr = InitWindowlessVMR(hwnd, pGraph, &g_pWc);
if (SUCCEEDED(hr))
{
// Build the graph. For example:
pGraph->RenderFile(wszMyFileName, 0);
// Release the VMR interface when you are done.
pWc->Release();
}
Positon the Video
·VMR-7
1.调用IVMRWindowlessControl :: SetVideoPosition方法来指定两个矩形。
2.源矩形必须等于或小于原始视频大小; 您可以使用IVMRWindowlessControl :: GetNativeVideoSize方法获取原生视频大小。
·VMR-9
1.调用IVMRWindowlessControl9 :: SetVideoPosition方法来指定两个矩形。
2.源矩形必须等于或小于原始视频大小; 您可以使用IVMRWindowlessControl9 :: GetNativeVideoSize方法来获取原生视频大小。
例如,以下代码设置VMR-7的源矩形和目标矩形。 它将源矩形设置为等于整个视频图像,目标矩形等于整个窗口客户区:
// Find the native video size.
long lWidth, lHeight;
HRESULT hr = g_pWc->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
if (SUCCEEDED(hr))
{
RECT rcSrc, rcDest;
// Set the source rectangle.
SetRect(&rcSrc, 0, 0, lWidth, lHeight);
// Get the window client area.
GetClientRect(hwnd, &rcDest);
// Set the destination rectangle.
SetRect(&rcDest, 0, 0, rcDest.right, rcDest.bottom);
// Set the video position.
hr = g_pWc->SetVideoPosition(&rcSrc, &rcDest);
}
Handle Window Messages
·VMR-7
1.WM_PAINT。 调用IVMRWindowlessControl :: RepaintVideo。 此方法会导致VMR-7重新绘制最近的视频帧。 2.WM_DISPLAYCHANGE:调用IVMRWindowlessControl :: DisplayModeChanged。 此方法通知VMR-7必须以新的分辨率或颜色深度显示视频。
3.WM_SIZE或WM_WINDOWPOSCHANGED:重新计算视频的位置并在需要时调用IVMRWindowlessControl :: SetVideoPosition更新位置。
·VMR-9
1.WM_PAINT。 调用IVMRWindowlessControl9 :: RepaintVideo。 此方法会导致VMR-9重新绘制最近的视频帧。 2.WM_DISPLAYCHANGE:调用IVMRWindowlessControl9 :: DisplayModeChanged。 此方法通知VMR-9必须以新的分辨率或颜色深度显示视频。
3.WM_SIZE或WM_WINDOWPOSCHANGED:重新计算视频的位置并在需要时调用IVMRWindowlessControl9 :: SetVideoPosition更新位置。
以下示例显示了一个WM_PAINT消息处理程序。 它绘制由客户矩形减去视频矩形定义的区域。 不要在视频矩形上绘制,因为VMR会覆盖它,导致闪烁。 出于同样的原因,不要在窗口类中设置背景画笔。
void OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc;
RECT rcClient;
GetClientRect(hwnd, &rcClient);
hdc = BeginPaint(hwnd, &ps);
if (g_pWc != NULL)
{
// Find the region where the application can paint by subtracting
// the video destination rectangle from the client area.
// (Assume that g_rcDest was calculated previously.)
HRGN rgnClient = CreateRectRgnIndirect(&rcClient);
HRGN rgnVideo = CreateRectRgnIndirect(&g_rcDest);
CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF);
// Paint on window.
HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);
FillRgn(hdc, rgnClient, hbr);
// Clean up.
DeleteObject(hbr);
DeleteObject(rgnClient);
DeleteObject(rgnVideo);
// Request the VMR to paint the video.
HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc);
}
else // There is no video, so paint the whole client area.
{
FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1));
}
EndPaint(hwnd, &ps);
}
参考:
https://www.yuque.com/docs/share/6c6329ba-62e6-4b66-8d01-0c57d47828de
最后
以上就是健壮水杯为你收集整理的DirectShow之视频渲染的全部内容,希望文章能够帮你解决DirectShow之视频渲染所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复