Como impedir que seu stream ABR fique alternando entre bitrates

Este artigo foi traduzido do inglês com a ajuda de IA. Ler o original

Como projetar uma escada de transcodificação que não enlouqueça os algoritmos ABR

Se você já passou algum tempo observando a reprodução HLS em condições reais, já viu isso: o stream fica alternando entre duas renditions. Para cima, para baixo, para cima, para baixo. O espectador vê uma mudança constante de qualidade, às vezes a cada poucos segundos. É pior do que ficar numa rendition inferior o tempo todo. Pelo menos um stream estável em 720p parece intencional. Um stream que oscila entre 720p e 1080p a cada 10 segundos parece quebrado.

A causa raiz é quase sempre a mesma: a escada de codificação tem renditions muito próximas em bitrate, ou a diferença de qualidade entre os degraus não justifica o salto em largura de banda. O algoritmo ABR do lado do cliente não consegue se decidir, porque a diferença entre "consigo arcar com isso" e "não consigo arcar com isso" é mínima.

Vamos ver como resolver isso corretamente.

O teste de sanidade de bits por pixel

Antes de tudo, você precisa entender o que os bits por pixel (BPP) dizem sobre sua escada. É a métrica mais simples para avaliar se um bitrate específico realmente faz sentido para uma resolução dada.

A fórmula é direta:

BPP = bitrate / (width × height × framerate)

Por exemplo, um stream de 1920×1080 a 4500 kbps e 30 fps:

BPP = 4,500,000 / (1920 × 1080 × 30) = 0.072

Por que isso importa? Porque o BPP indica a densidade de compressão em cada degrau. Se dois degraus adjacentes da sua escada têm valores de BPP muito similares, o espectador não verá uma diferença de qualidade significativa — mas o algoritmo ABR ainda tentará alternar entre eles. É assim que você acaba com o comportamento de ping-pong.

Uma escada bem projetada deve ter uma curva de BPP descendente à medida que a resolução aumenta. Isso reflete uma propriedade real dos codecs de vídeo: eles são mais eficientes em resoluções mais altas. Você precisa de menos bits por pixel em 1080p para alcançar a mesma qualidade percebida que em 480p. Se o seu BPP é plano ou inconsistente entre os degraus, algo está errado.

A "Regra do 0.70" é uma referência prática aqui. A ideia é que quando você dobra a contagem de pixels (por exemplo, ao passar de 720p para 1080p), deve aplicar aproximadamente 0.70× o BPP da resolução inferior. É uma heurística, não uma lei, mas dá uma forma rápida de identificar anomalias. Se você plotar os valores de BPP da sua escada e um degrau se destacar claramente — muito alto ou muito baixo comparado aos seus vizinhos — esse degrau causará problemas.

A conclusão: não escolha simplesmente bitrates que pareçam números redondos bonitos. Calcule o BPP para cada degrau e certifique-se de que a curva faça sentido. Se dois degraus adjacentes estão a 15-20% de diferença em BPP, o espectador não os distinguirá, mas a heurística ABR perderá tempo alternando entre eles.

Espaçamento de bitrates: a regra do fator 1.5×

Não existe um padrão universal, mas uma diretriz comum de engenharia é manter pelo menos uma proporção de 1.5× entre degraus de bitrate adjacentes. Algumas implementações elevam essa proporção para 2×.

Por quê? Porque os algoritmos ABR usam a estimativa de largura de banda para decidir qual rendition escolher. A estimativa tem um intervalo de confiança — nunca é exata. Se duas renditions estão a 2,5 Mbps e 3,0 Mbps, o BWE pode facilmente oscilar acima e abaixo de 3,0 Mbps numa conexão levemente variável, causando trocas constantes. Se, em vez disso, o salto é de 2,0 Mbps para 4,0 Mbps, o algoritmo precisa de uma mudança de largura de banda muito mais significativa para acionar uma troca. O resultado: uma reprodução mais estável.

Aqui está um exemplo concreto. Suponha que você tem uma escada limpa de quatro degraus:

Resolução Bitrate BPP (30fps) Proporção com o anterior
480×270400 kbps0.103
960×5402000 kbps0.1295.0×
1280×7202800 kbps0.1011.4×
1920×10804500 kbps0.0721.6×

À primeira vista parece razoável — quatro resoluções, bitrates crescentes. Mas veja o salto 540p→720p: de 2000 kbps para 2800 kbps. Isso é apenas uma proporção de 1.4×. Em qualquer conexão que oscile em torno de 2,5–3 Mbps (que é a maioria das conexões móveis), o BWE cruzará constantemente esse limiar. Para cima, para baixo, para cima, para baixo. O espectador vê uma mudança de resolução a cada poucos segmentos.

E aqui está o outro problema: o BPP na verdade cai de 0,129 a 540p para 0,101 a 720p. Então o espectador obtém mais pixels mas menos dados por pixel. Dependendo do conteúdo, a rendition de 720p pode não parecer significativamente melhor que a de 540p — você adicionou resolução mas perdeu margem de compressão. O algoritmo ABR está alternando para nada.

Uma versão melhor desta escada aumentaria o bitrate do 720p e ajustaria o 540p para baixo:

Resolução Bitrate BPP (30fps) Proporção com o anterior
480×270400 kbps0.103
960×5401500 kbps0.0963.75×
1280×7203000 kbps0.1092.0×
1920×10805800 kbps0.0931.93×

Agora o salto 540p→720p é uma proporção limpa de 2×. O BWE precisa dobrar antes que o reprodutor sequer considere subir de qualidade. E o BPP na verdade aumenta de 0,096 para 0,109, o que significa que o degrau 720p entrega tanto mais pixels quanto melhor qualidade de compressão — o espectador vê uma melhoria real. O salto 720p→1080p a 1,93× é igualmente sólido, e o BPP cai apenas levemente para 0,093, que é o ganho de eficiência esperado em resoluções mais altas.

Verificação degrau por degrau: teste de reprodução individual

Aqui está algo que raramente vejo equipes fazerem, mas é crítico: reproduzir cada rendition individualmente e assistir tudo completo.

Parece óbvio, mas a maioria das pessoas só testa o ABR como um stream multi-variante completo. Elas nunca isolam uma única rendition e a reproduzem do início ao fim. Quando você faz isso, detecta problemas que o comportamento ABR esconde:

  • Uma rendition que faz buffering mesmo no seu próprio bitrate declarado (porque o BANDWIDTH declarado na playlist é muito baixo comparado ao bitrate de pico real)
  • Uma rendition onde o codificador teve dificuldades e produziu artefatos visíveis em certas cenas
  • Uma rendition onde o framerate cai ou engasga porque a combinação resolução/bitrate é muito exigente para o decodificador do dispositivo alvo

Para testar isso, você pode forçar a reprodução de uma única rendition de várias formas:

Com a página de demo do hls.js: Carregue seu stream multi-variante, depois no menu suspenso do seletor de qualidade, fixe manualmente cada nível um por um. A demo do hls.js em hlsjs.video-dev.org/demo/ expõe todos os níveis de qualidade e permite que você substitua o ABR. Reproduza cada um por pelo menos alguns minutos de conteúdo representativo. Observe os frames perdidos na aba «Buffer & Statistics».

Com AVPlayer nas plataformas Apple: Use preferredPeakBitRate e preferredMaximumResolution no AVPlayerItem para restringir a reprodução a uma única rendition. Ou ainda mais simples: crie uma playlist de teste que inclua apenas uma variante.

Com ffprobe ou mediainfo: Antes mesmo de reproduzir qualquer coisa, verifique as estatísticas reais de bitrate de cada rendition. O valor de BANDWIDTH na sua playlist master deve considerar o pico, não apenas a média. Se sua codificação VBR tem picos de 40% acima da média, seu BANDWIDTH declarado precisa refletir isso.

Se uma única rendition não consegue ser reproduzida sem problemas no seu próprio bitrate declarado, ela absolutamente causará problemas no modo ABR. O algoritmo ABR seleciona essa rendition achando que tem largura de banda suficiente, depois encontra um pico VBR, trava, desce de nível, recupera, seleciona essa rendition novamente — ping-pong.

Duração dos segmentos: o relógio de comutação do ABR

Há outro fator que as pessoas tendem a ignorar: a duração dos segmentos controla diretamente com que frequência o algoritmo ABR pode tomar uma decisão. Cada fronteira de segmento é um ponto de comutação potencial. Então, se você usa segmentos de 2 segundos, o reprodutor pode reavaliar e trocar até 30 vezes por minuto. Com segmentos de 6 segundos, isso cai para 10 vezes por minuto. Com segmentos de 10 segundos, apenas 6.

Isso importa muito quando sua escada já tem um espaçamento de bitrate apertado. Segmentos curtos combinados com degraus de bitrate próximos é a pior combinação — você está dando ao algoritmo ABR o máximo de oportunidades para fazer trocas marginais que o espectador não precisa ver.

Por outro lado, segmentos mais longos atuam como um amortecedor natural contra a oscilação. Mesmo que a estimativa de largura de banda flutue, o reprodutor tem que se comprometer com sua rendition atual pela duração do segmento que acabou de baixar. Quando o próximo ponto de decisão chega, o BWE pode ter se estabilizado.

A especificação HLS não exige uma duração específica, mas as diretrizes da Apple recomendam um alvo de 6 segundos. Na prática:

  • Segmentos de 2 segundos: fazem sentido para live de baixa latência onde o início rápido e a adaptação rápida são críticos. Mas você precisa de uma escada bem espaçada para evitar a troca constante.
  • Segmentos de 6 segundos: são um bom padrão para VOD e live convencional. Dão ao algoritmo ABR tempo suficiente para construir uma estimativa de largura de banda confiável entre as decisões.
  • Segmentos de 10 segundos: muito estáveis mas lentos para se adaptar. Se a largura de banda cai abruptamente, o reprodutor fica preso baixando um segmento de alto bitrate que pode não conseguir terminar a tempo.

Há também uma sutileza com a codificação VBR: a variância de bitrate dentro de um segmento aumenta com a duração do segmento. Um segmento de 10 segundos de uma transição de cena — passando de um plano estático para uma sequência de ação — pode ter uma flutuação de bitrate massiva internamente. Se o BANDWIDTH declarado na playlist corresponde à média geral mas não aos picos por segmento, o algoritmo ABR é pego de surpresa. Segmentos mais curtos tendem a ter bitrates por segmento mais consistentes, o que torna o BWE mais preciso.

Resumindo: se você está vendo oscilação e o espaçamento da sua escada parece correto, verifique a duração dos seus segmentos. Passar de 4 segundos para 6 segundos pode ser tudo o que você precisa para acalmar as coisas.

Usar o Network Link Conditioner para simular condições reais

Testar o ABR numa conexão de fibra estável de 100 Mbps é inútil. Você precisa simular condições do mundo real, e o Network Link Conditioner da Apple é a melhor ferramenta para isso no macOS.

Você o obtém do pacote Additional Tools for Xcode da Apple: no Xcode, vá para Xcode > Open Developer Tool > More Developer Tools, que leva à página de downloads para desenvolvedores da Apple. Procure por «Additional Tools for Xcode», baixe o DMG para sua versão do Xcode, abra-o, e na pasta Hardware você encontrará Network Link Conditioner.prefPane. Clique duas vezes para instalar. Ele aparece então como um painel em Ajustes do Sistema (ou Preferências do Sistema em versões mais antigas do macOS). Permite definir perfis de largura de banda com velocidade, latência, taxa de perda de pacotes e atraso DNS específicos.

