Open-source project
aws-solutions-library-samples/video-on-demand-on-aws avatar
aws-solutions-library-samples/video-on-demand-on-aws

Video on Demand on AWS: a Step Functions workflow for transcoding pipelines

An automated reference implementation leveraging AWS Step Functions and AWS Media Services to deploy a scalable fault tolerant Video on demand workflow

521 stars242 forksJavaScriptApache-2.0

At a glance

What is it?
Video on Demand on AWS is an AWS Solutions Library reference implementation that wires Step Functions, Elemental MediaConvert, Elemental MediaPackage, S3 and CloudFront into an automated ingest and encoding pipeline, with per-video configuration through a metadata file. It suits a media team that wants the pipeline assembled by CloudFormation rather than hand-built, and it is an AWS-specific pattern rather than a portable tool.
Who is it for?
Video on Demand on AWS fits a media engineering team that wants the standard video-on-demand pipeline assembled and configurable rather than hand-wired, since the workflow, the encoding templates, the S3 triggers and the CloudFront playback URLs are all set at deployment time and per-video settings can ride along in a metadata file.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 114 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the reference implementation assembles

Video on Demand on AWS is described as an automated reference implementation leveraging AWS Step Functions and AWS Media Services to deploy a scalable, fault tolerant video on demand workflow. The readme states the components directly: how to implement a video-on-demand workflow on AWS leveraging AWS Step Functions, AWS Elemental MediaConvert and AWS Elemental MediaPackage.

MediaConvert is the transcoding engine, MediaPackage is the packaging layer that produces the segmented HLS output for delivery, Step Functions orchestrates the workflow, S3 holds the source and the outputs, and CloudFront serves the playback URLs. The architecture diagram at the repository root, architecture.png, is where the readme points for the shape of it.

The deployment mechanism is a CloudFormation template with a lambda backed custom resource, and the readme directs you to the guidance home page for the deployment details, which is where the parameter list lives.

There is a warning that is worth repeating before anything else: please ensure you test the new template before updating any production deployments. This is a pattern that reaches into your content pipeline, and a template change is a pipeline change.

The repository itself is Apache-2.0 licensed, with a LICENSE.txt and a NOTICE.txt at the root, and it holds deployment/, source/, a solution-manifest.yaml, the architecture diagram, a CHANGELOG.md, a SECURITY.md and a CONTRIBUTING.md. The recent releases are v6.1.14 from 2025-09-25, v6.1.17 from 2026-04-01 and v6.1.18 from 2026-06-09, with the last push on 2026-07-01.

The workflow configuration, as environment variables

The workflow configuration is set at deployment and is defined as environment variables for the input-validate lambda function, which is the first step in the ingest process. That single lambda is where the parameters of the pipeline live.

The variables cover the source and destination, the templates and the outputs. Archive Source, if enabled, tags the source video file for archiving to Glacier at the end of the workflow. CloudFront is the domain name used to generate the playback URLs for the MediaConvert outputs. Destination is the name of the S3 bucket for all of the MediaConvert outputs. Source is the name of the source S3 bucket. WorkflowName is used to tag all of the MediaConvert encoding jobs.

The three template variables are MediaConvert_Template_2160p for the UHD template, MediaConvert_Template_1080p for the HD template and MediaConvert_Template_720p for the SD template.

The two behavioural switches are InputRotate, which defines how MediaConvert rotates your video, and FrameCapture, which, if enabled, adds frame capture to the job submitted to MediaConvert.

Then there are the notification flags: enableSns sends SNS notifications for the workflow results and enableSqs sends the workflow results to an SQS queue. Both are opt-in, and having them as separate flags rather than one is the right granularity, since a pipeline that emits to SNS and one that emits to a queue are different integration shapes.

And acceleratedTranscoding is a three-valued setting with the options ENABLE, DISABLED and PREFERRED, pointing at the AWS documentation for Accelerated Transcoding.

The naming convention here is worth noting, since it will show up in your own code: the environment variable names are the literal strings MediaConvert_Template_2160p and similar, and the readme's examples of setting them refer to updating the environment variables for the input validate lambda function by name.

