推广

iOS 视频边下边播(缓存,预加载)

iseeyu3年前 (2024-02-21)推广130

image.png

具体实现

1.给AVURLAsset设置资源加载代理

AVPlayer在执行播放的时候,就回去问这个delegate,是能能够播放这个asset。于是就可以进行自定义的一些操作

AVURLAsset *asset = [AVURLAsset URLAssetWithURL:assetURL options:nil];
//设置代理
[asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];

2.资源下载及数据填充

找一个对象实现 AVAssetResourceLoaderDelegate 这个协议的方法

//在加载URLAsset资源时回调
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest;

在加载资源的代理方法中看看 request 里面的 url 是不是我们支持的,如果能支持就返回 YES!然后就可以一边下视频数据,一边塞数据给 AVPlayer 让它显示视频画面。数据交互流程图如下:

image.png

下载视频数据

在上面的回调方法中,得到了一个AVAssetResourceLoadingRequest对象,它的主要属性和方法:

@interface AVAssetResourceLoadingRequest : NSObject 
 
 @property (nonatomic, readonly) NSURLRequest *request;
 
 @property (nonatomic, readonly, nullable) AVAssetResourceLoadingContentInformationRequest *contentInformationRequest;
 
 @property (nonatomic, readonly, nullable) AVAssetResourceLoadingDataRequest *dataRequest ;
 
 - (void)finishLoading;
 
 - (void)finishLoadingWithError:(nullable NSError *)error;
 
 @end 

在 AVAssetResourceLoadingRequest 里面,request 代表原始的请求。dataRequest是数据请求,包含数据起始偏移量,数据长度等信息。
AVPlayer 是会触发分片下载的策略,需要从dataRequest 中得到请求范围的信息。
有了请求地址和请求范围,我们就可以重新创建一个设置了请求 Range 头的 NSURLRequest 对象,让下载器去下载这个文件的 Range 范围内的数据。

塞数据给AVPLayer

当 AVPlayer 触发下载时,总是会先发起一个 Range 为 0-2 的数据请求,这个请求的作用其实是用来确认视频数据的信息,如文件类型、文件数据长度。当下载器发起这个请求,收到服务端返回的 response 后,我们要把视频的信息填充到 AVAssetResourceLoadingRequest 的 contentInformationRequest 属性中,告知下载的视频格式以及视频长度。

获取完视频信息后,AVAssetResourceLoader 会继续发起之后的数据片段的请求,下载到的数据就可以塞给 AVAssetResourceLoadingRequest 里的 dataRequest 。 dataRequest 调动下面的方法接收下载的数据,这个方法可以调用多次,接收增量连续的 data 数据。与此同时对下载数据进行本地缓存。

 - (void)respondWithData:(NSData *)data;

当 AVAssetResourceLoadingRequest 要求的所有数据都下载完毕,调用 – (void)finishLoading 完成下载。如果本次请求失败,可以直接调用 – (void)finishLoadingWithError:(NSError *)error; 结束下载。

AVAssetResourceLoadingRequest 在 – (void)finishLoading 的时候,会根据 contentInformationRequest 中的信息,去判断接下去要怎么处理。例如:下载 AVURLAsset 中 URL 指向的文件,获取到的文件的 contentType 是系统不支持的类型,这个 AVURLAsset 将无法正常播放。

下载重试
//在取消加载资源后回调
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest;

AVAssetResourceLoader 在执行加载的时候,会时不时的触发取消下载,在这个回调里面,需要取消当前正在进行中的下载任务。然后重新发起加载请求的策略。如果下载了部分,那么重新发起的下载请求会从还没有下载的部分开始。

3.缓存

根据上面的 AVAssetResourceLoaderDelegate 的实现机制,当 AVAsset 需要加载数据时会通过 delegate 告诉外部,外部接管整个视频下载过程。
当我们接管了视频下载,便可以对视频数据做任何事情。比如:缓存、记录下载速度、获得下载进度等等。

实现一个下载器,用 URLSession 开启一个 DataTask 请求数据,把接收到的数据塞给 DataRequest 并写入本地磁盘。

分片下载

在每次的loadingRequest中,都包含着本次加载请求的dataRequest,他是一个AVAssetResourceLoadingDataRequest对象,看下他的属性:

@interface AVAssetResourceLoadingDataRequest : NSObject

@property (nonatomic, readonly) long long requestedOffset;
@property (nonatomic, readonly) NSInteger requestedLength;

- (void)respondWithData:(NSData *)data;

@end

根据dataRequest中的信息,在创建下载数据的 URLRequest 时需要设置 HTTPHeader 的 Range 值

NSString *range = [NSString stringWithFormat:@"bytes=%lld-%lld", fromOffset, (fromOffset + length -1)];
[request setValue:range forHTTPHeaderField:@"Range"];
取消下载

