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

歡迎訪問 生活随笔!

生活随笔

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

windows

Windows平台RTMP|RTSP播放器为什么要兼容GDI绘制

發(fā)布時(shí)間:2025/3/12 windows 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows平台RTMP|RTSP播放器为什么要兼容GDI绘制 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

為什么要支持GDI

先說結(jié)論,Windows平臺(tái)播放渲染這塊,一般來說99%以上的機(jī)器都是支持D3D的,實(shí)現(xiàn)GDI模式繪制,除了為了好的兼容性外,在遠(yuǎn)程連接的場景下,D3D創(chuàng)建不成功,需要使用GDI模式。

簡單來說,Windows平臺(tái)的RTMP播放器或RTSP播放器,設(shè)計(jì)如果系統(tǒng)支持D3D,優(yōu)先D3D,如果檢測到不支持D3D,數(shù)據(jù)回調(diào)上來,GDI模式繪制。

在之前的博客,我們提到過:D3D繪制出來的圖像效果更細(xì)膩,繪制效率也更高,CPU占用相對(duì)GDI更低

上圖以1920*1080分辨率、30幀、固定碼率(采集屏幕左側(cè)區(qū)域)為例,通過大牛直播SDK ( github) 的Windows平臺(tái)SmartPublisherDemo.exe工具推送到內(nèi)網(wǎng)nginx服務(wù)器,然后分別以D3D模式和GDI模式拉流(播放端緩沖設(shè)置為0)。

可以看到:

D3D模式,CPU占用只有2.7%,延遲:249-156 = 93ms;

GDI模式,CPU占用19.5%,延遲249-73 = 176ms。

無論是從延遲和CPU占用上看,D3D模式都占優(yōu)。

實(shí)現(xiàn)思路:

以C++的demo為例:

1. 先檢測系統(tǒng)是否支持D3D模式:

if ( NT_ERC_OK == player_api_.IsSupportD3DRender(player_handle_,wrapper_render_wnd_.RenderWnd(), &in_support_d3d_render)){if ( 1 == in_support_d3d_render ){is_support_d3d_render = true;}}

2. 如不支持D3D,數(shù)據(jù)回到上層,做繪制:

if ( is_support_d3d_render ){is_gdi_render_ = false;// 支持d3d繪制的話,就用D3D繪制player_api_.SetRenderWindow(player_handle_, wrapper_render_wnd_.RenderWnd());player_api_.SetRenderScaleMode(player_handle_, btn_check_render_scale_mode_.GetCheck() == BST_CHECKED ? 1 : 0);}else{is_gdi_render_ = true;// 不支持D3D就讓播放器吐出數(shù)據(jù)來,用GDI繪制wrapper_render_wnd_.SetRenderScaleMode(btn_check_render_scale_mode_.GetCheck() == BST_CHECKED ? 1 : 0);player_api_.SetVideoFrameCallBack(player_handle_, NT_SP_E_VIDEO_FRAME_FORMAT_RGB32,GetSafeHwnd(), SM_SDKVideoFrameHandle);} extern "C" NT_VOID NT_CALLBACK SM_SDKVideoFrameHandle(NT_HANDLE handle, NT_PVOID userData, NT_UINT32 status,const NT_SP_VideoFrame* frame) {/*if (frame != NULL){std::ostringstream ss;ss << "Receive frame time_stamp:" << frame->timestamp_ << "ms" << "\r\n";OutputDebugStringA(ss.str().c_str());}*/if ( frame != NULL ){if ( NT_SP_E_VIDEO_FRAME_FORMAT_RGB32 == frame->format_&& frame->plane0_ != NULL&& frame->stride0_ > 0&& frame->height_ > 0 ){std::unique_ptr<nt_rgb32_image > pImage(new nt_rgb32_image());pImage->size_ = frame->stride0_* frame->height_;pImage->data_ = new NT_BYTE[pImage->size_];memcpy(pImage->data_, frame->plane0_, pImage->size_);pImage->width_ = frame->width_;pImage->height_ = frame->height_;pImage->stride_ = frame->stride0_;HWND hwnd = (HWND)userData;if ( hwnd != NULL && ::IsWindow(hwnd) ){::PostMessage(hwnd, WM_USER_SDK_RGB32_IMAGE, (WPARAM)handle, (LPARAM)pImage.release());}}} }

具體繪制代碼:

LRESULT CSmartPlayerDlg::OnSDKRGB32Image(WPARAM wParam, LPARAM lParam) {nt_rgb32_image* pImage = (nt_rgb32_image*)(lParam);if (pImage == NULL)return S_OK;std::shared_ptr<nt_rgb32_image> sp_image(pImage);if ( is_gdi_render_ ){wrapper_render_wnd_.OnRGB32Image(sp_image);}return S_OK; } void nt_render_wnd::OnPaint() {CPaintDC dc(this); // device context for painting// TODO: Add your message handler code here// Do not call CWnd::OnPaint() for painting messagesif ( IsIconic() ){return;}// 先繪制一個(gè)黑色的背景CRect rc_client(0, 0, 0, 0);GetClientRect(rc_client);if ( rc_client.IsRectNull()|| rc_client.IsRectEmpty() ){return;}auto mem_dc = ::CreateCompatibleDC(dc.GetSafeHdc());if ( mem_dc == NULL )return;auto mem_bitmap = ::CreateCompatibleBitmap(dc.GetSafeHdc(), rc_client.Width(), rc_client.Height());if ( mem_bitmap == NULL ){::DeleteDC(mem_dc);return;}::SelectObject(mem_dc, mem_bitmap);HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0));::FillRect(mem_dc, &rc_client, brush);::DeleteObject(brush);if ( rgb32_image_ ){if ( player_api_.GDIDrawRGB32 != NULL&& player_handle_ != NULL ){auto render_rc = GetRenderRect(rc_client, rgb32_image_->width_, rgb32_image_->height_);player_api_.GDIDrawRGB32(player_handle_, mem_dc,render_rc.left, render_rc.top,render_rc.Width(), render_rc.Height(),0, 0,rgb32_image_->width_, rgb32_image_->height_,rgb32_image_->data_, rgb32_image_->size_,rgb32_image_->width_, rgb32_image_->height_,rgb32_image_->stride_);if (logo_ && logo_->data_ != nullptr){player_api_.GDIDrawARGB(mem_dc,render_logo_left_, render_logo_top_,render_logo_width_, render_logo_height_,0, 0,logo_->width_, logo_->height_,logo_->data_.get(), logo_->stride_,logo_->width_, logo_->height_);}}}::BitBlt(dc.GetSafeHdc(),0, 0,rc_client.Width(), rc_client.Height(),mem_dc,0, 0,SRCCOPY);::DeleteObject(mem_bitmap);::DeleteDC(mem_dc); }

目前來看,不支持D3D的機(jī)器少之又少,在環(huán)境具備的情況下,優(yōu)先建議考慮D3D模式繪制,不支持的情況下,同時(shí)兼容GDI繪制是個(gè)不錯(cuò)的選擇。

總結(jié)

以上是生活随笔為你收集整理的Windows平台RTMP|RTSP播放器为什么要兼容GDI绘制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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