requestVideoFrameCallback 是实现低延迟视频特效的关键调度机制,它将JS处理时机精准锚定在视频帧即将上屏的瞬间,避免传统方案1–2帧滞后。

不能直接用它“实现特效”,但它是实现低延迟视频特效的关键调度机制——它把 JS 处理时机精准锚定在视频帧即将上屏的瞬间,绕开了传统 drawImage + requestAnimationFrame 方案中常见的 1–2 帧滞后。
必须配合像素处理链使用
requestVideoFrameCallback 本身只通知“这一帧解码好了、马上要合成”,不提供像素数据。真正做滤镜、美颜、AR 跟踪,得靠后续环节:
- 用 VideoFrame.copyTo() 提取 RGBA 数据(需指定 format: 'rgba'),适合轻量 CPU 后处理(如灰度、简单卷积)
- 用 WebGL texImage2D(videoElement) 直接绑定 video 元素为纹理,把滤镜写进 fragment shader——这是性能最优路径,全程 GPU 加速,零 CPU 拷贝
- 若需 YUV 原始数据(如硬件加速的色度重采样),可用 copyTo 输出 yuv420 格式,但后续转换必须在 GPU 完成,否则主线程立刻卡死
高频下不掉帧的三个硬约束
60fps 动画里每帧只有约 16ms,回调内操作稍慢就会积压:
- 绝不新建对象:复用 ImageData 实例、预分配 OffscreenCanvas、缓存 WebGL 纹理和着色器程序
- 尺寸严格匹配:用 frame.displayWidth / displayHeight 而非 video.videoWidth,避免 letterboxing 或缩放导致的拉伸失真
- 必须手动续订 + 清理:每次回调末尾调用 video.requestVideoFrameCallback() 续订;组件卸载或 src 切换时调用 cancelVideoFrameCallback(),否则回调仍会执行并访问已销毁资源
浏览器与播放状态强相关
这个 API 不是“开箱即用”,触发条件很具体:
- 仅 Chrome 114+、Edge 114+、Firefox 125+ 支持;Safari 当前无计划支持
- video 必须已用户手势触发播放(如点击),且启用 playsinline(移动端免全屏)
- 静音 autoplay 失败时,回调永不触发;需监听 oncanplay 或 readyState === HAVE_CURRENT_DATA 再注册
- 回调中务必检查 metadata.mediaTime 是否更新,防止拿到重复帧或陈旧帧
比 requestAnimationFrame 准在哪
关键不是“更快”,而是“更准”:
- rAF 时间戳来自渲染管线,受 JS 阻塞、样式计算、布局等干扰,实际回调常滞后视频帧 2–4 帧
- RVFC 的 mediaTimestamp 来自硬件合成器,误差通常
- 有效回调频率 = min(视频帧率, 浏览器刷新率),比如 25fps 视频在 60Hz 屏幕上稳定 25Hz,不会出现“抽帧”或“插帧”抖动

















