I have a fabricjs Canvas which contains some animation data which is being used by animejs to move the objects around. I would like to create a webm out of it.
Current Solution
I am using mediaRecorderAPI to capture the frames, start the animation, wait till the animation finishes and then export it to webm
Problem
As I keep increasing the resolution of the canvas, the output starts to get laggy and short
Here is a snippet of what I am doing:
//Just a temporary Canvas
let canvas_to_capture = document.getElementById("export-canvas");
const canvasStream = canvas_to_capture.captureStream(30);
const mediaRecorder = new MediaRecorder(canvasStream, {
mimeType: "video/webm; codecs=vp9",
});
let chunks = [];
mediaRecorder.onstop = function () {
downloadVideo(chunks);
chunks = [];
scene.current?.dispose();
};
mediaRecorder.onerror = function (e) {
chunks = [];
};
mediaRecorder.ondataavailable = function (e) {
chunks.push(e.data);
};
const canvasJSON = canvasRef.current.toJSON(["name", "_anim"]);
const c = new fabric.Canvas("export-canvas", {
width: 1920,
height: 1080,
preserveObjectStacking: true,
skipOffscreen: false,
});
c.loadFromJSON(canvasJSON, () => {
const totalDuration = loadAnimations(c);
mediaRecorder.start();
let framesPlayed = 0;
exportTimelines.current = [];
Object.entries(timelines.current).forEach((frame) => {
Object.keys(frame[1]).forEach((prop) => {
const canvasObject = c?.getObjects().find((o) => o.name === frame[0]);
const timeline = anime.timeline({
easing: "linear",
update: () => {},
loop: false,
autoplay: false,
});
//Just a helper function to convert the frames to animejs readable format
const keyframes = canvasFramesToAnimFrames(
frame[1][prop].keyframes,
prop
);
if (keyframes.length) {
timeline.add({
keyframes: keyframes,
targets: canvasObject,
loopComplete: (e) => {
framesPlayed += 1;
if (framesPlayed === exportTimelines.current.length) {
if (mediaRecorder.state === "recording") mediaRecorder.stop();
}
},
update: (e) => {
c?.renderAll();
},
});
exportTimelines.current.push(timeline);
timeline.play();
}
});
});
scene.current = c;
});
downloadVideo:
const blob = new Blob(chunks, { type: "video/webm" });
const videoURL = URL.createObjectURL(blob);
const tag = document.createElement("a");
tag.href = videoURL;
tag.download = `video.webm`;
document.body.appendChild(tag);
tag.click();
document.body.removeChild(tag);