AVPlayerLayer isn't showing AVPlayer video?

Praxiteles picture Praxiteles · Jul 14, 2015 · Viewed 10.2k times · Source

What's the trick to getting AVPlayer video content to show up in one's view?

We are using the following AVPlayer code but nothing is appearing on screen. We know the video is there because we were able to show it using an MPMoviePlayerController.

Here is the code we are using:

AVAsset *asset = [AVAsset assetWithURL:videoTempURL];
AVPlayerItem *item = [[AVPlayerItem alloc] initWithAsset:asset];
AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:item];
player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:player];
// layer.frame = self.view.frame;
[self.view.layer addSublayer:layer];
layer.backgroundColor = [UIColor clearColor].CGColor;
//layer.backgroundColor = [UIColor greenColor].CGColor;
[layer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[player play];

Are we setting the layer improperly for the current view?

Answer

seo picture seo · Dec 17, 2015

You need to set the layer's frame property. e.g.:

 self.playerLayer.frame = CGRectMake(0, 0, 100, 100)

If you tried this and it didn't work in the view controller's view, it is likely that you tried to set the layer's frame property to the view-controllers frame or bounds property which was {0, 0, 0, 0} at the time the AVPlayerLayer was created. You will need to set the frame of the player during layout-passes, at which point the view-controller's frame will be set to something other than {0, 0, 0, 0}. To do this properly:

If you're using auto-layout in a custom UIView (including IB):

override func layoutSubviews() {
    super.layoutSubviews()

    //Match size of view
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    self.playerLayer.frame = self.bounds
    CATransaction.commit()
}

If you're using auto-layout in a custom UIViewController:

override fun viewDidLayoutSubviews() {
  //Match size of view-controller
  CATransaction.begin()
  CATransaction.setDisableActions(true)
  self.playerLayer.frame = self.view.bounds
  CATransaction.commit()
}

The CATransaction lines are to disable implicit animations on the layer's frame change. If you're wondering why this normally not needed, it's because layers that back UIView's will not implicitly animate by default. In this case, we are using a non-view backed layer (AVPlayerLayer)

The best route to take will be to add a new view to your view-controller through interface build and set a custom class on the newly added view. Then create that custom view class and implement the layoutSubviews code.