[LINUX] Utilisez le frame buffer (/ dev / fb0) avec Raspeye pour entrer et sortir directement les images d'affichage

À propos de cet article

Essayez de lire et d'écrire le tampon de trame (/ dev / fbXX) sous Linux. Cet article le mentionne spécifiquement pour le Raspberry Pi, mais je pense que c'est la même chose pour les autres Linux. L'environnement confirmé est Raspberry Pi 2, la sortie d'image est HDMI et la résolution est le mode DMT 9 (800x600). Utilisation principale:

――Je veux sortir l'écran de Raspeye sur mon propre périphérique d'affichage

À propos du tampon de trame

Sous Linux, vous pouvez accéder au frame buffer via le fichier de périphérique (/ dev / fbXX). Il est préparé en tant que / dev / fb0 dans Raspeye. Ce contenu est émis vers l'écran et HDMI.

Jouez avec les commandes

Obtenir des données d'image RAW à partir du tampon d'image

Vous pouvez enregistrer les données d'image en tapant ce qui suit à partir de la ligne de commande (identique à la capture d'écran). Si vous faites le contraire, vous pouvez écrire (dessiner sur l'écran).

cat /dev/fb0 > aaa.raw

Obtenir des informations sur le tampon de trame

Les données d'image RAW acquises sont composées de 4 octets (32 bits) tels que ARGB par pixel. Il s'agit de données de pixels brutes, contrairement au JPEG et au BMP. Par conséquent, il est nécessaire de spécifier la taille, etc. lors de la lecture. Vous pouvez obtenir les informations dont vous avez besoin avec la commande suivante.

fbset

mode "800x600"
    geometry 800 600 800 600 32
    timings 0 0 0 0 0 0 0
    rgba 8/16,8/

Vous pouvez également obtenir le même résultat avec la commande suivante.

cat /sys/class/graphics/fb0/bits_per_pixel
32

cat /sys/class/graphics/fb0/virtual_size
800,600

Afficher dans la visionneuse d'images

Ceci est un exemple de réglage lors de la visualisation avec IrfanView. Différents paramètres peuvent être définis en faisant glisser et en déposant une image avec l'extension définie sur RAW. Si l'écran possède les paramètres ci-dessus, vous devriez pouvoir afficher correctement avec les paramètres suivants. (La valeur de réglage change en fonction de l'environnement)

irfan.jpg

Note

Il aurait dû être peint en rouge, mais il ne sera pas mis à jour dans VNC. En le regardant avec HDMI, il est correctement rempli. image.png

Accéder au frame buffer à partir d'un programme C / C ++

Obtenir des informations sur le tampon de trame

Ceci est le code pour obtenir les informations sur le tampon de trame. Il y a deux manières de procéder. Le résultat est le même quel que soit celui que vous faites. getFrameBufferSize () lit les informations sous forme de chaîne de caractères à partir de ce qui précède / sys / class / graphics / fb0 / bits_per_pixel. getFrameBufferSize2 () utilise ʻioctl () `pour obtenir des informations sur le périphérique.

getSizeFrameBuffer.cpp


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <linux/omapfb.h>

void getFrameBufferSize(int* width, int* height, int* colorWidth)
{
	int fd;
	int n;
	char str[64];

	/* Get Bit Per Pixel (usually 32-bit(4Byte) */
	fd = open("/sys/class/graphics/fb0/bits_per_pixel", O_RDONLY);
	n = read(fd, str, sizeof(str));
	str[n] = '\0';
	*colorWidth = atoi(str);
	close(fd);

	/* Get Frame Buffer Size */
	fd = open("/sys/class/graphics/fb0/virtual_size", O_RDONLY);
	n = read(fd, str, sizeof(str));
	str[n] = '\0';
	/* divide "800,600" into "800" and "600" */
	*width  = atoi(strtok(str, ","));
	*height = atoi(strtok(NULL, ","));
	close(fd);
}

void getFrameBufferSize2(int* width, int* height, int* colorWidth)
{
	struct fb_var_screeninfo var;
	int fd;
	fd = open("/dev/fb0", O_RDWR);
	ioctl(fd, FBIOGET_VSCREENINFO, &var);
	*colorWidth = var.bits_per_pixel;
	*width      = var.xres_virtual;
	*height     = var.yres_virtual;
	close(fd);
}

Lire les données d'image dans le tampon de trame

Code qui lit les données d'image à partir du tampon de trame. Il fait la même chose que cat ci-dessus en ouvrant, lisant et se fermant sur / dev / fb0. Il peut également être lu en mappant / dev / fb0. Ce sont respectivement «readBuffer ()» et «readBuffer2 ()». Vous pouvez lire les données en utilisant l'un ou l'autre, mais selon la façon dont vous les utilisez, une copie de mémoire inutile peut se produire, il est donc préférable de l'utiliser en fonction de l'objectif.

readFrameBuffer.cpp


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <linux/omapfb.h>

void readBuffer(int width, int height, void* dstBuffer)
{
	int fd;
	fd = open("/dev/fb0", O_RDONLY);
	read(fd, dstBuffer, width * height * 4);
	close(fd);
}

void readBuffer2(int width, int height, void* dstBuffer)
{
	int fd;
	fd = open("/dev/fb0", O_RDONLY);
	uint32_t *frameBuffer = (uint32_t *)mmap(NULL, width * height * 4, PROT_READ, MAP_SHARED, fd, 0);
	for(int y = 0; y < height; y++) {
		for(int x = 0; x < width; x++) {
			((uint32_t*)dstBuffer)[x + y * width] = frameBuffer[x + y * width];	
		}
	}

	munmap(frameBuffer, width * height * 4);
	close(fd);
}

Ecrire les données d'image dans le tampon de trame

Code qui écrit les données d'image dans le tampon de trame. Cela vous permet de dessiner directement sur l'écran (sortie HDMI). cependant,

Il y a un problème tel que. Je voudrais avoir un moyen de détourner complètement l'accès au tampon de trame, mais j'enquête.

Vous pouvez écrire en ouvrant, en écrivant et en fermant vers / dev / fb0. Ici, à titre d'exemple, un tampon rempli d'une seule couleur est sorti. Vous pouvez faire la même chose en mmaping ainsi qu'en lisant. Puisque mmap peut écrire directement, je pense que ce sera plus efficace en fonction de l'application. Cependant, lorsque vous utilisez mMap, sachez que la valeur peut ne pas être écrite tant que vous n'avez pas appelé msync.

writeFrameBuffer.cpp


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <linux/omapfb.h>

// color = AARRGGBB
void drawColor(int width, int height, int color)
{
	uint32_t *canvas = new uint32_t[width * height];
	for(int y = 0; y < height; y++) {
		for(int x = 0; x < width; x++) {
			canvas[x + y * width] = color;	
		}
	}

	int fd;
	fd = open("/dev/fb0", O_WRONLY);
	write(fd, canvas, width * height * 4);
	close(fd);
	delete[] canvas;
}

// color = AARRGGBB
void drawColor2(int width, int height, int color)
{
	int fd;
	fd = open("/dev/fb0", O_RDWR);
	uint32_t *frameBuffer = (uint32_t *)mmap(NULL, width * height * 4, PROT_WRITE, MAP_SHARED, fd, 0);
	for(int y = 0; y < height; y++) {
		for(int x = 0; x < width; x++) {
			frameBuffer[x + y * width] = color;	
		}
	}

	msync(frameBuffer, width * height * 4, 0);
	munmap(frameBuffer, width * height * 4);
	close(fd);
}


Programme de démonstration

Ceci est un exemple de lecture des informations du tampon de trame, de capture d'écran et de remplissage de tout l'écran en rouge. Cependant, même s'il est peint en rouge, la zone près du curseur en mode CUI et la zone près de la barre de menu en mode GUI seront écrasées par le système d'exploitation (il semble que le dessin ne soit mis à jour que là où il y a un changement à l'écran).

Compilez avec g ++ main.cpp getSizeFrameBuffer.cpp readFrameBuffer.cpp writeFrameBuffer.cpp

main.cpp


#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void getFrameBufferSize(int* width, int* height, int* colorWidth);
void getFrameBufferSize2(int* width, int* height, int* colorWidth);
void drawColor(int width, int height, int color);
void drawColor2(int width, int height, int color);
void readBuffer(int width, int height, void* dstBuffer);
void readBuffer2(int width, int height, void* dstBuffer);
void saveFileBinary(const char* filename, void* data, int size);

// g++ main.cpp getSizeFrameBuffer.cpp readFrameBuffer.cpp writeFrameBuffer.cpp

int main()
{
	int colorWidth;
	int width;
	int height;

	/* get frame buffer size */
	getFrameBufferSize(&width, &height, &colorWidth);
	printf("%d(W) x %d(H) x %d(Bit)\n", width, height, colorWidth);

	/* screen capture */
	uint32_t *buffer = new uint32_t[width * height];
	readBuffer(width, height, buffer);
	saveFileBinary("capture.raw", buffer, width * height * 4);
	delete[] buffer;

	/* Fill solid color */
	drawColor(width, height, 0xFFFF0000);	// RED
}


void saveFileBinary(const char* filename, void* data, int size)
{
	FILE *fp;
	fp = fopen(filename, "wb");
	fwrite(data, 1, size, fp);
	fclose(fp);
}

Todo

Matériel de référence

http://archive.linux.or.jp/JF/JFdocs/kernel-docs-2.6/fb/framebuffer.txt.html

Recommended Posts

Utilisez le frame buffer (/ dev / fb0) avec Raspeye pour entrer et sortir directement les images d'affichage
Instrument de pesage utilisant Raspberry Pi et Hx711 (affichage GUI dans Tkinter)
Sonnez le buzzer en utilisant python sur Raspberry Pi 3!
Essayez d'utiliser le capteur de température (LM75B) avec Raspeye.
Sortie sur "LED 7 segments" en utilisant python avec Raspberry Pi 3!
Obtenez la météo en utilisant l'API et laissez Raspberry Pi parler!
Contrôlez le moteur avec un pilote de moteur en utilisant python sur Raspberry Pi 3!
MQTT sur Raspberry Pi et Mac
Essayez d'utiliser ArUco avec Raspberry Pi
Paramètres initiaux pour l'utilisation du kit de démarrage et de la caméra Grove Pi + avec Raspberry Pi
Détectez la "luminosité" en utilisant python sur Raspberry Pi 3!
Utiliser le capteur Grove avec Raspberry Pi
Exécutez un servomoteur en utilisant python sur Raspberry Pi 3
Détectez la température à l'aide de python sur Raspberry Pi 3!
Fabriquez un thermomètre avec Raspberry Pi et rendez-le visible sur le navigateur Partie 3
Connectez-vous à la console Raspberry PI et affichez les informations IP et SD locales
J'ai essayé d'exécuter Flask sur Raspberry Pi 3 Model B + en utilisant Nginx et uWSGI
Utilisation du capteur de température numérique à 1 fil DS18B20 avec Raspberry Pi de Python
Utilisez python sur Raspberry Pi 3 pour éclairer la LED quand il fait noir!
Détectez les interrupteurs à glissière à l'aide de python sur Raspberry Pi 3!
Essayez d'utiliser le code QR avec Raspberry Pi
Détectez les commutateurs magnétiques à l'aide de python sur Raspberry Pi 3!
Afficher la température du processeur toutes les 5 secondes sur Raspberry Pi 4
Installez PyCall sur Raspberry PI et essayez d'utiliser la bibliothèque GPIO pour Python de Ruby
Une histoire lorsque j'utilisais IntelliJ sous Linux et que je ne pouvais pas saisir le japonais