HTML视频每帧的事件



我想构建一个事件处理程序来处理HTML5Video元素的每个新帧。不幸的是,没有为每个新视频帧触发的内置事件(时间更新事件是最接近的,但为每个时间更改而不是每个视频帧触发(。

其他人遇到过同样的问题吗?有什么好办法绕过它吗?

有一个HTMLVideoElement.requestVideoFrameCallback()方法仍在起草中,因此既不稳定,也不广泛实现(它只在基于Chromium的浏览器中实现(,但它可以满足您的需求,并提供了有关该框架的许多其他细节。

对于您的Firefox用户,此浏览器有一个非标准的seekToNextFrame()方法,取决于您想做什么您可以使用该方法。不过,这并不是一个真正的活动,它更多的是一种方式,嗯。。。寻找下一帧。因此,这将极大地影响视频的播放,因为它不尊重每帧的持续时间。

对于Safari用户来说,最接近的确实是时间更新事件,但正如你所知,这与显示的帧并不匹配。

(async() => {
const log = document.querySelector("pre");
const vid = document.querySelector("video");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
if( vid.requestVideoFrameCallback ) {
await vid.play();
canvas.width = vid.videoWidth;
canvas.height = vid.videoHeight;
ctx.filter = "invert(1)";
const drawingLoop = (timestamp, frame) => {
log.textContent = `timestamp: ${ timestamp }
frame: ${ JSON.stringify( frame, null, 4 ) }`;
ctx.drawImage( vid, 0, 0 );
vid.requestVideoFrameCallback( drawingLoop );  
};
vid.requestVideoFrameCallback( drawingLoop );
}
else if( vid.seekToNextFrame ) {
const requestNextFrame = (callback) => {
vid.addEventListener( "seeked", () => callback( vid.currentTime ), { once: true } );
vid.seekToNextFrame();
};
await vid.play();
await vid.pause();
canvas.width = vid.videoWidth;
canvas.height = vid.videoHeight;
ctx.filter = "invert(1)";
const drawingLoop = (timestamp) => {
log.textContent = "timestamp: " + timestamp;
ctx.drawImage( vid, 0, 0 );
requestNextFrame( drawingLoop );
};
requestNextFrame( drawingLoop );
}
else {
console.error("Your browser doesn't support any of these methods, we should fallback to timeupdate");
}
})();
video, canvas {
width: 260px;
}
<pre></pre>
<video src="https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm" muted controls></video>
<canvas></canvas>

请注意,编码的帧和显示的帧不一定是相同的,并且浏览器可能根本不尊重编码的帧速率。因此,根据您的意愿,可能会有一个简单的requestAnimationFrame循环,它会在监视器的每次更新时启动,这可能会更好。

最新更新