Transmisión en vivo HTML5 con MPEG-DASH



Streaming a navegadores sin depender de servicios de tercerosCuando mi iglesia comenzó a transmitir nuestros servicios en vivo en línea, fuimos con YouTube. Como era gratuito y fácil de configurar, era una elección obvia. Pero durante los meses que lo usamos surgieron algunos problemas. El audio y el video con frecuencia no están sincronizados, a pesar de los interminables ajustes y cambios del codificador. Además, crear y configurar nuevos eventos cada semana fue una molestia.Una vez que descubrimos que YouTube no satisfaría nuestras necesidades, comencé a buscar otras opciones. Otros servicios de transmisión probablemente tendrían problemas similares, dando poco control de la canalización de codificación del lado del servidor. Varias soluciones llave en mano alojadas estaban disponibles, pero como geek de FOSS quería ver qué soluciones de código abierto estaban disponibles.

Como parte del alejamiento de los complementos del navegador como Flash, Motion Picture Experts Group (MPEG) desarrolló una nueva técnica de transmisión de medios: DASH , Dynamic Adaptive Streaming over HTTP. DASH funciona con casi todos los navegadores a través del reproductor dash.js . (Apple obtuvo otra marca negra en mi libro al no admitir DASH en iOS, lo que requiere un respaldo al protocolo HLS similar pero más feo de Apple ). Estas dos piezas de software, junto con FFmpeg (o Gstreamer si se desea), se unen para formar una solución eficaz de transmisión en vivo basada en navegador.

Visión de conjunto

Un poco sobre DASH

DASH funciona tomando una transmisión de medios entrantes y dividiéndola en fragmentos, luego mantiene un índice de fragmentos para que los espectadores los descarguen en secuencia. (El HLS de Apple funciona de manera muy similar, pero almacena el índice en un formato diferente). Una de las características más interesantes de DASH es la transmisión adaptativa, si se configura con varias copias de una transmisión a diferentes velocidades de bits (o tamaños), cambiará automáticamente las velocidades de bits para evitar que la transmisión se detenga en el búfer. Si bien YouTube y otros servicios de renombre han tenido esta característica durante mucho tiempo, no es tan común en las soluciones de transmisión de código abierto.

Software de transmisión: FFmpeg

La primera pieza de este sistema de transmisión es el software de transmisión. Existen muchas opciones, tanto de código abierto como propias, pero para esta guía usaré FFmpeg.
FFmpeg es una navaja suiza multimedia que captura, convierte y transmite casi todos los formatos bajo el sol. Es una herramienta increíblemente poderosa, pero también es algo difícil de usar debido a su interfaz de línea de comandos y una gran cantidad de opciones.
Utilizo FFmpeg porque es una de las pocas herramientas que permite la codificación simultánea a diferentes velocidades de bits, por lo que en lugar de enviar una sola transmisión y luego volver a codificar en el servidor, envío varias transmisiones desde el cliente, lo que reduce la carga de trabajo del servidor y evita la pérdida de calidad causado al volver a codificar la secuencia. Sin embargo, la PC de transmisión necesita suficiente potencia de procesamiento y ancho de banda de Internet.

Software de transmisión: Gstreamer

A pesar de su genialidad, a veces FFmpeg no es suficiente. Después de escribir esta guía, trasladé las tareas de transmisión de video de mi iglesia de una PC con procesador Intel i7 a una caja de servidor con cuatro CPU AMD Opteron de 12 núcleos. A pesar de la abundancia de potencia de procesamiento, FFmpeg no pudo gestionar ni siquiera una transmisión de calidad media, debido a la multiprocesamiento ineficiente. El mayor grado de control de Gstreamer me permitió establecer una tubería que mejor utilizaba el poder del Opteron.
Gstreamer es un marco multimedia de código abierto que funciona conectando elementos juntos en una tubería para realizar tareas. El conocimiento de cómo funciona la codificación de medios y la muxing es necesario para crear una tubería útil, FFmpeg es generalmente más simple de usar.

