150 votes

Mettre en boucle une vidéo avec AVFoundation AVPlayer ?

Existe-t-il un moyen relativement simple de mettre en boucle une vidéo dans AVFoundation ?

J'ai créé mon AVPlayer et mon AVPlayerLayer comme suit :

avPlayer = [[AVPlayer playerWithURL:videoUrl] retain];
avPlayerLayer = [[AVPlayerLayer playerLayerWithPlayer:avPlayer] retain];

avPlayerLayer.frame = contentView.layer.bounds;
[contentView.layer addSublayer: avPlayerLayer];

et ensuite je joue ma vidéo avec :

[avPlayer play];

La vidéo est bien diffusée mais s'arrête à la fin. Avec le MPMoviePlayerController, tout ce que vous avez à faire, c'est de régler sa fonction repeatMode à la bonne valeur. Il ne semble pas y avoir de propriété similaire sur AVPlayer. Il ne semble pas non plus y avoir de rappel pour me dire quand le film est terminé, afin que je puisse revenir au début et le relire.

Je n'utilise pas MPMoviePlayerController car il présente de sérieuses limitations. Je veux pouvoir lire plusieurs flux vidéo à la fois.

1 votes

Voir cette réponse pour un lien vers un code fonctionnel réel : stackoverflow.com/questions/7822808/

285voto

Bastian Points 6086

Vous pouvez recevoir une notification lorsque le lecteur se termine. Vérifiez AVPlayerItemDidPlayToEndTimeNotification

Lors de l'installation du lecteur :

ObjC

  avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; 

  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(playerItemDidReachEnd:)
                                               name:AVPlayerItemDidPlayToEndTimeNotification
                                             object:[avPlayer currentItem]];

cela empêchera le joueur de faire une pause à la fin.

dans la notification :

- (void)playerItemDidReachEnd:(NSNotification *)notification {
    AVPlayerItem *p = [notification object];
    [p seekToTime:kCMTimeZero];
}

ça va rembobiner le film.

N'oubliez pas de désenregistrer la notification lorsque vous relâchez le lecteur.

Swift

avPlayer?.actionAtItemEnd = .none

NotificationCenter.default.addObserver(self,
                                       selector: #selector(playerItemDidReachEnd(notification:)),
                                       name: .AVPlayerItemDidPlayToEndTime,
                                       object: avPlayer?.currentItem)

@objc func playerItemDidReachEnd(notification: Notification) {
    if let playerItem = notification.object as? AVPlayerItem {
        playerItem.seek(to: kCMTimeZero)
    }
}

Swift 4+

@objc func playerItemDidReachEnd(notification: Notification) {
    if let playerItem = notification.object as? AVPlayerItem {
        playerItem.seek(to: CMTime.zero, completionHandler: nil)
    }
}

6 votes

...et si vous voulez le lire juste après [p seekToTime:kCMTimeZero] (une sorte de "retour en arrière"), il suffit de refaire [p play].

25 votes

Cela ne devrait pas être nécessaire... si vous le faites avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone; il ne s'arrêtera pas, donc pas besoin de le régler pour qu'il joue à nouveau

0 votes

Pour faire jouer le son à nouveau, vous devez appeler [player play]; après le rembobinage.

79voto

Nabha Points 591

Si cela peut aider, dans iOS / tvOS 10, il y a un nouveau AVPlayerLooper() que vous pouvez utiliser pour créer une boucle continue de vidéo (Swift) :

player = AVQueuePlayer()
playerLayer = AVPlayerLayer(player: player)
playerItem = AVPlayerItem(url: videoURL)
playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
player.play()    

Ces résultats ont été présentés à la WWDC 2016 dans le cadre de la conférence "Advances in AVFoundation Playback" : https://developer.apple.com/videos/play/wwdc2016/503/

Même en utilisant ce code, j'ai eu un problème jusqu'à ce que je remplisse un rapport de bogue avec Apple et que j'obtienne cette réponse :

