HTMLVideoElement: requestVideoFrameCallback() 方法
requestVideoFrameCallback()
方法是 HTMLVideoElement
接口的方法,它注册一个回调函数,该函数在向合成器发送新视频帧时运行。这使开发者能够对每个视频帧执行高效的操作。
描述
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。如果 expectedDisplayTime
在 now
的大约五到十微秒内,则该帧已渲染。如果 expectedDisplayTime
大约在十六毫秒后(假设你的浏览器/屏幕以 60Hz 刷新),则回调函数延迟了一个 v-sync。
语法
requestVideoFrameCallback(callback)
参数
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 时间戳的数字。
注意:在某些情况下,width
和 height
可能与 HTMLVideoElement.videoWidth
和 HTMLVideoElement.videoHeight
不同(例如,变形视频可能具有矩形像素)。
返回值
一个表示唯一回调函数 ID 的数字。
这可以传递给 HTMLVideoElement.cancelVideoFrameCallback()
来取消回调函数注册。
示例
在画布上绘制视频帧
此示例展示了如何使用 requestVideoFrameCallback()
以与视频完全相同的帧速率将视频帧绘制到 <canvas>
元素上。它还会将帧元数据记录到 DOM 中,以供调试使用。
if ("requestVideoFrameCallback" in HTMLVideoElement.prototype) {
let paintCount = 0;
let startTime = 0.0;
const updateCanvas = (now, metadata) => {
if (startTime === 0.0) {
startTime = now;
}
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const elapsed = (now - startTime) / 1000.0;
const fps = (++paintCount / elapsed).toFixed(3);
fpsInfo.innerText = `video fps: ${fps}`;
metadataInfo.innerText = JSON.stringify(metadata, null, 2);
// Re-register the callback to run on the next frame
video.requestVideoFrameCallback(updateCanvas);
};
// Initial registration of the callback to run on the first frame
video.requestVideoFrameCallback(updateCanvas);
} else {
alert("Your browser does not support requestVideoFrameCallback().");
}
有关上述代码的工作实现,请参阅 requestVideoFrameCallback 演示。
规范
规范 |
---|
HTMLVideoElement.requestVideoFrameCallback() # dom-htmlvideoelement-requestvideoframecallback |
浏览器兼容性
BCD 表格仅在启用 JavaScript 的浏览器中加载。
另请参阅
- The
<video>
element HTMLVideoElement.cancelVideoFrameCallback()
- 使用
requestVideoFrameCallback()
在视频上执行高效的逐帧操作 在 developer.chrome.com (2023)