Search code examples
javascriptsafariwebrtchtml5-videovideo-capture

Why Safari produces giant videos compared to Chrome, when using the MediaDevices.getUserMedia() API?


I was setting up a little experiment to measure the size of the videos captured by the MediaDevices.getUserMedia() API.

When I was running my code in Safari it produces 5-10 times larger videos than in Chrome. Here is my code:

index.html:

<html lang="en">
  <head>
    <title>Video Spike</title>
  </head>
  <body>
    <video autoplay id="video" muted></video>
    <br />
    <button id="record">Record 10 second video</button>
  </body>
  <script src="./index.js"></script>
</html>

index.js:

const videoElem = document.getElementById("video");
const recordBtn = document.getElementById("record");

async function startCamera() {
  const stream = await navigator.mediaDevices.getUserMedia({
    audio: true,
    video: {
      frameRate: 30,
      height: 240,
      width: 240,
    },
  });

  videoElem.srcObject = stream;

  let buffer;

  recordBtn.addEventListener("click", () => {
    buffer = [];
    const recorder = new MediaRecorder(stream);

    setTimeout(() => recorder.stop(), 10000);

    recorder.ondataavailable = async (event) => {
      buffer.push(event.data);
      console.log(
        "current video size:",
        new Blob(buffer, { type: "video/webm" }).size / 1024 / 1024,
        "MB"
      );
    };

    recorder.start(1000);
  });
}

startCamera();

After 10 seconds, this logs 6.5MB for Safari, and 0.6MB for Chrome for me.

I tried to play around with the MediaContraints object, resolutions and recorded durations but it seem to always have this huge size difference between the two browsers.


Solution

  • There is an option to set the bitsPerSecond when creating a MediaRecorder.

    new MediaRecorder(stream, { bitsPerSecond: 200_000 });
    

    Looks like Chrome and Safari have different default values.

    There is also a possibility to set the audioBitsPerSecond and videoBitsPerSecond separately.