O problema do primeiro visualizador ou a difícil conversão de fluxos de vídeo WebRTC em HLS


Egor fechou a tampa do laptop e esfregou os olhos vermelhos por falta de sono. "Os clientes continuam reclamando sobre o congelamento do fluxo, o novo fix pack não ajudou em nada! Então, o que fazer com esse HLS (censurado)?" Ele disse no vazio do estudo.


O navegador não é apenas um hipertexto, mas também uma serpentina


Os navegadores adquirem players há muito tempo, mas com um codificador de vídeo e a transmissão da história é diferente. Agora, em quase qualquer navegador da versão mais recente, você pode encontrar módulos para codificação, streaming, decodificação e reprodução. Essas funções estão disponíveis através da API JavaScript e a implementação é chamada Web Real Time Communications ou WebRTC. Essa biblioteca incorporada nos navegadores pode fazer bastante: capturar vídeo de uma câmera embutida, virtual ou USB, compactar com os codecs H.264, VP8, VP9, ​​enviá-lo à rede via protocolo SRTP, ou seja, funciona como um codificador de streamer de vídeo de software. Como resultado, vemos um navegador que possui algo semelhante ao ffmpeg ou gstreamer, que comprime bem o vídeo, transmite em RTP e reproduz fluxos de vídeo.


O WebRTC oferece a liberdade de implementar uma variedade de casos de streaming em JavaScript:


  • transmitir o fluxo do navegador para o servidor para gravação e distribuição subsequente
  • ponto a ponto
  • reproduza o stream de outro usuário e envie o seu próprio (chat por vídeo)
  • converter outros protocolos pelo servidor, por exemplo, RTMP, RTSP, etc., e reproduzir no navegador como WebRTC

Os scripts de controle de fluxo refinados podem ter esta aparência:


//      session.createStream({name:”mystream”}).publish(); //   session.createStream({name:”mystream”}).play(); 

O HLS funciona onde o WebRTC não funciona


O WebRTC funciona nas versões mais recentes dos navegadores, no entanto, existem dois dos seguintes fatores: 1) Nem todos os usuários atualizam os navegadores em tempo hábil e podem ficar em algum tipo de Chrome por três anos. 2) Quase uma vez por semana são lançadas atualizações e novos navegadores, o WebView, além de outros clientes e mensageiros instantâneos que podem navegar na Internet. Desnecessário dizer que nem todos eles têm suporte para WebRTC e, se houver, podem ser completamente truncados. Veja como estão as coisas agora:



Dor de cabeça separada - os dispositivos Apple favoritos de todos. Recentemente, eles receberam suporte para o WebRTC e, às vezes, são surpreendentes em seu comportamento em comparação com os navegadores ortodoxos. E onde o WebRTC não funciona ou não funciona muito bem, o HLS funciona bem. Nesse sentido, é necessária compatibilidade, e algo como um conversor que converte WebRTC em HLS e o reproduz em quase qualquer dispositivo.


Inicialmente, o HLS não foi concebido para fluxos em tempo real. De fato, qual pode ser o tempo do vídeo em HTTP? A tarefa do HLS é cortar o vídeo em pedaços e entregá-lo ao player sem problemas, sem pressa, baixando um por um. O HLS player espera um fluxo de vídeo estritamente formado e suave. E aqui surge um conflito, já que o WebRTC, ao contrário, pode se permitir perder pacotes devido a requisitos em tempo real e baixa latência e ter um FPS / GOP flutuante e uma taxa de bits variável - para ser exatamente o oposto do HLS em termos de previsibilidade e dimensionalidade do fluxo.


Uma abordagem óbvia - a despacketization do WebRTC (SRTP) e a subsequente conversão para HLS, podem não funcionar no player Apple HLS nativo ou de forma inadequada para produção com frisos. Um player nativo aqui significa um player usado no Apple iOS Safari, Mac OS Safari e Apple TV.


Portanto, se você notar o friso HLS no player nativo, talvez seja isso, e a origem do fluxo é o WebRTC ou outro fluxo dinâmico com marcação irregular. Além disso, na implementação de players nativos da Apple, existe um comportamento que só pode ser entendido empiricamente. Por exemplo, o servidor deve começar a enviar segmentos HLS imediatamente, imediatamente após o retorno da lista de reprodução m3u8. Atraso por segundo ameaça com um congelamento. Se a configuração do fluxo de bits tiver sido alterada no processo (que é uma ocorrência bastante comum no streaming do WebRTC), também haverá um friso.


