loading...
Cover image for Implement Picture-in-Picture on the Web

Implement Picture-in-Picture on the Web

ananyaneogi profile image Ananya Neogi ・3 min read

One of my favourite things to do on the web is to implement and test out new and upcoming features. Today we are going to implement Picture-in-Picture.

What is Picture-in-Picture ?

According to W3C Picture-in-Picture Spec-

The specification intends to provide APIs to allow websites to create a floating video window always on top of other windows so that users may continue consuming media while they interact with other content sites, or applications on their device.

While in the PiP(Picture-in-Picture) mode the video is contained in a separate mini window that is always on top of other windows. This window stays visible even when the user agent is not visible.


How to implement Picture-in-Picture ?

HTML -

<video id="videoElement" controls="true" src="demo.mp4"></video>

<!-- button will be used to toggle the PiP mode -->
<button id="togglePipButton">Toggle Picture-in-Picture Mode!</button> 

JavaScript -

1. Call requestPictureInPicture() on click of togglePipButton button element.

requestPictureInPicture() returns a promise.
When the promise resolves, the browser will shrink the video into a mini window that the user can move around and position over other windows.

let video = document.getElementById('videoElement');
let togglePipButton = document.getElementById('togglePipButton');

togglePipButton.addEventListener('click', async function (event) {
    togglePipButton.disabled = true; //disable toggle button while the event occurs
    try {
        // If there is no element in Picture-in-Picture yet, request for it
        if (video !== document.pictureInPictureElement) {
            await video.requestPictureInPicture();
        }
        // If Picture-in-Picture already exists, exit the mode
        else {
            await document.exitPictureInPicture();
        }

    } catch (error) {
        console.log(`Oh Horror! ${error}`);
    } finally {
        togglePipButton.disabled = false; //enable toggle button after the event
    }
});

2. Check for Picture-in-Picture event changes

let video = document.getElementById('videoElement');
video.addEventListener('enterpictureinpicture', function (event) {
    console.log('Entered PiP');
    pipWindow = event.pictureInPictureWindow;
    console.log(`Window size -  \n Width: ${pipWindow.width} \n Height: ${pipWindow.height}`); // get the width and height of PiP window
});

video.addEventListener('leavepictureinpicture', function (event) {
    console.log('Left PiP');
    togglePipButton.disabled = false;
});

We can even update video size based on Picture-in-Picture window size changes by adding a resize event handler. This will be helpful for serving the right quality of video based on the window the user is viewing it on.

3. Always check for feature support

if ('pictureInPictureEnabled' in document) {
    showPipButton();

    // loadedmetadata event occurs when meta data for the specified audio/video has been loaded.Meta data might consists of: duration, dimensions etc.
    video.addEventListener('loadedmetadata', showPipButton);

    // emptied event is fired when the media has become empty, e.g. media has already been loaded or partially loaded.
    video.addEventListener('emptied', showPipButton);
} else {
    console.log('The Picture-in-Picture Web API is not available.');
    togglePipButton.hidden = true;
}

// Enable/disable toggle button depending on whether PiP availability.
function showPipButton() {
    togglePipButton.disabled = (video.readyState === 0) || !document.pictureInPictureEnabled || video.disablePictureInPicture;
}
// video.readyState === 0 means Video metadata have not been loaded yet 
// !document.pictureInPictureEnabled means if Pip is not available
// video.disablePictureInPicture means disablePictureInPicture attribute is present in the video which will result in requestPictureInPicture() rejected promise.

That's it! Your web app is now ready to use Picture-in-Picture!


Bonus! Made a quick demo for this, check it out!

GitHub logo ananyaneogi / picture-in-picture-demo

Upload any video and play it in Picture-in-Picture mode

Picture-in-Picture Demo 🎉

Add any video from your computer and play the video in Picture-in-Picture mode!

Check out the demo now!

Currently the API supports only on the HTMLVideoElement but it states to be extensible in the future.
Check the caniuse stats for browser support. Since this is a progressive enhancement, so regardless of the support, you can use it today on your existing apps! Yay!


References

  1. W3C Picture-in-Picture Spec
  2. Building Modern Web Media Experiences(Chrome Dev Summit 2018)

Posted on by:

Discussion

markdown guide
 

Really nice article Ananya!
I'm glad you enjoyed playing with the Picture-in-Picture Web API ;)

For info, we're currently working on awesome features for the next iteration of this API:

  1. Media Session integration: playback controls in the Picture-in-Picture window such as next track, previous track, etc.)
  2. Auto Picture-in-Picture: gives the browser to ability to automatically enter and exit Picture-in-Picture for a video when it makes sense.

Have a look and let us know what you think!

 

