【问题标题】:Event for every frame of HTML Video?HTML视频每一帧的事件?
【发布时间】:2021-07-16 11:08:39
【问题描述】:

我想构建一个事件处理程序来处理 HTML 5 Video 元素的每个新帧。不幸的是,没有为每个新视频帧触发的内置事件(timeupdate event 是最接近的,但每次更改都会触发,而不是每个视频帧触发)。

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

【问题讨论】:

  • 如果它是一个可以搜索的视频文件(ie: 不是网络摄像头),那么你可以只搜索每一帧。公式为 currentTime = ( (1000 / FPS ) * frameNum );,其中 FPS 是输入视频的每秒帧率。
  • 该公式仅适用于视频具有恒定帧速率的情况

标签: html html5-video


【解决方案1】:

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

对于您的 Firefox 用户,此浏览器有一个非标准的 seekToNextFrame() 方法,取决于您想要做什么,您可以使用该方法。不过,这不会完全作为一个事件起作用,它更像是一种方式,嗯......寻找下一帧。所以这将极大地影响视频的播放,因为它不会尊重每一帧的持续时间。

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

(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 循环会在每次更新监视器时触发可能会更好。

【讨论】:

  • 这是一种让 StackOverflow 变得很棒的答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 2018-05-24
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
相关资源
最近更新 更多