Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving desktopCapturer to video file in Electron

The desktopCapturer api example shows how to write a screen capture stream to a <video> element.

// In the renderer process.
var desktopCapturer = require('electron').desktopCapturer;

desktopCapturer.getSources({types: ['window', 'screen']}, function(error, sources) {
  if (error) throw error;
  for (var i = 0; i < sources.length; ++i) {
    if (sources[i].name == "Electron") {
      navigator.webkitGetUserMedia({
        audio: false,
        video: {
          mandatory: {
            chromeMediaSource: 'desktop',
            chromeMediaSourceId: sources[i].id,
            minWidth: 1280,
            maxWidth: 1280,
            minHeight: 720,
            maxHeight: 720
          }
        }
      }, gotStream, getUserMediaError);
      return;
    }
  }
});

function gotStream(stream) {
  document.querySelector('video').src = URL.createObjectURL(stream);
}

function getUserMediaError(e) {
  console.log('getUserMediaError');
}

I tried to replace the gotStream function with the following:

function gotStream(stream) {
  var fs = require('fs');
  fs.writeFileSync('vid.mp4', stream);
}

This creates a text file with [object MediaStream] as the contents.

How can I record this stream and save to a file on disk?

like image 598
styfle Avatar asked Apr 20 '16 19:04

styfle


3 Answers

I answered my own question with the help of Demian's link to MediaRecorder as well as other related questions.

Below is an excerpt from magnemite with some minor simplifications and converted from TypeScript to JavaScript ES5 for better understanding to most readers.

var fs = require('fs');
var electron = require('electron');

var SECRET_KEY = 'Magnemite';

var recorder;
var blobs = [];

function startRecording() {
    var title = document.title;
    document.title = SECRET_KEY;

    electron.desktopCapturer.getSources({ types: ['window', 'screen'] }, function(error, sources) {
        if (error) throw error;
        for (let i = 0; i < sources.length; i++) {
            let src = sources[i];
            if (src.name === SECRET_KEY) {
                document.title = title;

                navigator.webkitGetUserMedia({
                    audio: false,
                    video: {
                        mandatory: {
                            chromeMediaSource: 'desktop',
                            chromeMediaSourceId: src.id,
                            minWidth: 800,
                            maxWidth: 1280,
                            minHeight: 600,
                            maxHeight: 720
                        }
                    }
                }, handleStream, handleUserMediaError);
                return;
            }
        }
    });
}

function handleStream(stream) {
    recorder = new MediaRecorder(stream);
    blobs = [];
    recorder.ondataavailable = function(event) {
        blobs.push(event.data);
    };
    recorder.start();
}

function stopRecording() {
    recorder.stop();
    toArrayBuffer(new Blob(blobs, {type: 'video/webm'}), function(ab) {
        var buffer = toBuffer(ab);
        var file = `./videos/example.webm`;
        fs.writeFile(file, buffer, function(err) {
            if (err) {
                console.error('Failed to save video ' + err);
            } else {
                console.log('Saved video: ' + file);
            }
        });
    });
}

function handleUserMediaError(e) {
    console.error('handleUserMediaError', e);
}

function toArrayBuffer(blob, cb) {
    let fileReader = new FileReader();
    fileReader.onload = function() {
        let arrayBuffer = this.result;
        cb(arrayBuffer);
    };
    fileReader.readAsArrayBuffer(blob);
}

function toBuffer(ab) {
    return Buffer.from(ab);
}

// Record for 7 seconds and save to disk
startRecording();
setTimeout(function() { stopRecording() }, 7000);

This will record the current electron window for 7 seconds and save to disk.

like image 173
styfle Avatar answered Nov 09 '22 16:11

styfle


The desktopCapturer example shows how to get a Blob. You then need to convert the Blob to something accepted by fs.writeFile. The following is short and efficient:

fs.writeFile(filepath, Buffer.from(await blob.arrayBuffer()), ...);
like image 24
jameshfisher Avatar answered Nov 09 '22 18:11

jameshfisher


Take a look at the MediaRecorder API

You should convert that stream to binary chunks.

like image 2
demian85 Avatar answered Nov 09 '22 17:11

demian85