Oculus CTO卡马克经验分享:如何最大程度地优化360视频体验

查看引用/信息源请点击:映维网

经验教训

映维网 2019年10月24日)为了最大程度地优化沉浸式360视频体验,Oculus首席技术官约翰·卡马克一直在测试和实验VR视频技术。日前,他通过博文介绍了自己从中积累的经验教训。下面是映维网的具体整理:

文件下载

大多数移动VR开发者最终都会把某种标准的媒体播放器来支持视频播放(如ExoPlayer)。尽管存在一系列优秀的通用播放器,但大多数都不适合60fps视频,而且把生成的表面绘制到3D世界中的标准行为会丢失大量的质量。

这是我多年来所做的实验的集合,其演示了用于管理视频解码管道和在VR中实现最佳质量显示的底层技术。关键的技术是:

在合成器层显示视频表面,不要将其绘制到3D世界中。

根据视频内容选择正确的VR刷新率:60fps或72fps。

将解码帧复制到深层交换链,不要直接使用Surface来减轻小故障。

使用多个线程和条件变量来有效地管理编解码器。

使用sRGB格式的交换链和帧缓冲器进行伽玛校正过滤。

精确地将视频和音频速率锁定为显示速率。

上面所述同样适用于虚拟屏幕所显示的常规视频,以及沉浸式媒体内容。

我通常建议用5120(5k)作为360度或并排180视频的最高分辨率。Quest的绿色子像素密度更高(红色和蓝色的密度更低),所以5760十分合理,但最好将比特率用在5120。

分辨率的安全选择是:60fps时为4096×2048或30fps时为3840×3840,但在大多数情况下,你可以超出这个范围。请注意,对于Go和Quest,不同的视频编解码器有不同的限制:

尽管能够以60fps解码4096×2048,但H264无法以30fps解码4096×4096视频。这是由于限制了65535 16×16像素宏块的限制。大多数人只将3840×3840用于30fps的视频,但如果需要,你可以拉升到4096×4080。

H264的宽度或高度没有硬性限制,只要不超过宏块限制即可。这意味着你可以拥有5760×2880的视频。

H265的限制为4096宽,但没有高度限制。所以,如果要实现5120×2560的视频,则需要将其转置为2560×5120的视频,然后再转置回显示。这可能是标准播放器选择自上而下180度立体视图的原因,但我通常只是为实验而进行视频转置,而这同样适用于360度视频。

H265可以30fps的速率解码4096×4096,并且在较低帧速率下似乎有超过62k的余量。

某种程度上讲,你可以解码视频的确切帧速率取决于内容。规范仅保证60fps下的4096×2048,但H264似乎存在一定的余量,而且我们已经看到4800×2400或以下的视频依然能够流畅解码。然而,这是自找麻烦。H265似乎受限于实际规格。

上面链接的代码包括一个通用的BufferedVideo类,其可以有效地将视频解码为深度缓冲交换链,将播放与实际屏幕的刷新率(不完全是60.0或72.0 fps)同步,并对音频进行细微的重新采样以令其完全匹配所述速率。这个核心类用于沉浸式视频或常规视频的通用表示,以及少数的专用化。

裁剪视频:如果垂直裁剪到100度左右(即5120×1536),则可以以5k分辨率和60fps获得完整的180度水平视场。对于体育比赛等具有大量左右视图变化的内容,这可能是一个很好的折衷方案。

插入视频:如果你希望获得完整180×180度的视场,但想继续以中心区域作为焦点,则可以将峰值分辨率的视频覆盖在90×90度的中心区域,而其他地方则采用较低分辨率的背景。

交错视频:对于3D电影,存在对沉浸式视频特别有用的专用视频编解码器版本,但遗憾的是,我们的芯片组都不支持它们。我发现,仅交错编码3D视频而非并排,同时对x265使用-preset veryslow选项,这可以带来一系列的好处,这使它可以检查不仅只是前一帧的运动预测源。根据内容的不同,压缩效果最高可达到30%。其他编解码器和选项对交错视频的压缩具有灾难性的糟糕效果,所以适用范围有限。

标准的视频播放器无法处理交错3D帧,因为你需要同时访问两个解码后的帧,而不仅仅是最新的帧,但通过深度缓冲交换链,操作非常简单。

可以用以下命令将Ffmpeg重新编码成交错:ffmpeg -i SideBySideVideo.mp4 -c:a copy -vf stereo3d=sbsl:al -crf 18 -preset veryslow -c:v libx265 interleavedVideo.mp4。

