ios短视频播放缓存之道

3次阅读

共计 3217 个字符,预计需要花费 9 分钟才能阅读完成。

一套基于 AVPLayer 短视频播放缓存库 ShortMediaCache GitHub 地址。
主要特点:

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

业务背景
公司电商 APP 接入短视频模块也有半年多的时间了,之间一直在忙着完善业务功能,现在是时候沉淀下来总结这一路来的收获。
视频播放对于 ios 开发来说其实并不是一个难事儿,简单几行代码就能实现,确实,最初的短视频播放也是基于此,给定视频 url 直接丢给系统播放器(AVPlayer)就可以播放了。但是随着短视频业务发力,短视频模块在 APP 业务中承担了更多更重要的角色,如何提升短视频的播放速度变得尤为重要,随之便提出了短视频边播变缓存,短视频预加载相关功能要求。
业务分析,公司 APP 主业务是电商,短视频作为为电商引流业务,提高 APP 活跃度的业务模块,同时在 APP 其他业务功能中也存在视频播放,例如商品详情页面商品介绍,基于此设计之初并不打算将所有的播放业务耦合在一起,因为短视频的播放概率远远大于其他长视频,依次业务需求大致分为 2 类逻辑,短视频和在线播放,对于短视频统一按照短视频播放模块来执行边播变缓存,而其他的相对比较长一些的视频则直接在线播放也不缓存,此处也不做过多介绍。
边播边缓存的实现
短视频播放特点:1、全屏播放 2、快速播放,争取每个短视频都能秒播 3、内容高度浓缩,无需进度条与拖拽进度 4、精彩的短视频可能会被重复观看几次 5、其他 (声音控制、流量)
基于以上特点,可以大致将短视频播放划分为 2 个层级,第 1 层为播放器层,第 2 层为缓存层,播放器层是基于缓存层的,主要负责播放过程控制和 UI 展现,比如暂停,继续,声音控制,暂停播放显示控制以及其他的 UI;播放器层对于每个 APP 可能会有不同的业务需求,实现的功能也大不相同,故将缓冲层与播放器层剥离,而缓存层则主要负责短视频内容的下载,预加载,缓存管理,这也是 ShortMediaCache 的主要功能。
如何从缓存播放
ShortMediaCache 缓存播放逻辑大致的实现结构如下图:

对于 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 对象
持续更新
ShortMediaCache 大致类调用逻辑图如下:

更多功能细节和使用方式请前往 ShortMediaCacheGitHub 地址,下载源码运行 Demo 体验,后续会持续完善此库和其 Demo, 如果喜欢欢迎 Star, 使用问题请 Issue.
参考:https://mp.weixin.qq.com/s/v1…http://msching.github.io/blog…

正文完
 0