Building an OTT Platform with AWS MediaConvert, HLS & Advertisement Playback
Building an Over-The-Top (OTT) platform involves much more than uploading a video and playing it in a browser. A complete solution needs to manage movies, advertisements, metadata, video processing, playback URLs, and the relationship between application records and cloud resources.
In this project, I worked on building an end-to-end OTT platform covering the frontend, backend, database, asynchronous video processing, HLS generation, content delivery, and advertisement workflows.
The objective was to create a workflow in which uploaded videos could be processed asynchronously, converted into a streaming-friendly format, tracked throughout their processing lifecycle, and made available for playback after successful processing.
The platform also incorporates advertisement use cases, including pre-roll, mid-roll, and post-roll playback. This introduces another important dimension: managing advertisements independently from the main content while coordinating them with the viewing experience.
1. Understanding the OTT Platform
An OTT platform delivers video content directly to viewers over the internet. Unlike traditional broadcast systems, content is delivered through internet-connected applications and devices.
From an engineering perspective, an OTT platform consists of several interconnected components:
- A frontend for interacting with the application
- A backend that exposes APIs and manages business logic
- A database for movies, advertisements, processing information, and playback metadata
- Object storage for source videos and processed media
- A video-processing pipeline for transcoding uploaded content
- A content delivery layer for serving streaming media
- Advertisement management and playback coordination
These components have different responsibilities, but they must work together to provide a seamless viewing experience.
2. The Overall Architecture
The platform separates application management from video processing. The frontend communicates with the backend, while the backend manages movie records, advertisement information, and processing metadata.
The video-processing workflow uses AWS services to handle the resource-intensive work asynchronously. Once processing is complete, the application database is updated with the relevant job status and playback information.
A separate event-handling path connects MediaConvert with EventBridge and a status-update Lambda function. This path is responsible for processing job events and updating the corresponding application record.
3. Building the Frontend, Backend, and Database
The AWS infrastructure is only one part of the platform. An OTT application also needs an application layer that manages the content and exposes it to users.
For this project, I worked on the frontend, backend, and database components that support the movie and media-processing workflows.
Frontend
The frontend provides the interface through which users interact with the platform. It communicates with the backend to retrieve movie information and the metadata required for playback.
Separating the frontend from the media-processing infrastructure means the user interface does not need to interact directly with MediaConvert or understand the internal AWS job lifecycle.
Backend
The backend provides the API layer and handles application-level operations. It connects the frontend to the database and coordinates the information needed by the media-processing workflow.
For example, when a movie is registered, the application needs to maintain its metadata and associate it with the corresponding source video and processing job.
Database
The database stores the application's movie information and the identifiers required to track asynchronous processing.
One important responsibility is maintaining the relationship between a movie and its AWS MediaConvert job. This allows the application to identify which movie should be updated when a processing event arrives.
4. Managing Movie Records and MediaConvert Job IDs
A key part of the implementation is the relationship between the application's movie records and the MediaConvert jobs created to process their videos.
The application database stores the movie information along with the MediaConvert job ID. This association is essential because MediaConvert processes videos asynchronously and reports the results through events.
Conceptually, a movie record can contain fields such as:
movie_id
title
description
video_path
media_convert_job_id
status
playback_url
The exact schema depends on the application, but the important concept is that the movie record and its processing job can be correlated.
For example:
Movie ID: 12345
MediaConvert Job ID: 167f4...
Status: PROCESSING
Playback URL: Not available yet
When MediaConvert finishes processing the video, the event contains the job identifier. The application can use that identifier to find the corresponding movie record and update its status.
Without this relationship, a completed AWS job would not provide a reliable way to identify which application record needs to be updated.
5. Uploading Videos to Amazon S3
Amazon S3 provides object storage for the source videos used by the platform. When a movie or advertisement is uploaded, its source file can be stored in S3 and referenced by the application.
A structured object-key convention helps organize the uploaded content. For example, the source video path used in the workflow can follow this pattern:
videos/
└── <uuid>/
└── test_ads.mp4
Using a unique identifier for each video helps keep the storage structure organized and makes it easier to associate a source file with its corresponding application record.
The same principle applies to advertisement assets. The application can distinguish an advertisement from regular movie content using its metadata, including the video type where applicable.
6. Why Use Asynchronous Video Processing?
Video transcoding can take significantly longer than a typical API request. The processing time depends on factors such as the source video, its duration, the selected output settings, and the processing requirements.
If the backend waits for the entire conversion to finish, it can tie up application resources and create a poor user experience.
Instead, the platform submits the video for background processing and tracks its progress independently.
This design allows the application to remain responsive while video processing continues in the background.
7. Decoupling the Workflow with Amazon SQS
Amazon SQS provides the messaging layer between the upload workflow and the Lambda function responsible for creating MediaConvert jobs.
Instead of tightly coupling the application to every step of video processing, a processing message can be placed on a queue and handled asynchronously.
The queue helps decouple the processing stages and provides a mechanism for handling messages independently of the original upload request.
In a production implementation, the SQS visibility timeout, message retry policy, dead-letter queue, and Lambda event-source configuration should be designed together to avoid repeatedly processing failed requests or creating duplicate MediaConvert jobs.
8. Creating MediaConvert Jobs with Lambda
AWS Lambda connects the queue-based workflow to MediaConvert. The function processes the incoming message, identifies the source video, prepares the job configuration, and submits the job.
A simplified workflow is:
1. Receive the SQS message
2. Identify the source video
3. Retrieve the relevant movie metadata
4. Prepare the MediaConvert job settings
5. Submit the job
6. Capture the MediaConvert job ID
7. Associate the job ID with the movie record
The actual implementation can distribute these operations across the application and processing functions. The important requirement is that the job identifier is associated with the correct movie.
This association makes it possible to trace a video from its application record through the AWS processing pipeline.
9. Converting Videos to HLS with AWS MediaConvert
AWS Elemental MediaConvert performs the video transcoding required to prepare the source content for streaming.
For this project, the processing workflow generates HTTP Live Streaming (HLS) output.
HLS is a streaming format in which a playlist references a sequence of media segments. Instead of requiring the player to download one large video file, it requests the playlist and retrieves the corresponding media segments.
A successful job can generate an HLS playlist such as:
vod-output/
└── movies/
└── <uuid>/
└── hls/
├── test_ads.m3u8
└── media segments
The playlist acts as the entry point for playback. The player reads the playlist and requests the referenced media segments.
The exact segment extensions and directory structure depend on the MediaConvert output configuration.
10. Organizing HLS Output in S3
After transcoding, MediaConvert writes the generated streaming assets to the configured S3 output location.
The output structure separates the processed video from the original source file. This makes it easier to manage source assets, processed content, and playback references independently.
For example, the application can associate the generated playlist with the movie record once processing has completed successfully. This allows the frontend to retrieve the playback information through the backend instead of constructing media paths itself.
11. Tracking Processing Status with EventBridge
Submitting a MediaConvert job does not mean that the video is ready for playback. The job may still be running, or it may eventually fail.
The application therefore needs a mechanism to receive job status updates after submission.
Amazon EventBridge receives MediaConvert job events and routes matching events to the status-update Lambda function.
The status-update function reads the job information from the event and identifies the corresponding application record using the MediaConvert job ID.
When the job completes successfully, the function can update the movie's status and save the generated HLS playback URL. When the job fails, the application can record the failure state instead.
12. Managing the Movie Processing Lifecycle
The database represents the processing state so that the frontend can determine whether a movie is ready to play.
A simplified lifecycle is:
If processing fails, the workflow follows a different path:
The application can use these states to provide appropriate feedback. For example, a movie that is still processing should not be treated as ready for playback.
A production implementation should also account for duplicate or out-of-order events, transient database failures, and retries. These are important considerations when several distributed services participate in the same workflow.
13. Storing the Final Playback URL
Once MediaConvert finishes processing a movie successfully, the application needs a way to retrieve the resulting media.
The status-update workflow obtains the generated HLS playlist location and stores the playback URL against the corresponding movie record.
Movie ID: 12345
MediaConvert Job ID: 167f4...
Status: SUCCESS
Playback URL: https://<cloudfront-domain>/movies/<uuid>/hls/test_ads.m3u8
The URL above illustrates the structure; the actual hostname and path depend on the configured distribution and output location.
Storing the playback URL means the frontend can obtain the information from the backend without needing to understand the internal MediaConvert output configuration.
14. Delivering Streaming Content with CloudFront
Amazon CloudFront provides the content delivery layer for the processed video assets.
The player accesses the HLS playlist and its referenced media segments through the configured delivery endpoint.
CloudFront can cache content at edge locations, helping reduce latency and improve delivery efficiency for viewers.
For private media, access must be configured appropriately. Depending on the design, this may involve a private S3 origin, Origin Access Control, signed URLs, or signed cookies.
The playlist and every media segment it references must be accessible under the intended authorization model. A valid playlist URL alone does not guarantee successful playback if its referenced segments cannot be retrieved.
15. Advertisement Management in an OTT Platform
In addition to movie streaming, an OTT platform can support advertisements as a separate content type.
Advertisements have their own media assets and metadata. The application needs to identify them, track their processing status, and determine when they should be presented during playback.
In the video-processing workflow, an advertisement can use the same general processing pipeline as a movie: upload the source, create a MediaConvert job, generate HLS output, and record the result.
The application can distinguish an advertisement from regular movie content using metadata such as the video type.
Video
├── video_id
├── title
├── video_type
├── source_path
├── media_convert_job_id
├── status
└── playback_url
This is a conceptual example rather than a requirement to use this exact database schema. The important point is that the application can track advertisement assets independently from movie assets.
Processing the media and deciding when to play an advertisement are separate responsibilities. A processed advertisement is available as a media asset, but playback logic is still required to determine when that asset should be shown to the viewer.
16. Pre-roll Advertisements
A pre-roll advertisement plays before the main movie begins. It is one of the simplest advertising scenarios to understand because the advertisement appears at the beginning of the viewing session.
For example, if an advertisement is 30 seconds long, the player can present the advertisement before beginning the movie.
00:00 - Pre-roll advertisement starts
00:30 - Main movie starts
The playback layer needs to know which advertisement should be played and what should happen after the advertisement finishes.
This can be implemented using player-side ad playback, an advertising integration, or a server-side streaming solution. The correct approach depends on the actual playback architecture.
17. Mid-roll Advertisements
A mid-roll advertisement plays during the main content rather than before it starts or after it finishes.
This introduces an additional requirement: the system must know where an advertisement break should occur.
For example:
00:00 - Movie starts
15:00 - Mid-roll advertisement begins
15:30 - Movie resumes
The timestamps are illustrative. Actual ad-break positions depend on the content metadata and playback implementation.
The key engineering consideration is that an ad break needs a defined position or trigger. The playback system must coordinate the advertisement with the movie timeline and resume the content at the appropriate point.
Depending on the architecture, mid-roll opportunities can be managed through player logic, playlist manipulation, or server-side ad insertion. These approaches are not interchangeable, and they should not be treated as implemented features unless the corresponding mechanism exists in the platform.
18. Post-roll Advertisements
A post-roll advertisement plays after the main movie has finished. Unlike pre-roll, which delays the start of the requested content, post-roll appears at the end of the viewing experience.
For example, after the main movie reaches its end, the player can start the configured post-roll advertisement before marking the entire viewing session as complete.
As with pre-roll and mid-roll, the player or streaming system must coordinate the transition between the main content and the advertisement.
19. Bringing Movies and Advertisements Together
The movie-processing pipeline and advertisement-processing pipeline can share the same underlying media infrastructure. However, the application needs to maintain their distinct identities and playback requirements.
The movie record identifies the main content, while advertisement metadata identifies the available ad assets and their intended usage.
This separation makes it easier to manage advertisements without treating every advertisement as part of the movie itself.
It also provides a foundation for future capabilities such as campaign management, targeting rules, frequency limits, impression tracking, and advertisement performance reporting.
20. How the Complete Workflow Fits Together
The end-to-end movie processing workflow combines application operations with AWS services.
Advertisement assets can follow the same general upload and processing workflow. Their playback placement is then handled by the advertising and playback components of the application.
21. Common Challenges in an Event-Driven OTT Platform
An event-driven architecture simplifies the separation of responsibilities, but it introduces several engineering considerations.
Correlating jobs with movies
The application needs a reliable mapping between a movie record and its MediaConvert job. Storing the job ID makes it possible to identify the correct record when a completion or failure event arrives.
Handling asynchronous failures
A submitted job may fail, a Lambda invocation may encounter a temporary error, or a database update may not succeed on the first attempt.
The system needs appropriate retry policies, error logging, and a way to reconcile jobs whose final state was not recorded correctly.
Preventing duplicate processing
Queue-based systems can deliver a message more than once. If a message is processed repeatedly, the application should avoid creating unnecessary duplicate jobs.
An idempotent processing strategy can use a stable processing identifier or an existing job record to determine whether a request has already been handled.
Handling S3 and CloudFront permissions
The output playlist and media segments must be accessible through the configured delivery path. Incorrect bucket policies, origin permissions, or URL configuration can prevent playback even when transcoding succeeds.
Keeping application state consistent
The database should reflect the actual state of the processing workflow. The application should not mark a movie as ready before the required output has been generated and made available.
Coordinating advertisement playback
Playing advertisements at the correct time requires more than having the advertisement video available. The system needs a defined ad-break position or trigger and a playback mechanism that transitions between the ad and the main content.
22. Security and IAM Considerations
Multiple AWS services interact throughout the processing workflow. Each service needs the appropriate permissions to perform its role.
The exact permissions depend on how the services are configured. The principle is to grant each role only the permissions it needs, rather than relying on broad access policies.
For private video content, access control must also account for the HLS playlist and its referenced media segments.
23. Why This Architecture?
The architecture provides several useful characteristics for an OTT application.
Separation of responsibilities
The frontend, backend, database, and media-processing services each have a defined responsibility. Video conversion does not need to run inside the application backend.
Asynchronous processing
SQS and Lambda decouple the processing request from the long-running MediaConvert job. The application can continue serving requests while conversion runs in the background.
Traceable processing
Storing the MediaConvert job ID against the movie record provides a clear relationship between application data and cloud resources.
Event-driven updates
EventBridge allows the application to respond to MediaConvert job events without continuously polling the processing service for completion.
Scalable media delivery
HLS output stored in S3 and delivered through CloudFront provides a foundation for serving processed content to viewers.
Separate advertisement workflows
Movies and advertisements can share media-processing infrastructure while retaining separate application metadata and playback requirements.
24. Potential Future Improvements
The architecture provides a foundation that can be extended with additional capabilities as the platform evolves.
- Adaptive bitrate streaming with multiple HLS renditions
- Automated processing retries and dead-letter queues
- Centralized logs, metrics, and alarms
- Content protection and DRM integration
- Subtitle and multiple-audio-track support
- Advertisement campaign management
- Advertisement impression and completion tracking
- More advanced pre-roll, mid-roll, and post-roll scheduling
- Server-side ad insertion where required
- Playback analytics and viewer engagement reporting
- Automated cleanup of temporary and obsolete media assets
- Improved reconciliation of database records and AWS job states
These are potential extensions rather than prerequisites for the core processing pipeline. Each should be introduced according to the application's functional requirements and operational needs.
Conclusion
Building an OTT platform requires the coordination of application development, database design, asynchronous processing, media transcoding, content delivery, and playback logic.
This project brought together the frontend, backend, and database with an AWS-based video-processing pipeline using S3, SQS, Lambda, MediaConvert, EventBridge, and CloudFront.
A particularly important part of the implementation was storing the MediaConvert job ID against the movie record. This made it possible to correlate asynchronous processing events with the correct application data and update the processing status and playback URL.
The advertisement workflow adds another layer to the platform. By treating advertisement assets separately from movie content, the application can support pre-roll, mid-roll, and post-roll playback scenarios through an appropriate playback mechanism.
The broader engineering lesson is that an OTT platform is not just a video player or a transcoding pipeline. It is a collection of coordinated systems that manage content from upload through processing and delivery to the final viewing experience.
Understanding how these components interact is the foundation for building a more scalable, reliable, and maintainable streaming platform.