3

Je suis en train de mettre en œuvre le streaming hors ligne avec le streaming FairPlay. Par conséquent, je télécharge des flux en utilisant un AVAssetDownloadTask.Obtenez la taille d'un AVAssetDownloadTask avant de télécharger

Je veux donner la rétroaction des utilisateurs au sujet de la taille du téléchargement qui commence à commencer:

Êtes-vous sûr que vous voulez télécharger ce flux? Il faudra 2.4GB de télécharger et vous avez actuellement 14 Go d'espace laissé

J'ai vérifier des propriétés comme countOfBytesReceived et countOfBytesExpectedToReceive mais ceux-ci donnent l'habitude des valeurs de retour correctes.

let headRequest = NSMutableURLRequest(URL: asset.streamURL) 
headRequest.HTTPMethod = "HEAD" 
let sizeTask = NSURLSession.sharedSession().dataTaskWithRequest(headRequest) { (data, response, error) in 
    print("Expected size is \(response?.expectedContentLength)") 
}.resume() 

imprime une taille de 2464, où à la fin la taille est 3GB.

Pendant le téléchargement, je propriétés ci-dessus: connecté

func URLSession(session: NSURLSession, assetDownloadTask: AVAssetDownloadTask, didLoadTimeRange timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange) { 
    print("Downloaded \(convertFileSizeToMegabyte(Float(assetDownloadTask.countOfBytesReceived)))/\(convertFileSizeToMegabyte(Float(assetDownloadTask.countOfBytesExpectedToReceive))) MB") 
} 

Mais ceux-ci restent à zéro:

Téléchargé 0,0/0,0 MB

+0

Avez-vous déjà résolu ce @Antoine? – bnussey

Répondre

0

Je n'ai pas travaillé avec cette API personnellement, mais je suis au moins un peu familier avec HTTP Live Streaming. Avec cette connaissance, je pense savoir pourquoi vous n'êtes pas en mesure d'obtenir l'information que vous recherchez.

Le protocole HLS est conçu pour gérer la diffusion en continu en direct ainsi que le streaming d'actifs de longueur fixe. Il le fait en découpant les médias dans ce qui sont généralement des morceaux de dix secondes, IIRC, et en listant les URL de ces morceaux dans un fichier de playlist à une URL spécifique. Si la liste de lecture ne change pas, vous pouvez télécharger la liste de lecture, calculer le nombre de fichiers, obtenir la longueur du premier fichier et le multiplier par le nombre de fichiers. approximation, que vous pouvez remplacer par une valeur exacte lorsque vous commencez à récupérer le dernier bloc.

Cependant, il n'y a aucune garantie que la liste de lecture ne changera pas. Avec HLS, la liste de lecture peut potentiellement changer toutes les dix secondes, en supprimant les segments les plus anciens (ou non) et en ajoutant de nouveaux segments à la fin. De cette manière, HLS prend en charge le streaming d'émissions en direct qui n'ont pas de fin du tout. Dans ce contexte, la notion de téléchargement ayant une taille est absurde. Pour aggraver les choses, 2464 est probablement la taille du fichier playlist, pas la taille du premier élément, c'est-à-dire qu'il ne vous dit rien à moins que la méthode didReceiveResponse: de cette sous-classe fonctionne, auquel cas vous pourriez être capable d'obtenir la longueur de chaque segment en lisant l'en-tête Content-Length au fur et à mesure qu'il le récupère. Et même si cela fonctionne normalement, vous ne pouvez probablement toujours pas obtenir le nombre de segments de cette API (et il n'y a pas de garantie que tous les segments auront exactement la même longueur, bien qu'ils devraient être assez proches). Je soupçonne que pour obtenir l'information que vous voulez, même pour un actif non actif, vous devrez probablement aller chercher la liste de lecture, l'analyser vous-même et effectuer une série de demandes HEAD pour chacune des URL de segment de média listées dedans.Heureusement, la spécification HLS est une norme disponible publiquement, donc si vous voulez aller dans ce sens, il y a des RFC que vous pouvez lire pour en savoir plus sur la structure du fichier de playlist. Et AFAIK, la playlist elle-même n'est cryptée avec aucun DRM ou quoi que ce soit, donc il devrait être possible de le faire même si la partie de décryptage réelle de l'API n'est pas publique (AFAIK).

