MFC DirectShow视频预览 [大三TJB_708]
Posted 资质平庸的程序员
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MFC DirectShow视频预览 [大三TJB_708]相关的知识,希望对你有一定的参考价值。
1 简介
本笔记的主要内容是如何在MFC程序中实现DirectShow视频预览。
DirectShow是微软共公司在ActiveMove和Video for Windows 的基础上推出的新一代基于COM(Component Object Model)的流媒体处理的开发包。DirectShow使用一种叫Filter Graph 的模型来管理整个数据流的处理过程,运用DirectShow,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。这样使在多媒体数据库管理系统(MDBMS)中多媒体数据的存取变得更加方便。它广泛地支持各种媒体格式,包括Asf、Mpeg、Avi、Dv、Mp3、Wave等,为多媒体流的捕捉和回放提供了强有力的支持。如果具有MFC架构的基础知识就更好了。
2 术语基础
<1> 什么是COM组件
COM是Component Object Model(组件对象模型)的缩写。
COM是个开放的组件标准,它有很强的扩充和扩展能力,它的实质就是一个C++类。如
class Ifunction
Public:
virtual Method1(…) = 0;
virtual Method2(…) = 0;
//…
;
class Myobject : publicIfunction
Public:
virtual Method1(…) = 0;
virtual Method2(…) = 0;
//…
;
其中,Ifunction就是常说的接口,Myobject就是COM组件。COM组件就是集成纯虚接口而来。
<2> 什么是Filter
Filter是DirectShow中最基本的概念。DirectShow使用Filter Graph来管理Filter。filter是一种COM组件,为了在filter graph能够统一被操作,每个filter都至少实现一个IBaseFilter接口。Filter一般由一个或多个pin组成,filter之间通过pin相互连接,构成一条顺序的链路,根据功能可以分为三类:source filters(只有输出),Transform filters(既有输入又有输出),Rendering filters(只有输入)。filter的扩展名可以是.ax或者.dll。
<3> 什么是Filter Graph
由filter 的pin相互链接,将filter串联起来,如此就能构成filter graph。
<4>什么是Filter Graph Manage
简单点说,Filter Graph Manage就是用CoCreateInstance 函数创建的IGraphBuilder对象,它暴露了IGraphBuilder接口。
<5> 什么是Capture Graph Builder
Capture Graph Builder 是 用CoCreateInstance 函数创建的ICaptureGraphBuilder2对象,它暴露了ICaptureGraphBuilder2接口。
3 MFC DirectShow视频预览设计
<1> 目标
在一个对话框之上指定位置显示视频窗口,并由“捕获视频”、“停止捕获”、“继续捕获”等控件来控制视频。
<2>创建一个基于对话框的MFC程序
基于“MFC 架构入门”保存以下一个文件:MFCDialogCreate33.h、MFCDialogCreate33.cpp、MyDialog.h、MyDialog.cpp、Resource.h、stdafx.h、stdafx.cpp、targetver.h、MFCDialogCreate33.rc。
a. 继承一个应用程序类CMyWinApp,对话框类CMyDialog。CMyWinApp类主要用来定义应用程序类和重载InitInstance()函数。CMyDialog用来产生对话框及包含DirectShow的对象和自定义函数。
-----------------------------------------------------------------------------------------------------视频预览---------------------------------------------------------------------------
b. 编写CMyDialog类中“创建Filter Graph及Capture Graph Builder对象接口指针”的函数。
IGraphBuilder *pGraph=NULL;
ICaptureGraphBuilder2 *pBuilder=NULL;
if( SUCCEEDED(CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,CLSCTX_INPROC_SERVER,IID_ICaptureGraphBuilder2,(void**)&pBuilder) ) )
CoCreateInstance(CLSID_FilterGraph,0,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&pGraph);
c. 创建系统硬件设备、特定类型的硬件设备列表
Hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
IID_ICreateDevEnum, (void **)&pSysDevEnum);// CMyDialog: ICreateDevEnum *pSysDevEnum;
hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);// CMyDialog: IEnumMoniker *pEnumCat;
d. 检测系统是否包含特性类型设备后发生filter产生、filter加入filter graph、filter智能连接、filter运行操作
<1>.使用IEnumMoniker::Next(1, &pMoniker, &cFetched) == S_OK为真来检测是否检测到了符合特定类型的硬件设备。
<2>.一旦<1>.中条件发生就生成绑定到特定类型设备的filter
IMoniker::BindToObject(0,0,IID_IBaseFilter,(void**)&pBaseFilter);
<3>.将生成的filter加入到filter graph 中
IGraphBuilder:: AddFilter(pBaseFilter,L"Capture Filter");
<4>.实现filter的只能连接,此处默认此filter为一个render filter
ICaptureGraphBuilder2::RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,pBaseFilter,NULL,NULL);
<5>.查询指针些是否支持某类接口
是否支持视频窗口,若支持则可以使用pWindow指针访问IVideoWindow接口内的函数
IGraphBuilder::QueryInterface(IID_IVideoWindow,(void**)&pWindow);
同理
IGraphBuilder::QueryInterface(IID_IMediaControl,(void**)&pControl);
<6>.可以运行进行视频预览了
pControl->Run();
<7>.设置IVideoWindow窗口
//申明此视频窗口的所有者
//视频窗口的所有者是hWnd窗口,即此窗口将显示在hWnd窗口之上
pWindow->put_Owner((OAHWND)hWnd);
//设置视频窗口的样式
pWindow->put_WindowStyle(WS_CHILD);
//捕获视频窗口的宽度和高度
pWindow->get_Width(&pWidth);
pWindow->get_Height(&pHeight);
//设置视频窗口的位置,大小
pWindow->SetWindowPosition(0,0,pWidth, pHeight);
<8>.减少应用计数
pMoniker->Release();
pEnumCat->Release();
pSysDevEnum->Release();
----------------------------------------------------------------------------------------------------视频预览----------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------控件实现----------------------------------------------------------------------------
<9>.在对话框中添加CButton类的控件,属性设置为
Caption | ID |
全力预览视频 | IDC_CAPVEDIO |
停览,没啥嫌疑 | IDC_VEDIO_STOP |
续览,嫌疑重大 | IDC_VEDIOCONTINUE |
退出 | IDCANCEL |
还添加一个Text Control的控件,属性设置为
Caption | ID |
谜_mystery | IDC_VEDIO_WINDOW |
<10>.利用类向导为控件添加响应函数(除IDC_VEDIO_WINDOW,从控件用来载IVideoWindow窗口)
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_BN_CLICKED(IDC_CAPVEDIO, &CMyDialog::OnClickedCapvedio)
ON_BN_CLICKED(IDC_VEDIO_STOP, &CMyDialog::OnClickedVediostop)
ON_BN_CLICKED(IDC_VEDIOCONTINUE, &CMyDialog::OnClickedVediocontinue)
END_MESSAGE_MAP()
CMyDialog::OnClickedCapvedio()函数中包含了DirectShow程序视频预览的所有的代码。
CMyDialog::OnClickedVedioStop()函数中包含了视频预览停止的代码:pControl->Stop();
CMyDialog::OnClickedVediocontinue函数包含视频预览继续的代码:pControl->Run();
这三个函数中还包含了基本的逻辑判断,判断视频的是处于“预览”、“停览”、“续览”的哪一个阶段。
关于将视频窗口IVideoWindow显示在IDC_VEDIO_WINDOW控件上的方法:
a. 在CMyDialog::OnInitDialog()函数中获取IDC_VEDIO_WINDOW控件句柄
hWnd = GetDlgItem(IDC_VEDIO_WINDOW)->m_hWnd;
b. 在CMyDialog::OnClickedCapvedio()函数中指明IVideoWindow窗口的所有者为IDC_VEDIO_WINDOW
pWindow->put_Owner((OAHWND)hWnd);
-----------------------------------------------------------------------------------------------------控件实现--------------------------------------------------------------------------
4 运行结果
在MFC架构之下,实现DirectShow的程序运行界面为:
图1.MFC/DirectShow视频预览程序运行效果
程序运行后,点击“全力预览视频”再把杯子拿到摄像头之上就会显示此界面,预览的是我的爱杯哦~·~。当点击“停览,没啥嫌疑”按钮时视频停止不动,这时再点击“续捕,嫌疑重大”按钮时视频预览继续。
5 总结
MFC DirectShow视频预览总结
a. 继承一个应用程序类CMyWinApp,对话框类CMyDialog。CMyWinApp类主要用来定义应用程序类和重载InitInstance()函数。CMyDialog用来产生对话框及包含DirectShow的对象和自定义函数。
--------------------------------------------------视频预览------------------------------------------
b. 编写CMyDialog类中“创建Filter Graph及Capture Graph Builder对象接口指针”的函数。
(1) 定义IGraphBuilder及ICaptureGraphBuilder2指针对象。
(2) 用CoCreateInstance函数创建CLSID_CaptureGraphBuilder2及CLSID_FilterGraph类型COM组件对象,并用对应的指针对象返回。
a. 系统设备枚举
(1) 创建枚举器组件,CLSID 为CLSID_SystemDeviceEnum
(2) 指定某一种类型设备,参数CLSID,通过ICreateDevEnum::CreateClassEnumerator获取某一种类的枚举器,这个函数返回一个IEnumMoniker接口指针,如果该种类的空或者不存在,这个方法就返回S_FALSE。因此,当你调用这个函数时一定要检查返回值是否为S_OK,而不要用SUCCEEDED宏。
(3)然后IEnumMoniker::Next枚举每一个moniker。这个方法返回一个IMoniker接口指针。
(4) 要想知道设备的名称,可以通过下面的函数IMoniker::BindToStorage
(5) 然后利用IMoniker::BindToObject生成绑定道设备上的filter。调用IFilterGraph::AddFilter将filter添加到Graph图中。
(6) 用ICaptureGraphBuilder2::RenderStream函数实现filter的智能连接,此处默认此filter为一个render filter
d. 视频提交
(1) 用IGraphBuilder::QueryInterface函数查询是否支持视频窗口模式、IMediaControl接口是否可供使用。
(2) 可以用由(1)得来的IMediaControl接口函数Run()来预览视频。
(3) 窗口模式设置
<1> 用IVideoWindow::put_Owner函数设定视频窗口的所属者。
<2> 用IVideoWindow::put_WindowStyle函数设置窗口样式。
<3> 用IVideoWindow::get_Width,IVideoWindow:: get_Height函数获取视频窗口的大小。
<4> 用IVideoWindow::SetWindowPosition函数设置视频窗口的位置。
<5> 减少应用计数
pMoniker->Release();
pEnumCat->Release();
pSysDevEnum->Release();
--------------------------------------------------视频预览------------------------------------------
MFC Directshow Note Over.
以上是关于MFC DirectShow视频预览 [大三TJB_708]的主要内容,如果未能解决你的问题,请参考以下文章
以高分辨率从网络摄像头捕获图片,同时使用 DirectShow.Net 以较低的分辨率进行预览