Shaun Hevey
Create Video from HTML Canvas
October 31, 2021

In this post, I will discuss another little feature that you might be unaware of available in most major browsers called MediaRecorder. If the name didn't give away what it allows you to record media. If you want to dive into what MediaRecorder has to offer, you can read all about it here. In this post, I will show you how you can use MediaRecorder to record a canvas. Let's dive in.

Canvas to MP4

If you want to skip the explanation and see a complete working example (tested in chrome 95), just head to the bottom of the page, otherwise read on.

The first thing you need to do is set you some variables, check out the comments for some context.

	let frames = []; //This is used to store the captured frames.
let mediaRecorder; // This is the variable that stores the mediaRecorder object.

Next, we need to get a reference to the canvas that you want to create the video from.

	let canvas = document.getElementById('canvas');   

Ok, the last thing that needs to happen is to create a couple of functions to start and end the recording and just a utility function. Again check out the comments for a little bit of context.

	function startRecording() {
//Let's create the MediaRecorder object. This needs a "stream" that it will use to create the frames for the video in our context.
//It just so happens that the canvas object has the perfect function to allow it to be used with MediaRecorder, which is the captureStream function.

mediaRecorder = new MediaRecorder(canvas.captureStream());

//The next thing you need to do is set a function so that when some event is fired (like a frame update)
//then you can capture the data from that event to later be turned into a video.
mediaRecorder.ondataavailable = (event) => {
if (event.data)
frames.push(event.data);
}

//I am using the "onstop" event to call the method to populate the video player with the data that has been captured.
mediaRecorder.onstop = showVideo;

//This method start the MediaRecorder recording.
mediaRecorder.start();
}

//This is just a utility function to stop the MediaRecorder recording.
function endRecording() {
mediaRecorder.stop();
}

//This is the function that takes the frames that are captured above and turns them into a blob object, which is passed to the video player that has been created previously.
function showVideo() {
video.src = URL.createObjectURL(new Blob(frames, { type: mediaRecorder.mimeType }));
video.setAttribute("controls","controls")
}

There you have a quick and easy way to record the output of a canvas object. In this example, I only showed how you could populate a video player, but you could easily take the blob object and use it with an "a" tag so that the user could download it to be used outside of the browser.

The complete example below also contains some code to animate a box moving across the canvas. This was only used to demonstrate an animation on the canvas. I found this webkit blog post very helpful with creating this example.

<html>
<body>
<canvas id="canvas" height="300" width="600"></canvas>

<button onclick="startRecording()">start</button>
<button onclick="endRecording()">end</button>
<video id="video"></video>
<script>
let frames = [];
let mediaRecorder;

let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
let video = document.getElementById('video');

let x = 0;

function startRecording() {
mediaRecorder = new MediaRecorder(canvas.captureStream());
mediaRecorder.ondataavailable = (event) => {
if (event.data)
frames.push(event.data);
}
mediaRecorder.onstop = showVideo;
mediaRecorder.start();
}
function endRecording() {
mediaRecorder.stop();
}
function showVideo() {
video.src = URL.createObjectURL(new Blob(frames, { type: mediaRecorder.mimeType }));
video.setAttribute("controls","controls")
}

function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(x++, 50, 50,50);
requestAnimationFrame(draw);
}

draw()
</script>
</body>
</html>