Sync video in AVPlayerLayer and AVPlayerViewController











up vote
3
down vote

favorite












I'm working with AVPlayerto 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.










share|improve this question
























  • let player = AVPlayer(url: url) ? You already have a class variable named player.
    – El Tomato
    Nov 17 at 14:41










  • My mistake. Yes I've the class variable. I'll edit that.
    – PGDev
    Nov 17 at 14:45















up vote
3
down vote

favorite












I'm working with AVPlayerto 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.










share|improve this question
























  • let player = AVPlayer(url: url) ? You already have a class variable named player.
    – El Tomato
    Nov 17 at 14:41










  • My mistake. Yes I've the class variable. I'll edit that.
    – PGDev
    Nov 17 at 14:45













up vote
3
down vote

favorite









up vote
3
down vote

favorite











I'm working with AVPlayerto 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.










share|improve this question















I'm working with AVPlayerto 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.







ios swift avplayer avplayerviewcontroller avplayerlayer






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 17 at 14:45

























asked Nov 17 at 14:35









PGDev

6,24721144




6,24721144












  • let player = AVPlayer(url: url) ? You already have a class variable named player.
    – El Tomato
    Nov 17 at 14:41










  • My mistake. Yes I've the class variable. I'll edit that.
    – PGDev
    Nov 17 at 14:45


















  • let player = AVPlayer(url: url) ? You already have a class variable named player.
    – El Tomato
    Nov 17 at 14:41










  • My mistake. Yes I've the class variable. I'll edit that.
    – PGDev
    Nov 17 at 14:45
















let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 at 14:41




let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 at 14:41












My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 at 14:45




My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 at 14:45












1 Answer
1






active

oldest

votes

















up vote
4
down vote



accepted










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.






share|improve this answer





















  • Thank a lot for this solution. Really appreciate that.
    – PGDev
    Nov 18 at 14:53











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53352205%2fsync-video-in-avplayerlayer-and-avplayerviewcontroller%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
4
down vote



accepted










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.






share|improve this answer





















  • Thank a lot for this solution. Really appreciate that.
    – PGDev
    Nov 18 at 14:53















up vote
4
down vote



accepted










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.






share|improve this answer





















  • Thank a lot for this solution. Really appreciate that.
    – PGDev
    Nov 18 at 14:53













up vote
4
down vote



accepted







up vote
4
down vote



accepted






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.






share|improve this answer












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.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 17 at 17:11









Daniel Fernandez Y

817




817












  • Thank a lot for this solution. Really appreciate that.
    – PGDev
    Nov 18 at 14:53


















  • Thank a lot for this solution. Really appreciate that.
    – PGDev
    Nov 18 at 14:53
















Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 at 14:53




Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 at 14:53


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53352205%2fsync-video-in-avplayerlayer-and-avplayerviewcontroller%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

"Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

Alcedinidae

RAC Tourist Trophy