django-d
django-d

Reputation: 2280

How to show paused video instead of black screen when starting AVPlayer

I am able to successfully create a player but was annoyed with the initial black screen. I decided to overlay a UIImageView and hide it once the player started. This worked, but I didn't want the hassle of creating and maintaining images for all my videos.

I was able to achieve the exact results I wanted by playing and immediately pausing the player after instantiating it. The only issue was that sometimes the state of the player was getting recorded incorrectly, so when I went to start the player again, the status was listed as already "playing" even though the player was paused.

I starting looking into using AVPlayerItem seekToTime but haven't found any feasible solutions. Is there a "non hacky" way of achieving this?

Upvotes: 15

Views: 3877

Answers (2)

JAL
JAL

Reputation: 42459

If you're using an AVPlayerViewController, this is a perfect use of the player controller's contentOverlayView property. This is a UIView between the player layer and the controls exposed exactly for this purpose:

First, create the screenshot:

let asset = AVAsset(URL: URL(string: "")!) // link to some video
let imageGenerator = AVAssetImageGenerator(asset: asset)
let screenshotTime = CMTime(seconds: 1, preferredTimescale: 1)
if let imageRef = try? imageGenerator.copyCGImageAtTime(screenshotTime, actualTime: nil) {

    let image = UIImage(CGImage: imageRef)

    // see part 2 below
}

Now, add the image as a subview of the contentOverlayView in the player controller:

// in the same try block

let imageView = UIImageView(image: image)
let playerVC = AVPlayerViewController()
let playerItem = AVPlayerItem(asset: asset)
playerVC.player = AVPlayer(playerItem: playerItem)

self.presentViewController(playerVC, animated: true) { 
    playerVC.contentOverlayView?.addSubview(imageView)
    // adjust the frame of your imageView to fit on the player controller's contentOverlayView
}

Then, remove the imageView subview when the player starts playing the asset, or when buffering completes.

Upvotes: 11

Moose
Moose

Reputation: 2737

The AVPlayerLayer associated with your player has a readyForDisplay property.

You can try to make your host view an observer for this value, and do a refresh as soon as it is set to true.

It is set to true when the first frame is ready to be rendered, so before the player has enough data to play and set its status to readyToPlay.

Upvotes: 3

Related Questions