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组件

COMComponent 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,对话框类CMyDialogCMyWinApp类主要用来定义应用程序类和重载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::AddFilterfilter添加到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_WidthIVideoWindow:: get_Height函数获取视频窗口的大小。

<4> 用IVideoWindow::SetWindowPosition函数设置视频窗口的位置。

<5> 减少应用计数

pMoniker->Release();

pEnumCat->Release();

pSysDevEnum->Release();

--------------------------------------------------视频预览------------------------------------------

 

MFC Directshow Note  Over.

以上是关于MFC DirectShow视频预览 [大三TJB_708]的主要内容,如果未能解决你的问题,请参考以下文章

C# directshow 连接多个图

以高分辨率从网络摄像头捕获图片,同时使用 DirectShow.Net 以较低的分辨率进行预览

为啥 DirectShow 加载视频字幕文件?

Directshow:如何更改视频的大小和帧率?

WebRTC Windows Native视频中的DirectShow介绍

具有多个视频帧的 DirectShow 变换过滤器 - 与音频同步