기존 시스템을 하나도 건드리지 않고 인스타그램·유튜브에 동시 송출하기 (FFmpeg Simulcast) - 김팔복

김팔복 2026. 8. 2. 오후 10:32:18
조회 7 추천 0 댓글 0

기존 시스템을 하나도 건드리지 않고 인스타그램·유튜브에 동시 송출하기 (FFmpeg Simulcast)

운영 중인 라이브 커머스 방송을 인스타그램·유튜브에 동시 송출해야 하는 요구사항이 생겼습니다.
기존 스트리밍 파이프라인을 단 한 줄도 수정하지 않고 FFmpeg만으로 Simulcast 서버를 구축한 경험을 공유합니다.

발표 영상: YouTube에서 보기


Simulcast 란?

Simulcast = Simultaneous(동시의) + Broadcast(방송)

하나의 방송 영상을 여러 채널·여러 플랫폼에 동시에 송출하는 것을 뜻합니다.


배경: 이미 운영 중인 라이브 커머스

기존에 안정적으로 운영 중이던 라이브 커머스가 있었습니다. 영상 스펙은 다음과 같습니다.

항목 스펙
해상도 720 x 1280 (모바일 세로형)
화면비 9:16
코덱 H.264
프레임레이트 30fps
전송 방식 HLS

이 상태에서 "인스타그램, 유튜브에도 동시 송출이 필요하다" 는 기획 요청을 받았습니다.


어떤 방법을 선택할 것인가

선택지는 여러 가지가 있었습니다.

  • 스트림 서버(SRS, nginx-rtmp 등)를 구축해 인입 단계에서 분기
  • 외부 Simulcast SaaS 사용
  • FFmpeg으로 자체 Simulcast 서버 구축 ← 선택

기존 아키텍처는 스트리머 → AWS IVS → 시청자 앱으로 이어지는 구조였습니다. 그림으로는 간단해 보이지만 실제로는 복잡했고, 안정화까지 제법 시간이 걸린 시스템이었습니다.

잘 돌아가는 시스템은 최대한 건드리고 싶지 않았습니다.

그래서 인입 단계에서 분기하는 대신, 시청자가 보는 재생 URL을 그대로 읽어서 흘려보내는 구조를 택했습니다.


아키텍처

flowchart LR
    A[스트리머] --> B[AWS IVS<br/>스트리밍 서버]
    B --> C[시청자 앱<br/>1000명]
    B -.시청자 +1.-> D[Simulcast 서버<br/>FFmpeg]
    D --> E[Instagram RTMP]
    D --> F[YouTube RTMP]

    style D fill:#e8f4ff,stroke:#3b82f6

핵심은 이 한 문장입니다.

Simulcast 서버는 기존 시스템 입장에서 "시청자 한 명"이 늘어난 것에 불과하다.

  • 기존 라이브 커머스 코드 수정: 0
  • 기존 스트리밍 서버 설정 변경: 0
  • 기존 시스템에 가해지는 부하: 시청자 1000명 → 1001명 수준

Simulcast 서버는 시청자용 HLS URL을 입력으로 받아, FFmpeg으로 인스타그램·유튜브의 RTMP 엔드포인트에 그대로 흘려보냅니다.


이게 가능한 이유: RTMP 인제스트는 사실상 업계 표준

라이브 방송을 지원하는 SNS 대부분이 외부 인코더용 RTMP 인제스트를 제공합니다. OBS 같은 인코더를 붙이라고 열어둔 그 입구를, 우리 서버가 대신 사용하는 것뿐입니다.

인스타그램 라이브, 유튜브 라이브 모두 스트림 URL + 스트림 키 형태로 인제스트 주소를 발급해 줍니다.

SNS 라이브가 요구하는 스펙

항목 일반적인 요구사항 우리 영상
프로토콜 RTMP / RTMPS
비디오 코덱 H.264 H.264 ✅
프레임레이트 30 / 60fps 30fps ✅
해상도 720p 이상 대부분 지원 720x1280 ✅

즉, 우리가 송출하는 영상 스펙이 SNS 허용 범위 안에 전부 들어옵니다.
→ 별도의 재인코딩 없이 바로 사용할 수 있다는 뜻입니다.


재인코딩 vs 패스스루(re-mux)

재인코딩이 필요한 경우

  • 원본은 가로형인데 SNS에는 세로형으로 변환해서 내보내야 할 때
  • 코덱·해상도·프레임레이트가 플랫폼 허용 범위를 벗어날 때
  • 비트레이트를 강제로 낮춰야 할 때

