HTML5 video不支持负playbackRate,倒放需手动控制currentTime:暂停视频后用requestAnimationFrame逐帧递减并限幅至0,注意缓冲、I帧依赖及性能限制。
playbackRate设为负数直接给video.playbackRate = -1在所有主流浏览器都会被忽略,playbackRate只接受 ≥ 0 的值。这不是bug,是规范限制——W3C明确要求负值必须被clamp到0。所以“倒放”必须靠其他手段模拟。
requestAnimationFrame手动控制currentTime
核心思路:禁用默认播放,用定时循环不断减小video.currentTime,并确保帧率稳定。关键点不是“快慢”,而是“逐帧逆向跳转”的精度和同步性。
video.pause(),避免原生播放逻辑干扰requestAnimationFrame而非setInterval,更贴合渲染节奏,减少丢帧1000/60 ≈ 16.67ms)timeupdate或检查currentTime ≤ 0来终止,否则会卡在负值或触发异常let isReversing = false; let reverseInterval;function startReverse(video) { if (isReversing) return; isReversing = true; video.pau
se();
function reverseStep() { if (!isReversing || video.currentTime <= 0) { video.currentTime = 0; isReversing = false; return; } video.currentTime = Math.max(0, video.currentTime - 16.67); requestAnimationFrame(reverseStep); } requestAnimationFrame(reverseStep); }
video.buffered和解码限制浏览器不会预加载“反向所需”的帧。当currentTime跳到未缓冲的位置,会出现卡顿、黑屏或seeking事件反复触发。尤其H.264视频依赖I帧,倒放时若跳到P/B帧位置,可能无法渲染。
buffered(可监听canplaythrough后再操作)如果需要逐帧像素级控制(比如加滤镜、变速倒放),就得把视频帧抽成ImageBitmap或texture,用Canvas重绘。这时video仅作数据源,播放逻辑完全自控。
video.crossOrigin = "anonymous"才能读取像素(否则canvas.getContext('2d').getImageData()报错)video.requestVideoFrameCallback()(Chrome 94+)比requestAnimationFrame更准,能对齐视频帧节奏cancelVideoFrameCallback清理真要倒放,优先接受“近似可用”;追求精确,就得放弃标签直连,转向底层帧处理。这点容易被低估。