AWS Elemental Media Services: MediaLive, MediaPackage, MediaTailor and MediaConvert Compared

Key takeaways

AWS Elemental Media Services move broadcast-style video processing into AWS. This post walks through MediaLive for live encoding, MediaPackage for packaging and origin, MediaTailor for server-side ad insertion, MediaConnect for contribution transport and MediaConvert for file-based transcoding, and notes the end of support for MediaStore.

Introduction to AWS Elemental Media Services

AWS Elemental Media Services came out of Amazon’s acquisition of Elemental Technologies, announced in 2015. They move the jobs of a broadcast facility (live encoding, packaging, ad insertion, contribution transport and file transcoding) into managed AWS services.

The AWS Elemental Portfolio

  • AWS Elemental MediaLive: real-time live video encoding
  • AWS Elemental MediaPackage: just-in-time packaging and origin for live and VOD
  • AWS Elemental MediaTailor: server-side ad insertion and channel assembly
  • AWS Elemental MediaConnect: live video transport over IP
  • AWS Elemental MediaConvert: file-based transcoding for VOD
  • AWS Elemental MediaStore: a media-optimized origin store that AWS has announced the end of support for; new designs use S3 or MediaPackage instead

Why move this to the cloud?

A traditional broadcast chain runs on dedicated hardware encoders in a facility with redundant power and cooling, operated by broadcast engineers, and sized for the biggest event of the year. Most of that capacity sits idle between events and has to be replaced on a hardware refresh cycle. The managed services turn that into capacity you start and stop per event and pay for while it runs, with direct integration into S3, CloudFront, Lambda and EventBridge. The trade-off is that you give up some low-level control and take on per-hour costs that add up quickly if channels are left running.


AWS Elemental MediaLive

Core Concepts

MediaLive is a live video encoding service. It takes input sources (RTMP, RTP, HLS, MediaConnect flows and others), transcodes them into an adaptive bitrate (ABR) ladder, and sends the result to downstream destinations such as MediaPackage, S3 or an RTMP endpoint.

Architecture Components

Input Types

MediaLive supports multiple input protocols:

RTMP push is the most common choice for software encoders and cameras. MediaLive gives you the ingest URL when you create the input, in a form like:

rtmp://203.0.113.10:1935/live/stream-key

A STANDARD channel gets two endpoints so a primary and a backup encoder can push to each pipeline.

RTP push is used by professional contribution encoders, for example rtp://203.0.113.10:5000. Over the public internet, RTP without error correction is fragile, which is why it is often carried through MediaConnect instead.

HLS pull (a URL_PULL input) ingests an existing HLS stream such as https://example.com/live/stream.m3u8; MediaLive pulls it and re-encodes.

A MediaConnect input attaches a MediaConnect flow by ARN rather than by URL (shown in the MediaConnect section). This is the usual route when the contribution leg needs FEC, ARQ or source redundancy.

An MP4 file input plays a file from S3 or HTTP(S) as if it were live, which is handy for testing or for looping filler content.

Input Security Groups

Control access to RTMP/RTP inputs via CIDR whitelists:

{
  "InputSecurityGroupId": "isg-1234567890abcdef0",
  "WhitelistRules": [
    {"Cidr": "203.0.113.0/24"},
    {"Cidr": "198.51.100.42/32"}
  ]
}

Only these source ranges can push to the input, which keeps strangers from injecting a stream into your channel.

Channels

A channel is the core encoding pipeline:

Input → Input Attachment → Channel → Output Groups → Outputs → Destinations

There are two channel classes. A STANDARD channel runs two independent pipelines in different Availability Zones; a SINGLE_PIPELINE channel runs one and costs less. The two pipelines do not fail over inside MediaLive: each one sends its own output, and the downstream origin (for example MediaPackage, which exposes two ingest endpoints) switches to the other pipeline if one stops delivering. Whether viewers notice a pipeline failure therefore depends on the origin and player as well as on MediaLive.

Output Groups

Outputs are organized into output groups by destination type. The fragments below are abbreviated. In a real channel definition, an output group does not hold a URL directly: its Destination is a DestinationRefId that points to an entry in the channel’s Destinations list, and that entry holds one URL per pipeline.

{
  "Destinations": [
    {
      "Id": "hls-s3",
      "Settings": [
        {"Url": "s3ssl://my-bucket/live/pipeline0/index"},
        {"Url": "s3ssl://my-bucket/live/pipeline1/index"}
      ]
    }
  ]
}

The HLS output group generates HLS playlists and segments:

{
  "OutputGroupSettings": {
    "HlsGroupSettings": {
      "Destination": {"DestinationRefId": "hls-s3"},
      "ManifestDurationFormat": "FLOATING_POINT",
      "SegmentLength": 6,
      "ProgramDateTimePeriod": 600
    }
  }
}

The MediaPackage output group sends to a MediaPackage channel; its destination entry uses MediaPackageSettings with the channel ID instead of URLs:

{
  "OutputGroupSettings": {
    "MediaPackageGroupSettings": {
      "Destination": {"DestinationRefId": "mediapackage"}
    }
  }
}

The archive output group records transport stream files to S3, starting a new file every RolloverInterval seconds:

{
  "OutputGroupSettings": {
    "ArchiveGroupSettings": {
      "Destination": {"DestinationRefId": "archive-s3"},
      "RolloverInterval": 3600
    }
  }
}

The frame capture output group writes JPEG thumbnails. The group only names the destination; the capture interval is set on the output’s video description (FrameCaptureSettings with CaptureInterval and CaptureIntervalUnits).

Outputs and Encoding Profiles

Each output group contains multiple outputs (bitrate ladder):

{
  "Outputs": [
    {
      "OutputName": "1080p",
      "VideoDescriptionName": "video_1080p30",
      "AudioDescriptionNames": ["audio_aac_128k"],
      "OutputSettings": {
        "HlsOutputSettings": {
          "NameModifier": "_1080p",
          "HlsSettings": {"StandardHlsSettings": {"M3u8Settings": {}}}
        }
      }
    },
    {
      "OutputName": "720p",
      "VideoDescriptionName": "video_720p30",
      "AudioDescriptionNames": ["audio_aac_128k"],
      "OutputSettings": {
        "HlsOutputSettings": {
          "NameModifier": "_720p",
          "HlsSettings": {"StandardHlsSettings": {"M3u8Settings": {}}}
        }
      }
    },
    {
      "OutputName": "480p",
      "VideoDescriptionName": "video_480p30",
      "AudioDescriptionNames": ["audio_aac_96k"],
      "OutputSettings": {
        "HlsOutputSettings": {
          "NameModifier": "_480p",
          "HlsSettings": {"StandardHlsSettings": {"M3u8Settings": {}}}
        }
      }
    }
  ]
}

Video Encode Settings

H.264/AVC is the codec every player supports:

{
  "VideoDescriptions": [
    {
      "Name": "video_1080p30",
      "CodecSettings": {
        "H264Settings": {
          "Profile": "HIGH",
          "Level": "H264_LEVEL_4_1",
          "RateControlMode": "CBR",
          "Bitrate": 5000000,
          "FramerateControl": "SPECIFIED",
          "FramerateNumerator": 30,
          "FramerateDenominator": 1,
          "GopSize": 2.0,
          "GopSizeUnits": "SECONDS",
          "SceneChangeDetect": "ENABLED",
          "LookAheadRateControl": "MEDIUM",
          "AdaptiveQuantization": "HIGH"
        }
      },
      "Width": 1920,
      "Height": 1080,
      "ScalingBehavior": "DEFAULT"
    }
  ]
}

H.265/HEVC uses larger coding blocks and more prediction modes let it reach similar quality at a noticeably lower bitrate than H.264, at the cost of more encoding compute and narrower device support:

{
  "CodecSettings": {
    "H265Settings": {
      "Profile": "MAIN",
      "Tier": "MAIN",
      "Level": "H265_LEVEL_4_1",
      "RateControlMode": "CBR",
      "Bitrate": 3000000,
      "FramerateNumerator": 30,
      "FramerateDenominator": 1,
      "GopSize": 2.0,
      "LookAheadRateControl": "MEDIUM",
      "AdaptiveQuantization": "HIGH"
    }
  }
}

For rate control, CBR keeps the bitrate constant, which makes bandwidth predictable and is the traditional choice for live delivery. VBR lets the bitrate follow scene complexity. QVBR (quality-defined variable bitrate) targets a quality level and stays under a maximum bitrate, spending fewer bits on simple scenes; AWS recommends it for most internet delivery because it reduces CDN and storage cost without a visible quality drop on easy content.

The GOP (group of pictures) settings control keyframe placement:

{
  "GopSize": 2.0,
  "GopSizeUnits": "SECONDS",
  "GopClosedCadence": 1,
  "GopBReference": "ENABLED"
}

GopSize with GopSizeUnits: SECONDS sets the keyframe interval, here one every 2 seconds. A closed GOP does not reference frames from the previous GOP, so every segment can be decoded on its own, which packagers and ad splicing rely on. B-frames improve compression at the cost of a little encoding delay.

Audio Encode Settings

AAC is the default audio codec for streaming:

{
  "AudioDescriptions": [
    {
      "Name": "audio_aac_128k",
      "CodecSettings": {
        "AacSettings": {
          "Bitrate": 128000,
          "CodingMode": "CODING_MODE_2_0",
          "SampleRate": 48000,
          "RawFormat": "NONE",
          "Profile": "LC"
        }
      },
      "AudioSelectorName": "default"
    }
  ]
}

E-AC-3 (Dolby Digital Plus) carries surround sound:

{
  "CodecSettings": {
    "Eac3Settings": {
      "Bitrate": 384000,
      "CodingMode": "CODING_MODE_3_2",
      "LfeControl": "LFE",
      "DcFilter": "ENABLED",
      "SurroundMode": "ENABLED"
    }
  }
}

Advanced Features

Automatic Input Failover

Automatic input failover pairs two inputs so that MediaLive switches to the secondary when the active one fails:

{
  "InputAttachments": [
    {
      "InputId": "input-primary-1234567890abc",
      "InputSettings": {
        "SourceEndBehavior": "CONTINUE",
        "InputFilter": "AUTO"
      },
      "AutomaticInputFailoverSettings": {
        "SecondaryInputId": "input-backup-9876543210xyz",
        "InputPreference": "PRIMARY_INPUT_PREFERRED",
        "ErrorClearTimeMsec": 60000,
        "FailoverConditions": [
          {"FailoverConditionSettings": {"InputLossSettings": {"InputLossThresholdMsec": 3000}}}
        ]
      }
    }
  ]
}

If the active input has no data for 3 seconds, MediaLive switches to the other input. Failback depends on InputPreference: with PRIMARY_INPUT_PREFERRED, MediaLive returns to the primary once it has been healthy for ErrorClearTimeMsec; with the default EQUAL_INPUT_PREFERENCE, it stays on whichever input is currently working.

SCTE-35 Ad Marker Handling

SCTE-35 messages mark where ad breaks start and end. Two separate settings matter. Whether markers reach the output is set per output container (Scte35Behavior in the HLS M3u8Settings, Scte35Control in the TS M2tsSettings), and avail blanking decides whether the program video is replaced with a slate image during the break:

{
  "AvailBlanking": {
    "State": "ENABLED",
    "AvailBlankingImage": {"Uri": "s3ssl://my-bucket/slate.png"}
  }
}
{
  "M3u8Settings": {
    "Scte35Behavior": "PASSTHROUGH",
    "Scte35Pid": "500"
  }
}

Markers can come from the input (passed through) or be created by the channel itself with a schedule action, shown below. For MediaTailor, the markers must survive all the way through MediaPackage.

Audio Normalization

Maintain consistent loudness:

{
  "AudioNormalizationSettings": {
    "Algorithm": "ITU_1770_2",
    "TargetLkfs": -23.0
  }
}

