将暂停的视频帧捕获到画布的最佳方法

Posted

技术标签:

【中文标题】将暂停的视频帧捕获到画布的最佳方法【英文标题】:Best way to capture paused video frame to canvas 【发布时间】:2018-10-04 04:04:48 【问题描述】:

我知道如何使用 2D 上下文逐帧从正在播放的 html5 视频复制到画布。

但我想处理暂停的视频,动态更改其currentTime 并将当前视频帧复制到画布。

我的猜测是,当使用 currentTime 属性设置视频位置时,尚未调用某些过程,尽管视频本身确实会更新它显示的图像(但不会更新到画布)。

我发现可以通过设置 setTimeout 在下一步中执行画布“drawImage”来克服这个问题。

You can see here a jsfiddle that proves the point.

正如您在小提琴中看到的,您可以播放视频和画布更新,但如果您暂停视频,鼠标滚动会移动视频的currentTime。在那里,需要一个“seTimeout”来更新画布,如果我直接调用drawImage 方法,画布不会更新。

简而言之,我的问题是:

有没有更好的方法来做到这一点?是否可以在没有 setTimeout 和内部循环本身的情况下执行此操作?利弊?

非常感谢您阅读这里!

【问题讨论】:

【参考方案1】:

每次更改 VideoElement 的 currentTime 时,都会在视频实际更改其位置时触发 seeked 事件。

var vid = document.getElementById("v");
var canvas = document.getElementById("c");
var context = canvas.getContext('2d');
var targetFrame = document.getElementById('t');
var cw = canvas.width = 200;
var ch = canvas.height = Math.round(cw / 1.7777);
var targetOffset = 0;

window.addEventListener('wheel', function(e) 
  e.preventDefault();
  targetOffset = targetOffset + (e.deltaY / 1000);
  targetFrame.value = targetOffset;
  seek(); // for demo purpose, we only listen to wheel
  return false;
);
// that's all is needed
vid.addEventListener('seeked', function() 
  context.drawImage(vid, 0, 0, cw, ch);
);
// for demo
// removed the rendering loop
// now it only changes the video's currentTime property
function seek() 
  targetOffset = targetOffset * 0.9;
  targetFrame.value = Math.round(targetOffset * 100) / 100;
  var vct = vid.currentTime - targetOffset;
  if (vct < 0) 
    vct = vid.duration + vct;
   else if (vct > vid.duration) 
    vct = vct - vid.duration;
  
  vid.currentTime = vct;
.column 
  float: left;
  width: 50%;

.row:after 
  content: "";
  display: table;
  clear: both;

#c 
  border: 1px solid black;
<h3>
  scroll up is forward
</h3>
<div class="row">
  <div class="column">
    <div>
      Video element:
    </div>
    <video controls  id="v" tabindex="-1" autobuffer="auto" preload="auto">
    <source type="video/webm" src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"/>
</video>
  </div>
  <div class="column">
    <div>
      Canvas element:
    </div>
    <canvas id="c"></canvas>
    <div>
      Momentum: <input type=text id="t">
    </div>
  </div>
</div>

【讨论】:

非常感谢!这刚刚解决了我的问题!我只添加了vid.addEventListener('seeked', function() context.drawImage(vid, 0, 0, cw, ch); ); 并将其他所有内容都保留在循环中,如this fiddle 所示

以上是关于将暂停的视频帧捕获到画布的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

requestVideoFrameCallback() 简单实例

HTML5 drawimage 从视频到画布

来自视频帧的画布中的drawImage改变色调

以恒定帧速率捕获网络摄像头视频的方法?

ActionScript 3 将视频帧捕获到BitmapData(额外 - 将位图添加到PV3D材质)

将视频帧捕获到位图数据(额外-将位图添加到PV3D材质)