블로그 목록
Fundamentals20분 읽기

Video Frame 기초 — Interlaced, I/P/B-frame, GOP, PLI, FIR

Interlaced와 progressive scan, intra·predictive·bi-predictive picture, GOP의 관계를 설명합니다. RTP video session에서 decoder가 reference picture를 잃었을 때 RTCP PLI·FIR가 요청하는 동작도 구분합니다. GOP 길이와 B-frame 사용 여부는 서비스 유형과 codec 협상에 따라 달라집니다.

InterlacedProgressiveI-frameP-frameB-frameGOPPLIFIRRTCPH.264WebRTC기초
목차(45개 항목)
  1. 1. 프레임이란? 그리고 Interlaced의 역사
    1. 아날로그 시대의 문제
    2. Interlaced (비월 주사)의 등장
    3. Progressive vs Interlaced
    4. 왜 "부드러워 보이는가"
    5. 현대는 왜 Progressive가 표준인가
  2. 2. 720p의 "p"의 정체
  3. 3. I / P / B-frame — 세 가지 프레임 타입
    1. I-frame (Intra-coded)
    2. P-frame (Predictive)
    3. I-frame vs P-frame — 실제로 뭐가 다른가
    4. B-frame (Bi-directional predictive)
    5. B-frame은 "미래"를 어떻게 아는가 — 가장 근본적인 질문
    6. 용량 비교 (대략)
    7. 한눈에 보는 프레임 타입별 의존성
  4. 4. WebRTC는 왜 대부분 P-frame만 쓰는가
    1. I-frame만 보내면 어떻게 될까
    2. 왜 B-frame도 안 쓰는가
    3. 흔한 저지연 구성: I/IDR + P
    4. 전략 요약
  5. 5. GOP란 무엇인가
    1. GOP 길이와 I-frame 간격
    2. GOP 짧음 vs 김
    3. GOP 시각화
  6. 6. I-frame은 언제, 왜 새로 찍히는가
    1. 정기 I-frame
    2. 추가(동적) I-frame 트리거
  7. 7. PLI / FIR — RTCP 피드백 메시지
    1. PLI (Picture Loss Indication)
    2. FIR (Full Intra Request)
    3. 왜 필요한가
    4. 시각화 — RTCP 피드백 루프
    5. PLI와 FIR 선택
  8. 8. B-frame이 장애 복구를 어렵게 만드는 구조
    1. I + P만 있을 때 (WebRTC)
    2. B-frame이 섞일 때
  9. 9. 전송 순서 ≠ 표시 순서 — B-frame 지연의 정체
    1. 표시 순서 vs 전송 순서 — 시각화
    2. 순서 역전 예시
    3. 디코더 관점의 프로세스
    4. 실시간 통신에서의 영향
    5. Look-ahead 지연 시각화
  10. 정리
  11. 관련 글
  12. 참고 자료

"프레임이 뭐예요?", "720p의 p가 뭐예요?", "I-frame은 뭐고 P-frame은 뭐예요?", "GOP는 왜 있어요?". 영상 품질 이슈를 조사할 때마다 이 질문들이 반복됩니다. 이 글은 영상이 픽셀 덩어리에서 네트워크를 타고 눈에 도달할 때까지 반드시 이해해야 할 개념들을, 현실 예시와 다이어그램으로 정리합니다.

구성:

  1. 프레임의 개념과 Interlaced(비월) vs Progressive(순차)
  2. 720p의 "p"의 정체
  3. I / P / B-frame
  4. WebRTC는 왜 대부분 P-frame만 쓰는가
  5. GOP란 무엇인가
  6. I-frame은 언제, 왜 새로 찍히는가
  7. PLI와 FIR — "키프레임 다시 주세요" RTCP 피드백
  8. B-frame이 장애 복구를 어렵게 만드는 구조
  9. 전송 순서 ≠ 표시 순서 — B-frame 지연의 정체

1. 프레임이란? 그리고 Interlaced의 역사

TV 화면은 실제로는 정지 이미지(프레임)를 빠르게 연속으로 보여주는 것입니다. 초당 30장의 정지 이미지를 보여주면 사람 눈은 "움직임"으로 인식합니다. 이는 정지 이미지의 빠른 연속을 뇌가 움직임으로 해석하는 가현운동(apparent motion / phi 현상) 덕분입니다. 흔히 "잔상 효과(persistence of vision)"로 설명되지만, 잔상은 깜빡임이 연속광으로 보이는 부분(flicker fusion)만 설명할 뿐 움직임 지각의 원인은 아니라는 것이 현대 지각과학의 정설입니다.

