OBS 유튜브 라이브 HLS 출력 스트림 디버그 캡처

This article is available in English.

OBS의 유튜브 라이브 HLS 출력을 디스크에 저장해 분석하는 방법을 공유한다. 파이썬으로 PushCap 서버를 만들고 hosts 파일에서 유튜브 인제스트 주소를 우회하여 .m3u8 플레이리스트와 .ts 미디어 세그먼트를 순차 저장한다. 캡처한 OBS의 정상 출력과 직접 개발한 HLS 연동 모듈의 데이터를 비교해 미디어 시퀀스와 세그먼트 구성 오류를 추적한다.

유튜브 라이브 HLS 스트림을 캡처하자

본 필자가 와우자 스트리밍 엔진(Wowza Streaming Engine, 이하 와우자)의 유튜브 라이브 HLS 연동 모듈인 HLStoYTB를 개발하면서 가장 답답했던 것 중 하나는, 내가 만든 모듈이 제대로 동작하는가를 눈으로 직접 확인하기 곤란했다는 것이다.

와우자의 로그와 네트워크 트래픽을 살펴보면 모듈은 정상적으로 동작하고 있었고 실제 데이터도 출력되고 있었다. 하지만 정작 유튜브에서는 스트림을 인식하지 못해 방송이 시작되지 않는 상황이 종종 발생했다. 반대로 OBS의 경우에는 이러한 문제가 발생하지 않았다.

이에 HLStoYTB 모듈의 실제 출력 데이터를 OBS의 것과 하나씩 비교할 필요를 느낀 필자는, 파이썬(Python)을 이용해 HLS PUSH 스트림을 저장하고 확인하기 위한 디버그용 캡처 프로그램을 만들었고, 마침 기억난 아래의 노래에서 따와 PushCap이라고 이름을 붙였다.

OBS YouTube HLS 출력 캡처

OBS는 유튜브 라이브 연동 방법으로 RTMPS와 HLS를 지원하는데 인제스트 서버의 주소를 프로그램 내부에 고정된 값으로 가지고 있다. 때문에 일반적인 설정 화면에서는 HLS 스트림을 PushCap 서버로 전송하도록 설정할 수 없다. 때문에 운영체제의 DNS 해석 과정에서 유튜브 주소가 PushCap 서버를 가리키도록 우회해야 한다.

OBS 스트림 설정에서 YouTube-HLS와 기본 유튜브 인제스트 서버를 선택한 화면
서버의 주소를 직접 입력할 수 없다.

유튜브 라이브 스트림 캡처를 위한 hosts 파일 수정

유튜브 HLS 라이브는 기본 주소로 a.upload.youtube.comb.upload.youtube.com를 사용한다. OBS가 이 도메인으로 데이터를 전송하려 하면 운영체제(OS)는 먼저 도메인에 대응하는 IP 주소를 확인한 다음, 확인된 IP 주소의 서버로 OBS를 연결해 준다.

대부분의 OS는 도메인의 IP 주소를 확인할 때 로컬의 hosts 파일을 가장 먼저 확인한다. 따라서 hosts 파일에 유튜브 주소가 PushCap 서버의 IP 주소로 지정되어 있다면 OBS가 유튜브로 전송한 데이터는 실제로 PushCap 서버로 전송되게 된다. (이를 악용한 것인 hosts 파일 변조(Hosts file tampering) 공격이다.)

hosts 파일은 별도의 확장자가 없는 텍스트 파일로, 윈도우와 리눅스 모두 같은 이름을 사용한다. 이 파일이 있는 기본 경로는 다음과 같다.

윈도우
C:\Windows\System32\drivers\etc\hosts
리눅스
/etc/hosts

메모장이나 nano 같은 텍스트 편집기를 이용해 유튜브 업로드 주소가 바라볼 IP 주소를 PushCap이 실행 중인 호스트의 IP로 변경해 준다. 아래는 윈도우hosts 파일을 수정한 예이다.

# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host
127.0.0.1	a.upload.youtube.com
# 127.0.0.1	b.upload.youtube.com
# localhost name resolution is handled within DNS itself.
#	127.0.0.1       localhost
#	::1             localhost

