文章目录

  • 1、DriectShow 采集
    • 1.1 DirectShow 基础
    • 1.2 DriectShow 采集应用场景
  • 2、DirecShow 代码和原理介绍
    • 2.1 ICaptureGraphBuilder2
      • 使用捕获图构建器
    • 类图
      • 初始化捕获图构建器
      • 代码
    • 2.2 DirectShow Video Capture Filters
      • pin 类别
    • 2.3 获取设备信息
    • 枚举设备
    • 获取属性
  • 3、预览视频
  • 4、捕获到文件
  • 5、Control Capture Graph

1、DriectShow 采集

1.1 DirectShow 基础

DirectShow 其主要设计目标是通过将应用程序与数据传输的复杂性、硬件差异和同步隔离,简化在 Windows 平台上创建数字媒体应用程序的任务 ,DirectShow简化媒体播放、格式转换和捕获任务

下图显示了应用程序、DirectShow组件以及应用程序支持的一些硬件和软件DirectShow之间的关系。
在这里插入图片描述

Filter是DirectShow技术体系中最基本的概念。如上图所示,DirectShow中的Filter分成三大类:Source Filter、Transform Filter、Render Filter。Source Filter就是提供数据源的Filter,所有的数据都是从Source Filter流出去的。不管是多媒体文件还是多媒体设备,Source Filter都进行了封装统一了接口,在使用方式上保持了一致。Transform Filter则是对数据进行操作处理的Filter,所有的图像操作都应该在这里进行。而Render Filter则是用来渲染图像的Filter,不管是保存到文件还是输出到其他地方,都由这个Render Filter来实现。Windows系统本身提供了非常多的Filter,我们在开发的时候可以直接使用。

下面是UI 界面配置directshow 软件(graphstudionext)的示意图,通过拖动就可以配置,filter 的概念。而整个图就 Filter Graph。如果需要就向 Filter Graph 添加filter , 并且链接 pin(引脚)

1.2 DriectShow 采集应用场景

现在市场上大多数的摄像头和采集卡在Windows系统上的驱动基于WDM架构,微软定义了采集卡设备与上层程序间的通信驱动接口,这已经成为一种标准,因此,控制摄像头和采集图像基本都通过Directshow框架来实现。

2、DirecShow 代码和原理介绍

2.1 ICaptureGraphBuilder2

因为graph manager 的接口的管理是比较复杂的,为了简化 IGraphBuilder 的使用, DirectShow 提供了一个名为 Capture Graph Builder 的辅助对象,ICaptureGraphBuilder2 接口对IGraphBuilder 进行封装。ICaptureGraphBuilder2 包含用于构建和控制捕获图的方法。

使用捕获图构建器

类图

初始化捕获图构建器

首先调用 CoCreateInstance 创建 Capture Graph Builder(ICaptureGraphBuilder2 ) 和 Filter Graph Manager (IGraphBuilder )的新实例。然后通过使用指向过滤器图管理器的IGraphBuilder接口的指针调用ICaptureGraphBuilder2::SetFiltergraph 来初始化捕获图生成器。下图说明了这个过程。

代码

HRESULT InitCaptureGraphBuilder(IGraphBuilder **ppGraph,  // Receives the pointer.ICaptureGraphBuilder2 **ppBuild  // Receives the pointer.
)
{if (!ppGraph || !ppBuild){return E_POINTER;}IGraphBuilder *pGraph = NULL;ICaptureGraphBuilder2 *pBuild = NULL;// Create the Capture Graph Builder.HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&pBuild );if (SUCCEEDED(hr)){// Create the Filter Graph Manager.hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&pGraph);if (SUCCEEDED(hr)){// 此处就是说明2者的关系。pBuild->SetFiltergraph(pGraph);// Return both interface pointers to the caller.*ppBuild = pBuild;*ppGraph = pGraph; // The caller must release both interfaces.return S_OK;}else{pBuild->Release();}}return hr; // Failed
}

2.2 DirectShow Video Capture Filters

pin 类别

video capture file 有2类的pin

  • caputre pin : 带时间戳,会有一定的延迟,一般是编码和存储使用
  • preview pin:不带时间错,为了实时显示,会丢帧,只是为了渲染使用

