如何在Unity3d平台下低延迟播放RTMP或RTSP流

随着VR类、工业仿真、智慧城市等场景的快速发展,开发者对Unity3d低延迟的直播需求量越来越大,前两年,大牛直播SDK发布了Windows平台、Android平台和iOS平台的Unity3d RTMP和RTSP的播放,好多公司用起来体验都非常好,以下介绍大概实现流程。

本文以Android平台为例,我们的实现:基于大牛直播SDK现有非常成熟的native RTMP和RTSP播放模块,回调解码后的原始数据,传递给Unity3d,实现相应的绘制即可,对应demo,可以参考 Github。

具体步骤如下:

1. Native RTSP或RTSP直播播放SDK回调RGB/YUV420/NV12等其中的一种未压缩的图像格式;

2. Unity3D创建相应的RGB/YUV420等Shader;

3.Unity3D从各个平台获取图像数据来填充纹理即可。

以Android平台为例,我们在原有接口基础上,做了桥接接口,供Unity平台使用:

    /// <summary>/// Init/// </summary>public int NT_U3D_Init(){return DANIULIVE_RETURN_OK;}/// <summary>/// 开始/// 返回播放句柄/// </summary>public long NT_U3D_Open(){if ( 0 != player_obj_.Call<int>("Init", java_obj_cur_activity_) ){return 0;}return player_obj_.Call<long>("Open");}/// <summary>/// Register Game Object,用于消息传递/// </summary>public int NT_U3D_Set_Game_Object(long handle, string gameObjectName){return player_obj_.Call<int>("SetGameObject", handle, gameObjectName);}/// <summary>/// 设置H.264解码方式 false 软件解码 true 硬件解码 默认为false/// </summary>/// <param name="isHwDecoder"></param>public int NT_U3D_SetVideoDecoderMode(long handle, int isHwDecoder){return player_obj_.Call<int>("SetPlayerVideoHWDecoder", handle, isHwDecoder);}/// <summary>/// 设置H.265 解码方式 false 软件解码 true 硬件解码 默认为false/// </summary>/// <param name="isHevcHwDecoder"></param>public int NT_U3D_SetVideoHevcDecoderMode(long handle, int isHevcHwDecoder){return player_obj_.Call<int>("SetPlayerVideoHevcHWDecoder", handle, isHevcHwDecoder);}/// <summary>/// 设置音频输出模式: if 0: 自动选择; if with 1: audiotrack模式/// </summary>/// <param name="use_audiotrack"></param>public int NT_U3D_SetAudioOutputType(long handle, int use_audiotrack){return player_obj_.Call<int>("SetAudioOutputType", handle, use_audiotrack);}/// <summary>/// 设置播放端缓存大小, 默认200毫秒/// </summary>/// <param name="buffer"></param>public int NT_U3D_SetBuffer(long handle, int buffer){return player_obj_.Call<int>("SetBuffer", handle, buffer);}/// <summary>/// 接口可实时调用:设置是否实时静音,1:静音; 0: 取消静音/// </summary>/// <param name="is_mute"></param>public int NT_U3D_SetMute(long handle, int is_mute){return player_obj_.Call<int>("SetMute", handle, is_mute);}/// <summary>/// 设置RTSP TCP模式, 1: TCP; 0: UDP/// </summary>/// <param name="is_using_tcp"></param>public int NT_U3D_SetRTSPTcpMode(long handle, int is_using_tcp){return player_obj_.Call<int>("SetRTSPTcpMode", handle, is_using_tcp);}/// <summary>/// 设置RTSP超时时间, timeout单位为秒,必须大于0/// </summary>/// <param name="timeout"></param>public int NT_U3D_SetRTSPTimeout(long handle, int timeout){return player_obj_.Call<int>("SetRTSPTimeout", handle, timeout);}/// <summary>/// 设置RTSP TCP/UDP自动切换/// NOTE: 对于RTSP来说,有些可能支持rtp over udp方式,有些可能支持使用rtp over tcp方式./// 为了方便使用,有些场景下可以开启自动尝试切换开关, 打开后如果udp无法播放,sdk会自动尝试tcp, 如果tcp方式播放不了,sdk会自动尝试udp./// </summary>/// <param name="timeout"></param>/// timeout:如果设置1的话, sdk将在tcp和udp之间尝试切换播放,如果设置为0,则不尝试切换.public int NT_U3D_SetRTSPAutoSwitchTcpUdp(long handle, int is_auto_switch_tcp_udp){return player_obj_.Call<int>("SetRTSPAutoSwitchTcpUdp", handle, is_auto_switch_tcp_udp);}/// <summary>/// 设置快速启动该模式,/// </summary>/// <param name="is_fast_startup"></param>public int NT_U3D_SetFastStartup(long handle, int is_fast_startup){return player_obj_.Call<int>("SetFastStartup", handle, is_fast_startup);}/// <summary>/// 设置超低延迟模式 false不开启 true开启 默认false/// </summary>/// <param name="mode"></param>public int NT_U3D_SetPlayerLowLatencyMode(long handle, int mode){return player_obj_.Call<int>("SetPlayerLowLatencyMode", handle, mode);}/// <summary>/// 设置视频垂直反转/// is_flip: 0: 不反转, 1: 反转/// </summary>/// <param name="is_flip"></param>public int NT_U3D_SetFlipVertical(long handle, int is_flip){return player_obj_.Call<int>("SetFlipVertical", handle, is_flip);}/// <summary>/// 设置视频水平反转/// is_flip: 0: 不反转, 1: 反转/// </summary>/// <param name="is_flip"></param>public int NT_U3D_SetFlipHorizontal(long handle, int is_flip){return player_obj_.Call<int>("SetFlipHorizontal", handle, is_flip);}/// <summary>/// 设置顺时针旋转, 注意除了0度之外, 其他角度都会额外消耗性能/// degress: 当前支持 0度,90度, 180度, 270度 旋转/// </summary>/// <param name="degress"></param>public int NT_U3D_SetRotation(long handle, int degress){return player_obj_.Call<int>("SetRotation", handle, degress);}/// <summary>/// 设置是否回调下载速度/// is_report: if 1: 上报下载速度, 0: 不上报./// report_interval: 上报间隔,以秒为单位,>0./// </summary>/// <param name="is_report"></param>/// <param name="report_interval"></param>public int NT_U3D_SetReportDownloadSpeed(long handle, int is_report, int report_interval){return player_obj_.Call<int>("SetReportDownloadSpeed", handle, is_report, report_interval);}/// <summary>/// 设置是否需要在播放或录像过程中快照/// </summary>/// <param name="is_save_image"></param>public int NT_U3D_SetSaveImageFlag(long handle, int is_save_image){return player_obj_.Call<int>("SetSaveImageFlag", handle, is_save_image);}/// <summary>/// 播放或录像过程中快照/// </summary>/// <param name="imageName"></param>public int NT_U3D_SaveCurImage(long handle, string imageName){return player_obj_.Call<int>("SaveCurImage", handle, imageName);}/// <summary>/// 播放或录像过程中,快速切换url/// </summary>/// <param name="uri"></param>public int NT_U3D_SwitchPlaybackUrl(long handle, string uri){return player_obj_.Call<int>("SwitchPlaybackUrl", handle, uri);}/// <summary>/// 创建录像存储路径/// </summary>/// <param name="path"></param>public int NT_U3D_CreateFileDirectory(string path){return player_obj_.Call<int>("CreateFileDirectory", path);}/// <summary>/// 设置录像存储路径/// </summary>/// <param name="path"></param>public int NT_U3D_SetRecorderDirectory(long handle, string path){return player_obj_.Call<int>("SetRecorderDirectory", handle, path);}/// <summary>/// 设置单个录像文件大小/// </summary>/// <param name="size"></param>public int NT_U3D_SetRecorderFileMaxSize(long handle, int size){return player_obj_.Call<int>("SetRecorderFileMaxSize", handle, size);}/// <summary>/// 设置录像时音频转AAC编码的开关/// aac比较通用,sdk增加其他音频编码(比如speex, pcmu, pcma等)转aac的功能./// 注意: 转码会增加性能消耗/// </summary>/// <param name="is_transcode"></param>/// is_transcode:设置为1的话,如果音频编码不是aac,则转成aac,如果是aac,则不做转换. 设置为0的话,则不做任何转换. 默认是0.public int NT_U3D_SetRecorderAudioTranscodeAAC(long handle, int is_transcode){return player_obj_.Call<int>("SetRecorderAudioTranscodeAAC", handle, is_transcode);}/// <summary>/// 设置播放路径/// </summary>public int NT_U3D_SetUrl(long handle, string url){return player_obj_.Call<int>("SetUrl", handle, url);}/// <summary>/// 开始播放/// </summary>public int NT_U3D_StartPlay(long handle){return player_obj_.Call<int>("StartPlay", handle);}/// <summary>/// 获取YUV数据/// </summary>public AndroidJavaObject NT_U3D_GetVideoFrame(long handle){return player_obj_.Call<AndroidJavaObject>("GetVideoFrame", handle);}/// <summary>/// 停止播放/// </summary>public int NT_U3D_StopPlay(long handle){return player_obj_.Call<int>("StopPlay", handle);}/// <summary>/// 开始录像/// </summary>public int NT_U3D_StartRecorder(long handle){return player_obj_.Call<int>("StartRecorder", handle);}/// <summary>/// 停止录像/// </summary>public int NT_U3D_StopRecorder(long handle){return player_obj_.Call<int>("StopRecorder", handle);}/// <summary>/// 关闭播放/// </summary>public int NT_U3D_Close(long handle){return player_obj_.Call<int>("Close", handle);}/// <summary>/// UnInit Player/// </summary>public int NT_U3D_UnInit(){return DANIULIVE_RETURN_OK;}

