看点视频秒开优化:解码器复用优化方案篇

2020-10-14 17:40:21 浏览数 (1)

随着短视频的流行,用户在碎片化场景下消费的视频内容越来越多。短视频本身时长较短,首帧体验尤为重要。随着预加载、预下载、IP直通车等传统优化手段使用,首帧体验有了明显提升。但经过进一步的数据分析,在手Q中长尾中低端机上,首帧表现依然不够理想。首帧优化已经进入深水区,受Google ExoPlayer切换清晰度方案(不用重启解码器)的启发,我们探索出一种适合短视频场景的,基于Android平台的跨播放器解码器复用方案,对中低端机首帧性能提升明显。本文是对整体方案的介绍,希望能帮助大家在首帧优化方向上提供新的思路,欢迎多多交流。

一、背景

1.1 业务背景

本文看点视频特指手Q、快报、看点视频等腾讯看点内的视频场景业务,包含Feeds流、视频详情页、栏目详情页等场景,以短视频为主,类似抖音、微视等形态。由于手Q用户基数较多,机型覆盖面广,下面以手Q为例,逐步展开介绍解码器复用优化方案。

1.2 首帧体验至关重要

由于短视频时长较短,用户对于首帧加载时长容忍度更低。下面表格体现了在不同的首帧下,用户的主观感受。首帧时长越短越好,一般1s以内相对更容易接受。

为了更贴近用户的实际感受,下面的首帧主要是指从用户点击播放到第一帧画面渲染出来的时长(未经特殊说明,都指此段时长,而非一般情况下prepared的时长)。通常情况下,衡量首帧体验,主要是两个指标,一是平均首帧,主要表现首帧时长的平均水平;二是首帧秒开率(首帧1s内的播放数/总播放数),主要衡量首帧体验的稳定性。

1.3 首帧现状

经过多轮优化,目前平均首帧为333ms,秒开率为89%。只看这两个数据,总体指标已经比较优秀,但从首帧耗时分布来看,长尾机型首帧依然较差,且大于1s。

根据手Q版本大盘数据,首帧分布情况如下:

从上图来看,大于1s的首帧占比约11%,这部分耗时主要集中在长尾中低端机。

1.4 首帧优化已进入深水区

为了进一步寻找优化空间,我们将首帧流程进行拆解,目前已有的预换链、ip直通车、预下载等优化手段基本和业界内对齐。除了解码器初始化(指MediaCodec的create、configure()、start()等耗时操作)以外,其他流程几乎已经全部覆盖。

那么解码器初始化的耗时是否有优化的可能性呢?受到Google ExoPlayer优化切换清晰度时耗时的方案启发(具体可见《Improved decoder reuse in ExoPlayer》),解码器可以在一定条件下不经过重启,直接播放不同清晰度的视频,避免耗时带来的黑屏等问题。以ExoPlayer文章中数据为例,播放器在数据准备好后还有一段耗时不容忽略,其中 Galaxy S8播放1080p的H.264视频,音视频解码器初始化总和耗时高达170ms,占启动总耗时的60%(170ms / 280ms)。

为了进一步摸清中低端机解码器初始化对首帧耗时的影响,我们对常见低端机解码器初始化耗时进行统计,发现部分机型耗时超过1s,其中用户占比较大的vivo X5L(TOP30)解码器初始化耗时也高达1146ms。以下为不同低端机解码器初始化耗时排行的情况,单位为ms(当日播放次数>=10000认为数据有效)。由此可见,如果能优化掉中低端机解码器初始化的耗时时长,对首帧会有较大的提升。

二、跨播放器解码器复用方案

2.1 探索:适合短视频场景的解码器复用方案

2.1.1 什么是解码器复用

通常情况下,视频正常播放时解码器都需要进行create()、configure()、start()等初始化操作,而播放其他视频时,每次播放都必须重新进行这一初始化流程。

不重新初始化解码器MediaCodec,而将解码器直接用于其他播放器解码,称为解码器复用。而Google为了优化清晰度无缝切换时的耗时,在ExoPlayer上实现了播放器内的解码器复用。

2.1.2 Google的ExoPlayer方案不适合短视频场景

Google已经在ExoPlayer上进行了解码器复用实践,那么是否可以将对应方案直接应用到我们的业务呢?答案是不能的。ExoPlayer是一种播放器内部解码器复用方案,即解码器和播放器实例绑定。对于不同分辨率的视频A、B、C,下次播放时判断该播放器实例是否可以复用,如果可以,进行复用,否则重新初始化解码器。

总而言之,基于短视频切换频繁的特点,直接使用ExoPlayer方案会存在以下困难:

  1. 无法在player之间复用,由于有预加载等优化手段,短视频场景一般不同视频对应不同的player,与方案冲突。
  2. 复用率低,因为ExoPlayer方案局限在player内部,多个player之间不能共享解码器,而解码器复用是有条件限制的,这样会让复用率非常低。
  3. 接入困难,复用逻辑与播放器逻辑耦合严重。
2.1.3 探索出适合短视频场景的解码器复用方案

