[object Object] Icon

Encoding
Learn how to create, start, manage and modify Encodings

[object Object] Icon

Player
Learn how to create, start, manage and modify Players

[object Object] Icon

Analytics
Learn how to create, start, manage and modify Analyticss

Docs Home
User shortcuts for search
Focus by pressing f
Hide results by pressing Esc
Navigate via   keys

Sun Oct 09 2022

How to get Picture in Picture to work on iOS without Bitmovin Web UI

OverviewLink Icon

This tutorial will guide you through enabling Picture-in-Picture(PiP) mode on iOS when using a Custom Native UI instead of the Bitmovin HTML UI. Bitmovin introduced the ability to configure Picture-in-Picture mode within our Bitmovin Player as part of our V3 SDK. However, since enabling Picture-in-Picture requires listening to a AVKit level Delegate, the BitmovinPlayer is only able to support Picture-in-Picture within our own HTML-based Player UI. Luckily though, there is a very simple way to utilize that same AVPictureInPictureControllerDelegate if you instead prefer to create and use your own custom Native UI for iOS.

To implement Picture-in-Picture within a Native UI, the overall process is pretty simple actually and consists of using iOS' AVKit protocol AVPictureInPictureControllerDelegate along with just a couple of it’s built-in methods to control Picture-in-Picture

Player ConfigurationLink Icon

When using your Native UI, the first thing you will want to do is to let the Bitmovin Player know that you do not want to use the Bitmovin UI within the StyleConfig.

1let config = PlayerConfig()
2config.styleConfig.isUiEnabled = false

Optionally, if you also want PiP to work with Background Playback mode, you will need to enable BackgroundPlayback in the Bitmovin PlaybackConfig:

1config.playbackConfig.isBackgroundPlaybackEnabled = true

Native UI ClassLink Icon

When creating a Native Swift-based UI it is important that this class inherits from the following 2 classes/protocols

PlayerView - The core Bitmovin Player View class that holds the Player instance.

AVPictureInPictureControllerDelegate - Protocol that will allow your UI to handle Picture-in-Picture events.

1import Foundation
2import BitmovinPlayer
3
4class CustomPiPView: PlayerView, AVPictureInPictureControllerDelegate {
5}

In our newly created CustomPipView class we can now initialize the PlayerView and then initialize the AvPictureInPictureController to a stored variable like so:

1var controller: AVPictureInPictureController?
2override init(player: Player, frame: CGRect) {
3super.init(player: player, frame: frame)
4
5let layer = self.layer as! AVPlayerLayer
6if AVPictureInPictureController.isPictureInPictureSupported() {
7self.controller = AVPictureInPictureController(playerLayer: layer)
8self.controller?.delegate = self
9}
10}

Finally we can create two methods for entering and exiting Picture-in-Picture using the AvPictureInPictureController’s built-in methods startPictureInPicture and stopPictureInPicture.

1func enterPiP() {
2self.controller?.startPictureInPicture()
3}
4
5func exitPiP() {
6self.controller?.stopPictureInPicture()
7}

There are also some additional available Picture-in-Picture event listeners and additional capabilities(i.e. state callers, image customizations, etc..) which can found in the AvPictureInPictureController’s docs here → Apple Developer Documentation

Full Example Class:

1import Foundation
2import BitmovinPlayer
3
4class CustomPiPView: PlayerView, AVPictureInPictureControllerDelegate {
5var controller: AVPictureInPictureController?
6override init(player: Player, frame: CGRect) {
7super.init(player: player, frame: frame)
8
9let layer = self.layer as! AVPlayerLayer
10if AVPictureInPictureController.isPictureInPictureSupported() {
11 self.controller = AVPictureInPictureController(playerLayer: layer)
12 self.controller?.delegate = self
13}
14}
15
16func enterPiP() {
17self.controller?.startPictureInPicture()
18}
19
20func exitPiP() {
21self.controller?.stopPictureInPicture()
22}
23}

Using The Native UILink Icon

Now that our Player is configured and our Native UI class is configured for Picture-in-Picture functionality we can create an instance of this Native UI to be used with the Bitmovin Player form our ViewController:

1// class level variables:
2var playerView: CustomPiPView!
3
4// override the view loaded function
5override func viewDidLoad() {
6 self.playerView = createPlayerView(player: player)
7}
8
9private func createPlayerView(player: Player) -> CustomPiPView {
10let playerView = CustomPiPView(player: player, frame: .zero)
11playerView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
12playerView.frame = view.bounds
13
14return playerView
15}

Known LimitationsLink Icon

Custom Native Swift-based UI

Give us feedback