2026-10-29 정정 — RGB 24비트·30fps·10진 단위로 raw 용량을 재계산했습니다. 유튜브 파일 크기의 상한, 고정 SRT 지연과 TCP 재전송 시간 단정을 제거했습니다.

치지직 입사를 목표로 스트리밍 기술을 공부 중이다. HLS, WebRTC 같은 프로토콜부터 본 게 아니라 더 아래 — "동영상이 도대체 뭐길래 압축이 필요한가", "TCP는 왜 라이브에 안 맞나" 같은 기초부터 다시 정리했다.

이 글은 그 정리 노트다. 스트리밍 처음 공부하는 사람한테 도움이 될 것 같아서 올린다.


1. RGB 24비트 1080p30 raw 영상은 1시간에 약 672GB다

모니터에 보이는 영상은 사실 1초에 수십 장의 정지 이미지가 빠르게 바뀌는 거다. 30fps면 1초에 30장.

1080p 이미지 한 장의 크기를 계산해보면:

1920 × 1080 픽셀 × 3바이트(RGB 24비트) = 6,220,800바이트 = 6.2208MB

패딩 없는 RGB 24비트 30fps라면 6.2208MB × 30 = 186.624MB/s다. MB·GB는 10진 단위다.

1시간은 186.624MB/s × 3600초 = 671.8464GB, 약 672GB다. YUV 4:2:0처럼 픽셀 표현을 바꾸면 raw 용량도 달라진다.

비디오를 평균 6Mbps로 가정하면 1시간에 6,000,000 ÷ 8 × 3600 = 2.7GB다. 오디오·컨테이너 오버헤드는 별도다. 유튜브의 모든 1080p 영상에 적용되는 파일 크기나 같은 화질을 보장하는 압축 비율은 아니다.

압축이 가능한 이유 — 영상의 중복성

영상 데이터에는 엄청난 중복이 있다.

  • 공간적 중복: 하늘을 찍은 프레임에서 파란 픽셀이 수천 개 연속으로 나옴. 픽셀 하나하나 저장할 필요 없이 "파란색 3000개 연속"으로 표현.
  • 시간적 중복: 카메라가 고정된 채 사람만 움직이면, 배경은 프레임마다 똑같음. 바뀐 부분(사람 움직임)만 저장하면 됨.

이걸 표현한 게 I-frame (전체 화면) 과 P-frame (바뀐 부분만) 의 조합이다.

GOP 구조 — I-frame과 P-frame

이 묶음을 GOP (Group of Pictures) 라고 한다. FFmpeg 명령어에서 본 -g 30 옵션이 GOP 크기를 30프레임으로 설정한다는 뜻이다.

코덱 vs 컨테이너

기초에서 가장 헷갈리는 부분.

  • 코덱 (Codec): 데이터를 압축/해제하는 알고리즘. H.264, AAC 같은 것
  • 컨테이너 (Container): 압축된 데이터를 담는 그릇. MP4, MPEG-TS 같은 것

코덱과 컨테이너의 차이

내가 짜고 있는 PokeClip에서 MPEG-TS를 쓴 이유가 이거다. 한 컨테이너 안에 여러 오디오 트랙(게임 소리, 마이크, 디스코드)을 담을 수 있어서.

I-frame이 왜 중요한가

P-frame은 "이전 프레임에서 달라진 것"만 담고 있다. 그래서 P-frame 혼자선 화면을 못 그린다.

독립 재생할 HLS 세그먼트에 적절한 랜덤 액세스 경계가 필요한 이유다. I 영상과 IDR의 차이도 확인해야 한다. 세그먼트 파일을 처음 받았을 때 바로 화면을 그릴 수 있어야 하는데, P-frame으로 시작하면 이전 세그먼트 없이는 그릴 수가 없다.

