O que tem dentro de um manifesto HLS

14 de julho de 2026

Antes de um único frame de vídeo adaptativo chegar à tela, o player baixa um arquivinho de texto: o manifesto. Tudo o que ele faz — qual qualidade escolher, onde estão os segmentos, se é ao vivo ou sob demanda — sai da leitura desse arquivo. No HLS, ele é um playlist .m3u8, e depois que você aprende a ler um, muito "por que o vídeo está fazendo isso?" deixa de ser mistério.

São dois tipos, e o player os lê em ordem.

O master playlist: a escada de qualidades

O primeiro arquivo que o player busca é o master (ou multivariant). Ele não aponta pra vídeo — aponta pra outros playlists, um por degrau de qualidade:

#EXTM3U #EXT-X-VERSION:3 #EXT-X-STREAM-INF:BANDWIDTH=1280000,RESOLUTION=720x480,CODECS="avc1.42c01e,mp4a.40.2" 480p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=2560000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2" 720p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=6000000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2" 1080p.m3u8

Cada linha #EXT-X-STREAM-INF é um degrau da escada de bitrate adaptativo (ABR). BANDWIDTH é o número que a lógica de ABR observa: o player estima sua banda e pega o degrau mais alto que aguenta sem travar. CODECS deixa ele pular degraus que o aparelho não decodifica; RESOLUTION deixa ele evitar degraus maiores que a tela em que está desenhando. Esse é o cardápio inteiro — e o player ainda não tocou um byte de vídeo.

O media playlist: os segmentos

Escolha um degrau e você recebe um media playlist — a lista de fato dos pedaços:

#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:6 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:6.000, segment0.ts #EXTINF:6.000, segment1.ts #EXT-X-ENDLIST

#EXTINF é a duração de cada segmento; #EXT-X-TARGETDURATION é o teto pra qualquer um deles. O player baixa os segmentos em ordem, joga num buffer e reproduz. Trocar de qualidade é só buscar o próximo segmento de outro media playlist — mesma timeline, outro degrau. É por isso que o ABR muda a resolução no meio da reprodução sem um reload visível. Isso só funciona porque cada degrau é cortado nas mesmas fronteiras de segmento, com um keyframe no início de cada segmento — então o player troca de degrau em qualquer fronteira sem resetar o decoder. Erre esse alinhamento na hora de codificar e as trocas travam ou piscam; é a parte sem glamour que decide se o ABR parece fluido.

Ao vivo vs. sob demanda: uma linha

A diferença entre um filme e um canal ao vivo é quase uma tag só. #EXT-X-ENDLIST diz "acabaram os segmentos" — sob demanda. Tire ela, e o playlist é ao vivo: o player re-busca ele a cada poucos segundos pra descobrir segmentos novos conforme são codificados, usando #EXT-X-MEDIA-SEQUENCE pra saber onde parou. #EXT-X-DISCONTINUITY marca uma quebra na timeline — uma inserção de anúncio, um splice — pra o decoder resetar limpo em vez de dar glitch.

Esse é o núcleo: uma escada de qualidades, uma lista de segmentos por qualidade, e um par de tags que dizem ao-vivo-ou-não e onde estão as emendas — tudo em texto simples que você dá curl e lê.

Deixei de fora o que torna isso interessante em escala — segmentos fMP4/CMAF, faixas alternativas de áudio e legenda via #EXT-X-MEDIA, requisições por byte-range, e o Low-Latency HLS — mas o formato acima é a espinha por baixo de tudo.

Se quiser ver um tocando de verdade, mantenho um sandbox hls.js em /pt/lab apontado pra um stream de teste público da Mux. Abra ele com a aba Network aberta e você vai ver o master ser buscado, depois um media playlist, depois as requisições de segmento — e o degrau mudar conforme o ABR reage. Ou só dê curl no .m3u8 e leia o formato acima.

Este post descreve técnica geral e padrão da indústria. Não é baseado em, nem descreve, o sistema de nenhum empregador ou cliente específico.