欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~

本文由QQ音乐技术团队发表于云+社区专栏

一、问题背景与分析

不久前,团队发现其Android平台App在播放MV视频《凤凰花开的路口》时,会带有如电流声一般的杂音,这影响了用户体验。 研发同学在初步定位时,发现有如下特征:

  • Android平台杂音问题必现;
  • iOS、PC平台能正常播放,没有噪音。

然而,各平台都是统一用HLS格式播放,即源头都是一样的。对于该问题,我们的定位思路如下:

  1. 梳理视频播放流程;
  2. 找到切入点排查。

二、播放流程概览

img

分析播放流程如上图(图中内容从左往右),概括其关键步骤如下:

  1. 播放器初始化:

    • 创建读数据线程:read_thread
    • 创建存放audio解码前数据的队列:audioq
    • 创建存放audio解码后数据的队列:sampq
  2. 数据读取:
    • ①创建context;
    • ②探测协议类型:avformat_open_input
    • ③探测媒体类型:avformat_find_stream_info
    • ④获取音视频流:av_find_best_stream
    • ⑤打开媒体解码器:stream_component_open
    • ⑥读取媒体数据,获得AVPacket:av_read_frame(ic, pkt)
    • ⑦音视频数据分别送入audioq中;
    • 重复⑥、⑦步骤到数据完毕。
  3. 音频解码:
    • audio_thread中对audioq中的数据进行decoder_decode_frame解码;
    • 解码后的帧AVFrame存放到sampq中;
  4. 音频播放:
    • aout_thread_n中,通过调用回调接口sdl_audio_callback,对sampq中的音频帧数据进行解码成PCM数据;
    • 写入PCM数据到buffer数组,并由AudioTrack播放。

三、问题分解与切入

在梳理出播放流程后,标记出找到有可能出错的环节,方便进行“分层定位”(图中黄色标记)

  • 播放下载文件是否有问题;
  • 数据读取是否有问题;
  • 音频解码逻辑是否有问题;
  • AudioTrack的设置是否有问题;

接下来,根据难易程度,对上述环节逐个验证。

1、播放下载文件是否正常

把Android平台播放的ts文件与各平台的进行比对,发现两者一样,该环节正常。

2、AudioTrack设置是否正常

通过日志检查AudioTrack以下配置参数:

  • 采样率
  • 位深
  • 频道

以上参数设置的值与音频流的相符合,该环节正常。

3、音频解码逻辑是否有问题

验证解码逻辑是否有问题,可以通过对PCM数据进行分析来确认。 对aout_thread_n进行修改,将PCM数据额外输出到本地,并与正常的PCM数据进行对比。

正常PCM数据频谱图:

img

异常PCM数据频谱图:

img

正常PCM数据波形图:

img

异常PCM数据波形图:

img

对比分析可得出:

  • 从频谱图中看出,异常的PCM在人耳十分敏感的频响(1000~8000Hz )区域内的音频数据严重缺失,导致“杂音问题”
  • 从波形图中看出,异常的与正常的无声区和有声区都吻合,若解封装、解码逻辑出现异常,极大几率是呈现无波动(一条直线的形式)情况。因此可以先大胆假设解码、解封装逻辑是符合预期的

若解码逻辑正常,再结合之前已经验证文件下载正常。可以推测是数据读取环节出现异常

4、数据读取是否有问题

通过对数据读取的各步骤增加日志后,发现在av_find_best_stream音频流选择时出现异常: ffmpeg -i 发现,该视频ts分片有2个音频流

img

通过强制分别读取两条音频流数据播放,发现:

  • 第一条正常播放(PCM数据正常)
  • 第二条播放杂音(PCM数据异常)
  • Android平台选择了第二条进行播放

基于此,也就验证了在第3步中的假设是正确的。

由上分析,可以得出结论:Android平台选择了第二条数据有问题的流进行播放。

四、问题根源:音频流选择

1、选择方式

分析代码,大致如下所列,av_find_best_stream函数选择音频流,该函数会根据2个主要参数进行选择:

  1. 各音频流的在探测媒体类型(avformat_find_stream_info)时,额外解码出来的帧数(选择多的)
  2. 各音频流的比特率(选择高的)
