Register for this year’s #ChromeDevSummit happening on Nov. 11-12 in San Francisco to learn about the latest features and tools coming to the Web. Request an invite on the Chrome Dev Summit 2019 website

Watch video using Picture-in-Picture

Picture-in-Picture (PiP) allows users to watch videos in a floating window
(always on top of other windows) so they can keep an eye on what they’re
watching while interacting with other sites, or applications.

Background

In September 2016, Safari added Picture-in-Picture support through a WebKit API
in macOS Sierra. Six months later, Chrome automatically played
Picture-in-Picture video on mobile with the release of Android O using a
native Android API. Six months later, we announced our intent to build and
standardize a Web API, feature compatible with Safari’s, that would allow web
developers to create and control the full experience around Picture-in-Picture.
And here we are!

Get into the code

Enter Picture-in-Picture

Let’s start simply with a video element and a way for the user to interact
with it, such as a button element.

Only request Picture-in-Picture in response to a user gesture, and never in the
promise returned by videoElement.play(). This is because promises do not
yet propagate user gestures. Instead, call requestPictureInPicture() in a
click handler on pipButtonElement as shown below. It is your responsibility
to handle what happens if a users clicks twice.

The video element behaves the same whether it is in Picture-in-Picture or
not: events are fired and calling methods work. It reflects changes of state in
the Picture-in-Picture window (such as play, pause, seek, etc.) and it is also
possible to change state programmatically in JavaScript.

Exit Picture-in-Picture

Now, let's make our button toggle entering and exiting Picture-in-Picture. We
first have to check if the read-only object document.pictureInPictureElement
is our video element. If it isn’t, we send a request to enter
Picture-in-Picture as above. Otherwise, we ask to leave by calling
document.exitPictureInPicture(), which means the video will appear back in
the original tab. Note that this method also returns a promise.

Listen to Picture-in-Picture events

Operating systems usually restrict Picture-in-Picture to one window, so
Chrome's implementation follows this pattern. This means users can only play
one Picture-in-Picture video at a time. You should expect users to exit
Picture-in-Picture even when you didn't ask for it.

Warning: Listen to Picture-in-Picture events instead of waiting for promises
to update your media player controls. It's possible for the video to enter and
exit Picture-in-Picture at any time (e.g. user clicks some browser context menu
or Picture-in-Picture is triggered automatically).

The new enterpictureinpicture and leavepictureinpicture event handlers let
us tailor the experience for users. It could be anything from browsing a
catalog of videos, to surfacing a livestream chat.

Customize the Picture-in-Picture window

Chrome 74 supports play/pause, previous track and next track buttons in the
Picture-in-Picture window you can control by using the Media Session API.

Figure 1.
Media playback controls in a Picture-in-Picture window

By default, a play/pause button is always shown in the Picture-in-Picture
window unless the video is playing MediaStream objects (e.g. getUserMedia(),
getDisplayMedia(), canvas.captureStream()) or the video has a MediaSource
duration set to +Infinity (e.g. live feed). To make sure a play/pause button
is always visible, set somesee Media Session action handlers for both "Play" and
"Pause" media events as below.

Showing "Previous Track" and "Next track" window controls is similar. Setting
Media Session action handlers for those will show them in the Picture-in-Picture
window and you'll be able to handle these actions.

I’d suggest not hooking directly to the resize event as each small change made
to the Picture-in-Picture window size will fire a separate event that may cause
performance issues if you’re doing an expensive operation at each resize. In
other words, the resize operation will fire the events over and over again very
rapidly. I’d recommend using common techniques such as throttling and
debouncing to address this problem.

Feature support

The Picture-in-Picture Web API may not be supported, so you have to detect this
to provide progressive enhancement. Even when it is supported, it may be
turned off by the user or disabled by a feature policy. Luckily, you can use
the new boolean document.pictureInPictureEnabled to determine this.

MediaStream video support

Video playing MediaStream objects (e.g. getUserMedia(), getDisplayMedia(),
canvas.captureStream()) also support Picture-in-Picture in Chrome 71. This
means you can show a Picture-in-Picture window that contains user's webcam
video stream, display video stream, or even a canvas element. Note that the
video element doesn't have to be attached to the DOM to enter
Picture-in-Picture as shown below.