日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > windows >内容正文

windows

视频直播:Windows中各类画面源的截取和合成方法总结

發(fā)布時間:2025/3/8 windows 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 视频直播:Windows中各类画面源的截取和合成方法总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

當(dāng)今,視頻直播技術(shù)和實時音視頻技術(shù)已經(jīng)是很多行業(yè)必備,典型的應(yīng)用場景有教育直播、遠(yuǎn)程視頻會議、互聯(lián)網(wǎng)娛樂等。在移動端發(fā)起直播,其畫面源的種類是十分有限的,無非是取攝像頭、截屏等。PC端由于其系統(tǒng)資源充足,應(yīng)用程序豐富,畫面源種類多樣,更適合作為主播程序運行的平臺。在實際應(yīng)用中,經(jīng)常有一些場景是需要將不同的畫面源合在一起,然后推流出去的。本文粗淺介紹一些網(wǎng)易云信在開發(fā)過程中總結(jié)的一些獲取不同畫面源的畫面并將其合并的方法。

相關(guān)閱讀推薦

《如何快速實現(xiàn)移動端短視頻功能?》

《視頻私有云實戰(zhàn):基于Docker構(gòu)建點播私有云平臺》

?

各類畫面源的截取

  • 攝像頭畫面
  • Windows下采集攝像頭畫面,DShow是最常用的方法之一。通過DShow采集攝像頭數(shù)據(jù),創(chuàng)建視頻采集Filter,將其加入到圖表IGraphBuilder中,用IMediaControl接口來控制流媒體在Filter Graph中的流動,再通過Render來獲取視頻的原始數(shù)據(jù)。以上流程封裝在了我們的SDK中,用戶可以直接調(diào)用SDK接口。

  • 桌面取屏及應(yīng)用程序窗口截取
  • 在Windows系統(tǒng)中,桌面和所有應(yīng)用程序窗口一樣,本身也是一個HWND窗口,因此可以放在一起討論。獲取一個窗口的位圖數(shù)據(jù),最常用的方法是:創(chuàng)建一個用來接收窗口畫面的HBITMAP位圖對象以及一個HDC設(shè)備上下文對象,用SelectObject將兩者綁定,然后用BitBlt從被截取窗口的HDC將數(shù)據(jù)拷貝到目標(biāo)HDC。下面列出關(guān)鍵代碼:

    ?? HDChDc?=?GetDC(capture_hwnd_);

    HDCmem_dc?=?CreateCompatibleDC(hDc);?//創(chuàng)建一個兼容DC

    HBITMAPcapture_bitmap_?= ::CreateDIBSection(mem_dc, &bmi,?DIB_RGB_COLORS,

    ??????????? (void**)&capture_data_,?NULL, 0);?//創(chuàng)建HBITMAP

    HBITMAPold_hbitmap?= (HBITMAP)SelectObject(mem_dc,?capture_bitmap_);?//將mem_dc和capture_bitmap_綁定

    BitBlt(mem_dc, 0, 0,?capture_width,?capture_height,?hDc,?real_rect.left,?real_rect.top,?SRCCOPY);

    SelectObject(mem_dc,?old_hbitmap);?//還原

    DeleteDC(mem_dc);?//銷毀

    ReleaseDC(capture_hwnd_,?hDc);?//釋放

  • 其他截屏/截窗口方法
  • 教育直播中,PPT分享是非常重要的一個場景。但是據(jù)我考查,自從Microsoft Office 2013之后,BitBlt就取不到Word、Excel、PPT窗口的內(nèi)容了,截到的是一片白色。但是用PrintWindow這個Windows API卻可以取到。調(diào)用PrintWindow的程序會收到WM_PRINT或WM_PRINTCLIENT消息。PrintWindow的效率比BitBlt低,但當(dāng)BitBlt無法取到時,可以用PrintWindow。

    越來越多的程序的畫面是在顯存中的,此時,BitBlt和PrintWindow都不管用(得到的都是一塊黑色的位圖)。可以考慮用DirectX的方法。而且DirectX方法由于使用了GPU,所以相較前面兩種方法效率更高。以下是DirectX截屏的代碼:

    ???? ?externIDirect3DDevice9*?g_pd3dDevice;

    voidCaptureScreen()

    {

    ??? ????IDirect3DSurface9*?pSurface;

    ??? ????g_pd3dDevice->CreateOffscreenPlainSurface(ScreenWidth,?ScreenHeight,

    ??????? ????D3DFMT_A8R8G8B8,?D3DPOOL_SCRATCH, &pSurface,?NULL);

    ??? ????g_pd3dDevice->GetFrontBufferData(0,?pSurface);

    ??? ????D3DXSaveSurfaceToFile("Desktop.bmp",?D3DXIFF_BMP,?pSurface,?NULL,?NULL);

    ??? ????pSurface->Release();

    }

    GetFrontBufferData之后,也可以調(diào)用IDirect3DSurface9::GetDC()從pSurface得到HDC,然后用BitBlt將其拷貝到目標(biāo)HDC。

  • 獲取本地圖片的位圖數(shù)據(jù)
  • 將本地圖片(jpg、bmp、png、gif等格式)加載到內(nèi)存,并取得其位圖句柄或像素首地址的方法有很多種。這里列舉幾種最常見的。

    GdiPlus方法比較簡單。首先是通過圖片路徑創(chuàng)建一個Gdiplus::Bitmap對象,通過Gdiplus::Bitmap::LockBits()方法可以得到圖片的數(shù)據(jù),存放在一個Gdiplus::BitmapData結(jié)構(gòu)中。Gdiplus::BitmapData::Scan0就是圖片像素數(shù)據(jù)的首地址。如果想得到該圖片的HBITMAP句柄,只需調(diào)Gdiplus::Bitmap::GetHBITMAP()即可。

    另一種方法是使用Windows API LoadImage來加載一個本地bmp圖片得到HBITMAP句柄,但這種方法似乎只能加載位圖文件(.bmp格式)。使用ATL的CImage只需要3行代碼即可得到一個圖片文件的HBITMAP句柄。

    CImagecbmp;

    cbmp.Load(path);

    HBITMAP?image_bitmap?=?cbmp.Detach();

    ?

    畫面合成

    主播常常希望同時將自己的攝像頭畫面和桌面內(nèi)容或者某個程序的畫面共享給觀眾,有時甚至需要同一時刻分享10個以上的畫面源。這時候,需要將多個畫面粘貼到一個目標(biāo)畫面上,我們稱這個過程為畫面合成。合成的畫面通常還要支持改變各個畫面的尺寸、位置等操作。這樣一來,程序性能成了瓶頸問題。

    首先,對于各種畫面源的截取應(yīng)該盡量采用高效的方式,其次,畫面的拉伸壓縮是比較耗性能的地方。在1秒鐘需要合成20幀畫面的要求下,應(yīng)該避免直接強行壓縮HBITMAP,而是采用一些有加速的方案。

  • LibYuv方案
  • 我們找到一個一個yuv庫(LibYuv Project),支持圖形數(shù)據(jù)從rgb格式到各種yuv格式之間的互相轉(zhuǎn)換(定義在libyuv/convert.h中)。比較重要的一點是,它對yuv格式圖形的拉伸和壓縮以及其他各種變換(定義在libyuv/scale.h中)是有加速的。正好我們最終要推流的格式也是yuv格式的,所以我們方案的流程是:取得各個畫面源的畫面之后,先將它們各自轉(zhuǎn)化為yuv格式,然后把這些yuv畫面按照我們制定的方式粘貼到一個目標(biāo)yuv畫面上,最后將目標(biāo)yuv畫面數(shù)據(jù)推流出去。另外,由于主播的窗口上也要顯示合并畫面,所以還要把目標(biāo)畫面轉(zhuǎn)成rgb格式渲染到窗口HDC上。

    當(dāng)然,由于存在rgb格式和yuv格式之間反復(fù)的轉(zhuǎn)換以及頻繁的scale,而且yuv加速畢竟是軟件方式,程序的CPU占用率還是有點高。如果能采用DirectX、OpenGL等硬件加速解決方案,對程序性能以及用戶體驗的提升應(yīng)該是比較明顯的。

  • DirectX 9方案
  • 在DirectX 9方案中,我們的每個畫面源以及最終的目標(biāo)合成畫面,都對應(yīng)一個表面(IDirect3DSurface9)和一個紋理(IDirect3DTexture9)。

    由于畫面源的顏色內(nèi)存可能會被頻繁訪問和修改,所以創(chuàng)建其表面或紋理時,應(yīng)該將其創(chuàng)建在系統(tǒng)內(nèi)存或AGP中(D3DPOOL_MANAGED)而不是顯存中。對于yuv格式的攝像頭數(shù)據(jù)或網(wǎng)絡(luò)視頻幀,DirectX可以創(chuàng)建能直接接受yuv數(shù)據(jù)的紋理(D3DFMT_UYVY)。合成的時候,調(diào)用IDirect3DDevice9::DrawPrimitive()來將每個畫面源繪制到目標(biāo)畫面上。

    而最終合成畫面是要顯示到窗口上的,所以應(yīng)該創(chuàng)建在顯存中(D3DPOOL_DEFAULT)。渲染的時候,調(diào)用IDirect3DDevice9::DrawPrimitive()將目標(biāo)畫面的紋理繪制到窗口的渲染目標(biāo)紋理上,或者調(diào)用IDirect3DDevice9::StretchRect()將目標(biāo)畫面的表面粘貼到窗口的back buffer上。

    另外,由于要取得目標(biāo)畫面的數(shù)據(jù)用于推流,我們還要調(diào)用IDirect3DDevice9::CreateOffscreenPlainSurface()在系統(tǒng)內(nèi)存中(D3DPOOL_SYSTEMMEM)創(chuàng)建一個離屏表面,用IDirect3DDevice9::GetRenderTargetData()將目標(biāo)畫面取到離屏表面上,然后IDirect3DSurface9::LockRect()就能得到目標(biāo)畫面的rgb格式數(shù)據(jù)了,將其轉(zhuǎn)化為yuv格式就可以推流出去了。

    ?

    總? 結(jié)

    直播產(chǎn)品由于需要對每一幀畫面做處理,畫面的清晰度要高,幀率還不能太低,所以通常會存在消耗系統(tǒng)資源過多的問題。無論是取畫面還是合成畫面,方法有很多,不僅限于上面幾種。Win API效率一般,如果對程序性能要求高,就要在其他方面去想法設(shè)法減少資源消耗。而DirectX雖然對2D圖形加速不如3D加速那么顯著,但還是勝過Win API的。需要注意的是,使用DirectX時要非常清楚各個參數(shù)的意義,比如設(shè)備類型(D3DDEVTYPE)、內(nèi)存池類型(D3DPOOL)、用途類型(D3DUSAGE)等等。參數(shù)用錯,可能導(dǎo)致其性能還不如Win API。

    ?

    以上就是視頻直播中Windows中各類畫面源的截取和合成方法總結(jié)。

    另外,想要獲取更多產(chǎn)品干貨、技術(shù)干貨,記得關(guān)注網(wǎng)易云信博客

    總結(jié)

    以上是生活随笔為你收集整理的视频直播:Windows中各类画面源的截取和合成方法总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。