網易MC:Windows中各類畫麵源的截取和合成方法總結
概要
當今,視頻直播和實時音視頻技術已經是很多行業必需的,典型的應用場景有教育直播、遠程視頻會議、互聯網娛樂等。在移動端發起直播,其畫麵源的種類是十分有限的,無非是取攝像頭、截屏等。PC端由於其係統資源充足,應用程序豐富,畫麵源種類多樣,更適合作為主播程序運行的平台。在實際應用中,經常有一些場景是需要將不同的畫麵源合在一起,然後推流出去的。本文粗淺介紹一些我們在開發過程中總結的一些獲取不同畫麵源的畫麵並將其合並的方法。
各類畫麵源的截取
1)攝像頭畫麵
Windows下采集攝像頭畫麵,DShow是最常用的方法之一。通過DShow采集攝像頭數據,創建視頻采集Filter,將其加入到圖表IGraphBuilder中,用IMediaControl接口來控製流媒體在Filter Graph中的流動,再通過Render來獲取視頻的原始數據。以上流程封裝在了我們的SDK中,用戶可以直接調用SDK接口。
2)桌麵取屏及應用程序窗口截取
在Windows係統中,桌麵和所有應用程序窗口一樣,本身也是一個HWND窗口,因此可以放在一起討論。獲取一個窗口的位圖數據,最常用的方法是:創建一個用來接收窗口畫麵的HBITMAP位圖對象以及一個HDC設備上下文對象,用SelectObject將兩者綁定,然後用BitBlt從被截取窗口的HDC將數據拷貝到目標HDC。下麵列出關鍵代碼:
HDChDc = GetDC(capture_hwnd_);
HDCmem_dc = CreateCompatibleDC(hDc); //創建一個兼容DC
HBITMAPcapture_bitmap_ = ::CreateDIBSection(mem_dc, &bmi, DIB_RGB_COLORS,
(void**)&capture_data_, NULL, 0); //創建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); //釋放
3)其他截屏/截窗口方法
教育直播中,PPT分享是非常重要的一個場景。但是據我考查,自從Microsoft Office 2013之後,BitBlt就取不到Word、Excel、PPT窗口的內容了,截到的是一片白色。但是用PrintWindow這個Windows API卻可以取到。調用PrintWindow的程序會收到WM_PRINT或WM_PRINTCLIENT消息。PrintWindow的效率比BitBlt低,但當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();
}
4)獲取本地圖片的位圖數據
將本地圖片(jpg、bmp、png、gif等格式)加載到內存,並取得其位圖句柄或像素首地址的方法有很多種。這裏列舉幾種最常見的。
GdiPlus方法比較簡單。首先是通過圖片路徑創建一個Gdiplus::Bitmap對象,通過Gdiplus::Bitmap::LockBits()方法可以得到圖片的數據,存放在一個Gdiplus::BitmapData結構中。Gdiplus::BitmapData::Scan0就是圖片像素數據的首地址。如果想得到該圖片的HBITMAP句柄,隻需調Gdiplus::Bitmap::GetHBITMAP()即可。
另一種方法是使用Windows API LoadImage來加載一個本地bmp圖片得到HBITMAP句柄,但這種方法似乎隻能加載位圖文件(.bmp格式)。使用ATL的CImage隻需要3行代碼即可得到一個圖片文件的HBITMAP句柄。
CImagecbmp;
cbmp.Load(path);
HBITMAP image_bitmap = cbmp.Detach();
畫麵合成
主播常常希望同時將自己的攝像頭畫麵和桌麵內容或者某個程序的畫麵共享給觀眾,有時甚至需要同一時刻分享10個以上的畫麵源。這時候,需要將多個畫麵粘貼到一個目標畫麵上,我們稱這個過程為畫麵合成。合成的畫麵通常還要支持改變各個畫麵的尺寸、位置等操作。這樣一來,程序性能成了瓶頸問題。
首先,對於各種畫麵源的截取應該盡量采用高效的方式,其次,畫麵的拉伸壓縮是比較耗性能的地方。在1秒鍾需要合成20幀畫麵的要求下,應該避免直接強行壓縮HBITMAP,而是采用一些有加速的方案。
1)LibYuv方案
我們找到一個一個yuv庫(LibYuv Project),支持圖形數據從rgb格式到各種yuv格式之間的互相轉換(定義在libyuv/convert.h中)。比較重要的一點是,它對yuv格式圖形的拉伸和壓縮以及其他各種變換(定義在libyuv/scale.h中)是有加速的。正好我們最終要推流的格式也是yuv格式的,所以我們方案的流程是:取得各個畫麵源的畫麵之後,先將它們各自轉化為yuv格式,然後把這些yuv畫麵按照我們製定的方式粘貼到一個目標yuv畫麵上,最後將目標yuv畫麵數據推流出去。另外,由於主播的窗口上也要顯示合並畫麵,所以還要把目標畫麵轉成rgb格式渲染到窗口HDC上。
當然,由於存在rgb格式和yuv格式之間反複的轉換以及頻繁的scale,而且yuv加速畢竟是軟件方式,程序的CPU占用率還是有點高。如果能采用DirectX、OpenGL等硬件加速解決方案,對程序性能以及用戶體驗的提升應該是比較明顯的。
2)DirectX 9方案
總結
直播產品由於需要對每一幀畫麵做處理,畫麵的清晰度要高,幀率還不能太低,所以通常會存在消耗係統資源過多的問題。無論是取畫麵還是合成畫麵,方法有很多,不僅限於上麵幾種。Win API效率一般,如果對程序性能要求高,就要在其他方麵去想法設法減少資源消耗。而DirectX雖然對2D圖形加速不如3D加速那麼顯著,但還是勝過Win API的。需要注意的是,使用DirectX時要非常清楚各個參數的意義,比如設備類型(D3DDEVTYPE)、內存池類型(D3DPOOL)、用途類型(D3DUSAGE)等等。參數用錯,可能導致其性能還不如Win API。
以上由網易企業信息化服務提供商,湖南領先網絡科技整理發布。
網易企業服務(qiye163.co)是網易憑借其20年品牌優勢與經驗在企業郵箱的基礎上,為進一步布局企業市場而打造的企業級產品矩陣,致力於提供一站式企業信息化解決方案。湖南領先網絡科技是網易企業產品授權經銷商,專業為企業提供網易企業郵箱、網易辦公套件等一站式企業信息化專業解決方案。
最後更新:2017-10-08 00:17:33
上一篇:
Windows10有這些功能,你還要第三方殺軟嗎?
下一篇:
同時享用Mac和 Windows最新最強大的功能,Parallels讓你不糾結
你的設備已過期,並缺少重要的安全和質量更新,因此存在風險。讓我們帶你重回正軌,這樣
Microsoft store 無法聯網,顯示Microsoft Store需要聯網,你似乎沒有聯網
設備以遷移 由於僅部分匹配或匹配不明確,因此無法遷移設備
由於在創建轉儲期間出錯,創建轉儲文件失敗。
發生臨時 DNS 錯誤
應用商店,在我們這邊發生問題,無法使你登陸,錯誤代碼: 0xD000000D
照相機不可用,錯誤代碼:0xA00F4244(0xC00DABE0)
應用商店打開異常提示“清單中指定了未知的布局”
自定義掃描Windows defender裏麵的設備性能和運行狀況 黃色感歎號問題
windows預口體驗成員內口版本遇到問題需要重啟
熱門內容
windows10 點開此電腦後,有兩個顯示硬盤盤符的目錄是怎麼回事?
windows 10 專業版無法下載中文語言包
KB4056892
win10不能共享文件夾
在Surfacebook上用Windows to go 1703版本,更新後重啟藍屏,無法進入係統
windows10 1709版本更新失敗,錯誤0x8007001f
microdoft visual c++ 2015 redistributable
WIN10 Insider Preview 17025更新失敗,錯誤代碼0x80096004
計算機管理服務 出現一個內部錯誤(INVALID
關於控製麵板中的安全和維護內提示Windows defender 防病毒已關閉的問題