Lute contra frisos em jogadores nativos


Portanto, a despacketização e a embalagem direta e honesta do WebRTC no HLS geralmente não funcionam. No servidor de streaming de vídeo do Web Call Server (WCS) , resolvemos o problema de duas maneiras e oferecemos o terceiro como alternativa:


1) Transcodificação.


Essa é a maneira mais confiável de alinhar o fluxo do WebRTC com os requisitos de HLS, definir o GOP, o FPS desejado, etc. No entanto, em alguns casos, a transcodificação não é uma boa solução, por exemplo, a transcodificação de fluxos de 4K de vídeo em VR é uma idéia mais ou menos. Esses fluxos pesados ​​são muito caros para transcodificar em termos de tempo da CPU ou recursos da GPU.



2) Adaptação e alinhamento do fluxo do WebRTC em tempo real, de acordo com os requisitos do HLS.


Esses são analisadores especiais que analisam o fluxo de bits H.264 e o corrigem para os recursos / bugs dos players Apple HLS nativos. Aqui, devemos admitir que players não nativos, como video.js e hls.js, são mais tolerantes a fluxos com taxa de bits dinâmica e FPS, que é o WebRTC e não diminui a velocidade onde a implementação de referência do Apple HLS cai essencialmente em congelamento permanente.



3) Use RTMP como uma fonte de fluxo em vez de WebRTC.


Apesar do flash ser retirado, o protocolo RTMP é usado ativamente para streaming, faça o mesmo OBS Studio. E devo admitir que os codificadores RTMP geralmente produzem fluxos mais uniformes que o WebRTC e, portanto, praticamente não produzem frisos no HLS, ou seja, Converter RTMP> HLS do ponto de vista de frisos parece muito mais adequado, inclusive em players nativos de HLS. Portanto, se o streaming for realizado a partir da área de trabalho e do OBS, é melhor usá-lo para a conversão em HLS. Se a fonte for um navegador Chrome, o RTMP não poderá ser usado sem a instalação de plug-ins, e aqui apenas o WebRTC.



Todos os três métodos descritos acima são testados e funcionam, portanto, há uma oportunidade de escolha com base nas condições da tarefa.


WebRTC para HLS na CDN


Alguns problemas podem aguardar em um sistema distribuído quando vários servidores de entrega de fluxo WebRTC estão localizados entre a fonte de fluxo WebRTC e o player HLS, ou seja, CDN , no nosso caso, com base no servidor WCS. É assim: existe o Origin - um servidor que recebe um fluxo WebRTC, há Edge - servidores que distribuem esse fluxo, incluindo o HLS. Pode haver muitos servidores, o que permite o dimensionamento horizontal do sistema. Por exemplo, 1000 servidores HLS podem ser conectados a um servidor Origin, nesse caso, a capacidade do sistema é dimensionada 1000 vezes.



O problema já foi identificado um pouco mais alto, e esse problema geralmente surge em players nativos: iOS Safari, Mac OS Safari, Apple TV. Por nativo, queremos dizer um player que trabalha com uma indicação direta do URL da lista de reprodução na tag, por exemplo, <video src="https://host/test.m3u8"/> . Assim que o player solicita uma lista de reprodução, e essa ação é realmente o primeiro passo na reprodução do fluxo HLS, o servidor deve imediatamente, sem demora, começar a enviar segmentos de vídeo HLS. Se o servidor não começar a dar segmentos imediatamente, o jogador decide que ele foi enganado e para de jogar. Novamente, esse comportamento é típico dos players HLS nativos da Apple, mas não podemos dizer aos usuários: "por favor, não use o iPhone Mac e o Apple TV para reproduzir fluxos HLS", os usuários não entenderão.


Portanto, quando você tenta reproduzir o fluxo HLS no servidor de Borda, o servidor deve começar imediatamente a retornar segmentos, mas como o fará se não tiver um fluxo? De fato, ao tentar reproduzir um fluxo neste servidor está ausente. A lógica da CDN funciona com o princípio Lazy Loading - não direcionaremos o fluxo para o servidor até que alguém solicite esse fluxo neste servidor. Há um problema com a primeira conexão - o primeiro que solicitou o fluxo HLS do servidor Edge e teve a imprudência de fazer isso com o player nativo da Apple receberá um friso pelo motivo que leva algum tempo para solicitar esse fluxo no servidor Origin, para obtê-lo no Edge e continue com o fatiamento HLS. Mesmo que demore três segundos, o jogador não o salvará. Ele entrará no friso.



