文章的开始,想要申明一下:我的目的是在整个屏幕上显示红色。关于Framebuffer的原理知识我很少涉及,请读者自己查阅相关书籍或者上网查找资料。
开发环境:
物理机(不是虚拟机)Ubuntu 11.04
最近在作一个视频采集显示的东西,要用到Framebuffer,就看了点相关的知识。在这里稍微总结一下。
Framebuffer对应的文件是/dev/fb0。
这里我说明两点:
1.如果在/dev目录下没有fb0文件,那就重新启动试试。一开始我的电脑上也没有fb0文件,我就瞎捣鼓了一下Nvidia X Server Settings,修改了显示器设置参数,又重新启动了电脑就出现fb0文件了,具体原因我不知道(根据我的做事原则-用最简单、最有效、最直接的方法解决问题。我的目的是要显示器显示红色,既然我搞出来fb0文件了,离目的又进了一步,也就没有深究为什么)。
2.修改下fb0文件的权限,否则会在以后运行程序时出现无法打开文件的错误。
sudo chmod 666 /dev/fb0
操作Framebuffer的步骤如下:
1.打开文件:open函数
2.映射帧缓冲到应用程序空间:mmap函数
3.操作映射后的内存空间,在这里就是将红色对应的RGB和透析度的数值写到相关的内存空间内。
4.释放映射空间和关闭文件描述符。
程序总共两个:
1.第一个程序如下:
很简单的一个程序,就是打印出Framebuffer的一些相关信息,就是fb_var_screeninfo 和fb_fix_screeninfo 两个结构体主要成员的打印。
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <sys/ioctl.h> int main (int argc,char **argv ){ int fb_fd=-1; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; fb_fd = open("/dev/fb0",O_RDWR); if (fb_fd < 0){ printf("Error : Can not open framebuffer device\n"); exit(EXIT_FAILURE); } if(ioctl(fb_fd,FBIOGET_FSCREENINFO,&finfo)){ printf("Error reading fixed information\n"); exit(EXIT_FAILURE); } if (ioctl(fb_fd,FBIOGET_VSCREENINFO,&vinfo)){ printf("Error reading variable information\n"); exit(3); } printf("the fixed information is as follow:\n"); printf("id=%s\n",finfo.id); printf("sem_start=%lx\n",finfo.smem_start); printf("smem_len=%u\n",finfo.smem_len); printf("type=%u\n",finfo.type); printf("line_length=%u\n",finfo.line_length); printf("mmio_start=%lu\n",finfo.mmio_start); printf("mmio_len=%d\n",finfo.mmio_len); printf("variable information is as follow:\n"); printf("The xres is :%u\n",vinfo.xres); printf("The yres is :%u\n",vinfo.yres); printf("xres_virtual=%u\n",vinfo.xres_virtual); printf("yres_virtual=%u\n",vinfo.yres_virtual); printf("xoffset=%u\n",vinfo.xoffset); printf("yoffset=%u\n",vinfo.yoffset); printf("bits_per_pixel is :%u\n",vinfo.bits_per_pixel); printf("red.offset=%u\n",vinfo.red.offset); printf("red.length=%u\n",vinfo.red.length); printf("red.msb_right=%u\n",vinfo.red.msb_right); printf("green.offset=%d\n",vinfo.green.offset); printf("green.length=%d\n",vinfo.green.length); printf("green.msb_right=%d\n",vinfo.green.msb_right); printf("blue.offset=%d\n",vinfo.blue.offset); printf("blue.length=%d\n",vinfo.blue.length); printf("blue.msb_right=%d\n",vinfo.blue.msb_right); printf("transp.offset=%d\n",vinfo.transp.offset); printf("transp.length=%d\n",vinfo.transp.length); printf("transp.msb_right=%d\n",vinfo.transp.msb_right); printf("height=%x\n",vinfo.height); printf("width=%x\n",vinfo.width); close (fb_fd); return 0; }
the fixed information is as follow: id=VESA VGA sem_start=cf000000 smem_len=1245184 type=0 line_length=2560 mmio_start=0 mmio_len=0 variable information is as follow: The xres is :640 The yres is :480 xres_virtual=640 yres_virtual=480 xoffset=0 yoffset=0 bits_per_pixel is :32 red.offset=16 red.length=8 red.msb_right=0 green.offset=8 green.length=8 green.msb_right=0 blue.offset=0 blue.length=8 blue.msb_right=0 transp.offset=24 transp.length=8 transp.msb_right=0 height=ffffffff width=ffffffff
有几个输出要重视:
The xres is :640
The yres is :480//虚拟控制台屏幕的分辨率(虚拟控制台,即:Ctrl+Alt+Fn(n=1,2,3,4,5,6)时进入的控制台。我的机器是物理机,虚拟机没有尝试过)
bits_per_pixel is :32//一个像素点占用32位,也就是说明像素点对应的内存中存放的RGB32(R、G、B各占8位,剩下的八位用来存放透析度(不知道是什么东西,也没管它))数据。这里有个问题很重要啊:到底这32位的数据怎么存放的的呢?????最低的八位放R、G、B还是透析度数据呢。。。。。。接着往下看---------
red.offset=16//看来R数据放在32数据中的16-23上
red.length=8
red.msb_right=0//指的是数据的最高有效位在最左边
green.offset=8//看来G数据放在32数据中的8-15上
green.length=8
green.msb_right=0
blue.offset=0//看来B数据放在32数据中的0-7上
blue.length=8
blue.msb_right=0
transp.offset=24//看来透析度数据放在32数据中的24-31上
transp.length=8
transp.msb_right=0
以上内容一定要明白,否则先别往下看,查查资料先把理论搞明白再说。
2.第二个程序如下:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> #include <sys/ioctl.h> #define IMAGE_W 640 //对应上一个程序的xres #define IMAGE_H 480 //对应上一个程序的yres typedef struct { char red; char blue; char green; char trans; } PIXEL; //自定义的结构体用于存放一个像素点的颜色数据,这里比较简单就是存放红色的RGB和透析度数据 int main(){ PIXEL pixel; pixel.trans=0; pixel.red=255; pixel.green=0; pixel.blue=0; //查表得到。。。。程序后面有插图 int fb_fd=0,i=0,j=0; unsigned long int *fbp,*mmap_start; unsigned long buffersize; char * cur_pix; struct fb_var_screeninfo vinfo; struct fb_fix_screeninfo finfo; fb_fd = open("/dev/fb0",O_RDWR); if (fb_fd < 0){ printf("Error : Can not open framebuffer device\n"); exit(1); } if(ioctl(fb_fd,FBIOGET_FSCREENINFO,&finfo)){ printf("Error reading fixed information\n"); exit(2); } if (ioctl(fb_fd,FBIOGET_VSCREENINFO,&vinfo)){ printf("Error reading variable information\n"); exit(3); } /* printf("The xres is :%d\n",vinfo.xres); printf("The yres is :%d\n",vinfo.yres); printf("bits_per_pixel is :%d\n",vinfo.bits_per_pixel); */ buffersize=vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8; mmap_start=(unsigned long int *)mmap(0,buffersize,PROT_READ | PROT_WRITE,MAP_SHARED,fb_fd,0); if((long int )mmap_start==-1){ perror("mmap error!\n"); exit(EXIT_FAILURE); } fbp=mmap_start; for(i=0;i<IMAGE_H;i++){ for(j=0;j<IMAGE_W;j++){ cur_pix=(char *)fbp; cur_pix[0]=pixel.blue; cur_pix[1]=pixel.green; cur_pix[2]=pixel.red; cur_pix[3]=pixel.trans; fbp++; } } munmap(mmap_start,buffersize); close (fb_fd); return 0; } }
查表可得红色对应的RGB数据是0xFF0000 。
现在请按下组合键(Ctrl+Alt+Fn(n=1,2,3,4,5,6))进入虚拟控制台,通过cd命令转到存放源程序的目录下,编译后运行,是不是屏幕全变成红色了呢?