来源:映维网 作者 黄颜
为了最大程度地优化沉浸式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://yivian.com/news/67859.html