欢迎您,来到佳维网络科技!

从Flash到MP4,直播礼物特效精进之路

2021-04-24 10:15:26


虚拟礼物是主播和观众互动的重要道具,也是主播很大一部分的收入来源。当刷满足够礼物数量时,直播间就会飞出炫酷的礼物动效,它既能刺激主播更好地直播,也能满足用户在虚拟世界的荣誉感,越有诚意的礼物会触发越精彩的礼物动效,这也加深了主播和用户之间的羁绊。

随着直播平台的发展,设计人员不断创作出精美的礼物动效,相应的,动效加载时长和文件体积逐渐变大,而开发人员要需要能够吃下这些负担,在保证动效播放的高效和顺滑的同时,不给用户机器带来负担也不给设计人员的创作带去局限,这便是我们本文需要考虑的几个难点。本文将以奇秀PCweb端为例,从动效效果、性能、研发效率、兼容性等多角度谈谈礼物动效的发展。

演进之路

礼物动效的实现格式可以有很多种,不同文件格式之间各有利弊,从业务角度出发选取相对较优的方案是我们的目的。整条演进路上,我将带领大家从Flash时代开始了解多种动效格式,希望在了解多种方案后,你能找到适合自己业务的较优方案。

动效格式

●过去的王者:Flash

●动图:GIF、APNG、Webp

●开源和自研:Lottie、SVGA、IXD(自研)

●视频:MP4

Flash时代

奇秀平台刚开始上线的时候,视频行业在网页端还是Flash的天下,基于Flash的流媒体播放器几乎是唯一选择,拿它实现动效制作也是很自然的事情,对设计师来说使用Adobe Flash CC导出Flash动画也是常规操作。

没多久,Flash式微,html5技术飞速发展,替换Flash变成迫切需要做的事情。彼时团队内部出现两种实现方向:

●APNG动图

●自研新的动效方案

APNG动图

APNG(Animated Portable Network Graphics)诞生于2004年,是一个基于png的位图动画格式,扩展方法类似主要用于网页的GIF 89a,仍对传统PNG保留向下兼容,2017年主流浏览器几乎都已经支持APNG。由于当时平台上移动端一直是使用图片序列生成的APNG/Webp作为动效资源,为了保持多端的统一,PCweb端也开始尝试使用动图作为后续的动效格式。

综合对比文件大小、效果以及浏览器兼容性,选择使用APNG作为新的动效格式。单纯使用标签直接展示APNG会遇到如下几个问题:

●小部分浏览器不支持播放APNG

●为了动效播放连贯性,需要预加载APNG

●APNG播放开始、过程、结束等时间点不受控

为了解决这几个问题,我们开始研究APNG的文件格式结构,包括PNG的结构和扩展的acTL(动画控制块)、fcTL(帧控制块)、fdAT(帧数据块)。

基于对APNG的了解,对一些开源方案进行了调研测试,最终决定使用apng-js帮助我们解决上述几个问题。使用apng-js解析APNG,可以得到APNG的很多信息,包括宽高、帧数、播放时长,以及播放过程中的每一帧画面,有了这些再配合canvas便可以将APNG绘制和控制起来。下面是设计的播放器参数的结构:

  1. {
  2. src: string, // 动效地址
  3. selector: string            // dom容器
  4. playStart: () => void, // 动画开始
  5. playProgress: (index: number, totalTime: number, remainTime: number) => void, // 动画过程
  6. playEnd: () => void, // 动画结束
  7. };

上述设计以及播放、暂停、重播等使用方法,基本满足对APNG播放的控制,且在后续业务中也可直接实现支持音效礼物,只要在start处读配置播放对应的音频资源,end处删除音频即可。为了提高动效播放的连贯性,在解析APNG后会将解析出的数据存入indexedDB,后面在播放同一动效时便可省去下载和格式解析的耗时。

这种方案对于设计来说也很方便,AE做好动画后,使用格式工具和插件直接导出动图即可。但是后面也发现了该方案的弊端,平台对动效的要求越来越高,越酷炫的动效体积越大,很多复杂动效甚至达到5、6M。

自研IXD

后Flash时代,另一部分同学开始了动效自研的路子。APNG的本质是对PNG格式的扩展,除了向下兼容的IDAT(图像数据块)块外,多了很多fdAT(帧数据块),每一块都是完整的图像,每多一帧就会做一张位图的大小。如果每一数据块不是完整位图,而是图集素材,且数据块表示素材的位置、宽高、缩放等各种信息,那么素材复用率会极高,再辅以对应的解析,那么整体文件大小也会降低很多。

按照该思路去实现,封装了自研的IXD格式,原本10M的PNG序列可以被拆解压缩到1M以内,动效效果几乎没有收到影响。

