I have feed in which different categories have multiple videos fro this I use UICollectionView with in UIStackView. when I scroll to uicollectionview it take some time to load video and their is lagging when scroll
code to play video in UICollectionview cell
self.videoPreview.layer.sublayers?.forEach {
if $0 is AVPlayerLayer {
$0.removeFromSuperlayer()
}
}
self.player = AVPlayer(url: self.templateURL)
let playerLayer = AVPlayerLayer(player: self.player)
playerLayer.frame = self.videoPreview.bounds
self.player!.isMuted = true
self.videoPreview.layer.addSublayer(playerLayer)
self.player!.play()
self.layoutSubviews()
self.videoPreview.layoutIfNeeded()
Related
I have a custom UITableViewCell that displays either an image or a video. If there's a video, it initially downloads and displays the thumbnail from that video while the video is loading and preparing to play.
It all works, the problem is that I get the ratio of the thumbnail, store it in the database and when I download the thumbnail, it makes the height based on that ratio. It works great for images. But the issue is that the AVPlayerLayer frame doesn't cover the entire thumbnail and it looks like this:
Here's how I do it:
func updateView() {
if let videoUrlString = post?.videoUrl, let videoUrl = URL(string: videoUrlString) {
volumeView.isHidden = false
player = AVPlayer(url: videoUrl)
playerLayer = AVPlayerLayer(player: player)
playerLayer!.frame = postImageView.frame // thumbnail image
playerLayer!.videoGravity = AVLayerVideoGravity.resizeAspectFill
contentView.layer.addSublayer(playerLayer!)
self.volumeView.layer.zPosition = 1
layoutIfNeeded()
player?.play()
player?.isMuted = videoIsMuted
}
if let ratio = post?.ratio {
photoHeightConstraint.constant = UIScreen.main.bounds.width / ratio
layoutIfNeeded()
}
}
I'm not doing something right apparently or I'm missing something based on my final result. Any clue?
UPDATE:
I notice that if you scroll the cells slowly, the video is being displayed according to the size of the thumbnail. But if you scroll fast, it mismatches the frame. I assume it has something to do with reusability or it simply cannot catch up with the frame? Here's my code for prepareForReuse() method:
override func prepareForReuse() {
super.prepareForReuse()
profileImageView.image = UIImage(named: "placeholder")
postImageView.image = UIImage(named: "profile_placeholder")
volumeView.isHidden = true
if let p = player, let pLayer = playerLayer {
p.pause()
pLayer.removeFromSuperlayer()
}
}
The solution turned out to be rather simple. Basically each post contains either post or a video, but either way, it always contains an image. I also set the ratio of that image (the width devided by the height). So, all I had to do is set the player's width to the screen width devided by the ratio and it gives your the proper frame.
playerLayer.frame.size.height = UIScreen.main.bounds.width / postRatio
I have an app where I'd like a video to play in the background of a single view.
What I did is create an AVPlayer, add that to an AVPlayerLayer and add that as a sublayer to my view.
Then I set the frame and the videoGravity property:
self.player = AVPlayer(url: URL(fileURLWithPath: path))
let playerLayer = AVPlayerLayer(player: self.player)
self.layer.addSublayer(playerLayer)
playerLayer.frame = self.bounds
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
Now the video plays, except it doesn't fill the entire screen. It fills it's original size, but it doesn't stretch/scale.
Am I missing something? Why is my video not resizing?
Thanks.
Edit:
I added a screenshot and made the view purple for easier reference.
If you want to video to be stretch on the entire view, just delete the line
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
videoGravity default value is AVLayerVideoGravityResize
Update for Swift 5
playerLayer.videoGravity = .resizeAspectFill
Define the playerLayer.frame inside viewDidLayoutSubviews()
At the time you are defining the frames the final frames for the views were not yet calculated.
I am working with apple tv. I have a UIView inside my UIViewController. I am adding AVPlayerViewController as subview of my UIView. UIView's frame is CGRect(x: 50, y: 50, width: 1344, height: 756). I am setting AVPlayerViewController frame equals to my UIView's frame.
Issue is that video plays fine in its frame but the controls like pause, play, forward etc. are hidden and not working. But when I set frame as CGRect(x: 0, y: 0, width: 1920, height: 1080), controls are visible and working.
My code is as per below:
let url = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let item = AVPlayerItem(url: url!)
self.player = AVPlayer(playerItem: item)
self.avplayerController = AVPlayerViewController()
self.avplayerController.player = self.player
self.avplayerController.view.frame = videoPreviewLayer.frame
self.avplayerController.showsPlaybackControls = true
self.avplayerController.requiresLinearPlayback = true
self.addChildViewController(self.avplayerController)
self.view.addSubview(self.avplayerController.view)
self.avpController.player?.play()
Please help.
I managed to solve this using this code:
let player = AVPlayer(url: self.videoUrl!)
let avPlayerController = AVPlayerViewController()
avPlayerController.player = player;
avPlayerController.view.frame = self.videoPlayView.bounds;
self.addChildViewController(avPlayerController)
self.videoPlayView.addSubview(avPlayerController.view);
Now AVPlayerViewController shows most playback controls even as child to a uiview.
Courtesy:
https://www.techotopia.com/index.php/IOS_8_Video_Playback_using_AVPlayer_and_AVPlayerViewController
This is an expected behaviour:
AVPlayerViewController is designed such that when in full screen, the
full playback experience (scrubbing, info panel access, etc) are all
available. When in a space less than full screen, the assumption is
that it is just one of several interactive elements on screen, and
thus the view should not absorb all touch surface events as transport
control.
You can read more about this on this thread: https://forums.developer.apple.com/thread/19526
I'm trying to display a video with this code:
self.videoPlayer = AVPlayer.init(url: videoUrl as URL)
let playerLayer = AVPlayerLayer.init(player: self.videoPlayer)
self.videoPlayerView.layer.addSublayer(playerLayer)
playerLayer.frame = self.videoPlayerView.layer.bounds
self.videoPlayer.play()
but it does not appear inside of the UIView (i.e. self.videoPlayerView). It just shows a thin Rect at the middle of the screen as shown in the screenshot. How do I fix this?
screen shot
try this...
set the layer's frame to equal the view's frame
self.videoPlayer = AVPlayer.init(url: videoUrl as URL)
let playerLayer = AVPlayerLayer.init(player: self.videoPlayer)
self.videoPlayerView.layer.addSublayer(playerLayer)
playerLayer.frame = self.videoPlayerView.frame
self.videoPlayer.play()
Firstly the code is in Swift not Obective-C, I would change that tag! Secondly, how do you define the videoPlayerView frame? Thirdly, you change the frame of the playerLayer after it has already been added. Thus the frame will not change visually! Set the frame before you add it as a subLayer. Hope that helps.
I am having a problem when the iPad is rotated the sub views frame needs to be changed to landscape as well.
The video is used as a landing screen on the home page and is played behind various elements on the page.
The problem is shown here
I currently have the code that detects if the screen is in landscape or horizontal which will be used to make the changes to the sub view if possible.
The player is set up using the code shown:
player = AVPlayer(URL: contentURL!)
player.actionAtItemEnd = .None
player.muted = true
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
playerLayer.zPosition = -1
playerLayer.frame = view.frame
view.layer.addSublayer(playerLayer)
player.play()
Any help would be appreciated, thank you.