AWS Elemental로 클라우드 비디오 처리 파이프라인 구성하기
이 글의 핵심
인코더와 오리진 서버를 직접 운영하면 장애 대응과 확장이 큰 부담이 되는데, AWS Elemental은 이 구간을 서비스별로 나눠 관리형으로 제공합니다. 각 서비스의 역할과 연결 지점, 매니페스트 조작과 광고 비콘 추적, 스케줄링과 모니터링 포인트를 짚어 라이브와 VOD 파이프라인을 어떤 조합으로 구성할지 결정할 수 있게 합니다.
AWS Elemental 미디어 서비스 소개
AWS Elemental 미디어 서비스는 아마존이 2015년에 인수한 Elemental Technologies의 방송용 비디오 처리 기술을 클라우드 서비스로 제공하는 제품군입니다. 하드웨어 인코더와 오리진 서버를 직접 운영하는 대신, 수집·인코딩·패키징·광고 삽입·전송 단계를 서비스 단위로 나눠 관리형으로 쓸 수 있습니다.
제품군 구성
- AWS Elemental MediaLive: 실시간 라이브 비디오 인코딩 및 트랜스코딩
- AWS Elemental MediaPackage: 저스트 인 타임 비디오 패키징 및 오리진
- AWS Elemental MediaTailor: 서버 사이드 광고 삽입과 채널 어셈블리
- AWS Elemental MediaConnect: IP 기반의 안정적인 라이브 비디오 전송
- AWS Elemental MediaConvert: VOD용 파일 기반 비디오 트랜스코딩
- AWS Elemental MediaStore: 미디어용 오리진 스토리지였으나 2025년 11월 13일에 지원이 종료되었습니다. 새 설계에서는 S3나 MediaPackage를 오리진으로 씁니다.
직접 구축과 비교했을 때의 차이
전통적인 방송 인프라는 고가의 하드웨어 인코더, 이중화된 전원과 냉각을 갖춘 설비, 방송 엔지니어링 인력, 그리고 결승전이나 선거 개표 같은 피크에 맞춘 과다 프로비저닝을 요구합니다. 하드웨어 교체 주기도 길어서 새 코덱을 도입하기가 느립니다.
관리형 서비스로 옮기면 장비 구매 비용이 사라지고 이벤트가 있을 때만 채널을 띄울 수 있으며, S3, CloudFront, Lambda, EventBridge 같은 AWS 서비스와 바로 연결됩니다. 대신 채널이 실행되는 동안은 입력이 들어오든 안 들어오든 계속 과금되므로, 24시간 채널이 아니라면 이벤트가 끝난 뒤 채널을 중지하는 운영 절차가 필요합니다.
AWS Elemental MediaLive
핵심 개념
MediaLive는 라이브 비디오 스트림을 실시간으로 처리하는 인코딩 서비스입니다. 입력 소스(RTMP, RTP, HLS, MediaConnect 등)를 받아 적응형 비트레이트(ABR) 렌디션으로 인코딩하고, MediaPackage나 S3 같은 다운스트림으로 출력합니다.
아키텍처 구성 요소
입력 타입
RTMP push는 소프트웨어 인코더와 카메라에서 가장 흔히 쓰는 방식입니다. 인코더가 MediaLive가 발급한 엔드포인트로 스트림을 밀어 넣습니다.
rtmp://a.b.c.d:1935/live/stream-key
STANDARD 채널에서는 엔드포인트가 두 개 발급되므로, 인코더가 두 곳에 모두 보내야 두 파이프라인이 각각 입력을 받습니다.
RTP push는 전문 방송 장비에서 MPEG-TS over RTP로 보낼 때 씁니다. MediaLive는 RTSP 입력은 지원하지 않습니다.
rtp://a.b.c.d:5000
HLS pull은 이미 HLS로 송출 중인 소스를 MediaLive가 가져와 다시 인코딩하는 방식입니다.
https://example.com/live/stream.m3u8
MediaConnect 입력은 URL 대신 MediaConnect 플로우 ARN을 참조합니다. FEC, ARQ, 소스 이중화가 필요한 전문 워크플로에 적합하며, STANDARD 채널에서는 서로 다른 가용 영역에 있는 플로우 두 개를 지정해야 합니다.
MP4/TS 파일 입력은 S3나 HTTP에 있는 파일을 라이브 소스처럼 재생하는 방식으로, 테스트나 반복 재생 채널에 유용합니다.
s3ssl://my-bucket/input.mp4
입력 보안 그룹
RTMP/RTP push 입력은 입력 보안 그룹으로 접근을 허용할 CIDR을 제한합니다.
{
"InputSecurityGroupId": "isg-1234567890abcdef0",
"WhitelistRules": [
{"Cidr": "203.0.113.0/24"},
{"Cidr": "198.51.100.42/32"}
]
}
여기 나열한 IP만 입력으로 푸시할 수 있습니다. 스트림 키가 노출되더라도 허용 범위 밖에서는 스트림을 보낼 수 없으므로, push 입력에는 넓은 범위(0.0.0.0/0)를 쓰지 않는 편이 좋습니다.
채널
채널은 인코딩 파이프라인 자체입니다.
Input → Input Attachment → Channel → Output Groups → Outputs → Destinations
채널 클래스는 두 가지입니다. STANDARD는 서로 다른 가용 영역에서 동일한 파이프라인 두 개를 실행하고, SINGLE_PIPELINE은 파이프라인 하나만 실행하므로 더 저렴하지만 파이프라인 장애에 대한 보호가 없습니다.
STANDARD 클래스에서 한 파이프라인이 멈추면 다른 파이프라인의 출력이 계속 다운스트림에 도달합니다. 시청자에게 끊김 없이 넘어가려면 다운스트림(MediaPackage의 이중화 수집 엔드포인트 등)이 두 출력을 받아 전환할 수 있어야 하므로, 채널 클래스만 바꾼다고 이중화가 완성되지는 않습니다.
출력 그룹과 대상
출력 그룹 설정에는 URL을 직접 넣지 않고 DestinationRefId로 채널의 Destinations 항목을 참조합니다. STANDARD 채널은 파이프라인마다 대상이 하나씩 필요하므로 URL도 두 개를 넣습니다.
{
"Destinations": [
{
"Id": "hls-dest",
"Settings": [
{"Url": "s3ssl://my-bucket/live/pipeline0/index"},
{"Url": "s3ssl://my-bucket/live/pipeline1/index"}
]
},
{
"Id": "mp-dest",
"MediaPackageSettings": [{"ChannelId": "my-live-channel"}]
}
]
}
HLS 출력 그룹은 HLS 매니페스트와 세그먼트를 생성합니다.
{
"OutputGroupSettings": {
"HlsGroupSettings": {
"Destination": {"DestinationRefId": "hls-dest"},
"ManifestDurationFormat": "FLOATING_POINT",
"SegmentLength": 6,
"ProgramDateTimePeriod": 600
}
}
}
MediaPackage 출력 그룹은 MediaPackage 채널로 바로 전송하며, 수집 URL과 인증 정보를 따로 관리하지 않아도 됩니다.
{
"OutputGroupSettings": {
"MediaPackageGroupSettings": {
"Destination": {"DestinationRefId": "mp-dest"}
}
}
}
Archive 출력 그룹은 TS 파일을 일정 간격으로 끊어 S3에 기록합니다. RolloverInterval은 초 단위입니다.
{
"OutputGroupSettings": {
"ArchiveGroupSettings": {
"Destination": {"DestinationRefId": "archive-dest"},
"RolloverInterval": 3600
}
}
}
Frame Capture 출력 그룹은 썸네일 JPEG를 추출합니다. 추출 간격은 출력 그룹이 아니라 해당 출력이 쓰는 비디오 설명의 FrameCaptureSettings에서 지정합니다.
{
"VideoDescriptions": [
{
"Name": "thumbnail",
"CodecSettings": {
"FrameCaptureSettings": {
"CaptureInterval": 30,
"CaptureIntervalUnits": "SECONDS"
}
},
"Width": 640,
"Height": 360
}
]
}
출력과 비트레이트 래더
각 출력 그룹에는 여러 출력이 들어가고, 각 출력은 비디오 설명과 오디오 설명을 이름으로 참조합니다.
{
"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": {}}}
}
}
}
]
}
비디오 인코딩 설정
H.264/AVC는 지원 기기 범위가 가장 넓습니다.
{
"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",
"ScanType": "PROGRESSIVE"
}
},
"Width": 1920,
"Height": 1080,
"ScalingBehavior": "DEFAULT"
}
]
}
ScanType을 PROGRESSIVE로 두면 인터레이스 입력은 인코딩 과정에서 디인터레이싱됩니다.
H.265/HEVC는 같은 화질을 더 낮은 비트레이트로 낼 수 있지만, 인코딩 비용이 더 들고 재생 기기 지원 범위가 H.264보다 좁습니다. 그래서 보통 H.264 래더를 기본으로 두고 HEVC 렌디션을 추가하는 식으로 씁니다.
{
"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"
}
}
}
레이트 컨트롤 모드는 세 가지입니다. CBR은 대역폭이 일정해 라이브 전송에서 예측하기 쉽고, VBR은 장면 복잡도에 따라 비트레이트가 변해 품질 대비 효율이 좋지만 대역폭 예측이 어렵습니다. QVBR은 목표 품질 수준과 최대 비트레이트를 정하면 단순한 장면에서는 비트를 아끼고 복잡한 장면에서는 최대치까지 쓰는 방식입니다.
GOP 구조는 다음처럼 지정합니다.
{
"GopSize": 2.0,
"GopSizeUnits": "SECONDS",
"GopClosedCadence": 1,
"GopBReference": "ENABLED"
}
GopSize는 키프레임 간격으로, 위 설정은 2초마다 키프레임을 넣습니다. GopClosedCadence는 몇 개의 GOP마다 closed GOP를 둘지 정하며, closed GOP는 앞 GOP를 참조하지 않으므로 세그먼트 경계에서 탐색과 광고 삽입이 깔끔해집니다. B-프레임 참조는 압축 효율을 높이지만 디코딩 순서 때문에 지연이 약간 늘어납니다.
오디오 인코딩 설정
AAC는 스트리밍의 기본 오디오 코덱입니다. AudioSelectorName은 입력 연결에서 정의한 오디오 셀렉터 이름과 일치해야 합니다.
{
"AudioDescriptions": [
{
"Name": "audio_aac_128k",
"CodecSettings": {
"AacSettings": {
"Bitrate": 128000,
"CodingMode": "CODING_MODE_2_0",
"SampleRate": 48000,
"RawFormat": "NONE",
"Profile": "LC"
}
},
"AudioSelectorName": "default"
}
]
}
서라운드 사운드가 필요하면 Dolby Digital Plus(EAC-3)를 씁니다.
{
"CodecSettings": {
"Eac3Settings": {
"Bitrate": 384000,
"CodingMode": "CODING_MODE_3_2",
"LfeControl": "LFE",
"DcFilter": "ENABLED",
"SurroundMode": "ENABLED"
}
}
}
고급 기능
자동 입력 페일오버
입력 두 개를 채널에 붙이고 한쪽을 다른 쪽의 보조 입력으로 지정합니다.
{
"InputAttachments": [
{
"InputId": "input-primary-1234567890abc",
"InputAttachmentName": "main-feed",
"InputSettings": {
"SourceEndBehavior": "CONTINUE",
"InputFilter": "AUTO"
},
"AutomaticInputFailoverSettings": {
"SecondaryInputId": "input-backup-9876543210xyz",
"InputPreference": "PRIMARY_INPUT_PREFERRED",
"ErrorClearTimeMsec": 60000,
"FailoverConditions": [
{"FailoverConditionSettings": {"InputLossSettings": {"InputLossThresholdMsec": 3000}}}
]
}
}
]
}
기본 입력이 3초 동안 끊어지면 백업으로 전환합니다. 기본 입력으로 자동 복귀(페일백)하는 것은 InputPreference가 PRIMARY_INPUT_PREFERRED일 때뿐이며, 이때 기본 입력이 ErrorClearTimeMsec(여기서는 60초) 동안 안정적이어야 돌아갑니다. 기본값인 EQUAL_INPUT_PREFERENCE에서는 백업으로 넘어간 뒤 그대로 머뭅니다.
SCTE-35 광고 마커 처리
입력에 들어온 SCTE-35 메시지를 HLS 출력에 전달하려면 출력의 M3u8Settings에서 전달을 켜고, HLS 출력 그룹에서 매니페스트에 쓸 광고 마커 형식을 고릅니다.
{
"HlsGroupSettings": {
"AdMarkers": ["ELEMENTAL_SCTE35"]
},
"M3u8Settings": {
"Scte35Behavior": "PASSTHROUGH",
"Scte35Pid": "500"
}
}
Scte35Behavior는 PASSTHROUGH(전달)와 NO_PASSTHROUGH(제거) 중 하나입니다. 광고 구간 동안 원본 화면을 가려야 한다면 avail blanking을 켜고 대체 이미지를 지정합니다.
{
"AvailBlanking": {
"State": "ENABLED",
"AvailBlankingImage": {"Uri": "s3ssl://my-bucket/slate.png"}
}
}
오디오 정규화
채널이나 광고마다 음량이 달라 시청자가 볼륨을 계속 조절하는 문제를 줄이려면 음량 정규화를 켭니다.
{
"AudioNormalizationSettings": {
"Algorithm": "ITU_1770_2",
"AlgorithmControl": "CORRECT_AUDIO",
"TargetLkfs": -23.0
}
}
ITU-R BS.1770은 음량 측정 표준이며, LKFS와 LUFS는 같은 단위입니다. 유럽 방송(EBU R128)은 -23 LUFS, 미국 방송(ATSC A/85)은 -24 LKFS를 기준으로 하고, 스트리밍 플랫폼은 그보다 큰 값(-14~-16 LUFS 부근)을 쓰는 경우가 많으므로 송출 대상의 기준을 확인해 맞춥니다.
노이즈 감소
H.264 설정의 시간 필터는 프레임 간 노이즈를 줄여 같은 비트레이트에서 화질을 높입니다. 강도를 너무 높이면 디테일이 뭉개지므로 소스 상태를 보고 조절합니다.
{
"FilterSettings": {
"TemporalFilterSettings": {
"PostFilterSharpening": "AUTO",
"Strength": "STRENGTH_8"
}
}
}
자막
입력의 CEA-608/708 자막을 출력 비디오에 그대로 임베드할 수 있습니다.
{
"CaptionDescriptions": [
{
"CaptionSelectorName": "caption-selector-1",
"Name": "caption_608",
"DestinationSettings": {
"EmbeddedDestinationSettings": {}
}
}
]
}
임베디드 자막을 읽지 못하는 플레이어를 위해 WebVTT 사이드카를 함께 만들 수도 있습니다.
{
"DestinationSettings": {
"WebvttDestinationSettings": {}
}
}
HLS 출력에서는 비디오 세그먼트와 별도로 .vtt 세그먼트와 자막 플레이리스트가 생성됩니다.
스케줄링과 자동화
스케줄 액션
입력 전환, 슬레이트 표시, 광고 브레이크 삽입 같은 동작은 채널 스케줄에 등록합니다. 별도의 create-schedule-action 명령은 없고, batch-update-schedule로 액션을 한꺼번에 추가합니다.
aws medialive batch-update-schedule \
--channel-id 1234567 \
--creates file://actions.json
{
"ScheduleActions": [
{
"ActionName": "switch-to-main-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}
}
}
]
}
SCTE-35의 Duration은 90kHz 틱 단위입니다. 1초가 90,000틱이므로 90초 광고 브레이크는 8,100,000입니다.
EventBridge 연동
채널 상태가 바뀔 때 Lambda나 SNS를 호출하려면 EventBridge 규칙을 만듭니다.
{
"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"]
}
}
모니터링과 문제 해결
CloudWatch 메트릭
MediaLive 메트릭은 MediaLive 네임스페이스에 있고, 대부분 ChannelId와 Pipeline 차원을 가집니다. 자주 보는 지표는 다음과 같습니다.
ActiveAlerts: 현재 활성화된 알림 수InputVideoFrameRate: 입력 비디오의 프레임 레이트InputTimecodesPresent: 입력에 타임코드가 있는지 여부PrimaryInputActive: 입력 페일오버 구성에서 기본 입력이 활성인지 여부NetworkIn/NetworkOut: 네트워크 처리량DroppedFrames: 인코더가 처리하지 못해 버린 프레임 수FillMsec: 입력이 없어 채움 프레임을 넣은 시간SvqTime: 실시간을 맞추려고 화질 최적화를 줄인 시간의 비율로, 이 값이 계속 높으면 인코딩 설정이 채널 처리 능력에 비해 무겁다는 뜻입니다.
알람
활성 알림이 생기면 운영 채널로 알리는 알람 예시입니다. 파이프라인마다 따로 만들어야 합니다.
aws cloudwatch put-metric-alarm \
--alarm-name medialive-active-alerts-p0 \
--namespace MediaLive \
--metric-name ActiveAlerts \
--dimensions Name=ChannelId,Value=1234567 Name=Pipeline,Value=0 \
--statistic Maximum \
--period 60 \
--evaluation-periods 1 \
--comparison-operator GreaterThanThreshold \
--threshold 0 \
--alarm-actions arn:aws:sns:us-west-2:123456789012:ops-alerts
로그
채널에 로그 레벨을 설정하면 입력 연결 상태, 인코딩 오류, 페일오버, 스케줄 액션 실행 같은 이벤트가 CloudWatch Logs로 전송됩니다. 기본값은 로그를 보내지 않는 설정이므로, 장애가 난 뒤에야 로그가 없다는 것을 알게 되는 일이 없도록 채널을 만들 때 켜 두는 편이 좋습니다.
AWS Elemental MediaPackage
개요
MediaPackage는 저스트 인 타임 패키징 서비스이자 적응형 스트리밍 오리진입니다. MediaLive가 인코딩한 콘텐츠를 받아 요청 시점에 HLS, DASH, CMAF로 패키징하고, CDN에 매니페스트와 세그먼트를 제공합니다.
아래 예시는 오래 쓰여 온 v1 API(aws mediapackage) 기준입니다. 새로 구축한다면 채널 그룹 개념과 CMAF 기반 HLS·DASH 동시 출력을 제공하는 v2 API(aws mediapackagev2)도 검토하는 것이 좋습니다.
핵심 개념
채널
채널은 수집 지점입니다.
aws mediapackage create-channel \
--id my-live-channel \
--description "Live sports channel"
응답에는 이중화된 수집 엔드포인트 두 개가 들어 있습니다.
{
"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"
}
]
}
}
STANDARD 채널의 두 파이프라인이 각각 한 엔드포인트로 HLS를 보내고, MediaPackage는 한쪽 입력이 끊기면 다른 쪽으로 이어서 패키징합니다.
오리진 엔드포인트
오리진 엔드포인트는 콘텐츠를 어떤 형식으로 패키징해 내보낼지 정의합니다. 한 채널에 여러 엔드포인트를 붙일 수 있습니다.
HLS 엔드포인트입니다.
aws mediapackage create-origin-endpoint \
--channel-id my-live-channel \
--id hls-endpoint \
--manifest-name index \
--startover-window-seconds 7200 \
--hls-package '{
"SegmentDurationSeconds": 6,
"PlaylistWindowSeconds": 60,
"ProgramDateTimeIntervalSeconds": 60,
"AdMarkers": "SCTE35_ENHANCED",
"IncludeIframeOnlyStream": true
}'
다음과 같은 URL에서 HLS를 제공합니다.
https://abcdef.mediapackage.us-west-2.amazonaws.com/out/v1/xyz123/index.m3u8
DASH 엔드포인트입니다. DASH에는 HLS의 AdMarkers 대신, 광고 마커가 있을 때 새 Period를 시작하도록 하는 PeriodTriggers가 있습니다.
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"]
}'
CMAF 엔드포인트는 fMP4 세그먼트를 만들고 HLS 매니페스트로 제공합니다. v1의 CMAF 엔드포인트는 HLS 매니페스트만 지원하며, 같은 CMAF 세그먼트를 HLS와 DASH가 함께 쓰는 구성은 v2에서 가능합니다.
aws mediapackage create-origin-endpoint \
--channel-id my-live-channel \
--id cmaf-endpoint \
--cmaf-package '{
"SegmentDurationSeconds": 6,
"HlsManifests": [
{"Id": "hls", "ManifestName": "index"}
]
}'
고급 기능
타임시프트 시청
엔드포인트의 startover 윈도우를 설정하면 시청자가 지난 구간부터 다시 볼 수 있습니다.
{
"StartoverWindowSeconds": 3600
}
위 설정이면 최대 1시간 전부터 다시 시작할 수 있습니다. 재생 URL에 start/end 쿼리 파라미터를 붙여 특정 구간을 요청하는 방식이며, Harvest 작업도 이 윈도우 안의 구간만 추출할 수 있습니다.
시간 지연을 설정하면 라이브 엣지를 일정 시간 늦춰 내보냅니다.
{
"TimeDelaySeconds": 30
}
생방송 중 문제 장면을 걸러낼 시간이 필요할 때 씁니다.
DVR 윈도우
매니페스트에 담는 구간(PlaylistWindowSeconds)을 늘리면 플레이어에서 뒤로 탐색할 수 있는 범위가 넓어집니다. 다만 6초 세그먼트로 몇 시간 분량을 매니페스트에 담으면 매니페스트가 수천 줄이 되고, 플레이어는 이 매니페스트를 몇 초마다 다시 받습니다. 긴 되감기가 필요하면 매니페스트 윈도우는 적당히 두고 startover 윈도우로 구간을 요청하게 하는 편이 효율적입니다.
콘텐츠 보호(DRM)
DRM은 SPEKE(Secure Packager and Encoder Key Exchange) API를 구현한 키 서버와 연동해 붙입니다.
{
"Encryption": {
"SpekeKeyProvider": {
"SystemIds": [
"9a04f079-9840-4286-ab92-e65be0885f95",
"edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"
],
"Url": "https://drm-provider.example.com/speke/v2",
"ResourceId": "my-live-channel",
"RoleArn": "arn:aws:iam::123456789012:role/MediaPackageSpeke"
}
}
}
시스템 ID는 DRM 종류를 나타냅니다.
9a04f079-9840-4286-ab92-e65be0885f95: PlayReadyedef8ba9-79d6-4ace-a3c8-27dcd51d21ed: Widevine94ce86fb-07ff-4f43-adb8-93d2fa968ca2: FairPlay
PlayReady와 Widevine은 주로 DASH나 CMAF 엔드포인트에, FairPlay는 HLS 엔드포인트에 씁니다. 키 서버는 직접 구현할 수도 있고 SPEKE를 지원하는 상용 DRM 사업자를 쓸 수도 있습니다.
DRM 없이 세그먼트만 암호화하려면 HLS의 AES-128을 씁니다.
{
"Encryption": {
"EncryptionMethod": "AES_128",
"KeyRotationIntervalSeconds": 600,
"ConstantInitializationVector": "12345678901234567890123456789012",
"SpekeKeyProvider": {
"SystemIds": ["81376844-f976-481e-a84e-cc25d39b0b33"],
"Url": "https://key-server.example.com/speke",
"ResourceId": "my-live-channel",
"RoleArn": "arn:aws:iam::123456789012:role/MediaPackageSpeke"
}
}
}
ConstantInitializationVector는 128비트 값을 16진수 32자로 쓰며 0x 접두사는 붙이지 않습니다. 이 경우에도 키는 SPEKE 키 서버에서 받아오고, 매니페스트에는 키 자체가 아니라 키를 받아올 URI만 들어갑니다. 키 URI에 인증을 걸지 않으면 누구나 키를 받을 수 있으므로, AES-128은 접근 제어가 갖춰진 키 서버와 함께 쓸 때만 의미가 있습니다.
매니페스트 필터링
엔드포인트마다 노출할 렌디션 범위를 제한할 수 있습니다.
{
"StreamSelection": {
"MinVideoBitsPerSecond": 500000,
"MaxVideoBitsPerSecond": 5000000,
"StreamOrder": "ORIGINAL"
}
}
모바일 전용 엔드포인트에서 고비트레이트 렌디션을 빼는 식으로 씁니다.
광고 마커 시그널링
HLS 엔드포인트의 AdMarkers는 SCTE-35 정보를 매니페스트에 어떻게 표시할지 정합니다.
NONE: 광고 마커를 매니페스트에 넣지 않습니다.PASSTHROUGH: 입력 HLS 매니페스트에 있던 광고 마커를 그대로 복사합니다.SCTE35_ENHANCED: 입력 스트림의 SCTE-35 메시지를 바탕으로#EXT-X-CUE-OUT,#EXT-X-CUE-OUT-CONT,#EXT-X-CUE-IN,#EXT-OATCLS-SCTE35태그를 생성합니다.DATERANGE: SCTE-35 정보를#EXT-X-DATERANGE태그로 표시합니다.
MediaTailor와 연동할 때는 MediaTailor가 해석할 수 있는 형식(SCTE35_ENHANCED나 DATERANGE)을 고릅니다.
Harvest 작업
라이브 스트림의 특정 구간을 VOD 자산으로 내보냅니다. 엔드포인트에 startover 윈도우가 설정되어 있어야 하고, 추출할 구간이 그 윈도우 안에 있어야 합니다.
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
2시간 분량을 S3에 HLS로 추출하며, 하이라이트나 다시보기 제작에 씁니다.
VOD 패키징
MediaPackage는 VOD 콘텐츠도 요청 시점에 패키징합니다. 소스는 HLS 매니페스트나 MP4 파일을 기술한 SMIL 매니페스트여야 하므로, 보통 MediaConvert로 만든 HLS 출력을 소스로 씁니다.
aws mediapackage-vod create-asset \
--id my-vod-asset \
--source-arn arn:aws:s3:::my-bucket/videos/movie/index.m3u8 \
--source-role-arn arn:aws:iam::123456789012:role/MediaPackageVOD \
--packaging-group-id my-packaging-group
패키징 구성은 패키징 그룹 단위로 붙습니다.
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}
]
}'
소스 하나를 저장해 두고 HLS, DASH, 서로 다른 DRM 구성을 패키징 구성만 추가해 제공할 수 있다는 점이 장점입니다.
모니터링
MediaPackage 메트릭은 AWS/MediaPackage 네임스페이스에 있습니다.
IngressBytes,IngressResponseTime: MediaLive에서 받은 데이터 양과 수집 요청 응답 시간EgressBytes,EgressResponseTime: CDN이나 시청자에게 보낸 데이터 양과 응답 시간EgressRequestCount: 매니페스트와 세그먼트 요청 수이며,StatusCodeRange차원(2xx, 4xx, 5xx)으로 오류 비율을 볼 수 있습니다.
오리진 5xx 응답이 늘어나면 알리는 알람 예시입니다.
aws cloudwatch put-metric-alarm \
--alarm-name mediapackage-egress-5xx \
--namespace AWS/MediaPackage \
--metric-name EgressRequestCount \
--dimensions Name=Channel,Value=my-live-channel Name=StatusCodeRange,Value=5xx \
--statistic Sum \
--period 60 \
--evaluation-periods 2 \
--comparison-operator GreaterThanThreshold \
--threshold 10
AWS Elemental MediaTailor
개요
MediaTailor는 서버 사이드 광고 삽입(SSAI)과 채널 어셈블리 서비스입니다. 서버에서 광고 세그먼트를 매니페스트에 스티칭하므로, 플레이어는 광고와 콘텐츠를 하나의 스트림으로 재생하고 광고 차단기는 광고를 구별하기 어렵습니다.
서버 사이드 광고 삽입을 쓰는 이유
클라이언트 사이드 광고 삽입(CSAI)의 흐름은 다음과 같습니다.
플레이어가 매니페스트 요청 → 매니페스트에 광고 마커 포함 → 플레이어가 광고 서버 호출 → 광고 서버가 광고 URL 반환 → 플레이어가 광고 재생으로 전환 → 다시 콘텐츠로 전환
이 방식에서는 광고 서버와 광고 파일의 도메인이 콘텐츠와 달라 광고 차단기가 쉽게 막고, 콘텐츠와 광고 사이를 전환할 때 버퍼링이 생기기 쉽습니다. 광고와 콘텐츠의 패키징·DRM 구성이 달라 플레이어 로직도 복잡해집니다.
서버 사이드 광고 삽입(SSAI)의 흐름은 다음과 같습니다.
플레이어가 MediaTailor에 매니페스트 요청 → MediaTailor가 오리진 매니페스트를 받아 광고 마커 확인 → 광고 결정 서버 호출 → 광고 세그먼트를 매니페스트에 스티칭 → 플레이어는 하나의 매니페스트를 재생
광고 세그먼트가 콘텐츠와 같은 CDN 도메인에서 제공되므로 차단이 어렵고, 플레이어는 별도 광고 SDK 없이 일반 HLS/DASH 재생만 하면 됩니다. 대신 광고 노출 추적을 서버가 대신하거나 플레이어가 별도로 보고해야 하는데, 이 부분은 아래 비콘 절에서 다룹니다.
핵심 개념
재생 구성
재생 구성(playback configuration)은 콘텐츠 오리진, 광고 결정 서버(ADS), CDN 설정을 묶습니다. ADS URL에는 &와 []가 들어가므로 셸에서 따옴표로 감싸야 합니다.
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?uid=[player_params.user_id]&ip=[session.client_ip]&ua=[session.user_agent]' \
--cdn-configuration '{
"AdSegmentUrlPrefix": "https://cdn.example.com",
"ContentSegmentUrlPrefix": "https://cdn.example.com/content"
}' \
--slate-ad-url https://cdn.example.com/slate.mp4
재생 URL은 다음 형태입니다.
https://abcdef.mediatailor.us-west-2.amazonaws.com/v1/master/xyz123/my-live-channel/index.m3u8
시청자는 MediaPackage URL 대신 이 URL을 요청하고, 마지막 경로(index.m3u8)는 콘텐츠 소스 URL 뒤에 붙어 오리진 요청이 됩니다.
ADS 호출과 동적 변수
라이브에서는 매니페스트의 광고 마커를 만났을 때 광고 구간마다 ADS를 호출합니다. 호출 전에 ADS URL의 변수를 실제 값으로 바꿉니다.
[session.client_ip],[session.user_agent],[session.id]: MediaTailor가 세션에서 채우는 값[session.avail_duration_secs]: 채워야 할 광고 구간 길이[player_params.이름]: 플레이어가 재생 URL에ads.이름=값으로 넘긴 값
플레이어 파라미터는 ads. 접두사를 붙여 넘깁니다.
https://abcdef.mediatailor.us-west-2.amazonaws.com/v1/master/xyz123/my-live-channel/index.m3u8?ads.user_id=12345&ads.device=mobile
이렇게 요청하면 ADS URL의 [player_params.user_id]가 12345로 바뀌어 전달되고, ADS는 이 정보로 타겟 광고를 고릅니다.
VAST와 VMAP
ADS는 VAST 응답으로 광고 크리에이티브와 추적 URL을 돌려줍니다.
<VAST version="4.2">
<Ad id="ad1">
<InLine>
<AdTitle>Sample Product</AdTitle>
<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은 VOD에서 여러 광고 브레이크의 위치를 한 번에 정의합니다.
<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.000" breakType="linear" breakId="midroll-1">
<vmap:AdSource id="midroll-ad-1">
<vmap:VASTAdData>
<VAST>...</VAST>
</vmap:VASTAdData>
</vmap:AdSource>
</vmap:AdBreak>
</vmap:VMAP>
MediaTailor는 VPAID 같은 인터랙티브 크리에이티브는 스티칭할 수 없으므로, ADS가 선형 비디오 파일(MP4 등)을 돌려주도록 설정해야 합니다.
매니페스트 조작
오리진(MediaPackage, SCTE35_ENHANCED)이 내보낸 HLS 매니페스트에 18초짜리 광고 구간이 있다고 가정합니다.
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:1000
#EXTINF:6.0,
segment1000.ts
#EXT-X-CUE-OUT:18.000
#EXTINF:6.0,
segment1001.ts
#EXT-X-CUE-OUT-CONT:ElapsedTime=6.000,Duration=18.000
#EXTINF:6.0,
segment1002.ts
#EXT-X-CUE-OUT-CONT:ElapsedTime=12.000,Duration=18.000
#EXTINF:6.0,
segment1003.ts
#EXT-X-CUE-IN
#EXTINF:6.0,
segment1004.ts
MediaTailor가 개인화한 매니페스트는 다음과 같습니다(광고 세그먼트 경로는 줄였습니다).
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:1000
#EXTINF:6.0,
https://cdn.example.com/content/out/v1/xyz123/segment1000.ts
#EXT-X-DISCONTINUITY
#EXTINF:6.0,
https://cdn.example.com/tm/.../ad-0.ts
#EXTINF:6.0,
https://cdn.example.com/tm/.../ad-1.ts
#EXTINF:6.0,
https://cdn.example.com/tm/.../ad-2.ts
#EXT-X-DISCONTINUITY
#EXTINF:6.0,
https://cdn.example.com/content/out/v1/xyz123/segment1004.ts
광고 구간에 해당하던 콘텐츠 세그먼트(1001~1003)는 광고 세그먼트로 교체되고, 인코딩이 바뀌는 지점마다 #EXT-X-DISCONTINUITY가 들어갑니다. 콘텐츠와 광고 세그먼트 URL에는 CDN 접두사가 붙지만 시청자별 값은 들어가지 않으므로, 세그먼트 자체는 모든 시청자가 CDN 캐시를 공유하고 매니페스트만 시청자별로 달라집니다. ADS가 구간 길이보다 짧은 광고를 주면 남은 시간은 슬레이트로 채웁니다.
광고 트랜스코딩
ADS가 돌려준 광고 파일은 콘텐츠의 렌디션 구성과 다르므로, MediaTailor가 콘텐츠 매니페스트의 렌디션에 맞춰 광고를 트랜스코딩하고 결과를 캐시해 재사용합니다. 이 트랜스코딩은 비동기로 진행되기 때문에, 처음 등장한 크리에이티브는 준비가 끝날 때까지 스티칭되지 않고 해당 구간이 슬레이트나 원래 콘텐츠로 채워집니다. 새 캠페인을 시작한 직후 광고가 안 나온다는 문의가 오면 이 동작부터 확인합니다.
추적과 비콘
서버 사이드 보고
기본 모드에서는 MediaTailor가 플레이어를 대신해 VAST의 추적 URL(impression, start, firstQuartile, midpoint, complete)을 호출합니다. 플레이어가 광고 세그먼트를 포함한 구간을 요청하는 흐름을 보고 재생 진행을 추정하는 방식이라, 플레이어 쪽 구현이 필요 없지만 실제 화면 노출과는 차이가 생길 수 있습니다.
클라이언트 사이드 보고
광고 네트워크가 플레이어 측 측정을 요구하면 클라이언트 사이드 보고를 씁니다. 플레이어가 세션 초기화 URL에 reportingMode를 지정해 POST하면 매니페스트 URL과 추적 URL을 돌려받습니다.
POST https://abcdef.mediatailor.us-west-2.amazonaws.com/v1/session/xyz123/my-live-channel/index.m3u8
{
"reportingMode": "client",
"adsParams": {"user_id": "12345"}
}
플레이어는 응답의 추적 URL을 주기적으로 조회해 광고 구간과 비콘 URL 목록을 받고, 재생 위치에 맞춰 비콘을 직접 호출합니다.
광고 구간 억제
시청자가 광고 구간 도중에 접속하거나 라이브 엣지보다 뒤에서 재생을 시작하면, 이미 지나간 광고 구간까지 채우는 것이 어색할 수 있습니다. avail suppression은 이런 구간을 채우지 않게 합니다.
{
"AvailSuppression": {
"Mode": "BEHIND_LIVE_EDGE",
"Value": "00:00:00"
}
}
BEHIND_LIVE_EDGE 모드에서는 세션 시작 시점에 라이브 엣지에서 Value만큼 떨어진 지점이나 그보다 뒤에 있는 광고 구간을 채우지 않습니다. 유료 구독자에게 광고를 빼는 용도라면 이 기능이 아니라 별도의 재생 구성을 두거나 ADS가 빈 응답을 돌려주도록 처리합니다.
VOD 광고 삽입
aws mediatailor put-playback-configuration \
--name my-vod-asset \
--video-content-source-url https://cdn.example.com/vod \
--ad-decision-server-url https://ad-server.example.com/vmap \
--personalization-threshold-seconds 2
VOD에서는 세션 시작 시 ADS를 한 번 호출해 VMAP으로 모든 광고 브레이크를 받고, 지정된 위치에 광고를 넣은 매니페스트를 만듭니다. --personalization-threshold-seconds는 광고 구간에서 채우지 못한 시간을 얼마까지 허용할지 정하는 값입니다. 채우지 못한 시간이 이 값을 넘으면 MediaTailor는 그 구간을 광고로 채우지 않습니다.
채널 어셈블리
채널 어셈블리는 VOD 자산을 이어 붙여 별도 인코딩 없이 선형 채널을 만드는 기능입니다. 소스 위치, VOD 소스, 채널, 프로그램 순서로 만듭니다.
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=default,Type=HLS
aws mediatailor create-channel \
--channel-name my-linear-channel \
--playback-mode LOOP \
--outputs '[{"ManifestName": "index", "SourceGroup": "default", "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}'
LOOP 모드는 등록된 프로그램을 순서대로 반복 재생하고, LINEAR 모드는 절대 시각 기준으로 편성합니다. 프로그램에 --ad-breaks로 광고 브레이크 위치를 지정하면 SCTE-35 마커가 들어가므로, 채널 출력을 재생 구성의 콘텐츠 소스로 지정해 광고를 넣을 수 있습니다. 채널은 생성 후 start-channel로 시작해야 출력이 나옵니다.
모니터링
MediaTailor 메트릭은 AWS/MediaTailor 네임스페이스에 있습니다.
AdDecisionServer.Errors,AdDecisionServer.Timeouts: ADS 호출 실패와 시간 초과AdDecisionServer.Latency: ADS 응답 시간Avail.Duration: 광고 구간의 계획된 총 길이Avail.FillRate: 광고 구간 중 실제로 광고로 채운 비율GetManifest.Errors: 매니페스트 요청 처리 오류Origin.Errors,Origin.Timeouts: 콘텐츠 오리진 요청 실패
Avail.FillRate가 떨어지면 ADS가 광고를 충분히 주지 못하거나, 새 크리에이티브가 트랜스코딩 대기 중이거나, 광고 길이가 구간과 맞지 않는 경우가 많습니다.
AWS Elemental MediaStore 지원 종료와 대안
MediaStore는 라이브 HLS 세그먼트처럼 작은 객체를 자주 쓰고 읽는 오리진 용도로 만들어진 스토리지였고, MediaLive가 mediastoressl:// 대상으로 쓰거나 청크 전송으로 인코딩 중인 세그먼트를 업로드하는 기능을 제공했습니다. AWS는 2025년 11월 13일에 MediaStore 지원을 종료했으므로 새 파이프라인에서는 쓰지 않습니다.
대안은 용도에 따라 나뉩니다. 라이브 오리진이 필요하면 MediaPackage를 쓰는 것이 가장 직접적이고, 저지연 HLS나 CMAF가 필요하면 MediaPackage v2를 검토합니다. 단순히 MediaLive HLS 출력을 저장하고 CloudFront로 서빙하는 구조라면 S3를 대상으로 쓸 수 있습니다. 이때 S3 버킷은 공개하지 말고 CloudFront 오리진 액세스 제어(OAC)로만 읽게 하는 편이 안전합니다.
AWS Elemental MediaConnect
개요
MediaConnect는 기여(contribution)와 배포(distribution)를 위한 라이브 비디오 전송 서비스입니다. 위성이나 전용 회선으로 보내던 방송 피드를 인터넷과 AWS 네트워크 위의 IP 전송으로 대체하는 데 씁니다.
사용 사례
기여 용도로는 경기장에서 방송 센터나 클라우드로 원격 제작 피드를 보내거나, 다중 카메라 피드를 모으거나, 백업 전송 경로를 마련하는 경우가 있습니다. 배포 용도로는 다른 리전이나 파트너 방송사에 피드를 나눠 주고, MediaLive 입력을 이중화하는 경우가 있습니다.
핵심 개념
플로우
플로우는 하나의 라이브 비디오 전송 연결입니다.
aws mediaconnect create-flow \
--name remote-camera-feed \
--source Name=Camera-1,Protocol=zixi-push,WhitelistCidr=203.0.113.0/24
지원 프로토콜은 다음과 같습니다.
- Zixi: FEC와 ARQ를 갖춘 상용 UDP 기반 프로토콜
- RIST: 방송 업계 단체가 만든 개방형 신뢰 전송 프로토콜
- RTP / RTP-FEC: 실시간 전송 프로토콜과 SMPTE 2022-1 FEC
- SRT: 오픈 소스 신뢰 전송 프로토콜로, listener와 caller 모드가 있습니다.
- CDI, ST 2110 JPEG XS: AWS 안에서 비압축 또는 경량 압축 영상을 낮은 지연으로 주고받는 용도이며, VPC 인터페이스 구성이 필요합니다.
소스
push 소스는 현장 장비가 MediaConnect 플로우의 수집 IP와 포트로 스트림을 보냅니다. 수집 IP는 플로우를 만든 뒤 콘솔이나 describe-flow 응답에서 확인합니다.
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
pull 방식이 필요하면 MediaConnect가 인코더에 접속하는 프로토콜(SRT caller, Zixi pull)을 씁니다. RTP는 push 전용입니다.
aws mediaconnect create-flow \
--name encoder-pull \
--source Name=Encoder,Protocol=srt-caller,SourceListenerAddress=203.0.113.42,SourceListenerPort=5000
출력과 MediaLive 연동
일반 출력은 프로토콜과 대상 주소를 지정해 추가합니다.
aws mediaconnect add-flow-outputs \
--flow-arn arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123 \
--outputs Protocol=srt-listener,Port=5001,Name=To-Partner,CidrAllowList=198.51.100.0/24
MediaLive로 보낼 때는 출력을 직접 만들지 않고, MediaLive 입력을 MEDIACONNECT 타입으로 만들어 플로우 ARN을 지정합니다. STANDARD 채널이라면 서로 다른 가용 영역의 플로우 두 개가 필요합니다.
{
"Name": "camera-input",
"Type": "MEDIACONNECT",
"RoleArn": "arn:aws:iam::123456789012:role/MediaLiveAccessRole",
"MediaConnectFlows": [
{"FlowArn": "arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123"},
{"FlowArn": "arn:aws:mediaconnect:us-west-2:123456789012:flow:def456"}
]
}
다른 AWS 계정의 파트너에게 피드를 나눠 줄 때는 entitlement를 부여합니다.
aws mediaconnect grant-flow-entitlements \
--flow-arn arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123 \
--entitlements Name=Partner-A,Subscribers=210987654321
파트너는 이 entitlement를 소스로 삼아 자기 계정에 플로우를 만듭니다.
이중화
플로우에 소스 두 개를 두고 페일오버를 설정합니다.
aws mediaconnect update-flow \
--flow-arn arn:aws:mediaconnect:us-west-2:123456789012:flow:abc123 \
--source-failover-config 'State=ENABLED,FailoverMode=MERGE,RecoveryWindow=200'
MERGE 모드는 두 소스의 패킷을 합쳐 한쪽에서 빠진 패킷을 다른 쪽으로 채우므로 끊김 없는 전환이 가능하지만, 두 소스가 같은 인코더에서 나온 동일한 스트림이어야 합니다. FAILOVER 모드는 기본 소스가 끊기면 보조 소스로 전환하며, SourcePriority로 기본 소스를 지정합니다.
모니터링
AWS/MediaConnect 네임스페이스에서 소스 비트레이트(SourceBitRate), 패킷 손실률(SourcePacketLossPercent), ARQ·FEC로 복구한 패킷 수와 복구하지 못한 패킷 수를 봅니다. 복구된 패킷이 늘어나는 것은 회선 품질이 나빠지고 있다는 신호이고, 복구하지 못한 패킷이 생기면 실제 화면 깨짐으로 이어집니다.
AWS Elemental MediaConvert
개요
MediaConvert는 VOD용 파일 기반 트랜스코딩 서비스입니다. MP4, MOV, MXF 같은 소스 파일을 ABR 렌디션과 HLS, DASH, CMAF 패키지로 변환합니다.
작업 제출
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,
"CodingMode": "CODING_MODE_2_0",
"SampleRate": 48000
}
}
}
]
}
]
}
]
}
QVBR에서는 Bitrate 대신 MaxBitrate를 지정합니다. QvbrQualityLevel은 1~10 범위이며, 값이 높을수록 화질 목표가 높아지고 파일이 커집니다.
고급 기능
자동 ABR
Automated ABR을 켜면 렌디션 개수와 각 렌디션의 해상도·비트레이트를 MediaConvert가 소스 내용을 분석해 정합니다. 최대 렌디션 수와 최대·최소 비트레이트만 지정하면 되고, QVBR 레이트 컨트롤과 함께 써야 합니다. 정적인 강의 영상처럼 단순한 소스라면 고정 래더보다 렌디션 수와 저장 용량이 줄어드는 경우가 많습니다.
HDR10
HDR10 출력은 HEVC Main10으로 인코딩하고, 컬러 보정 전처리에서 HDR10 색 공간과 마스터링 메타데이터를 지정합니다.
{
"VideoDescription": {
"CodecSettings": {
"Codec": "H_265",
"H265Settings": {"Profile": "MAIN10_MAIN", "RateControlMode": "QVBR", "MaxBitrate": 15000000}
},
"VideoPreprocessors": {
"ColorCorrector": {
"ColorSpaceConversion": "FORCE_HDR10",
"Hdr10Metadata": {
"RedPrimaryX": 34000,
"RedPrimaryY": 16000,
"GreenPrimaryX": 13250,
"GreenPrimaryY": 34500,
"BluePrimaryX": 7500,
"BluePrimaryY": 3000,
"WhitePointX": 15635,
"WhitePointY": 16450,
"MaxLuminance": 10000000,
"MinLuminance": 50,
"MaxContentLightLevel": 1000,
"MaxFrameAverageLightLevel": 400
}
}
}
}
}
원색 좌표는 0.00002 단위(BT.2020 원색과 D65 백색점), 마스터링 밝기는 0.0001 cd/m² 단위이므로 MaxLuminance 10000000은 1000니트입니다. MaxCLL과 MaxFALL은 소스를 분석한 실제 값을 넣어야 하며, 위 숫자는 예시입니다.
Dolby Vision 출력은 별도의 Dolby Vision 전처리 설정이 필요하고, 지원하는 프로필과 소스 조건이 정해져 있으므로 공식 문서의 지원 조합을 먼저 확인합니다.
오디오 패스스루
Dolby Atmos처럼 다시 인코딩하면 안 되는 오디오는 패스스루로 그대로 넘깁니다.
{
"AudioDescriptions": [
{
"CodecSettings": {
"Codec": "PASSTHROUGH"
}
}
]
}
패스스루는 출력 컨테이너가 해당 오디오 코덱을 담을 수 있을 때만 동작합니다.
아키텍처 패턴
라이브 스트리밍
기본 라이브 워크플로입니다.
Encoder (RTMP) → MediaLive (Transcode) → MediaPackage (Origin) → CloudFront (CDN) → 시청자
광고 삽입을 포함하면 MediaTailor가 MediaPackage 앞에서 매니페스트를 개인화하고, CloudFront는 MediaTailor(매니페스트)와 MediaPackage(콘텐츠 세그먼트), 광고 세그먼트를 경로별 오리진으로 나눠 전달합니다.
Encoder → MediaLive (SCTE-35) → MediaPackage → MediaTailor (SSAI) → CloudFront → 시청자
기여 구간을 이중화하면 다음과 같습니다.
Encoder (Primary) ─┐
├─→ MediaConnect (Merge) → MediaLive → MediaPackage → CloudFront
Encoder (Backup) ──┘
VOD
Source File (S3) → MediaConvert (Transcode) → S3 (ABR Assets) → CloudFront → 시청자
DRM을 붙이려면 MediaPackage VOD로 요청 시점에 암호화합니다.
Source → MediaConvert → S3 → MediaPackage VOD (SPEKE Encryption) → CloudFront → 시청자
라이브와 VOD 결합
Encoder → MediaLive ─┬→ MediaPackage (Live) → CloudFront (Live)
└→ Archive Output Group → S3 (Recording)
S3 Recording → MediaConvert (Trim/Edit) → S3 VOD → CloudFront (VOD)
MediaPackage Harvest 작업으로 라이브 구간을 바로 VOD로 추출하는 방법도 있습니다.
다중 리전
Encoder (Primary) → MediaLive (us-west-2) → MediaPackage (us-west-2) ─┐
├→ CloudFront
Encoder (Backup) → MediaLive (us-east-1) → MediaPackage (us-east-1) ─┘
리전 간 전환은 CloudFront 오리진 그룹의 오리진 페일오버나 Route 53 상태 확인으로 구성합니다. 두 리전의 세그먼트 번호와 타임라인이 다르면 전환 순간 플레이어가 재생 위치를 잃을 수 있으므로, 출력 타임코드와 세그먼트 설정을 두 리전에서 똑같이 맞춰야 합니다.
비용 구조
각 서비스의 과금 기준은 다음과 같습니다. 단가는 리전과 시기에 따라 바뀌므로 숫자는 AWS 공식 요금 페이지와 Pricing Calculator에서 확인합니다.
- MediaLive: 채널이 실행 중인 시간에 대해 입력과 각 출력의 코덱, 해상도, 비트레이트, 프레임 레이트, 채널 클래스에 따라 과금합니다. 출력 렌디션 하나를 추가할 때마다 비용이 늘어나고, STANDARD 채널은 파이프라인이 두 개라 SINGLE_PIPELINE보다 비쌉니다.
- MediaPackage: 수집한 데이터 양과 오리진에서 내보낸 데이터 양에 따라 과금합니다. 오리진 앞에 CDN을 두면 오리진 전송량이 크게 줄어듭니다.
- MediaTailor: 삽입한 광고 수와 채널 어셈블리 채널 실행 시간 등에 따라 과금합니다.
- MediaConnect: 플로우 실행 시간과 외부로 내보낸 데이터 양에 따라 과금합니다.
- MediaConvert: 출력 영상 길이(분)에 대해 요금 등급, 코덱, 해상도, 프레임 레이트에 따라 과금합니다.
비용에서 자주 놓치는 부분은 MediaLive 채널을 이벤트가 끝난 뒤에도 실행 상태로 두는 것입니다. 입력이 없어도 실행 중인 채널은 과금되므로, 정해진 일정의 이벤트라면 EventBridge Scheduler 등으로 채널 시작과 중지를 자동화합니다.
라이브 채널을 운영할 때 챙길 설정
STANDARD 채널은 두 파이프라인을 서로 다른 가용 영역에서 돌리지만, 입력이 하나뿐이면 현장 인코더나 회선이 끊기는 순간 두 파이프라인이 함께 멈춥니다. 중요한 이벤트라면 기본/백업 입력을 따로 두고 입력 페일오버를 설정해야 이중화가 의미를 가집니다.
입력이 끊겼을 때 검은 화면 대신 슬레이트 이미지를 내보내도록 입력 손실 동작을 설정해 두면, 플레이어가 세그먼트 공백 때문에 재생을 멈추는 일을 줄일 수 있습니다.
ABR 전환과 SCTE-35 광고 삽입은 세그먼트 경계에서 일어나므로, closed GOP를 쓰고 세그먼트 길이가 GOP 길이의 정수배가 되도록 맞춥니다. 그래야 모든 세그먼트가 IDR 프레임으로 시작해 렌디션 간 전환이 매끄럽습니다.
시청 기기 분포를 보고 거의 선택되지 않는 렌디션은 빼는 편이 좋습니다. 렌디션 하나가 늘 때마다 인코딩 비용과 오리진 저장·전송량이 함께 늘어납니다.
접근 제한도 단계별로 겁니다. RTMP/RTP push 입력에는 입력 보안 그룹으로 허용 IP를 좁히고, 유료 콘텐츠는 MediaPackage의 SPEKE 연동으로 DRM을 붙이며, CDN 쪽은 서명된 URL이나 쿠키로 보호합니다.
CloudWatch에서는 MediaLive의 ActiveAlerts와 FillMsec, MediaPackage의 StatusCodeRange별 EgressRequestCount에 알람을 걸고, 페일오버는 이벤트 전에 실제로 입력을 끊어 보며 확인합니다.