VS2010 C++学习(5):基于DirectShow的视频预览录像程序

简介: <h2 align="center"><span style="font-family:Arial">VS2010 C++</span>学习(<span style="font-family:Arial">5</span>):基于<span style="font-family:Arial">DirectShow</span>的视频</h2> <h2 align="center">预览

VS2010 C++学习(5):基于DirectShow的视频

预览录像程序

 

学习VC++编制的基于DirectShow视频捕获程序,主要练习基于DirectShow程序的应用。

 

一、           主要内容:

 

1.        基于DirectShow视频预览;

2.        基于DirectShow视频录像;

 

二、           设计实现:

(一)、安装DirectShow

首先我们安装DirectShow SDK,由于现在directShow没有和direcxtx一起发布,而是和windows sdk 打包发布了,可以到官网下载最新的windows sdk 开发包。一个可用的下载地址为http://dl-sh-ctc-2.pchome.net/07/hh/DXSDK_Feb10.rar

然后安装好windows SDK。安装完DirectShow SDK的目录为C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow

(二)、开发环境配置

开发环境的配置主要有两个工作要做:

一是在使用Directshow SDK开发自己的程序时需要的DirectShow的有关静态库的配置,

二是visual C++开发环境的配置。

1)      生成DirectShow SDK开发库

使用DirectShow SDK开发用户自己的程序需要几个静态链接库:quartz.libstrmbasd.libSTRMBASE.libstrmiids.lib。中间两个lib需要用户自己编译生成,而其他两个微软已经提供。下表列出了使用DirectShow SDK开发程序所有要使用的库。

库名

功能说明

Strmiids.lib

定义了DirectShow标准的输出类标识(CLSID)和接口标识(IID

Strmbasd.lib

流媒体开发用到的库,DebugDebug_Unicode版本

Strmbase.lib

流媒体开发用到的库,ReleaseRelease_Unicode版本

Quartz.lib

定义了导出函数AMGetErrorText

Winmm.lib

使用Windows多媒体编程用到的库

 

2)      更改添加的include内容:

C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses;

C:\Program Files\Microsoft SDKs\Windows\v7.1\Include;

添加过程如下。选择“Ex005属性”→“选项” →“VC++目录” →“包含目录”,将上面的2个Include内容添加进去。

3)      更改添加lib路径

要添加的lib内容:

C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Debug;

C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib;

添加过程和Include内容相似,选择“Ex005属性”→“选项” →“VC++目录” →“库文件”选项。

4)      添加链接库支持

C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Debug;

C:\Program Files\Microsoft SDKs\Windows\v7.1\Lib;

5)       小贴士

     DirectShow中的例子,在编译的过程中经常会出现这样的错误:

Error 1 error C2061: syntax error : identifier 'CAMSchedule' c:/program files/microsoft sdks/windows/v6.0/samples/multimedia/directshow/baseclasses/refclock.h 80
    
这主要是因为在不同SDK的目录里包含了多个 schedule.h file 和 refclock.h
因此需要在
“Ex005属性”→“选项” →“VC++目录” →“包含目录”中调整 include 的顺序,将samples/multimedia/directshow/baseclasses 放到其他的sdk之前即可

 

(三)、DirectShow视频采集方案

流媒体处理技术以其复杂性和技术性一直受到人们的关注。随着网络技术的不断发展,流媒体在网络上得到了广泛地应用。如何能够简单、有效地进行流媒体处理,已成为一个焦点问题。为此,Microsoft推出了DirectShowDirectShowMicrosoft推出的基于Windows平台的流媒体处理开发包,它与DirectX一起发布。DirectShow对流媒体的捕捉、回放提供了强大的支持。

1)      DirectShow系统结构分析

DirectShow主要由过滤器(Filter Graph)图表构成。过滤图表中包含了各种Filter,这些Filter能够按一定顺序连接在一起,构成一条流水线。

从功能的角度划分,Filter 大体可以分为3类,

Source Filters;主要负责获取数据,可以是一个文件、一个采集卡、声卡或数码相机等。

Transform Filters;负责数据的转换、传输。例如各种码器、解码器等。

Rendering Filters。负责数据的最终去向,例如将数据传送到声卡、显卡或存储为文件。

在开发DirectShow应用程序时,通常需要设计一个过滤图表(Filter Graph),向过滤图表中添加相应的过滤器,最后连接过滤器的引脚就完成了功能的设计。

