Can you call out to FFMPEG in a Firebase Cloud Function

17,276

Solution 1

Update: ffmpeg is now preinstalled in the Cloud Functions environment. For a complete list of preinstalled packages, check out https://cloud.google.com/functions/docs/reference/system-packages.

Note: you only have disk write access at /tmp/.

Option 1: use ffmpeg-fluent npm module

This module abstracts the ffmpeg command line options with an easy to use Node.js module.

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

let cmd = ffmpeg('example.mp4')
    .clone()
    .size('300x300')
    .save('/tmp/smaller-file.mp4')
    .on('end', () => {
      // Finished processing the video.
      console.log('Done');

      // E.g. return the resized video:
      res.sendFile('/tmp/smaller-file.mp4');
    });

Full code on GitHub

Option 2: invoke the ffmpeg binary directly

Because ffmpeg is already installed, you can invoke the binary and its command line options via a shell process.

const { exec } = require("child_process");

exec("ffmpeg -i example.mp4", (error, stdout, stderr) => {
  //ffmpeg logs to stderr, but typically output is in stdout.
  console.log(stderr);
});

Full code on GitHub

Option 3: upload your own binary

If you need a specific version of ffmpeg, you can include an ffmpeg binary as part of the upload and then run a shell command using something like child_process.exec. You'll need an ffmpeg binary that's compiled for the target platform (Ubuntu).

File listing with pre-compiled ffmpeg binary

./
../
index.js
ffmpeg

index.js

const { exec } = require("child_process");

exec("ffmpeg -i example.mp4", (error, stdout, stderr) => {
  //ffmpeg logs to stderr, but typically output is in stdout.
  console.log(stderr);
});

I've included two full working examples on GitHub. The examples are for Google Cloud Functions (not specifically Cloud Functions for Firebase).

Solution 2

While you technically can run FFMPEG on a Firebase Functions instance, you will quickly hit the small quota limits.

As per this answer, you can instead use Functions to trigger a request to GCP's more powerful App Engine or Compute Engine services. The App Engine process can grab the file from the same bucket, handle the transcoding, and upload the finished file back to the bucket. If you check the other answers at the link, one user posted a sample repo that does just that.

Solution 3

ffmpeg is now included in the Cloud Functions environment so it can be used directly:

spawn(
  'ffmpeg',
  ['-i', 'video.mp4'] 
)

Full list of installed packages: https://cloud.google.com/functions/docs/reference/nodejs-system-packages

Solution 4

Use the lib https://github.com/eugeneware/ffmpeg-static

const ffmpeg = require('fluent-ffmpeg');
const ffmpeg_static = require('ffmpeg-static');


let cmd = ffmpeg.('filePath.mp4')
   .setFfmpegPath(ffmpeg_static.path)
   .setInputFormat('mp4')
   .output('outputPath.mp4')
   ...
   ...
   .run()

Solution 5

Practically, no. FFMPEG processes audio/video files which typically exceed the Cloud Functions quotas (10MB uploads).

You would need to run Node.js on GCP's AppEngine.

Share:
17,276
Dave Parks
Author by

Dave Parks

Updated on June 03, 2022

Comments

  • Dave Parks
    Dave Parks about 2 years

    Per the Firebase Cloud Functions documentation, you can leverage ImageMagick from within a cloud function: https://firebase.google.com/docs/functions/use-cases

    Is it possible do something similar but call out to FFMPEG instead of ImageMagick? While thumbnailing images is great, I'd also like the capability to append incoming images to a video file stored out on Firebase Storage.

  • Omar HossamEldin
    Omar HossamEldin over 6 years
    How do I refer to a file in cloud firebase function, I mean what is the path to write in the FFMPEG command to refer to a file in firebase storage?
  • Henry
    Henry over 6 years
  • Bret McGowen
    Bret McGowen about 6 years
    @OmarHossamEldin everything you upload as part of your function is stored in the /user_code/ directory on the server.
  • Peza
    Peza about 6 years
    This was a life saver - thank you!! It was such a help having the refs the Github pages. Just a side note though, I am using fluent-ffmpeg npm package, and needed to add the ffmpeg path to the binary in the Docker file as an ENV variable: ENV PATH="/usr/src/app/node_modules/ffmpeg-static/bin/linux/x64:‌​${PATH}"
  • Igniter
    Igniter over 4 years
    Thanks, just wondering if you've seen any repos with code templates that you could build upon for such tasks? Specifically how you would trigger the workflow in GAE?
  • Vojtěch
    Vojtěch about 4 years
    Note that current version of ffmpeg-static is returns directly the path, so you need to call .setFfmpegPath(ffmpeg_static) directly, without the .path
  • Vojtěch
    Vojtěch about 4 years
    Note that current version of ffmpeg-static is returns directly the path, so you need to call .setFfmpegPath(ffmpeg_static) directly, without the .path
  • wabisabit
    wabisabit almost 4 years
    ffmpeg is now included in the Cloud Functions environment
  • danday74
    danday74 over 2 years
    This answer lacks detail. ffmpeg-static is great. You just add it as a dependency and it auto installs a suitable version of ffmpeg when someone (or the system) does an npm install. You can get the path to the ffmpeg bin with ... const pathToFfmpeg = require('ffmpeg-static') ... and then use that path when executing commands with, for example, Node's execSync function - however, I'm not sure how well it will work on a Cloud Runtime environment and the quotas issue is likely to still be a problem - best stick to using AppEngine - but +1 for a good idea
  • danday74
    danday74 over 2 years
    the version on the runtime environment was too old, it didn't even support the var_stream_map flag - I moved the heavy lifting to App Engine
  • danday74
    danday74 over 2 years
    you use functions to trigger the workflow and they make requests to GAE to do the heavy lifting - and similarly when the heavy lifting is done - GAE can make requests to HTTP functions - or use PubSub for comms since functions also can handle PubSub