Search code examples
javascripthtmlmediarecorderwebm

Using mediaRecorder to capture a JS animation but blob is null value


I use Vanta js to create an animation background and use mediaRecorder to capture the canvas as webm. The page will be recorded from the beginning and stop and export the webm after 1 sec.

However, nothing is stored in blob, the webm exported is empty.

Any suggestions? Thank you!

<body id="ele">
<div><canvas id="canvas"></canvas></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.clouds.min.js"></script>


<script>
    VANTA.CLOUDS("#ele");
</script>

<script>
  const startRecording = () => {
  const newcanvas = document.querySelector("canvas");
  const chunks = []; // here we will store our recorded media chunks (Blobs)
  const stream = newcanvas.captureStream(30); // grab our canvas MediaStream
  const rec = new MediaRecorder(stream); // init the recorder
  // every time the recorder has new data, we will store it in our array
  rec.ondataavailable = (e) => chunks.push(e.data);
  // only when the recorder stops, we construct a complete Blob from all the chunks
  rec.onstop = (e) =>
    downloadVideo(new Blob(chunks, { type: "video/webm;codecs=h264" }));
  rec.start();
  setTimeout(() => {
    rec.stop();
  }, 1000); // stop recording in 1s
};

const downloadVideo = async (blob) => {
  const div = document.querySelector("div");
  var url = URL.createObjectURL(blob);
  console.log(url);
  var a = document.createElement("a");
  a.href = url;
  a.download = "test.webm";
  a.className = "button";
  a.innerText = "click here to download";
  div.appendChild(a);
};

  startRecording();

</script>
   
</body>

Solution

  • Just remove the <canvas id="canvas"></canvas> from your html. VANTA.CLOUDS inserts a canvas element of it's own.

    Your Javascript code for querying your canvas element results in fetching the element with no data in it.

    VANTA.CLOUDS("#ele");
    
    
    const startRecording = () => {
        const newcanvas = document.querySelector("canvas");
        const chunks = []; // here we will store our recorded media chunks (Blobs)
        const stream = newcanvas.captureStream(60); // grab our canvas MediaStream
        const rec = new MediaRecorder(stream); // init the recorder
        
        // every time the recorder has new data, we will store it in our array
        rec.ondataavailable = (e) => {
              chunks.push(e.data);
            };
        // only when the recorder stops, we construct a complete Blob from all the chunks
        rec.onstop = (e) =>
              downloadVideo(new Blob(chunks, { type: "video/webm" }));
        
        rec.start(100);
        setTimeout(() => {
              rec.stop();
              //   alert("wow");
            }, 2000); // stop recording in 1s
          };
    
    const downloadVideo = async (blob) => {
        const div = document.querySelector("div#link");
        var url = URL.createObjectURL(blob);
        var a = document.createElement("a");
        var span = document.createElement("span");
        
        a.href = url;
        a.download = "test.webm";
        a.innerText = `Click to download`;
        span.innerHTML = ` Link is <b>${url}</b>`;
    
        div.appendChild(a);
        div.appendChild(span)
    };
    
    startRecording();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.clouds.min.js"></script>
    
    <div style="display: flex; flex-direction: column;">
        <div id="link" style="height: 20px;"></div>
        <div id="ele"></div>
    </div>

    The null blob url is because this code is running inside the browser file system environment.