VR头显如何低延迟播放8K的RTSP|RTMP流

技术背景

我们在做Unity平台RTSP、RTMP播放器的时候,有公司提出来这样的技术需求,希望在头显播放全景的8K RTSP|RTMP直播流,8K的数据,对头显和播放器,都提出了新的要求,我们从几个方面,探讨下VR头显设备如何播放8K的RTSP|RTMP流数据:

一、播放器支持

  1. 兼容性:首先,RTSP|RTMP播放器需要支持8K分辨率的视频流。这意味着播放器必须能够解码8K视频,并在支持8K分辨率的显示设备上播放,这个不必多说,我们已经支持。
  2. 解码能力:播放器需要具备强大的解码能力,以处理8K视频流中的大量数据。这通常要求播放器使用高效的解码算法,并充分利用硬件加速功能(如GPU加速),这就需要头显支持8K的硬解码。

二、网络要求

  1. 带宽:8K视频流需要极高的网络带宽来支持实时传输。确保网络带宽足够大,以避免播放过程中出现卡顿、延迟或缓冲等问题,如果是内网环境下,基本不要纠结带宽问题。
  2. 稳定性:网络连接的稳定性也非常重要。不稳定的网络连接可能导致视频流中断或质量下降。

三、硬件要求

  1. 处理器与内存:VR头显播放8K的视频流,对VR头显的性能,提了很高的要求,比如说quest3,就是不错的选择。

四、播放步骤

  1. 选择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;
	}

	//获取输入框的url
	string 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 time

	NT_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 reader

	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 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");
	else
		Debug.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视频数据播放,以满足平衡操控等对实时性要求非常高的使用场景,感兴趣的开发者,可以单独跟我探讨。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mongo数据库迁移

前言 mongo数据库迁移的方式目前常见的有两种: 1,mongodump与mongorestore 2,mongoimport与mongoexport 二者主要区别有: 1、mongoexport 可以导出json和csv格式, mongodump导出的是bson可读性不如前者 2,…

智慧金融-数据可视化

智慧金融-数据可视化 导入所需的库 import numpy as np import numpy_financial as npf import matplotlib.pyplot as plt from pylab import mpl mpl.rcParams[font.sans-serif][FangSong] mpl.rcParams[axes.unicode_minus]False单图曲线图 r 0.05 # 贷款的年利率 n 30…

LeetCode LCR024.反转链表 经典题目 C写法

LeetCode LCR024.反转链表 经典题目C写法 第一种思路🧐: ​ 使用三个指针,n1,n2,n3,n1为空,n2为头结点,n3为头结点的next。开始反转后,n1赋值给n2的next,n2赋值给n1,n3赋…

深入理解FFmpeg--libavformat接口使用(一)

libavformat(lavf)是一个用于处理各种媒体容器格式的库。它的主要两个目的是去复用(即将媒体文件拆分为组件流)和复用的反向过程(以指定的容器格式写入提供的数据)。它还有一个I/O模块,支持多种…

推荐一个比 Jenkins 使用更简单的项目构建和部署工具

最近发现了一个比 Jenkins 使用更简单的项目构建和部署工具,完全可以满足个人以及一些小企业的需求,分享一下。 项目介绍 Jpom 是一款 Java 开发的简单轻量的低侵入式在线构建、自动部署、日常运维、项目监控软件。 日常开发中,Jpom 可以解…

[Linux]基本指令(二)

