Display multiple videos with AVPlayer - swift - programmatically

862 views Asked by At

I have a AVPlayer that displays a video from a url, this is how I set it up:

fileprivate func setUpPlayer(cardModel : CardModel){
    
    cardModel.urlStrings?.forEach({ (urlstring) in
        
        guard let url = URL(string: urlstring) else {
            return
        }
        
        urlStrings.append(url)
    })
    
    player = AVPlayer(url: urlStrings[0])
    playerLayer = AVPlayerLayer(player: player)
    playerLayer.videoGravity = .resizeAspectFill
    player.play()
    self.playerView.layer.insertSublayer(playerLayer, at: 0).
    }
  

As you can see at the beginning I create a list of urls, I want to display this urls whenever a touch event occurs:

This are the two snippets I created to display this list of video from the array of urls:

 fileprivate func goToNextVideo(){
    counter = counter + 1
    counter = min(counter, cardModel!.urlStrings!.count - 1)
    
   
    player = AVPlayer(url: urlStrings[counter])
    
    playerLayer = AVPlayerLayer(player: player)
    playerLayer.videoGravity = .resizeAspectFill
    player.play()
}



fileprivate func goToPreviousVideo(){
    counter = counter - 1
    counter = max(0, counter)
   
    player = AVPlayer(url: urlStrings[counter])
    playerLayer = AVPlayerLayer(player: player)
    playerLayer.videoGravity = .resizeAspectFill
    player.play()
}

This implementation doesn't seem to work, when I go to the next video I can only hear the audio but can't see the video, do you know how can I play videos using AVPlayer from a list of urls?

1

There are 1 answers

0
apodidae On

The following demo will play an array of video urls, forward and back. Unfortunately I could not get it to run in Xcode: 'error = AudioObjectRemovePropertyListenerBlock: can't remove a NULL listener proc' and I do not know how to fix the problem. However it runs ok using Terminal. You will need to add your own file paths to be converted to urls (or add video urls). Copy/paste the code into a file named 'videoPlayer.swift' and use the command line code shown below in Terminal.

/*
1. Add paths to video urls array
2. To run in Terminal:
swiftc videoPlayer.swift -framework Cocoa -o videoPlayer && ./videoPlayer
*/

import Cocoa
import AVKit
import AVFoundation

var videos = [URL]() // video url array
var count:Int = 3 // Starts on videos[3]

class AppDelegate: NSObject, NSApplicationDelegate {
var window:NSWindow!
var playerView:AVPlayerView!

@objc func playAction(_ sender:AnyObject ) {
   let player = AVPlayer(url:videos[count])
    playerView.player = player
    player.play()
    window.setTitleWithRepresentedFilename(videos[4].lastPathComponent)
  print("index = \(count)")
}

@objc func forwardAction(_ sender:AnyObject ) {
 if (count == videos.count - 1) {
  count = 0
 } else {
  count = count + 1
 }
 print("index = \(count)")     
 let player = AVPlayer(url: videos[count]) 
 playerView.player = player   
 player.play()
 window.setTitleWithRepresentedFilename(videos[count].lastPathComponent) 
 }

@objc func backAction(_ sender:AnyObject ) {
if (count == 0) {
  count = videos.count - 1
 } else {
 count = count - 1
 }
 print("index = \(count)")
 let player = AVPlayer(url: videos[count]) 
 playerView.player = player   
 player.play()
 window.setTitleWithRepresentedFilename(videos[count].lastPathComponent)
 
}

func loadPlayList() {
videos.append(URL(fileURLWithPath:"/Users/xxxx/Movies/myVideo0.m4v"))
videos.append(URL(fileURLWithPath:"/Users/xxxx/Movies/myVideo1.m4v"))
videos.append(URL(fileURLWithPath:"/Users/xxxx/Movies/myVideo2.mp4"))
videos.append(URL(fileURLWithPath:"/Users/xxxx/Movies/myVideo3.mp4"))
videos.append(URL(fileURLWithPath:"/Users/xxxx/Movies/myVideo4.m4v"))
videos.append(URL(fileURLWithPath:"/Users/xxxx/Movies/myVideo5.mpg"))

 for video in videos {
  print(video)
 }
 print("total videos = \(videos.count)")
}

func buildMenu() {
 let mainMenu = NSMenu()
 NSApp.mainMenu = mainMenu
 // **** App menu **** //
 let appMenuItem = NSMenuItem()
 mainMenu.addItem(appMenuItem)
 let appMenu = NSMenu()
 appMenuItem.submenu = appMenu
 appMenu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q") 
}
    
func buildWnd() {
    
let _wndW : CGFloat = 500
let _wndH : CGFloat = 400

 window = NSWindow(contentRect:NSMakeRect(0,0,_wndW,_wndH),styleMask:[.titled, .closable, .miniaturizable, .resizable], backing:.buffered, defer:false)
 window.center()
 window.title = "AVPlayer"
 window.makeKeyAndOrderFront(window)

// **** AVPlayerView **** //
playerView = AVPlayerView(frame:NSMakeRect( 0, 60, _wndW, _wndH - 60))
playerView.autoresizingMask = [.width, .height]
window.contentView!.addSubview (playerView)

// **** Play Button **** //
let playBtn = NSButton (frame:NSMakeRect( 155, 10, 95, 24 ))
 playBtn.bezelStyle = .rounded
 playBtn.autoresizingMask = [.maxXMargin,.maxYMargin]
 playBtn.title = "Play"
 playBtn.action = #selector(self.playAction(_:))
 window.contentView!.addSubview (playBtn)

// **** Forward Button **** //
let forwardBtn = NSButton (frame:NSMakeRect( 260, 10, 65, 24 ))
 forwardBtn.bezelStyle = .rounded
 forwardBtn.autoresizingMask = [.maxXMargin,.maxYMargin]
 forwardBtn.title = "Fwd"
 forwardBtn.action = #selector(self.forwardAction(_:))
 window.contentView!.addSubview (forwardBtn)

// **** Backward Button **** //
let backBtn = NSButton (frame:NSMakeRect( 330, 10, 65, 24 ))
 backBtn.bezelStyle = .rounded
 backBtn.autoresizingMask = [.maxXMargin,.maxYMargin]
 backBtn.title = "Back"
 backBtn.action = #selector(self.backAction(_:))
 window.contentView!.addSubview (backBtn)

// **** Quit btn **** //
let quitBtn = NSButton (frame:NSMakeRect( _wndW - 50, 10, 40, 40 ))
 quitBtn.bezelStyle = .circular
 quitBtn.autoresizingMask = [.minXMargin,.maxYMargin]
 quitBtn.title = "Q"
 quitBtn.action = #selector(NSApplication.terminate)
 window.contentView!.addSubview(quitBtn)
}
 
func applicationDidFinishLaunching(_ notification: Notification) {
 buildMenu()
 buildWnd()
 loadPlayList() 
}

func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
 return true
}

}
let appDelegate = AppDelegate()

// **** main.swift **** //
let app = NSApplication.shared
app.delegate = appDelegate
app.setActivationPolicy(.regular)
app.activate(ignoringOtherApps:true)
app.run()