Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
311 views
in Technique[技术] by (71.8m points)

javascript - Saving desktopCapturer to video file from Electron app

Basing on electron api and this question I'm trying to save recorded user screen to .webm file in videos folder in root app folder.

Actually it's almost working because it save .webm file but the file which is saved is empty, it weigh 0B.. I don't know what I'm missing here.

example file is 0 bytes

So it looks like it's somehow not recording correctly because file is empty..

edit when debbuging I discovered that recording is probably working correctly because blobs which I console log has value inside, after toArrayBuffer my blob no longer has value inside.

Code is:

(function () {
    'use strict';

    var fs = require('fs');
    var { desktopCapturer } = require('electron');
    var recorder, blobs = [];

    angular
        .module('app')
        .controller('loggedScreen', Controller);

    Controller.$inject = ['$scope'];

    function Controller($scope) {

        var startRecord = function () {
            console.log('started');
            desktopCapturer.getSources({types: ['window', 'screen']}, function(error) {
                if (error) throw error;
                navigator.webkitGetUserMedia({
                    audio: false,
                    video: {
                        mandatory: {
                            chromeMediaSource: 'desktop',
                            minWidth: 1280,
                            maxWidth: 1280,
                            minHeight: 720,
                            maxHeight: 720
                        }
                    }
                }, handleStream, handleError);
                return;
            });
        };

        function handleError(err) {
            console.log('something went wrong but it shouldnt');
        }

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

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

        function toBuffer(ab) {
            var buffer = new Buffer(ab.byteLength);
            var arr = new Uint8Array(ab);
            for (var i = 0; i < arr.byteLength; i++) {
                buffer[i] = arr[i];
            }
            return buffer;
        }

        function stopRecording() {
            recorder.stop();
            console.log(blobs); // 300k bytes
            toArrayBuffer(new Blob(blobs, {type: 'video/webm'}), function(ab) {
                console.log(ab); // 0 bytes
                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);
                    }
                });
            });
        }

        startRecord();
        setTimeout(function() {
            // stop recording after 7sec
            stopRecording();
        }, 7000);
    }
})();

startRecord() function is executed immediately, it also console.log started as expected just after hitting this controller.

stopRecording() function is executed after 7 second correctly, it console.log('Saved video: ' + file); just fine.

Then I go to my just created videos folder I open my saved example.webm file and it's empty.

It doesn't print any error in console.


  • I consoled.log(blobs) after stoping recorder in stopRecording() function to see if it's actually Blob.
  • I console.log(ab) inside toArrayBuffer(new Blob(blobs, {type: 'video/webm'}), function(ab) {}) callback.

screenshot of consoled things

I've got behaviour as blobs contains value when ab not.


I really can't solve it myself, looking for answer I create demo repository with minimal reproduced example just clone it to see behaviour for your own

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your recorder.stop() will run as follows: (from MediaRecorder docs)

When the stop() method is invoked, the UA queues a task that runs the following steps:

  1. If MediaRecorder.state is "inactive", raise a DOM InvalidState error and terminate these steps. If the MediaRecorder.state is not "inactive", continue on to the next step.
  2. Set the MediaRecorder.state to "inactive" and stop capturing media.
  3. Raise a dataavailable event containing the Blob of data that has been gathered.
  4. Raise a stop event.

In your case you don't wait up the stop event, so dataavailable will fill blobs only after you started the file saving method.

You have to restructure stopRecording to ensure recorded data is available. For example:

function stopRecording () {
  const save = () => {
    ...
  }
  recorder.onstop = save
  recorder.stop()
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...