El problema del primer espectador, o la difícil conversión de las transmisiones de video WebRTC a HLS


Egor cerró la tapa del portátil y se frotó los ojos rojos por la falta de sueño. "Los clientes continúan quejándose por la congelación de la transmisión, ¡el nuevo fixpack no ayudó en absoluto! Entonces, ¿qué hacer con este HLS (censurado)?" Dijo al vacío del estudio.


El navegador no solo es hipertexto, sino también un transmisor


Los navegadores han adquirido jugadores durante mucho tiempo, pero con un codificador de video y transmisión, la historia es diferente. Ahora, en casi cualquier navegador de la última versión, puede encontrar módulos para codificación, transmisión, decodificación y reproducción. Estas funciones están disponibles a través de la API de JavaScript, y la implementación se llama Web Real Time Communications o WebRTC. Esta biblioteca integrada en los navegadores puede hacer mucho: capturar video de una cámara incorporada, virtual o USB, comprimir con códecs H.264, VP8, VP9, ​​enviarlo a la red a través del protocolo SRTP, es decir. funciona como un codificador de transmisión de video de software. Como resultado, vemos un navegador que tiene algo similar a ffmpeg o gstreamer debajo del capó, que comprime bien el video, transmite en RTP y reproduce transmisiones de video.


WebRTC le da la libertad de implementar una variedad de casos de transmisión en JavaScript:


  • transmita la transmisión desde el navegador al servidor para su grabación y posterior distribución
  • de igual a igual
  • reproducir la transmisión de otro usuario y enviar la suya (video chat)
  • convertir otros protocolos por el servidor, por ejemplo RTMP, RTSP, etc., y jugar en el navegador como WebRTC

Los scripts de control de flujo refinados pueden verse así:


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

HLS funciona donde WebRTC no funciona


WebRTC funciona en las últimas versiones de los navegadores, sin embargo, hay dos de los siguientes factores: 1) No todos los usuarios actualizan los navegadores de manera oportuna y es posible que permanezcan en algún tipo de Chrome durante tres años. 2) Casi una vez a la semana se lanzan actualizaciones y nuevos navegadores, WebView, así como otros clientes y mensajeros instantáneos que pueden navegar por Internet. No hace falta decir que no todos tienen soporte WebRTC, y si lo es, puede truncarse bastante. Mira cómo están las cosas ahora:



Dolor de cabeza por separado: los dispositivos Apple favoritos de todos. Recientemente han recibido soporte para WebRTC y, a veces, son sorprendentes en su comportamiento en comparación con los navegadores webkits ortodoxos. Y donde WebRTC no funciona o no funciona muy bien, HLS funciona bien. En este sentido, se requiere compatibilidad, y algo así como un convertidor que convertirá WebRTC a HLS y lo reproducirá en casi cualquier dispositivo.


Inicialmente, HLS no fue concebido para transmisiones en tiempo real. De hecho, ¿cuál puede ser el tiempo de video a través de HTTP? La tarea de HLS es cortar el video en pedazos y entregárselos al jugador sin problemas, sin prisas, descargándolos uno por uno. El reproductor HLS espera una transmisión de video estrictamente formada y fluida. Y aquí surge un conflicto, ya que WebRTC, por el contrario, puede permitirse perder paquetes debido a requisitos en tiempo real y baja latencia y tener un FPS / GOP flotante y una velocidad de bits variable, para ser exactamente lo contrario de HLS en términos de previsibilidad y dimensionalidad del flujo.


Un enfoque obvio: la desempaquetación de WebRTC (SRTP) y la posterior conversión a HLS, puede no funcionar en el reproductor HLS nativo de Apple o en una forma inadecuada para la producción con frisos. Un jugador nativo aquí significa un jugador que se usa en Apple iOS Safari, Mac OS Safari, Apple TV.


Por lo tanto, si observa el friso HLS en el reproductor nativo, tal vez sea este, y la fuente de la transmisión es WebRTC u otra transmisión dinámica con marcado desigual. Además, en la implementación de reproductores nativos de Apple hay un comportamiento que solo se puede entender empíricamente. Por ejemplo, el servidor debe comenzar a enviar segmentos HLS inmediatamente, inmediatamente después de que se devuelva la lista de reproducción m3u8. El retraso por segundo amenaza con congelarse. Si la configuración del flujo de bits ha cambiado en el proceso (que es una ocurrencia bastante común con la transmisión WebRTC), también habrá un friso.