재인코딩은 영상을 받아서 디코딩 → 재가공 → 다시 인코딩하는 과정입니다. 당연히 CPU 사용률이 크게 올라가고, 인코딩 단계만큼 지연도 추가됩니다.

재인코딩 코드

ffmpeg \
  -headers $'Origin: https://simulcast.example.com\r\n' \
  -i "https://<재생용 HLS URL>.m3u8" \
  -s 720x1280 -r 30 -g 60 \
  -c:v libx264 -profile:v main -preset veryfast \
  -b:v 3000k -maxrate 3500k -bufsize 6000k \
  -c:a copy \
  -flvflags no_duration_filesize \
  -f flv "rtmps://<SNS RTMP 주소>/<스트림 키>"
  1. 기존 앱에서 시청자가 보는 재생 URL을 그대로 가져오고
  2. 원하는 영상 스펙으로 변환한 뒤
  3. SNS RTMP로 전송

재인코딩 없는(패스스루) 코드

ffmpeg \
  -headers $'Origin: https://simulcast.example.com\r\n' \
  -i "https://<재생용 HLS URL>.m3u8" \
  -c:v copy -c:a copy \
  -flvflags no_duration_filesize \
  -f flv "rtmps://<SNS RTMP 주소>/<스트림 키>"
  1. 시청자가 보는 재생 URL을 그대로 가져오고
  2. 변환 없이 컨테이너만 HLS(TS) → FLV로 바꿔서
  3. SNS RTMP로 전송

차이는 사실상 -c:v copy -c:a copy 한 줄입니다. 디코딩/인코딩을 하지 않고 컨테이너만 바꾸는 re-mux이기 때문에 CPU 사용률이 비교가 안 될 정도로 낮습니다. (btop으로 두 프로세스를 비교해 보면 체감이 확실합니다.)

저희는 스펙이 이미 맞았기 때문에 인코딩이 필요 없었고, 그 덕분에 자체 Simulcast 서버를 운영해도 서버 부담과 비용을 걱정할 필요가 거의 없었습니다. 이 점이 이 아키텍처를 선택한 결정적인 이유였습니다.


지연 시간(Latency)

한 단계를 더 거치는 구조이므로 지연은 늘어납니다. 실제 측정값은 다음과 같았습니다.

경로 지연
기존 라이브 (앱) 약 2초
Simulcast → 인스타그램 약 20초
Simulcast → 유튜브 약 9초

실시간 인터랙션이 중요한 서비스라면 이 수치를 먼저 검토해야 합니다. 반대로 "노출 채널 확대"가 목적이라면 충분히 감수할 만한 수준입니다.


실제 운영에서 추가로 필요한 것들

위 코드는 설명을 위해 최소화한 형태입니다. 실서비스로 운영하려면 다음 작업이 필요합니다.

  • 방송 라이프사이클 연동 — HTTP 통신으로 방송 시작/종료 시점을 서버와 동기화
  • 외부 컨트롤 API — 어드민에서 송출 시작/중지, 대상 플랫폼 선택
  • 프로세스 감시 — FFmpeg 프로세스 헬스체크
  • 재시작 로직 — 네트워크 순단, 원본 끊김 시 자동 복구

이런 방식으로 몇 개월 운영해 봤지만 특별한 문제 없이 잘 사용하고 있습니다.


정리: 이럴 때 추천합니다

추천

  • 기존 시스템을 수정하지 않고 여러 SNS 플랫폼에 동시 송출하고 싶을 때
  • 기존 영상 스펙이 SNS 요구 범위 안에 있어 재인코딩이 필요 없는 경우

주의사항

  • 재인코딩이 필요하면 Simulcast 서버의 CPU 사용량이 크게 늘어나므로 서버 스펙 상향이 필요할 수 있다
  • 원본 라이브가 먼저 시작되어야 Simulcast가 가능하다 (원본을 복사하는 구조이기 때문)
  • 한 단계를 더 거치므로 지연 시간이 발생한다
  • 프로세스 감시, 방송 라이프사이클 연동, 재시작 로직 등 운영을 위한 서버 개발이 필요하다

기존 시스템을 지키면서 요구사항을 만족시키는 것, 그리고 그 과정에서 운영 비용까지 최소화하는 것. 이 두 가지를 동시에 잡을 수 있었던 선택이었습니다.

댓글 0

아직 댓글이 없습니다.