Linux的帧缓冲(Frame Buffer)之三:LCD上显示摄像头

一个简单的应用程序,来实现在LCD上显示当前camera的图像数据,也可以根据键盘输入保存摄像头数据到BMP图片中。

(1) 如下:

         文件头和全局变量:

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4. #include <fcntl.h>  
  5. #include <unistd.h>  
  6. #include <ctype.h>  
  7. #include <errno.h>  
  8. #include <sys/mman.h>  
  9. #include <sys/time.h>  
  10. #include <sys/ioctl.h>  
  11. #include <asm/types.h>   
  12. #include <linux/videodev2.h>  
  13. #include <linux/fb.h>  
  14.   
  15. static unsigned int capframe = 0;       //保存的图片计数  
  16. static char filename[30];       //保存的图片文件名  
  17. FILE *bmpFile;                  //保存图片时创建的文件指针  
  18.   
  19. unsigned char bmp_head_t[] = {          //66字节的BMP位图头  
  20.          0x42,0x4d,0x42,0x58,0x02,0x00,0x00,0x00,0x00,0x00,  
  21.         0x42,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0xf0,0x00,  
  22.         0x00,0x00,0x40,0x01,0x00,0x00,0x01,0x00,0x10,0x00,  
  23.         0x03,0x00,0x00,0x00,0x00,0x58,0x02,0x00,0x00,0x00,  
  24.         0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,  
  25.         0x00,0x00,0x00,0x00,0x00,0xf8,0x00,0x00,0xe0,0x07,  
  26.         0x00,0x00,0x1f,0x00,0x00,0x00  
  27. };  
  28. static char *vf_buff;       //从摄像头读取数据保存的内存指针  
  29. static int fb_bpp;              //帧缓冲设备的每像素位数  
  30. unsigned char bmp_head[54];         //54字节的BMP位图头  
  31.   
  32. static int cam_fp = -1;         //打开的摄像头句柄  
  33. static int fb_fp = -1;          //打开的帧缓冲句柄  
  34. static char *fb_addr = NULL;        //帧缓冲mmap的映射返回地址  
  35. static char *cam_name = "/dev/video1";  //摄像头设备路径和名字  
  36. int width=0;                //帧缓冲的resolution width  
  37. int height=0;               //帧缓冲的resolution height  

          主函数如下:

[cpp]  view plain  copy
  1. int main(int argc, char *argv[])  
  2. {  
  3.     struct timeval tv1;     //监控键盘输入的select时间参数  
  4.     unsigned long size;     //一帧画面的字节数  
  5.     int index=0;            //V4L2 input索引号  
  6.     struct v4l2_capability cap;     //V4L2设备功能结构体变量  
  7.     struct v4l2_input i;        //V4L2设备输入信息  
  8.     struct v4l2_framebuffer fb;     //V4L2的一帧设备缓存  
  9.     int on=1;               //控制V4L2设备overlay的参数  
  10.     int tmp;  
  11.     fd_set fds1;            //监控键盘输入的select fd_set变量  
  12.     int fd;             //监控键盘输入的select句柄  
  13.     char cmd[256];          //存储从键盘读入的字符串  
  14.       
  15.     cam_fp = cam_init();        //获得摄像头句柄  
  16.     fb_fp = fb_init();          //获得帧缓冲句柄  
  17.       
  18.     size=width*height*fb_bpp/8;  
  19.   
  20.     if((tmp=ioctl(cam_fp, VIDIOC_QUERYCAP, &cap))<0) {       //查询驱动功能  
  21.         printf("VIDIOC_QUERYCAP error, ret=0x%x\n",tmp);  
  22.         goto err;  
  23.     }  
  24.     printf("Driver:%s, Card:%s, cap=0x%x\n",cap.driver,cap.card,cap.capabilities);  
  25.       
  26.     memset(&i, 0, sizeof(i));  
  27.     i.index=index;  
  28.     if(ioctl(cam_fp, VIDIOC_ENUMINPUT, &i)<0)        //枚举输入源  
  29.         goto err;  
  30.     printf("input name:%s\n",i.name);     
  31.       
  32.     index=0;  
  33.     if(ioctl(cam_fp, VIDIOC_S_INPUT, &index)<0)      //设置输入源  
  34.         goto err;  
  35.   
  36.     if(ioctl(cam_fp, VIDIOC_S_OUTPUT, &index)<0)     //设置输出源  
  37.             goto err;  
  38.   
  39.     if(ioctl(cam_fp, VIDIOC_G_FBUF, &fb)<0)      //获取V4L2设备FB属性参数  
  40.         goto err;  
  41.     printf("g_fbuf:capabilities=0x%x,flags=0x%x,width=%d,height=%d\npixelformat=0x%x,bytesperline=%d,colorspace=%d,base=0x%x\n",  
  42.         fb.capability,fb.flags,fb.fmt.width,fb.fmt.height,fb.fmt.pixelformat,  
  43.         fb.fmt.bytesperline,fb.fmt.colorspace,fb.base);  
  44.     fb.capability = cap.capabilities;           //V4L2设备功能赋值给V4L2的FB功能属性  
  45.     fb.fmt.width =width;                //LCD的FB宽度赋值给V4L2的FB宽度  
  46.     fb.fmt.height = height;             //LCD的FB高度赋值给V4L2的FB高度  
  47.     fb.fmt.pixelformat = (fb_bpp==32)?V4L2_PIX_FMT_BGR32:V4L2_PIX_FMT_RGB565;       //赋值V4L2的FB像素位数  
  48.   
  49.     if(ioctl(cam_fp, VIDIOC_S_FBUF, &fb)<0)      //设置新的FB属性给摄像头  
  50.         goto err;  
  51.     on = 1;  
  52.     if(ioctl(cam_fp, VIDIOC_OVERLAY, &on)<0)     //使能摄像头的overlay  
  53.         goto err;  
  54.       
  55.     vf_buff = (char*)malloc(size);  
  56.     if(vf_buff==NULL)  
  57.         goto err;  
  58.   
  59.     if(fb_bpp==16){         //16位BMP  
  60.         *((unsigned int*)(bmp_head_t+18)) = width;  
  61.         *((unsigned int*)(bmp_head_t+22)) = height;  
  62.         *((unsigned short*)(bmp_head_t+28)) = 16;  
  63.     }else{  
  64.     bmp_head[0] = 'B';  
  65.     bmp_head[1] = 'M';  
  66.     *((unsigned int*)(bmp_head+2)) = (width*fb_bpp/8)*height+54;        //整个位图大小  
  67.     *((unsigned int*)(bmp_head+10)) = 54;               //从54字节开始存图像  
  68.     *((unsigned int*)(bmp_head+14)) = 40;               //图像描述信息块的大小  
  69.     *((unsigned int*)(bmp_head+18)) = width;  
  70.     *((unsigned int*)(bmp_head+22)) = height;  
  71.     *((unsigned short*)(bmp_head+26)) = 1;              //图像的plane总数  
  72.     *((unsigned short*)(bmp_head+28)) = fb_bpp;  
  73.     *((unsigned short*)(bmp_head+34)) = (width*fb_bpp/8)*height;        //图像数据区大小  
  74.     }  
  75.       
  76.     while(1)  
  77.     {  
  78.         if (!read_data(cam_fp, vf_buff, width, height, fb_bpp))     //读摄像头数据到vf_buff  
  79.         {  
  80.         printf("read error\n");  
  81.         }  
  82.         memcpy(fb_addr,vf_buff,width*height*fb_bpp/8);      //将读到的图像数据从内存拷贝到帧缓冲地址  
  83.         fd=0;                           //键盘句柄  
  84.         tv1.tv_sec=0;  
  85.         tv1.tv_usec=0;                      //无限等待  
  86.         FD_ZERO(&fds1);  
  87.         FD_SET(fd,&fds1);                   //绑定句柄跟监控对象  
  88.         select(fd+1,&fds1,NULL,NULL,&tv1);          //监控键盘输入  
  89.         if(FD_ISSET(fd,&fds1))                  //如果键盘有输入  
  90.         {  
  91.         memset(cmd,0,sizeof(cmd));  
  92.         read(fd,cmd,256);                   //读取键盘输入的字符  
  93.         if(strncmp(cmd,"quit",4)==0){           //如果键盘输入quit  
  94.             printf("-->quit\n");  
  95.             on=0;  
  96.             if(ioctl(cam_fp, VIDIOC_OVERLAY, &on)<0)     //关掉V4L2设备的overlay  
  97.             goto err;  
  98.             close(fb_fp);  
  99.             close(cam_fp);                  //释放FB跟摄像头的句柄  
  100.             return 0;  
  101.         }else if(strncmp(cmd,"capt",4)==0){         //如果键盘输入capt  
  102.             printf("-->capture\n");  
  103.             printf("write to img --> ");  
  104.             writeImageToFile(size);             //把FB数据保存到位图中  
  105.             printf("OK\n");  
  106.         }  
  107.         }  
  108.     }  
  109.   
  110. err:  
  111.     if (cam_fp)  
  112.         close(cam_fp);  
  113.     if (fb_fp)  
  114.         close(fb_fp);  
  115.     return 1;  
  116. }  

