Software
1st December 2015 | By:

Capture/manipulate video in canvas [HTML5]

With HTML5 it is now possible to directly capture video from the camera and stream it to the

First let’s start with a simple HTML5 page and all the necessary elements which will host the streaming of the video and the storing of the picture.

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<body>
	<div>
		<video id="camera_video" width="400" height="300" autoplay></video>
		<canvas id="camera_filter_canvas" width="400" height="300"></canvas>
		<img id="camera_image" src="" width="400" height="300" />
	</div>
</body>
</html>

You can ask the browser to request an access to the user’s camera by using the getUserMedia call. Unfortunately not all the browsers yet support this, some of the browsers have different naming for this, let’s make sure we can support as many browsers as we can.

navigator.getUserMedia = (navigator.getUserMedia ||
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia ||
                          navigator.msGetUserMedia);

This will handle all main browsers and assign the detected media device as the `navigator.getUserMedia`. The next stage would be to actually request access to the camera by calling getUserMedia. This function takes 3 arguments, the first argument is an object with the properties you want to access to, in our case we only want to access the video, hence the audio is set to false. The second and third arguments are callback functions, respectively for successful stream and error.

var video = document.getElementById('camera_video');
if(navigator.getUserMedia){
	navigator.getUserMedia(
		{
			video: true, // stream video
			audio: false // in this example we don't need to capture audio
		},
		function(stream){ // success function
			video.src = window.URL.createObjectURL(stream);
		},
		function(error){ // error function
			alert('Something went wrong. (error code ' + error.name + ')');
			return;
		}
	);
}

By changing the source attribute of the video element we are now effectively directly streaming from the camera to the browser. We will use our a element for this and copy the video stream to the canvas and apply a filter on it. We will be targeting 60fps.

	var canvas = document.getElementById('camera_filter_canvas');
	var context = canvas.getContext('2d');
	var w = canvas.width;
	var h = canvas.height;
	video.addEventListener('play', function(){
		setInterval(function(){
			if(video.paused || video.ended) return;
			context.drawImage(video, 0, 0, w, h); // draw actual video frame
		}, 1000/60);
	});

Now let’s try and add some filters to our video such as GrayScale filter.

video.addEventListener('play', function(){
	setInterval(function(){
		if(video.paused || video.ended) return;
		context.drawImage(video, 0, 0, w, h); // draw actual video frame
		var pixels = context.getImageData(0, 0, w, h);
		var d = pixels.data;
		for(var i=0; i<d.length; i+=4){
			var r = d[i];
			var g = d[i+1];
			var b = d[i+2];
			// CIE luminance for the RGB
			var v = 0.2126*r + 0.7152*g + 0.0722*b;
			d[i] = d[i+1] = d[i+2] = v
		}
		context.putImageData(pixels, 0, 0);
	}, 1000/60);
});

Its also possible to take a screenshoot of that video by using `toDataURL` property of the element and assign the result and use that result as a source for element.

	var img = document.getElementById('camera_image');
	var img_base64 = canvas.toDataURL("image/png");
	img.src = img_base64;

As you can see this is really simple, yet very powerful.

The full example from this post can be found on CodePen.

Tags: , , , , ,