Saving DesktopCapturer to file in Electron since Buffer() deprecated - javascript

Hello I have already read and attempted the thread: Saving desktopCapturer to video file in Electron
This is what I have so far:
const { desktopCapturer } = require('electron')
var fs = require('fs');
function startRecording(){
desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
for (const source of sources) {
if (source.name === 'Entire Screen') {
try {
const stream = await navigator.mediaDevices.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: source.id,
minWidth: 1280,
maxWidth: 1280,
minHeight: 720,
maxHeight: 720
}
}
})
handleStream(stream)
} catch (e) {
handleError(e)
}
return
}
}})
}
function handleStream(stream) {
recorder = new MediaRecorder(stream);
blobs = [];
recorder.ondataavailable = function(event) {
blobs.push(event.data);
};
recorder.start();
}
function stopRecording() {
recorder.stop();
console.log(blobs);
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) {
let buffer = Buffer.alloc(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 just want to save the recorded video to a file.
The file ends up being empty when it saves. I have been stuck at this awhile and would appreciate any advice. Thank you

Welp I stumbled upon this thread: Saving desktopCapturer to video file from Electron app
and changed my stopRecording() function to :
function stopRecording() {
const save = () =>{
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);
}
});
});
}
recorder.onstop = save;
recorder.stop();
}
and it seems to be working. Cool!

Related

Merging data:application/octet-stream;base64 video chunks into a file

I have an upload button on my page which user can click to upload a video. If video is large, Javascript's File Reader can't handle it. So I've implemented a function that slices uploaded video into chunks with 'data:application/octet-stream;base64,' label at the beginning. Meanwhile the function sends each chunk to the NodeJS backend, where I use some 'fs' approaches to merge the video file back and save it as an mp4 file on my disc. The problem is that the file is 'empty'. It's recognized by my PC as an mp4 file, there is no error of wrong file format. But the video has no content and it's 0 seconds long. How can I merge chunks properly to make the mp4 file work?
Frontend:
let reader;
let file;
const slice_size = 1024;
const start_chunks_upload = (e) => {
event.preventDefault();
reader = new FileReader();
file = e.target.files[0];
upload_file_chunks(0);
}
const upload_file_chunks = (start) => {
const next_slice = start + slice_size + 1;
const blob = file.slice(start, next_slice);
reader.onloadend = (e) => {
if (e.target.readyState !== FileReader.DONE) {
return;
}
$.ajax({
type: 'POST',
url: 'http://localhost:5000/video',
data: {
video: e.target.result.replace('data:application/octet-stream;base64,', ''),
is_done: next_slice < file.size ? null : true,
},
success: function(data) {
const size_done = start + slice_size;
const percent_done = Math.floor((size_done / file.size) * 100);
console.log(percent_done + '%');
if (next_slice < file.size) {
upload_file_chunks(next_slice);
} else {
console.log('done');
}
}
});
};
reader.readAsDataURL(blob);
}
video_upload_button.addEventListener('change', (e) => start_chunks_upload(e));
Backend:
let string = '';
app.post('/video', (req, res) => {
string += req.body.video;
if (req.body.is_done) {
let buff = new Buffer.from(string, 'base64');
fs.writeFileSync('/one.mp4', buff);
fs.writeFile("/two.mp4", string, 'base64', function(err) {
console.log(err);
});
fs.appendFile('/log.txt', string, function (err) {
if (err) {
console.log(err);
}
})
} else {
return res.json({ok: 1,});
}
})

Chrome extension video recording blob not able to convert in to video file

I am creating a chrome extension to record screen, facing an issue in converting the video recording blob into a video file, in background js video is getting recorded correctly but in content.js not able to convert the video blob to a video file
I am creating a chrome extension to record screen, facing an issue in converting the video recording blob into a video file, in background js video is getting recorded correctly but in content.js not able to convert the video blob to a video file
function startRecording() {
var constraints = {
audio: true,
video: true,
maxframeRate: fps,
};
navigator.mediaDevices.getDisplayMedia(constraints).then(function (stream) {
let output = new MediaStream();
if (output.getAudioTracks().length == 0) {
// Get microphone audio (system audio is unreliable & doesn't work on Mac)
if (micable) {
micsource.connect(destination);
output.addTrack(destination.stream.getAudioTracks()[0]);
}
} else {
syssource = audioCtx.createMediaStreamSource(stream);
if (micable) {
micsource.connect(destination);
}
syssource.connect(destination);
output.addTrack(destination.stream.getAudioTracks()[0]);
}
output.addTrack(stream.getVideoTracks()[0]);
mediaConstraints = {
audio: true,
video: true,
mimeType: "video/webm;codecs=vp8,opus",
};
mediaRecorder = new MediaRecorder(stream, mediaConstraints);
mediaRecorder.start(1000);
var recordedBlobs = [];
let writer = "";
mediaRecorder.ondataavailable = (event) => {
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
}
console.log("recordedBlobs", recordedBlobs);
};
mediaRecorder.onstop = () => {
chrome.tabs.getSelected(null, (tab) => {
chrome.tabs.sendMessage(tab.id, {
message: "download-video",
obj: {
blobs: recordedBlobs,
},
// camerasize: camerasize
});
});
endRecording(stream, writer, recordedBlobs);
};
stream.getVideoTracks()[0].onended = function () {
cancel = false;
mediaRecorder.stop();
};
});
}
content.js
function convertVideoBlobToVideo(obj) {
let chunk = obj.blobs;
// mediaRecorder.onstop = () => {
var superBuffer;
superBuffer = new Blob(chunks, {
type: "video/webm",
});
chunks = [];
// Create a video or audio element
// that stores the recorded media
const recordedMedia = document.createElement("video");
recordedMedia.controls = true;
const recordedMediaURL = URL.createObjectURL(superBuffer);
recordedMedia.src = recordedMediaURL;
const downloadButton = document.createElement("a");
downloadButton.download = "Recorded-Media";
downloadButton.href = recordedMediaURL;
downloadButton.innerText = "Download it!";
downloadButton.onclick = () => {
URL.revokeObjectURL(recordedMedia);
};
document.body.appendChild(recordedMedia, downloadButton);
// };
}

How to upload video recorded with MediaRecorder API using PHP?

I am working on a video recording task using MediaRecorder API. As from frontend I can start the webcam, record video, play the recorded video and download the video.
But when I try to upload the video to php server, it's not at all working. I don't really understand why it is happening, I also tried using so many methods but none of it is working. Please check the code attatched below.
JS:-
let mediaRecorder
let recordedBlobs
const errorMsgElement = document.querySelector('span#errorMsg');
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
const playButton = document.querySelector('button#play');
const downloadButton = document.querySelector('button#download');
document.querySelector("button#start").addEventListener("click", async function() {
const hasEchoCancellation = document.querySelector("#echoCancellation").checked
const constraints = {
audio: {
echoCancellation:{
exact: hasEchoCancellation
}
},
video: {
width: 1280,
height: 720
}
}
await init(constraints)
})
async function init(constraints) {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints)
handleSuccess(stream)
} catch(e) {
console.log(e)
}
}
function handleSuccess(stream) {
recordButton.disabled = false
window.stream = stream
const gumVideo = document.querySelector("video#gum")
gumVideo.srcObject = stream
}
recordButton.addEventListener("click", () => {
if(recordButton.textContent === "Record") {
startRecording()
} else {
stopRecording()
recordButton.textContent = 'Record'
playButton.disabled = false
downloadButton.disabled = false
}
})
function startRecording() {
recordedBlobs = []
let options = {
mimeType: "video/webm;codecs=vp9,opus"
}
try {
mediaRecorder = new MediaRecorder(window.stream, options)
} catch(e) {
console.log(e)
}
recordButton.textContent = "Stop Recording"
playButton.disabled = true
downloadButton.disabled = true
mediaRecorder.onstop = (event) => {
console.log('Recording Stopped')
}
mediaRecorder.ondataavailable = handleDataAvailable
mediaRecorder.start()
}
function handleDataAvailable(event) {
if(event.data && event.data.size > 0) {
recordedBlobs.push(event.data)
}
}
function stopRecording() {
mediaRecorder.stop()
}
playButton.addEventListener('click', function() {
const superBuffer = new Blob(recordedBlobs, {
type: 'video/webm'
})
var file = new File([superBuffer], 'test.webm')
var url = window.URL.createObjectURL(superBuffer)
// var video = blobToFile(superBuffer, 'test.webm')
sendToServer(file)
recordedVideo.src = null
recordedVideo.srcObject = null
recordedVideo.src = url
recordedVideo.controls = true
recordedVideo.play()
})
downloadButton.addEventListener('click', () => {
const blob = new Blob(recordedBlobs, {type: 'video/mp4'});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'test.mp4';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 100);
});
function sendToServer(file) {
let url = 'send.php'
let headers = {
'Content-Type': 'multipart/form-data'
}
var formData = new FormData()
formData.append("file", file)
axios.post(url, formData, headers)
.then((response) => {
console.log(response.data)
})
.catch((error) => {
console.log(error.response)
})
}
function blobToFile(theBlob, fileName){
//A Blob() is almost a File() - it's just missing the two properties below which we will add
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
}
PHP:-
$target_dir = "uploads/";
$target_file = $target_dir . 'test.webm';
if(move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
echo "File uploaded successfully";
} else {
echo "File not uploaded";
}
print_r($_FILES['file']['error']);
No matter how much I tried, I can't figure out why it is not working. It is showing that "File not uploaded" like it can't read the file from tmp_name. Please help me fix the problem.
Any help on this problem will be really appreciated.
Thank you.

