OBS-VirtualCam 与vcam项目

下面是OBS-VirtualCam项目结构与Vivek‘s VCam项目结构的对比,OBS-VirtualCam比vcam项目多出来关于virtual-audio的相关代码,猜测应该是链接obs音频的。视频部分两者非常的相似。


image.png

为了更清楚的了解两个项目,我们在比较了各自的头文件,virtual-cam.h与filters.h:
Filter 类对比:


image.png

output in类对比:
image.png

可以看到,不论是取名、注释还是继承,类结构,两者是非常一致的,可以看出来OBS-VirtualCam正式在Vivek‘s VCam项目的基础上开发的。
Vivek‘s VCam项目作为一个示例项目主要是根据xx产生vedio数据,模拟摄像头。OBS-VirtualCam同样是模拟摄像头,但是数据来源与obs的流,已经是一个实用的产品。参照这两个项目,应该可以写出我们想要的虚拟摄像头项目了。

CVCam类
CVCam类继承于CSource, CSource由directshow 基础类库提供,用来实现基于Push模式的fitler(文档中指的是source fitler, 这里开发的是capture filter, 看来这两个在filter开发上是通用的)。


image.png
class CVCam : public CSource
{
public:
    DECLARE_IUNKNOWN;
    //////////////////////////////////////////////////////////////////////////
    //  IUnknown
    //////////////////////////////////////////////////////////////////////////
    
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
    IFilterGraph *GetGraph() { return m_pGraph; }
    FILTER_STATE GetState(){ return m_State; }
    CVCam(LPUNKNOWN lpunk, HRESULT *phr, const GUID id, int mode);
protected:
    CVCamStream *stream = nullptr;

};

directorshow fitler 需要满足COM规范的要求,根据注释DECLARE_IUNKNOWN;应该自动添加了IUnkown需要实现的三个接口。
NonDelegatingQueryInterface来自于CUnknown, 根据CUnknown的描述,它主要用来帮助创建com对象,filter需要继承自它或子类,并且在public区域调用DECLARE_IUNKNOWN; micro。
NonDelegatingQueryInterface用来overwirte QueryInterface的行为,从而不在调用baseObject的默认QueryInterface实现。
m_pGraph在cbasefilter中用于指向filter graph manager,也有对应的GetFilterGraph方法,这里重新声明的方法被用于pin的使用中(CVCamStream的实现中可以看到),这里感觉是重复的方法。
m_State也是在cbase中定义的,也有同名方法:

HRESULT GetState(
   DWORD        dwMilliSecsTimeout,
   FILTER_STATE *State
);

可以看到,这里是做了重载,直接返回了状态。
CVCam中声明了一个output pin, 名字为stream,类型为CVCamStream,对应生命的第二个类。

CVCamStream *stream = nullptr;

CVCamStream类
两个项目的 都一样继承自CSourceStream, 同时实现了 IAMStreamConfig, IKsPropertySet:
CSourceStream是所有pin的基础类,提供了pin所需要的基础实现和预留了的处理函数,以下的方法皆来自于对基础实现的overwrite.

HRESULT FillBuffer(IMediaSample *pms);
    HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties);
    HRESULT CheckMediaType(const CMediaType *pMediaType);
    HRESULT GetMediaType(int iPosition,CMediaType *pmt);
    HRESULT SetMediaType(const CMediaType *pmt);
    HRESULT OnThreadCreate(void);
    HRESULT OnThreadDestroy(void);

一个Capurefilter 可以支持多种输出格式,不同的格式下又支持多种frame sizes. IAMStreamConfig 用来报告CapD支持那种格式以及设置格式。IAMStreamConfig接口描述的正式这些功能。

   HRESULT CreateClassEnumerator(
  [in]  REFCLSID     clsidDeviceClass,      // 确定Filter Categories,
  [out] IEnumMoniker **ppEnumMoniker,
  [in]  DWORD        dwFlags      //获取满足flag条件的fitler
);

IKsPropertySet 用来设置或获取设备属性,每一个output pin 需要实现这个接口:

HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwID, 
        void *pInstanceData, DWORD cbInstanceData, void *pPropData, DWORD cbPropData);

    HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, 
        void *pInstanceData, DWORD cbInstanceData, void *pPropData, 
        DWORD cbPropData, DWORD *pcbReturned);

    HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, 
        DWORD dwPropID, DWORD *pTypeSupport);

OBS vcam项目的功能实现要比Vivek‘s VCam项目复杂,它还定义了很多私有函数。
最后,两个实现的CVCamStream类还都定义了对vcam类的指针。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容