如何从Linux帧缓冲区获取RGB像素值?

时间:2017-10-21 18:42:06

标签: c linux linux-kernel device-driver framebuffer

我希望使用Linux以最有效的方式获取屏幕像素的RGB值。所以我决定在C( fb.h )中使用framebuffer库来访问framebuffer设备( / dev / fb0 )并直接读取它。

这是代码:

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

int main() {

    int fb_fd;
    struct fb_fix_screeninfo finfo;
    struct fb_var_screeninfo vinfo;
    uint8_t *fb_p;

    /* Open the frame buffer device */
    fb_fd = open("/dev/fb0", O_RDWR);
    if (fb_fd < 0) {
        perror("Can't open /dev/fb0\n");
        exit(EXIT_FAILURE);
    }

    /* Get fixed info */
    if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
        perror("Can't get fixed info\n");
        exit(EXIT_FAILURE);
    }

    /* Get variable info */
    if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
        perror("Can't get variable info\n");
        exit(EXIT_FAILURE);
    }

    /* To access to the memory, it can be mapped*/
    fb_p = (uint8_t *) mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    if (fb_p == MAP_FAILED) {
        perror("Can't map memory\n");
        exit(EXIT_FAILURE);
    }

    /* Print each byte of the frame buffer */
    for (int i = 0; i < finfo.smem_len; i++) {
        printf("%d\n", *(fb_p + i));

        // for (int j = 0; j < 500000000; j++);       /* Delay */
    }

    munmap(fb_p, 0);
        close(fb_fd);

    return 0;
}

但是当我打印出这些价值观时,我并没有得到我所期待的......

如果我使用像 grabc 这样的工具选择像素(0,0)的RGB值,我会得到:

#85377e
133,55,126

但是我的代码首次打印是:

126
145
198
...

看起来我很好地获得了第一个像素的第一个值,对应于蓝色,但其余的都是错误的。

3 个答案:

答案 0 :(得分:4)

在一些使用fbdev的稀有越野车设备中,您可能需要将mmap返回的指针对齐到下一个system page,以便正确获取第一个像素,这样做可能还需要再绘制一个页面。

我不认为这是你的情况,看起来你正试图通过使用linux fbdev获取xserver桌面像素,除非你的xserver配置为使用fbdev驱动程序(和即便如此,我也不确定会工作)是不会工作的。 如果阅读桌面像素是您的目标,您应该查看一些截图工具。

此外,fbdev驱动程序通常是基本的,是低级访问,但是没有关于映射和读取像素的效率,Xlib或任何更高级别的图形系统可能知道并支持您的图形卡加速度和效率更高(可能使用DMA将整个帧缓冲区读取到系统内存而不加载cpu)。

答案 1 :(得分:3)

如果你看看抓取源代码(https://www.muquit.com/muquit/software/grabc/grabc.html),你会发现他正在查询X Windows(而 NOT 硬件帧缓冲本身)。

root_window=XRootWindow(display,XDefaultScreen(display));
target_window=selectWindow(display,&x,&y);
...
ximage=XGetImage(display,target_window,x,y,1,1,AllPlanes,ZPixmap);
...
color->pixel=XGetPixel(ximage,0,0);
XDestroyImage(ximage);

无论价值多少 - 出于几个不同的原因 - 我强烈建议你考虑做同样的事情。

您可能也对以下内容感兴趣:

答案 2 :(得分:1)

在iOS上工作时,有一个私有框架iOMobileFrameBuffer,并为屏幕创建了一个可爱的录制软件。我之前已经涉足过,所以我会告诉你我所知道的。 iOS明显不同于Linux FrameBuffer(缺少文档很相似......)但我个人会看一下this 的答案。虽然问题不符合您的要求,但该答案解释了PixelBuffer以及您提出的确切问题的一个小例子。如有任何问题,请阅读并回复,我会尽我所能回答。