淘票票 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
167 3
|
1月前
|
存储 缓存 监控
|
1月前
|
存储 缓存 负载均衡
Nginx代理缓存机制
【10月更文挑战第2天】
69 4
|
6月前
|
存储 缓存 编解码
实现iOS平台的高效图片缓存策略
【4月更文挑战第23天】在移动应用开发领域,尤其是图像处理密集型的iOS应用中,高效的图片缓存策略对于提升用户体验和节省系统资源至关重要。本文将探讨一种针对iOS平台设计的图片缓存方案,该方案通过结合内存缓存与磁盘缓存的多层次结构,旨在优化图片加载性能并降低内存占用。我们将深入分析其设计理念、核心组件以及在实际场景中的应用效果,同时对比其他常见缓存技术的优势与局限。
|
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
118 0
|
5月前
|
缓存 NoSQL Java
Redis系列学习文章分享---第四篇(Redis快速入门之Java客户端--商户查询缓存+更新+双写一致+穿透+雪崩+击穿+工具封装)
Redis系列学习文章分享---第四篇(Redis快速入门之Java客户端--商户查询缓存+更新+双写一致+穿透+雪崩+击穿+工具封装)
71 0
|
6月前
|
移动开发 iOS开发 Perl
iOS客户端和h5页面的互相调用,服务器和客户端间通信方式
iOS客户端和h5页面的互相调用,服务器和客户端间通信方式
86 0
|
6月前
|
缓存 定位技术 iOS开发
清除ios的缓存
清除ios的缓存
39 0
|
7天前
|
安全 数据处理 Swift
深入探索iOS开发中的Swift语言特性
本文旨在为开发者提供对Swift语言在iOS平台开发的深度理解,涵盖从基础语法到高级特性的全面分析。通过具体案例和代码示例,揭示Swift如何简化编程过程、提高代码效率,并促进iOS应用的创新。文章不仅适合初学者作为入门指南,也适合有经验的开发者深化对Swift语言的认识。
24 9