Existe-t-il un moyen de savoir si une lecture AVPlayer
est bloquée ou si elle est terminée?
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];
}];
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
}
}
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.
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é AVPlayer
timeControlStatus
.
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
.
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;
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
}
}
Extension rapide basée sur la réponse de maz
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
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!
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
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
}