HTMLVideoElement: requestVideoFrameCallback() 方法

Baseline 2024
新推出

自 2024 年 10 月以來,此功能已可在最新的裝置和瀏覽器版本上使用。此功能可能不適用於舊裝置或瀏覽器。

HTMLVideoElement 介面的 requestVideoFrameCallback() 方法會註冊一個回撥函式,該函式會在新的影片幀傳送到合成器時執行。這使得開發者能夠對每個影片幀執行高效的操作。

語法

js
requestVideoFrameCallback(callback)

引數

回撥

當新的影片幀傳送到合成器時執行的回撥函式。它包含兩個引數

now

一個 DOMHighResTimeStamp,表示回撥函式被呼叫的時間。

metadata(元資料)

包含以下屬性的物件:

expectedDisplayTime

一個 DOMHighResTimeStamp,表示瀏覽器期望該幀可見的時間。

height

一個數字,以媒體畫素為單位,表示影片幀的高度(可見解碼畫素,不考慮寬高比調整)。

mediaTime

一個數字,以秒為單位,表示已呈現幀的媒體呈現時間戳。這等於 HTMLMediaElement.currentTime 時間線上的幀時間戳。

presentationTime

一個 DOMHighResTimeStamp,表示瀏覽器提交該幀進行合成的時間。

presentedFrames

一個數字,表示到目前為止與當前回撥一起提交進行合成的幀數。這可用於檢測回撥例項之間是否錯過了幀。

processingDuration

一個數字,以秒為單位,表示具有與該幀相同的呈現時間戳的編碼資料包提交到解碼器(即 mediaTime)與解碼後的幀準備好呈現之間的時間。

width

一個數字,以媒體畫素為單位,表示影片幀的寬度(可見解碼畫素,不考慮寬高比調整)。

WebRTC 應用程式中使用的 requestVideoFrameCallback() 回撥中可能還會提供其他元資料屬性。

captureTime

一個 DOMHighResTimeStamp,表示捕獲幀的時間。這適用於來自本地或遠端源的影片幀。對於遠端源,捕獲時間是使用時鐘同步和 RTCP 傳送方報告估算的,以將 RTP 時間戳轉換為捕獲時間。

receiveTime

一個 DOMHighResTimeStamp,表示編碼幀被平臺接收的時間。這適用於來自遠端源的影片幀。具體來說,這對應於屬於該幀的最後一個數據包透過網路接收的時間。

rtpTimestamp

一個數字,表示與該影片幀關聯的 RTP 時間戳。

注意:在某些情況下,widthheight 可能與 HTMLVideoElement.videoWidthHTMLVideoElement.videoHeight 不同(例如,變形影片可能具有矩形畫素)。

返回值

一個數字,表示一個唯一的回撥 ID。

這可以傳遞給 HTMLVideoElement.cancelVideoFrameCallback() 來取消回撥註冊。

描述

requestVideoFrameCallback() 的典型用例包括影片處理和繪製到畫布、影片分析以及與外部音訊源同步。過去,透過在 timeupdate 事件觸發時在當前影片顯示上執行操作來執行每幀處理,這種方式效率低下且不準確。這種技術無法訪問實際的影片幀。

requestVideoFrameCallback() 的用法與 Window.requestAnimationFrame() 類似。您使用它來執行一個回撥函式,該函式在下一個影片幀傳送到合成器時執行某些操作。回撥透過再次呼叫 requestVideoFrameCallback() 來完成,以便在下一個影片幀合成時執行回撥,以此類推。然而,requestVideoFrameCallback() 在幾個方面針對影片操作進行了最佳化:

  • requestVideoFrameCallback() 提供了對每個獨立影片幀的可靠訪問。
  • requestAnimationFrame() 嘗試匹配顯示重新整理率,通常為 60Hz。另一方面,requestVideoFrameCallback() 嘗試匹配影片幀率。更具體地說,回撥的執行速率將是影片幀率和瀏覽器繪製重新整理率中的較低者。例如,在以 60Hz 繪製的瀏覽器中播放的幀率為 25fps 的影片,其回撥速率為 25Hz。在同一 60Hz 瀏覽器中執行的幀率為 120fps 的影片,其回撥速率為 60Hz。
  • requestVideoFrameCallback() 在回撥函式中提供了有用的影片元資料。

需要注意的一點是,requestVideoFrameCallback() 不提供任何嚴格的保證,確保您的回撥輸出將與影片幀率保持同步。它可能比新影片幀呈現時晚一個垂直同步(v-sync)才被觸發。(V-sync 是一種圖形技術,用於將影片的幀率與顯示器的重新整理率同步)。

該 API 在主執行緒上執行,而影片合成很可能發生在單獨的合成執行緒上。您必須考慮這些操作完成所需的時間,以及影片本身以及您的 requestVideoFrameCallback() 操作結果顯示在螢幕上所需的時間。

您可以比較 now 回撥引數和 expectedDisplayTime 元資料屬性來確定您的回撥是否是 v-sync 延遲。如果 expectedDisplayTimenow 的差值在十微秒左右,則該幀已渲染。如果 expectedDisplayTime 大約在十六毫秒之後(假設您的瀏覽器/螢幕以 60Hz 重新整理),那麼回撥就是 v-sync 錯過。

示例

在畫布上繪製影片幀

此示例展示瞭如何使用 requestVideoFrameCallback() 以與影片完全相同的幀率將影片幀繪製到 <canvas> 元素上。它還記錄幀元資料到螢幕上以便於除錯。

js
const button = document.querySelector("button");
const video = document.querySelector("video");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const fpsInfo = document.querySelector("#fps-info");
const metadataInfo = document.querySelector("#metadata-info");

button.addEventListener("click", () =>
  video.paused ? video.play() : video.pause(),
);

video.addEventListener("play", () => {
  if (!("requestVideoFrameCallback" in HTMLVideoElement.prototype)) {
    console.error(
      "Your browser does not support the `Video.requestVideoFrameCallback()` API.",
    );
  }
});

let width = canvas.width;
let height = canvas.height;

let paintCount = 0;
let startTime = 0.0;

const updateCanvas = (now, metadata) => {
  if (startTime === 0.0) {
    startTime = now;
  }

  ctx.drawImage(video, 0, 0, width, height);

  const elapsed = (now - startTime) / 1000.0;
  const fps = (++paintCount / elapsed).toFixed(3);
  fpsInfo.innerText = !isFinite(fps) ? 0 : fps;
  metadataInfo.innerText = JSON.stringify(metadata, null, 2);

  video.requestVideoFrameCallback(updateCanvas);
};

video.src = "https://mdn.github.io/shared-assets/videos/flower.mp4";
video.requestVideoFrameCallback(updateCanvas);
css
video,
canvas {
  max-width: 49%;
}
html
<p>
  Start <button type="button">⏯</button> playing the video. Pause the video to
  read the metadata. Drawing video frames on the canvas is synced with the
  actual video framerate.
</p>
<video controls playsinline></video>
<canvas width="960" height="540"></canvas>
<p><span id="fps-info">0</span>fps</p>
<pre id="metadata-info"></pre>

規範

規範
HTMLVideoElement.requestVideoFrameCallback()
# dom-htmlvideoelement-requestvideoframecallback

瀏覽器相容性

另見