Réponses:
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 l' évolution de la position de la tête de lecture dans un objet AVPlayer » en utilisant addPeriodicTimeObserverForInterval: file: usingBlock: ou addBoundaryTimeObserverForTimes: file: usingBlock: .
L'exemple vient d'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];
}];
-replaceCurrentItemWithPlayerItem:
, et que vous ne le gérez pas correctement. Une manière plus fiable pour moi est de suivre AVPlayer
le statut de KVO en utilisant KVO. Voir ma réponse ci-dessous pour plus de détails: stackoverflow.com/a/34321993/3160561
AVPlayerItemFailedToPlayToEndTimeNotification
Vous pouvez dire qu'il joue en utilisant:
AVPlayer *player = ...
if ((player.rate != 0) && (player.error == nil)) {
// player is playing
}
Extension Swift 3:
extension AVPlayer {
var isPlaying: Bool {
return rate != 0 && error == nil
}
}
- [AVPlayer setRate:-1.0]
), car il -1.0
est inférieur à 0.
Dans iOS10, il existe une propriété intégrée pour cela maintenant: timeControlStatus
Par exemple, cette fonction lit ou met en pause le avPlayer en fonction de son état et met à jour le bouton lecture / pause de manière appropriée.
@IBAction func btnPlayPauseTap(_ 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)
}
}
Quant à votre deuxième question, pour savoir si l'avPlayer a atteint la fin, la chose la plus simple à faire serait de mettre en place une notification.
NotificationCenter.default.addObserver(self, selector: #selector(self.didPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)
Lorsqu'il arrive à la fin, par exemple, vous pouvez le faire 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
n'est PAS le moyen de vérifier si une vidéo est en cours de lecture (elle pourrait se bloquer). De la documentation de rate
:
Indique la vitesse de lecture souhaitée; 0.0 signifie "en pause", 1.0 indique un désir de jouer à la vitesse naturelle de l'élément actuel.
Mots clés «désir de jouer» - un taux de 1.0
ne signifie pas que la vidéo est en cours de lecture.
La solution depuis iOS 10.0 est d'utiliser AVPlayerTimeControlStatus
ce qui peut être observé sur la AVPlayer
timeControlStatus
propriété.
La solution antérieure à iOS 10.0 (9.0, 8.0, etc.) consiste à lancer votre propre solution. Un taux de 0.0
signifie que la vidéo est mise en pause. Lorsque rate != 0.0
cela signifie que la vidéo est en cours de lecture ou est bloquée.
Vous pouvez découvrir la différence en observant le temps du joueur via: func addPeriodicTimeObserver(forInterval interval: CMTime, queue: DispatchQueue?, using block: @escaping (CMTime) -> Void) -> Any
Le bloc renvoie l'heure actuelle du joueur CMTime
, donc une comparaison de lastTime
(l'heure qui a été reçue pour la dernière fois du bloc) et currentTime
(l'heure à laquelle le bloc vient d'être signalé) dira si le joueur joue ou est bloqué. Par exemple, si lastTime == currentTime
et rate != 0.0
, alors le joueur a calé.
Comme indiqué par d'autres, déterminer si la lecture est terminée est indiqué par AVPlayerItemDidPlayToEndTimeNotification
.
Une alternative plus fiable NSNotification
consiste à vous ajouter en tant qu'observateur à la rate
propriété du joueur .
[self.player addObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionNew
context:NULL];
Vérifiez ensuite si la nouvelle valeur du taux observé est zéro, ce qui signifie que la lecture s'est arrêtée pour une raison quelconque, comme atteindre la fin ou bloquer en raison 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
}
}
}
Par rate == 0.0
exemple, pour savoir exactement 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 atteint la fin:
self.player.actionAtItemEnd = AVPlayerActionAtItemEndPause;
AVPlayerItemFailedToPlayToEndTimeNotification
. Si cette erreur se produit, n'atteindra jamais l'heure de fin. Ou en lisant la réponse de maz, ajoutez à votre code une vérification player.error != nil
, auquel cas la lecture s'est "terminée" en raison d'une erreur.
AVPlayerItemDidPlayToEndTimeNotification
?
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 : la
player.rate > 0
condition a été modifiée player.rate != 0
car si la vidéo est lue à l'envers, elle peut être négative grâce à Julian pour l'avoir signalé.
Remarque : Cela pourrait ressembler à la réponse ci-dessus (Maz), mais dans Swift '! Player.error' me donnait une erreur de compilation, vous devez donc vérifier l'erreur en utilisant 'player.error == nil' dans Swift. (Parce que la propriété d'erreur 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
}
}
player.rate = -1.0
), car -1,0 est inférieur à 0.
Extension Swift basée sur la réponse de Maz
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}
La version 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!
nil
! Mais j'ai besoin de savoir quand la vue commence (pas se termine). Un moyen de faire ça?
La réponse est l'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
}
player.timeControlStatus == AVPlayer.TimeControlStatus.playing