Swift AVPlayerLayer videoGravity .resizeAspect only respects height not width - ios

I have an AVPlayer and AVPlayerLayer embedded in a simple UIView. This plays the movie but adjusting playerLayer.videoGravity only effects the movies relative height:
.resizeAspect fills all the way to side of the videoview UIView and crops the height
.resizeAspectFill looks like a zoomed in version of the stretched .resizeAspect
var player = AVPlayer()
#IBOutlet weak var videoview: UIView!
override func viewDidAppear(_ animated: Bool) {
player = AVPlayer(url: url)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.setAffineTransform(CGAffineTransform(rotationAngle: CGFloat((-90 * Double.pi)/180)))
playerLayer.frame = videoview.bounds
playerLayer.videoGravity = .resizeAspect
videoview.layer.addSublayer(playerLayer)
player.play()
}

The issue here was with playerLayer.setAffineTransform(CGAffineTransform(rotationAngle: CGFloat((-90 * Double.pi)/180))) and the video/image size. The wrong height/width were used previously (and needed to be transposed). This resolved the issue.

Related

Swift -Why aren't CALayer images visible inside the Debug View Hierarchy

I have a video that plays inside a CALayer. Everything works fine but when I go to the Debug View Hierarchy, the CALayer that the video plays in, always shows up blank.
Why can't I see the video frame that is visible on the CALayer inside the Debug View Hierarchy?
class AVPlayerView: UIView {
var playerLayer: CALayer?
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: layer)
playerLayer?.frame = self.bounds
}
}
lazy var avPlayerView: AVPlayerView = {
let playerView = AVPlayerView()
playerView.tag = 2
return playerView
}()
func setPlayerAndPlayerLayer(url: URL) {
let asset = AVAsset(url: url)
playerItem = AVPlayerItem(asset: asset)
player = AVPlayer(playerItem: playerItem)
contentView.addSubview(avPlayerView)
avPlayerView.frame = self.bounds
playerLayer.frame = avPlayerView.bounds
avPlayerView.layer.addSublayer(playerLayer!)
avPlayerView.playerLayer = playerLayer
avPlayerView.layoutIfNeeded()
}

Video player in iOS 13 and SWIFT 5 is not working

I am trying to create a simple video player using iOS 13 and SWIFT 5. Below you will see my few lines of code but when I run the app all I see is a blank screen. I hear the video but it is not until I rotate the screen that I even see a section of the video. In my project the "video" appears to be just a photo. The video is not even moving it is just the still image you see in the example below. I am new to iOS/SWIFT but this is the oddest problem I have encountered so far. What am I doing wrong?
ViewController:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var playerLayer = AVPlayerLayer()
override func viewDidLoad() {
super.viewDidLoad()
playVideo()
}
func playVideo(){
let videoURL = URL(string: "https://www.radiantmediaplayer.com/media/bbb-360p.mp4")
let player = AVPlayer(url: videoURL!)
playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspect
self.view.layer.addSublayer(playerLayer)
player.play()
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
playerLayer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
}
}
Give the frame for the playerLayer in playVideo method like this:
playerLayer.frame = view.bounds

AVPlayer resizeAspect works only properly on iPhone X

resizeAspect as the video gravity only works properly for me, when using an iPhone X.
For some reasons, the black aspect bar gets only added to the top and not to the bottom. This is how it looks like when I'm not using an iPhone X (the image is white)
This is how it should look like:
As you can see, on the iPhone X, everything looks clean and balanced as expected.
This is how I play the video:
avPlayerLayer = AVPlayerLayer(player: avPlayer)
avPlayerLayer.frame = PreviewLayer.bounds
avPlayerLayer.videoGravity = .resizeAspect //Will automatically add black bars
PreviewLayer.layer.insertSublayer(avPlayerLayer, at: 0)
let playerItem = AVPlayerItem(url: video)
avPlayer?.replaceCurrentItem(with: playerItem)
avPlayer?.play()
Try this steps
1- Check bottom constraint connect with safe are
2- Try this code
import UIKit
import AVKit
class ViewController: UIViewController {
#IBOutlet weak var playerView: UIView!
private var player: AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
playVideo(from: "Intro.mp4")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func playVideo(from file:String) {
let file = file.components(separatedBy: ".")
guard let path = Bundle.main.path(forResource: file[0], ofType:file[1]) else {
debugPrint( "\(file.joined(separator: ".")) not found")
return
}
player = AVPlayer(url: URL(fileURLWithPath: path))
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: .main) { _ in
self.player?.seek(to: kCMTimeZero)
self.player?.play()
}
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspect
playerLayer.frame = playerView.layer.bounds
playerView.layer.insertSublayer(playerLayer, at: 0)
player.play()
}
}
Result on iphone X
Result on iphone 7
Note : if you need video full view on all devices try to link Bottom
constraint and Top constraint with superview not with safe area
Make your videoLayer View a subview of:
class VideoContainerView: UIView {
var playerLayer: CALayer?
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: layer)
playerLayer?.frame = self.bounds
}
}
and add:
self.VideoShareLayer.playerLayer = avPlayerLayer;
before inserting the layer.

