使用AES-128加密iOS播放离线HLS

Cyk*_*let 3 encryption http-live-streaming ios

我想在iOS中集成离线HLS AVFoundation.我有一个简单的AES-128加密HLS,它不希望在离线模式下玩,我是想整合AVAssetResourceLoaderDelegate,但不知道如何整合applicationCertificatecontentKeyFromKeyServerModuleWithSPCData那些在 https://developer.apple.com/streaming/fps / examples.我有一种感觉,我做错了什么,这是一个样本AES-128 encryption,甚至没有DRM.

没有互联网,AVPlayer仍然试图encryption key通过GET请求.如果有人成功地在本地保存加密密钥并以某种方式将其与之AVPlayer一起放在一起,那将是很棒的AVURLAsset.

有人设法整合这个吗?

Cyk*_*let 12

我写过苹果支持,他们的回答对我来说并不新鲜.在我开始与他们对话之前,我从wwdc视频和文档中获得了他们提供给我的信息.(https://developer.apple.com/streaming/fps/)

此外,我将介绍如何使用AES-128加密在离线模式下播放HLS.注意AVDownloadTask在模拟器上不起作用,因此您应该有一个用于此实现的设备.首先,您需要一个流URL.

步骤1: 在创建AVURLAsset之前,我们应该采用流URL并将方案更改为无效的(例如:https - > fakehttps,我是通过URLComponents完成的)并将AVAssetResourceLoaderDelegate分配给新创建的url资产.所有这些更改都会强制AVAssetDownloadTask调用:

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
}
Run Code Online (Sandbox Code Playgroud)

(它正在调用因为AVFoundation看到无效的URL并且不知道如何处理它)

第2步: 当调用委托时,我们应该检查该url是否是我们之前的那个url.我们需要将方案更改为有效方案并使用它创建一个简单的URLSession.我们将得到第一个.m3u8文件,应该是这样的:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1697588,RESOLUTION=1280x720,FRAME-RATE=23.980,CODECS="mp4a"
https://avid.avid.net/avid/information_about_stream1
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1132382,RESOLUTION=848x480,FRAME-RATE=23.980,CODECS="mp4a"
https://avid.avid.net/avid/information_about_stream2
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=690409,RESOLUTION=640x360,FRAME-RATE=23.980,CODECS="mp4a"
https://avid.avid.net/avid/information_about_stream3
Run Code Online (Sandbox Code Playgroud)

步骤3: 从这些数据中解析所有需要的信息并将所有https方案更改为无效的一个fakehttps 现在你应该从shouldWaitForLoadingOfRequestedResource委托设置AVAssetResourceLoadingRequest,如:

loadingRequest.contentInformationRequest?.contentType = response.mimeType
loadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
loadingRequest.contentInformationRequest?.contentLength = response.expectedContentLength
loadingRequest.dataRequest?.respond(with: modifiedData)
loadingRequest.finishLoading()
downloadTask?.resume()
Run Code Online (Sandbox Code Playgroud)

其中:response - >来自URLSession的响应,modifiedData - >带有更改URL的数据

恢复下载任务并在shouldWaitForLoadingOfRequestedResource委托中返回true

第4步: 如果一切正常,AVAssetDownloadDelegate将触发:

- (void)URLSession:(NSURLSession *)session assetDownloadTask:(AVAssetDownloadTask *)assetDownloadTask didResolveMediaSelection:(AVMediaSelection *)resolvedMediaSelection NS_AVAILABLE_IOS(9_0) {
}
Run Code Online (Sandbox Code Playgroud)

步骤5:当AVFoundation选择最佳媒体流URL时, 我们已将所有https更改为fakehttps,shouldWaitForLoadingOfRequestedResource将再次使用来自第一个.m3u8的URL之一触发

第6步: 当再次调用委托时,我们应该检查网址是否是我们需要的网址.将伪方案再次更改为有效方案,并使用此URL创建一个简单的URLSession.我们将获得第二个.m3u8文件:

#EXTM3U
#EXT-X-TARGETDURATION:12
#EXT-X-ALLOW-CACHE:YES
#EXT-X-KEY:METHOD=AES-128,URI="https://avid.avid.net/avid/key”
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1
#EXTINF:6.006,
https://avid.avid.net/avid/information_about_stream1
#EXTINF:4.713,
https://avid.avid.net/avid/information_about_stream2
#EXTINF:10.093,
https://avid.avid.net/avid/information_about_stream3
#EXT-X-ENDLIST
Run Code Online (Sandbox Code Playgroud)

步骤7: 解析第二个.m3u8文件并从中获取所需的所有信息,同时查看

#EXT-X-KEY:METHOD=AES-128,URI="https://avid.avid.net/avid/key”
Run Code Online (Sandbox Code Playgroud)

我们有加密密钥的URL

步骤8: 在将一些信息发送回AVAssetDownloadDelegate之前,我们需要从服务器下载密钥并将其本地保存在设备上.在此之后,您应该将URI = https://avid.avid.net/avid/key从第二个.m3u8更改为无效的URI = fakehttps://avid.avid.net/avid/key,或者可能是您已保存本地密钥的本地文件路径.现在你应该从shouldWaitForLoadingOfRequestedResource委托smth 设置AVAssetResourceLoadingRequest .喜欢:

loadingRequest.contentInformationRequest?.contentType = response.mimeType
loadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
loadingRequest.contentInformationRequest?.contentLength = response.expectedContentLength
loadingRequest.dataRequest?.respond(with: modifiedData)
loadingRequest.finishLoading()
downloadTask?.resume()
Run Code Online (Sandbox Code Playgroud)

其中:response - >来自URLSession的响应,modifiedData - >带有更改URL的数据

恢复下载任务并在shouldWaitForLoadingOfRequestedResource委托中返回true(与步骤3相同)

步骤9: 当然,当下载任务将尝试创建具有修改的请求时URI=,再次不是有效的请求,将再次触发shouldWaitForLoadingOfRequestedResource.在这种情况下,您应该检测到这一点并使用您的持久密钥(您在本地保存的密钥)创建新数据.请注意这里contentType应该AVStreamingKeyDeliveryPersistentContentKeyType没有它AVFoundation不理解这包含密钥.

loadingRequest.contentInformationRequest?.contentType = AVStreamingKeyDeliveryPersistentContentKeyType
loadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true
loadingRequest.contentInformationRequest?.contentLength = keyData.count
loadingRequest.dataRequest?.respond(with: keyData)
loadingRequest.finishLoading()
downloadTask?.resume()
Run Code Online (Sandbox Code Playgroud)

步骤10: AVFoudnation将自动下载块.下载完成后,将调用此委托:

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
}
Run Code Online (Sandbox Code Playgroud)

你应该保存在location某个地方,当你想从设备播放流时,你应该从这个locationURL 创建AVURLAsset

所有这些信息都由AVFoundation在本地保存,因此下次当您尝试在离线状态下播放本地内容AVURLAsset会因为URI =而调用委托fakehttps://avid.avid.net/avid/key,这是一个无效链接,此处您将再次执行步骤9,视频将在离线状态下播放模式.

这对我有用,如果有人知道更好的实现,我会很高兴知道.