iOS 邊下邊播的實現(xiàn)代碼
項目中之前使用的是AVPlayer直接播放URL地址,但是不知道是相機的wifi不夠穩(wěn)定還是代碼的問題,app總是出現(xiàn)緩沖卡頓,就考慮改寫成邊下邊播的模式,查過了許多資料,發(fā)現(xiàn)大部分都是用的同一種方法
AVAssetResourceLoaderDelegate 代理方法,來看看如何實現(xiàn)
首先要實現(xiàn)兩個必須的代理方法
AVAssetResourceLoaderDelegateObjective-C
#pragma mark - AVAssetResourceLoaderDelegate
//開始加載
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
[self addLoadingRequest:loadingRequest];
return YES;
}
//取消加載
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
[self removeLoadingRequest:loadingRequest];
}
#pragma mark - AVAssetResourceLoaderDelegate
//開始加載
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
[self addLoadingRequest:loadingRequest];
return YES;
}
//取消加載
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
[self removeLoadingRequest:loadingRequest];
}
然后要定義一個下載類,其實就是分段下載數(shù)據(jù)的下載器
AVAssetResourceLoaderDelegateObjective-C
- (void)start {
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[self.requestURL originalSchemeURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:RequestTimeout];
if (self.requestOffset > 0) {
[request addValue:[NSString stringWithFormat:@"bytes=%ld-%ld", self.requestOffset, self.fileLength - 1] forHTTPHeaderField:@"Range"];
}
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
self.task = [self.session dataTaskWithRequest:request];
[self.task resume];
}
#pragma mark - NSURLSessionDataDelegate
//服務(wù)器響應(yīng)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
if (self.cancel) return;
SRQLog(@"response: %@",response);
completionHandler(NSURLSessionResponseAllow);
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
NSString * contentRange = [[httpResponse allHeaderFields] objectForKey:@"Content-Range"];
NSString * fileLength = [[contentRange componentsSeparatedByString:@"/"] lastObject];
self.fileLength = fileLength.integerValue > 0 ? fileLength.integerValue : response.expectedContentLength;
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidReceiveResponse)]) {
[self.delegate requestTaskDidReceiveResponse];
}
}
//服務(wù)器返回數(shù)據(jù) 可能會調(diào)用多次
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
if (self.cancel) return;
//SRQLog(@"收到響應(yīng)了: %@",data);
self.cacheLength += data.length;
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidUpdateCache)]) {
[self.delegate requestTaskDidUpdateCache];
}
}
//請求完成會調(diào)用該方法,請求失敗則error有值
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (self.cancel) {
SRQLog(@"下載取消");
}else {
if (error) {
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidFailWithError:)]) {
[self.delegate requestTaskDidFailWithError:error];
}
}else {
//可以緩存則保存文件
if (self.cache) {
[FileHandle cacheTempFileWithFileName:[NSString fileNameWithURL:self.requestURL]];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidFinishLoadingWithCache:)]) {
[self.delegate requestTaskDidFinishLoadingWithCache:self.cache];
}
}
}
}
- (void)start {
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[self.requestURL originalSchemeURL] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:RequestTimeout];
if (self.requestOffset > 0) {
[request addValue:[NSString stringWithFormat:@"bytes=%ld-%ld", self.requestOffset, self.fileLength - 1] forHTTPHeaderField:@"Range"];
}
self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
self.task = [self.session dataTaskWithRequest:request];
[self.task resume];
}
#pragma mark - NSURLSessionDataDelegate
//服務(wù)器響應(yīng)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
if (self.cancel) return;
SRQLog(@"response: %@",response);
completionHandler(NSURLSessionResponseAllow);
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
NSString * contentRange = [[httpResponse allHeaderFields] objectForKey:@"Content-Range"];
NSString * fileLength = [[contentRange componentsSeparatedByString:@"/"] lastObject];
self.fileLength = fileLength.integerValue > 0 ? fileLength.integerValue : response.expectedContentLength;
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidReceiveResponse)]) {
[self.delegate requestTaskDidReceiveResponse];
}
}
//服務(wù)器返回數(shù)據(jù) 可能會調(diào)用多次
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
if (self.cancel) return;
//SRQLog(@"收到響應(yīng)了: %@",data);
self.cacheLength += data.length;
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidUpdateCache)]) {
[self.delegate requestTaskDidUpdateCache];
}
}
//請求完成會調(diào)用該方法,請求失敗則error有值
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (self.cancel) {
SRQLog(@"下載取消");
}else {
if (error) {
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidFailWithError:)]) {
[self.delegate requestTaskDidFailWithError:error];
}
}else {
//可以緩存則保存文件
if (self.cache) {
[FileHandle cacheTempFileWithFileName:[NSString fileNameWithURL:self.requestURL]];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidFinishLoadingWithCache:)]) {
[self.delegate requestTaskDidFinishLoadingWithCache:self.cache];
}
}
}
}
最后將拿到的數(shù)據(jù)塞進AVAssetResourceLoaderDelegate代理中,交還給AVPlayer,就可以播放了
AVAssetResourceLoaderDelegateObjective-C
- (BOOL)finishLoadingWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
//填充信息
CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(MimeType), NULL);
loadingRequest.contentInformationRequest.contentType = CFBridgingRelease(contentType);
loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
loadingRequest.contentInformationRequest.contentLength = self.requestTask.fileLength;
//讀文件,填充數(shù)據(jù)
NSUInteger cacheLength = self.requestTask.cacheLength;
NSUInteger requestedOffset = loadingRequest.dataRequest.requestedOffset;
if (loadingRequest.dataRequest.currentOffset != 0) {
requestedOffset = loadingRequest.dataRequest.currentOffset;
}
NSUInteger canReadLength = cacheLength - (requestedOffset - self.requestTask.requestOffset);
NSUInteger respondLength = MIN(canReadLength, loadingRequest.dataRequest.requestedLength);
//SRQLog(@"好不容易填充一次");
[loadingRequest.dataRequest respondWithData:[FileHandle readTempFileDataWithOffset:requestedOffset - self.requestTask.requestOffset length:respondLength]];
//如果完全響應(yīng)了所需要的數(shù)據(jù),則完成
NSUInteger nowendOffset = requestedOffset + canReadLength;
NSUInteger reqEndOffset = loadingRequest.dataRequest.requestedOffset + loadingRequest.dataRequest.requestedLength;
if (nowendOffset >= reqEndOffset) {
[loadingRequest finishLoading];
return YES;
}
return NO;
}
- (void)player{
self.resouerLoader = [[ResourceLoader alloc] init];
self.asset = [AVURLAsset URLAssetWithURL:[self.videoUrl customSchemeURL] options:nil];
[self.asset.resourceLoader setDelegate:self.resouerLoader queue:dispatch_get_main_queue()];
_playerItem = [AVPlayerItem playerItemWithAsset:self.asset];
_players = [AVPlayer playerWithPlayerItem:_playerItem];
}
- (BOOL)finishLoadingWithLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
//填充信息
CFStringRef contentType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef)(MimeType), NULL);
loadingRequest.contentInformationRequest.contentType = CFBridgingRelease(contentType);
loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
loadingRequest.contentInformationRequest.contentLength = self.requestTask.fileLength;
//讀文件,填充數(shù)據(jù)
NSUInteger cacheLength = self.requestTask.cacheLength;
NSUInteger requestedOffset = loadingRequest.dataRequest.requestedOffset;
if (loadingRequest.dataRequest.currentOffset != 0) {
requestedOffset = loadingRequest.dataRequest.currentOffset;
}
NSUInteger canReadLength = cacheLength - (requestedOffset - self.requestTask.requestOffset);
NSUInteger respondLength = MIN(canReadLength, loadingRequest.dataRequest.requestedLength);
//SRQLog(@"好不容易填充一次");
[loadingRequest.dataRequest respondWithData:[FileHandle readTempFileDataWithOffset:requestedOffset - self.requestTask.requestOffset length:respondLength]];
//如果完全響應(yīng)了所需要的數(shù)據(jù),則完成
NSUInteger nowendOffset = requestedOffset + canReadLength;
NSUInteger reqEndOffset = loadingRequest.dataRequest.requestedOffset + loadingRequest.dataRequest.requestedLength;
if (nowendOffset >= reqEndOffset) {
[loadingRequest finishLoading];
return YES;
}
return NO;
}
- (void)player{
self.resouerLoader = [[ResourceLoader alloc] init];
self.asset = [AVURLAsset URLAssetWithURL:[self.videoUrl customSchemeURL] options:nil];
[self.asset.resourceLoader setDelegate:self.resouerLoader queue:dispatch_get_main_queue()];
_playerItem = [AVPlayerItem playerItemWithAsset:self.asset];
_players = [AVPlayer playerWithPlayerItem:_playerItem];
}
注意:此方法服務(wù)器端最好支持Range頭,這樣才是分段下載。
總結(jié)
以上所述是小編給大家介紹的iOS 邊下邊播的實現(xiàn)代碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
iOS 檢測網(wǎng)絡(luò)狀態(tài)的兩種方法
一般有Reachability和AFNetworking監(jiān)測兩種方式,都是第三方的框架,下文逐一詳細給大家講解,感興趣的朋友一起看看吧2016-10-10
IOS 實現(xiàn)微信自動搶紅包(非越獄IPhone)
這篇文章主要介紹了IOS 實現(xiàn)微信自動搶紅包(非越獄IPhone)的相關(guān)資料,這里對實現(xiàn)自動搶紅包做一個詳細的實現(xiàn)步驟,需要的朋友可以參考下2016-11-11
詳解iOS開發(fā)中UITableview cell 頂部空白的多種設(shè)置方法
這篇文章主要介紹了詳解iOS開發(fā)中UITableview cell 頂部空白的多種設(shè)置方法的相關(guān)資料,需要的朋友可以參考下2016-04-04
iOS App使用SQLite之句柄的定義及數(shù)據(jù)庫的基本操作
SQLite中在定義過句柄之后就可以指向數(shù)據(jù)庫,從而利用iOS應(yīng)用程序進行打開或關(guān)閉等各種操作,這里我們就來看一下iOS App使用SQLite之句柄的定義及數(shù)據(jù)庫的基本操作2016-06-06

