问题
I'm working with AVPlayer
to show the playing video using a URL
in it. There are 2 parts to it:
1. Firstly, I've embedded the AVPlayer
to a view's sublayer using AVPlayerLayer
, i.e.
var player: AVPlayer?
func configure() {
let urlString = "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
if let url = URL(string: urlString) {
self.player = AVPlayer(url: url)
let playerLayer = AVPlayerLayer(player: self.player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
player.play()
}
}
The above code is working fine and the video is playing.
2. Secondly, on a UIButton
tap, I'm presenting a AVPlayerViewController
using the same AVPlayer
instance that I created earlier, i.e.
@IBAction func onTapVideoButton(_ sender: UIButton) {
self.player?.pause()
let controller = AVPlayerViewController()
controller.player = self.player
self.present(controller, animated: true) {
self.player?.play()
}
}
The problem I'm facing here is, after the AVPlayerViewController
opens, the video stops playing but the audio still plays on.
What I want is to sync the video in both AVPlayerLayer
and AVPlayerViewController
.
回答1:
I think there is a problem when sharing a player already created to the AVPlayerViewController. I'm not sure why is stoping but it wont happen if you create a new AVPlayer for that controller. A way to sync your player and your AVPlayerViewController could be like this:
First, you create a Notification Name that you'll use when the AVPlayerViewController is dismiss (apple does not give you a way to know when the user dismiss the AVPlayerViewController):
extension Notification.Name {
static let avPlayerDidDismiss = Notification.Name("avPlayerDidDismiss")
}
Then, you extend AVPlayerViewController to post this notification when is going to be dismiss and to send the time when the user left the video:
extension AVPlayerViewController {
open override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let seekTime = player?.currentTime() {
let userInfo = ["seekTime": seekTime]
NotificationCenter.default.post(name: .avPlayerDidDismiss, object: nil, userInfo: userInfo)
}
}
}
And in your ViewController you observe that notification, get the seekTime you want to go and use it to setup your avPlayer:
class ViewController: UIViewController {
var player: AVPlayer?
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
configure()
NotificationCenter.default.addObserver(self, selector: #selector(avPlayerDidDismiss), name: .avPlayerDidDismiss, object: nil)
}
func configure() {
self.player = getPlayer()
let playerLayer = AVPlayerLayer(player: self.player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
self.player?.play()
}
@IBAction func onTapVideoButton(_ sender: UIButton) {
self.player?.pause()
let controllerPlayer = getPlayer()
controllerPlayer.currentItem?.seek(to: self.player!.currentTime(), completionHandler: nil)
let controller = AVPlayerViewController()
controller.player = controllerPlayer
self.present(controller, animated: true, completion: {
controller.player?.play()
})
}
func getPlayer() -> AVPlayer {
let url = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")!
return AVPlayer(url: url)
}
@objc
private func avPlayerDidDismiss(_ notification: Notification) {
if let seekTime = notification.userInfo?["seekTime"] as? CMTime {
player?.currentItem?.seek(to: seekTime, completionHandler: nil)
player?.play()
}
}
}
Cons: It will send the notification for every AVPlayerViewController. You use add you as an observer when you need this info. Hope it can help.
来源:https://stackoverflow.com/questions/53352205/sync-video-in-avplayerlayer-and-avplayerviewcontroller