DSHOW 显示视频
原文链接
显示视频
DirectShow 提供了如下过滤器来显示视频:
l Video Renderer 过滤器. 该过滤器可用于所有的支持DirectX的平台,它对平台没有其它特殊的要求。可以是它,或GDI来显示视频。它是在WindowsXP之前操作系统的默认视频显示过滤器。
l Video Mixing Renderer Filter 7 (VMR-7). VMR-7可用于WindowsXP操作系统,并且是该系统下的默认视频显示过滤器。与老的视频显示过滤器相比,它具有一些更强大的性能,包括采用插件模式来控制DirectShow显示。
l Video Mixing Renderer Filter 9 (VMR-9). VMR-9是一个更新的视频混合显示过滤器,它采用了Direct3D来显示。它可用于所有的支持DirectX的平台。它不是默认的显示过滤器,因为它与其它的显示过滤器相比,对系统要求更高。
一般来说,在视频显示应用上,VMR-9是首选。因为,它使用了最新的图像API,并且提供了最好的性能。
窗体模式和非窗体模式
DirectShow视频显示可以选择在窗体模式或者非窗体模式下进行。
l 在窗体模式下,视频将创建一个它自己的窗体来显示。
l 在非窗体模式下,视频可以自己在你程序的一个窗口上显示,而不让视频自己区创建窗体来显示。
Video Renderer过滤器只支持窗体模式,VMR-7和VMR-9支持这两种模式。它们默认状态是窗体模式。
设置视频窗口
在窗体模式下,视频将创建一个窗口,然后在该窗口上显示视频。大多数情况下,你可能想要把该窗口绑定到你的应用程序中。通过使用IVideoWindow接口,可以设置视频窗口的类型和位置。
在开始播放前,在过滤器图表管理器中去查找IVideoWindow接口:
IVideoWindow *pVidWin = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void **)&g_pVidWin);
调用IVideoWindow::put_Owner方法去处理你应用程序的窗体。该方法提供了一个OAHWND类型的变量,所以要把句柄转换为该类型:
pVidWin->put_Owner((OAHWND)hwnd);
调用IVideoWindow::Put_WindowStyle来改变视频窗体的类型:
pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
WS_CHILD标志设置视频窗体为一个子窗体,WS_CLIPSIBLINGS标志可以防止视频窗体在另一个子窗体的客户区内显示视频。
调用IVideoWindow::SetWindowPosition方法可以视频窗口的相对于你应用程序的客户区的位置。该方法的参数带了一个RECT参数,用它去指定视频窗口的位置。下例,让视频窗口和它父窗体的客户区想匹配。
RECT grc;
GetClientRect(hwnd, &grc);
pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);
通过在过滤器图表管理器上调用IBaseicVide:GetVideoSize方法可以得到视频本身的尺寸大小。你可以通过这些信息让视频保持正确的纵横比例。
在应用程序退出前,停止图表并重置视频窗口为NULL。否则,窗口消息可能被错误的发送给错误的窗口,从而导致错误发生,
pControl->Stop();
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);
使用非窗体模式
视频混合显示过滤器(VMR-7和 VMR-9)都支持非窗体模式。这里将描述窗体模式和非窗体模式之间的不同,以及如何使用非模式窗体。
为了向后兼容已经在使用的应用程序,VMR默认的显示模式为窗体模式。在窗体模式中,视频创建一个它自己的窗体去显示视频。应用程序设置这个视频窗体为它的一个子窗体。这个单独存在的窗体会导致如下问题:
l 最严重的是,如果窗体的消息在线程间发送可能导致消息死锁。
l 过滤器图表管理器必须传递某些window消息,比如WM_PAINT,给视频显示器(Video Renderer)。这些对IvideoWIndow的操作必须是由过滤器图表管理器来完成,而不是视频显示器来完成,所以要靠过滤器图表管理器来纠正内部状态。
l 要视频窗体的鼠标或者键盘事件,应用程序必须建立一个“消息通道”,让视频窗口把消息传递给应用程序。
l 为了防止剪接的情况,视频窗体还必须拥有正确的窗口状态。
非窗体模式通过使用VMR直接在应用程序的客户区上画图来避免了上述的问题。它使用DirectDraw去剪接视频矩形。非窗体模式极大程度减少了死锁的偶然发生。同样,应用程序不必去设置视频自身创建的窗口和窗口的状态。事实上,当VRM使用窗体模式时,它也不使用IVideoWindow接口。
要使用非窗体模式,你必须明确地去配置VMR。你会发现配置工作非常灵活并且比窗体模式更容易。
在配置VMR 前应建立过滤器图表(Filter graph):
- 创建过滤器图表管理器(Filter Graph Manager)。
- 创建VMR并添加到过滤器图表中(filter graph)。
- 在VMR中调用IVMRFilterConfig::SetRenderingMode 设置VMRMode_Windowless 标识。
- 在VMR中调用 IVMRWindowlessControl::SetVideoClippingWindow 去指定视频将要显示的窗体句柄。
现在调用IGraphBuilder::RenderFile完成过滤器图表余下的工作。过滤器图表管理器将自动使用这个你添加到过滤器图表中的VMR实例。
下面代码显示了这些工作:
HRESULT InitWindowlessVMR(
HWND hwndApp, // 视频窗体
IGraphBuilder* pGraph, // 过滤器图表指针
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;
}
// 把VMR添加到过滤器图表中
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))
{
// 设置窗体
hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);
if( SUCCEEDED(hr))
{
hr = pWc->SetVideoClippingWindow(hwndApp);
if (SUCCEEDED(hr))
{
*ppWc = pWc; //返回AddRef指针
}
else
{
pWc->Release();
}
}
}
pVmr->Release();
return hr;
}
该函数假设正在显示一个视频流并没有混合的静态位图。你将看到按如下调用该函数:
IVMRWindowlessControl *pWc = NULL;
hr = InitWindowlessVMR(hwnd, pGraph, &g_pWc);
if (SUCCEEDED(hr))
{
// 建立图表
pGraph->RenderFile(wszMyFileName, 0);
//完成后释放VMR接口
pWc->Release();
}
视频定位
配置完VMR后,下一个步骤就是去设置视频显示的位置。有两个矩形位置要考虑,一个是Source矩形位置,一个是desitnation矩形位置。Source定义视频显示的位置。Destination指定包含视频的窗体的客户区的位置。VMR从source把图像按destination的尺寸匹配后显示出来。
调用IVMRWindowlessControl::SetVideoPosition去指定这个两个矩形位置。Source矩形的大小必须等于或小于视频本身的尺寸大小;你可以使用IVMRWindowlessControl::GetNativeVideoSize去获得视频本身的尺寸。
下面的实例,将设置Source等于视频尺寸1/4(左上角的位置相等),并设置destination矩形等于窗体客户区的大小1/(左上角的位置相等):
// 获得视频自身尺寸大小
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);
// 获得显示窗体的客户区尺寸
GetClientRect(hwnd, &rcDest);
//设置destination尺寸
SetRect(&rcDest, 0, 0, rcDest.right/2, rcDest.bottom/2);
// 视频定位
hr = g_pWc->SetVideoPosition(&rcSrc, &rcDest);
}
处理窗体消息
因为VMR没有自己的窗体,当视频需要重画或者尺寸要改变是,你必须要通知窗体来适应。
l 当接收到一个WM_PAINT消息,可调用IVMRWindowlessControl::RepaintVideo 来重画图像。
l 当接收到一个WM_DISPLAYCHANGE 消息, 可调用 IVMRWindowlessControl::DisplayModeChanged消息。VMR就可以获得如下行为比如改变分辨率或者色深。
l 当接收到一个WM_SIZE 消息, 可以重新调用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)
{
// 查找窗体需要重绘的客户区,该区域应该减去视频显示的区域
// (这里假设g_rcDest 是已经计算好了的区域)
HRGN rgnClient = CreateRectRgnIndirect(&rcClient);
HRGN rgnVideo = CreateRectRgnIndirect(&g_rcDest);
CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF);
// 重绘窗体
HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);
FillRgn(hdc, rgnClient, hbr);
// 释放对象
DeleteObject(hbr);
DeleteObject(rgnClient);
DeleteObject(rgnVideo);
// 请求VMR to 重绘视频
HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc);
}
else // 没有视频显示,重绘整个客户区
{
FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1));
}
EndPaint(hwnd, &ps);
}
DSHOW 显示视频相关推荐
- VS+MFC+Opencv显示视频和图像。
读入图片: void CDrawImgVideoDlg::OnBnClickedShowImg() { // TODO: 在此添加控件通知处理程序代码 CDC *pDC = GetDl ...
- glide缩略图存储 android,Glide 显示视频缩略图及遇到的坑
Glide 显示视频缩略图及遇到的坑 实现原理 Glide支持视频格式的文件,但是在3.x里会有些欠缺.其底层是通过 MediaMetadataRetriever实现的. MediaMetadataR ...
- java制作h5视频聊天_JAVA实现大华摄像头WEB方式实时显示视频,H5界面展示方式思路。...
JAVA实现大华摄像头WEB方式实时显示视频,H5界面展示方式思路. 2018-09-17 问题:大华IPC枪型摄像头需要在WEB中显示实时监控视频,官方提供的SDK只有C#的桌面程序访问方式. 解决 ...
- 微信小程序点播插件_微信小程序 wxParse插件显示视频问题
修改wxParse/html2json.js 文件 ,在 html2json(html, bindName)方法里 var node = { node: 'element', tag: tag, }; ...
- video 设置 poster,默认显示视频第一帧
video 设置 poster,默认显示视频第一帧 <video:src="videoUrl":poster="videoUrl + '?x-oss-process ...
- 微信小程序video默认不播放且显示视频第一帧
小程序video 只设置 controls="{{false}}" 会显示播放按钮 通过设置show-center-play-btn="{{false}}" 就 ...
- android显示视频预览
android 11 kotlin显示视频预览 权限 读sd卡中的mp4文件的权限 <uses-permission android:name="android.permission. ...
- 解决百度ueditor富文本编辑器不能插入视频的问题/src掉链/src清空,不能显示视频
如果你嫌弃自己配置比较麻烦,出现各种奇奇怪怪的问题你下载我 这个文件 加入到你的项中, 只 需要 修改 项目名称 就可以 运行 地址 https://download.csdn.net/d ...
- Unity 基础 之 在 UGUI 上简单实现VideoPlayer视频播放的功能,简单暂停播放/显示视频名称/显示时长/拖拽播放等
Unity 基础 之 在 UGUI 上简单实现VideoPlayer视频播放的功能,简单暂停播放/显示视频名称/显示时长/拖拽播放等 目录 Unity 基础 之 在 UGUI 上简单实现VideoPl ...
最新文章
- RabbitMQ入门(4)--路由
- 全球首款碳纳米管通用计算芯片问世!RISC-V架构,5倍于摩尔定律,Nature连发三文推荐...
- ML之xgboost:利用xgboost算法(sklearn+GridSearchCV)训练mushroom蘑菇数据集(22+1,6513+1611)来预测蘑菇是否毒性(二分类预测)
- 120. 三角形最小路径和
- 知乎python练手的_Python—爬虫之初级实战项目:爬取知乎任一作者的文章练手
- C#中的结构和类之间的区别
- mysql 表的存储类型_MySQL数据表存储引擎类型及特性
- 【OpenCV 例程200篇】03. 图像的显示(cv2.imshow)
- mt4交易软件云服务器_MT4软件使用教程1常见货币对交易图表类型
- Shiro框架(一)-Shiro概述
- mysql 统计每天、每周、每月、每年数据
- MAC word2015 插入罗马字母
- 仿ios相机apk_iCamera摄像头下载|iCamera仿苹果相机安卓版v4.0下载 _当游网
- Android加载超大图片
- 数据库的ACID(原子性、一致性、隔离性与持久性)
- MaxScript调用IGame
- 709元我上了斐讯K2P的车
- java 好学_java是什么?对于新手好学吗?
- EVE-NG物理机启动报错
- FortiGate防火墙GRE隧道监控