FFmpeg에서 -hls_time 6을 설정해도 정확히 6초마다 못 자르는 이유가 이거. 6초가 지나도 I-frame이 안 나오면 다음 I-frame이 나올 때까지 기다린다.


2. TCP의 재전송은 버퍼링에 어떻게 영향을 주나

브라우저에서 영상 세그먼트(.ts 파일) 하나를 요청한다고 하자. TCP는 데이터를 패킷 단위로 쪼개서 보낸다. MTU 1500, IPv4·TCP 헤더가 각각 20바이트인 예에서는 TCP 페이로드가 1460바이트다. 전체 패킷 크기와 다르며 TCP 옵션·터널링 등으로 달라진다.

1MB짜리 .ts 파일 = 약 700개 패킷.

근데 이 700개가 인터넷을 여행하면서 순서가 뒤바뀔 수 있다. 라우터마다 다른 경로로 보내니까.

보낸 순서:  [1] [2] [3] [4] [5]
도착 순서:  [1] [3] [2] [5] [4]

TCP가 이걸 다시 정렬해서 애플리케이션에 넘긴다. 그리고 손실된 패킷은 다시 보내달라고 요청한다.

TCP 패킷 손실과 재전송

이는 버퍼링에 영향을 주는 여러 원인 중 하나다. seq:3이 손실되면, seq:4가 이미 도착해 있어도 애플리케이션에 안 넘긴다. 재전송이 올 때까지 기다린다.

대역폭 ≠ 지연

많이 헷갈리는 두 개념.

대역폭 (Bandwidth) 지연 (Latency)
의미 1초에 얼마나 많이 보내나 한 번 가는 데 얼마나 걸리나
단위 Mbps ms
비유 고속도로 차선 수 고속도로 거리

대역폭이 충분해도 지연과 손실은 문제다. 다만 재전송 시간은 손실 감지·혼잡 제어·RTT에 좌우되므로 “150ms 지연이면 최소 300ms”로 고정할 수 없다.

프로토콜이 이 문제에 대처하는 방식

프로토콜 전송 방식 설계 의도
RTMP TCP 스트리머 → 플랫폼 ingest. 안정성 우선
HLS HTTP; HTTP/3에서는 QUIC HTTP 배포와 CDN 캐시 활용
SRT UDP + ARQ 구성한 지연 예산 안에서 재전송

SRT의 지연 설정은 재전송과 수신 버퍼링을 위한 예산이다. 120ms는 보편적인 고정 제한이 아니며, 네트워크 조건과 송수신 설정을 함께 봐야 한다.


3. Progressive Download의 한계가 HLS를 만들었다

2000년대 초반 유튜브는 영상 파일 전체를 그냥 HTTP로 받아서 재생했다. 이걸 Progressive Download라고 한다.

언뜻 괜찮아 보이는데 치명적 문제가 3개 있다.

Progressive Download vs HLS Segments

  1. 화질 고정: 파일 요청 순간 화질이 결정됨. 와이파이 → LTE 전환 시 버퍼링.
  2. 시킹(탐색) 어려움: 1시간 30분 지점이 파일의 몇 바이트인지 알아야 함. I-frame 위치도 모름.
  3. 라이브 불가능: "파일"이 전제라 아직 녹화 중인 라이브는 안 됨.

해결책: 파일을 잘게 쪼개기

영상을 6초짜리 작은 파일들로 쪼개고, 목차 파일을 따로 둔다.

playlist.m3u8 (목차)
├── seg001.ts  (0~6초)
├── seg002.ts  (6~12초)
├── seg003.ts  (12~18초)
...
  • ABR 해결: 네트워크 느려지면 다음 세그먼트부터 720p로
  • 시킹 해결: 1시간 30분 = 540번째 세그먼트. I-frame으로 시작하니 바로 재생
  • 라이브 해결: 인코더가 만드는 족족 서버에 올리고 목차에 추가

이게 HLS (HTTP Live Streaming) 다. 이름 그대로 HTTP로 라이브를 스트리밍한다.

세그먼트 크기의 트레이드오프

세그먼트를 얼마나 잘게 자를지가 핵심 결정이다.

세그먼트 크기 트레이드오프

산업 표준이 6초인 이유. 2초는 지연이 짧지만 CDN 효율과 재버퍼링이 안 좋고, 10초는 반대. 6초가 셋 다 적당한 균형점.


4. CDN은 동영상 스트리밍의 진짜 영웅이다

치지직 서버가 서울에 있고 전세계 시청자가 본다고 가정.

서울 시청자:    지연 5ms
LA 시청자:      지연 150ms
브라질 시청자:  지연 300ms

브라질에서 6초짜리 세그먼트 요청하면 왕복만 600ms. 그리고 동시 접속자 100만 명이 서울 서버에 붙으면? 24TB를 한 번에 전송해야 한다. 서버 죽는다.

CDN의 아이디어: 가까운 곳에 미리 복사

CDN (Content Delivery Network): 콘텐츠를 시청자 가까운 곳에 미리 복사해두는 분산 네트워크.

CDN 분산 구조

LA 시청자가 세그먼트 요청하면 LA 엣지 서버에서 준다. 서울까지 안 간다.

Cache Hit가 핵심이다

  • 첫 LA 시청자: LA 엣지에 없음 (Cache Miss) → 서울에서 가져옴 → LA 엣지에 저장
  • 두 번째 LA 시청자부터: LA 엣지에 있음 (Cache Hit) → 서울 서버 부하 없음

100만 명이 같은 세그먼트를 보면, 서울 원본 서버는 딱 한 번만 요청받는다. 나머지 99만 9999명은 엣지에서 처리.

HLS가 CDN과 잘 맞는 이유

HTTP 응답에 캐시 정책이 있다.

seg001.ts     → Cache-Control: max-age=86400  (24시간)
playlist.m3u8 → Cache-Control: max-age=2      (2초)

.ts 세그먼트는 한 번 만들어지면 안 변하니 길게 캐시. .m3u8은 라이브 중에 계속 업데이트되니 짧게 캐시.

RTMP나 SRT는 이게 불가능하다. 지속 연결 방식이라 중간에 캐시 서버를 못 끼운다. 이게 HLS가 라이브 시청자 측 표준이 된 진짜 이유다.


전체 그림 — 라이브 스트리밍 파이프라인

지금까지 본 내용을 합치면 이 그림이 나온다.

라이브 스트리밍 전체 파이프라인

  • OBS: 캡처 + H.264 인코딩
  • RTMP: 스트리머가 플랫폼으로 송출
  • Origin Server: 트랜스코딩 + ABR 사다리 + HLS 패키징
  • Storage: .ts + .m3u8 저장
  • CDN Edges: 전세계 분배
  • Viewer Player: .m3u8 폴링 + .ts 다운로드 + 재생

PokeClip 같은 분석 파이프라인은 위 그림의 RTMP 인제스트 단계에서 분기해서 SRT+MPEG-TS로 따로 받는 구조다.


정리하면

스트리밍을 공부하다 보니 결국 모든 결정이 두 가지 제약에서 나왔다.

  1. 동영상은 너무 크다 → 코덱이 압축 (I/P-frame, GOP)
  2. 인터넷은 불안정하다 → TCP 재전송 / SRT의 ARQ / HLS 세그먼트 / CDN 캐시

HLS가 산업 표준이 된 건 이 두 가지를 가장 균형 있게 해결했기 때문이다. HTTP 위에서 동작해서 CDN을 그대로 활용하고, 세그먼트 단위라 시청자 측 ABR과 라이브가 자연스럽게 된다.

다음엔 RTMP/MPEG-TS/SRT 같은 ingest 프로토콜이나 LL-HLS의 저지연 기법으로 더 깊이 들어가볼 예정이다.


참고