위의 예에서는, 메인 업로드 주소인 a.upload.youtube.comPushCap이 실행 중인 PC로 설정했다. 127.0.0.1은 루프백 주소로 자기 자신을 가르킨다. 즉, OBS와 PushCap이 동일한 서버에서 동작할 것이란 의미다.

예비 주소의 경우, 줄 앞에 #이 붙어있다. 이것은 주석을 의미하며, 예비 주소에 대해서는 변경하지 않겠다는 의미이다. 리눅스 시스템의 hosts 역시 동일한 방식으로 수정해 주면 된다.

OBS HLS PUSH 출력 캡처

hosts 파일을 수정한 다음 OBS에서 YouTube HLS 스트리밍을 시작하면, 유튜브 인제스트 도메인으로 전송되는 HLS 데이터가 PushCap 서버로 전달된다.

  1. HLS PUSH 서비스 선택

    OBS 프로그램의 설정 화면에서 방송(Stream)을 선택한 다음, 타겟 서비스 목록에서 YouTube-HLS를 선택해 준다.

    OBS 방송 설정의 서비스 목록에서 YouTube-HLS 항목을 선택할 수 있는 화면
    OBS 유튜브 라이브는 HLS와 RTMPS를 지원한다.
  2. 스트림 키 설정

    스트림키 사용(Use Stream Key)을 선택해 스트림 키 입력 모드로 진입한 뒤, Stream Key 항목에 임의의 키 번호를 입력해 준다. 여기에서 입력하는 항목은 굳이 자리수를 맞출 필요는 없다. 예시화면의 내용은 본 필자가 임의로 생성한 내용이다.

    OBS YouTube-HLS 설정의 Stream Key 항목에 시험용 스트림 키를 입력하는 화면
    임의의 스트림 키를 입력
  3. 방송 시작

    방송 시작(Start Streaming)을 선택하여 스트리밍을 시작한다. 연결에 성공하면 OBS가 전송한 플레이리스트와 미디어 세그먼트가 PushCap에 차례로 업로드되고, 콘솔에는 수신한 파일의 이름과 크기가 출력된다.

    OBS가 전송한 TS 세그먼트와 M3U8 플레이리스트의 저장 내역이 연속으로 출력된 화면
    HLS 데이터를 수신하는 모습

HLS 캡처 데이터 확인

OBS의 스트리밍을 종료한 후, PushCap.py 파일이 있는 디렉토리를 확인해 보면 uploads라는 하위 디렉토리가 생성된 것을 확인할 수 있다. 해당 디렉토리 안에는 위에서 사용한 키 이름의 디렉토리가 있고, 그 안에는 OBS가 전송한 HLS 데이터를 캡처한 파일이 들어있다.

PushCap을 이용해 캡처한 OBS 유튜브 라이브 HLS 스트림
캡처한 HLS 스트림 데이터

확장자가 .ts인 파일은 동영상 데이터로, OBS가 업로드한 파일이 그대로 저장된다. 플레이리스트인 .m3u8 파일은 OBS가 업로드할 때마다 번호를 붙여 저장한다.

번호가 없는 .m3u8 파일은 OBS가 가장 마지막으로 전송한 플레이리스트이고, 가장 큰 번호가 붙은 .m3u8 파일과 내용이 같다. 번호가 붙은 파일들을 순서대로 비교하면 스트리밍이 진행되는 동안 미디어 시퀀스와 세그먼트 목록이 어떻게 변경되었는지 확인할 수 있다.

데이터 검증

캡처가 끝나면 플레이리스트와 미디어 세그먼트가 정상적으로 생성되었는지 확인한다. 먼저 .m3u8 파일에 기록된 세그먼트 이름과 실제 .ts 파일이 일치하는지 확인하고, 미디어 시퀀스 번호가 순서대로 증가하는지, 각 세그먼트의 재생 시간이 올바르게 표시되는지 살펴본다.

유튜브로 전송할 HLS 스트림을 검증할 때에는 유튜브 HLS 라이브 콘텐츠 명세서를 기준으로 플레이리스트의 태그, 세그먼트 길이, 코덱과 컨테이너 형식 등을 확인한다.

PushCap 소스와 실행 방법

실행 환경의 준비

  1. 파이썬 설치

    PushCap은 파이썬을 기반으로 작동되는 프로그램이다. 서버로 사용할 PC에 파이썬을 설치한다.

  2. 추가 패키지 설치

    프로그램 실행에 필요한 추가 패키지를 설치해 준다. flask 패키지와 tornado 패키지가 필요하며, 다음 명령을 통해 설치가 가능하다.

    py -m pip install flaskpy -m pip install tornado
  3. HTTPS 인증서 생성

    현대 HLS 프로토콜은 HTTPS를 이용해 이루어진다. 때문에 인증서 파일이 필요하다. 생성한 cert.pem 파일과 key.pem 파일을 PushCap.py와 같은 경로에 복사해 둔다.

    인증서 파일을 생성하는 방법은 와우자 스트리밍 엔진에 HTTPS 사설 인증서를 적용하는 방법을 참고하기 바란다.

    cert.pem
    HTTPS 서버가 제공하는 인증서 파일
    key.pem
    인증서와 함께 사용하는 개인 키 파일

프로그램 파일 생성과 실행

  1. 코드 파일 다운로드

    GitHub의 PushCap 프로젝트에서 PushCap.py을 다운로드 받는다.

  2. PushCap.py 저장

    적당한 디렉토리에 PushCap.py를 저장한다.

  3. PushCap 실행

    콘솔 창에서 PushCap.py가 있는 디렉토리로 이동해 PushCap.py를 실행시켜 준다. 앞에서 준비한 cert.pemkey.pem도 같은 디렉토리에 둔다.

아래와 같이 스트림을 쏘세요!라는 메시지가 출력되면 프로그램이 실행되어 HLS를 수신할 준비가 완료되었다는 뜻이다.

Microsoft Windows [Version 10.0.20348.4052]
(c) Microsoft Corporation. All rights reserved.
D:\HLSWEB>py PushCap.py
Starting PushCap HTTPS server on port 443...
스트림을 쏘세요!

PushCapBSD 3-Clause License에 따라 배포한다. 사용자는 저작권 고지와 라이선스 조건을 준수하는 범위에서 소스 및 바이너리 형태로 프로그램을 사용·수정·재배포할 수 있다. 이 프로그램은 어떠한 보증 없이 현재 상태 그대로 제공되며, 사용에 따른 모든 책임은 사용자에게 있다.

마무리

어떤 프로그램이 제대로 동작하는지 확인하는 가장 확실한 방법은 실제 출력 데이터가 의도한 형태로 생성되는지를 확인하는 것이다. 로그에 정상으로 기록되었다는 사실만으로는 플레이리스트와 미디어 세그먼트가 외부 서비스의 요구사항에 맞게 전송되었는지까지 확인하기 어렵다.

본 필자는 PushCap을 이용해 OBS의 유튜브 라이브 HLS 출력을 파일로 저장하고, 스트리밍이 진행되는 동안 그 내용이 어떻게 변경되는지 직접 확인했다. 이를 이용해 OBS의 정상 출력과 HLStoYTB 모듈의 출력을 비교하면서 유튜브가 스트림을 인식하지 못한 원인을 추적할 수 있었다.

혹 OBS나 기타 프로그램의 HLS 출력을 캡처하고자 하는 독자 제위가 계시다면 목적을 이루시는 데 본 필자의 글이 도움이 되길 바란다.

FAQ

