I know how to copy on frame by frame basis from a playing HTML5 video to a canvas using 2D context.
But I want to work with a paused video, change dinamically its currentTime
and copy current frame of video to canvas.
My guess is some process is not called yet when video position is set with currentTime
property, although the video itself does update the image it shows (but not to the canvas).
I've found that it's posible to overcome this by setting a setTimeout to do the canvas ´drawImage´ in the next step.
You can see here a jsfiddle that proves the point.
As you can see in the fiddle you can play the video, and canvas updates, but if you pause the video, mouse scroll moves currentTime
of video. There, a ´seTimeout´ is needed to update the canvas, if I call the drawImage
method directly, canvas doesn't update.
In short, my question is:
Is there a better way to do this? Is it posible to do this without setTimeout and inside de loop itself? Pros & Cons?
Thank you very much for reading through here!
Every time you change the currentTime
of your VideoElement, a seeked Event will trigger when the video actually changed its position.
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>