Event传递,我们在unity3d里面解析相应的字串即可:

   /// <summary>/// android 传递过来 code/// </summary>/// <param name="code"></param>public void onNTSmartEvent(string param){if (!param.Contains(",")){Debug.Log("[onNTSmartEvent] android传递参数错误");return;}string[] strs = param.Split(',');string player_handle =strs[0];string code = strs[1];string param1 = strs[2];string param2 = strs[3];string param3 = strs[4];string param4 = strs[5];Debug.Log("[onNTSmartEvent] code: 0x" + Convert.ToString(Convert.ToInt32(code), 16));switch (Convert.ToInt32(code)){case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:Debug.Log("开始。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:Debug.Log("连接中。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:Debug.Log("连接失败。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:Debug.Log("连接成功。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:Debug.Log("连接断开。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP:Debug.Log("停止播放。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:Debug.Log("分辨率信息: width: " + Convert.ToInt32(param1) + ", height: " + Convert.ToInt32(param2));break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:Debug.Log("收不到媒体数据,可能是url错误。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:Debug.Log("切换播放URL。。");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:Debug.Log("快照: " + param1 + " 路径:" + param3);if (Convert.ToInt32(param1) == 0){Debug.Log("截取快照成功。.");}else{Debug.Log("截取快照失败。.");}break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:Debug.Log("[record]开始一个新的录像文件 : " + param3);break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:Debug.Log("[record]已生成一个录像文件 : " + param3);break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:Debug.Log("Start_Buffering");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:Debug.Log("Buffering: " + Convert.ToInt32(param1));break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:Debug.Log("Stop_Buffering");break;case EVENTID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:Debug.Log("download_speed:" + param1 + "Byte/s" + ", "+ (Convert.ToInt32(param1) * 8 / 1000) + "kbps" + ", " + (Convert.ToInt32(param1) / 1024)+ "KB/s");break;}}

