我使用AVAssetResourceLoaderDelegate进行视频缓存,但视频会在完全下载后播放。 我将KVO观察者添加到loadedTimeRanges属性:
[self.player.currentItem addObserver:self
forKeyPath:@"loadedTimeRanges"
options:NSKeyValueObservingOptionNew
context:nil];
检查范围并开始播放:
- (void)checkRanges {
if (self.player.currentItem.asset) {
CMTimeRange loadedTimeRange =
[[self.player.currentItem.loadedTimeRanges firstObject] CMTimeRangeValue];
Float64 videoDuration = CMTimeGetSeconds(self.player.currentItem.asset.duration);
Float64 buffered = CMTimeGetSeconds(loadedTimeRange.duration);
Float64 percent = buffered / videoDuration;
if (percent > 0.2) {
[self.player play];
}
}
}
但是通知无法正常工作,出于某种原因,我会在视频下载时收到通知。 视频下载是通过使用AVAssetResourceLoaderDelegate实现的,允许在视频播放中使用缓存。 下载在方法AVAssetResourceLoaderDelegate:
中初始化func resourceLoader(_ resourceLoader: AVAssetResourceLoader,
shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
if let resourceURL = loadingRequest.request.url, resourceURL.isVCSVideoScheme(),
let originalURL = resourceURL.vcsRemoteVideoURL() {
let assetLoader: VideoAssetLoader
if let loader = assetLoaderForRequest(loadingRequest) {
assetLoader = loader
} else {
assetLoader = VideoAssetLoader(url: originalURL)
assetLoader.delegate = self
assetLoaders[keyForAssetLoaderWithURL(resourceURL)] = assetLoader
}
assetLoader.addRequest(loadingRequest)
return true
}
return false
}
VideoAssetLoader接收带有文件信息的HEAD请求,然后更新AVAssetResourceLoadingRequest:
private func fillInContentInformation(_ contentInformationRequest: AVAssetResourceLoadingContentInformationRequest?) {
guard let contentInformationRequest = contentInformationRequest,
let contentInformation = self.contentInformation else {
return
}
contentInformationRequest.isByteRangeAccessSupported = contentInformation.byteRangeAccessSupported
contentInformationRequest.contentType = contentInformation.contentType
contentInformationRequest.contentLength = Int64(contentInformation.contentLength)
}
然后VideoAssetLoader下载请求的字节范围,然后更新AVAssetResourceLoadingDataRequest:
private func processPendingRequests() {
for request in pendingRequests {
fillInContentInformation(request.contentInformationRequest)
let didRespondCompletely = respondWithDataForRequest(request.dataRequest)
if didRespondCompletely {
request.finishLoading()
}
}
pendingRequests = pendingRequests.filter({ !$0.isFinished })
}
private func respondWithDataForRequest(_ dataRequest: AVAssetResourceLoadingDataRequest?) -> Bool {
guard let dataRequest = dataRequest, let downloadTask = videoDownloadTask else {
return false
}
var startOffset: UInt64 = UInt64(dataRequest.requestedOffset)
if dataRequest.currentOffset != 0 {
startOffset = UInt64(dataRequest.currentOffset)
}
let numberOfBytesToRespondWith = UInt64(dataRequest.requestedLength)
var didRespondFully = false
if let data = downloadTask.readCachedDataWithOffset(startOffset, lenght: numberOfBytesToRespondWith) {
dataRequest.respond(with: data)
didRespondFully = data.count >= dataRequest.requestedLength
}
return didRespondFully
}
不幸的是,视频在没有完全下载(AVAssetResourceLoadingRequest.finishLoading())时也没有播放,也没有获得通知loadedTimeRanges。
有没有人有这方面的经验指出我可能做错事的地方? 谢谢!