fluent-ffmpeg / node-fluent-ffmpeg

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

Use ffmpeg as Transform? #689

Open pyldin601 opened 7 years ago

pyldin601 commented 7 years ago

ffmpeg can use Readable stream for input and Writable stream as output, but I can't see is it possible to use ffmpeg as Transform stream?

source.pipe(ffmpeg(options)).pipe(destination);
njoyard commented 7 years ago

You'd have to write some wrapper code for that. But as I recall, using both input and output streams with an external process in nodejs can lead to deadlocks.

sorokinvj commented 5 years ago

In case anyone needed I manage to use it with Transform streams (I need to encode audio to ogg and pass to Google Storage without saving locally). Here is my code:

const ffmpeg = require('fluent-ffmpeg')
const transformStream = require('stream')
const oggstream = new transformStream.Transform()

oggstream._transform = function (data, encoding, done) {
        this.push(data)
        done()
    }

// stream is any readableStream
const transcode = ffmpeg(stream).audioCodec('libopus').format('ogg').audioFilters('loudnorm').outputOptions(['-ar 16000', '-b:a 24000'])
                .on('error', function(err) {
                    console.log('an error happened: ' + err.message);
                })
                .on('end', function() {
                    console.log('file has been converted succesfully');
                })
                // save to stream
                .pipe(oggstream)

then you can consume oggstream again as any readable stream

MrOrz commented 8 months ago

To wrap fluent-ffmpeg as a Transform, basically we use a PassThrough for fluent-ffmpeg's input and output respectively, and the combine the two PassThrough as a Duplex, such that when the previous stream (input) writes to the Duplex it goes to ffmpeg's input, and when next stream (output) reads from the Duplex it actually takes data from ffmpeg's output.

Environment: NodeJS 18

const { pipeline, PassThrough, Duplex } = require('stream');
const fs = require('fs');
const ffmpeg = require('fluent-ffmpeg');

// Returns a Duplex stream whose input and output are connected (basically a Transform)
//
function getFfmpegTransform() {
  const input = new PassThrough();
  const output = new PassThrough();
  ffmpeg(input)
    .on('stderr', function(stderrLine) {
      console.log('Stderr output: ' + stderrLine);
    })
    // Stream input requires manually specifying input format
    .inputFormat('mp4')
    // Stream output requires manually specifying output format
    .format('mp4')
    // Stream output requires fragmented output
    // https://github.com/fluent-ffmpeg/node-fluent-ffmpeg/issues/346#issuecomment-67299526
    .outputOptions('-movflags dash')
    .pipe(output);

  return Duplex.from({
    // previous stream writes to input
    writable: input,
    // next stream reads from output
    readable: output,
  });
}

// Use getFfmpegTransform() as a Transform stream:
pipeline(
  fs.createReadStream('input.mp4'),
  getFfmpegTransform(),
  fs.createWriteStream('output.mp4'),
  console.log
);