Two trigger options, and the metadata file

The workflow can be triggered in one of two ways, and the choice is made with the workflow trigger parameter at deployment time.

With the Source Video option, set to VideoFile, the CloudFormation template configures S3 event notifications on the source S3 bucket to trigger the workflow whenever a video file is uploaded. The accepted extensions are mpg, mp4, m4v, mov and m2ts.

With the Source Metadata option, set to MetadataFile, the S3 notification is configured to trigger the workflow whenever a JSON file is uploaded. The point of this is that it allows different workflow configuration to be defined for each source video processed by the workflow.

The ordering rule is important and is flagged as important in the readme. The source video file must be uploaded to S3 before the metadata file is uploaded, and the metadata file must be valid JSON with a .json file extension. With source metadata enabled, uploading video files to S3 will not trigger the workflow.

The minimal metadata file is:

json
{
    "srcVideo": "example.mpg",
    "archiveSource": true,
    "frameCapture": false,
    "jobTemplate": "custom-job-template"
}

The only required field is srcVideo. The workflow defaults to the environment variable settings for the ingest validate lambda function for any settings not defined in the metadata file. So the metadata file is an override mechanism layered on top of the deployment-wide defaults, not a replacement for them.

The full option list shows how much can be overridden per video:

json
{
    "srcVideo": "string",
    "archiveSource": string,
    "frameCapture": boolean,
    "srcBucket": "string",
    "destBucket": "string",
    "cloudFront": "string",
    "jobTemplate_2160p": "string",
    "jobTemplate_1080p": "string",
    "jobTemplate_720p": "string",
    "jobTemplate": "custom-job-template",
    "inputRotate": "DEGREE_0|DEGREES_90|DEGREES_180|DEGREES_270|AUTO",
    "captions": {
        "srcFile": "string",
        "fontSize": integer,
        "fontColor": "WHITE|BLACK|YELLOW|RED|GREEN|BLUE"
    }
}

The captions block with a source file, a font size and a font colour is the one that most affects output quality, since burned-in captions are rendered by the encoder rather than delivered as a sidecar track.

The guidance also supports adding additional metadata, such as title, genre or any other information you want to store in Amazon DynamoDB. That is how a pipeline like this ends up with a catalogue: the workflow carries arbitrary metadata through to a table.

Encoding templates and the profiler step

At launch the guidance creates three MediaConvert job templates, which become the default encoding templates for the workflow: MediaConvert_Template_2160p, MediaConvert_Template_1080p and MediaConvert_Template_720p.

The selection between them is automatic. By default, the profiler step in the process step function checks the source video height and sets the parameter jobTemplate to one of the available templates. That variable is then passed to the encoding step, which submits a job to AWS Elemental MediaConvert.

So the workflow does not transcode blind. It measures the source, picks a rung on the ladder, and encodes to it. For a source that is already 1080p, the 2160p template is not used; for a low-resolution source, the pipeline will not invent resolution it does not have.

Customisation has two routes, and the readme explains both. You can either replace the existing templates, by using the system templates or creating three new templates through the MediaConvert console, or you can use the source metadata version of the workflow and define the jobTemplate as part of the source metadata file, as the example above does with the custom-job-template value.

The readme also documents a QVBR mode section and an accelerated transcoding section, and the acceleratedTranscoding environment variable with its ENABLE, DISABLED and PREFERRED options belongs to the latter. QVBR is quality-based variable bitrate, which is the mode where the encoder spends bits where the picture is complex, and it interacts with the template settings in ways that are worth understanding before you commit to it, which is why the readme has a section rather than a line.

For the custom-build path, the readme lays out five steps: run the unit tests for customization, create an Amazon S3 bucket, build MediaInfo, create the deployment packages, and launch the CloudFormation template. MediaInfo has to be built because the profiler step needs it to read the source video's properties, and the source code section covers Node.js 22 and Python 3.13, so the workflow logic itself has two implementations.

Where the reference implementation is the wrong choice

