Windows平台Unity3d下如何同时播放多路RTSP或RTMP流
好多开发者在做AR、VR或者教育类产品时,苦于如何在windows平台构建一个稳定且低延迟的RTSP或者RTMP播放器,如果基于Unity3d完全重新开发一个播放器,代价大、而且周期长,不适合快速出产品,我们认为当前最好的方式就是集成现有Native平台上成熟稳定播放器,回调rgb/yuv数据到上层,上层做绘制即可。
废话不多说,以Windows平台多路播放为例:
1.Native播放器SDK支持吐RGB/YUV420/NV12等其中的一种未压缩的图像格式
比如Windows平台,我们回调YUV上来(NT_SP_E_VIDEO_FRAME_FROMAT_I420),本文以调用大牛直播SDK(Github)的Windows平台RTSP、RTMP播放器SDK为例,具体代码如下:
public void Play(int sel){if (videoctrl[sel].is_running){Debug.Log("已经在播放..");return;}lock (videoctrl[sel].frame_lock_){videoctrl[sel].cur_video_frame_ = null;}OpenPlayer(sel);if (videoctrl[sel].player_handle_ == IntPtr.Zero)return;//设置播放URLNTSmartPlayerSDK.NT_SP_SetURL(videoctrl[sel].player_handle_, videoctrl[sel].videoUrl);/* ++ 播放前参数配置可加在此处 ++ */int play_buffer_time_ = 100;NTSmartPlayerSDK.NT_SP_SetBuffer(videoctrl[sel].player_handle_, play_buffer_time_); //设置buffer timeint is_using_tcp = 0; //TCP模式NTSmartPlayerSDK.NT_SP_SetRTSPTcpMode(videoctrl[sel].player_handle_, is_using_tcp);int timeout = 10;NTSmartPlayerSDK.NT_SP_SetRtspTimeout(videoctrl[sel].player_handle_, timeout);int is_auto_switch_tcp_udp = 1;NTSmartPlayerSDK.NT_SP_SetRtspAutoSwitchTcpUdp(videoctrl[sel].player_handle_, is_auto_switch_tcp_udp);Boolean is_mute_ = false;NTSmartPlayerSDK.NT_SP_SetMute(videoctrl[sel].player_handle_, is_mute_ ? 1 : 0); //是否启动播放的时候静音int is_fast_startup = 1;NTSmartPlayerSDK.NT_SP_SetFastStartup(videoctrl[sel].player_handle_, is_fast_startup); //设置快速启动模式Boolean is_low_latency_ = false;NTSmartPlayerSDK.NT_SP_SetLowLatencyMode(videoctrl[sel].player_handle_, is_low_latency_ ? 1 : 0); //设置是否启用低延迟模式//设置旋转角度(设置0, 90, 180, 270度有效,其他值无效)int rotate_degrees = 0;NTSmartPlayerSDK.NT_SP_SetRotation(videoctrl[sel].player_handle_, rotate_degrees);int volume = 100;NTSmartPlayerSDK.NT_SP_SetAudioVolume(videoctrl[sel].player_handle_, volume); //设置播放音量, 范围是[0, 100], 0是静音,100是最大音量, 默认是100// 设置上传下载报速度int is_report = 0;int report_interval = 1;NTSmartPlayerSDK.NT_SP_SetReportDownloadSpeed(videoctrl[sel].player_handle_, is_report, report_interval);/* -- 播放前参数配置可加在此处 -- *///video frame callback (YUV/RGB)videoctrl[sel].video_frame_call_back_ = new SP_SDKVideoFrameCallBack(NT_SP_SetVideoFrameCallBack);NTSmartPlayerSDK.NT_SP_SetVideoFrameCallBack(videoctrl[sel].player_handle_, (Int32)NT.NTSmartPlayerDefine.NT_SP_E_VIDEO_FRAME_FORMAT.NT_SP_E_VIDEO_FRAME_FROMAT_I420, window_handle_, videoctrl[sel].video_frame_call_back_);UInt32 flag = NTSmartPlayerSDK.NT_SP_StartPlay(videoctrl[sel].player_handle_);if (flag == DANIULIVE_RETURN_OK){videoctrl[sel].is_need_get_frame_ = true;Debug.Log("播放成功");}else{videoctrl[sel].is_need_get_frame_ = false;Debug.LogError("播放失败");}videoctrl[sel].is_running = true;}
2. 处理回调上来的数据
private void SDKVideoFrameCallBack(UInt32 status, IntPtr frame, int sel){//这里拿到回调frame,进行相关操作NT_SP_VideoFrame video_frame = (NT_SP_VideoFrame)Marshal.PtrToStructure(frame, typeof(NT_SP_VideoFrame));VideoFrame u3d_frame = new VideoFrame();u3d_frame.width_ = video_frame.width_;u3d_frame.height_ = video_frame.height_;u3d_frame.timestamp_ = (UInt64)video_frame.timestamp_;int d_y_stride = video_frame.width_;int d_u_stride = (video_frame.width_ + 1) / 2;int d_v_stride = d_u_stride;int d_y_size = d_y_stride * video_frame.height_;int d_u_size = d_u_stride * ((video_frame.height_ + 1) / 2);int d_v_size = d_u_size;int u_v_height = ((u3d_frame.height_ + 1) / 2);u3d_frame.y_stride_ = d_y_stride;u3d_frame.u_stride_ = d_u_stride;u3d_frame.v_stride_ = d_v_stride;u3d_frame.y_data_ = new byte[d_y_size];u3d_frame.u_data_ = new byte[d_u_size];u3d_frame.v_data_ = new byte[d_v_size];CopyFramePlane(u3d_frame.y_data_, d_y_stride,video_frame.plane0_, video_frame.stride0_, u3d_frame.height_);CopyFramePlane(u3d_frame.u_data_, d_u_stride,video_frame.plane1_, video_frame.stride1_, u_v_height);CopyFramePlane(u3d_frame.v_data_, d_v_stride,video_frame.plane2_, video_frame.stride2_, u_v_height);lock (videoctrl[sel].frame_lock_ ){videoctrl[sel].cur_video_frame_ = u3d_frame;//Debug.LogError("sel: " + sel + " w:" + u3d_frame.width_ + "h:" + u3d_frame.height_);}}
3.Unity3D创建相应的RGB/YUV420等Shader,获取图像数据来填充纹理即可
private void UpdateYUVTexture(VideoFrame video_frame, int sel){if (video_frame.y_data_ == null || video_frame.u_data_ == null || video_frame.v_data_ == null){Debug.Log("video frame with null..");return;}if (videoctrl[sel].yTexture_ != null){videoctrl[sel].yTexture_.LoadRawTextureData(video_frame.y_data_);videoctrl[sel].yTexture_.Apply();}if (videoctrl[sel].uTexture_ != null){videoctrl[sel].uTexture_.LoadRawTextureData(video_frame.u_data_);videoctrl[sel].uTexture_.Apply();}if (videoctrl[sel].vTexture_ != null){videoctrl[sel].vTexture_.LoadRawTextureData(video_frame.v_data_);videoctrl[sel].vTexture_.Apply();}}
4. 具体播放效果如下
总结
Unity3d下,做多路播放的话,首先确保调用的拉流解码数据的模块具备回调yuv/rgb数据能力,回上来后,再上层直接刷新显示即可,是不是没有你想的那么复杂?
Windows平台Unity3d下如何同时播放多路RTSP或RTMP流相关推荐
- 猿大师播放器在Chrome播放多路RTSP视频流时,总是有几路播放不出来是怎么回事?
问:我们在我们自己的开发环境测试猿大师播放器同时播放多路RTSP视频流一直都是正常的,但是换到正式环境中,总有几路视频流播放不出来,这是怎么回事? 答:作为一款专业的RTSP视频流网页直接播放程序, ...
- Unity3D下Linux平台播放RTSP或RTMP流
背景 尽管Windows平台有诸多优势,Linux平台的发展还是势不可挡,特别实在传统行业,然而Linux生态构建,总是差点意思,特别是有些常用的组件,本文基于已有的Linux平台RTSP.RTMP播 ...
- IE浏览器下如何低延迟播放RTSP或RTMP流
首先,虽然本文是介绍IE浏览器下OCX控件播放RTSP或RTMP,但这种方式并不推荐,毕竟它只能用于IE浏览器环境下,局限太大,而且随着微软IE浏览器的更新,不确定后续支持情况.当然,话说回来,如果是 ...
- Windows上ffmpeg使用GPU硬件加速多路rtsp转HLS直播流
项目需要接入20多路rtsp转hls视频流,机器的CPU为i9-10900,显卡为P2200. CPU转码 最开始测试使用脚本: start ./ffmpeg -i rtsp://<账号> ...
- 如何在IE浏览器播放RTSP或RTMP流
好多开发者一直苦恼于如何在IE浏览器环境下,构建低延迟的RTSP或RTMP播放,对于RTSP流来说,好多公司通常的做法是把RTSP转RTMP,然后分发到RTMP服务器,然后服务器转http-flv出来 ...
- Android平台实现Unity3D下RTMP推送
像Unity3D下的RTMP或RTSP播放器一样,好多开发者苦于在Unity环境下,如何高效率低延迟的把数据采集并编码实时推送到流媒体服务器,实现Unity场景下的低延迟推拉流方案. 关于屏幕采集,有 ...
- 海康4200平台与国标GB28181视频平台EasyGBS级联后不能播放的排查及解决方法
国标视频云服务EasyGBS支持设备/平台通过国标GB28181协议注册接入,并能实现视频的实时监控直播.录像.检索与回看.语音对讲.云存储.告警.平台级联等功能.平台部署简单.可拓展性强,支持将接入 ...
- 拉取数据_如何拉取公网RTSP/RTMP流在内网多客户端播放
好多情况下,一路RTSP或RTMP网络流过来后,想共享给更多局域网内的客户端播放,一般来说,有两种设计方案: 1. 拉取的RTSP或RTMP流,回调后的数据,转推RTMP服务器,内网部署一台RTMP服 ...
- 如何拉取公网RTSP/RTMP流在内网多客户端播放
好多情况下,一路RTSP或RTMP网络流过来后,想共享给更多局域网内的客户端播放,一般来说,有两种设计方案: 1. 拉取的RTSP或RTMP流,回调后的数据,转推RTMP服务器,内网部署一台RTMP服 ...
最新文章
- JAVA坏境变量中的JAVA_HOME path classpath 的设置与作用。
- ML.NET 0.2版增加了集群和新示例
- Pixhawk(PX4)之驱动详解篇(0)_前期准备(招贤令)
- HTML和css重要的知识点,html 和 css 基础知识点(一)(示例代码)
- 2135亿!2018 双11阿里数据库技术战报新鲜出炉
- Java 异常种类及处理方法
- POJ 1163 The Triangle
- Android中SQLiteOpenHelper类的onUpgrade方法浅谈
- [转]加载纹理与使用glGenTextures时应注意的一点(解决吃内存)
- Java8刚刚普及,Java12即将发布,程序员吐槽学不动求慢一点
- 单片机编程用什么软件?单片机开发软件有哪些?
- pentaho mysql_pentaho移植到MySQL
- IPD的主要难点在I即集成,这需要在别人身上穿洞
- 1146 mysql_MySQL错误处理--1146错误
- 无业务不技术:那些誓用区块链重塑的行业,发展怎么样了?
- 小巧的本地缓存Jodd
- 微信小程序转盘demo
- Ubuntu系统环境中C语言开发配置备忘笔记
- 几张大数据可视化大屏界面设计
- 自动化、智能、机器人-2023-
热门文章
- 虚拟机安装spark配置推荐
- 郁金香汇编代码注入怎么写看雪_世界黑客编程大赛冠军的汇编代码 你见过吗?...
- mac活动监视器_什么是活动监视器?
- c程序预处理器的设计与实现_C预处理器-能力问题与解答
- 功能区不显示工具条_【新老客户必知】软件支持超高清屏显示器了
- java如何实现乌龟爬行_请教:一只乌龟的运动
- 数组重复次数最多的元素递归_在不使用递归的情况下计算链接列表中元素的出现次数...
- ruby 覆盖率测试_Ruby方法覆盖
- python 生成对称矩阵_对称矩阵| 使用Python的线性代数
- 卡诺模板_无关条件的卡诺地图