将暂停的视频帧捕获到 canvas 的最佳方式
Best way to capture paused video frame to canvas
我知道如何使用 2D 上下文将正在播放的 HTML5 视频逐帧复制到 canvas。
但我想处理暂停的视频,动态更改其 currentTime
并将当前视频帧复制到 canvas。
我的猜测是,当使用 currentTime
属性 设置视频位置时,某些过程尚未调用,尽管视频本身会更新它显示的图像(但不会更新到 canvas).
我发现可以通过设置 setTimeout 来在下一步中执行 canvas 'drawImage' 来克服这个问题。
You can see here a jsfiddle that proves the point.
正如您在 fiddle 中看到的,您可以播放视频,并且 canvas 更新,但是如果暂停视频,鼠标滚动会移动 currentTime
视频。在那里,需要“seTimeout”来更新 canvas,如果我直接调用 drawImage
方法,canvas 不会更新。
简而言之,我的问题是:
有更好的方法吗?是否可以在没有 setTimeout 和 de loop 本身的情况下执行此操作?优点和缺点?
非常感谢您阅读这里!
每次您更改 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 height="120" 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>
我知道如何使用 2D 上下文将正在播放的 HTML5 视频逐帧复制到 canvas。
但我想处理暂停的视频,动态更改其 currentTime
并将当前视频帧复制到 canvas。
我的猜测是,当使用 currentTime
属性 设置视频位置时,某些过程尚未调用,尽管视频本身会更新它显示的图像(但不会更新到 canvas).
我发现可以通过设置 setTimeout 来在下一步中执行 canvas 'drawImage' 来克服这个问题。
You can see here a jsfiddle that proves the point.
正如您在 fiddle 中看到的,您可以播放视频,并且 canvas 更新,但是如果暂停视频,鼠标滚动会移动 currentTime
视频。在那里,需要“seTimeout”来更新 canvas,如果我直接调用 drawImage
方法,canvas 不会更新。
简而言之,我的问题是:
有更好的方法吗?是否可以在没有 setTimeout 和 de loop 本身的情况下执行此操作?优点和缺点?
非常感谢您阅读这里!
每次您更改 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 height="120" 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>