I am trying to play videos in my app, but when I selected larger files from data that I download from Dropbox, I get a crossed out play button, and can't see or play my video.
I understand that there must be a couple of reasons why the player might disable itself, but is there a way to get feedback from the player to see what it might be complaining about?
This is my code:
let path = URL.init(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let url = path.appendingPathComponent("temp.mov")
do {
try data.write(to: url, options: .atomic)
} catch let error {
print("WRITING: \(error)")
}
player = AVPlayer(url: url)
let playerController = AVPlayerViewController()
playerController.player = player
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
playerController.view.frame = videoView.frame
player.play()
Thanks!
JK
Related
I have set up a function that creates an AVPlayerViewController instance in order to play an audio track (stored in our server).
func playAudio(_ url: URL) {
let avAssest = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: avAssest)
audioPlayer = AVPlayer(playerItem: playerItem)
let playerViewController = AVPlayerViewController()
playerViewController.player = audioPlayer
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
self.present(playerViewController, animated: true, completion: {
self.audioPlayer.play()
})
}
The player works fine while in the foreground. If I go to the lock screen, the audio continues to play. If I press the Pause button in the lock screen, the audio pauses. The problem is, if I then click play on the lock screen, the audio I was listening to resumes, but a second instance of the audio starts playing from the start, so now i have 2 instances of the audio playing simultaneously. If I pause again and press play again, yet another instance of the audio starts playing.
How can I fix this so the lock screen buttons only affect the original audio?
I'm working on Xcode 11, with Swift 4.2.
The problem cannot be reproduced based on the code you showed. Therefore it sounds like you have an extra reference somewhere to self.audioPlayer, and the problem is caused by code you did not reveal to us.
To test that theory, let's start by not making it a global. There's no need for that within the scope of the question.
Modify your code to look like this (note the changes to make this a local):
let avAssest = AVAsset(url: url)
let playerItem = AVPlayerItem(asset: avAssest)
let audioPlayer = AVPlayer(playerItem: playerItem) // *
let playerViewController = AVPlayerViewController()
playerViewController.player = audioPlayer
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [])
self.present(playerViewController, animated: true, completion: {
audioPlayer.play() // *
})
Now delete the audioPlayer property and, if your code fails to compile, comment out everything that refers to it until the code does compile. Test the app; all is well. Now go back and figure out where in the code you did not show us the problem is coming from.
I am attempting to play a video file from a youtube url. I have created the AVPlayer and linked the url to the player. The player opens when I click the button, but the video player just shows the file continuously loading. I have changed the App Transport Security Settings -> Allow Arbitrary Loads on the plist.
Heres the code:
#IBAction func playVideo(_ sender: Any) {
let movieId = "xLCn88bfW1o"
let path = URL(string: "https://www.youtube.com/watch?v=\(movieId)")
let video = AVPlayer(url: path!)
let videoPlayer = AVPlayerViewController()
videoPlayer.player = video
present(videoPlayer, animated: true, completion: {
video.play()
})
}
EDIT: I've also tried by using the URL for sharing the video; https://youtu.be/xLCn88bfW1o.
The url you are using is not the url to the video, it is the url to a webpage which has the video embedded. There are tools out there that can help you get the actual url of the video file.
For example: YoutubeDirectLinkExtractor
YoutubeDirectLinkExtractor allows you to obtain the direct link to a YouTube video, which you can easily use with AVPlayer. It uses type safety and optionals to guarantee that you won't crash while extracting the link no matter what. There are popular alternatives, which use more straightforward and risky approach, though:
Use extracted video link with AVPlayer:
let y = YoutubeDirectLinkExtractor()
y.extractInfo(for: .urlString("https://www.youtube.com/watch?v=HsQvAnCGxzY"), success: { info in
let player = AVPlayer(url: URL(string: info.highestQualityPlayableLink!)!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}) { error in
print(error)
}
You need to pass the video file's direct URL to AVPlayer (not a Youtube website URL)
For example:
let path = URL(string: "https://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4")
Im trying to display a local recorded video in a AVPlayerLayer which works sometimes. I can hear the audio from the recorded video but can't see the video. Sometimes both video and audio is working, sometimes only audio.
I've tried both with a AVPlayerLayer and AVPlayerViewController but the same issue occurs in both cases. So it's not because of the frames being wrong.
Example code AVPlayerViewController:
let player = AVPlayer(url: url)
let playerController = AVPlayerViewController()
playerController.player = player
self.present(playerController, animated: true) {
player.play()
}
Example code AVPlayerLayer:
let asset = AVAsset(url: url)
let item = AVPlayerItem(asset: asset)
self.player = AVPlayer(playerItem: item)
self.player?.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions(), context: nil)
self.playerLayer = AVPlayerLayer(player: self.player!)
self.playerLayer?.frame = imageView.bounds
imageView.layer.addSublayer(self.playerLayer!)
Edit 1:
When observing the status of the player, error is nil and the status is readyToPlay
Edit 2:
Works fine if the URL is remote.
Edit 3:
Seems to work if I wait a couple of seconds after the video has completed the export. Could it be something to have with the file not 100% written to the filesystem?
Edit 4:
Video of the problem, in this case it played the 3rd time.
Here's how I set a AVPlayerLayer with the video working (I think what you're missing is the videoGravity parameter).
let bundle = Bundle.main
let moviePath = bundle.path(forResource: "myVideo", ofType: "mp4")
let moviePlayer = AVPlayer(url: URL(fileURLWithPath: moviePath!))
playerLayer = AVPlayerLayer(player: moviePlayer)
playerLayer.frame = movieView.bounds
playerLayer.videoGravity = AVLayerVideoGravityResizeAspect
movieView.layer.addSublayer(playerLayer)
playerLayer.player?.play()
It's the frame height or width is equal to zero
i have the same issues as you did. the reason is in iOS 10.xx , if you export video with animationTool .
You will meet the trouble like that .
try to fix them by remove this code .
something like that
mainComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentlayer)
Hope to help you
What caused this issue for me was I was changing assets to play a new video. The problem was I was reinitializing the same AVPlayer and setting setting it to the playerLayer which was previously set
Incorrect
player = AVPlayer()
playerLayer = AVPlayerLayer(player: player)
// ...
player?.replaceCurrentItem(with: playerItem)
Correct
if player == nil {
player = AVPlayer()
playerLayer = AVPlayerLayer(player: player)
// ...
}
player?.replaceCurrentItem(with: playerItem)
Or better yet I should've just called this by itself
player?.replaceCurrentItem(with: playerItem)
I have a video player in an IOS App and I want to update the video when I click on a button, but I do not see how to manage this.
(Note : it's not a list of video within a queue)
Here is the code for adding the AVPlayer:
let url = NSURL.fileURLWithPath(path)
let player = AVPlayer(URL: url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
..
..
self.ViewForVideo.addSubview(playerViewController.view)
self.addChildViewController(playerViewController)
player.play()
I have done like this : each time I want to change the video I create a new AVPlayer and affect it to the playerViewController.player like this
let url = NSURL.fileURLWithPath(path)
let player = AVPlayer(URL: url)
playerViewController.player = player
I want to play YouTube videos from my tvOS application. I found to play URL videos by AVPlayer, but not getting to play YouTube videos since UIWebView is not supported on tvOS. I don't want to use any third party libraries.
You need to use YoutubeSourceParserKit to parse data that you receive from url. Then you will have the url and you will be able to play video with the following code (Swift 2 solution for tvOS 9):
Youtube.h264videosWithYoutubeURL(NSURL.init(string: "https://www.youtube.com/any-video-url")!)
{ (videoInfo, error) -> Void in
if let videoURLString = videoInfo?["url"] as? String,
videoTitle = videoInfo?["title"] as? String {
let videoURL = NSURL(string: videoURLString)
let player = AVPlayer(URL: videoURL!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.presentViewController(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
}