在详细的内容,大家可以自己看下微软官网DirectShow Video Capture Filters

2.3 获取设备信息

枚举设备

1、调用 CoCreateInstance 创建 System Device Enumerator 一个实例 ICreateDevEnum
2、 ICreateDevEnum::CreateClassEnumerator 并将设备类别指定为 GUID。对于捕获设备,以下类别是相关的。

3、CreateClassEnumerator方法返回一个指针IEnumMoniker接口。要枚举名字,请调用IEnumMoniker::Next。(Moniker 是 绰号的意思)

#include <windows.h>
#include <dshow.h>#pragma comment(lib, "strmiids")HRESULT EnumerateDevices(REFGUID category, IEnumMoniker **ppEnum)
{// Create the System Device Enumerator.ICreateDevEnum *pDevEnum;HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,  CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));if (SUCCEEDED(hr)){// Create an enumerator for the category.hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);if (hr == S_FALSE){hr = VFW_E_NOT_FOUND;  // The category is empty. Treat as an error.}pDevEnum->Release();}return hr;
}

获取属性

设备含义如下:

“FriendlyName”:属性可用于每个设备。它包含设备的可读名称。
“Description”:属性仅适用于 DV 和 D-VHS/MPEG 摄像机设备。有关详细信息,请参阅MSDV 驱动程序和MSTape 驱动程序。如果可用,它包含比“FriendlyName”属性更具体的设备描述。通常它包括供应商名称。
“DevicePath”:属性不是人类可读的字符串,但保证对于系统上的每个视频捕获设备都是唯一的。您可以使用此属性来区分同一型号设备的两个或多个实例。
如果存在“WaveInID”属性,则表示 DirectShow 捕获过滤器在内部使用波形音频API 与设备进行通信。“WaveInID”:属性的值对应于waveIn*函数使用的标识符,例如waveInOpen。

代码示例

  • 调用IMoniker::BindToStorage 获得IPropertyBag 的接口
  • 调用IPropertyBag::Read 获取属性
void DisplayDeviceInformation(IEnumMoniker *pEnum)
{IMoniker *pMoniker = NULL;while (pEnum->Next(1, &pMoniker, NULL) == S_OK){IPropertyBag *pPropBag;HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));if (FAILED(hr)){pMoniker->Release();continue;  } VARIANT var;VariantInit(&var);// Get description or friendly name.hr = pPropBag->Read(L"Description", &var, 0);if (FAILED(hr)){hr = pPropBag->Read(L"FriendlyName", &var, 0);}if (SUCCEEDED(hr)){printf("%S\n", var.bstrVal);VariantClear(&var); }hr = pPropBag->Write(L"FriendlyName", &var);// WaveInID applies only to audio capture devices.hr = pPropBag->Read(L"WaveInID", &var, 0);if (SUCCEEDED(hr)){printf("WaveIn ID: %d\n", var.lVal);VariantClear(&var); }hr = pPropBag->Read(L"DevicePath", &var, 0);if (SUCCEEDED(hr)){// The device path is not intended for display.printf("Device path: %S\n", var.bstrVal);VariantClear(&var); }pPropBag->Release();pMoniker->Release();}
}void main()
{HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);if (SUCCEEDED(hr)){IEnumMoniker *pEnum;hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum);if (SUCCEEDED(hr)){DisplayDeviceInformation(pEnum);pEnum->Release();}hr = EnumerateDevices(CLSID_AudioInputDeviceCategory, &pEnum);if (SUCCEEDED(hr)){DisplayDeviceInformation(pEnum);pEnum->Release();}CoUninitialize();}
}

如果要为一个设备创建一个Filter,设备IMoniker 指针,调用IMoniker::BindToObject 获得一个IBaseFilter 指针,然后调用IFilterGraph::AddFilter 加入到 Filter Graph中

IBaseFilter *pCap = NULL;
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap);
if (SUCCEEDED(hr))
{hr = m_pGraph->AddFilter(pCap, L"Capture Filter");
}

3、预览视频

