我们在Swift IOS应用程序中使用视频流,效果非常好。问题是我们想使用AVAssetResourceLoader,所以我们可以使用我们自己的URLSession而不是AVPlayer使用的任何内容向流服务器发出请求(我完全无法找出AVPlayer使用的会话或如何影响它使用的会话。)
确切的行为是,对.m3u8文件上的两个字节调用shouldWaitForLoadingOfRequestedResource,然后再次调用它请求整个文件,然后(根据开始时间)请求正确的.ts文件。在我们获取.ts文件后,视频播放器根本无法做任何事情。
无论我们是否使用示例流式视频文件" https://tungsten.aaplimg.com/VOD/bipbop_adv_example_v2/master.m3u8"或我们自己的服务器。如果我们不使用AVAssetResourceLoader(我们可以从我们的服务器告诉),直到请求.ts文件,序列是相同的。此时,当我们不使用自定义加载程序时,AvPlayer会显示视频并不断请求.ts文件。如果我们注释掉与AVPlayer的所有其他交互,包括设置行为相同的初始时间,那么我只会包含来自viewDidLoad和shouldWaitForLoadingOfRequestedResource的代码。
如果我们只是删除" xyzzy"前缀使AVAssetResourceLoader不被使用,一切正常。此外,我想重要的是,如果我们定位的视频文件不是流媒体文件,那么一切都有效。
我们为.ts文件转换mime类型的另一件事产生了某种奇怪的动态uti,但这似乎与问题无关,因为即使我们对uti进行硬编码也是如此事情发生了。
override func viewDidLoad() {
super.viewDidLoad()
avPlayer = AVPlayer()
avPlayerLayer = AVPlayerLayer(player: avPlayer)
videoView.layer.insertSublayer(avPlayerLayer, at: 0)
videoView.backgroundColor = UIColor.black
url = URL(string: "xyzzy" + currentPatient.videoURL())!
let asset = AVURLAsset(url: url)
asset.resourceLoader.setDelegate(self, queue: DispatchQueue.main)
let item = AVPlayerItem(asset: asset)
let avPlayerItem = item
avPlayer.replaceCurrentItem(with: avPlayerItem)
videoScrollView.delegate = self
videoScrollView.minimumZoomScale = 1.0
videoScrollView.maximumZoomScale = 6.0
}
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
let urlString = loadingRequest.request.url?.absoluteString
let urlComponents = urlString?.components(separatedBy: "xyzzy")
let url = URL(string: urlComponents![1])
let request = loadingRequest.dataRequest!
let infoRequest = loadingRequest.contentInformationRequest
let task = globalSession.dataTask(with: url!) { (data, response, error) in
self.avPlayerThread.async {
if error == nil && data != nil {
let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, response?.mimeType as! CFString, nil)
if let infoRequest = infoRequest {
infoRequest.contentType = uti?.takeRetainedValue() as? String
if request.requestsAllDataToEndOfResource == false {
infoRequest.contentLength = Int64(request.requestedLength)
} else {
infoRequest.contentLength = Int64((data?.count)!)
}
infoRequest.isByteRangeAccessSupported = true
}
if infoRequest == nil || request.requestsAllDataToEndOfResource == true {
loadingRequest.dataRequest?.respond(with: data!)
}
loadingRequest.finishLoading()
} else {
print ("error \(error)")
loadingRequest.finishLoading(with: error)
}
}
}
task.resume()
return true
}