Created
April 17, 2022 14:48
-
-
Save pacarvalho/9692f49f3d5e35b94813e4f7f90187f3 to your computer and use it in GitHub Desktop.
NodeJS Lambda for Processing Video from S3 Event
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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