我正在尝试使用AVPlayer播放视频,该视频已加载到AVAssetResourceLoaderDelegate内,但我始终会出现空白屏幕,并且该视频无法播放。
这是代码:
let asset = AVURLAsset(url: URL(string: "fakescheme://video.mp4")!)
asset.resourceLoader.setDelegate(ResourceLoaderDelegate(), queue: DispatchQueue.main)
let item = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: item)
let playerLayer = AVPlayerLayer(player: self.player)
playerLayer!.frame = self.view.bounds;
self.view.layer.addSublayer(self.playerLayer!)
player!.play()
...
class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URLSessionDelegate, URLSessionDataDelegate, URLSessionTaskDelegate {
public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource resourceLoadingRequest: AVAssetResourceLoadingRequest) -> Bool {
var newRequest = URLRequest(url: URL(string: "https://example.com/video.mp4")!)
newRequest.allHTTPHeaderFields = resourceLoadingRequest.request.allHTTPHeaderFields
let sessionTask = URLSession.shared.dataTask(with: newRequest) { data, response, error in
resourceLoadingRequest.contentInformationRequest?.contentType = "video/mp4"
resourceLoadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
resourceLoadingRequest.contentInformationRequest?.contentLength = Int64(data.count)
resourceLoadingRequest.response = response
resourceLoadingRequest.dataRequest?.respond(with: data)
resourceLoadingRequest.finishLoading()
}
sessionTask.resume()
return true
}
}
这是基本概念:
[fakescheme://导致调用resourceLoader()委托,在其中创建了一个新的HTTP请求,以下载实际的视频。
然后它调用resourceLoadingRequest.dataRequest?.respond(with:data),这应该导致AVPlayer播放下载的视频。数据变量已正确填充,但我总是黑屏。
视频文件也很好,如果我直接将其输入AVURLAsset(),则可以播放。
我尝试了上百万种事物和组合,但是无法使用委托使其发挥作用。任何帮助将不胜感激!
编辑:我将添加更多信息。
我曾尝试使用AES加密视频来执行此操作,该视频使用3个文件-.m3u8,加密密钥和.ts视频。我设法使它使用委托下载.m3u8和密钥,但是当我尝试对视频文件进行操作时,再次出现黑屏。
这使我认为它可能需要分批进行下载,但是我不确定如何正确进行下载。我也找不到关于它的任何文档,例如-您是否应该将HTTP标头设置为好像来自Web服务器,还是应该设置contentInformationRequest等,则该委托被调用了2次:
// first time:
resourceLoadingRequest.dataRequest!.requestedLength == 2,
resourceLoadingRequest.dataRequest!.requestsAllDataToEndOfResource == false
// second time:
resourceLoadingRequest.dataRequest!.requestedLength == MAX_INT,
resourceLoadingRequest.dataRequest!.requestsAllDataToEndOfResource == true
我不确定要怎么做-我两次都给了整个视频,但没有成功。
我看到其他人一直在同一个方面挣扎而没有成功,有人能做到这一点吗?至少知道这是有可能的,并且这不是一些未记录的限制或类似限制。
我终于让它工作了。因此,上面的代码有2个问题:
1)contentType应该是AVFileType.mp4.rawValue,它是“ public.mpeg-4”。传递“ video / mp4”或其他值会破坏它
2)resourceLoadingRequest.dataRequest!.requestedLength实际上需要得到尊重,因此视频文件需要按请求分块发送。
这是工作代表代码:
// this IF is an ugly way to catch the first request to the delegate
// in this request you should populate the contentInformationRequest struct with the size of the video, etc
if (resourceLoadingRequest.dataRequest!.requestedLength == 2) {
let bytes : [UInt8] = [0x0, 0x0] // these are the first 2 bytes of the video, as requested
let data = Data(bytes: bytes, count: bytes.count)
resourceLoadingRequest.contentInformationRequest?.contentType = AVFileType.mp4.rawValue // this is public.mpeg-4, video/mp4 does not work
resourceLoadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
resourceLoadingRequest.contentInformationRequest?.contentLength = Int64(videoSize)
resourceLoadingRequest.dataRequest!.respond(with: data)
resourceLoadingRequest.finishLoading()
return true
}
// here we are at the second request. the OS may request the entire file, or a portion of it
// here we don't need to set any headers or contentInformationRequest, just reply with the requested data
resourceLoadingRequest.dataRequest?.respond(with: data)
resourceLoadingRequest.finishLoading()
return true