我试着用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:数据),这应该会导致AVPlayer播放下载的视频。数据变量已正确填充,但我始终得到一个黑色屏幕。
视频文件也很好,如果我将它直接输入到AVURLAsset()中,它就会播放。
我尝试了无数的东西和组合,但不能让它发挥使用委托。任何帮助都将不胜感激!
编辑:我会添加更多的信息。
我试着用AES加密的视频做这件事,其中它使用了3个文件-- .m3u8、加密密钥和.ts视频。我成功地让它使用委托下载了.m3u8和密钥,但是当我尝试用视频文件下载它时,我的屏幕就变黑了。
这导致我认为可能需要下载部分,但我不知道如何正确地做到这一点。我也找不到关于它的任何文档,例如-应该设置headers,就像它来自web服务器,应该设置contentInformationRequest等等。委托会被调用2次:
// first time:
resourceLoadingRequest.dataRequest!.requestedLength == 2,
resourceLoadingRequest.dataRequest!.requestsAllDataToEndOfResource == false
// second time:
resourceLoadingRequest.dataRequest!.requestedLength == MAX_INT,
resourceLoadingRequest.dataRequest!.requestsAllDataToEndOfResource == true我不知道该做什么-我给它整个视频两次,但没有成功。
发布于 2020-02-19 10:33:01
我终于让它开始工作了。因此,上面的代码有两个问题:
这是工作委托代码:
// 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
// take a look at resourceLoadingRequest.dataRequest!.requestedLength, requestedOffset, currentOffset, requestsAllDataToEndOfResource
resourceLoadingRequest.dataRequest?.respond(with: data)
resourceLoadingRequest.finishLoading()
return true这是供参考的整个文件的代码:
import Foundation
import AVKit
class ResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate, URLSessionDelegate, URLSessionDataDelegate, URLSessionTaskDelegate {
public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource resourceLoadingRequest: AVAssetResourceLoadingRequest) -> Bool {
if ((resourceLoadingRequest.request.url?.absoluteString.contains(".mp4"))!) {
// replace the fakeScheme and get the original video url
var originalVideoURLComps = URLComponents(url: resourceLoadingRequest.request.url!, resolvingAgainstBaseURL: false)!
originalVideoURLComps.scheme = "file"
let originalVideoURL = originalVideoURLComps.url
var videoSize = 0
do {
let value = try originalVideoURL!.resourceValues(forKeys: [.fileSizeKey])
videoSize = value.fileSize!
} catch {
print("error getting video size")
}
if (resourceLoadingRequest.contentInformationRequest != nil) {
// this is the first request where we should tell the OS what file is to be downloaded
let bytes : [UInt8] = [0x0, 0x0] // TODO: repeat .requestedLength times?
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
}
// this is the second request where the actual file is to be downloaded
let requestedLength = resourceLoadingRequest.dataRequest!.requestedLength
let requestedOffset = resourceLoadingRequest.dataRequest!.requestedOffset
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: requestedLength)
let inputStream = InputStream(url: originalVideoURL!) // TODO: keep the stream open until a new file is requested?
inputStream!.open()
if (requestedOffset > 0) {
// move the stream pointer to the requested position
let buffer2 = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(requestedOffset))
inputStream!.read(buffer2, maxLength: Int(requestedOffset)) // TODO: the requestedOffset may be int64, but this gets truncated to int!
buffer2.deallocate()
}
inputStream!.read(buffer, maxLength: requestedLength)
// decrypt the video
if (requestedOffset == 0) { // TODO: this == 0 may not always work?
// if you use custom encryption, you can decrypt the video here, buffer[] holds the bytes
}
let data = Data(bytes: buffer, count: requestedLength)
resourceLoadingRequest.dataRequest?.respond(with: data)
resourceLoadingRequest.finishLoading()
buffer.deallocate()
inputStream!.close()
return true
}
return false
}
}https://stackoverflow.com/questions/60285860
复制相似问题