DirectShow视频采集方案
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2.3 DirectShow
流媒体处理技术以其复杂性和技术性一直受到人们的关注。随着网络技术的不断发展,流媒体在网络上得到了广泛地应用。如何能够简单、有效地进行流媒体处理,已成为一个焦点问题。为此,Microsoft推出了DirectShow,DirectShow是Microsoft推出的基于Windows平台的流媒体处理开发包,它与DirectX一起发布。DirectShow对流媒体的捕捉、回放提供了强大的支持,使用它还可以在基于WDM驱动的采集卡上进行数据捕捉。本节将介绍有关DirectShow的相关知识。
while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK)
{
pOutpin->QueryDirection(&pDir);
if (pDir==dir)
{
return pOutpin;
}
}
return 0;
}
用户可以按下面的方式获得某个过滤器的输入、输出引脚。
IPin * pComOut,*pComIn ;
在开发DirectShow应用程序时,通常需要设计一个过滤图表(Filter Graph),向过滤图表中添加相应的过滤器,最后连接过滤器的引脚就完成了功能的设计。例如,实现一个简单的视频预览功能,需要向过滤图表中添加一个视频捕捉源过滤器和一个Video Renderer过滤器,将视频捕捉源过滤器的输出引脚与Video Renderer过滤器的输入引脚相连就可以了。而在程序中只需要按照设计过滤图表的捕捉添加过滤器并连接过滤器引脚就可以了。在连接过滤器引脚时需要注意:只能是输出过滤器引脚与输入过滤器引脚相连,两个输出过滤器或两个输入过滤器引脚是不能相连的。
为了在程序中使用DirectShow,需要单独安装DirectX,当前DirectX的最新版本为9.0,即DirectX9.0,用户可以从Microsoft的官方网站上免费下载。在安装DirectX之后,程序中需要引用“dshow.h”头文件,并导入“Strmiids.lib”库文件和“quartz.lib”库文件才可以使用DirectShow。代码如下:
图2.12添加视频捕捉源过滤器窗口
提示:如果系统中没有安装摄像头及其驱动程序,该节点下将不会有视频捕捉源过滤器。
(3)在“DirectShow Filters”节点下选择“Video Renderer”过滤器,将其添加到图表中,如图2.13所示。
图2.13添加“Video Renderer”过滤器窗口
//查找引脚
IPin* CKinescopeDlg::FindPin(IBaseFilter *pFilter, PIN_DIRECTION dir)
{
IEnumPins* pEnumPins;
IPin* pOutpin;
PIN_DIRECTION pDir;
pFilter->EnumPins(&pEnumPins);
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);
//枚举视频设备
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **)&pDevEnum);
IEnumMoniker *pClassEnum = NULL;
{
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);
pMoniker->Releaseum->Release();
而下面的代码则用于判断系统中是否安装了指定的视频压缩器。
ICreateDevEnum *pDevEnum = NULL;
(4)利用鼠标将视频捕捉源过滤器的“Capture”引脚与“Video Renderer”过滤器的“VMR Input0”引脚相连,如图2.14所示。
图2.14连接过滤器引脚窗口
(5)单击工具栏中的“ ”按钮运行过滤图表,将显示一个视频预览窗口,如图2.15所示。
图2.15视频预览窗口
2.3.3
使用Graph Edit工具,用户可以非常方便地获得与某一系统设备相关的过滤器。但是,在程序中该如何获得这些过滤器呢?
while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pProp= NULL;
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pProp);
VARIANT varName;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
ULONG cFetched;
while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
(2)在“DirectShow Filters”节点下将“Video Render”过滤器添加到图表中,如图2.17所示。
pMoniker->Release();
break;
}
VariantClear(&varName);
}
pClassEnum->Release();
2.3.4
每一个过滤器(Filter)至少应有一个引脚(Pin),或者是输入引脚或者是输出引脚。有些过滤器还拥有多个引脚,即又输入引脚又有输出引脚。但是过滤器的输入、输出引脚并不是对应的,有些过滤器可以有多个输入引脚,而只有一个输出引脚或者没有输出引脚。在程序中为了连接过滤器间的引脚,通常需要获得过滤器的各个引脚。用户可以使用IEnumPins接口来枚举某一个过滤器的输入、输出引脚。过滤器IBaseFilter提供了一个EnumPins方法用于生成一个IEnumPins接口实例,这样,通过调用IEnumPins的Next方法便可以访问各个引脚了。下面的代码定义了一个FindPin函数,用于获得某个过滤器的输入或输出引脚。
pComIn = FindPin(pCompress,PINDIR_INPUT);
pComOut = FindPin(pCompress,PINDIR_OUTPUT);
2.3.5
使用Graph Edit工具,用户可以利用鼠标非常方便地连接两个过滤器间的引脚。但是在程序中却没这么简单了。首先需要按照2.3.4节介绍的方法获得两个过滤器的输入、输出引脚,然后将第一个过滤器的输出引脚连接到第二个过滤器的输入引脚,其中,连接两个引脚需要调用IGraphBuilder接口的ConnectDirect方法。下面的代码演示了如何连接两个过滤器的引脚。
图2.10 Graph Edit工具
下面笔者介绍如何使用Graph Edit工具设计过滤图表,过滤图表的功能是实现视频的预览功能。具体步骤如下:
(1)在图2.4中单击“Graph/Insert Filters”菜单项打开“添加过滤器”窗口,如图2.11所示。
图2.11添加过滤器窗口
(2)在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按钮将其添加到过滤图表中,如图2.12所示
(1)启动Graph Edit工具,在Graph Edit工具中单击“Graph \Insert Filters”菜单项打开“添加过滤器窗口”,在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按钮将其添加到过滤图表中,如图2.11所示。
在上面的描述中,ICreateDevEnum实例的CreateClassEnumerator方法的第一个参数确定枚举的系统设备。例如,第一个参数为CLSID_VideoInputDeviceCategory,表示将要枚举系统中的视频捕捉卡,为CLSID_VideoCompressorCategory,表示枚举系统中的视频压缩器。下面的代码演示了如何枚举系统中的视频捕捉卡。
用户可以采用枚举的方式列举系统中安装的设备。以列举系统中的视频捕捉设备为例,首先定义一个设备列举接口ICreateDevEnum的一个指针,调用CoCreateInstance方法创建ICreateDevEnum实例,然后定义一个列举监视器IEnumMoniker的一个指针,调用ICreateDevEnum实例的CreateClassEnumerator方法创建IEnumMoniker实例,最后以循环的方式调用IEnumMoniker实例的Next方法遍历系统设备,调用IEnumMoniker实例的BindToObject方法将系统设备绑定到过滤器上。
#pragma comment (lib,"Strmiids")
#pragma comment (lib,"quartz")
#include <dshow.h>
2.3.2 Filter
为了方便用户设计过滤图表,DirectX提供了一个Graph Edit工具。用户可以单击“开始”菜单下的“Microsoft DirectX 9 SDK\DirectX Utilities\Graph Edit”菜单项打开Graph Edit工具,如图2.10所示。
IPin * pComOut,*pComIn ;
pComIn = FindPin(pCompress,PINDIR_INPUT);
pComOut = FindPin(pCompress,PINDIR_OUTPUT);
IPin* pOutpin = FindPin(pSrc,PINDIR_OUTPUT); //pSrc的输出引脚
2.3.1 DirectShow
DirectShow主要由过滤器(Filter Graph)图表构成。过滤图表中包含了各种Filter,这些Filter能够按一定顺序连接在一起,构成一条流水线。从功能的角度划分,Filter大体可以分为3类,Source Filters、Transform Filters和Rendering Filters。Source Filters主要负责获取数据,可以是一个文件、一个采集卡、声卡或数码相机等。Transform Filters负责数据的转换、传输。例如各种编码器、解码器等。Rendering Filters负责数据的最终去向,例如将数据传送到声卡、显卡或存储为文件。
HRESULT result ;
result = pGraph->ConnectDirect(pOutpin,pComIn,NULL);
2.3.6
在开发视频应用程序时,一个最基本的功能是视频预览。本节将介绍如何应用DirectShow实现视频预览,效果如图2.16所示。
图2.16视频预览设计方案
在使用DirectShow开发应用程序时,通常需要先设计过滤图表,然后根据图表来设计应用程序。在设计视频预览过滤图表时,只需要两个步骤,第一个步骤是添加视频捕捉的源过滤器,第二个步骤是添加Video Render过滤器,并连接两个过滤器引脚。过滤图表具体设计步骤如下:
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **)&pDevEnum);
IEnumMoniker *pClassEnum = NULL;
//列举视频压缩设备
pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pClassEnum, 0);
流媒体处理技术以其复杂性和技术性一直受到人们的关注。随着网络技术的不断发展,流媒体在网络上得到了广泛地应用。如何能够简单、有效地进行流媒体处理,已成为一个焦点问题。为此,Microsoft推出了DirectShow,DirectShow是Microsoft推出的基于Windows平台的流媒体处理开发包,它与DirectX一起发布。DirectShow对流媒体的捕捉、回放提供了强大的支持,使用它还可以在基于WDM驱动的采集卡上进行数据捕捉。本节将介绍有关DirectShow的相关知识。
while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK)
{
pOutpin->QueryDirection(&pDir);
if (pDir==dir)
{
return pOutpin;
}
}
return 0;
}
用户可以按下面的方式获得某个过滤器的输入、输出引脚。
IPin * pComOut,*pComIn ;
在开发DirectShow应用程序时,通常需要设计一个过滤图表(Filter Graph),向过滤图表中添加相应的过滤器,最后连接过滤器的引脚就完成了功能的设计。例如,实现一个简单的视频预览功能,需要向过滤图表中添加一个视频捕捉源过滤器和一个Video Renderer过滤器,将视频捕捉源过滤器的输出引脚与Video Renderer过滤器的输入引脚相连就可以了。而在程序中只需要按照设计过滤图表的捕捉添加过滤器并连接过滤器引脚就可以了。在连接过滤器引脚时需要注意:只能是输出过滤器引脚与输入过滤器引脚相连,两个输出过滤器或两个输入过滤器引脚是不能相连的。
为了在程序中使用DirectShow,需要单独安装DirectX,当前DirectX的最新版本为9.0,即DirectX9.0,用户可以从Microsoft的官方网站上免费下载。在安装DirectX之后,程序中需要引用“dshow.h”头文件,并导入“Strmiids.lib”库文件和“quartz.lib”库文件才可以使用DirectShow。代码如下:
图2.12添加视频捕捉源过滤器窗口
提示:如果系统中没有安装摄像头及其驱动程序,该节点下将不会有视频捕捉源过滤器。
(3)在“DirectShow Filters”节点下选择“Video Renderer”过滤器,将其添加到图表中,如图2.13所示。
图2.13添加“Video Renderer”过滤器窗口
//查找引脚
IPin* CKinescopeDlg::FindPin(IBaseFilter *pFilter, PIN_DIRECTION dir)
{
IEnumPins* pEnumPins;
IPin* pOutpin;
PIN_DIRECTION pDir;
pFilter->EnumPins(&pEnumPins);
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);
//枚举视频设备
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **)&pDevEnum);
IEnumMoniker *pClassEnum = NULL;
{
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc);
pMoniker->Releaseum->Release();
而下面的代码则用于判断系统中是否安装了指定的视频压缩器。
ICreateDevEnum *pDevEnum = NULL;
(4)利用鼠标将视频捕捉源过滤器的“Capture”引脚与“Video Renderer”过滤器的“VMR Input0”引脚相连,如图2.14所示。
图2.14连接过滤器引脚窗口
(5)单击工具栏中的“ ”按钮运行过滤图表,将显示一个视频预览窗口,如图2.15所示。
图2.15视频预览窗口
2.3.3
使用Graph Edit工具,用户可以非常方便地获得与某一系统设备相关的过滤器。但是,在程序中该如何获得这些过滤器呢?
while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
{
IPropertyBag* pProp= NULL;
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pProp);
VARIANT varName;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
ULONG cFetched;
while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK)
(2)在“DirectShow Filters”节点下将“Video Render”过滤器添加到图表中,如图2.17所示。
pMoniker->Release();
break;
}
VariantClear(&varName);
}
pClassEnum->Release();
2.3.4
每一个过滤器(Filter)至少应有一个引脚(Pin),或者是输入引脚或者是输出引脚。有些过滤器还拥有多个引脚,即又输入引脚又有输出引脚。但是过滤器的输入、输出引脚并不是对应的,有些过滤器可以有多个输入引脚,而只有一个输出引脚或者没有输出引脚。在程序中为了连接过滤器间的引脚,通常需要获得过滤器的各个引脚。用户可以使用IEnumPins接口来枚举某一个过滤器的输入、输出引脚。过滤器IBaseFilter提供了一个EnumPins方法用于生成一个IEnumPins接口实例,这样,通过调用IEnumPins的Next方法便可以访问各个引脚了。下面的代码定义了一个FindPin函数,用于获得某个过滤器的输入或输出引脚。
pComIn = FindPin(pCompress,PINDIR_INPUT);
pComOut = FindPin(pCompress,PINDIR_OUTPUT);
2.3.5
使用Graph Edit工具,用户可以利用鼠标非常方便地连接两个过滤器间的引脚。但是在程序中却没这么简单了。首先需要按照2.3.4节介绍的方法获得两个过滤器的输入、输出引脚,然后将第一个过滤器的输出引脚连接到第二个过滤器的输入引脚,其中,连接两个引脚需要调用IGraphBuilder接口的ConnectDirect方法。下面的代码演示了如何连接两个过滤器的引脚。
图2.10 Graph Edit工具
下面笔者介绍如何使用Graph Edit工具设计过滤图表,过滤图表的功能是实现视频的预览功能。具体步骤如下:
(1)在图2.4中单击“Graph/Insert Filters”菜单项打开“添加过滤器”窗口,如图2.11所示。
图2.11添加过滤器窗口
(2)在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按钮将其添加到过滤图表中,如图2.12所示
(1)启动Graph Edit工具,在Graph Edit工具中单击“Graph \Insert Filters”菜单项打开“添加过滤器窗口”,在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按钮将其添加到过滤图表中,如图2.11所示。
在上面的描述中,ICreateDevEnum实例的CreateClassEnumerator方法的第一个参数确定枚举的系统设备。例如,第一个参数为CLSID_VideoInputDeviceCategory,表示将要枚举系统中的视频捕捉卡,为CLSID_VideoCompressorCategory,表示枚举系统中的视频压缩器。下面的代码演示了如何枚举系统中的视频捕捉卡。
用户可以采用枚举的方式列举系统中安装的设备。以列举系统中的视频捕捉设备为例,首先定义一个设备列举接口ICreateDevEnum的一个指针,调用CoCreateInstance方法创建ICreateDevEnum实例,然后定义一个列举监视器IEnumMoniker的一个指针,调用ICreateDevEnum实例的CreateClassEnumerator方法创建IEnumMoniker实例,最后以循环的方式调用IEnumMoniker实例的Next方法遍历系统设备,调用IEnumMoniker实例的BindToObject方法将系统设备绑定到过滤器上。
#pragma comment (lib,"Strmiids")
#pragma comment (lib,"quartz")
#include <dshow.h>
2.3.2 Filter
为了方便用户设计过滤图表,DirectX提供了一个Graph Edit工具。用户可以单击“开始”菜单下的“Microsoft DirectX 9 SDK\DirectX Utilities\Graph Edit”菜单项打开Graph Edit工具,如图2.10所示。
IPin * pComOut,*pComIn ;
pComIn = FindPin(pCompress,PINDIR_INPUT);
pComOut = FindPin(pCompress,PINDIR_OUTPUT);
IPin* pOutpin = FindPin(pSrc,PINDIR_OUTPUT); //pSrc的输出引脚
2.3.1 DirectShow
DirectShow主要由过滤器(Filter Graph)图表构成。过滤图表中包含了各种Filter,这些Filter能够按一定顺序连接在一起,构成一条流水线。从功能的角度划分,Filter大体可以分为3类,Source Filters、Transform Filters和Rendering Filters。Source Filters主要负责获取数据,可以是一个文件、一个采集卡、声卡或数码相机等。Transform Filters负责数据的转换、传输。例如各种编码器、解码器等。Rendering Filters负责数据的最终去向,例如将数据传送到声卡、显卡或存储为文件。
HRESULT result ;
result = pGraph->ConnectDirect(pOutpin,pComIn,NULL);
2.3.6
在开发视频应用程序时,一个最基本的功能是视频预览。本节将介绍如何应用DirectShow实现视频预览,效果如图2.16所示。
图2.16视频预览设计方案
在使用DirectShow开发应用程序时,通常需要先设计过滤图表,然后根据图表来设计应用程序。在设计视频预览过滤图表时,只需要两个步骤,第一个步骤是添加视频捕捉的源过滤器,第二个步骤是添加Video Render过滤器,并连接两个过滤器引脚。过滤图表具体设计步骤如下:
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_ICreateDevEnum, (void **)&pDevEnum);
IEnumMoniker *pClassEnum = NULL;
//列举视频压缩设备
pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pClassEnum, 0);