淘票票 iOS 客户端:视频本地代理与缓存方案

简介: 提高客户端视频起播速度一直是比较关键的优化点。如何提高起播速度?除了通过优化网络、提高服务器带宽、优化视频文件码率帧率等常规方案外,还可以从哪些方面进行优化呢?一起来看看吧!

作者| 阿里文娱无线开发专家 德夫

一、概述

提高客户端视频起播速度一直是比较关键的优化点。如何提高起播速度?除了通过优化网络、提高服务器带宽、优化视频文件码率帧率等常规方案外,还可以从以下两个方面进一步优化:
1)预加载视频数据。在端侧通过预加载部分视频数据,使播放器在起播时可立即读取本地 视频数据,实现秒开起播;
2)边播放边缓存。通过将正在播放的视频数据缓存在本地,实现当用户再次播放时,可立 即从本地缓存读取视频数据进行播放,无需再次从网络下载,从而提高起播速度。
对于大部分播放器,出于使用方便简单的考虑,都是播放器内部实现视频数据下载和缓存 功能。大部分播放器都没有暴露数据回调接口,使得视频数据业务层不可获得,因此也无法做 这方面的优化。
所以,视频本地代理与缓存方案,关键解决的是:如何将播放器自带的下载逻辑,移交给 业务层,使播放器只负责接收数据、播放和播控。

二、技术方案

1. 早期基于系统播放器 API 的实现方案

使用系统播放器 AVPlayer,其提供了 resourceLoader ,可以实现前面所述的接管视频数据 下载的能力。
resourceLoader 原本用于自定义的资源下载,当AVURLAsset 所对应的资源系统无法处理时,就会调用 resourceLoader 的一系列回调方法,让业务层处理资源的下载。 其中比较关键的回调是:

image.png

其中 AVAssetResourceLoadingRequest 是 AVURLAsset 的一个数据请求,包含了请求相关的 信息,比如数据请求段等。我们要做的就是根据这些请求信息去获得相应的数据,然后把数据 填充给 AVAssetResourceLoadingRequest,完成这个请求。
通过这样的流程,下载数据的逻辑就移交给了业务层,业务层通过自己创建网络请求,下 载获取到的数据除了填充给 AVAssetResourceLoadingRequest 让播放器正常播放,还可以同时写 入本地做视频缓存。当每次收到 AVAssetResourceLoadingRequest 请求时,可以先尝试从本地读 取缓存数据起播视频。

2. 基于视频本地代理的实现方案

上述基于系统播放器 API 的实现方案,依赖于系统播放器提供的接口。而实际业务场景里, 除了使用系统播放器,可能还会使用一些其他的播放器,例如开源的 ijkplayer 等。这些播放器 不一定提供相应的接口供业务层实现缓存视频数据的功能。因此,一个不依赖播放器实现的方 案就显得更加重要。
因此,淘票票客户端决定采用在端上建立一个本地服务器的方式来实现。通过将视频文件 的网络地址,转换为本地地址,再传给播放器。当播放器开始请求数据时,本地服务器即可获 取该请求,从而接管数据下载等逻辑。
原始的播放器流程(如图 1):

image.png

加入本地服务器后的流程(如图 2):

image.png

基于这个思路,我们开发了 AliSmartVideoCache 组件。

3. AliSmartVideoCache 组件

AliSmartVideoCache 是一套包含视频本地服务器代理、缓存和预加载的组件。 其整体架构(如图 3):

image.png

AliSmartVideoCache 对业务方暴露两个组件,预加载组件和本地代理组件。在设备闲置时, 可以通过预加载组件提前下载部分视频数据,支持指定预加载的数据量以及不同网络环境下预 加载的策略。视频以队列形式预加载。
本地代理组件负责转换视频地址,判断视频资源格式,不同视频格式的本地代理策略以及 本地服务器的维护等。

4. 视频文件缓存

视频的文件缓存部分稍复杂,原因是视频文件缓存数据经常是不连续的。一般情况下,如 果用户从头开始播放视频,那么视频文件理论上是从头开始下载,数据连续。但当用户在播放 过程中,拖动进度条到任意位置时,缓存就会出现下载的数据不连续的情况。
为了最大化缓存所下载的数据,我们开发了基于单个文件的视频缓存组件。其通过在文件 头部维护一个映射表(见图 4),将数据在原始文件的偏移量与本地缓存文件的偏移量建立映射 关系,从而实现不连续的视频数据在缓存文件中的连续缓存(类似 Sparse File)。

image.png

5. 整体流程

image.png

