개요
이전 포스팅에서는 HTTP Range Request를 활용해 완성된 VOD 파일을 스트리밍하는 방식을 다뤘습니다.
완성된 VOD에서 OBS(Open Broadcaster Software)에서 RTMP로 수신한 실시간 영상을 HLS(HTTP Live Streaming) 형식으로 변환 및 배포하는 전환기를 작성합니다.
[전체 아키텍처]
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ OBS 클라이언트 │──RTMP→│ 미디어 서버 │──HLS→│ 클라이언트 │
│ (송출자) │ │ (ffmpeg/nginx) │ │ (플레이어) │
│ │ │ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
주요 구성 요소
- OBS (송출자): RTMP 프로토콜로 라이브 영상 스트림 송출
- 미디어 서버: RTMP 입력을 수신하여 HLS 형식으로 변환
- HTTP 서버: 생성된 HLS 파일 및 플레이리스트 배포
- 클라이언트: HTML5 video 태그 또는 HLS.js를 이용한 재생
[ RTMP란?]
RTMP (Real Time Messaging Protocol)
- Adobe가 개발한 실시간 미디어 스트리밍 프로토콜
- 초저지연(~1초 이하)으로 실시간 라이브 영상 전송
- 기본 포트: 1935 (TCP)
- OBS, 유튜브 라이브, 트위치 등 라이브 방송 표준
- 단점: 플레이어 지원이 제한적 → HLS 변환 필요
[HLS란?]
HLS (HTTP Live Streaming)
- Apple이 개발한 HTTP 기반 스트리밍 프로토콜
- 영상을 작은 세그먼트(일반적으로 2~10초)로 분할
- 각 세그먼트 정보를 M3U8 플레이리스트에 기록
- 모든 주요 브라우저/기기에서 지원
- 네트워크 불안정 시 적응형 품질 전환 가능
[시스템 구성 요소]
FFmpeg을 이용한 RTMP → HLS 변환
FFmpeg은 강력한 멀티미디어 프레임워크로, RTMP 입력을 HLS로 변환합니다.
핵심 명령어:
ffmpeg -i rtmp://localhost:1935/live/stream \
-c:v libx264 \ # 비디오 코덱 (H.264)
-preset veryfast \ # 인코딩 속도 (빠를수록 CPU 부하 증가)
-crf 23 \ # 화질 (0-51, 낮을수록 고화질)
-c:a aac \ # 오디오 코덱
-b:a 128k \ # 오디오 비트레이트
-f hls \ # 출력 포맷 (HLS)
-hls_time 4 \ # 각 세그먼트 길이 (초)
-hls_list_size 5 \ # 플레이리스트에 유지할 세그먼트 수
-hls_flags delete_segments \ # 재생 완료된 세그먼트 삭제
/var/www/html/hls/output.m3u8
파라미터 설명:
| 파라미터 | 설명 |
|---|---|
-i |
입력 스트림 주소 |
-preset |
인코딩 속도 (ultrafast, veryfast, fast, medium, slow, slower) |
-crf |
화질 (권장: 18-28) |
-hls_time |
세그먼트 길이 (짧을수록 지연 시간 감소, 파일 수 증가) |
-hls_list_size |
메모리에 유지할 세그먼트 수 (라이브 상황에서 중요) |
NGINX을 이용한 RTMP 수신 및 HLS 배포
Nginx 설정 (nginx.conf):
http {
# HLS 콘텐츠 타입 정의
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
# HLS 파일 디렉토리
server {
listen 80;
server_name localhost;
location /hls/ {
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
alias /var/www/html/hls/;
add_header Cache-Control "max-age=3, must-revalidate";
add_header 'Access-Control-Allow-Origin' '*';
}
}
}
rtmp {
server {
listen 1935;
application live {
live on;
# FFmpeg으로 HLS 변환 (외부 프로세스)
exec ffmpeg -i rtmp://localhost/live/$name \
-c:v libx264 -preset veryfast -b:v 2500k \
-c:a aac -b:a 128k \
-f hls -hls_time 4 -hls_list_size 5 \
-hls_flags delete_segments \
/var/www/html/hls/$name.m3u8;
}
}
}
[구현 단계]
서버 세팅
1단계: 필요 소프트웨어 설치
# Ubuntu/Debian
sudo apt-get install -y ffmpeg nginx
# Nginx RTMP 모듈은 컴파일 필요 (또는 nginx-rtmp-module 사용)
# 또는 Docker 이용 권장
2단계: HLS 출력 디렉토리 생성
mkdir -p /var/www/html/hls
chmod 755 /var/www/html/hls
3단계: FFmpeg 프로세스 시작 (또는 systemd 서비스화)
ffmpeg -i rtmp://localhost:1935/live/stream \
-c:v libx264 -preset veryfast -crf 23 \
-c:a aac -b:a 128k \
-f hls -hls_time 4 -hls_list_size 5 \
-hls_flags delete_segments \
/var/www/html/hls/output.m3u8
OBS 설정
- OBS 설정 → 방송 설정
- 서비스: 맞춤
- 서버:
rtmp://your-server-ip:1935/live - 스트림키:
stream(또는 원하는 이름)
- OBS 시작 → RTMP로 송출 시작
클라이언트 재생 (HTML5)
기본 HTML5 video 태그:
<!DOCTYPE html>
<html>
<head>
<title>HLS 스트리밍 플레이어</title>
</head>
<body>
<video width="800" height="600" controls autoplay>
<source src="http://your-server-ip/hls/output.m3u8" type="application/x-mpegURL">
Your browser does not support the video tag.
</video>
</body>
</html>
HLS.js 이용 (낮은 브라우저 호환성 개선):
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<video id="video" width="800" height="600" controls></video>
<script>
var video = document.getElementById('video');
var player = new Hls();
player.loadSource('http://your-server-ip/hls/output.m3u8');
player.attachMedia(video);
player.on(Hls.Events.MANIFEST_PARSED, function() {
video.play();
});
</script>
</body>
</html>
[성능 최적화 및 고려 사항]
지연 시간(Latency) 최소화
| 파라미터 | 영향 |
|---|---|
-hls_time |
작을수록 지연 감소 (권장: 2~4초) |
-preset |
빠를수록 CPU 사용량 증가 |
-crf |
높을수록 인코딩 빠르지만 화질 저하 |
권장 설정 (저지연):
-hls_time 2 -preset ultrafast -crf 28
CPU 부하 관리
- 멀티코어 활용:
-threads [N]옵션 추가 - 하드웨어 가속: NVIDIA GPU 시
-c:v h264_nvenc사용 - 비트레이트 조정: 서버 리소스에 맞게
-b:v값 조정
메모리 관리
-hls_list_size값을 제한하여 메모리 사용 최소화-hls_flags delete_segments: 재생 완료된 세그먼트 자동 삭제
[문제 해결]
Q1: "Connection refused" 에러
→ RTMP 서버가 실행 중인지 확인: netstat -tuln | grep 1935
Q2: 비디오 끊김 현상
→ 서버 CPU 부하 확인 및 -preset 값을 더 빠르게 조정
Q3: 지연 시간이 너무 김
→ -hls_time 값을 2초 이하로 감소
[향후 개선 방향 (MVP 이후)]
- 다중화질 (Adaptive Bitrate): 1080p, 720p, 480p 등 여러 화질 동시 제공
CDN 연동: 글로벌 사용자 대응- 실시간 분석: 시청자 수, 대역폭 사용량 모니터링
마무리
이 방식은 개발자용 라이브 스트리밍 MVP 구축에 가장 효과적입니다.
RTMP 입력의 단순함과 HLS 출력의 광범위한 지원이 결합되어,
최소한의 복잡성으로 실시간 스트리밍 서비스를 구현할 수 있습니다.
질문이나 추가 구현 내용이 있으시면 댓글 남겨주세요!
참고자료: