漆像素通过Linux的帧缓冲屏幕

问题描述 投票:34回答:7

我最近被一个奇怪的想法袭击采取从/ dev / urandom的输入,转换相关的字符随机整数,并使用这些整数作为RGB / X-Y值的像素画到屏幕上。

我做了一些研究(这里在计算器上和其他地方)和许多建议,你可以简单地写到/ dev / fb0设备直接,因为它是设备的文件表示。不幸的是,这似乎并没有产生任何明显的视觉效果。

我发现了一个样品C程序,这是从所使用的MMAP写入到缓冲器的QT教程(不再可用)。该程序成功运行,但是也没有输出到屏幕上。有趣的是,当我把我的笔记本电脑进入暂停,后来恢复时,我看到被写入到帧缓冲早得多的图像(红方)的瞬间闪光。请问在Linux中不再写入帧缓冲区工作绘画到屏幕?理想情况下,我想编写一个(BA)sh脚本,但C或类似的将正常工作。谢谢!

编辑:这里的示例程序...可以很熟悉的兽医。

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

int main()
{
    int fbfd = 0;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;
    long int screensize = 0;
    char *fbp = 0;
    int x = 0, y = 0;
    long int location = 0;

    // Open the file for reading and writing
    fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd == -1) {
        perror("Error: cannot open framebuffer device");
        exit(1);
    }
    printf("The framebuffer device was opened successfully.\n");

    // Get fixed screen information
    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        perror("Error reading fixed information");
        exit(2);
    }

    // Get variable screen information
    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        perror("Error reading variable information");
        exit(3);
    }

    printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    // Figure out the size of the screen in bytes
    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

    // Map the device to memory
    fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
    if ((int)fbp == -1) {
        perror("Error: failed to map framebuffer device to memory");
        exit(4);
    }
    printf("The framebuffer device was mapped to memory successfully.\n");

    x = 100; y = 100;       // Where we are going to put the pixel

    // Figure out where in memory to put the pixel
    for (y = 100; y < 300; y++)
        for (x = 100; x < 300; x++) {

            location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) +
                       (y+vinfo.yoffset) * finfo.line_length;

            if (vinfo.bits_per_pixel == 32) {
                *(fbp + location) = 100;        // Some blue
                *(fbp + location + 1) = 15+(x-100)/2;     // A little green
                *(fbp + location + 2) = 200-(y-100)/5;    // A lot of red
                *(fbp + location + 3) = 0;      // No transparency
        //location += 4;
            } else  { //assume 16bpp
                int b = 10;
                int g = (x-100)/6;     // A little green
                int r = 31-(y-100)/16;    // A lot of red
                unsigned short int t = r<<11 | g << 5 | b;
                *((unsigned short int*)(fbp + location)) = t;
            }

        }
    munmap(fbp, screensize);
    close(fbfd);
    return 0;
}
c linux framebuffer
7个回答
7
投票

如果你正在运行X11,你必须通过X11 API来绘制到屏幕上。绕来绕去的X服务器很破(和,常为你所看到的,不工作)。它也可能造成死机,或只是一般的显示器损坏。

如果您希望能够到处运行(包括控制台和下X),看看SDL或GGI。如果你只关心X11,你可以使用GTK,QT,甚至Xlib的。有很多很多的选择...


11
投票

我已经受够了以下几个实验的成功。

首先,找出如果X使用真彩色RGB填充到32个比特(或只是假设是这种情况)。然后找出如果你有FB0(和它的存在)的写入权限。如果这些都是真的(我估计很多现代工具包/桌面/个人电脑可能使用这些作为默认值),那么你应该能够做到以下几点(如果这些缺省值不成立,那么你可能仍然有一些成功下面的测试,虽然细节可能会有所不同):

测试1:打开一个虚拟终端(在X)和输入:$回声“DDD ... DDD”>的/ dev / FB0其中... d的实际上是几个屏幕充盈。其结果将是灰色的一个或多个(部分)线在你的屏幕的顶部,这取决于多久你的回音串并已启用的像素分辨率。您也可以选择任意的字母(ASCII值均大于0x80的少,所以产生的颜色将是深灰色..如果你想除了灰色的东西改变字母)。显然,这可以推广到一个shell循环,也可以猫一个大文件更清楚地看到效果:如:$猫/lib/libc.so.6>的/ dev / fb0设备才能看到的一些真面目FSF支持者;-P

如果你的屏幕的一大块被写入了别担心。 X仍然有鼠标指针的控制,仍然有它的地方的窗户被映射的想法。所有你需要做的就是抓住任何窗口,拖动它周围有点抹去的噪音。

