영상 스트리밍 프로토콜 완벽 가이드 | RTMP·RTSP·HLS·DASH·CMAF 비교
이 글의 핵심
영상 스트리밍 프로토콜 완벽 가이드. RTMP, RTSP, HLS, DASH, CMAF, WebRTC 등 주요 프로토콜의 원리와 실전 활용법을 비교합니다.
들어가며
영상 스트리밍 프로토콜은 영상을 인터넷으로 전송하는 방법을 정의합니다. YouTube, Netflix, Twitch 등 모든 스트리밍 서비스는 이런 프로토콜을 사용합니다.
비유로 말씀드리면, 프로토콜은 택배 배송 방식입니다. RTMP는 빠른 퀵서비스, HLS는 안정적인 일반 택배, WebRTC는 즉시 배달입니다.
이 글을 읽으면
- 주요 스트리밍 프로토콜의 원리를 이해합니다
- 각 프로토콜의 장단점을 파악합니다
- 상황별 최적의 프로토콜을 선택할 수 있습니다
- 실전 구현 방법을 익힙니다
목차
스트리밍 프로토콜 기초
스트리밍이란?
스트리밍은 영상을 다운로드하면서 동시에 재생하는 기술입니다.
다운로드:
[========================================] 100%
다운로드 완료 후 재생
스트리밍:
[=====> ] 10%
다운로드 중인데 이미 재생 시작!
스트리밍의 2가지 방식
1. 라이브 스트리밍 (Live Streaming)
- 실시간 방송 (Twitch, YouTube Live)
- 낮은 지연시간 중요
- 예: 스포츠 중계, 게임 방송
2. VOD (Video on Demand)
- 녹화된 영상 (Netflix, YouTube)
- 안정성과 품질 중요
- 예: 영화, 드라마
프로토콜 선택 기준
| 기준 | 설명 |
|---|---|
| 지연시간 | 실시간성 (1초 vs 30초) |
| 확장성 | 동시 시청자 수 (100명 vs 100만명) |
| 호환성 | 브라우저/기기 지원 |
| 비용 | 서버/CDN 비용 |
| 품질 | 화질, 적응형 스트리밍 |
RTMP (Real-Time Messaging Protocol)
RTMP란?
RTMP는 Adobe가 개발한 실시간 영상 전송 프로토콜입니다. 라이브 스트리밍 인제스트(업로드)의 사실상 표준입니다.
특징:
- TCP 기반 (안정적)
- 낮은 지연시간 (1-5초)
- Flash 기반 (브라우저 지원 종료)
RTMP 워크플로우
[스트리머] → RTMP → [서버] → HLS/DASH → [시청자]
(OBS) (Nginx) (브라우저)
1. 스트리머: OBS로 RTMP 송출
2. 서버: RTMP 수신 → HLS/DASH 변환
3. 시청자: HLS/DASH로 시청
RTMP 구현 (Nginx)
nginx.conf:
rtmp {
server {
listen 1935; # RTMP 포트
application live {
live on; # 라이브 스트리밍 활성화
# HLS 변환
hls on;
hls_path /tmp/hls;
hls_fragment 3s; # 세그먼트 길이
hls_playlist_length 60s;
# DASH 변환
dash on;
dash_path /tmp/dash;
dash_fragment 3s;
}
}
}
http {
server {
listen 8080;
# HLS 제공
location /hls {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
root /tmp;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
# DASH 제공
location /dash {
types {
application/dash+xml mpd;
}
root /tmp;
add_header Cache-Control no-cache;
add_header Access-Control-Allow-Origin *;
}
}
}
OBS 설정:
서버: rtmp://your-server.com/live
스트림 키: stream-key-123
RTMP 장단점
장점:
- ✅ 낮은 지연시간 (1-5초)
- ✅ 안정적인 전송 (TCP)
- ✅ 업계 표준 (모든 인코더 지원)
단점:
- ❌ 브라우저 직접 재생 불가 (Flash 종료)
- ❌ 방화벽 문제 (1935 포트)
- ❌ 확장성 제한
RTSP (Real Time Streaming Protocol)
RTSP란?
RTSP는 IP 카메라와 CCTV에서 주로 사용하는 프로토콜입니다.
특징:
- UDP/TCP 지원
- 양방향 제어 (재생, 일시정지, 탐색)
- RTP/RTCP로 실제 데이터 전송
RTSP 구조
RTSP (제어 채널)
↓
RTP (미디어 전송)
↓
RTCP (품질 피드백)
RTSP URL 형식
rtsp://username:[email protected]:554/stream1
rtsp:// - 프로토콜
username - 인증 사용자명
password - 인증 비밀번호
192.168.1.100 - IP 주소
554 - 포트 (기본값)
/stream1 - 스트림 경로
RTSP 재생 (FFmpeg)
# RTSP 스트림 재생
ffplay rtsp://192.168.1.100:554/stream1
# RTSP → RTMP 변환
ffmpeg -i rtsp://192.168.1.100:554/stream1 \
-c copy \
-f flv rtmp://your-server.com/live/stream
# RTSP → HLS 변환
ffmpeg -i rtsp://192.168.1.100:554/stream1 \
-c:v libx264 -c:a aac \
-f hls -hls_time 3 -hls_list_size 10 \
output.m3u8
RTSP 장단점
장점:
- ✅ 낮은 지연시간
- ✅ 양방향 제어
- ✅ IP 카메라 표준
단점:
- ❌ 브라우저 지원 없음
- ❌ 방화벽 문제 (UDP)
- ❌ 확장성 제한
HLS (HTTP Live Streaming)
HLS란?
HLS는 Apple이 개발한 HTTP 기반 스트리밍 프로토콜입니다. 가장 널리 사용되는 프로토콜입니다.
특징:
- HTTP 기반 (CDN 활용 가능)
- 적응형 비트레이트 (ABR)
- 모든 Apple 기기 지원
HLS 구조
영상 → 세그먼트로 분할 → Playlist 생성
video.mp4
↓
segment0.ts (6초)
segment1.ts (6초)
segment2.ts (6초)
↓
playlist.m3u8 (세그먼트 목록)
HLS Playlist (M3U8)
Master Playlist (다중 화질):
#EXTM3U
#EXT-X-VERSION:3
# 1080p
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p.m3u8
# 720p
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720
720p.m3u8
# 480p
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=854x480
480p.m3u8
Media Playlist (세그먼트 목록):
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:6.0,
segment0.ts
#EXTINF:6.0,
segment1.ts
#EXTINF:6.0,
segment2.ts
#EXT-X-ENDLIST
HLS 생성 (FFmpeg)
# 단일 화질 HLS
ffmpeg -i input.mp4 \
-c:v libx264 -c:a aac \
-f hls \
-hls_time 6 \
-hls_list_size 0 \
-hls_segment_filename 'segment%03d.ts' \
playlist.m3u8
# 다중 화질 HLS (ABR)
ffmpeg -i input.mp4 \
-filter_complex \
"[0:v]split=3[v1][v2][v3]; \
[v1]scale=w=1920:h=1080[v1out]; \
[v2]scale=w=1280:h=720[v2out]; \
[v3]scale=w=854:h=480[v3out]" \
-map "[v1out]" -c:v:0 libx264 -b:v:0 5M \
-map "[v2out]" -c:v:1 libx264 -b:v:1 2.5M \
-map "[v3out]" -c:v:2 libx264 -b:v:2 1M \
-map a:0 -c:a aac -b:a 128k \
-f hls -hls_time 6 \
-hls_playlist_type vod \
-master_pl_name master.m3u8 \
-var_stream_map "v:0,a:0 v:1,a:0 v:2,a:0" \
stream_%v/playlist.m3u8
HLS 재생 (JavaScript)
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<video id="video" controls width="640"></video>
<script>
const video = document.getElementById('video');
const videoSrc = 'https://example.com/master.m3u8';
if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Safari (네이티브 HLS 지원)
video.src = videoSrc;
} else if (Hls.isSupported()) {
// 다른 브라우저 (hls.js 사용)
const hls = new Hls();
hls.loadSource(videoSrc);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play();
});
}
</script>
</body>
</html>
HLS 장단점
장점:
- ✅ HTTP 기반 (CDN 활용)
- ✅ 방화벽 문제 없음
- ✅ 적응형 비트레이트 (ABR)
- ✅ Apple 기기 네이티브 지원
- ✅ 무한 확장성
단점:
- ❌ 높은 지연시간 (6-30초)
- ❌ 세그먼트 파일 많음
DASH (Dynamic Adaptive Streaming over HTTP)
DASH란?
DASH는 MPEG 표준 스트리밍 프로토콜입니다. HLS의 오픈 표준 대안입니다.
특징:
- HTTP 기반
- 코덱 독립적 (H.264, H.265, VP9, AV1)
- DRM 지원 우수
DASH 구조
영상 → 세그먼트 분할 → MPD 생성
video.mp4
↓
init.mp4 (초기화 세그먼트)
segment1.m4s
segment2.m4s
segment3.m4s
↓
manifest.mpd (세그먼트 목록)
DASH Manifest (MPD)
<?xml version="1.0"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011">
<Period>
<!-- 비디오 -->
<AdaptationSet mimeType="video/mp4" codecs="avc1.4d401f">
<!-- 1080p -->
<Representation id="1" bandwidth="5000000" width="1920" height="1080">
<SegmentTemplate timescale="1000"
initialization="init-$RepresentationID$.mp4"
media="segment-$RepresentationID$-$Number$.m4s"
startNumber="1">
<SegmentTimeline>
<S t="0" d="6000" r="9"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
<!-- 720p -->
<Representation id="2" bandwidth="2500000" width="1280" height="720">
<!-- ... -->
</Representation>
</AdaptationSet>
<!-- 오디오 -->
<AdaptationSet mimeType="audio/mp4" codecs="mp4a.40.2">
<Representation id="audio" bandwidth="128000">
<!-- ... -->
</Representation>
</AdaptationSet>
</Period>
</MPD>
DASH 생성 (FFmpeg + MP4Box)
# 1. 다중 화질 인코딩
ffmpeg -i input.mp4 \
-c:v libx264 -b:v 5M -s 1920x1080 -profile:v high -level 4.1 1080p.mp4 \
-c:v libx264 -b:v 2.5M -s 1280x720 -profile:v high -level 4.0 720p.mp4 \
-c:v libx264 -b:v 1M -s 854x480 -profile:v main -level 3.1 480p.mp4
# 2. DASH 패키징 (MP4Box)
MP4Box -dash 6000 -frag 6000 -rap \
-segment-name 'segment_$RepresentationID$_' \
-out manifest.mpd \
1080p.mp4 720p.mp4 480p.mp4
DASH 재생 (dash.js)
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
</head>
<body>
<video id="video" controls width="640"></video>
<script>
const url = 'https://example.com/manifest.mpd';
const player = dashjs.MediaPlayer().create();
player.initialize(document.getElementById('video'), url, true);
</script>
</body>
</html>
DASH 장단점
장점:
- ✅ 오픈 표준 (로열티 없음)
- ✅ 코덱 독립적
- ✅ DRM 지원 우수
- ✅ HTTP 기반
단점:
- ❌ Apple 기기 지원 약함
- ❌ 복잡한 구현
CMAF (Common Media Application Format)
CMAF란?
CMAF는 HLS와 DASH를 통합하는 차세대 포맷입니다. 하나의 파일로 두 프로토콜 지원이 가능합니다.
특징:
- fMP4 기반
- HLS + DASH 동시 지원
- 낮은 지연시간 (LL-HLS, LL-DASH)
CMAF 구조
기존:
HLS용 파일 (TS) + DASH용 파일 (MP4)
→ 2배 저장 공간, 2배 인코딩 시간
CMAF:
공통 파일 (fMP4)
→ HLS와 DASH 모두 사용
→ 1배 저장 공간, 1배 인코딩 시간
CMAF 생성 (FFmpeg)
# CMAF 인코딩
ffmpeg -i input.mp4 \
-c:v libx264 -b:v 5M -s 1920x1080 -profile:v high \
-c:a aac -b:a 128k \
-f hls \
-hls_segment_type fmp4 \
-hls_fmp4_init_filename init.mp4 \
-hls_segment_filename 'segment%03d.m4s' \
-hls_playlist_type vod \
playlist.m3u8
LL-HLS (Low-Latency HLS)
특징:
- 지연시간: 2-3초 (기존 HLS의 1/10)
- 부분 세그먼트 (Partial Segment)
- HTTP/2 Server Push
#EXTM3U
#EXT-X-VERSION:9
#EXT-X-TARGETDURATION:6
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.0
#EXT-X-PART-INF:PART-TARGET=0.5
#EXT-X-PART:DURATION=0.5,URI="part0.m4s"
#EXT-X-PART:DURATION=0.5,URI="part1.m4s"
#EXTINF:6.0,
segment0.m4s
CMAF 장단점
장점:
- ✅ HLS + DASH 동시 지원
- ✅ 저장 공간 절약 (50%)
- ✅ 낮은 지연시간 (LL-HLS)
- ✅ 미래 지향적
단점:
- ❌ 최신 기술 (지원 제한적)
- ❌ 복잡한 구현
WebRTC (Web Real-Time Communication)
WebRTC란?
WebRTC는 P2P 실시간 통신 프로토콜입니다. 초저지연이 특징입니다.
특징:
- UDP 기반
- 지연시간: 0.5-1초
- 브라우저 네이티브 지원
WebRTC 구조
[발신자] ←→ Signaling Server ←→ [수신자]
↓ ↓
└──────── P2P 연결 ────────────┘
(STUN/TURN)
WebRTC 구현 (JavaScript)
발신자:
// 1. MediaStream 획득
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
// 2. RTCPeerConnection 생성
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
// 3. 스트림 추가
stream.getTracks().forEach(track => {
pc.addTrack(track, stream);
});
// 4. Offer 생성
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// 5. Offer 전송 (Signaling Server)
sendToSignalingServer({ type: 'offer', sdp: offer.sdp });
수신자:
// 1. RTCPeerConnection 생성
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
// 2. Offer 수신
pc.setRemoteDescription(new RTCSessionDescription(offer));
// 3. Answer 생성
const answer = await pc.createAnswer();
await pc.setLocalDescription(answer);
// 4. Answer 전송
sendToSignalingServer({ type: 'answer', sdp: answer.sdp });
// 5. 스트림 수신
pc.ontrack = (event) => {
videoElement.srcObject = event.streams[0];
};
WebRTC 장단점
장점:
- ✅ 초저지연 (0.5-1초)
- ✅ P2P (서버 부하 적음)
- ✅ 브라우저 네이티브 지원
단점:
- ❌ 확장성 제한 (P2P)
- ❌ 방화벽/NAT 문제
- ❌ 녹화 어려움
프로토콜 비교
전체 비교표
| 프로토콜 | 지연시간 | 확장성 | 브라우저 지원 | 주요 용도 |
|---|---|---|---|---|
| RTMP | 1-5초 | 중간 | ❌ | 라이브 인제스트 |
| RTSP | 1-3초 | 낮음 | ❌ | IP 카메라 |
| HLS | 6-30초 | 높음 | ✅ | VOD, 라이브 |
| DASH | 6-30초 | 높음 | ✅ | VOD, 라이브 |
| CMAF | 2-6초 | 높음 | ✅ | 차세대 스트리밍 |
| WebRTC | 0.5-1초 | 낮음 | ✅ | 화상 통화 |
상황별 추천
1. 라이브 스트리밍 (대규모)
RTMP (인제스트) → HLS/DASH (배포)
지연시간: 10-30초
확장성: 무제한
2. 라이브 스트리밍 (저지연)
RTMP → LL-HLS 또는 WebRTC
지연시간: 1-3초
확장성: 중간
3. VOD (주문형 비디오)
HLS (Apple) + DASH (Android)
또는 CMAF (통합)
4. 화상 통화
WebRTC
지연시간: 1초 미만
5. IP 카메라
RTSP → RTMP/HLS 변환
실전 구현
완전한 라이브 스트리밍 시스템
아키텍처:
[스트리머] → RTMP → [Nginx-RTMP] → HLS/DASH → [CDN] → [시청자]
(OBS) (서버) (CloudFlare) (브라우저)
Docker Compose:
version: '3'
services:
nginx-rtmp:
image: tiangolo/nginx-rtmp
ports:
- "1935:1935" # RTMP
- "8080:80" # HLS/DASH
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./hls:/tmp/hls
- ./dash:/tmp/dash
nginx.conf (완전판):
rtmp {
server {
listen 1935;
chunk_size 4096;
application live {
live on;
record off;
# 인증 (선택)
on_publish http://localhost:8000/auth;
# HLS
hls on;
hls_path /tmp/hls;
hls_fragment 3s;
hls_playlist_length 60s;
hls_continuous on;
hls_cleanup on;
hls_nested on;
# DASH
dash on;
dash_path /tmp/dash;
dash_fragment 3s;
dash_playlist_length 60s;
dash_cleanup on;
dash_nested on;
# 트랜스코딩 (다중 화질)
exec ffmpeg -i rtmp://localhost/live/$name
-c:v libx264 -b:v 5M -s 1920x1080 -f flv rtmp://localhost/hls/$name_1080p
-c:v libx264 -b:v 2.5M -s 1280x720 -f flv rtmp://localhost/hls/$name_720p
-c:v libx264 -b:v 1M -s 854x480 -f flv rtmp://localhost/hls/$name_480p;
}
}
}
트러블슈팅
1. HLS 지연시간 줄이기
문제: HLS 지연시간이 30초 이상
해결:
# 세그먼트 길이 단축
hls_fragment 2s; # 6s → 2s
# Playlist 길이 단축
hls_playlist_length 10s; # 60s → 10s
# 결과: 지연시간 30초 → 6-10초
2. CORS 에러
문제: 브라우저에서 HLS 재생 안됨
해결:
location /hls {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Range";
}
3. 버퍼링 문제
문제: 영상이 자주 멈춤
해결:
// hls.js 버퍼 설정
const hls = new Hls({
maxBufferLength: 30, // 최대 버퍼 (초)
maxMaxBufferLength: 600, // 최대 최대 버퍼
maxBufferSize: 60 * 1000 * 1000, // 60MB
maxBufferHole: 0.5 // 버퍼 홀 허용
});
마무리
영상 스트리밍 프로토콜은 상황에 맞게 선택해야 합니다.
핵심 요약:
| 프로토콜 | 한 줄 요약 |
|---|---|
| RTMP | 라이브 업로드 표준 |
| RTSP | IP 카메라 표준 |
| HLS | 가장 범용적 |
| DASH | 오픈 표준 대안 |
| CMAF | 차세대 통합 포맷 |
| WebRTC | 초저지연 P2P |
실전 추천:
라이브 스트리밍:
RTMP (인제스트) → HLS (배포)
VOD:
HLS (Apple) + DASH (Android)
또는 CMAF (통합)
저지연 라이브:
WebRTC 또는 LL-HLS
IP 카메라:
RTSP → HLS 변환
다음 단계:
- H.264 코덱 가이드
- WebM 컨테이너 포맷
- Opus 오디오 코덱
영상 스트리밍의 세계에 오신 것을 환영합니다! 🎥