swiftxcodecocoaswift3avplayerviewcontroller

How to embed and stream a video from the web within an Xcode macOS Cocoa Application?


I am trying to get my macOS Cocoa Application Xcode project to play some video when I feed it a specified URL.

To simplify the question lets just use an empty Xcode project.

I want to achieve the same level of control as I am able to get using AVPlayerViewController() in my iOS Single View Application. Within that app I am currently using the solution offered here.

However, only the second example works in my macOS Cocoa Application when adapted like so:

import Cocoa
import AVFoundation
import AVKit

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        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()

    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }


}

This option however has 2 downsides:

  1. It creates a repetitive error message in the console:

    2017-06-27 18:22:06.833441+0200 testVideoOnmacOS[24456:1216773] initWithSessionInfo: XPC connection interrupted
    2017-06-27 18:22:06.834830+0200 testVideoOnmacOS[24456:1216773] startConfigurationWithCompletionHandler: Failed to get remote object proxy: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.rtcreportingd" UserInfo={NSDebugDescription=connection to service named com.apple.rtcreportingd}
    
  2. This AVPlayer solution does not offer the same control as the AVPlayerViewController() solution.

So I attempted to get the following AVPlayerViewController() solution to work. But it fails:

import Cocoa
import AVFoundation
import AVKit

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        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()
        }

    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }


}

The error I am getting is:

Use of unresolved identifier 'AVPlayerViewController' - Did you mean 'AVPlayerViewControlsStyle'?

I have tried to work around this in many different ways. It will be confusing if I spell them all out. My prominent problem seems to be that the vast majority of online examples are iOS based.

Thus, the main question:

How would I be able to successfully use AVPlayerViewController within my Xcode macOS Cocoa Application?


Solution

  • Yes, got it working!

    Thnx to ninjaproger's comment.

    This seems to work in order to get a video from the web playing / streaming on a macOS Cocoa Application in Xcode.

    First, create a AVKitPlayerView on your storyboard and link it as an IBOutlet to your NSViewController.

    Then, simply apply this code:

    import Cocoa
    import AVFoundation
    import AVKit
    
    class ViewController: NSViewController {
        @IBOutlet var videoView: AVPlayerView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
            let player = AVPlayer(url: videoURL!)
            let playerViewController = videoView
            playerViewController?.player = player
            playerViewController?.player!.play()
        
        }
    
        override var representedObject: Any? {
            didSet {
            // Update the view, if already loaded.
            }
        }
    
    
    } 
    

    Update august 2021

    Ok, it's been a while since this answer has been up and I am no longer invested in it. But it seems others still end up here and the solution needs a bit more work to work properly at times.

    With thanks to @SouthernYankee65:

    What is needed sometimes is to go to the project file and on the Signing & Capabilities tab check Outgoing Connection (Client). Then in the info.plist add App Transport Security Settings dictionary property, then add Allows Arbitrary Loads boolean property and set it to YES.

    The video now plays. However, some errors in the console might occur.