Crie perfis personalizados que importam:

  • 4G medíocre: 8 Mbps de download / 2 Mbps de upload, 80ms RTT, 1% de perda de pacotes
  • WiFi ruim: 3 Mbps de download / 1 Mbps de upload, 150ms RTT, 3% de perda de pacotes
  • Transicional: Comece a 15 Mbps, mude manualmente para 2 Mbps durante a reprodução

Esse último teste é o decisivo. Se sua escada está bem projetada, o reprodutor deve descer suavemente para uma rendition inferior em poucos segundos e ficar lá. Se começar a oscilar entre duas renditions, seus degraus estão muito próximos na fronteira de largura de banda.

Em dispositivos iOS, o Network Link Conditioner está disponível pelas configurações de Desenvolvedor (ative-o em Ajustes > Desenvolvedor após conectar o dispositivo ao Xcode).

O objetivo desses testes não é simplesmente «faz buffering?» — é «o stream se estabiliza numa rendition e fica lá?». Uma boa experiência ABR é aquela onde as trocas são raras e decisivas. O espectador vê a mudança de qualidade uma vez, e depois estabiliza.

Usar o AVMetrics da Apple para monitorar trocas em produção

A partir do iOS 18, a Apple introduziu a API AVMetrics no AVFoundation. Isso é uma mudança revolucionária para monitorar o comportamento ABR em campo.

O tipo de evento chave para nosso propósito é o evento de troca de variante. Cada vez que o AVPlayer troca entre variantes HLS, você recebe um evento de métrica que informa de onde trocou, para onde trocou, e os detalhes da rendition de mídia. Você também recebe eventos de travamento quando o reprodutor faz rebuffering, e um evento de resumo no final da sessão com os KPIs gerais.

Aqui está o padrão em Swift:

let playerItem: AVPlayerItem = // your configured item

let switchMetrics = playerItem.metrics(
    forType: AVMetricPlayerItemVariantSwitchEvent.self
)
let stallMetrics = playerItem.metrics(
    forType: AVMetricPlayerItemStallEvent.self
)

for await (event, _) in switchMetrics.chronologicalMerge(with: stallMetrics) {
    switch event {
    case let switchEvent as AVMetricPlayerItemVariantSwitchEvent:
        // Log: from variant, to variant, timestamp
        await analytics.logSwitch(switchEvent)
    case let stallEvent as AVMetricPlayerItemStallEvent:
        // Log: stall duration, variant at time of stall
        await analytics.logStall(stallEvent)
    default:
        break
    }
}

O que você deve procurar nas suas análises:

  • Frequência de troca: Se a sessão média tem mais de 3-4 trocas por minuto, sua escada tem problemas. Streams saudáveis trocam talvez uma ou duas vezes por sessão, tipicamente no início.
  • Padrões de oscilação: Duas renditions que continuam alternando — sinal clássico de degraus muito próximos.
  • Travamentos correlacionados com subidas de qualidade: Se os travamentos ocorrem logo após trocar para uma rendition superior, suas declarações de BANDWIDTH na playlist estão muito baixas.

Para a WWDC 2025, a Apple expandiu o AVMetrics para incluir informações de rendition de mídia nos eventos de troca de variante, facilitando ver exatamente quais faixas de áudio/vídeo/legendas estavam ativas durante a troca.

Se você não está nas plataformas Apple, dados similares podem ser coletados do hls.js através dos eventos LEVEL_SWITCHED e FRAG_BUFFERED. Os mesmos princípios se aplicam.

Experimentar com o hls.js: ajustar o comportamento ABR

A página de demo do hls.js (hlsjs.video-dev.org/demo/) é a melhor ferramenta gratuita para experimentar com o comportamento de comutação ABR na web. Carregue seu stream HLS e use os painéis «Real-time metrics» e «Buffer & Statistics» para observar o que acontece.