双重视频:某些立体180度相机会产生两个带有鱼眼镜头变形的独立视频文件。对于这一点,通常会用软件工具将其转换成180度等距投影视频。直接播放两个视频文件,并在VR合成器中进行失真映射可以实现最小的质量损失。普通视频播放器无法令两个视频流保持帧同步,但两个缓冲的视频播放器实例则有可能。它同时包括一定的计算机视觉代码以对透镜进行最简单校准。对于制作用例来说,这并不是非常实际,但它是一个优秀的参考点。

我曾为Oculus Go开发了Z CAM播放器,而这是关于它的第一篇博文,而后续博文包括立体音频轨道,以及添加校准文件的功能。

最极端的代码专用化是我去年开发的基于视图的5k×5k,60fps立体视频播放器的改进版本。

原始版本中的四个同步视频流解码已证明存在问题。由于我们依然不清楚的原因,视频解码系统会降低已使用数周的头显的性能,最终导致5k播放器开始出现慢动作和音频失真。重新启动可以解决这一问题,但我们仍未发现系统级别的缓解措施。

我一直有计划以某种方式将各个strip整合到能够更有效解码的单一视频文件中,但我最终找到了一种相当简单的方法。

不是将详细的区域分成十个独立的视频文件,而是将其分成三个文件(每个文件包含四个strip),并将视频显式编码为四个h265 slice,这意味着它们位于独立的网络抽象层(Network Abstraction Layer;NAL)单元。这允许你通过简单的字节扫描寻找边界,无需对整个比特流进行解码。

在运行时,对于每个帧,通过将最初创建的十二个slice中的四个slice拼凑在一起来创建合成的视频样本。这具有单个视频解码而不是四个的效率。

我最初的计划是调整低分辨率基础视图的大小并对其进行转置,从而将其与高分辨率的slice连接成一个完整的视频解码器,但另一个取得了足够优秀结果的实验令我们改变了方向。

2048×2048基础层显然十分模糊。我认为在2880×2880基础层上花费相同数量的像素解码速率(仅以30fps而非60fps进行动画处理)可能是更好的选择。事实证明,这确实是一笔好买卖,但大小和帧速率使其不兼容高分辨率的strip,所以确实需要两个独立的视频解码。

由于基础层总是要与高分辨率层分开解码,所以不用提供strip实现快速切换所需的半秒视频GoP大小。为基础层提供更长的GoP只会影响搜索粒度,而不会影响视图适应速度,所以可以提高压缩率。

事实证明,挑战比我预期的要多,你确实需要对x265编码器进行一定的调整,但我现在有了一种变通的方法:

有必要确保所有slice视频具有完全相同的参考帧,以便可以将它们混合在一起。仅设置scenecut = 0来禁用自动iFrame插入并不足,当看起来像是节省了压缩成本时,它依然会将B帧转换为P帧。Scenecut-bias允许你为不同的编码调整比特率的比较,从而确定什么时候是场景剪辑,但它限制在0到100之间,而且为了确保不存在场景剪辑,我们希望将其设为负数。将其设置为“nan”是一个可怕的技巧,它可以令其通过参数检查,并且导致is-scenecut计算始终返回false。我认为scenecut = 0根本不应该强制提升B帧。

启用slice编码会导致压缩率的大幅降低。x265中的多线程运动估计似乎是一个问题,但现在设置-frame-threads = 1仍然是一种解决方法,并且不会严重损害编码速度。

x265编码器不仅将运动矢量搜索限制在它正在编码的slice上,所以如果你不走运,当相邻文件的一个slice混入时,它可能会引用实际上并不存在的像素,而这偶尔会造成高分辨率区域上方或下方的伪影。x265编码器源中有关于这一点的FIXME注释,并可以有效地解决这个问题,但就目前而言,我用一点点粉红色的填充和一对牢固交叉的手指来将其分开。注意,理想情况下,运动和帧内搜索范围将足够大,可以令strip的右眼部分在已解码的左眼部分中找到有用的像素。

所以,与原来的5K播放器相比,我们有了下面的优势:

1.减速没有问题。

2.解码高分辨率的4/12而非3/10,这样你在看到低分辨率之前能够再看到10%的像素。

3.《Dear Angelica》中的额外边缘和时间渐隐效果可减少细节溢出。

4.低分辨率基础是翻倍分辨率,但只需帧速率的一半。

请注意,你需要安装最新版本的ffmpeg。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20191024A04CSJ00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码关注腾讯云开发者

领取腾讯云代金券