1

Les flux HLS sont en fait une collection de fichiers connus sous le nom de manifestes et de flux de transport. Les manifestes contiennent généralement une liste textuelle de sous-manifestes (chacun correspondant à un débit binaire différent), et ces sous-manifestes contiennent une liste de flux de transport qui contiennent les données réelles du film.

Dans votre code, lorsque vous téléchargez l'URL HLS, vous êtes en train de télécharger uniquement le manifeste principal, généralement de quelques milliers d'octets. Si vous souhaitez copier le flux entier, vous devez analyser tous les manifestes, répliquer la structure de dossiers du flux d'origine et récupérer les segments de transport (généralement en segments de 10 secondes). Il peut donc y en avoir des centaines celles-ci). Vous devrez peut-être réécrire les URL si les manifestes sont également spécifiés avec des URL absolues.

Pour calculer la taille de chaque flux, vous pouvez multiplier le débit (indiqué dans le manifeste principal) par la durée du flux; cela pourrait être une estimation assez bonne à des fins de téléchargement.

Une meilleure réponse ici, puisque vous utilisez AVAssetDownloadTask dans le contexte de FairPlay déconnecté, consiste à implémenter AVAssetDownloadDelegate. L'une des méthodes dans ce protocole vous donne les progrès que vous cherchez:

URLSession:assetDownloadTask:didLoadTimeRange:totalTimeRangesLoaded:timeRangeExpectedToLoad:

Voici WWDC 2016 Session 504 montrant ce délégué en action.

Il y a beaucoup de détails liés à la lecture hors ligne avec FairPlay, donc c'est une bonne idée de parcourir cette vidéo très attentivement.

0

Ceci est mon code C#/Xamarin pour calculer la taille de téléchargement finale. Il est très probablement imparfait, surtout avec les nouveaux codecs pris en charge avec iOS11, mais vous devriez avoir l'idée.

private static async Task<long> GetFullVideoBitrate(string manifestUrl) 
{ 
    string bandwidthPattern = "#EXT-X-STREAM-INF:.*(BANDWIDTH=(?<bitrate>\\d+)).*"; 
    string videoPattern = "^" + bandwidthPattern + "(RESOLUTION=(?<width>\\d+)x(?<height>\\d+)).*CODECS=\".*avc1.*\".*$"; 
    string audioPattern = "^(?!.*RESOLUTION)" + bandwidthPattern + "CODECS=\".*mp4a.*\".*$"; 

    HttpClient manifestClient = new HttpClient(); 
    Regex videoInfoRegex = new Regex(videoPattern, RegexOptions.Multiline); 
    Regex audioInfoRegex = new Regex(audioPattern, RegexOptions.Multiline); 
    string manifestData = await manifestClient.GetStringAsync(manifestUrl); 
    MatchCollection videoMatches = videoInfoRegex.Matches(manifestData); 
    MatchCollection audioMatches = audioInfoRegex.Matches(manifestData); 
    List<long> videoBitrates = new List<long>(); 
    List<long> audioBitrates = new List<long>(); 

    foreach (Match match in videoMatches) 
    { 
     long bitrate; 

     if (long.TryParse(match.Groups["bitrate"] 
           .Value, 
          out bitrate)) 
     { 
      videoBitrates.Add(bitrate); 
     } 
    } 

    foreach (Match match in audioMatches) 
    { 
     long bitrate; 

     if (long.TryParse(match.Groups["bitrate"] 
           .Value, 
          out bitrate)) 
     { 
      audioBitrates.Add(bitrate); 
     } 
    } 

    if (videoBitrates.Any() && audioBitrates.Any()) 
    { 
     IEnumerable<long> availableBitrate = videoBitrates.Where(b => b >= Settings.VideoQuality.ToBitRate()); 
     long videoBitrateSelected = availableBitrate.Any() ? availableBitrate.First() : videoBitrates.Max(); 
     long totalAudioBitrate = audioBitrates.Sum(); 

     return videoBitrateSelected + totalAudioBitrate; 
    } 

    return 0; 
}