Run FFmpeg in AWS Lambda for Video Transcoding
Running FFmpeg on AWS Lambda enables a lightweight, cost-effective, and fully serverless video processing pipeline without managing dedicated virtual machines. This guide details how to bundle a static FFmpeg binary into a Lambda Layer, configure the required execution environment, manage temporary local storage, and invoke transcoding commands triggered by Amazon S3 events using Python.
1. Package FFmpeg into a Lambda Layer
AWS Lambda functions run on Amazon Linux. To run FFmpeg, you must provide a statically compiled Linux binary that includes all necessary codecs.
Download a static build of FFmpeg targeting
x86_64(orarm64, depending on your Lambda architecture).Create a directory structure matching
/bin:mkdir -p ffmpeg-layer/bin cp /path/to/ffmpeg ffmpeg-layer/bin/ chmod +x ffmpeg-layer/bin/ffmpegCompress the directory into a zip file:
cd ffmpeg-layer zip -r ../ffmpeg-layer.zip .In the AWS Lambda Console, navigate to Layers, click Create layer, upload
ffmpeg-layer.zip, and set the compatible architecture to match your binary (x86_64orarm64).
Attaching this layer puts the ffmpeg executable into
/opt/bin/ffmpeg, which AWS Lambda includes in the default
execution $PATH.
Alternatively, if your binary and dependencies exceed Lambda's 250 MB unzipped layer limit, package your application as an OCI-compliant container image based on an AWS Lambda base image.
2. Configure Lambda Storage, Memory, and Timeout
Video transcoding is compute- and I/O-intensive. Standard Lambda defaults are insufficient for this workload:
- Ephemeral Storage (
/tmp): Lambda offers between 512 MB and 10,240 MB (10 GB) of/tmpdisk space. Set this to at least 3–5 times the size of your input video to accommodate the input file, output file, and intermediate chunks. - Memory: Allocate between 2048 MB and 10240 MB of RAM. Lambda scales vCPU allocation proportionally to memory; higher memory allocations provide more CPU cores to FFmpeg, significantly reducing processing time.
- Timeout: Set the timeout close to the maximum limit of 15 minutes (900 seconds) to prevent premature termination during complex encoding passes.
3. Implement the Lambda Handler
Use AWS SDK (boto3 for Python) along with the native
subprocess module to stream or download the file from
Amazon S3, execute the command, and upload the result.
import os
import subprocess
import boto3
s3_client = boto3.client('s3')
def lambda_handler(event, context):
# Extract bucket and key from the event
record = event['Records'][0]['s3']
source_bucket = record['bucket']['name']
source_key = record['object']['key']
input_path = f"/tmp/{os.path.basename(source_key)}"
output_key = f"transcoded/{os.path.splitext(os.path.basename(source_key))[0]}.mp4"
output_path = f"/tmp/output.mp4"
# 1. Download file from S3 to /tmp
s3_client.download_file(source_bucket, source_key, input_path)
# 2. Run FFmpeg command
# Converts input video to H.264 / AAC 720p
command = [
"ffmpeg",
"-y",
"-i", input_path,
"-vf", "scale=-2:720",
"-c:v", "libx264",
"-preset", "fast",
"-crf", "23",
"-c:a", "aac",
"-b:a", "128k",
output_path
]
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode != 0:
print(f"FFmpeg error: {result.stderr}")
raise RuntimeError("Video processing failed.")
# 3. Upload the transcoded file back to S3
s3_client.upload_file(output_path, source_bucket, output_key)
# 4. Clean up /tmp directory to avoid filling disk across invocations
if os.path.exists(input_path):
os.remove(input_path)
if os.path.exists(output_path):
os.remove(output_path)
return {
"statusCode": 200,
"body": f"Successfully transcoded {source_key} to {output_key}"
}4. Optimize Performance
- Multi-threading: Ensure your FFmpeg command
utilizes available cores by default, or explicitly pass the
-threadsflag matching your allocated vCPU count. - Stream I/O with Pipes: For formats that support streaming (such as fragmented MP4 or certain audio streams), pipe input from standard input and output to standard output using S3 streaming wrappers to avoid disk I/O bottlenecks.
- Long Video Limitations: If video files take longer than 15 minutes to transcode, split videos into chunks using AWS Step Functions to process parts in parallel, or offload the job to AWS Batch or AWS Elemental MediaConvert.