Thanks! 🙂
The Media Session integration definitely seems like a good idea!
For the auto Picture-in-Picture, the use case you provided for video meetings does seem like a good fit for it however I would think that giving the user an option to enable/disable the auto Picture-in-Picture mode would be nice.

 

Rest assured that the Auto Picture-in-Picture mode will be available only to web apps user trust enough. See bugs.chromium.org/p/chromium/issue...

 

What about multiple picture-in-picture? It would be useful. If it's not possible do this in a same page, maybe one pip per tab should help.

 

Oh god, this reminds how much I hope people stop implementing these things and making the awful autoplay videos that then follow me around when I didn't care about them in the first place.

This is why I need more and more browser extensions all the time, to block these things.

"so that users may continue consuming media while they interact with other content sites, or applications on their device" - what about the people who hate websites deciding what I want to do?

 

This is based on user interaction. The user has an option to enable/disable the PiP mode.

 

Nah, typically it's based on the assumption that the user WANTS it, and "giving me an option" to disable it is just not right. If I, as a brand new user, land on your website and start scrolling past some video, and suddenly it pops out and starts following me around and I then have to stop what I was doing to close that thing, that's not ok.

These things additionally often have awful bugs where e.g. the autoplay on the video might be disabled otherwise (as it ALWAYS should be unless specifically on Youtube or other purely video content website), but then when the video pops out and starts following me around it suddenly starts playing by itself and then I first close it, and then I have to find where it vanished so I can try to figure out how that custom video player (please guys, stop doing that) can be paused. Worst case scenario I have to open developer tools and just delete the DOM nodes to make that thing shut up.

It's like spamming me with popups asking me if I want to sign up for your newsletter, or if I want desktop notifications from your random site? The answer is always no, and developers thinking they are doing good because they're giving me an option to say no is enough, is what pisses me off and why I need so many browser extensions.

The feature is not the problem, it is indeed good that we have these kind of advancements as a platform.
Problem are those who abuse the platform, like Facebook or YouTube.
Want to make an actual difference? I see two ways (each impacting the world differently, though):
1) Boycott abusers. Don't use their apps. Don't give them your money. Call your data back to you, demand them erase your data from their servers (in some countries they must abide by), and go to their competitors.
2) Grow better in your area and, instead of ranting on people online who only wanted to help, seek to have voice in the Working Groups, Consortiums and Committees.

You are simply wrong - the feature is the problem.

If I browse the internet randomly I regularly bump into sites abusing various things you would consider "advancements", things like notifications and picture-in-picture.

The reason they are able to abuse these features? Because the features have been designed wrong.

Yes, we should have picture-in-picture, but only if I want it, not when the website developer wants it. We should have notifications, but only when I expressly ask for it, not so every website out there can spam you with "bs-news.com would want to send you notifications? Allow / Deny" dialogs.

Your non-solutions are not amusing.

You are simply wrong - the feature is the problem.

If I browse the internet randomly I regularly bump into sites abusing various things you would consider "advancements", things like notifications and picture-in-picture.

The reason they are able to abuse these features? Because the features have been designed wrong.

Yes, we should have picture-in-picture, but only if I want it, not when the website developer wants it. We should have notifications, but only when I expressly ask for it, not so every website out there can spam you with "blahsite would want to send you notifications? Allow / Deny" dialogs.

Your non-solutions are not amusing.

 

Case in point #facebook pip. It was an awful experience when the pip feature just decided to have a life of its own like a rogue AI. It annoyed me greatly while experiencing it.

Choice is all that matters for the end users.

 

Awesome, i learned something today. I totally wasn't aware of this feature.

 

Hey!

I have implemented PIP myself through HTML, but the problem is i need to get the events for closing picture in picture and maximize window separately.
Right now, the event i'm getting is 'leavepictureinpicture'.

If anyone has any thoughts in this one, it would be really helpful.

Thanks

 

Amazing :) Thanks. Before I heard this, I use our polyfill solution :)

 

Out of curiosity, which polyfill was it?

 

Our polyfill similar to this repository github.com/gbentaieb/pip-polyfill/

I know all features won't work if the browser doesn't support.

 

I love reading about new features coming to the web!

 
 

Very cool Ananya, the demo worked perfectly for me. It'll be interesting to see how this gets adopted across different sites. Any use cases you're interested in seeing first?

 

Thanks! 🙂
I spend a lot of time watching conference talks and video shorts on Vimeo so I would love this feature over there. YouTube has implemented a miniplayer feature recently but it only seems useful while you're on YouTube, if PiP gets implemented, we would be able to watch YouTube videos while doing other work too!

 

In the mean time, you can install Picture-in-Picture extension and use the Alt+P keyboard shortcut on YouTube to toggle Picture-in-Picture seamlessly. That's what I do on a daily basis and I love it ;)

Ah! Didn't know about this! Thanks for sharing 🙂