Published
- 7 min read
브라우저에서 HEVC 영상 스트리밍하기 #2
Overview
RTSP패킷을 파싱해서 비디오와 오디오, 그리고 메타데이터를 추출해내야 한다. 그리고 그걸 브라우저에게 신경써서 전송해야 한다.
RTSP
일단 이글을 보고 있다면 이 문서를 읽어봤다는 뜻이다. 따라서 RTSP에 대한 설명은 생략, 당신은 이미 RTSP에 능통하다고 가정하겠다. 또, 당신은 Naver Cloud 기술블로그와 Twitch 기술블로그 그리고 StackOverflow나 Reddit에서 웹 비디오 스트리밍에 필요한 서버 구성도와 영상정보가 어디에서 시작해서 어디로 흐르는지 대해 퇴근 이후 매일 몇시간씩 조사하고 또 직접 만들어 봤을 것이다, 관련 내용은 생략.
우리는 WebRTC를 사용하지 않으므로(우리가 재생할 영상의 코덱이 브라우저가 지원하지 않는 코덱이므로 RTP 패킷을 직접 제어해야 하는데 브라우저 정책상 RTP 직접제어 못하고 High level API만 제공해줌) RTSP 패킷으로부터 영상을 직접 추출해야 한다.
영상 추출이야 RTSP에 통달한 당신에게 문제가 되지 않을 것이다. 근데 그걸 브라우저에게 전송할때 생각할 점들이 있다.
여담: AVCC와 AnnexB는 컨테이너 포맷이다(오픈소스 기여)
사용하는 RTSP 클라이언트 오픈소스 라이브러리가 간헐적으로 IFrame이 10초간 들어오지 않았다면서 세션을 종료하는 현상이 계속 발생했고 프로덕션 환경에서도 재현이 되었다(해당 카메라는 30 IPS였음). Github에 해당 오픈소스 라이브러리 이슈들을 살펴보다가 우리 상황일 것이라고 의심되는 이슈가 이미 존재했고 아무도 그걸 고치지 않고 있었다.
원인은 RTP Client가 RTP 패킷을 받자마자 AVCC, AnnexB 파싱을 하고 있었기 때문이었다. 당신도 알다시피, AVCC와 AnnexB는 컨테이너 포맷이고 RTP Payload에는 그냥 NALu가 packetization mode에 맞게 1개 혹은 여러개가 들어있을 뿐이다. 당연히 Emulation Prevention이 없으므로 AVCC 검증 실패할 경우 Single NALu가 여러 데이터 쪼가리로 쪼개지고 IFrame 검증 로직에서 잘못된 비트를 검사한 후 IFrame이 안들어온다는 예외를 발생시킨다.
심지어, Packetization Mode를 전부 구현하지도 않았다! 우연히 우리 RTP서버가 해당 RTSP 클라이언트가 파싱가능한 Packetization Mode로 패킷을 전송했을 뿐이었다.
그 2가지 문제를 모두 고쳐서 풀리퀘스트를 올렸다. 이전에도 동일 라이브러리의 버그 수정을 위해 풀리퀘스트를 올렸고 그 때는 메인테이너가 내가 작성한 풀리퀘를 확인하는 데에 1년정도 걸렸는데 과연 이번에는 어떨까.
웹개발자들은 갸우뚱하겠지만 웹 생태계가 이상하리만치 오픈소스에 활기가 넘치는거고 원래는 이렇다…
프로토콜 선택
브라우저가 지원하는 프로토콜 중 어떤 걸로 영상을 전송할지 정해야 한다.
- HTTP/1과 HTTP/2
- WebSocket
- HTTP/3
백프래셔(브라우저쪽에서 디코딩을 하고 나면 영상이 메모리를 꽤 많이 먹는다 비디오 압축방식이 효율이 엄청좋아서 그럼)는 반드시 필요하다. 백프래셔 안하면 브라우저 메모리 터진다. 따라서 TCP window size를 동적으로 조절할 수 있는 2번과 3번으로 좁혀진다.
여기서 핵심은 공급속도를 클라이언트 측에서 제어할 방법이 필요하다는 것이다. 그게 위에서 설명한 TCP window size를 줄이는 방식이건 내가 생각치못한 다른 방식이건 어쨌건 간에 당신은 고민 끝에 2번과 3번 중에 선택하게 되어있다. 나는 안다.
RTSP와 WebSocket/WebTransport 는 따로 생각해야 한다. 단순히 릴레이만 하면 안된다.
TCP window size를 줄여버리는 상황이 꽤 빈번하게 온다. 그럴때 당신이 그냥 릴레이만 하는 서버를 만들었다고 하자. 나중에 브라우저가 메모리가 남아돌아서 TCP window size를 다시 높였을때까지 꽤 오랜 시간이 걸렸고 RTSP는 이미 끊어졌을 것이고(VOD이고 영상이 끝난 경우) 당신이 구현한 서버는 릴레이만 하니까 RTSP가 끊어졌을때 WebSocket/WebTransport가 끊어지게 된다. 그럼 브라우저 입장에서는 막상 메모리가 여유로워지고 나니 재생할게 더이상 없게 되는 것이다.
그런 상황을 방지하기 위해 스트리밍에 들어가는 서버 들 중, Media 서버가 OnDemand라면 당신은 Event Driven 아키텍처로 구현해야 한다.
미디어 서버 다 만들었다면 이제 플레이어의 시간이다. 다음편에 계속