Skip to content
Blog
Go back

HLS: master playlist

먼저 털어놓자면 나는 HLS를 깊게 아는 개발자가 아니다. 음악 플랫폼을 처음 만들던 시기에 HLS를 붙였고, 이 글은 그때 어디까지 알았고 무엇을 몰랐는지를 적은 회고다.

문제 파악

음악 플랫폼을 초기부터 만드는 일이었다. 일정은 빠듯했고 야근이 이어졌다. 나는 아직 2년차였고 솔직히 그 업무는 상당히 버거웠다. 그런 상황에서는 원리를 끝까지 파고들 여유가 잘 안 생긴다. 일단 재생이 되게 만들고 다음 일로 넘어가야 했다. 그래서 그때 쌓인 지식은 playlist를 받고 segment를 순서대로 가져온다는 기본 원리였다. buffering 설정 같은 튜닝은 거의 손대지 못했다.

증상은 구글 기기 연동에서 나왔다. 연동한 기기는 Google Nest였다. 기존 음악 서비스는 media playlist만 내려주고 있었다. 그 방식을 그대로 붙였더니 재생이 시작되지 않거나, 시작되더라도 몇 초 만에 멈췄다. 처음에는 buffer 문제라고 생각했는데 buffer 문제는 아니었다.

문제 정의

이건 스펙 이해 부족이었다. m3u8을 하나의 형식이라고만 알았는데, 우리 환경에서는 master playlist를 내려주자 Nest에서 재생됐다.

문제 해결

master playlist가 있다는 걸 알게 된 뒤 담당 팀에 master playlist를 내려주도록 바꿔 달라고 했고, 그걸로 Nest 재생이 됐다. 그 전에 내가 이해하고 있던 전체 흐름은 이 다이어그램 정도다. 당시 직접 그렸던 그림을 옮겼다.

media server가 음원을 encoding해서 잘게 나눈 뒤 CDN에 업로드하면, 그 조각들이 CDN에 caching된다. client는 manifest인 m3u8 파일을 받아 재생할 segment 목록을 알아내고 segment를 차례로 요청한다. 콘텐츠 보호를 위해 key server가 있었고 client가 key를 요청하면 key server가 검증한 뒤 key를 내려주는 단계가 흐름에 들어 있었다.

key server를 먼저 부르는 건 그 서비스 백엔드 자체의 구조였다. 표준 HLS에서는 media playlist를 읽은 뒤에 key를 가져온다. 다이어그램에서 key 요청이 1번인 건 실제 서비스의 요청 순서였다.

나중에 RFC 8216을 읽어 보니 구분 자체는 단순했다. playlist는 media playlist이거나 master playlist 둘 중 하나다. playlist 안의 URI 줄이 전부 media segment를 가리키면 media playlist이고 전부 media playlist를 가리키면 master playlist다. 둘이 섞인 playlist는 유효하지 않다.

master playlist는 같은 콘텐츠를 여러 버전으로 제공할 때 쓰인다. 각 버전(Variant Stream)마다 bitrate나 codec 정보를 적고 그 버전의 media playlist 주소를 달아 둔다. client는 네트워크 상황에 맞춰 이 중 하나를 고르고 상황이 바뀌면 다른 버전으로 갈아탄다.

아래는 구조를 보여 주려고 만든 예시다. 실제 서비스 파일이 아니다.

# master.m3u8 (master playlist)
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=320000,CODECS="mp4a.40.2"
high/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=128000,CODECS="mp4a.40.2"
low/playlist.m3u8
# high/playlist.m3u8 (media playlist)
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
segment0.ts
#EXTINF:10.0,
segment1.ts
#EXTINF:4.5,
segment2.ts
#EXT-X-ENDLIST

master 쪽의 EXT-X-STREAM-INF에는 BANDWIDTH가 반드시 있어야 하고 media 쪽에는 EXT-X-TARGETDURATION이 반드시 있어야 한다. EXTINF는 바로 다음 media segment의 길이(초)이고 EXT-X-ENDLIST는 더 추가될 segment가 없다는 표시다.

구분master playlistmedia playlist
안에 적힌 URImedia playlistmedia segment
대표 태그EXT-X-STREAM-INF, EXT-X-MEDIAEXT-X-TARGETDURATION, EXTINF, EXT-X-ENDLIST
하는 일여러 버전 중 고를 수 있게 목록을 줌실제로 재생할 조각의 순서를 줌

용어 하나를 덧붙이면, RFC 8216의 후속 개정 초안(rfc8216bis)과 Apple 문서에서는 master playlist를 Multivariant Playlist라고 부른다. 검색할 때 두 이름을 다 넣어 보는 게 편하다.

개선할 점

못 했던 건 분명히 적어 둔다. buffer를 얼마나 앞서 채울지, 처음 재생을 얼마나 빨리 시작할지 같은 buffering 설정은 제대로 튜닝하지 못했다. 그때 쓴 player 설정은 library 기본값을 그대로 썼다. master playlist가 있다는 것도 기기 연동을 하다가 알았다. 스펙을 더 일찍 봤다면 출발이 달랐을 것이다.

playlist에서 segment로 이어지는 메커니즘은 이미 알고 있으니, 그 위에서 buffering 설정과 bitrate 전환이 실제 재생 경험을 어떻게 바꾸는지 한 단계 더 깊게 들어가 볼 생각이다.

2년차의 나는 구조를 다 알지 못한 채로 재생을 붙였고 기기 하나를 연동하다가 playlist에 종류가 있다는 걸 배웠다. 자랑할 만한 깊이는 아니어도 어디까지 알고 어디부터 모르는지는 이제 분명하다. 여러분은 처음 HLS를 붙였을 때 어떤 개념에서 막혔는가?

참고


Share this post:

Previous Post
Reverse Proxy: legacy와 신버전
Next Post
CloudFront: 티켓팅 화면 caching 설계