首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >看点视频秒开优化:解码器复用优化方案篇

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

作者头像
腾讯VTeam技术团队
发布2020-10-14 17:40:21
5.2K0
发布2020-10-14 17:40:21
举报
文章被收录于专栏:VTeam技术团队VTeam技术团队

随着短视频的流行,用户在碎片化场景下消费的视频内容越来越多。短视频本身时长较短,首帧体验尤为重要。随着预加载、预下载、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

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯VTeam技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、背景
    • 1.1 业务背景
      • 1.2 首帧体验至关重要
        • 1.3 首帧现状
          • 1.4 首帧优化已进入深水区
          • 二、跨播放器解码器复用方案
            • 2.1 探索:适合短视频场景的解码器复用方案
              • 2.1.1 什么是解码器复用
              • 2.1.2 Google的ExoPlayer方案不适合短视频场景
              • 2.1.3 探索出适合短视频场景的解码器复用方案
            • 2.2 跨播放器解码器复用方案设计
              • 2.2.1 跨播放器复用
              • 2.2.2 跨播放器复用方案的演进
              • 2.2.3 方案实现的难点
            • 2.3 低侵入实现
              • 2.3.1 为什么要做hook
              • 2.3.2 hook方案的选型
              • 2.3.3 代理方式实现低入侵方案
            • 2.4 提高复用率
              • 2.4.1 解码器不能直接复用
              • 2.4.2 提升复用率的关键
              • 2.4.3 优化淘汰策略提高复用率
            • 2.5 监控模块
              • 2.5.1 现象和原理同时检测保证质量
              • 2.5.2 WeTest自动化方案提升测试效率
              • 2.5.3 线上监控保证线上质量
            • 2.6 方案总结
              • 2.6.1 整体架构
              • 2.6.2 如何接入
          • 三、性能数据
            • 3.1 中低端机优化效果显著
              • 3.2 首帧大盘优化
                • 3.3 内存无明显影响
                  • 4.1 思考
                  • 4.2 后言
              • 四、写在最后
              相关产品与服务
              云点播
              面向音视频、图片等媒体,提供制作上传、存储、转码、媒体处理、媒体 AI、加速分发播放、版权保护等一体化的高品质媒体服务。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档