ICaptureGraphBuilder2 *pBuild; // Capture Graph Builder
// Initialize pBuild (not shown).IBaseFilter *pCap; // Video capture filter./* Initialize pCap and add it to the filter graph (not shown). */hr = pBuild->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCap, NULL, NULL);

ICaptureGraphBuilder2::RenderStream方法的
第一个参数指定引脚类别;对于预览图,请使用PIN_CATEGORY_PREVIEW。

第二个参数指定媒体类型,作为主要类型 GUID。对于视频,请使用MEDIATYPE_Video。DV 设备提供交错的音频和视频,其媒体类型为MEDIATYPE_Interleaved。(有关 DV 捕获的更多信息,请参阅DirectShow 中的数字视频。)

第三个参数是指向捕获过滤器的IBaseFilter接口的指针。本示例中不需要接下来的两个参数。它们用于指定渲染流可能需要的其他过滤器。将最后一个参数设置为NULL会导致 Capture Graph Builder 根据媒体类型为流选择默认渲染器。对于视频,Capture Graph Builder 始终使用Video Renderer过滤器作为默认渲染器。

虽然 pin 类别被指定为PIN_CATEGORY_PREVIEW,但过滤器是否真的有预览 pin 并不重要;它可以有一个视频端口引脚或只是一个捕获引脚。无论哪种情况,Capture Graph Builder 都会自动构建正确的图形

4、捕获到文件

下图显示了将视频捕获到 AVI 文件的最简单的图形。

该AVI多路复用器过滤从捕捉引脚获取视频流并将其打包成AVI流。音频流也可以连接到 AVI Mux 过滤器,在这种情况下,mux 将交错两个流。该文件写入过滤器的AVI流写入到磁盘中。

要构建图形,首先调用ICaptureGraphBuilder2::SetOutputFileName方法,如下所示:

