AVPlayerLayer shows black screen but sound is working - ios

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)

Related

Play several videos using AVPlayer in a view

I have an UIView which contains some some texts and views. in each view I need to play a video with AVPlayer , but my problem is only the first view shows the video :
Here is my code :
func playVideo(name:String , onView:UIView) {
let path = Bundle.main.path(forResource: name, ofType: "mp4")
let videoURL = URL(fileURLWithPath: path!)
let player = AVPlayer(url: videoURL)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = onView.frame
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
onView.layer.addSublayer(playerLayer)
player.play()
}
Using the function :
override func viewDidLoad() {
super.viewDidLoad()
//ScrollView
scrollView.contentSize = menuView.frame.size
scrollView.addSubview(menuView)
//Play videos
playVideo(name: "pizza", onView: videoView1)
playVideo(name: "salad", onView: videoView2)
playVideo(name: "fries", onView: videoView3)
}
when I run the app video only play in videoView1 , any suggestion why this happens ?
I also put my code in viewWillAppear , viewDidLayoutSubviews
According to Apple doc:
class AVPlayer
Note
AVPlayer is intended for playing a single media asset at a time.
I just found an alternative solution , I replaced UIView with UIContainerView and then link them with Embed to other view controller and play video in each view controller. Now it works perfectly as I expected.

Debbugging a 'crossed' or disabled play button on AVPlayerViewController

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

Swift: AVPlayer release memory / resources

I am writing an app that need display different video according to the selection of the user. When the user select a video, the function playVideo will be called. And after the video finish playing, then the videoView will be hidden again.
My code is as follows:
var player: AVPlayer?
func playVideo(String: videoFile) {
self.videoView.isHidden = false
let videoURL: NSURL = Bundle.main.url(forResource: videoFile, withExtension: "mp4")! as NSURL
self.player = AVPlayer(url: videoURL as URL)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.videoView.frame
self.videoView.layer.addSublayer(playerLayer)
let duration : Int64 = 0
let preferredTimeScale : Int32 = 1
let seekTime : CMTime = CMTimeMake(duration, preferredTimeScale)
self.player?.seek(to: seekTime)
self.player?.play()
NotificationCenter.default.addObserver(self, selector: #selector(self.playerItemDidReachEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem)
}
#objc func playerItemDidReachEnd()
{
self.player?.pause()
self.videoView.isHidden = true
NotificationCenter.default.removeObserver(self)
}
However, with the code above, i have several question:
How to delete / deallocate the player gracefully? If just using my current code, will it consume lots of memory?
Every time, when the user press a button, the function playVideo will be called, and the corresponding player will be created and play. Is this the right way to do so? Is there any other method or more efficient way or elegant way to do so?
I did try to replace the code on creation of the player by the following, but it fails to play the video.
let playerItem: AVPlayerItem = AVPlayerItem(url: videoURL as URL)
self.player? = AVPlayer(playerItem: playerItem)
Thank you

AVPlayer does not sound if disabled audio / vibration: on

Hy, I'm trying to understand if there is a way to get sound from the player even when your iPhone is set to silent .. Is there a Swift code to enable the Tone?
//IMPOSRT FOUNDATION PER PLAYER
import AVFoundation
let url = NSURL(string: "https://mywebsite.site/file/\(audio_r!)")
playerItem = AVPlayerItem(URL: url!)
player = AVPlayer(playerItem: playerItem!)
let playerLayer = AVPlayerLayer(player: player!)
playerLayer.frame = CGRectMake(0,0,300,50)
self.view.layer.addSublayer(playerLayer)
//imposto il volume
player!.muted = false
player!.volume = 1.0
Someone can help me?
A playback category should not obey the mute switch
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
AVAudioSession.sharedInstance().setActive(true)

How to play video with AVPlayer?

I am using AVPlayer to play a video. But I can not set the Layer of video to be on full screen on iPhone 4s. Is there any difference on iPhone 4s?
Here is what I do:
var playerItem = AVPlayerItem(URL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("demo_video", ofType: "mp4")!))
var player = AVPlayer(playerItem: playerItem)
var playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.frame
self.view.layer.addSublayer(playerLayer)
Thanks
Your video might not be in the frame of the whole screen. Add background color to the PlayerLayer and see if it is full screen.

Resources