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,一经查实,立即删除!

相关文章

Windows平台RTMP|RTSP播放器实现画面全屏功能

我们在Windows平台实现RTSP或者RTMP播放的时候&#xff0c;有个功能是绕不开的&#xff0c;那就是播放窗口全屏。本文就以大牛直播SDK&#xff08;官方&#xff09;的Windows播放器为例&#xff0c;大概讲下大概实现&#xff1a; 全屏播放需要考虑的点不多&#xff1a; 第一&…

tim怎么设置检测到新版本自动安装 tim安全自动更新的开启方法

TIM想要开启自动检测新版本并下载安装&#xff0c;该怎么设置呢?下面我们就来看看详细的教程。 1、首先&#xff0c;在你的 电脑中找到TIM; tim怎么设置检测到新版本自动安装?tim安全自动更新的开启方法 2、打开TIM&#xff0c;登录你的个人账号&#xff0c;登陆之后&…

Android平台实现Unity3D下RTMP推送

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

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

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

钉钉调岗申请单怎么写 钉钉申请调岗的教程

钉钉中想要申请调岗申请单&#xff0c;调岗申请单在哪&#xff0c;该怎么填写呢?下面我们就来看看详细的教程。 1、首先打开钉钉客户端&#xff0c;点击下方的工作。 钉钉调岗申请单怎么写? 钉钉申请调岗的教程 2、向下滑动找到并打开调岗申请单应用。 钉钉调岗申请单怎么…

Android平台RTMP推送端实现外部数据对接推送和录像

背景 好多开发者在做Android平台RTMP推送对接的同时&#xff0c;除了编码前的数据外&#xff0c;还有些外部编码数据推送诉求&#xff0c;他们希望外部的编码音视频数据不止可以实现RTMP推送&#xff0c;还可以同时在推送端实时录制下来&#xff0c;本文以我们&#xff08;官方…

excel怎么删除浏览记录 方法介绍

Excel 2013工作表删除浏览记录的步骤&#xff1a; 1、鼠标左键双击计算机桌面Excel2013程序图标&#xff0c;将其打开运行。在打开的Excel2013程序窗口&#xff0c;点击“空白工作薄”选项&#xff0c;新建一个空白Excel工作薄。如图所示; excel怎么删除浏览记录&#xff1f;…

爱奇艺怎么开启数据流量自动播放

1、打开手机&#xff0c;点击爱奇艺 爱奇艺怎么开启数据流量自动播放 2、进入爱奇艺&#xff0c;点击我的 爱奇艺怎么开启数据流量自动播放 3、然后在我的界面&#xff0c;点击设置 爱奇艺怎么开启数据流量自动播放 4、进入设置界面&#xff0c;点击播放与下载 爱奇艺怎…

Win7系统账户被禁用的解决方法

我们都知道Win7系统中可以建立多个账户来进行不同的登录使用&#xff0c;十分的方便&#xff0c;但是有的用户建立了多个账户&#xff0c;却发现所有的账号都被禁用&#xff0c;那遇到这个问题应该怎么解决呢&#xff0c;下面就为小伙伴们带来 了Win7系统账户被禁用的解决方法&…

Win11系统如何隐藏快速搜索

近日网络中已经出现了很多Windows 11的泄露版本&#xff0c;意味着Win11版本正式确定&#xff0c;现在只是等待微软正式发布了。Windows系统中菜单栏都会默认放一个快速搜索的图标&#xff0c;快速搜索一直是Windows系统中的一个重要功能&#xff0c;那么在Win11系统中该如何隐…

网易邮箱广告标签怎么关 163邮箱去广告标签的教程

1、打开百度输入网易邮箱 网易邮箱广告标签怎么关? 163邮箱去广告标签的教程 网易邮箱广告标签怎么关? 163邮箱去广告标签的教程 2、输入账号和密码&#xff0c;进入邮箱主页&#xff0c;在标签栏看到广告标签 网易邮箱广告标签怎么关? 163邮箱去广告标签的教程 3、选中…

Linux|麒麟操作系统实现多路RTMP|RTSP播放

技术背景 无论是Windows平台还是Linux&#xff0c;多路播放诉求非常普遍&#xff0c;比如针对智慧工地、展馆、教育等宏观场景下的摄像头展示&#xff0c;关于RTSP或RTMP直播播放器开发需要注意的点&#xff0c;可参考之前博客&#xff0c;总的来说有以下一些点&#xff1a; …

TIM提示“个人文件夹被占用,请稍候再登录”怎么解决

在登录TIM的时候&#xff0c;弹出提示“个人文件夹被占用&#xff0c;请稍后再登录”的提示&#xff0c;无法正常登录TIM TIM提示“个人文件夹被占用&#xff0c;请稍候再登录”怎么解决&#xff1f; 这个时候&#xff0c;我们可以直接关闭上面的登录窗口&#xff0c;然后过一…

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

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

Windows平台RTMP推送摄像头对接介绍

背景 好多开发者在对接大牛直播SDK&#xff08;官方&#xff09;的Windows平台RTMP推送时&#xff0c;不熟悉摄像头调用&#xff0c;实际上&#xff0c;摄像头调用逻辑并不复杂&#xff0c;以下是大概流程&#xff1a; 首先调用我们sdk接口获取摄像头个数&#xff0c;调用接口…

Outlook2016未读邮件怎么设置字体颜色

Outlook2016中想要设置未读邮件的字体颜色&#xff0c;该怎么设置呢?下面我们就来看看详细的教程。 Outlook2016未读邮件怎么设置字体颜色? 1、下载安装outlook软件。 Outlook2016未读邮件怎么设置字体颜色? 2、双击打开outlook软件&#xff0c;登入邮箱账户。 Outlook…

Android平台RTMP推送模块如何对接NV21、YV12、RGB、YUV等编码前数据

前言 我们在对接Android平台摄像头或者屏幕采集、编码打包推送场景的时候&#xff0c;随着采集设备的不同&#xff0c;出来的数据也是多样化的&#xff0c;比如NV21、YV12、RGB、YUV等&#xff0c;更有图像数据甚至是翻转或者倒置的&#xff0c;如果上层处理&#xff0c;效率低…

庖丁解牛之-Android平台RTSP|RTMP播放器设计

背景 我们在做Android平台RTSP或者RTMP播放器开发的时候&#xff0c;需要注意的点非常多&#xff0c;以下&#xff0c;以大牛直播SDK(官方)的接口为例&#xff0c;大概介绍下相关接口设计&#xff1a; 接口设计 1. Open() 接口 Open接口的目的&#xff0c;主要是创建实例&a…

如何在Android端实现轻量级RTSP服务(类似于IPC)

为什么要设计轻量级RTSP服务 首先声明一点&#xff0c;本blog提到的轻量级RTSP服务&#xff0c;类似于网络摄像头&#xff08;IPC&#xff09;&#xff0c;而非传统意义的接受外部推流的RTSP服务器。 轻量级RTSP服务解决的核心痛点&#xff1a;避免用户单独部署RTSP或者RTMP服…

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

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