Custom video player in swift using AVPlayer

Apple provided AVKit framework, to allow developers play multimedia content inside their apps. With AVPlayerViewController, we can use Apple default playback controls. But in case if we want to play video in our customized player, then AVPlayer class comes to rescue. In this tutorial, we will learn how to play video using AVPlayer in swift. You can check how to play video using AVPlayerViewController from here

Creating video player in swift

In this tutorial we will create, a custom class inherited from UIView and add our AVPlayer to it. You can learn how to create custom UIView class in swift from below link

Create custom UIView class with xib in swift

Creating UIView class for video player

Create a new file in xcode and select cocoa touch class, name it VideoPlayer. This class should be subclass of UIView as shown in below image

Creating video player class a subclass of UIView
Creating video player class a subclass of UIView

Now we need to create a xib file for our player, so create a new file in xcode, but this time we need to select view class under User Interface section. We will name it “VideoPlayer“.

Adding UIView xib

Steps to create custom video player using AVPlayer

1. Open VIdeoPlayer.xib and add a UIView object from object library on to the view. Add constraint’s leading, trailing, top, bottom having constant value 0 with respect to superview.

2. In VideoPlayer.swift create an IBOutlet of UIView and name it as vwPlayer

class VideoPlayer: UIView {
    @IBOutlet weak var vwPlayer: UIView!
}

3. Connect IBOutlet created in step 2 with view object in VideoPlayer.xib.

4. Open VideoPlayer.swift, now we will first import AVKit framework and create an instance of AVPlayer

import UIKit
import AVKit

class VideoPlayer: UIView {
    @IBOutlet weak var vwPlayer: UIView!
    var player: AVPlayer?
}

5. Add required intializer’s to our class. And also create a function that will be responsible for getting view from VideoPlayer.xib class.

import UIKit
import AVKit

class VideoPlayer: UIView {
    @IBOutlet weak var vwPlayer: UIView!
    var player: AVPlayer?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    fileprivate func commonInit() {
        let viewFromXib = Bundle.main.loadNibNamed("VideoPlayer", owner: self, options: nil)![0] as! UIView
        viewFromXib.frame = self.bounds
        addSubview(viewFromXib)
    }
}

Using AVPlayer inside VideoPlayer.swift

6. Create a new function that will initialize AVPlayer instance and, add player to VideoPlayer as a sub view. Frame of AVPlayer will be same as per of our view object of VideoPlayer class.

 fileprivate func addPlayerToView(_ view: UIView) {
        player = AVPlayer()
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = self.bounds
        playerLayer.videoGravity = .resizeAspectFill
        view.layer.addSublayer(playerLayer)
    }

7. We will call our addPlayerToView function from inside of commonInit function. Because player should get intialized and added as soon as an object of VideoPlyer gets created.

8. Next, we will create a function named playVideoWithFileName. Function accept two parameters, file name as one of its parameter and other parameter will be file type. In this function, first player will try to get file path of the filename player was asked to play. Secondly, if player found the file, it will gets played by player.

 func playVideoWithFileName(_ fileName: String, ofType type:String) {
        
        guard let filePath = Bundle.main.path(forResource: fileName, ofType: type) else { return }
        let videoURL = URL(fileURLWithPath: filePath)
        let playerItem = AVPlayerItem(url: videoURL)
        player?.replaceCurrentItem(with: playerItem)
        player?.play()
    }

Get notified when player stops playing video

Till now, we successfully added code that will play video from the file specified in playVideoWithFileName function. So, question arises how the system will get to know as soon as player finish playing video. Answer to last question is using AVPlayerItemDidPlayToEndTime notification. Notification observer will be added to function addPlayerToView and thus allowing VideoPlayer to listen for AVPlayer end playing notification.

 NotificationCenter.default.addObserver(self, selector: #selector(playerEndPlay), name: .AVPlayerItemDidPlayToEndTime, object: nil)

  @objc func playerEndPlay() {
        print("Player ends playing video")
    }

Complete code for VideoPlayer.swift

import UIKit
import AVKit

class VideoPlayer: UIView {
    @IBOutlet weak var vwPlayer: UIView!
    var player: AVPlayer?

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    fileprivate func commonInit() {
        let viewFromXib = Bundle.main.loadNibNamed("VideoPlayer", owner: self, options: nil)![0] as! UIView
        viewFromXib.frame = self.bounds
        addSubview(viewFromXib)
        addPlayerToView(self.vwPlayer)
    }
    
    fileprivate func addPlayerToView(_ view: UIView) {
        player = AVPlayer()
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = self.bounds
        playerLayer.videoGravity = .resizeAspectFill
        view.layer.addSublayer(playerLayer)
        NotificationCenter.default.addObserver(self, selector: #selector(playerEndPlay), name: .AVPlayerItemDidPlayToEndTime, object: nil)
    }
    
    func playVideoWithFileName(_ fileName: String, ofType type:String) {
        guard let filePath = Bundle.main.path(forResource: fileName, ofType: type) else { return }
        let videoURL = URL(fileURLWithPath: filePath)
        let playerItem = AVPlayerItem(url: videoURL)
        player?.replaceCurrentItem(with: playerItem)
        player?.play()
    }
    
    @objc func playerEndPlay() {
        print("Player ends playing video")
    }
}

Using custom video player class inside main project

Open Main.storyboard and drag a UIView object to it. Add constraints to it and finally change UIView class name to VideoPlayer from Identity inspector.

Identity inspector changing UIView class name

In ViewController.swift, create IBOutlet of VideoPlayer and connect this IBOutlet with VideoPlayer object added to storyboard. From viewDidLoad function, call playVideoWithFileName function. That’s it.

class ViewController: UIViewController {

    @IBOutlet weak var player:VideoPlayer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        player.playVideoWithFileName("videoTutorial1", ofType: "mp4")
    }
}