APP下载

用于外接式HMD的全景视频播放器软件的设计与实现

2021-11-03李永亮黄滔

电子技术与软件工程 2021年16期
关键词:缓冲区全景材质

李永亮 黄滔

(中山职业技术学院艺术设计学院 广东省中山市 528400)

1 引言

虚拟现实技术所具备的沉浸感、交互性、想象性和智能性4种特征[1],使之在教育、培训和娱乐等领域具有相当高的应用价值[2],特别是在消费级头戴式显示设备(HMD,Head Mounted Displayer)以及全景摄像设备相继问世以来,虚拟现实技术进入大众生活的趋势愈加明显,其中文化娱乐是虚拟现实技术在大众生活中发挥作用的重要领域[3],而借助HMD 欣赏360 度全景视频是较为常见的一种娱乐方式。从用户体验的角度看,利用HMD 播放360 度全景视频的效果要求有较高的流畅度和清晰度,如果播放直播视频则对低延时性也有较高的要求,因此该项应用对设备的计算能力、显示能力和网络带宽都有较高的要求。

HMD 按照其系统构成形式可分为外接式、外壳式和一体式三种[4]。外接式HMD 需要与外部主机(主要是PC 机)相连接,本身不包含主要计算能力,仅包含显示系统与传感系统。而外壳式HMD 不具有显示和计算系统,仅具有光学系统,有些也具有传感系统,需要通过与智能手机等智能终端结合实现完整的功能。一体式HMD 则是将显示、传感和计算等系统集成在一起的设备。从设备的系统构成可以看出,由于外接式HMD 可以充分借助PC 机的计算能力(包括CPU 和显卡)和网络带宽,因此较为适合用于播放360 度全景视频,特别是流媒体形式的直播视频。

本文以libVLC 为基础,以三维引擎Unity 为开发工具,C#为编程语言,设计和实现了一款用于外接式HMD 的流媒体播放器软件,利用本软件用户可以沉浸式的观看以流媒体方式在网络上推送的全景视频和全景摄像机的直播画面,用户可以通过PC 端的窗口设置流媒体的地址、画面尺寸相关参数以及校正默认观看角度,并在佩戴HMD 设备后获得沉浸式的360 度全景观看效果。

2 系统设计

2.1 系统构成

本软件的系统构成如图 1所示,其中libVLC 为VideoLAN 项目组开源的VLC media player 播放器软件的内核引擎及其接口,开发者利用libVLC 可以开发任何基于VLC 架构的多媒体应用程序[5]。由于libVLC 是由C 语言开发的,为了使之能够与Unity 引擎兼容,本文设计了VLCNativeMethod 类,利用C#的DllImport 特性将libVLC 中常用的方法引入到VLCNativeMethod 类中,从而为在Unity C#脚本中使用libVLC 的功能创造了条件。而VLCUnity 模块则为一个典型的Unity C#脚本组件类,它是对VLCNativeMethod类的进一步封装,提供了创建VLC 实例对象、创建播放器对象、指定提取视频画面回调函数、播放媒体资源、设置视频画面规格、暂停播放和停止播放等功能。VLCUnityPlayer 也是一个Unity C#脚本组件类,其本质上是构造了一个在Unity 引擎中使用的播放器组件,该组件有两大主要功能,其一为实现用户的操作意图,包括设置媒体资源、播放、暂停和停止等,其二为在虚拟场景中渲染视频画面,在渲染之前还需要对视频的画面进行帧同步以保证每一帧画面的渲染顺序是正确的。FrameBuffer 类即为用于实现帧同步的视频画面数据缓冲区管理类,该类提供了实现帧同步的相关方法,包括读、写缓冲区以及设置缓冲区状态的方法。CameraRigRotate则用于在播放360 度全景视频的过程中,调整用户视角的方位角和翻滚角。而UIManager 则为人机交互接口管理组件,用于将UI 界面上的控件与VLCUnityPlayer 组件以及CameraRigRotate 组件的功能进行关联。

图1:系统构成

2.2 视频资源播放流程

本系统在VLCUnityPlayer 组件的控制下实现视频资源的播放,具体流程如图 2所示。其中,视频URL 和画面规格通过UIManager 组件从用户界面上获取。VLC 实例、播放器实例以及播放控制通过VLCUnity 组件实现。而画面的渲染则通过将画面提取回调函数中获得的视频画面数据复制到目标材质的贴图中实现,目标材质事先已经设置为虚拟场景的天空盒材质从而保证视频画面以360 度全景的形式展现。

图2:视频资源播放流程

3 关键技术

3.1 画面帧同步

由于在视频播放过程中,libVLC 模块逐帧提取视频画面的过程与Unity 引擎的画面渲染过程是相互独立的,刷新频率各不相同,因此如何在Unity 引擎中进行视频画面的帧同步从而保证视频画面在场景中有正确的渲染顺序是需要解决的一个关键技术问题。

通过libVLC 模块逐帧提取视频画面是通过VideoLockCB、VideoUnlockCB 和VideoDisplayCB 三个回调函数实现的。 当libVLC 模块将要提取新的一帧视频画面数据时VideoLockCB 函数被调用,在该函数中要创建并指定视频画面数据的缓冲区,从而保证新的视频画面帧数据被写入缓冲区中。当VideoLockCB 函数执行完毕后,libVLC 模块开始向缓冲区写入视频画面帧数据,当写入操作完成后VideoUnlockCB 函数会被调用,在该函数中可以从缓冲区中获取视频画面帧数据。随后VideoDisplayCB 函数会被调用,在该函数中可以将视频画面帧数据渲染到指定位置。在普通的应用程序中,只要设置一个视频画面帧数据缓冲区,并在VideoDisplayCB 函数中更新画面显示内容即可实现画面的播放,此时画面的更新频率取决于libVLC 模块提取视频画面的频率。然而在本系统中,视频画面的渲染由Unity 引擎控制,Unity 的画面帧率是不固定的并且其刷新过程与libVLC 模块提取视频画面的过程完全独立,因此造成了视频画面数据的获取与渲染不同步的情况。如果不进行帧同步处理,当渲染速度比获取速度快时,会导致缓存区中未写入完成的画面数据被渲染到场景中从而造成大量非正常的残缺画面;而当渲染速度比获取速度慢时,又会导致部分画面无法被渲染出来从而造成丢帧。

本系统通过VLCUnityPlayer 组件协调libVLC 模块和缓冲区管理类FrameBuffer 来解决帧同步问题。其中FrameBuffer 类采用了读、写双缓冲区队列的方法来保证每个视频画面帧的渲染顺序是正确的,原理如图 3所示。在最开始时缓冲区都在写队列中,借助队列所具有的先入先出的特点,在每次从libVLC 模块获取帧画面数据时,首先从写队列中取出一个缓冲区并由libVLC 模块将帧画面数据写入该缓冲区,然后将该缓冲区放入读队列中,而当需要渲染视频画面时则从读队列中取出最早放入队列的缓冲区,将其中的数据渲染到目标材质后再将该缓冲区放入写队列中。重复上述过程,从而在缓冲区数量足够多的情况下,能够保证视频画面的每一帧都会按照视频中原本的顺序被渲染到目标材质中。

图3:采用读写双缓冲区队列实现帧同步的原理

帧同步过程的泳道图如图 4所示,由图可知当渲染画面的速度较获取画面数据的速度慢时会造成写缓冲区耗尽,从节约内存资源的角度考虑本系统选择不扩充缓冲区的数量,而是提供一个弃帧缓冲区给libVLC用于保障运行流程顺畅但放弃该帧数据不进行渲染。通过实验,在HMD 为HTC VIVE,PC 机条件如下:CPU 为Intel Core i7,GPU 为NVIDIA GeForce GTX 1080,内存容量64 GB ,操作系统为Windows10 时,缓冲区个数设置为4 就已经能够保证长时间播放像素宽度为3008、像素高度为1504 的360 度全景视频而不出现缓冲区耗尽的情况。

图4:实现帧同步的泳道图

3.2 画面的渲染

从libVLC 获取的视频画面虽然是全景画面,但是在媒体资源中其存储形式是二维平面,为了使之在用户身处的虚拟场景中呈现360 度的沉浸式效果,需要将二维画面映射成立体球面。在Unity引擎所构造的虚拟场景中有天空盒的概念,其本质是以360 度全景的形式呈现场景背景画面的一种特殊材质,因此只要将全景画面的纹理复制到天空盒材质的渲染纹理上,即可实现二维平面到立体球面的映射。具体实现方法分为虚拟场景中天空盒材质相关的设置和运行时对天空盒材质的主贴图纹理进行更新两部分,流程示例如图5所示。

图5:视频全景图像渲染的示例流程

