从 Electron 应用程序将 desktopCapturer 保存到视频文件
Saving desktopCapturer to video file from Electron app
基于 electron api and 我正在尝试将录制的用户屏幕保存到根应用程序文件夹中的视频文件夹中的 .webm 文件中。
实际上它几乎可以正常工作,因为它保存了 .webm 文件,但保存的文件是空的,它的重量为 0B。我不知道我在这里遗漏了什么。
所以看起来好像没有正确记录,因为文件是空的..
编辑 调试时我发现记录可能正常工作,因为我控制日志的 blob 在里面有价值,在 toArrayBuffer
之后我的 blob 不再有价值。
代码是:
(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()
函数立即执行,它也 console.log
在点击此控制器后按预期启动。
stopRecording()
函数在7秒后正确执行,console.log('Saved video: ' + file);
就好了。
然后我转到我刚刚创建的视频文件夹我打开我保存的 example.webm 文件,它是空的。
它不会在控制台中打印任何错误。
- 我
consoled.log(blobs)
在 stopRecording()
函数中停止记录器后查看它是否真的是 Blob。
- 我
console.log(ab)
在 toArrayBuffer(new Blob(blobs, {type: 'video/webm'}), function(ab) {})
回调中。
我的行为是 blobs
包含值,而 ab
不包含值。
我真的无法自己解决,寻找我创建的答案 demo repository 用最少的复制示例只需克隆它以查看您自己的行为
您的 recorder.stop()
将 运行 如下:(from MediaRecorder docs)
When the stop() method is invoked, the UA queues a task that runs the
following steps:
- 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.
- Set the
MediaRecorder.state
to "inactive" and stop capturing media.
- Raise a
dataavailable
event containing the Blob of data that has been gathered.
- Raise a
stop
event.
在您的情况下,您不会等待 stop
事件,因此 dataavailable
将仅在您启动文件保存方法后填充 blobs
。
您必须重组 stopRecording
以确保记录的数据可用。例如:
function stopRecording () {
const save = () => {
...
}
recorder.onstop = save
recorder.stop()
}
基于 electron api and
实际上它几乎可以正常工作,因为它保存了 .webm 文件,但保存的文件是空的,它的重量为 0B。我不知道我在这里遗漏了什么。
所以看起来好像没有正确记录,因为文件是空的..
编辑 调试时我发现记录可能正常工作,因为我控制日志的 blob 在里面有价值,在 toArrayBuffer
之后我的 blob 不再有价值。
代码是:
(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()
函数立即执行,它也 console.log
在点击此控制器后按预期启动。
stopRecording()
函数在7秒后正确执行,console.log('Saved video: ' + file);
就好了。
然后我转到我刚刚创建的视频文件夹我打开我保存的 example.webm 文件,它是空的。
它不会在控制台中打印任何错误。
- 我
consoled.log(blobs)
在stopRecording()
函数中停止记录器后查看它是否真的是 Blob。 - 我
console.log(ab)
在toArrayBuffer(new Blob(blobs, {type: 'video/webm'}), function(ab) {})
回调中。
我的行为是 blobs
包含值,而 ab
不包含值。
我真的无法自己解决,寻找我创建的答案 demo repository 用最少的复制示例只需克隆它以查看您自己的行为
您的 recorder.stop()
将 运行 如下:(from MediaRecorder docs)
When the stop() method is invoked, the UA queues a task that runs the following steps:
- If
MediaRecorder.state
is "inactive", raise a DOMInvalidState
error and terminate these steps. If theMediaRecorder.state
is not "inactive", continue on to the next step.- Set the
MediaRecorder.state
to "inactive" and stop capturing media.- Raise a
dataavailable
event containing the Blob of data that has been gathered.- Raise a
stop
event.
在您的情况下,您不会等待 stop
事件,因此 dataavailable
将仅在您启动文件保存方法后填充 blobs
。
您必须重组 stopRecording
以确保记录的数据可用。例如:
function stopRecording () {
const save = () => {
...
}
recorder.onstop = save
recorder.stop()
}