每次迭代后AVPlayerLooper黑色闪烁 [英] AVPlayerLooper black flash after each iteration
问题描述
我正在使用Apple的示例代码在UICollectionViewCell
背景上播放视频.
I am using a sample code from Apple to play a video on a UICollectionViewCell
background.
我正在使用AVPlayerLooper
,因为它是同一视频的迭代.
I'm using AVPlayerLooper
, since it is a iteration of the same video.
我的问题是,当视频播放完时,它会显示出轻微的黑点闪烁,也许我正在寻找0倍的视频,我不确定.
My problem here is that when the video reaches the end, it shows a slight black-bip screen flash, maybe it is seeking the video to 0 time, I'm not sure.
代码如下:
Apple协议
protocol Looper {
init(videoURL: URL, loopCount: Int)
func start(in layer: CALayer)
func stop()
}
Apple提供的"Player Looper类"
// Code from Apple
class PlayerLooper: NSObject, Looper {
// MARK: Types
private struct ObserverContexts {
static var isLooping = 0
static var isLoopingKey = "isLooping"
static var loopCount = 0
static var loopCountKey = "loopCount"
static var playerItemDurationKey = "duration"
}
// MARK: Properties
private var player: AVQueuePlayer?
private var playerLayer: AVPlayerLayer?
private var playerLooper: AVPlayerLooper?
private var isObserving = false
private let numberOfTimesToPlay: Int
private let videoURL: URL
// MARK: Looper
required init(videoURL: URL, loopCount: Int) {
self.videoURL = videoURL
self.numberOfTimesToPlay = loopCount
super.init()
}
func start(in parentLayer: CALayer) {
player = AVQueuePlayer()
player?.isMuted = true
playerLayer = AVPlayerLayer(player: player)
guard let playerLayer = playerLayer else { fatalError("Error creating player layer") }
playerLayer.frame = parentLayer.bounds
parentLayer.addSublayer(playerLayer)
let playerItem = AVPlayerItem(url: videoURL)
playerItem.asset.loadValuesAsynchronously(forKeys: [ObserverContexts.playerItemDurationKey], completionHandler: {()->Void in
/*
The asset invokes its completion handler on an arbitrary queue when
loading is complete. Because we want to access our AVPlayerLooper
in our ensuing set-up, we must dispatch our handler to the main queue.
*/
DispatchQueue.main.async(execute: {
guard let player = self.player else { return }
var durationError: NSError? = nil
let durationStatus = playerItem.asset.statusOfValue(forKey: ObserverContexts.playerItemDurationKey, error: &durationError)
guard durationStatus == .loaded else { fatalError("Failed to load duration property with error: \(String(describing: durationError))") }
self.playerLooper = AVPlayerLooper(player: player, templateItem: playerItem)
self.startObserving()
player.play()
})
})
}
func stop() {
player?.pause()
stopObserving()
playerLooper?.disableLooping()
playerLooper = nil
playerLayer?.removeFromSuperlayer()
playerLayer = nil
player = nil
}
// MARK: Convenience
private func startObserving() {
guard let playerLooper = playerLooper, !isObserving else { return }
playerLooper.addObserver(self, forKeyPath: ObserverContexts.isLoopingKey, options: .new, context: &ObserverContexts.isLooping)
playerLooper.addObserver(self, forKeyPath: ObserverContexts.loopCountKey, options: .new, context: &ObserverContexts.loopCount)
isObserving = true
}
private func stopObserving() {
guard let playerLooper = playerLooper, isObserving else { return }
playerLooper.removeObserver(self, forKeyPath: ObserverContexts.isLoopingKey, context: &ObserverContexts.isLooping)
playerLooper.removeObserver(self, forKeyPath: ObserverContexts.loopCountKey, context: &ObserverContexts.loopCount)
isObserving = false
}
// MARK: KVO
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &ObserverContexts.isLooping {
if let loopingStatus = change?[.newKey] as? Bool, !loopingStatus {
print("Looping ended due to an error")
}
}
else if context == &ObserverContexts.loopCount {
guard let playerLooper = playerLooper else { return }
if numberOfTimesToPlay > 0 && playerLooper.loopCount >= numberOfTimesToPlay - 1 {
print("Exceeded loop limit of \(numberOfTimesToPlay) and disabling looping");
stopObserving()
playerLooper.disableLooping()
}
}
else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
}
}
}
我的收藏夹视图单元格循环初始化
var looper: Looper? {
didSet {
configLooper()
}
}
func configLooper() {
looper?.start(in: layer)
}
我的集合视图委托用于单元初始化
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FirstLaunchCollectionViewCell
let videoURL = Bundle.main.url(forResource: "video3", withExtension: "MOV")
cell.looper = PlayerLooper(videoURL: videoURL!, loopCount: -1)
return cell
}
loopCount
设置为-1
,因此视频播放了无数次.
The loopCount
set to -1
so the video playback infinite number of times.
我尝试使用较小的视频文件,但在每次迭代结束时仍显示黑框.
I've tried using smaller video size files but it still shows a black frame at the end of each iteration.
有人知道这可能是什么原因吗,还是有更好的方法?可以在此处
Does anyone have any clue what might be causing this, or there's any better approach ? The Apple source code can be found here
推荐答案
您可以采用的另一种方法是为视频完成添加观看者,如下所示:
Another way you could go about it is to add an observer for the video finishing like so:
NotificationCenter.default.addObserver(forName: AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.player.seek(to: kCMTimeZero)
self.player.play()
}
})
这篇关于每次迭代后AVPlayerLooper黑色闪烁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!