Le fichier vidéo dont la durée est supérieure à celle des pistes audio/vidéo est le problème. FigPlayer_File désactive la transition sans interruption parce que le montage de la piste audio est plus court que la durée de la vidéo (15.682 contre 15.787).

Vous devez soit corriger les fichiers de film pour que la durée du film et le nombre d'images soient identiques. pour que la durée de la vidéo et celle de la piste soient de même longueur, soit vous pouvez utiliser l'intervalle de temps de AVPlayerLooper (définir la plage de temps de 0 à la durée de la piste audio)

Il s'est avéré que Premiere exportait des fichiers avec une piste audio d'une longueur légèrement différente de celle de la vidéo. Dans mon cas, il suffisait de supprimer complètement l'audio, ce qui a réglé le problème.

28voto

alino-91 Points 30

Sur Swift :

Vous pouvez recevoir une notification lorsque le lecteur se termine... vérifiez AVPlayerItemDidPlayToEndTimeNotification.

lors de l'installation du lecteur :

avPlayer.actionAtItemEnd = AVPlayerActionAtItemEnd.None

NSNotificationCenter.defaultCenter().addObserver(self, 
                                                 selector: "playerItemDidReachEnd:", 
                                                 name: AVPlayerItemDidPlayToEndTimeNotification, 
                                                 object: avPlayer.currentItem)

cela empêchera le joueur de faire une pause à la fin.

dans la notification :

func playerItemDidReachEnd(notification: NSNotification) {
    if let playerItem: AVPlayerItem = notification.object as? AVPlayerItem {
        playerItem.seekToTime(kCMTimeZero)
    }
}

Swift3

NotificationCenter.default.addObserver(self,
    selector: #selector(PlaylistViewController.playerItemDidReachEnd),
     name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
     object: avPlayer?.currentItem)

ça va rembobiner le film.

N'oubliez pas de désenregistrer la notification lorsque vous relâchez le lecteur.

21voto

Islam Q. Points 11

Voici ce que j'ai fini par faire pour éviter le problème de la pause et du hoquet :

Swift :

NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
                                       object: nil,
                                       queue: nil) { [weak self] note in
                                        self?.avPlayer.seek(to: kCMTimeZero)
                                        self?.avPlayer.play()
}

Objectif C :

__weak typeof(self) weakSelf = self; // prevent memory cycle
NSNotificationCenter *noteCenter = [NSNotificationCenter defaultCenter];
[noteCenter addObserverForName:AVPlayerItemDidPlayToEndTimeNotification
                        object:nil
                         queue:nil
                    usingBlock:^(NSNotification *note) {
                        [weakSelf.avPlayer seekToTime:kCMTimeZero];
                        [weakSelf.avPlayer play];
                    }];

NOTE : Je n'ai pas utilisé avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone car ce n'est pas nécessaire.

2 votes

@KostiaDombrovsky avez-vous essayé sur un appareil réel ou sur différentes vidéos ?

0 votes

@IslamQ. J'enregistre un fichier MP4 et j'essaie de le lire en boucle, un peu comme le fait Snapchat.

0 votes

@KostiaDombrovsky avez-vous comparé votre lecture avec snapchat côte à côte ? Je pense que comme les images de début et de fin ne correspondent pas, on a l'impression d'être en pause, mais ça ne l'est jamais.

8voto

NSCoder Points 114

Swift 5 :

J'ai fait quelques petits ajustements par rapport aux réponses précédentes, comme ajouter le playerItem à la file d'attente avant de l'ajouter au playerLayer.

let playerItem = AVPlayerItem(url: url)
let player = AVQueuePlayer(playerItem: playerItem)
let playerLayer = AVPlayerLayer(player: player)

playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)

playerLayer.frame = cell.eventImage.bounds
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill

// Add the playerLayer to a UIView.layer

player.play()

Et faites de playerLooper une propriété de votre UIViewController, sinon la vidéo ne pourra être lue qu'une seule fois.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X