使用AES-128加密iOS播放离线HLS [英] Playing Offline HLS with AES-128 encryption iOS

查看:1297
本文介绍了使用AES-128加密iOS播放离线HLS的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想通过 AVFoundation 在iOS中集成离线HLS。
我有一个带有简单AES-128的加密HLS,它不想在离线模式下播放,我试图整合 AVAssetResourceLoaderDelegate 但不知道如何整合 applicationCertificate & https://开发人员中的 contentKeyFromKeyServerModuleWithSPCData 。 apple.com/streaming/fps/ 示例。我有一种感觉,我做错了,它是一个样本 AES-128加密,甚至不是 DRM

I want to integrate offline HLS in iOS through AVFoundation. I have an encrypted HLS with simple AES-128 and it doesn't want to play in offline mode, I was trying to integrate AVAssetResourceLoaderDelegate but don't know how to integrate applicationCertificate & contentKeyFromKeyServerModuleWithSPCData that are in https://developer.apple.com/streaming/fps/ examples. I have a feeling that I am doing something wrong, it is a sample AES-128 encryption, not even DRM.

没有互联网, AVPlayer 仍在尝试获取加密密钥通过 GET 请求。
如果有人成功地在本地保存加密密钥并以某种方式将其与 AVPlayer 一起提供给 AVURLAsset 。

Without the internet, AVPlayer is still trying to get encryption key through GET request. It would be great if someone succeeded to save encrypted key locally and somehow gave it to AVPlayer together with AVURLAsset.

有人设法整合这个吗?

推荐答案

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

I have written to apple support and their responses weren't new for me. Information that they provided to me I got from wwdc videos and documentation before I started a conversation with them. (https://developer.apple.com/streaming/fps/)

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

Further, I will describe how I achieve to play HLS in offline mode with AES-128 encryption. Take care AVDownloadTask doesn’t work on the simulator so you should have a device for this implementation. At the beginning, you need a stream URL.

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

Step 1: Before creating AVURLAsset we should take stream URL and change scheme to an invalid one (example: https -> fakehttps, I did it through URLComponents) and assign AVAssetResourceLoaderDelegate to the new created url asset. All this changes force AVAssetDownloadTask to call:

func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {

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

(it is calling because AVFoundation see an invalid URL and doesn’t know what to do with it)

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

Step 2: When delegate is called we should check that url is that one that we had before. We need to change back scheme to valid one and create a simple URLSession with it. We will get first .m3u8 file that should be like:

#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

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

Step 3: Parse all needed information from this data and change all https schemes to invalid one fakehttps Now you should setup AVAssetResourceLoadingRequest from shouldWaitForLoadingOfRequestedResource delegate like:

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

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

where: response -> response from URLSession, modifiedData -> data with changed URL’s

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

Resume your download task and return true in shouldWaitForLoadingOfRequestedResource delegate

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

Step 4: If everything will be ok AVAssetDownloadDelegate will fire with:

- (void)URLSession:(NSURLSession *)session assetDownloadTask:(AVAssetDownloadTask *)assetDownloadTask didResolveMediaSelection:(AVMediaSelection *)resolvedMediaSelection NS_AVAILABLE_IOS(9_0);

第5步:
我们已更改所有 https fakehttps 当AVFoundation将选择最佳媒体流网址时, shouldWaitForLoadingOfRequestedResource 将再次使用其中一个网址来触发.m3u8

Step 5: We have changed all https to fakehttps when AVFoundation will select best media stream URL, shouldWaitForLoadingOfRequestedResource will trigger again with one of the URL from first .m3u8

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

Step 6: When delegate is called again we should check that url is that one that we needed. Change again fake scheme to a valid one and create a simple URLSession with this url. We will get second .m3u8 file:

#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

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

Step 7: Parse second .m3u8 file and take all information that you need from it, also take a look on

#EXT-X-KEY:METHOD=AES-128,URI="https://avid.avid.net/avid/key"

我们有加密密钥的URL

We have URL for encryption key

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

Step 8: Before sending some information back to AVAssetDownloadDelegate we need to download the key from the server and save it locally on the device. After this you should change URI=https://avid.avid.net/avid/key from second .m3u8 to an invalid URI=fakehttps://avid.avid.net/avid/key, or maybe a local file path where you have saved your local key. Now you should setup AVAssetResourceLoadingRequest from shouldWaitForLoadingOfRequestedResource delegate smth. like:

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

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

where: response -> response from URLSession, modifiedData -> data with changed URL’s

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

Resume your download task and return true in shouldWaitForLoadingOfRequestedResource delegate (Same as on Step 3)

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

Step 9: Of course, when download task will try to create request with modified URI= that again is not a valid one shouldWaitForLoadingOfRequestedResource will trigger again. In this case, you should detect this and create new data with your persistent key(the key that you saved locally. Take care here contentType should be AVStreamingKeyDeliveryPersistentContentKeyType without it AVFoundation doesn’t understand that this contains key).

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

第10步:
块将由AVFoudnation自动下载。
下载完成后,将调用此委托:

Step 10: Chunks will be downloaded automatically by AVFoudnation. When download is finished this delegate will be called:

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) 

你应该保存 location 某处,当你想从设备播放流时你应该从这个位置创建AVURLAsset URL

You should save location somewhere, when you want to play stream from device you should create AVURLAsset from this location URL

所有这些信息由AVFoundation在本地保存,因此下次当你尝试在离线AVURLAsset中播放本地内容时,因为URI = fakehttps://avid.avid.net/avid/key ,这是一个无效的链接,在这里你将再次执行第9步,视频将以离线模式播放。

All this information is saved locally by AVFoundation so next time when you will try to play local content in offline AVURLAsset delegate will be called because of URI=fakehttps://avid.avid.net/avid/key, that is an invalid link, here you will do Step 9 again and video will play in offline mode.

如果有人知道更好的实现,这适用于我很高兴知道。

This works for me if anyone knows better implementation I will be glad to know.

这篇关于使用AES-128加密iOS播放离线HLS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