2017-08-14 4 views
2

Je souhaite intégrer HLS hors ligne dans iOS via AVFoundation. J'ai un crypté HLS avec simple AES-128 et il ne veut pas jouer en mode hors ligne, j'essayais d'intégrer AVAssetResourceLoaderDelegate mais ne sais pas comment intégrer applicationCertificate & contentKeyFromKeyServerModuleWithSPCData qui sont dans https://developer.apple.com/streaming/fps/ exemples. J'ai le sentiment que je fais quelque chose de mal, c'est un échantillon AES-128 encryption, pas même DRM.Lecture hors ligne HLS avec cryptage AES-128 iOS

Sans Internet, AVPlayer essaie toujours d'obtenir encryption key par GET demande. Ce serait génial si quelqu'un réussissait à sauvegarder la clé cryptée localement et en quelque sorte l'a donné à AVPlayer avec AVURLAsset.

Est-ce que quelqu'un a réussi à intégrer cela?

+0

Avez-vous résolu ce problème? – bnussey

+0

yeap Je suis en train d'écrire en ce moment répondre à ma question – Cyklet

Répondre

7

J'ai écrit sur Apple Support et leurs réponses n'étaient pas nouvelles pour moi. Les informations qu'ils m'ont fournies m'ont été fournies par les vidéos et la documentation de wwdc avant d'entamer une conversation avec eux. (https://developer.apple.com/streaming/fps/)

En outre, je vais décrire comment je parviens à jouer HLS en mode hors ligne avec le chiffrement AES-128. Attention AVDownloadTask ne fonctionne pas sur le simulateur, vous devez donc avoir un périphérique pour cette implémentation. Au début, vous avez besoin d'une URL de flux.

Étape 1: Avant de créer AVURLAsset nous devrions prendre l'URL du flux et système de modification d'un un non valide (exemple: https ->fakehttps, je l'ai fait par URLComponents) et attribuer AVAssetResourceLoaderDelegate au nouveau créé url atout. Tout cela change AVAssetDownloadTask force appeler:

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

(il appelle parce AVFoundation voir une URL non valide et ne sait pas quoi faire avec elle)

Étape 2: Lorsque délégué est appelé nous devrions vérifier que l'URL est celle que nous avions avant. Nous devons changer le schéma en valide et créer une URLSession simple avec celui-ci. Nous aurons d'abord.fichier m3u8 qui devrait être comme:

#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 

Étape 3: Parse toute l'information nécessaire à partir de ces données et modifier tous les https systèmes d'invalide un fakehttps AVAssetResourceLoadingRequest d'installation Maintenant, vous devriez de shouldWaitForLoadingOfRequestedResource déléguer comme:

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

où: réponse -> resp onse de URLSession, modifiedData -> données avec de

URL changé

Reprenez votre tâche de téléchargement et de retour vrai dans shouldWaitForLoadingOfRequestedResource délégué

Étape 4: Si tout sera AVAssetDownloadDelegate ok se déclenche avec:

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

Étape 5: Nous avons tout changé https à fakehttps lorsque AVFoundation sélectionnera le meilleur URL de flux multimédia, shouldWaitForLoadingOfRequestedResource déclenchera à nouveau avec l'une des URL de la première .m3u8

Étape 6: Lorsque délégué est appelé à nouveau nous devrions vérifier que l'URL est celui dont nous avions besoin. Changez de nouveau le schéma faux en un schéma valide et créez une URLSession simple avec cette URL. Nous allons obtenir deuxième fichier .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 

Étape 7: Parse second fichier .m3u8 et de prendre toutes les informations que vous avez besoin de lui, aussi jeter un oeil sur

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

Nous avons URL pour le chiffrement à clé

Étape 8: Avant d'envoyer une information à AVAssetDownloadDelegate nous avons besoin de télécharger la clé le serveur et enregistrez-le localement sur l'appareil. Après cela, vous devez changer l'URI = https://avid.avid.net/avid/key du second .m3u8 à un URI invalide = fakehttps://avid.avid.net/avid/key, ou peut-être un chemin de fichier local où vous avez enregistré votre clé locale. Vous devez maintenant configurer AVAssetResourceLoadingRequest à partir de shouldWaitForLoadingOfRequestedResource délégué smth.comme:

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

où: réponse -> réponse de URLSession, modifiedData -> données avec l'URL modifiée de

Reprendre votre tâche de téléchargement, et va déléguer shouldWaitForLoadingOfRequestedResource (Identique à l'étape 3)

Étape 9: Bien sûr, lorsque la tâche de téléchargement va essayer de créer une demande avec URI= modifié qui n'est pas encore valide shouldWaitForLoadingOfRequestedResource w mauvais déclenchement à nouveau. Dans ce cas, vous devriez le détecter et créer de nouvelles données avec votre clé persistante (la clé que vous avez enregistrée localement.) Prenez soin ici contentType devrait être AVStreamingKeyDeliveryPersistentContentKeyType sans AVFoundation ne comprend pas que cette clé contient).

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

Etape 10: Chunks seront téléchargés automatiquement par AVFoudnation. Lorsque le téléchargement est terminé ce délégué sera appelé:

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

Vous devez enregistrer location quelque part, quand vous voulez lire le flux de l'appareil, vous devez créer AVURLAsset de cette location URL

Toutes ces informations sont enregistrées localement par AVFoundation donc la prochaine fois que vous essayerez de lire du contenu local en mode hors connexion AVURLAsset délégué sera appelé en raison de URI = fakehttps://avid.avid.net/avid/key, ce qui est un lien invalide, ici vous allez refaire l'étape 9 et la vidéo jouera en mode déconnecté.

Cela fonctionne pour moi si quelqu'un connaît une meilleure mise en œuvre, je serai heureux de savoir.

+0

Merci mon ami, je faisais face à un autre problème avec AES-128 bits HLS https://stackoverflow.com/questions/46097856/avplayer-stops-playing-aes-encrypted-offline-hls -video-in-online-mode/46300060 # 46300060 Votre réponse m'a donné un indice sur ce qu'il faut faire. – MARTIN