Assista-me na íntegra: tire o máximo proveito do vídeo ao vivo em plataformas móveis



A maneira mais fácil de reproduzir vídeo em um dispositivo móvel é abrir o link com um player existente no sistema, mas isso nem sempre é eficaz.

Você pode usar o ExoPlayer e otimizá-lo, ou pode até escrever seu próprio player de vídeo usando apenas codecs e soquetes. O artigo falará sobre o trabalho de streaming e reprodução de vídeo e como reduzir o atraso no início do vídeo, reduzir o tempo de resposta entre a serpentina e o espectador e otimizar o consumo de energia e a carga de ferro.

Analisaremos isso usando aplicativos específicos como exemplo: cliente móvel Odnoklassniki (onde os vídeos são reproduzidos) e OK Live (onde as transmissões são transmitidas do telefone para 1080p). Não haverá masterclasses sobre como reproduzir um vídeo por referência, com exemplos de código. A história se concentrará na aparência do vídeo por dentro e em como, conhecendo a arquitetura geral dos players de vídeo e do streaming de vídeo, você pode entender qualquer sistema e torná-lo melhor.

O material é baseado na transcrição do relatório de Alexander Tobol ( @alatobol ) e Ivan Grigoriev ( @ivan_a ) da conferência Mobius .




Entrada


Para começar - alguns números sobre o vídeo em Odnoklassniki.

O pico médio do tráfego diário de VOD (vídeo sob demanda) é de mais de um terço e meio por segundo e para transmissões ao vivo - mais de três terabits por segundo.

Agora, em OK, existem mais de 870 milhões de visualizações de vídeo por dia, mais da metade das quais são de dispositivos móveis.



Se você observar o histórico do streaming, um vídeo para celular apareceu no YouTube em 2007. Entramos nesse trem mais tarde, mas em 2014-2015 já tínhamos reprodução de vídeo em 4K em dispositivos móveis e, nos últimos anos, desenvolvemos ativamente nossos players. Sobre isso e a conversa continuará.

A segunda tendência que surgiu com o Periscope em 2015 foi a transmissão por telefone. Lançamos nosso aplicativo OK Live, que permite transmitir até vídeo Full HD em redes móveis. Na segunda metade do material, também falaremos sobre streaming.

Não vamos nos concentrar na API para trabalhar com vídeo, mas agora mergulhe profundamente e tente descobrir o que está acontecendo lá dentro.



Quando você grava um vídeo em uma câmera, ele chega ao codec, de lá para o soquete e depois para o servidor (independentemente de ser VOD ou Live). E então o servidor na ordem inversa o distribui para o público.

Vamos começar com o KPI player. O que queremos dele?

  • Primeiro quadro rápido. Os usuários não querem esperar o início da reprodução.
  • Falta de buffer. Ninguém gosta de correr para um torso.
  • Alta qualidade. Quando ainda não havia quase nenhum conteúdo em 4K, já fizemos o suporte ao 4K "para o crescimento": se você adiar o player e descobrir o desempenho, o 1080p será reproduzido perfeitamente, mesmo em dispositivos fracos.
  • Requisitos de UX. Precisamos que o vídeo seja reproduzido na fita durante a rolagem e, para a fita, precisamos buscar previamente o vídeo.


Existem muitos problemas dessa maneira. O fluxo de vídeo em 4K é grande e trabalhamos em dispositivos móveis onde há problemas com a rede, há vários recursos de formatos de vídeo e contêineres em diferentes dispositivos, e os próprios dispositivos também podem se tornar um problema.

Onde você acha que o vídeo começa mais rápido, no iOS ou Android?

De fato, qualquer resposta está correta: depende do que, onde e como jogar. Se tomarmos uma região da Rússia com uma rede não tão boa, veremos que o AVPlayer começa em cerca de 800 milissegundos. Mas com a mesma rede, o ExoPlayer no Android, reproduzindo um formato diferente, o iniciará em 660 ms. E se você criar seu player no iOS, ele poderá ser executado ainda mais rápido.



Há uma nuance em que medimos a média dos usuários e a potência média dos dispositivos iOS é maior que no Android.

