web-dev-qa-db-fra.com

Vérifier l'état de lecture de AVPlayer

Existe-t-il un moyen de savoir si une lecture AVPlayer est bloquée ou si elle est terminée?

100
Egil

Pour recevoir une notification pour atteindre la fin d'un élément (via Apple ):

[[NSNotificationCenter defaultCenter] 
      addObserver:<self>
      selector:@selector(<#The selector name#>)
      name:AVPlayerItemDidPlayToEndTimeNotification 
      object:<#A player item#>];

Et pour suivre la lecture, vous pouvez:

"suivre les modifications de la position de la tête de lecture dans un objet AVPlayer" en utilisant addPeriodicTimeObserverForInterval: queue: usingBlock: ou addBoundaryTimeObserverForTimes: file d'attente: usingBlock: .

Exemple: Apple:

// Assume a property: @property (retain) id playerObserver;

Float64 durationSeconds = CMTimeGetSeconds([<#An asset#> duration]);
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 1);
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 1);
NSArray *times = [NSArray arrayWithObjects:[NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird], nil];

self.playerObserver = [<#A player#> addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{
    // Passing NULL for the queue specifies the main queue.

    NSString *timeDescription = (NSString *)CMTimeCopyDescription(NULL, [self.player currentTime]);
    NSLog(@"Passed a boundary at %@", timeDescription);
    [timeDescription release];
}];
57
Todd Hopkinson

Vous pouvez dire qu'il joue en utilisant:

AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
    // player is playing
}

Swift 3 extension:

extension AVPlayer {
    var isPlaying: Bool {
        return rate != 0 && error == nil
    }
}
319
maz

Dans iOS10, il existe maintenant une propriété intégrée pour cela: timeControlStatus

Par exemple, cette fonction lit ou met en pause l'avPlayer en fonction de son statut et met à jour le bouton de lecture/pause de manière appropriée.

@IBAction func btnPlayTap(_ sender: Any) {
    if aPlayer.timeControlStatus == .playing {
        aPlayer.pause()
        btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
    } else if aPlayer.timeControlStatus == .paused {
        aPlayer.play()
        btnPlay.setImage(UIImage(named: "control-pause"), for: .normal)
    }
}

En ce qui concerne votre deuxième question, pour savoir si avPlayer est arrivé à la fin, la chose la plus simple à faire serait de configurer une notification.

NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)

Lorsque vous arrivez à la fin, vous pouvez, par exemple, revenir au début de la vidéo et réinitialiser le bouton Pause sur Lecture.

@objc func didPlayToEnd() {
    aPlayer.seek(to: CMTimeMakeWithSeconds(0, 1))
    btnPlay.setImage(UIImage(named: "control-play"), for: .normal)
}

Ces exemples sont utiles si vous créez vos propres contrôles, mais si vous utilisez un AVPlayerViewController, les contrôles sont intégrés.

37
Travis M.

rate est PAS le moyen de vérifier si une vidéo est en lecture (il pourrait caler). De la documentation de rate:

Indique le taux de lecture souhaité. 0.0 signifie "en pause", 1.0 indique une volonté de jouer au rythme naturel de l'élément en cours.

Mots clés "désir de jouer" - n taux de 1.0 Ne signifie pas que la vidéo est en cours de lecture.

La solution depuis iOS 10.0 consiste à utiliser AVPlayerTimeControlStatus qui peut être observé sur la propriété AVPlayertimeControlStatus.

La solution antérieure à iOS 10.0 (9.0, 8.0, etc.) consiste à lancer votre propre solution. n taux de 0.0 Signifie que la vidéo est en pause. Lorsque rate != 0.0 Cela signifie que la vidéo est en cours de lecture ou est bloqué.

Vous pouvez trouver la différence en observant l'heure du joueur via: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any

Le bloc renvoie le temps de lecture actuel dans CMTime, de sorte qu'une comparaison de lastTime (la dernière heure reçue du bloc) et de currentTime (l'heure à laquelle le bloc vient rapportée) dira si le joueur joue ou est bloqué. Par exemple, si lastTime == currentTime Et rate != 0.0, Le joueur est bloqué.

