弹幕穿人功能,能使用户在弹幕刷屏的情况下,又不错过人物画面。因此,弹幕穿人功能一经推出就受到了广大用户的喜爱。
就技术方案而言,弹幕穿人方案可以分为以下两大类:“云端离线人体分割+端侧渲染”和“端侧实时人体分割+端侧渲染”。在这里我们分别简称为云端方案和端侧方案。
不管是云端方案还是端侧方案,高效的弹幕渲染及弹幕穿人效果的渲染都是其中不可或缺的重要组成部分。
本文主要聚焦在优酷弹幕穿人渲染相关技术介绍,包括弹幕渲染流程、弹幕穿人渲染实现及工程上的优化实践等相关方面。
一、背景
1. 弹幕穿人效果
我们先体验一下目前在优酷主客上已经上线的弹幕穿人效果。
(1) 截图:
通过截图我们可以看出,整体人物穿透的效果处理上很赞,肩膀和胳膊边缘、特别是发丝等细节处的处理都非常细腻。
(2) 录屏:
通过录屏我们可以看到,弹幕穿人的效果把整个视频画面分为了3个层次:人物在最外层,中间一层是弹幕,最里面一层是视频画面背景。这样给人一种很好的观影沉浸感,能有效提升在满屏弹幕下的观影体验。
2. 弹幕穿人方案介绍
2.1 云端弹幕穿人方案
整体流程如下云端和移动端两大部分:
2.1.1 云端
主要完成人体图像分割数据的生产和部署:算法同学提供AI算法,部署到云端服务器上,针对需要穿人效果的剧进行离线人体模板数据生产。然后将生产出来的模板数据对接到ups服务中,成为ups的一个节点。这样,端侧在播放对应视频时,同步请求ups对应节点拿到对应的模板数据资源链接,就可以做后续的下载、解码、弹幕穿人等相关的处理来完成弹幕穿人的效果了。
2.1.2 移动端
分为两块:
(1). MetaPipe:
MetaPipe是端智能算法的集大成者。对应弹幕穿人场景,MetaPipe完成模板数据的下载、解析和解码等工作,对接OPR吐出对应pts的人体分割模板数据。
(2). OPR渲染:
OPR渲染主要完成人体分割模板数据的获取、弹幕及模板数据的渲染等工作,从而实现弹幕穿人的效果。具体实现细节后续章节会详细介绍。
2.2 端侧弹幕穿人方案
端侧弹幕穿人是纯端侧方案,相较于云端方案的显著优势是实时(能适用于直播等实时场景),生产成本低,并且在视频介质发生变化时不用重新生产(云端方案必须重新生产)。
简单介绍一下端侧弹幕穿人流程:
端侧在video正常渲染的同时,截取视频帧画面,送给OPR端智能模块去做数据处理。对应弹幕穿人这种场景,端智能算法负责实时完成人体图像分割,生成人体分割模板数据。最后将当前帧的人体分割模板数据送给OPR弹幕渲染模块去做穿人效果的渲染。
2.3 弹幕穿人在移动端的基本要求
弹幕穿人作为一个新的互动形态,弹幕在渲染每一帧的时候,都会涉及大量的运算,特别是纯端侧方案场景更是如此(高效截取视频帧画面,人体检测,弹幕及穿人效果渲染等等)。
弹幕穿人要能在移动端落地产品化,需要满足以下两个条件:
(1) 穿人效果要能得到保证,不能出现错位、偏移、穿人弹幕画面频繁闪烁等影响观感的情况发生,这样才能给用户很好的观感和用户体验。
(2)不能因为引入新的计算量而产生弹幕卡顿、抖动、闪烁等不良影响,不能出现系统资源包括CPU/GPU和内存占用等增长过多,否则影响视频画面观感效果,那就是舍本逐末了!
二、优酷弹幕穿人渲染技术
1. 弹幕渲染技术
弹幕的渲染可以通过canvas来完成(比如著名的开源框架烈焰弹幕使),也可以通过opengl/metal在GPU中来完成。
为了更好的渲染性能,优酷移动端弹幕的渲染全部通过opengl/metal在GPU中完成。
2. 弹幕穿人渲染技术
2.1 简单流程图
整体流程如下:
opr拿到当前视频帧的人体轮廓数据,上传到GPU中去做blur,然后把blur后的数据作为alpha通道去跟弹幕纹理做blend,就能得到穿人效果,最后上屏。
2.2 实现细节
2.2.1 架构图
2.2.2 实现步骤
(1) OPR针对当前video的pts拿到人体轮廓mask数据(无论是云端方案从MetaPipe获取还是端侧方案从OPR端智能模块实时获取的),先把纹理数据上传到GPU。
弹幕穿人轮廓数据,RLE解码后就是0和255(二值数据更利于做RLE编码,编码出来的数据更小),如下图所示:
这个数据对应如下画面:
(2) 在GPU里通过shader实现上下及左右各5个像素做gaussian blur,这样做有两个好处:
a. 主体mask数据没有变化,但边缘处会更平滑、不会那么突兀,锯齿感也会抹平。
b. 会增加mask数据的容错性,如果检测出来的人体轮廓有些许偏差,blur处理后会使偏差看起来没那么明显。
(3) 将blur后的mask纹理作为alpha通道,去跟弹幕的纹理做一次blend。针对每一个点去调整弹幕内容的alpha值,从而达到人体部分的穿透效果。
(4) 最后将blend之后的数据上屏,得到最终的穿人效果如下图:
三、工程上的优化
要达到一个最优的显示效果,在产品中落地,工程上要做大量的优化。2018年优酷也有团队做过尝试,当时遇到的种种问题最终没能上线。
这些问题我们在落地过程中也都遇到,并都解决掉了。下面举几个例子:
1. 人体边缘突兀、不自然
可以看一下上面截图,由于边缘处没有处理好,导致人物头发、眼部的弹幕文字显得特别突兀不自然。
2. 视频与弹幕宽高比不同时导致弹幕mask错位
如上图所示,弹幕是全屏的,视频画面会根据视频的宽高比等比缩放,一般左右两端或上下两端会留黑。如果拿到视频的人体轮廓数据直接往全屏弹幕上贴的话,产生的就是上图效果,弹幕mask错位。
所以,每一帧人体轮廓数据,我们不能直接贴到弹幕上去做blend,而需要根据两者的尺寸比例差去调整贴图的坐标。
3. 性能相关问题
弹幕对性能非常敏感。好多因素会导致弹幕渲染性能的下降,频繁切换render target是导致渲染性能急剧下降的主要因素之一。我们以这一因素为例讲解一下我们是如何做优化的。
由于不是每一帧都有轮廓数据,在没有轮廓数据时,弹幕需要直接上屏,这时就会涉及render target的频繁改变。由于每一次改变,相当于一次render pipeline的重建,对性能会有一定的损耗。render target的频繁改变会导致渲染性能的急剧下降,从而产生弹幕画面卡顿、抖动等现象。
为了解决这一难题,我们采用一种比较tricky的做法:针对需要做弹幕穿人的场景,我们把渲染管线固定为一直有弹幕穿人的mask。在某一帧视频画面没有人体轮廓数据时,我们会拿一个1x1的假数据作为伪mask,然后去跟弹幕数据做blend。这样既不会对弹幕画面产生任何影响,也不会增加渲染耗时,从而非常有效解决了频繁切换render target导致的性能急剧下降问题。
目前发现的影响弹幕穿人渲染性能的其他问题,我们也都一一解决了。
四、参考
https://developer.aliyun.com/article/829886
https://www.khronos.org/opengles/resources
https://developer.apple.com/metal/
https://developer.apple.com/documentation/metal?language=objc