Reputation: 495
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
Reputation: 158
Create AVPlayer Instance globally then override it again when you want to play a new video from new URL.
Upvotes: -1
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
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;
It provides the same thing I would, were I to post code of my own.
Upvotes: 5
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