- reStream lz4 streaming
- The Frame Buffer Device API
- Tutorial 1: Intro to Low-Level Graphics on Linux
- Cómo programar el framebuffer en Linux
$ cd ~/git
$ git clone https://github.com/eduardofilo/streaming_receiver.git
Contiene los siguientes módulos:
screeninfo
: Muestra los parámetros del framebuffer actual. Sirve para averiguar la resolución de la pantalla y la profundidad de color de cada píxel.streaming
: Lee el framebuffer y emite por la salida estándar un streaming de frames comprimidos.receiver
: Recoge el streaming de frames comprimidos que generastreaming
por la entrada estándar y genera por la salida estándar un streaming de rawvideo.convert.py
: Pequeño script Python para convertir un volcado completo del framebuffer a PNG. Sirve para visualizar el contenido completo del framebuffer en un momento dado para ayudarnos a interpretarlo (por ejemplo para ver si estamos utilizando el pixel_format correcto).
Lo compilamos desde máquina Linux donde se va a recibir el streaming:
$ cd ~/git/git/streaming_receiver/receiver
$ make
Necesitamos el contenedor Docker con toolchain para RG350. La primera vez lo instalamos:
$ docker run -it -v ~/git:/root/git --name RG350_buster_buildroot eduardofilo/rg350_buster_buildroot
Posteriormente sólo necesitamos arrancarlo:
$ docker container start RG350_buster_buildroot
$ docker exec -it RG350_buster_buildroot /bin/bash
Finalmente compilamos:
# cd ~/git/streaming_receiver/streaming
# make
Y transferimos a la RG ya que se ejecutará en ella:
# scp streaming root@10.1.1.2:
Compilamos también desde el contenedor Docker con toolchain para RG350 y transferimos a la RG:
# cd ~/git/streaming_receiver/screeninfo
# make
# scp screeninfo root@10.1.1.2:
Ejecutando por ejemplo este binario en la RG (por SSH por ejemplo) mientras se está ejecutando por ejemplo GMenu2X obtenemos la siguiente salida:
Vscreen Info:-
Xres = 320 | Yres = 240
Xres_virtual = 320 | Yres_virtual = 720
Xoffset = 0 | Yoffset = 0
BPP = 32 | Height = -1 | Width = -1
Xres_V = -1 | Yres_V = -1
Pixel format : RGBX_8888
Begin of bitfields(Byte ordering):-
Red : 16
Blue : 0
Green : 8
Transp : 24
Fscreen Info:-
Device ID : jz-lcd
Start of FB physical address : 205520896
Length of FB : 3686400
XPan step for hardware panning : 1
YPan step for hardware panning : 1
YWrap step for hardware ywrap : 0
Length of Line : 1280
Start of MMIO physical address : 0
Length of MMIO : 0
Los siguientes elementos son importantes se interpretan así:
- Xres: Resolución horizontal de cada frame.
- Yres: Resolución vertical de cada frame.
- Xres_virtual: Resolución horizontal del framebuffer.
- Yres_virtual: Resolución horizontal del framebuffer.
- Yoffset: Primera linea vertical del frame activo en el buffer (será Yres * el número de frame activo empezando a contar en 0).
- BPP: Bits por pixel.
- Byte ordering: Nos indica en qué orden llegan los bits de cada uno de los tres colores y la transparencia.
- Length of FB: Tamaño total del framebuffer en bytes.
- Length of Line: Tamaño de cada linea horizontal del framebuffer en bytes.
Ejecutando este binario en distintos programas ejecutándose en la RG se han encontrado los siguientes parámetros:
Programa | Xres | Yres | BPP | pixel_format | Frames en buffer |
---|---|---|---|---|---|
GMenu2X | 320 | 240 | 32 | bgr0 | 2 |
DinguxCmdr | 320 | 240 | 16 | rgb565le | 1 |
FCeux | 320 | 240 | 16 | rgb565le | 3 |
PCSX4All Sony logo | 640 | 448 | 15 | bgr555le | 3 |
Gambatte-M | 640 | 480 | 16 | rgb565le | 3 |
Para conocer todos los pixel_format disponibles, ejecutar el comando:
$ ffplay -pix_fmts
Hay un comando en el sistema que también nos permite interrogar al framebuffer sobre su modo. Es fbset
. Ejecutándolo sin argumentos nos ofrece mucha información. Por ejemplo, ejecutándolo con GMenu2X abierto obtenemos lo siguiente:
RG350M:/media/data/local/home # fbset
mode "320x240-0"
# D: 0.000 MHz, H: 0.000 kHz, V: 0.000 Hz
geometry 320 240 320 720 32
timings 0 16 16 16 4 48 2
accel false
rgba 8/16,8/8,8/0,8/24
endmode
Si nos fijamos bien, podemos encontrar la mayoría de los valores que habíamos obtenido antes con screeninfo
.
Por ejemplo con FCeux en ejecución. Como vemos en la tabla anterior el framebuffer en este caso trabaja a 320x240 y pixel_format rgb565le. Para visualizar al vuelo el streaming desde la consola ejecutaremos así desde el directorio donde se encuentre el binario receiver
en el ordenador que recibirá el streaming (cambiaremos los parámetros anteriores en pixel_format
y video_size
):
$ ssh root@10.1.1.2 -- ./streaming | ./receiver | ffplay -vcodec rawvideo -f rawvideo -pixel_format rgb565le -video_size 320x240 -framerate 30 -i -
Si en lugar de visualizar al vuelo preferimos capturar el streaming ejecutaremos así:
$ ssh root@10.1.1.2 -- ./streaming | ./receiver > dump.bin
Finalmente convertiremos a video ejecutando:
$ ffmpeg -vcodec rawvideo -f rawvideo -pixel_format rgb565le -video_size 320x240 -framerate 30 -i dump.bin -vcodec h264 out.mp4
Según vemos en la información que obtiene screeninfo el framebuffer es bastante más grande de lo que sería necesario para contener toda la pantalla. Por ejemplo en el caso de GMenu2X la pantalla tiene 320x240 y 4 bytes por pixel. Por tanto sería suficiente 320*240*4 = 307200
bytes de buffer, pero sin embargo tiene 3686400, es decir suficiente para contener 3686400/307200 = 12
pantallas.
Podemos capturar el buffer entero ejecutando lo siguiente en la RG:
# cp /dev/fb0 buffer.data
Transfiriendo el fichero buffer.data
al ordenador y convirtiéndolo a PNG con el pequeño programa convert.py
en Python (necesita que tengamos instalado el módulo ffpyplayer
), vemos en la imagen resultante que en el buffer se utilizan sólo el espacio correspondiente a los dos primeros frames de los 12 posibles. De hecho se dibujan en esas posiciones los distintos cambios en la pantalla alternativamente, es decir, primero en la posición 0 y luego en la 1, volviendo a la 0 a continuación.
Para convertir el dump del framebuffer anterior ejecutamos convert.py
así:
$ python3 convert.py buffer.data
Hay que adaptar el tamaño del buffer y el pixel_format en el script convert.py
.
En lugar de utilizar el script convert.py, podemos utilizar esta utilidad online.
Otra opción es abrir con Gimp seleccionando el formato Datos de imagen en bruto
. Aparecerá un cuadro de diálogo donde podremos ajustar la resolución y el pixel_format.