Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you loop AVPlayer in Swift?

Tags:

ios

swift

Simple question I can't seem to find an answer to for some reason.

How do you loop AVPlayer in Swift?

numberOfLoops = -1 only works for AVAudioPlayer

I do need it to loop without any delay / black flash etc. That's why I'm not using MPMoviePlayerViewController.

Thanks for any help.

Code:

    let url_1 = NSURL.fileURLWithPath(outputFilePath_1)

    let asset_1 = AVAsset.assetWithURL(url_1) as? AVAsset
    let playerItem_1 = AVPlayerItem(asset: asset_1)

    let player_1 = AVPlayer(playerItem: self.playerItem_1)

    let playerLayer_1 = AVPlayerLayer(player: self.player_1)

    playerLayer_1!.frame = self.view.frame

    self.view.layer.addSublayer(self.playerLayer_1)

    player_1!.play()
like image 589
Jonathan Plackett Avatar asked Jan 06 '15 22:01

Jonathan Plackett


3 Answers

Swift 5 (iOS 10.0+)

var playerLooper: AVPlayerLooper! // should be defined in class
var queuePlayer: AVQueuePlayer!
...

let asset: AVAsset = ... // AVAsset with its 'duration' property value loaded
let playerItem = AVPlayerItem(asset: asset)
self.queuePlayer = AVQueuePlayer(playerItem: playerItem)

// Create a new player looper with the queue player and template item
self.playerLooper = AVPlayerLooper(player: queuePlayer, templateItem: playerItem)

< iOS 10.0

All below works in any iOS version. But, for < iOS 10.0 it's the only solution.

Swift 4

var player: AVPlayer!

...

NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: .main) { [weak self] _ in
    self?.player?.seek(to: CMTime.zero)
    self?.player?.play()
}

Swift 3

NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: .main) { [weak self] _ in
    self?.player?.seek(to: kCMTimeZero)
    self?.player?.play()
}

Swift 2

After AVPlayerItem is configured and player is created:

var player: AVPlayer!

...

// Invoke after player is created and AVPlayerItem is specified
NSNotificationCenter.defaultCenter().addObserver(self,
    selector: "playerItemDidReachEnd:",
    name: AVPlayerItemDidPlayToEndTimeNotification,
    object: self.player.currentItem)

...
 
func playerItemDidReachEnd(notification: NSNotification) {
    self.player.seekToTime(kCMTimeZero)
    self.player.play()
}

Don't forget to import AVFoundation

like image 196
Alexander Volkov Avatar answered Nov 06 '22 11:11

Alexander Volkov


Starting from iOS 10, there's no need to use notifications to loop a video, simply use a AVPlayerLooper, just like this:

let asset = AVAsset(url: videoURL)
let item = AVPlayerItem(asset: asset)
let player = AVQueuePlayer(playerItem: item)
videoLooper = AVPlayerLooper(player: player, templateItem: item)

make sure this looper is created outside of a function scope, in case it stops when function returns.

like image 23
Bright Avatar answered Nov 06 '22 11:11

Bright


@Christopher Pickslay's answer updated for Swift 4:

func loopVideo(videoPlayer: AVPlayer) {
    NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
        videoPlayer.seek(to: CMTime.zero)
        videoPlayer.play()
    }
}

But, as I mentioned below his answer, be sure to specify the object as the AVPlayer's player item if you have multiple players.

like image 41
Ben Stahl Avatar answered Nov 06 '22 11:11

Ben Stahl