將桌面捕獲到虛擬攝像頭

當然你可以直接用現(xiàn)成的虛擬攝像頭軟件實現(xiàn)這個功能。不過當初我開發(fā)這個插件的原因是,需要在Flash產(chǎn)品里面共享桌面云稚,如果此時需要引導用戶安裝一個第三方的虛擬攝像頭體驗不好,所以公司希望我自己開發(fā)一個虛擬攝像頭沈堡,一鍵安裝減少用戶的使用門檻静陈。所謂的虛擬攝像頭實際上在windows系統(tǒng)上注冊了一個特殊dll,這個dll是一個COM組件诞丽。

虛擬攝像頭需要用到Direct Show編程鲸拥。

下載Direct Show開發(fā)代碼

里面有如下的文件夾,我只需要用到第一個文件夾里面的代碼—— baseclasses

baseclasses
capture
common
dmo
dvd
filters
misc
players
vmr9

創(chuàng)建工程

打開Visual Studio 僧免,新建一個win32 Dll項目刑赶。
打開屬性頁,在VC++ 目錄一欄中的庫目錄里面添加剛才的baseclasses的路徑懂衩,這樣我們就能在項目中引用這個目錄里的代碼了角撞。
在C/C++屬性頁里面的附加庫目錄里面也把baseclasses的路徑填入。
在dll.cpp中勃痴,我們需要把Filter注冊成COM組件。
分別需要調用AMovieSetupRegisterServer函數(shù)热康、CreateComObject函數(shù)以及IFilterMapper2接口的RegisterFilter函數(shù)完成注冊沛申。

主邏輯

在頭文件中,我們需要聲明兩個類

class CVCamStream;
class CVCam : public CSource
{
public:
    //////////////////////////////////////////////////////////////////////////
    //  IUnknown
    //////////////////////////////////////////////////////////////////////////
    static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);

    IFilterGraph *GetGraph() {return m_pGraph;}
    static int cx, cy;
    static HANDLE SocketThread;
    static SOCKET ClientSocket;
private:

    CVCam(LPUNKNOWN lpunk, HRESULT *phr);
};

class CVCamStream : public CSourceStream, public IAMDroppedFrames,public IAMStreamConfig, public IKsPropertySet
{
public:

COM組件只需要實現(xiàn)CUnknown接口即可姐军。我們繼承了Direct Show的CSource類铁材,那么就已經(jīng)實現(xiàn)了這個接口尖淘。
CVCamStream類用來實現(xiàn)圖像數(shù)據(jù)的輸出。
在CVCam的構造函數(shù)里面我們創(chuàng)建CVCamStream類的實例

m_paStreams = (CSourceStream **) new CVCamStream*[1];
m_paStreams[0] = new CVCamStream(phr, this, L"Flex COM");

在實現(xiàn)COM接口的QueryInterface函數(shù)中著觉,我們調用了CVCamStream類的QueryInterface

HRESULT CVCam::QueryInterface(REFIID riid, void **ppv)
{
    //Forward request for IAMStreamConfig & IKsPropertySet to the pin
    if(riid == _uuidof(IAMStreamConfig) || 
        riid == _uuidof(IAMDroppedFrames)  ||
        riid == _uuidof(IKsPropertySet))
        return m_paStreams[0]->QueryInterface(riid, ppv);
    else
        return CSource::QueryInterface(riid, ppv);
}

定義媒體類型

HRESULT CVCamStream::GetMediaType(int iPosition, CMediaType *pmt)

在這個函數(shù)中村生,我們配置了媒體的具體的格式參數(shù),比如24位RGB格式饼丘,圖像的寬高等等趁桃。
另外還需要對GetStreamCaps函數(shù)進行實現(xiàn),配置媒體的格式肄鸽。

HRESULT STDMETHODCALLTYPE CVCamStream::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC)

捕獲桌面

