好多开发者在做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流相关推荐

  1. 猿大师播放器在Chrome播放多路RTSP视频流时,总是有几路播放不出来是怎么回事?

    问:我们在我们自己的开发环境测试猿大师播放器同时播放多路RTSP视频流一直都是正常的,但是换到正式环境中,总有几路视频流播放不出来,这是怎么回事?  答:作为一款专业的RTSP视频流网页直接播放程序, ...

  2. Unity3D下Linux平台播放RTSP或RTMP流

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

  3. IE浏览器下如何低延迟播放RTSP或RTMP流

    首先,虽然本文是介绍IE浏览器下OCX控件播放RTSP或RTMP,但这种方式并不推荐,毕竟它只能用于IE浏览器环境下,局限太大,而且随着微软IE浏览器的更新,不确定后续支持情况.当然,话说回来,如果是 ...

  4. Windows上ffmpeg使用GPU硬件加速多路rtsp转HLS直播流

    项目需要接入20多路rtsp转hls视频流,机器的CPU为i9-10900,显卡为P2200. CPU转码 最开始测试使用脚本: start ./ffmpeg -i rtsp://<账号> ...

  5. 如何在IE浏览器播放RTSP或RTMP流

    好多开发者一直苦恼于如何在IE浏览器环境下,构建低延迟的RTSP或RTMP播放,对于RTSP流来说,好多公司通常的做法是把RTSP转RTMP,然后分发到RTMP服务器,然后服务器转http-flv出来 ...

  6. Android平台实现Unity3D下RTMP推送

    像Unity3D下的RTMP或RTSP播放器一样,好多开发者苦于在Unity环境下,如何高效率低延迟的把数据采集并编码实时推送到流媒体服务器,实现Unity场景下的低延迟推拉流方案. 关于屏幕采集,有 ...

  7. 海康4200平台与国标GB28181视频平台EasyGBS级联后不能播放的排查及解决方法

    国标视频云服务EasyGBS支持设备/平台通过国标GB28181协议注册接入,并能实现视频的实时监控直播.录像.检索与回看.语音对讲.云存储.告警.平台级联等功能.平台部署简单.可拓展性强,支持将接入 ...

  8. 拉取数据_如何拉取公网RTSP/RTMP流在内网多客户端播放

    好多情况下,一路RTSP或RTMP网络流过来后,想共享给更多局域网内的客户端播放,一般来说,有两种设计方案: 1. 拉取的RTSP或RTMP流,回调后的数据,转推RTMP服务器,内网部署一台RTMP服 ...

  9. 如何拉取公网RTSP/RTMP流在内网多客户端播放

    好多情况下,一路RTSP或RTMP网络流过来后,想共享给更多局域网内的客户端播放,一般来说,有两种设计方案: 1. 拉取的RTSP或RTMP流,回调后的数据,转推RTMP服务器,内网部署一台RTMP服 ...

最新文章

  1. JAVA坏境变量中的JAVA_HOME path classpath 的设置与作用。
  2. ML.NET 0.2版增加了集群和新示例
  3. Pixhawk(PX4)之驱动详解篇(0)_前期准备(招贤令)
  4. HTML和css重要的知识点,html 和 css 基础知识点(一)(示例代码)
  5. 2135亿!2018 双11阿里数据库技术战报新鲜出炉
  6. Java 异常种类及处理方法
  7. POJ 1163 The Triangle
  8. Android中SQLiteOpenHelper类的onUpgrade方法浅谈
  9. [转]加载纹理与使用glGenTextures时应注意的一点(解决吃内存)
  10. Java8刚刚普及,Java12即将发布,程序员吐槽学不动求慢一点
  11. 单片机编程用什么软件?单片机开发软件有哪些?
  12. pentaho mysql_pentaho移植到MySQL
  13. IPD的主要难点在I即集成,这需要在别人身上穿洞
  14. 1146 mysql_MySQL错误处理--1146错误
  15. 无业务不技术:那些誓用区块链重塑的行业,发展怎么样了?
  16. 小巧的本地缓存Jodd
  17. 微信小程序转盘demo
  18. Ubuntu系统环境中C语言开发配置备忘笔记
  19. 几张大数据可视化大屏界面设计
  20. 自动化、智能、机器人-2023-

热门文章

  1. 虚拟机安装spark配置推荐
  2. 郁金香汇编代码注入怎么写看雪_世界黑客编程大赛冠军的汇编代码 你见过吗?...
  3. mac活动监视器_什么是活动监视器?
  4. c程序预处理器的设计与实现_C预处理器-能力问题与解答
  5. 功能区不显示工具条_【新老客户必知】软件支持超高清屏显示器了
  6. java如何实现乌龟爬行_请教:一只乌龟的运动
  7. 数组重复次数最多的元素递归_在不使用递归的情况下计算链接列表中元素的出现次数...
  8. ruby 覆盖率测试_Ruby方法覆盖
  9. python 生成对称矩阵_对称矩阵| 使用Python的线性代数
  10. 卡诺模板_无关条件的卡诺地图