将 desktopCapturer 从 Electron 应用程序保存到视频文件

时间:2023-01-29
本文介绍了将 desktopCapturer 从 Electron 应用程序保存到视频文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

基于

所以看起来它以某种方式无法正确录制,因为文件是空的..

edit 调试时我发现记录可能正常工作,因为我控制台日志的 blob 在内部具有价值,在 toArrayBuffer 之后,我的 blob 内部不再具有价值.

代码是:

(function () {'使用严格';var fs = 需要('fs');var { desktopCapturer } = 要求('电子');var 记录器,blob = [];有角度的.module('app').controller('loggedScreen', 控制器);Controller.$inject = ['$scope'];功能控制器($范围){var startRecord = 函数 () {console.log('开始');desktopCapturer.getSources({types: ['window', 'screen']}, function(error) {if (error) 抛出错误;navigator.webkitGetUserMedia({音频:假,视频: {强制的: {chromeMediaSource: '桌面',最小宽度:1280,最大宽度:1280,最小高度:720,最大高度:720}}},句柄流,句柄错误);返回;});};函数句柄错误(错误){console.log('出了点问题,但不应该');}函数句柄流(流){记录器 = 新媒体记录器(流);斑点 = [];recorder.ondataavailable = 函数(事件){blobs.push(event.data);};记录器.start();}函数 toArrayBuffer(blob, cb) {var fileReader = new FileReader();fileReader.onload = 函数() {var arrayBuffer = this.result;cb(数组缓冲区);};fileReader.readAsArrayBuffer(blob);}函数 toBuffer(ab) {var buffer = new Buffer(ab.byteLength);var arr = new Uint8Array(ab);for (var i = 0; i < arr.byteLength; i++) {缓冲区[i] = arr[i];}返回缓冲区;}功能停止记录(){记录器.stop();console.log(blob);//300k 字节toArrayBuffer(new Blob(blob, {type: 'video/webm'}), function(ab) {控制台.log(ab);//0 字节var 缓冲区 = toBuffer(ab);var 文件 = `./videos/example.webm`;fs.writeFile(文件,缓冲区,函数(错误){如果(错误){console.error('保存视频失败' + err);} 别的 {console.log('保存的视频:' + 文件);}});});}开始记录();设置超时(函数(){//7秒后停止录制停止录制();}, 7000);}})();

startRecord() 函数会立即执行,它也 console.log 在点击此控制器后按预期启动.

stopRecording() 函数在 7 秒后正确执行,它 console.log('Saved video: ' + file); 就好了.

然后我转到我刚刚创建的视频文件夹,打开我保存的 example.webm 文件,它是空的.

它不会在控制台中打印任何错误.

<小时>
  • 我在 stopRecording() 函数中停止记录器后 consoled.log(blob) 看看它是否真的是 Blob.
  • 我在 toArrayBuffer(new Blob(blob, {type: 'video/webm'}), function(ab) {}) 内的 console.log(ab)回调.

ab 不包含值时,我的行为是 blob 包含值.

<小时>

我自己真的解决不了,寻找答案我创建了demo repository 复制最少的示例,只需克隆它以查看您自己的行为

解决方案

您的 recorder.stop() 将按如下方式运行:(来自 MediaRecorder 文档)

<块引用>

当调用 stop() 方法时,UA 将运行以下步骤:

  1. 如果 MediaRecorder.state 为非活动",则引发 DOM InvalidState 错误并终止这些步骤.如果 MediaRecorder.state 不是非活动",则继续下一步.
  2. MediaRecorder.state 设置为非活动"并停止捕获媒体.
  3. 引发一个 dataavailable 事件,其中包含已收集的 Blob 数据.
  4. 引发 stop 事件.

在您的情况下,您无需等待 stop 事件,因此 dataavailable 仅在您启动文件保存方法后才会填充 blob.

您必须重组 stopRecording 以确保记录的数据可用.例如:

function stopRecording () {常量保存 = () =>{...}recorder.onstop = 保存记录器.stop()}

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.

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.

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

解决方案

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()
}

这篇关于将 desktopCapturer 从 Electron 应用程序保存到视频文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!