A primeira parte do material será teórica: aprenderemos o que é o vídeo e como é a arquitetura de qualquer player ao vivo. E na segunda parte, vamos comparar os jogadores e falar sobre quando escrever o seu.

Parte um


O que é vídeo


Vamos começar com o mais básico. O vídeo tem 60 ou 24 fotos por segundo.

Obviamente, armazenar isso com um conjunto completo de fotos é bastante caro. Portanto, eles são armazenados desta maneira: alguns quadros são chamados de quadros de referência (quadros I), enquanto outros (quadros B e quadros P) são chamados de "diffs". Na verdade, você tem um arquivo jpg e um conjunto específico de alterações.



Existe também o conceito de GOP (grupo de imagens) - este é um conjunto independente de quadros, que começa com um quadro de referência e continua com um conjunto de diferenças. Pode ser reproduzido independentemente, desembalado e assim por diante. Ao mesmo tempo, se você perdeu um opornik no grupo, os quadros restantes não são mais relevantes.

Existem muitos algoritmos de codificação, matrizes de transformação, pesquisa de movimento e similares - é nisso que os codecs diferem.

Desempenho do codec





O H.264 clássico é conhecido desde 2003 e se desenvolveu bem. Tomaremos sua eficácia como base. Ele trabalha e toca em todos os lugares. Possui suporte de hardware para CPU / GPU (ambos no iOS, no Android). Isso significa que existe algum tipo de coprocessador especial que pode codificá-lo ou conjuntos de instruções internos que permitem fazer isso rapidamente. Em média, o suporte de hardware oferece desempenho até 10 vezes mais rápido e economiza a bateria.

Em 2010, o VP8 do Google apareceu. Não difere em eficiência do H.264. Bem, na verdade a eficácia do codec é uma coisa muito controversa. Na testa, é medida como a proporção do vídeo original para o compactado, mas é claro que existem diferentes artefatos de vídeo. Portanto, fornecemos um link para comparações detalhadas de codecs da Universidade Estadual de Moscou. Mas aqui nos restringimos ao fato de que o VP8 está focado em uma organização de software, você pode arrastá-lo para qualquer lugar e geralmente é usado como um substituto se não houver suporte H.264 nativo.

Em 2013, uma nova geração de codecs apareceu - H.265 (HEVC) e VP9. O codec H.265 aumenta em 50% a eficiência, mas no vídeo do Android eles não podem ser codificados, o decodificador apareceu apenas no Android 5.0 ou superior. Mas no iOS há suporte.

Existe uma alternativa ao H.265 - VP9. Mesmo assim, mas com suporte do Google. Bem, V9 é o YouTube e H.265 é Netflix. Portanto, cada um tem suas próprias peculiaridades: um não funcionará no iOS, o outro terá problemas no Android. No final, muitos permanecem no H.264.

No futuro, prometemos o codec AV1, ele já possui uma implementação de software e sua eficiência é 35% maior que a dos codecs de 2013. Agora disponível no Chrome e Firefox, e em 2020 o Google promete suporte de hardware - acho que, provavelmente, todos iremos mudar para ele.

Finalmente, eles anunciaram recentemente o codec H.266 / JVEC, dizendo que tudo será melhor e mais rápido.

O padrão principal: quanto maior a eficiência do codec, mais recursos de computação são necessários para os dispositivos.

Em geral, por padrão, todos usam o H.264 e, em dispositivos específicos, pode ser complicado.

Qualidade, resolução e taxa de bits


Em 2019, você não surpreenderá ninguém com qualidade adaptativa: os usuários enviam ou transmitem vídeos em uma qualidade e cortamos uma linha de diferentes qualidades e enviamos as mais adequadas aos dispositivos.

Nesse caso, é necessário que a resolução do vídeo se correlacione com a taxa de bits. Se a resolução for dobrada, a taxa de bits também deverá dobrar:



Obviamente, se você compactar uma resolução grande com uma taxa de bits baixa ou vice-versa, haverá artefatos ou gravação inútil da taxa de bits.

Como a taxa de bits do vídeo codificado se compara à quantidade original de informações? Em uma tela 4K, podemos reproduzir quase 6 Gb / s de informação (se você contar todos os pixels e sua frequência em 60 quadros por segundo), enquanto a taxa de bits do codec pode ser de 50 Mb / s. Ou seja, o codec comprime o vídeo até 100 vezes.

Tecnologia de entrega


Você tem áudio e vídeo compactados com alguns codecs. Se você o mantiver em casa, poderá adicionar todo o áudio e vídeo adicionando um pequeno índice que indica a partir de que segundo o áudio e o vídeo são iniciados. Mas o vídeo não pode ser entregue ao telefone e, para transmitir on-line para o espectador, existem duas classes principais de protocolos: streaming e segmento.



O protocolo de streaming implica que você tem algum tipo de estado no servidor, o cliente também e envia dados. O servidor pode ajustar, por exemplo, a qualidade. Muitas vezes, essa é uma conexão UDP.

Tais protocolos são altamente complexos para o servidor e difíceis de entregar. Para traduções muito carregadas, usamos protocolos segmentados que funcionam sobre HTTP, podem ser armazenados em cache pelo nginx e CDN e são muito mais fáceis de distribuir. E o servidor não é responsável por nada e, nesse caso, sem estado.

Como é a entrega por segmento: cortamos o vídeo existente em segmentos, acompanhamos-os com um cabeçalho para áudio e vídeo, MPEG-TS e MP4 como exemplo de transporte. No telefone, fornecemos um manifesto com informações sobre onde e qual a qualidade do segmento, e esse manifesto pode ser atualizado periodicamente.

Historicamente, a Apple entrega através do HLS e o Android através do DASH. Vamos ver como eles diferem.

Vamos começar com o HLS mais antigo, que possui um manifesto que descreve todas as qualidades disponíveis - baixa, média, alta e assim por diante. Existem taxas de bits dessas qualidades para que o jogador possa escolher imediatamente a correta. Ele escolhe a qualidade e obtém um manifesto aninhado com uma lista de links para segmentos. A duração desses segmentos também é indicada.



Há uma característica interessante aqui: para começar a reproduzir o primeiro quadro, você terá que fazer duas viagens adicionais de ida e volta. A primeira solicitação, você obtém o manifesto principal, o segundo aninhado, e só então acessa os dados, o que não é muito bom.



A segunda dificuldade: o HLS foi projetado para funcionar na Internet via HTTP, mas o MPEG-2 Transport Stream herdado foi escolhido como um contêiner para dados de vídeo, desenvolvido para finalidades completamente diferentes: transmitir um sinal de um satélite em canais ruidosos. Como resultado, obtemos cabeçalhos adicionais, que no caso do HLS são completamente inúteis e apenas acrescentam sobrecarga.



Adicione sobrecarga de rede e a complexidade da análise: se você tentar reproduzir 4K no DASH e HLS no Chrome, sentirá a diferença quando o computador "decolar" com pacotes HLS.

A Apple está tentando resolver isso. Em 2016, eles anunciaram a possibilidade de usar o MPEG-4 fragmentado, havia algum suporte para o DASH no HLS, mas o RTT extra e seus recursos não desapareceram.



O DASH parece um pouco mais simples: você tem um manifesto com todas as qualidades internas e cada qualidade é um conjunto de segmentos. Você pode reproduzir um segmento para reproduzir em uma qualidade e entender que a velocidade aumentou, do próximo segmento para o outro. Todos os segmentos sempre começam com quadros de referência, permitindo a troca.

Aqui está um pequeno prato sobre o que escolher:



No HLS, os codecs de vídeo historicamente suportados são apenas H.264; no MPEG-DASH você pode empurrar qualquer um. O principal problema do HLS é uma viagem de ida e volta extra no início, que funciona bem no iOS e no Android com 4.0. E o DASH é suportado principalmente pelo Google (Chrome e Android) e não pode ser reproduzido no iOS.

Arquitetura do jogador


Classificamos o vídeo mais ou menos, agora vamos ver como é qualquer player.



