
스트리밍 서버와 Adobe Flash Player 간에 오디오 및 비디오 파일을 전송하기 위해 Adobe에서 개발한 레거시 프로토콜

WebRTC(Web Real-Time Communication)는 웹 브라우저 간에 플러그인의 도움 없이 서로 통신할 수 있도록 설계된 API이다. 음성 통화, 영상 통화, P2P 파일 공유 등으로 활용될 수 있다.

SRT는 Haivision이 개발한 오픈 소스 비디오 전송 프로토콜로, 공용 인터넷을 포함한 다양한 네트워크에서 지연 시간이 짧은 비디오 및 미디어 스트림을 제공하기 위해 두 개의 엔드포인트를 연결하도록 설계되었다.
스트리머의 방송을 다수의 이용자가 시청을 하고 시청해야하기 때문에 WebRTC 는 적당하지 않다고 생각했다. 그래서 RTMP와 SRT를 고려해보았는데, SRT의 정점이 RTMP에 비해 좋아보이지만, 정보가 많지 않아서 RTMP로 구현하고 추후에 SRT를 고려해보는 것으로 생각했다.

user root;
worker_processes auto;
events {
worker_connections 768;
}
rtmp {
server {
# rtmp 포트 번호
listen 1935;
listen [::]:1935 ipv6only=on;
chunk_size 4096;
application live {
live on;
record off;
#HLS로 저장
hls on;
hls_path /tmp/hls;
hls_fragment 3;
hls_playlist_length 60m;
# 임시파일
dash on;
dash_path /tmp/dash;
}
}
}
https://github.com/arut/nginx-rtmp-module/wiki/Directives
FROM alpine:3.13.4 as builder
RUN apk add --update build-base git bash gcc make g++ zlib-dev linux-headers pcre-dev openssl-dev
# nginx, nginx-rtmp-module 다운
RUN git clone https://github.com/arut/nginx-rtmp-module.git && \
git clone https://github.com/nginx/nginx.git
# nginx를 설치하고 nginx-rtmp-module 추가
RUN cd nginx && ./auto/configure --add-module=../nginx-rtmp-module && make && make install
FROM alpine:3.13.4 as nginx
# ffmpeg 설치
RUN apk add --update pcre ffmpeg
# 빌드된 파일 및 설정파일 복사
COPY --from=builder /usr/local/nginx /usr/local/nginx
COPY nginx.conf /usr/local/nginx/conf/nginx.conf
# 실행
ENTRYPOINT ["/usr/local/nginx/sbin/nginx"]
CMD ["-g", "daemon off;"]
https://github.com/arut/nginx-rtmp-module


http {
server {
listen 8088;
root /tmp;
location /hls {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Content-Type' 'application/json' always;
types {
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
}
}
}
}

rtmp로 실시간으로 받은 영상을 로컬서버에 저장하는 것은 용량에 큰 문제가 생길 뿐아니라, 동영상에 대한 정보를 우리의 서버에도 기록을 해야 서비스가 원할하게 구현될 것이라고 생각했다.
하지만, 서버나 S3에 동영상을 저장하는 방법을 여러가지 시도하였으나 모두 실패했다.
정말 다양한 방법을 통해 http를 통해 우리 서버로 스트림을 전송하고 내부에서 처리하고자 하였으나 rtmp를 http로 전송하는 방법이 존재하지 않았다.(내가 못찾은 것일수도..)
hls폴더에 변화를 감지해서 변화가 생기면 파일들을 s3에 업로드를 구현하려했으나 ts파일은 한번에 작성되지않고 계속해서 업데이트 되기 때문에 실패했다.
ffmpeg -listen 1 명령을 통해 rtmp응답을 직접 받아오는 것이 가능했지만 stream key가 정확하지 않아도 받아오는 문제가 있었고, 많은 정보조사를 했지만 이를 ffmpeg내에서 해결은 불가능했다.
version: '1'
services:
spring-app:
image: van133/streaming:latest
container_name: streaming
ports:
- "8080:8080"
volumes:
- tmp:/tmp
# restart: unless-stopped
mysql:
image: mysql:latest
container_name: db-mysql
ports:
- "3306:3306"
# restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ttink1245!
TZ: Asia/Seoul
nginx-rtmp:
image: van133/nginx-rtmp
ports:
- "1935:1935"
volumes:
- tmp:/tmp
volumes:
tmp:
tmp 폴더를 공유 volume으로 지정해서 우리의 서버에서 rtmp로 들어온 파일들을 체크할 수있게 구성하였다. 그 후 10분간 유효한 stream key에 대해서 m3u8 인덱스 파일이 생기면 이벤트를 방생시키는 동작을 구현하였다.
private fun checkStreamStart(m3u8Path: Path): Flux<Boolean> {
return Flux.interval(Duration.ofSeconds(1))
.take(600)
.map {
logger.info { m3u8Path }
if (m3u8Path.exists()) {
sink.tryEmitNext(Event("finish", "finish"))
return@map true
}
else{
return@map false
}
}
.takeUntil{it == true}
}

와.. 이번 구현은
ffmpeg,rtmp,nginx,docker등등 배경지식을 매우 많이 필요로 했던 것같다. 이 포스팅에는 모든 내용을 담지 못했지만, 수 많은 시도를 했고 정말 힘들었다.
그냥 라이브 스트리밍만을 목표로 한다면, nginx-rtmp만으로도 가능하겠지만, 앞의 장면으로도 돌아갈 수있고 스트리머가 원한다면 저장할 수도 있는 서비스가 목표이기 때문에 조금 더 복잡했던 것 같다.하지만 그만큼 스트리밍과 rtmp프로토콜에 대해 깊게 공부할 수 있었다.
https://getstream.io/blog/streaming-protocols/
https://corp.kaltura.com/blog/rtmp-server-guide/
https://velog.io/@highway92/RTMP-%EC%99%80-WebRTC-%EB%B9%84%EA%B5%90
https://velog.io/@happyjarban/WebRTC-%ED%8C%8C%ED%97%A4%EC%B9%98%EA%B8%B01-WebRTC-%EC%9D%B4%EB%A1%A0
https://github.com/arut/nginx-rtmp-module/wiki/Directives
https://qteveryday.tistory.com/371
https://github.com/arut/nginx-rtmp-module/wiki/Directives
https://ffmpeg.org/ffmpeg.html