基于前面的问题,需要探索出一种更适合短视频场景的,可以跨播放器全局共享的解码器复用方案。目标如下:

  1. 跨播放器复用:解码器能够在多个播放器之间共享,适应多player场景。
  2. 高复用率:闲置的解码器能够被选择,需要保证播放器在起播时尽可能的复用解码器。
  3. 低入侵接入:解码器复用逻辑需要和播放器逻辑解耦,让接入时尽可能减少代码入侵。
  4. 通用性高:能够让几乎所有基于MediaCodec的播放器都能使用无缝切换方案。

2.2 跨播放器解码器复用方案设计

2.2.1 跨播放器复用

为了满足多player架构,解码器在多个player之间复用,理想的模型是全局只需要一个解码器,进行复用即可。

2.2.2 跨播放器复用方案的演进

上文中的理想模型因为解码条件限制(即解码器能否复用受一些条件限制)难以满足要求,因此,我们加入了解码器复用池,可以让多个播放器共享解码器。当新播放器起播时,可以根据视频特征选择合适的解码器。

以顺序播放A、B、C视频为例,一个完善的复用流程需要下面一些步骤:

  1. 当播放器A、B停止时,需要保持其对应的解码器运行状态(可以对照前文MediaCodec的生命周期图,只有Executing状态才能正常解码),放入解码器复用池中。而通常情况下,播放器stop时会调用MediaCodec的stop()、release()方法,需要对以上API进行hook,保证MediaCodec的Executing状态,以便其他播放器可以复用。
  2. 当C视频开始播放时,会优先从解码器复用池中选择合适的解码器,进行复用。换言之,当解码器池中没有能复用的解码器时,只能重新初始化解码器。例如播放器B不能使用播放器A的解码器。
  3. 为了保证解码器对应的渲染层重新和C播放器绑定,复用时,需要将C视频对应的surface设置到解码器A上
2.2.3 方案实现的难点
  1. 低侵入实现:由于要在放入解码器到解码器池时保持运行状态,要想方案更为通用,且上层不做改动,需要对MediaCodec等相关API进行hook,保证不被释放。
  2. 提高复用率:由于解码器的复用受一些条件限制,我们需要通过实验以及结合ExoPlayer的经验,摸清楚复用条件。在复用条件的限制下,尽可能用比较低的成本提高复用率。
  3. 保证解码质量:由于解码器复用比较偏向系统底层,而Android上机型众多,需要用一定的手段来解决兼容问题保证解码质量。

2.3 低侵入实现

2.3.1 为什么要做hook

传统的方案解码器复用逻辑和播放器耦合严重,且复用逻辑复杂,无法通用。要实现通用方案,并且所有基于MediaCodec的播放器可用,需要对MediaCodec的API进行hook并且将复用逻辑与播放器隔离。也就是说,理想的复用模型应该是无入侵,不修改现有播放器代码,复用逻辑通过独立模块hook MediaCodec实现。

2.3.2 hook方案的选型

我们的目标是hook MediaCodec的API,这里调研了一些常见的hook手段,并做出对比。

以上方案都有一些限制,比如Legend和Whale的支持系统版本限制,Whale增量较大以及编译时方案javaassist不支持系统类等问题。而MediaCodec属于系统类,且是final类型,使用任何一种方案都会有各种各样的问题,为了保证方案的轻量,以上的常见的hook方案都不适用。

2.3.3 代理方式实现低入侵方案

以上方案都被否定,我们这里考虑使用代理方案,让代理类TMediaCodec和MediaCodec使用完全一致的接口,这样在接入TMediaCodec时只需要代理内部实现逻辑即可,也可以很好的将复用逻辑和外部隔离,也有较低的入侵性。

首先我们定义了和MediaCodec有完全一致的API的CodecWrapper,具体如下:

其中ReuseCodecWrapper为复用的codec的包装类,DirectCodecWrapper为非复用的codec的包装类。即需要复用时,会获取ReuseCodecWrapper进行是使用,其中的初始化逻辑是不耗时的,非复用时会直接使用DirectCodecWrapper,里面直接进行了系统MediaCodec的API代理。具体的类关系如下图:

2.4 提高复用率

2.4.1 解码器不能直接复用

经过反复的实验和结合ExoPlayer的落地经验,摸索出解码器复用需要遵循下面条件:

解码器复用的核心条件是支持自适应播放属性,此属性是指Android提供的一种无缝切换不同分辨率视频的能力,可以由系统接口(Seeking & Adaptive Playback Support)查询是否支持。

由于篇幅有限,这里对解码器复用条件不做展开,具体可以期待下一实践篇文章。

2.4.2 提升复用率的关键

由上表格可以看出,能不能复用除了机器本身是否支持自适应播放属性外,最主要受编码格式和分辨率以及MAXINPUTSIZE影响。

1. 编码格式

为了兼顾各个业务的实际情况,比如看点常见编码格式是H264和H265,解码器池支持自定义编码格式解码器池大小,这里默认是优先保留一个H264和一个H265两个解码器,以便复用时提高复用率。当然业务也可以根据实际情况进行设置。

2. MAXINPUTSIZE

