Using HTML5 Canvas to capture frames from a video

HTML5 has some interesting capability that allows extracting individual frames from a video source and draw it on a canvas element. The following example quickly shows how to capture a frame from a video and attach it to the DOM as an HTML5 canvas. To run this example please use FireFox 3.5 or a WebKit based browser.

Once you have captured an image click on it to see the base64 encoded version on a separate window.

Javascript code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
var videoId = 'video';
var scaleFactor = 0.25;
var snapshots = [];
 
/**
 * Captures a image frame from the provided video element.
 *
 * @param {Video} video HTML5 video element from where the image frame will be captured.
 * @param {Number} scaleFactor Factor to scale the canvas element that will be return. This is an optional parameter.
 *
 * @return {Canvas}
 */
function capture(video, scaleFactor) {
    if(scaleFactor == null){
        scaleFactor = 1;
    }
    var w = video.videoWidth * scaleFactor;
    var h = video.videoHeight * scaleFactor;
    var canvas = document.createElement('canvas');
        canvas.width  = w;
        canvas.height = h;
    var ctx = canvas.getContext('2d');
        ctx.drawImage(video, 0, 0, w, h);
    return canvas;
} 
 
/**
 * Invokes the <code>capture</code> function and attaches the canvas element to the DOM.
 */
function shoot(){
    var video  = document.getElementById(videoId);
    var output = document.getElementById('output');
    var canvas = capture(video, scaleFactor);
        canvas.onclick = function(){
            window.open(this.toDataURL());
        };
    snapshots.unshift(canvas);
    output.innerHTML = '';
    for(var i=0; i<4; i++){
        output.appendChild(snapshots[i]);
    }
}
var videoId = 'video';
var scaleFactor = 0.25;
var snapshots = [];

/**
 * Captures a image frame from the provided video element.
 *
 * @param {Video} video HTML5 video element from where the image frame will be captured.
 * @param {Number} scaleFactor Factor to scale the canvas element that will be return. This is an optional parameter.
 *
 * @return {Canvas}
 */
function capture(video, scaleFactor) {
	if(scaleFactor == null){
		scaleFactor = 1;
	}
	var w = video.videoWidth * scaleFactor;
	var h = video.videoHeight * scaleFactor;
	var canvas = document.createElement('canvas');
		canvas.width  = w;
	    canvas.height = h;
	var ctx = canvas.getContext('2d');
		ctx.drawImage(video, 0, 0, w, h);
    return canvas;
} 

/**
 * Invokes the <code>capture</code> function and attaches the canvas element to the DOM.
 */
function shoot(){
	var video  = document.getElementById(videoId);
	var output = document.getElementById('output');
	var canvas = capture(video, scaleFactor);
		canvas.onclick = function(){
			window.open(this.toDataURL());
		};
	snapshots.unshift(canvas);
	output.innerHTML = '';
	for(var i=0; i<4; i++){
		output.appendChild(snapshots[i]);
	}
}

HTML code:

1
2
3
4
5
6
7
8
9
<div style="border: solid 1px #ccc; padding: 10px; text-align: center;">
    <video id="video" width="320" controls="true">
        <source src="video.ogv"><!-- FireFox 3.5 -->
        <source src="movie.mp4"><!-- WebKit -->
        Your browser does not support HTML5 video tag. Please download FireFox 3.5 or higher.
    </video><br/>
    <button onclick="shoot()" style="width: 64px;border: solid 2px #ccc;">Capture</button><br/>
    <div id="output" style="display: inline-block; top: 4px; position: relative ;border: dotted 1px #ccc; padding: 2px;"></div>
</div>
<div style="border: solid 1px #ccc; padding: 10px; text-align: center;">
	<video id="video" width="320" controls="true">
		<source src="video.ogv"><!-- FireFox 3.5 -->
		<source src="movie.mp4"><!-- WebKit -->
		Your browser does not support HTML5 video tag. Please download FireFox 3.5 or higher.
	</video><br/>
	<button onclick="shoot()" style="width: 64px;border: solid 2px #ccc;">Capture</button><br/>
	<div id="output" style="display: inline-block; top: 4px; position: relative ;border: dotted 1px #ccc; padding: 2px;"></div>
</div>