DirectShow之视频渲染
概述
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之视频渲染相关推荐
- madVR(视频渲染器)免费版 v0.92.17
madVR是一款高品质的DirectShow视频渲染器.该软件非常实用,能够兼容非常多的视频播放器,在播放器播放视频时,你可以通过该软件得到高质量的图像,madVR可以和绝大部分的播放器一起使用,像M ...
- webrtc 渲染_WebRTC 开发(六)摄像头采集与视频渲染分析
在上一篇文章 WebRTC 开发(五)编译与运行 Mac 工程 中,我们编译了 WebRTC 的工程 AppRTCMobile,也看到了 App 启动后的初始界面.本文基于 WebRTC M76 ,将 ...
- 在iOS端使用AVSampleBufferDisplayLayer进行视频渲染
原文在这里:http://blog.csdn.net/fernandowei/article/details/52179631 目前大多数iOS端的视频渲染都使用OpenGLES,但如果仅仅为了渲染而 ...
- 将 libVLC 视频渲染到 QWidget 中
作者:一去.二三里 个人微信号:iwaleon 微信公众号:高效程序员 在用 libVLC 播放视频时,会默认显示一个 Direct3D output 窗口.这个窗口不太美观,而且也没办法做一些定制, ...
- Android OpenGL ES视频渲染(一)GLSurfaceView
相关文章:Android OpenGL ES视频渲染(二)EGL+OpenGL Android中视频渲染有几种方式,之前的文章使用的是nativewindow(包括softwareRender).今天 ...
- webrtc视频引擎之video_render(视频渲染)介绍
此部分为webrtc视频渲染显示,代码结构如下: 其实此部分代码与<webrtc视频引擎之vedio_capture_module介绍>的代码结构一样 1,图中能够直接看到的.h和.cc文 ...
- Qt WA_TranslucentBackground 导致视频渲染不了的问题
使用QT5.7 + VS2015做的试验,视频渲染使用D3D9.发现的规律是: 顶层窗口(指父窗口为NULL的窗口)如果设置了 this->setWindowFlags( Qt::Framele ...
- SDL2音视频渲染入门
SDL, "Simple DirectMedia Layer",它是一套开放源代码的跨平台多媒体开发库,使用C语言写成.其主要用于游戏开发中的多媒体处理,如视频渲染,音频播放,鼠标 ...
- c++封装webrtc sdk(二):在sdk端实现webrtc视频渲染
如果你用过其它厂商的rtc sdk,比如声网,在渲染视频时,只需要传入窗口句柄,即可进行渲染,接口如下: 初始化本地视图 virtual int setupLocalVideo(const Vid ...
- iOS音视频开发十三:视频渲染,用 Metal 渲染
本系列文章通过拆解采集 → 编码 → 封装 → 解封装 → 解码 → 渲染流程并实现 Demo 来向大家介绍如何在 iOS/Android 平台上手音视频开发. 这里是第十三篇:iOS 视频渲染 De ...
最新文章
- 【BZOJ】1726 [Usaco2006 Nov]Roadblocks第二短路
- Android:面试官死亡问答,如何优化一个网络请求?大牛多个网络优化方案帮你解决!
- linux下free命令详解
- crontab -e 运行python的脚本的坑
- frida 安装特定版本
- 【今晚七点半】:主编对话李宇翔——我所经历的“前端”开发
- 图解 ElasticSearch 原理,太牛了
- Android 雪花飘落动画效果 自定义View
- 3D slicer的教程网站
- java判断小数点后是否为0,是的话则取整,不是的话则保留
- 谈谈对象和XML文件的转换
- 尚学堂马士兵Linux视频教程笔记
- 《python 计算机视觉编程》教程+图片+代码
- 扩展Redux——Store Enhancer
- 【原创】彻底解决2440触摸屏跳点以及抖动问题
- 多台计算机虚拟化方案,虚拟化建设解决方案
- 计算机毕业设计之java+ssm基于个人需求的外卖订餐推荐系统
- SYSTEM大法好!!!
- android 应用性能监控软件,App性能监控工具
- Linux小白想成为007,先会用“John the Ripper工具”
热门文章
- vivado快速下载及解压安装教程
- 试用华为3D建模服务
- matlab求边界点,MATLAB Delaunay算法提取离散点边界的方法
- 最新高德地图使用——申请key、显示地图
- 关于4442卡的读密码问题
- [工具] multidesk
- scipy回归分析_业余时间学数据分析,如何快速上手
- 电子厂计算机维修周记,关于电子厂实习周记范文
- DELMIA软件:机器人固定点焊仿真
- Linux tar命令无法执行,Linux执行tar解压报错tar: Error is not recoverable: exiting now