AlphaPlayer 是字节跳动开源的直播中台使用的一个视频动画特效 SDK,可以通过制作 Alpha 通道分离的视频素材,再在客户端上通过OpenGL ES 重新实现 Alpha 通道和 RGB 通道的混合,从而实现在端上播放带透明通道的视频。
这套方案对设计师而言明显降低了特效的制作成本,对于客户端而言有着更可靠的性能和稳定性,且相比cocos2d引擎有着更低的入门门槛和维护成本,为复杂动画的实现提供了一种全新的方式,新的复杂动画开发将会变得更加简单高效。
在直播项目的原有礼物动画实现效果是通过 cocos 引擎实现的,大部分动画都是通过一系列的旋转平移缩放组合而成,能实现的动画效果较简单且开发成本较高。为了丰富动画的表现形式,降低开发成本,引入了 AlphaPlayer 的动画实现方案。
目前较常见的动画实现方案有原生动画、帧动画、gif/webp、lottie/SVGA、cocos引擎,对于复杂动画特效的实现做个简单对比
方案 | 实现成本 | 上手成本 | 还原程度 | 接入成本 |
---|---|---|---|---|
原生动画 | 复杂动画实现成本高 | 低 | 中 | 低 |
帧动画 | 实现成本低,但资源消耗大 | 低 | 中 | 低 |
gif/webp | 实现成本低,但资源消耗大 | 低 | 只支持8位颜色 | 低 |
Lottie/SVGA | 实现成本低,部分复杂特效不支持 | 低 | 部分复杂特效不支持 | 低 |
cocos2d引擎 | 实现成本高 | 高 | 较高 | 较高 |
AlphaPlayer | 开发无任何实现成本,一次接入永久使用 | 低 | 高 | 低 |
而在复杂动画特效高效实现的场景中,我们的备选方案会更少一些,可以将讨论集中在Cocos2d、Lottie、Webp和本文的AlphaPlayer上。
Lottie是非常优选的多平台动画效果解决方案,其简单原理是将AE动画导出的json文件解析成每个layer层级对象,再绘制成对应的Drawable,最后显示在View上。在不涉及mask和mattes等特性时性能非常优选,主要耗时基本集中在Canvas#draw()上而已,json解析时通过流读取的方式避免一次性加载全部json数据带来的OOM问题。
但是也存在部分不足:
实际使用过程中,最常见的首启全屏引导动画基本都会包含上面提到的前三点不足,这种情况下性能其实是大幅退化的。因此对于直播场景的复杂特效动画而言,Lottie就不是一个很合适的实现方案了。
Cocos2d-x 支持非常多的游戏功能,诸如精灵、动作、动画、粒子特效、骨骼动画等等,可以供开发者自由实现各种姿势的动画效果,再加上自身具备跨平台能力和轻量级,同时支持 Lua 作为开发语言,可以说是非常适合植入移动端作为动画效果实现方案的游戏引擎。
但实际使用维护中会面临很多问题:
Webp 相比 PNG 和 JPEG 格式体积可以减少 25%,在移动端的平台支持上也很全面,支持 24 位 RGB 色;缺点是资源体积比较大,而且使用的软解效率低下,低端机上有明显卡顿问题。
相比于上面提到的几个方案,AlphaPlayer 的接入体积极小(只有40KB左右),而且对动画资源的还原程度极高,资源制作时不用考虑特效是否支持的问题,对开发者和设计师都非常友好。通过接入ExoPlayer或者自研播放器可以解决系统播放器在部分机型上可能存在的兼容性问题,且能带来更好的解码性能。
主要有两个核心,一个是IMediaPlayer,负责视频解码,支持外部自行实现;另一个是VideoRenderer,负责将解析出来的每一帧画面进行透明度混合,再输出到GLTextureView或者GLSurfaceView上。
大致的混合过程可以看下图示例
原素材的画面中左边部分使用RGB通道存储了原透明视频的Alpha值,右边部分使用RGB通道存储了原透明视频的RGB值,然后在端上通过OpenGL重新将每个像素点的Alpha值和RGB值进行组合,重新得到ARGB视频画面,实现透明视频的动画效果。
混合过程的详细代码可以见 frag.sh
和vertex.sh
,
添加依赖
pod 'BDAlphaPlayer'
初始化View
BDAlphaPlayerMetalView *metalView = [[BDAlphaPlayerMetalView alloc] initWithDelegate:self]; [self.view addSubview:metalView];
播放动画视频
BDAlphaPlayerMetalConfiguration *configuration = [BDAlphaPlayerMetalConfiguration defaultConfiguration]; NSString *testResourcePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"TestResource"]; NSString *directory = [testResourcePath stringByAppendingPathComponent:@"heartbeats"]; configuration.directory = directory; configuration.renderSuperViewFrame = self.view.frame; configuration.orientation = BDAlphaPlayerOrientationPortrait; [self.metalView playWithMetalConfiguration:configuration];
添加依赖
allprojects { repositories { ... maven { url 'https://jitpack.io' } } } dependencies { implementation 'com.github.bytedance:AlphaPlayer:1.0.4' }
初始化PlayerController
val config = Configuration(context, lifecycleOwner) // 支持GLSurfaceView&GLTextureView, 默认使用GLSurfaceView config.alphaVideoViewType = AlphaVideoViewType.GL_TEXTURE_VIEW // 也可以设置自行实现的Player, demo中提供了基于ExoPlayer的实现 val playerController = PlayerController.get(config, DefaultSystemPlayer()) playerController.setPlayerAction(object: IPlayerAction { override fun onVideoSizeChanged(videoWidth: Int, videoHeight: Int, scaleType: ScaleType) { } override fun startAction() { } override fun endAction() { } }) playController.setMonitor(object: IMonitor { override fun monitor(result: Boolean, playType: String, what: Int, extra: Int, errorInfo: String) { } })
将PlayerController绑定到ViewGroup
playerController.attachAlphaView(mVideoContainer)
播放动画视频
fun startVideoAnimation() { val baseDir = "your video file base dir" val portraitFileName = "portrait.mp4" val portraitScaleType = 2 val landscapeFileName = "landscape.mp4" val landscapeScaleType = 2 val dataSource = DataSource().setBaseDir(baseDir) .setPortraitPath(portraitFileName, portraitScaleType) .setLandscapePath(landscapeFileName, landscapeScaleType) .setLooping(false) // 可设置该视频是否循环播放 if (dataSource.isValid()) { playerController.start(dataSource) } }
资源释放
fun releasePlayerController() { playerController.detachAlphaView(mVideoContainer) playerController.release() }
SurfaceView和TextureView都是用来显示视频画面的,主要差异在于性能和层级,SurfaceView的性能要优于TextureView,但是层级限制在最顶层,TextureView则没有层级限制。可以通过如下方式指定alphaVideoViewType来设置。
val config = Configuration(context, lifecycleOwner) // 支持GLSurfaceView&GLTextureView, 默认使用GLSurfaceView config.alphaVideoViewType = AlphaVideoViewType.GL_TEXTURE_VIEW val playerController = PlayerController.get(config, DefaultSystemPlayer())
为了解决不同屏幕尺寸的兼容问题和支持半屏动画视频的指定位置播放,我们提供了多种视频裁剪对齐方式,详细可见ScaleType.kt
/BDAlphaPlayerDefine.h
。
对齐模式 | 描述 |
---|---|
ScaleToFill | 拉伸铺满全屏 |
ScaleAspectFitCenter | 等比例缩放对齐全屏,居中,屏幕多余部分留空 |
ScaleAspectFill | 等比例缩放铺满全屏,居中,裁剪视频多余部分 |
TopFill | 等比例缩放铺满全屏,顶部对齐 |
BottomFill | 等比例缩放铺满全屏,底部对齐 |
LeftFill | 等比例缩放铺满全屏,左边对齐 |
RightFill | 等比例缩放铺满全屏,右边对齐 |
TopFit | 等比例缩放至屏幕宽度,顶部对齐,底部留空 |
BottomFit | 等比例缩放至屏幕宽度,底部对齐,顶部留空 |
LeftFit | 等比例缩放至屏幕高度,左边对齐,右边留空 |
RightFit | 等比例缩放至屏幕高度,右边对齐,左边留空 |
提供多种动画对齐方式的目的有二:一是需要对不同屏幕尺寸的设备进行兼容;二是希望尽量减少屏幕中视频动画的渲染区域(这对GPU功耗有线性收益),所以如果局部渲染可以满足动画表现需求,建议尽量使用局部渲染,即减少mVideoContainer
的布局大小。
为了进一步减少视频动画文件的体积,我们做了很多方向的尝试,包括透明画面像素点冗余channel的复用和整体尺寸压缩,可以期待后续更新。
SurfaceView和TextureView都是用来显示视频画面的,主要差异在于性能和层级,SurfaceView的性能要优于TextureView,但是层级限制在最顶层,TextureView则没有层级限制。可以通过如下方式指定alphaVideoViewType来设置。
val config = Configuration(context, lifecycleOwner) // 支持GLSurfaceView&GLTextureView, 默认使用GLSurfaceView config.alphaVideoViewType = AlphaVideoViewType.GL_TEXTURE_VIEW val playerController = PlayerController.get(config, DefaultSystemPlayer())
素材制作的方式有两种:
一种是直接使用AE导出成品素材,大致流程就是后期在AE上完成动画效果后,分离出Alpha通道视频,然后在同一个AE合成里左边带Alpha通道后边带正常动画,一起渲染导出。如果还是不理解,还是让设计师去代劳吧,专业的人做专业的事。
第二种方式,在AE上完成动画后期效果后,直接输出视频序列帧,然后使用我们提供的素材制作脚本 convertAlphaVideo.py
进行处理也可以直接得出成品素材视频,脚本的大致原理如下:
素材制作的方式有两种:
一种是直接使用AE导出成品素材,大致流程就是后期在AE上完成动画效果后,分离出Alpha通道视频,然后在同一个AE合成里左边带Alpha通道后边带正常动画,一起渲染导出。如果还是不理解,还是让设计师去代劳吧,专业的人做专业的事。
第二种方式,在AE上完成动画后期效果后,直接输出视频序列帧,然后使用我们提供的素材制作脚本 convertAlphaVideo.py
进行处理也可以直接得出成品素材视频,脚本的大致原理如下:
可以看到通道分离和画面拼接是基于ffmpeg和ImageMagick两套工具实现的,所以运行前需要先配置ffmpeg和ImageMagick的环境。
执行下面命令,等待成品素材生成。
python convertAlphaVideo.py --dir 'your pictures parent file path'
文档:https://github.com/bytedance/AlphaPlayer AlphaPlayer是直播中台使用的一个视频动画特效SDK,可以通过制作Alpha通道分离的视频素材,再在客户端上通过OpenGL ES重新实现Alpha通道和RGB通道的混合,从而实现在端上播放带透明通道的视频。 作为技术生成脚本的过程梳理下: 官方给出的命令: python convertAlphaVid
注意:对于 Photoshop CC 之前的 Photoshop 版本,只有当您拥有 Photoshop Extended 时,本文所讨论的某些功能才可能可用。Photoshop 不提供单独的 Extended 版本。Photoshop Extended 中的所有功能是 Photoshop 的一部分。 关于视频图层 可以使用 Photoshop 编辑视频和图像序列文件的各个帧。除了使用任一 Pho
注意:对于 Photoshop CC 之前的 Photoshop 版本,只有当您拥有 Photoshop Extended 时,本文所讨论的某些功能才可能可用。Photoshop 不提供单独的 Extended 版本。Photoshop Extended 中的所有功能是 Photoshop 的一部分。 预览帧动画 执行下列操作之一: 单击“时间轴”面板中的“播放”按钮 。 使用空格键播放和暂停动画
注意:对于 Photoshop CC 之前的 Photoshop 版本,只有当您拥有 Photoshop Extended 时,本文所讨论的某些功能才可能可用。Photoshop 不提供单独的 Extended 版本。Photoshop Extended 中的所有功能是 Photoshop 的一部分。 变换视频图层 可以像在 Photoshop 中变换其它任何图层一样变换视频图层。但是,必须在变换
本文向大家介绍IOS实现视频动画效果的启动图,包括了IOS实现视频动画效果的启动图的使用技巧和注意事项,需要的朋友参考一下 先上效果图 实现思路 主要思路就是用一个控制器来作为播放视频的载体,然后在让这个控制器作为根视图,视频播放完成之后那就该干嘛干嘛了。 话不多说了,下面就放代码好了 先新建一个控制器AnimationViewController在控制器中新建一个属性moviePlayer,记得
我有一个应用程序,它只是一个动画(一些圆圈在移动)。 我想知道如何将这个动画保存为MP4之类的视频? 或者可以记录(捕获)节点内发生的事情并将其保存为视频格式吗?