7

I have an electron app that has very simple desktop capturing functionality:

const {desktopCapturer} = require('electron')
const fs = require('fs');

var recorder;
var chunks = [];
var WINDOW_TITLE = "App Title";

function startRecording() {
    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 === WINDOW_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);
    chunks = [];
    recorder.ondataavailable = function(event) {
        chunks.push(event.data);
    };
    recorder.start();
}

function stopRecording() {
    recorder.stop();
    toArrayBuffer(new Blob(chunks, {type: 'video/webm'}), function(ab) {
        var buffer = toBuffer(ab);
        var file = `./test.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) {
    let buffer = new Buffer(ab.byteLength);
    let arr = new Uint8Array(ab);
    for (let i = 0; i < arr.byteLength; i++) {
        buffer[i] = arr[i];
    }
    return buffer;
}


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

I know that to save the MediaRecorder blob sources, I need to read it into an ArrayBuffer, then copy that into a normal Buffer for the file to be saved.

However, where this seems to be failing for me is combining the chunk of blobs into blobs. When the chunks are added into a single Blob - it's like they just disappear. The new Blob is empty, and every other data structure they are copied into afterwards also is completely empty.

Before creating the Blob, I know I have valid Blob's in the chunks array.

Here's what the debug info of chunks is, before executing the new Blob(chunks, {.. part.

console.log(chunks)

console.log(chunks)

Then here's the debug info of the new Blob(chunks, {type: 'video/webm'}) object.

console.log(ab)

console.log(ab)

I'm completely stumped. All the reference tutorials or other SO answers I can find basically follow this flow. What am I missing?

Electron version: 1.6.2

Andy Baird
  • 6,088
  • 4
  • 43
  • 63

2 Answers2

1

This problem literally just fixed itself today without me changing anything. I'm not sure what about my system changed (other than a reboot) but it's now working exactly as it should.

Andy Baird
  • 6,088
  • 4
  • 43
  • 63
  • When I do a search for "chunks" on this page of code, (ctrl+f), it appears that "stopRecording" method uses chunks to be passed in as a parameter. I would check if chunks has a value by using this solution : http://stackoverflow.com/questions/1181575/determine-whether-an-array-contains-a-value –  Apr 21 '17 at 15:20
  • I've got exact same code and exact same behavior issue but it doesn't want to fix " itself ", please help here: https://stackoverflow.com/questions/49208343/saving-desktopcapturer-to-video-file-from-electron-app – BT101 Mar 10 '18 at 19:12
1

That's not possible to be working. You didn't wait for value to come in stopReocoring. You need to change your stopRecording function to following:

function stopRecording() {
    var save = function() {
        console.log(blobs);
        toArrayBuffer(new Blob(blobs, {type: 'video/webm'}), function(ab) {
            console.log(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);
                }
            });
        });
    };
    recorder.onstop = save;
    recorder.stop();
}
BT101
  • 3,666
  • 10
  • 41
  • 90