前端于我
bilibili / video / vr

Bilibili全景视频原理

最近一个同事推给我看了一个B站的全景视频。可以全景观看一个视频,也就是说用户可以使用拖拽的方式进行视角的调整。参照视频

乍看之下十分惊奇,不禁去研究了一下它的原理。研究手段也非常简单,由于之前有去研究过这些视频网站的加密方式,所以很自然的把它的js脚本搞下来。

step1

最初的设想是觉得前端没办法处理这么复杂的视频数据,所以应该会是把用户旋转的角度回传到服务器,然后服务器处理视频后再切换视频流(也就是切换清晰度的那套),但是后来觉得这个设想明显站不住脚,因为它的切换角度太流畅了,完全没有一点延迟,明显不可能经过服务端的处理。

验证一下,打开控制台简单看一下它的视频资源请求,在旋转角度的时候并没有发现有密集的视频资源请求。所以不是服务端处理的,那么就只能是前端处理的了,事情变得更有趣了一些。

step2

第二个设想是那应该就是根据用户的角度在前端进行处理了视频了。这时候同事眼睛很尖锐的发现全景视频的封面都是一张略微扭曲的截图,并且鼠标在进度条上查看缩略图时也很明显看到视频似乎本身是一帧帧的全景图片组成的。

如图

既然如此,打算把整个视频搞下来看看,由于之前有过类似的经验。所以很轻车熟路的就把视频搞下来了(因为B站为了兼容性/可切换清晰度/转流式格式等原因将视频处理成m4s的格式,并且对连接做了请求限制,所以直接用netword面板的连接是拿不到视频的)。

拿到原始视频之后看果然视频的每帧都是全景图片, 这时候就猜测是在js层面对每帧视频数据根据角度做了处理。

但是想到js的性能,似乎说不过去。最终还是继续研究一下代码里是怎么写的,但是代码越看越奇怪,似乎并没有根据角度去处理视频数据,只是记录了角度以及用一个定时器去更新视图。这时我机智的同事眼尖看到代码中出现了camera的字眼,猜测是不是绘制在了canvas上了,因为 three.js中也有camera的概念。

step3

既然有这个可能性,那就去页面找一找canvas吧。直接在console面板全局搜一下canvas,果然发现了有一个canvas。试着隐藏一下这个canvas就露出了底下被遮盖的video,而video播放的正是未处理的扭曲的全景视频。

至此所有事情关联起来事情就清晰了,全景视频的播放并不是通过video标签,video标签只是用来播放声音并控制播放进度,而实际的视频播放画面是通过webgl绘制到canvas上。而绘制方法也非常的简单,只需要将视频帧画面绘制到一个球体内部,并且将摄影机摆在球中心处,根据用户的角度旋转摄影机,就可以很简单的实现这个全景视频的效果。并且基于webgl是直接通过GPU进行运算的特点,将复杂的视频画面计算放到了GPU, 从而解放了js,而js只需要每40ms将画面重新绘制,并且根据用户操作调整摄影机角度。

end

最终的实现效果是很简单的,并没有想象中那么的复杂。其实很多表面上似乎很厉害很高大上的东西都是这样,底层的思路简单到令人发指。就酱先吧。

发表于: 2021-02-24