FrameBuffer应用编程

FrameBuffer应用编程

步骤:

  1. 首先打开/dev/fbX 设备文件。
  2. 使用 ioctl()函数获取到当前显示设备的参数信息,譬如屏幕的分辨率大小、像素格式,根据屏幕参
    数计算显示缓冲区的大小。
  3. 通过存储映射 I/O 方式将屏幕的显示缓冲区映射到用户空间(mmap)。
  4. 映射成功后就可以直接读写屏幕的显示缓冲区,进行绘图或图片显示等操作了。
  5. 完成显示后, 调用 munmap()取消映射、并调用 close()关闭设备文件。

一、使用 ioctl()获取屏幕参数信息

#include <linux/fb.h>

#define FBIOGET_VSCREENINFO	0x4600
#define FBIOPUT_VSCREENINFO	0x4601
#define FBIOGET_FSCREENINFO	0x4602

FBIOGET_VSCREENINFO:表示获取 FrameBuffer 设备的可变参数信息,可变参数信息使用 struct fb_var_screeninfo 结 构 体 来 描 述 , 所 以 此 时 ioctl() 需 要 有 第 三 个 参 数 , 它 是 一 个 struct fb_var_screeninfo *指针,指向 struct fb_var_screeninfo 类型对象

struct fb_var_screeninfo fb_var;

ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);

FBIOPUT_VSCREENINFO:表示设置 FrameBuffer 设备的可变参数信息,既然是可变参数,那说明应用层可对其 进行修改、重新配置。尽量别去动它

FBIOGET_FSCREENINFO:表示获取 FrameBuffer 设备的固定参数信息,既然是固定参数,那就
意味着应用程序不可修改。固定参数信息使用struct fb_fix_screeninfo结构体来描述,所以此时ioctl()
需要有第三个参数,它是一个 struct fb_fix_screeninfo *指针

struct fb_fix_screeninfo fb_fix;

ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
struct fb_var_screeninfo {
	__u32 xres; /* 可视区域,一行有多少个像素点, X 分辨率 */
	__u32 yres; /* 可视区域,一列有多少个像素点, Y 分辨率 */
	__u32 xres_virtual; /* 虚拟区域,一行有多少个像素点 */
	__u32 yres_virtual; /* 虚拟区域,一列有多少个像素点 */
	__u32 xoffset; /* 虚拟到可见屏幕之间的行偏移 */
	__u32 yoffset; /* 虚拟到可见屏幕之间的列偏移 */
    __u32 bits_per_pixel; /* 每个像素点使用多少个 bit 来描述,也就是像素深度 bpp */
	__u32 grayscale; /* =0 表示彩色, =1 表示灰度, >1 表示 FOURCC 颜色 */
	/* 用于描述 R、 G、 B 三种颜色分量分别用多少位来表示以及它们各自的偏移量 */
	struct fb_bitfield red; /* Red 颜色分量色域偏移 */
	struct fb_bitfield green; /* Green 颜色分量色域偏移 */
	struct fb_bitfield blue; /* Blue 颜色分量色域偏移 */
	struct fb_bitfield transp; /* 透明度分量色域偏移 */
	__u32 nonstd; /* nonstd 等于 0,表示标准像素格式;不等于 0 则表示非标准像素格式 */
	__u32 activate;
	__u32 height; /* 用来描述 LCD 屏显示图像的高度(以毫米为单位) */
	__u32 width; /* 用来描述 LCD 屏显示图像的宽度(以毫米为单位) */
	__u32 accel_flags;
	/* 以下这些变量表示时序参数 */
	__u32 pixclock; /* pixel clock in ps (pico seconds) */
	__u32 left_margin; /* time from sync to picture */
	__u32 right_margin; /* time from picture to sync */
	__u32 upper_margin; /* time from sync to picture */
	__u32 lower_margin;
	__u32 hsync_len; /* length of horizontal sync */
	__u32 vsync_len; /* length of vertical sync */
	__u32 sync; /* see FB_SYNC_* */
	__u32 vmode; /* see FB_VMODE_* */
	__u32 rotate; /* angle we rotate counter clockwise */
	__u32 colorspace; /* colorspace for FOURCC-based modes */
	__u32 reserved[4]; /* Reserved for future compatibility */
};
struct fb_bitfield {
	__u32 offset; /* 偏移量 */
	__u32 length; /* 长度 */
	__u32 msb_right; /* != 0 : Most significant bit is right */
};
struct fb_fix_screeninfo {
	char id[16]; /* 字符串形式的标识符 */
	unsigned long smem_start; /* 显存的起始地址(物理地址) */
	__u32 smem_len; /* 显存的长度 */
	__u32 type;
	__u32 type_aux;
	__u32 visual;
	__u16 xpanstep;
	__u16 ypanstep;
	__u16 ywrapstep;
	__u32 line_length; /* 一行的字节数 */
	unsigned long mmio_start; /* Start of Memory Mapped I/O(physical address) */
	__u32 mmio_len; /* Length of Memory Mapped I/O */
	__u32 accel; /* Indicate to driver which specific chip/card we have */
	__u16 capabilities;
	__u16 reserved[2];
};

