[LINUX] Verwenden Sie den Bildspeicher (/ dev / fb0) mit Raspeye, um Anzeigebilder direkt einzugeben und auszugeben

Über diesen Artikel

Versuchen Sie, den Frame Buffer (/ dev / fbXX) unter Linux zu lesen und zu schreiben. Dieser Artikel erwähnt es speziell für den Raspberry Pi, aber ich denke, es ist das gleiche für andere Linux. Die bestätigte Umgebung ist Raspberry Pi 2, die Bildausgabe ist HDMI und die Auflösung ist DMT-Modus 9 (800 x 600). Hauptanwendung:

――Ich möchte den Bildschirm von Raspeye auf meinem eigenen Anzeigegerät ausgeben

Über den Frame Buffer

Unter Linux können Sie über die Gerätedatei (/ dev / fbXX) auf den Frame-Puffer zugreifen. Es wird in Raspeye als / dev / fb0 vorbereitet. Dieser Inhalt wird auf dem Display und HDMI ausgegeben.

Spielen Sie mit Befehlen

Ruft RAW-Bilddaten aus dem Bildspeicher ab

Sie können die Bilddaten speichern, indem Sie Folgendes über die Befehlszeile eingeben (wie bei der Bildschirmaufnahme). Wenn Sie das Gegenteil tun, können Sie schreiben (auf dem Display zeichnen).

cat /dev/fb0 > aaa.raw

Frame Buffer Informationen abrufen

Die erfassten RAW-Bilddaten bestehen aus 4 Bytes (32 Bit), z. B. ARGB pro Pixel. Dies sind im Gegensatz zu JPEG und BMP Rohpixeldaten. Daher ist es notwendig, beim Spielen die Größe usw. anzugeben. Mit dem folgenden Befehl erhalten Sie die benötigten Informationen.

fbset

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

Alternativ können Sie das gleiche Ergebnis mit dem folgenden Befehl erhalten.

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

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

Ansicht im Bildbetrachter

Dies ist ein Einstellungsbeispiel beim Anzeigen mit IrfanView. Durch Ziehen und Ablegen eines Bildes mit der Erweiterung RAW können verschiedene Einstellungen vorgenommen werden. Wenn das Display die oben genannten Einstellungen hat, sollten Sie in der Lage sein, mit den folgenden Einstellungen korrekt anzuzeigen. (Der Einstellwert ändert sich je nach Umgebung.)

irfan.jpg

Memo

Es sollte rot gestrichen sein, wird aber in VNC nicht aktualisiert. Wenn Sie es mit HDMI betrachten, ist es richtig gefüllt. image.png

Greifen Sie über ein C / C ++ - Programm auf den Frame-Puffer zu

Frame Buffer Informationen abrufen

Dies ist der Code zum Abrufen der Bildpufferinformationen. Es gibt zwei Möglichkeiten, dies zu tun. Das Ergebnis ist das gleiche, unabhängig davon, welches Sie tun. getFrameBufferSize () liest Informationen als Zeichenfolge aus dem oben genannten / sys / class / graphics / fb0 / bits_per_pixel. getFrameBufferSize2 () verwendetioctl (), um die Geräteinformationen abzurufen.

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);
}

Lesen Sie die Bilddaten im Bildspeicher

Code, der Bilddaten aus dem Bildspeicher liest. Es macht dasselbe wie die obige Katze, indem es / dev / fb0 öffnet, liest und schließt. Es kann auch durch Zuordnen von / dev / fb0 gelesen werden. Sie sind "readBuffer ()" bzw. "readBuffer2 ()". Sie können die Daten mit beiden Methoden lesen. Je nachdem, wie Sie sie verwenden, kann es jedoch zu einer nutzlosen Speicherkopie kommen. Daher ist es besser, sie je nach Verwendungszweck zu verwenden.

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);
}

Schreiben Sie Bilddaten in den Bildspeicher

Code, der Bilddaten in den Bildspeicher schreibt. Auf diese Weise können Sie direkt auf dem Display zeichnen (HDMI-Ausgang). Jedoch,

Es gibt ein Problem wie. Ich hätte gerne eine Möglichkeit, den Zugriff auf den Frame-Puffer vollständig zu entführen, aber ich untersuche dies.

Sie können schreiben, indem Sie / dev / fb0 öffnen, schreiben und schließen. Hier wird beispielsweise ein mit einer einzelnen Farbe gefüllter Puffer ausgegeben. Sie können dasselbe tun, indem Sie sowohl mmaping als auch lesen. Da mmap direkt schreiben kann, denke ich, dass es je nach Anwendung effizienter sein wird. Beachten Sie jedoch bei der Verwendung von mMap, dass der Wert möglicherweise erst geschrieben wird, wenn Sie "msync" aufrufen.

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);
}


Demo-Programm

Ein Beispiel ist das Lesen der Bildpufferinformationen, das Aufnehmen einer Bildschirmaufnahme und das Ausfüllen des gesamten Bildschirms in Rot. Selbst wenn es rot gestrichen ist, werden der Bereich in der Nähe des Cursors im CUI-Modus und der Bereich in der Nähe der Menüleiste im GUI-Modus vom Betriebssystem überschrieben (es scheint, dass die Zeichnung nur aktualisiert wird, wenn sich auf dem Bildschirm etwas ändert).

Kompilieren Sie mit 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

Referenzmaterial

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

Recommended Posts

Verwenden Sie den Bildspeicher (/ dev / fb0) mit Raspeye, um Anzeigebilder direkt einzugeben und auszugeben
Wiegeinstrument mit Himbeer-Pi und hx711 (GUI-Anzeige in Tkinter)
Lassen Sie den Summer mit Python auf Raspberry Pi 3 erklingen!
Versuchen Sie es mit dem Temperatursensor (LM75B) mit Raspeye.
Ausgabe auf "7 Segment LED" mit Python mit Raspberry Pi 3!
Holen Sie sich das Wetter mit API und lassen Sie Raspberry Pi sprechen!
Steuern Sie den Motor mit einem Motortreiber mit Python auf Raspberry Pi 3!
MQTT auf Raspberry Pi und Mac
Versuchen Sie es mit ArUco mit Raspberry Pi
Grundeinstellungen für die Verwendung des Grove Pi + Starterkits und der Kamera mit Raspberry Pi
Erkennen Sie "Helligkeit" mit Python auf Raspberry Pi 3!
Verwenden Sie den Grove-Sensor mit Raspberry Pi
Lassen Sie einen Servomotor mit Python auf Raspberry Pi 3 laufen
Ermitteln Sie die Temperatur mit Python auf Raspberry Pi 3!
Machen Sie ein Thermometer mit Raspberry Pi und machen Sie es im Browser Teil 3 sichtbar
Stellen Sie eine Verbindung zur Raspberry PI-Konsole her und zeigen Sie lokale IP- und SD-Informationen an
Ich habe versucht, Flask auf Raspberry Pi 3 Model B + mit Nginx und uWSGI auszuführen
Verwendung des digitalen 1-Draht-Temperatursensors DS18B20 mit Raspberry Pi von Python
Verwenden Sie Python auf Raspberry Pi 3, um die LED zu beleuchten, wenn es dunkel wird!
Erkennen Sie Schiebeschalter mit Python auf Raspberry Pi 3!
Versuchen Sie, QR-Code mit Raspberry Pi zu verwenden
Erkennen Sie Magnetschalter mit Python auf Raspberry Pi 3!
Zeigen Sie die CPU-Temperatur alle 5 Sekunden auf dem Raspberry Pi 4 an
Installieren Sie PyCall auf Raspberry PI und versuchen Sie, die GPIO-Bibliothek für Python von Ruby zu verwenden
Eine Geschichte, als ich IntelliJ unter Linux verwendete und kein Japanisch eingeben konnte