下面是OBS-VirtualCam項目結(jié)構(gòu)與Vivek‘s VCam項目結(jié)構(gòu)的對比踪危,OBS-VirtualCam比vcam項目多出來關(guān)于virtual-audio的相關(guān)代碼裙盾,猜測應(yīng)該是鏈接obs音頻的刊头。視頻部分兩者非常的相似现横。
為了更清楚的了解兩個項目怀各,我們在比較了各自的頭文件听系,virtual-cam.h與filters.h:
Filter 類對比:
output in類對比:
可以看到舍悯,不論是取名航棱、注釋還是繼承,類結(jié)構(gòu)萌衬,兩者是非常一致的饮醇,可以看出來OBS-VirtualCam正式在Vivek‘s VCam項目的基礎(chǔ)上開發(fā)的。
Vivek‘s VCam項目作為一個示例項目主要是根據(jù)xx產(chǎn)生vedio數(shù)據(jù)秕豫,模擬攝像頭朴艰。OBS-VirtualCam同樣是模擬攝像頭观蓄,但是數(shù)據(jù)來源與obs的流,已經(jīng)是一個實用的產(chǎn)品祠墅。參照這兩個項目侮穿,應(yīng)該可以寫出我們想要的虛擬攝像頭項目了。
CVCam類
CVCam類繼承于CSource毁嗦, CSource由directshow 基礎(chǔ)類庫提供亲茅,用來實現(xiàn)基于Push模式的fitler(文檔中指的是source fitler, 這里開發(fā)的是capture filter, 看來這兩個在filter開發(fā)上是通用的)。
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規(guī)范的要求狗准,根據(jù)注釋DECLARE_IUNKNOWN;應(yīng)該自動添加了IUnkown需要實現(xiàn)的三個接口克锣。
NonDelegatingQueryInterface來自于CUnknown, 根據(jù)CUnknown的描述,它主要用來幫助創(chuàng)建com對象,filter需要繼承自它或子類,并且在public區(qū)域調(diào)用DECLARE_IUNKNOWN; micro缸榄。
NonDelegatingQueryInterface用來overwirte QueryInterface的行為,從而不在調(diào)用baseObject的默認QueryInterface實現(xiàn)巾乳。
m_pGraph在cbasefilter中用于指向filter graph manager,也有對應(yīng)的GetFilterGraph方法故俐,這里重新聲明的方法被用于pin的使用中(CVCamStream的實現(xiàn)中可以看到)想鹰,這里感覺是重復(fù)的方法。
m_State也是在cbase中定義的药版,也有同名方法:
HRESULT GetState(
DWORD dwMilliSecsTimeout,
FILTER_STATE *State
);
可以看到辑舷,這里是做了重載,直接返回了狀態(tài)槽片。
CVCam中聲明了一個output pin, 名字為stream何缓,類型為CVCamStream,對應(yīng)生命的第二個類还栓。
CVCamStream *stream = nullptr;
CVCamStream類
兩個項目的 都一樣繼承自CSourceStream, 同時實現(xiàn)了 IAMStreamConfig, IKsPropertySet:
CSourceStream是所有pin的基礎(chǔ)類碌廓,提供了pin所需要的基礎(chǔ)實現(xiàn)和預(yù)留了的處理函數(shù),以下的方法皆來自于對基礎(chǔ)實現(xiàn)的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支持那種格式以及設(shè)置格式谷婆。IAMStreamConfig接口描述的正式這些功能。
HRESULT CreateClassEnumerator(
[in] REFCLSID clsidDeviceClass, // 確定Filter Categories辽聊,
[out] IEnumMoniker **ppEnumMoniker,
[in] DWORD dwFlags //獲取滿足flag條件的fitler
);
IKsPropertySet 用來設(shè)置或獲取設(shè)備屬性纪挎,每一個output pin 需要實現(xiàn)這個接口:
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項目的功能實現(xiàn)要比Vivek‘s VCam項目復(fù)雜,它還定義了很多私有函數(shù)跟匆。
最后异袄,兩個實現(xiàn)的CVCamStream類還都定義了對vcam類的指針。