cb428
cb428

Reputation: 495

Play video from new URL without creating a new AVPlayer object

I'm trying to allow users to be able to cycle through videos, changing the AVPlayer URL on the fly without refreshing the view. However, right now I'm just instantiating AVPlayer objects every time a video is played (resulting in audio to be played over one another), which I feel isn't the best way to do this. Is there a more efficient way similar to changing the image in an imageView?

This is the code where I play the clip:

player = AVPlayer(URL: fileURL)
playerLayer = AVPlayerLayer(player: player)
playerLayer!.frame = self.view.bounds
self.view.layer.addSublayer(playerLayer!)
player!.play()

Upvotes: 14

Views: 11705

Answers (4)

Talha Ahmed
Talha Ahmed

Reputation: 158

Create AVPlayer Instance globally then override it again when you want to play a new video from new URL.

Upvotes: -1

Matthew Cawley
Matthew Cawley

Reputation: 2998

Do not use an AVPlayer.

Instead use an AVQueuePlayer which allows you to insert and remove items from a queue.

//create local player in setup methods
self.localPlayer = AVQueuePlayer.init()

to add items you can simply use

//optional: clear current queue if playing straight away
self.localPlayer.removeAllItems()

//get url of track
let url : URL? = URL.init(string: "http://urlOfItem")
if url != nil {
   let playerItem = AVPlayerItem.init(url: url!)

   //you can use the after property to insert 
   //it at a specific location or leave it nil
   self.localPlayer.insert(playerItem, after: nil)
   self.localPlayer.play()
}

AVQueuePlayer supports all of the functionality of the AVPlayer but has the added functionality of adding and removing items from a queue.

Upvotes: 27

James Bush
James Bush

Reputation: 1527

Use AVPlayerItem to add and remove outputs to an AVPlayer object.

Instead of adding a video to the AVPlayer when you create it, create an empty AVPlayer instance, and then use the addOutput method of the AVPlayerItem class to add the video.

To remove the video and add a new one, use the removeOutput method of the AVPlayerItem class to remove the old video, and then the addOutput method again to insert the new one.

Sample code is available from Apple's developer site at;

https://developer.apple.com/library/prerelease/content/samplecode/AVBasicVideoOutput/Introduction/Intro.html

It provides the same thing I would, were I to post code of my own.

Upvotes: 5

MikeG
MikeG

Reputation: 4044

I am able to accomplish what you are looking for by doing this...

I have a tableView of song names, for which the mp3 files are stored on Parse.com. In didSelectRowAtIndexPath I do...

 override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    SelectedSongNumber = indexPath.row
    grabSong()
}


   func grabSong () {

    let songQuery = PFQuery(className: "Songs")
    songQuery.getObjectInBackgroundWithId(iDArray[SelectedSongNumber], block: {
        (object: PFObject?, error : NSError?) -> Void in


        if let audioFile = object?["SongFile"] as? PFFile {
            let audioFileUrlString: String = audioFile.url!
            let audioFileUrl = NSURL(string: audioFileUrlString)!

            myAVPlayer = AVPlayer(URL: audioFileUrl)
            myAVPlayer.play()

            currentUser?.setObject(audioFileUrlString, forKey: "CurrentSongURL")
            currentUser?.saveInBackground()
        }
    }) 
 }

when I run this, i select a row and the song starts playing. If i then wait a few seconds and select a different row, the AVPlayer plays the song from the new cell that i selected and does NOT play one song over the other. My AVPlayer is declared as a public variable for all classes to see.

Upvotes: -2

Related Questions