直播 App 中 Android 酷炫礼物动画实现方案(下篇):SVGA 由来与 Lottie 的对比
这个动画,如果输出成 GIF 的话,要 3MB,尺寸是 750*750。在上一篇文章中已经介绍过几种被否掉的方法,这里再稍作补充说明,如果使用 GIF 实现,有以下问题。
动画文件太大(3MB 的大小)
播放资源占用高(当时测试的机子,内存占用约 30MB/CPU 占用约 50%)
效果差(GIF 只支持 8 位颜色)
那么,使用 WebP 呢?嗯,使用 WebP 可以把动画文件大小压缩到一半,但是,播放资源占用问题没有解决,这依然是头疼的问题,想想,一个视频直播流已经占用了系统给进程分配的大量内存,然后直播间里面可能成千上万甚至更大体量的人同时在线,观众们一个个赠送礼物的动画出来,应用直接给搞挂掉了……
如果使用 A-PNG 呢?使用 A-PNG 可以完美地解决效果差的问题,因为 PNG 支持 32 位颜色啊,但是,同样的天使动画,大小可以达到 9M,播放资源占用更更更高!
探索
那么,有没有更好的方法去解决以上的问题?其实是有的,早在 2015 年,Adobe 就已经把 CreateJS 收归旗下,并且可以完美地将 Flash 动画导出至 Web 中。也正是同一个时期,BodyMovin 出现了,BodyMovin 可以将另一个 Adobe 的软件 After Effects 所设计的动画完美地导出至 Web 中。这两者的出现,是我们开发 SVGA 灵感的源泉。
具体的思路是,将动画脚本导出,再将动画元素(位图)导出,然后在对应的客户端,重新拼合这些位图。这样做的好处很明显,元素是有限的,动画脚本也非常轻量,我们只需要一次性地把元素还原出来就可以了。
相比序列帧,这种方案得到的动画文件非常小,播放资源占用也非常小,效果却相当好(因为使用 PNG 支持 32 位颜色)。
实现
在 2016 年的时候,Lottie 还没开源,并且 BodyMovin 的文档也相当欠缺,我们是不可能重新实现一个 BodyMovin 在 iOS/Android 上的播放器的。
于是,干脆重写一个?然后 Pony 就用了两周的时间,把 SVGA Flash 转换器写出来了,再用两周时间,把 iOS 和 Android 的 Player 也写出来(当然,只是 Demo 阶段)。一个月后,拿出来,给 Da Lao 们欣赏欣赏,Da Lao 们都惊呆了……
这个方案,不仅资源占用很小很小(当时测试的数据内存占用约 8M 左右,CPU 占用约 2%),文件大小也非常小(天使动画只需 295K),效果还狂拽酷炫高逼格。
紧接着接着,在 YY 内部就开始有了 SVGA 这个项目(当时没有开源),经过了一整年的迭代,在 YY 系的产品中有超过十多个产品的使用,应用范围涵盖 iOS/Android/Web/PC 客户端等。
SVGA 与 Lottie
在上一篇文章发出后,很多同学都在关注一个问题,SVGA 和 Lottie 有什么区别?嗯,没有对比就没有伤害,既然 Lottie 这么强大,我们就用 SVGA 来跟它做一番对比,以下列了一些特性差异:
从 CreateJS/Lottie 实现的原理来看,都是将设计软件中的时间轴完整地导出来,包括里面的各种关键帧信息、矢量路径、样式等等。其中,最为关键的是『关键帧』!由于使用的是关键帧动画描述,那么对应的 Player 就难免变得复杂起来。如果只是简单的一次线性方程,比如,物体从 A 点匀速移动至 B 点,还 OK。但是,当遇到二次线性方程、贝塞尔曲线方程这些高阶插值计算的时候,Player 就会很吃力。(矢量动画就是通过一些公式能表达的矢量线条和色块,以此来表示每一帧动画)
CreateJS 可以导出 Flash 动画,Lottie 可以导出 After Effects 动画,但是它们都不能导出对方的动画(每种设计工具的脚本都是不一致的),这也意味着,你家的设计师只能使用其中一种设计工具。
Lottie 在导出位图动画方面不够友好,从 UI 设计师和开发人员使用角度来看都比较麻烦,开发人员需要先将做好的效果打包成 ZIP,再解压到本地目录,才能播放。
SVGA 使用另外一套逻辑,它不关心关键帧,因为 SVGA 里面的每一帧都是关键帧!也就是说,SVGA 已经在导出动画的时候,把每一帧的信息都计算好了,如此一来,Player 也就不用关心插值计算的过程。正因为如此,SVGA 可以同时支持 Flash 和 After Effects 的导出,只需要在各自转换器中计算差值就好了。
SVGA 在设计之初就支持位图元素,在 1.x 格式时使用 ZIP 进行打包,在 2.x 格式中,直接使用 ProtoBuf+Zlib 方式打包,作为开发者,完全不用关心应该怎样下载、解压、获取位图文件,直接把 svga 文件扔进去 Player 就可以了。
功能上,SVGA 更贴合直播应用场景,SVGA 所提供的动态文本、动态图像功能都是其它库所不能提供的。
Android
我们最关心的永远是性能问题,SVGA 在设计之初就考虑到性能问题(这里只讨论 Android 端的实现)。Android 端最初的 SVGA Player 是通过继承 SurfaceView(TextureView)实现的的,但是 SurfaceView 在硬件加速的情况下只能独立于 UI 层级(在最顶或者最底),如果不开启硬件加速渲染呢?效果会变得非常感人。并且在使用 SurfaceView 绘制 Bitmap 时,还伴随着各种问题,包括内存回收、Activity 生命周期以及 UI 层级各种牵扯不清的问题。
后期通过继承重写 ImageView 来实现 Android 端的 SVGA Player,使用 Canvas 绘制 Drawable 的方式来绘制动画,这样也使得 SVGA 可以任意地嵌入到 UI 层级中,同时也解决之前诸多的存在问题。
当然,关于 SVGA Player,UED 还在不断的继续优化,大家可以持续关注官网和 Github 的更新…
评论