VR头显如何低延迟播放8K的RTSP|RTMP流
技术背景
我们在做Unity平台RTSP、RTMP播放器的时候,有公司提出来这样的技术需求,希望在头显播放全景的8K RTSP|RTMP直播流,8K的数据,对头显和播放器,都提出了新的要求,我们从几个方面,探讨下VR头显设备如何播放8K的RTSP|RTMP流数据:
一、播放器支持
- 兼容性:首先,RTSP|RTMP播放器需要支持8K分辨率的视频流。这意味着播放器必须能够解码8K视频,并在支持8K分辨率的显示设备上播放,这个不必多说,我们已经支持。
- 解码能力:播放器需要具备强大的解码能力,以处理8K视频流中的大量数据。这通常要求播放器使用高效的解码算法,并充分利用硬件加速功能(如GPU加速),这就需要头显支持8K的硬解码。
二、网络要求
- 带宽:8K视频流需要极高的网络带宽来支持实时传输。确保网络带宽足够大,以避免播放过程中出现卡顿、延迟或缓冲等问题,如果是内网环境下,基本不要纠结带宽问题。
- 稳定性:网络连接的稳定性也非常重要。不稳定的网络连接可能导致视频流中断或质量下降。
三、硬件要求
- 处理器与内存:VR头显播放8K的视频流,对VR头显的性能,提了很高的要求,比如说quest3,就是不错的选择。
四、播放步骤
- 选择RTSP播放器:我们的做法,是用大牛直播SDK的原生的RTSP|RTMP播放器,硬解码模式,回调解码后的YUV或RGB数据到unity,需要注意的是,由于8K的RTSP|RTMP流,数据量非常大,特别是解码后的数据,条件允许的情况下,需要尽可能少的减少拷贝。
技术实现
本文以大牛直播SDK的Android平台Unity3D RTSP|RTMP播放模块为例:

开始播放:
/** SmartPlayerAndroidMono.cs* Author: daniusdk.com* QQ:89030985*/
public void Play()
{if (is_running){Debug.Log("已经在播放。。"); return;}//获取输入框的urlstring url = input_url_.text.Trim();if (!url.StartsWith("rtmp://") && !url.StartsWith("rtsp://")){videoUrl = "rtsp://admin:daniulive12345@192.168.0.120:554/h264/ch1/main/av_stream";}else{videoUrl = url;}OpenPlayer();if ( player_handle_ == 0 )return;NT_U3D_Set_Game_Object(player_handle_, game_object_);/* ++ 播放前参数配置可加在此处 ++ */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_SetAudioVolume(player_handle_, cur_audio_volume_); //设置播放音量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_output = 1;int disable_use_image_planes = 0;bool is_supports_texture_format = SystemInfo.SupportsTextureFormat(TextureFormat.RG16);Debug.Log("is_supports_texture_format: " + is_supports_texture_format);int is_supported_multiple_format = is_supports_texture_format? 1:0;int max_images = 3;int buffer_pool_max_size = 0;NT_U3D_SetImageReaderOutput(player_handle_, is_output, disable_use_image_planes, is_supported_multiple_format, max_images, buffer_pool_max_size); //硬解码image readerint 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 is_audiotrack = 1;NT_U3D_SetAudioOutputType(player_handle_, is_audiotrack); //设置音频输出模式: if 0: 自动选择; if with 1: audiotrack模式NT_U3D_SetUrl(player_handle_, videoUrl);/* -- 播放前参数配置可加在此处 -- */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;
}
对应的OpenPlayer()实现如下:
private void OpenPlayer()
{if ( java_obj_cur_activity_ == null ){Debug.LogError("getApplicationContext is null");return;}player_handle_ = NT_U3D_Open();if (player_handle_ != 0)Debug.Log("open success");elseDebug.LogError("open fail");
}
关闭Player:
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;video_format_ = VideoFrame.FORMAT_UNKNOWN;video_width_ = 0;video_height_ = 0;
}
Update刷新数据:
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){u3d_video_frame_obj.Call("release");u3d_video_frame_obj = null;return;}if (!is_need_init_texture_){if (converted_video_frame.format_ != video_format_){is_need_init_texture_ = true;}else if (converted_video_frame.width_ != video_width_|| converted_video_frame.height_ != video_height_|| converted_video_frame.stride0_ != y_row_bytes_|| converted_video_frame.stride1_ != u_row_bytes_|| converted_video_frame.stride2_ != 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.java_frame_obj_ = null;converted_video_frame = null;u3d_video_frame_obj.Call("release");u3d_video_frame_obj = null;
}
总结
VR头显如果需要播放8K的RTSP或RTSP流,对硬件和网络的要求非常高,因此在实际应用中可能会遇到一些挑战。通过实际测试,在quest3头显,配合我们的RTSP|RTMP播放器,在unity下,可以实现毫秒级延迟的8K视频数据播放,以满足平衡操控等对实时性要求非常高的使用场景,感兴趣的开发者,可以单独跟我探讨。
相关文章:
VR头显如何低延迟播放8K的RTSP|RTMP流
技术背景 我们在做Unity平台RTSP、RTMP播放器的时候,有公司提出来这样的技术需求,希望在头显播放全景的8K RTSP|RTMP直播流,8K的数据,对头显和播放器,都提出了新的要求,我们从几个方面,探讨下V…...
2、ASPX、.NAT(环境/框架)安全
ASPX、.NAT(环境/框架)安全 源自小迪安全b站公开课 1、搭建组合: WindowsIISaspxsqlserver .NAT基于windows C开发的框架/环境 对抗Java xx.dll <> xx.jar 关键源码封装在dll文件内。 2、.NAT配置调试-信息泄露 功能点…...
在家上网IP地址是固定的吗?
在数字化时代,互联网已成为我们日常生活中不可或缺的一部分。无论是工作、学习还是娱乐,我们都离不开网络的支持。然而,当我们在家中接入互联网时,可能会产生这样一个疑问:在家上网IP地址是固定的吗?下面一…...
交换机和路由器的工作流程
1、交换机工作流程: 将接口中的电流识别为二进制,并转换成数据帧,交换机会记录学习该数据帧的源MAC地址,并将其端口关联起来记录在MAC地址表中。然后查看MAC地址表来查找目标MAC地址,会有一下一些情况: MA…...
算法笔记——LCR
一.LCR 152. 验证二叉搜索树的后序遍历序列 题目描述: 给你一个二叉搜索树的后续遍历序列,让你判断该序列是否合法。 解题思路: 根据二叉搜索树的特性,二叉树搜索的每一个结点,大于左子树,小于右子树。…...
ChatGPT对话:如何制作静态网页?
【编者按】编者在很早以前制作过静态网页,之后长期没有使用,已完全不知道最新现状了。所以,从制作工具开始询问ChatGPT,回答非常全面,完全可以解决初学者的问题。 编者虽然长期不制作网页,但一直在编程&…...
k8s(二)
五、kubernetes架构(K8S的架构也是master和node模式) 集群里至少需要有一个master节点,即就是主节点。node节点可以多个。 若是多个master节点,worker节点和master的apiserverr进行交互时,就需要通过LB(load banlance)…...
ClickHouse表引擎概述
ClickHouse表引擎概述 表引擎的功能: 数据的存储方式 数据的存储位置 是否可以使用索引 是否可以使用分区 是否支持数据副本 并发数据访问 ClickHouse在建表时必须指定表引擎。 表引擎主要分为四大类:MergeTree系列、Log系列、与其他存储/处理系…...
jenkins系列-04-jenkins参数化构建
使用maven build之前,先checkout 指定分支或标签: 拖拽调整顺序:shell执行在前,构建在后: gitee新建标签tag:...
Flutter框架时间线梳理
Flutter是一个开源的UI工具包,它用于构建高质量的原生移动应用。Flutter的版本历史如下: Flutter 0.1.2: 2018年发布,这是第一个正式发布的版本,包含了基本的框架和工具。 Flutter 1.0.0: 2019年发布&…...
RAG 效果提升的最后一步—— 微调LLM
如果说,rerank能够让RAG的效果实现百尺竿头更进一步,那么LLM微调应该是RAG效果提升的最后一步。 把召回的数据,经过粗排,重排序后,送给模型,由模型最后总结答案。LLM的确已经是RAG的最后一步了。 这里还是会…...
C语言 | Leetcode C语言题解之第230题二叉搜索树中第K小的元素
题目: 题解: /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int search_num(struct TreeNode* root, int k, int *result, int num) {if(num k 1){retu…...
YOWOv2(yowov2)动作识别+Fastreid身份识别 详细安装与实现
首先yowov2是一款简单且实时的时空动作检测方案,fastreid是行人重识别(身份识别) yowov2介绍链接直达fastreid链接直达为时空动作检测任务设计实时框架仍然是一个挑战。YOWOv2 提出了一种新颖的实时动作检测框架,利用三维骨干和二…...
【微服务】Spring Cloud中如何使用Eureka
摘要 Eureka作为Netflix开源的服务发现框架,在Spring Cloud体系中扮演着至关重要的角色。本文详细介绍了Eureka的基本概念、工作原理以及如何在Spring Cloud中集成和使用Eureka进行服务发现和管理。通过深入分析Eureka的注册与发现机制、区域感知和自我保护等高级特…...
【Neo4j】实战 (数据库技术丛书)学习笔记
Neo4j实战 (数据库技术丛书) 第1章演示了应用Neo4j作为图形数据库对改进性能和扩展性的可能性, 也讨论了对图形建模的数据如何正好适应于Neo4j数据模型,现在到了该动 手实践的时间了。第一章 概述 Neo4j将数据作为顶点和边存储(或者用Neo4j术语,节点和关系存 储)。用户被定…...
【Perl】Perl 语言入门
1. Perl语言介绍 Perl 是一种高级、解释型、动态编程语言,由Larry Wall在1987年发布。Perl 以其强大的文本处理能力而闻名,特别是在处理报告生成、文件转换、系统管理任务等方面。它吸收了C、Shell脚本语言、AWK、sed等语言的特性,并加入了大…...
godis源码分析——database存储核心1
前言 redis的核心是数据的快速存储,下面就来分析一下godis的底层存储是如何实现,先分析单机服务。 此文采用抓大放小原则,先大的流程方向,再抓细节。 流程图 源码分析 现在以客户端连接,并发起set key val命令为例…...
【UE5.1】Chaos物理系统基础——06 子弹破坏石块
前言 在前面我们已经完成了场系统的制作(【UE5.1】Chaos物理系统基础——02 场系统的应用_ue5)以及子弹的制作(【UE5.1 角色练习】16-枪械射击——瞄准),现在我们准备实现的效果是,角色发射子弹来破坏石柱。…...
Django是干什么的?好用么?
Django是一个开源的Python Web框架,用于快速开发高质量的Web应用程序。它提供了许多功能和工具,以简化常见的Web开发任务,如路由、请求处理、数据库管理等。 Django的优点包括: 简单易用:Django提供了清晰的文档和丰…...
C语言实现数据结构B树
B树(B-Tree)是一种自平衡的树数据结构,它维护着数据的有序性,并允许搜索、顺序访问、插入、删除等操作都在对数时间内完成。B树广泛用于数据库和操作系统的文件系统中。 B树的基本特性 根节点:根节点至少有两个子节点…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
