iOS短视频播放缓存之道

一套基于AVPLayer短视频播放缓存库ShortMediaCache GitHub地址ios

主要特色:git

  • 1.为短视频量身设计,接入方便,不侵占业务
  • 2.边播变缓存,缓存后直接播放
  • 3.预加载功能,秒播下一条短视频
  • 4.自动缓存管理

原文地址github

业务背景

公司电商APP接入短视频模块也有半年多的时间了,之间一直在忙着完善业务功能,如今是时候沉淀下来总结这一路来的收获。缓存

视频播放对于ios开发来讲其实并非一个难事儿,简单几行代码就能实现,确实,最初的短视频播放也是基于此,给定视频url直接丢给系统播放器(AVPlayer)就能够播放了。可是随着短视频业务发力,短视频模块在APP业务中承担了更多更重要的角色,如何提高短视频的播放速度变得尤其重要,随之便提出了短视频边播变缓存,短视频预加载相关功能要求。网络

业务分析,公司APP主业务是电商,短视频做为为电商引流业务,提升APP活跃度的业务模块,同时在APP其余业务功能中也存在视频播放,例如商品详情页面商品介绍,基于此设计之初并不打算将全部的播放业务耦合在一块儿,由于短视频的播放几率远远大于其余长视频,依次业务需求大体分为2类逻辑,短视频和在线播放,对于短视频统一按照短视频播放模块来执行边播变缓存,而其余的相对比较长一些的视频则直接在线播放也不缓存,此处也不作过多介绍。app

边播边缓存的实现

短视频播放特色:
一、全屏播放
二、快速播放,争取每一个短视频都能秒播
三、内容高度浓缩,无需进度条与拖拽进度
四、精彩的短视频可能会被重复观看几回
五、其余(声音控制、流量)ide

基于以上特色,能够大体将短视频播放划分为2个层级,第1层为播放器层,第2层为缓存层,播放器层是基于缓存层的,主要负责播放过程控制和UI展示,好比暂停,继续,声音控制,暂停播放显示控制以及其余的UI;播放器层对于每一个APP可能会有不一样的业务需求,实现的功能也大不相同,故将缓冲层与播放器层剥离,而缓存层则主要负责短视频内容的下载,预加载,缓存管理,这也是ShortMediaCache的主要功能。url

如何从缓存播放

ShortMediaCache缓存播放逻辑大体的实现结构以下图:spa

结构图.png

对于AVPlayer链接播放器层与缓存层的数据交互是经过自定义实现AVAssetResourceLoaderDelegate协议实现的,在播放器加载的过程当中,播放器会经过AVPlayerItem向AVURLAsset的resourceLoader获取须要加载数据信息,好比加载的数据偏移,大小等,最终这些数据请求(AVAssetResourceLoadingRequest)会到达其代理(AVAssetResourceLoaderDelegate)对象,代理对象根据请求数据的位置和大小,去读取相关文件缓存数据,而后回填给请求,以此来响应播放器的数据缓冲请求,与此同时缓存层经过网络请求将下载下来的数据写入文件保存。线程

对于AVAssetResourceLoaderDelegate协议主要须要实现如下方法:

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

播放器的数据加载请求会放到loadingRequest里面,经过其dataRequest对象的requestedOffset和requestedLength能够知道本次数据请求的区块,从缓存文件中按需读取数据填充后执行finishLoading方法便可完成本次数据请求

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

请求取消回调

下载

对于下载应该放到子线程中去经过NSURLSession来实现,由于视频文件可能以前已经缓存了部分,须要从已缓存的位置大小处继续下载缓存,在每次开启下载前须要去读取已缓存文件的大小,并设置请求头部字段Range即可今后处继续下载后面未下载的部分。

NSString *range = [NSString stringWithFormat:@"bytes=%ld-", (long)cachedSize];
[downloadRequest setValue:range forHTTPHeaderField:@"Range"];

因为针对短视频的播放不存在进度拖拽或seek功能,因此每次下载到的数据能够直接经过缓存管理的相关方法直接append到缓存文件末尾。
由于短视频的播放首要任务就是保证当前单个视频的流畅播放,因此在理论上只会存在一个下载任务来独享全部的下载带宽,当在空闲状态的状况下才适合去作其余的短视频资源的预加载。

缓存管理

缓存主要建立了三个目录管理,分别为temp、media和trash目录,缓存分为临时缓存和最终缓存,当短视频资源未下载完时是放在一个目录下的(temp目录)、而当视频资源缓存完时移动到另一个目录(media),这样分别存放便能方便读取和管理两种状态的缓存,全部须要删除的缓存文件都是先移入trash目录,随后再删除以此来保证较高的删除效率。全部文件命名使用的是视频资源的url md5值保证惟一性。

缓存应该具备自动管理功能,以防止其无限膨胀,默认配置下ShortMediaCache容许临时缓存最多保存1天,最大100Mb,而最终缓存则容许最多保存2天最大200Mb,若是业务须要能够自定义ShortMediaCacheConfig配置实现。

预加载

要实现下一个视频或者几个视频能快速的播放起来,预加载的下载任务应该和正常的边下边播任务区分开,由于首先应该保证正在播放的短视频能顺畅的播放,因此边下边播任务优先级应该高于预加载任务,在没有边下边播任务时才能执行预加载任务,而且当有新的边下边播任务时应当中止当前的预加载任务,首要执行边下边播任务。

ShortMediaCache提供了预加载功能实现,经过调用ShortMediaManager如下方法:

- (void)resetPreloadingWithMediaUrls:(NSArray<NSURL *> *)mediaUrls;

使用者能够屡次调用此方法,来不断更新须要预加载的资源队列

ShortMediaCache使用方式

下载源码文件,将ShortMediaCache文件夹引入工程, 经过ShortMediaResourceLoader来建立AVPlayer须要播放视频的AVPlayerItem便可

#import "ShortMediaResourceLoader.h"
ShortMediaResourceLoader _resourceLoader = [ShortMediaResourceLoader new];
AVPlayerItem _playerItem = [_resourceLoader playItemWithUrl:videoUrl]; 
AVPlayer _player = [AVPlayer playerWithPlayerItem:_playerItem];

正常状况下应该持有_resourceLoader对象

预加载视频

[[ShortMediaManager shareManager] resetPreloadingWithMediaUrls:preloadUrls];

preloadUrls存放须要预加载的视频url

持续更新

ShortMediaCache大体类调用逻辑图以下:

类图.png

更多功能细节和使用方式请前往ShortMediaCacheGitHub地址,下载源码运行Demo体验,后续会持续完善此库和其Demo,若是喜欢欢迎Star,使用问题请Issue.

参考:
https://mp.weixin.qq.com/s/v1...
http://msching.github.io/blog...

相关文章
相关标签/搜索