作者| 阿里文娱无线开发专家 德夫
一、概述
提高客户端视频起播速度一直是比较关键的优化点。如何提高起播速度?除了通过优化网络、提高服务器带宽、优化视频文件码率帧率等常规方案外,还可以从以下两个方面进一步优化:
1)预加载视频数据。在端侧通过预加载部分视频数据,使播放器在起播时可立即读取本地 视频数据,实现秒开起播;
2)边播放边缓存。通过将正在播放的视频数据缓存在本地,实现当用户再次播放时,可立 即从本地缓存读取视频数据进行播放,无需再次从网络下载,从而提高起播速度。
对于大部分播放器,出于使用方便简单的考虑,都是播放器内部实现视频数据下载和缓存 功能。大部分播放器都没有暴露数据回调接口,使得视频数据业务层不可获得,因此也无法做 这方面的优化。
所以,视频本地代理与缓存方案,关键解决的是:如何将播放器自带的下载逻辑,移交给 业务层,使播放器只负责接收数据、播放和播控。
二、技术方案
1. 早期基于系统播放器 API 的实现方案
使用系统播放器 AVPlayer,其提供了 resourceLoader ,可以实现前面所述的接管视频数据 下载的能力。
resourceLoader 原本用于自定义的资源下载,当AVURLAsset 所对应的资源系统无法处理时,就会调用 resourceLoader 的一系列回调方法,让业务层处理资源的下载。 其中比较关键的回调是:
其中 AVAssetResourceLoadingRequest 是 AVURLAsset 的一个数据请求,包含了请求相关的 信息,比如数据请求段等。我们要做的就是根据这些请求信息去获得相应的数据,然后把数据 填充给 AVAssetResourceLoadingRequest,完成这个请求。
通过这样的流程,下载数据的逻辑就移交给了业务层,业务层通过自己创建网络请求,下 载获取到的数据除了填充给 AVAssetResourceLoadingRequest 让播放器正常播放,还可以同时写 入本地做视频缓存。当每次收到 AVAssetResourceLoadingRequest 请求时,可以先尝试从本地读 取缓存数据起播视频。
2. 基于视频本地代理的实现方案
上述基于系统播放器 API 的实现方案,依赖于系统播放器提供的接口。而实际业务场景里, 除了使用系统播放器,可能还会使用一些其他的播放器,例如开源的 ijkplayer 等。这些播放器 不一定提供相应的接口供业务层实现缓存视频数据的功能。因此,一个不依赖播放器实现的方 案就显得更加重要。
因此,淘票票客户端决定采用在端上建立一个本地服务器的方式来实现。通过将视频文件 的网络地址,转换为本地地址,再传给播放器。当播放器开始请求数据时,本地服务器即可获 取该请求,从而接管数据下载等逻辑。
原始的播放器流程(如图 1):
加入本地服务器后的流程(如图 2):
基于这个思路,我们开发了 AliSmartVideoCache 组件。
3. AliSmartVideoCache 组件
AliSmartVideoCache 是一套包含视频本地服务器代理、缓存和预加载的组件。 其整体架构(如图 3):
AliSmartVideoCache 对业务方暴露两个组件,预加载组件和本地代理组件。在设备闲置时, 可以通过预加载组件提前下载部分视频数据,支持指定预加载的数据量以及不同网络环境下预 加载的策略。视频以队列形式预加载。
本地代理组件负责转换视频地址,判断视频资源格式,不同视频格式的本地代理策略以及 本地服务器的维护等。
4. 视频文件缓存
视频的文件缓存部分稍复杂,原因是视频文件缓存数据经常是不连续的。一般情况下,如 果用户从头开始播放视频,那么视频文件理论上是从头开始下载,数据连续。但当用户在播放 过程中,拖动进度条到任意位置时,缓存就会出现下载的数据不连续的情况。
为了最大化缓存所下载的数据,我们开发了基于单个文件的视频缓存组件。其通过在文件 头部维护一个映射表(见图 4),将数据在原始文件的偏移量与本地缓存文件的偏移量建立映射 关系,从而实现不连续的视频数据在缓存文件中的连续缓存(类似 Sparse File)。
5. 整体流程
当本地代理收到视频下载请求后,会先通过业务方指定的规则,从 url 规则来判断视频的 格式类型。如果是 HLS 视频,就会走解析 playlist 文件,替换分片地址的流程;如果是其他视 频格式,则先查找本地缓存数据,将已有缓存数据直接返回,缺失的部分发起网络请求。从网 络获得的数据,在返还给播放器的同时,根据本地策略决定是否写入本地缓存。
三、总结
以上提到的技术,针对一些小细节和特殊情况的处理还是要额外留心的。 比如按照前面的设想,缓存视频开头部分的数据有助于提高视频起播速度,但有些视频的moov 段是置后的,也就是说播放器要起播,必须直接跳到文件尾去下载部分数据,解析 moov 元数据。如此一来,缓存开头部分数据所带来的起播速度提升就会打折扣。因此,在处理淘票票的实际业务场景时,协调服务端做了二次转码来保证移动 moov 段到文件头部。
另外前面也提到了因为用户拖拽而导致的下载策略变化,还需要考虑一种情况,就是服务 端不支持 206 partial content。在这种情况下,客户端不能通过 Content-Range 去指定所需要的 数据位置,请求的数据永远是从文件起始位置开始的,下载策略就需要针对这种情况做特殊处理。
还有比如网络请求失败、重试、数据错误的异常情况,设备磁盘空间不够导致缓存类新建 或扩展文件失败的处理等等,都需要小心处理。
在使用这套视频播放器本地代理组件并配合业务层预加载逻辑后,系统播放器和第三方播 放器的视频秒播率和有效 vv 率都得到了显著的提高,其中秒播率更是达到 95% 以上,效果还是很不错的。