The first limitation is that it is entirely AWS-specific. Step Functions, MediaConvert, MediaPackage, S3, CloudFront, SNS, SQS, DynamoDB and Lambda are all load-bearing parts of the design, and the workflow trigger is an S3 event notification. Porting the pattern means porting the whole thing, so a team that has standardised on another cloud gets a reference document rather than a starting point.

The second is that it is a reference implementation, which means it is optimised for being read and adapted rather than for being the thing you run unchanged. The document says as much in its disclaimer, which states that customers are responsible for making their own independent assessment of the information, that the guidance is for informational purposes only, that it represents current product offerings and practices subject to change without notice, and that it creates no commitments or assurances from AWS. The deployment warning reinforces the point.

The third is the per-rendition cost model. Three encoding templates plus optional frame capture plus optional accelerated transcoding plus MediaPackage packaging is a pipeline that costs real money per title, and the cost is driven by the number of outputs and the length of the content. A library of short clips is a poor fit; a catalogue of feature-length titles is a good one.

The fourth is the two-runtime source code. The readme's source code section covers Node.js 22 and Python 3.13, which means there are two implementations of the workflow logic to understand, and the custom-build instructions include running the unit tests for customization and building MediaInfo before packaging. That is a real maintenance surface for a team that intends to change the behaviour.

The fifth is the ordering constraint in the metadata mode, which is a genuine footgun. With source metadata enabled, uploading a video file does nothing at all, and the metadata file has to arrive after the video and be valid JSON with a .json extension. A pipeline that silently does nothing when a file is uploaded is a pipeline that will page someone at three in the morning.

Editorial conclusion

Video on Demand on AWS fits a media engineering team that wants the standard video-on-demand pipeline assembled and configurable rather than hand-wired, since the workflow, the encoding templates, the S3 triggers and the CloudFront playback URLs are all set at deployment time and per-video settings can ride along in a metadata file. It is the wrong choice if you are on another cloud or need to own the pipeline code end to end, and it is the wrong choice if your content is short-form and does not justify a per-rendition encoding ladder. Before deploying, read the QVBR and accelerated transcoding sections, test the template against a production deployment as the readme advises, and note that the last push was on 2026-07-01 with v6.1.18 released on 2026-06-09 under an Apache-2.0 licence.

Frequently asked questions

What does the Video on Demand on AWS solution do?

It is an automated reference implementation for a video-on-demand workflow using AWS Step Functions, AWS Elemental MediaConvert and AWS Elemental MediaPackage, with S3 for source and destination, CloudFront for playback and CloudFormation for deployment. The whole pipeline is deployed from a CloudFormation template with a lambda backed custom resource.

How do I configure the Video on Demand on AWS workflow?

The workflow configuration is set at deployment as environment variables for the input-validate lambda, the first step of the ingest process. They cover the source and destination buckets, the CloudFront domain, the three MediaConvert job templates, archiving, rotation, frame capture, accelerated transcoding and SNS or SQS notifications.

What can a source metadata JSON file override in the Video on Demand workflow?

Only srcVideo is required. The other fields are archiveSource, frameCapture, srcBucket, destBucket, cloudFront, the three jobTemplate variants, a custom jobTemplate, inputRotate and a captions block with srcFile, fontSize and fontColor, and any settings not defined fall back to the environment variable defaults.

How does the Video on Demand workflow choose an encoding template?

By default the profiler step in the process step function checks the source video height and sets the jobTemplate parameter to one of the available templates, which the encoding step then passes to MediaConvert. You can also override the choice by defining jobTemplate in the source metadata file.

What licence is the Video on Demand on AWS solution released under?

Apache-2.0, with LICENSE.txt and NOTICE.txt at the root of the repository. The last push was on 2026-07-01 and the newest release is v6.1.18 from 2026-06-09, following v6.1.17 in April 2026 and v6.1.14 in September 2025.

Official sources

  1. aws-solutions-library-samples/video-on-demand-on-aws on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/aws-solutions-library-samples-video-on-demand-on-aws.svg)](https://hysenlabs.com/projects/aws-solutions-library-samples-video-on-demand-on-aws)

Was this useful?