将暂停的视频帧捕获到画布的最佳方法
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() 简单实例