例如,实现一个简单的视频预览功能,需要向过滤图表中添加一个视频捕捉源过滤器和一个Video Renderer过滤器,将视频捕捉源过滤器的输出引脚与Video Renderer过滤器的输入引脚相连就可以了。

而在程序中只需要按照设计过滤图表的捕捉添加过滤器并连接过滤器引脚就可以了。在连接过滤器引脚时需要注意:只能是输出过滤器引脚与输入过滤器引脚相连,两个输出过滤器或两个输入过滤器引脚是不能相连的。

2)      Filter图表设计

为了方便用户设计过滤图表,DirectX提供了一个Graph Edit工具。

位于 C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\graphedt.exe

点击运行。演示如何使用Graph Edit工具设计过滤图表,过滤图表的功能是实现视频的预览功能。具体步骤如下:

1)单击“Graph/Insert Filters”菜单项打开“添加过滤器”窗口,

选择一个视频捕捉源过滤器。选择“Video Renderer”最终去向过滤器,连接,如图1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

                   2 宽屏haali视频分离器             

单击工具栏中的“>”按钮运行过滤图表,将显示一个视频预览窗口。

 

3)      枚举系统设备

使用Graph Edit工具,用户可以非常方便地获得与某一系统设备相关的过滤器。但是,在程序中该如何获得这些过滤器呢?

用户可以采用枚举的方式列举系统中安装的设备。

以列举系统中的视频捕捉设备为例,

(1)    首先定义一个设备列举接口 ICreateDevEnum的一个指针;

(2)    调用CoCreateInstance方法创建ICreateDevEnum实例。

(3)    然后定义一个列举监视器 IEnumMoniker的一个指针;

(4)    调用ICreateDevEnum实例的CreateClassEnumerator方法创建 IEnumMoniker实例。

(5)    最后以循环的方式调用IEnumMoniker实例的Next方法遍历系统设备;

(6)    调用IEnumMoniker实例的 BindToObject方法将系统设备绑定到过滤器上。

在上面的描述中,ICreateDevEnum实例的CreateClassEnumerator方法的第一个参数确定枚举的系统设备。例如,第一个参数为CLSID_VideoInputDeviceCategory,表示将要枚举系统中的视频捕捉卡,为 CLSID_VideoCompressorCategory,表示枚举系统中的视频压缩器。

下面的代码演示了如何枚举系统中的视频捕捉卡。

//枚举视频设备;= CLSID_VideoInputDeviceCategory

//     音频设备的= CLSID_ AudioInputDeviceCategory

ICreateDevEnum *pDevEnum = NULL;

CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,

IID_ICreateDevEnum, (void **)&pDevEnum);

IEnumMoniker *pClassEnum = NULL;

pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);

ULONG cFetched;

while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)    

{

pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);

pMoniker->Release();

break;

}

pClassEnum->Release();

而下面的代码则用于判断系统中是否安装了指定的视频压缩器。

ICreateDevEnum *pDevEnum = NULL;

CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,

IID_ICreateDevEnum, (void **)&pDevEnum);

IEnumMoniker *pClassEnum = NULL;

//列举视频压缩设备;=CLSID_VideoCompressorCategory

pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pClassEnum, 0);

while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)    

{

IPropertyBag* pProp= NULL;

pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pProp);

VARIANT varName;

varName.vt = VT_BSTR;

pProp->Read(L"FriendlyName", &varName,0);

CString str = varName.bstrVal;

if (str.Find("Microsoft Video 1",0)!= -1)

{

pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCompress);

pMoniker->Release();

break;

}

VariantClear(&varName);

}

pClassEnum->Release();

 

4)      查找Filter Pin过滤器引脚

每一个过滤器(Filter)至少应有一个引脚(Pin),或者是输入引脚或者是输出引脚。有些过滤器还拥有多个引脚,即又输入引脚又有输出引脚。但是过滤器的输入、输出引脚并不是对应的,有些过滤器可以有多个输入引脚,而只有一个输出引脚或者没有输出引脚。在程序中为了连接过滤器间的引脚,通常需要获得过滤器的各个引脚。

用户可以使用IEnumPins接口来枚举某一个过滤器的输入、输出引脚。过滤器 IBaseFilter提供了一个EnumPins方法用于生成一个IEnumPins接口实例,这样,通过调用IEnumPinsNext方法便可以访问各个引脚了。

下面的代码定义了一个FindPin函数,用于获得某个过滤器的输入或输出引脚。

//查找引脚

IPin* CKinescopeDlg::FindPin(IBaseFilter *pFilter, PIN_DIRECTION dir)