Vamos começar com a parte da rede: ao iniciar um vídeo, o player segue o manifesto, de alguma forma seleciona a qualidade, depois segue o segmento, baixa-o, depois decodifica os quadros, entende que há quadros suficientes no buffer para reprodução e inicia a reprodução.

A arquitetura geral do jogador:



Há uma parte da rede, um soquete, de onde vêm os dados.

Depois disso - um desmultiplexador ou algum tipo de coisa que obtém fluxos de áudio e vídeo de um transporte (HLS / DASH). Ela os envia para os codecs apropriados.

Os codecs decodificam vídeo e áudio e, em seguida, o mais interessante acontece: eles precisam ser sincronizados para que seu vídeo e áudio sejam reproduzidos simultaneamente. Existem vários mecanismos baseados em timestamps para isso.

Então você precisa renderizá-lo em algum lugar - em Textura, Superfície, GL ou Metal, em qualquer lugar.

E na entrada existe um controle de carga, que carrega os dados e controla o buffer.

Como é o controle de carga em todos os players? Há uma quantidade de dados que precisa ser baixada. O jogador espera até que seja baixado, começa a tocar e fazemos o download. Temos o limite máximo de buffer, ao atingir o qual o download é interrompido. Depois disso, durante a reprodução, a quantidade de dados no buffer cai - e há uma borda mínima na qual ele começa a carregar. Então, tudo isso também vive:



Como é o segmento do loop principal? Os jogadores estão familiarizados com o conceito de "tick thread", parece estar aqui. Há uma parte responsável pela rede que empilha tudo em um buffer. Existe um extrator que descompacta e envia para os codecs, onde seu buffer intermediário e depois processa. E você tem uma marca que muda e controla, lida com a sincronização.



Lá fora, você tem um aplicativo que envia alguns comandos através de uma fila de mensagens e recebe algumas informações através dos ouvintes. E, às vezes, a pressão de retorno pode aparecer, o que reduz a qualidade - por exemplo, em uma situação em que seu buffer se esgota ou a renderização não consegue lidar (por exemplo, soltar quadros aparecem).

Estimador


Ao se adaptar, o reprodutor conta com 2 parâmetros principais: velocidade da rede e buffer de dados.

Como fica: primeiro, uma certa qualidade é reproduzida, por exemplo, 720p. Você tem um buffer crescente, armazenando em cache cada vez mais. Então a velocidade aumenta, você entende que pode baixar ainda mais, o buffer aumenta. E neste momento você entende que está pisando em alguns limites do buffer mínimo quando pode experimentar a seguinte qualidade.



É claro que você precisa tentar com cuidado: também existe um estimador que diz se você pode obter essa qualidade em termos de velocidade da rede. Se você se encaixa nessa avaliação e o estoque de buffer permite, então você muda, por exemplo, para 1080p e continua a jogar.

Proteção contra sobre pressão


Com a gente, ela apareceu ao longo do tempo através de tentativa e erro. A necessidade disso surge quando você sobrecarrega levemente seu equipamento.

Há uma situação em que a rede fica entorpecida durante a reprodução ou os recursos acabam no back-end. Quando o reprodutor retoma a reprodução, ele começa a recuperar o atraso.

Um grande conjunto de segmentos se acumulou no manifesto do player nesse momento, ele os baixa rapidamente de uma só vez e temos um "golpe de trânsito". A situação pode ser agravada se ocorrer um tempo limite nos clientes e o player começar a consultar novamente os dados. Portanto, é imperativo fornecer contrapressão no sistema.

A primeira maneira simples que, é claro, usamos é o acelerador no servidor. Ele entende que o tráfego acaba, reduz a qualidade e desacelera deliberadamente os clientes, para não ser atingido.



Mas isso não afeta muito bem os estimadores. Eles podem gerar as mesmas "reviravoltas". Portanto, se possível, apoie a remoção da qualidade do manifesto. Para fazer isso, você deve atualizar periodicamente o manifesto ou, se houver um canal de feedback, dar o comando para remover a qualidade e o player mudará automaticamente para outro, mais baixo.

Jogadores