How to add mimetype (video/webm) and codec (vp9) to the blob object before sending to server

Am recording video using webrtc and send each 10 seconds video as blob to server, and all 10 seconds files are getting saved on server, till now everything is fine but only problem is only first video file is getting played as video rest other files are not getting played since it is missing codec and MIMEType. please help me how to send each 10 seconds blob with mimetype and wit codec vp9
// This code is adapted from
// https://rawgit.com/Miguelao/demos/master/mediarecorder.html
'use strict';
/* globals MediaRecorder */
const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', handleSourceOpen, false);
let mediaRecorder;
let recordedBlobs;
let sourceBuffer;
const errorMsgElement = document.querySelector('span#errorMsg');
const recordedVideo = document.querySelector('video#recorded');
const recordButton = document.querySelector('button#record');
recordButton.addEventListener('click', () => {
if (recordButton.textContent === 'Start Recording') {
startRecording();
} else {
stopRecording();
recordButton.textContent = 'Start Recording';
playButton.disabled = false;
downloadButton.disabled = false;
}
});
const playButton = document.querySelector('button#play');
playButton.addEventListener('click', () => {
const superBuffer = new Blob(recordedBlobs, {type: 'video/webm'});
recordedVideo.src = null;
recordedVideo.srcObject = null;
recordedVideo.src = window.URL.createObjectURL(superBuffer);
recordedVideo.controls = true;
recordedVideo.play();
console.log('start- display recordedblob');
console.log(recordedVideo);
console.log('end- display recordedblob');
});
const downloadButton = document.querySelector('button#download');
downloadButton.addEventListener('click', () => {
const blob = new Blob(recordedBlobs, {type: 'video/webm'});
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = 'test.webm';
document.body.appendChild(a);
a.click();
setTimeout(() => {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 100);
});
function handleSourceOpen(event) {
console.log('MediaSource opened');
sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vp8"');
console.log('Source buffer: ', sourceBuffer);
}
function handleDataAvailable(event) {
console.log('handleDataAvailable', event);
console.log('shree sai baba', event.data);
if (event.data && event.data.size > 0) {
recordedBlobs.push(event.data);
console.log('heyy'+recordedBlobs);
// to save video as each blob
var formData = new FormData();
formData.append('video', event.data);
console.log('result blob which am trying to send to server', event.data);
// Execute the ajax request, in this case we have a very simple PHP script
// that accepts and save the uploaded "video" file
xhr('/webcam/', formData, function (fName) {
console.log("video successfully uploaded !");
});
// Helper function to send
function xhr(url, data, callback) {
var request = new XMLHttpRequest();
request.onreadystatechange = function () {
if (request.readyState == 4 && request.status == 200) {
callback(location.href + request.responseText);
}
};
request.open('POST', url);
request.send(data);
console.log(data);
console.log('logg')
console.log(request.response);
}
console.log('10 seconds video sent to the server');
// end of save video as each
}
}
function startRecording() {
recordedBlobs = [];
let options = {mimeType: 'video/webm;codecs=vp9'};
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = {mimeType: 'video/webm;codecs=vp8'};
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = {mimeType: 'video/webm'};
if (!MediaRecorder.isTypeSupported(options.mimeType)) {
console.error(`${options.mimeType} is not Supported`);
errorMsgElement.innerHTML = `${options.mimeType} is not Supported`;
options = {mimeType: ''};
}
}
}
try {
mediaRecorder = new MediaRecorder(window.stream, options);
} catch (e) {
console.error('Exception while creating MediaRecorder:', e);
errorMsgElement.innerHTML = `Exception while creating MediaRecorder: ${JSON.stringify(e)}`;
return;
}
console.log('Created MediaRecorder', mediaRecorder, 'with options', options);
recordButton.textContent = 'Stop Recording';
playButton.disabled = true;
downloadButton.disabled = true;
mediaRecorder.onstop = (event) => {
console.log('Recorder stopped: ', event);
console.log('naduuuuuuuuuuuuuuuuuuuuzz');
console.log('Recorded Blobss: ', recordedBlobs);
console.log('ans', recordedBlobs);
// console.log(Blob.arrayBuffer())
console.log('Recorded Blobss: ', recordedBlobs.type);
console.log('naduuuuuuuuuuuuuuuuuuuu');
};
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start(10000); // collect 10s of data
console.log('MediaRecorder started', mediaRecorder);
}
function stopRecording() {
mediaRecorder.stop();
}
function handleSuccess(stream) {
recordButton.disabled = false;
console.log('getUserMedia() got stream:', stream);
window.stream = stream;
const gumVideo = document.querySelector('video#gum');
gumVideo.srcObject = stream;
}
async function init(constraints) {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handleSuccess(stream);
} catch (e) {
console.error('navigator.getUserMedia error:', e);
errorMsgElement.innerHTML = `navigator.getUserMedia error:${e.toString()}`;
}
}
document.querySelector('button#start').addEventListener('click', async () => {
const hasEchoCancellation = document.querySelector('#echoCancellation').checked;
const constraints = {
audio: {
echoCancellation: {exact: hasEchoCancellation}
},
video: {
width: 720, height: 480
}
};
console.log('Using media constraints:', constraints);
await init(constraints);
});
request.setRequestHeader('Content-Type', 'video/webm');

