AVPlayerItem.loadedTimeRanges通知不能使用自定义AVAssetResourceLoaderDelegate

时间:2017-08-28 08:50:47

标签: ios avfoundation avplayer avasset avplayeritem

我使用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。

有没有人有这方面的经验指出我可能做错事的地方? 谢谢!

0 个答案:

没有答案