优酷移动端弹幕穿人架构设计与工程实战总结

简介: 优酷移动端弹幕穿人架构设计与工程实战总结

文娱妹导读


   弹幕穿人方案主要分为两类:“云端离线人体分割+端侧渲染”和“移动端端侧实时人体分割+端侧渲染”。在这里我们分别简称为云端方案端侧方案

   本系列文章主要聚焦在优酷端侧弹幕穿人的技术实战上,主要包括优酷跨平台多媒体渲染引擎OPR简介、优酷端侧弹幕穿人架构设计与工程实战、淘系端智能PixelAI移动端实时人像分割技术、以及优酷弹幕渲染及弹幕穿人渲染技术的方方面面。



一、背景

1. 弹幕穿人的价值

弹幕是目前用户观影的一个标配,弹幕能使用户在观影过程中与其他用户实时互动,提升了观影体验。但弹幕也会遮挡视频画面,也会给用户带来一些困扰。弹幕穿人是视频内容与弹幕内容争夺用户视觉焦点的一种平衡,能够让用户在消费弹幕的同时,依然可以观看到视频中涉及人物等的关键画面区域。在有弹幕穿人效果的时候,用户有更强的意愿打开更多行弹幕,弹幕穿人对用户弹幕开启行数有一定促进作用,从而证明弹幕穿人能产生正向的价值。


2. 端侧弹幕穿人的优势

相较于云端方案需要提前针对某个剧生产、部署、下发,在介质有变化时需要重新生产等等不利因素,以及动则上百万的生产、储存及带宽成本,不适用于直播等实时场景。端侧弹幕穿人则完全依赖于移动端自身的算力,最大优势是实时、低成本,并且利于大规模铺量。


3. 端侧弹幕穿人的技术要求及难点

3.1)穿人效果要准确

无论是云端还是端侧,穿人效果都要求准确。否则如果不达标,mask与人物有错位、弹幕渲染频繁抖动等等现象,这些都是不可接受的。

3.2)性能要达标

我们要在端侧保证弹幕穿人效果和性能,不能因为端侧弹幕穿人而导致CPU/GPU/内存等资源占用的飙升,或者导致弹幕本身渲染卡顿,更不能影响到视频或音频渲染的效果和性能。否则就是本末倒置了。

相较于云端方案,端侧方案的挑战更大,主要表现在如下几个方面:

(1) 算力有限

端侧方案只能利用移动端自身的CPU或GPU来完成链路上所有操作。相较于云端方案,端侧的算力非常有限。移动端、边缘端和云端的GPU算力的介绍可以参考这篇文章《GPU深度报告,三大巨头,十四个国内玩家一文看懂》。

(2) 模型小

由于端侧的限制,我们不可能用大模型,这给检测的准确性也带来更大的挑战。

(3) 实时性

弹幕穿人需要跟视频画面实时匹配。由于视频帧率一般在25~60之间,为了达到好的穿人效果,我们对整个端侧弹幕穿人链路的实时性要求是非常高的。端侧穿人链路上所有操作,包括视频画面获取、人像分割检测、弹幕穿人效果的实现及渲染上屏,所有这些操作加起来要求在20ms以内时间完成(超过20ms就基本能感知到弹幕的卡顿了),这样才能达到一个好的效果。否则穿人效果就会有滞后感、穿人效果与画面不匹配,甚至会对弹幕本身渲染的流畅度和视频渲染的流畅度都产生严重影响。

以上这些因素都会给端侧弹幕穿人项目带来巨大的挑战。


在淘系算法同学的大力支持下,PixelAI很好地完成了移动端实时人像分割的任务,给优酷端侧弹幕穿人功能的上线铺量打下了坚实的基础。另外,我们在工程侧也做了大量的优化(优化手段后面会有介绍),使市面上机型的大规模覆盖成为了现实。


二、整体架构设计

1. 架构图

OPR(OPen Render的缩写)作为优酷主客全端的渲染引擎,主要负责audio、video和弹幕的渲染。另外,我们也在OPR中引入了端智能引擎。由于OPR天生离audio、video和弹幕的raw数据最近,我们可以直接在OPR里就去消费这些数据,产生我们所需的端智能结果,给业务带来更大的价值。我们不需要把数据再一层层地回传给更高的层次去做处理去做消费处理。所以我们在OPR里融入一层端智能层,直接拿数据就可以处理端侧智能相关操作,然后把结果在OPR层展示、上报或者传给上层去消费,这样做的效率是最高的!


