Skip to content

Instantly share code, notes, and snippets.

@pacarvalho
Created April 17, 2022 14:48
Show Gist options
  • Save pacarvalho/9692f49f3d5e35b94813e4f7f90187f3 to your computer and use it in GitHub Desktop.
Save pacarvalho/9692f49f3d5e35b94813e4f7f90187f3 to your computer and use it in GitHub Desktop.
NodeJS Lambda for Processing Video from S3 Event
const s3Util = require("./s3-util");
const childProcessPromise = require("./child-process-promise");
const path = require("path");
const os = require("os");
const fs = require("fs");
const https = require("https");
const OUTPUT_BUCKET = process.env.OUTPUT_BUCKET;
const VIDEO_MIME_TYPE = process.env.VIDEO_MIME_TYPE;
const LAMBDA_SHARED_SECRET = process.env.LAMBDA_SHARED_SECRET;
exports.handler = async (eventObject, context) => {
const eventRecord = eventObject.Records && eventObject.Records[0];
const inputBucket = eventRecord.s3.bucket.name;
const key = eventRecord.s3.object.key;
const id = context.awsRequestId;
const workdir = os.tmpdir();
// Get the filename without the path
const filename = path.basename(key); // /path/1/.../n/filename
// Names for files once they are placed in the output S3 bucket
const lowResKey = "processed/lowRes/" + filename;
// Names for files while they reside in Lambda prior to uploading to output bucket
const inputFile = path.join(workdir, id + path.extname(key));
const lowResOutputFile = path.join(workdir, "lowRes-" + id + ".mp4");
console.log("Download file from S3...");
await s3Util.downloadFileFromS3(inputBucket, key, inputFile);
// lowRes
console.log("Generate lowRes optimized (plays on Chrome) video file...");
await childProcessPromise.spawn(
"/opt/bin/ffmpeg",
[
"-loglevel",
"error",
"-y",
"-i",
inputFile,
"-movflags",
"faststart",
"-vf",
"scale=480:-2",
lowResOutputFile,
],
{ env: process.env, cwd: "./" }
);
console.log("Upload lowRes file...");
await s3Util.uploadFileToS3(
OUTPUT_BUCKET,
lowResKey,
lowResOutputFile,
VIDEO_MIME_TYPE
);
// callback to the API to signal that this file is finished processing
console.log("Informing server lowRes derivative is ready...");
await informServerOfCompletion({ key: key, low_res_key: lowResKey });
// Clean up remaining artifacts
console.log(
"Delete unused files to avoid running out of space on future runs..."
);
fs.unlinkSync(inputFile); // Original
fs.unlinkSync(lowResOutputFile);
console.log(`Signaling post process complete for ${key}`);
};
// Helper method
const informServerOfCompletion = async (data) => {
data = JSON.stringify(data);
const options = {
hostname: process.env.API_HOSTNAME,
port: 443,
path: "/api/videos/derivative",
method: "PUT",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"Content-Length": data.length,
"User-Agent": "Lambda-PreviewGenerator",
Authorization: LAMBDA_SHARED_SECRET,
},
};
console.log("Callback to server...", data);
await new Promise((resolve) => {
const req = https.request(options, (res) => {
console.log(`/api/videos/derivative statusCode: ${res.statusCode}`);
res.on("data", (d) => {
process.stdout.write(d);
resolve();
});
});
req.on("error", (error) => {
console.log(`/api/videos/derivative failed ${error}`);
resolve();
});
req.write(data);
req.end();
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment