RTMP(Real Time Messaging Protocol) + HLS 으로 실시간 방송 구현하기(기초 구성) - 1

구현 전 사전 간단한 개념.


1. RTMP(Real-Time Messaging Protocol) 

    1-1. 역할

        - 실시간 오디오/비디오 데이터를 Client -> Server 로 전달 하기 위한 전송 프로토콜

    1-2. 네트워크 특성

        - 기본 포트 : 1935

        - TCP 기반 연결 (지속 연결과 신뢰성 우선)

    1-3. 전송 방식

        - Push 방식

        - Client(OBS-RTMP)가 Server로 밀어 넣음

    1-4. 한계

        - 일부 브라우저 에선 직접 재생 불가 Safari에선 가능하지만 다른 브라우저는 hls.js로 화면을 송출 해야함.


2. NGINX-RTMP-MODULE

    2-1. 역할

        - RTMP Stream을 받아들이는 ingest Server

    2-2. 기능

        - RTMP 연결 수신 (listen 1935)

        - Stream Session 관리(Application, Stream Key)

        - Stream Life Cycle 관리 (on_publish, on_done, on_pley)

        - RTMP -> HLS 패키징(ts 기반)를 nginx-rtmp-module이 자체적으로 수행 가능(DASH 패키징은 불가능)

    2-3. FFmpeg 연동

        - exec 지시자를 통해 외부 FFmpeg 프로세스 실행

        - RTMP ingest 이후 트랜스코딩/재패키징을 외부로 위임 가능

        - NGINX-RTMP-MODULE 내에서 연동은 가능하지만 FFmpeg는 따로 컨테이너를 띄우는 방식으로 함.

    2-3. 한계

        - 인코딩 없음

        - 트랜스코딩 없음

        - DASH / CMAF 패키징 없음

        - HLS(ts) 패키징만 자체 지원


3.FFmpeg(오디오 / 비디오 처리용 멀티미디어 프레임워크)

    3-1. 역할

        - RTMP Stream 디코딩(필요 시)

        - 재인코딩(Transcoding)

        - 포맷 변환 및 패키징(Packaging)

    3-2. 대표 처리

        - 해상도 및 비트레이트 분기(ABR를 위해 다중 화질 스트림을 생성)

    3-3. 결과물

        - .ts, .m4s, .m3u8, .mpd 등

        - HTTP 기반 스트리밍 가능 형태


4.OBS Studio(RTMP client)

    4-1. 역할

        - 사용자 화면/카메라/오디오 캡처

        - Stream Key 지정

        - 실시간 인코딩 수행

    4-2. 인코딩

        - Video: H.264

        - Audio: AAC

    4-3. 출력

        - RTMP Push to Server


5. HLS(Http Live Streaming)

    5-1. 역할

        - 실시간/준실시간 오디오/비디오를 HTTP 기반으로 전달하기 위한 적응형 스트리밍 프로토콜

        - 브라우저/모바일 단말에서 재생 가능한 최종 배포 포맷

    5-2. 네트워크 특성

        - 전송 방식: HTTP/HTTPS

        - 포트: 80 / 443

        - CDN 친화적 (Segment는 캐시 가능, Playlist는 캐시 제어 필요)

        - TCP 기반(HTTP 위에서 동작)

    5-3. 전송 방식

        - Pull 방식

        - Client(Player)가 서버로부터 Segment 파일을 요청

        - 다중 화질 스트림 중 시청자의 네트워크 상태에 따라 적절한 화질을 자동으로 선택 및 전환할 수 있는 ABR 구조를 제공

    5-4. 구성 요소(HLS의 핵심 구조: .m3u8과 .ts의 관계)

        - Media Playlist

            - .m3u8

            - Master Playlist (Variant 선택)

            - Media Playlist (Segment 목록)

        - Media Segment

            - .ts(전통적)

            - .m4s(CMAF 기반)

        📌이 부분은 HLS 동작 원리이므로 추후에 설명.

    5-5. 특징

        - Safari / iOS 네이티브 지원

        - <video src="*.m3u8"> 로 바로 재생 가능

        - 라이브 / VOD 모두 지원

        - LL-HLS(Low Latency HLS) 지원가능

    5-6. 한계

        - DASH 대비 표준 유연성 낮음(Apple 주도)

        - 브라우저 DRM 확장성 제한적 (FairPlay 중심)

        - 전통 HLS(ts) 기준으로 초저지연에는 제약



