178

How do you play a video with AV Kit Player View Controller in Swift?

override func viewDidLoad() {
        super.viewDidLoad()
        let videoURLWithPath = "http://****/5.m3u8"
        let videoURL = NSURL(string: videoURLWithPath)
        playerViewController = AVPlayerViewController()

        dispatch_async(dispatch_get_main_queue()) {
            self.playerViewController?.player = AVPlayer.playerWithURL(videoURL) as AVPlayer
        }
    }
Kara
  • 5,650
  • 15
  • 48
  • 55
orazz
  • 2,059
  • 2
  • 13
  • 16
  • For using `AVPlayer` (doesn't have the controls), see [this answer](https://stackoverflow.com/a/47413973/3681880). – Suragch Nov 21 '17 at 13:27

13 Answers13

569

Swift 3.x - 5.x

Necessary: import AVKit, import AVFoundation

AVFoundation framework is needed even if you use AVPlayer

If you want to use AVPlayerViewController:

let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
    playerViewController.player!.play()
}

or just AVPlayer:

let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer)
player.play()

It's better to put this code into the method: override func viewDidAppear(_ animated: Bool) or somewhere after.


Objective-C

AVPlayerViewController:

NSURL *videoURL = [NSURL URLWithString:@"https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"];
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
AVPlayerViewController *playerViewController = [AVPlayerViewController new];
playerViewController.player = player;
[self presentViewController:playerViewController animated:YES completion:^{
  [playerViewController.player play];
}];

or just AVPlayer:

NSURL *videoURL = [NSURL URLWithString:@"https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"];
AVPlayer *player = [AVPlayer playerWithURL:videoURL];
AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player];
playerLayer.frame = self.view.bounds;
[self.view.layer addSublayer:playerLayer];
[player play];
pkis
  • 6,147
  • 1
  • 14
  • 15
  • @pikis Thanks for the code example. Strange, we tried the AVPlayerController as written and get a SIGABRT on: [self presentViewController:playerViewController animated:YES completion:nil]; – Praxiteles Jul 16 '15 at 00:03
  • @Praxiteles, it works on iOS8 or later, maybe it is the reason. – pkis Jul 16 '15 at 10:57
  • 8
    Also required **import AVFoundation** for me – Rich Fox Oct 14 '15 at 18:25
  • @pkis Thanks for this! Do you know if this should work with youtube links? I'm using Swift with `AVPlayerViewController`. For example: i've amended the url to be: `let videoURL = NSURL(string: "https://youtu.be/d88APYIGkjk")`, but all that comes up is a blank AVplayer. it never plays anything from YouTube. If I use the video url you mentioned, it works and plays fine. But I've tried urls from Youtube, IMDB and Apple Movie trailers. But nothing works. Thanks in advance – Nick89 Jan 08 '16 at 21:23
  • 1
    @Nick89, AVPlayer works correct with direct links, but if you need to use services like YouTube, Vimeo, etc.(that have indirect links), you should use their own library or SDK. (e.g. for YouTube: [guide](https://developers.google.com/youtube/v3/guides/ios_youtube_helper)). – pkis Jan 11 '16 at 07:53
  • @elliotrock, also don't forget about transport security: http://stackoverflow.com/questions/31254725/transport-security-has-blocked-a-cleartext-http ,there is a test link: https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8 – pkis Mar 09 '16 at 19:19
  • for swift 3 this should be: guard let url = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4") else { return } No NSUrl Needed – ilan Jan 10 '17 at 08:36
  • @pkis, how to play .m3u8 format video on AVPlayer. And HLS video on AVPlayer? – Gautam Sareriya Mar 14 '17 at 09:56
  • @GautamSareriya, i.e. `let videoURL = URL(string: "https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8")` – pkis Mar 14 '17 at 10:26
  • @pkis, Hello bro Do you know trick play (2x, 3x, 4x) speed feature in this AVPlayerViewController with swift 3? – May Phyu Mar 23 '17 at 10:05
  • @MayPhyu, not sure about ability of native controls, but you can set it by custom (set: _playerViewController.player!.rate = 3_). This link: https://developer.apple.com/reference/avfoundation/avplayer/1388846-rate can be useful too. – pkis Mar 24 '17 at 10:59
  • 2
    The order of the instructions is important, also I needed to import AVKit – htafoya May 23 '17 at 19:00
  • Objective-C version has an unwanted line (probably a refuse): [self.view addSubview: playerViewController.view] is to be removed; – Jim75 Jul 24 '17 at 15:50
  • Tip: controller must be inside NavController sequence to be presented. – ingconti May 29 '18 at 09:14
  • 1
    @pkis Perfect :) , Thank You.! – Khushbu Desai Sep 08 '18 at 10:41
  • If I remember correctly there is a difference on how you do this on OS X and iOS could someone here outline those differences in using AVPlayerViewController/AVPlayer on OS X versus iOS? – Neal Davis Oct 23 '18 at 22:54
  • Thank you for your awesome answer, I'm trying to add the observer from the response below to manage the end of the video and automatically play another one. It has required to expose his didfinishplaying method with @obj-c prefix, but it doesn't trigger anything (not even its alert...) Do you see something I should change from your code or his to add that observer stuff?? thank you :) – Manu Oct 26 '18 at 03:59
