What is Picture-in-Picture in JavaScript?

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.

Check if Picture-in-Picture is supported

let isPiPSupported =  'pictureInPictureEnabled' in document,
    isPiPEnabled = document.pictureInPictureEnabled;
if (!isPiPSupported) {
  console.log('The Picture-in-Picture Web API is not available.');
}
else if (!isPiPEnabled) {
  console.log('The Picture-in-Picture Web API is disabled.');
} else {
  console.log("PiP supported");
}

Enable PiP

Consider that we have a video element and a button. When the user clicks the button, we need to enable a floating video.

To enable PiP:

  • We need to call requestPictureInPicture() on the video element. This will return a promise.
  • Once the promise is resolved, the video element will be shrieked into the right corner and we will be able to move it around anywhere.
  • We can check if there is already a PiP video playing by using document.pictureInPictureElement, which has the video element playing in PiP mode.

Implementing PiP

Events in Picture-in-Picture

There are two events regarding the state of the PiP video:

  • enterpictureinpicture: is triggered once the PiP mode is enabled.
  • leavepictureinpicture: is triggered once the PiP mode is exited. This may be due to the video being left in Picture-in-Picture or the user playing another Picture-in-Picture video from a different page.
video.addEventListener('enterpictureinpicture', (event)=> {
    toggleBtn.textContent = "Exit Pip Mode";
});

video.addEventListener('leavepictureinpicture', (event) => {
     toggleBtn.textContent = " Enter PiP Mode";
});

Get the width and height of a Picture-in-Picture player

In the event handler, when the enterpictureinpicture event is fired, we get the pictureInPictureWindow that allows us to find the width and height (we can also bind the resize event to the PIP-Window). With this technique, we can load different quality videos based on the size.

var pipWindow;
video.addEventListener('enterpictureinpicture', function(event) {
  pipWindow = event.pictureInPictureWindow;
  console.log(`> Window size is ${pipWindow.width}x${pipWindow.height}`);
  pipWindow.addEventListener('resize', onPipWindowResize);
});

video.addEventListener('leavepictureinpicture', function(event) {
  pipWindow.removeEventListener('resize', onPipWindowResize);
});

function onPipWindowResize(event) {
  console.log(`> Window size changed to ${pipWindow.width}x${pipWindow.height}`);
  // Change video quality based on Picture-in-Picture window size.
}

Show a user’s webcam in the Picture-in-Picture window

We access the user’s webcam using the getUserMedia method in the mediaDevices property of the navigator object:

const video = document.createElement('video');
video.muted = true;
video.srcObject = await navigator.mediaDevices.getUserMedia({ video: true });
video.play()

video.requestPictureInPicture();

Show user display in the Picture-in-Picture window

We access the user display using the getDisplay method in the mediaDevices property of the navigator object:

const video = document.createElement('video');
video.muted = true;
video.srcObject = await navigator.mediaDevices.getDisplayMedia(video: { mediaSource: "screen"});
video.play();

video.requestPictureInPicture();

Free Resources

Attributions:
  1. undefined by undefined