Windows下视频采集的方法
在 Windows 下主要有两种方法来采集视频: 一种是通过 Media Foundation,另一种是通过 DirectShow。
Meida Foundation 是 Windows 从 vista 之后推出的一套全新的 多媒体SDK,简单方便,从 Win7 开始成熟起来。
另一种是 DirectShow,它主要用于 win7 之前的采集视频。使用 DirectShow 编写代码比较麻烦,主要是因为 Windows 工程师按照逻辑电路的思维方式设计了 DirectsShow 的开发接口,引入了什么 filter, pin之类的概念。这些老掉牙的东西现在估计没几个人能搞明白,除非你是从那个时代过来的,哈哈。
这也解释了为啥现在很少有人学习 Windows 程序开发了,就是因为跟不上时代。你看人家 Android/iOS做视频采集多简单,你整的这么麻烦,谁还愿意学!
Media Foundation的一些概念
DirectShow 方案我们放到以后再分析,今天我们主要讲下 MediaFoundation 如何进行视频采集。
在讲之前,我们先要补充一些基本概念。这些概念大家可以从Media Foundation Programming Guide 找到。下面的文字基本是翻译的 Windows 的官方文档。
MF(MediaFoundation)的整体结构图如下:
MF 提供了两种不同的编程模型。第一种是上图的左半部分,媒体数据通过端到端的管道传递。Application首先初始化管道,然后调用相应方法控制管道中的流。第二种如上图的右半部分,Application可以从 Source Reader拉数据,也可以向 Sink Writer 推数据。这种模型对于处理数据非常有用。
Primitives 和 Platfrom
图底部的 Primitives 是一些辅助API:
- Attributes: 相当于一个 Map, 由 key/value 组成。
- Media Type: 描述媒体数据流的格式。
- Media Buffers: 存放一段媒体数据。
- Media Samples: 存放 Media Buffers 的容器,相当于一个 Buffter List。
MF Platform 提供了一些核心功能的API。例如异步调用、工作队列。
Media Pipeline
Media Pipeline 包括三种类型对象:Media Sources、MFTs(Media Foundation Transfors)、Media Sink。
- Media Sources: 将数据引入到管道里。数据可以来自本地文件,网络流或都是硬件设备。
- MFTs: 处理流数据。在 MFTs 里实现了编解码器。
- Media Sink: 消费数据。显示视频到显示屏上,播放声音或写数据到媒体文件。
Media Session 通过管道控制数据流。如质量控制,音频/视频同步,格式的改变。
Source Reader 和 Sink Writer
Source Reader 和 Sink Writer提供了使用 Media Foundation 的另一种方法(相较于 media source, transforms, media sink)。
- Source Reader 控制着 media source 和 多个解码器。
- Sink Writer 控制着 media sink 和 多个编码器。
你可以使用 Source Reader 从 media source 获取到压缩或未压缩的数据,并使用 Sinker Writer 编码数据并发送给 media sink。
下面我们就来看看 MF 是如何采集视频数据的。
采集视频数据
通过上面的介绍,我们基本可以知道 MF 采用 从源采集数据,编解码,输出渲染这种架构来处理多媒体。这种方式通俗易懂,使用起来非常方便。
MF采集视频的基本步骤
MF采集数据使用的是架构中的第二种编程模型,其步骤如下:
- 初始化 COM 组件。
- 获取视频设备列表。
- 激活某个视频设备,获取该设备的 Media Source。
- 根据请求命令和 Media Source 创建 Source Reader。
- 为 Source Reader 设置 Media Type。
- 通过 Source Reader 从设备中读取 Media Type 格式的视频数据。
以上就是 MF 从视频设备采集数所的基本步骤,下面我们来详细介绍每一步。
详细分析
由于每一步的代码都实分简单,我这里就不做过多的文字描述了,通过下面的代码及其注释大家很容易理解其中的每一步。
初始化 COM 组件并启动 MF
CoInitializeEx(NULL, COINIT_APARTMENTTHREAD | COINIT_DISABLE_OLEDDE) MFStartup(MF_VERSION)
获取所有的视频设备
IMFAttributes *videoCmd = NULL; IMFActivate **videoDevices = NULL; UINT32 videoDeviceCount = 0; //设置获取视频设备的命令 MFCreateAttributes(videoCmd, 1/*表示只分配一项*/); videoCmd->setGUID( MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, //key MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID); //value //获取视频设备列表 MFEnumDeviceSources( videoCmd, &videoDevices, //这里是设备列表 &videoDeviceCount); //这里存放的是设备的个数
激活某个视频设备
IMFMediaSource *mediaSource = NULL; //激活第一个视频设备,并为该设置备生成逻辑上的媒体源(Media Source) videoDevices[0]->ActivateObject(IID_PPV_ARGS(&mediaSource));
创建 Source Reader
IMFSourceReader *soureReader = NULL; //通过媒体源和请求命令,可以获取source reader。(第二种开发模型) MFCreateSourceReaderFromMediaSource( mediaSource, videoCmd, &sourceReader);
设置 Media Type
IMFMediaType *mediaType = NULL; MFCreateMediaType(&mediaType); //设置媒体为视频 mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video); //YUV格式为 I420 mediaType->SetGUID(MF_MT_SUBTYPE, WMMEDIASUBTYPE_I420); //每个视频帧的大小为 640 * 480 MFSetAttributeSize(mediaType, MF_MT_FRAME_SIZE, 640, 480); sourceReader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, mediaType);
读取数据
IMFSample *sample = NULL; DWORD index, flags; LONGLONG llVideoTs; while(runing){ sourceReader->ReadSample( MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, &index, //实际流的index &flags, //staus flags &llVideoTs, //时间戳 &sample); //存放采集到的视频数据 }
通过上面简单的几步,就可以轻松的从视频设备里取到视频数据了。MF相对于 DirectShow真是简单太多了。
上面介绍的是使用同步方式使用MF采集视频数据,MF还提供了效率更高的异步方式获取视频数据,有兴趣的朋友可以以本篇文章为基础去学习它的异步方式。
小结
今天向大家介绍了在 Windows下使用 MF 如何采集视频的方法。通过以下 6 步即可做到:
- 初始化 COM 组件。
- 获取视频设备列表。
- 激活某个视频设备,获取该设备的 Media Source。
- 根据请求命令和 Media Source 创建 Source Reader。
- 为 Source Reader 设置 Media Type。
- 通过 Source Reader 从设备中读取 Media Type 格式的视频数据。
另外, MF 的采集方案只适用于 Win7 以后的系统,对于之前的系统还是要使用 DirectShow 方案。我也会在后面再为大家介绍如何使用 DirectShow 采集视频。
原文地址:https://www.cnblogs.com/CDNfast/p/10209283.html