31

Try this, definitely works for Swift 2.0

 let player = AVPlayer(URL: url)
    let playerController = AVPlayerViewController()

    playerController.player = player
    self.addChildViewController(playerController)
    self.view.addSubview(playerController.view)
    playerController.view.frame = self.view.frame

    player.play()  
Forge
  • 5,854
  • 6
  • 41
  • 58
Chetan Dobariya
  • 782
  • 8
  • 13
  • 1
    Thanks. The addChildViewController made it embedded just what I want. :) – SDW Mar 16 '16 at 17:19
  • 1
    Embedding does work flawlessly but how will you handle orientation changes? Let say player takes half of screen in portrait and view controller only supports portrait but video can be seen in portrait like most apps do e.. youtube, vimeo etc. – Abid Hussain Jun 01 '16 at 13:45
  • Note: addChildViewController is necessary. I tried without that and then it _almost_ works - it plays once, it expands to full screen. But it doesn't play again, or get out of full screen mode. So child view controller is necessary. – n13 Nov 25 '16 at 10:46
  • `self.addChildViewController(playerController)` is now `self.addChild(playerController)` fyi – Marquis103 Apr 29 '19 at 04:51
12

Try This

var player:AVPlayer!
var avPlayerLayer:AVPlayerLayer = AVPlayerLayer(player: player)
avPlayerLayer.frame = CGRectMake(your frame)
self.view.layer .addSublayer(avPlayerLayer)
var steamingURL:NSURL = NSURL(string:playerURL)
player = AVPlayer(URL: steamingURL)
player.play()
Matteo Gobbi
  • 16,670
  • 3
  • 24
  • 38
Ramesh
  • 617
  • 6
  • 16
  • When I run this code i get the empty view controller – orazz Sep 19 '14 at 13:17
  • @Oneperson you set avPlayerLayer frame ? – Ramesh Sep 19 '14 at 13:19
  • 1
    @Oneperson ok set this avPlayerLayer.frame = CGRectMake(50,50,100,100) – Ramesh Sep 19 '14 at 13:25
  • code var player:AVPlayer! var playerItem:AVPlayerItem!; var avPlayerLayer:AVPlayerLayer = AVPlayerLayer(player: player) avPlayerLayer.frame = CGRectMake(50,50,100,100) self.view.layer .addSublayer(avPlayerLayer) let videoURLWithPath = "http://*****/45.m3u8" var steamingURL:NSURL = NSURL(string: videoURLWithPath) player = AVPlayer(URL: steamingURL) player.play() code – orazz Sep 19 '14 at 13:34
  • @Oneperson http://edge.tolkun.tv/45.m3u8 is not working. can you give your full url – Ramesh Sep 19 '14 at 13:38
  • let videoURLWithPath = "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8" – orazz Sep 19 '14 at 13:43
  • @Oneperson This url is not working . check it in browser – Ramesh Sep 19 '14 at 13:47
  • Cool thanks! Was trying to use a custom UIView subclass to override the AVPlayerLayer's getter and setter but that didn't work. – ratsimihah Oct 29 '14 at 15:30
  • You don't need the playerItem using @Ramesh method – iEmad Nov 08 '15 at 07:55
12

Swift 3.0 Full source code:

import UIKit
    import AVKit
    import AVFoundation

    class ViewController: UIViewController,AVPlayerViewControllerDelegate
    {
        var playerController = AVPlayerViewController()


        @IBAction func Play(_ sender: Any)
        {
            let path = Bundle.main.path(forResource: "video", ofType: "mp4")

            let url = NSURL(fileURLWithPath: path!)

            let player = AVPlayer(url:url as URL)

            playerController = AVPlayerViewController()


            NotificationCenter.default.addObserver(self, selector: #selector(ViewController.didfinishplaying(note:)),name:NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)

            playerController.player = player

            playerController.allowsPictureInPicturePlayback = true

            playerController.delegate = self

            playerController.player?.play()

            self.present(playerController,animated:true,completion:nil)
        }

        func didfinishplaying(note : NSNotification)
        {
            playerController.dismiss(animated: true,completion: nil)
            let alertview = UIAlertController(title:"finished",message:"video finished",preferredStyle: .alert)
            alertview.addAction(UIAlertAction(title:"Ok",style: .default, handler: nil))
            self.present(alertview,animated:true,completion: nil)
        }


        func playerViewController(_ playerViewController: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
                let currentviewController =  navigationController?.visibleViewController

                if currentviewController != playerViewController
                {
                    currentviewController?.present(playerViewController,animated: true,completion:nil)
                }


            }
    }
ronak patel
  • 402
  • 5
  • 17
  • Hello ronak, thank you for introducing the observers in swift to handle the end of the video!! I didn't managed to make it work by creating the AVPlayerViewController with the code provided from the answer on top of yours (first code snippet), what is different? What I missed or should implement in order to make the observer in your methods work? – Manu Oct 26 '18 at 04:05
7

Objective c

This only works in Xcode 7

Go to .h file and import AVKit/AVKit.h and AVFoundation/AVFoundation.h. Then go .m file and add this code:

NSURL *url=[[NSBundle mainBundle]URLForResource:@"arreg" withExtension:@"mp4"];
AVPlayer *video=[AVPlayer playerWithURL:url];
AVPlayerViewController *controller=[[AVPlayerViewController alloc]init];
controller.player=video;
[self.view addSubview:controller.view];
controller.view.frame=self.view.frame;
[self addChildViewController:controller];
[video play];
cbuchart
  • 8,748
  • 6
  • 43
  • 72
user6171720
  • 81
  • 1
  • 1
7

Swift 5+

First of all you have to define 2 variables globally inside your view controller.

var player: AVPlayer!
var playerViewController: AVPlayerViewController!

Here I'm adding player to a desired view.

@IBOutlet weak var playerView: UIView!

Then add following code to the viewDidLoad method.

let videoURL = URL(string: "videoUrl")
self.player = AVPlayer(url: videoURL!)
self.playerViewController = AVPlayerViewController()
playerViewController.player = self.player
playerViewController.view.frame = self.playerView.frame
playerViewController.player?.pause()
self.playerView.addSubview(playerViewController.view)

If you are not defining player and playerViewController globally, you won't be able to embed player.

  • I am using Swift 5 and all my first try's to play a video right after application startup inside the UIView (I have a mix of Scenekit and UI Components) resulted in a black screen doing nothing. It seems it's really necessary to define the variables globally. Works like charm. This example is really a good one. – ZAY May 18 '21 at 16:20
4

Using MPMoviePlayerController :

 import UIKit
 import MediaPlayer

 class ViewController: UIViewController {

     var streamPlayer : MPMoviePlayerController =  MPMoviePlayerController(contentURL: NSURL(string:"video url here"))
     override func viewDidLoad() {
         super.viewDidLoad()
         streamPlayer.view.frame = self.view.bounds
         self.view.addSubview(streamPlayer.view)

         streamPlayer.fullscreen = true
         // Play the movie!
         streamPlayer.play()
}
}

Using AVPlayer :

import AVFoundation

var playerItem:AVPlayerItem?
var player:AVPlayer?

override func viewDidLoad() {
        super.viewDidLoad() 
      let url = NSURL(string: "url of the audio or video") 
      playerItem = AVPlayerItem(URL: url!)
      player=AVPlayer(playerItem: playerItem!)
      let playerLayer=AVPlayerLayer(player: player!)
      playerLayer.frame=CGRectMake(0, 0, 300, 50)
      self.view.layer.addSublayer(playerLayer)
}

I have a play button to handle button tap.

playButton.addTarget(self, action: "playButtonTapped:", forControlEvents: .TouchUpInside)

func playButtonTapped(sender: AnyObject) {
        if player?.rate == 0
        {
            player!.play()
            playButton.setImage(UIImage(named: "player_control_pause_50px.png"), forState: UIControlState.Normal)
        } else {
            player!.pause()
            playButton.setImage(UIImage(named: "player_control_play_50px.png"), forState: UIControlState.Normal)
        }
    }

I have added an observer listening for AVPlayerItemDidPlayToEndTimeNotification.

override func viewWillAppear(animated: Bool) {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "finishedPlaying:", name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem)
    }

override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

When video/audio play is finished, reset button image and notification

  func finishedPlaying(myNotification:NSNotification) {
        playButton.setImage(UIImage(named: "player_control_play_50px.png"), forState: UIControlState.Normal)

        let stopedPlayerItem: AVPlayerItem = myNotification.object as! AVPlayerItem
        stopedPlayerItem.seekToTime(kCMTimeZero)
    }
A.G
  • 13,048
  • 84
  • 61
