Search code examples
swiftswift3avplayernotificationcenter

Add Observer for end of short, high resolution video


I am trying to play a 4k Video in the AVPlayer with Swift 3 for iOS12 and it works totally fine, but i want this video to play inside a loop. I found articles that stated, that you should use this method to register for the end of the video playback:

    NotificationCenter.default.addObserver(self, selector: #selector(self.replay), 
    name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

In this case self.replay is beeing called once the player reached the end of the video. This works fine for normal videos, but once i try to play a ~4 second long video it does not loop. The replay function looks like this:

@objc func replay() {
    self.playerViewController!.player?.seek(to: CMTime.zero)
    self.playerViewController!.player!.playImmediately(atRate: 1)
}

Im adding the Observer in the presenting ViewController's viewDidLoad. Is this a race-condition, because as stated longer videos work fine? How can i prevent this behaviour.

(Sidenote: Not a regular poster, so please tell me if my question is asked wrong or hard to understand)


Solution

  • NotificationCenter.default.addObserver(self, selector: #selector(replay), 
    name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
    
    @objc func replay() {
        self.playerViewController!.player!.seek(to: CMTime.zero)
        self.playerViewController!.player!.play()
    }
    

    Not sure what playImmediately(atRate:) does, however, I know in my experience playing videos on loop is to reset the player to time zero, as you have done. Then, just naturally play the video.

    ADDITION: On another note, you can WAIT until the video is ready to play to add the observer AND start the video.

    override func viewDidLoad() {
        player.addObserver(self, forKeyPath: "status", options: [], context: nil)
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if(keyPath == "status" && self.playerViewController!.player!.status == .readyToPlay) {
            NotificationCenter.default.addObserver(self, selector: #selector(replay), name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
            self.playerViewController!.player!.play()
        }
    }