DirectShow摄像头和虚拟摄像头

DirectShow摄像头虚拟摄像头
DShow简介
DirectShow(简称 DShow) 是⼀个 Windows 平台上的流媒体框架,提供了⾼质量的多媒体流采集和回放功能。⽀持使⽤ WDM 驱动
或早期的 VFW 驱动来进⾏多媒体流的采集。横跨WINXP,WIN7,WIN8,WIN10,适配性好,稳定性⾼。DirectShow位于应⽤层中。它使⽤
管理整个数据流的处理过程;参与数据处理的各个功能模块叫Filter;各个Filter 在Filter Graph中按⼀定的顺序连⼀种叫Filter Graph的模型来管理整个数据流的处理过程
接成⼀条"流⽔线"协同⼯作。( 可以看出TFilterGraph是个Filter的容器 )按照功能来分,Filter⼤致分为三类:Source Filters、Transform
Filters和Rendering Filters。
Source Filters主要负责取得数据,数据源可以是⽂件、因特⽹、或者计算机⾥的采集卡、数字摄像机等;
Transform Fitlers主要负责数据的格式转换、传输;
Rendering Filtes主要负责数据的最终去向,我们可以将数据送给声卡、显卡进⾏多媒体的演⽰,也可以输出到⽂件进⾏存储。
下图简单展⽰了DShow⼯作流过程
Dir ec tSho w操作摄像头流程
Direc
1. 使⽤CoCreateInstance创建 IGraphBuilder接⼝(所有接⼝的“总管”)。
2. 从IGraphBuilder查询出IMediaControl控制接⼝。
3. 创建ICreateDevEnum接⼝,枚举出系统所有安装的摄像头。
4. 选择摄像头,并且获取这个摄像头的IBaseFilter接⼝, 把这个接⼝添加到IGraphBuilder中 。
5. 选择其他Filter,⽐如压缩的Filter,Render Filter等,加到IGraphBuilder中。
6. 定义SourceFilter,TransformFilter,RenderFilter,⽤RenderStream将这些链接起来。这样就构成了⼀个DShow的连接图。
7.运⾏ IMediaControl 的Run函数,要使整个“”图“” 动起来,这样摄像头的数据就会流经每个Filter,最终到达RenderFilter并在终端显
⽰出来。
主要代码实现如下
主要代码实现如下:
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,IID_IGraphBuilder, (void**)&graphBuilder); ///创建IGraphBuilder接⼝
hr = graphBuilder->QueryInterface(IID_IMediaControl, (void**)&control); //查询IMediaControl
CComPtr<ICreateDevEnum> DevEnum; ///创建枚举摄像头设备接⼝
中国海警hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&DevEnum); CComPtr<IEnumMoniker> pEM;//枚举
IMoniker* pM; //查询到的每个设备
hr = DevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEM, 0);
while (pEM->Next(1, &pM, &fetch) == S_OK) {
///开始枚举每个设备,如果是我们的虚拟DSHOW摄像头,也会被枚举到
........
///选择我们感兴趣的摄像头, 获取Filter接⼝,⽐如deviceFilter名字
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&deviceFilter);
}
//调⽤RenderStream把graph⾥的filter链接起来
m_pCaptureGB->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video,
deviceFilter, m_pSampleGrabberFilter, NULL); 调⽤control->Run , 即可让其运⾏起来
虚拟摄像头
1.虚拟摄像头注册
在windows系统中,虚拟摄像头的注册是通过在注册表中添加摄像头信息实现的,windows规定修改注册表的程序需要在DLL动态库中实现, 这个DLL要具备COM接⼝动态库的基本条件,需要实现DllRegisterServer, DllUnregisterServer,
DllGetClassObject,DllCanUnloadNow四个导出函数。并且在DllRegisterServer函数中实现虚拟摄像头注册,然后就可以使⽤regsvr32命名进⾏注册表写⼊,  其主要代码如下:
IFilterMapper2* pFM = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER, IID_IFilterMapper2, (void**)&pFM); REGFILTERPINS VCamPins = {
L"Pins",
FALSE, ///
TRUE,  /// output
FALSE, /// can hav none
FALSE, /// can have many
&CLSID_NULL, // obs
L"PIN",
1,
&PinTypes
};
REGFILTER2 rf2;
rf2.dwVersion = 1;
rf2.dwMerit = MERIT_DO_NOT_USE;
rf2.cPins = 1;
//根据上边提供的信息,调⽤RegisterFilter 注册。
hr = pFM->RegisterFilter(CLSID_VCamDShow, L"TAL_Camera", &pMoniker, &CLSID_VideoInputDeviceCategory, NULL, &rf2);
2.虚拟摄像头实现
DShow虚拟摄像头,除了必须实现的 DllRegisterServer, DllUnregisterServer, DllGetClassObject,DllCanUnloadNow四个导出函数外,还需要开发虚拟摄像头类,这个类必须继承IBaseFilter接⼝,IBaseFilter是DShow Filter的基础导出接⼝,每个Filter下有⼀个或者多个PIN接⼝,因此还必须实现IPIN接⼝,⼤致数据结构如下:
class VCamDShowFilter: public IUnknown,public IBaseFilter, public IAMovieSetup
{
protected:
。。。//内部数据变量和私有函数
VCamStream*    m_Stream; /// 这个就是我们的 IPin接⼝, 就只需要⼀个就可以了,          VCamStream数据结构下⾯会描述。
public:
//IUnknow 接⼝
舆情管理。。。。
// IBaseFilter 接⼝
STDMETHODIMP GetClassID(...);///
STDMETHODIMP Stop() ;/// 停⽌, IMediaControl接⼝调⽤
STDMETHODIMP Pause(); ///暂停,
STDMETHODIMP Run();  ///运⾏
STDMETHODIMP GetState(...); ///获取运⾏,暂停,停⽌等状态
STDMETHODIMP GetSyncSouce(...);
STDMETHODIMP SetSyncSource(...);
STDMETHODIMP  EnumPins(...);    查询当前filter 提供的IPin 接⼝信息, DirectShow库通过此函数获取当前Filter提供的IPin信息
网站STDMETHODIMP  FindPin(...);  //
STDMETHODIMP QueryFilterInfo(...); ///获取当前Filter信息
STDMETHODIMP JoinFIlterGraph(...); /// 把当前filter加⼊到DirectShow图中,其实就是对应 IGraphBuilder->AddFilter 调⽤时候被调⽤。
............
};
class VCamStreamPin : public IUnknown,public IPin, public IQualityControl, public IAMStreamConfig, public IKsPropertySet
{
protected:
。。。//内部数据变量和私有函数
VCamDShowFilter*  m_pFilter;        // 所属的Filter,对应上⾯定义的VCamDShow数据结构。
/ 下⾯是数据源相关的线程,在 StreamTreadLoop 中循环采集数据,并且通过 IMemInputPin 把数据传输给输⼊PIN。
南京禽流感最新消息HANDLE  m_hThread; ///
HANDLE  m_event;
BOOL    m_quit;
static DWORD CALLBACK thread(void* _p)
{
VCamStreamPin* p = (VCamStreamPin*)_p;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
p->StreamTreadLoop();
CoUninitialize();
return 0;
}
void StreamTreadLoop();
public:
//IUnknow 接⼝
.....
IPin 接⼝
STDMETHODIMP  Connect(....); 把 输⼊PIN和输出PIN连接起来,这个是主要函数,其实就是对应                                                                        IGraphBuilder->Connect(devicePin,renderPin);      STDMETHODIMP  ReceiveConnection(...); ///接收连接
yjpSTDMETHODIMP  DIsconnect(...);  ///断开与其他PIN的连接
STDMETHODIMP  ConnectTo(...);  以下基本都是⼀些状态和数据信息查询
STDMETHODIMP  ConnectionMediaType(...); ///
STDMETHODIMP  QueryPinInfo(....);
STDMETHODIMP  QueryDirection(...); ///
.............
IQualityControl
....
/
STDMETHODIMP SetFormat(...); ///
STDMETHODIMP  GetFormat(...); ///
STDMETHODIMP  GetNumberOfCapabilities(...); ///
STDMETHODIMP  GetStreamCaps(....);
/// IKsPropertySet
STDMETHODIMP  Get(...); ///
STDMETHODIMP  Set(...);
STDMETHODIMP  QuerySupported(...); /
};
制氧正如上⾯的查询摄像头的伪代码所说, ICreateDevEnum 接⼝查询到我们感兴趣的摄像头,
当绑定到这个摄像头获取IBaseFilter接⼝,调⽤  IMoniker 的  BindToObject 函数,
虽然没有 BindToObject 源代码,但可以知道⼤致流程:
BindToObject查CLSID_VCamDShow(我们⾃定义的GUID)等信息,
调⽤系统函数CoCreateInstance函数创建我们的对象并且获取IBaseFilter接⼝,

本文发布于:2024-09-22 07:37:25,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/436261.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:摄像头   数据   函数   虚拟   实现
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议