百度APP视频播放中的解码优化
全文3514字,预计阅读时间26分钟
一、背景
在全民视频的时代,百度APP中视频播放是十分重要的业务。随着 5G 的到来,视频播放已经不满足以前的标清/高清,超清乃至于 4K 已经是旧时王谢堂前燕飞入寻常百姓家。越来越清晰的视频源,越来越复杂的视频编码,对 APP 的视频解码能力也有越来越高的要求。
与此同时,大家的手机性能越来越好,很多手机都逐步提供了强悍的硬件解码能力;而软件解码发展多年,也有其不可替代的优势。所以,如何合理利用手机的软/硬件解码能力,充分发挥其各自优势,为用户们提供更加优质的视频播放体验,就成为了我们重点优化的方向。
1.1 软/硬件解码优缺点
解码器有两种模式:软件解码与硬件解码。
软件解码目前业界有比较成熟的 FFmpeg ,利用 CPU 进行解码。
硬件解码发展起步较晚,在 Android 手机上,利用专用解码芯片进行解码。系统提供 MediaCodec ,用于访问底层硬件解码器。
事物都有两面性,两种解码模式各有优缺点,在很多播放器中,两种模式并存。软硬解码的优缺点,对音视频开发者其实算老生常谈了。
说明:在 Android 上,MediaCodec 更加具体来说,是 Google 提供的一套框架,因为各个芯片厂商,手机厂商实现差异,所以经常出现兼容性问题。另外 MediaCodec 的初始化流程长,且一些手机上,需要内部缓存多个帧后才对外输出第一个帧,这两个因素导致硬解在首帧解码速度上明显比软解慢。
1.2 效率对比
1. 软件解码:使用 FFmpeg ,解码后得到 YUV 数据,需要通过 libyuv 转换为 RGB ,渲染上屏。
2. 硬解码 buffer 模式:使用 MediaCodec ,解码后从 buffer 中得到 YUV 数据,需要通过 libyuv 转换为 RGB ,渲染上屏。
3. 硬解码 surface 模式:使用 MediaCodec ,官方说明中 surface 模式为最高效的模式:解码时绑定 surface ,解码后可通过系统 API 直接上屏到 surface。
首帧解码耗时线上统计:
(百度APP版本V11.20.0.14,数据日期:2020年03月20日)
解码帧率和 CPU 占用统计需要进行压测(不进行音视频同步,完全放开解码性能),以下这两项采用线下测试数据。测试源:4K HEVC ,测试机魅族 16th。
说明:解码帧率越高,表示1秒内解码帧数越多,单帧解码耗时更少,性能更高。
CPU 如下图:
由此可以看出,在视频播放上,MediaCodec surface 模式是效率最高的模式,既充分利用了硬解码的优势,又因为系统直接上屏降低了数据拷贝和 YUV 转换 RGB 的耗时,有效降低了 CPU 负载和对内存的消耗。
1.3 痛点
综上所述,在视频播放中,理想状态是尽可能地去用硬解码 surface 模式,其次是使用硬解码 buffer 模式,最后再考虑软解码。但同时需要兼顾首屏解码速度,硬解码的机型兼容性,在这些场景下需要优先使用软解码。
对此,我们需要解决以下痛点:
1. 怎么完善硬解码的兼容性判断?
2. 怎么在保证首屏解码速度的情况下,尽可能使用硬件解码?
二、我们的方案
痛点 1:怎么完善硬解码的兼容性判断?
主流做法:线下测试各种机型硬件解码兼容性,维护静态硬件解码黑名单。
劣势:测试人力成本高,且线下测试很难 cover 线上多种机型;手机型号不断迭代,这种方式,无法保证新的异常机型及时拉黑。
我们的方案 1:在静态硬件解码黑名单机制上,增加解码器监控。
痛点 2:怎么在保证首屏解码速度的情况下,尽可能使用硬件解码?
主流做法:需要保障解码效率的播放场景选择硬件解码,需要保证首屏解码速度则选择软件解码。
劣势:选择软件解码的场景,无法充分发挥手机硬件解码的优势。
我们的方案 2:
划定首屏解码耗时阈值,例如 200ms 。
从解码器监控模块中获取历史硬解码首屏耗时进行预测,若低于阈值,直接使用 MediaCodec surface 模式;高于阈值,使用软解起播,中途无缝切换为 MediaCodec buffer 模式。
如上述,下文具体介绍这 2 个方案。
方案 1:解码器监控
1. 解码器监控模块设计
解码监控模块通过编码类型(H264/HEVC)& profile & level作为一个ID,记录各种编码方式源的软硬件解码情况;
说明:profile 指定视频的压缩率;level 指定分辨率、帧率和码率的。两者都是视频编码的重要特征。同一编码类型,解码器对不同级别的 profile/level 支持可能不同。
记录该编码方式中软硬件解码的首屏解码速度和平均解码速度。
针对硬件解码,还记录了硬件解码器是否存在崩溃;运行次数及运行期间出现异常的次数(包括解码接口抛异常;解码 block 等)。
刚安装百度APP的一段时间内,视频播放会随机使用软/硬件播放,用于采集该机器的解码器运行情况。
2. 流程
起播时,在 prepared 阶段,先通过静态硬解码黑名单,再细分到 编码类型 & profile & level,从解码监控模块看视频源编码方式硬解是否崩溃—>硬解是否异常过多,判断硬解码兼容性是否满足。
从解码监控模块获取当前视频源编码方式使用软硬解码首帧耗时进行首屏耗时的预测,硬解码满足特定首屏耗时时,优先使用硬解码,反之则选软件解码起播。
视频播放后,将本次的首帧解码耗时、解码器运行情况(是否崩溃、是否有异常、每帧平均耗时)更新到监控模块,用于下次播放预测。
对于硬件解码有崩溃、异常过多的情况,我们判定硬件解码存在兼容性问题,用软件解码播放完整个视频。
对于硬件解码首屏耗时超过阈值的,其实兼容性是OK的,那么在用软件解码快速起播后,我们可以用方案2进一步优化。
方案 2:软硬件解码器无缝切换
1. 解码通路的统一
为什么要统一?工欲善其事,必先利其器。
如果有一个统一的解码模块,封装软/硬解码器(包括三种解码方式),对外提供统一接入接口,那么对于 Player 仍然像使用一个普通解码器一样使用。在整个架构实现上更加合理,维护扩展也方便。
模块内部维护前后台解码器,内部状态,切换追帧等逻辑,对外无感。而I帧标识,可切换标识等,均可携带在pkt中传入,这样也不需要对解码模块增加一些解码无关的接口,接口设计更加合理。
2. 解码器切换逻辑
两种时机可以切换:1)播放解码到第二个 GOP;2)Player 发生 seek。
播放到第二个 GOP 切换:
播放开始时,解码模块内打开软解码器作为前台解码器;同时创建后台硬解线程,处于等待状态,并不会阻塞住前台解码任务。
Player(播放器)开始播放,把第一个 GOP 的 pkt(视频包)给解码模块,利用前台解码器(软解)的优势,快速解码首个视频帧用于渲染显示,实现快速起播。
4-5秒后,第二个 GOP 到来,pkt(视频包)携带可切换的flag通知解码模块,同时输入 GOP2 的多个 pkt 给硬解码器在后台解码,进入追帧状态。前台软解码器解码保持不变,输入一个 pkt ,解码一个帧。
当后台硬解码器 PTS 追上软解码器的 PTS ,即可关闭硬解码线程,前后台解码器切换。此过程需保证帧的连续,到达无缝切换,用户无感。
GOP2 的后续的 pkt 和后续的 GOP3/4/5……都会使用 MediaCodec buffer 模式。这样在利用软解保证首帧解码速度的同时,也最大限度的利用了 MediaCodec 的解码优势。
Player 发生 seek 切换:
这种场景逻辑比较简单,在 Player seek 时,需要调用 decoder 的 flush,我们趁此机会把前台解码器切换为硬解码器,后续一直用 MediaCodec buffer 模式即可。
3. 保证解码器无缝切换
追帧和解码器切换过程中有两种情况:
(左图)GOP2 硬解码解码N帧后,才追上软解码,那么这些重复的 frame (灰色部分),需要进行丢弃,避免画面重复和回跳。
(右图)GOP2 硬解码解码第一帧,即已经追上软解码,那么必须填入空 pkt包,将软解码器内部缓存全部输出,避免画面跳变。
三、结语
目前百度APP Android端,在保障首屏速度和解码错误率没有退化的前提下,视频播放中硬件解码占比已达到 87%,如下:
在目前视频业务百花齐放的时代,编解码也在不断发展进步,各种新的编码方式层出不穷,端上也在这个方向上不断强化自身解码能力。解码作为视频播放中重要的一环,可以预见的是,后续我们仍会在端上解码不断进行探索、优化,为用户提供更优的体验。
推荐阅读:
百度爱番番实时CDP建设实践
当技术重构遇上DDD,如何实现业务、技术双赢?
接口文档自动更改?百度程序员开发效率MAX的秘诀
技术揭秘!百度搜索中台低代码的探索与实践
百度智能云实战——静态文件CDN加速
化繁为简–百度智能小程序主数据架构实战总结
百度搜索中台海量数据管理的云原生和智能化实践
---------- END ----------
百度 Geek 说
百度官方技术公众号上线啦!
技术干货 · 行业资讯 · 线上沙龙 · 行业大会
招聘信息 · 内推信息 · 技术书籍 · 百度周边
百度APP视频播放中的解码优化相关推荐
- 百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇
本文由百度技术团队"蔡锐"原创发表于"百度App技术"公众号,原题为<百度App网络深度优化系列<三>弱网优化>,感谢原作者的无私分享. ...
- 百度APP移动端网络深度优化实践分享(一):DNS优化篇
本文由百度技术团队"蔡锐"原创发表于"百度App技术"公众号,原题为<百度App网络深度优化系列<一>DNS优化>,感谢原作者的无私分享 ...
- ijkplayer点播和直播视频 问题 解决及优化,视频播放中可能有的bug
弱网丢帧策略:丢弃原始队列未编码的数据帧,丢弃编码队列的数据帧. 视频移动端播放内核技术:视频加载时长,秒播的体验.流畅度和清晰度都是用户最根本的诉求和最基础的产品体验.播放器的主要工作原理类似于编码 ...
- 前端性能优化实践 | 百度APP个人主页优化
性能是每个前端工程师都应该关注的话题,通用的优化手段已有许多文章和实践,就不再赘述,本篇以百度 App 个人主页为例,聊聊针对业务特点进行的一些性能优化实践.适用于:传统意义的优化手段能用的都用了:打 ...
- html个人主页_前端性能优化实践 之 百度App个人主页优化
作者:潘铭 @祝余 前言 性能是每个前端工程师都应该关注的话题,通用的优化手段已有许多文章和实践,就不再赘述,本篇以百度App个人主页为例,聊聊针对业务特点进行的一些性能优化实践. 适用于:传统意义的 ...
- 百度App网络深度优化系列(一):DNS优化
一.前言 网络优化是客户端几大技术方向中公认的一个深度领域,所以百度App给大家带来网络深度优化系列文章,其中包含系列<一>DNS优化,系列<二>连接优化,系列<三> ...
- 百度App Android启动性能优化-工具篇
一.前言 启动性能是APP的极为重要的一环,启动阶段出现卡顿.黑屏问题,会影响用户体验,导致用户流失.百度APP在一些比较低端的机器上也有类似启动性能问题,为保留存,需要对启动流程做深入优化.现有的性 ...
- 百度App性能优化工具篇 - Thor原理及实践
01 背景 App开发过程中,如果遇到一些疑难问题或者性能问题(如低端机卡顿),由于没法拿到更多系统的有效信息很难有效定位.这时,Hook不失为一种好的解决方案,Hook技术是在程序运行的过程中,动态 ...
- android中添加分页小表情,百度APP表情面板体验升级——小面板大文章
原标题:百度APP表情面板体验升级--小面板大文章 导语:表情面板是百度APP互动场景中非常重要的基础输入体验功能:本文以三个核心设计环节为例,分享在不同设计阶段,对表情面板体验细节的理解和感悟,阐述 ...
最新文章
- LeetCode简单题之数组序号转换
- electron 改变窗体 大小_8个瑜伽常见体式变体,小改变,大不同!
- 【持久化框架】Mybatis简介与原理
- ServletContext 对象
- 火灾自动报警系统及消防设施联动控制
- mysql数据库上传ftp服务器中_备份部分mysql表并上传至指定ftp服务器目录中
- POJ 2808 校门外的树
- Linux多任务编程(三)---exec函数族及其基础实验
- Redhat AS4上中文乱码问题解决方案
- webm格式怎么转换成mp4?几步就能够完成转换
- 生成QQ/MSN/旺旺/SKYPE等在线状态图标
- 读书笔记:《少有人走的路1----心智成熟的旅程》
- 没有Console线,又不知道自己通过哪个IP连接到路由器,怎么办?
- 微信公众号回复小程序链接
- python廖老师课程资源,廖老师的python教程
- php spry文本域_SPRY验证文本域之时间及浏览器设置
- PS2020从入门到卸载
- android类似于ios剪切框图片,不必羡慕 iOS,Android 上也有这些好用的截图处理工具...
- [转]gps中的广义和狭义相对论效应
- 记一次报错原因Error: ENOENT: no such file or directory, open ‘E:\目录‘
热门文章
- 缓存篇(二)- JetCache
- 多数据源,提示无效的绑定语句(Invalid bound statement (not found))
- 账号密码登录和注册业务逻辑
- day23面向对象第一篇
- ff14 人最多的服务器,记录FF14全服人数最少的服务器红茶川
- Linq之IQueryable与IEnumerable
- 【小家Spring】注意BeanPostProcessor启动时对依赖Bean的“误伤”陷阱(is not eligible for getting processed by all...)
- appium关于小米系统连接电脑
- PHP框架设计之 ThinkPHP5 源码解析
- python项目实战:控制Windows电脑桌面壁纸