DirectShow视频采集方案
- 格式:doc
- 大小:642.50 KB
- 文档页数:23
第37卷第2期(总第144期)2008年6月火控雷达技术Fire Control Radar TechnologyVol.37No.2(Series 144)J un.2008 收稿日期:2007-12-12 作者简介:郭昊,男,1979年生,助理工程师,研究方向为雷达软件开发。
文章编号:1008-8652(2008)02-097-04基于Direct Show 技术实现视频采集郭 昊(西安电子工程研究所 西安 710100)【摘要】 介绍Direct Show 技术的基本概念,提出了基于Direct Show 技术采集视频数据的软件设计方案,文中详细叙述了软件开发的实现框架。
关键词:Direct Show ;视频捕获;过滤器;过滤器图表中图分类号:TP274+12 文献标志码:AImplementation of Video C apture B ased on DirectShow T echnologyGuo Hao(X i ’an Elect ronic Engi neeri ng Research I nstit ute ,X i ’an 710100)Abstract :In t his paper ,t he basic concept of Direct Show technology is int roduced.A software design scheme based on Direct Show technology for video capt ure is p resented.Meanwhile ,t he implementation f rame for developing t he software is described in detail.K eyw ords :Direct Show ;video capt ure ;filter ;filter grap h1 引言为了支持多媒体信息的采集、压缩、解压和回放,针对Windows 平台,微软提供了两种多媒体开发框架:一种是Video for Windows (简称V FW ),另一种是Direct Show 。
我们知道目前很多工业相机的图像数据采集都是基于DirectShow的,常见的有映美精等。
DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,与DirectX开发包一起发布。
DirectShow为多媒体流的捕捉和回放提供了强有力的支持。
运用DirectShow,我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。
它广泛地支持各种媒体格式,包括Asf、Mpeg、Avi、Dv、Mp3、Wave等等,使得多媒体数据的回放变得轻而易举。
另外,DirectShow还集成了DirectX其它部分(比如DirectDraw、DirectSound)的技术,直接支持DVD的播放,视频的非线性编辑,以及与数字摄像机的数据交换。
更值得一提的是,DirectShow提供的是一种开放式的开发环境,我们可以根据自己的需要定制自己的组件。
笔者使用visual studio 2005 来开发了基于DirectShow的视频捕获软件,并用开发的软件对映美精相机进行了测试。
本软件不但可以实现对相机的视频捕获,而且还可以抓取图像帧。
软件运行时自动搜索所连接的相机,预览后可以对相机参数进行设置。
下面是软件的主界面。
预览视频后可以对视频格式和图像参数进行设置。
开始预览时,捕获的视频是黑白的,我们将颜色空间设置为UYVY即可捕获彩色视频。
下面是捕获的一帧图像,图像质量虽然没有映美精自带的软件效果好,但已经实现了所需各项基本功能,接下来的工作将会进一步提高软件性能。
另外我们还可以捕获视频,点击“捕获视频”按钮,输入要保持的文件名,注意要以.avi后缀结尾,点确定就开始捕获视频。
从我们开发的软件可以看到,映美精的相机能够很好的支持DirectShow的驱动,我们的软件对映美精相机的识别是如此的容易。
接下来我们将继续开发基于其它驱动的图像捕获软件,为最终实现在一个软件中识别各种相机而努力。
[C++]DirectShow检测⾳视频输⼊设备及其采集参数创建CLR类库项⽬(CSharpDirectShow),编写托管的DirectShow类库,右键项⽬属性-->链接器--> 输⼊-->附加依赖项;添加静态库⽂件Strmiids.lib和Quartz.lib;定义头⽂件CSharpDirectShow.h,包含头⽂件dshow.h,定义如下⽅法:#pragma once#include <dshow.h>using namespace System;using namespace System::Runtime::InteropServices;public ref class DirectShow{public:///<summary>///在当前线程上初始化COM库,并将并发模型标识为单线程单元(STA)///</summary>///<returns></returns>static Boolean ComInit();///<summary>///关闭当前线程上的COM库,卸载该线程加载的所有DLL,释放该线程维护的所有其他资源,并强制关闭该线程上的所有RPC连接///</summary>static void ComUinit();///<summary>///获取视频输⼊设备///</summary>///<param name="devices"></param>///<returns></returns>static Int32 GetVideoInputDevices([Out]array<VideoInputDsDevice^>^% devices);///<summary>///获取⾳频输⼊设备///</summary>///<param name="device"></param>///<returns></returns>static Int32 GetAudioInputDevices([Out]array<AudioInputDsDevice^>^% device);};其中,初始化COM库只能在STA线程调⽤,控制台程序直接调⽤会返回失败,在Winform和WPF等应⽤程序应该在第⼀次使⽤时初始化COM 库;当前线程初始化COM库和关闭COM库:Boolean DirectShow::ComInit(){HRESULT hr = CoInitialize(NULL);return hr == S_OK || hr == S_FALSE;}void DirectShow::ComUinit(){CoUninitialize();}1、创建视频输⼊设备的枚举器IEnumMonikerHRESULT DirectShow::EnumerateDevices(REFGUID category, IEnumMoniker** ppEnum){// 创建系统设备枚举器ICreateDevEnum* pDevEnum;HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));if (SUCCEEDED(hr)){// 为类别创建枚举数.hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);if (hr == S_FALSE)hr = VFW_E_NOT_FOUND; // 类别是空的,视为错误pDevEnum->Release();}return hr;}Int32 DirectShow::GetVideoInputDevices([Out]array<VideoInputDsDevice^>^% devices){devices = nullptr;IEnumMoniker* pEnum;HRESULT hr = EnumerateDevices(CLSID_VideoInputDeviceCategory, &pEnum); // 创建视频输⼊设备枚举器if (FAILED(hr))return hr;hr = EnumerateVideoInputDevices(pEnum, devices); // 枚举视频输⼊设备pEnum->Release();return hr;}2、调⽤IEnumMoniker::Next()⽅法枚举设备,调⽤IPropertyBag::Read⽅法读取设备属性,以获取设备的友好名称和设备标识字符串:HRESULT DirectShow::EnumerateVideoInputDevices(IEnumMoniker* pEnum, [Out]array<VideoInputDsDevice^>^% devices){HRESULT hr = S_FALSE;devices = nullptr;List<VideoInputDsDevice^>^ list = gcnew List<VideoInputDsDevice^>();IMoniker* pMoniker;while (pEnum->Next(1, &pMoniker, NULL) == S_OK){IPropertyBag* pPropBag;hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));if (FAILED(hr)){pMoniker->Release();continue;}VideoInputDsDevice^ device = gcnew VideoInputDsDevice();VARIANT var;VariantInit(&var);// 获取设备友好名hr = pPropBag->Read(L"FriendlyName", &var, 0);if (FAILED(hr))hr = pPropBag->Read(L"Description", &var, 0);if (SUCCEEDED(hr)){device->FriendlyName = System::String(var.bstrVal).ToString();VariantClear(&var);}// 获取设备Moniker名LPOLESTR pOleDisplayName = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(MAX_MONIKER_NAME_LENGTH * 2));hr = pMoniker->GetDisplayName(NULL, NULL, &pOleDisplayName);if (SUCCEEDED(hr)){device->MonikerName = System::String(pOleDisplayName).ToString();array<VideoParams^>^ params;hr = EnumerateVideoParams(pMoniker, params); // 枚举设备的采集参数if (SUCCEEDED(hr))device->Params = params;}CoTaskMemFree(pOleDisplayName);list->Add(device);pPropBag->Release();pMoniker->Release();}devices = list->ToArray();return S_OK;}3、枚举视频输⼊设备的采集参数:HRESULT DirectShow::EnumerateVideoParams(IMoniker* pMoniker, [Out]array<VideoParams^>^% params){params = nullptr;IBaseFilter* pFilter;HRESULT hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pFilter);if (FAILED(hr))return hr;IEnumPins* pinEnum;hr = pFilter->EnumPins(&pinEnum);if (FAILED(hr)) {pFilter->Release();return hr;}List<VideoParams^>^ list = gcnew List<VideoParams^>();IPin* pPins;while (pinEnum->Next(1, &pPins, NULL) == S_OK){PIN_INFO pinInfo;hr = pPins->QueryPinInfo(&pinInfo);if (FAILED(hr) || pinInfo.dir != PINDIR_OUTPUT){pPins->Release();continue;}IEnumMediaTypes* mtEnum;hr = pPins->EnumMediaTypes(&mtEnum);if (FAILED(hr)){pPins->Release();continue;}AM_MEDIA_TYPE* mt;while (mtEnum->Next(1, &mt, NULL) == S_OK){VideoParams^ param = nullptr;if (mt->formattype == FORMAT_VideoInfo){VIDEOINFOHEADER* pVih = reinterpret_cast<VIDEOINFOHEADER*>(mt->pbFormat);param = gcnew VideoParams();param->FrameWidth = pVih->bmiHeader.biWidth;param->FrameHeight = pVih->bmiHeader.biHeight;param->AverageFrameRate = pVih->AvgTimePerFrame == 0 ? 0 : 10000000 / pVih->AvgTimePerFrame;}else if (mt->formattype == FORMAT_VideoInfo2) {VIDEOINFOHEADER2* pVih = reinterpret_cast<VIDEOINFOHEADER2*>(mt->pbFormat);param = gcnew VideoParams();param->FrameWidth = pVih->bmiHeader.biWidth;param->FrameHeight = pVih->bmiHeader.biHeight;param->AverageFrameRate = pVih->AvgTimePerFrame == 0 ? 0 : 10000000 / pVih->AvgTimePerFrame;}if (param && param->AverageFrameRate > 1){Boolean isExit = false;for each (VideoParams ^ item in list){if (item->FrameWidth == param->FrameWidth && item->FrameHeight == param->FrameHeight && item->AverageFrameRate == param->AverageFrameRate) {isExit = true;break;}}if (!isExit)list->Add(param);}}pPins->Release();}pFilter->Release();params = list->ToArray();return S_OK;}调⽤代码及结果:var ret = DirectShow.GetVideoInputDevices (out VideoInputDsDevice[] videoInputDevices);if (ret == 0) {Console.WriteLine ("视频输⼊设备:");foreach (var videoInputDevice in videoInputDevices) {Console.WriteLine ($"{videoInputDevice.FriendlyName}\t{videoInputDevice.MonikerName}");if (videoInputDevice.Params.Length > 0) {Console.WriteLine ("像素宽度\t像素⾼度\t1秒平均帧数");foreach (var param in videoInputDevice.Params) {Console.WriteLine ($"{param.FrameWidth}\t{param.FrameHeight}\t{param.AverageFrameRate}");}}Console.WriteLine ();}}ret = DirectShow.GetAudioInputDevices (out AudioInputDsDevice[] audioInputDevices);if (ret == 0) {Console.WriteLine ("⾳频输⼊设备:");foreach (var audioInputDevice in audioInputDevices) {Console.WriteLine ($"{audioInputDevice.FriendlyName}\t{audioInputDevice.MonikerName}");if (audioInputDevice.Params.Length > 0) {Console.WriteLine ("⾳频格式\t通道数\t采样速率\t块对齐\t位数");foreach (var param in audioInputDevice.Params) {Console.WriteLine ($"{param.Format}\t{param.Channels}\t{param.SampleRate}\t{param.BlockAlign}\t{param.BitsPerSample}"); }}Console.WriteLine ();}}。
基于DirectShow的多摄像头视频采集1.为什么使用DirectShow笔者使用的是两个USB摄像头,单摄像头视频采集使用OpenCV的VideoCapture类没有问题,但是双摄像头就有问题,一个正常,另外一个采集不到信息,显示一片灰色。
网上有种解决方法是逆序打开摄像头,结果两个窗口是可以采集到视频信息,但是竟然是同一个摄像头的视频信息,无奈的只能使用DirectShow采集多摄像头视频信息。
先看看什么是DirectShow:DirectShow 是 DirectX 的组件之一, DirectX 软件开发包是 Microsoft 提供的一套在 Windows平台上开发高性能图形、声音、输入、输出和网络游戏的编程接口。
这其中,DirectShow提供了应用程序从适当的硬件中捕捉和预览音、视频的能力。
数据源包括: VCR、 Camera、 TV Tuner、 Microphone 或其他的数据源。
应用程序可以立刻显示捕捉的数据(预览),或是保存到一个文件中。
摄像头采集信息常用的软件AMCap就是基于DirectShow SDK编写的。
查阅一下官方文档,感觉好难的样子,难道要新学一门“快过时”的技术吗?幸好于仕琪老师写了一个CCameraDS类,可直接返回IplImage,使用方便。
2.在VS2010中配置DirectShow并采集双目摄像头视频下载DirectShow相关文件,我已经共享在百度云盘,点击下载。
解压以后copy到D:\opencv里(放在这里为了管理方便)在解决资源管理器中的项目名称处右键\属性\配置属性\VC++目录,引用目录中添加DirectShow的include文件夹,我添加的是D:\opencv\DirectShow\Include在引用目录下面有一个库目录,添加DirectShow的Lib文件夹,我添加的是D:\opencv\DirectShow\Lib;下载CCameraDS类相关文件,点击下载。
DirectShow视频采集系统目前,多媒体技术飞速发展,各行业对多媒体技术的应用也越来越广泛,传统的视频采集技术存在着一定的局限性,不能很好的应用于当前的视频系统。
本文提出了一种基于DirectShow的视频采集系统,克服现状。
本文采用的一种基于DirectShow的视频采集系统支持多种格式的视频文件的捕捉和回放,也支持使用Windows驱动模型(WDM)设备或过去的VFW设备。
在开发过程中是基于组件对象模型(COM),通过编写COM客户程序来实现视频的采集回放等功能。
在具体实现过程中通过编写Filter来实现各功能模块,最后把各功能模块通过Filter Graph组建起来。
标签:DirectShow 视频采集COM一、引言随着多媒体技术的不断发展,与之相关的软件与硬件层出不穷,现在与多媒体视频会议(Video Conference)、视频对话相关的软硬件正成为人们关注的热点应用。
而在这些应用中无不涉及视频数据的采集。
传统的视频采集技术存在诸多的局限性,无法很好地应用于当前的各类视频系统。
针对这一现状,本文提出了一种先进的基于DirectShow的视频采集系统。
该系统充分利用DirectShow与WDM视频采集卡的良好集成特性,采用组件对象模型的系统架构,克服了传统视频采集技术的不足,在实际应用中取得了满意的效果。
二、DirectShow技术微软DirectShow是微软windows平台上的流式媒体体系结构。
DirectShow 提供媒体流的高质量的捕捉与回放。
它支持多种格式,包括高级流格式,活动图片专家组格式,音频-视频交叉格式,第三层mpeg格式(mp3)和wav文件格式。
他也支持使用windows驱动模型设备或老的windows视频设备的捕捉。
DirectShow 与其他DirectX技术集成于一体,自动感觉和使用视频和音频硬件加速,同时也支持没有硬件加速的系统。
DirectShow简化了媒体回放,格式转换和捕捉任务。
音视频采集主要内容:●Directshow的概述和系统组成●Directshow中的音视频同步机制●Directshow应用程序开发流程●Directshow实现音视频的采集程序●Fliter的开发(RTP实时传输和H.264编解码)整个系统的设计:一、Directshow概述和系统组成1.DirectShow介绍DirectShow是一个windows平台上的流媒体框架,提供了高质量的多媒体流采集和回放功能。
它支持多种多样的媒体文件格式,包括ASF、MPEG、AVI、MP3和WAV文件,同时支持使用WDM驱动或早期的VFW驱动来进行多媒体流的采集。
DirectShow整合了其它的DirectX技术,能自动地侦测并使用可利用的音视频硬件加速,也能支持没有硬件加速的系统。
DirectShow是建立在组件对象模型(COM)上的,因此编写DirectShow应用时,必须具备COM客户端程序编写的知识。
对于大部分的应用,需要实现自己的COM对象,DirectShow提供了大部分你需要的DirectShow组件,但是假如需要编写自己的DirectShow组件(RTP传输Fliter以及H.264编解码Fliter),还需要具备编写COM组件的知识。
2.DirectShow系统组成如图所示,最大一块就是DirectShow系统,虚线以下是Ring 0(内核模式)特权级别的硬件设备,虚线以上是Ring 3(用户模式)特权级别的应用层。
Dshow系统位于应用层中。
它使用一种叫做Fliter Graph的模型来管理整个数据流的处理过程;参与数据处理的各个功能模块叫做Fliter,一组Fliter按一定的顺序连接成一条“流水线”协同工作,就组成一个Fliter Graph。
3.Fliter Graph和Fliter每个Fliter与一个或多个其它的Fliter相连,其中的连接点也是一个COM对象,称作Pin,Fliter使用Pin将数据从一个Fliter转移到另一个,图中的箭头指示了数据流动的方向。
随着计算机网络和多媒体技术的发展,多媒体应用如视频会议、远程监控、远程教育、可视电话、医疗视频会诊等迅速兴起,视频和音频捕获成为多媒体应用中的关键环节和重要前提。
目前采用较多的基于设备软件开发工具箱(SDK)的捕获方式存在成本较高、灵活性和扩展性较差等问题,难以满足用户需求和网络环境的变化。
微软公司推出的多媒体开发软件包———DirectShow成为解决这些问题的一个有力工具。
DirectShow提供高质量的多媒体数据流的捕获和回放功能,广泛支持多种媒体格式,包括ASF、MPEG、A VI、DV、MP3和W A V等。
同时DirectShow对VFW具有良好的兼容性,并具有其无法比拟的优势,包括支持大量多媒体数据捕获的同时可通过网络传播和播放,支持视频与音频在捕获和播放中的完全同步,支持来自不同媒体源数据捕获的合成等。
本文着重介绍如何利用Visual C++实现基于DirectShow的视频和音频捕获以及其中涉及到的关键问题,以供工程人员和开发人员参考使用。
DirectShow的原理1、DirectShow的体系结构。
应用程序与DirectShow组件以及DirectShow所支持的软硬件之间的关系如图1所示。
DirectShow使用模块化的架构,系统中的基础模块称为过滤器(Filter)。
过滤器作为软件的组件,可完成单一的数据流处理功能。
按照功能,过滤器大致分为3类:源过滤器(Source Filter)、转换过滤器(Transform Filter)和表现过滤器(Rendering Filter)。
源过滤器负责从媒体源获取数据;转换过滤器负责数据的格式转换、传输,如数据流分离/合成、编码/解码等;表现过滤器负责数据的最终去向,将数据送往显卡和声卡进行播放,或输出到文件进行存储。
过滤器之间通过引脚(Pin)进行有序连接,组合而成过滤器图(Filter Graph),用以实现组合的一系列功能。
应用程序创建过滤器图管理器(Filter Graph Manager),负责过滤器图的组织和连接功能并控制数据在其中的流动。