requestvideoframecallback 是 web 平台专为低延迟、高帧率视频处理设计的底层 api,直接绑定视频帧解码完成时刻,需配合 offscreencanvas+webgl 零拷贝渲染与智能调度策略落地。

✅ 确保视频源支持 rVFC(基础前提)
不是所有视频元素都可用:rVFC 目前仅在 Chrome 94+ 和 Edge 94+ 中稳定支持,且要求视频满足以下条件:
- 使用 HTMLVideoElement(canvas.captureStream() 不支持)
- 视频已加载元数据(loadedmetadata 事件后)且处于播放中(或至少调用过 play())
- 若来自 MediaStream(如摄像头),需确保 track 已激活、无静音/暂停,且 videoElement.srcObject 已正确赋值
✅ 使用 OffscreenCanvas + WebGL 实现零拷贝滤镜渲染
高频下反复调用 canvas.getContext('2d').drawImage(video) 会触发像素上传(CPU → GPU)、格式转换、同步等待,极易掉帧。正确路径是:
- 创建 OffscreenCanvas(脱离主线程,可绑定 WebGL)
- 用 WebGL 绑定视频纹理(texImage2D 传入 video 元素),避免读回 CPU 内存
- 编写 GLSL 滤镜着色器(如 vignette、sepia、sharpen),每帧仅执行一次绘制
- 将 WebGL 渲染结果通过 commit() 提交到关联的 visible canvas(或继续用于后续合成)
示例关键片段:
// 假设已初始化 WebGL 上下文和 program
function onVideoFrame(now, metadata) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, videoTexture);
// ⚠️ 关键:不调用 readPixels,直接用 video 元素作为纹理源
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, videoElement);
gl.useProgram(program);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); // 全屏四边形
offscreenCanvas.commit(); // 提交到可视 canvas
videoElement.requestVideoFrameCallback(onVideoFrame); // 持续注册
}
✅ 控制调度节奏:按需启用 / 节流 / 错帧处理
rVFC 默认每帧都触发,但滤镜计算可能耗时。不能让 JS 执行阻塞下一帧解码。建议:
- 在回调内用 performance.now() 记录开始时间,若上一帧处理超 8ms(≈120fps 容忍上限),跳过本次滤镜更新,只做纹理绑定+提交(保持画面流畅)
- 对复杂滤镜(如光流、AI 推理),改用 WebWorker + Transferable 图像数据,主回调只负责调度和合成
- 监听 metadata.presentedFrames 和 metadata.mediaTime 判断是否丢帧;若连续两次 presentedFrames 差值 > 2,说明解码压力大,可临时降级滤镜精度










