MediaRecorder only record one frame

Viewed 322

I'm developing a react native app and there I'm recording a canvas and make 5 seconds video files to upload to the server. Everything works great except all my webm files have only one frame. Here is my code. Please help me to understand what's wrong here. Thanks!

    initMediaRecorder = () => {
    
    const promise = new Promise((resolve) => {
      const stream = this.selfieCanvas.captureStream(10);
      let mediaRecorder = null;
      let options;
      if (MediaRecorder.isTypeSupported('video/webm; codecs=vp9')) {
        options = { mimeType: 'video/webm; codecs=vp9', videoBitsPerSecond: 2500000 };
      } else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
        options = { mimeType: 'video/webm; codecs=vp8', videoBitsPerSecond: 2500000 };
      } else {
        options = 'video/vp8'; // Chrome 47
      }
      try {
        mediaRecorder = new MediaRecorder(stream, options);
      } catch (e0) {
        resolve(null);
      }

      mediaRecorder.ondataavailable = (event) => {
        console.log(`LOG - Data available ${event.data.size}`);
        this.sendToSaveVideo(event.data);
      };

      resolve(mediaRecorder);
    });

    return promise;
  }

  captureVideo = async (oldMediaRecorder) => {

    this.initMediaRecorder().then((mediaRecorder) => {
      if (oldMediaRecorder !== null && typeof oldMediaRecorder !== 'undefined') {
        // I don't want to stop previous recorder until I init the next recorder
        oldMediaRecorder.stop();
      }
      if (mediaRecorder !== null) {
        mediaRecorder.start();
      }
      
      this.captureVideoTimer = setTimeout(() => {
        this.captureVideo(mediaRecorder);
      }, 5000);
      
    });
  }

  sendToSaveVideo = async (eventData) => {
    const blobChunk = [];
    blobChunk.push(eventData);
    const video = new Blob(blobChunk, { type: 'video/webm' });
    saveBlobToCloud(video); // save the file to cloud
  }```
1 Answers

You are not setting up start(), this (probably) makes ondataavailable run every frame.
Also try avoiding using ondataavailable like that, onstop exists exactly for that purpose.
If this doesn't work try checking if the canvas is actually changing the frames.

 initMediaRecorder = () => {
    const promise = new Promise((resolve) => {
      const stream = this.selfieCanvas.captureStream(10);
      let chunks = [];
      let mediaRecorder = null;
      let options;
      if (MediaRecorder.isTypeSupported('video/webm; codecs=vp9')) {
        options = { mimeType: 'video/webm; codecs=vp9', videoBitsPerSecond: 2500000 };
      } else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
        options = { mimeType: 'video/webm; codecs=vp8', videoBitsPerSecond: 2500000 };
      } else {
        options = 'video/vp8'; // Chrome 47
      }
      try {
        mediaRecorder = new MediaRecorder(stream, options);
      } catch (e0) {
        resolve(null);
      }

      mediaRecorder.ondataavailable = (event) => {
        chunks.push(event.data);
      };

      mediaRecorder.onstop = (event) => {
        this.sendToSaveVideo(chunks);
      };

      resolve(mediaRecorder);
    });

    return promise;
  }

  captureVideo = async (oldMediaRecorder) => {

    this.initMediaRecorder().then((mediaRecorder) => {
      if (oldMediaRecorder !== null && typeof oldMediaRecorder !== 'undefined') {
        // I don't want to stop previous recorder until I init the next recorder
        oldMediaRecorder.stop();
      }
      if (mediaRecorder !== null) {
        // make ondataavailable run every second.
        // ondataavailable should not be used as a stop!
        mediaRecorder.start(1000);
      }
      
      this.captureVideoTimer = setTimeout(() => {
        this.captureVideo(mediaRecorder);
      }, 5000);
      
    });
  }

  sendToSaveVideo = async (chuncks) => {
    const video = new Blob(chunks, { type: 'video/webm' });
    saveBlobToCloud(video); // save the file to cloud
  }

Edit
Also you do not need to declare the mediarecorder every single time...
Something like this would be better:

      const stream = selfieCanvas.captureStream(10);
      let mediaRecorder = null;
      let options;
      if (MediaRecorder.isTypeSupported('video/webm; codecs=vp9')) {
        options = { mimeType: 'video/webm; codecs=vp9', videoBitsPerSecond: 2500000 };
      } else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
        options = { mimeType: 'video/webm; codecs=vp8', videoBitsPerSecond: 2500000 };
      } else {
        options = 'video/vp8'; // Chrome 47
      }
      try {
        mediaRecorder = new MediaRecorder(stream, options);
      } catch (e0) {
        resolve(null);
      }

      
      mediaRecorder.ondataavailable = (event) => {
          chunks.push(event.data);
      };

      mediaRecorder.onstop = (event) => {
          const video = new Blob(chunks, { type: 'video/webm' });
          saveBlobToCloud(video);
          chunks = [];
      };

      // makes ondataavailable run every 5 seconds
      mediaRecorder.start(1000);

      // a video is made for every 5 seconds
      setInterval(function(){
          mediaRecorder.stop();
          // ondataavailable should be running more often than stop
          mediaRecorder.start(1000);
      }, 5000);

Here are some other useful links:

  1. https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder/dataavailable_event
  2. MediaRecorder ondataavailable work successfully once
Related