Skip to content

Creación de Apps de audio y video con GStreamer (parte II)

Share on twitter
Share on linkedin
Share on email
Share on whatsapp
Creación de Apps de audio y video con GStreamer

En la primera parte de «Creación de apps de audio y video con GStreamer», vimos una introducción al framework GStreamer, su arquitectura básica y algunos ejemplos de lo que podemos hacer con él y con las Command Line Tools.

Hoy, vamos a profundizar un poco en casos de uso como el streaming multimedia y la vigilancia remota.

Caso de uso: streaming multimedia

El protocolo HLS, o HTTP Live Streaming, permite entre otros casos de uso la emisión de «contenidos a la carta» que ya utilizamos desde hace varios gracias plataformas como RTVE Play, Atresplayer o Mitele. Estas plataformas nos permiten disfrutar de sus contenidos utilizando casi cualquier navegador web o clientes como QuickTime o VLC. Sin entrar demasiado en detalle, explicaré a continuación como funciona.

Para emitir un stream con HLS, necesitamos dos cosas:

  1. Convertir la fuente de video o fichero a pequeños «trocitos», ficheros que contienen algunos segundos de video y el audio codificados y multiplexados en formato .ts (Transport Stream).
  2. Un servidor web (Apache, nginx, etc.) en uno de cuyos directorios estarán los ficheros .ts y un fichero «índice» m3u8 que contiene información sobre el orden en que deben reproducirse los .ts.

Ejemplo 1: streaming con HLS

El siguiente pipeline de GStreamer hace precisamente esto:

gst-launch-1.0 filesrc location=sintel_trailer-480p.webm ! decodebin ! x264enc ! mpegtsmux ! hlssink playlist-root=http://localhost/three location=/Library/WebServer/Documents/three/hlssink.%05d.ts playlist-location=/Library/WebServer/Documents/three/playlist.m3u8

Primero descodifica el fichero «sintel_trailer-480p.webm» (que como pudimos ver en el post anterior se puede descargar aquí desde el browser o con wget, curl o similar). Después lo codifica y multiplexa en un formato adecuado para HLS, y «pone» los segmentos en un directorio del servidor web. (Por simplicidad, no estamos incluyendo el audio en el stream). También crea el fichero índice o playlist m3u8.

Para visualizar el stream, en el browser o cliente introducimos la URL remota del fichero m3u8, y se irán reproduciendo uno a uno los ficheros ts.

Reproducción de un video desde el navegador web

Como podéis ver, este formato permite pausar y rebobinar el video, por lo que es muy útil para casos de uso de emisión de contenidos a la carta. Aunque también se puede emitir contenido en «directo» (desde una cámara usb, por ejemplo) hay que tener en cuenta que HLS siempre tiene una latencia alta, por lo que no es el formato más aconsejable para videollamada o videovigilancia.

Caso de uso: vigilancia remota

Si tienes una cámara IP doméstica, seguro que te habrás preguntado por qué necesitas una App para ver el stream en directo o las grabaciones.

En realidad no la necesitas pero los fabricantes suelen ofrecer almacenamiento gratuito ¿? y seguro ¿? en la nube de tus grabaciones. Para esto utilizan una aplicación móvil que envía el stream a sus servidores, gestiona las grabaciones, recibe notificaciones, etc.

Algunas de estas cámaras económicas permiten el acceso al stream mediante una URL, de forma que puedas verlo con VLC, ffmpeg u otros clientes. Sin embargo a veces no es posible, y si se quiere tener control sobre la cámara hay que cambiar o modificar el firmware (Si esto te interesa, puedes leer nuestro post sobre Seguridad en hardware e IoT).

Una cámara de vigilancia sencilla

Por simplicidad, vamos a ver otras alternativas: la cámara de tu portátil, una webcam USB conectada a una Raspberry Pi o un móvil viejo nos pueden valer, por supuesto con la ayuda de nuestro aliado GStreamer.

Ejemplo 2: cámaras disponibles

El siguiente pipeline sirve para ver qué cámaras tenemos disponibles:

gst-device-monitor-1.0 Video/Source

En mi Mac, puedo ver la cámara integrada y cualquier otra que tuviera conectada por USB. La salida del comando será algo así:

Device found: name : FaceTime HD Camera
class : Video/Source
caps : video/x-raw(memory:GLMemory), width=1280, height=720, format=UYVY, framerate=[ 1/1, 30/1 ], texture-target=rectangle video/x-raw, width=1280, height=720, format={ (string)UYVY, (string)YUY2, (string)NV12, (string)BGRA }, framerate=[ 1/1, 30/1 ] properties: device.api = avf avf.unique_id = CC28422JTHUGJJM1J avf.model_id = «Apple\ Camera\ VendorID_0x106B\ ProductID_0x1570» avf.has_flash = false avf.has_torch = false avf.manufacturer = «Apple\ Inc.»

gst-launch-1.0 avfvideosrc device-index=0 ! …

puedes ver que al final aparece una pista de cómo hay que empezar el pipeline de captura con esa cámara (llamada avfvideosrc).

Ejemplo 3: captura del stream de video de la cámara

El pipeline de captura en este ordenador podría ser así:

gst-launch-1.0 avfvideosrc device-index=0 ! videoscale ! video/x-raw,width=1920,height=1080 ! autovideosink

En la Raspberry con una cámara USB, quedaría algo así:

gst-launch-1.0 v4l2src device=/dev/video2 device-index=0 ! videoscale ! video/x-raw,width=1920,height=1080 ! clockoverlay time-format=»%h-%G %r» ! autovideosink

Si te fijas, he añadido el elemento «clockoverlay» al pipeline, para superponer de forma super-profesional 🙂 la fecha y hora sobre la grabación:

Captura de la cámara y visualización con fecha y hora superpuestas

Emisión y recepción en tiempo real

Ahora que ya sabemos capturar de la cámara, vamos a enviar el stream por la red, en lugar de reproducirlo localmente con «autovideosink».

Ya hemos visto el formato HLS, pero como decía antes, para este caso de uso no es el más adecuado, pues tiene cierta latencia. En su lugar vamos a usar RTP (Real time Transport Protocol), que con los parámetros adecuados, nos va a permitir la emisión con una latencia mínima (pocos milisegundos).

Ejemplo 4: pipelines multicast con el formato RTP

El pipeline es un poco más complejo de entender, pero lo que hace básicamente es: obtener el vídeo de la cámara USB conectada a la Raspberry, escalarlo a 640×360, superponer la fecha y hora, codificar en H264, multiplexar el stream, y emitirlo por UDP a una dirección multicast… Esto último es muy interesante, ya que con una sola emisión podemos tener muchos clientes recibiendo, sin que «gastemos» ancho de banda con cada uno de ellos.

gst-launch-1.0 v4l2src device=»/dev/video2″ ! videoscale ! video/x-raw,width=640,height=360 ! videoconvert ! clockoverlay time-format=»%h-%G %T %Z» ! v4l2h264enc ! ‘video/x-h264,level=(string)5.1’ ! rtph264pay ! udpsink host=224.1.1.1 port=5600

En el lado del receptor, podemos usar VLC u otro cliente que pueda recibir RTP. En mi caso lo recibo usando otro pipeline (este lo ejecuto en el portátil):

gst-launch-1.0 udpsrc multicast-group=224.1.1.1 port=5600 caps=’application/x-rtp, media=(string)video, encoding-name=(string)H264,payload=(int)96′ ! rtpjitterbuffer mode=1 ! rtph264depay ! decodebin ! videoconvert ! autovideosink

Este se encarga de «escuchar» en la misma dirección multicast y puerto UDP que el emisor, ir poniendo los datos en un buffer, de-multiplexar, decodificar, y visualizar en el video sink por defecto. Así de fácil!

Como puedes ver en el video siguiente, la latencia es mínima (observa el timestamp superpuesto en la imagen, y el reloj del receptor a la derecha de la imagen).

Una vez más, espero que os haya parecido muy interesante el artículo, y que podáis poner vuestras ideas y proyectos a funcionar con estas potentes herramientas de gestión de multimedia. En próximas entregas dentro de esta serie de artículos estilo hands-on hablaremos sobre visión artificial, deep learning y otras tecnologías super-interesantes.

Comparte el artículo

Share on twitter
Twitter
Share on linkedin
LinkedIn
Share on email
Email
Share on whatsapp
WhatsApp

Una nueva generación de servicios tecnológicos y productos para nuestros clientes