(2)子函数叙述如下。FB和摄像头的初始化如下:

[cpp]  view plain  copy
  1. static inline int fb_init(void)  
  2. {  
  3.     int dev_fp = -1;  
  4.     int fb_size;  
  5.     struct fb_var_screeninfo vinfo;  
  6.   
  7.     dev_fp = open("/dev/graphics/fb0", O_RDWR);  
  8.     if (dev_fp < 0) {  
  9.         perror("/dev/fb0");  
  10.         return -1;  
  11.     }  
  12.     if (ioctl(dev_fp, FBIOGET_VSCREENINFO, &vinfo)) {   //获取FB基本信息  
  13.             printf("Error reading variable information.\n");  
  14.         exit(1);  
  15.     }  
  16.     width=vinfo.xres;  
  17.     height=vinfo.yres;  
  18.     fb_bpp=vinfo.bits_per_pixel;    //将FB值赋值给全局变量  
  19.     if(fb_bpp==24) fb_bpp=32;  
  20.     fb_size=width*height*fb_bpp/8;  //一帧FB的字节大小  
  21.     if ((fb_addr = (char*)mmap(0, fb_size,    
  22.             PROT_READ | PROT_WRITE, MAP_SHARED, dev_fp, 0)) < 0) {   //从文件的0位置开始在内存中自动映射fb_size大小空间  
  23.         perror("mmap()");  
  24.         return -1;  
  25.     }  
  26.     printf("%dx%d bpp:%d mmaped 0x%08x\n",width,height,fb_bpp,fb_addr);  
  27.   
  28.     return dev_fp;  
  29. }  
  30. static inline int cam_init(void)  
  31. {  
  32.     int dev_fp = -1;  
  33.   
  34.     dev_fp = open(cam_name, O_RDWR);  
  35.     if (dev_fp < 0) {  
  36.         printf("error open %s\n",cam_name);  
  37.         return -1;  
  38.     }  
  39.   
  40.     return dev_fp;  
  41. }  

       从摄像头读数据到内存中:

[cpp]  view plain  copy
  1. static inline int read_data(int fp, char *buf, int width, int height, int bpp)  
  2. {  
  3.     int ret=0;  
  4.     if ((ret = read(fp, buf, (width*height*bpp/8))) != (width*height*bpp/8)) {  
  5.         printf("read %d--0x%x\n",ret,ret);  
  6.         return 0;  
  7.     }  
  8.     return ret;  
  9. }  

        把内存中图像存储成BMP

[cpp]  view plain  copy
  1. void writeImageToFile(unsigned int size)  
  2. {  
  3.     capframe++;       //图像序号计数  
  4.     sprintf(filename,"/tmp/0%d.bmp",capframe);   //位图的文件名  
  5.     bmpFile=fopen(filename, "w+");      //可写可追加内容的方式创建文件  
  6.     if(fb_bpp == 16)  
  7.         fwrite(bmp_head_t,1,66,bmpFile);  
  8.     else  
  9.         fwrite(bmp_head,1,54,bmpFile);      //往文件中写入BMP位图头  
  10.     fwrite(vf_buff,1,size,bmpFile);         //在继续往文件中追加位图数据  
  11.     fclose(bmpFile);  
  12. }  

(3)使用的makefile如下: 

[cpp]  view plain  copy
  1. CROSS_COMPILE  = /home/zhangcheng/gcc/arm-2008q3/bin/arm-linux-  
  2. CC    = $(CROSS_COMPILE)gcc  
  3.   
  4. cam2fb: cam2fb.c  
  5.     $(CC)  -o cam2fb cam2fb.c -static  

执行make编译后,看到属性是不可执行属性,所以先将其属性改成可执行。通过adb将这个可执行文件拷贝入/data内,先修改其属性后,再用./执行即可。过一会儿,即可在LCD上显示camera捕获的动态图像,同时adb显示如下:

(4)该程序还可以实现输入键盘字符quit退出,输入键盘字符capt保存当前图片到某个目前下成一个BMP,由于没有键盘输入,该部分无法验证。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值