IBaseFilter *pMux;
hr = pBuild->SetOutputFileName(&MEDIASUBTYPE_Avi,  // Specifies AVI for the target file.L"C:\\Example.avi", // File name.&pMux,              // Receives a pointer to the mux.NULL);              // (Optional) Receives a pointer to the file sink.

接下来,调用ICaptureGraphBuilder2::RenderStream方法将捕获过滤器连接到 AVI Mux,如下所示:

hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, // Pin category.&MEDIATYPE_Video,      // Media type.pCap,                  // Capture filter.NULL,                  // Intermediate filter (optional).pMux);                 // Mux or file sink filter.// Release the mux filter.
pMux->Release();

5、Control Capture Graph

过滤器图形管理器的IMediaControl接口具有运行、停止和暂停整个图形的方法。但是,如果过滤器图具有捕获和预览流,您可能希望独立控制这两个流。例如,您可能想要预览视频而不捕获它。您可以通过ICaptureGraphBuilder2::ControlStream方法执行此操作。

以下代码将视频捕获流设置为运行四秒,在图形运行后一秒开始:

// Control the video capture stream.
REFERENCE_TIME rtStart = 10000000, rtStop = 50000000;
const WORD wStartCookie = 1, wStopCookie = 2;  // Arbitrary values.
hr = pBuild->ControlStream(&PIN_CATEGORY_CAPTURE, // Pin category.&MEDIATYPE_Video,      // Media type.pCap,                 // Capture filter.&rtStart, &rtStop,     // Start and stop times.wStartCookie, wStopCookie  // Values for the start and stop events.
);
pControl->Run();

windows - 摄像头采集相关推荐

  1. ffmpeg实现摄像头拉流_利用ffmpeg一步一步编程实现摄像头采集编码推流直播系统...

    了解过ffmpeg的人都知道,利用ffmpeg命令即可实现将电脑中摄像头的画面发布出去,例如发布为UDP,RTP,RTMP等,甚至可以发布为HLS,将m3u8文件和视频ts片段保存至Web服务器,普通 ...

  2. linux 从摄像头采集一帧 jpg,使用FFmpeg捕获一帧摄像头图像

    最近在研究FFmpeg,比较惊讶的是网上一大堆资料都是在说如何从已有的视频中截取一帧图像,却很少说到如何直接从摄像头中捕获一帧图像,其实我一直有个疑问,就是在Linux下,大家是用什么库来采集摄像头的 ...

  3. [转]GStreamer资料(摄像头采集,视频保存,远程监控)DVR

    http://blog.csdn.net/wzwxiaozheng/archive/2010/12/26/6099397.aspx GStreamer资料整理(包括摄像头采集,视频保存,远程监控,流媒 ...

  4. GStreamer资料(摄像头采集,视频保存,远程监控)DVR

    转载自:http://blog.chinaunix.net/uid-10747583-id-282761.html http://blog.csdn.net/wzwxiaozheng/archive/ ...

  5. 米联客 ZYNQ/SOC 精品教程 S02-CH24 利用AXI VDMA 实现MT9V034摄像头采集

    软件版本:VIVADO2017.4 操作系统:WIN10 64bit 硬件平台:适用米联客 ZYNQ系列开发板 米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!! ...

  6. linux 从摄像头采集一帧 jpg,基于Video4Linux 的USB 摄像头图像采集实现.pdf

    基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 1 基于基于 Video4Linux 的的 USB 摄像头图像采集实现摄像头图像采集实现 Write by dail ...

  7. fedora 9下驱动摄像头采集图像手记

    最近一个月,在做视屏图像采集方面的项目.我安装了的是fedora 9.在fedora 9下让摄像头采集数据可谓是费尽了我半个月的时间.看似简单的问题,不知道我为什么做了这么长时间.    首先,摄像头 ...

  8. 麒麟操作系统/Linux 摄像头采集录制

    Linux系统上采集摄像头,可以使用V4L2相关接口,Linux上的摄像头设备文件是/dev/videoxx, 采集和控制摄像头只要调用open("/dev/videoxx", f ...

  9. OBS源码使用学习(一)之摄像头采集相关

    我之前也没接触过obs相关的东西,磕磕绊绊可好一阵.现在特把obs的研究心得记录下来,也希望学习这个的萌新们能够少走弯路. 一.从OBS的使用中知晓大体流程 直接看代码,对于刚刚接触obs的萌新而言非 ...

最新文章

  1. 【思维导图】redis
  2. nginx mysql 安装_CentOS7下安装Nginx+MySQL教程
  3. Postfix 邮件服务 - 基础服务
  4. python写算法求最短路径,Python实现迪杰斯特拉算法并生成最短路径的示例代码
  5. Homebrew 更换阿里云镜像源
  6. 从Python中的另一个文件调用函数
  7. 中台之上(五):业务架构和中台的难点,都是需要反复锤炼出标准模型
  8. MySQL数据库MyISAM与InnoDB存储引擎的比较
  9. 数据--第46课 - 图算法课后练习
  10. 笔记二:云上传与调用获取openid
  11. 再谈 最速下降法/梯度法/Steepest Descent
  12. Wonderware-InTouch安装 Intouch 2014 R2 SP1
  13. optisystem中器件的学习(5-Receivers Library/Tools Library/Optiwave/ external Software Library/Free Space )
  14. DateTimeFormatter获取时间戳
  15. 图片复印如何去除黑底_如何将扫描后的图片底色去掉
  16. C++输出透明背景字体
  17. 网站搜索引擎优化诊断
  18. The nodejs-legacy package simply installs a symbolic link so that it can be executed using the node
  19. 2018中国民营企业500强榜单
  20. 浪潮服务器键盘自动输空格,键盘空格键的常用技巧分享

热门文章

  1. ssh被暴力猜解登录密码,利用pandas简单分析ssh登录失败记录
  2. 我们静静地等待着老师的怀念到来
  3. APP开发实战132-Git命令介绍
  4. 《我不知道该说什么,关于死亡还是爱情》······
  5. linux xd命令,Linux下命令rm -rf的补救方法
  6. 【好用的软件分享】Snipaste截图工具
  7. 内存条怎么插在电脑上使用
  8. 全网一触即发,自媒体人的内容分发全能助手——融媒宝
  9. 肤质测试html,怎么测肤质
  10. python 方差分解_干货 :教你用Python来计算偏差-方差权衡