系統(tǒng)會調用FillBuffer函數(shù)卫病,在這個函數(shù)中,我們將捕獲到的數(shù)據(jù)填充到緩沖里面典徘,Direct Show會處理剩下的事情蟀苛。

HRESULT CVCamStream::FillBuffer(IMediaSample *pms)

捕獲桌面只需要用到一個函數(shù)CopyScreenToBitmap

 HANDLE hDib = CopyScreenToBitmap(&ScreenRect, pData, (BITMAPINFO *)&(pVih->bmiHeader), m_hCursor);
    if (hDib)   DeleteObject(hDib);

pData是我們定義的一個指針,通過下面的代碼逮诲,我們的pData就指向了緩存帜平,數(shù)據(jù)填充到pData指向的內存中。

BYTE *pData;
pms->GetPointer(&pData);

進階

實際產(chǎn)品會有很多需求梅鹦,光實現(xiàn)捕獲桌面是遠遠不夠的裆甩,我們需要對這個捕獲進行控制,比如捕獲制定區(qū)域帘瞭,停止捕獲淑掌,恢復捕獲等等。那么就涉及到和COM進行通訊了蝶念。
我們可以通過VS的窗口設計器創(chuàng)建一個windows窗口抛腕,然后提供一個用戶操作界面。


窗口設計器

如何響應這個窗口的用戶操作呢媒殉?
通過windows消息

INT_PTR CALLBACK WindowMessage(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

當然最關鍵是需要在Flash產(chǎn)品的程序里面喚起這個窗口担敌,需要用的socket編程。

SOCKET Listen_Sock = socket(AF_INET, SOCK_STREAM, 0);
    SOCKADDR_IN serverAddr;
    ZeroMemory((char *)&serverAddr, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(1234);
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    bind(Listen_Sock, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
    listen(Listen_Sock, 5);

C++的socket編程十分的繁瑣廷蓉,其他語言都會進行封裝全封,讓開發(fā)變的十分便利。
在一個線程里面寫個死循環(huán)進行讀取socket的數(shù)據(jù)桃犬,這是比較初級的多線程阻塞式的socket編程刹悴。對于我們這個程序是綽綽有余了。畢竟不是服務器攒暇,不需要面對并發(fā)的問題土匀。

源碼

https://github.com/langhuihui/FlexCOM

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市形用,隨后出現(xiàn)的幾起案子就轧,更是在濱河造成了極大的恐慌证杭,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妒御,死亡現(xiàn)場離奇詭異解愤,居然都是意外死亡,警方通過查閱死者的電腦和手機乎莉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門送讲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人梦鉴,你說我怎么就攤上這事李茫。” “怎么了肥橙?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵魄宏,是天一觀的道長。 經(jīng)常有香客問我存筏,道長宠互,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任椭坚,我火速辦了婚禮予跌,結果婚禮上,老公的妹妹穿的比我還像新娘善茎。我一直安慰自己券册,他們只是感情好,可當我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布垂涯。 她就那樣靜靜地躺著烁焙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耕赘。 梳的紋絲不亂的頭發(fā)上骄蝇,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機與錄音操骡,去河邊找鬼九火。 笑死,一個胖子當著我的面吹牛册招,可吹牛的內容都是我干的岔激。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼是掰,長吁一口氣:“原來是場噩夢啊……” “哼鹦倚!你這毒婦竟也來了?” 一聲冷哼從身側響起冀惭,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤震叙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后散休,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體媒楼,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年戚丸,在試婚紗的時候發(fā)現(xiàn)自己被綠了划址。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡限府,死狀恐怖夺颤,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情胁勺,我是刑警寧澤世澜,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站署穗,受9級特大地震影響寥裂,放射性物質發(fā)生泄漏。R本人自食惡果不足惜案疲,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一封恰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧褐啡,春花似錦诺舔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至萍恕,卻和暖如春逸嘀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背允粤。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工崭倘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人类垫。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓司光,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悉患。 傳聞我的和親對象是個殘疾皇子残家,可洞房花燭夜當晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內容