Write file to disk from blob in electron application
Asked Answered
C

2

11

I am creating an Electron Application in which I am recording data from webcam and desktop, at the end of the recording session, I want to save the data to a file in the background. I do not know how to write the data from a blob to a file directly. Any suggestions? Below is my current handling for MediaRecord Stop event.

this.mediaRecorder.onstop = (e) => {                                      
       var blob = new Blob(this.chunks,                                      
                           { 'type' : 'video/mp4; codecs=H.264' });                                                       
       var fs = require('fs');                                               
       var fr = new FileReader();                                            
       var data = null;                                                      
       fr.onload = () => {                                                   
           data = fr.result;                                                 
           fs.writeFile("test.mp4", data, err => {                           
               if(err) {                                                     
                   return console.log(err);                                  
               }                                                             
               console.log("The file was saved!");                           
           });                                                               
       };                                                                    
       fr.readAsArrayBuffer(blob);                                           
   }                          
Cicatrize answered 22/4, 2017 at 17:15 Comment(0)
S
16

You can do it using FileReader and Buffer.

In the renderer process, send the event to the main process to save the file with the buffer:

function saveBlob(blob) {
    let reader = new FileReader()
    reader.onload = function() {
        if (reader.readyState == 2) {
            var buffer = new Buffer(reader.result)
            ipcRenderer.send(SAVE_FILE, fileName, buffer)
            console.log(`Saving ${JSON.stringify({ fileName, size: blob.size })}`)
        }
    }
    reader.readAsArrayBuffer(blob)
}

Get back the confirmation:

ipcRenderer.on(SAVED_FILE, (event, path) => {
    console.log("Saved file " + path)
})

(SAVE_FILE and SAVED_FILE are static strings containing event name)

and in the main process:

ipcMain.on(SAVE_FILE, (event, path, buffer) => {
    outputFile(path, buffer, err => {
        if (err) {
            event.sender.send(ERROR, err.message)
        } else {
            event.sender.send(SAVED_FILE, path)
        }
    })
})

outputFile is from 'fs-extra'

Handling node operations in main process is preferred. See Electron Security suggestions.

If you do want to not use main process, you can use 'electron-remote' to create background processes to write the file. Additionally, you can invoke ffmpeg in the background process to compress/encode the file into different format.

Strength answered 25/4, 2017 at 14:17 Comment(6)
Sorry for coming to you a bit late. But haven't had time to try your solution until today. And it is working well, thank you. I only have one more issue in the output file. When I try to play it with any video player, it does not show the length of the video correctly, it shows only it has 1 sec of video, and even that the 1 second ends it keeps playing the video fully. but I can not forward, backward if the video, if you know what I mean.Cicatrize
Yes I have the same issue. I am not sure why it is this way. Someone familiar with codecs and their playback can explain it. I end up re-rendering it using ffmpeg to mp4 after which it shows it correctly.Strength
The duration issue is a problem with MediaRecorder. If you transcode using ffmpeg, it should correct itself.Constraint
Please, post the content for variables SAVE_FILE and SAVED_FILERetrenchment
@JetersonMirandaGomes those are arbitrary, you can designate whatever strings you want to use for event names in interprocess communication, see electronjs.org/docs/api/ipc-main for more infoContagion
Would a SharedArrayBuffer with a RingBuffer be useful to speed the process? Seen a ffmpeg worker stdin encoder at ffmpeg.js that uses such shared buffers between the WebPage and a Worker. Is it worth or possible to do it this way in Electron? Or even the same as that shared regular buffer?Incantatory
C
0
const buffer = Buffer.from(await blob.arrayBuffer())
require("fs").writeFile(
  'filename.ext', buffer, (err) => { 
     console.log(err ? err : 'file saved')
   })

If you are in the IpcMain of your electron application, this code will do the trick

Convolvulus answered 10/5, 2024 at 18:1 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.