我们首先看一下整个OPR的架构图:

image.gif图片.png

OPR从上到下分为4个层次:

(1) 接入层

OPR是跨平台的,我们支持Android(Android手机和OTT设备)、iOS(iPhone、iPad、Mac)和Windows(DX9、DX11、DX12)平台。我们抽象出对应平台的接口,供业务层调用,来完成相应数据元素的渲染。

(2) 引擎层

引擎层,按功能分为Video Engine,Audio Engine和Danmaku Engine,分别对应video、audio和弹幕的引擎。

(3.1) 渲染层

除了基本的Video、Audio和弹幕渲染功能之外,OPR也包括相应的后处理能力,比如视频的帧享相关后处理、特效广告、色盲、zoom等等能力,音频的倍速、均衡器等能力,弹幕的节奏弹幕、流光弹幕、心动弹幕等特效能力。

(3.2) 端智能层

主要包括人脸相关能力、语音能力、超分能力等,下层是其对应的支撑库。

(4) 平台层

对各平台渲染接口的封装,包括2d/3d的opengl es、metal、directx和audio的opensl、audioqueue、directsound等。


2. 流程图

端侧弹幕穿人流程如下:

image.gif图片.png

(1) video正常解码、渲染流程中,我们去实时截取当前视频画面帧;

(2) 送给端智能模块,去做人像分割,得到人体分割mask数据;

(3) mask作为单通道纹理上传至GPU;

(4) mask数据上传至GPU之后,我们做一次5x5的gaussian blur,这样边缘处边缘处更加平滑;

(5) 把blur处理之后的纹理作为alpha去跟弹幕纹理做blend;

(6) 有穿透效果的弹幕surface叠加在视频surface之后,就能得到如上丝滑的弹幕穿人效果了。


三、工程实战

1. 技术选型及实践

人像分割能力,外部开源的opencv和集团内的mnn都有这个能力。但是我们在移动端实测之后得的结论是,性能和效果都达不到我们端侧弹幕穿人的要求。后来我们了解到,集团内部已经有一个强大的端上引擎PixelAI,有强大的人脸等处理能力,已经在淘宝直播等场景上线。我们快速实测了一下,的确在效果和性能都能满足我们的需求。所以我们最终定型PixelAI来作为我们端智能的主引擎来针对端侧弹幕穿人来实时做人体分割。


2. 性能优化

1.1)帧画面高效获取

(1)正常video渲染流程如下:

image.gif图片.png


video正常上屏流程是这样的,video解码后的数据(硬解或软解),通过aliplayer调到opr的接口。video_player->video_engine->video_layer->video_pipeline,后面对接一个个后处理filters去完成各个后处理功能,最后上屏。

(2)用户截图场景下,帧画面的获取流程如下:

image.gif图片.png

针对用户截图场景,由于截图场景不需要上屏,所以我们自然而然想到如下流程,在所有的filter之后加一个snapshot的filter,这个filter完成数据渲染到一个纹理,然后拷贝出来即可。

针对用户截图这种场景,上述流程没问题任何问题。我们在加上snapshot filter之后重新走一遍渲染流程,截图完成后卸载snapshot filter,整个流程耗时若干毫秒。针对用户主动截图这个场景,我们不会因为这若干毫秒感知到性能存在问题问题。但是,当我们把整个链路应用到端侧弹幕穿人这个场景下,我们发现每一帧截图的这个若干毫秒的时间,就是一个致命的性能问题了。如果不压缩时间的话,留给算法的处理时间就太少了,无法达到上线的标准。


(3) 端侧弹幕穿人场景,帧画面获取流程如下

图片.png

针对这种需要频繁实时截帧的场景,我们设计了如上链路。

我们在所有filter的末端增加一路quick_snapshot filter,这个filter有两路渲染command。一路command按正常流程去渲染、正常上屏,不做任何额外处理。同时,另一路command把数据渲染到纹理,然后再拷贝出来。这样,两路相当于并行起来。在每一帧渲染过程中,不会有任何多余的创建和销毁snapshot filter的过程,完全不会对正常渲染链路造成任何影响。同时,新加的一路command使截帧的效率最大化,很好地实时完成了频繁截帧的任务。