AVAsset 在加载视频时,经常会在某次数据请求还没有完成时触发取消下载,然后发起一个新的 LoadingReqeust。所以在接到取消下载的代理回调时,需要立刻停止当前正在进行中的下载。由于 DataRequest 的 cancel 操作是异步的,就有可能在 cancel 还未完成时,下一个 LoadingRequest 就已经到来,所以还需要需要保证同一个 URL 同时只存在一个下载器在下载,否则会出现数据混乱的问题。

分片缓存

由于AVAsset请求资源数据的时候,不是完整的视频数据,但是为了方便数据管理和魂村读取,对于同一个视频URL的数据我们应该缓存到同一个文件中,根据range将下载到的数据拼接完整即可。
对于更复杂的场景,比如用户seek操作,还要处理播放进度和已缓存数据以及还未缓存的远程数据之间的协调。(我们的业务暂时不涉及到此场景,具体的处理方案可参考:VIMediaCache文档)

4.预加载

在当前视频播放时,开启下载任务,提前将后面的视频资源下载并缓存到本地。需要切换视频时,根据loadingRequest的url判断本地是否已经缓存了这个视频的数据,根据range从本地读取数据填充到dataRequest中。如果本地没有缓存,从上面第2步,走边下边播逻辑。

不足与展望

现在的预加载处理方式是,提前下载后续几条视频完整的视频数据,因此预加载的任务量大,耗时长。切换视频时,可能预加载的任务还没有完成就被提前终止,然后又开始新的预加载。
最好的处理方式是,预加载的视频,只下载开头的一部分数据缓存,到播放这条视频的时候再边下边播剩余的数据。这里就涉及到这样一个场景,如下图示:

image.png

对于这次的loadingRequest,我们需要从本地缓存中读取一段数据,再从远端下载一部分数据,最后将两部分数据合并填充给dataRequest。

扫描二维码推送至手机访问。

版权声明:本文由西安泽虎代运营发布,如需转载请注明出处。

转载请注明出处https://www.0291.com.cn/post/57610.html

相关文章

西安企业做百度推广,一个月花三千和花三万到底差在哪?

4|最近跟几个西安的老板聊天,发现一个挺有意思的现象:同样做百度推广,有人一个月花三千块,询盘不断;有人一个月砸三万,水花都没见着。问他们区别在哪,大多数人说不清楚,只知道'钱花了,没效果'。 5| 6|百度推广这东西,说复杂也复杂,说简单也简单。核心就一件事:让你的潜在客户搜某个词的时候,你的信息...

我想当策划,大学应该选什么专业?

我想当策划,大学应该选什么专业?

学,广告,传播,公关,这些专业其实都可以。另外也可以学像汉语言文学,以及一些跟文学相关的一些专业,会对你找工作有帮助。但是,你想从事这个这份职业,除了专业的学习之外,更多的是,你要在上学的时候积极参与一些更营销策划相关的社会实践。比如说你可以做一些兼职,比如说帮别人去写稿,...

服装市场营销策略分析,“定位不慎满盘皆输”

服装市场营销策略分析,“定位不慎满盘皆输”

不同的区域需要不同的策略,而不同的营销策略需要不同的销售思路来配合。因此,在研究女装产品销售思路之前,最好先对于市场与营销策略做一次深入地了解。1.市场区域化(market segmentation):目标营销的第一步,是将整个市场拆分成若干个同性质的小市场。2.目标市场的...

晚间悦读丨你的思维方式,决定你的人生高度!

晚间悦读丨你的思维方式,决定你的人生高度!

越长大,越发现,能够决定你人生高度的,往往是你的认知层次。 你的认知在哪个层级,你的人生就处在什么状态。你认知的高度,决定了你人生的高度。 那如何才能升级方式、提升认知能力呢?可以从这三个方面做出改变。 NO. 1 改变态度 有人...

编写项目营销策划方案六大要点

编写项目营销策划方案六大要点

现在商业发展非常迅速,的需求非常的大,但是要做好营销策划是有一定难度的,我把自己做营销策划的一些体会在这里分享给朋友们。营销策划方案六大要点我们先说项目营销策划方案这个话题。大部分的营销策划人都是在企业里工作,大部分项目之初都是来源于一个想法,创始人、老板或者创始团队的一个...

【商场营销策划】如何进行商场营销策划?

【商场营销策划】如何进行商场营销策划?

商场是策划者们关注的永恒话题,那么究竟该如何作好商场营销策划呢?掌握以下这几点营销策略设计原则,至关重要!1.义利兼顾的原则。商场在获取利润的同时要充分考虑到消费者的合法利益和商场的长远利益。在作商场活动营销策略方案的时候应该将这一点作为首要的原则。对商场有利而对顾客不利的...

现在,非常期待与您的又一次邂逅

我们努力让每一部企业宣传片和抖音短视频成为商业大片