MESUT ÇAKIR | Tüm yazılar etiketlendi 'lambda'

AWS Lambda Video Screenshot (Ekran Görüntüsü) Oluşturma

Merhaba,

Amazon S3 video yüklemeleri sonrası video içerisinden bir ekran görüntüsü üretilmesi ve sistem içerisinde kullanılması ihtiyacı doğmaktadır. Bunu kendi uygulamanız içerisinde yapabilirsiniz fakat memory, cpu gibi kaynaklarımızın yüke göre nasıl karşılık vereceğini yönetmekle uğraşmak istemediğimizde AWS S3 Event & AWS Lambda servislerini birlikte kullanabiliriz. Bu yazımda bunu nasıl yapabileceğiniz ile ilgili örnekler veriyor olacağım.

Maliyet Planı

Yapacağım uygulama 30MB video dosyasını ortalama 7 saniye içerisinde işler ve içerisinden istemiş olduğunuz resmi s3 üzerinde belirttiğiniz bölüme kayıt eder. 300MB Ram kullanır. 

Bu metriklerle bir hesap yaptığımızda 1 Milyon video için 1 resim üretmek istediğimiz 512MB kaynak ve ortalama 10 saniye üzerinden hesapladığımızda 83$ bir maliyet yaratırız. https://dashbird.io/lambda-cost-calculator 

Kaynaklar

https://github.com/mesutcakir/s3-video-portal/tree/master/VideoPortal-lambda

const fs = require('fs');
const childProcess = require('child_process');
const AWS = require('aws-sdk');
const path = require('path');
const ffmpeg = require('fluent-ffmpeg');
ffmpeg.setFfmpegPath("/tmp/ffmpeg");
ffmpeg.setFfprobePath("/tmp/ffprobe");
const s3 = new AWS.S3();
process.env['S3_BucketName'] = process.env['S3_BucketName'] || 's3-videoportal';
process.env['S3Key_ffmpeg'] = process.env['S3Key_ffmpeg'] || '_dev/ffmpeg';
process.env['S3Key_ffprobe'] = process.env['S3Key_ffprobe'] || '_dev/ffprobe';
process.env['SS_Size'] = process.env['SS_Size'] || '240x180';
exports.handler = (event, context, callback) => {
	console.log("started");
	//First Video 
	const srcKey = event.Records.find(x => x).s3.object.key;
	const findExtention = /(?:\.([^.]+))?$/;
	const srcExtention = findExtention.exec(srcKey)[1];
	const targetKey = srcKey.replace("." + srcExtention, ".jpg");
	const randomKey = Math.random().toString().replace(".", "");
	const videoFileName = "/tmp/" + randomKey + "." + srcExtention;
	//Copy Work Files
	const copy_ffmpeg = CopyFileFromS3(process.env['S3Key_ffmpeg'], "/tmp/ffmpeg");
	const copy_ffprobe = CopyFileFromS3(process.env['S3Key_ffprobe'], "/tmp/ffprobe");
	const copy_video = CopyFileFromS3(srcKey, videoFileName);
	Promise.all([copy_ffmpeg, copy_ffprobe, copy_video]).then(() => {
		SaveScreenshotToS3(videoFileName, {
			s3Key: "thumbnail/" + targetKey,
			imageTargetName: randomKey + ".jpg",
			ScreenshotSize: process.env['SS_Size'],
			ScreenshotCount: 1
		}, callback);
	}).catch(err => {
		console.log("Promise Error:", err);
	});
};
function SaveS3Object(s3Key, stream, callback) {
	s3.putObject({
		Bucket: process.env['S3_BucketName'],
		Key: s3Key,
		Body: stream,
		ContentType: "image/jpg"
	}, function (err, data) {
		if (err !== null)
			console.log("error: " + err);
		else
			console.log("upload s3 data");

		callback(err);
	});
}
function SaveScreenshotToS3(videoFileName, options, callback) {
	ffmpeg(videoFileName)
		.on('filenames', function (filenames) {
			console.log('Will generate ' + filenames.join(', '));
		})
		.on('end', function () {
			console.log(videoFileName + 'Screenshots taken');
			SaveS3Object(options.s3Key, fs.createReadStream("/tmp/" + options.imageTargetName), callback);
		})
		.screenshots({
			count: options.ScreenshotCount,
			size: options.ScreenshotSize,
			folder: '/tmp',
			filename: options.imageTargetName
		});
}
function givePermissionFile(fileName, callback) {
	childProcess.exec(
		'chmod 755 ' + fileName + ';',
		function (error, stdout, stderr) {
			if (error) {
				console.log('givePermissionFile Error', error);
			} else {
				console.log("givePermissionFile Success: " + fileName);
			}
			callback(error);
		}
	);
}
function CopyFileFromS3(srcKey, targetKey) {
	return new Promise((resolve, reject) => {
		var s3VideoStream = s3.getObject({ Bucket: process.env['S3_BucketName'], Key: srcKey }).createReadStream();
		s3VideoStream.on("end", function () {
			console.log("copy file:", targetKey);
			givePermissionFile(targetKey, (err) => {
				if (err) reject(err); else resolve();
			});
		});
		s3VideoStream.pipe(fs.createWriteStream(targetKey));
	});
}

//var event = require("./testdata.json");
//var findExtention = /(?:\.([^.]+))?$/;
//const srcKey = event.Records.find(x => x).s3.object.key;
//const srcExtention = findExtention.exec(srcKey)[1];
//var randomKey = Math.random().toString().replace(".", "");
//var videoFileName = "/tmp/" + randomKey + "." + srcExtention;

//console.log("srcKey:", srcKey)
//console.log("srcExtention:", srcExtention)
//console.log("videoFileName:", videoFileName)
//console.log("randomKey:", randomKey)