{

IEnumPins* pEnumPins;

IPin* pOutpin;

PIN_DIRECTION pDir;

pFilter->EnumPins(&pEnumPins);

while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK)

{

pOutpin->QueryDirection(&pDir);

if (pDir==dir) {return pOutpin;}

}

return 0;

}

用户可以按下面的方式获得某个过滤器的输入、输出引脚。

IPin * pComOut,*pComIn ;

pComIn  = FindPin(pCompress,PINDIR_INPUT);

pComOut = FindPin(pCompress,PINDIR_OUTPUT);

 

5)      连接Filter Pin过滤器引脚

使用Graph Edit工具,用户可以利用鼠标非常方便地连接两个过滤器间的引脚。但是在程序中却没这么简单了。首先需要按照上面介绍的方法获得两个过滤器的输入、输出引脚,然后将第一个过滤器的输出引脚连接到第二个过滤器的输入引脚,其中,连接两个引脚需要调用IGraphBuilder接口的 ConnectDirect方法。

下面的代码演示了如何连接两个过滤器的引脚。

IPin * pComOut,*pComIn ;

pComIn  = FindPin(pCompress,PINDIR_INPUT);

pComOut = FindPin(pCompress,PINDIR_OUTPUT);

IPin* pOutpin = FindPin(pSrc,PINDIR_OUTPUT); //pSrc的输出引脚

HRESULT result ;

result = pGraph->ConnectDirect(pOutpin,pComIn,NULL);

 

 

 

 

相关文章
|
13天前
|
算法 网络安全 区块链
2023/11/10学习记录-C/C++对称分组加密DES
本文介绍了对称分组加密的常见算法(如DES、3DES、AES和国密SM4)及其应用场景,包括文件和视频加密、比特币私钥加密、消息和配置项加密及SSL通信加密。文章还详细展示了如何使用异或实现一个简易的对称加密算法,并通过示例代码演示了DES算法在ECB和CBC模式下的加密和解密过程,以及如何封装DES实现CBC和ECB的PKCS7Padding分块填充。
36 4
2023/11/10学习记录-C/C++对称分组加密DES
|
4月前
|
C++
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
C++ 根据程序运行的时间和cpu频率来计算在另外的cpu上运行所花的时间
54 0
|
4月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
93 0
|
2月前
|
编译器 C语言 C++
配置C++的学习环境
【10月更文挑战第18天】如果想要学习C++语言,那就需要配置必要的环境和相关的软件,才可以帮助自己更好的掌握语法知识。 一、本地环境设置 如果您想要设置 C++ 语言环境,您需要确保电脑上有以下两款可用的软件,文本编辑器和 C++ 编译器。 二、文本编辑器 通过编辑器创建的文件通常称为源文件,源文件包含程序源代码。 C++ 程序的源文件通常使用扩展名 .cpp、.cp 或 .c。 在开始编程之前,请确保您有一个文本编辑器,且有足够的经验来编写一个计算机程序,然后把它保存在一个文件中,编译并执行它。 Visual Studio Code:虽然它是一个通用的文本编辑器,但它有很多插
|
2月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
170 21
|
2月前
|
Java 编译器 C++
c++学习,和友元函数
本文讨论了C++中的友元函数、继承规则、运算符重载以及内存管理的重要性,并提到了指针在C++中的强大功能和使用时需要注意的问题。
30 1
|
3月前
|
C++
【C++基础】程序流程结构详解
这篇文章详细介绍了C++中程序流程的三种基本结构:顺序结构、选择结构和循环结构,包括if语句、三目运算符、switch语句、while循环、do…while循环、for循环以及跳转语句break、continue和goto的使用和示例。
72 2
|
4月前
|
PHP C++ Python
右手坐标系,空间点绕轴旋转公式&程序(Python和C++程序)
右手坐标系,空间点绕轴旋转公式&程序(Python和C++程序)
102 0
|
4月前
|
C++
c++学习笔记03 程序流程结构
C++学习笔记,主要介绍了程序流程结构,包括顺序结构、选择结构和循环结构。选择结构中详细解释了if语句、三目运算符和switch语句的用法和注意事项。循环结构部分则涵盖了while循环、do-while循环和for循环的语法和使用技巧。此外,还介绍了跳转语句,包括break、continue和goto语句的用途和用法。
38 0
|
5月前
|
存储 安全 编译器
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)
【C++入门 四】学习C++内联函数 | auto关键字 | 基于范围的for循环(C++11) | 指针空值nullptr(C++11)