Background video not playing

Hello. I am trying to have a video in the background in my initial ViewController. So far, I have this:


import UIKit
import AVFoundation
import AVKit

class IGASplashVC: UIViewController
{

    var player: AVPlayer?

    override func viewDidLoad()
    {
        super.viewDidLoad()

        self.view.backgroundColor = UIColor.blackColor()
        setupVideoBackground()
       
        // Draws buttons
        drawOutlets()
    }

    func setupVideoBackground()
    {
      
        let path = NSBundle.mainBundle().pathForResource("launch", ofType: "mp4")
      
        if let path = path
        {
            let url = NSURL(fileURLWithPath: path)
            self.player = AVPlayer(URL: url)

            self.player!.actionAtItemEnd = AVPlayerActionAtItemEnd.None
            let playerLayer = AVPlayerLayer(player: self.player)
            playerLayer.frame = self.view.bounds
            playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
            self.view.layer.insertSublayer(playerLayer, atIndex: 0)
          
            NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd", name: AVPlayerItemDidPlayToEndTimeNotification, object: self.player!.currentItem)
          
            self.player!.seekToTime(kCMTimeZero)
            self.player!.play()
          
            let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y", type: .TiltAlongVerticalAxis)
            verticalMotionEffect.minimumRelativeValue = -10
            verticalMotionEffect.maximumRelativeValue = 10
          
            let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x", type: .TiltAlongHorizontalAxis)
            horizontalMotionEffect.minimumRelativeValue = -10
            horizontalMotionEffect.maximumRelativeValue = 10
          
            let group = UIMotionEffectGroup()
            group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
          
            self.view.addMotionEffect(group)
       }
  }


   func playerItemDidReachEnd()
    {
        self.player!.seekToTime(kCMTimeZero)
    }
}


However, it is just black screen, no video. Thanks for your help in advance!

Replies

viewDidLoad is way too early to be triggering playback. You should not trigger playback until viewWillAppear or viewDidAppear.


Also, it's probable that you're calling play before the video is loaded. You should set an observer on the status property on the AVPlayerItem to note when it changes to AVPlayerItemStatusReadyToPlay, and only call play() once that is the case. Otherwise, you're calling play before the media is ready, and will likely put the player into an error state.

TidBits.


Thank you so much for a prompt response. I changed it to the following:


override func viewWillAppear(animated: Bool)
    {
        setupVideoBackground()
    }

func setupVideoBackground()
    {
        let path = NSBundle.mainBundle().pathForResource("b737_launch", ofType: "mp4")

        if let path = path
        {
            let url = NSURL(fileURLWithPath: path)
            self.player = AVPlayer(URL: url)
            self.player!.actionAtItemEnd = AVPlayerActionAtItemEnd.None
         
            let playerLayer = AVPlayerLayer(player: self.player)     
            playerLayer.frame = self.view.bounds
            playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        
            self.view.layer.insertSublayer(playerLayer, atIndex: 0)
         
            NSNotificationCenter.defaultCenter().addObserver(self,
                selector: "playerItemDidReachEnd",
                name: AVPlayerItemDidPlayToEndTimeNotification,
                object: self.player!.currentItem)
         
            self.player!.seekToTime(kCMTimeZero)
         
            let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y", type: .TiltAlongVerticalAxis)
            verticalMotionEffect.minimumRelativeValue = -10
            verticalMotionEffect.maximumRelativeValue = 10
         
            let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x", type: .TiltAlongHorizontalAxis)
            horizontalMotionEffect.minimumRelativeValue = -10
            horizontalMotionEffect.maximumRelativeValue = 10
         
            let group = UIMotionEffectGroup()
            group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
         
            self.view.addMotionEffect(group)         
         
            self.player?.addObserver(self, forKeyPath: "status", options:NSKeyValueObservingOptions.New, context: nil)
        }
    }


override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>)
    {
        if keyPath! == "status"
        {
            if (self.player!.currentItem!.status == AVPlayerItemStatus.ReadyToPlay)
            {
                print("READY TO PLAY")
              
                self.player!.play()
            }
            else if (player!.status == AVPlayerStatus.Failed)
            {

            }
        }
    }


Still the same problem: no video. I am obviously doing something wrong here: I do not see "READY TO PLAY" on the console...

You added the observer to the player, not the playerItem.

Same problem. I do not understand it. The observer is not even called even with the following:


func setupVideoBackground()
    {
        let path = NSBundle.mainBundle().pathForResource("b737_launch", ofType: "mp4")
    
        if let path = path
        {
            let url = NSURL(fileURLWithPath: path)
        
            self.playerItem = AVPlayerItem(URL: url)
        
            self.player = AVPlayer(playerItem: self.playerItem!)
        
            self.player!.actionAtItemEnd = AVPlayerActionAtItemEnd.None
        
            let playerLayer = AVPlayerLayer(player: self.player)
        
            playerLayer.frame = self.view.bounds
        
            playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
        
            self.view.layer.insertSublayer(playerLayer, atIndex: 0)
        
            NSNotificationCenter.defaultCenter().addObserver(self,
                                                            selector: "playerItemDidReachEnd",
                                                            name: AVPlayerItemDidPlayToEndTimeNotification,
                                                            object: self.player!.currentItem)

            self.playerItem?.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: nil)
        }
    }


Thank you for bearing with me!


EDIT: I think I figured out that the problem actually lies here:


if let path = path
{
...
}


The code inside is not implemented! But if I do not include the unwrapping code, I get the fatal error: unexpectedly found nil while unwrapping an Optional value error. Catch 22...

Are you sure you're actually including that video in the target?


Either way, you needed to modify to observe the playerItem, not the player.

Finally, I have found the solution:


I had to manually add the mp4 file here: TARGETS -> Build Phases -> Copy Bundle Resources.


Issue resolved. Thank you, TidBits!