Este fin de semana he estado entretenida montando un par de ejemplos con el servidor Nginx, el módulo que dispone este para el protocolo RTMP, y con el módulo de Kaltura para VoD, muy utilizados en el mundo media. Como no quería montarme una máquina para hacer mis pruebas, me he creado un par de contenedores Docker, uno para Live Streaming y otro para Video On Demand y los he desplegado en Azure Container Instances. Hoy quiero compartir contigo el que he usado para los eventos en directo, por si te fuera de utilidad.
nginx.conf
Para el video en directo, o Live Streaming, me he inspirado en este artículo donde un arquitecto de Nginx nos cuenta la configuración mínima necesaria para este escenario. En mi ejemplo, he habilitado además la opción record all para que se guarde todo lo que se reproduzca, ubicándolo en la carpeta /recordings y transformándolo a formato MP4 cuando termine la ingesta.
worker_processes auto;
events {
worker_connections 768;
}
rtmp{
server{
listen 1935;
#rtmp endpoint /live
application live{
live on;
record all;
record_path /recordings;
record_unique on;
# convert recorded file to mp4 format
exec_record_done ffmpeg -i $path -c copy $dirname/$basename.mp4;
#optimization for video and audio in the same package
interleave on;
#HLS for iOs/MacOs devices
hls on;
#The path where the fragments will go for HLS
hls_path /tmp/hls;
#How long the fragments are gonna be
hls_fragment 15s;
#The same for dash
dash on;
dash_path /tmp/dash;
dash_fragment 15s;
}
}
}
http{
default_type application/octet-stream;
server{
listen 80;
location / {
#Where the fragments for HLS and DASH are
root /tmp;
# CORS setup
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length';
# allow CORS preflight requests
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
}
types {
#HLS
application/vnd.apple.mpegurl m3u8;
video/mp2t ts;
#HTML
text/html html;
#DASH
application/dash+xml mpd;
}
}
}
Te recomiendo que veas el video de dicho artículo para que entiendas cada parte, aunque he dejado mis anotaciones en el código 🙂
Dockerfile
Como quiero utilizar Azure Container Instances para montar mi servidor Nginx, necesito un Dockerfile que me permita generar la imagen:
FROM buildpack-deps:stretch
# Versions of Nginx and nginx-rtmp-module
ENV NGINX_VERSION nginx-1.17.10
ENV NGINX_RTMP_MODULE_VERSION 1.2.1
# Install dependencies
RUN apt-get update && \
apt-get install -y ca-certificates openssl libssl-dev ffmpeg && \
rm -rf /var/lib/apt/lists/*
# Download and decompress Nginx
RUN mkdir -p /tmp/build/nginx && \
cd /tmp/build/nginx && \
wget -O ${NGINX_VERSION}.tar.gz https://nginx.org/download/${NGINX_VERSION}.tar.gz && \
tar -zxf ${NGINX_VERSION}.tar.gz
# Download and decompress RTMP module
RUN mkdir -p /tmp/build/nginx-rtmp-module && \
cd /tmp/build/nginx-rtmp-module && \
wget -O nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}.tar.gz https://github.com/arut/nginx-rtmp-module/archive/v${NGINX_RTMP_MODULE_VERSION}.tar.gz && \
tar -zxf nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}.tar.gz && \
cd nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION}
# Build and install Nginx
RUN cd /tmp/build/nginx/${NGINX_VERSION} && \
./configure \
--sbin-path=/usr/local/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx/nginx.lock \
--http-log-path=/var/log/nginx/access.log \
--http-client-body-temp-path=/tmp/nginx-client-body \
--with-http_ssl_module \
--with-threads \
--with-ipv6 \
--add-module=/tmp/build/nginx-rtmp-module/nginx-rtmp-module-${NGINX_RTMP_MODULE_VERSION} && \
make -j $(getconf _NPROCESSORS_ONLN) && \
make install && \
mkdir /var/lock/nginx && \
rm -rf /tmp/build
# Set up config file
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 1935 80
CMD ["nginx", "-g", "daemon off;"]
En este simplemente descargo tanto el servidor Nginx como el módulo Nginx-rtmp, los descomprimo e instalo el servidor con una serie de parámetros para este. Por último, copio el archivo de configuración del apartado anterior, expongo los dos puertos que utilizo en el mismo y por último ejecuto Nginx para que arranque el servidor.
Desplegar Nginx en Azure Container Instances
Ahora que ya tienes la configuración y el Dockerfile para generar la imagen, puedes utilizar los siguientes comando para desplegar el contenedor en ACI:
#Build and push your image
docker build . -t YOUR_USERNAME/nginx-rtmp-live
docker push YOUR_USERNAME/nginx-rtmp-live
#Azure Storage Account where I'll save the live streaming events
RESOURCE_GROUP="Nginx-Demos"
AZ_STORAGE_NAME="media"
#Get the Azure Storage Account Key
AZ_STORAGE_KEY=$(az storage account keys list --resource-group $RESOURCE_GROUP --account-name $AZ_STORAGE_NAME --query "[0].value" --output tsv)
#Create a the Live container with nginx-rtmp
az container create \
--resource-group $RESOURCE_GROUP \
--name nginx-rtmp-live \
--image YOUR_USERNAME/nginx-rtmp-live \
--dns-name-label nginx-rtmp-live --ports 1935 80 \
--cpu 2 --memory 3.5 \
--azure-file-volume-share-name recordings \
--azure-file-volume-account-name $AZ_STORAGE_NAME \
--azure-file-volume-account-key $AZ_STORAGE_KEY \
--azure-file-volume-mount-path /recordings
Para comprobar que funciona correctamente puedes utilizar ffmpeg en local haciendo streming de un archivo en local a tu contenedor, utilizando el protocolo RTMP:
ffmpeg -re -i ../videos/sample.mkv -vcodec copy -loop -1 -c:a aac -b:a 160k -ar 44100 -strict -2 -f flv rtmp://nginx-rtmp-live.northeurope.azurecontainer.io/live/test
O bien puedes utilizar herramientas como OBS Studio para compartir directamente tu webcam.

Nota: Siguiendo el ejemplo anterior, si usas OBS el Stream Key es el nombre del evento, en este caso test.
Si abres un reproductor como VLC, que soporta RMTP, puedes abrir la ubicación de red, en mi caso, rtmp://nginx-rtmp-live.northeurope.azurecontainer.io/live/sample a través de File > Open Network… y ver que efectivamente se está retransmitiendo tu archivo desde ACI.
Por otro lado, una vez que comiences probar tu evento en directo, gracias a record all, lo que estés retransmitiendo se grabará en el path recordings, que a su vez está mapeado con una carpeta en Azure Files con el mismo nombre. Además, una vez que finalice el evento se generará de manera automática el mismo archivo en formato MP4.

Como en el archivo de configuración de Nginx también está habilitado HLS y DASH, puedes utilizar un ejemplo como el siguiente para reproducirlo en un sitio web:

El código lo tienes en mi GitHub.
¡Saludos!