6. 아키텍쳐 구조

        


7. 구현 코드

    7-1. docker-compose.yml

services:
  nginx-rtmp:
    image: alfg/nginx-rtmp:latest
    container_name: hls-nginx
    environment:
      RTMP_PORT: "1935"
      HTTP_PORT: "80"
    ports:
      - "1935:1935"
      - "8080:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf.template
      - ./www:/var/www/html
      - ./hls:/var/www/hls
    restart: unless-stopped


    7-2. nginx.conf
daemon off;
events { worker_connections 1024; }

rtmp {
    server {
        listen ${RTMP_PORT};
        chunk_size 4096;
       
        # OBS publish
        # EndPoint : rtmp://HOST:${RTMP_PORT}/live
        # RTMP URL EndPoint의 /live는 application 이름이며, application live {} 설정에 의해 결정된다.
        application live {
            live on;

            # RTMP -> HLS
            # RTMP ingest → (nginx 내부) HLS 패키징
            hls on;
            hls_path /var/www/hls;
            hls_fragment 5;
            hls_playlist_length 10;
        }
    }
}

http {
    # 응답 헤더/에러 페이지 등에 nginx 버전 노출을 줄임(보안/깔끔함)
    server_tokens off;
   
    # HTTP access log를 파일 대신 표준출력으로 보냄
    # Docker에서 로그 수집하기 좋음.
    access_log /dev/stdout combined;

    server {
        listen ${HTTP_PORT};
       
        # 정적 파일 제공 루트 디렉토리
        # index.html을 찾는 기준.
        root /var/www/html;

        location = / {
          try_files /index.html =404;
        }

        # HLS 제공 http://HOST:${HTTP_PORT}/live/hello.m3u8
        # hello는 OBS Studio에서 정한 Stream Key
        location /live/ {
            alias /var/www/hls/;
            types {
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }
           
            # HLS는 “계속 바뀌는 라이브 파일”이므로 캐시로 오래 잡히면 문제가 됨.
            add_header Cache-Control no-cache;
            # CORS 허용.
            add_header Access-Control-Allow-Origin *;
        }
    }
}


    7-3. index.html

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>HLS Player</title>
  <style>
    body{font-family:system-ui,Segoe UI,Arial;margin:24px}
    video{width:min(960px,100%);background:#000;border-radius:12px}
    code{background:#f2f2f2;padding:2px 6px;border-radius:6px}
  </style>
</head>
<body>
  <h2>HLS Player</h2>
  <p>Stream: <code id="u"></code></p>
  <video id="v" controls autoplay muted playsinline></video>

  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
  <script>
    const url = "http://localhost:8080/live/hello.m3u8";
    document.getElementById("u").textContent = url;

    const video = document.getElementById("v");
    if (Hls.isSupported()) {
      const hls = new Hls({
        lowLatencyMode: false
      });
      hls.loadSource(url);
      hls.attachMedia(video);
    } else if (video.canPlayType("application/vnd.apple.mpegurl")) {
      video.src = url; // Safari 등
    } else {
      document.body.insertAdjacentHTML("beforeend", "<p>HLS not supported</p>");
    }
  </script>
</body>
</html>

    7-4. 디렉토리 구조

    hls-live
        ├── docker-compose.yml
        ├── nginx.conf
        └── www
                └── index.html


   7-5. 실행 방법

        1. 디렉토리 구조 설정
        2. docker Desktop 실행
        3. wsl 실행
        4. hls-live (cd 로 들어감)
        5. docker compose up -d
        6. OBS Studio 실행
        7. Stream Key: hello, Server: rtmp://localhost:1935/live 방송 시작
        7. localhost:8080 으로 접속


8. 실행 결과


9. 레퍼런스

https://datatracker.ietf.org/doc/html/rfc8216

https://github.com/arut/nginx-rtmp-module

https://www.cloudflare.com/ko-kr/learning/video/what-is-http-live-streaming/

댓글

이 블로그의 인기 게시물

[보안] CA인증서, 서버인증서, 클라이언트 인증서와 Openssl

TCP/UDP 통신 방식 (WireShark)

HTTP/HTTPS 프로토콜의 개념과 작동 원리 (WireShark)