AVPlayer 视频缓存

AVPlayer 视频缓存

背景

目前买家版发布视频动态以及自动播放功能已经上线,视频白名单也已经全量开发。如果直接使用URL通过AVPlayer播放,系统并不会进行缓存,每次播放都必须重新下载。对于用户而言,流量是极大的消耗,播放体验也不够友好。

AVAssetResourceLoaderDelegate

AVAssetResourceLoaderDelegate:专门用来处理AVAsset资源加载的协议。
使用方式:

1
2
AVURLAsset *urlAsset = ...
[urlAsset.resourceLoader setDelegate:<AVAssetResourceLoaderDelegate> queue:dispatch_get_main_queue()];

设置了resourceLoaderdelegate 后,AVPlayer将把视频资源的下载工作交给AVAssetResourceLoaderDelegate来完成。

AVAssetResourceLoaderDelegate 主要有以下两个方法,分别会在资源开始下载以及取消时被执行:

是否拦截资源下载请求

1
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest;

取消请求

1
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest

AVAssetResourceLoadingRequest 分析

AVAssetResourceLoadingRequest携带了AVPlayer的请求信息,主要有以下几个属性:

  • NSURLRequest *request: 视频的URL相关信息

  • AVAssetResourceLoadingContentInformationRequest *contentInformationRequest: 视频文件的信息请求,主要是为了获取视频类型、视频大小等相关信息,该请求会在视频第一个AVAssetResourceLoadingRequest中携带。

  • AVAssetResourceLoadingDataRequest *dataRequest: 视频数据请求,指定了视频请求的数据范围,每次请求完成后,都要通过dataRequestresponse塞给AVPlayer

AVAssetResourceLoaderDelegate 实现视频请求流程图

如何实现视频缓存

AVAssetResourceLoadingRequest视频请求实际上就是Http文件下载过程,需要通过URLSession创建一个DataTask请求数据。通过以上的分析,我们知道视频下载是一个分片下载的过程,因此视频缓存也应该是基于分片的缓存。而因为有了缓存的存在,当AVPlayer发起一个AVAssetResourceLoadingRequest请求了,就有可能一部分数据命中缓存,而一部分则没有。这时候我们就需要就AVAssetResourceLoadingRequest请求拆分成本地请求与远端请求了,拆分请求需要根据已缓存的数据来进行,因此需要一个缓存配置模块来存储,已缓存视频的信息。如下图所示:

内存缓存还是磁盘缓存?

视频文件一般都比较大,如果采用内存缓存会对内存造成很大的压力,因此采用磁盘缓存,虽然磁盘缓存的读取速度要比内存慢,但对于视频来说其实可以忽略不计了。

其他

同一个url的视频缓存在同一个文件中,为了避免多线程同步的问题,因此同一时间同一个视频url不能存在多个下载请求

整体架构设计

缓存策略

既然是缓存,那么缓存策略就是必不可少的了。这里视频缓存参考了SDWebImage的缓存方案,采用了LRU缓存。主要通过过期时间与最大缓存空间两个维度来清理缓存。