Playing video on login page as full screen

I want to play background video on login screen on swift 3.0. But when I run program, video do not working as full screen. It is workingHow can I fix this ? Here is the storyboard picture.
enter code here
import UIKit
import AVFoundation
class ViewController: UIViewController {
var Player: AVPlayer!
var PlayerLayer: AVPlayerLayer!
var frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let URL:NSURL = NSURL(string: "https://firebasestorage.googleapis.com/v0/b/pattyapp-34c16.appspot.com/o/dog1.mp4?alt=media&token=98ab3c41-c645-4535-a70b-41511b5df602")!
Player = AVPlayer.init(url: URL as URL)
PlayerLayer = AVPlayerLayer(player: Player)
PlayerLayer.videoGravity = AVLayerVideoGravityResizeAspect
PlayerLayer.frame.size = frame.size
Player.actionAtItemEnd = AVPlayerActionAtItemEnd.none
Player.isMuted = true
Player.play()
view.layer.insertSublayer(PlayerLayer, at: 0)
NotificationCenter.default.addObserver(self, selector: #selector(playerItemReachEnd(notification:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: Player.currentItem)
}
func playerItemReachEnd(notification: NSNotification) {
Player.seek(to: kCMTimeZero)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Play video into background you can use the following list of 3rd party library to resolve your problem.
VideoSplashKit
HAPlayerView
Video You are trying to play has dimensions different from layer size. I'd recommend You to try
PlayerLayer.videoGravity = AVLayerVideoGravityResize
or
PlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill

Using VideoPlayer in swift project

I am trying to display a video inside a cell. Instead, it just comes up as a black box. It is possible it is not initializing the player. I do, however see the black box so I know it is initializing the VideoPlayerView. When I print the frame of the playerLayer it prints (0.0, 0.0, 0.0, 0.0), possibly due to how I am initializing the view. Is there any way to extend the playerlayer to the edges of the view without using frame?
class VideoPlayerView : UIView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.black
let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
let player = AVPlayer(url: videoURL!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.bounds
//print(playerLayer.frame)
self.layer.addSublayer(playerLayer)
player.play()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Thanks!
I've tried this a couple of different ways and ended up using a custom UIView class approach (like you did) but a few differences. For example, your class could look like this:
class PlayerView: UIView {
var player: AVPlayer? {
get {
return playerLayer.player
}
set {
playerLayer.player = newValue
}
}
var playerLayer: AVPlayerLayer {
return layer as! AVPlayerLayer
}
// Override UIView property
override static var layerClass: AnyClass {
return AVPlayerLayer.self
}
}
Then, you add a UIView in IB, set the class to PlayerView (instead of default UIView), add your constraints like normal and drag an outlet to your controller like any other control. To use it, you do the following:
playerView.player = AVPlayer(url: url)
playerView.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
Then trigger the Play command however your application needs it.
You could create this view dynamically using the same method but I tend to use IB most of the time.
Hope this helps!
You can set constraints to playerLayer, for example:
let width = UIScreen.main.bounds.width
let height = 300
let playerLayer = AVPlayerLayer(player: player)
playerLayer.translatesAutoresizingMaskIntoConstraints = false
playerLayer.widthAnchor.constraint(equalToConstant: width).isActive = true
playerLayer.heightAnchor.constraint(equalToConstant: height).isActive = true
I figured out that all you need to do is add this code:
Turns out when you resize it doesn't automatically resize layer sizes.
override func layoutSublayers(of layer: CALayer) {
super.layoutSublayers(of: layer)
playerLayer?.frame = self.bounds
}

Resources