使用子母畫面觀看影片

François Beaufort
François Beaufort

子母畫面 (PiP) 可讓使用者在浮動視窗中觀看影片 (一律顯示在其他視窗上方),方便他們留意 在其他網站或應用程式互動時觀看

有了 Picture-in-Picture Web API,即可啟動及控制 網站中影片元素的子母畫面。前往我們的 官方的子母畫面範例

背景

2016 年 9 月起,Safari 透過 WebKit API 新增子母畫面支援功能 。六個月後,Chrome 就會自動播放 在 Android O 版本中,使用 原生 Android API。六個月後,我們宣布將 標準化 Web API (與 Safari 相容的功能),讓 能夠建立及控管子母畫面功能的完整體驗, 我們到了!

進入程式碼

進入子母畫面模式

讓我們先從影片元素著手,以及使用者與影片互動的方式 例如按鈕元素

<video id="videoElement" src="https://example.com/file.mp4"></video>
<button id="pipButtonElement"></button>

只有在回應使用者手勢時,才要求子母畫面。 videoElement.play() 傳回的 promise。因為保證不會 會傳播使用者手勢。請改為呼叫 requestPictureInPicture(), 按一下 pipButtonElement 上的處理常式,如下所示。您的責任 來處理使用者按下兩次的情形。

pipButtonElement.addEventListener('click', async function () {
  pipButtonElement.disabled = true;

  await videoElement.requestPictureInPicture();

  pipButtonElement.disabled = false;
});

問題解決後,Chrome 就會將影片縮小成一個小視窗, 使用者即可四處移動及放置其他視窗上方

大功告成!做得好!您值得我們繼續閱讀 度假。不幸的是,情況並不一定。但 可能拒絕 可能原因如下:

  • 系統不支援子母畫面。
  • 由於限制限制,文件無法使用子母畫面 權限政策
  • 尚未載入影片中繼資料 (videoElement.readyState === 0)。
  • 影片檔案只能播放音訊。
  • 新的 disablePictureInPicture 屬性會顯示在影片元素上。
  • 並非透過使用者手勢事件處理常式 (例如按鈕點擊) 發出該呼叫。 從 Chrome 74 版開始,僅適用於 子母畫面。

下方的「功能支援」一節將說明如何根據 這些限制。

讓我們新增 try...catch 區塊來擷取這些潛在錯誤,並讓 讓使用者知道自己接下來會發生什麼事

pipButtonElement.addEventListener('click', async function () {
  pipButtonElement.disabled = true;

  try {
    await videoElement.requestPictureInPicture();
  } catch (error) {
    // TODO: Show error message to user.
  } finally {
    pipButtonElement.disabled = false;
  }
});

無論影片元素為子母畫面或 不行: 會觸發事件並呼叫方法。反映了 子母畫面視窗 (例如播放、暫停、跳轉等),而且也可以 在 JavaScript 中以程式輔助方式變更狀態

離開子母畫面

現在讓我們讓按鈕切換鈕進入及退出子母畫面模式。三 就必須先檢查唯讀物件 document.pictureInPictureElement 做為影片元素如果不是,我們會傳送輸入申請書 。否則,我們會請致電給對方 document.exitPictureInPicture(),這代表影片會重新出現在 原始分頁請注意,這個方法也會傳回承諾。

    ...
    try {
      if (videoElement !== document.pictureInPictureElement) {
        await videoElement.requestPictureInPicture();
      } else {
        await document.exitPictureInPicture();
      }
    }
    ...
敬上

監聽子母畫面活動

作業系統通常會將子母畫面限制在一個視窗中,因此 Chrome 的實作模式會遵循這個模式。也就是說,使用者只能在 一次只播放一個子母畫面影片。您應預期使用者會離開 即使您並未提出要求,也能使用子母畫面功能。

新的 enterpictureinpictureleavepictureinpicture 事件處理常式可讓您 為使用者打造個人化體驗例如瀏覽 影片目錄和聊天室訊息。

videoElement.addEventListener('enterpictureinpicture', function (event) {
  // Video entered Picture-in-Picture.
});

videoElement.addEventListener('leavepictureinpicture', function (event) {
  // Video left Picture-in-Picture.
  // User may have played a Picture-in-Picture video from a different page.
});

自訂子母畫面視窗

Chrome 74 支援的 您可以使用 Media Session API 來控制子母畫面視窗。

子母畫面視窗中的媒體播放控制項
圖 1. 子母畫面視窗中的媒體播放控制項
,瞭解如何調查及移除這項存取權。

