Streaming con el módulo rtmp de nginx

He descubierto hace poco que es posible publicar en Periscope un stream RTMP, al igual que con Youtube o Twich y en general con casi todos los servicios de streaming en directo. En todos los casos la idea es poder utilizar otros aparatos para grabar y no limitarse al teléfono móvil o a la webcam de tu ordenador.

Para hacer streaming one-to-one, lo más sencillo es utilizar FFmpeg, que permite recuperar una fuente, convertirla si es necesario y enviarla a cualquier destino. Pero cuando se quiere servir un flujo a un numéro ilimitado de clientes, es mas práctico utilizar un servidor de streaming.

Existen muchos servidores de streaming en el mercado, como por ejemplo Wowza , aunque es de pago. Yo no soy un experto y no os puedo decir mucho sobre las alternativas, pero soy un fan de NGINX y de su simplicidad, y buscando en internet encontré que existe un módulo RTMP para NGINX, que convierte nuestro servidor favorito en un servidor de streaming de alto rendimiento y sobre todo muy fácil de configurar.

Para probarlo tenéis que compilar NGINX con el módulo de RTMP, siguiendo estas instrucciones.

La belleza del asunto es la facilidad con la que el módulo de RTMP gestiona los flujos. Con los comandos pull y push es posible recuperar un streaming remoto y reenviarlo a varios sitios al mismo tiempo. Si se necesita recodificar la fuente, el comando exec_push y exec_pull permiten lanzar directamente un FFmpeg para hacer el trabajo sucio.

Os voy a dar un ejemplo que encontraréis fácilmente en internet, sin embargo el comando para la publicación en Periscope no es tan fácil de encontrar. Tengo una webcam que permite recuperar su vídeo a través de una conexión RTSP. La idea es poder ver la webcam con un reproductor embebido en una pagina web, y al mismo tiempo publicar el streaming en Youtube y Periscope. Nada más sencillo gracias al módulo RTMP de NGINX, veamos la configuration necesaria.

Lo primero que hay que saber, es que los flujos RTMP siguen una estructura bien definida, el puerto por defecto es el 1935, la primera parte de la URL es la aplicación y la segunda parte es el nombre del stream. Application y name son dos variables disponibles en el bloque de configuración, ya que el módulo permite gestionar varios streams dentro de una misma aplicaión.

application webcam {  
  live on;
  record off;
  meta copy;

  push rtmp://a.rtmp.youtube.com/live2/<youtube-key>;
  push rtmp://de.pscp.tv:80/x/<periscope-key>;

  exec_pull ffmpeg -i 'rtsp://<my-webcam>/<url>' -crf 30 -preset ultrafast -acodec aac -strict experimental -ar 44100 -ac 2 -b:a 64k -vcodec libx264 -x264-params keyint=60:no-scenecut=1 -r 30 -b:v 800k -maxrate 800k -bufsize 2M -s 960x540 -f flv 'rtmp://localhost:1935/webcam/casa';

   on_play_done http://localhost:90/control/drop/publisher?app=webcam;
}

Este es un ejemplo del bloque application. Por defecto no se pasa nada porque para que haya un push la aplicación debe recibir un stream, pero el exec_pull sólo se ejecuta cuando la aplicación recibe un play. En lugar del exec_pull podríamos haber lanzado directamente el comando FFmpeg, pero en este caso siempre estaría en ejecución consumiendo ancho de banda incluso cuando nadie mira. El comando ffmpeg no sólo recupera el stream de mi webcam, sino que tambien lo codifica para que sea apto para su publicación según las reglas de Periscope.

Cuando un player se activa en rtmp://mi-servidor:1935/webcam/casa, el comando exec_pull se dispara y ffmpeg recupera el stream RTSP de mi webcam y lo envía recodificado sobre rtmp://mi-servidor:1935/webcam/casa. La publicación de un stream sobre la aplicación webcam dispara a su vez los comandos push y transcurridos unos pocos segundos deberíamos ver nuestra webcam en el reproductor, en Youtube y Periscope!

Cuando el player se desconecta el evento on_play_done sirve para terminar el comando FFmpeg, lo que significa que el stream deja de publicarse en la application webcam y los push se paran, como tengo un Apache corriendo, mi NGINX escucha en el puerto 90.

Si queremos utilizar un reproductor HTML5, NGINX-RTMP también soporta los protocolos HLS, Http Live Streaming, de Apple y el MPEG-DASH, pero como estos protocolos utilizan un acceso HTTP no disponemos de los eventos publish, play, etc.

Si os ha interesado este post, os recomiendo que echéis un vistazo a la página oficial del módulo, a su wiki así como a sus ejemplos. Además de la funcionalidad de relay que os he comentado aquí, también podéis grabar los streams o simplemente publicar vuestras pelis o ficheros favoritos.

Como anécdota, si queréis utilizar este servidor para publicar el stream de vuestros juegos, tened cuidado de implementar un retardo, si no, vuestros rivales podrán ver dónde os encondéis!