No iOS, existe apenas o AVPlayer nativo, mas no Android há uma opção. Existe um MediaPlayer nativo, mas existe um ExoPlayer de código aberto baseado em Java que os aplicativos "trazem com eles". Quais são os seus prós e contras?

Compare todos os três:



No caso de streaming adaptável, o ExoPlayer reproduz o DASH / HLS e possui muitos módulos expansíveis para outros protocolos, enquanto o AVPlayer está piorando.

O suporte para versões do sistema operacional, em princípio, atende a todos os lugares.

A pré-busca ocorre quando você sabe que após o final de um vídeo deseja reproduzir o seguinte na fita e pré-carregá-lo.

Há um problema com correções de bugs de jogadores nativos. No caso do ExoPlayer, basta transformá-lo em uma nova versão do seu aplicativo, mas no AVPlayer nativo e no MediaPlayer o bug será corrigido apenas na próxima versão do sistema operacional. Nos deparamos com isso dolorosamente: no iOS 8.01, nosso vídeo começou a ser ruim, no iOS 8.02 o portal inteiro parou de funcionar, no 8.03 tudo funcionou novamente. E nada dependia de nós, neste caso, apenas nos sentamos e esperamos a Apple lançar a próxima versão.

A equipe do ExoPlayer fala sobre a ineficiência do consumo de energia no caso do áudio. Existem recomendações gerais do Google: para reproduzir áudio, use o MediaPlayer, para todo o resto do Exo.

Entendido, usaremos o ExoPLayer com DASH para vídeo no Android e o AVPlayer com HLS no iOS.

Primeiro quadro rápido


Novamente, lembre-se do tempo até o primeiro quadro. Como fica no iOS HLS: primeiro RTT atrás do manifesto, depois outro RTT atrás do manifesto aninhado, só então - obtendo o segmento e reproduzindo. No Android, um RTT é menor, ele começa um pouco melhor.



Tamanho do buffer


Agora vamos lidar com os buffers. Temos uma quantidade mínima de dados que precisam ser baixados antes de começarmos a jogar. No AVPlayer, esse valor é configurado usando o AVPlayerItem preferidoForwardBufferDuration.



No Android, o ExoPlayer possui muito mais mecanismos de configuração. Existe o mesmo buffer mínimo necessário para iniciar. Mas há também uma configuração separada para rejeitar (se sua rede cair, os dados do buffer acabarão e, em seguida, retornarão):



Qual é o lucro? Se você tem uma boa rede, inicia e luta rapidamente por um primeiro quadro rápido; pela primeira vez, pode tentar arriscar. Mas se a rede interromper durante a reprodução, é óbvio que você precisará solicitar mais buffer para reproduzir durante a rejeição, para que não haja problemas repetidos.

Qualidade original





O HLS no iOS tem um problema interessante: ele sempre começa a ser reproduzido a partir da primeira qualidade no manifesto m3u8. O que você devolver a ele começará. E só então ele medirá a velocidade do download e começará a tocar com qualidade normal. É claro que isso não deve ser permitido.

Otimização lógica - re-classifique a qualidade. No servidor (adicionando um parâmetro adicional à qualidade preferencial, ele classifica novamente o manifesto) ou no cliente (crie um proxy que faça isso por você).

E no Android, há um parâmetro DefaultBandwidthMeter para isso. Ele fornece um valor que considera a largura de banda padrão da sua banda.



Como funciona: há uma enorme tabela de constantes no código, e os parâmetros são simples - o país (região) e o tipo de conexão (wi-fi, 2G, 3G, 4G). Quais são os significados? Por exemplo, se você possui Wi-Fi e está localizado nos EUA, sua largura de banda inicial é de 5,6 Mbps. E se 3G é de 700 kbps.

Pode-se ver que, de acordo com as estimativas do Google, o 4G na Rússia é 2-3 vezes mais rápido que nos Estados Unidos.

, — , . , , , , .

, , , , . , ( Android ).


(seek), , . , , , .



, , - . iOS, , , , ( , , ).

ExoPlayer 2.7.0 , , « ». . , .



( , ), - , Android prepare(mediaSource), seekTo(). , , , . — :