El servidor: nginx-rtmp

nginx-rtmp es un módulo para el popular servidor web nginx . El módulo recibe la transmisión (o transmisiones, en caso de transmisión adaptativa) del software de transmisión y la divide en fragmentos adecuados para la transmisión DASH. Estoy usando esta bifurcación del módulo que tiene soporte de transmisión adaptativo adicional.

El jugador: dash.js

dash.js se ejecuta en el navegador del espectador, descargando y reproduciendo los fragmentos generados por nginx-rtmp. Es bastante sencillo incrustar y usar en un sitio web existente.

Configurando nginx-rtmp

Requisitos

nginx-rtmp tiene bajos requisitos de recursos, por ejemplo, la instalación de mi iglesia está alojada en el plan de nivel más bajo de Digital Ocean y ejecuta nuestras tres transmisiones de calidad diferente sin problemas. Sin embargo, un servidor debe tener una buena conexión a Internet, ya que la transmisión de video requiere bastante ancho de banda. Como los fragmentos de video se almacenan en el disco, se recomienda una SSD.
Cualquier distribución moderna de Linux debería funcionar como servidor, pero para este documento asumiré Ubuntu Server 16.04 LTS. Para los fines de esta guía, también asumiré que el servidor está dedicado a ejecutar solo nginx-rtmp, si está utilizando el mismo servidor para otros fines, deberá ajustar un poco las instrucciones.

Instalar nginx-rtmp

Si está ejecutando Ubuntu 16.04, simplemente copie y pegue lo siguiente (como root):
apt-get build-dep nginx
apt-get source nginx
git clone https://github.com/ut0mt8/nginx-rtmp-module/
cd nginx-1.10.0
./configure --add-module=../nginx-rtmp-module
make
make install
wget https://isrv.pw/html5-live-streaming-with-mpeg-dash/nginx.service.txt -O /lib/systemd/system/nginx.service
systemctl daemon-reload
systemctl enable nginx.service
Esto instalará nginx con nginx-rtmp para /usr/local/nginx, luego configurará systemd para iniciarlo en el arranque.

Configuración

El primer paso es configurar SSL / TLS. Si el sitio web que mostrará la transmisión no usa HTTPS, entonces se puede omitir este paso, sin embargo, dado que la mayoría de los navegadores están restringiendo la compatibilidad con el tráfico no encriptado, recomiendo usar HTTPS.
Let's Encrypt es un servicio que proporciona certificados SSL / TLS. Todo lo que necesitas es un nombre de dominio que apunte a tu servidor. (La adquisición y configuración de un nombre de dominio está fuera del alcance de este documento). Generalmente, querrá un subdominio del nombre de dominio de su sitio web, por ejemplo, si su sitio web está en example.comel servidor nginx-rtmp estaría en video.example.comlive.example.com.
Primero, instale el cliente Let's Encrypt con apt-get install letsencryptLuego, detenga nginx con y systemctl stop nginx.serviceluego obtenga su certificado ejecutándose letsencrypt certonlySiga las indicaciones e ingrese su nombre de dominio cuando se le solicite. Una vez que el cliente finaliza, estás listo para ir al siguiente paso.
La configuración de nginx-rtmp es algo complicada, aquí está la configuración de mi iglesia como punto de partida:
pid /run/nginx.pid;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    sendfile        on;    
    keepalive_timeout  65;

    server {
        listen 80;
        server_name <your_server_domain_here>;
        return 301 https://$host$request_uri;
    }

    server {
        listen       443 ssl;
        server_name  <your_server_domain_here>;

        ssl_certificate /etc/letsencrypt/live/<your_server_domain_here>/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/<your_server_domain_here>/privkey.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security max-age=15768000;

        client_max_body_size 128M;

        add_header Access-Control-Allow-Origin * always;
        add_header Cache-Control no-cache always;

        # Redirect this domain to a different URL
        location / {
            root   html;
            return 301 <your_redirect_here>;
        }

        # Return an empty response, used by dash.js to sync with server time
        location /time {
            return 200;
        }

        # DASH files
        location /dash {
            root /tmp;
        }

        # HLS files
        location /hls {
            root /tmp;
        }
    }
}