int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type,int wanted_stream_nb, int related_stream,AVCodec **decoder_ret, int flags)
{for (i = 0; i < nb_streams; i++) {count = st->codec_info_nb_frames; //音频流探测中解码的帧数bitrate = avctx->bit_rate;//音频流的比特率multiframe = FFMIN(5, count);//先比较解码帧数,再比较音频流比特率,谁大谁选if ((best_multiframe >  multiframe) ||(best_multiframe == multiframe && best_bitrate >  bitrate) ||(best_multiframe == multiframe && best_bitrate == bitrate && best_count >= count))continue;best_count   = count;best_bitrate = bitrate;best_multiframe = multiframe;ret          = real_stream_index;//最后选择的流indexbest_decoder = decoder;}   return ret;
}

在该视频中,我们可以看到:

codec_info_nb_frames bit_rate
audio_stream 1 38 122625
audio_stream 2 39 126375

第二条流的解码帧数和比特率要比第一条高,因此选择了第二条流播放

2、对比同类方案

分析了以上选择规则后,我们对各平台、框架进行了选择规则的对比:

img

备注:

  • ExoPlayer对多音频流的ts分片支持不完善(issue),因此测试时需要调整相关接口。但选择规则依然以上述所示(DefaultTrackSelector)
  • iOS和PC平台采用闭源组件,因此测试时使用了**“互换两条音频流顺序”**的方法进行测试。互换后,两平台都播放了杂音音频流 ffmpeg -i INPUT_FILE -map 0:0 -map 0:2 -map 0:1 -c copy -y OUTPUT_FILE
  • QuickTime同样是闭源,互换音频流后无法明显差别,通过合成第三条音频流,来验证是它是对所有音频流全播放 ffmpeg -i INPUT_FILE_1 -i INPUT_FILE_2 -map 0:0 -map 0:1 -map 0:2 -map 1:0 -c copy OUTPUT_FILE

3、总结

从以上数据看到,iOS和PC平台会默认选择第一条流,而在Android平台的FFmpeg和ExoPlayer会根据音频流属性来选择数值更好的一条。

  • “默认选择第一条”方案能更容易地把音源问题暴露
  • “比较音频流属性”方案能更大几率地选择质量更好的流来提升用户体验。

但以上2个选择方案都无法识别“内容异常”的音频流。

五、问题解决方案

因此,处理该问题,需要从音源上进行修复和规避,我们的建议是从源头杜绝,从终端规避:

  1. 编辑重新上架正常音源;
  2. 短期内增加双音频流的检测上报,帮助后台、编辑进行复查;
  3. 长远看由后台开发工具,分别对存量视频进行双音频流检测和对增量视频保证只转码单音频流;

参考资料

  • https://ffmpeg.org/doxygen/2.8/
  • https://github.com/google/ExoPlayer
  • https://www.jianshu.com/p/daf0a61cc1e0
  • https://www.jianshu.com/p/a6a4bf59cdae
  • http://km.oa.com/articles/show/319627
  • https://codeday.me/bug/20170711/39603.html

相关阅读
wamp2.0配置Zend Optimizer
藏匿在邮件里的“坏小子”
打造一个个人阅读追踪系统
【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

此文已由作者授权腾讯云+社区发布,更多原文请点击

搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!

海量技术实践经验,尽在云加社区!

5步告诉你QQ音乐的完美音质是怎么来的,播放器的秘密都在这里相关推荐

  1. QQ音乐远程控制,旧iPhone连音响当播放器,另一个手机远程控制

    2017/2/7日更新,适配新版qq音乐接口.修复主控端不显示封面图片. 有套惠威的低音炮,音质不错,经常将退役的iPhone 4s连上听歌. 由于音响不是蓝牙的,所以就萌生了旧手机耳机孔直连音响做播 ...

  2. vue+element高度仿照QQ音乐,完美实现PC端QQ音乐

    一.前言 QQ音乐官网:点击访问 作者成品效果预览:点击访问 作者其他博客成品汇总预览:点击访问 暂时源码并没有提供其他获取渠道,私聊作者获取即可,或通过博客后面名片添加作者,很简单! 二.主要功能点 ...

  3. PureCodec 2021 完美解码 全能超高清解码播放器

    前言 完美解码是一款为众多影视发烧友精心打造的专业高清播放器.超强HDTV支持,画质远超主流播放器! 解码设置中心"预设多种解码模式,使用默认模式即可获得良好播放效果,有经验的用户更可自行调 ...

  4. 【音乐App】—— Vue-music 项目学习笔记:播放器内置组件开发(一)

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 播放暂停 前进后退 一.播 ...

  5. php html5 播放器,html5实现完美兼容各大浏览器的播放器_html5教程技巧

    歌词同步播放器-powered by widuu xiaowei [ar:测试用 ] [00:03.00]洋葱 [00:06.00]演唱:平安 [00:09.00] [00:11.38]如果你眼神能够 ...

  6. html5视频自动播放兼容谷歌浏览器,html5实现完美兼容各大浏览器的播放器

    歌曲播放我们会发现他的兼容性不是很好,譬如IE上能播放的flash播放器,再firfox或者chrome上就不是很好的应用了,因为有插件的阻碍!HTML5的出现让这一切成为了可能,但是播放器虽然播放了 ...

  7. 有自定义皮肤的计算机,QQ音乐怎么自定义皮肤丨QQ音乐自定义皮肤图解

    在使用QQ音乐的时候,突然觉得自己的播放器主页面不是那么精彩怎么办,这时候你可以通过皮肤的更换来解决,那么QQ音乐怎么自定义皮肤,为此电脑系统城为你带来一个详细的QQ音乐自定义皮肤方法介绍,让你可以轻 ...

  8. 依米花音乐播放器php源码下载

    仿依米花音乐播放器是一款简约的HTML悬浮音乐播放器,免费分享和之前分享的绚丽彩虹在线音乐播放器生成源码差不多,功能界面都是大同小异的.这款依米花音乐播放器php源码支持网易云/QQ音乐,可搭建类是与 ...

  9. python爬取qq音乐周杰伦_Python爬取20万条评论,告诉你周杰伦为啥弄崩QQ音乐?

    作者 | 哈哈浩 责编 | 伍杏玲 9 月 16 日晚间,周董在朋友圈发布了最新单曲<说好不哭>. 发布后,真的让一波人哭了,一群想抢鲜听的小伙伴直接泪奔. 因为 QQ 音乐直接被搞崩了! ...

最新文章

  1. Awk使用案例总结(运维必会)
  2. Visual Assist X 安装、使用 和 快捷键
  3. 细说Android 4.0 NDK编程pdf
  4. 南明区将引进和培养大数据高端人才逾千名
  5. javascript继承机制
  6. 深度学习模型建立过程_所有深度学习都是统计模型的建立
  7. 【计蒜客 - 2019南昌邀请赛网络赛 - M】Subsequence(字典树,dp预处理)
  8. RT-Thread的线程(任务)处理【RT-Thread学习笔记 2】
  9. 微信qq一键登录php代码6,Laravel6实现第三方 微信登录
  10. 变位齿轮重合度计算公式_渐开线圆柱齿轮传动的重合度计算.pdf
  11. 列表页 编辑页 删除页
  12. Oracle查询优化改写技巧与案例总结三
  13. GRE_××× 配置(建议选择Cisco2811路由器)
  14. unity 导入 obj 模型 和 json 数据
  15. 国家开放大学计算机网络技术毕业设计,精编国家开放大学毕业论文:购物网站设计...
  16. GitLab版本升级
  17. python春节对客流量的影响_2018年2月各城市地铁日均客流、春节长假日均客流分析...
  18. 键盘上的按键--键码 对应表
  19. php 时区对应的地区,PHP 输出的各个时区对应的时差表
  20. layui表头样式_layui表格的样式设置

热门文章

  1. 用Scipy实现K-means聚类算法
  2. 未来云计算虚拟化技术的发展趋势
  3. 西瓜视频解析原理及源码,使用CRC32的签名算法,获得视频源地址
  4. 鲲鹏云服务器运行python项目_鲲鹏云实验-Python+Jupyter机器学习基础环境
  5. ajax学员信息php,PHP开源AJAX框架
  6. PCL中点云特征描述与提取精通级实例解析
  7. SpringBoot接入支付宝沙箱返回支付二维码
  8. Python计算:sympy解数学方程
  9. quartz原理 java_Quartz原理解密
  10. java Date days_JAVA的Date类与Calendar类(常用方法)