ITU-R BS.1770 defines the loudness measurement. EBU R128 broadcast in Europe targets -23 LUFS and the US ATSC A/85 recommendation targets -24 LKFS; streaming services publish their own targets, often louder, so check the requirements of where the stream is going.

Video Preprocessing

A temporal noise filter in the H.264 settings reduces noise before encoding, which saves bits on grainy sources:

{
  "FilterSettings": {
    "TemporalFilterSettings": {
      "PostFilterSharpening": "AUTO",
      "Strength": "STRENGTH_8"
    }
  }
}

Embedded Captions/Subtitles

Captions selected from the input can be embedded in the video (608/708) or written as separate tracks:

{
  "CaptionDescriptions": [
    {
      "CaptionSelectorName": "caption-selector-1",
      "Name": "caption_608",
      "DestinationSettings": {
        "EmbeddedDestinationSettings": {}
      }
    }
  ]
}

For a WebVTT sidecar track in HLS:

{
  "DestinationSettings": {
    "WebvttDestinationSettings": {}
  }
}

Generates .vtt files alongside video segments.

Scheduling and Automation

Schedule Actions

The schedule lets you switch inputs, show a slate or insert ad breaks at a given time. There is no per-action CLI command; you submit a batch to batch-update-schedule:

aws medialive batch-update-schedule \
  --channel-id 1234567 \
  --creates file://actions.json
{
  "ScheduleActions": [
    {
      "ActionName": "start-feed-0800",
      "ScheduleActionStartSettings": {"FixedModeScheduleActionStartSettings": {"Time": "2026-05-14T08:00:00.000Z"}},
      "ScheduleActionSettings": {"InputSwitchSettings": {"InputAttachmentNameReference": "main-feed"}}
    },
    {
      "ActionName": "show-slate",
      "ScheduleActionStartSettings": {"FixedModeScheduleActionStartSettings": {"Time": "2026-05-14T12:00:00.000Z"}},
      "ScheduleActionSettings": {"StaticImageActivateSettings": {"Image": {"Uri": "s3ssl://my-bucket/slate.png"}}}
    },
    {
      "ActionName": "ad-break-1",
      "ScheduleActionStartSettings": {"FixedModeScheduleActionStartSettings": {"Time": "2026-05-14T15:30:00.000Z"}},
      "ScheduleActionSettings": {"Scte35SpliceInsertSettings": {"SpliceEventId": 1, "Duration": 8100000}}
    }
  ]
}

The splice insert Duration is in 90 kHz ticks, so 8,100,000 ticks is a 90-second break.

EventBridge Integration

An EventBridge rule can trigger a Lambda function or notification on channel state changes:

{
  "source": ["aws.medialive"],
  "detail-type": ["MediaLive Channel State Change"],
  "detail": {
    "channel_arn": ["arn:aws:medialive:us-west-2:123456789012:channel:1234567"],
    "state": ["RUNNING", "IDLE", "STARTING", "STOPPING"]
  }
}

Monitoring and Troubleshooting

CloudWatch Metrics

MediaLive publishes per-channel, per-pipeline metrics in the AWS/MediaLive namespace. The ones worth an alarm or a dashboard first are ActiveAlerts (count of active channel alerts), InputVideoFrameRate (is the source arriving at the expected rate), DroppedFrames, FillMsec (time filled with fill frames because input was missing), OutputVideoFrameRate, and NetworkIn/NetworkOut. The SVQ (speed versus quality) metric is not a picture-quality score: it reports how much the encoder had to reduce quality optimizations to keep up in real time, so a rising value means the channel is short of processing headroom.

Alerting

Configure CloudWatch alarms:

aws cloudwatch put-metric-alarm \
  --alarm-name medialive-pipeline0-alerts \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 1 \
  --metric-name ActiveAlerts \
  --namespace AWS/MediaLive \
  --period 60 \
  --statistic Maximum \
  --threshold 0 \
  --dimensions Name=ChannelId,Value=1234567 Name=Pipeline,Value=0 \
  --alarm-actions arn:aws:sns:us-west-2:123456789012:ops-alerts

Logs

When you set a log level on the channel, MediaLive writes channel logs (input connection changes, encoder errors, failovers, schedule actions) to CloudWatch Logs. Channel alerts are also visible in the console and through EventBridge.


AWS Elemental MediaPackage

Overview

MediaPackage is a just-in-time packaging service and origin. It ingests encoded content from MediaLive, packages it into HLS, DASH or CMAF on request, and serves manifests and segments to a CDN. The examples below use the original MediaPackage API (aws mediapackage). AWS also offers MediaPackage v2 (aws mediapackagev2), which organizes resources as channel groups, channels and origin endpoints and supports low-latency HLS and CMAF-based DASH; new live designs are usually built on v2.

Core Concepts

Channels

A channel is the ingest point:

aws mediapackage create-channel \
  --id my-live-channel \
  --description "Live sports channel"

Response includes two redundant ingest endpoints:

{
  "Id": "my-live-channel",
  "HlsIngest": {
    "IngestEndpoints": [
      {
        "Id": "endpoint1",
        "Url": "https://abcdef.mediapackage.us-west-2.amazonaws.com/in/v2/my-live-channel/channel",
        "Username": "user-e8d9f7c6",
        "Password": "pass-a1b2c3d4"
      },
      {
        "Id": "endpoint2",
        "Url": "https://ghijkl.mediapackage.us-west-2.amazonaws.com/in/v2/my-live-channel/channel",
        "Username": "user-5f4e3d2c",
        "Password": "pass-9z8y7x6w"
      }
    ]
  }
}

Each MediaLive pipeline sends HLS to one of the two endpoints, which is what gives a STANDARD channel end-to-end redundancy.

Origin Endpoints

Origin endpoints define how content is packaged and delivered:

HLS Endpoint:

aws mediapackage create-origin-endpoint \
  --channel-id my-live-channel \
  --id hls-endpoint \
  --manifest-name index \
  --hls-package '{
    "SegmentDurationSeconds": 6,
    "PlaylistWindowSeconds": 60,
    "ProgramDateTimeIntervalSeconds": 60,
    "AdMarkers": "PASSTHROUGH",
    "IncludeIframeOnlyStream": true
  }'

