iOS之播放器边下边播的实例演示
来源:爱站网时间:2019-02-24编辑:网友分享
在开发iOS时,有时候需要一个播放器,并且需要缓存视频,其实这个时候是边下边播,如果数据完整,可以将视频数据保存到硬盘,那么iOS之播放器边下边播的实例演示大家有了解过吗?下面就让爱站技术频道小编根据问题逐步分析一下吧!
在开发iOS时,有时候需要一个播放器,并且需要缓存视频,其实这个时候是边下边播,如果数据完整,可以将视频数据保存到硬盘,那么iOS之播放器边下边播的实例演示大家有了解过吗?下面就让爱站技术频道小编根据问题逐步分析一下吧!
首先要实现两个必须的代理方法
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]; }
然后要定义一个下载类,其实就是分段下载数据的下载器
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 //服务器响应 - (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]; } } //服务器返回数据 可能会调用多次 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { if (self.cancel) return; //SRQLog(@"收到响应了: %@",data); self.cacheLength += data.length; if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidUpdateCache)]) { [self.delegate requestTaskDidUpdateCache]; } } //请求完成会调用该方法,请求失败则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 //服务器响应 - (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]; } } //服务器返回数据 可能会调用多次 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { if (self.cancel) return; //SRQLog(@"收到响应了: %@",data); self.cacheLength += data.length; if (self.delegate && [self.delegate respondsToSelector:@selector(requestTaskDidUpdateCache)]) { [self.delegate requestTaskDidUpdateCache]; } } //请求完成会调用该方法,请求失败则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]; } } } }
最后将拿到的数据塞进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; //读文件,填充数据 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]]; //如果完全响应了所需要的数据,则完成 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; //读文件,填充数据 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]]; //如果完全响应了所需要的数据,则完成 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]; }
注意:此方法服务器端最好支持Range头,这样才是分段下载。
上面是iOS之播放器边下边播的实例演示,希望对你有帮助。如果您有任何问题,请留言,小编会及时回复您。非常感谢您对爱站技术频道的支持。