自适应播放虽然可以适应不同分辨率的解码,但是受最大分辨率(MAXWIDTHMAXHEIGHT)以及MAXINPUTSIZE限制,这里只需要确定了最大解码的分辨率,MAXINPUTSIZE可以推导得出。所以我们也暴露了业务支持最大分辨率的接口,在MediaCodec.configure()时,根据最大分辨率设置MAXWIDTHMAXHEIGHTMAXINPUTSIZE相关信息,保证所有视频复用解码器时不受分辨率影响。

2.4.3 优化淘汰策略提高复用率

默认解码器池由两个codec实例组成,整个方案默认是采用相同codec优先淘汰的策略,也就是保证解码器池中有不同的解码器格式类型,尽可能保证不同的编码格式都能进行复用。整个方案也将具体的淘汰策略暴露给业务,可供配置。

2.5 监控模块

由于Android机型众多,而MediaCodec贴近硬件,且上层业务较为复杂,所以在实践过程中难免遇到一些bug。所以需要一种简单高效的手段来保证解码质量,在测试阶段尽可能发现问题,在线上可以监控问题。

2.5.1 现象和原理同时检测保证质量

由于解码问题比较底层,且不是很好发现,为了更快速地定位分析问题,我们引入现象和原理同时检测。现象检测是指检测视频播放中出现的问题,比如场景的黑屏、画面卡住等,这里主要是利用截屏检测思路。对于更深层次的原因,我们对常规解码API进行梳理,并自定义了错误码,方便分析问题。

2.5.2 WeTest自动化方案提升测试效率

如果用传统的测试手工测试办法,效率很低,且很难复现问题。我们基于wetest探索出了一种自动化检测方案,主要用于及时复现和检测测试阶段的问题,具体内容可参考《看点视频基于WeTest的播放自动化测试实践》。相对传统方案,有以下优点:

2.5.3 线上监控保证线上质量

为了保证线上质量,我们采用白名单逐步放量的方式,并利用线上分析实时监控来反馈。将现象检测和原理检测结合,利用错误率报表监控,来保证解码质量。

线上监控解码错误率:当线上分析监控解码错误率超过1%,会进行该机型的预警,在放量过程中会自动加入黑名单。这里的错误是指MediaCodec硬解错误,就算出错,播放器也有切换软解策略。

目前在手Q上已有TOP500机型落地,覆盖用户达到的96.14%。

2.6 方案总结

2.6.1 整体架构

目前整个解码器复用方案命名为TMediaCodec,包含以下一些模块。Hook模块用于MediaCodec类以及TextureView的功能代理。策略模块用于各个业务具体视频播放场景的策略配置,保证复用率最大化。监控模块用于监控解码中的错误,保证播放质量。解码器包装模块主要用于用户代理MediaCodec的功能。解码器池用于保存闲置的解码器。

整个方案有以下优点:

优点:

接入简单,灵活配置,入侵小,学习成本低,机型兼容性良好。

解决痛点:

跨播放器复用,全局选择解码器,支持业务配置,几乎支持所有基于MediaCodec的播放器。

2.6.2 如何接入

其他播放器接入:如果没有使用中台播放器,我们也可以支持其他播放器的接入。由于使用了TMediaCodec使用了和MediaCodec完全一致的API,只需要将系统的MediaCoedc替换成TMediaCodec即可。具体细节可以参考工程TMediaCodec。

三、性能数据

3.1 中低端机优化效果显著

以手Q中的一款用户占比较多的经典机型vivo Y66为例,优化效果视觉上可感知。对于中低端机的首帧体验有明显提升。

3.2 首帧大盘优化

以手Q841版本大盘数据为例,对于中低端机,平均首帧提升显著,几乎对半提升。首先我们对机型按照下面标准进行了分类,将手机分成:极低端机、低端机、中端机和高端机。

极低端机的优化幅度约39%,低端机的优化幅度约33%,中端机的优化幅度约29%。而秒开率方面,中低端机从88.79%提升到96.57%。

3.3 内存无明显影响

方案的本质是空间换时间,经过对vivo Y66机型的视频场景峰值测试,内存占用影响不是很大。

不复用内存占用:

复用内存占用:

四、写在最后

4.1 思考

常见的首帧优化手段已经相对较为成熟,我们团队在优化进入深水区时,受益于ExoPlayer视频清晰度切换的方案,经过实践,探索出特有的适合短视频场景的跨播放器解码器复用方案,算是对传统优化手段的创新和突破。传统手段的优化会有部分限制以及适用场景,解码器复用方案以空间换时间,对性能较差的机型的首帧耗时也有实际的提升。当我们的优化进入瓶颈时,不妨打开思路,去关注业界内比较领先的优化手段,针对自身业务场景结合改进,也不失为一种好的思路。

4.2 后言

目前已在看点视频、手Q、快报等App全面落地,方案能够突破中低端机性能限制,优化效果较为显著。也欢迎对技术有兴趣的同学随时交流。在方案实际落地的时候,遇到了一些困难,在解决问题时也收获颇多,欢迎大家期待《看点视频秒开优化:解码器复用优化实践篇》。

0 人点赞