Generates HLS output at:

https://abcdef.mediapackage.us-west-2.amazonaws.com/out/v1/xyz123/index.m3u8

DASH Endpoint:

aws mediapackage create-origin-endpoint \
  --channel-id my-live-channel \
  --id dash-endpoint \
  --manifest-name manifest \
  --dash-package '{
    "SegmentDurationSeconds": 6,
    "ManifestWindowSeconds": 60,
    "Profile": "NONE",
    "PeriodTriggers": ["ADS"]
  }'

Generates DASH output at:

https://abcdef.mediapackage.us-west-2.amazonaws.com/out/v1/abc456/manifest.mpd

CMAF Endpoint:

aws mediapackage create-origin-endpoint \
  --channel-id my-live-channel \
  --id cmaf-endpoint \
  --cmaf-package '{
    "SegmentDurationSeconds": 6,
    "HlsManifests": [
      {"Id": "hls", "ManifestName": "index"}
    ]
  }'

CMAF (Common Media Application Format) uses fragmented MP4 segments that both HLS and DASH players can read. In the original MediaPackage API a CMAF endpoint produces HLS manifests only; serving the same CMAF segments with a DASH manifest is one of the reasons to use MediaPackage v2.

Advanced Features

Time-Shifted Viewing (Catch-Up TV)

A startover window keeps content available behind the live edge:

{
  "StartoverWindowSeconds": 3600
}

With 3600 seconds, viewers can request the stream from up to an hour ago (for example by passing start and end times in the manifest request). Harvest jobs also need the requested range to be inside this window.

A time delay holds the live edge back:

{
  "TimeDelaySeconds": 30
}

This delays the live edge by 30 seconds, for example to give an operator time to react before content reaches viewers.

DVR (Network PVR)

Configure manifest window for DVR:

{
  "PlaylistWindowSeconds": 86400
}

This would put 24 hours of segments into every live playlist. Long playlists are large and are re-downloaded on every refresh, so a lookback window of minutes to a couple of hours is common, with longer lookback served through the startover window or harvested VOD.

Content Protection (DRM)

Encryption:

{
  "Encryption": {
    "SpekeKeyProvider": {
      "SystemIds": [
        "9a04f079-9840-4286-ab92-e65be0885f95",
        "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
      ],
      "Url": "https://drm-provider.example.com/speke",
      "ResourceId": "my-live-channel",
      "RoleArn": "arn:aws:iam::123456789012:role/MediaPackageSpeke"
    }
  }
}

The system IDs identify the DRM systems:

  • 9a04f079-9840-4286-ab92-e65be0885f95: PlayReady
  • edef8ba9-79d6-4ace-a3c8-27dcd51d21ed: Widevine
  • 94ce86fb-07ff-4f43-adb8-93d2fa968ca2: FairPlay

MediaPackage obtains keys from a DRM key provider through SPEKE (Secure Packager and Encoder Key Exchange). AWS does not issue DRM licenses itself; you use a SPEKE-compatible DRM vendor, and in practice FairPlay goes on HLS endpoints while PlayReady and Widevine go on DASH (or CMAF) endpoints.

HLS AES-128 encryption is simpler:

{
  "Encryption": {
    "EncryptionMethod": "AES_128",
    "KeyRotationIntervalSeconds": 600,
    "SpekeKeyProvider": {"...": "same key provider settings as above"}
  }
}

This is not DRM. Segments are encrypted, and the playlist carries the URI of a key server; anyone who can fetch that key can decrypt the content, so the key server’s access control is the real protection. MediaPackage still gets the keys through SPEKE.

Manifest Filtering

Stream selection filters the bitrate ladder per endpoint:

{
  "StreamSelection": {
    "MinVideoBitsPerSecond": 500000,
    "MaxVideoBitsPerSecond": 5000000,
    "StreamOrder": "ORIGINAL"
  }
}

This is useful for device-specific endpoints, for example one that leaves out the top renditions for mobile.

Ad Marker Signaling

For HLS endpoints, AdMarkers controls how ad breaks appear in playlists. PASSTHROUGH copies the cue tags from the input, SCTE35_ENHANCED generates #EXT-X-CUE-OUT/#EXT-X-CUE-IN tags with the SCTE-35 data, DATERANGE writes #EXT-X-DATERANGE tags, and NONE drops them. Which one to choose depends on what the downstream ad insertion system or player expects; MediaTailor reads the common forms.

Harvest Jobs

Export time ranges to VOD assets:

aws mediapackage create-harvest-job \
  --id game1-highlights \
  --origin-endpoint-id hls-endpoint \
  --s3-destination BucketName=my-vod-bucket,ManifestKey=highlights/game1/index.m3u8,RoleArn=arn:aws:iam::123456789012:role/MediaPackageHarvest \
  --start-time 2026-05-14T19:00:00Z \
  --end-time 2026-05-14T21:00:00Z

This writes two hours of the live stream to S3 as a VOD HLS asset, for highlights, replays or archiving. The range must still be inside the endpoint’s startover window.

VOD Assets

MediaPackage can also package VOD content:

aws mediapackage-vod create-asset \
  --id my-vod-asset \
  --source-arn arn:aws:s3:::my-bucket/videos/movie.smil \
  --source-role-arn arn:aws:iam::123456789012:role/MediaPackageVOD \
  --packaging-group-id my-packaging-group

Packaging Configurations:

aws mediapackage-vod create-packaging-configuration \
  --id hls-vod-config \
  --packaging-group-id my-packaging-group \
  --hls-package '{
    "SegmentDurationSeconds": 6,
    "HlsManifests": [{"ManifestName": "index", "IncludeIframeOnlyStream": true}]
  }'

The VOD source is an HLS playlist or a SMIL file that lists the MP4 renditions, not a single MP4. MediaPackage packages it on request into each packaging configuration in the group.

Monitoring

CloudWatch Metrics

