requestVideoFrameCallback 是 Web API 中用于视频帧精准捕获的低延迟接口,需视频已播放且可渲染,支持 Chrome 111+、Edge 111+、Firefox 125+;推荐结合 OffscreenCanvas 异步提取帧、智能筛选上传、前后端协同协议实现高效云端比对。

关键前提:确保视频源支持 requestVideoFrameCallback
该 API 仅在 已播放且处于可渲染状态 的 <video> 元素上可用,且需满足以下条件:
- 视频必须已调用
play()并完成首次渲染(可监听canplay或playing事件) - 不能是静音自动播放被拦截的状态(需用户手势触发或启用
muted autoplay) - 浏览器支持:Chrome 111+、Edge 111+、Firefox 125+(Safari 尚未支持,需降级方案)
- 若视频来自
MediaStream(如摄像头),需确保 track 处于 live 状态且未被停止
异步提取关键帧:用 OffscreenCanvas 避免主线程阻塞
直接在回调中操作 canvas.getContext('2d') 可能引发渲染卡顿。推荐使用 OffscreenCanvas 在 Worker 或主线程离屏绘制,再提交像素数据:
- 创建
OffscreenCanvas,尺寸与视频自然宽高一致(video.videoWidth/video.videoHeight) - 在
requestVideoFrameCallback回调中调用ctx.transferFromImageBitmap()或ctx.drawImage(video, ...) - 使用
offscreenCanvas.convertToBlob({type: 'image/jpeg', quality: 0.8})异步生成压缩图像 Blob - 将 Blob 转为
ArrayBuffer或 Base64,便于后续上传(避免直接传 Blob 导致序列化失败)
智能触发比对:按需而非逐帧上传
连续上传每帧会极大增加带宽和云端负载。应结合业务逻辑做筛选:
- 利用
mediaInfo参数中的presentedFrames和processingDuration判断是否为关键帧(I-frame)或渲染稳定帧 - 添加时间间隔控制(如每 500ms 最多上传 1 帧),用
setTimeout或AbortController防抖 - 客户端预筛:用 WebAssembly 模块(如 TinyYolo、MediaPipe Pose)在本地粗筛目标对象/动作,仅上传含特征的帧
- 服务端返回比对结果后,可通过
video.currentTime跳转到匹配位置,实现“视频锚点”反馈
云端比对协同设计要点
前端不只是“发图”,需与后端约定清晰协议以提升鲁棒性:
- 请求体包含:
videoId(标识视频流)、timestampMs(相对于video.currentTime的毫秒偏移)、frameId(单调递增序号)、blobHash(SHA-256,防重复/校验) - 使用
fetch(..., { keepalive: true })确保页面卸载前发送完成(适用于长视频中途关闭场景) - 对 429/503 响应启用指数退避重试;对 401/403 触发 token 刷新流程
- 建议云端返回结构化结果:匹配 ID、相似度、时间范围、置信矩形(x,y,w,h),前端可叠加 SVG 标注层实时呈现

















