Skip to content

Migrating from fluent ffmpeg 1.x

Nicolas Joyard edited this page Jul 4, 2014 · 5 revisions

fluent-ffmpeg 2.0 is mostly compatible with previous versions, as all previous method names have been kept as aliases. The paragraphs below list new features and explain how to get around the few remaining incompatibilities.

New features

New constructor syntax

The fluent-ffmpeg constructor now supports multiple calling syntaxes. The 1.x syntax is still valid, though.

Passing an input file or stream to the constructor is optional, you can add input(s) later with the input() method (which is an alias for the legacy addInput() method).

var Ffmpeg = require('fluent-ffmpeg');
var command1 = new Ffmpeg().input('input1.avi').input('input2.avi');
var command2 = new Ffmpeg({ timeout: 30 }).input('input1.avi');
var command3 = new Ffmpeg({ timeout: 30 }).addInput('input1.avi');

Instead of passing the first input in the options object, you can now pass it as the first argument to the constructor.

var Ffmpeg = require('fluent-ffmpeg');
var command1 = new Ffmpeg('input.avi');
var command2 = new Ffmpeg('input.avi', { timeout: 30 });
var command3 = new Ffmpeg({ source: 'input.avi', timeout: 30 });

The fluent-ffmpeg constructor can also be called without the new operator.

var ffmpeg = require('fluent-ffmpeg');
var command1 = ffmpeg();
var command2 = ffmpeg('input.avi');
var command3 = ffmpeg({ source: 'input.avi', timeout: 30 });
var command4 = ffmpeg('input.avi', { timeout: 30 });

New method names

Most methods now have multiple aliases (including short ones). All method names from previous versions have been kept for compatibility. See the documentation for the complete list of available methods and their aliases.

// 1.x code
var Ffmpeg = require('fluent-ffmpeg');
new Ffmpeg({source:'file.avi'})
  .withSize('320x?')
  .usingPreset('flashvideo')
  .saveToFile('out.avi');

// 2.x code
var ffmpeg = require('fluent-ffmpeg');
ffmpeg('file.avi')
  .size('320x?')
  .preset('flashvideo')
  .save('out.avi');

Better input options handling

In previous versions, when using multiple inputs, you had no way of specifying which inputs the options applied to. From now on, every input-related method applies to the last input that was specified (including the one passed to the constructor, if any).

var ffmpeg = require('fluent-ffmpeg');
var command1 = ffmpeg('input1.avi')
  // Those apply to input1
  .fromFormat('avi') 
  .inputFps(24)
  
  .input('input2.mov')
  // Those apply to input2
  .fromFormat('mov') 
  .inputFps(30);

var command2 = ffmpeg()
  .input('input1.avi')
  // Those apply to input1
  .fromFormat('avi') 
  .inputFps(24)

  .input('input2.mov')
  // Those apply to input2
  .fromFormat('mov') 
  .inputFps(30);

var command3 = ffmpeg()
  // Throws an error, no input specified yet
  .inputFps(24);

Output streaming

When using nodejs v0.10 or later, passing a writable stream to the stream() method (an alias for writeToStream()) is now optional. When no stream has been passed, fluent-ffmpeg will create a PassThrough stream, have ffmpeg write its output to it and return it.

var ffmpeg = require('fluent-ffmpeg');
var outStream = require('fs').createWriteStream('out.avi');

// Passing a readable stream
ffmpeg('input.avi').stream(outStream);

// Not passing a readable stream
var stream = ffmpeg('input.avi').stream();
stream.pipe(outStream);

Multiple outputs

You can now set multiple outputs for a command with the output() method, and then call the run() method to start processing. The output() method accepts both filenames and writable streams, but at most one writable stream may be used with a single command.

All output options methods apply to the last output added, but for compatibility reasons, you may call those methods before specifying the first output, in which case they will apply to the first output.

Nearly all options methods are output-related, except for input-related methods, and the complexFilter() method which is global.

var outStream = fs.createWriteStream('videotrack.avi');

ffmpeg('input.avi')
  .output('audiotrack.mp3')

  // Apply to 'audiotrack.mp3'
  .noVideo() 
  .audioCodec('libmp3lame')

  // An optional pipe() options object can be passed here
  .output(outStream, { end: true })

  // Applies to outStream (videotrack.avi)
  .noAudio()
  .videoCodec('libx264')

  .on('end', function() { console.log('Finished processing'); })
  .run();