一些剩下的指令部分 mv指令(重要) mv 命令是 move 的缩写,可以用来移动文件或者将文件改名( move (rename) files ),是 Linux 系统下常用的命令, 经常用来备份文件或者目录。 语法 : mv [ 选项…

前端挑战:Tkinter布局与设计【三种布局】

前端挑战:Tkinter布局与设计【三种布局】 文章目录 前端挑战:Tkinter布局与设计【三种布局】前言Frame 窗口组件代码效果Tkinter的布局grid 网格布局效果展示:代码讲解pack 布局基本使用左右布局place 布局代码预览前言 作为一个前端开发,习惯性的用HTML去解决客户端的问题…

文学式开发工具 Jupyter Notebook

前言:Hello大家好,我是小哥谈。为什么说Jupyter Notebook是文学式开发工具?因为Jupyter Notebook将代码、说明文本、数学方程式、数据可视化图表内容全部组合到一起并显示在一个共享的文档中,可以实现一边写代码一边记录的效果&am…

地理信息科学在交通规划中的应用:GIS绘制智慧出行新蓝图

在当代城市化迅猛发展的背景下,交通规划面临着前所未有的挑战与机遇。作为地理信息与遥感领域的研究者,我深感地理信息科学(GIS)在解决这些问题时扮演着无可替代的角色。本文将深入探讨GIS如何在交通网络分析和优化中发挥核心作用…

Qt:13.多元素控件(QLinstWidget-用于显示项目列表的窗口部件、QTableWidget- 用于显示二维数据表)

目录 一、QLinstWidget-用于显示项目列表的窗口部件: 1.1QLinstWidget介绍: 1.2属性介绍: 1.3常用方法介绍: 1.4信号介绍: 1.5实例演示: 二、QTableWidget- 用于显示二维数据表: 2.1QTabl…

零信任安全新纪元:零信任沙箱的源代码保护策略

在数字世界的战场上,安全防护是每一家企业的生命线。今天,我们要介绍的是一款革命性的安全工具——SDC沙箱,它以零信任的理念为核心,为您的源代码和敏感数据筑起一道坚不可摧的防线。 什么是零信任沙箱? 零信任&…

【开发工具】webStrom2024版-永久使用

1、解压文件 2、安装步骤 先执行unistall-current-user.vbs,确保当前环境变量下没有历史使用记录。再执行install-current-user.vbs。运行的时候,会有第一个弹窗,点击确定,稍微等待一会,会出现 Done 的弹窗&#xff0…

uView、ColorUI与Vant框架的深入分析与案例实践

摘要: 随着移动开发技术的不断发展,框架的选择对于项目的成功至关重要。本文将对uView、ColorUI和Vant这三个主流移动端框架进行深入分析,探讨它们的优缺点,并通过实际案例展示如何根据项目需求选择合适的框架。 一、引言 在移动…

超声波清洗机哪家清洁力最强?家用超声波眼镜清洗机推荐

在如今快节奏的生活中,清洁工作愈发显得繁琐而耗时。家用超声波清洗机凭借其高效的一体化清洗金银首饰功能和智能化操作,为人们生活带来了极大的便利。面对众多款品牌的家用超声波机型,大家不禁会问:哪家超声波清洗机清洁力最强&a…

什么是渲染:两种渲染类型、工作原理

如果您是网页设计师或数字艺术家,您可能熟悉渲染过程的概念。这是数字艺术中的重要步骤,帮助您将图形模型转换为最终结果。在本文中,您将了解数字艺术中的渲染是什么、它的工作原理以及它的类型。 一、什么是渲染? 渲染是使用计算机软件对数…

微信小程序毕业设计-汽车维修项目管理系统项目开发实战(附源码+论文)

大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:微信小程序毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计…

后端之路——登录校验前言(Cookie\ Session\ JWT令牌)

前言:Servlet 【登录校验】这个功能技术的基础是【会话技术】,那么在讲【会话技术】的时候必然要谈到【Cookie】和【Session】这两个东西,那么在这之前必须要先讲一下一个很重要但是很多人都会忽略的一个知识点:【Servlet】 什么是…

Suricata引擎二次开发之命中规则定位

二开背景 suricata是一款高性能的开源网络入侵检测防御引擎,旨在检测、预防和应对网络中的恶意活动和攻击。suricata引擎使用多线程技术,能够快速、准确地分析网络流量并识别潜在的安全威胁,是众多IDS和IPS厂商的底层规则检测模块。 前段时间…

css实现每个小盒子占32%,超出就换行

代码 <div class"visitors"><visitor class"item" v-for"(user,index) in userArr" :key"user.id" :user"user" :index"index"></visitor></div><style lang"scss" scoped&…

openWrt(4) - uci

uci show 1) uci show - 查看所有配置文件列表 2)查看特定配置文件的详细信息&#xff1a; uci show network 我们以 network 为例 3&#xff09;查看特定配置项的详细信息&#xff1a; uci show network.wan 添加一个新的配置条目&#xff1a;uci add network interface …