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

为什么要支持GDI

先说结论,Windows平台播放渲染这块,一般来说99%以上的机器都是支持D3D的,实现GDI模式绘制,除了为了好的兼容性外,在远程连接的场景下,D3D创建不成功,需要使用GDI模式。

简单来说,Windows平台的RTMP播放器或RTSP播放器,设计如果系统支持D3D,优先D3D,如果检测到不支持D3D,数据回调上来,GDI模式绘制。

在之前的博客,我们提到过:D3D绘制出来的图像效果更细腻,绘制效率也更高,CPU占用相对GDI更低

上图以1920*1080分辨率、30帧、固定码率(采集屏幕左侧区域)为例,通过大牛直播SDK ( github) 的Windows平台SmartPublisherDemo.exe工具推送到内网nginx服务器,然后分别以D3D模式和GDI模式拉流(播放端缓冲设置为0)。

可以看到:

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

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

无论是从延迟和CPU占用上看,D3D模式都占优。

实现思路:

以C++的demo为例:

1. 先检测系统是否支持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,数据回到上层,做绘制:

		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就让播放器吐出数据来,用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;}// 先绘制一个黑色的背景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的机器少之又少,在环境具备的情况下,优先建议考虑D3D模式绘制,不支持的情况下,同时兼容GDI绘制是个不错的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/553049.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android平台实现Unity3D下RTMP推送

像Unity3D下的RTMP或RTSP播放器一样&#xff0c;好多开发者苦于在Unity环境下&#xff0c;如何高效率低延迟的把数据采集并编码实时推送到流媒体服务器&#xff0c;实现Unity场景下的低延迟推拉流方案。 关于屏幕采集&#xff0c;有两种方案&#xff1a; 1. 直接封装Android原…

Windows平台实现Unity下窗体|摄像头|屏幕采集推送

技术背景 随着Unity3D的应用范围越来越广&#xff0c;越来越多的行业开始基于Unity3D开发产品&#xff0c;如传统行业中虚拟仿真教育、航空工业、室内设计、城市规划、工业仿真等领域。 基于此&#xff0c;好多开发者苦于在Unity环境下&#xff0c;没有低延迟的推拉流解决方案…

数据推送选择GB28181、RTSP还是RTMP?

GB/T28181 国标GB/T28181协议全称《安全防范视频监控联网系统信息传输、交换、控制技术要求》&#xff0c;是一个定义视频联网传输和设备控制标准的白皮书&#xff0c;由公安部科技信息化局提出&#xff0c;该标准规定了城市监控报警联网系统中信息传输、交换、控制的互联结构…

Android平台基于RTMP或RTSP的一对一音视频互动技术方案探讨

背景 随着智能门禁等物联网产品的普及&#xff0c;越来越多的开发者对音视频互动体验提出了更高的要求。目前市面上大多一对一互动都是基于WebRTC&#xff0c;优点不再赘述&#xff0c;我们这里先说说可能需要面临的问题&#xff1a;WebRTC的服务器部署非常复杂&#xff0c;可…

Android前端音视频数据接入GB28181平台意义

技术背景 在我们研发Android平台GB28181前端音视频接入模块之前&#xff0c;业内听到最多的是&#xff0c;如何用Android或者Windows端&#xff0c;在没有国标IPC设备的前提下&#xff0c;模拟GB28181的信令和媒体流交互流程&#xff0c;实现GB28181整体方案的测试&#xff1f…

std::atomic和std::mutex区别

​std::atomic介绍​ ​模板类std::atomic是C11提供的原子操作类型&#xff0c;头文件 #include<atomic>。​在多线程调用下&#xff0c;利用std::atomic可实现数据结构的无锁设计。​​ ​和互斥量的不同之处在于&#xff0c;std::atomic原子操作&#xff0c;主要是保…

C++ std::remove/std::remove_if/erase用法探讨

​std::remove 不会改变输入vector/string的长度。其过程相当于去除指定的字符&#xff0c;剩余字符往前靠。后面的和原始字符保持一致。​ 需要注意的是&#xff0c;remove函数是通过覆盖移去的&#xff0c;如果容器最后一个值刚好是需要删除的&#xff0c;则它无法覆盖掉容器…

再谈NULL和nullptr(C++11)区别

在谈NULL和nullptr区别之前&#xff0c;我们先看段代码&#xff1a; #include "stdafx.h" #include <iostream>using namespace std; void func(void *p) {cout << "p is pointer " << p << endl; } void func(int num) {cout &l…

C++11新特性探索:原始字符串字面值(raw string literal)

原始字符串字面值(raw string literal)是C11引入的新特性。 原始字符串简单来说&#xff0c;“原生的、不加处理的”&#xff0c;字符表示的就是自己&#xff08;所见即所得&#xff09;&#xff0c;引号、斜杠无需 “\” 转义&#xff0c;比如常用的目录表示&#xff0c;引入…