, ( , ), . ( 100 ), , .




iOS , Android legacy-.
TextureView. , , , , UI. — .

SurfaceView. , . Android- . YouTube , .

GLSurfaceView — . , .



: , ExoPlayer, 23%. «» 10%. 4% . 4% — , .

: Android


  • MediaPlayer , ExoPlayer
  • start, seek, swap
  • ,
  • view

: iOS


iOS :

  • RTT HLS AVPlayer
  • AVPlayer#pause
  • — , iOS


DASH-, « live-». :

  • cURL GCDAsyncSocket
  • AVAssetReader,
  • CADisplayLink
  • AVSampleBufferDisplayLayer


, . 28%, «» 6%. , HLS DASH 100 /, 6%.

iOS :

  • start seek
  • HLS over Fragmented mp4
  • DASH-


, .

:


, , .

  • ( mp4)
  • (ExoPlayer, AVPlayer)
  • firstFrame, seek, emptyBuffer
  • ( )
  • - , . 4, : performance, , .


— .

:


, ?



API . API iOS Android, — , .

: - wrapper , POSIX-, , .

?

  • Início rápido


?

  • bandwidth
  • (N x RTT, RTT)






— . , , .

: , , . — low latency.

, — . .

— 4K. , , . , 30 , . , .


, , , . ( 100 ).

- , , .

. 100 , . , 300 kbps FullHD- 480p, FullHD . , : , , overhead-. .

:



, , . , - , , .

MediaCodec VideoToolbox ( ). Server Transcoder.

— , .


Quando começamos a nos aprofundar no streaming, encontramos um certo número de compromissos. Em particular, há um triângulo nos cantos em que confiabilidade é confiabilidade (sem quedas), rendimento é largura de banda (quanto usamos a rede) e baixa latência é baixa latência (obtemos baixa latência).



Se começarmos a otimizar um desses parâmetros, o resto inevitavelmente falhará. Não podemos conseguir tudo de uma vez, temos que sacrificar alguma coisa.

Protocolos


Os protocolos que veremos hoje: RTMP e WebRTC são protocolos padrão, OKMP é o nosso protocolo personalizado.

Vale ressaltar que o RTMP é executado sobre o TCP e os outros dois no UDP.

RTMP


O que ele dá? De certa forma, esse é um padrão suportado por todos os serviços - YouTube, Twitch, Flash, OK. Eles o usam para que os usuários possam fazer upload de transmissões ao vivo. Se você deseja transmitir uma transmissão ao vivo para algum serviço de terceiros, provavelmente precisará trabalhar com o RTMP.

O atraso mínimo que conseguimos obter de uma unidade de fita para um reprodutor é de 300 ms, mas está em uma rede ideal quando o tempo está bom. Quando temos uma rede real, o atraso geralmente aumenta para 2 a 3 segundos e, se tudo estiver ruim com a rede, pode aumentar para dezenas de segundos.

O RTMP oferece suporte à alteração da resolução e da taxa de bits em tempo real (os outros protocolos mencionados são os mesmos, mas há informações errôneas sobre o RTMP de que não há alterações em andamento).

Das desvantagens: construídas no TCP (explicaremos mais tarde por que isso é ruim), o atraso não é controlado.

Se você observar o triângulo, o RTMP não poderá fornecer baixa latência. Pode ser obtido, mas não garantido.

Além disso, o RTMP é uma porcaria: não suporta novos codecs, já que a Adobe não faz isso, e a documentação é bastante antiga e torta.



Por que o TCP não é adequado para transmissões ao vivo? O TCP oferece uma garantia de entrega: os dados que você coloca no soquete serão entregues exatamente na ordem e na forma em que você os coloca lá. Nada será descartado ou reorganizado. O TCP fará isso ou morrerá. Mas isso significa que uma garantia de atraso é excluída - ele não poderá descartar dados antigos, que talvez já não precisem ser enviados. O buffer, os pedidos em atraso e assim por diante começam a crescer.



Como ilustração, o problema de bloqueio do chefe de linha. É encontrado não apenas no streaming, mas também em muitos outros casos.

