Commit caaf264d authored by Gojko Adzic's avatar Gojko Adzic

deployed to SAR as an app

parent a661549f
GPL v2, see http://ffmpeg.org/legal.html
BASE_NAME=ffmpeg
DEPLOYMENT_BUCKET_NAME := desole-packaging
DEPLOYMENT_KEY := $(shell echo $(BASE_NAME)-$$RANDOM.zip)
STACK_NAME := $(BASE_NAME)-lambda-layer
STACK_NAME ?= ffmpeg-lambda-layer
clean:
rm -rf build
build/bin/ffmpeg:
mkdir -p build/bin
build/layer/bin/ffmpeg:
mkdir -p build/layer/bin
rm -rf build/ffmpeg*
cd build; \
curl https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | tar x
mv build/ffmpeg*/ffmpeg build/ffmpeg*/ffprobe build/bin
cd build && curl https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | tar x
mv build/ffmpeg*/ffmpeg build/ffmpeg*/ffprobe build/layer/bin
build/layer.zip: build/bin/ffmpeg
cd build && zip -r layer.zip bin
build/output.yaml: template.yaml build/layer/bin/ffmpeg
aws cloudformation package --template $< --s3-bucket $(DEPLOYMENT_BUCKET) --output-template-file $@
# cloudformation has no support for packaging layers yet, so need to do this manually
#
build/output.yml: build/layer.zip cloudformation/template.yml
aws s3 cp build/layer.zip s3://$(DEPLOYMENT_BUCKET_NAME)/$(DEPLOYMENT_KEY)
sed "s:DEPLOYMENT_BUCKET_NAME:$(DEPLOYMENT_BUCKET_NAME):;s:DEPLOYMENT_KEY:$(DEPLOYMENT_KEY):" cloudformation/template.yml > build/output.yml
deploy: build/output.yml
aws cloudformation deploy --template-file build/output.yml --stack-name $(STACK_NAME)
aws cloudformation describe-stacks --stack-name $(STACK_NAME) --query Stacks[].Outputs[].OutputValue --output text
deploy: build/output.yaml
aws cloudformation deploy --template $< --stack-name $(STACK_NAME)
aws cloudformation describe-stacks --stack-name $(STACK_NAME) --query Stacks[].Outputs --output table
deploy-example:
cd example && \
make deploy DEPLOYMENT_BUCKET=$(DEPLOYMENT_BUCKET) LAYER_STACK_NAME=$(STACK_NAME)
# FFmpeg/FFprobe Lambda Layer for Amazon Linux 2 AMIs
Static build of FFmpeg/FFprobe for Amazon Linux 2, packaged as a Lambda layer. Bundles FFmpeg 4.1.3.
This application provides a single output, `LayerVersion`, which points to a
Lambda Layer ARN you can use with Lambda runtimes based on Amazon Linux 2 (such
as the `nodejs10.x` runtime).
For an example of how to use the layer, check out
<https://github.com/serverlesspub/ffmpeg-aws-lambda-layer/tree/master/example>
# FFmpeg/FFprobe AWS Lambda layer
# FFmpeg/FFprobe for AWS Lambda
This is an AWS Lambda layer containing statically linked `ffmpeg` and `ffprobe` binary utilities from the [`FFmpeg`](https://www.ffmpeg.org/) Linux package, allowing you to convert videos and extract metadata about video files in AWS Lambda, deployable as an AWS lambda layer. It can help you get started quickly with FFmpeg inside Lambda functions.
A Lambda layer containing a static version of FFmpeg/FFprobe utilities from the [`FFmpeg`](https://www.ffmpeg.org/) Linux package, compatible with Amazon Linux 2.x and Amazon Linux 1.x instances (including the `nodejs10.x` runtime, and the updated 2018.03 Amazon Linux 1 runtimes).
## Use within Lambda
## Usage
You can use a pre-deployed ARN: `arn:aws:lambda:us-east-1:145266761615:layer:ffmpeg:4` or deploy yourself -- edit Makefile to set your deployment bucket etc, then just run `make deploy`.
Absolutely the easiest way of using this is to pull it directly from the AWS Serverless Application repository into a CloudFormation/SAM application, or deploy directly from the Serverless Application Repository into your account, and then link as a layer.
The binares will be in `/opt/bin/ffmpeg` and `/opt/bin/ffprobe` inside your Lambda container.
The `ffmpeg` and `ffprobe` binaries will be in `/opt/bin/` after linking the layer to a Lambda function.
For more information, check out the [ffmpeg-lambda-layer](https://serverlessrepo.aws.amazon.com/applications/arn:aws:serverlessrepo:us-east-1:145266761615:applications~ffmpeg-lambda-layer) application in the Serverless App Repository.
Check out the [Serverless Video Thumbnail Builder](https://github.com/effortless-serverless/s3-lambda-ffmpeg-thumbnail-builder) project for an example of how to wire this to a Lambda function.
For manual deployments and custom builds, read below...
## FFmpeg Version
## Prerequisites
This package includes FFmpeg 4.1, packaged by Johan Van Sickle. Please consider supporting him for maintaining statically built FFmpeg packages. For more information, check out <https://johnvansickle.com/ffmpeg/>
* Unix Make environment
* AWS command line utilities (just for deployment)
## Copyright and license
## Deploying to AWS as a layer
FFMpeg is licensed under [GNU GENERAL PUBLIC LICENSE 2.1 or later](https://www.ffmpeg.org/legal.html).
This package includes FFmpeg 4.1.3, packaged by Johan Van Sickle. Please consider supporting him for maintaining statically built FFmpeg packages. For more information, check out <https://johnvansickle.com/ffmpeg/>
The output will be in the `result` dir.
Run the following command to deploy the compiled result as a layer in your AWS account.
```
make deploy DEPLOYMENT_BUCKET=<YOUR BUCKET NAME>
```
### configuring the deployment
By default, this uses `ffmpeg-lambda-layer` as the stack name. Provide a `STACK_NAME` variable when calling `make deploy` to use an alternative name.
### example usage
An example project is in the [example](example) directory. It sets up two buckets, and listens to file uploads on the first bucket to convert and generate thumbnails from uploaded video files. You can deploy it from the root Makefile using:
```
make deploy-example DEPLOYMENT_BUCKET=<YOUR BUCKET NAME>
```
For more information on using FFmpeg and FFprobe, check out <https://ffmpeg.org/documentation.html>
## Author
Gojko Adzic <https://gojko.net>
## License
* These scripts: [MIT](https://opensource.org/licenses/MIT)
* FFmpeg: http://ffmpeg.org/legal.html
Description: FFMPEG AWS Lambda Layer
Parameters:
AllowedPrincipal:
Type: String
Description: Account principal allowed to deploy this layer
Default: '*'
Resources:
LambdaLayer:
Type: AWS::Lambda::LayerVersion
Properties:
CompatibleRuntimes:
- nodejs8.10
- python3.6
- ruby2.5
- java8
- go1.x
Description: FFMPEG for AWS Lambda
LayerName: ffmpeg
LicenseInfo: GPL-2.0-or-later
Content:
S3Bucket: DEPLOYMENT_BUCKET_NAME
S3Key: DEPLOYMENT_KEY
DeploymentPermission:
Type: "AWS::Lambda::LayerVersionPermission"
Properties:
Action: lambda:GetLayerVersion
LayerVersionArn: !Ref LambdaLayer
Principal: !Ref AllowedPrincipal
Outputs:
LambdaLayer:
Value: !Ref LambdaLayer
STACK_NAME ?= ffmpeg-layer-example
LAYER_STACK_NAME ?= ffmpeg-lambda-layer
LAMBDA_LAYER ?=$(shell aws cloudformation describe-stacks --stack-name $(LAYER_STACK_NAME) --query Stacks[].Outputs[].OutputValue --output text)
SOURCES=$(shell find src/)
clean:
rm -rf build
output.yaml: template.yaml $(SOURCES)
mkdir -p build
aws cloudformation package --template-file $< --output-template-file $@ --s3-bucket $(DEPLOYMENT_BUCKET)
deploy: output.yaml
aws cloudformation deploy --template-file $< --stack-name $(STACK_NAME) --capabilities CAPABILITY_IAM --parameter-overrides LambdaLayer=$(LAMBDA_LAYER)
aws cloudformation describe-stacks --stack-name $(STACK_NAME) --query Stacks[].Outputs --output table
/*global module, require, console, Promise */
'use strict';
const childProcess = require('child_process'),
spawnPromise = function (command, argsarray, envOptions) {
return new Promise((resolve, reject) => {
console.log('executing', command, argsarray.join(' '));
const childProc = childProcess.spawn(command, argsarray, envOptions || {env: process.env, cwd: process.cwd()}),
resultBuffers = [];
childProc.stdout.on('data', buffer => {
console.log(buffer.toString());
resultBuffers.push(buffer);
});
childProc.stderr.on('data', buffer => console.error(buffer.toString()));
childProc.on('exit', (code, signal) => {
console.log(`${command} completed with ${code}:${signal}`);
if (code || signal) {
reject(`${command} failed with ${code || signal}`);
} else {
resolve(Buffer.concat(resultBuffers).toString().trim());
}
});
});
};
module.exports = {
spawn: spawnPromise
};
const s3Util = require('./s3-util'),
childProcessPromise = require('./child-process-promise'),
path = require('path'),
os = require('os'),
EXTENSION = process.env.EXTENSION,
THUMB_WIDTH = process.env.THUMB_WIDTH,
OUTPUT_BUCKET = process.env.OUTPUT_BUCKET,
MIME_TYPE = process.env.MIME_TYPE;
exports.handler = function (eventObject, context) {
const eventRecord = eventObject.Records && eventObject.Records[0],
inputBucket = eventRecord.s3.bucket.name,
key = eventRecord.s3.object.key,
id = context.awsRequestId,
resultKey = key.replace(/\.[^.]+$/, EXTENSION),
workdir = os.tmpdir(),
inputFile = path.join(workdir, id + path.extname(key)),
outputFile = path.join(workdir, id + EXTENSION);
console.log('converting', inputBucket, key, 'using', inputFile);
return s3Util.downloadFileFromS3(inputBucket, key, inputFile)
.then(() => childProcessPromise.spawn(
'/opt/bin/ffmpeg',
['-loglevel', 'error', '-y', '-i', inputFile, '-vf', `thumbnail,scale=${THUMB_WIDTH}:-1`, '-frames:v', '1', outputFile],
{env: process.env, cwd: workdir}
))
.then(() => s3Util.uploadFileToS3(OUTPUT_BUCKET, resultKey, outputFile, MIME_TYPE));
};
/*global module, require, Promise, console */
const aws = require('aws-sdk'),
fs = require('fs'),
s3 = new aws.S3(),
downloadFileFromS3 = function (bucket, fileKey, filePath) {
'use strict';
console.log('downloading', bucket, fileKey, filePath);
return new Promise(function (resolve, reject) {
const file = fs.createWriteStream(filePath),
stream = s3.getObject({
Bucket: bucket,
Key: fileKey
}).createReadStream();
stream.on('error', reject);
file.on('error', reject);
file.on('finish', function () {
console.log('downloaded', bucket, fileKey);
resolve(filePath);
});
stream.pipe(file);
});
}, uploadFileToS3 = function (bucket, fileKey, filePath, contentType) {
'use strict';
console.log('uploading', bucket, fileKey, filePath);
return s3.upload({
Bucket: bucket,
Key: fileKey,
Body: fs.createReadStream(filePath),
ACL: 'private',
ContentType: contentType
}).promise();
};
module.exports = {
downloadFileFromS3: downloadFileFromS3,
uploadFileToS3: uploadFileToS3
};
\ No newline at end of file
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: >
Example project demonstrating the usage of the FFmpeg Layer for AWS Linux 2 runtimes.
Parameters:
LambdaLayer:
Type: String
ConversionFileType:
Type: String
Default: jpg
ConversionMimeType:
Type: String
Default: image/jpeg
ThumbWidth:
Type: Number
Default: 300
Description: Thumbnail width in pixels
Resources:
UploadBucket:
Type: AWS::S3::Bucket
ResultsBucket:
Type: AWS::S3::Bucket
ConvertFileFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Timeout: 180
MemorySize: 1024
Runtime: nodejs10.x
CodeUri: src
Layers:
- !Ref LambdaLayer
Policies:
- S3CrudPolicy:
BucketName: !Sub "${AWS::StackName}-*"
Environment:
Variables:
OUTPUT_BUCKET: !Ref ResultsBucket
EXTENSION: !Sub '.${ConversionFileType}'
MIME_TYPE: !Ref ConversionMimeType
THUMB_WIDTH: !Ref ThumbWidth
Events:
FileUpload:
Type: S3
Properties:
Bucket: !Ref UploadBucket
Events: s3:ObjectCreated:*
Outputs:
UploadBucket:
Description: "Upload S3 bucket"
Value: !Ref UploadBucket
ResultsBucket:
Description: "Results S3 bucket"
Value: !Ref ResultsBucket
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: >
Static build of FFmpeg/FFprobe for Amazon Linux 2
Check out https://github.com/serverlesspub/ffmpeg-aws-lambda-layer
for more information.
Resources:
LambdaLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: ffmpeg
Description: FFMPEG for AWS Lambda
ContentUri: build/layer
CompatibleRuntimes:
- nodejs10.x
- python3.6
- ruby2.5
- java8
- go1.x
LicenseInfo: GPL-2.0-or-later
RetentionPolicy: Retain
Outputs:
LayerVersion:
Description: Layer ARN Reference
Value: !Ref LambdaLayer
Metadata:
AWS::ServerlessRepo::Application:
Name: ffmpeg-lambda-layer
Description: >
Static build of FFmpeg/FFprobe for Amazon Linux 2,
packaged as a Lambda layer. Bundles FFmpeg 4.1.3
Author: Gojko Adzic
SpdxLicenseId: GPL-2.0-or-later
LicenseUrl: LICENSE.txt
ReadmeUrl: README-SAR.md
Labels: ['layer', 'lambda', 'ffmpeg', 'ffprobe']
HomePageUrl: https://github.com/serverlesspub/ffmpeg-aws-lambda-layer
SemanticVersion: 1.0.0
SourceCodeUrl: https://github.com/serverlesspub/ffmpeg-aws-lambda-layer
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment