12 · 인코딩 파이프라인 (ffmpeg · MediaConvert · CRF/CBR/VBR)
이 문서가 답하는 질문: 비디오 인코딩 파이프라인은 어떻게 짜고, CRF·CBR·VBR은 언제 무엇을 쓰는가? 선행:
06-containers.md,08-codec-h264.md
한 줄 답
**인코딩 파이프라인은 “원본 → 분석 → 정규화 → 인코딩 → 패키징 → 배포” 6단계로 구성되며, 각 단계의 결정은 최종 소비자(브라우저/디바이스/네트워크)에서 거꾸로 추론된다. Rate control(CRF·CBR·VBR·CapVBR)은 비트 예산을 어떻게 분배할지 의 정책이다.
Why — 왜 파이프라인이 필요한가
비디오 한 편을 그냥 ffmpeg 한 줄로 인코딩해도 동작은 한다. 하지만 수백만 시간의 콘텐츠를 자동으로 처리하려면:
- 다양한 원본 (mp4·mov·mkv·VFR·anamorphic·interlaced…) 을 통일해야 함
- 여러 클라이언트 (iOS·Android·Smart TV·Web·구형) 에 모두 송출
- 품질 일관성: 어두운 장면에서 비트가 부족하면 안 됨
- 비용 통제: 인코딩·CDN·스토리지 비용이 균형
- 장애 처리: 한 영상이 깨지면 전체 파이프라인이 멈추면 안 됨
→ 단일 명령어가 아니라 단계별 결정의 트리가 필요.
How — 6단계 파이프라인
표준 인코딩 파이프라인
1) 원본 수신
- 사용자 업로드 (multipart/tus → S3)
- 또는 외부 ingest (RTMP·SRT 라이브)
- 무결성 검증: 파일 크기·MD5·magic byte (
00-foundations)
2) 분석 (ffprobe)
ffprobe -v error -print_format json \
-show_format -show_streams in.mp4 > metadata.json추출 정보:
- 컨테이너 (
format_name) - 비디오 코덱·해상도·fps·color matrix·field order·pix_fmt
- 오디오 코덱·sample rate·channels·LUFS
- duration·bit_rate·tags(rotation·creation_time…)
- VFR vs CFR (
avg_frame_ratevsr_frame_rate비교)
→ 다음 단계의 결정 입력. 자동화 파이프라인에서는 분석 결과로 ladder를 가변 결정.
3) 정규화
| 입력 상태 | 변환 |
|---|---|
| Interlaced (1080i59.94) | bwdif/yadif → 1080p |
| Telecine (3:2 pulldown) | fieldmatch + decimate → 24p |
| VFR | -vsync cfr → CFR |
| 회전 메타만 있음 | transpose 필터로 픽셀 회전 |
| BT.601 SD → BT.709 HD upscale | colormatrix 변환 + scale |
| Anamorphic 720×480 | scale=854:480, setsar=1:1 |
| 4:4:4 마스터 | yuv420p 변환 |
| 10bit HDR → SDR | zscale + tonemap |
→ 이 단계가 빠지면 클라이언트마다 깨짐. 자동화에서 가장 깐깐한 단계.
4) 인코딩 (ABR ladder)
Ladder 설계
콘텐츠 특성과 타겟 디바이스 별로 ladder가 다름:
| 콘텐츠 | 권장 ladder |
|---|---|
| 단편/SNS | 360p · 540p · 720p · 1080p (4-step) |
| 일반 OTT | 240·360·480·720·720p60·1080·1080p60 (7-step) |
| 4K HDR | + 1440p · 4K · 4K HDR (10-step) |
| 라이브 게임 | 720p60·1080p60 단순 (latency 우선) |
Per-Title encoding (Netflix 발명): 모든 타이틀에 같은 ladder 강제 X. 콘텐츠 복잡도에 따라 동적 ladder.
Rate Control 정책
| 모드 | 풀이 | 사용처 |
|---|---|---|
| CBR (Constant Bit Rate) | 비트레이트 고정 | 라이브·방송·CDN 대역폭 예측 |
| VBR (Variable Bit Rate) | 비트레이트 가변, 평균 목표 | 일반 OTT |
| CapVBR | VBR + 최대 cap | 안전한 라이브·CMAF |
| CRF (Constant Rate Factor) | 시각 품질 고정, 비트레이트 가변 | 마스터링·아카이브 |
| 2-pass VBR | 1-pass 분석 + 2-pass 인코딩 | 정확한 사이즈 목표 |
# CRF (가장 흔함)
-c:v libx264 -crf 22
# 2-pass VBR (정확한 비트레이트)
ffmpeg -y -i in.mov -c:v libx264 -b:v 4M -pass 1 -an -f null /dev/null
ffmpeg -i in.mov -c:v libx264 -b:v 4M -pass 2 out.mp4
# CBR (라이브)
-c:v libx264 -b:v 4M -minrate 4M -maxrate 4M -bufsize 8M
# CapVBR (라이브 안전)
-c:v libx264 -b:v 4M -maxrate 6M -bufsize 12M코덱별 ladder 비교
같은 1080p 품질 기준:
| 코덱 | 권장 비트레이트 |
|---|---|
| H.264 | 5 Mbps |
| HEVC | 3 Mbps |
| VP9 | 3 Mbps |
| AV1 | 2.5 Mbps |
5) 패키징
HLS
ffmpeg -i normalized.mp4 \
-c:v libx264 -c:a aac \
-hls_time 6 -hls_list_size 0 \
-hls_segment_type fmp4 \
-hls_segment_filename "v_%v_%03d.m4s" \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0,name:1080p v:1,a:1,name:720p v:2,a:2,name:480p" \
-hls_playlist_type vod \
out_%v.m3u8→ master.m3u8 + 각 variant playlist + 세그먼트(fMP4 또는 ts).
DASH
ffmpeg -i in.mp4 \
-map 0:v -map 0:a \
-c:v libx264 -c:a aac \
-seg_duration 6 \
-use_template 1 -use_timeline 1 \
-f dash out.mpdCMAF (HLS+DASH 공통)
CMAF fMP4 fragment를 만들어 HLS와 DASH manifest 두 개를 동시에.
6) 배포
- Origin S3 + CloudFront/Cloudflare CDN
- 필요시 서명 URL (private 콘텐츠)
- DRM packaging (Widevine·FairPlay·PlayReady) —
06-streaming챕터 참조
What — 실용적 명령어 모음
풀 ABR ladder (H.264, single-shot)
ffmpeg -i in.mov \
-filter_complex "\
[0:v]split=4[v1][v2][v3][v4]; \
[v1]scale=w=1920:h=1080[v1080]; \
[v2]scale=w=1280:h=720[v720]; \
[v3]scale=w=854:h=480[v480]; \
[v4]scale=w=640:h=360[v360]" \
-map "[v1080]" -c:v:0 libx264 -b:v:0 5M -profile:v:0 high -level 4.0 \
-map "[v720]" -c:v:1 libx264 -b:v:1 2.5M -profile:v:1 high -level 3.1 \
-map "[v480]" -c:v:2 libx264 -b:v:2 1.2M -profile:v:2 main -level 3.0 \
-map "[v360]" -c:v:3 libx264 -b:v:3 600k -profile:v:3 baseline -level 3.0 \
-map a:0 -c:a aac -b:a 128k -ac 2 \
-g 60 -keyint_min 60 -sc_threshold 0 \
-hls_time 6 -hls_playlist_type vod \
-hls_segment_type fmp4 \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0,name:1080p v:1,a:0,name:720p v:2,a:0,name:480p v:3,a:0,name:360p" \
out_%v.m3u82-pass with target file size
# 100 MB로 1시간 영상 맞추기
TARGET_SIZE_MB=100
DURATION=$(ffprobe -v error -show_entries format=duration -of csv=p=0 in.mov)
BITRATE=$(echo "($TARGET_SIZE_MB * 8 * 1024) / $DURATION - 128" | bc)k
ffmpeg -y -i in.mov -c:v libx264 -b:v $BITRATE -pass 1 -an -f null /dev/null
ffmpeg -i in.mov -c:v libx264 -b:v $BITRATE -pass 2 -c:a aac -b:a 128k out.mp4AWS Elemental MediaConvert 패턴
MediaConvert는 ffmpeg를 완전 매니지드 + ABR job 자동화 한 서비스.
Job 구조 (간략):
{
"Settings": {
"Inputs": [{
"FileInput": "s3://bucket/in.mp4",
"DeblockFilter": "DISABLED",
"DenoiseFilter": "DISABLED"
}],
"OutputGroups": [{
"Name": "Apple HLS",
"OutputGroupSettings": {
"Type": "HLS_GROUP_SETTINGS",
"HlsGroupSettings": {
"SegmentLength": 6,
"MinSegmentLength": 0,
"Destination": "s3://bucket/hls/"
}
},
"Outputs": [
{"NameModifier": "_1080", "VideoDescription": {"Width": 1920, "Height": 1080, "CodecSettings": {"Codec": "H_264", "H264Settings": {"Bitrate": 5000000}}}},
{"NameModifier": "_720", "VideoDescription": {"Width": 1280, "Height": 720, "CodecSettings": {"Codec": "H_264", "H264Settings": {"Bitrate": 2500000}}}}
]
}]
}
}→ MediaConvert는 ABR auto-ladder (AutomatedEncodingSettings)도 지원: 비트레이트 cap만 주면 콘텐츠 복잡도 분석해 자동 ladder 생성.
화질 검증 — VMAF
Netflix가 만든 perceptual quality metric. PSNR/SSIM보다 사람 인지에 가까움.
# 원본 vs 인코딩본 VMAF 점수
ffmpeg -i original.mp4 -i encoded.mp4 \
-lavfi "[0:v][1:v]libvmaf=log_path=vmaf.json" -f null -VMAF 점수 가이드:
- 95+: 시각적으로 손실 거의 없음
- 90~95: 일반 OTT 품질
- 80~90: 모바일 데이터 절감 모드
- < 70: 품질 저하 인지 가능
흔한 정규화 명령어
# 회전 메타 → 픽셀 회전
ffmpeg -i in.mp4 -vf "transpose=1" -metadata:s:v rotate=0 out.mp4
# 자동 디인터레이스 (input field order 자동 감지)
ffmpeg -i in.mov -vf "bwdif=mode=1:parity=auto:deint=1" out.mp4
# VFR → CFR
ffmpeg -i screen.mp4 -vsync cfr -r 60 -c:v libx264 cfr.mp4
# Anamorphic 정규화
ffmpeg -i ana.mov -vf "scale=854:480,setsar=1:1" out.mp4
# Color matrix 명시
-color_primaries bt709 -color_trc bt709 -colorspace bt709What-if — 잘못 다루면 어떻게 깨지는가
❌ 함정 1 — 정규화 단계 생략
원본을 그대로 인코딩 → 어떤 클라이언트에서는 깨진 영상. 정규화는 비싸지만 반드시 통과해야 하는 게이트. 자동 파이프라인의 90% 버그가 여기서 나옴.
❌ 함정 2 — Key frame 위치가 ladder마다 다름
ABR 전환 시 반드시 모든 ladder에서 같은 시각에 key frame이 있어야 함.
# 모든 ladder에 동일 GOP 강제
-g 60 -keyint_min 60 -sc_threshold 0 \
-force_key_frames "expr:gte(t,n_forced*2)"❌ 함정 3 — CBR을 VOD에 사용
CBR은 모든 장면에 같은 비트 — 정적 장면에서 비트 낭비, 격렬한 장면에서 비트 부족. VOD는 VBR 또는 CRF가 정석. CBR은 라이브의 대역폭 예측 용도.
❌ 함정 4 — CRF 값을 ladder마다 똑같이
CRF는 해상도 비-aware. 1080p CRF 22와 360p CRF 22는 다른 비트레이트. 해상도가 낮을수록 CRF를 낮춰야 (더 좋은 화질) — 작은 해상도에서 비트가 적게 쓰이는 걸 보정.
1080p: CRF 22
720p: CRF 21
480p: CRF 20
360p: CRF 19❌ 함정 5 — 인코딩 후 검증 안 함
인코딩이 silently fail (예: 일부 NAL 손상) 해도 재생 시 깨질 때까지 모름. ffprobe로 패킷 무결성 + VMAF 샘플 점수로 검증 단계 추가.
❌ 함정 6 — 모든 코덱·모든 해상도 ladder 풀 인코딩
H.264 7-step + HEVC 5-step + AV1 4-step + VP9 3-step = 19 인코딩. 콘텐츠 시청 분포에 비해 비싸짐. 상위 70% 시청 디바이스 커버하는 ladder만 선택.
❌ 함정 7 — 마스터 원본 폐기
ABR ladder만 남기고 원본 폐기하면 미래 코덱(VVC·AV2)으로 재인코딩 불가. 마스터(고품질)는 cold storage에 영구 보관, ABR은 재생성 가능한 derivative.
Insight — 흥미로운 이야기
“Netflix Per-Title Encoding”
2015년 Netflix가 발표 — 모든 타이틀에 같은 ladder를 쓰지 말자. 애니메이션은 평면 영역 많아 1080p에 1.5 Mbps로 충분, 액션 영화는 4 Mbps 필요. 콘텐츠 분석 후 맞춤 ladder 생성 → 평균 20% 대역폭 절감 + 같은 품질. 이후 Per-Shot Encoding, Dynamic Optimizer로 진화 — 한 영상 안에서도 장면별 다른 비트.
“VMAF가 VAS-MAF가 된 사연”
Netflix가 PSNR/SSIM이 사람 인지와 안 맞는다는 걸 깨닫고 만든 metric. 여러 quality metric (VIF·DLM·motion)을 머신러닝으로 융합 — 이름의 ‘M’은 Machine learning. 2016년 오픈소스화. AV1·VP9 인코더 튜닝의 de facto 평가 도구.
“AWS MediaConvert는 ffmpeg + 매니지드”
MediaConvert는 내부적으로 Elemental Server (AWS가 인수한 회사)의 인코더 사용. 핵심 차별점:
- 자동 ABR ladder (콘텐츠 분석)
- QVBR (Quality-Defined Variable Bit Rate) — Elemental 고유 rate control
- DRM packaging 통합 (Widevine·FairPlay·PlayReady 한번에)
- per-job pricing — 사용한 만큼만 → 자체 ffmpeg 클러스터 운용보다 총비용 더 쌀 가능성 — 규모에 따라.
“YouTube의 trick — Two-pass with cluster”
YouTube는 영상 한 편을 청크로 쪼개 수천 GPU에 병렬 인코딩. 각 청크가 독립적으로 2-pass 후 다시 합침. 1시간 영상이 수 분 만에 인코딩. 이게 가능한 이유: GOP 경계에서 청크를 나누면 디코딩 호환성 유지.
“라이브 vs VOD의 진짜 차이는 Rate Control”
VOD: CRF (사이즈 가변, 품질 일정) 라이브: CBR (비트 고정, 품질 가변) 왜 라이브는 비트 고정? — 인터넷 송출 시 대역폭 예측 가능성이 가장 중요. 갑자기 비트 폭증하면 ABR 전환이 어긋남.
“인코딩은 비대칭 비용 게임”
한 번 인코딩 = O(시간 × 1) 재생 = O(시간 × 사용자 수) = 수백만 배. 그래서 OTT는 인코딩에 시간을 더 쓰는 결정이 합리적 —
libsvtav1 preset 4가preset 9보다 4배 느려도 대역폭 5% 절감이면 회수.
요약 + Mermaid
인코딩 파이프라인은 6단계(수신 → 분석 → 정규화 → 인코딩 → 패키징 → 배포)이며, 각 단계는 최종 소비자에서 거꾸로 추론된다. CRF는 마스터링·VOD, CBR은 라이브, VBR/CapVBR은 일반 OTT. ABR ladder는 모든 변형의 key frame 위치 일치 필수. Per-Title encoding과 VMAF가 모던 OTT의 표준이고, MediaConvert는 매니지드 옵션. 마스터는 영구 보관, ladder는 재생성 가능한 derivative.