O que é isso Temos um buffer receptor inicialmente vazio. Estamos recebendo dados de algum lugar: muitos dados e muitos pacotes IP. Recebemos o primeiro pacote IP e, no receptor, usando o método recv (), podemos subtrair esse pacote, obter dados, perder, renderizar. Mas, de repente, o segundo pacote foi perdido. O que acontece depois?

Para recuperar um pacote IP perdido, o TCP deve retransmitir. Para que isso aconteça, você precisa gastar RTT, enquanto a retransmissão também pode ser perdida, e nós iremos em ciclos. Se houver muitos pacotes, isso definitivamente acontecerá.

Depois disso, existem muitos dados que não podemos ler, porque estamos aguardando o segundo pacote. Embora ele tenha mostrado um quadro de transmissão que aconteceu cinco minutos atrás e não é mais necessário.

Para entender outro problema, vejamos a adaptação do RTMP. Fazemos a adaptação no lado do remetente. Se a rede não puder empilhar dados na velocidade com que são inseridos no soquete, o buffer é preenchido e o soquete diz EWOULDBLOCK ou é bloqueado se o bloqueio for usado neste momento.



Somente neste momento entendemos que temos problemas e precisamos reduzir a qualidade.

Digamos que temos uma rede com uma velocidade específica de 4 Mbps. Escolhemos um tamanho de soquete de 250 KB (correspondente a 0,5 segundos em nossa velocidade). De repente, a rede falhou 10 vezes - esta é uma situação normal. Temos 400 kbps. O buffer encheu-se rapidamente em meio segundo, e somente nesse momento entendemos que precisamos desligar.



Mas agora o problema é que temos um buffer de 250 KB que será transmitido por 5 segundos. Já estamos completamente atrasados: precisamos empurrar os dados antigos primeiro, e somente então os novos e adaptados serão atualizados em tempo real.

O que fazer Aqui o nosso "triângulo de compromissos" é apenas relevante.



  • Podemos reduzir o buffer do remetente, colocar em vez de 0,5 s - 0,1 s. Mas estamos perdendo largura de banda, pois frequentemente entramos em pânico e diminuímos. Além disso, o TCP funciona de tal maneira que, se você colocar um buffer de remetente menor que o RTT, não poderá usar toda a largura de banda do canal, diminuirá várias vezes.
  • Nós podemos aumentar o buffer do receptor. Com um buffer grande, os dados chegam, podemos atenuar algumas irregularidades no buffer. Mas, é claro, estamos perdendo baixa latência, pois montamos imediatamente um buffer de 5 segundos.
  • Podemos eliminar agressivamente dados antigos. No TCP, a única opção para isso é interromper a conexão e recriá-la. Perdemos a confiabilidade, porque neste momento o jogador não tem nada para mostrar.


WebRTC


Esta é uma biblioteca C ++ que já leva em conta a experiência e é executada sobre o UDP. Constrói em iOS, Android, é incorporado em navegadores, suporta HTML5. Como está preso para chamadas P2P, o atraso é de 0,1 a 1 segundo.



Dos pontos negativos: esta é uma biblioteca monolítica com uma abundância de legados que não podem ser removidos. Além disso, devido ao seu foco nas chamadas P2P, ele prioriza a baixa latência. Parece que queríamos isso, mas, por causa disso, ela sacrifica outros parâmetros. E não há configurações para alterar prioridades.

Também deve-se ter em mente que a biblioteca é orientada ao cliente para uma conversa entre dois clientes sem um servidor. Você precisa procurar um servidor de terceiros ou escrever o seu.

O que escolher - RTMP ou WebRTC? Implementamos os dois protocolos e os testamos em diferentes cenários. No gráfico, o WebRTC tem um atraso baixo, mas um rendimento baixo, enquanto o RTMP tem o oposto. E entre eles há um buraco.

E queríamos criar um protocolo que cubra completamente esse buraco e possa funcionar tanto no WebRTC quanto no modo RTMP. Eles criaram e deram o nome de OKMP.


Okmp


Este é um protocolo flexível para UDP.

