技术背景
VR头显需要更高的分辨率以提供更清晰的视觉体验、满足沉浸感的要求、适应透镜放大效应以及适应更广泛的可视角度,超高分辨率的优势如下:
- 提供更清晰的视觉体验:VR头显的分辨率直接决定了用户所看到的图像的清晰度。更高的分辨率意味着更多的像素数,可以呈现更细腻、更逼真的图像,从而提升用户的视觉体验,更高的分辨率可以进一步减少图像中的颗粒感和纱窗效应,让用户感受到更加真实的虚拟世界。
- 满足沉浸感的要求:VR头显的主要目的是为用户提供沉浸式的体验,使用户感觉自己完全置身于虚拟环境中。为了达到这种效果,头显需要能够呈现足够清晰、细腻的图像,以便用户能够清晰地看到虚拟环境中的各种细节。更高的分辨率可以确保用户在头部移动或转动时,依然能够保持画面的清晰度和稳定性,从而增强沉浸感。
- 适应透镜放大效应:VR头显通过透镜将小屏幕放大至用户眼前,以模拟大屏幕的效果。然而,这种放大效应会导致图像的像素密度降低,使得图像看起来相对模糊。因此,为了保持放大后的图像依然清晰,VR头显需要更高的分辨率来弥补透镜放大带来的像素密度降低问题。
- 适应更广泛的可视角度:一些VR头显设计倾向于在画质可以接受的情况下,尽量增大可视角度,以便用户能够更自然地观察虚拟环境。然而,这也会导致图像在边缘区域出现拉伸和变形。为了保持这些区域依然清晰可辨,VR头显需要更高的分辨率来确保整个画面的清晰度和稳定性。
技术实现
实际上,大牛直播SDK在2018年就发布了Unity的RTSP|RTMP的播放模块,平台陆续覆盖了Windows、Android、iOS和Linux,Unity下播放RTSP|RTMP流,原理很简单,底层原生模块,把RTSP|RTMP流拉过来,做解析解码回调YUV或RGB数据到上层,Unity环境下,做绘制即可。说来容易,难点在于,如果需要更好的解码效率、资源占用和低延迟,需要确保每个环节都做到极致,总体延迟可以达到200-400ms。
目前我们实现的功能如下:
- [支持播放协议]高稳定、超低延迟(毫秒级延迟,行业内几无效果接近的播放端)、业内首屈一指的RTMP、RTSP直播播放SDK;
- [多实例播放]支持多实例播放;
- [事件回调]支持网络状态、buffer状态等回调;
- [视频格式]支持RTMP扩展H.265,H.264;
- [音频格式]支持AAC/PCMA/PCMU/Speex;
- [H.264/H.265软解码]支持H.264/H.265软解;
- [H.264硬解码]Android/iOS支持H.264特定机型硬解;
- [H.265硬解]Android/iOS支持H.265特定机型硬解;
- [RTSP模式设置]支持RTSP TCP/UDP模式设置;
- [RTSP TCP/UDP自动切换]支持RTSP TCP、UDP模式自动切换;
- [RTSP超时设置]支持RTSP超时时间设置,单位:秒;
- [RTSP 401认证处理]支持上报RTSP 401事件,如URL携带鉴权信息,会自动处理;
- [缓冲时间设置]支持buffer time设置;
- [首屏秒开]支持首屏秒开模式;
- [低延迟模式]支持超低延迟模式设置;
- [复杂网络处理]支持断网重连等各种网络环境自动适配;
- [快速切换URL]支持播放过程中,快速切换其他URL,内容切换更快;
- [实时静音]支持播放过程中,实时静音/取消静音;
- [实时快照]支持播放过程中截取当前播放画面;
- [渲染角度]支持0°,90°,180°和270°四个视频画面渲染角度设置;
- [渲染镜像]支持水平反转、垂直反转模式设置;
- [实时下载速度更新]支持当前下载速度实时回调(支持设置回调时间间隔);
- [音视频自适应]支持播放过程中,音视频信息改变后自适应播放;
- [扩展录像功能]完美支持和录像模块组合使用。
废话不多说,上代码,先说开始播放:
/*
* SmartPlayerAndroidMono.cs
* Author: daniusdk.com
* Created on 2018/05/10.
*/
public void Play()
{
if (is_running)
{
Debug.Log("已经在播放。。");
return;
}
//获取输入框的url
string url = input_url_.text.Trim();
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");
}
ClosePlayer实现如下:
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;
}
总结
VR头显下播放超高分辨率的RTSP或RTMP,实现低延迟的播放,意义很大,比如平衡操控场景下,可以远程操控挖掘机等危险设备,提高工作效率、改善工作环境、降低安全风险、节约人力成本。在虚拟仿真、无人机操控等场景下也意义重大,感兴趣的开发者,可以单独跟我交流。