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

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

文娱妹导读


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

   本系列文章主要聚焦在优酷端侧弹幕穿人的技术实战上,主要包括优酷跨平台多媒体渲染引擎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里衍生出更多的端智能应用场景,给优酷用户的观影带来更好的用户体验。


相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
7天前
|
弹性计算 Java 数据库
Web应用上云经典架构实战
本课程详细介绍了Web应用上云的经典架构实战,涵盖前期准备、配置ALB、创建服务器组和监听、验证ECS公网能力、环境配置(JDK、Maven、Node、Git)、下载并运行若依框架、操作第二台ECS以及验证高可用性。通过具体步骤和命令,帮助学员快速掌握云上部署的全流程。
|
1月前
|
消息中间件 Java Kafka
实时数仓Kappa架构:从入门到实战
【11月更文挑战第24天】随着大数据技术的不断发展,企业对实时数据处理和分析的需求日益增长。实时数仓(Real-Time Data Warehouse, RTDW)应运而生,其中Kappa架构作为一种简化的数据处理架构,通过统一的流处理框架,解决了传统Lambda架构中批处理和实时处理的复杂性。本文将深入探讨Kappa架构的历史背景、业务场景、功能点、优缺点、解决的问题以及底层原理,并详细介绍如何使用Java语言快速搭建一套实时数仓。
173 4
|
1月前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
86 4
|
2月前
|
缓存 前端开发 JavaScript
前端的全栈之路Meteor篇(二):容器化开发环境下的meteor工程架构解析
本文详细介绍了使用Docker创建Meteor项目的准备工作与步骤,解析了容器化Meteor项目的目录结构,包括工程准备、环境配置、容器启动及项目架构分析。提供了最佳实践建议,适合初学者参考学习。项目代码已托管至GitCode,方便读者实践与交流。
|
2月前
|
存储 前端开发 API
DDD领域驱动设计实战-分层架构
DDD分层架构通过明确各层职责及交互规则,有效降低了层间依赖。其基本原则是每层仅与下方层耦合,分为严格和松散两种形式。架构演进包括传统四层架构与改良版四层架构,后者采用依赖反转设计原则优化基础设施层位置。各层职责分明:用户接口层处理显示与请求;应用层负责服务编排与组合;领域层实现业务逻辑;基础层提供技术基础服务。通过合理设计聚合与依赖关系,DDD支持微服务架构灵活演进,提升系统适应性和可维护性。
|
3月前
|
负载均衡 数据库 开发工具
|
3月前
|
运维 持续交付 API
深入理解并实践微服务架构:从理论到实战
深入理解并实践微服务架构:从理论到实战
155 3
|
3月前
|
存储 缓存 负载均衡
亿级流量架构理论+秒杀实战系列(二)
亿级流量架构理论+秒杀实战系列(二)
|
3月前
|
运维 监控 持续交付
深入浅出:微服务架构的设计与实战
微服务,一个在软件开发领域如雷贯耳的名词,它代表着一种现代软件架构的风格。本文将通过浅显易懂的语言,带领读者从零开始了解微服务的概念、设计原则及其在实际项目中的运用。我们将一起探讨如何将一个庞大的单体应用拆分为灵活、独立、可扩展的微服务,并分享一些实践中的经验和技巧。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
89 3
|
4月前
|
安全 IDE Java
从0到1探索淘宝短视频流的架构再设计和工程重构
随着视频流业务的发展,业务的复杂性越来越高,视频流老工程在架构设计、代码质量、工程能力等方面的问题也逐渐凸显。本次重构是一次对大型业务工程进行架构再设计和重构的探索,本文是对这次探索的一次梳理与总结。

热门文章

最新文章