The save(), saveToFile(), stream(), writeToStream(), mergeToFile() and takeScreenshots() methods are actually shortcuts for calling output() and then run(). You should not use them when specifying outputs manually (as they call output(), you won't be able to set options on the last output).

Filter syntax

A new syntax is supported for audio and video filters. You can still pass them as filter strings, but you can now also pass filter specification objects.

A filter specification object contains the following keys:

  • filter: filter name
  • options (optional): filter options, either as a plain string, a string array (for multiple unnamed options) or an object (to specify options as key-value pairs).
  • inputs (optional): input stream(s) specification, either as a string or a string array. Each stream specification may or may not be enclosed in square brackets (fluent-ffmpeg will add them if not present).
  • outputs (optional): output stream(s) specification, either as a string or a string array. Each stream specification may or may not be enclosed in square brackets (fluent-ffmpeg will add them if not present).
var ffmpeg = require('fluent-ffmpeg');

ffmpeg()
  // Same as .audioFilters('volume=2')
  .audioFilters({
    filter: 'volume',
    options: '2'
  });
  .videoFilters([
    // Generates 'scale=320:200[scaled]'
    {
      filter: 'scale',
      options: [320, 200],
      outputs: 'scaled'
    },

    // Generates '[scaled]pad=w=iw*2:h=ih*2:color=black[padded]'
    {
      filter: 'pad',
      options: {
        w: 'iw*2',
        h: 'ih*2',
        color: 'black'
      },
      inputs: ['scaled'],
      outputs: 'padded'
    }
  ]);

Filters may be passed to the filter methods either as multiple arguments or as a single array argument.

Complex filters

fluent-ffmpeg now supports complex filtergraphs. The complexFilter() method expects an array of filter specifications (either as filter strings or filter specification objects) and an optional output stream list (or single stream name) as arguments.

Note that only one complex filtergraph may be set on a given command. Calling complexFilter() again will override any previously set filtergraph, but you can set as many filters as needed in a single call.

ffmpeg('video.avi')
  .complexFilter([
    // Duplicate video stream 3 times into streams a, b, and c
    {
      filter: 'split', options: '3',
      outputs: ['a', 'b', 'c']
    },

    // Create stream 'red' by removing green and blue channels from stream 'a'
    {
      filter: 'lutrgb', options: { g: 0, b: 0 },
      inputs: 'a', outputs: 'red'
    },

    // Create stream 'green' by removing red and blue channels from stream 'b'
    {
      filter: 'lutrgb', options: { r: 0, b: 0 },
      inputs: 'b', outputs: 'green'
    },

    // Create stream 'blue' by removing red and green channels from stream 'c'
    {
      filter: 'lutrgb', options: { r: 0, g: 0 },
      inputs: 'c', outputs: 'blue'
    },

    // Pad stream 'red' to 3x width, keeping the video on the left,
    // and name output 'padded'
    {
      filter: 'pad', options: { w: 'iw*3', h: 'ih' },
      inputs: 'red', outputs: 'padded'
    },

    // Overlay 'green' onto 'padded', moving it to the center,
    // and name output 'redgreen'
    {
      filter: 'overlay', options: { x: 'w', y: 0 },
      inputs: ['padded', 'green'], outputs: 'redgreen'
    },

    // Overlay 'blue' onto 'redgreen', moving it to the right
    {
      filter: 'overlay', options: { x: '2*w', y: 0 },
      inputs: ['redgreen', 'blue'], outputs: 'output'
    },
  ], 'output');

Command cloning

fluent-ffmpeg now enables cloning a command to run several transcoding operations with the same options.

var command = ffmpeg('/path/to/file.avi').withSomeOption(...);
var clone = command.clone();

Note: you should not use the clone() method when using an input stream, as both commands will fight to read input from it. Either one command will get the full input data and the other will get nothing, or both will get parts of the input.

Incompatible changes

Callbacks and event handling

Passing callback to the saveToFile(), writeToStream(), takeScreenshots() and mergeToFile() methods has been deprecated for some time now, and is now unsupported from version 2.0 onwards. You must use event handlers instead.

// 1.x code
command
  .saveToFile('/path/to/output.avi', function(err) {
    if (err) {
      console.log('An error occurred: ' + err.message);
    } else {
      console.log('Processing finished');
    }
  });

// 2.x code
command
  .on('error', function(err) {
    console.log('An error occurred: ' + err.message);
  })
  .on('end', function() {
    console.log('Processing finished');
  })
  .saveToFile('/path/to/output.avi');

The same goes for the onProgress and onCodecData methods.

// 1.x code
command
  .onProgress(function(progress) { ... })
  .onCodecData(function(data) { ... });

// 2.x code
command
  .on('progress', function(progress) { ... })
  .on('codecData', function(data) { ... };

Note that you should always set a handler for the error event. If an error happens without an error handler, nodejs will terminate your program.

See the events documentation for more information.

Metadata and Calculate submodules

Both the Metadata and Calculate submodules have been removed, as they were pretty unreliable.

The Calculate submodule has no replacement, as fluent-ffmpeg does not do size calculations anymore (we use ffmpeg filters instead).

The Metadata submodule is replaced by the ffprobe() method which is much more reliable. Have a look at its documentation for more information.

var ffmpeg = require('fluent-ffmpeg');

ffmpeg('/path/to/file.avi').ffprobe(function(err, data) {
  console.dir(data.streams);
  console.dir(data.format);
});

ffmpeg.ffprobe('/path/to/file.avi', function(err, data) {
  console.dir(data.streams);
  console.dir(data.format);
});

"-strict experimental" mode

The withStrictExperimental() method has been removed. As it is only useful when using experimental codecs, fluent-ffmpeg now automatically adds the correct ffmpeg option when they are used.

// 1.x code
command
  .withAudioCodec('aac')
  .withStrictExperimental();

// 2.x code
command.audioCodec('aac');