Comme l'ont noté d'autres personnes, le fait de savoir si la lecture est terminée est indiqué par AVPlayerItemDidPlayToEndTimeNotification.

20
kgaidis

Une alternative plus fiable à NSNotification consiste à vous ajouter en tant qu'observateur à la propriété rate du joueur.

[self.player addObserver:self
              forKeyPath:@"rate"
                 options:NSKeyValueObservingOptionNew
                 context:NULL];

Vérifiez ensuite si la nouvelle valeur du taux observé est égale à zéro, ce qui signifie que la lecture s’est arrêtée pour une raison quelconque, par exemple si vous avez atteint la fin ou bloqué à cause d’un tampon vide.

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context {
    if ([keyPath isEqualToString:@"rate"]) {
        float rate = [change[NSKeyValueChangeNewKey] floatValue];
        if (rate == 0.0) {
            // Playback stopped
        } else if (rate == 1.0) {
            // Normal playback
        } else if (rate == -1.0) {
            // Reverse playback
        }
    }
}

Pour rate == 0.0 _ cas, pour savoir ce qui a provoqué l'arrêt de la lecture, vous pouvez effectuer les vérifications suivantes:

if (self.player.error != nil) {
    // Playback failed
}
if (CMTimeGetSeconds(self.player.currentTime) >=
    CMTimeGetSeconds(self.player.currentItem.duration)) {
    // Playback reached end
} else if (!self.player.currentItem.playbackLikelyToKeepUp) {
    // Not ready to play, wait until enough data is loaded
}

Et n'oubliez pas de faire arrêter votre lecteur lorsqu'il arrive à la fin:

self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;

18
maxkonovalov

Pour Swift:

AVPlayer :

let player = AVPlayer(URL: NSURL(string: "http://www.sample.com/movie.mov"))
if (player.rate != 0 && player.error == nil) {
   println("playing")
}

Mise à jour:
player.rate > 0 condition changée en player.rate != 0 _ parce que si la lecture de la vidéo est inversée, elle peut être négative grâce à Julian .
Note: Cela pourrait ressembler à la réponse ci-dessus (Maz) mais Swift '! Player.error' me donnait une erreur de compilateur Je dois vérifier l'erreur en utilisant "player.error == nil" dans Swift (car la propriété error n'est pas de type "Bool")

AVAudioPlayer:

if let theAudioPlayer =  appDelegate.audioPlayer {
   if (theAudioPlayer.playing) {
       // playing
   }
}

AVQueuePlayer:

if let theAudioQueuePlayer =  appDelegate.audioPlayerQueue {
   if (theAudioQueuePlayer.rate != 0 && theAudioQueuePlayer.error == nil) {
       // playing
   }
}
17
Aks

Extension rapide basée sur la réponse de maz

extension AVPlayer {

    var isPlaying: Bool {
        return ((rate != 0) && (error == nil))
    }
}
9
Mark Bridges

La version de Swift de la réponse de maxkonovalov est la suivante:

player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)

et

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if keyPath == "rate" {
        if let rate = change?[NSKeyValueChangeNewKey] as? Float {
            if rate == 0.0 {
                print("playback stopped")
            }
            if rate == 1.0 {
                print("normal playback")
            }
            if rate == -1.0 {
                print("reverse playback")
            }
        }
    }
}

Merci maxkonovalov!

5
Mr Stanev

Actuellement, avec Swift 5 le moyen le plus simple de vérifier si le joueur joue ou en pause est de vérifier la variable . TimeControlStatus.

player.timeControlStatus == .paused
player.timeControlStatus == .playing
2
azemi

La réponse est objectif C

if (player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
    //player is playing
}
else if (player.timeControlStatus == AVPlayerTimeControlStatusPaused) {
    //player is pause
}
else if (player.timeControlStatus == AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate) {
    //player is waiting to play
}
0
iOS Lifee