播放器技术分享(4):首开时间-创新互联
搞音视频开发好些年,分享过许多博客文章,比如:前几年发布的《FFmpeg Tips》系列,《Android 音频开发》系列,《直播疑难杂症排查》系列等等。最近想把多年来开发和优化播放器的经验也分享出来,希望能帮助到音视频领域的初学者。第一期文章要推出的内容主要涉及到播放器比较核心的几个技术点,大概的目录如下:
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:空间域名、网站空间、营销软件、网站建设、科尔沁右翼前网站维护、网站推广。1. 播放器技术分享(1):架构设计
2. 播放器技术分享(2):缓冲区管理
3. 播放器技术分享(3):音画同步
4. 播放器技术分享(4):首开时间
5. 播放器技术分享(5):延时优化
本篇是系列文章的第四篇,主要聊一聊如何优化播放器的首开时间。
1 首开时间的定义
首开时间:从点击播放到第一帧画面显示出来的耗时。通常大家说的 “首屏秒开” 指的就是播放器的“首开时间”在 1s 以内。
首开速度是用户最简单、最直接的体验,所以通常是播放器开发中优化的重点。
下面是一个典型的首开速度和用户感受的关系表:
2 首开时间的影响因子
要优化播放器的首开时间,我们得先了解一下影响播放器首开时间的因素有哪些,下图简单展示了播放器向服务器申请播放一个视频流的全过程。
想优化播放器的首开时间,首先关注一下播放流程中的每个环节,如图所示,可能的优化点列表如下:
申请资源的播放 URL 地址的时机优化 -> 争取在用户点击播放之前拿到 URL
DNS 解析优化 -> 提前完成 DNS 解析,并缓存结果
服务器的连接和数据传输速度优化 -> 主要是服务器节点与播放器之间的网络传输优化
视频流的媒体信息解析优化 -> 主要是解析提取算法的优化
解码和渲染策略优化 -> GOP 缓存,确保首帧为关键帧解码渲染
其他优化手段 -> 测速选线、解码算法性能等
在这个过程中,每一个环节都有一些影响因子会决定播放器的首开时间,我们下面详细展开优化思路。
3 首开优化方法
3.1 优化 URL 的获取时机
如图是一个播放列表,每个视频都会对应一个资源的 URL 播放地址,如果在用户点击视频后,APP 再去后台业务服务器去申请这个 URL 播放地址,无疑增加了一次 HTTP 请求和应答的耗时,特别是网络不稳定的时候,耗时更加明显。
因此,这是一个可以在 APP 层进行的优化点:在拉取视频播放列表的时候,“同时” 把视频的 URL 播放地址也拉取下来,在用户点击视频后无需再向服务器申请播放地址,即可立即开始播放了。
3.2 优化 DNS 解析时间
视频资源的 URL 地址,往往是包含域名的,比如:
http://jhuster.com/video/movie.mp4
播放器在播放前,需要先进行 DNS 解析,把 jhuster.com 这个域名解析为一台服务器的 IP 地址,然后才能通过 TCP 连接上去,发送资源请求。
我们在 17CE 网站上简单测测这个域名解析的时间:
可以看到,平均 DNS 解析时间在 673ms 左右,但是在很多地区(比如:佛山市电信,北京市电信)解析时间都超过 2s 了,可想而知,在这些地区 DNS 解析缓慢对播放器首开时间是致命的伤害。
为了确保所有地区的视频播放不过于受 DNS 解析速度的影响,除了为视频资源的域名购买付费的专业 DNS 解析服务外,播放器层面也可以针对性地做一些优化,如下图所示:
播放器内部新增一个 DNS 结果缓存模块
在异步线程定时执行 DNS 解析,并把 “域名 & IP 表” 缓存在内存中
视频播放时,直接查表,取出域名对应的 IP 地址,送入播放器
注意事项:
一个 APP 的资源域名个数是收敛的,不是无限个,所以可以在 APP 启动的时候,送入播放器提前去完成 DNS 解析和缓存
未提前配置的域名,在第一次解析的时候,依然会首开慢,但该域名第二次即可从本地缓存中取了
需要注意缓存的 IP 地址的刷新:
DNS 解析有一个 TTL 超时时间,到期前要记得重新解析刷新
监测手机网络切换事件,比如:WiFi 切换到 4G 后,需要清空缓存
举个例子:
DNS Cache Map:
如果要播放 URL:http://jhuster.com/video/movie.mp4
可直接替换为播放: http://185.199.108.153/video/moive.mp4
坑在哪 ?
当我们真的用 ip 地址去播放的时候,会发现服务器会拒绝访问,例如报如下错误:
原因:视频资源的 CDN 服务商需要知道是 “谁” 在申请这个视频资源 -> 为了计量和计费,服务商的判断访问依据是“域名”,所以直接使用 IP 访问会遇到上述问题。
怎么解决 ?
HTTP 协议:有个 HOST 字段,记录了服务器的域名
RTMP 协议:有个 tcUrl 参数,记录了完整的播放器地址(含 服务器的域名)
其实 CDN 服务商并不是从 URL 取的域名,而是从 HTTP/RTMP 协议中的上述字段中 “提取” 的域名,因此,我们需要改造播放器底层的 HTTP/RTMP 代码模块,提供一个接口,可以把 URL 中原始的域名填入到上述协议字段中即可。
3.3 优化服务器连接和数据传输时间
播放器通过 DNS 解析拿到了服务器的 IP 地址,下一步就是通过 TCP 连接服务器,然后发送请求读取数据了。在这个过程中,与服务器的连接速度以及数据的传输时间非常重要,直接影响着首开体验。
这个因素并不是在播放器层面可以执行的优化,因此就简单提一下,优化的关键因素在于服务器的负载、CDN 的节点分布和带宽情况了。这也是为什么一般的 APP 公司会采购和使用 CDN 服务的原因了。
3.4 优化媒体信息的读取策略
视频的媒体信息里都有啥 ?
是否包含:音频、视频
音频、视频的编码格式,如 H.264,AAC 等
视频的信息,如 分辨率、帧率、码率
音频的信息,如 采样率、位宽、通道数
码流的总时长
其他附加信息,如 作者、日期等
可见,媒体信息对于初始化播放器还是非常重要的。不同的音视频封装格式,媒体信息存放的位置也不太一样,像 flv 格式,媒体信息往往直接存放在开头,因此是比较容易第一时间读取到的。而 mp4 格式,常常会遇到 moov 在尾部的情况,这种是播放器优化的重点,如图所示:
对于这种把媒体信息存放到了尾部的 mp4 文件,默认的播放器需要把整个 mp4 全部下载下来才能拿到媒体信息,对首开是极其不友好的。
如何优化呢 ?—— 双 IO 技术
如图所示,对于 moov 媒体信息在尾部的 mp4 文件,播放器读取一定数据后,如果判断 moov 在尾部,则可以暂停这个线程,同时启动第二线程通过 http range 字段读取尾部的 moov,从而拿到关键的媒体信息,这样的技术策略的好处是:
无需下载整个 mp4 即可播放 moov 在尾部的视频
第一个 IO 已下载的部分可继续利用,不用丢弃
3.5 优化媒体信息的解析时间
媒体信息解析的工作量在哪 ?
判断码流的封装格式,比如 mp4,flv,m3u8 等等
根据封装格式的协议约定,提取数据中的媒体信息
为了提高对非标准码流的兼容性,ffmpeg 使用了一套非常复杂的解析策略,即使从码流中已经提取到了 metadata,依然会做各种 double check,比如,多次 try_decode_frame 测试是否真的可以成功解码数据,从而导致底层基于 ffmpeg 的播放器,首开速度会在这里降下来。
如何优化呢 ?如果是基于 ffmpeg 内核的播放器,那么常用的手段如下:
减小 probesize
减小 analyzeduration
预设码流的音视频格式
3.6 优化首帧解码和渲染
我们知道,编码后的视频帧是分 I、B、P 帧的,I 帧是关键帧,可独立解码出图像;B/P 帧分别是前向预测帧/双向参考帧,是需要参考 I 帧或前后帧才能解码出图像的。
因此,为了尽快解码出首帧画面,需要确保送入编码器的首帧即是 I 帧。
如图所示,在直播场景下,如果观众在 C 时间点拉流,则正好可以拉取到一个 I 帧,迅速完成解码播放,实现秒开。但是如果不巧,正好在 A 时间点或者 B 时间点拉流,则会导致无法解码,一直要等到下一个 I 帧才能完成解码渲染。
因此,一般的直播云厂商,都会在服务端缓存一个 GOP 的数据,无论任何时候,播放器申请播放,都会首先下发这样一个以 I 帧开头的 GOP 数据,从而加快了播放器的解码和首开。
对于播放器而言,需要注意的时候,当第一帧还没有渲染之前,先不要主动缓冲,而是尽快先渲染首帧。
4 总结
当然,还有很多其他的播放器首开时间的优化策略,测速选线、解码算法性能等,用的不是很广泛,这里就不展开介绍了。关于播放器的首开时间优化,就分享这么多了,如有疑问的小伙伴欢迎来信 lujun.hust@gmail.com 交流。另外,也欢迎大家关注我的新浪微博 @卢_俊 或者 微信公众号 @Jhuster 获取最新的文章和资讯。
分享文章:播放器技术分享(4):首开时间-创新互联
路径分享:http://myzitong.com/article/csihdd.html