为什么 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()
}
可能有两个问题:
如 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
由于您的初始代码不保留对返回的内部不透明时间观察器的引用,因此观察器可能会立即释放,因此永远不会被调用。
确保您注册观察的时间值正确:
- 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”
使用较小的值找到“开始”作为快速解决方案。
我正在尝试观察我的 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()
}
可能有两个问题:
如
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
由于您的初始代码不保留对返回的内部不透明时间观察器的引用,因此观察器可能会立即释放,因此永远不会被调用。
确保您注册观察的时间值正确:
- 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”
使用较小的值找到“开始”作为快速解决方案。