测试2:猫的/ dev / fb0设备> XXX然后改变你的桌面(例如,打开新的窗口和关闭等)的外观。最后,做相反:猫XXX>的/ dev / FB0为了得到你的旧桌面回来了!

哈,好了,不完全是。旧的台式机的形象是一种错觉,你会很快免除它,当你打开的任何窗口到全屏。

测试3:写一个小应用程序,抓住的/ dev / fb0设备的前转储和修改像素的颜色,例如,以去除红色成分或增加蓝色,或翻转红色和绿色等,然后​​写回这些像素到一个新的文件,你可以看看在以后通过测试2.还简单外壳的方法,请注意您可能会被处理每个像素BGRA 4字节的数量。这意味着你要忽略每4个字节,也可治疗率先在每一组的蓝色成分。 “ARGB” 是大端,因此,如果访问通过增加C数组的索引这些字节,蓝色会来首先,然后绿色,然后红色..即,B-G-R-A(未A-R-G-B)。

测试4:在循环在视频的速度发送非正方形图片(认为xeyes)屏幕的一部分,从而没有任何窗户边框创建一个动画任何语言编写的应用程序。对于加分,都在屏幕上动画的举动。你将不得不确保绘制像素的一小行值之后跳过一个大的空间(以弥补屏幕的宽度很可能比图片进行动画处理更广泛的)。

测试5:捉弄的朋友,例如,延长测试4,这样一个动画人的图片出现弹出在桌面上(也许电影自己获得的像素数据),然后走到自己的重要桌面的一个文件夹,拿起文件夹和碎片它拆开,然后开始歇斯底里笑,然后有一个火球出来,吞噬了整个桌面。虽然这都将是一种错觉,他们可能吓坏了一点..但使用它作为一个学习的经验炫耀Linux和开放源代码,并显示其如何可怕得多找一个新手比实际情况。 [“病毒”通常是无害的幻想,在Linux上]


2
投票

我想说的是试图写入到/ dev / fb0设备,如上述建议前小心。我在Ubuntu 10.04试过X下和)什么都没有发生视觉,B),它破坏了所有的shell窗口,甚至是其他的ttys,导致内核错误和缺乏功能。


1
投票

您应该使用fb_fix_screeninfo.smem_len的屏幕尺寸,而不是做自己的乘法。缓冲区可能会在4个字节或别的东西来对齐。

screensize = finfo.smem_len;

0
投票

当我用这个程序写的全屏幕,它已坠毁是由于屏幕尺寸的计算是错误的。

// Figure out the size of the screen in bytes     
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

这应该是:

/* Calculate the size of the screen in bytes */   
screensize = vinfo.xres_virtual * vinfo.yres_virtual * (vinfo.bits_per_pixel / 8);

0
投票

如果您调试程序时,你会发现行:

 screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;

screensize为0,因为vinfo.xres为0,你应该将其更改为:

long ppc_fx = (((long)fixed_info.smem_start) - ((long) fixed_info.smem_start & ~(PAGE_SIZE-1)));
screensize = finfo.smem_len + ppc_fx;

因为Linux 2.6.2? ,MMAP的第二个参数(),screensize,决不能为0,否则mmap()的返回MAP_FAILED。


0
投票

我想编写一个基于framebuffer的程序的,只是因为我需要能够滚动(SDR瀑布)。见https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=232493&p=1425567#p1425567滚动测试,我认为成功的。在这2层结构,我们通过IOCTL获取的信息有也对颜色深度的东西。你似乎已经根据你对我做了同样的例子程序。 How to get pixel colour from framebuffer on linux (Raspberry Pi)

防雷工程罚款我的树莓派,无论是与X或没有。它在我的笔记本电脑屏幕上没有任何影响。这有一个的/ dev / fb0设备,程序运行和数据看起来正确的,但它确实没有什么直观。也许这是双缓冲或东西。

在X它实际上并没有做任何损害。如果您拖动这样的事情重绘一些窗口都回来了。然后,我决定要备份什么是在屏幕上,并把它放回去我做的时候,那也可以。我感动,放回到一个窗口的工作原理一样,如果我从来没有碰过它。 X并没有意识到我已经与屏幕缓冲区搞砸,它知道它放在那里,并相应寄存器鼠标点击。如果我移动的窗口,并没有把它放回去的点击仍然能工作在哪里。

© www.soinside.com 2019 - 2024. All rights reserved.