用v4l2和framebuffer实现usb摄像头视频采集并显示

用v4l2和framebuffer实现usb摄像头图像采集并显示

 

前言

很多天了,看了数不尽的论坛和各网站的帖子后,我把我遇到的问题都解决的差不多了,感觉应该是把摄像头跑起来了,但还是遇到了一些问题,似乎是图像处理方面的,我好像解决不了这个问题了,我好想有个人帮帮我。写这篇文章估计得花3~4小时,我真心希望哪位朋友能明白我的想法,能顺手帮帮我。

 

正文

一,我的思路

我想用一幅图来说明我所做的事情,如图1所示(图中uvcdriver标错了,应该是uvcvideo)。

                                                                                                                          图1

 图1左侧是图像采集,右侧是图像显示。采集的帧速是30 帧/秒。

 

二,v4l2(video for linux two)

驱动摄像头的是uvcdriver,该驱动设计时采用了v4l系列的标准(该标准好像是linuxTV制定的,linuxTV的官网是http://linuxtv.org/),我的CentOS6.3(内核是linux-2.6.32.60)采用的是v4l2标准。一开始我编写应用程序的时候什么都不懂,见论坛上帖子怎么讲,我就怎么写,当中很多是参照v4l标准,我当时不知道,直接照抄,出了问题,改用v4l2标准后才解决了问题。v4l2 API的在/usr/include/linux/videodev2.h头文件中,很容易就找到了。

采集图像的实例程序网上很多,但最经典的还是linuxTV官网推出的capture.c,这里给出地址http://linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/v4l2spec/capture.c这个程序写的很好,很值得研究。

我就是借鉴的这个程序,然后得到我的摄像头设备的信息,如图2(那个pixel_format应该用十六进制表示的,我没注意,十六进制的话应该是0x56595559,即YUYV的意思)所示。

                                                                 图2

一插上摄像头,uvcvideo就直接把我的摄像头识别了。

v4l2我不想再多写了,基本上只要看了那个经典的capture.c就够了。

 

三,framebuffer

就目前我这水平,我还不想涉及到QT或者别的什么面向对象编程,我想简单一点,慢慢来。于是我直接选择了framebuffer,它的API在usr/include/linux/fb.h头文件中。刚开始用open函数打开/dev/fb0的时候根本就打不开,愣是要把grub设置一下,如图3所示。后面显示的时候要切记切换到命令行模式。

                                                                                                                                      图3

关于那个vga=0x311以及一系列的frambuffer编程我是参照http://bbs.chinaunix.net/thread-2000076-1-1.html这个人的文章的,这里我复制一下他的一张表到下面,如表1所示。

[csharp]  view plain copy
  1.               4bit        8bit         15bit        16bit        24bit        32bit  
  2.    
  3. 640x400       x           0x300        x            x            x            x  
  4.    
  5. 640x480       x           0x301        0x310        0x311        0x312        x  
  6.    
  7. 800x600       0x302       0x303        0x313        0x314        0x315        x  
  8.    
  9. 1024x768      x           0x305        0x316        0x317        0x318        x  
  10.    
  11. 1280x1024     x           0x307        0x319        0x31A        0x31B        x  
  12.    
  13. 1600x1200     x           0x31C        0x31D        0x31E        0x31F        x  

                                                                                                          表1

 

因为我采集视频的图像时640*480,然后是16bit的BPP,所以我选择了0x311

framebuffer编程很简单,比v4l2简单多了。我截个图来表达我用framebuffer API得到的我的显示屏的信息,如图4所示。

                                                    图4

 四,v4l2+framebuffer

我把v4l和framebuffer集成到一块儿了。因为capture.c图像处理部分没有什么内容,所以,图像处理部分是我自己写的。我的摄像头采集的图像的像素编码是YUYV或者说是YUV422格式,每个像素是16bit。我做的事情就是把YUV422_16转换成RGB565_16,采集的图像尺寸是640*480的,显示屏也是640*480。

对于YUV422_16我想具体一点(因为当初觉得YUV格式很抽象,总是搞不懂)。然后看到一个表好像蛮形象的,我先把表画下来,如表2所示

[csharp]  view plain copy
  1. 像素:Y0U0V0  Y1U1V1  Y2U2V2  Y3U3V3  ...  
  2.   
  3. 采集:Y0U0V0  Y1      Y2U2V2  Y3      ...  
  4.   
  5. 存储:Y0U0Y1V0  Y2U2Y3V2  

表2

Y0是一个字节,U0也是一个字节,V0也是一个字节,都是一个字节。

客观上每个像素是3个字节,但采集的时候却不是3个字节都采集,这样采集:第0个像素(Y0 U0 V0)采集了3个字节(Y0 U0 V0),第1个像素采集了1个字节(Y1),第2个像素采集了3个字节(Y2 U2 V2),第3个像素采集了1个字节(Y3)……第n个像素采集了3个字节(Yn Un Vn),第n+1个像素采集了1个字节(Yn+1)……。这种采集方式叫相邻两像素共用UV(不知道能不能从数学上证明如果每个像素3个字节都采集的话是不是就是冗余)。

怎么存储呢?好像是间隔存储。我记得好像有宏像素的概念,即2个像素占4个字节或者说4个字节的存储单元保存着2个像素的信息。比如Y0U0V1V0共需要一个字(4个字节),这个字的存储单元里保存着第0个像素和第1个像素的信息,第0个像素和第1个像素共享U0和V0。反正在后面的图像处理当中,我是用一个unsigned long *p的指针来处理一个宏像素的。当然了,这张表看不懂没关系,我当初就没看懂。
然后就是RGB了,我感觉RGB还是蛮形象的,尤其是RGB565_16,网上好多人研究这个,这里我就不多说了。

对于YUV和RGB之间的转换,我理解的程度也不深,我怕我的图像处理问题就是出在这个上面。

 

五,v4l2+framebuffer的组合效果

我看到我的摄像头采集出来的视频流了,因为担心YUV和RGB之间的转换时的数值处理出问题,我就只取了Y分量,我听说有黑白图像一说(其实YUV分量都提取的话,效果还是一样)。

1,提取YUV2分量代码如下:

[csharp]  view plain copy
  1. Y0=(*from & 0x000000FF)>>0;         
  2. U0=(*from & 0x0000FF00)>>8;   //colorful  
  3. //U0=128;                           //white and black  
  4. Y1=(*from & 0x00FF0000)>>16;  
  5. V0=(*from & 0xFF000000)>>24;  //colorful  
  6. //V0=128;                           //white and blcak  

注:from是unsigned long型的指针变量,指向YUV2缓存。 

 

2,根据提取到的YUV分量,转换成RGB分量函数:

[csharp]  view plain copy
  1. static  void YUV2RGB(unsigned char Y,unsigned char U,unsigned char V,  
  2.                     unsigned char *R,unsigned char *G,unsigned char *B)                   
  3. {  
  4. /* 
  5.     *R=Y+1.4075*(V-128); 
  6.     *G=Y-0.3455*(U-128)-0.7169*(V-128); 
  7.     *B=Y+1.779*(U-128); 
  8.  
  9.     *R=Y+1.140*V; 
  10.     *G=Y-0.394*U-0.581*V; 
  11.     *B=Y+2.032*U; 
  12. */  
  13.   
  14.     *R=Y+(V-128)+((V-128)*103>>8);  
  15.     *G=Y-((U-128)*88>>8)-((V-128)*183>>8);  
  16.     *B=Y+(U-128)+((U-128)*198>>8);  
  17. }  

 

3,把RGB分量再编码成像素:

[csharp]  view plain copy
  1. *to = (R0&0x1F)<<11 | (G0&0x3F)<<5 |(B0&0x1F)<<0;  
  2. *to |= ((R1&0x1F)<<11 | (G1&0x3F)<<5 |(B1&0x1F)<<0)<<16;  

注:to是unsigned long型指针变量,指向RGB565输出缓存。


 编译好程序后,我用ctrl+alt+F2切换到命令行模式看看效果,我先截图,如图5和图6所示

                                                             图5(我的v4l2+framebuffer)

 

                                                                图6(关掉台灯,我的v4l2+framebuffer)

 

我ctrl+alt+F1切换到图形界面,看看cheese的效果,如图7所示。

                                                                                                     图7(cheese)

 为什么cheese的效果会这么好(显示效果不流畅,但画面很美),为什么我的视频的图像会成为这个样子(显示效果很流畅,但画面很丑),我搞了好长时间都发现不了问题出在哪里。谁能帮帮我吗?

 

六,程序

我的程序就一个bluelover.c文件。

[csharp]  view plain copy
  1. /* 
  2. *  This program can be used and distributed without restrictions. 
  3. */  
  4.  
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <string.h>  
  8. #include <fcntl.h>              /* low-level i/o */  
  9. #include <unistd.h>  
  10. #include <errno.h>  
  11. #include <assert.h>  
  12. #include <sys/stat.h>  
  13. #include <sys/types.h>  
  14. #include <sys/time.h>  
  15. #include <sys/mman.h>  
  16. #include <sys/ioctl.h>  
  17. #include <stdbool.h>  
  18.  
  19. #include <linux/videodev2.h>  
  20. #include <linux/fb.h>  
  21.  
  22. #define CLEAR(x) memset(&(x), 0, sizeof(x))  
  23.   
  24. struct buffer {  
  25.         void   *start;  
  26.         size_t  length;  
  27. };  
  28.   
  29. static char *dev_name1;  
  30. static char *dev_name2;  
  31. static int  fd1 = -1;  
  32. static int  fd2 = -1;  
  33.   
  34. struct buffer          *buffers;  
  35. static unsigned int     n_buffers;  
  36. static char *fb_buffer;  
  37. static unsigned long screensize;  
  38.   
  39. static char *yuv_buffer;  
  40. static char *rgb_buffer;  
  41.   
  42.   
  43. static int              force_format=false;  
  44. static int              frame_count = 1000;  
  45.   
  46. static void errno_exit(const char *s)  
  47. {  
  48.         fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));  
  49.         exit(EXIT_FAILURE);  
  50. }  
  51.   
  52. static int xioctl(int fh, int request, void *arg)  
  53. {  
  54.         int r;  
  55.   
  56.         do {  
  57.                 r = ioctl(fh, request, arg);  
  58.         } while (-1 == r && EINTR == errno);  
  59.   
  60.         return r;  
  61. }  
  62. /* 
  63. static void process_image(const void *p, int size) 
  64. { 
  65.     unsigned short *fb; 
  66.     unsigned short *rgb; 
  67.     unsigned long height = 480; 
  68.     if(size>screensize) 
  69.         size=screensize; 
  70.  
  71.     //move 
  72.     memcpy(yuv_buffer,p,size); 
  73.  
  74.     //proc 
  75.     memcpy(rgb_buffer,yuv_buffer,size); 
  76.  
  77.     //move 
  78.     memcpy(fb_buffer,yuv_buffer,size); 
  79.      
  80.  
  81.     //move 
  82.     rgb=(unsigned short*)rgb_buffer; 
  83.     fb=(unsigned short*)fb_buffer; 
  84.     while(height--) 
  85.     { 
  86.         memcpy(fb,rgb,1280); 
  87.         fb+=640; 
  88.         rgb+=640;    
  89.     } 
  90.  
  91.      
  92.     fflush(stderr); 
  93.     fprintf(stderr, "."); 
  94.     fflush(stdout); 
  95. } 
  96. */  
  97. static  void YUV2RGB(unsigned char Y,unsigned char U,unsigned char V,  
  98.                     unsigned char *R,unsigned char *G,unsigned char *B)  
  99. /*static  void YUV2RGB(int Y,int U,int V, 
  100.                     int *R,int *G,int *B)*/                   
  101. {  
  102. /* 
  103.     *R=Y+1.4075*(V-128); 
  104.     *G=Y-0.3455*(U-128)-0.7169*(V-128); 
  105.     *B=Y+1.779*(U-128); 
  106. */  
  107.   
  108.     *R=Y+(V-128)+((V-128)*103>>8);  
  109.     *G=Y-((U-128)*88>>8)-((V-128)*183>>8);  
  110.     *B=Y+(U-128)+((U-128)*198>>8);  
  111. }  
  112.   
  113. static void process_image(const unsigned long *from, int size)  
  114. {  
  115.     unsigned long *to =(unsigned long*)fb_buffer;  
  116.       
  117.     unsigned char Y0;  
  118.     unsigned char U0;  
  119.     unsigned char Y1;  
  120.     unsigned char V0;  
  121.       
  122.     unsigned char R0;  
  123.     unsigned char G0;  
  124.     unsigned char B0;  
  125.     unsigned char R1;  
  126.     unsigned char G1;  
  127.     unsigned char B1;     
  128.   
  129.     size>>=2;  
  130.     while(size--)  
  131.     {  
  132.         Y0=(*from & 0x000000FF)>>0;         
  133.         U0=128;                         //white and black  
  134.         //U0=(*from & 0x0000FF00)>>8; //colorful  
  135.         Y1=(*from & 0x00FF0000)>>16;        
  136.         V0=128;                         //white and blcak  
  137.         //V0=(*from & 0xFF000000)>>24;    //colorful        
  138.         YUV2RGB(Y0,U0,V0,&R0,&G0,&B0);  
  139.         YUV2RGB(Y1,U0,V0,&R1,&G1,&B1);  
  140.   
  141.         *to = (R0&0x1F)<<11 | (G0&0x3F)<<5 |(B0&0x1F)<<0;  
  142.         *to |= ((R1&0x1F)<<11 | (G1&0x3F)<<5 |(B1&0x1F)<<0)<<16;          
  143.           
  144.         from++;  
  145.         to++;  
  146.     }  
  147. }  
  148.       
  149. static int read_frame(void)  
  150. {  
  151.     struct v4l2_buffer buf;  
  152.   
  153.     CLEAR(buf);  
  154.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  155.     buf.memory = V4L2_MEMORY_MMAP;  
  156.     if (-1 == xioctl(fd1, VIDIOC_DQBUF, &buf))  
  157.     {  
  158.         switch (errno)   
  159.         {  
  160.             case EAGAIN:  
  161.                 return 0;  
  162.             case EIO:  
  163.             default:  
  164.                 errno_exit("VIDIOC_DQBUF");  
  165.         }  
  166.     }  
  167.   
  168.     assert(buf.index < n_buffers);  
  169.       
  170.     process_image(buffers[buf.index].start, buf.bytesused);  
  171.   
  172.     if (-1 == xioctl(fd1, VIDIOC_QBUF, &buf))  
  173.         errno_exit("VIDIOC_QBUF");  
  174.   
  175.     return 1;  
  176. }  
  177.   
  178. static void mainloop(void)  
  179. {  
  180.         unsigned int count;  
  181.   
  182.         count = frame_count;  
  183.         while (count-- > 0) {  
  184.                 for (;;) {  
  185.                         fd_set fds;  
  186.                         struct timeval tv;  
  187.                         int r;  
  188.   
  189.                         FD_ZERO(&fds);  
  190.                         FD_SET(fd1, &fds);  
  191.   
  192.                         /* Timeout. */  
  193.                         tv.tv_sec = 2;  
  194.                         tv.tv_usec = 0;  
  195.   
  196.                         r = select(fd1 + 1, &fds, NULL, NULL, &tv);  
  197.   
  198.                         if (-1 == r) {  
  199.                                 if (EINTR == errno)  
  200.                                         continue;  
  201.                                 errno_exit("select");  
  202.                         }  
  203.   
  204.                         if (0 == r) {  
  205.                                 fprintf(stderr, "select timeout\n");  
  206.                                 exit(EXIT_FAILURE);  
  207.                         }  
  208.   
  209.                         if (read_frame())  
  210.                                 break;  
  211.                         /* EAGAIN - continue select loop. */  
  212.                 }  
  213.         }  
  214. }  
  215.   
  216. static void stop_capturing(void)  
  217. {  
  218.     enum v4l2_buf_type type;  
  219.       
  220.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  221.     if (-1 == xioctl(fd1, VIDIOC_STREAMOFF, &type))  
  222.         errno_exit("VIDIOC_STREAMOFF");  
  223. }  
  224.   
  225. static void start_capturing(void)  
  226. {  
  227.     unsigned int i;  
  228.     enum v4l2_buf_type type;  
  229.     struct v4l2_buffer buf;  
  230.           
  231.     for (i = 0; i < n_buffers; ++i)   
  232.     {         
  233.         CLEAR(buf);  
  234.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  235.         buf.memory = V4L2_MEMORY_MMAP;  
  236.         buf.index = i;  
  237.         if (-1 == xioctl(fd1, VIDIOC_QBUF, &buf))  
  238.             errno_exit("VIDIOC_QBUF");  
  239.     }  
  240.       
  241.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  242.     if (-1 == xioctl(fd1, VIDIOC_STREAMON, &type))  
  243.         errno_exit("VIDIOC_STREAMON");  
  244.   
  245. }  
  246.   
  247. static void uninit_device(void)  
  248. {  
  249.         unsigned int i;  
  250.   
  251.     for (i = 0; i < n_buffers; ++i)  
  252.         if (-1 == munmap(buffers[i].start, buffers[i].length))  
  253.             errno_exit("munmap");  
  254.           
  255.     if(-1 == munmap(fb_buffer,screensize))  
  256.         errno_exit("munmap");  
  257.       
  258.     free(buffers);  
  259.     free(rgb_buffer);  
  260.     free(yuv_buffer);  
  261. }  
  262.   
  263. static void init_mmap(void)  
  264. {  
  265.     struct v4l2_requestbuffers req;  
  266.     struct v4l2_buffer buf;  
  267.   
  268.     //VIDIOC_REQBUFS  
  269.     CLEAR(req);  
  270.     req.count = 4;  
  271.     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  272.     req.memory = V4L2_MEMORY_MMAP;  
  273.     if(-1 == xioctl(fd1, VIDIOC_REQBUFS, &req))   
  274.     {  
  275.         if (EINVAL == errno)   
  276.         {  
  277.             fprintf(stderr, "%s does not support ""memory mapping\n", dev_name1);  
  278.             exit(EXIT_FAILURE);  
  279.         }   
  280.         else  
  281.             errno_exit("VIDIOC_REQBUFS");  
  282.     }  
  283.     if(req.count < 2)   
  284.     {  
  285.             fprintf(stderr, "Insufficient buffer memory on %s\n",dev_name1);  
  286.             exit(EXIT_FAILURE);  
  287.     }  
  288.   
  289.     //VIDIOC_QUERYBUF  
  290.     buffers = calloc(req.count, sizeof(*buffers));  
  291.     if (!buffers)   
  292.     {  
  293.             fprintf(stderr, "Out of memory\n");  
  294.             exit(EXIT_FAILURE);  
  295.     }  
  296.     for (n_buffers = 0; n_buffers < req.count; ++n_buffers)   
  297.     {          
  298.         CLEAR(buf);  
  299.         buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  300.         buf.memory      = V4L2_MEMORY_MMAP;  
  301.         buf.index       = n_buffers;  
  302.         if (-1 == xioctl(fd1, VIDIOC_QUERYBUF, &buf))  
  303.             errno_exit("VIDIOC_QUERYBUF");  
  304.         buffers[n_buffers].length = buf.length;  
  305.         buffers[n_buffers].start =mmap(NULL /* start anywhere */,buf.length,  
  306.                                 PROT_READ | PROT_WRITE /* required */,  
  307.                                 MAP_SHARED /* recommended */,  
  308.                                 fd1, buf.m.offset);  
  309.         if (MAP_FAILED == buffers[n_buffers].start)  
  310.         {  
  311.             errno_exit("mmap");  
  312.         }  
  313.     }//now n_buffers is 4  
  314.   
  315.     //fbmmap  
  316.     fb_buffer=(char*)mmap(NULL,screensize,PROT_READ | PROT_WRITE,MAP_SHARED,fd2,0);  
  317.     if(MAP_FAILED == fb_buffer)  
  318.     {  
  319.         errno_exit("mmap");  
  320.     }  
  321.       
  322.     //malloc the yuv_buffer  
  323.     yuv_buffer = (char*)malloc(screensize);  
  324.     if (!yuv_buffer)   
  325.     {  
  326.             fprintf(stderr, "Out of memory\n");  
  327.             exit(EXIT_FAILURE);  
  328.     }  
  329.       
  330.     //malloc the rgb_buffer  
  331.     rgb_buffer = (char*)malloc(screensize);  
  332.     if (!rgb_buffer)   
  333.     {  
  334.             fprintf(stderr, "Out of memory\n");  
  335.             exit(EXIT_FAILURE);  
  336.     }     
  337. }  
  338.   
  339. static void init_device(void)  
  340. {  
  341.     struct v4l2_capability cap;  
  342.     struct v4l2_format fmt;  
  343.     struct fb_fix_screeninfo finfo;  
  344.     struct fb_var_screeninfo vinfo;  
  345.   
  346.     CLEAR(cap);  
  347.     if (-1 == xioctl(fd1, VIDIOC_QUERYCAP, &cap))  
  348.     {  
  349.         if (EINVAL == errno)   
  350.         {  
  351.             fprintf(stderr, "%s is no V4L2 device\n",dev_name1);  
  352.             exit(EXIT_FAILURE);  
  353.         }   
  354.         else   
  355.             errno_exit("VIDIOC_QUERYCAP");  
  356.     }  
  357.     if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))   
  358.     {  
  359.         fprintf(stderr, "%s is no video capture device\n",dev_name1);  
  360.         exit(EXIT_FAILURE);  
  361.     }  
  362.     if (!(cap.capabilities & V4L2_CAP_STREAMING))   
  363.     {  
  364.         fprintf(stderr, "%s does not support streaming i/o\n",dev_name1);  
  365.         exit(EXIT_FAILURE);  
  366.     }  
  367.   
  368.     CLEAR(fmt);  
  369.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  370.     if (force_format)   
  371.     {  
  372.         fmt.fmt.pix.width       = 640;  
  373.         fmt.fmt.pix.height      = 480;  
  374.         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;  
  375.         fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;  
  376.         if (-1 == xioctl(fd1, VIDIOC_S_FMT, &fmt))  
  377.             errno_exit("VIDIOC_S_FMT");  
  378.     }   
  379.     else  
  380.     {  
  381.         if (-1 == xioctl(fd1, VIDIOC_G_FMT, &fmt))  
  382.             errno_exit("VIDIOC_G_FMT");  
  383.     }  
  384.     fprintf(stdout,"<------------camera infomation------------->\n");  
  385.     fprintf(stdout,"device driver=%s\n",cap.driver);  
  386.     fprintf(stdout,"device name=%s\n",cap.card);  
  387.     fprintf(stdout,"bus_infomation=%s\n",cap.bus_info);  
  388.     fprintf(stdout,"image_width=%d\n",fmt.fmt.pix.width);  
  389.     fprintf(stdout,"image_height=%d\n",fmt.fmt.pix.height);  
  390.     fprintf(stdout,"pixel_format=%d\n",fmt.fmt.pix.pixelformat);  
  391.     fprintf(stdout,"\n");  
  392.   
  393.   
  394.     CLEAR(finfo);  
  395.     if(-1 == xioctl(fd2,FBIOGET_FSCREENINFO,&finfo))  
  396.         errno_exit("FBIOGET_FSCREENINFO");  
  397.   
  398.     CLEAR(vinfo);  
  399.     if(-1 == xioctl(fd2,FBIOGET_VSCREENINFO,&vinfo))  
  400.         errno_exit("FBIOGET_VSCREENINFO");  
  401.     screensize = vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8;  
  402.   
  403.     fprintf(stdout,"<------------screen infomation------------->\n");  
  404.     fprintf(stdout,"id=%s\n",finfo.id);  
  405.     fprintf(stdout,"x=%d\n",vinfo.xres);  
  406.     fprintf(stdout,"y=%d\n",vinfo.yres);  
  407.     fprintf(stdout,"bpp=%d\n",vinfo.bits_per_pixel);  
  408.     fprintf(stdout,"redoffset=%d,redlength=%d,msb_right=%d\n",  
  409.             vinfo.red.offset,vinfo.red.length,vinfo.red.msb_right);  
  410.     fprintf(stdout,"greenoffset=%d,greenlength=%d,msb_right=%d\n",  
  411.             vinfo.green.offset,vinfo.green.length,vinfo.green.msb_right);  
  412.     fprintf(stdout,"blueoffset=%d,bluelength=%d,msb_right=%d\n",  
  413.             vinfo.blue.offset,vinfo.blue.length,vinfo.blue.msb_right);  
  414.     fprintf(stdout,"screensize=%d\n",screensize);  
  415.       
  416.     init_mmap();  
  417. }  
  418.   
  419. static void close_device(void)  
  420. {  
  421.     if (-1 == close(fd1))  
  422.         errno_exit("close");  
  423.     fd1 = -1;  
  424.       
  425.     if (-1 == close(fd2))  
  426.         errno_exit("close");  
  427.     fd2 = -1;  
  428. }  
  429.   
  430. static void open_device(void)  
  431. {  
  432.   
  433.     fd1 = open(dev_name1, O_RDWR /* required */ | O_NONBLOCK, 0);  
  434.     if (-1 == fd1)   
  435.     {  
  436.         fprintf(stderr, "Cannot open '%s': %d, %s\n",dev_name1, errno, strerror(errno));  
  437.         exit(EXIT_FAILURE);  
  438.     }  
  439.   
  440.     fd2 = open(dev_name2,O_RDWR,0);  
  441.     if(-1 == fd2)  
  442.     {  
  443.         fprintf(stderr, "Cannot open '%s': %d, %s\n",dev_name2, errno, strerror(errno));  
  444.         exit(EXIT_FAILURE);       
  445.     }     
  446. }  
  447.   
  448. int main(int argc, char **argv)  
  449. {  
  450.     dev_name1 = "/dev/video0";  
  451.     dev_name2 = "/dev/fb0";  
  452.   
  453.     open_device();  
  454.     init_device();  
  455.     start_capturing();  
  456.     mainloop();  
  457.     stop_capturing();  
  458.     uninit_device();  
  459.     close_device();  
  460.     fprintf(stderr, "\n");  
  461.     return 0;  
  462. }  


 

 

后记

等解决了这个问题再写吧。


FROM: http://blog.csdn.net/ddddwant/article/details/8475211

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值