0

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);
RikTheGuy
  • 1
  • 1

0 Answers0