为什么 AVPlayer 边界时间观察器不工作?

Why is AVPlayer Boundary Time Observer not working?

我正在尝试观察我的 AVPlayer 时间轴中的某个时间。

我在主队列上试过了;这没有用。然后我根据 this stack overflow post 的建议切换到后台队列;这两者都没有。寻找可行的解决方案或解释为什么这不起作用。

//add boundary time notification to global queue
avLayer.player!.addBoundaryTimeObserver(forTimes: [NSValue(time: avLayer.player!.currentItem!.duration)], queue: DispatchQueue.main){

                        self.avLayer.player!.pause()
                    }


//add boundary time notification to background queue                
avLayer.player!.addBoundaryTimeObserver(forTimes: [NSValue(time: avLayer.player!.currentItem!.duration)], queue: DispatchQueue.global(qos: .userInteractive)){

                        self.avLayer.player!.pause()
                    }

更新: 保留对观察者return值的强引用后,我在回调中设置断点。它仍然无法正常工作。

 //add boundary time notification
                    boundaryTimeObserver = avLayer.player!.addBoundaryTimeObserver(forTimes: [NSValue(time: avLayer.player!.currentItem!.duration)], queue: DispatchQueue.main){

                        self.avLayer.player!.pause()
                    }

可能有两个问题:

  1. addBoundaryTimeObserver 的文档所述:

    You must maintain a strong reference to the returned value as long as you want the time observer to be invoked by the player

    由于您的初始代码不保留对返回的内部不透明时间观察器的引用,因此观察器可能会立即释放,因此永远不会被调用。

  2. 确保您注册观察的时间值正确:

    • playerItem.duration 可能不确定(请参阅此 属性 的文档)
    • 甚至 playerItem 的 asset 的持续时间也可能是未知的,或者是一个不准确的估计,这取决于资产的类型和加载状态(同样,请参阅 AVAsset.duration 的文档).

    因此,您注册观察的时间可能永远不会到达(请注意,可以通过插入 CMTimeShow(duration) 轻松检查时间)

解决此问题的方法:

  • 如果您只是想在到达 playerItem 的末端时停止播放器,将 player.actionAtItemEnd 设置为 pause 可能就足够了

  • 如果您需要在到达项目末尾时执行一些自定义逻辑,请为 AVPlayerItemDidPlayToEndTime 通知注册一个观察者,并将 playerItem 作为对象。这种机制独立于可能不精确的持续时间,因此希望更可靠

2019简单例子..

var player = AVPlayer()
var token: Any?

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    let u = "https... "
    
    let playerItem = AVPlayerItem(url: URL(string: u)!)
    player = AVPlayer(playerItem: playerItem)
    player.play()

    token = player.addBoundaryTimeObserver(
       forTimes: [0.5 as NSValue],
       queue: DispatchQueue.main) { [weak self] in
         self?.spinner.stopAnimating()
         print("The audio is in fact beginning about now...")
    }
}

完美运行。

重要..它不会找到“0”

使用较小的值找到“开始”作为快速解决方案。