The useful metrics are IngressBytes and IngressResponseTime for the MediaLive side, and EgressBytes, EgressResponseTime and EgressRequestCount for the CDN side. Error rates are not separate metrics: EgressRequestCount has a StatusCodeRange dimension (2xx, 4xx, 5xx), so an alarm on origin errors looks like this:

aws cloudwatch put-metric-alarm \
  --alarm-name mediapackage-egress-5xx \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 2 \
  --metric-name EgressRequestCount \
  --namespace AWS/MediaPackage \
  --period 60 \
  --statistic Sum \
  --threshold 10 \
  --dimensions Name=Channel,Value=my-live-channel Name=StatusCodeRange,Value=5xx

AWS Elemental MediaTailor

Overview

MediaTailor is a server-side ad insertion (SSAI) service. It rewrites the manifest for each viewer so that ad segments appear in the same stream as the content, which makes ads much harder for ad blockers to separate and keeps the player logic simple.

Why Server-Side Ad Insertion?

With client-side ad insertion (CSAI) the player does the work:

Player requests manifest → Manifest contains ad markers → Player calls ad server → Ad server returns ad URL → Player requests ad manifest → Player switches streams

Ad blockers can recognize the ad server calls, switching between content and ad streams can stall playback, ads and content may use different packaging or DRM, and every player platform has to implement the logic. With server-side ad insertion (SSAI) the manifest service does it:

Player requests manifest → MediaTailor fetches the origin manifest → MediaTailor calls ad server → MediaTailor inserts ad segments into the manifest → Player plays one continuous stream

The player sees one stream, ad segments come from the same CDN hostname as content, and players need no ad SDK for basic playback. The cost is that ad tracking now has to be done on the server or reported back by the player, as described below.

Core Concepts

Configurations

A playback configuration ties a content origin to an ad decision server:

aws mediatailor put-playback-configuration \
  --name my-live-channel \
  --video-content-source-url https://abcdef.mediapackage.us-west-2.amazonaws.com/out/v1/xyz123 \
  --ad-decision-server-url "https://ad-server.example.com/vast?session=[session.id]&device=[player_params.device]" \
  --cdn-configuration '{
    "AdSegmentUrlPrefix": "https://cdn.example.com/ads/",
    "ContentSegmentUrlPrefix": "https://cdn.example.com/content/"
  }' \
  --slate-ad-url https://cdn.example.com/slate.mp4

MediaTailor Playback URL:

https://abcdef.mediatailor.us-west-2.amazonaws.com/v1/master/xyz123/my-live-channel/index.m3u8

The content source URL is a prefix; MediaTailor appends the path from the playback request (index.m3u8 here). Viewers request the MediaTailor URL instead of the MediaPackage URL.

Session Initialization

When a viewer requests the manifest, MediaTailor:

  1. Calls the ad decision server (ADS) when it reaches an ad break, filling in the URL variables
  2. Receives a VAST (or VMAP) response describing the ad creatives
  3. Uses its transcoded copies of those creatives that match the content renditions
  4. Rewrites the manifest to include the ad segments
  5. Returns the personalized manifest to the player

Ad Decision Server URL:

https://ad-server.example.com/vast?uid=[player_params.user_id]&ip=[session.client_ip]&ua=[session.user_agent]&dur=[session.avail_duration_secs]

MediaTailor replaces session.* variables with values it knows about the session (client IP, user agent, break duration and so on) and player_params.* variables with parameters the player passed in its request.

VAST/VMAP Integration

A VAST (Video Ad Serving Template) response describes each ad, its media files and its tracking URLs. The duration, media files and tracking events sit inside a linear creative:

<VAST version="4.2">
  <Ad id="ad1">
    <InLine>
      <AdSystem>ExampleAdServer</AdSystem>
      <AdTitle>Example Product</AdTitle>
      <Impression>https://ad-server.example.com/track/impression?ad=ad1</Impression>
      <Creatives>
        <Creative>
          <Linear>
            <Duration>00:00:30</Duration>
            <TrackingEvents>
              <Tracking event="start">https://ad-server.example.com/track/start?ad=ad1</Tracking>
              <Tracking event="firstQuartile">https://ad-server.example.com/track/q1?ad=ad1</Tracking>
              <Tracking event="midpoint">https://ad-server.example.com/track/mid?ad=ad1</Tracking>
              <Tracking event="complete">https://ad-server.example.com/track/complete?ad=ad1</Tracking>
            </TrackingEvents>
            <MediaFiles>
              <MediaFile delivery="progressive" type="video/mp4" width="1920" height="1080">
                https://ad-cdn.example.com/ad123.mp4
              </MediaFile>
            </MediaFiles>
          </Linear>
        </Creative>
      </Creatives>
    </InLine>
  </Ad>
</VAST>

VMAP (Video Multiple Ad Playlist) describes where breaks go in a VOD asset:

<vmap:VMAP xmlns:vmap="http://www.iab.net/videosuite/vmap" version="1.0">
  <vmap:AdBreak timeOffset="start" breakType="linear" breakId="preroll">
    <vmap:AdSource id="preroll-ad">
      <vmap:VASTAdData>
        <VAST>...</VAST>
      </vmap:VASTAdData>
    </vmap:AdSource>
  </vmap:AdBreak>
  <vmap:AdBreak timeOffset="00:05:00" breakType="linear" breakId="midroll-1">
    <vmap:AdSource id="midroll-ad-1">
      <vmap:VASTAdData>
        <VAST>...</VAST>
      </vmap:VASTAdData>
    </vmap:AdSource>
  </vmap:AdBreak>
</vmap:VMAP>

Each AdBreak gives a time offset and the VAST data for that break.

Manifest Manipulation

HLS Manifest Personalization

Original MediaPackage Manifest:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:1000
#EXTINF:6.0,
segment1000.ts
#EXTINF:6.0,
segment1001.ts
#EXT-X-DATERANGE:ID="splice-1",START-DATE="2026-05-14T20:00:00.000Z",DURATION=18,SCTE35-OUT=0xFC30...
#EXTINF:6.0,
segment1002.ts

