node.jsamazon-web-servicesffmpegaws-lambda

SIGSEGV from ffmpeg on Amazon Lambda


Trying out Amazon Lambda / nodejs 8. My goal is to launch ffmpeg, generate a short clip and upload it to S3 bucket.

I created the function following the image resize tutorial. Edited the code to get output from simple linux commands like ls or cat /proc/cpuinfo - all works.

Now, added the ffmpeg binary for i686 - ffmpeg static build by JohnVan Sickle (thanks!). Changed the code to launch simple ffmpeg command that is supposed to create sa 2-seconds small video clip.

That fails, according to logs, with the signal SIGSEGV returned to the "close" event handler of child_process.spawn()

As far as I understand, this could be caused by the ffmpeg binary incompatibility with the static build. Or by some mistake in my code.

Several npm modules rely on the static builds from johnvansickle.com/ffmpeg and there are no such issues filed on their github. Maybe there's some other mistake I made?

Should I compile ffmpeg myself under Amazon Linux AMI amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2 which is under the hood of AWS Lambda?


upd. Launched EC2 t2.micro instance from the same AMI, downloaded the same ffmpeg static build, and it works just fine from the command line. Now I doubt that it is a compilation issue.

Also tried copying ffmpeg executable to /tmp/ffmpeg and chmod 755 just to make sure. Running simple ffmpeg --help command via child_process.execSync() returns "Error: Command failed: /tmp/ffmpeg --help"


const join = require('path').join;
const tmpdir = require('os').tmpdir;
const process = require('process');
const fs = require('fs');
const spawn = require('child_process').spawn;
const exec = require('child_process').exec;

const async = require('async');
const AWS = require('aws-sdk');
const util = require('util');

process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'];


const tempDir = process.env['TEMP'] || tmpdir();
const filename = join(tempDir, 'test.mp4');
const s3 = new AWS.S3();


exports.handler = function(event, context, callback) {
  var dstBucket = srcBucket + "resized";
  var dstKey  = "render-test.mp4";

  async.waterfall([
    function transform(next) {
      var args = [
        '-filter_complex',
        '"testsrc=r=25:s=640x480:d=3"',
        '-an',
        '-y',
        '-hide_banner',
        '-c:v', 'libx264',
        filename,
      ];

      console.log("Will launch ffmpeg");
      const childProcess = spawn('ffmpeg', args);

      childProcess.on('close', function(e) {
        console.log('ffmpeg close event: ' + JSON.stringify(arguments));
        next();
      });

      console.log("After launched ffmpeg");
    },

    function upload(next) {
      ...
    }
  ], function (err) {
    ...
  });
};

Solution

  • Fixed. Despite the misleading fact that static build of ffmpeg from JohnVanSickle.com does run on Amazon EC2 instance of the AMI, mentioned in Lambda environment, same binary fails to execute under AWS Lambda.

    I compiled ffmpeg on the AWS EC2 t2.micro instance of the same AMI using markus-perl/ffmpeg-build-script. It also surprised me with an error of aom codec version. Changed one line in the script to disable the aom codec and ffmpeg finally has compiled. Took a couple of hours on the weak t2.micro instance.

    The resulting ffmpeg binary is ~10Mb lighter than the static build mentioned above and runs on AWS Lambda just fine!

    Hope this will help someone.