用 JavaScript 构建悬浮窗视频播放器(画中画效果)
构建画中画(Picture-in-Picture)效果的悬浮窗视频播放器

主要内容

  • 什么是画中画;
  • 查看是否支持画中画效果;
  • 实现画中画视频效果;
  • 画中画事件;
  • 获取画中画播放器的宽度和高度;
  • 小型项目。

画中画

Picture-in-Picture (PiP) 可以让用户通过悬浮窗口(始终在其他窗口顶部)观看视频,便于用户在浏览其他网站或使用其他应用时继续观看视频。

也就是说,即使用户切换了正在播放视频的标签,仍然能看到视频元素,并且可以在屏幕上随意拖动该视频元素。


查看是否支持画中画

使用 document.pictureInPictureEnabled 布尔值确定是否已启用 PiP

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");
}

实现画中画视频效果

我们有视频元素和一个按键,用户单击按键,就可以启用悬浮窗视频效果。

<video id="videoElement" controls="true" src="video_url"> </video>
<button id="PiP"> Enable Floating Video </button>

启用 PiP 需要在视频元素上调用 requestPictureInPicture(),该方法会返回一个 promise

解析 promise 后,视频元素会移动到右下角,我们可以将视频元素拖动至任何位置。

另外,我们可以使用 document.pictureInPictureElement 查看是否已有 PiP 视频正在播放,document.pictureInPictureElement 中包含处于 PiP 模式的 video 元素。

<html>
  <head>
   
  </head>
  <body>
    
    <button id="PiP"> Enable Floating Video </button>
    <script>
        let video = document.getElementById('videoElement');
        let toggleBtn = document.getElementById('PiP');
       toggleBtn.addEventListener('click', togglePiPMode);
        async function togglePiPMode(event) {
            toggleBtn.disabled = true; //disable btn ,so that no multiple request are made
            try {
                if (video !== document.pictureInPictureElement) {
                    await video.requestPictureInPicture();
                    toggleBtn.textContent = "Exit Pip Mode";
                }
                // If already playing exit mide
                else {
                    await document.exitPictureInPicture();
                    toggleBtn.textContent = "Enable Pip Mode";
                }
            } catch (error) {
                console.log(error);
            } finally {
                toggleBtn.disabled = false; //enable toggle at last
            }
        }
      
    </script>
  </body>
</html>

粘贴上述代码可以创建一个基础版 PiP 视频播放器。

画中画事件

PiP 视频状态有下列两个事件:

  1. enterpictureinpicture → 启用 PiP 模式后触发。
  2. leavepictureinpicture 退出 PiP 模式时触发,退出原因可能是:
  • 视频离开了画中画;
  • 用户在其他页面播放了画中画视频。
video.addEventListener('enterpictureinpicture', (event)=> {
    toggleBtn.textContent = "Exit Pip Mode";
});

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

获取画中画播放器的宽度和高度

用户进入 PiP 模式后,我们就可以得到 PiP 播放器的宽度和高度。

宽度和高度存储在 enterpictureinpicture 事件对象的 pictureInPictureWindow 特性中。

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.
}

两个小项目

下面我们用 PiP 做两个有趣的小项目:

1. 在画中画窗口中显示用户的网络摄像头

我们将使用 navigator 对象的 mediaDevices 特性中的 getUserMedia 方法访问用户的网络摄像头。

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

video.requestPictureInPicture();

2. 在画中画窗口中显示用户的显示屏

我们将使用 navigator 对象的 mediaDevices 特性中的 getDisplay 方法访问用户的显示屏。

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

video.requestPictureInPicture();

感谢大家的阅读,欢迎在文章下方评论!

请参阅:https://googlechrome.github.io/samples/picture-in-picture/



原文作者:Javascript Jeep​
原文链接:https://medium.com/javascript-in-plain-english/implementing-floating-video-player-picture-in-picture-in-javascript-f4b7c540723b
推荐阅读
相关专栏
音视频杂谈
158 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和声网 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。