Im currently using 'AVKit' and 'AVFoundation' to enable the video playing through my app but I can only done by starting the video by tapping a button. But I am currently facing a problem of trying to making an automatic function like playing the video footage right after we start an app on an iOS device.
override func viewDidLoad()
{
super.viewDidLoad()
self.playingVideo()
self.nowPlaying(self)
}
#IBAction func nowPlaying(_ sender: Any)
{
self.present(self.playerController, animated: true, completion:{
self.playerController.player?.play()
})
after I compiled it, the system printed out:
Warning: Attempt to present on whose view is not in the window hierarchy!
Please try following working code.
import AVFoundation
import UIKit
class SomeViewController: UIViewController {
func openVideo() {
let playerController = SomeMediaPlayer()
playerController.audioURL = URL(string: "Some audio/video url string")
self.present(playerController, animated: true, completion: nil)
}
}
class SomeMediaPlayer: UIViewController {
public var audioURL:URL!
private var player = AVPlayer()
private var playerLayer: AVPlayerLayer!
override func viewDidLoad() {
super.viewDidLoad()
self.playerLayer = AVPlayerLayer(player: self.player)
self.view.layer.insertSublayer(self.playerLayer, at: 0)
let playerItem = AVPlayerItem(url: self.audioURL)
self.player.replaceCurrentItem(with: playerItem)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.player.play()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.playerLayer.frame = self.view.bounds
}
// Force the view into landscape mode if you need to
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
get {
return .landscape
}
}
}
Related
I have some ViewCotroller where i tapped a button - some audio file is playing. I want to stop playing audio when change/close this ViewController. How I can do this?
I try add some method to viewWillDisappear and it crashed if I don't tap any button. But if I tapped some button - it will works fine. 🙁
import UIKit
import AVFoundation
class BossViewController: UIViewController {
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: - Stop sound when we're change/close this viewController
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
audioPlayer.stop()
}
This is how my button is look like:
#IBAction func boss1(_ sender: AnyObject) {
let audioFile = NSURL(fileURLWithPath: Bundle.main.path(forResource: "shamp", ofType: "mp3")!)
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioFile as URL)
audioPlayer.prepareToPlay()
} catch {
print("Problem in getting File")
}
audioPlayer.play()
}
You can check if the audio player is playing, as #SandeepBhandari mentioned, or you can use a Bool variable to keep track whether or not the user tapped the button:
var buttonTapped = false
#IBAction func boss1(_ sender: AnyObject) {
...
buttonTapped = true
}
Then, you can check the variable in your viewWillDisappear(_ animated: Bool) method:
override func viewWillDisappear(_ animated: Bool) {
if buttonTapped {
audioPlayer.stop()
}
}
Okay So I have one view controller that is an AVPlayer. I want that controller to be able to rotate to landscape mode and portrait freely
import Foundation
import UIKit
import AVFoundation
import AVKit
class EventPromoVideoPlayer: UIViewController {
public var eventKey = ""
override var prefersStatusBarHidden: Bool {
return true
}
//URL of promo video that is about to be played
private var videoURL: URL
// Allows you to play the actual mp4 or video
var player: AVPlayer?
// Allows you to display the video content of a AVPlayer
var playerController : AVPlayerViewController?
init(videoURL: URL) {
self.videoURL = videoURL
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.gray
let downSwipe = UISwipeGestureRecognizer(target: self, action: #selector(swipeAction(_:)))
downSwipe.direction = .down
view.addGestureRecognizer(downSwipe)
//Setting the video url of the AVPlayer
player = AVPlayer(url: videoURL)
playerController = AVPlayerViewController()
guard player != nil && playerController != nil else {
return
}
playerController!.showsPlaybackControls = false
// Setting AVPlayer to the player property of AVPlayerViewController
playerController!.player = player!
self.addChildViewController(playerController!)
self.view.addSubview(playerController!.view)
playerController!.view.frame = view.frame
// Added an observer for when the video stops playing so it can be on a continuous loop
NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player!.currentItem)
//TODO: Need to fix frame of x and y
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
player?.play()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.isHidden = true
tabBarController?.tabBar.isHidden = true
}
override var supportedInterfaceOrientations:UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.all
}
// Allows the video to keep playing on a loop
#objc fileprivate func playerItemDidReachEnd(_ notification: Notification) {
if self.player != nil {
self.player!.seek(to: kCMTimeZero)
self.player!.play()
}
}
#objc func cancel() {
dismiss(animated: true, completion: nil)
}
#objc func swipeAction(_ swipe: UIGestureRecognizer){
if let swipeGesture = swipe as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case UISwipeGestureRecognizerDirection.right:
print("Swiped right")
break
case UISwipeGestureRecognizerDirection.down:
print("Swiped Down")
dismiss(animated: true, completion: nil)
break
case UISwipeGestureRecognizerDirection.left:
print("Swiped left")
break
case UISwipeGestureRecognizerDirection.up:
print("Swiped up")
break
default:
break
}
}
}
}
When I dismiss the screen I still need the previous controller to be in portrait. This shouldnt be a problem seeing as portrait mode is locked in as the only orientation in my settings and I want to keep it that way. However I want this one screen to be able to move freely. Any ideas and hints would be greatly appreciated.
The app delegate method does not work for me.
Neither does overriding shouldAutoRotate or supportedInterfaceOrientations in the function
You can use the below method in app delegate.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = UIApplication.topViewController() {
if (rootViewController.responds(to: Selector(("canRotate")))) || String(describing: type(of: rootViewController)) == "AVFullScreenViewController" {
// Unlock landscape view orientations for this view controller
return .allButUpsideDown;
}
}
// Only allow portrait (standard behaviour)
return .portrait
}
Add the below method in view controller where you want to display as landscape.
func canRotate() -> Void {}
extension UIApplication {
class func topViewController(base: UIViewController? = (UIApplication.sharedApplication().delegate as! AppDelegate).window?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
I have a ViewController with an AVPlayer, but the video is autorotate even when I have set portrait as the only supported orientation in info.plist and in delegate supportedInterfaceOrientationsFor function.
I have search for documentation without succeed.
Here is some code:
var videoPlayer = AVPlayerViewController()
var player = AVPlayer.init(url: URL.init(fileURLWithPath: urlString))
videoPlayer?.player = player
videoPlayer?.view.frame = self.view.frame
videoPlayer?.showsPlaybackControls = false
self.present(videoPlayer!, animated: false, completion: {action in
self.player?.play()
})
This can be done by subclassing AVPlayerViewController and return UIInterfaceOrientationMask.portrait from supportedInterfaceOrientations here is the code.
class PlayerVideoViewController: AVPlayerViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
return .portrait
}}
Thank you to Rhythmic Fistman for the answer.
I'm new to Swift and am trying to add a video to the view and then remove it when my "stopScreenSaver" notification is dispatched. All seems to work well except for when I go to remove the video layer (playerLayer.removeFromSuperlayer()).
Any guidance would be appreciated. I feel like I'm missing some basic concept here for adding and removing the layer!
import UIKit
import AVFoundation
import QuartzCore
import CoreMedia
class ViewController: UIViewController {
let contentURL = NSBundle.mainBundle().URLForResource("testvideo", withExtension: "mp4")
var player = AVPlayer()
var playerLayer = AVPlayerLayer()
let screenSize : CGRect = UIScreen.mainScreen().bounds
override func viewDidLoad() {
super.viewDidLoad()
// Used for starting and stopping the videos related to the screen saver
NSNotificationCenter.defaultCenter().addObserver(self, selector: "playScreenSaver:", name: "playScreenSaverID", object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "stopScreenSaver:", name: "stopScreenSaverID", object: nil)
}
override func viewDidAppear(animated: Bool) {
// Player
player = AVPlayer(URL: contentURL!)
// Layer for display… Video plays at the full size of the iPad
playerLayer = AVPlayerLayer(player: player)
var view = UIView(frame: CGRectMake(0, 0, screenSize.width, screenSize.height))
self.view.layer.addSublayer(playerLayer)
playerLayer.frame = view.bounds
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func playScreenSaver(notification: NSNotification){
print("play")
dispatch_async(dispatch_get_main_queue()) {
self.view.layer.addSublayer(self.playerLayer!)
self.player!.play()
}
}
func stopScreenSaver(notification: NSNotification){
print("pause")
dispatch_async(dispatch_get_main_queue()) {
self.player!.pause()
self.playerLayer!.removeFromSuperlayer()
}
}
}
Using the dispatch fixed the issue I was having.
dispatch_async(dispatch_get_main_queue()) {
self.player!.pause()
self.playerLayer!.removeFromSuperlayer()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
DispatchQueue.main.async {
self.player.currentItem?.removeObserver(self, forKeyPath: "duration", context: nil)
self.player!.pause()
self.playerLayer!.removeFromSuperlayer()
}
}
Try this
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
DispatchQueue.main.async {
self.player?.pause()
self.playerLayer?.removeFromSuperlayer()
}
}
Please see below code. I am trying to remove the video subview from view when the 'done' button is pressed or video stops playing. I show no errors in the code but the removeFromSubview method does not seem to be working. I am not sure if my syntax is wrong or if it is something to do with having the movieplayer code within the IBAction method and the moviePlayBackDidFinish outside below the viewDidLoad. Any advise much appreciated. Thanks
import Foundation
import UIKit
import MediaPlayer
class VideoViewController: UIViewController {
var moviePlayer:MPMoviePlayerController!
#IBAction func videoLaunch(sender: AnyObject) {
playVideo()
}
func playVideo() {
let path = NSBundle.mainBundle().pathForResource("MyVideo", ofType:"mp4")
let url = NSURL.fileURLWithPath(path!)
moviePlayer = MPMoviePlayerController(contentURL: url)
if let player = moviePlayer {
player.view.frame = self.view.bounds
moviePlayer?.controlStyle = MPMovieControlStyle.Fullscreen
player.prepareToPlay()
self.view.addSubview(player.view)
}
}
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "moviePlayBackDidFinish:",
name: MPMoviePlayerPlaybackDidFinishNotification,
object: moviePlayer)
func moviePlayBackDidFinish(notification: NSNotification){
self.view.removeFromSuperview()
}
}
}
You are trying to remove self.view not moviePlayer.view.
Change your moviePlayBackDidFinish code to:
func moviePlayBackDidFinish(notification: NSNotification)
{
if let player = moviePlayer
{
player.view.removeFromSuperview()
}
}