유튜브 라이브 HLS 스트리밍 데이터에는 어떤 것들이 있는가?
유튜브 라이브 HLS 스트리밍 데이터는 실제 동영상 데이터가 들어있는 .ts 파일과 동영상 데이터 파일을 재생할 순서에 대한 정보를 가지고 있는 .m3u8 파일로 구성된다.
OBS의 YouTube HLS 출력을 캡처하면 무엇을 확인할 수 있는가?
OBS가 실제로 전송한 HTTP 요청과 .m3u8 플레이리스트, .ts 미디어 세그먼트를 확인할 수 있다. 이를 통해 파일 전송 순서, 미디어 시퀀스 증가, 세그먼트 길이, 파일 이름과 플레이리스트의 일치 여부를 분석할 수 있다. 다른 HLS 인코더나 직접 개발한 모듈의 출력을 OBS의 정상 출력과 비교할 때도 유용하다.
HLS .m3u8 파일에 들어가는 정보는?
이 m3u8 파일의 버전, 동영상 파일의 길이, 동영상 파일의 재생할 순서 번호, 각 순서별로 재생할 동영상 파일의 이름등이 들어간다. 추가적으로 SCTE-35 디지털 큐톤 데이터, 다중 비트레이트 대응을 위한 비트레이트별 동영상 파일 이름 등의 데이터도 존재 한다.
OBS의 유튜브 라이브 HLS 청크 데이터 길이는?
OBS 유튜브 라이브 HLS 청크는 2초를 기준으로 생성된다. 유튜브에서 권장하는 길이는 2026년 6월을 기준으로 1~4초로 변경 되었으며 최대 5초를 초과하지 않을 것을 명시한다.
유튜브의 HLS 입수 주소와 일반적인 HLS 서버와의 차이는?
유튜브의 HLS PUSH 주소는 cid와 파일 이름 매개변수를 포함하며, 여러 비트레이트의 Master Playlist가 아니라 하나의 인코딩된 소스 스트림과 Media Playlist를 받는다. 때문에 HLS PUSH를 지원하는 스트리밍 소프트웨어라고 할 지라도 출력 주소와 청크의 형태에 따라 적용이 불가능한 경우가 있을 수 있다.
HLS 전송에 HTTPS 인증서가 필요한 이유는 무엇인가?
HLS 프로토콜 자체가 항상 HTTPS 인증서를 요구하는 것은 아니지만, 유튜브 HLS 인제스트는 플레이리스트와 미디어 세그먼트를 HTTPS로 전송하도록 요구한다. 때문에 OBS역시 HLS 기본 전송 모드로 HTTPS를 사용한다. 다만, OBS는 호스트 검증 절차를 거치지 않는다.
YouTube가 HTTP 202 응답을 반환하면 전송에 실패한 것인가?
아니다. HTTP 202 Accepted는 유튜브가 미디어 세그먼트를 수신했지만, 해당 세그먼트가 기록된 플레이리스트는 아직 받지 못했다는 의미이다. 모듈은 해당 세그먼트를 포함하는 갱신된 플레이리스트를 가능한 한 빨리 전송해야 한다. 정상적인 처리 완료는 일반적으로 HTTP 200 OK로 확인할 수 있다.
HLS 스트림 데이터의 주요 확인 사항은?
요청 URL과 HTTP 요청 방식, 응답 코드를 확인한다. 다음으로 플레이리스트의 EXT-X-MEDIA-SEQUENCE, EXT-X-TARGETDURATION, EXTINF, 세그먼트 파일 이름과 전송 순서를 확인한다. 마지막으로 미디어 세그먼트의 길이, M2TS 구조, PAT·PMT, 코덱, 오디오·동영상 먹싱과 타임스탬프의 연속성을 확인해야 한다.
캡처가 끝난 뒤 반드시 확인해야 할 사항은 무엇인가?
hosts 파일에 추가한 유튜브 인제스트 도메인 항목을 삭제하거나 주석 처리하여 원래의 이름 해석 상태로 복구해야 한다. 복구하지 않으면 OBS가 이후에도 실제 유튜브 서버 대신 PushCap 서버로 연결되어 정상적인 유튜브 라이브 방송을 시작하지 못할 수 있다.
YouTube HLS 연동 모듈은 어떤 HTTP 요청 방식을 사용해야 하는가?
유튜브 HLS 인제스트 엔드포인트는 HTTPS를 통해 전송되는 HTTP PUT 또는 POST 요청을 받는다. 모듈은 기본 인제스트 URL의 cid 값을 유지하고, 전송할 플레이리스트나 미디어 세그먼트의 파일 이름을 file 매개변수에 지정해야 한다. 모든 요청에는 지속적인 HTTPS 연결을 사용하는 것이 요구된다.

갱신 내역

  • 최초 게시
  • 수정 및 주소 이전