How do you loop AVPlayer in Swift?

后端 未结 8 2014
后悔当初
后悔当初 2020-12-02 15:15

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

<
相关标签:
8条回答
  • 2020-12-02 15:36

    I've managed to create a seamless video looping for OSX in swift 3. It should work on iOS and with little modification on swift 2 as well.

    var player : AVQueuePlayer!
    
    // Looping video initial call
    internal func selectVideoWithLoop(url : URL)
    {
        let asset = AVAsset(url: url)
        player.pause()
        let playerItem1 = AVPlayerItem(asset: asset)
        let playerItem2 = AVPlayerItem(asset: asset)
        player.removeAllItems()
        player.replaceCurrentItem(with: playerItem1)
        player.insert(playerItem2, after: playerItem1)
        player.actionAtItemEnd = AVPlayerActionAtItemEnd.advance
        player.play()
    
        let selector = #selector(ViewController.playerItemDidReachEnd(notification:))
        let name = NSNotification.Name.AVPlayerItemDidPlayToEndTime
        // removing old observer and adding it again for sequential calls. 
        // Might not be necessary, but I like to unregister old notifications.
        NotificationCenter.default.removeObserver(self, name: name, object: nil)
        NotificationCenter.default.addObserver(self, selector: selector, name: name, object: nil)
    }
    
    // Loop video with threadmill pattern
    // Called by NotificationCenter, don't call directly
    func playerItemDidReachEnd(notification: Notification)
    {
        let item = player.currentItem!
        player.remove(item)
        item.seek(to: kCMTimeZero)
        player.insert(item, after: nil)
    }
    

    When you want to change the video, just call selectVideoWithLoop with a different url again.

    0 讨论(0)
  • 2020-12-02 15:43

    Alternatively, you can use the block-based NSNotificationCenter API:

    func loopVideo(videoPlayer: AVPlayer) {
        NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: nil, queue: nil) { notification in
            videoPlayer.seekToTime(kCMTimeZero)
            videoPlayer.play()
        }
    }
    
    0 讨论(0)
  • 2020-12-02 15:47

    @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.

    0 讨论(0)
  • 2020-12-02 15:47

    Might be a bit late to the conversation, but for the sake of upade (in case anyone comes here again), I found this answer HERE (it's another answer on SO) that worked for me.

    0 讨论(0)
  • 2020-12-02 15:53

    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 above 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

    0 讨论(0)
  • 2020-12-02 15:53

    OK I have worked it out. Thanks Msencenb for pointing me in the right direction with an Objective C answer.

    player_1?.actionAtItemEnd = .None
    
    //set a listener for when the video ends   
    NSNotificationCenter.defaultCenter().addObserver(self,
            selector: "restartVideoFromBeginning",
            name: AVPlayerItemDidPlayToEndTimeNotification,
            object: player_1?.currentItem)
    
    
    //function to restart the video
    func restartVideoFromBeginning()  {
    
        //create a CMTime for zero seconds so we can go back to the beginning
        let seconds : Int64 = 0
        let preferredTimeScale : Int32 = 1
        let seekTime : CMTime = CMTimeMake(seconds, preferredTimeScale)
    
        player_1!.seekToTime(seekTime)
    
        player_1!.play()
    
    }
    
    0 讨论(0)
提交回复
热议问题