Recorded video can't be forwarded/backwarded, Using MediaRecorder API chrome extension

I am implementing a chrome extension which records the screen with microphone and after recording it generates the recorded video perfectly but the problem is that the recorded video can not be forwarded/ backwarded or start video from any point first time.
When it plays the first time after that it works perfectly but when I download this video then the problem is same. I take help from muaz khan plugin.
I am using this code for start recording:
function gotStream(stream) {
if (cameraStream && cameraStream.getAudioTracks().length) {
cameraStream.getAudioTracks().forEach(function(track) {
// cameraStream.removeTrack(track);
stream.addTrack(track);
});
}
if (typeof MediaRecorder.isTypeSupported == 'function') {
/*
MediaRecorder.isTypeSupported is a function announced in https://developers.google.com/web/updates/2016/01/mediarecorder and later introduced in the MediaRecorder API spec http://www.w3.org/TR/mediastream-recording/
*/
if (MediaRecorder.isTypeSupported('video/mp4;codecs=h264')) {
var options = {
type: 'video',
mimeType: 'video/mp4;codecs=h264'
};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
var options = {
type: 'video',
mimeType: 'video/webm;codecs=vp9'
};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
var options = {
mimeType: 'video/webm;codecs=vp8'
};
}
console.log('Using ' + options.mimeType);
recorder = new RecordRTC(stream, options);
} else {
console.log('Using default codecs for browser');
recorder = new MediaRecorder(stream);
}
recorder.streams = [stream];
recorder.start(10);
recorder.ondataavailable = function(e) {
chunks.push(e.data);
};
recorder.onerror = function(e) {
console.log('Error: ', e);
};
recorder.onstart = function() {
isRecording = true;
onRecording();
console.log('Started & state = ' + recorder.state);
};
recorder.onpause = function() {
console.log('Paused & state = ' + recorder.state);
}
recorder.onresume = function() {
console.log('Resumed & state = ' + recorder.state);
}
recorder.onwarning = function(e) {
console.log('Warning: ' + e);
};
recorder.onstop = function() {
stopScreenRecording();
}
stream.onended = function() {
if (stream) {
stream.onended = null;
}
recorder.stop();
};
if (stream.getVideoTracks().length) {
stream.getVideoTracks().forEach(function(track) {
track.onended = function() {
if (!recorder) return;
if (!stream || typeof stream.onended !== 'function') return;
stream.onended();
};
});
}
}
and this for stop recording:
function stopScreenRecording(blob) {
isRecording = false;
var blob = new Blob(chunks, {
type: "video/mp4"
});
chunks = [];
var file = new File([blob ? blob : ''], getFileName(fileExtension), {
type: mimeType
});
DiskStorage.Store({
key: 'latest-file',
value: file
}, function(success) {
if (success) {
chrome.browserAction.setPopup({
popup: "popup.html"
});
chrome.tabs.create({
url: 'preview.html'
});
}
});
setTimeout(function() {
setDefaults();
// chrome.runtime.reload();
}, 1000);
try {
videoPlayers.forEach(function(player) {
player.src = null;
});
videoPlayers = [];
} catch (e) {}
// for dropdown.js
chrome.storage.sync.set({
isRecording: 'false' // FALSE
});
if (timer) {
clearTimeout(timer);
}
setBadgeText('');
}
I saw another screen recorder whose video blob is like:
filesystem:chrome-extension://mmeijimgabbpbgpdklnllpncmdofkcpn/persistent/e6ad7ba1-6afe-4d45-y6f5-47e08a87e036.webm
and our video blob is like:
blob:chrome-extension://hgpenkfjeddjngnojmcmgbclkoakihhg/af3dcfa6-b990-464b-9726-e8b6022762a2
How can I get this type of blob?

Categories

Resources