Я воспроизводю видео из пользовательской библиотеки в своем приложении. Я использую этот метод в ViewDidLoad()
, чтобы получить видео:
fileprivate let imageManager = PHImageManager()
fileprivate var playerLayer: AVPlayerLayer?
fileprivate var player:AVPlayer?
fileprivate var videoView:UIView?
imageManager.requestPlayerItem(forVideo: videoAsset, options: options, resultHandler: { playerItem, info in
DispatchQueue.main.sync {
guard self.playerLayer == nil else { return }
self.player = AVPlayer(playerItem: playerItem)
self.playerLayer = AVPlayerLayer(player: self.player)
self.videoView = UIView(frame: self.view.frame)
self.videoView?.contentMode = .scaleAspectFit
self.playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspect
self.playerLayer?.frame = self.videoView!.layer.bounds
self.videoView!.layer.addSublayer(self.playerLayer!)
self.photoScrollView.addSubview(self.videoView!)
self.addObserversForVideo()
}
})
Внутри addObserversForVideo() я устанавливаю разные наблюдатели для обновления ползунка, управляющего видео, а также устанавливаю его минимальное и максимальное значения:
guard let currentPlayer = player else {return}
guard let currentItem = currentPlayer.currentItem else {return}
NotificationCenter.default.addObserver(self,
selector: #selector(self.playerFinishedPlayingVideo),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: nil)
let interval = CMTime(seconds: 0.5, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
_ = playerLayer?.player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { [weak self] (time) in
self?.videoSlider.maximumValue = Float(currentItem.duration.seconds)
self?.videoSlider.minimumValue = 0.0
self?.videoSlider.value = Float(currentItem.currentTime().seconds)
self?.videoElapsedTimeLabel.text = self?.getStringFromCMTime(time: currentItem.currentTime())
let remainingTime = currentItem.duration - currentItem.currentTime()
self?.videoRemainingTimeLabel.text = self?.getStringFromCMTime(time: remainingTime)
})
Теперь проблема в том, что я иногда получаю эту ошибку, которая приводит к сбою моего приложения:
'NSInternalInconsistencyException', reason: 'Attempting to set a slider's minimumValue (0.000000) to be larger than the maximumValue (nan)'
Я не понимаю, почему это происходит, поскольку я проверяю, что currentItem
не равен нулю с помощью оператора защиты в начале, а также я устанавливаю минимальное значение после максимального значения. Я был бы признателен, если кто-то может мне помочь.
Благодаря @TonyNguyen я смог решить проблему одной строкой:
guard currentItem.status.rawValue == AVPlayerItem.Status.readyToPlay.rawValue else {return}
Вам нужно остерегаться двух дополнительных вещей:
currentPlayer.currentItem.status == .readyToPlay
currentPlayer.currentItem.duration >= CMTime.zero
В моем periodicTimeObserver
я меняю (time)
на секунды, затем проверяю, является ли значение NaN
или Infinite
, прежде чем что-либо обновлять.
_ = player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { [weak self] (time) in
let seconds = CMTimeGetSeconds(time)
guard !(seconds.isNaN || seconds.isInfinite) else {
return
}
// the rest of your code
})
Вы должны устанавливать эти значения только тогда, когда продолжительность вашего плеера готова. Другими словами, вы должны полагаться на свойство
status
, чтобы знать, когда игрок готов к игре. Подробнее о developer.apple.com/documentation/avfoundation/…