fluent-ffmpeg / node-fluent-ffmpeg

A fluent API to FFMPEG (http://www.ffmpeg.org)
MIT License
7.62k stars 873 forks source link

How to reduce the size of video file as a buffer or blob before writing it on Nodejs? #1196

Open hypo-thesis opened 1 year ago

hypo-thesis commented 1 year ago

I send live feed from client to the server using websocket from the client side like this :

    recorder = new MediaRecorder(canvasStream, {
        mimeType: 'video/webm;codecs=vp9',
        videoBitsPerSecond: 3 * 1024 * 1024
    });
    recorder.ondataavailable = async (e) => {
        const arbuf = await e.data.arrayBuffer()
        ws.send(pack({ type: 'REC', data: arbuf })) //sends to server
    }

and on the server side I get them like this :

 let blob = new Blob(chunks, { type: 'video/mp4' })
      const buffer = Buffer.from(await blob.arrayBuffer());
      fs.writeFile("foo.mp4", buffer, () => console.log('video saved!'));

However foo.mp4 is really large. Please help me find a way to reduce the size of foo.mp4 as it is being written down to the disc. ( I can reduce it after it is written, however that won't do the trick for me. It has to be encoded and compressed before it is written )

soyniqolas-meli commented 1 year ago

FFMPEG can receive a readableSteam as input. Try to use Blob.stream() as input parameter.

Example:

let blob = new Blob(chunks, { type: 'video/mp4' });
const command = ffmpeg()
    .input(blob.stream())
    .audioCodec('libfaac')
    .videoCodec('libx264')
    .output('/path/to/destination.mp4')
soyniqolas-meli commented 1 year ago

BTW: This creates a transcoding process, which is CPU intensive.

hypo-thesis commented 1 year ago

I am reopening this issue since I am getting :

ERROR Error: Invalid input
    at proto.mergeAdd.proto.addInput.proto.input (/www/wwwroot/english.uk.ms/api/node_modules/fluent-ffmpeg/lib/options/inputs.js:34:15)

My code is :

let blob = new Blob(chunks, options);
        try {

        ffmpeg().input(blob.stream()).videoCodec('libx264').audioCodec('aac').format('mp4').outputOptions([
            "-preset",
            "veryfast",
            "-crf",
            "30",
            "-max_muxing_queue_size",
            "9999",
            "-threads 5"
          ]).on('end', () => {
            console.log(`done`)
          }).on('codecData', function (data) {
            console.log('Input is ' + data.audio + ' audio ' +
              'with ' + data.video + ' video');
          })
            .on('error', (err, stdout, stderr) => {
              if (err) {
                console.log(err.message);
                console.log("stdout:\n" + stdout);
                console.log("stderr:\n" + stderr);
              }
            }).save(`./videos/1.mp4`);
soyniqolas commented 1 year ago

Use ffmpeg(blob.stream()) instead of ffmpeg().input(blob.stream())

QC2168 commented 2 months ago

It not working? source is blob type

FfmpegCommand(source.stream())
    .addOutputOptions('-movflags +frag_keyframe+separate_moof+omit_tfhd_offset+empty_moov')
    .format('mp4').on('error', function (err:any) {
        console.log('An error occurred: ' + err.message);
    })
    .on('end', function () {
        console.log('Merging finished !');
        resolve(true)
    })
    .save(targetPath) 

// An error occurred: ffmpeg exited with code 1: Output #0, mp4, to 'E:\2024-04-19-14-05-55.mp4':
// Output file #0 does not contain any stream