播放器技术分享(4):首开时间

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 表” 缓存在内存中

2. 视频播放时,直接查表,取出域名对应的 IP 地址,送入播放器

注意事项:

一个 APP 的资源域名个数是收敛的,不是无限个,所以可以在 APP 启动的时候,送入播放器提前去完成 DNS 解析和缓存

未提前配置的域名,在第一次解析的时候,依然会首开慢,但该域名第二次即可从本地缓存中取了

需要注意缓存的 IP 地址的刷新:

DNS 解析有一个 TTL 超时时间,到期前要记得重新解析刷新

监测手机网络切换事件,比如:WiFi 切换到 4G 后,需要清空缓存

举个例子:

坑在哪 ?

当我们真的用 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 总结

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20181222G16IQK00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券