采用系统AVPlayer组件来播放,对于需要手动处理加密的hls视频,通过AVAssetResourceLoader拦截代理方法来手动代理系统的m3u8文件下载、解密key下载等。
苹果的hls有自己的标准,注意参考标准来实现,否则可能播不出来,而且很难排查原因,参考文档:https://developer.apple.com/documentation/http-live-streaming/hls-authoring-specification-for-apple-devices?language=objc
我们如何去主动控制播放过程中m3u8文件下载、解密key下载等逻辑呢?
- 通常情况下,只要你设置了正确的播放url,AVAssetResourceLoader怎么都不会调用下面的代理方法,即使url报错也不会,无法访问也不会。不知道为什么这么设计😊
想要触发下面的代理调用,只有把设置进去的url改成非url的形式才行,比如去掉url前面http/https,这样系统就会调用下面代理方法了,就有操作空间了
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool
- 通过let url = loadingRequest.request.url?.absoluteString拿到系统当前要执行的url,判断url的后缀来实现逻辑扭转。
- 判断如果是播放url
// 自己下载m3u8文件,
下载完成block里面的代码: {
// 下载完成后塞给系统
loadingRequest.dataRequest?.respond(with: newData!)
// 通知系统请求结束
loadingRequest.finishLoading()
}
// 通知系统等待
return true
如果你的hls视频加密是自定义的,比如秘钥下载完是加密的,那就要在m3u8文件里面#EXT-X-KEY:METHOD:后面的URI给改成非url,这样系统就会调用这个代理,你自己去处理秘钥下载然后解密的逻辑,自己下载完以上面同样方式塞给系统。
视频切片文件下载的逻辑不能用上面方式来实现,采用同样方式,塞Data给系统,系统也不会播放,原因未知。系统只接受url重定向。
因此碰到因为音视频编码问题,直接播放视频切片文件播放不了的时候,目前我采用的是本地服务器的形式实现,即把切片的url给改成非url,然后采用上面同样的方式,手动把视频下载下来,如果加密了还需要解密,然后使用ffmpeg转码,转码完成后,如果m3u8包含加密的,还需要再加密回去,(因为AVAssetResourceLoader解密逻辑是内部进行的),然后启动本地服务器,把url重定向到本地视频切片文件url
// 下载切片文件完成回调: {
let localUrl = "http://localhost:port/" + fileName
if let u = URL(string: localUrl) {
let redirect = URLRequest(url: u)
loadingRequest.redirect = redirect
//设置需要重定向
loadingRequest.response = HTTPURLResponse(url: u, statusCode: 301, httpVersion: nil, headerFields: nil)
loadingRequest.finishLoading()
}
}