Search code examples
iosswiftvideotvos

How to loop video with AVPlayerLooper


I try to loop a video in a TV OS app with the AVPlayerLooper because this should get rid of the pause/hicup when playing the video again. I watched the WWDC2016 video https://developer.apple.com/videos/play/wwdc2016/503/ and try to implement the code but it doesn't loop. I have one PlayerViewController which inherits AVPlayerViewController. I put the code to let the video loop. If I have the following code, it shows nothing. If I change the second line to self.queuePlayer = AVQueuePlayer(playerItem:playerItem), it only plays once.

  let playerItem = AVPlayerItem(url: url as URL)
  self.queuePlayer = AVQueuePlayer()   //I declared this as a variable in the view controller
  self.playerLayer = AVPlayerLayer(player: self.queuePlayer) //I declared this as a variable in the view controller
  let playerLooper = AVPlayerLooper(player:  self.queuePlayer!, templateItem: playerItem)
  self.view.layer.addSublayer(self.playerLayer!)
  self.playerLayer?.frame = self.view.frame
  self.queuePlayer?.play()

Have any of you succeeded in playing looped video with the latest AVPlayerLooper?


Solution

  • I fixed the problem myself.

    The playerLooper must be a member variable in the class otherwise it doesn't work because a local variable is gone after the method has been called. So I put this line at the beginning of the class to declare it. I didn't declare it as an AVPlayerLooper because this is only for tvos10.0 and newer versions. I want my class to be adaptive to tvos9.0. This is my working code.

    var playerLooper: NSObject?
    var playerLayer:AVPlayerLayer!
    var queuePlayer: AVQueuePlayer?
    
    
    func playVideo(_ filmName: String){
        if let path = Bundle.main.path(forResource: filmName, ofType: "mov") {
            let url =  URL(fileURLWithPath: path)
    
            if #available(tvOS 10.0, *) {
    
                // Use a new player looper with the queue player and template item
                let playerItem = AVPlayerItem(url: url as URL)
                self.player = AVQueuePlayer(items: [playerItem])
                self.playerLayer = AVPlayerLayer(player: self.player)
                self.playerLooper = AVPlayerLooper(player: self.player! as! AVQueuePlayer, templateItem: playerItem)
                self.view.layer.addSublayer(self.playerLayer!)
                self.playerLayer?.frame = self.view.frame
                self.player?.play()
    
    
            } else {
                // Fallback on earlier versions, this solution has hicup at end
                player = AVPlayer(url: url)
                player?.play()
                loopVideo(player!)
            }
    
        }
    }
    
    func loopVideo(_ videoPlayer: AVPlayer) {
        NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
            if(!self.isStopped){
    
                videoPlayer.seek(to: kCMTimeZero)
                videoPlayer.play()
    
            }
        }
    }