Lucha contra frisos en jugadores nativos


Por lo tanto, el desempaquetado y empaquetado directo y honesto de WebRTC en HLS generalmente no funciona. En el servidor de transmisión de video del Servidor de llamadas web (WCS) , resolvemos el problema de dos maneras, y ofrecemos el tercero como alternativa:


1) Transcodificación.


Esta es la forma más confiable de alinear el flujo de WebRTC con los requisitos de HLS, establecer el GOP deseado, FPS, etc. Sin embargo, en algunos casos, la transcodificación no es una buena solución, por ejemplo, transcodificar transmisiones de 4k de video VR es una idea regular. Estas transmisiones pesadas son muy caras de transcodificar en términos de tiempo de CPU o recursos de GPU.



2) Adaptación y alineación del flujo de WebRTC sobre la marcha bajo los requisitos de HLS.


Estos son analizadores especiales que analizan el flujo de bits H.264 y lo corrigen para las características / errores de los reproductores nativos de Apple HLS. Aquí debemos admitir que los jugadores no nativos como video.js y hls.js son más tolerantes a las transmisiones con una tasa de bits dinámica y FPS, que es WebRTC y no se ralentiza donde la implementación de referencia de Apple HLS cae esencialmente en congelación perpetua.



3) Use RTMP como fuente de transmisión en lugar de WebRTC.


A pesar de que el flash está retirado, el protocolo RTMP se usa activamente para la transmisión, tome el mismo OBS Studio. Y debo admitir que los codificadores RTMP producen generalmente transmisiones más uniformes que WebRTC y, por lo tanto, prácticamente no producen frisos en HLS, es decir. Convertir RTMP> HLS desde el punto de vista de frisos parece mucho más adecuado, incluso en reproductores nativos de HLS. Por lo tanto, si la transmisión se realiza desde el escritorio y OBS, entonces es mejor usarla para la conversión a HLS. Si la fuente es un navegador Chrome, entonces RTMP no se puede usar sin instalar complementos, y aquí solo WebRTC.



Los tres métodos descritos anteriormente se prueban y funcionan, por lo que existe la oportunidad de elegir según las condiciones de la tarea.


WebRTC a HLS en CDN


Algunos problemas pueden esperar en un sistema distribuido cuando varios servidores de entrega de flujo de WebRTC se encuentran entre la fuente de flujo de WebRTC y el reproductor HLS, es decir, CDN , en nuestro caso, basado en el servidor WCS. Se ve así: hay Origin, un servidor que recibe un flujo de WebRTC, hay Edge, servidores que distribuyen este flujo, incluido HLS. Puede haber muchos servidores, lo que permite el escalado horizontal del sistema. Por ejemplo, se pueden conectar 1000 servidores HLS a un servidor Origin, en este caso la capacidad del sistema se escala 1000 veces.



El problema ya se ha identificado un poco más alto, y este problema generalmente surge en jugadores nativos: iOS Safari, Mac OS Safari, Apple TV. Por nativo queremos decir un jugador que trabaja con una indicación directa de la url de la lista de reproducción en la etiqueta, por ejemplo, <video src="https://host/test.m3u8"/> . Tan pronto como el jugador solicite una lista de reproducción, y esta acción es en realidad el primer paso para reproducir la transmisión HLS, el servidor debe comenzar de inmediato, sin demora, a comenzar a enviar segmentos de video HLS. Si el servidor no comienza a dar segmentos inmediatamente, el jugador decide que fue engañado y deja de jugar. Una vez más, este comportamiento es típico de los reproductores HLS nativos de Apple, pero no podemos decirles a los usuarios: "no utilicen iPhone Mac y Apple TV para reproducir transmisiones HLS", los usuarios no lo entenderán.


Entonces, cuando intentas reproducir la transmisión HLS en el servidor Edge, el servidor debería comenzar a devolver segmentos inmediatamente, pero ¿cómo lo hará si no tiene una transmisión? De hecho, al intentar reproducir una transmisión en este servidor falta. La lógica de CDN funciona según el principio de carga diferida: no llevaremos la transmisión al servidor hasta que alguien solicite esta transmisión en este servidor. Hay un problema con la primera conexión: la primera que solicitó la transmisión HLS del servidor Edge y fue imprudente al hacerlo desde el reproductor nativo de Apple recibirá un friso por la razón que lleva un tiempo ordenar esta transmisión del servidor de origen y obtenerla en Edge y continúe con el corte HLS. Incluso si toma tres segundos, el jugador no lo guardará. Él entrará en el friso.



