Using AWS for Video Transcoding and Fast Delivery Streaming

There are several compelling platforms out there for streaming an optimized video content to your website visitors’ devices, be it laptops, tablets or smartphones. AWS, with its S3 buckets, Elastic Transcoder, and CloudFront is certainly one of the top contenders. In this article, we will configure an AWS account to accept video files via an S3 bucket, optimize them for streaming to a smartphone, and deliver them with minimal latency through Amazon’s content delivery network CloudFront. Let’s get started!

The Process — What We’ll Learn

First, let’s summarize the video storing and preparation process:

  1. We’ll create two S3 buckets: One for storing the video files we want to make available for streaming, one for storing a version of the videos that is optimized for streaming to smartphones and tablets.
  2. We’ll create an Elastic Transcoder pipeline for optimizing the uploaded videos for streaming.
  3. We’ll create an AWS Lambda function to automatically push each uploaded video file through the Elastic Transcoder pipeline with the goal of optimizing the video for streaming and storing the final video in the second S3 bucket.
  4. We’ll configure CloudFront to distribute the optimized video files from the second S3 bucket through the content delivery network (CDN) for low latency streaming, e.g. minimal lag in delivery.

Once these components are in place, they will trigger one another in the following sequence: A video file is uploaded to the first S3 bucket. That event triggers the Lambda function, which creates a job in the Elastic Transcoder pipeline. Once the transcoding job is finished, the transcoded file is stored in the second S3 bucket. As soon as a user initiates streaming of the transcoded video, CloudFront loads the video from the second S3 bucket and streams it to the user’s device.

Let’s go through the steps:

Prepare Two S3 Buckets

For pedagogic purposes, let’s call the two buckets “streaming-video-raw” and “streaming-video-optimized” for storing the original unoptimized video and the videos optimized for streaming, respectively. It’s possibly that by the time you’re reading this article, those S3 bucket names will be already taken. In that case, simply name them differently.

Go the S3 section of your AWS console and create two buckets, one named “streaming-video-raw”, the other “streaming-video-optimized”.

As you go through the S3 bucket creation wizard, leave the properties and permissions at their default values.

Now, we should have our two S3 buckets ready.

Also, in order to be able to play the video from the second S3 bucket, we have to make it public, that is, allow reading the content from the bucket by any Internet user. To do that, go to the bucket and click on the “Permissions” tab. Then click on the “Bucket Policy” button. A screen shown below will open with a text editor to enter the policy configuration.

Enter this code into the policy editor:

"Version": "2012-10-17",
"Statement": [
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::streaming-video-optimized/*"

Click the “Save” button. Moving on…

Create Elastic Transcoder Pipeline

Next, we will create the Elastic Transcoder pipeline that will take the video from the input S3 bucket, optimize it for streaming to a smartphone and save the optimized version in the output S3 bucket.

Navigate to the Elastic Transcoder AWS service and click on the “Create New Pipeline” button.

The screenshot below shows the configuration parameters for the new pipeline:

The pipeline is essentially a queue of transcoding jobs; it takes video files from the input bucket one at a time, transcodes them to the desired format, which will be specified later in the Lambda function, and stores the transcoded files in the output bucket specified above. It will also create a thumbnail image for each video and store it in the output bucket along with the video.

Create AWS Lambda Function to Create Transcoder Pipeline Jobs

The next step is to write an AWS Lambda function that will be triggered every time a new video file is uploaded to the “streaming-video-raw” S3 bucket, trigger Elastic Transcoder to transcode the video and store it in the “streaming-video-optimized” bucket.

To create the Lambda function and connect it to the S3 bucket “Create Object” event — the event triggered every time a file is uploaded to the bucket — go to the AWS Lambda service section, click on “Create function” and fill the form like so:

From the “Policy templates” drop-down box, select “Basic Edge Lambda permissions”. Click on the “Create function” button at the bottom to submit the form. You’ll see a screen like this:

From the list of triggers on the top left, select S3. Then scroll down to the second half of the page and configure the connection between the Lambda function and the S3 bucket. The below screenshot shows the configuration:

We are telling Lambda to trigger the function when a new object (file) is created in the “streaming-video-raw” S3 bucket. Click “Add” to save the changes.

Next, click on the “transcodeVideo” function name in the rectangle in the center top of the screen. A function editor will open in the lower half of the screen. Enter the following code there. We will just change a few parameters:

var AWS = require('aws-sdk');
var s3 = new AWS.S3({
apiVersion: '2012–09–25'
var eltr = new AWS.ElasticTranscoder({
apiVersion: '2012–09–25',
region: 'us-east-1'
exports.handler = function(event, context) {
var bucket = event.Records[0];
var key = event.Records[0].s3.object.key;
var pipelineId = '1519927986763-h63mfd';

if (bucket !== 'streaming-video-raw') {'Incorrect input bucket');

var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); // the object may have spaces
var newKey = key.split('.')[0];
var params = {
PipelineId: pipelineId,
OutputKeyPrefix: newKey + '/',
Input: {
Key: srcKey,
FrameRate: 'auto',
Resolution: 'auto',
AspectRatio: 'auto',
Interlaced: 'auto',
Container: 'auto'
Outputs: [{
Key: newKey + '.mp4',
ThumbnailPattern: 'thumbs-' + newKey + '-{count}',
PresetId: '1351620000001-100020',
Watermarks: [],

console.log('Starting a job');
eltr.createJob(params, function(err, data) {
if (err){
} else {
context.succeed('Job successfully completed');

When you paste the above code to your Lambda function editor, replace the pipelineId variable with the with ID of the pipeline in your account. You can get the pipeline ID by using the AWS terminal command like so:

aws elastictranscoder list-pipelines

The output JSON string will contain the pipeline Id field. Paste its value into your AWS Lambda function. The other variable you might want to change in the future is the PresetId . The value the above code sample contains refers to a preset that transcodes the video to a progressively streaming MP4 file optimized for smartphones and tablets. If AWS changes the Id of the preset in the future, you might need to get the new value. You can retrieve it by running this command:

aws elastictranscoder list-presets

Scroll through the JSON output and find the Id of the preset called “System preset: iPhone 4s and above, iPad 3G and above, iPad mini, Samsung Galaxy S2/S3/Tab 2”. Set the value of the PresetId variable in our function code and click on “Create function” to submit the form. Your function is now ready.

Also, before saving the AWS Lambda function, scroll down and set the execution role to the one we created earlier as shown on the following screenshot:

Finally, press the “Save” button to create the function.

Currently, the role “videoTranscoderLambdaRole” that is attached to this function doesn’t include the permission to submit jobs to the Elastic Transcoder. Let’s add that policy so that our function can submit jobs to the Elastic Transcoder.

Navigate to the IAM section. There, click on “Roles”. From the list of available roles, click on “videoTranscoderLambdaRole”. On the role detail page, click on the “Attach policy” button and search for the “ElasticTranscoderJobsSubmitter” role. Once found, select it and attach it to the role as shown on the screenshot below:

Ok, at this point, we are done with the fundamentals. You can try to upload a video file to the “streaming-video-raw” bucket. Wait a while and you should see the transcoded MP4 file appear in the “streaming-video-optimized” bucket.

The last step is distributing the optimized video files that get created in the “streaming-video-optimized” S3 bucket to a content delivery network for speedy delivery to your users’ smartphones. That’s where AWS CloudFront come to play:

Configure CloudFront Distribution

Navigate to the CloudFront section of the AWS console and click on the “Create Distribution” button. There, click on the “Get Started” button in the “Web” section.

Set the first few values as shown in the screenshot below; specifically, select the “streaming-video-optimized” S3 bucket as the “Origin Domain Name”. Leave the rest of the settings at their current values (unless you want to change them knowing what you’re doing). Click on “Create Distribution” at the bottom of the page and wait a while (might be up to 20+ minutes) for the distribution to get created. It will show as “In progress” for a while.

When it’s created, you’ll be able to replace the domain name of the S3 bucket with the domain name of the CloudFront distribution. In this example, the screenshot shows the domain name to be It will be different on your AWS.

Let’s Test It

Let’s test our configuration! Take a video on your phone and download it to your computer. Navigate to the “streaming-video-raw” S3 bucket in the AWS console and upload the video there. Wait some time and the video should appear in the “streaming-video-optimized” bucket. Go there, click on the file and on the right side, you’ll see a URL link to it as shown on the screenshot below — the red arrow points to it. Click on the link. Your browser should open the file and start streaming it.

Now let’s play the video file through CloudFront. What is the URL? You can determine it by taking the S3 bucket file URL from the S3 bucket as shown on the screenshot above using the red arrow. In our example case, the url is:

To convert it to a CloudFront URL, replace the part


so the final link looks like:

And that’s it! We have a pipeline that takes video files from an input S3 bucket, converts them to a streaming optimized files stored in an output S3 bucket and distributes the files through a CDN for low latency streaming experience.


This article builds on top of this article:

For more articles, follow me on Medium, Twitter @petrkout, or visit my website at