Android国标接入终端实现GB28181实时位置(MobilePosition)上报

技术背景 在实现本文提到的Android平台国标GB28181接入终端的实时位置上报之前&#xff0c;之前已经完成了Android终端GB28181常规功能接入&#xff0c;采集到实时音视频数据&#xff0c;编码PS打包后&#xff0c;按需传到GB28281服务平台&#xff0c;媒体流支持最新GB28181-2…

基于RTMP的智慧数字人|AI数字人传输技术方案探讨

技术背景 随着智慧数字人、AI数字人的兴起&#xff0c;越来越多的公司着手构建​全息、真实感数字角色等技术合成的数字仿真人虚拟形象&#xff0c;通过“虚拟形象语音交互&#xff08;T-T-S、ASR&#xff09;自然语言理解&#xff08;NLU&#xff09;深度学习”&#xff0c;构…

​GB28181心跳机制探讨和技术实现

​GB/T 28181-2016心跳机制​ ​通过周期性的状态信息报送&#xff0c;实现注册服务器与源设备之间的状态检测即心跳机制。 ​ ​心跳发送方、接收方需统一配置“心跳间隔”参数&#xff0c;按照“心跳间隔”定时发送心跳消息&#xff0c;默认心跳间隔60s。心跳发送方、接收方…

Unity3D下Linux平台播放RTSP或RTMP流

背景 尽管Windows平台有诸多优势&#xff0c;Linux平台的发展还是势不可挡&#xff0c;特别实在传统行业&#xff0c;然而Linux生态构建&#xff0c;总是差点意思&#xff0c;特别是有些常用的组件&#xff0c;本文基于已有的Linux平台RTSP、RTMP播放模块&#xff0c;构建Unit…

Unity3D平台实现全景实时RTMP|RTSP流渲染

好多开发者的使用场景&#xff0c;需要在Windows特别是Android平台实现Unity3D的全景实时视频渲染&#xff0c;本文以Windows平台为例&#xff0c;简单介绍下具体实现&#xff1a; 如果是RTSP或RTMP流数据&#xff0c;实际上难点&#xff0c;主要在于拉取RTSP或RTMP流&#xf…

C++17新特性之std::string_view

std::string_view系C17标准发布后新增的内容&#xff0c;类成员变量包含两个部分&#xff1a;字符串指针和字符串长度&#xff0c;相比std::string, std::string_view涵盖了std::string的所有只读接口。如果生成的std::string无需进行修改操作&#xff0c;可以把std::string转换…

Android平台实现RTSP|RTMP转GB28181网关接入

背景 在事先Android平台RTSP、RTMP转GB28181网关之前&#xff0c;我们已经实现了Android平台GB28181的接入&#xff0c;可实现Android平台采集到的音视频数据&#xff0c;编码后&#xff0c;打包按需发到GB28181服务平台。此外&#xff0c;拉流端&#xff0c;我们已经有了成熟…

Unity3D下实现Linux平台RTMP推流(以采集Unity窗体和声音为例)

技术背景 随着物联网等行业的崛起&#xff0c;越来越多的传统行业如虚拟仿真、航天工业、工业仿真、城市规划等&#xff0c;对Linux下的生态构建&#xff0c;有了更大的期望&#xff0c;Linux平台下&#xff0c;可选的直播推拉流解决方案相对Windows和移动端&#xff0c;非常少…

Android平台实现VR头显Unity下音视频数据RTMP推送

背景 随着技术发展的日新月异&#xff0c;虚拟现实产业已经从过去的探索期&#xff0c;自2020年起&#xff0c;慢慢过渡到高速发展期&#xff0c;随着5G时代的到来&#xff0c;大带宽高可靠低延迟网络环境&#xff0c;为虚拟现实产业提供了很好的网络保障&#xff0c;虚拟现实…

C++11特性之std:call_once介绍

std:call_once是C11引入的新特性&#xff0c;如需使用&#xff0c;只需要#include <mutex>即可&#xff0c;简单来说std:call_once的作用&#xff0c;确保函数或代码片段在多线程环境下&#xff0c;只需要执行一次&#xff0c;常用的场景如Init()操作或一些系统参数的获取…

2022年了,该学C++还是Java?

最近好多朋友私信我&#xff0c;C好不好学&#xff1f;学C好还是Java好&#xff1f; 我的回答是&#xff1a;C不好学&#xff0c;但你觉得C不好学的话&#xff0c;Java也不好学。因为C难是难在语言本身&#xff0c;java难是难在各种框架和库。 C学习进阶比较陡, 对新手不友好&…