Aquí nuevamente surgen dos decisiones: una es normal y la otra no. Se podría abandonar el enfoque de carga diferida en el CDN y enviar tráfico a todos los nodos, independientemente de si hay espectadores allí o no. Una solución, posiblemente adecuada para aquellos que no están limitados en tráfico y recursos informáticos. Origin conducirá el tráfico a todos los servidores Edge, como resultado, todos los servidores y la red entre ellos se cargarán constantemente. Quizás este esquema sería adecuado solo para algunas soluciones específicas con un pequeño número de flujos entrantes. Al replicar una gran cantidad de subprocesos, dicho esquema será claramente ineficiente en cuanto a recursos. Y si recuerda que solo estamos resolviendo el "problema de la primera conexión desde el navegador nativo", entonces está claro que no vale la pena.



La segunda opción es más elegante, pero también alternativa. Le damos una imagen de video al primer usuario conectado, pero esta no es la transmisión que quiere ver, es un precargador. Como debemos dar algo ahora y hacerlo de inmediato, pero no tenemos la transmisión de origen (todavía se ordena y se entrega desde Origin), decidimos pedirle al cliente que espere un poco y le muestre un video del precargador con animación en movimiento. El usuario espera unos segundos, el precargador gira y, cuando llega la transmisión real, el usuario comienza a mostrar la transmisión real. Como resultado, el primer usuario vio el precargador, y los posteriores que se conectaron al fin vieron el flujo normal de HLS proveniente de la CDN, trabajando según el principio de carga diferida. Problema de ingeniería resuelto.


Pero no hasta el final


Parece que todo funciona muy bien. CDN funciona, las secuencias HLS se toman de los servidores Edge Edge y se resuelve el problema de la primera conexión. Y aquí hay otro escollo: le damos al precargador en una relación de aspecto fija de 16: 9, y CDN puede incluir transmisiones de cualquier formato: 16: 9, 4: 3, 2: 1 (video VR). Y esto es un problema, porque si le das al jugador un precargador en formato 16: 9, y la transmisión ordenada estará en formato 4: 3, entonces el jugador nativo nuevamente espera el friso.


Por lo tanto, surge una nueva tarea: debe saber con qué relación de aspecto ingresa el flujo a la CDN y le da al precargador en la misma relación. Una característica de las transmisiones WebRTC es la preservación de la relación de aspecto al cambiar la resolución y durante la transcodificación; si el navegador decide reducir la resolución, la reduce en la misma relación. Si el servidor decide transcodificar la secuencia, mantiene la relación de aspecto en la misma proporción. Por lo tanto, es lógico que si queremos mostrar el precargador para HLS, lo muestremos en la misma relación de aspecto en la que ingresa el flujo.



El CDN funciona de la siguiente manera: cuando el tráfico ingresa al servidor de Origin, informa a los otros servidores de la red, incluidos los servidores Edge, acerca de la nueva transmisión. El problema es que en este punto, la resolución de la secuencia fuente aún no se conoce. La resolución es transportada por configuraciones de flujo de bits H.264 junto con el cuadro clave. Por lo tanto, puede suceder que el servidor Edge reciba información de que hay una secuencia, pero no sabrá acerca de su resolución y relación de aspecto, lo que no le permitirá generar correctamente el precargador. A este respecto, es necesario señalar la presencia de una transmisión en la red CDN solo si hay un cuadro clave; esto garantiza garantizar la información del tamaño del servidor Edge y permitir que se genere el precargador correcto para evitar "el problema del primer visor conectado".



Resumen


La conversión de WebRTC a HLS generalmente proporciona frisos cuando se juega en reproductores nativos de Apple. El problema se resuelve analizando y ajustando el flujo de bits H.264 a los requisitos HLS de Apple, ya sea transcodificando o utilizando la migración al protocolo RTMP y al codificador como fuente de flujo. En una red distribuida con carga lenta de secuencias, existe un problema con el primer visor conectado, que se resuelve utilizando el precargador y determinando la resolución en el lado del servidor de origen, el punto de entrada de la secuencia en la CDN.


Referencias


Web Call Server - Servidor WebRTC


CDN de transmisión de baja latencia WebRTC - CDN basado en WCS


Reproduzca transmisiones de video WebRTC y RTMP a través de HLS : funciones del servidor para convertir transmisiones de varias fuentes a HLS

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


All Articles