2

I am trying to play video playlist in loop and also play individual video clip from playlist in loop in AVQueuePlayer using AVPlayerItem, but i am unable to find the solution for same below is the code that i have tried so far

General

var player : AVQueuePlayer?
var playerLayer: AVPlayerLayer?
var playerItem: [AVPlayerItem] = []

func playAtIndex(index:Int){
        for i in index ..< playerItem.count {
            let obj = playerItem[i]
            if (self.player?.canInsert(obj, after: nil))! {
                obj.seek(to: .zero, completionHandler: nil)
                self.player?.insert(obj, after: nil)
                }
        }
    }

Initialise video player

self.player = AVQueuePlayer.init(items: self.playerItem)
self.playerLayer = AVPlayerLayer(player: self.player)
self.playerLayer?.frame = self.view!.bounds
self.playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
self.view!.layer.addSublayer(self.playerLayer!)
self.player?.play()

code done so far for looping playlist, this works but some of the video from the loop does not play sometimes.

self.playAtIndex(index: 0)

code done for looping individual video clip in playlist, but does not work

let playerItem: AVPlayerItem = note.object as! AVPlayerItem // here we get current item 
playerItem.seek(to: CMTime.zero, completionHandler: nil)
self.player?.play()

Any help will be great.!!

Zღk
  • 854
  • 7
  • 25

1 Answers1

0

To loop the playerItems in AVQueuePlayer, you need to add a an observer to the notification - AVPlayerItemDidPlayToEndTimeNotification

A notification that's posted when the item has played to its end time.

NotificationCenter.default.addObserver(self, selector: #selector(playerEndedPlaying), name: Notification.Name("AVPlayerItemDidPlayToEndTimeNotification"), object: nil)

The method playerEndedPlaying(_:) will be called whenever the notification is fired.

@objc func playerEndedPlaying(_ notification: Notification) {
    DispatchQueue.main.async {[weak self] in
        if let playerItem = notification.object as? AVPlayerItem {
            self?.player?.remove(playerItem)
            playerItem.seek(to: .zero, completionHandler: nil)
            self?.player?.insert(playerItem, after: nil)
            if playerItem == self?.playerItems?.last {
                self?.pauseVideo()
            }
        }
    }
}

The above method will be called every time a playerItem in the AVQueuePlayer ends playing.

  1. AVQueuePlayer's insert(_:after:) is called where each playerItem is appended to the queue.

afterItem

The player item that the newly inserted player item should follow in the queue. Pass nil to append the item to the queue.

  1. Loop is identified using playerItem == self?.playerItems?.last. You can add your custom handling here. I've paused the player once all the videos end playing.
PGDev
  • 23,751
  • 6
  • 34
  • 88