对于使用端,只需要支持二进制数据和PNG位图的处理,再按照设定的格式解析数据块动态去渲染每一帧即可。对于开发人员,我们同步配套了web端SDK。

为了方便设计师生产,也配套开发了动效编辑器,将素材导入到工具中,通过复用素材和组合效果的方式,支持叠加多个图层,最终导出IXD文件。对于有动态数据的动效,也支持变量占位,开发人员按照占位符取值,使得同一动效不同用户看到的各不一样。

同期市面上也出现了Airbnb的Lottie和YY的SVGA方案:

●Lottie需要AE安装Bodymovin插件导出JSON文件给开发同学使用,有兴趣的同学可以去了解下。

●SVGA也提供了AE插件,它做的事情其实和IXD类似。SVGA从AE源文件里提取素材,并将素材在时间轴里的表现(位移、旋转、缩放等)导出,各端parser负责将这些还原到画布上。它比IXD优秀的点在于,提供了IOS、Android端的解析SDK。

目前我们有APNG方案和IXD方案,包括市面上的SVGA方案,从播放可控到文件大小都有了一定的解决方案,似乎已经可以告一段落了。但这几个方案依旧有各自的缺陷:

MP4

有没有既能尽量保证AE动效,也能保证文件体积小的方案呢?有,用MP4!肯定会有人以为我在开玩笑,MP4都不支持透明,如何能够用来承担直播动效呢。我们先了解下透明是什么:图像的透明使用Alpha通道表示,即RGBA里的A,该通道是一个8位灰度通道,由256级灰度来记录图像中的透明信息。说白了透明和RGB一样都是颜色信息,虽然MP4不支持透明通道,只要想办法给它展示出来就好了吧!还是canvas技术,只要我们可以用canvas把透明视频画出来就可以了。

通过和设计同学沟通,也参考了网络上的文章和讨论,最终决定将动效以上下同步的两块视频拼接而成。上面的视频保留原始的RGB信息,下面的视频将A信息用黑白来表示,当MP4播放的时候分别读取上下两块视频进行拼接,得到完整了RGBA像素信息,然后绘制在目标画布上。

代码很简单,canvas入门的同学应该都可以写出来:

  1. // 绘制视频
  2. buffer.drawImage(video, 0, 0, width, height * 2);
  3. // 读取上下视频图像数据
  4. let imageData = buffer.getImageData(0, 0, width, height).data;
  5. let alphaData = buffer.getImageData(0, height, width, height).data;
  6. // 塞alpha通道
  7. for (let i = 3,len= imageData.length; i
  8. imageData[i] = alphaData[i-1];
  9. }
  10. // 绘制canvas
  11. output.putImageData(image, 0, 0, 0, 0, width, height);

本以为一切都特别顺利,结果进行性能测试发现动效绘制时CPU暴涨,根本无法投入生产。原因其实看代码也能发现,在视频播放过程中密集遍历处理像素点,计算频率太高,所以CPU暴涨。既然单纯canvas2d不行,我们就打算试试性能更好的WebGL。WebGL(Web Graphics Library)基于OpenGL,可以为HTML5 Canvas提供硬件3D加速渲染,也可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型。WebGL里的概念很多,有scene、camera、texture等,这里不会一一介绍,有兴趣的同学可以去了解下。在实现中为了便捷,我们借助Three.js来实现功能,利用THREE.ShaderMaterial自定义的着色器去处理,以下是核心代码:

  1. gl_FragColor = vec4(
  2. texture2D(texture, vec2(vUv.x, 0.5 + vUv.y/2.)).rgb,
  3. texture2D(texture, vec2(vUv.x, vUv.y/2.)).r
  4. );

经过性能测试和对比,动效播放时的CPU使用率显著降低:

总结

通过对以上各种方案的分析,从实际效果、资源大小、成本的角度我们得出以下表格:

我们的场景主要是直播间的礼物动效,暂时没有什么动效的用户交互需要,因此我们选择让设计同学充分发挥才能的MP4方案,设计同学无需学习第三方插件,也不用考虑资源大小而被迫抽帧导致降低动效质量。

我们坚持认为在礼物动效制作方面,MP4的是未来的大趋势,视频编解码技术也在不断发展,H.265、H.266,视频文件体积将会不断缩小,用户等待的时长减少和带宽节省都是很不错的收益。

后续我们将继续深入MP4方案,在格式解析和动态素材占位上下功夫,尝试参照IXD的方案将配置信息写到文件中,创建一个新的BOX塞入MP4文件里,播放时候先取这个BOX读取配置信息,然后和后续的视频帧播放时结合起来达到实现动态素材的效果。也将继续研究WebGL,寻求更加高效的渲染方式,争取进一步提高播放性能。

原文链接 https://blog.csdn.net/weixin_38753262/article/details/111714102



淘宝店铺