目录
前言
一、DirectShow简介
二、DirectShow视频采集主要流程介绍
1、DirectShow视频采集主要API介绍
三、视频采集软件设计框图
四、音频采集软件设计框图
《windows平台使用DirectShow采集摄像头视频代码实现》:
https://edu.csdn.net/learn/38258/606131?spm=1003.2001.3001.4157
《windows平台使用DirectShow采集麦克风音频代码实现》:
https://edu.csdn.net/learn/38258/606135?spm=1003.2001.3001.4157
在实时视频传输中视频的采集/捕获是很健的流程,也是第一步。通常不同平台/系统其都有不同的视频捕获组件/API,如安卓平台Camera 和 Camera2 ,linux系统下V4L、苹果系AVFoundation以及windows平台的DirectShow。通过视频捕获的组件可以获取所需的视频格式来用于显示或者编码存储/传输。
DirectShow应用程序编程接口 (API) 是 Microsoft Windows的媒体流式处理体系结构。 使用DirectShow,应用程序可以对视频和音频播放或捕获。DirectShow不仅仅可以从摄像头中捕获视频,也可以从网络甚至本地文件中捕获视频。此外DirectShow是基于 COM的,DirectShow的筛选器Graph管理器和筛选器都是 COM 对象。本文主要介绍的是基于DirectShow的摄像头视频捕获流程以及关键代码的介绍。有关DirectShow的详细接受可以微软官方网站中查看,连接如下:DirectShow - Win32 apps | Microsoft Docs。其中对于DirectShow的介绍以及API的使用范例都有详细的说明。
下图显示了应用程序、DirectShow组件以及DirectShow支持的一些硬件和软件组件之间的关系。
DirectShow的基本模块是Filters(筛选器),DirectShow有三种Filters:SourceFilters(筛选器)、TransformFilters(转换筛选器)、RenderingFilters(呈现器 )。Source Filters 主要负责取得数据然后将数据传递给下一个Filters;Transfor Filters 主要负责数据的格式转换,如编码器/解码器,然后传输到下一个filters;Rendering Filters 是数据的最终去向,通常输出到显卡,也可以输出到文件进行存储。通常每个筛选器都具有输入、输出pin,输入pin用于接收上一个Filters的源数据,输出pin用于将当前Filter的数据传递到下一个Filters。Filter Graph Manager(筛选器Graph管理器)用于生成和控制筛选器Graph, 此对象是DirectShow中的中心组件。 应用程序使用它来生成和控制筛选器Graph, 筛选器Graph管理器还处理控制筛选器Graph的同步、事件通知和其他方面,通过调用 CoCreateInstance 创建此对象/组件。
DirectShow的C++ API的示例介绍可以参考DirectShow示例 - Win32 apps | Microsoft Docs 或者 DirectShow编辑服务 C++ 参考 - Win32 apps | Microsoft Docs
关于 DirectShow的C++ API的示例通常在SDK\Samples\Multimedia\DirectShow的目录下,如果没有这个目录就需要下载安装最新版本的 Windows SDK;点击链接后点击“下载”会下载winsdk_web.exe,按照提示安装,就会下载sdk到指定路径。可以从csdn下载,csdn下载链接为Microsoft Windows SDK for Windows 7。
DirectShow视频采集用到的库:windows基础库(ws2_32.lib、Winmm.lib)、strmbase.lib
CoInitialize():用于初始化COM,使用该函数表明之后以单线程的方式创建com对象/组件。CoUninitialize():用于关闭COM,释放资源,CoInitialize()和CoUninitialize()需要成对使用。CoCreateInstance():用指定的标识符创建一个Com对象/组件。其函数声明如下,
参数rclsid:待创建组件的CLSID。DirectShow的对象DirectShowObjects。
对象值 | 含义 |
CLSID_SystemDeviceEnum | System Device Enumerator |
CLSID_FilterGraph |
Filter Graph Manager |
CLSID_CaptureGraphBuilder2 | Capture Graph Builder |
参数pUnkOuter:用于聚合组件。
参数dwClsContext:dwClsContext的作用是限定所创建的组件的执行上下文。常用的值如下表。
值 | 含义 |
CLSCTX_INPROC_SERVER | 希望创建在同一进程中运行的组件 |
CLSCTX_INPROC_HANDLER | 管理此类对象的代码是进程内处理程序。这是一个动态链接库 (DLL),它在客户端进程中运行,并在远程访问该类的实例时实现该类的客户端结构 |
CLSCTX_LOCAL_SERVER | 希望创建在同一台机器上运行,但在不同的进程中的组件 |
CLSCTX_REMOTE_SERVER | 远程机器上下文。创建和管理此类对象的LocalServer32或LocalService代码在不同的机器上运行 |
参数riid:iid为组件上待使用的接口的iid。
参数ppv:用来接收指向Com对象接口地址的指针变量。
CreateClassEnumerator():用于枚举设备通常用于选择采集的摄像头。详细的使用方法和说明连接:使用系统设备枚举器 - Win32 apps | Microsoft Docs
QueryInterface():通过该查询组件是否支持某个特定的接口。
ISampleGrabber :来源于Sample Grabber Filter,Sample Grabber Filter是一个TransforFitlers类型的筛选器。通过调用ISampleGrabber::SetMediaType 方法指定Filters的输入和输出引脚连接的媒体类型,如设置图像格式为RGB。可以调用ISampleGrabber::SetBufferSamples设置值为true,捕获Filters会缓存它接收到的数据,然后再将其传递到下游。调用ISampleGrabber::GetCurrentBuffer方法来检索缓冲区的当前数据;或者可以调用ISampleGrabber::SetCallback让Filter在收到样本时调用回调函数。即通过ISampleGrabber在获取图像数据的时候可以通过调用GetCurrentBuffer来直接获取图像,也可以通过注册回调函数到ISampleGrabber通过回调函数来获取图像。
ISampleGrabberCB 接口:为 ISampleGrabber::SetCallback 提供回调方法。回调函数有两种:BufferCB和SampleCB。其函数接口声明如下:
HRESULT BufferCB(
double SampleTime,
BYTE *pBuffer,
long BufferLen
);
HRESULT SampleCB(
double SampleTime,
IMediaSample *pSample
);
获取图像数据需要重新实现其中的一个函数即可,一般重新实现BufferCB这种方式。
AddFilter() 接口:通常这个函数将Filter 加入到Graph。第一个参数是要添加的Filter的IBaseFilter接口的指针,第二个参数是设置Filter名字(宽字符)的指针。Filter的名字可以为NULL,在这种情况下Filter Graph Manager会自动生成一个名字,如果设置Filter名字在Filter Graph中有重复的名字,则会生成新的唯一的名字,新的名字生成成功,则函数会返回 VFW_S_DUPLICATE_NAME,如果无法生成唯一名称,则返回 VFW_E_DUPLICATE_NAME。AddFilter
须在尝试使用ICaptureGraphBuilder2::RenderStream、IGraphBuilder::Connect、IFilterGraph::ConnectDirect或IGraphBuilder::Render方法连接之前调用。
directShow视频采集软件模块设计如下图3-1所示。下面对 directShow视频采集软件模块做个说明。
首先通过CoCreateInstance()来创建Filter Graph Manager(IGraphBuilder)对象、Capture Graph Builder(ICaptureGraphBuilder2)对象、捕获Filter对象以及视频枚举(ICreateDevEnum)对象;
通过SetFiltergraph()将ICaptureGraphBuilder2和IGraphBuilder对象关联起来(Filter Graph Manager对象就可以管理Capture Graph Builder对象),并使用IGraphBuilder对象Filter初始化ICaptureGraphBuilder2;
Filter Graph Manager对象通过QueryInterface()来查询IVideoWindow和IMediaControl是否可用,如果可以并返回相应的指针,那么就可以使用IVideoWindow来控制采集到的视频是否通过DirectShow显示,也可以使用IMediaControl来控制整个视频采集流程的开启/关闭。
通过CamerID使用视频枚举(ICreateDevEnum)对象可以确定具体视频输入源设备,并通过BindToObject将视频输入源设备绑定到VideoFilter上。
通过AddFilter将VideoFilter和捕获Filter添加到Filter Graph Manager对象;Filter Graph Manager可以管理VideoFilter和捕获Filter,直到VideoFilter和捕获Filter调用了Release。
通过ICaptureGraphBuilder2的RenderStream()将VideoFilter和捕获Filter进行连接;捕获Filter就可以接收到VideoFilter采集来的数据。捕获Filter通过QueryInterface()来查询ISampleGrabber是否可用,如果可用则返回ISampleGrabber可用的指针。通过ISampleGrabber来设置捕获图像的输出方式(如通过SetCallback回调的方式输出图像)。最终捕获Filter通过ISampleGrabber来将采集到的视频输出到缓存队列中。
图3-1
directShow音频采集软件模块设计如下图4-1所示。下面对 directShow音频采集软件模块做个说明。
首先通过CoCreateInstance()来创建Filter Graph Manager(IGraphBuilder)对象、Capture Graph Builder(ICaptureGraphBuilder2)对象、捕获Filter对象以及音频枚举(ICreateDevEnum)对象;这一过程和视频采集中的一样。
通过SetFiltergraph()将ICaptureGraphBuilder2和IGraphBuilder对象关联起来(Filter Graph Manager对象就可以管理Capture Graph Builder对象),并使用IGraphBuilder对象Filter初始化ICaptureGraphBuilder2;这一过程和视频采集中的一样。
Filter Graph Manager对象通过QueryInterface()来查询IMediaControl是否可用,如果可以并返回相应的指针,那么就可以使用IMediaControl来控制整个视频采集流程的开启/关闭。音频采集中不需要显示窗口所以就不需要IVideoWindow。
通过micID使用音频频枚举(ICreateDevEnum)对象可以确定具体音频输入源设备,并通过BindToObject将音频输入源设备绑定到AudioFilter上;这一过程和视频采集中的一样。
通过AddFilter将AudioFilter和捕获Filter添加到Filter Graph Manager对象中;Filter Graph Manager可以管理AudioFilter和捕获Filter,直到AudioFilter和捕获Filter调用了Release。这一过程和视频采集中的一样。
通过Filter Graph Manager对象的Connect()将AudioFilter的输出Pin和捕获Filter的输入PIn进行连接;捕获Filter就可以接收到AudioFilter采集来的数据;Filter的引脚的获取通过IBaseFilter::EnumPins()来枚举当前Filter的所有引脚IPin,通过IPin的QueryDirection()来判断当前IPin是PINDIR_INPUT(输入引脚)还是PINDIR_OUTPUT(输出引脚)。可以通过AudioFilter的输入引脚来配置采集音量的大小;可以通过AudioFilter的输出引脚来配置采集的缓存信息,如缓存帧数,每帧的大小。
捕获Filter通过QueryInterface()来查询ISampleGrabber是否可用,如果可用则返回ISampleGrabber可用的指针。通过ISampleGrabber来设置捕获音频的输出方式(如通过SetCallback回调的方式输出音频)。最终捕获Filter通过ISampleGrabber来将采集到的音频频输出到缓存队列中。这一过程和视频采集中的一样。
图4-1
directShow视频采集的代码见《directShow采集摄像头数据课程》
directShow音频采集的代码见《directShow采集音频数据课程》