Skip to content

Instantly share code, notes, and snippets.

@identiq
Created November 25, 2018 17:37
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save identiq/d633dfda66698d24c390bbe8422090b3 to your computer and use it in GitHub Desktop.
Save identiq/d633dfda66698d24c390bbe8422090b3 to your computer and use it in GitHub Desktop.
Video preview generation (like giphy) with FFMPEG (ffmpeg-fluent) on node Serverless Lambda
const config = require('../config.json');
const fs = require('fs');
const _ = require('lodash');
const path = require('path');
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
const ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath(ffmpegPath);
const AWS = require('aws-sdk');
const s3 = new AWS.S3({
accessKeyId: config.AWS_ACCESS_KEY_ID,
secretAccessKey: config.AWS_SECRET_ACCESS_KEY,
useAccelerateEndpoint: true,
});
const TMP_PATH = process.env.TMP_PATH;
module.exports = {
async giphy(event) {
for (const record of event.Records) {
await handleRecord(record.s3);
}
},
};
async function handleRecord(record) {
const key = record.object.key;
const videoPath = await downloadFile(key);
try {
const res = await ffmpegToGif(videoPath, key);
console.log('ffmpegToGif', res);
} catch (err) {
console.error(err);
}
}
function downloadFile(key) {
return new Promise((resolve, reject) => {
const destPath = `${TMP_PATH}/${path.basename(key)}`
const params = {
Bucket: process.env.S3_BUCKET_NAME,
Key: key
}
const s3Stream = s3.getObject(params).createReadStream();
const fileStream = fs.createWriteStream(destPath);
s3Stream.on('error', reject);
fileStream.on('error', reject);
fileStream.on('close', () => {
resolve(destPath);
});
s3Stream.pipe(fileStream);
});
}
function ffmpegToGif(videoPath, key) {
return new Promise((resolve, reject) => {
const filename = _.first(path.basename(key).split('.'));
const bucketPath = _.first(key.split('.'));
ffmpeg(videoPath)
.inputOptions(['-t 2.5', '-ss 61.0'])
.complexFilter('[0:v]palettegen')
.on('end', () => {
ffmpeg(videoPath)
.inputOptions(['-t 2.5', '-ss 61.0'])
.addInput(`${TMP_PATH}/${filename}.png`)
.complexFilter(['[0:v][1:v]paletteuse'])
.on('end', async () => {
const gif = fs.createReadStream(`${TMP_PATH}/${filename}.gif`);
const res = await s3.putObject({
Bucket: process.env.S3_BUCKET_NAME,
Key: bucketPath + '.gif',
Body: gif,
ContentType: 'image/gif'
}).promise();
resolve(res)
})
.on('error', err => {
reject(err);
})
.save(`${TMP_PATH}/${filename}.gif`);
})
.on('error', err => {
reject(err);
})
.save(`${TMP_PATH}/${filename}.png`);
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment