Introducción: ffmpeg

En Ubuntu 24.04 hay un conflicto en la biblioteca de SDL que hace que quede colgado el bloque Video SDL Sink, tenga la entrada que tenga. Aquí presentamos un parche, que aunque no es lo más cómodo, sí funciona y razonablemente bien. De nuevo, lo que se presenta aquí sólo es necesario si el bloque Video SDL Sink no funciona. 

La solución propuesta necesita tener instalado ffmpeg, por lo que comenzamos instalándolo, que es tan fácil como ejecutar:

$ sudo apt-get install ffmpeg

Este programa trae una utilidad para reproducir prácticamente cualquier tipo de video llamada ffplay. Lo que queremos nosotros en este laboratorio es reproducir un video "raw", donde cada byte representa un pixel (en el caso blanco y negro) y paquetes de tres bytes representan la luminancia y las dos cromas (en ese orden y sucesivamente). Esto determina el formato de pixel, y hay muchísimas variantes, pero tener esto claro es importante para ver el porqué del comando que usaremos cuando ejecutemos ffplay.

Caso blanco y negro: named pipe

Separemos en dos casos, empezando por blanco y negro, que aprovechamos para ver cómo reproducir el video "en vivo". Primero hace falta crear un named pipe. Es decir, un archivo especial donde GNU Radio escribirá bytes, y del cual ffplay los leerá, sin necesidad de guardar a disco y que el archivo crezca de forma desmedida. Esto se hace ejecutando

$ mkfifo salida.raw

El nombre del archivo y su terminación da lo mismo. Lo importante es agregar un file sink del tipo que termine generando nuestro video (el tipo de dato que hayamos configurado como entrada al SDL Sink). Lo que sigue está probado con tipo byte y creemos que tipo short no va a ser tan fácil que funcione (pues ahí serían dos bytes por componente y pixel).

Si ejecutamos el flowgraph debería quedarse quieto, esperando a que alguien consuma los bytes que estamos escribiendo en nuestro named pipe. Es en este momento que vamos a ejecutar el ffplay con el siguiente comando:

$ ffplay -f rawvideo -pixel_format gray -video_size 300x225 -i salida.raw 

El comando es bastante claro. El -f es el formato del video (raw), el formato de pixel es tipo gris (un byte y sólo para la intensidad de blanco), la resolución es la de la imagen y el archivo de entrada (-i) es nuestro named pipe. Notar que nunca le dijimos la tasa de refresco (o fps), y al igual que el SDL Sink leerá pixels tan rápido como pueda.

Caso color: packed/planar pixels

Ahora pasamos al caso color. En este caso está la complejidad de que tenemos tres canales y existen infinidad de formas de transmitirlo. Nosotros estamos generándolos de forma empaquetada, donde los tres canales van interleaved, lo que se denomina packed (o sea, enviamos para cada pixel las tres componentes sucesivas, del estilo Y1U1V1,Y2U2V2,Y3U3V3, donde el índice indica el número de pixel, Y es el brillo, U es Cb y V es Cr, una nomenclatura confusa pero muy usada). Pero además, no estamos haciendo sub-sampling, algo que muchos formatos usan enviando más pixeles en el brillo que en los cromas

Lamentablemente, este formato de pixel no está soportado en ffplay (ver una explicación de cada uno en https://github.com/FFmpeg/FFmpeg/blob/master/libavutil/pixfmt.h). Sí está soportado el tipo planar, donde se envian primero todos los bytes correspondientes al brillo del frame, después todas las cromas b, y después todas las cromas r (o sea, y retomando el ejemplo anterior, deberíamos enviar Y1,Y2,Y3,..Yn,U1,U2,..Un,V1,V2,..,Vn). Este formato se llama yuvj444p (donde la j es porque usa todo el rango entre 0 y 255, el 444 es porque no hacemos sub-sampling de las cromas y el p es de planar).

Por lo tanto, tenemos que re-organizar nuestra recepción para generar un stream planar. Basta con usar el bloque Stream Mux de GNU Radio, donde en el parámetro Num Inputs ingresaremos 3 y en Lengths ingresaremos (300*225, 300*225,300*225) (si fuera otra resolución, se cambia a esos valores). Si en cada entrada ponemos el brillo y las cromas, tendremos entonces que de esta forma generamos un flujo planar tal cual lo espera ffplay. 

Haciendo igual que hicimos en el caso blanco y negro, el único cambio es en la ejecución del comando de ffplay, que ahora debería ser: 

$ ffplay -f rawvideo -pixel_format yuvj444p -video_size 300x225 -i salida.raw


Última modificación: miércoles, 20 de noviembre de 2024, 08:56