rtmp {
    server {
        listen 1935;
        chunk_size 4096;

        publish_time_fix off;

        application dash {
            live on;
            record off;
            allow publish <your_sender_ip_here>;
            allow publish 127.0.0.1;
            deny publish all;

            # Copy incoming streams to the HLS application
            exec ffmpeg -re -i rtmp://localhost:1935/$app/$name -c:v copy -c:a copy -f flv rtmp://localhost:1935/hls/${name};

            dash on;
            dash_nested on;
            dash_path /tmp/dash;
            dash_fragment 3;
            dash_playlist_length 120;
            dash_cleanup on;

            dash_clock_compensation http_head;
            dash_clock_helper_uri https://<your_server_domain_here>/time;

            dash_variant _low   bandwidth="500000"  width="640"  height="360";
            dash_variant _med  bandwidth="1500000" width="1280"  height="720";
            dash_variant _high bandwidth="5000000" width="1920" height="1080" max;
        }

        application hls {
            # I despise iOS devices!
            live on;
            hls on;
            hls_path /tmp/hls;
            hls_nested on;

            hls_variant _low   BANDWIDTH=500000;
            hls_variant _med  BANDWIDTH=1500000;
            hls_variant _high BANDWIDTH=5000000;
        }
    }
}
Copie esta configuración en /usr/local/nginx/conf/nginx.conf, reemplazando el contenido predeterminado del archivo. Reemplace todas las instancias de <your_server_domain_here>con el nombre de dominio de su servidor, y reemplace la instancia de <your_redirect_here>con una URL a su sitio web, en el caso improbable de que los usuarios naveguen hacia el dominio del servidor de video.
Reemplace <your_sender_ip_here>con la dirección IP del remitente del flujo. Puede agregar varias allow_publishlíneas para permitir el envío desde múltiples IP.
Las líneas dash_varianthls_variantpueden modificarse con la velocidad de bits (en bits por segundo) y la resolución de cada una de las cualidades de su flujo. Puede tener tan pocas o tantas transmisiones de velocidad de bits diferente como desee.

Enviar la transmisión con FFmpeg

Esta es la pieza más compleja y vital del sistema de transmisión. Aquí está la línea de comando FFmpeg que usó mi iglesia:
ffmpeg -re -i "Test Video.mp4" \
    -c:a aac -ac 2 -b:a 128k -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset ultrafast -tune zerolatency -vsync cfr -x264-params "nal-hrd=cbr" -b:v 500k -minrate 500k -maxrate 500k -bufsize 1000k -g 60 -s 640x360 -f flv rtmp://example.com/dash/streamname_low \
    -c:a aac -ac 2 -b:a 128k -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset ultrafast -tune zerolatency -vsync cfr -x264-params "nal-hrd=cbr" -b:v 1500k -minrate 1500k -maxrate 1500k -bufsize 3000k -g 60 -s 1280x720 -f flv rtmp://example.com/dash/streamname_med \
    -c:a aac -ac 2 -b:a 128k -c:v libx264 -pix_fmt yuv420p -profile:v baseline -preset ultrafast -tune zerolatency -vsync cfr -x264-params "nal-hrd=cbr" -b:v 5000k -minrate 5000k -maxrate 5000k -bufsize 10000k -g 60 -s 1920x1080 -f flv rtmp://example.com/dash/streamname_high 
