ABR Ladder의 Layer B 정렬 — 화질 전환 시 키프레임 동기화
"720p로 보다가 1080p로 자동 전환되는 순간 화면이 깨져요." 화질을 바꿀 때 잠깐 멈추거나 검은 화면이 뜨는 신고는 대부분 ABR ladder의 모든 화질이 같은 시간점에 키프레임을 갖지 못해서 생깁니다. 이 글은 화질 전환이 결국 다른 스트림으로 갈아타는 일이라는 점에서 출발해, 왜 모든 화질의 I-frame이 같은 시각에 박혀야 하는지, 그리고 단일 인코더 동시 출력과 force_key_frames, scene-cut 끄기로 그 정렬을 보장하고 ffprobe로 검증하는 방법까지 풀어냅니다.
목차(37개 항목)
- 0. 핵심 명제 — 두 개의 정렬
1. SA 의사결정 흐름 — 한 장 요약
2. ABR이 필요한 이유
3. 화질 전환의 본질 — 시간축에서 스트림을 갈아탐
4. Layer B 정렬 위반 시나리오
6. ABR Ladder 설계 — 일반 권장값
7. 검증 — 실제로 정렬됐는지 확인
- 9. SA 체크리스트 — ABR Ladder 검증
10. 한 줄 결론
- 관련 글
- 참고 자료
"720p로 보다가 1080p로 자동 전환되는 순간 화면이 깨져요". "시청자가 화질 바꿀 때 0.5초 멈춤이 생긴다는데 왜요?" — 두 신고 다 같은 원인입니다. ABR 화질 간 키프레임이 같은 시간점에 안 박혀 있을 때 일어나는 현상.
#37에서 GOP가 세그먼트 길이와 정렬되어야 한다는 Layer A (시간축 정렬) 를 다뤘다면, 이 글은 Layer B (스트림 간 정렬) — ABR ladder의 모든 화질이 같은 시간점에 I-frame을 가져야 하는 이유와 그 구현 방법을 정리합니다.
0. 핵심 명제 — 두 개의 정렬
라이브 송출에는 두 가지 정렬이 동시에 성립해야 한다. ① GOP가 세그먼트 길이의 정수 약수여야 하고(Layer A), ② 모든 ABR 화질이 같은 시간점에 I-frame을 가져야 한다(Layer B). 어느 한쪽만 맞으면 화질 전환 시 깨짐 또는 멈춤이 발생한다.
| Layer | 정렬 | 위반 시 증상 |
|---|---|---|
| A (시간축) | GOP 길이 ↔ HLS 세그먼트 길이 | 패키저가 세그먼트 늘이거나 재인코딩 (#37) |
| B (스트림 간) | 모든 ABR 화질의 키프레임 시간점이 일치 | 화질 전환 시 디코딩 실패 / 검은 화면 / 멈춤 |
1. SA 의사결정 흐름 — 한 장 요약
라이브 송출 설계는 비즈니스 요구사항에서 시작해 검증으로 끝나는 단방향 결정 트리입니다.
시나리오 인터뷰 — 고객사와 만났을 때 7가지 질문
이 7가지를 순서대로 묻고 답변을 채우면 자연스럽게 ladder 설정이 나옵니다.
2. ABR이 필요한 이유
시청자마다 다른 환경
5G에서 보는 사람, 지하철 와이파이, 해외 셀룰러 — 같은 라이브 방송이라도 받을 수 있는 비트레이트가 천차만별.
단일 화질로 송출하면:
- 1080p만: 시청자 C는 끊김
- 360p만: 시청자 A는 화질 불만
ABR — 같은 영상, 여러 화질
같은 라이브 방송을 여러 화질로 동시 인코딩해서 발행. 시청자 디바이스가 자기 네트워크 상태에 맞게 매 세그먼트마다 판단해 골라 받음.
시청자 디바이스의 ABR 알고리즘:
이게 YouTube/Twitch에서 자동 화질 전환되는 원리. 사용자 개입 없이 매 세그먼트 경계에서 판단.
Master Playlist (m3u8)
ABR ladder는 master playlist 한 장에 표현됩니다.
플레이어는 master를 먼저 받고, 처음에 적당한 화질을 골라 그 child playlist를 받음. 이후 매 세그먼트마다 평가 → 필요 시 다른 child로 전환.
3. 화질 전환의 본질 — 시간축에서 스트림을 갈아탐
ABR에서 "화질을 바꾼다"는 건 시청자 디바이스가 다음 세그먼트를 다른 ladder에서 받는다는 뜻입니다.
제약: 새 ladder의 첫 세그먼트는 반드시 I-frame으로 시작해야 함. 안 그러면 디코딩 실패.
왜 P-frame으로 시작하면 안 되나
#37 Layer 4에서 다룬 것과 같은 이유. P-frame은 이전 P 또는 I를 메모리에 갖고 있어야 디코딩 가능. 시청자는 720p의 P를 갖고 있는데, 1080p의 P는 720p의 P를 참조 못 함. 해상도도 다르고 인코딩 컨텍스트도 다름.
→ 새 화질의 첫 세그먼트가 I-frame으로 시작 = ABR 전환의 필수 조건.
이걸 만족하려면 모든 ladder가 같은 시간점에 I-frame을 박아야 함.
4. Layer B 정렬 위반 시나리오
시나리오 A: 정렬됨 (정상)
시나리오 B: Layer B 위반 (각 ladder가 독립적으로 인코딩됨)
이런 패턴은 보통 각 화질을 독립된 인코더로 따로 인코딩할 때 발생합니다. 인코더마다 scene-cut 감지가 다르게 작동하거나, GOP 시작점이 어긋나거나.
시나리오 C: GOP 길이는 같은데 시작점이 다름
각 화질의 GOP 간격은 같아도 위상(phase)이 다르면 정렬 안 됨. 절대 시간점이 같아야 함.
5. Layer B를 보장하는 4가지 방법
방법 1: 단일 인코더에서 ABR ladder 동시 출력
가장 안전. 하나의 인코더가 timestamp 기반으로 모든 화질의 키프레임을 동기화.
핵심 옵션:
-g 60 -keyint_min 60모든 출력에 동일하게 → 60프레임마다 강제 I-frame-sc_threshold 0scene-cut OFF → 가변 GOP 방지- 단일 입력 timestamp가 모든 출력에 동기 전파됨
방법 2: -force_key_frames로 절대 시간 강제
expr:gte(t,n_forced*2) = "직전 강제 키프레임 시점 + 2초 도달 시 키프레임 강제". 절대 시간 기반이라 stream restart 후에도 정렬 유지.
방법 3: 클라우드 트랜스코더 사용
AWS MediaLive, Wowza Streaming Engine, Agora Cloud Recording의 transcoding 옵션 등 — 입력 단일 → ladder 동시 출력 자동 동기화.
Agora Media Push 한정: Media Push는 RTMP 단일 출력 채널입니다. ABR ladder를 직접 만들지 않으므로, Layer B 정렬은 송출 받는 쪽 플랫폼(YouTube/Twitch)이 책임집니다. YouTube가 ladder를 자체 트랜스코딩으로 생성하면 동기화도 그쪽이 처리.
방법 4: 프록시 인코더 + 멀티 RTMP push (커스텀 파이프라인)
자체 CDN이나 멀티 플랫폼 동시 송출 시 — 클라이언트 인코더에서 ladder를 만들고 각각 RTMP push.
이 경우 Layer B 보장이 가장 까다로움. 모든 인코더 인스턴스가 동일 timestamp 기준 + 동일 GOP + scene-cut OFF + force_key_frames 동기 사용 필수.
6. ABR Ladder 설계 — 일반 권장값
플랫폼/콘텐츠 종류에 따라 다르지만 일반적인 시작점:
권장 ladder (16:9 비디오)
| 화질 | 해상도 | 비트레이트 (H.264) | fps | 용도 |
|---|---|---|---|---|
| 1080p | 1920×1080 | 4500~6000 kbps | 30 | 데스크톱/대화면 |
| 720p | 1280×720 | 2500~4000 kbps | 30 | 모바일 와이파이 |
| 480p | 854×480 | 1000~1500 kbps | 30 | 모바일 LTE |
| 360p | 640×360 | 500~750 kbps | 30 | 저속 셀룰러 |
| 240p | 426×240 | 250~400 kbps | 30 | 비상용 |
[NEEDS VERIFICATION] 비트레이트는 콘텐츠 종류(움직임 많은 스포츠 vs 정적인 강의)에 따라 ±30% 변동. 실제 측정 필수.
60fps 송출 (게임/스포츠)
| 화질 | 해상도 | 비트레이트 | fps |
|---|---|---|---|
| 1080p60 | 1920×1080 | 6000~9000 kbps | 60 |
| 720p60 | 1280×720 | 4500~6000 kbps | 60 |
| 720p30 | 1280×720 | 2500 kbps | 30 (저속용 폴백) |
60fps + 2초 세그먼트 → GOP = 120 프레임으로 모든 ladder 동일.
비트레이트 간격 — 1.5~2배 룰
연속한 화질 간 비트레이트가 1.5~2배 차이가 안 나면 ABR 알고리즘이 의미 있게 구분 못 함.
[NEEDS VERIFICATION] Apple HLS Authoring Spec은 비트레이트 단계가 너무 좁거나 너무 넓으면 경고. 자세한 비율 가이드는 Apple mediastreamvalidator로 검증.
7. 검증 — 실제로 정렬됐는지 확인
ladder를 인코딩한 뒤 정렬 여부는 ffprobe로 확인합니다.
각 ladder의 키프레임 timestamp 추출
한 줄 헬스체크 스크립트
Apple mediastreamvalidator
Apple 공식 도구로 HLS Authoring Spec 준수 여부 검증:
키프레임 정렬, 비트레이트 단계, 세그먼트 길이 변동, 코덱 일관성까지 한 번에 체크.
8. 흔한 실수 패턴
실수 1: 각 화질을 독립 ffmpeg 프로세스로
각 프로세스가 자기 timestamp로 독립 인코딩 → scene-cut 위치, 첫 키프레임 시점이 어긋남.
해결: 단일 ffmpeg에서 -filter_complex split + 다중 출력.
실수 2: scene-cut 비활성화 누락
해결: 모든 ladder에 -sc_threshold 0 또는 -x264-params scenecut=0:no-scenecut.
실수 3: VFR(가변 프레임레이트)
입력이 가변 fps면 출력 timestamp도 흔들림 → ladder 간 불일치.
해결: -vsync cfr 또는 -r 30 명시로 CFR 강제.
실수 4: GOP는 같은데 force_key_frames 누락
-g 60만으로는 인코더 내부 상태(rate control 등)에 따라 약간 어긋날 수 있음.
해결: -force_key_frames "expr:gte(t,n_forced*2)"로 절대 시간 강제.
실수 5: 코덱/프로파일이 화질별로 다름
이러면 디코더 재초기화 비용 발생 → 전환 시 멈춤. profile은 일관되게 (보통 Main + bframes=0, #28 참고).
9. SA 체크리스트 — ABR Ladder 검증
10. 한 줄 결론
Layer A는 시간축 정렬, Layer B는 스트림 간 정렬. 둘 다 만족해야 ABR이 깨끗하게 동작한다. 핵심 처방은 "단일 인코더에서 동일 GOP + force_key_frames + scene-cut OFF로 ladder를 동시 출력하는 것".
두 Layer 한눈에
관련 글
- GOP-세그먼트 정렬의 산수 — Layer A 시간축 정렬
- 프레임의 모든 것 — I·P·B-frame / GOP / PLI·FIR
- B-frame 완전정복 — 왜 ABR ladder에서 B-frame이 위험한가
- x264 실전 옵션 — keyint, force_key_frames
- H.264 Profile·인코더 옵션·비트레이트의 현실 — ladder 비트레이트 산정 근거
- Bitrate 완전정복 — 비트레이트 간격 1.5~2배 룰의 이유
- 라이브 스트림 점검 — ffprobe / gstreamer — 키프레임 검증 명령어
참고 자료
- Apple — HLS Authoring Specification for Apple Devices — ABR ladder 비트레이트 단계, 키프레임 정렬, 세그먼트 요구사항 등 권위 있는 1차 기준
- RFC 8216 — HTTP Live Streaming —
#EXT-X-STREAM-INF마스터 플레이리스트와 variant 전환 규칙의 표준 정의 - FFmpeg —
-force_key_frames문서 (Main options) —expr:gte(t,n_forced*N)등 강제 키프레임 표현식의 공식 레퍼런스 - FFmpeg — HLS muxer (
-var_stream_map,-master_pl_name) — 단일 명령으로 다중 화질 ladder + 마스터 플레이리스트 생성 옵션 - Apple — HLS Tools (
mediastreamvalidator) — Authoring Spec 준수 여부 검증 공식 도구 - x264 —
--keyint/--no-scenecut옵션 (FFmpeg trac encoding guide) — 고정 GOP·scene-cut OFF로 ladder 간 위상 정렬을 보장하는 인코더 설정