本笔记的主要内容是如何在MFC程序中实现DirectShow视频预览。
DirectShow是微软共公司在ActiveMove和Video for Windows 的基础上推出的新一代基于COM(Component Object Model)的流媒体处理的开发包。DirectShow使用一种叫Filter Graph 的模型来管理整个数据流的处理过程,运用DirectShow,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。这样使在多媒体数据库管理系统(MDBMS)中多媒体数据的存取变得更加方便。它广泛地支持各种媒体格式,包括Asf、Mpeg、Avi、Dv、Mp3、Wave等,为多媒体流的捕捉和回放提供了强有力的支持。如果具有MFC架构的基础知识就更好了。
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组件就是集成纯虚接口而来。
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。
由filter 的pin相互链接,将filter串联起来,如此就能构成filter graph。
简单点说,Filter Graph Manage就是用CoCreateInstance 函数创建的IGraphBuilder对象,它暴露了IGraphBuilder接口。
Capture Graph Builder 是 用CoCreateInstance 函数创建的ICaptureGraphBuilder2对象,它暴露了ICaptureGraphBuilder2接口。
在一个对话框之上指定位置显示视频窗口,并由“捕获视频”、“停止捕获”、“继续捕获”等控件来控制视频。
基于“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对象接口指针”的函数。
c. 创建系统硬件设备、特定类型的硬件设备列表
d. 检测系统是否包含特性类型设备后发生filter产生、filter加入filter graph、filter智能连接、filter运行操作
<1>.使用IEnumMoniker::Next(1, &pMoniker, &cFetched) == S_OK为真来检测是否检测到了符合特定类型的硬件设备。
<2>.一旦<1>.中条件发生就生成绑定到特定类型设备的filter
<3>.将生成的filter加入到filter graph 中
<4>.实现filter的只能连接,此处默认此filter为一个render filter
<5>.查询指针些是否支持某类接口
是否支持视频窗口,若支持则可以使用pWindow指针访问IVideoWindow接口内的函数
同理
<6>.可以运行进行视频预览了
<7>.设置IVideoWindow窗口
<8>.减少应用计数
----------------------------------------------------------------------------------------------------视频预览----------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------控件实现----------------------------------------------------------------------------
<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窗口)
CMyDialog::OnClickedCapvedio()函数中包含了DirectShow程序视频预览的所有的代码。
CMyDialog::OnClickedVedioStop()函数中包含了视频预览停止的代码:pControl->Stop();
CMyDialog::OnClickedVediocontinue函数包含视频预览继续的代码:pControl->Run();
这三个函数中还包含了基本的逻辑判断,判断视频的是处于“预览”、“停览”、“续览”的哪一个阶段。
关于将视频窗口IVideoWindow显示在IDC_VEDIO_WINDOW控件上的方法:
a. 在CMyDialog::OnInitDialog()函数中获取IDC_VEDIO_WINDOW控件句柄
b. 在CMyDialog::OnClickedCapvedio()函数中指明IVideoWindow窗口的所有者为IDC_VEDIO_WINDOW
-----------------------------------------------------------------------------------------------------控件实现--------------------------------------------------------------------------
在MFC架构之下,实现DirectShow的程序运行界面为:
图1.MFC/DirectShow视频预览程序运行效果
程序运行后,点击“全力预览视频”再把杯子拿到摄像头之上就会显示此界面,预览的是我的爱杯哦~·~。当点击“停览,没啥嫌疑”按钮时视频停止不动,这时再点击“续捕,嫌疑重大”按钮时视频预览继续。
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();
--------------------------------------------------视频预览------------------------------------------