Este comando reproducirá el archivo de video Test Video.mp4, lo codificará en tres cualidades diferentes y lo enviará a rtmp://example.com/dash/streamnamePuede adaptar este comando a sus propósitos reemplazándolo example.comcon el nombre de dominio de su servidor nginx-rtmp y reemplazándolo streamnamecon cualquier nombre de flujo deseado. Debe usar las mismas terminaciones variantes (en este ejemplo _low_med_high) que usó en la configuración nginx-rtmp de la sección anterior. Puede tener conjuntos de secuencias múltiples siempre que tengan nombres de secuencias diferentes.
La transmisión en vivo de un archivo de video pregrabado no es muy útil, excepto para las pruebas. La primera línea del comando se puede modificar para especificar cualquier tipo de entrada compatible con FFmpeg , hay muchos de ellos.
Usamos una Mini grabadora Blackmagic Decklink que recibe la alimentación de nuestro mezclador de video:
ffmpeg -f decklink -rtbufsize 702000k -deinterlace -i "DeckLink Mini Recorder@11" \
En sistemas basados ​​en Linux, puede capturar video desde una cámara web con:
ffmpeg -f v4l2 -i /dev/video0

Usando Gstreamer

Para un mayor control sobre la canalización de codificación y transmisión (o si FFmpeg no satisface sus necesidades), Gstreamer también se puede utilizar para alimentar video a nginx-rtmp. Un manual de Gstreamer está fuera del alcance de esta guía, pero aquí está el script Python / Gstreamer que mi iglesia está usando ahora, que debería ser un punto de partida decente.
Tendrá que reemplazar videotestsrcaudiotestsrccon los elementos apropiados para su fuente de medios deseada, Gstreamer tiene muchos de ellos.

Reproduciendo la transmisión usando dash.js

Tus URL de transmisión

Una vez que FFmpeg envíe la transmisión, estará disponible a través de DASH y HLS. Para DASH, la URL será https://<your_domain>/dash/<streamname>.mpdCada calidad de transmisión está disponible por separado en https://<your_domain>/dash/<streamname>_<quality>/index.mpd, lo que es útil para verificar cada velocidad de bits de transmisión para garantizar que tengan una calidad aceptable. Para HLS, la URL será https://<your_domain>/hls/<streamname>.m3u8.

El jugador de referencia DASH-IF

DASH-IF (el Foro de la Industria de DASH) proporciona un reproductor dash.js de referencia , que es muy útil para probar su transmisión. Simplemente ingrese la URL de su transmisión y haga clic en "Cargar".

Código para incrustar

Para incrustar dash.js en su sitio web, use el siguiente HTML y Javascript:
<video id="live-video" poster="<poster_image_here>" controls />

<script src="https://cdnjs.cloudflare.com/ajax/libs/dashjs/2.4.1/dash.all.min.js"></script>

<script>
document.addEventListener("DOMContentLoaded", function (event) {
    var video_element = document.getElementById('#live-video');

    if (window.MediaSource) {
        // For good web browsers, use dash.js

        player = dashjs.MediaPlayer().create();
        player.initialize(video_element, null, true);                    
        player.setFastSwitchEnabled(true);

        player.attachSource("<your_dash_stream_url>");
    } else {
        // For Safari on iOS, use HLS

        video_element.src = "<your_hls_stream_url>";
    }
});
</script>
Este fragmento comprueba si el navegador admite DASH e inicializa el reproductor dash.js, o vuelve a HLS si DASH no es compatible. Reemplace <your_dash_stream_url><your_hls_stream_url>con sus URL de transmisión DASH y HLS como se describe en la sección anterior. (Deje las comillas dobles circundantes intactas, es decir "https://example.com/dash/streamname.mpd").

Resumen

Después de completar los pasos anteriores, debe tener una configuración de transmisión en vivo autohospedada en funcionamiento. Si tiene algún problema o tiene alguna pregunta, no dude en dejarme un mensaje en los comentarios a continuación.

Comentarios

Entradas más populares de este blog

Stalker / Ministra Middleware install script for Debian and Ubuntu Distros

IPTV CANALES DOMINICANOS

How To Setup Linux Media Server Using Jellyfin