fluent-ffmpeg / node-fluent-ffmpeg

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

How to install fluent-ffmpeg in AWS Lamdba? #1069

Open ipr0310 opened 4 years ago

ipr0310 commented 4 years ago

Version information

Code to reproduce

Hi, can you help how did you set up the library in the lambda function correctly?

Because i already set up the:

-Serverless file with it's layer -Uploaded the binaries to the lambda function as a layer -Already set up the FFPROBE_PATH AND FFMPEG_PATH from the lambda function

Also the weird thing is that: the lambda function just finish working, like sending a response. image

I mean also if you could show me step by step how did you installed it in a lambda function?

1- This is from the lambda console image

image

2- My json dependencies

 "dependencies": {
    "aws-sdk": "^2.764.0",
    "aws-serverless-express": "^3.3.8",
    "fluent-ffmpeg": "^2.1.2",
    "lambduh-execute": "^1.3.0"
  }

3- My serverless file

`service: functionName

provider:
  name: aws
  runtime: nodejs12.x
  memorySize: 3008
  timeout: 300
  stage: live
  region: us-east-1
  environment:
    FFMPEG_PATH: /opt/ffmpeg/ffmpeg
    FFPROBE_PATH: /opt/ffmpeg/ffprobe

functions:
  api:
    handler: lambda.handler
    events:
      - s3: ${self:custom.bucket}
    layers:
      - { Ref: FfmpegLambdaLayer }

layers:
  ffmpeg:
    path: layer

custom:
  bucket: buckename

4- The directory of the layer

image

5- Javascript file


const fs = require("fs");
const AWS = require("aws-sdk");
const ffmpeg = require("fluent-ffmpeg");
const s3 = new AWS.S3();

exports.handler = async (event, context, callback) => {

ffmpeg({
        source: `**Object file which i already verified it exists**`,
        nolog: true,
      })
        .on("filenames", async (filenames) => {
          console.log("Uploading please wait");
        })
        .on("error", function (err) {
          console.log("Error in filenames section: " + JSON.stringify(err));
        })
        .on("end", function () {
          console.log("Screenshots taken");
        })
        .screenshots({
          count: 10,
          folder: "tmp/",
          filename: "thumbnail-at-%i.png",
          size: "1600x900",
        })
        .on("end", function (stdout, stderr) {
          let destparams = {
            Bucket: dstBucket,
            Key: imageGotoUrl,
            Body: buffer,
            ContentType: "image",
          };

        })
        .on("error", function (err) {
          console.log("Error writing video to disk: " + JSON.stringify(err));
          throw "An error: " + err.message;
        });

};

Expected results

The dependecy must work as expected in a AWS lambda function.

Observed results

Lambda function just finish it's job without showing any log (Error) messages In the cloudwatch console it just show the log that lambda finished de function succesfully (Not the expected from the dependency)

I already used this dependecy locally, and it works! but in LAMBDA it is too hard

Checklist

lafiosca commented 3 years ago

I know nothing about using this ffmpeg library, but I use Lambda frequently. It appears that ffmpeg is event/stream based, so it appears to me that your code is executing an asynchronous function and immediately returning.

There are two ways to structure the execution of a Lambda. One is by having the function return a promise which resolves on success or rejects on failure. The other is by having the function return void and using an explicit callback when the execution is over. Your code is using the first approach because your function is declared async. Even though you don't have a return statement, your function is returning Promise<void> because of the async declaration. The Lambda service interprets this as a successful return and terminates, whether the ffmpeg logic has completed yet or not.

If you're using an async function, you need to make it not return until ffmpeg is done, perhaps by subscribing to ffmpeg's stream events and converting that information into a promise resolution. Alternatively you could instead use a callback-based lambda and make the success callback in an ffmpeg 'end' event handler.

funct7 commented 3 years ago

You have to return a Promise. Simply using the async keyword won't achieve anything. Here is the code I'm running.

const f = (in, out) => new Promise((res, rej) => {
  // ------ NOT IMPORTANT ------
  out
    .reduce(
      (acc, out) => acc.output(out),
      ffmpeg(inStream))
  // ------ IMPORTANT BELOW -------
    .on('progress', progress => console.log(progress))
    .on('error', err => rej(err)) // Here
    .on('end', () => res()) // Here
    .run();
});

Notice calling res and rej in each of the callback event.

ipr0310 commented 3 years ago

@lafiosca Sorry for the late response it's been a while without using github, @funct7 It seems to be so useful those advices, really appreciate it! Did not know bout these details on lambda

I'll give a try!

JulianBerger commented 5 months ago

@ipr0310 I have the same issue, lambda just finishes the run without any error.

Did you resolve the issue?