不能直接替代,但能显著降低延迟——requestVideoFrameCallback提供解码帧原始像素数据,绕过drawImage同步拷贝开销,适合美颜、AR等逐帧处理场景,需Chrome114+/Firefox125+支持,且必须配合video元素使用。
不能直接替代,但能显著降低延迟——requestVideoFrameCallback 提供的是视频解码帧的原始像素数据(通过 VideoFrame 对象),绕过了 canvas 的 drawImage 同步拷贝和合成开销。它适合对帧率敏感、需逐帧处理(如美颜、AR 特征点跟踪)的场景,但不适用于简单 CSS 滤镜或纯 GPU 渲染的静态效果。
关键区别在于时机:requestVideoFrameCallback 在浏览器即将提交该帧到屏幕前触发,而 drawImage + requestAnimationFrame 通常滞后 1–2 帧,尤其在 60fps 动画中容易积压。
video.requestVideoFrameCallback 使用,不能用在 canvas 或 img 上VideoFrame 默认是 YUV 格式(format: "yuv420"),不能直接传给 putImageData
playsinline 或未用户手势触发播放,回调可能永不触发YUV 到 RGBA 的转换必须在 GPU 完成,否则 CPU 解码 + JS 转换会卡死主线程。最轻量方案是用 WebGL 2 的 copyTextureToBuffer + 自定义着色器,但更通用的做法是利用 VideoFrame.copyTo 输出为 RGBA 格式(需显式指定):
video.requestVideoFrameCallback((frame) => { const rgbaBuffer = new OffscreenCanvas(1, 1).getContext('2d').createImageData(frame.displayWidth, frame.displayHeight); // 注意:copyTo 会自动做色彩空间转换,但要求目标 canvas 尺寸匹配 frame.copyTo(rgbaBuffer.data, { format: 'rgba' });<p>// 此时 rgbaBuffer.data 是 Uint8ClampedArray,可传给 WebGL texturegl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, frame.displayWidth, frame.displayHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, rgbaBuffer.data);</p><p>frame.close(); // 必须调用,否则内存泄漏});
frame.copyTo 的 format: 'rgba' 会触发内部 YUV→RGB 转换,性能尚可(硬件加速),但比原生 YUV 纹理多一次拷贝frame.displayWidth/frame.displayHeight,它们可能与 video.videoWidth 不同(受缩放、letterboxing 影响)gl.NEAREST 和禁用 mipmapOffscreenCanvas 的 ImageData,每次应新建或重置 data 视图高频回调下,卡顿几乎都源于隐式内存分配或同步阻塞。最典型的是:
Uint8ClampedArray 或 ImageData —— 每秒 60 次 GC 压力极大;应预分配并复用缓冲区frame.close() —— VideoFrame 持有底层解码帧引用,不释放会导致视频解码器停顿video.setAttribute('playsinline', '') 且页面在 iOS Safari 中运行 —— 回调完全不触发一个最小可行复用模式:
let cachedBuffer = null;video.requestVideoFrameCallback(function processFrame(frame) { if (!cachedBuffer || cachedBuffer.length !== frame.displayWidth * frame.displayHeight * 4) { cachedBuffer = new Uint8ClampedArray(frame.displayWidth * frame.displayHeight * 4); } frame.copyTo(cachedBuffer, { format: 'rgba' }); // → 直接传给 WebGL 或 WASM 滤镜函数 frame.close(); video.requestVideoFrameCallback(processFrame); // 主动续订});
如果你需要精确控制解码参数(如跳过 B 帧、指定分辨率)、做编码回传,或处理非播放态视频(如分析本地文件),requestVideoFrameCallback 不够用,得上 WebCodecs。但它更重、兼容性更差(仅 Chromium 系),且无法对接 <video> 元素的播放状态。
requestVideoFrameCallback 是「播放时截帧」,零配置,依赖 video 元素生命周期WebCodecs 是「手动解码流」,可暂停/seek/丢帧,但需自己管理 VideoDecoder 和 EncodedVideoChunk
decoder.decode(),<video> 就不再输出帧,requestVideoFrameCallback 会静默失效requestVideoFrameCallback 的帧率稳定性优于 WebCodecs(后者易因解码压力丢帧)真正在意首帧延迟和持续帧率的滤镜应用,优先跑通 requestVideoFrameCallback + WebGL pipeline,别过早切 WebCodecs。