Playing video with AVFoundation

Playing video with AVFoundation is pretty similar to playing audio. We can use an AVPlayer instance and pass it an instance of AVPlayerItem that points to a video on the web. This approach requires us to create an AVPlayerLayer that uses the AVPlayer as an input for its visual contents, as shown in the following code:

import UIKit 
import AVFoundation

class VideoViewController: UIViewController {

let url = URL(string: "path/to/video/file")
var videoPlayer: AVPlayer!
var playerLayer: AVPlayerLayer!

override func viewDidLoad() {
super.viewDidLoad()

let videoItem = AVPlayerItem(url: url!)
videoPlayer = AVPlayer(playerItem: videoItem)
playerLayer = AVPlayerLayer(player: videoPlayer)

playerLayer.backgroundColor = UIColor.black.cgColor
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill

view.layer.addSublayer(playerLayer)

videoPlayer.play()
}

override func viewDidLayoutSubviews() {
let playerWidth = view.bounds.width - 20
let playerHeight = playerWidth / (16/9)
let yPos = (view.bounds.height - playerHeight) / 2

playerLayer.frame = CGRect(x: 10,
y: yPos,
width: playerWidth,
height: playerHeight)
}
}

The preceding code speaks for itself. You'll notice the similarities to playing audio and how we manually set up a player layer that uses the player instance to drive its visual contents. If you test this example, you'll notice that there are no controls available for the video. Users typically expect to be able to have some control over video play back, for instance, pausing the video or scrubbing through it to move the video playback forward or backward.

For this purpose, Apple has created the AVPlayerViewController. This view controller provides all the native interaction controls your users expect from iOS, and it's often a great idea to use this view controller instead of manually programming controls for your media playback. Let's take a look at a quick example:

playerController = AVPlayerViewController() 
playerController.willMove(toParentViewController: self)
addChildViewController(playerController)
playerController.didMove(toParentViewController: self)

playerController.player = videoPlayer
view.addSubview(playerController.view)
playerController.view.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
playerController.view.widthAnchor.constraint(equalTo: view.widthAnchor,
multiplier: 1, constant: -20),
playerController.view.heightAnchor.constraint(equalTo:
playerController.view.widthAnchor, multiplier: 9/16),
playerController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
playerController.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -70)
])

You'll notice that there are a couple of lines at the beginning of this code snippet that you haven't seen before, and that aren't even related to AVFoundation. When you use a component such as AVPlayerViewController, you can embed the component in another view controller by adding it as a child view controller.

This means that we create an instance of a view controller, such as AVPlayerViewController, and add its view to the container view controller's view. We need to call willMove(toParentViewController:) and didMove(toParentViewController:) so that the child and parent view controllers can perform some internal work. Once a view controller is another view controller's child, the parent will pass several life cycle methods to its child, such as trait collection changes or orientation changes. It's important that you properly take care of adding a child view controller, otherwise the child will never receive life cycle updates that could be important to it.

After we create the player view controller, we associate a player with it, and we're good to go. All that's left to do is to add the player controller's view and set up some constraints for it so it has a good-looking layout. It's interesting to note that if you have multiple players that use the same player item, both players will play the media item back in sync. Go ahead and take a look at the sample code to see this in action.

With this video primer done, it's time to move on to using the camera. We didn't cover all of AVFoundation since there's simply too much to cover, and most of it is very specialized and only useful if you're building a video or audio editing app. If you're interested in more information about AVFoundation, I highly recommend browsing Apple's documentation and example code. There is a lot of great information there.