科技 > 人工智能 > VR/AR虚拟现实

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

72人参与 2024-08-01 VR/AR虚拟现实

技术背景

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

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

元宇宙与AI能否相辅相成,打造一个全新的世界观

08-01

UE5VR一体机开发问题及解决方案

08-01

3D技术与企业级VR 新体验来了

08-01

Unity导入大朋VR SDK后打包APK报错

08-01

虚拟现实与增强现实:如何改变我们与技术的互动

08-01

2 常见术语定义和坐标系统-VR光学测量手册

08-01

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论