使用多个 AVPlayer 时如何检测哪个视频结束了?

Posted

技术标签:

【中文标题】使用多个 AVPlayer 时如何检测哪个视频结束了?【英文标题】:How to detect which video ended when using multiple AVPlayers? 【发布时间】:2019-11-09 12:55:52 【问题描述】:

我在屏幕上并排播放两个视频,所以我有两个 AVPlayer 实例。我正在使用工作正常的通知检测视频播放结束。我的选择器(playerDidFinishPlaying)在两个视频结束时都会被调用。

NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: nil) 

现在我的问题出在选择器(playerDidFinishPlaying)中,我想检测它是为哪个 avplayer 调用的?如何唯一标识视频结束的 AVPlayer?

【问题讨论】:

我的选择器在两个视频结束时都被完美调用。我想唯一标识调用它的 avplayer。 【参考方案1】:

另一个想法。更新了@black_pearl 的方法

不同的通知注册,不同的通知方式。

    var player = AVPlayer()
    var playerTwo = AVPlayer()



    override func viewDidLoad() 
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlay(_:)), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishMusic(_:)), name: .AVPlayerItemDidPlayToEndTime, object: playerTwo.currentItem)

    


       @objc func playerDidFinishPlay(_ noti: Notification) 
           if let p = noti.object as? AVPlayerItem, p == player.currentItem 
                print("1")
           
       


    @objc func playerDidFinishMusic(_ noti: Notification) 
        if let p = noti.object as? AVPlayerItem, p == playerTwo.currentItem
            print("2")
        
    

【讨论】:

【参考方案2】:

通过通知对象唯一标识,

发布通知.AVPlayerItemDidPlayToEndTime,对象为player.currentItem

NotificationCenter
    .default
    .addObserver(self, 
                 selector: #selector(self.moviePlayBackFinished(sender:)),
                 name: .AVPlayerItemDidPlayToEndTime,
                 object: player.currentItem)

简单的方法:

下面的代码有效,缺点是当一个玩家结束时,notify方法会被调用两次。

    var player = AVPlayer()
    var playerTwo = AVPlayer()


    override func viewDidLoad() 
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlay(_:)), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlay(_:)), name: .AVPlayerItemDidPlayToEndTime, object: playerTwo.currentItem)

    


     @objc func playerDidFinishPlay(_ noti: Notification) 
        if let p = noti.object as? AVPlayerItem, p == player.currentItem
             print("1")
        

        if let p = noti.object as? AVPlayerItem, p == playerTwo.currentItem
             print("2")
        
    

轨道状态方式:

通过Notification,你可以看到,有一个玩家结束了。

你需要找到播放器。

玩家必须遵守两条规则,开始,结束。

使用var hasPlay: (one: Bool, two: Bool),查找正在播放的玩家。

使用isPlaying查找播放器,不再播放。

var player = AVPlayer()
var playerTwo = AVPlayer()

var hasPlay: (one: Bool, two: Bool) = (false, false)


override func viewDidLoad() 
        super.viewDidLoad()
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlay), name: .AVPlayerItemDidPlayToEndTime, object: nil)
    

    @IBAction func beepPressed(_ sender: UIButton) 
        hasPlay.one = true
        let url = // ...
        player = AVPlayer(url: url!)
        player.play()

    


    @IBAction func beepPressedTwo(_ sender: UIButton) 
       hasPlay.two = true

       let url = // ...
       playerTwo = AVPlayer(url: url!)
       playerTwo.play()

    

    @objc func playerDidFinishPlay() 

        if player.isPlaying == false, hasPlay.one == true
            hasPlay.one = false
            print("1")
        

        if playerTwo.isPlaying == false, hasPlay.two == true
            hasPlay.two = false
            print("2")
        


    






extension AVPlayer 
    var isPlaying: Bool 
        return rate != 0 && error == nil
    

【讨论】:

我有两个玩家。那么我应该通过哪个对象? player1.currentItem 还是 player2.currentItem?【参考方案3】:

更新了@dengST30 的方法一,比较轻松。

注册了两个通知,任何结束方法都会被调用两次。

所以需要加一些互斥的。

var player = AVPlayer()
var playerTwo = AVPlayer()

var justEnded: (one: Bool, two: Bool) = (false, false)

override func viewDidLoad() 
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlay(_:)), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
    NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlay(_:)), name: .AVPlayerItemDidPlayToEndTime, object: playerTwo.currentItem)
    playButton.tintColor = .systemBlue




@objc func playerDidFinishPlay(_ noti: Notification) 
           if let p = noti.object as? AVPlayerItem, p == player.currentItem 

                if justEnded.one == false
                    print("1")
                
                justEnded.one.toggle()
           

           if let p = noti.object as? AVPlayerItem, p == playerTwo.currentItem
                if justEnded.two == false
                    print("2")
                

                justEnded.two.toggle()
           
       

【讨论】:

以上是关于使用多个 AVPlayer 时如何检测哪个视频结束了?的主要内容,如果未能解决你的问题,请参考以下文章

AVPlayer 层不显示视频内容

在锁定屏幕上检测播放结束 - AVPlayer

在视图中使用 AVPlayer 播放多个视频

使用swift 3点击单元格时如何在Avplayer中播放来自url的视频

在 UICollectionView 上使用 AVPlayer 和 AVPlayerLayer 显示多个视频

用户关闭 AVPlayer 时如何获取视频播放时间