Aqui, novamente, duas decisões se aproximam: uma é normal, a outra não é muito. Pode-se abandonar a abordagem Lazy Loading na CDN e enviar tráfego para todos os nós, independentemente de haver ou não espectadores. Uma solução, possivelmente adequada para quem não está limitado em recursos de tráfego e computação. O Origin direcionará o tráfego para todos os servidores de Borda; como resultado, todos os servidores e a rede entre eles serão carregados constantemente. Talvez esse esquema seja adequado apenas para algumas soluções específicas com um pequeno número de fluxos de entrada. Ao replicar um grande número de threads, esse esquema será claramente ineficiente em termos de recursos. E se você se lembra de que estamos apenas resolvendo o “problema da primeira conexão do navegador nativo”, fica claro que não vale a pena.



A segunda opção é mais elegante, mas também alternativa. Damos ao primeiro usuário conectado uma imagem de vídeo, mas ainda não é o fluxo que ele deseja ver - este é um pré-carregador. Como devemos fornecer algo agora e fazê-lo imediatamente, mas não temos o fluxo de origem (ele ainda é solicitado e entregue pela Origin), decidimos pedir ao cliente que espere um pouco e mostre a ele um vídeo do pré-carregador com animação em movimento. O usuário espera alguns segundos, o pré-carregador gira e, quando o fluxo real chega, o usuário começa a mostrar o fluxo real. Como resultado, o primeiro usuário viu o pré-carregador e os subsequentes que se conectaram finalmente viram o fluxo HLS normal vindo da CDN, trabalhando no princípio do Lazy Loading. Problema de engenharia resolvido.


Mas não até o fim


Parece que tudo funciona muito bem. A CDN está funcionando, os fluxos HLS são obtidos dos servidores de borda e o problema da primeira conexão é resolvido. E aqui está outra armadilha: fornecemos o pré-carregador em uma proporção fixa de 16: 9, e a CDN pode incluir fluxos de qualquer formato: 16: 9, 4: 3, 2: 1 (vídeo em VR). E isso é um problema, porque se você der ao pré-carregador um player no formato 16: 9 e o fluxo ordenado estiver no formato 4: 3, o player nativo aguardará novamente o friso.


Portanto, surge uma nova tarefa - você precisa saber com qual proporção o fluxo entra na CDN e fornecer o pré-carregador na mesma proporção. Um recurso dos fluxos WebRTC é a preservação da proporção ao alterar a resolução e durante a transcodificação - se o navegador decide diminuir a resolução, ele a reduz na mesma proporção. Se o servidor decidir transcodificar o fluxo, ele manterá a proporção na mesma proporção. Portanto, é lógico que, se queremos mostrar o pré-carregador para HLS, mostramos na mesma proporção em que o fluxo entra.



A CDN funciona da seguinte maneira: quando o tráfego entra no servidor Origin, ele informa os outros servidores da rede, incluindo os servidores de Borda, sobre o novo fluxo. O problema é que, neste ponto, a resolução do fluxo de origem ainda não pode ser conhecida. A resolução é realizada pelas configurações de fluxo de bits H.264 junto com o quadro-chave. Portanto, pode ser que o servidor de Borda receba informações de que há um fluxo, mas não saberá sobre sua resolução e proporção, o que não permitirá gerar corretamente o pré-carregador. Nesse sentido, é necessário sinalizar a presença de um fluxo na CDN apenas se houver um quadro-chave - isso garante informações ao tamanho do servidor Edge e permite que o pré-carregador correto seja gerado para evitar “o problema do primeiro visualizador conectado”.



Sumário


A conversão do WebRTC para HLS geralmente fornece frisos quando reproduzidos em players nativos da Apple. O problema é resolvido analisando e ajustando o fluxo de bits H.264 aos requisitos de HLS da Apple, transcodificando ou usando a migração para o protocolo RTMP e o codificador como fonte de fluxo. Em uma rede distribuída com carregamento lento de fluxos, há um problema do primeiro visualizador conectado, que é resolvido usando o pré-carregador e determinando a resolução no lado do servidor Origin - o ponto de entrada do fluxo na CDN.


Referências


Servidor de Chamada pela Web - Servidor WebRTC


CDN de fluxo contínuo WebRTC de baixa latência - CDN baseado em WCS


Reproduzir fluxos de vídeo WebRTC e RTMP sobre HLS - Funções de servidor para converter fluxos de várias fontes em HLS

Source: https://habr.com/ru/post/pt480432/


All Articles