MFC DirectShow视频预览

关于DirectShow这篇博客,写的通俗易懂,所以转了过来。

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对象接口指针”的函数。

[cpp]  view plain copy print ?
  1. IGraphBuilder *pGraph=NULL;  
  2.   
  3. ICaptureGraphBuilder2 *pBuilder=NULL;  
  4.   
  5. if( SUCCEEDED(CoCreateInstance(CLSID_CaptureGraphBuilder2,NULL,CLSCTX_INPROC_SERVER,IID_ICaptureGraphBuilder2,(void**)&pBuilder) ) ){  
  6.   
  7.     CoCreateInstance(CLSID_FilterGraph,0,CLSCTX_INPROC_SERVER,IID_IGraphBuilder,(void**)&pGraph);  
  8. }  


c.      创建系统硬件设备、特定类型的硬件设备列表

[cpp]  view plain copy print ?
  1. Hr  = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,  
  2.   
  3. IID_ICreateDevEnum, (void **)&pSysDevEnum);// CMyDialog: ICreateDevEnum *pSysDevEnum;  
  4.   
  5.     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

[cpp]  view plain copy print ?
  1. IMoniker::BindToObject(0,0,IID_IBaseFilter,(void**)&pBaseFilter);  


<3>.将生成的filter加入到filter graph 中

[cpp]  view plain copy print ?
  1. IGraphBuilder:: AddFilter(pBaseFilter,L"Capture Filter");  


<4>.实现filter的只能连接,此处默认此filter为一个render filter

[cpp]  view plain copy print ?
  1. ICaptureGraphBuilder2::RenderStream(&PIN_CATEGORY_PREVIEW,&MEDIATYPE_Video,pBaseFilter,NULL,NULL);  


 

<5>.查询指针些是否支持某类接口

是否支持视频窗口,若支持则可以使用pWindow指针访问IVideoWindow接口内的函数

[cpp]  view plain copy print ?
  1. IGraphBuilder::QueryInterface(IID_IVideoWindow,(void**)&pWindow);  


同理

[cpp]  view plain copy print ?
  1. IGraphBuilder::QueryInterface(IID_IMediaControl,(void**)&pControl);  


<6>.可以运行进行视频预览了

[cpp]  view plain copy print ?
  1. pControl->Run();  


<7>.设置IVideoWindow窗口

[cpp]  view plain copy print ?
  1. //申明此视频窗口的所有者  
  2. //视频窗口的所有者是hWnd窗口,即此窗口将显示在hWnd窗口之上  
  3. pWindow->put_Owner((OAHWND)hWnd);  
  4. //设置视频窗口的样式  
  5. pWindow->put_WindowStyle(WS_CHILD);  
  6. //捕获视频窗口的宽度和高度  
  7. pWindow->get_Width(&pWidth);  
  8. pWindow->get_Height(&pHeight);  
  9. //设置视频窗口的位置,大小  
  10. pWindow->SetWindowPosition(0,0,pWidth, pHeight);  


<8>.减少应用计数

[cpp]  view plain copy print ?
  1. pMoniker->Release();  
  2. pEnumCat->Release();  
  3. 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窗口)

[cpp]  view plain copy print ?
  1. BEGIN_MESSAGE_MAP(CMyDialog, CDialog)  
  2.     ON_BN_CLICKED(IDC_CAPVEDIO, &CMyDialog::OnClickedCapvedio)  
  3.     ON_BN_CLICKED(IDC_VEDIO_STOP, &CMyDialog::OnClickedVedioStop)  
  4.     ON_BN_CLICKED(IDC_VEDIOCONTINUE, &CMyDialog::OnClickedVediocontinue)  
  5. END_MESSAGE_MAP()  

CMyDialog::OnClickedCapvedio()函数中包含了DirectShow程序视频预览的所有的代码。

CMyDialog::OnClickedVedioStop()函数中包含了视频预览停止的代码:pControl->Stop();

CMyDialog::OnClickedVediocontinue函数包含视频预览继续的代码:pControl->Run();

这三个函数中还包含了基本的逻辑判断,判断视频的是处于“预览”、“停览”、“续览”的哪一个阶段。

 

关于将视频窗口IVideoWindow显示在IDC_VEDIO_WINDOW控件上的方法:

a.  在CMyDialog::OnInitDialog()函数中获取IDC_VEDIO_WINDOW控件句柄

[cpp]  view plain copy print ?
  1. hWnd = GetDlgItem(IDC_VEDIO_WINDOW)->m_hWnd;  

b.  在CMyDialog::OnClickedCapvedio()函数中指明IVideoWindow窗口的所有者为IDC_VEDIO_WINDOW

[cpp]  view plain copy print ?
  1. pWindow->put_Owner((OAHWND)hWnd);  

 -----------------------------------------------------------------------------------------------------控件实现--------------------------------------------------------------------------

 

4 运行结果

在MFC架构之下,实现DirectShow的程序运行界面为:

MFC DirectShow视频预览_第1张图片

图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_WidthIVideoWindow:: get_Height函数获取视频窗口的大小。

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

<5> 减少应用计数

pMoniker->Release();

pEnumCat->Release();

pSysDevEnum->Release();

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

你可能感兴趣的:(directx,mfc,DirectX)