Search code examples
javascriptgoogle-chromepicture-in-picture

A way to make a real time picture in picture


There is something that is bothering me, and I am here yelling for help :

I want to make a project in which there is a video that if I activate the picture in picture form, it plays on both the main page and picture in picture page.


Solution

  • There is no other way than duplicating that video element...

    You can make the synchronization a bit better by feeding the clone with a MediaStream generated from the original video, and using that clone as the source for the PiP window.

    if( 1 && "pictureInPictureElement" in document ) {
    
    const button = document.getElementById( "btn" );
    const in_doc = document.getElementById( "in_doc" );
    const clone = document.getElementById( "clone" );
    
    in_doc.onloadedmetadata = (evt) => {
      const stream = in_doc.captureStream();
      // we stop the audio coming in the clone
      // otherwise wed have two audio feeds in the output
      // with few µs of delay, creating an horrible echo effect
      stream.getAudioTracks().forEach( track => track.stop() );
      // feed the clone with a MediaStream generated from in-doc video
      // they'll thus display the same images
      clone.srcObject = stream;
    };
    
    // our own UI
    button.onclick = (evt) => {
      if( document.pictureInPictureElement === clone ) {
        clone.pause();
        document.exitPictureInPicture()
      }
      else {
        clone.play();
        clone.requestPictureInPicture();
      }
    };
    
    // handle the default UI
    in_doc.addEventListener( 'enterpictureinpicture', (evt) => {
      if( document.pictureInPictureElement === clone ) {
        // already active
        return;
      }
      else {
        // there can be only only one PiP window at a time
        clone.play();
        clone.requestPictureInPicture();
      }
    } );
    
    }
    else {
      console.error( "Your browser doesn't support the PiP API." );
      console.error( "This demo won't work for you." );
    }
    #clone {
      visibility: hidden;
      position: absolute;
      pointer-events: none;
    }
    video {
      height: 100vh;
      vertical-align: top;
    }
    <button id="btn" >toggle PiP</button>
    <video id="in_doc" controls src="https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm" crossorigin ></video>
    <!-- The following will be hidden and only used to generate the PiP -->
    <video id="clone" autoplay ></video>

    Also beware, while currently Chrome's UI doesn't set any controls on the PiP window, they may add some in the future, and other implementations could (e.g Firefox own PiP, which is not the API one, has a play/pause button). So to be future proof, you will probably want to link all the media events triggered by users (play, pause, seek etc.) from the clone to the visible video.