I am trying to loop a video with playerViewController on Swift for TVOS. I have the video playing fine, but I want to loop the video. Here is my code so far:
override func viewDidAppear(_ animated: Bool) {
let videoURL = URL(string: "https://url-to-video.com/video.mp4")
let player = AVPlayer(url: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
Any help is appreciated. Thanks
The quickest way to do this is to use an AVQueuePlayer with an AVPlayerLooper. You can set the player on your player view controller the same as you would with an ordinary AVPlayer, but you need to keep a persistent reference around to the looper so it’ll keep working. In other words, add this to your view controller’s interface:
var looper: AVPlayerLooper?
…and in your viewDidAppear, replace this:
let player = AVPlayer(url: videoURL!)
with this:
let player = AVQueuePlayer()
looper = AVPlayerLooper(player: player, templateItem: AVPlayerItem(asset: AVAsset(url: videoURL!)))
Then, once you start the player playing, its video will loop indefinitely.
Related
I have collectionView and each cell has a video displayed.
When a cell is tapped I present a ViewController that plays the video.
The code that does this in the ViewController is as follows:
fileprivate func configureVideo(with moment : Moment){
guard let urlString = moment.videoUrl else { return }
guard let videoUrl = URL(string: urlString) else { return }
self.player = AVPlayer(url: videoUrl)
dispatchGroup.enter()
self.player!.addObserver(self, forKeyPath: #keyPath(player.currentItem.isPlaybackLikelyToKeepUp),
options: .new, context: &playbackLikelyToKeepUpContext)
NotificationCenter.default.addObserver(self, selector: #selector(videoReachedEnd), name: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
self.playerLayer = AVPlayerLayer(player: player)
self.view.layer.insertSublayer(playerLayer!, at: 0)
self.playerLayer?.frame = self.view.bounds
self.player?.play()
}
The fact that the video is being loaded when the controller is presented makes the process of video loading longer than I would like it to.
I would like that the videos are being loaded before, when I am scrolling through the cells of the collectionView, so that when I tap on a cell and the controller is presented, the video is already ready to play.
But I don't know what would be the right approach for it.
If you have any suggestions I am willing to listen.
I am trying to determine if a user taps on the unmute button while watching a video. I am aware of player.isMuted but I am not sure how to check if there is a change if value. I am using AVPlayerVideoViewController and want to override the unmute button functionality.
I created a sample ViewController, you can observe isMuted changes easily:
import AVKit
class ViewController: AVPlayerViewController {
var muteObservation: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
guard let videoPath = Bundle.main.path(forResource: "video", ofType: "mov") else {
return
}
let videoURL = URL(fileURLWithPath: videoPath)
player = AVPlayer(url: videoURL)
player?.play()
muteObservation = player?.observe(\.isMuted) { player, _ in
print("isMuted: \(player.isMuted)")
}
}
}
I created a game that has a starting menu screen. In this menu screen, I want a video(I recorded me playing this game via iPhone 6 simulator) to play in the background of this menu screen. I got the video to play, but what happens is when the view loads, it will show the menu, then it will show the video replacing the menu itself.
import SpriteKit
import UIKit
import AVFoundation
class MenuScene: SKScene {
var player:AVPlayer!
var VideoSprite:SKVideoNode!
override func didMoveToView(view: SKView) {
let videoURL: NSURL = NSBundle.mainBundle().URLForResource("startTo32", withExtension: "mov")!
player = AVPlayer(URL: videoURL)
player?.actionAtItemEnd = .None
player?.muted = true
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
playerLayer.zPosition = -100
playerLayer.frame = view.frame
player?.play()
NSNotificationCenter.defaultCenter().addObserver(self,
selector: #selector(MenuScene.loopVideo),
name: AVPlayerItemDidPlayToEndTimeNotification,
object: nil)
view.layer.addSublayer(playerLayer)
}
func loopVideo() {
player?.seekToTime(kCMTimeZero)
player?.play()
}
--------UPDATE--------
Here's the link to see what I'm talking about. the screen with the words is where I'm trying to get the video to play, but instead it just makes the screen go white and then plays the video itself.
Any questions or need for me to add information, just comment.
Thanks, Jordan.
Try using your SKVideoNode instead of adding a layer to your view.
Something like this:
let videoURL: NSURL = NSBundle.mainBundle().URLForResource("startTo32", withExtension: "mov")!
VideoSprite = SKVideoNode(url: videoURL)
self.addChild(VideoSprite)
VideoSprite.play()
SKVideoNode documentation is available here.
Here is your updated video player for Swift 4 and Spritekit:
import SpriteKit
import UIKit
import AVFoundation
class MenuScene: SKScene {
var player:AVPlayer!
var VideoSprite:SKVideoNode!
override func didMoveToView(view: SKView) {
let videoURL: NSURL = Bundle.main.url(forResource: "yourvideonamehere", withExtension: "mp4")! as NSURL
VideoSprite = SKVideoNode(url: videoURL as URL)
self.addChild(VideoSprite)
VideoSprite.play()
player = AVPlayer(url: videoURL as URL)
player?.actionAtItemEnd = .none
player?.isMuted = true
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
playerLayer.zPosition = 100
playerLayer.frame = view.frame
player?.play()
}
func loopVideo() {
player?.seek(to: CMTime.zero)
player?.play()
}
}
I hope this helps.
I have an AVPlayer inside a scrollView and for some reason when the AVPlayer plays the scrollview jumps to the top causing the video to not be visible on the screen as the video is torward the bottom of the scrollView. So inorder to stop the scrollView from jumping I want to disable and enable scrolling when the user starts/stops the video. Not sure if that will solve my problem but I'm hoping someone knows the right way to add an observer or notification for the player so I can test it out.
This is the code I have inside my ViewController that contains some static text and the AVPlayer.
Code Below:
let path = NSBundle.mainBundle().pathForResource("carbon_video", ofType:"mp4")
let url = NSURL.fileURLWithPath(path!)
var player = AVPlayerViewController()
var avPlayer = AVPlayer(URL: url)
player.player = avPlayer
self.addChildViewController(player)
player.view.translatesAutoresizingMaskIntoConstraints = false
player.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: nil)
player.addObserver(self, forKeyPath: "rate", options: NSKeyValueObservingOptions.New, context: nil)
I think this can help you
func playerItemDidReachEnd(notification: NSNotification) {
let p: AVPlayerItem = notification.object as! AVPlayerItem
p.seekToTime(kCMTimeZero)
}
override func viewDidAppear(animated: Bool) {
avPlayer.play()
paused = false
// Disable scrolling
}
override func viewDidDisappear(animated: Bool) {
avPlayer.pause()
paused = true
// Enable scrolling
}
I'm attempting to play a simple local clip in Xcode7 using Swift for tvOS. All I want is for the video to load fullscreen in the view and loop. Every tutorial I see has the old MPMoviePlayerController or loads from a URL. What is the best way to do this on tvOS?
Update2: This got the video to loop but there is a pause in between. looking into it now to see how to do it seamlessly.
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
var videoPlayer: AVPlayer!
var playerLayer: AVPlayerLayer?
override func viewDidLoad() {
super.viewDidLoad()
let path = NSBundle.mainBundle().pathForResource("video", ofType:"mp4")
let url = NSURL(fileURLWithPath: path!)
let playerItem = AVPlayerItem(URL: url)
self.videoPlayer = AVPlayer(playerItem: playerItem)
self.playerLayer = AVPlayerLayer(player: self.videoPlayer)
self.playerLayer!.frame = self.view.frame
self.videoPlayer!.play()
self.view.layer.addSublayer(self.playerLayer!)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("playerDidReachEnd:"), name: AVPlayerItemDidPlayToEndTimeNotification, object:nil)
}
func playerDidReachEnd(notification: NSNotification) {
self.videoPlayer.seekToTime(kCMTimeZero)
self.videoPlayer.play()
}
}
Let's say your file is named video.m4v and is stored locally on the device (don't forget to add it to Copy Bundle Resources in Build Phases). Create a stored property so you can access the AVPlayer-instance:
var videoPlayer: AVPlayer?
Setup the video player and add the AVPlayerLayer to your view hierarchy.
if let path = NSBundle.mainBundle().pathForResource("video", ofType:"m4v") {
let url = NSURL(fileURLWithPath: path)
let playerItem = AVPlayerItem(URL: url)
self.videoPlayer = AVPlayer(playerItem: playerItem)
self.playerLayer = AVPlayerLayer(player: self.videoPlayer)
self.playerLayer!.frame = self.view.frame
self.view.layer.addSublayer(self.playerLayer!)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("playerDidReachEnd:"), name: AVPlayerItemDidPlayToEndTimeNotification, object:nil)
}
You have now subscribed a notification that i sent when this video ends. Implement handler and tell the player to replay video.
func playerDidReachEnd(notification: NSNotification) {
self.videoPlayer.seekToTime(kCMTimeZero)
self.videoPlayer.play()
}