MediaTailor Personalized Manifest:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:1000
#EXTINF:6.0,
https://cdn.example.com/content/segment1000.ts?aws.sessionId=xyz
#EXTINF:6.0,
https://cdn.example.com/content/segment1001.ts?aws.sessionId=xyz
#EXT-X-DISCONTINUITY
#EXTINF:6.0,
https://cdn.example.com/ads/ad-seg1.ts?aws.sessionId=xyz
#EXTINF:6.0,
https://cdn.example.com/ads/ad-seg2.ts?aws.sessionId=xyz
#EXTINF:6.0,
https://cdn.example.com/ads/ad-seg3.ts?aws.sessionId=xyz
#EXT-X-DISCONTINUITY
#EXTINF:6.0,
https://cdn.example.com/content/segment1002.ts?aws.sessionId=xyz

In this simplified example MediaTailor found an 18-second ad break, got ads from the ad server and inserted three 6-second ad segments in place of the content for that duration. The #EXT-X-DISCONTINUITY tags tell the player that timestamps and encoding parameters change at the boundary, and the segment URLs were rewritten to the CDN prefixes from the configuration. If the ads returned are shorter than the break, MediaTailor fills the rest with the slate.

Ad Transcoding

Ad creatives arrive as mezzanine files that rarely match the content’s renditions. MediaTailor transcodes each new creative into renditions that match the content and caches the result. The first time a creative is returned by the ad server it is not ready yet, so it is skipped (and the time filled by other ads or slate) until transcoding finishes. That is why a brand-new campaign can appear to “not show” for its first requests.

Tracking and Beacons

Server-Side Beacon Firing

There are two ways to report ad playback.

With server-side reporting, the default, MediaTailor fires the VAST impression and quartile beacons itself. Ad segment URLs in the personalized manifest point back through MediaTailor, so when the player requests the segment at each quartile position, MediaTailor knows how far the viewer got and calls the tracking URLs.

With client-side reporting, the player initializes a session with MediaTailor and then polls the session’s tracking URL. The response lists the ad breaks with their timing and tracking URLs, and the player (or an ad measurement SDK such as Open Measurement) fires the beacons as playback reaches each point. This is more accurate for viewability, and some ad buyers require it.

Personalization

Dynamic Configuration Variables

Player parameters must be prefixed with ads. in the playback request:

https://abcdef.mediatailor.us-west-2.amazonaws.com/v1/master/xyz123/my-live-channel/index.m3u8?ads.user_id=12345&ads.device=mobile

With an ADS URL template of https://ad-server.example.com/vast?uid=[player_params.user_id]&device=[player_params.device], MediaTailor calls:

https://ad-server.example.com/vast?uid=12345&device=mobile

Avail Suppression

Avail suppression controls whether MediaTailor fills ad breaks near the live edge when a session starts:

{
  "AvailSuppression": {
    "Mode": "BEHIND_LIVE_EDGE",
    "Value": "00:00:05"
  }
}

With BEHIND_LIVE_EDGE, MediaTailor does not fill ad breaks that are at or behind the live edge minus the value, so a viewer joining partway through a break sees the content (or slate) instead of an ad that would start late. It is not a per-user switch; to skip ads for premium subscribers, have the ad server return an empty response for them or use a separate playback configuration.

VOD Ad Insertion

VOD Configuration:

aws mediatailor put-playback-configuration \
  --name my-vod-asset \
  --video-content-source-url https://cdn.example.com/vod/movie.m3u8 \
  --ad-decision-server-url https://ad-server.example.com/vmap \
  --personalization-threshold-seconds 1

For VOD, ad break positions come from markers in the content manifest or from a VMAP response, and MediaTailor builds the whole personalized manifest when the session starts. --personalization-threshold-seconds is the largest unfilled gap MediaTailor tolerates in an ad break; if the ads leave more than that unfilled, it fills the rest with slate (live) or shortens the break (VOD).

Channel Assembly

Channel assembly builds a linear channel out of existing VOD assets without re-encoding them. You register where the assets live, define each asset as a VOD source, create a channel, and add programs to its schedule:

aws mediatailor create-source-location \
  --source-location-name my-vod-library \
  --http-configuration BaseUrl=https://cdn.example.com/vod/

aws mediatailor create-vod-source \
  --source-location-name my-vod-library \
  --vod-source-name movie1 \
  --http-package-configurations '[{"Path": "movie1/index.m3u8", "SourceGroup": "hls", "Type": "HLS"}]'

aws mediatailor create-channel \
  --channel-name my-linear-channel \
  --playback-mode LOOP \
  --outputs '[{"ManifestName": "index", "SourceGroup": "hls", "HlsPlaylistSettings": {"ManifestWindowSeconds": 30}}]'

aws mediatailor create-program \
  --channel-name my-linear-channel \
  --program-name program-1 \
  --source-location-name my-vod-library \
  --vod-source-name movie1 \
  --schedule-configuration '{"Transition": {"Type": "RELATIVE", "RelativePosition": "AFTER_PROGRAM"}}'

With LOOP playback the schedule repeats. Programs can declare ad breaks with --ad-breaks, and putting a MediaTailor playback configuration in front of the channel output fills them.

Monitoring

CloudWatch Metrics

Start with AdDecisionServer.Errors and AdDecisionServer.Duration (is the ad server failing or slow), Avail.Duration and Avail.FillRate (how much of each break gets filled), and GetManifest.Errors and Origin.Errors (is playback itself failing). A low fill rate with no ADS errors usually means the ad server returned too few ads or creatives that are still being transcoded.


AWS Elemental MediaStore

MediaStore was a storage service tuned as a low-latency origin for live HLS and DASH segments. AWS has announced the end of support for MediaStore, so it should not appear in a new design. MediaLive can write HLS straight to S3, and MediaPackage (especially v2) covers the live origin role with just-in-time packaging, DRM and time-shift features. If you are migrating an existing MediaStore workflow, the main things to recheck are write latency for short segments, CORS rules on the new origin, and restricting the origin to the CDN (CloudFront origin access control for S3) rather than relying on header checks.