Parâmetros chave do hls.js para experimentar:

  • abrEwmaFastVoD e abrEwmaSlowVoD: Estes controlam a média móvel ponderada exponencialmente (EWMA) para estimativa de largura de banda. Valores mais baixos fazem o reprodutor reagir mais rápido a mudanças de largura de banda (troca mais agressiva). Valores mais altos o tornam mais conservador (troca mais lenta, mais estável). Se você está vendo muitas trocas, tente aumentar esses valores.
  • abrBandWidthFactor (padrão: 0.95) e abrBandWidthUpFactor (padrão: 0.7): São margens de segurança. O reprodutor seleciona uma rendition cujo bitrate está abaixo de estimatedBandwidth × factor. O fator de subida é deliberadamente mais baixo — o reprodutor é mais conservador para subir do que para descer de qualidade. Se sua escada tem espaçamento apertado, você pode querer baixar abrBandWidthUpFactor para 0.6 para reduzir a oscilação.
  • abrMaxWithRealBitrate (padrão: false): Quando habilitado, o controlador ABR usa o bitrate real medido dos segmentos baixados em vez do BANDWIDTH declarado na playlist. Isso é particularmente útil se seus bitrates declarados são imprecisos.

Mas aqui está a questão: se você precisa ajustar muito esses parâmetros para obter uma reprodução estável, sua escada provavelmente está mal projetada. Esses controles são para ajuste fino. A escada de codificação em si é o fundamento. Uma escada bem espaçada funciona bem com as configurações ABR padrão em qualquer reprodutor.

Recomendações práticas

Se eu tivesse que resumir tudo isso numa checklist:

  1. Calcule o BPP para cada degrau da sua escada. Certifique-se de que ele diminui à medida que a resolução aumenta. Remova ou ajuste qualquer degrau cujo BPP esteja dentro de 15% do seu vizinho.
  2. Mantenha pelo menos uma proporção de bitrate de 1.5× entre degraus adjacentes. Prefira 2× quando possível, especialmente na metade inferior da escada onde a flutuação de largura de banda tem maior impacto.
  3. Teste cada rendition isoladamente. Force a reprodução de uma única variante e assista conteúdo representativo do início ao fim. Se não consegue ser reproduzido sem problemas sozinho, não o fará em ABR.
  4. Use o Network Link Conditioner para simular quedas de largura de banda. O stream deve se estabilizar numa rendition rapidamente e ficar lá.
  5. Verifique a duração dos seus segmentos. Se você está em 2–4 segundos e vê oscilação, tente 6 segundos. Segmentos mais longos reduzem naturalmente a frequência de troca ao dar ao BWE mais tempo para se estabilizar entre as decisões.
  6. Instrumente seu reprodutor. Use AVMetrics na Apple, eventos do hls.js na web. Rastreie a frequência de troca por sessão. Se as sessões têm em média mais do que um punhado de trocas fora da fase de inicialização, investigue.
  7. Não confie apenas no BANDWIDTH declarado. Use abrMaxWithRealBitrate no hls.js ou verifique com ffprobe que seus picos VBR não excedem o valor declarado.
  8. Menos degraus geralmente é melhor. Uma escada de 5 degraus com renditions bem espaçadas superará uma escada de 10 degraus onde metade dos degraus está muito próxima. O espectador não precisa de 12 níveis de qualidade. Precisa de 4 ou 5 que pareçam significativamente diferentes e sejam reproduzidos de forma confiável.

O objetivo do ABR é ser invisível. O espectador não deveria perceber que está funcionando. Se ele percebe, algo está errado — e nove em cada dez vezes, é a escada.

Referências:

Need Help With Your Streaming Project?

This article was written by experienced professionals available through iReplay.tv. Whether you need expertise in streaming, HLS, hls.js—our network of specialists can bring your project to life.

Hire a Professional →