Windows平台Unity3d下如何同时播放多路RTSP或RTMP流

2023-10-26

好多开发者在做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;

        //设置播放URL
        NTSmartPlayerSDK.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 time

        int 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数据能力,回上来后,再上层直接刷新显示即可,是不是没有你想的那么复杂?

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Windows平台Unity3d下如何同时播放多路RTSP或RTMP流 的相关文章

  • OBS推流工具介绍及桌面录屏推流功能实现

    OBS推流工具介绍及桌面录屏推流功能实现 文章目录 OBS推流工具介绍及桌面录屏推流功能实现 1 OBS工具介绍 2 OBS工具安装及简单使用 2 1 安装步骤 2 2 简单使用介绍 3 OBS实现桌面录屏推流工具实现 4 总结 流媒体开发
  • 国网B接口资源上报(Push_Resourse)接口描述和消息示例

    上篇blog 梳理了国网B接口的REGISTER接口描述和消息示例 前端系统加电启动并初次注册成功后 向平台上报前端系统的设备资源信息 包括 视频服务器 DVR DVS 摄像机 告警设备 环境量采集设备等模拟或数字信号采集设备信息 前端系统
  • 海康rtsp抓包分析

    海康h264 rtp rtsp rtcp包分析 1 DESCRIBE rtsp 192 168 0 186 554 mpeg4 ch01 main av stream RTSP 1 0 CSeq 0 Accept application s
  • H.264(H264)视频文件的制作

    一 准备工作 1 下载并安装优酷客户端 2 下载ffmpeg可执行文件 解压可用 不需要下载源码自己编译 ffmpeg可执行文件下载链接 http download csdn net detail caoshangpa 9492758 二
  • wireshark提取视频数据之RTP包中提取H264和H265

    wireshark提取视频数据之RTP包中提取H264和H265 文章目录 wireshark提取视频数据之RTP包中提取H264和H265 1 背景 2 提取前工作 3 H264视频从RTP包中提取步骤 4 H265视频从RTP包中提取步
  • H264 NALU 使用PS封装 RTP发送

    最近由于项目平台需求 要将H264 NALU封装为PS再用RTP发送 PS封装按照ISO DEC 13818 1标准 一个PS包包含PS Header PES Header PS system header PS system map等 针
  • GB28181-2022注册注销基本要求、注册重定向解读和技术实现

    规范解读 GB28181 2022注册 注销基本要求相对GB28181 2016版本 做了一定的调整 新调整的部分如下 更改了注册和注销基本要求 见 9 1 1 2016 年版的 9 1 1 1 增加对NAT模式网络传输要求 宜增加TCP传
  • 如何快速实现Android平台前端设备接入能力

    技术背景 SIP 会话初始化协议 是在 IP网络上进行多媒体通信的应用层控制协议 以几种RFC的形式提供 其中最重要的是包含核心协议规范的RFC3261 该协议用于创建 修改和终止与一个或多个参与者的会话 通过会话 我们了解了一组进行通信的
  • Android平台GB28181设备接入端如何实时更新经纬度实现国标平台侧电子地图位置标注

    技术背景 我们在做GB28181设备接入端的时候 其中有个功能 不难但非常重要 那就是GB28181实时位置的订阅 mobileposition subscribe 和上报 notify 特别是执法记录仪 智能安全帽 车载终端等场景下 现场
  • GB28181媒体保活机制探究与实现

    规范解读 GB28181 2016和GB28181 2022关于媒体保活机制这块 并无调整 平台 设备媒体流保活机制规定如下 a 链路建立后 码流经过的各级平台应具备媒体流丢失监测能力 若监测到媒体流丢失 应释放该条媒体链路 并通过会话内B
  • RTP和RTCP详解

    1 RTP和RTCP详解 文章目录 1 RTP和RTCP详解 1 1 概述 1 2 RTP协议详解 1 3 RTCP协议详解 1 1 概述 在流媒体相关的领域 我们进场会看到RTP RTCP 其用于流式传输的最常见的码流传输协议 位于传输层
  • 视频中的I帧、B帧、P帧

    视频文件都是一帧一帧存储的 为了使文件的大小减小 通常会对文件进行压缩 mpeg4 MP4 文件中的每一帧开始都是固定的 00 00 01 b6 那么在接下来的每一帧分别是什么帧呢 I帧 B帧 P帧 一般在这固定帧的后面2bit就是标志是什
  • [轻量级RTSP服务]Linux

    背景 随着国产操作系统的推进 传统行业对Linux平台的呼声和需求越来越大 之前几年 我们发布了Linux平台运营商级的RTSP转RTMP推送模块 RTMP推送模块和RTSP RTMP播放模块 前段时间 有开发者问我们 是不是可以在Linu
  • Andorid平台GB28181设备接入端如何生成黑帧并推送至国标平台

    我们在做Android平台GB28181设备接入模块的时候 遇到这样的需求 做移动对讲的时候 是不需要视频数据的 但是国标平台侧 没有视频的话 大多平台又无法播纯音频打包的数据 网页端大多基于http flv或webrtc实现 基于此 我们
  • 使用nginx做为http-flv服务如何解决跨域问题

    什么是跨域 跨域是指浏览器的同源策略限制 这个策略会阻止一个域的javascript脚本和另外一个域的内容进行交互 如果一个请求url的协议 域名 端口三者之间任意一个与当前页面的url不同即为跨域 如下图所示即为跨域时的报错 使用ngin
  • RTP时间戳概念

    RTP协议不依赖于底层协议 由于UDP包的快速 时实性高的特点 它通常和UDP结合在一起 作为UDP的上层载体数据的形式传播 typedef struct rtp header t uint32 t v 2 protocol version
  • Android平台一对一音视频通话方案对比:WebRTC VS RTMP VS RTSP

    一对一音视频通话使用场景 一对一音视频通话都需要稳定 清晰和流畅 以确保良好的用户体验 常用的使用场景如下 社交应用 社交应用是一种常见的使用场景 用户可以通过音视频通话进行面对面的交流 在线教育 老师和学生可以通过音视频通话功能进行实时互
  • live555 流媒体开源库

    live555对每一个从事过流媒体开发的从业者而言 都不曾陌生 就像每一个从事音视频行业的从业者而言 ffmpeg也不曾陌生 随着行业需求的发展 live555也是越见强大 因前几天帮朋友项目查找问题 重拾live555 没想到时隔10年
  • 最新VLC命令行参数大全(一)

    用法 vlc 选项 流 您可以在命令行中指定多个流 它们将被加入播放列表队列 指定的首个项目将被首先播放 选项风格 选项 用于设置程序执行期间的全局选项 选项 单字母版本的全局 选项 选项 仅对此选项之前的单条流生效 且优先级高于先前的设置
  • Android平台GB28181设备接入侧(编码前

    在之前 我有写过Android平台GB28181设备接入模块的好多blog 包括参数设置 功能支持与扩展等 以数据接入为例 支持的数据类型涉及编码前 编码后或直接流数据 RTSP或RTMP流 可用于如智能监控 智慧零售 智慧教育 远程办公

随机推荐

  • rust nom 实现一个简单的sql解析器

    rust nom 实现一个简单的sql解析器 祝福 前言 分析 字段 表 查询语句 编码 关键字 字符规则 alias 字段 常规格式的字段处理 字符串格式字段处理 子查询处理 字段处理汇总 表 整个查询语句 结尾 祝福 过年期间 新型冠状
  • socket error总结

    Socket error 0 Directly send error Socket error 10004 Interrupted function call Socket error 10013 Permission denied Soc
  • nfs 成功挂载后,写入时出现permission denied的解决

    nfs服务器端 etc exports文件中已指定 rw 可读可写 在客户端也能正常挂载 可在向挂载目录里写入内容提示 permission denied 后来才搞清楚 nfs在服务器端导出的目录 也有一定权限要求 当把服务端导出目录 修改
  • T88合并两个有序数组

    题目 合并两个有序数组 给你两个有序整数数组 nums1 和 nums2 请你将 nums2 合并到 nums1 中 使 nums1 成为一个有序数组 初始化 nums1 和 nums2 的元素数量分别为 m 和 n 你可以假设 nums1
  • DropDownList控件的数据绑定

    DropDownList控件如何进行数据绑定 简单方法 在单击控件的向右箭头 在 编辑项 里面进行编辑添加 如下图所示 在前台代码中添加 方法一 在页面初始化时候将集合绑定到DropDownList 人工绑定 public void Pag
  • 致 Python 初学者

    文章目录 1 前言 2 明确学习目标 不急于求成 不好高骛远 3 在开始学习 Python 之前 你需要做一些准备 2 1 Python 的各种发行版 2 2 安装 Python 2 3 选择一款趁手的开发工具 3 习惯使用IDLE 这是学
  • 未来城市规划

    未来城市规划 题目描述 n n n 个节点的树 m m m 次操作 每个边都有初始边权 c
  • Kubernetes将会在1.24版本中弃用dockershim

    点击上方 分布式实验室 关注公众号 回复 1 抽取技术书 Kubernetes 计划在即将发布的 1 24 版本里弃用并移除 dockershim 使用 Docker 引擎作为其 Kubernetes 集群的容器运行时的工作流或系统需要在升
  • MFC的静态库.lib、动态库.dll(包含引入库.lib)以及Unicode库示例

    以vs2012为标准 转自 http technet microsoft com zh cn library w4zd66ye 有改动 一 MFC的静态库 lib MFC静态库使用下列命名约定 uAFXcWd LIB 库命名约定的说明符如下
  • VOSviewer 操作指南 简明

    VOSviewer 操作指南 Vosviewer 软件是一种知识图谱可视化软件 并且可以使用基本的分类聚类方法 帮助我们得到进一步的信息 下载地址 https www vosviewer com download 解压完成后 你得到因该是一
  • 27 个为什么,帮助你更好的理解Python

    选自 Python官方文档 https docs python org zh cn 3 7 faq design html
  • pytorch报错:RuntimeError: CUDA error: device-side assert triggered究极解决方案

    原因 模型的数据处理出了问题 一般是类似于数组访问越界的问题 1 例如分类的标签是数据处理的时候是1 10 但是torch在计算交叉熵是默认是0 9 2 embedding模块的词表长度问题 比如embedding中词表总长度是100 但是
  • Unix时间与Win32 FileTime时间

    Unix 时间 1970 01 01 00 00 00 与 Win32 FileTime 时间 1601 01 01 00 00 00 两者相差毫秒数为 11644473600000L Win32 FileTime 采用 100ns 为单位
  • Postgres安装

    准备工作 1 查看自己的电脑是多少位 cmd界面中输入 systeminfo 按回车 主要是看一下系统类型 系统类型 64 位操作系统 基于 x64 的处理器 版本 Windows 10 专业版 版本号 20H2 安装日期 2021 10
  • 【IDEA】idea 调试技巧 查看字段 什么时候修改的

    文章目录 1 概述 1 概述 如果你阅读源码 你一定会有个困扰 类中的某个字段的值到底是在哪里改变的 你要一点点追踪调用栈 逐步排查 稍不留神 就可能有遗漏 我们可以在 IntelliJ IDEA 中为某个字段添加断点 当字段值有修改时 自
  • es--基础--06--es集群

    es 基础 06 es集群 1 集群概念 概念看es入门学习3 理论 2 集群的搭建 利用原有的单机 elasticsearch 5 6 8 来搭建 搭建三台es服务器 分别提供的端口是9201 9202 9203 2 1 停止elasti
  • 特征选择策略:为检测乳腺癌生物标志物寻找新出口

    内容一览 microRNA 小分子核糖核酸 是一类短小的单链非编码 RNA 转录体 这些分子在多种恶性肿瘤中呈现失控性生长 因此近年来被诸多研究确定为确诊癌症的可靠的生物标志物 biomarker 在多种病理分析中 差异表达分析 Diffe
  • 解决Dropbox国内无法实时更新的问题

    Dropbox软件需要在全局模式下才能时时同步 但全局模式下无法打开某些国内网站 所以需要解决该问题 解决方法 通过设置代理的方式让Dropbox软件自动同步 但在尝试中 设置为socks5代理发现不能使用 改为http代理 马上生效 打开
  • 十分钟带你走进Hive世界(每走一步都是为了离你更近些)

    该文章已更新到语雀中 后台回复 语雀 可获取进击吧大数据整个职业生涯持续更新的所有资料 该文基于Hive专题 从SQL聊Hive底层执行原理进一步的深入学习Hive 相信大多数童鞋对于Hive底层的执行流程只是局限于理论层面 那么本篇将带大
  • Windows平台Unity3d下如何同时播放多路RTSP或RTMP流

    好多开发者在做AR VR或者教育类产品时 苦于如何在windows平台构建一个稳定且低延迟的RTSP或者RTMP播放器 如果基于Unity3d完全重新开发一个播放器 代价大 而且周期长 不适合快速出产品 我们认为当前最好的方式就是集成现有N