Article

Adopting Picture in Picture in a Custom Player

Add controls to your custom player user interface to invoke Picture in Picture (PiP) playback.

Overview

Add PiP playback to your custom player by using the AVKit framework’s AVPictureInPictureController class. This class lets you implement the same PiP behavior found in AVPlayerViewController in your custom player.

Update Your Custom Player User Interface

Begin by adding a UI to your custom player interface to enable users to begin PiP playback. Make this UI consistent with the system default UI presented by AVPlayerViewController. Access the standard images for controlling PiP playback by using the pictureInPictureButtonStartImage and pictureInPictureButtonStopImage class properties of AVPictureInPictureController. These methods return system default images to present in your UI.

@IBOutlet weak var pipButton: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()
    
    let startImage = AVPictureInPictureController.pictureInPictureButtonStartImage
    let stopImage = AVPictureInPictureController.pictureInPictureButtonStopImage
    
    pipButton.setImage(startImage, for: .normal)
    pipButton.setImage(stopImage, for: .selected)
}

Create the Picture in Picture Controller

Create an instance of AVPictureInPictureController to control PiP playback in your app. Before attempting to create the controller instance, verify that the current hardware supports PiP playback by calling the isPictureInPictureSupported() method.

func setupPictureInPicture() {
    // Ensure PiP is supported by current device.
    if AVPictureInPictureController.isPictureInPictureSupported() {
        // Create a new controller, passing the reference to the AVPlayerLayer.
        pictureInPictureController = AVPictureInPictureController(playerLayer: playerLayer)
        pictureInPictureController.delegate = self
        
        pipPossibleObservation = pictureInPictureController.observe(\AVPictureInPictureController.isPictureInPicturePossible,
                                                                    options: [.initial, .new]) { [weak self] _, change in
            // Update the PiP button's enabled state.
            self?.pictureInPictureButton.isEnabled = change.newValue ?? false
        }
    } else {
        // PiP isn't supported by the current device. Disable the PiP button.
        pictureInPictureButton.isEnabled = false
    }
}

This example creates a new AVPictureInPictureController instance, passing it a reference to the AVPlayerLayer that presents the video content. You need to maintain a strong reference to the controller object for PiP functionality to work.

To participate in PiP life-cycle events, your code should adopt the AVPictureInPictureControllerDelegate protocol and set itself as the controller’s delegate. Also, use key-value observing (KVO) on the controller’s isPictureInPicturePossible property. This property indicates whether using PiP mode is possible in the current context; for example, when the system is displaying an active FaceTime window. By observing this property, you can determine when it’s appropriate to change the enabled state of your PiP button.

Handle User-Initiated Requests

With the AVPictureInPictureController setup complete, add an @IBAction method to handle user-initiated requests to start or stop Picture in Picture playback.

@IBAction func togglePictureInPictureMode(_ sender: UIButton) {
    if pictureInPictureController.isPictureInPictureActive {
        pictureInPictureController.stopPictureInPicture()
    } else {
        pictureInPictureController.startPictureInPicture()
    }
}

Restore Control to Your App

A user taps the button in the PiP window to return control to your app. By default, this action terminates playback when control returns to the app. AVKit can’t make assumptions about how you’ve structured your app and is unaware of how to properly restore your video playback interface. Instead, it delegates that responsibility to you.

To handle the restore process, implement the pictureInPictureController(_:restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:) delegate method and restore your player interface as needed. When the restoration is complete, call the completion handler with a value of true.

func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController,
                                restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
    // Restore user interface
    completionHandler(true)
}

Dismiss Playback Controls

While Picture in Picture is active, dismiss playback controls in your main player and present artwork inside its bounds to indicate that PiP mode is active. To implement this functionality, use the pictureInPictureControllerWillStartPictureInPicture(_:) and pictureInPictureControllerDidStopPictureInPicture(_:) delegate methods and take the required actions.

func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
    // hide playback controls
    // show placeholder artwork
}

func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
    // hide placeholder artwork
    // show playback controls
}

See Also

Media Playback

Adopting Picture in Picture in a Standard Player

Add Picture in Picture (PiP) playback to your app using a player view controller.

Working with Interstitial Content in tvOS

Present additional content such as legal text, content warnings, or advertisements alongside your main media presentation.

Using AVKit in iOS

This sample code project demonstrates techniques for tracking AVPlayerViewController presentation state across multiple application scenarios, including being displayed fullscreen, embedded inline, or as Picture in Picture.

Adopting Custom Interactive Overlays, Channel Flipping, and Parental Controls in tvOS Video Playback

This sample demonstrates support for custom interactive overlays, and parental controls, using AVPlayerViewController.

Adding Information to the Info Panel (tvOS)

Add metadata information and navigation markers to the Info panel in Apple TV.

class AVPlayerViewController

A view controller that displays the video content from a player object along with system-supplied playback controls.

class AVPlayerView

A macOS-only object that displays the video content from a player object along with system-supplied playback controls.

class AVPictureInPictureController

A controller that responds to user-initiated Picture in Picture playback of video in a floating, resizable window.

class AVInterstitialTimeRange

A time range in an audiovisual presentation designated as interstitial content, such as advertisements or legal notices.

class AVNavigationMarkersGroup

A set of markers for navigating playback of an audiovisual presentation.