Sync video in AVPlayerLayer and AVPlayerViewController
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
.
ios swift avplayer avplayerviewcontroller avplayerlayer
add a comment |
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
.
ios swift avplayer avplayerviewcontroller avplayerlayer
let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 '18 at 14:41
My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 '18 at 14:45
add a comment |
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
.
ios swift avplayer avplayerviewcontroller avplayerlayer
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
.
ios swift avplayer avplayerviewcontroller avplayerlayer
ios swift avplayer avplayerviewcontroller avplayerlayer
edited Nov 17 '18 at 14:45
PGDev
asked Nov 17 '18 at 14:35
PGDevPGDev
6,48221245
6,48221245
let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 '18 at 14:41
My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 '18 at 14:45
add a comment |
let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 '18 at 14:41
My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 '18 at 14:45
let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 '18 at 14:41
let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 '18 at 14:41
My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 '18 at 14:45
My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 '18 at 14:45
add a comment |
1 Answer
1
active
oldest
votes
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.
Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 '18 at 14:53
add a comment |
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',
autoActivateHeartbeat: false,
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 '18 at 14:53
add a comment |
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.
Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 '18 at 14:53
add a comment |
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.
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.
answered Nov 17 '18 at 17:11
Daniel Fernandez YDaniel Fernandez Y
817
817
Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 '18 at 14:53
add a comment |
Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 '18 at 14:53
Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 '18 at 14:53
Thank a lot for this solution. Really appreciate that.
– PGDev
Nov 18 '18 at 14:53
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
let player = AVPlayer(url: url) ? You already have a class variable named player.
– El Tomato
Nov 17 '18 at 14:41
My mistake. Yes I've the class variable. I'll edit that.
– PGDev
Nov 17 '18 at 14:45