经过实测,我们的截帧性能提升若干倍,为算法去做实时人体分割节省了大量的时间。

1.2)避免在cpu中完成耗时操作

PixelAI有大模型和小模型,为了使底层的MNN不做频繁的初始化操作,大小模型要求的帧数据尺寸是固定的。如果大于或小于算法要求的尺寸,PixelAI会先使用OpenCV去做scale。了解到这些scale操作全部在CPU中完成,会造成大量的耗时,所以我们针对大小模型,直接在前面的截帧操作中,通过纹理大小的变化,我们就可以在GPU里完成了帧画面的scale,使截帧输出的尺寸就是PixelAI大小模型所要求的尺寸。这样就避免了使用OpenCV在CPU中做scale锁消耗的大量时间了。

1.3)异步调用模型

从算法同学了解到,PixelAI人像分割过程是一个原子操作,对应的底层MNN tensor等运算不可中端。一般来说,在GPU和高端手机的移动端运算比较快,但也有那种耗时比较久的场景。算法侧我们保证在一个固定的时间内返回结果。

如果算法耗时较久不返回数据,我们在这里死等的话,就会导致弹幕渲染卡顿、穿人效果的错位等异常case,这是不可接受的。为了达到最好的性能和效果,我们必须要实现一个异步调用模型。在正常时间内返回结果的,直接使用mask数据上屏。在正常时间没有返回的,我们丢弃掉当前帧的mask数据。如果是若干帧以内没有返回,我们都使用上一次检测的数据;为了避免这种场景下穿人效果的错位,超过若干帧就直接上屏,没有穿人效果了。这也是在工程上对弹幕穿人渲染效果做出的一个均衡处理了。


3. 效果优化

要做到好的穿人效果,我们在渲染层面也做了大量的优化,参见文章《优酷弹幕穿人渲染技术揭秘》。


4. 测试结论

(1) 算法测试结果,参见文章《PixelAI移动端实时人像分割》

(2) 优酷整体测试结果

测试结论:我们并没有因为引入端侧弹幕穿人带来大量的性能损耗。


四、展望

移动端端智能是未来一个趋势,移动端弹幕穿人是端智能一个很好的应用场景。后续我们会在OPR里衍生出更多的端智能应用场景,给优酷用户的观影带来更好的用户体验。


相关实践学习
基于阿里云DeepGPU实例,用AI画唯美国风少女
本实验基于阿里云DeepGPU实例,使用aiacctorch加速stable-diffusion-webui,用AI画唯美国风少女,可提升性能至高至原性能的2.6倍。
相关文章
|
2天前
|
存储 安全 网络安全
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:八
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:八
|
2天前
|
分布式计算 关系型数据库 大数据
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:九
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:九
|
2天前
|
存储 负载均衡 算法
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:一
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:一
|
2天前
|
存储 机器学习/深度学习 固态存储
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:二
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:二
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:二
|
2天前
|
存储 缓存 运维
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:三
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:三
|
2天前
|
存储 缓存 负载均衡
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:四
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:四
|
2天前
|
存储 缓存 运维
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:五
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:五
|
2天前
|
存储 负载均衡 分布式数据库
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:六
「读书笔记」《大规模分布式存储系统:原理解析与架构实战》:六
|
2天前
|
安全 Java 数据安全/隐私保护
Spring Boot优雅实现多租户架构:概念与实战
【4月更文挑战第29天】在多租户系统中,一个应用实例服务于多个租户,每个租户享有独立的数据视图,而应用的基础设施被共享。这样的架构不仅优化了资源使用,还能降低维护和运营成本。本文将详细介绍如何在Spring Boot中实现多租户架构,并提供具体的实战案例。
41 2
|
2天前
|
Cloud Native Dubbo 应用服务中间件
【Dubbo3高级特性】「微服务云原生架构」带你从零基础认识搭建公司内部服务用户中心体系(实战指南-序章)
【Dubbo3高级特性】「微服务云原生架构」带你从零基础认识搭建公司内部服务用户中心体系(实战指南-序章)
66 0