Render HTML5 video to Canvas via the video tag

Learn how to draw video frames to a Canvas element and facilitate all kinds of effects


Learn how to draw video frames to a Canvas element and facilitate all kinds of effects



1. Video the star

Sites such as make web video the central focal point to the experience. HTML5, and the ability to embed and play video natively inside the browser, makes this kind of design far more robust. The Greenpeace project utilises the <video> tag for intro background and archive clips, all stretched full width to provide an immersive experience.

2. The <video> tag

HTML5 video begins with the tag itself, defining attributes for how the player element appears or behaves. A set of <source> tags wrapped inside then point to each file path and the encoding types: WEBM, MP4 and OGG formats. In this example we will start from a video tag like so:

<video id="theVideo" autoplay loop>         
<source src="myVideo.webm" type=video/webm>
<source src="myVideo.mp4" type=video/mp4>
<source src="myVideo.ogg" type=video/ogg>

3. Canvas and overlay wrapper

Our video tag from the last step is called ‘theVideo’, is set to be looped and will autoplay – this is useful for full-width/height backgrounds. This is also how we’ll use it here, although rather than maximise the video we’ll draw the video to a full-screen <canvas> element instead, placed above our video within a wrapper

<div> element:
<div id="overlay" class="fullsize">
<canvas id="theCanvas" class="fullsize"></canvas>
<video id="theVideo" autoplay loop>
<source src="myVideo.webm" type=video/webm>
<source src="myVideo.mp4" type=video/mp4>
<source src="myVideo.ogg" type=video/ogg>

4. Force elements to be .fullsize

Moving to our CSS, we start our styling with the .fullsize class linked to the Canvas and wrapper elements. Both of these will occupy 100 per cent of the browser by setting dimensions to maximum percentage, while positioned absolute and all four edges forced to zero.

.fullsize {
width: 100%;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;

5. Add the patterned overlay

In this instance, our Canvas video background will be deliberately styled to appear pixelated by using a repeating transparent PNG grid pattern overlay. This is achieved via the full-screen overlay wrapper <div> and by setting its background to the simple pattern graphic. Here you can see the class with the background set to the image file itself or the base64 encode:

#overlay {
background: url(grid.png) fixed repeat;
background:     url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGklEQVQYGWNkgID/UBonRVABE06tSBLDWxEAcWcCDlgMZ/kAAAAASUVORK5CYII=') fixed repeat;

6. Additional element styles

Now add a couple of classes for cosmetic tweaks. Lower the opacity of our Canvas very slightly to make the overlay more prominent. Secondly, we can either position our video box on the page to compare playback or hide it by setting display to none, shown commented here:

#theCanvas {
opacity: 0.8;
#theVideo {
position: absolute;
width: 480px;
height: auto;
right: 3%;
bottom: 5%;
/*display: none;*/

7. Initialise the objects

Once the window and video is loaded, a JS <script> begins by grabbing the Canvas, its 2D drawing context and the video from the document. From here we can call a function we’ll recursively call ‘drawVideo()’, passing in all those iniltialised objects and the drawing surface width/height of the Canvas:

var canvas = document.getElementById("theCanvas");
var context = canvas.getContext("2d");
// grab canvas and 2D drawing context
var video = document.getElementById("theVideo");
// grab the video element
drawVideo(context, video, canvas.width, canvas.height);
// calls drawVideo() function, passing all the objects

8. Recursive drawing function

The drawVideo() function crucially calls drawImage() on the Canvas context, passing the current video frame. Here you can set a millisecond delay after the first pass to add a slower frame-rate effect when passed into setTimeout() to recursively call the function indefinitely, as long as the video is looped.

function drawVideo(context, video, width, height) {         
context.drawImage(video, 0, 0, width, height); // draws current video frame to canvas     
var delay = 100; // milliseconds delay for slowing framerate
setTimeout(drawVideo, delay, context, video, width, height); // recursively calls drawVideo() again after delay


Warning: file_get_contents( failed to open stream: HTTP request failed! HTTP/1.0 500 Internal Server Error in /var/www/html/ on line 9