4

a bug(?!) in iOS10/Swift3/Xcode 8?

if let url = URL(string: "http://devstreaming.apple.com/videos/wwdc/2016/102w0bsn0ge83qfv7za/102/hls_vod_mvp.m3u8"){
    let playerItem = AVPlayerItem(url: url)
    let player = AVPlayer(playerItem: playerItem)
    let playerLayer = AVPlayerLayer(player: player)
    playerLayer.frame=CGRect(x: 10, y: 10, width: 300, height: 300)
    self.view.layer.addSublayer(playerLayer)
}

does not work (empty rect...)

this works:

if let url = URL(string: "http://devstreaming.apple.com/videos/wwdc/2016/102w0bsn0ge83qfv7za/102/hls_vod_mvp.m3u8"){

            let player = AVPlayer(url: url)
            let controller=AVPlayerViewController()
            controller.player=player
            controller.view.frame = self.view.frame
            self.view.addSubview(controller.view)
            self.addChildViewController(controller)
            player.play()
        }

Same URL...

ingconti
  • 9,213
  • 2
  • 51
  • 39
  • add this line: `player.play()` after: `self.view.layer.addSublayer(playerLayer)` and try again – orazz Aug 29 '16 at 12:25
4

Swift 3:

import UIKit
import AVKit
import AVFoundation

class ViewController: UIViewController {

    @IBOutlet weak var viewPlay: UIView!
    var player : AVPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        let url : URL = URL(string: "http://static.videokart.ir/clip/100/480.mp4")!
        player = AVPlayer(url: url)
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = self.viewPlay.bounds
        self.viewPlay.layer.addSublayer(playerLayer)

    }

    @IBAction func play(_ sender: Any) {
        player?.play()
    }

    @IBAction func stop(_ sender: Any) {
        player?.pause()
    }

}
Mohammad Razipour
  • 3,324
  • 3
  • 26
  • 44
2

This worked for me in Swift 5

Just added sample video to the project from Sample Videos

Added action Buttons for playing videos from Website and Local with the following swift code example

import UIKit
import AVKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        //TODO : Make Sure Add and copy "SampleVideo.mp4" file in project before play
    }

    @IBAction func playWebVideo(_ sender: Any) {

        guard let url = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4") else {
            return
        }
        // Create an AVPlayer, passing it the HTTP Live Streaming URL.
        let player = AVPlayer(url: url)
        let controller = AVPlayerViewController()
        controller.player = player
        present(controller, animated: true) {
            player.play()
        }
    }

    @IBAction func playLocalVideo(_ sender: Any) {

        guard let path = Bundle.main.path(forResource: "SampleVideo", ofType: "mp4") else {
            return
        }
        let videoURL = NSURL(fileURLWithPath: path)

        // Create an AVPlayer, passing it the local video url path
        let player = AVPlayer(url: videoURL as URL)
        let controller = AVPlayerViewController()
        controller.player = player
        present(controller, animated: true) {
            player.play()
        }
    }

}
swiftBoy
  • 33,793
  • 26
  • 129
  • 124
1
let videoUrl = //URL: Your Video URL

//Create player first using your URL
let yourplayer = AVPlayer(url: videoUrl)

//Create player controller and set it’s player
let playerController = AVPlayerViewController()
playerController.player = yourplayer


//Final step To present controller  with player in your view controller
present(playerController, animated: true, completion: {
   playerController.player!.play()
})
RobC
  • 16,905
  • 14
  • 51
  • 62
dilip
  • 123
  • 8
0

Swift 5

  @IBAction func buttonPressed(_ sender: Any) {
    let videoURL = course.introductionVideoURL
    let player = AVPlayer(url: videoURL)
    let playerViewController = AVPlayerViewController()
    playerViewController.player = player

    present(playerViewController, animated: true, completion: {

        playerViewController.player!.play()
    })

// here the course includes a model file, inside it I have given the url, so I am calling the function from model using course function.

// also introductionVideoUrl is a URL which I declared inside model .

 var introductionVideoURL: URL

Also alternatively you can use the below code instead of calling the function from model

Replace this code

  let videoURL = course.introductionVideoURL

with

  guard let videoURL = URL(string: "https://something.mp4) else {
        return
0

Swift 5.0

Improved from @ingconti answer . This worked for me.

 if let url = URL(string: "urUrlString"){
            let player = AVPlayer(url: url)
            let avController = AVPlayerViewController()
            avController.player = player
            // your desired frame
            avController.view.frame = self.view.frame
            self.view.addSubview(avController.view)
            self.addChild(avController)
            player.play()
        }
Ram
  • 670
  • 1
  • 10
  • 19