아날로그 시대의 문제

옛날 아날로그 TV는 전송할 수 있는 대역폭이 제한적이었습니다.

  • 30fps → 그럭저럭 전송 가능
  • 같은 공간 해상도에서 frame rate를 두 배로 만들면 sample 수와 필요한 전송량이 늘어남
  • 30fps는 깜빡임(flicker)이 심해 눈이 피로

Interlaced (비월 주사)의 등장

"한 프레임을 두 번에 나눠서 보내자"는 해결책이 나왔습니다. 화면의 가로 주사선을 홀수 줄 / 짝수 줄로 나눕니다.

전체 프레임 (예: 480줄)
├── 홀수 줄: 1, 3, 5, 7, ..., 479  → Field 1 (1/60초에 전송)
└── 짝수 줄: 2, 4, 6, 8, ..., 480  → Field 2 (다음 1/60초에 전송)

시각화:

화면 한 장면:
━━━━━━━━━━━━━━━━━━━━━━━━━━━  ← 1번 줄
                              ← 2번 줄 (다음 field)
━━━━━━━━━━━━━━━━━━━━━━━━━━━  ← 3번 줄
                              ← 4번 줄
━━━━━━━━━━━━━━━━━━━━━━━━━━━  ← 5번 줄
...

Field 1에는 홀수 줄만 존재 → 1/60초 뒤 Field 2에 짝수 줄이 채워짐

Progressive vs Interlaced

Progressive (순차)Interlaced (비월)
방식한 프레임을 통째로 전송홀수/짝수 줄 번갈아 전송
초당 전송 횟수30회60회 (반쪽씩)
데이터량frame/field rate와 해상도를 함께 놓고 비교예: 480i60은 초당 60 field, 약 30 frame 분량의 line sample
움직임frame rate에 따름서로 다른 시점의 field를 초당 60회 갱신
정지 화면 화질선명깨끗 (두 field 합성)
움직이는 화면깔끔Comb 아티팩트 발생 가능

왜 "부드러워 보이는가"

Field 1과 Field 2는 서로 다른 시점에 촬영되므로 60Hz motion sampling을 제공합니다. 대신 각 field의 수직 표본은 절반이고, 움직이는 영역을 두 field로 합치면 comb artifact가 생길 수 있습니다.

현대는 왜 Progressive가 표준인가

  • 디지털 전송은 대역폭 충분
  • LCD/OLED 모니터는 픽셀 전체를 한 번에 그림 (Interlaced를 재현하려면 디인터레이싱 처리 필요)
  • 스포츠처럼 빠른 움직임에서 Interlaced는 Comb 아티팩트 (머리카락 빗 모양 줄무늬)가 보임
  • 현대 WebRTC·스마트폰·웹캠 파이프라인은 대체로 Progressive를 사용하며, interlaced source는 ingest 단계에서 deinterlace가 필요할 수 있음

2. 720p의 "p"의 정체

  • p = progressive
  • i = interlaced

숫자는 세로 픽셀 수(해상도의 높이)입니다.

표기해상도스캔 방식
720p1280 × 720Progressive
1080p1920 × 1080Progressive
1080i1920 × 1080Interlaced
2160p (4K UHD)3840 × 2160Progressive
4320p (8K)7680 × 4320Progressive

"숫자의 의미"는 세로 픽셀 수. 다른 해상도 표기(Full HD = 1080p, HD = 720p, UHD = 2160p)와 본질이 같고 "p"는 스캔 방식을 명시할 뿐입니다.


3. I / P / B-frame — 세 가지 프레임 타입

H.264/H.265 같은 비디오 코덱은 intra prediction과 inter prediction을 함께 사용합니다. 엄밀히는 H.264의 I/P/B는 picture 전체가 아니라 slice type이며, 한 picture에 여러 slice type이 섞일 수도 있습니다. 이 글에서는 이해를 위해 주된 slice type에 따라 I/P/B-picture라고 부릅니다.

I-frame (Intra-coded)