开始播放:

    public void Play(){if (is_running){Debug.Log("已经在播放。。");   return;}//获取输入框的urlstring url = input_url_.text.Trim();if (!url.StartsWith("rtmp://") && !url.StartsWith("rtsp://")){videoUrl = "rtmp://202.69.69.180:443/webcast/bshdlive-pc";}else{videoUrl = url;}OpenPlayer();if ( player_handle_ == 0 )return;NT_U3D_Set_Game_Object(player_handle_, game_object_);NT_U3D_SetUrl(player_handle_, videoUrl);/* ++ 播放前参数配置可加在此处 ++ */int is_using_tcp = 0;        //TCP/UDP模式设置NT_U3D_SetRTSPTcpMode(player_handle_, is_using_tcp);int is_report = 0;int report_interval = 1;NT_U3D_SetReportDownloadSpeed(player_handle_, is_report, report_interval);  //下载速度回调NT_U3D_SetBuffer(player_handle_, play_buffer_time_);                        //设置buffer timeNT_U3D_SetPlayerLowLatencyMode(player_handle_, is_low_latency_ ? 1 : 0);    //设置是否启用低延迟模式NT_U3D_SetMute(player_handle_, is_mute_ ? 1 : 0);                           //是否启动播放的时候静音NT_U3D_SetVideoDecoderMode(player_handle_, is_hw_decode_ ? 1 : 0);          //设置H.264软硬解模式NT_U3D_SetVideoHevcDecoderMode(player_handle_, is_hw_decode_ ? 1 : 0);          //设置H.265软硬解模式int is_fast_startup = 1;NT_U3D_SetFastStartup(player_handle_, is_fast_startup);                     //设置快速启动模式int rtsp_timeout = 10;NT_U3D_SetRTSPTimeout(player_handle_, rtsp_timeout);                        //设置RTSP超时时间int is_auto_switch_tcp_udp = 1;NT_U3D_SetRTSPAutoSwitchTcpUdp(player_handle_, is_auto_switch_tcp_udp);    //设置TCP/UDP模式自动切换/* -- 播放前参数配置可加在此处 -- */int flag = NT_U3D_StartPlay(player_handle_);if (flag  == DANIULIVE_RETURN_OK){is_need_get_frame_ = true;Debug.Log("播放成功");}else{is_need_get_frame_ = false;Debug.LogError("播放失败");}is_running = true;  }

开始播放后,native模块,回调yuv/rgb数据,unity3d模块,做相应的绘制处理即可。

    private void Update(){if (!is_need_get_frame_)return;if (player_handle_ == 0)return;AndroidJavaObject u3d_video_frame_obj = NT_U3D_GetVideoFrame(player_handle_);if (u3d_video_frame_obj == null)return;VideoFrame converted_video_frame = ConvertToVideoFrame(u3d_video_frame_obj);if (converted_video_frame == null)return;if ( !is_need_init_texture_){if (converted_video_frame.width_ != video_width_|| converted_video_frame.height_ != video_height_|| converted_video_frame.y_stride_ != y_row_bytes_|| converted_video_frame.u_stride_ != u_row_bytes_|| converted_video_frame.v_stride_ != v_row_bytes_){is_need_init_texture_ = true;}}if (is_need_init_texture_){if (InitYUVTexture(converted_video_frame)){is_need_init_texture_ = false;}}UpdateYUVTexture(converted_video_frame);converted_video_frame = null;}

关闭播放:

    private void ClosePlayer(){is_need_get_frame_ = false;is_need_init_texture_ = false;int flag = NT_U3D_StopPlay(player_handle_);if (flag == DANIULIVE_RETURN_OK){Debug.Log("停止成功");}else{Debug.LogError("停止失败");}flag = NT_U3D_Close(player_handle_);if (flag == DANIULIVE_RETURN_OK){Debug.Log("关闭成功");}else{Debug.LogError("关闭失败");}player_handle_ = 0;NT_U3D_UnInit();is_running = false;}

以上是大概的实现流程,Unity环境下,实际测试时延,和 native直播模块相差无几,都是毫秒级延迟。Windows平台和iOS平台也是如此。

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

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

相关文章

轻量级RTSP服务存在的意义

为什么要设计轻量级RTSP服务 轻量级RTSP服务解决的核心痛点是避免用户或者开发者单独部署RTSP或者RTMP服务。 轻量级RTSP服务可满足内网无纸化/电子教室等内网超低延迟的低并发需求&#xff0c;避免让用户配置单独的服务器&#xff0c;大牛直播SDK在推送端发布了轻量级RTSP服…

foxmail邮件怎样打印日历

foxmail邮件中的日历有很多信息&#xff0c;想要打印日历&#xff0c;该怎么打印呢?我们点击日历信息。点击设置按钮&#xff0c;再点击打印按钮&#xff0c;先进行设置打印机&#xff0c;然后打印邮件的日历&#xff0c;下面我们就来看看详细的图文教程。 foxmail邮件怎样打…

Windows平台RTMP/RTSP直播推送模块设计和使用说明

开发背景 好多开发者一直反馈&#xff0c;Windows平台&#xff0c;做个推屏或者推摄像头&#xff0c;推RTMP或者RTSP出去&#xff0c;不知道哪些功能是必须的&#xff0c;哪些设计是可有可无的&#xff0c;还有就是&#xff0c;不知道如何选技术方案&#xff0c;以下是基于我们…

跨平台低延迟的RTMP/RTSP直播播放器设计实现

开发背景 2015年&#xff0c;当我们试图在市面上找一款专供直播播放使用的低延迟播放器&#xff0c;来配合测试我们的RTMP推送模块使用时&#xff0c;居然发现没有一款好用的&#xff0c;市面上的&#xff0c;如VLC或Vitamio&#xff0c;说白了都是基于FFMPEG&#xff0c;在点…

win7系统锁定计算机设置方法

我们都知道电脑长时间不使用的话&#xff0c;计算机就会自动进入锁定状态&#xff0c;但是也有用户不想让计算机自动进入锁定状态&#xff0c;但是却不知道应该怎么操作&#xff0c;为此非常苦恼&#xff0c;那么Win7锁定计算机怎么设置呢?今天为大家分享win7系统锁定计算机设…

Windows平台基于RTMP实现一对一互动直播

目前市面上大多一对一互动都是基于WebRTC&#xff0c;缺点如下&#xff1a; 服务器部署非常复杂&#xff0c;不利于私有部署&#xff0c;在一些私密性高的场景下&#xff0c;无法使用&#xff0c;如公安、市政等体系&#xff1b;传输基于UDP&#xff0c;很难保证传输质量&…

网易云音乐电脑版怎么下载电台节目 主播电台节目下载教程

网易云音乐不仅可以听歌&#xff0c;还可以在主播电台中&#xff0c;听到各类主播的声音&#xff0c;下面我们就来讲讲网易云音乐电脑版怎么下载电台节目&#xff0c;一起来看教程吧! 网易云音乐电脑版怎么下载电台节目 主播电台节目下载教程 网易云音乐PC版主播电台节目下载…

如何实现RTMP推送Android Camera2数据

Camera2简介 在Google 推出Android 5.0的时候, Android Camera API 版本升级到了API2(android.hardware.camera2), 之前使用的API1(android.hardware.camera)就被标为 Deprecated 了。 Camera API2相较于API1有很大不同, 并且API2是为了配合HAL3进行使用的, API2有很多API1不…

Android平台RTMP多实例推送的几种情况探讨

好多开发者提到&#xff0c;如何实现Android平台&#xff0c;多实例推送&#xff0c;多实例推送&#xff0c;有几种理解&#xff1a; 多路编码&#xff0c;多个实例分别推送到不同的RTMP URL&#xff08;如Android采集板卡同时接2路出去&#xff09;&#xff1b;同一路编码&am…

雨林木风win11 64位全新专业版系统v2021.08

雨林木风win11 64位全新专业版系统v2021.08是目前非常火热的电脑操作系统&#xff0c;系统运行速度非常的快速&#xff0c;拥有稳定、安全、兼容性强等特点&#xff0c;多样化的服务可供你的使用&#xff0c;支持在线的升级&#xff0c;非常的便捷&#xff0c;可以提高系统的性…

面向内网无纸化会议/智慧教室/实时同屏,组播还是RTMP?

一、背景 为满足内网无纸化/电子教室等内网超低延迟需求&#xff0c;避免让用户配置单独的服务器&#xff0c;我们研发了轻量级RTSP服务开发包。 单播不再赘述&#xff0c;这里重点介绍下我们的组播技术方案&#xff1a; 组播解决的主要痛点是服务器部署和带宽占用问题&…

打印更无缝:微软改善Win11中通用打印体验

微软昨日透露&#xff0c;将会在 Windows 11 系统中改进打印体验。从下面的截图中可以看到&#xff0c;用户可以直接在设置应用中添加打印机。对于使用通用打印机驱动的打印机&#xff0c;微软增加了为打印作业添加密码的功能。 打印更无缝&#xff1a;微软改善Win11中通用打印…

Windows平台如何快速实现RTSP/RTMP直播播放

前段时间&#xff0c;我们在 https://blog.csdn.net/renhui1112/article/details/104143794 提到“RTSP播放器开发过程中需要考虑哪些关键因素”&#xff0c;本次主要介绍&#xff0c;如何调用SDK实现RTSP/RTMP播放能力。 本文以调用大牛直播SDK为例&#xff1a; demo说明 SD…

Windows平台RTSP播放器/RTMP播放器设计需要考虑的几个点

我们在实现Windows平台RTSP播放器或RTMP播放器的时候&#xff0c;需要考虑的点很多&#xff0c;比如多实例设计、多绘制模式兼容、软硬解码支持、快照、RTSP下TCP-UDP自动切换等&#xff0c;以下就其中几个方面&#xff0c;做个大概的探讨。 1. 视频绘制模式 我们在实现Windo…

网易邮箱大师如何定时发送 定时发送邮件方法步骤详解

网易邮箱大师是我们日常使用邮箱的最佳软件&#xff0c;不仅能批量登录邮件&#xff0c;还能定时发送邮件&#xff0c;可谓功能齐全&#xff0c;很多小伙伴不知道如何定时发送邮件&#xff0c;那么接下来小编说的这篇文章肯定会对你有帮助。 操作步骤如下&#xff1a; 1、打开…

Windows平台下如何实现Unity3D下的RTMP推送

好多开发者苦于很难在unity3d下实现RTMP直播推送&#xff0c;本次以大牛直播SDK&#xff08;Github&#xff09;的Windows平台RTMP推送模块&#xff08;以推摄像头为例&#xff0c;如需推屏幕数据&#xff0c;设置相关参数即可&#xff09;为例&#xff0c;介绍下unity3d的RTMP…

Android平台如何实现屏幕数据采集并推送至RTMP服务器

随着无纸化、智慧教室等场景的普及&#xff0c;好多企业或者开发者开始寻求更高效稳定低延迟的RTMP同屏方案&#xff0c;本文以大牛直播SDK(Github)的同屏demo&#xff08;对应工程&#xff1a;SmartServicePublisherV2&#xff09;为例&#xff0c;介绍下如何采集编码推送RTMP…

网易邮箱大师如何注册邮箱 注册邮箱方法步骤介绍

网易邮箱大师是款高效强大的全平台邮箱客户端&#xff0c;支持所有邮箱登录&#xff0c;功能强大&#xff0c;一个PC端就能登录多个邮箱&#xff0c;很多小伙伴不知道如何注册登录邮箱&#xff0c;那么就跟着小编一起来看看如何操作吧。 操作步骤如下&#xff1a; 1、打开网易…

D3D还是GDI? Windows平台播放RTSP或RTMP渲染模式比较

先说结论&#xff0c;Windows平台播放渲染这块&#xff0c;支持D3D的前提下&#xff0c;优先D3D&#xff0c;如果检测到不支持D3D&#xff0c;数据回调上来&#xff0c;GDI模式绘制。 相比GDI模式&#xff0c;D3D绘制更细腻&#xff0c;绘制效率更高&#xff0c;CPU占用低&…

Android投屏(屏幕共享)设计需要考虑的关键因素

许多开发者&#xff0c;在做智慧教室同屏、会议同屏之类的方案时&#xff0c;基于Andriod平台的采集&#xff0c;往往遇到各种各样的问题&#xff0c;以下就几个点&#xff0c;抛砖引玉&#xff1a; 1. 内网环境下&#xff0c;组播还是RTMP&#xff1f; 回答&#xff1a;这个…