web-dev-qa-db-fra.com

Progression du streaming AVPlayer

J'utilise avec succès AVPlayer pour diffuser de l'audio à partir d'un serveur et ce que je veux faire maintenant est d'afficher un UISlider personnalisé qui montre la progression de la mise en mémoire tampon.

Quelque chose comme ça:

enter image description here

Avec AVPlayer, il ne semble pas y avoir de moyen d'obtenir la taille totale du téléchargement ou la quantité actuellement téléchargée pour le fichier audio, uniquement la durée de lecture actuelle et la durée totale de lecture.

Il y a des solutions pour cela?

35
pablasso

Je ne fais que travailler là-dessus, et j'ai jusqu'à présent les éléments suivants:

- (NSTimeInterval) availableDuration;
{
  NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
  CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
  Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
  Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
  NSTimeInterval result = startSeconds + durationSeconds;
  return result;
}
56
Andrew Kuklewicz

Cela devrait bien fonctionner:

Objectif-C:

- (CMTime)availableDuration
{
    NSValue *range = self.player.currentItem.loadedTimeRanges.firstObject;
    if (range != nil){
        return CMTimeRangeGetEnd(range.CMTimeRangeValue);
    }
    return kCMTimeZero;
}

version Swift:

func availableDuration() -> CMTime
{
    if let range = self.player?.currentItem?.loadedTimeRanges.first {
        return CMTimeRangeGetEnd(range.timeRangeValue)
    }
    return .zero
}

Pour regarder la valeur de l'heure actuelle, vous pouvez utiliser: CMTimeShow ([self availableDuration]); ou CMTimeShow (availableDuration ()) (pour Swift)

11
pkis

Personnellement, je ne suis pas d'accord pour dire que la valeur timeRanges aura toujours un compte de 1.

Selon la documentation

Le tableau contient des objets NSValue contenant une valeur CMTimeRange indiquant les plages de temps pour lesquelles l'élément de lecteur dispose de données multimédias facilement disponibles. Les plages de temps renvoyées peuvent être discontinues.

Cela peut donc avoir des valeurs similaires à:

[(début1, fin1), (début2, fin2)]

D'après mon expérience avec le framework hls.js dans le monde du web de bureau, les trous entre ces plages de temps peuvent être très petits ou grands en fonction d'une multitude de facteurs, ex: recherche, discontinuités, etc.

Donc, pour obtenir correctement la longueur totale du tampon, vous devez parcourir le tableau et obtenir la durée de chaque élément et concat.

Si vous recherchez une valeur de tampon à partir de la tête de lecture actuelle, vous devez filtrer les plages de temps pour une heure de début supérieure à l'heure actuelle et une heure de fin inférieure à l'heure actuelle.

public extension AVPlayerItem {

    public func totalBuffer() -> Double {
        return self.loadedTimeRanges
            .map({ $0.timeRangeValue })
            .reduce(0, { acc, cur in
                return acc + CMTimeGetSeconds(cur.start) + CMTimeGetSeconds(cur.duration)
            })
    }

    public func currentBuffer() -> Double {
        let currentTime = self.currentTime()

        guard let timeRange = self.loadedTimeRanges.map({ $0.timeRangeValue })
            .first(where: { $0.containsTime(currentTime) }) else { return -1 }

        return CMTimeGetSeconds(timeRange.end) - currentTime.seconds
    }

}
6
John Gainfort

Le code de Suresh Kansujiya dans l'Objectif C

NSTimeInterval bufferAvail;

if (player.currentItem != nil) {

    AVPlayerItem *item = player.currentItem;
    if (item.status == AVPlayerStatusReadyToPlay) {
        NSArray *timeRangeArray = item.loadedTimeRanges;
        CMTimeRange aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
        Float64 startTime = CMTimeGetSeconds(aTimeRange.start);
        Float64 loadedDuration = CMTimeGetSeconds(aTimeRange.duration);

        bufferAvail = startTime + loadedDuration;

        NSLog(@"%@ - %f", [self class], bufferAvail);
    } else {
        NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid)); }
}
else {
    NSLog(@"%@ - %f", [self class], CMTimeGetSeconds(kCMTimeInvalid));
}
0
Ing. Ron

Cette méthode renverra l'intervalle de temps du tampon pour votre UISlider

public var bufferAvail: NSTimeInterval {

    // Check if there is a player instance
    if ((player.currentItem) != nil) {

        // Get current AVPlayerItem
        var item: AVPlayerItem = player.currentItem
        if (item.status == AVPlayerItemStatus.ReadyToPlay) {

            var timeRangeArray: NSArray = item.loadedTimeRanges
            var aTimeRange: CMTimeRange = timeRangeArray.objectAtIndex(0).CMTimeRangeValue
            var startTime = CMTimeGetSeconds(aTimeRange.start)
            var loadedDuration = CMTimeGetSeconds(aTimeRange.duration)

            return (NSTimeInterval)(startTime + loadedDuration);
        }
        else {
            return(CMTimeGetSeconds(kCMTimeInvalid))
        }
    } 
    else {
        return(CMTimeGetSeconds(kCMTimeInvalid))
    }
}
0
Suresh Kansujiya

La réponse sélectionnée peut vous poser des problèmes si le tableau retourné est vide. Voici une fonction fixe:

- (NSTimeInterval) availableDuration
{
    NSArray *loadedTimeRanges = [[_player currentItem] loadedTimeRanges];
    if ([loadedTimeRanges count])
    {
        CMTimeRange timeRange = [[loadedTimeRanges objectAtIndex:0] CMTimeRangeValue];
        Float64 startSeconds = CMTimeGetSeconds(timeRange.start);
        Float64 durationSeconds = CMTimeGetSeconds(timeRange.duration);
        NSTimeInterval result = startSeconds + durationSeconds;
        return result;
    }
    return 0;
}
0