根據預設,子母畫面一律會顯示「播放/暫停」按鈕。 視窗,除非影片正在播放 MediaStream 物件 (例如 getUserMedia()getDisplayMedia()canvas.captureStream()),或是影片有 MediaSource 時間長度設為 +Infinity (例如即時動態饋給)。如果畫面中確實顯示播放/暫停按鈕 是否一律會顯示,請為「播放」兩個選項設定一些媒體工作階段動作處理常式和 「Pause」(暫停)媒體事件,如下所示。

// Show a play/pause button in the Picture-in-Picture window
navigator.mediaSession.setActionHandler('play', function () {
  // User clicked "Play" button.
});
navigator.mediaSession.setActionHandler('pause', function () {
  // User clicked "Pause" button.
});

顯示「上一首」和「下一首」視窗控制項也是一樣的設定 這些應用程式的媒體工作階段動作處理常式會在子母畫面中顯示 你就能處理這些動作

navigator.mediaSession.setActionHandler('previoustrack', function () {
  // User clicked "Previous Track" button.
});

navigator.mediaSession.setActionHandler('nexttrack', function () {
  // User clicked "Next Track" button.
});

如要瞭解實際運作方式,請參閱官方的媒體工作階段範例

設定子母畫面視窗大小

針對影片進入及離開畫面時調整畫質 您必須確定子母畫面視窗的大小, 通知使用者手動調整視窗大小。

以下範例說明如何取得 建立或調整子母畫面視窗。

let pipWindow;

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

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

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

我建議不要直接在大小調整事件中跟隨大小變更事件,因為每次稍做變更 調整子母畫面視窗大小會觸發獨立的事件,並可能導致 如果每次調整大小時執行消耗大量資源的作業,會導致效能問題。於 換句話說,調整大小作業會不斷重複觸發事件 可迅速獲取資源建議您採用常見的技術,像是 以處理此問題

功能支援

系統可能不支援子母畫面 Web API,因此你必須偵測 提供漸進式增強功能即使瀏覽器支援 使用者關閉或權限政策停用。幸好,您可以使用 新的布林值 document.pictureInPictureEnabled 來判斷這一點。

if (!('pictureInPictureEnabled' in document)) {
  console.log('The Picture-in-Picture Web API is not available.');
} else if (!document.pictureInPictureEnabled) {
  console.log('The Picture-in-Picture Web API is disabled.');
}

套用到影片的特定按鈕元素時 處理子母畫面按鈕的顯示設定。

if ('pictureInPictureEnabled' in document) {
  // Set button ability depending on whether Picture-in-Picture can be used.
  setPipButton();
  videoElement.addEventListener('loadedmetadata', setPipButton);
  videoElement.addEventListener('emptied', setPipButton);
} else {
  // Hide button if Picture-in-Picture is not supported.
  pipButtonElement.hidden = true;
}

function setPipButton() {
  pipButtonElement.disabled =
    videoElement.readyState === 0 ||
    !document.pictureInPictureEnabled ||
    videoElement.disablePictureInPicture;
}

MediaStream 影片支援

播放 MediaStream 物件的影片 (例如 getUserMedia()getDisplayMedia()canvas.captureStream()) 也在 Chrome 71 中支援子母畫面。這個 代表您可以顯示有使用者網路攝影機的子母畫面視窗 影片串流、多媒體影片串流 甚至畫布元素請注意, 影片元素不一定要附加至 DOM 才能進入 子母畫面,如下所示。

在子母畫面視窗中顯示使用者的網路攝影機

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

// Later on, video.requestPictureInPicture();

在子母畫面視窗中顯示螢幕

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

// Later on, video.requestPictureInPicture();

在子母畫面視窗中顯示畫布元素

const canvas = document.createElement('canvas');
// Draw something to canvas.
canvas.getContext('2d').fillRect(0, 0, canvas.width, canvas.height);

const video = document.createElement('video');
video.muted = true;
video.srcObject = canvas.captureStream();
video.play();

// Later on, video.requestPictureInPicture();

結合 canvas.captureStream()Media Session API 即可 執行個體是在 Chrome 74 中建立音訊播放清單視窗。歡迎造訪官方網站 音訊播放清單範例

子母畫面視窗中的音訊播放清單
圖 2. 子母畫面視窗中的音訊播放清單
,瞭解如何調查及移除這項存取權。

範例、示範和程式碼研究室

歡迎查看官方的子母畫面範例,體驗子母畫面功能 網頁 API。

我們將帶你體驗示範和程式碼研究室。

後續步驟

首先,請參閱導入狀態頁面,瞭解 API 目前已在 Chrome 和其他瀏覽器中實作。

以下是不久後可能會出現的異動:

瀏覽器支援

Chrome、Edge、Opera 和 Safari 皆支援子母畫面 Web API。 詳情請參閱 MDN

資源

感謝 Mounir Lamouri 和 Jennifer Apacible 的傑出表現 子母畫面和本文說明。感謝各位的貢獻 進行標準化作業