在虚拟场景的设置中,需要创建播放全景视频专用的材质,该材质采用的Shader 为Skybox 分类下的Panoramic。并且由于全景画面映射到天空盒的立体球面上之后画面是上下颠倒的,因此还需要将场景中的主摄像机进行180 度的翻滚,即围绕自身坐标系Z 轴正向旋转180 度。其次,在VLCUnityPlayer 组件中,根据视频画面的提取规格(包括像素宽度、像素高度、色彩编码)创建一个渲染贴图(RenderTexture)对象,并将其设置为全景视频专用材质的主贴图,同时要创建一个二维贴图(Texture2D)对象作为从缓冲区获取画面数据的中介。当播放视频时,每从缓冲区读队列获取一帧画面数据,便使用缓冲区中的数据更新二维贴图对象,再使用Unity 引擎 Graphics 类的静态方法 Blit(Texture,RenderTexture)将二维贴图上的纹理数据复制到天空盒材质的渲染贴图上,从而实现全景二维画面到立体球面画面的映射。

3.3 视角控制

在全景视频播放过程中,可能会出现视频拍摄的视角与观众视角不匹配的情况,特别是拍摄视角处于移动状态的时候,移动的方向与用户视角默认的前方(即视频开始播放时用户视角在虚拟场景中的正前方)不一致的情况下,会给用户带来不适感,甚至可能导致动晕症。此外当视频数据的来源是全景摄像机的直播推流时,如果全景摄像机的摆放不平整并且没有对画面的倾斜进行修正,则全景视频播放器中呈现的画面将会持续的倾斜,同样会给观看体验带来负面影响。

为了解决上述问题,本系统设计了CameraRigRotate 组件用于实现在播放过程中调整用户视角方位角和翻滚角的功能。通过向用户提供方位角调整的功能可以解决运动过程中拍摄视角和观看视角不匹配的问题,而通过提供翻滚角调整的功能则可以解决画面倾斜的问题。

在Unity 场景中以CameraRig 对象代表用户视角,方位角表示CameraRig 对象相对其默认姿态围绕世界坐标系Y 轴旋转的角度,而翻滚角则表示CameraRig 对象相对其默认姿态围绕自身坐标系Z轴旋转的角度。CameraRigRotate 组件具有SetRotation(float,float)和ResetRotation()两个函数,分别用于更新用户视角和恢复默认视角。其中SetRotation(float,float)的第一个形参表示方位角的值,第二个形参表示翻滚角的值,该函数被调用时用户视角的主摄像机对象将会按照参数值更新其在虚拟场景中的姿态,从而实现用户视角的调整。而当ResetRotation()函数被调用时则用户视角会恢复到默认状态。

利用Unity 事件机制,将CameraRigRotate 组件的SetRotation(float,float)函数设置为UI 界面上水平滑动条和垂直滑动条OnValueChanged 事件的回调函数,同时也设置为HMD 设备手柄用户输入事件的回调函数。对ResetRotation()函数也做类似的设置,从而保证用户可以同时使用UI 界面和手柄来调整用户视角。

4 效果展示

进入系统后,PC 端窗口全屏显示,并且其操作界面默认为隐藏状态,按下键盘上的空格键可以使操作界面在隐藏和显示状态之间切换。当操作界面隐藏时,窗口显示流媒体中用户可见部分的视频画面,当操作界面显示后的状态如图 6所示,其中steam path 输入框用于输入视频资源的URL,Width 和Height 输入框用于输入提取视频画面的像素宽度和高度,用户单击OK 按钮可以开始播放视频并隐藏界面控件,水平和垂直滑动条则用于在播放过程中调整用户视角的方位角和翻滚角,如果单击Reset 按钮则用户视角会恢复到默认状态。

图6:PC 端界面展示

视频完整的全景画面与用户在佩戴HMD 后的视角画面之间的对比如图 7所示,可以看出用户的体验是完全沉浸式的,就如同身处视频拍摄的场景当中。

图7:全景画面与玩家视角效果对比

5 总结

本文提出了一种用于外接式HMD 设备的360 度全景视频播放器软件的设计与实现方法,该软件以URL 的方式定位视频资源,既可以播放PC 机本地的视频也可以播放通过网络推流的流媒体视频,为使用外接式HMD 的用户提供了一种沉浸式观看360 度全景视频和直播的手段。本系统结合视频的拍摄设备以及直播推流技术,可以在文化娱乐和培训教育等领域提供一种基于沉浸式360 度全景视频的解决方案。

猜你喜欢

缓冲区全景材质
戴上耳机,享受全景声 JVC EXOFIELD XP-EXT1
全景敞视主义与侦探小说中的“看”
嫩江重要省界缓冲区水质单因子评价法研究
从5.1到全景声就这么简单 FOCAL SIB EVO DOLBY ATMOS
外套之材质对比战
针织衫之材质对比战
10KV配变绕组材质鉴别初探
关键链技术缓冲区的确定方法研究
地理信息系统绘图缓冲区技术设计与实现
AVS标准中的视频码流缓冲区校验模型分析