AWS Elemental MediaConnect

Overview

MediaConnect transports live video into, within and out of AWS. It is used where satellite or dedicated fiber would traditionally carry a contribution or distribution feed, adding error recovery, encryption and source redundancy on top of internet or Direct Connect paths.

Use Cases

On the contribution side, typical uses are bringing feeds from a venue into the cloud for remote production and providing a backup contribution path. On the distribution side, MediaConnect sends feeds to partner stations or other regions, and it feeds MediaLive with redundant sources.

Core Concepts

Flows

A flow is a live video transport connection:

aws mediaconnect create-flow \
  --name remote-camera-feed \
  --source Name=Camera-1,Protocol=zixi-push,IngestPort=2088,WhitelistCidr=203.0.113.0/24

Supported transport protocols include:

  • Zixi (push): proprietary protocol over UDP with ARQ and FEC, common in broadcast contribution
  • RIST: Reliable Internet Stream Transport, an open specification with ARQ
  • RTP and RTP-FEC: plain RTP, optionally with SMPTE 2022-1 forward error correction
  • SRT (listener or caller): Secure Reliable Transport, an open-source protocol with ARQ and AES encryption
  • CDI and SMPTE ST 2110 JPEG XS: uncompressed or lightly compressed video inside a VPC, for live production workflows that run in AWS

Sources

For a push source, the encoder sends to the flow’s ingest IP and port. Only addresses in the whitelist CIDR are accepted:

aws mediaconnect update-flow-source \
  --flow-arn arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123 \
  --source-arn arn:aws:mediaconnect:us-west-2:123456789012:source:src-xyz \
  --ingest-port 5000 \
  --whitelist-cidr 203.0.113.42/32

For a source where MediaConnect connects out to the encoder, use SRT in caller mode:

aws mediaconnect create-flow \
  --name venue-encoder-feed \
  --source Name=Encoder,Protocol=srt-caller,SourceListenerAddress=203.0.113.42,SourceListenerPort=5000

Outputs

To feed MediaLive, create a MediaLive input of type MEDIACONNECT that references the flow. MediaLive adds the outputs it needs to the flow itself; you do not create an RTP output by hand:

aws medialive create-input \
  --name from-mediaconnect \
  --type MEDIACONNECT \
  --media-connect-flows FlowArn=arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123 \
  --role-arn arn:aws:iam::123456789012:role/MediaLiveAccessRole

For a STANDARD channel, pass two flows (ideally in different Availability Zones), one per pipeline.

Entitlements share a flow with another AWS account:

aws mediaconnect grant-flow-entitlements \
  --flow-arn arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123 \
  --entitlements Name=Partner-A,Subscribers=210987654321

The partner account then creates a flow in its own account whose source is that entitlement.

Redundancy

With two sources on one flow, source failover keeps the feed going:

aws mediaconnect update-flow \
  --flow-arn arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123 \
  --source-failover-config State=ENABLED,FailoverMode=MERGE,SourcePriority={"PrimarySource":"source-1"}

MERGE combines packets from both sources, so a packet lost on one path can be taken from the other without a visible switch; it requires both sources to carry identical streams over a protocol that supports it, such as RTP. FAILOVER switches to the other source when the primary stops.

Monitoring

CloudWatch Metrics

Watch the source bitrate, packet loss before and after recovery, and the number of packets recovered by ARQ or FEC. A steady rise in recovered packets is an early warning that the network path is degrading even while the picture is still clean. Check the MediaConnect documentation for the exact metric names for your protocol.


AWS Elemental MediaConvert

Overview

MediaConvert is a file-based transcoding service for VOD. It converts source files (MP4, MOV, MXF and others) into adaptive bitrate packages and broadcast deliverables.

Job Submission

aws mediaconvert create-job \
  --role arn:aws:iam::123456789012:role/MediaConvertRole \
  --settings file://job-settings.json

job-settings.json:

{
  "Inputs": [
    {
      "FileInput": "s3://my-source-bucket/input-video.mp4",
      "TimecodeSource": "ZEROBASED",
      "VideoSelector": {},
      "AudioSelectors": {
        "Audio Selector 1": {"DefaultSelection": "DEFAULT"}
      }
    }
  ],
  "OutputGroups": [
    {
      "Name": "HLS ABR",
      "OutputGroupSettings": {
        "Type": "HLS_GROUP_SETTINGS",
        "HlsGroupSettings": {
          "Destination": "s3://my-output-bucket/hls/",
          "SegmentLength": 6,
          "MinSegmentLength": 0,
          "ManifestDurationFormat": "FLOATING_POINT",
          "SegmentControl": "SEGMENTED_FILES"
        }
      },
      "Outputs": [
        {
          "NameModifier": "_1080p",
          "ContainerSettings": {"Container": "M3U8"},
          "VideoDescription": {
            "CodecSettings": {
              "Codec": "H_264",
              "H264Settings": {
                "RateControlMode": "QVBR",
                "QvbrSettings": {"QvbrQualityLevel": 8},
                "MaxBitrate": 5000000
              }
            },
            "Width": 1920,
            "Height": 1080
          },
          "AudioDescriptions": [
            {
              "CodecSettings": {
                "Codec": "AAC",
                "AacSettings": {"Bitrate": 128000, "SampleRate": 48000, "CodingMode": "CODING_MODE_2_0"}
              }
            }
          ]
        }
      ]
    }
  ]
}

Advanced Features

With QVBR you set a quality level (1 to 10) and a maximum bitrate instead of a fixed bitrate; MaxBitrate is the cap, and Bitrate is not used in this mode. On top of that, automated ABR (AutomatedEncodingSettings on an HLS, DASH or CMAF group) lets MediaConvert choose how many renditions to create and at which resolutions and bitrates, based on the content.

HDR Support

For HDR10 output, color conversion and the mastering display metadata go in the color corrector preprocessor, and the output codec must be HEVC with a 10-bit profile:

{
  "VideoDescription": {
    "ColorMetadata": "INSERT",
    "VideoPreprocessors": {
      "ColorCorrector": {
        "ColorSpaceConversion": "FORCE_HDR10",
        "Hdr10Metadata": {
          "RedPrimaryX": 34000,
          "RedPrimaryY": 16000,
          "GreenPrimaryX": 13250,
          "GreenPrimaryY": 34500,
          "BluePrimaryX": 7500,
          "BluePrimaryY": 3000,
          "WhitePointX": 15635,
          "WhitePointY": 16450,
          "MaxFrameAverageLightLevel": 400,
          "MaxContentLightLevel": 1000
        }
      }
    }
  }
}

The primaries are in units of 0.00002, so these values describe a P3 mastering display with a D65 white point. Use the values from your source’s mastering metadata rather than copying these. Dolby Vision output needs Dolby Vision metadata in the source as well.

Audio Processing

To keep a Dolby Atmos (E-AC-3 JOC) track as it is, pass the audio through instead of re-encoding:

{
  "AudioDescriptions": [
    {
      "CodecSettings": {
        "Codec": "PASSTHROUGH"
      }
    }
  ]
}

Architecture Patterns

Live Streaming Architecture

The basic live workflow:

Encoder (RTMP) → MediaLive (Transcode) → MediaPackage (Origin) → CloudFront (CDN) → Viewers

With ad insertion, MediaTailor logically sits between the origin and the viewers. In practice CloudFront is in front of both, routing manifest requests to MediaTailor and segment requests to the origin or the ad segment location:

Encoder → MediaLive (w/ SCTE-35) → MediaPackage → MediaTailor (SSAI) → CloudFront → Viewers

With redundant contribution:

Encoder (Primary) ─┐
                   ├─→ MediaConnect (Merge) → MediaLive → MediaPackage → CloudFront
Encoder (Backup) ─┘

VOD Workflow

Source File (S3) → MediaConvert (Transcode) → S3 (ABR Assets) → CloudFront → Viewers

With DRM applied at packaging time:

Source → MediaConvert → S3 → MediaPackage VOD (SPEKE Encryption) → CloudFront → Viewers

Hybrid Live-to-VOD

Encoder → MediaLive → MediaPackage (Live) → harvest job → S3 (Recording)
                                  ↓
                            CloudFront (Live)
                                  
S3 Archive → MediaConvert (Trim/Edit) → S3 VOD → CloudFront (VOD)

Multi-Region Resilience

Encoder (Primary) → MediaLive (us-west-2) → MediaPackage (us-west-2) → CloudFront
                                                                              ↓
Encoder (Backup) → MediaLive (us-east-1) → MediaPackage (us-east-1) ────────┘

CloudFront origin failover or Route 53 health checks switch viewers between regions. Running two full regions doubles the cost, so this is usually reserved for events where an outage is unacceptable.


Pricing

All of these services are billed by usage, and the rates change by region and over time, so the AWS pricing pages and the AWS Pricing Calculator are the only reliable source. What drives the bill differs per service:

  • MediaLive: per running hour for each input and each output, with rates that depend on codec, resolution, frame rate and channel class. A STANDARD channel runs two pipelines.
  • MediaPackage: data ingested and data delivered from the origin. With a CDN in front, origin egress is a fraction of what viewers download, which is the main reason to put CloudFront there.
  • MediaTailor: ad insertions for SSAI and channel hours for channel assembly.
  • MediaConnect: flow hours plus data transfer out.
  • MediaConvert: per minute of output, depending on resolution, codec, frame rate and pricing tier (or a reserved queue).

For live work the number to watch is running hours: an idle MediaLive channel that was never stopped costs the same as one carrying an event.


Live-channel settings that fail quietly

A few settings decide whether a live event survives trouble, and none of them produce an error when they are wrong; you only find out mid-event.

Pipeline redundancy has to reach the origin. A STANDARD MediaLive channel runs two independent pipelines, and it only protects you if each pipeline sends to its own ingest endpoint (MediaPackage channels expose two for this reason) and the origin fails over between them. Pointing both pipelines at the same destination, or using a SINGLE_PIPELINE channel to save money, removes that protection while the channel still looks healthy in the console.

Plan for input loss before it happens. When the contribution feed drops, MediaLive’s input loss behavior decides what viewers see: it can repeat the last frame for a set time, then switch to black, a solid color, or a slate image you upload. Leaving the defaults means viewers get a frozen or black frame with no explanation; configuring a slate (“We’ll be right back”) costs nothing and is far better for a live audience.

Keep GOP and segment lengths aligned. Use closed GOPs and make the HLS/DASH segment length a whole multiple of the GOP duration, so every segment starts on a keyframe. Misaligned values still produce playable streams, but the packager can only cut at keyframes, so segment durations drift from the target and renditions stop sharing the same boundaries, which makes bitrate switching and ad-break splicing less clean.

Push inputs need an input security group. RTMP and RTP push inputs only accept traffic from the CIDR ranges in their input security group. An on-site encoder behind a connection whose public IP changes will simply fail to connect, and from the channel’s side it just looks like no input is arriving (the whitelist format is shown in the Input Security Groups section above). Confirm the venue’s outbound IP before the event, or use a pull input or MediaConnect flow instead.


Choosing which Elemental services a workflow needs

Most workflows need fewer of these services than the architecture diagrams suggest. For file-based video on demand, MediaConvert writing HLS or DASH to S3 behind CloudFront is often the whole pipeline. Add MediaPackage when you want to store one set of outputs and package them just in time into several formats or DRM schemes, instead of storing each variant. For live streams, MediaLive encodes and MediaPackage (or S3 for simple HLS) serves as the origin. MediaConnect is for moving contribution feeds reliably into AWS over protocols such as SRT or Zixi, and MediaTailor matters only if you insert ads server side. For MediaStore, AWS has announced the end of support, so check its current status before designing around it; S3 or MediaPackage cover the origin role in new designs.

The cost mistake to avoid is leaving MediaLive channels running. A channel bills while it is running whether or not any input arrives, and a standard channel runs two pipelines. Stop channels between events, and automate starting and stopping them around a schedule.


References