Hacking macOS Sierra's PIP

Hacking macOS Sierra's PIP

One of the headline features in macOS Sierra is Picture in Picture. Unfortunately Apple decided to restrict this to Safari and iTunes which means the majority of users will never get to use it.

Picture in Picture on Apple's website

Digging into the Sierra GM PrivateFrameworks directory revealed a very helpfully named framework called PIP.framework.

Thank you Apple

As with any framework it can be included in a project and used like any other. However Apple remove the headers from their private frameworks which stops us from using them freely. I ran the framework through Steve Nygard's excellent class-dump spitting out a number of helpful header files in the process.

Reading through the PIPViewController.h file it gave me I noticed a PIPViewControllerDelegate that the class-dump didn't uncover. Thank fully WebKit is open-source and Apple happened to include the header files for both the view controller and the delegate online and I stumbled across them on Github.

Using PIP.framework

I put together a little test project (at 1am last night so it's far from complete) to figure out how the framework works. Here's what I uncovered:

  • The PIPViewController is displayed in a PIPPanel that is ran via a PIPAgent. This seems to be a global daemon with the bundle ID of com.apple.PIPAgent.
  • The PIPViewController is a class that can present another NSViewController as a Picture in Picture window.
  • ANY view controller — not just video — can be displayed but the play/pause button cannot be removed or hidden (at least not via any accessible method).
  • The PIPViewControllerDelegate has methods to control play, pause, stop and close.
  • Replacement windows, views and rects control the segue between the original window and the Picture in Picture panel.

There are also a number of methods/properties that control the behaviour of the PIPPanel.

  • aspectRatio is a CGSize that restricts resizing of the panel to a specific ratio. Useful to set the panel to 16:9 or 4:3.
  • setPlaying() sets the state of the play/pause button. Likewise the read-only playing property shows the current state of the panel.
  • userCanResize is there but doesn't seem to be respected by the panel. I'd guess this was added as a possibility but never used by Apple.

Test Project

Piecing it all together I managed to hack together a project that will present a video in the PIPPanel. The video is in an AVPlayerView and I'm then just presenting the containing view controller. The PIPViewControllerDelegate methods are being used to control the player with play/pause.

Currently the view will not return to its original window when closing the PIPPanel and I'm not entirely sure why. Maybe one day I'll spend the time to figure it out 😊

Download on Github

I'm still unsure why Apple chose to keep this private and not allow developers to use it. Even if it was restricted to the AVPlayerView and functioned in the same way as the iOS PIP it would have been a great addition and I'm sure many developers would have jumped at the chance to add this to their media applications.

Maybe in 10.13? Or maybe we'll finally get UIKit (or perhaps that's just wishful thinking).

✌️

Come Say Hello! Drop me an email, follow me on Twitter, or check out Cocoon (you totally should, we're doing some cool stuff over there).