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播放模块为例:

开始播放:

cs 复制代码
/*
 * 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()实现如下:

cs 复制代码
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:

cs 复制代码
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刷新数据:

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

相关推荐
拉拉尼亚2 天前
WebRTC 完全指南:原理、教程与应用场景
前端·typescript·实时音视频
音视频牛哥3 天前
鸿蒙 NEXT 行业视频方案选型:消费级播放器、自研、SmartMediaKit,哪条路走得通?
华为·harmonyos·大牛直播sdk·鸿蒙rtsp播放器·鸿蒙next rtsp播放器·鸿蒙next rtmp播放器·鸿蒙 rtmp播放器
音视频牛哥4 天前
国产化浪潮下,鸿蒙NEXT低延迟RTSP|RTMP直播播放器的破局之路
harmonyos·大牛直播sdk·鸿蒙rtmp播放器·鸿蒙rtsp播放器·鸿蒙next rtsp播放器·鸿蒙next rtmp播放器·纯血鸿蒙rtsp播放器
王家视频教程图书馆5 天前
另外还有一个小问题,就是两个部手机进行测试的时候,进行外部 RTC 通话的时候。我使用 QQ 音乐播放背景音乐,但是背景音乐没有加上。有冲突
实时音视频
海水冷却9 天前
2026年实时音视频服务计费模式指南
实时音视频
番茄灭世神11 天前
PN学堂GD32教程第8篇——RTC
实时音视频
runner365.git11 天前
RTC实现VoiceAgent(二)
大模型·webrtc·实时音视频·voiceagent
xuxie9911 天前
N18 RTC
单片机·嵌入式硬件·实时音视频
runner365.git12 天前
RTC会议实时翻译系统
实时音视频
runner365.git12 天前
如何使用RTCPilot配置一个集群RTC服务
webrtc·实时音视频·音视频开发