Reputation: 1658
We load an MP4 video from a URL into an AVPlayer. The AVPlayer is behind a skeleton image which we hide when the AVPlayer gets to status "Ready To Play".
We expect to see the first frame of the video as soon as we hide the skeleton image. However, that first frame of the video appears after a slight delay. What is the status that indicates that the video in the AVPlayer is loaded and ready?
func prepareVideo(videoUrl: URL?, owner: UIView, autoStart: Bool = false) {
self.player = AVPlayer(url: videoUrl!)
let playerController = AVPlayerViewController()
playerController.player = player
playerController.view.layer.shouldRasterize = true
playerController.view.frame = owner.frame
playerController.view.isOpaque = true
playerController.view.backgroundColor = UIColor.clear
playerController.view.layer.borderColor = UIColor.clear.cgColor
playerController.view.layer.borderWidth = 0
playerController.showsPlaybackControls = false
playerController.updatesNowPlayingInfoCenter = false
owner.addSubview(playerController.view)
owner.sendSubview(toBack: playerController.view)
timerStart() // this starts a timer that checks the AVPlayer status
if autoStart {
playVideo()
}
}
@objc func timerStatusCheck() {
// function called by a Timer and checks the status of AVPlayer
if player!.status == AVPlayerStatus.readyToPlay {
print("ready to play")
timerStop()
if (readyToPlayHandler != nil) {
self.readyToPlayHandler!() // here we hide the skeleton image that shows while video is loading
}
} else if player!.status == AVPlayerStatus.failed {
timerStop()
MessageBox.showError("Video Failed to start")
}
}
Upvotes: 2
Views: 2766
Reputation: 114
When the AVPlayer reports rate = 1, it's playing the video. However, that doesn't mean the video is visible in the AVPlayerViewController. For that, you need the AVPlayerViewController's property "isReadyForDisplay" to be true.
https://developer.apple.com/documentation/avkit/avplayerviewcontroller/1615830-isreadyfordisplay
Note both AVPlayerViewController.isReadyForDisplay and AVPlayer.status are both KVO observable, which will be more responsive than using a Timer.
Also note if you use an AVPlayerLayer to display the video (instead of AVPlayerViewController), you need to observe the AVPlayerLayer's "isReadyForDisplay" for the same reason.
@objc func timerStatusCheck() {
// function called by a Timer and checks the status of AVPlayer
if player!.status == AVPlayerStatus.readyToPlay {
print("ready to play")
// check that controller's view is showing video frames from player
if playerController.isReadyForDisplay == false {
print("view not yet showing video")
return
}
timerStop()
if (readyToPlayHandler != nil) {
self.readyToPlayHandler!() // here we hide the skeleton image that shows while video is loading
}
} else if player!.status == AVPlayerStatus.failed {
timerStop()
MessageBox.showError("Video Failed to start")
}
}
Upvotes: 1