当本地代理收到视频下载请求后,会先通过业务方指定的规则,从 url 规则来判断视频的 格式类型。如果是 HLS 视频,就会走解析 playlist 文件,替换分片地址的流程;如果是其他视 频格式,则先查找本地缓存数据,将已有缓存数据直接返回,缺失的部分发起网络请求。从网 络获得的数据,在返还给播放器的同时,根据本地策略决定是否写入本地缓存。

三、总结

以上提到的技术,针对一些小细节和特殊情况的处理还是要额外留心的。 比如按照前面的设想,缓存视频开头部分的数据有助于提高视频起播速度,但有些视频的moov 段是置后的,也就是说播放器要起播,必须直接跳到文件尾去下载部分数据,解析 moov 元数据。如此一来,缓存开头部分数据所带来的起播速度提升就会打折扣。因此,在处理淘票票的实际业务场景时,协调服务端做了二次转码来保证移动 moov 段到文件头部。
另外前面也提到了因为用户拖拽而导致的下载策略变化,还需要考虑一种情况,就是服务 端不支持 206 partial content。在这种情况下,客户端不能通过 Content-Range 去指定所需要的 数据位置,请求的数据永远是从文件起始位置开始的,下载策略就需要针对这种情况做特殊处理。
还有比如网络请求失败、重试、数据错误的异常情况,设备磁盘空间不够导致缓存类新建 或扩展文件失败的处理等等,都需要小心处理。
在使用这套视频播放器本地代理组件并配合业务层预加载逻辑后,系统播放器和第三方播 放器的视频秒播率和有效 vv 率都得到了显著的提高,其中秒播率更是达到 95% 以上,效果还是很不错的。

相关文章
|
3月前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Redission客户端连接Azure:客户端出现 Unable to send PING command over channel
【Azure Redis 缓存】Redission客户端连接Azure:客户端出现 Unable to send PING command over channel
151 3
|
1月前
|
存储 缓存 监控
|
1月前
|
存储 缓存 负载均衡
Nginx代理缓存机制
【10月更文挑战第2天】
62 4
|
3月前
|
测试技术 Linux 虚拟化
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
详细的VMware虚拟机安装macOS Big Sur的保姆级教程,包括下载VMware和macOS镜像、图解安装步骤和遇到问题时的解决方案,旨在帮助读者顺利搭建macOS虚拟机环境。
122 3
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
|
3月前
|
测试技术 开发工具 iOS开发
iOS自动化测试方案(三):WDA+iOS自动化测试解决方案
这篇文章是iOS自动化测试方案的第三部分,介绍了在没有MacOS系统条件下,如何使用WDA(WebDriverAgent)结合Python客户端库facebook-wda和tidevice工具,在Windows系统上实现iOS应用的自动化测试,包括环境准备、问题解决和扩展应用的详细步骤。
230 1
iOS自动化测试方案(三):WDA+iOS自动化测试解决方案
|
3月前
|
测试技术 数据安全/隐私保护 iOS开发
iOS自动化测试方案(四):保姆级搭建iOS自动化开发环境
iOS自动化测试方案的第四部分,涵盖了基础环境准备、iPhone虚拟机设置、MacOS虚拟机与iPhone真机的连接,以及扩展问题和代码示例,确保读者能够顺利完成环境搭建并进行iOS自动化测试。
233 0
iOS自动化测试方案(四):保姆级搭建iOS自动化开发环境
|
3月前
|
测试技术 虚拟化 iOS开发
iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone
这篇文章是iOS自动化测试方案的第二部分,详细介绍了在Xcode开发者工具中构建WebDriverAgent(WDA)应用到iPhone的全过程,包括环境准备、解决构建过程中可能遇到的错误,以及最终成功安装WDA到设备的方法。
170 0
iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone
|
3月前
|
测试技术 开发工具 虚拟化
iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程
这篇文章提供了一份保姆级的教程,指导如何在MacOS虚拟机上安装Xcode,包括环境准备、基础软件安装以及USB扩展插件的使用,以实现iOS自动化测试方案的第一步。
94 0
iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程
|
3月前
|
缓存 监控 NoSQL
【Azure Redis 缓存】Azure Redis出现了超时问题后,记录一步一步的排查出异常的客户端连接和所执行命令的步骤
【Azure Redis 缓存】Azure Redis出现了超时问题后,记录一步一步的排查出异常的客户端连接和所执行命令的步骤
|
3月前
|
缓存 NoSQL Java
【Azure Redis 缓存 Azure Cache For Redis】当使用Jedis客户端连接Redis时候,遇见JedisConnectionException: Could not get a resource from the pool / Redis connection los
【Azure Redis 缓存 Azure Cache For Redis】当使用Jedis客户端连接Redis时候,遇见JedisConnectionException: Could not get a resource from the pool / Redis connection los
114 0