获取屏幕分辨率、像素深度、RGB格式

#include <linux/fb.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>

int main(int argc,char * argv[])
{
    int fd;
    struct fb_var_screeninfo fb_var;
    struct fb_fix_screeninfo fb_fix;

    if(2!=argc){
        fprintf(stderr,"argc err\n");
        exit(1);
    }

    fd=open(argv[1],O_WRONLY);
    if(-1==fd){
        perror("open err\n");
        exit(1);
    }
    ioctl(fd,FBIOGET_VSCREENINFO,&fb_var);
    ioctl(fd,FBIOGET_FSCREENINFO,&fb_fix);

    printf("分辨率:%d*%d\n",fb_var.xres,fb_var.yres);
    printf("像素深度bpp:%d\n",fb_var.bits_per_pixel);
    printf("一行的字节数:%d\n",fb_fix.line_length);
    printf("像素格式:Red<偏移量:%d,长度:%d>,Green<偏移量:%d,长度:%d>,Blue<偏移量:%d,长度:%d>\n",fb_var.red.offset,fb_var.red.length,
    fb_var.green.offset,fb_var.green.length,fb_var.blue.offset,fb_var.blue.length);

    exit(0);
}

二、存储映射I/O

[存储映射I/O]((23条消息) 嵌入式Linux中高级I/O的常用知识点_sharp_OvO的博客-CSDN博客)

三、LCD中显示BMP图片

1.BMP图片组成

典型的 BMP 图像文件由四部分组成:

  • BMP 文件头14Byte),它包含 BMP 文件的格式、大小、 位图数据的偏移量等信息;

  • 位图信息头40或56Byte) ,它包含位图信息头大小、 图像的尺寸、 图像大小、 位平面数、
    压缩方式以及颜色索引等信息;

  • 调色板,这部分是可选的,如果使用索引来表示图像, 调色板就是索引与其对应颜色的映射表;(真彩色图像不需要调色板

  • 位图数据,也就是图像数据。

     //bmp 文件头定义了如下结构体:
    typedef struct tagBITMAPFILEHEADER
    {
    	UINT16 bfType;			//说明 bmp 文件的类型,可取值为:BM – Windows
    	DWORD bfSize;			//4个字节,说明该文件的大小,以字节为单位。
    	UINT16 bfReserved1;		//保留字段,必须设置为 0。
    	UINT16 bfReserved2;		//保留字段,必须设置为 0。
    	DWORD bfOffBits;		//说明从文件起始位置到图像数据之间的字节偏移量。
    } BITMAPFILEHEADER;
    

    bfType:说明 bmp 文件的类型(实验中用到的是BM);

    bfSize:说明该文件的大小;

    bfOffBits:说明从文件起始位置到图像数据之间的字节偏移量。(重要

    //位图信息头定义了如下结构体:
    typedef struct tagBITMAPINFOHEADER {
    	DWORD biSize;				//位图信息头大小
    	LONG biWidth;				//图像的宽度,以像素为单位(4byte)
    	LONG biHeight;				//图像的高度,以像素为单位(4byte)
    	WORD biPlanes;
    	WORD biBitCount;			//像素深度,指明一个像素点需要多少个 bit 数据来描述(2byte)
    	DWORD biCompression;
    	DWORD biSizeImage;
    	LONG biXPelsPerMeter;		//水平分辨率,用像素/米来表示,有符号整数。
    	LONG biYPelsPerMeter;		//垂直分辨率,用像素/米来表示,有符号整数
    	DWORD biClrUsed;
    	DWORD biClrImportant;
    } BITMAPINFOHEADER;
    

    biHeight:这个值除了用于描述图像的高度之外, 它还有另外一个用途,用于指明该图像是倒向 的位图、还是正向的位图。 如果该值是一个正数,说明是倒向的位图;如 果该值是一个负数,则说明是正向的位图。 一般情况下, BMP 图像都是倒向的位图,也就 是该值是一个正数。

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    #include <string.h>
    #include <linux/fb.h>
    #include <sys/mman.h>
    
    /**** BMP文件头数据结构 ****/
    typedef struct {
        unsigned char type[2];      //文件类型
        unsigned int size;          //文件大小
        unsigned short reserved1;   //保留字段1
        unsigned short reserved2;       //保留字段2
        unsigned int offset;        //到位图数据的偏移量
    } __attribute__ ((packed)) bmp_file_header;
    
    /**** 位图信息头数据结构 ****/
    typedef struct {
        unsigned int size;          //位图信息头大小
        int width;                  //图像宽度
        int height;                 //图像高度
        unsigned short planes;          //位面数
        unsigned short bpp;         //像素深度 
        unsigned int compression;   //压缩方式
        unsigned int image_size;    //图像大小
        int x_pels_per_meter;       //像素/米
        int y_pels_per_meter;       //像素/米 
        unsigned int clr_used;
        unsigned int clr_omportant;
    } __attribute__ ((packed)) bmp_info_header;
    
    /**** 静态全局变量 ****/
    static int width;                       //LCD X分辨率
    static int height;                      //LCD Y分辨率
    static unsigned short *screen_base = NULL;        //映射后的显存基地址
    static unsigned long line_length;       //LCD一行的长度(字节为单位)
    
    /********************************************************************
     * 函数名称: show_bmp_image
     * 功能描述: 在LCD上显示指定的BMP图片
     * 输入参数: 文件路径
     * 返 回 值: 成功返回0, 失败返回-1
     ********************************************************************/
    static int show_bmp_image(const char *path)
    {
        bmp_file_header file_h;
        bmp_info_header info_h;
        unsigned short *line_buf = NULL;    //行缓冲区
        unsigned long line_bytes;   //BMP图像一行的字节的大小
        unsigned int min_h, min_bytes;
        int fd = -1;
        int j;
    
        /* 打开文件 */
        if (0 > (fd = open(path, O_RDONLY))) {
            perror("open error");
            return -1;
        }
    
        /* 读取BMP文件头 */
        if (sizeof(bmp_file_header) !=
            read(fd, &file_h, sizeof(bmp_file_header))) {
            perror("read error");
            close(fd);
            return -1;
        }
    
        if (0 != memcmp(file_h.type, "BM", 2)) {
            fprintf(stderr, "it's not a BMP file\n");
            close(fd);
            return -1;
        }
    
        /* 读取位图信息头 */
        if (sizeof(bmp_info_header) !=
            read(fd, &info_h, sizeof(bmp_info_header))) {
            perror("read error");
            close(fd);
            return -1;
        }
    
        /* 打印信息 */
        printf("文件大小: %d\n"
             "位图数据的偏移量: %d\n"
             "位图信息头大小: %d\n"
             "图像分辨率: %d*%d\n"
             "像素深度: %d\n", file_h.size, file_h.offset,
             info_h.size, info_h.width, info_h.height,
             info_h.bpp);
    
        /* 将文件读写位置移动到图像数据开始处 */
        if (-1 == lseek(fd, file_h.offset, SEEK_SET)) {
            perror("lseek error");
            close(fd);
            return -1;
        }
    
        /* 申请一个buf、暂存bmp图像的一行数据 */
        line_bytes = info_h.width * info_h.bpp / 8;
        line_buf = malloc(line_bytes);
        if (NULL == line_buf) {
            fprintf(stderr, "malloc error\n");
            close(fd);
            return -1;
        }
    
        if (line_length > line_bytes)
            min_bytes = line_bytes;
        else
            min_bytes = line_length;
    
        /**** 读取图像数据显示到LCD ****/
        /*******************************************
         * 为了软件处理上方便,这个示例代码便不去做兼容性设计了
         * 如果你想做兼容, 可能需要判断传入的BMP图像是565还是888
         * 如何判断呢?文档里边说的很清楚了
         * 我们默认传入的bmp图像是RGB565格式
         *******************************************/
        if (0 < info_h.height) {//倒向位图
            if (info_h.height > height) {
                min_h = height;
                lseek(fd, (info_h.height - height) * line_bytes, SEEK_CUR);
                screen_base += width * (height - 1);    //定位到屏幕左下角位置
            }
            else {
                min_h = info_h.height;
                screen_base += width * (info_h.height - 1); //定位到....不知怎么描述 懂的人自然懂!
            }
    
            for (j = min_h; j > 0; screen_base -= width, j--) {
                read(fd, line_buf, line_bytes); //读取出图像数据
                memcpy(screen_base, line_buf, min_bytes);//刷入LCD显存
            }
        }
        else {  //正向位图
            int temp = 0 - info_h.height;   //负数转成正数
            if (temp > height)
                min_h = height;
            else
                min_h = temp;
    
            for (j = 0; j < min_h; j++, screen_base += width) {
                read(fd, line_buf, line_bytes);
                memcpy(screen_base, line_buf, min_bytes);
            }
        }
    
        /* 关闭文件、函数返回 */
        close(fd);
        free(line_buf);
        return 0;
    }
    
    int main(int argc, char *argv[])
    {
        struct fb_fix_screeninfo fb_fix;
        struct fb_var_screeninfo fb_var;
        unsigned int screen_size;
        int fd;
    
        /* 传参校验 */
        if (2 != argc) {
            fprintf(stderr, "usage: %s <bmp_file>\n", argv[0]);
            exit(-1);
        }
    
        /* 打开framebuffer设备 */
        if (0 > (fd = open("/dev/fb0", O_RDWR))) {
            perror("open error");
            exit(EXIT_FAILURE);
        }
    
        /* 获取参数信息 */
        ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
        ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
    
        screen_size = fb_fix.line_length * fb_var.yres;
        line_length = fb_fix.line_length;
        width = fb_var.xres;
        height = fb_var.yres;
    
        /* 将显示缓冲区映射到进程地址空间 */
        screen_base = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);
        if (MAP_FAILED == (void *)screen_base) {
            perror("mmap error");
            close(fd);
            exit(EXIT_FAILURE);
        }
    
        /* 显示BMP图片 */
        memset(screen_base, 0xFF, screen_size);
        show_bmp_image(argv[1]);
    
        /* 退出 */
        munmap(screen_base, screen_size);  //取消映射
        close(fd);  //关闭文件
        exit(EXIT_SUCCESS);    //退出进程
    }
    
    
    
    
    
    
    
    
    
    
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值