"Intra"는 다른 picture의 sample을 참조하지 않고 같은 picture 안의 이미 복원된 이웃 sample을 예측에 쓰는 coding 방식입니다. 압축된 완전 픽셀 dump나 JPEG와 같은 형식은 아닙니다.

  • 다른 프레임을 참조하지 않음
  • inter picture보다 큰 경우가 많지만 크기는 content·QP·encoder에 따라 달라짐
  • random access에는 일반 I-picture가 아니라 IDR 등 decoder refresh point가 중요
I-frame은 스스로 완결된 이미지:
┌──────────────────────┐
│  [intra prediction + transform residual] │ ← 외부 reference picture 불필요
└──────────────────────┘

P-frame (Predictive)

P-slice는 주로 과거 reference picture 후보(list 0)에서 motion-compensated prediction을 만들고 residual을 함께 부호화합니다. 단순히 직전 frame의 바뀐 픽셀만 보내는 방식은 아닙니다.

P-picture ≈ reference prediction + motion vector + residual

이전 P-frame:                  현재 P-frame:
┌──────────────────────┐      ┌──────────────────────┐
│                      │      │                      │
│    ● ← 얼굴 위치      │  →  │      ● ← 얼굴 이동    │
│                      │      │                      │
│   [배경 동일]         │      │   [배경 동일, 안 보냄] │
└──────────────────────┘      └──────────────────────┘

전송되는 것:
  "얼굴 영역이 오른쪽으로 5픽셀 이동했음" + 잔차(residual)
  → 데이터 매우 작음

I-frame vs P-frame — 실제로 뭐가 다른가

예시: 사람이 오른쪽으로 살짝 움직이는 영상 I-frame (완전한 그림) t=0 (I-frame 내용) 데이터에 담긴 것 • 모든 픽셀의 색깔 정보 • "(0,0)은 회색, (1,0)도 회색, (112,85)는 주황…" • 배경 + 얼굴 + 몸 전부 • 용량: content·QP·encoder에 따라 달라짐 P-frame (변화량만) t=1 (변화) 데이터에 담긴 것 • "사람을 오른쪽으로 10 픽셀 이동" • 배경은 언급 없음 (안 바뀜) • 변화량(delta) + 잔차(residual)만 지시 • 시간 중복이 크면 intra보다 작을 수 있음

핵심 차이:

I-frameP-frame
담는 것절대값 — 전체 픽셀 색깔변화량 — 이전 대비 delta
지시 방식"이 장면을 이렇게 그려라""이전 프레임에서 이만큼만 바꿔라"
비유그림을 처음부터 다 그리기수정 지시서
용량inter picture보다 큰 경우가 많음content·reference·QP에 따라 달라짐

따라서 시간적으로 비슷한 장면에서는 inter prediction이 중복을 줄일 수 있습니다. 실제 frame 크기 비율은 고정값이 아닙니다.

B-frame (Bi-directional predictive)

B-slice는 list 0, list 1 또는 양쪽 reference list에서 prediction을 만들 수 있습니다. 표시 순서상 뒤의 reference를 사용하면 decoding order 재배열과 buffer가 필요합니다.

B-frame은 "미래"를 어떻게 아는가 — 가장 근본적인 질문

가장 헷갈리는 지점입니다. 답이 의외로 간단합니다.

답: 인코더는 미래를 알고 있습니다. 왜냐하면 이미 다 찍혔으니까.

인코더 관점 — 미래를 안다

카메라는 계속 프레임을 찍어서 버퍼(임시 저장소)에 쌓습니다. 30fps면 1초에 30장이 버퍼에 쌓입니다.

인코더는 이 버퍼를 보면서 작업합니다:

"지금 t=1을 인코딩해야 함. B-frame으로 만들 거야"
"이 예에서는 t=0(과거)과 t=3(표시 순서상 이후)을 reference로 선택"
"t=3? 아, 버퍼에 이미 있네. 카메라가 진작 찍었으니까"  ← 핵심
"선택한 reference들로 prediction을 만들고 residual을 부호화 → B-picture 완성"

인코더 입장에서는 미래도 과거도 다 "이미 찍힌 프레임" 입니다. 시간 순서는 사용자 입장이지, 인코더 입장에서는 그냥 "버퍼에 쌓인 데이터들"일 뿐입니다.

