Node-fluent-ffmpeg: Promises, Promises

Created on 17 May 2017  路  4Comments  路  Source: fluent-ffmpeg/node-fluent-ffmpeg

I searched the issues for any mention of promises and couldn't find any. Are there any plans to add support for returning promises?

In the meantime, I've managed to achieve this using bluebird:

ffprobe

const Promise = require('bluebird')
const ffprobe   = Promise.promisify(require('fluent-ffmpeg').ffprobe)

ffprobe(path)
.then(  (metadata) => { ... } )
.catch( (error)    => { ... } )

run

const Promise = require('bluebird')
const ffmpeg  = require('fluent-ffmpeg')

function promisifyCommand (command) {
    return Promise.promisify( (cb) => {
        command
        .on( 'end',   ()      => { cb(null)  } )
        .on( 'error', (error) => { cb(error) } )
        .run()
    })
}

let command = ffmpeg().input(...).output(...)
command = promisifyCommand(command)
command()
.then(  ()      => { ... } )
.catch( (error) => { ... } )

Hopefully this will help the next person who comes looking.

Most helpful comment

a more simple/complete example that seems to work for me, with await/async as well.

  new Promise((resolve, reject) => {
    ffmpeg('...')
      .on('progress', (progress) => {
        log.verbose(`[ffmpeg] ${JSON.stringify(progress)}`);
      })
      .on('error', (err) => {
        log.info(`[ffmpeg] error: ${err.message}`);
        reject(err);
      })
      .on('end', () => {
        log.verbose('[ffmpeg] finished');
        resolve();
      })
      .save('...');
  });

All 4 comments

I personally have no plans to add support for promises. There are already a bunch of libs that allow doing that, and if you can do it in ~4 lines of code there's no point in including it in fluent-ffmpeg. Using simple callbacks allows anyone to plug what they want on it :)

Sorry to reopen, but I was just forced into making a significant improvement to my implementation to support the screenshots() method, and want to include it here for others to save them the time it took me to figure it out:

function promisifyCommand (command, run='run') {
    return Promise.promisify( (...args) => {
        const cb = args.pop()        
        command
        .on( 'end',   ()      => { cb(null)  } )
        .on( 'error', (error) => { cb(error) } )[run](...args)
    })
}

Used like this:

run

const command = ffmpeg().input( '...' ).output( '....mp4' ).outputFormat('mp4')
                        .audioBitrate('128k').audioChannels(2).audioCodec('aac')
                        .videoCodec('libx264').size('640x360').autopad().outputOptions('-crf 22')
                        .outputOptions('-movflags +faststart')

promisifyCommand(command)()
.then(  ()      => { ... } )
.catch( (error) => { ... } )

screenshots

promisifyCommand( ffmpeg().input( '...' ), 'screenshots' )({
            folder:   '...',
            filename: 'prefix.%i.png',
            count:    10,
            size:     '640x360',
        })
.then(  ()      => { ... } )
.catch( (error) => { ... } )

a more simple/complete example that seems to work for me, with await/async as well.

  new Promise((resolve, reject) => {
    ffmpeg('...')
      .on('progress', (progress) => {
        log.verbose(`[ffmpeg] ${JSON.stringify(progress)}`);
      })
      .on('error', (err) => {
        log.info(`[ffmpeg] error: ${err.message}`);
        reject(err);
      })
      .on('end', () => {
        log.verbose('[ffmpeg] finished');
        resolve();
      })
      .save('...');
  });

You can't expect a library to not have a promise interface in 2021 :)

Was this page helpful?
0 / 5 - 0 ratings