Suporta multiplexação. O que isso significa: existem vários canais dentro da sessão (no caso do OK Live - o gerente, áudio e vídeo). Dentro de cada canal, os dados são garantidos para serem entregues em uma determinada ordem (mas eles não são garantidos para serem entregues), e a ordem entre os canais não é garantida, pois não é importante.

O que isso dá? Primeiro, nos deu a oportunidade de priorizar os canais. Podemos dizer que o canal de controle tem alta prioridade, o som é médio e o vídeo é baixo. É mais fácil disfarçar a instabilidade de vídeo e a exibição irregular de vídeo, e o usuário tem menos problemas com problemas de vídeo do que com a desagradável interrupção do áudio.



Além disso, nosso protocolo possui uma garantia de entrega opcional. Podemos dizer que em um determinado canal trabalhamos no modo TCP, com entrega garantida, e no restante permitimos algumas quedas.

Graças a isso, uma garantia de atraso pode ser feita: não há garantia de atraso no canal TCP, mas nos outros onde as gotas são permitidas, é definido um limite, após o qual os dados começam a cair e paramos de fornecer dados antigos.

Por exemplo, para áudio, isso é 1 segundo e, para vídeo, 0,5 segundos. Por que o limite é diferente? Esse é outro mecanismo de priorização. Como é mais importante para nós que o áudio seja suave, começamos a soltar o vídeo antes de tudo.

Nosso protocolo é configurado com flexibilidade: não existe um modo de operação único, alteramos as configurações rapidamente para alternar para o modo desejado sem efeitos visíveis para o usuário. Porque Por exemplo, para as mesmas videochamadas: se uma videochamada iniciar em um fluxo, transferimos-a silenciosamente para o modo de baixa latência. E, em seguida, volte ao modo de taxa de transferência para obter a máxima qualidade.
Dificuldades de implementação



Obviamente, se você decidir escrever seu protocolo no UDP, encontrará alguns problemas. Usando o TCP, obtemos mecanismos que teremos que escrever no UDP:

  • Embalagem / despacketizing. Você precisa cortar os dados em pacotes de aproximadamente 1,5 KB de tamanho para que eles se encaixem na rede MTU.
  • Reordenação. Você envia pacotes em um pedido e eles são reorganizados no caminho e vêm em outro. Para superar isso, você precisa definir a sequência com o número da embalagem e reorganizá-las no receptor.
  • Perdas. Claro, há perdas. Quando ocorre uma perda, o destinatário deve informar ao remetente separadamente que "eu recebi esses pacotes, mas não os recebi" e o remetente deve retransmitir os pacotes ausentes. Ou largue-os.
  • Controle de fluxo Se o Receptor não receber dados, não acompanhar a velocidade com que o empurramos, os dados podem começar a se perder, devemos processar essa situação. No caso do TCP, o soquete de envio será bloqueado e, no caso do UDP, não será bloqueado, você deve entender que o receptor não está recebendo dados e reduzir a quantidade de dados enviados.
  • Controle de congestionamento. Uma coisa semelhante, somente nesse caso a rede morreu. Se enviarmos pacotes para a rede falecida, destruiremos não apenas nossa conexão, mas também as vizinhas.
  • Criptografia Precisa cuidar da criptografia
  • ... e muito mais


OKMP vs RTMP


O que obtivemos quando começamos a usar o OKMP em vez do RTMP?

  • O aumento médio na taxa de bits do OKLive é de 30%.
  • Tremulação (medida da chegada desigual de pacotes) - 0% (em média, o mesmo).
  • Áudio de jitter - -25%
  • Vídeo de instabilidade - 40%


Mudanças em áudio e vídeo - demonstração de prioridades em nosso protocolo. O áudio dá uma prioridade mais alta e começou a ficar mais suave devido ao vídeo.

Como escolher um protocolo para streaming





Se você precisar de baixa latência - WebRTC.

Se você quiser trabalhar com serviços externos, publicar vídeos em serviços de terceiros, precisará usar o RTMP.

Se você deseja um protocolo personalizado para seus scripts - implemente o seu.

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


All Articles