카메라 → 버퍼 (이미 쌓인 프레임들) I t=0 B₁ t=1 B₂ t=2 P t=3 ← 인코더가 접근 가능 인코더 사고 과정 "뒤쪽 reference가 필요하면 해당 picture가 들어올 때까지 buffer한 뒤 prediction"

그래서 인코딩 지연이 생긴다

근데 이게 문제입니다. 영상통화는 실시간인데:

B-frame을 쓰려면:
  인코더가 t=1을 받고도 "아직 인코딩 안 함"
  t=2도 받고도 "아직"
  t=3이 찍힐 때까지 기다림
  그제야 t=3 인코딩 → 이어서 t=1, t=2 인코딩

→ "기다리는 시간" = 인코딩 지연

이게 WebRTC가 B-frame을 쓰지 않는 두 번째 이유입니다:

어느 쪽 지연인가원인
1번째 이유디코딩 지연 (수신측)B-frame 디코딩하려면 미래 P-frame 대기
2번째 이유인코딩 지연 (송신측)인코더가 미래 프레임이 쌓일 때까지 기다림

디코더 관점 — 미래 모름, 재배열로 해결

디코더는 네트워크에서 도착하는 순서대로만 받을 수 있습니다. 그래서 인코더가 일부러 순서를 바꿔서 보냅니다:

카메라가 찍은 순서 (= 표시 순서):  I → B₁ → B₂ → P
네트워크로 보내는 순서:             I → P 먼저 → B₁ → B₂

이러면 디코더가 B₁을 받는 시점에는 이미 I와 P를 둘 다 가지고 있음 → 참조 가능 → B₁ 디코딩 OK.

결론: "디코더가 미래를 계산하는 게 아니라, 인코더가 미래를 미리 봐서 계산해놓고 순서를 재배열한 것."

표시 순서:    I₁   B   B   P₁   B   B   P₂
              ↑   ↑↓  ↑↓   ↑  ↑↓  ↑↓   ↑
              │   참조│    │  참조│    │
              └─양방향┘    └─양방향┘

B-slice는 한쪽 또는 양쪽 reference list를 사용할 수 있음
→ 가장 잘 압축됨
→ 대신 "미래"를 기다려야 하므로 지연 발생

용량 비교 (대략)

프레임 타입상대 용량특징
I-picturecontent·QP에 따라 다름외부 reference 없이 coding, IDR 여부 별도
P-picturecontent·reference 선택에 따라 다름list 0 기반 inter prediction 가능
B-picturecontent·reference 선택에 따라 다름list 0/list 1 prediction 가능

한눈에 보는 프레임 타입별 의존성

I-frame 독립, 용량 큼 I 참조 없음 P-frame 과거만 참조 I P 한 방향 의존 B-frame 과거 + 미래 참조 I B P 양방향 의존

핵심: 저지연 WebRTC encoder는 흔히 B-picture를 끄지만, RTP나 WebRTC 표준이 모든 B-picture를 금지하는 것은 아닙니다. 실제 profile과 bitstream은 SDP 협상과 구현 설정으로 확인합니다.


4. WebRTC는 왜 대부분 P-frame만 쓰는가

I-frame만 보내면 어떻게 될까

모든 프레임을 I-frame으로 보내면:

all-intra는 inter prediction을 쓰지 않으므로 같은 quality target에서 더 높은 bitrate가 필요한 경우가 많습니다.
정확한 차이는 resolution만으로 계산할 수 없고 content·QP/CRF·encoder를 고정해 측정해야 합니다.

왜 B-frame도 안 쓰는가

B-frame을 쓰면 압축은 더 잘 되지만:

  • 디코더가 "미래 프레임"을 기다리는 지연 발생 (look-ahead)
  • reference graph와 reorder buffer가 복잡해질 수 있음
  • gateway와 receiver가 negotiated profile·decoding order를 지원해야 함. RTP timestamp 자체는 non-monotonic일 수 있음

이건 별도 글에서 자세히 다뤘습니다 → RTMP 라이브 송출의 B-frame이 만든 PTS rollback

흔한 저지연 구성: I/IDR + P

저지연 H.264 encoder의 한 구성 예:

[I  P  P  P  P  P  P  P  P  P  P  P  P  P  P] [I  P  P  P  P  P  P ...
  └──── 약 2초 (60 frames) ────────────────┘   └──── 다음 GOP ────...

I-frame: 드물게 (재시작/복구 기준점)
P-frame: 대부분 (직전 프레임과의 차분)
B-frame: 거의 없음

전략 요약

  • I-frame을 너무 자주 → 대역폭 폭증
  • I-frame을 너무 드물게 → 조인/복구 느림
  • GOP 간격은 join, loss recovery, bitrate와 대상 platform 요구사항을 함께 보고 선택

5. GOP란 무엇인가

🌱 처음부터 — fps가 뭐지? "2초마다 I-frame"이 무슨 뜻이지?

fps = frames per second = 초당 프레임 수. 영상은 사실 정지 이미지(프레임)를 빠르게 연속으로 보여주는 것입니다. 애니메이션 원리와 같습니다.

  • 영화: 24fps (초당 24장)
  • TV / YouTube: 30fps
  • 게임: 60fps, 120fps (더 부드러움)
  • 화상회의: 보통 30fps

"2초마다 I-frame"의 뜻:

30fps = 1초에 30 프레임
2초 = 60 프레임
→ 60 프레임에 한 번씩 I-frame 하나
→ 나머지 59개는 P-frame
→ 이 60 프레임 묶음 = GOP 1개

왜 2초 예시를 자주 보나?

  • 여러 live ingest platform이 2초 keyframe interval을 권장해 운영 예시로 흔함
  • 짧으면 random-access 기회는 늘지만 intra picture 비용도 늘 수 있음
  • 길면 자연 refresh를 기다리는 시간은 늘 수 있음
  • WebRTC 표준의 고정값은 아니며 feedback 기반 keyframe 요청과 encoder 정책에 따라 달라짐

GOP = Group of Pictures. I-frame에서 다음 I-frame 직전까지의 프레임 묶음입니다.

[I  P  P  P  P  P  P  P  P  P  P  P  P  P  P]  [I  P  P  P  P  P  P  P  P  P  P  P  P  P  P]
 └────────── GOP 1 (15 frames) ────────────┘    └────────── GOP 2 ──────────────────────┘

GOP 길이와 I-frame 간격

30fps 기준:

GOP 길이I-frame 간격용도
301초마다저지연 실시간 (빠른 복구, 대역폭 많이 씀)
602초마다live ingest 설정 예시
1505초마다더 긴 간격의 예시
30010초마다VOD용 긴 GOP 예시

GOP 짧음 vs 김

GOP 짧으면:

  • 새 참여자 조인 빠름 (곧 다음 I-frame 옴)
  • 패킷 유실 시 복구 빠름
  • 대역폭 많이 씀 (I-frame 자주 반복)

GOP 길면:

  • 대역폭 절약 (I-frame 드묾)
  • 조인/복구 느림
  • 장기 재생에는 유리

GOP 시각화

GOP = 30 (1초 간격):
t=0   t=1   t=2   t=3   t=4   t=5 (초)
 I-----I-----I-----I-----I-----I    ← 많은 재진입 지점

GOP = 300 (10초 간격):
t=0             t=10            t=20
 I─────────────I───────────────I    ← 재진입 거의 없음
                                      새 시청자는 최대 10초 대기

WebRTC 자체는 2초 GOP를 표준으로 정하지 않습니다. 실제 간격은 encoder 기본값, PLI/FIR 처리, simulcast layer, downstream ingest 요구사항으로 확인합니다.


6. I-frame은 언제, 왜 새로 찍히는가

정기 keyframe 간격 외에도 구현은 다음 event에서 decoder refresh picture를 만들 수 있습니다.

정기 I-frame

GOP 설정에 따라 주기적으로. 예: GOP 60 + 30fps → 2초마다.

추가(동적) I-frame 트리거

① 수신자가 PLI/FIR 요청
   "프레임 손실됨, 키프레임 다시 보내줘"
   → 송신자가 가능한 시점에 decoder refresh picture 생성 여부를 결정

② 장면 전환(scene change) 감지
   "카메라가 완전히 다른 장면으로 바뀜"
   → P-frame으로는 차분이 너무 커서 효율 떨어짐
   → 인코더가 자발적으로 I-frame 삽입

③ 새 참여자 합류
   "이 사람은 이전 프레임 없음, I-frame부터 필요"
   → SFU가 PLI/FIR를 전달하거나 cached keyframe을 쓰는 등 구현별 처리

④ 네트워크 상태 급변
   → 인코더가 재시작 기준점 확보를 위해 I-frame 삽입

즉 "정기 + 필요할 때 수시" 구조입니다.


7. PLI / FIR — RTCP 피드백 메시지

🌱 처음부터 — PLI가 대체 뭐예요?

영상통화 상황을 상상해보세요. 상대방이 비디오를 계속 보내는 중. 어느 순간 인터넷이 불안해서 비디오 패킷 하나가 사라졌습니다. 내 화면이 깨집니다. 어떻게 복구할까요?

평소의 방향:

Sender → (비디오 RTP) → Receiver

문제 발생 시 수신자가 거꾸로 요청:

Sender ← (RTCP PLI: "I-frame 다시 보내줘") ← Receiver

PLI = Picture Loss Indication입니다. 수신자가 하나 이상의 picture를 잃어 prediction을 계속하기 어렵다는 사실을 알립니다. 응답 방식은 sender가 결정합니다.

  • 평소엔 송신자 → 수신자로 한쪽 방향
  • 깨졌을 때만 수신자 → 송신자로 구조 요청
  • sender는 decoder refresh picture 생성, feedback 병합 또는 rate-limit 등을 결정
  • refresh picture를 정상 수신하면 prediction chain을 다시 시작할 수 있음

이게 RTCP (RTP Control Protocol)가 하는 일의 핵심입니다. 미디어 전송은 RTP, 피드백·제어는 RTCP.

둘 다 decoder refresh와 관련된 RTCP feedback이지만 의미와 사용 조건이 다릅니다.

PLI (Picture Loss Indication)

  • RFC 4585 정의
  • 하나 이상의 picture 손실로 prediction이 어렵다는 indication
  • sender가 intra picture를 만들 수 있지만 즉시 응답이 보장되지는 않음

FIR (Full Intra Request)

  • RFC 5104 정의
  • decoder refresh point가 필요하다는 command와 sequence number를 전달
  • RFC 5104의 중복 억제·응답 규칙을 따르며 단순한 "더 강한 PLI"는 아님

왜 필요한가

inter-coded picture 손실은 그 picture를 참조하는 후속 picture에 전파될 수 있습니다. 영향 범위는 reference selection, error concealment, RTX/FEC와 refresh 정책에 따라 달라집니다.

정상 시나리오:
  I → P → P → P → P → P → P → P (잘 재생)

손실 시나리오:
  I → P → P → [P 유실] → P? → P? → P? → P? (깨짐)
                        └── 뒤로 다 박살
                        ↓
                  수신자: "PLI 보냄"
                        ↓
                  송신자: I 즉시 전송
                        ↓
  I → P → P → P  (다시 정상)

시각화 — RTCP 피드백 루프

  Sender                                Receiver
    │                                     │
    ├── RTP (P-frame seq=100) ───────────▶│
    ├── RTP (P-frame seq=101) ───────────▶│
    ├── RTP (P-frame seq=102) ─X          │    ← 유실
    ├── RTP (P-frame seq=103) ───────────▶│    ← 참조할 102 없어서 깨짐
    │                                     │
    │                                     │ 수신자: 손실 감지
    │◀── RTCP PLI (keyframe 요청) ────────┤
    │                                     │
    │   "즉시 I-frame 찍어!"              │
    ├── RTP (I-frame seq=110) ───────────▶│   ← 복구됨
    ├── RTP (P-frame seq=111) ───────────▶│
    │                                     │

PLI와 FIR 선택

상황고려할 feedback
일반 패킷 유실 복구PLI
새 참여자 합류SFU/endpoint 구현에 따라 PLI 또는 FIR
mixer가 새 spatial relationship을 만들 때RFC 5104가 설명하는 FIR 사용 사례
단순 packet 재전송PLI/FIR가 아니라 NACK/RTX 지원 여부 확인

8. B-frame이 장애 복구를 어렵게 만드는 구조

I + P만 있을 때와 B가 섞였을 때의 차이입니다.

I + P만 있을 때 (WebRTC)

전송 순서:   I₁  P₁  P₂  P₃  P₄  P₅  P₆  I₂
디코딩 순서: I₁  P₁  P₂  P₃  P₄  P₅  P₆  I₂
             (전송 순서 = 디코딩 순서, 동일)

의존성:
  I₁ ← P₁ ← P₂ ← P₃ ← P₄ ← P₅ ← P₆
  (단방향 선형 체인)

P₃ 손실 시:
  → P₄, P₅, P₆ 디코딩 불가 (줄줄이)
  → 해결: PLI 요청 → I₂ 받으면 복구
  → 구조가 단순, 복구 판단 쉬움

B-frame이 섞일 때

표시 순서:    I₁  B₁  B₂  P₁  B₃  B₄  P₂
              (사용자가 보는 순서)

전송 순서:    I₁  P₁  B₁  B₂  P₂  B₃  B₄
              (디코더가 받는 순서 — 다름!)
              ↑    ↑   ↑
              B₁을 디코딩하려면 I₁과 P₁ 둘 다 필요
              그래서 P₁을 B₁보다 먼저 보냄

의존성:
  I₁ ──→ P₁ ──→ P₂
   │  ↘  │  ↘   │
   ↓   ↘ ↓   ↘  ↓
   B₁    B₂   B₃   B₄
   (양방향 그물망)

P₁ 손실 시:
  → B₁, B₂ 디코딩 불가 (P₁ 참조)
  → P₂도 디코딩 불가 (P₁ 체인)
  → B₃, B₄도 디코딩 불가 (P₂ 참조)
  → 실제 reference graph에 따라 여러 후속 picture가 영향 받을 수 있음
  → "어디부터 어디까지 버려야 하는가" 판단 복잡
  → 게다가 전송 순서 ≠ 표시 순서라 타이밍 조정도 복잡

결론: B-frame은 장애 영향 범위가 커지고 복구 경로가 복잡해집니다. 이것이 WebRTC가 B-frame을 피하는 구조적 이유 중 하나입니다.


9. 전송 순서 ≠ 표시 순서 — B-frame 지연의 정체

B-frame이 포함되면 디코더가 프레임을 받는 순서와 화면에 보여줘야 하는 순서가 달라집니다.

🌱 왜 순서가 달라져야만 하나? — 보간(interpolation) 비유

영화 필름을 보세요. 사용자는 시간 순서대로 봅니다: 0초 → 1초 → 2초 → 3초. 당연합니다.

그런데 이 예의 B-picture는 표시 순서상 앞뒤 reference에서 motion-compensated prediction을 만듭니다. 단순한 시간 중간값 보간은 아닙니다.

예를 들어 t=1의 B₁ 프레임이 담고 있는 건:

"t=0과 t=3 reference에서 block prediction을 만들고 residual로 차이를 보정하라"

즉 B₁ 자체에는 완전한 그림이 없습니다. I와 P가 둘 다 있어야 B₁을 그릴 수 있습니다.

그래서 어떻게 되냐면:

  • 사용자가 보는 순서 (당연한 시간 순서): I → B₁ → B₂ → P
  • 네트워크로 보내는 순서 (디코더가 계산 가능한 순서): I → P 먼저 → B₁ → B₂

P를 보낼 때: "I만 참조하면 되니까 바로 그릴 수 있음" ✓ B₁을 보낼 때: "I와 P가 필요한데 P는 이미 보냈음" ✓

디코더는 받은 순서대로 처리합니다. P를 못 받았으면 B₁을 계산할 방법이 없습니다. 그래서 인코더가 일부러 P를 B보다 먼저 보내는 것. 이게 "표시 순서 ≠ 전송 순서"의 뜻입니다.

표시 순서 vs 전송 순서 — 시각화

표시 순서 (사용자가 보는 순서) I t=0 B₁ t=1 B₂ t=2 P t=3 전송 순서 (네트워크 도착 순서) I P B₁ B₂ P 먼저 받아야 B₁, B₂ 디코딩 가능 P 받은 시점 ~ B₁ 표시 시점 = look-ahead 지연 latency budget에 추가되는 reorder delay WebRTC는 이 구조를 피함 전송 순서 = 디코딩 순서 = 표시 순서 (I + P만). 한 프레임 받으면 즉시 표시 가능.

순서 역전 예시

표시 순서 (사용자가 보는 순서):
  프레임 번호:   0   1   2   3
  타입:         I   B   B   P
  PTS (표시):    0  33  66  99 ms

B₁은 I(과거, 프레임 0)와 P(미래, 프레임 3) 둘 다 참조
B₂도 마찬가지

전송 순서 (디코더가 받는 순서):
  타입:         I   P   B₁  B₂
  DTS (디코딩):  0  33  66  99 ms
  PTS (표시):    0  99  33  66 ms
                    ↑   ↑   ↑
                    PTS가 뒤로 갔다가 앞으로 갔다가

디코더 관점의 프로세스

t=0   I 받음 → 바로 디코딩 → 화면에 I 표시 (정상)

t=33  P 받음 → 디코딩 가능
             → 근데 B₁, B₂가 먼저 표시되어야 함
             → 디코딩만 하고 화면 표시 대기

t=66  B₁ 받음 → I와 P 다 있으니 B₁ 디코딩 → 화면에 B₁ 표시

t=99  B₂ 받음 → B₂ 디코딩 → 화면에 B₂ 표시

t=99  P의 presentation time에 맞춰 P를 화면에 표시

P를 먼저 받고도 화면에 띄우지 못하고 기다리는 시간 — 이것이 B-frame 지연의 본질입니다.

실시간 통신에서의 영향

지연 예산 비교:

WebRTC 목표: end-to-end 200~500ms

B-frame 2개 + 30fps 가정:
  look-ahead 지연 = 2 × (1/30) × 1000 ≈ 67ms 추가

B-frame 4개:
  look-ahead 지연 = 133ms 추가

추가 지연의 허용 여부는 전체 mouth-to-eye latency budget으로 판단

이것이 WebRTC, 라이브 인터랙션, 원격회의에서 B-frame을 쓰지 않는 구조적 이유입니다 (스펙상 "금지"가 아니라, 구현 선택으로 사실상 거의 배제).

Look-ahead 지연 시각화

B-frame 없음 (WebRTC 기본):

송출 ──→ 인코딩 ──→ 전송 ──→ 수신 ──→ 디코딩 ──→ 표시
 0ms    10ms      80ms    90ms    100ms    105ms
                                             ↑
                                         총 지연 ~105ms

B-frame 포함 (VOD/방송):

송출 ──→ 인코딩 ──→ 전송 ──→ 수신 ──→ 디코딩 ──→ [B 참조용 미래 프레임 대기] ──→ 표시
 0ms    10ms      80ms    90ms    100ms       +67ms (B-frame 2개)          172ms
                                                                            ↑
                                                                      총 지연 ~172ms

VOD에서는 175ms 지연이 문제 없지만, 실시간 통신에서는 체감 가능한 격차입니다.


정리

  • 프레임은 정지 이미지의 연속이고, 뇌가 빠른 연속을 움직임으로 해석하는 가현운동(phi 현상)이 "움직임"을 만든다 (잔상 효과는 flicker fusion만 설명, 움직임 지각의 원인은 아님)
  • Interlaced는 아날로그 시대 대역폭 절약 기법, 현대는 Progressive가 표준
  • "720p"의 p = progressive, 숫자는 세로 픽셀 수
  • I-frame(독립 완결) / P-frame(이전 참조, 차분) / B-frame(양방향 참조, 최고 압축)
  • 저지연 WebRTC H.264 encoder는 흔히 B-picture를 끄지만 실제 profile과 bitstream을 확인해야 함
  • GOP/keyframe 간격은 encoder와 platform 정책이며 WebRTC 표준의 고정 2초 값이 아님
  • PLI는 picture loss indication, FIR은 decoder refresh command이며 sender 응답은 구현 정책을 따름
  • B-picture의 reference/reorder 구조는 latency와 loss recovery의 tradeoff를 늘릴 수 있음

다음 글에서는 H.264 프로파일, x264 인코더 옵션, 하드웨어 인코더, 비트레이트 계산을 다룹니다. 이 글이 "왜 WebRTC가 이렇게 생겼는가"에 대한 개념 기초라면, 다음 글은 "실무에서 어떻게 설정해야 하는가"의 현장 지침입니다.

정정/보강: RFC 7742의 H.264 필수 구현 범위는 Constrained Baseline이며 다른 profile은 협상에 따라 사용할 수 있습니다. RFC 6184는 B-picture를 포함한 H.264 전송을 표현할 수 있고 RFC 3550은 sampling order와 transmission order가 다를 때 non-monotonic RTP timestamp를 허용합니다. VP8 bitstream은 key frame과 interframe 두 frame type을 정의하며 H.264의 B-slice에 대응하는 별도 frame type은 없습니다.


관련 글

참고 자료

© 2026 Frank Kim. All rights reserved.