3

I was trying to make a basic media recorder with the MediaRecorder API which is fairly straight forward: get the stream from getDisplayMedia, then record it.

The problem: This only records the maximum screen size, but no more. So if my screen is 1280/720, it will not record 1920/1080.

This may seem quite obvious, but my intent is that it should record the smaller resolution inside of the bigger one. For example:enter image description here

With the red rectangle representing what my actual screen is recording, and the surrounding black rectangle is simply black space, but the entire video is now a higher resolution, 1920/1080, which is useful for youtube, since youtube scales down anything that is in between 720 and 1080 resolution, which is a problem.

Anyway I tried simply adding the stream from getDisplayMedia to a video element video vid.srcObject = stream, then made a new canvas with the resolution 1920/1080, and in the animate loop just did ctx.drawImage(vid, offsetX, offsetY), and outside of the loop, where the MediaRecorder was made, simply did newStream = myCanvas.captureStream() as per the documentation of the API, and passed that to the MediaRecorder; however, the problem is that because of the huge canvas overhead, everything is really slow and the framerate is absolutely terrible (don't have video example, but just test it yourself).

So is there some way to optimize the canvas to not affect the framerate (tried looking into OffscreenCanvas but I couldn't find a way to get the stream from it itself to use with MediaRecorder, so it didn't really help), or is there a better way to capture and record the canvas, or is there a better way to record the screen within a larger resolution, in client-size JavaScript? If not with client-size JavaScript, is there some kind of real-time video encoder (ffmpeg is too slow) that could be run on the server, and each frame of the canvas could be sent to the server and saved there? Is there some better way to make a video recorder with any kind of JavaScript -- client or server or both?

1 Answers1

1

Don't know what your code looks like, but I managed to get a smooth experience with this piece of code:

(You will also find very good example here: https://mozdevs.github.io/MediaRecorder-examples/)

<!doctype html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="script.js"></script>
</head>
<body>
  <canvas id="canvas" style="background: black"></canvas>
</body>
// DISCLAIMER: The structure of this code is largely based on examples
// given here: https://mozdevs.github.io/MediaRecorder-examples/.

window.onload = function () {
  navigator.mediaDevices.getDisplayMedia({
    video: true
  })
  .then(function (stream) {

    var video = document.createElement('video');
    // Use "video.srcObject = stream;" instead of "video.src = URL.createObjectURL(stream);" to avoid
    // errors in the examples of https://mozdevs.github.io/MediaRecorder-examples/
    // credits to https://stackoverflow.com/a/53821674/5203275
    video.srcObject = stream;
    video.addEventListener('loadedmetadata', function () {
      initCanvas(video);
    });
    video.play();
  });
};

function initCanvas(video) {

  var canvas = document.getElementById('canvas');

  // Margins around the video inside the canvas.
  var xMargin     = 100;
  var yMargin     = 100;
  
  var videoWidth  = video.videoWidth;
  var videoHeight = video.videoHeight;

  canvas.width  = videoWidth  + 2 * xMargin;
  canvas.height = videoHeight + 2 * yMargin;

  var context = canvas.getContext('2d');
  var draw = function () {
    // requestAnimationFrame(draw) will render the canvas as fast as possible
    // if you want to limit the framerate a particular value take a look at
    // https://stackoverflow.com/questions/19764018/controlling-fps-with-requestanimationframe
    requestAnimationFrame(draw);
    context.drawImage(video, xMargin, yMargin, videoWidth, videoHeight);
  };

  requestAnimationFrame(draw);
}
geauser
  • 1,005
  • 8
  • 20