linux -- camera shot 拍照功能

  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <errno.h>  
  4. #include <stdlib.h>  
  5. #include <sys/types.h>  
  6. #include <sys/stat.h>  
  7. #include <fcntl.h>  
  8. #include <time.h>  
  9. #include <sys/mman.h>  
  10. #include <assert.h>  
  11. #include <linux/videodev2.h>  
  12. #include <linux/fb.h>  
  13. #include <pthread.h>  
  14.   
  15. //照相机延时等待  
  16. #define TimeOut 5   
  17. //拍照 个数  
  18. #define CapNum 10  
  19. //设置照片宽度 高度  
  20. #define CapWidth 320  
  21. #define CapHeight 240  
  22. //申请Buf个数  
  23. #define ReqButNum 4  
  24. //使用前置或者后置Camera 前置设0,后置设1  
  25. #define IsRearCamera 0  
  26. //设置帧率  
  27. #define  FPS 10  
  28. //设置格式  
  29. #define PIXELFMT V4L2_PIX_FMT_YUYV  
  30.   
  31. #define CapDelay 100*1000  
  32.   
  33.   
  34. #define CLEAR(x)    memset(&(x), 0, sizeof(x))  
  35.   
  36. typedef unsigned char BYTE;  
  37. typedef unsigned short WORD;  
  38. typedef unsigned int DWORD;  
  39. typedef long LONG;  
  40.   
  41. typedef struct  
  42. {  
  43.     void *start;  
  44.     int length;  
  45. }BUFTYPE;  
  46. struct tsp_event {  
  47.     struct timeval time;  
  48.     unsigned short type;  
  49.     unsigned short code;  
  50.     unsigned int value;  
  51. };  
  52. typedef struct tagBITMAPFILEHEADER {  
  53.   WORD  bfType;  
  54.   DWORD bfSize;  
  55.   WORD  bfReserved1;  
  56.   WORD  bfReserved2;  
  57.   DWORD bfOffBits;  
  58. }__attribute__((packed)) BITMAPFILEHEADER, *PBITMAPFILEHEADER;  
  59.   
  60.   
  61. typedef struct tagBITMAPINFOHEADER {  
  62.   DWORD biSize;  
  63.   LONG  biWidth;  
  64.   LONG  biHeight;  
  65.   WORD  biPlanes;  
  66.   WORD  biBitCount;  
  67.   DWORD biCompression;  
  68.   DWORD biSizeImage;  
  69.   LONG  biXPelsPerMeter;  
  70.   LONG  biYPelsPerMeter;  
  71.   DWORD biClrUsed;  
  72.   DWORD biClrImportant;  
  73. }__attribute__((packed)) BITMAPINFOHEADER, *PBITMAPINFOHEADER;  
  74.   
  75.   
  76.   
  77. static BITMAPFILEHEADER file_head;  
  78. static BITMAPINFOHEADER info_head;  
  79.   
  80. typedef struct tagRGBQUAD {  
  81.   BYTE rgbBlue;  
  82.   BYTE rgbGreen;  
  83.   BYTE rgbRed;  
  84.   BYTE rgbReserved;  
  85. }__attribute__((packed)) RGBQUAD;  
  86.   
  87.   
  88. BUFTYPE *user_buf;  
  89. static int n_buffer = 0;  
  90.   
  91.   
  92. static struct fb_var_screeninfo vinfo;  
  93. static struct fb_fix_screeninfo finfo;  
  94. static int lcd_buf_size;  
  95. static char *fb_buf = NULL;  
  96. static int tsp_fd;  
  97. static pthread_t capture_tid;   
  98.   
  99. int display_x = 0;  
  100. int display_y = 0;  
  101.   
  102. int save_image()  
  103. {  
  104.     FILE *fp;  
  105.     static int num = 0;  
  106.     char picture_name[40]={''};  
  107.     char *addr = (char *)fb_buf;  
  108.     int length = CapWidth * CapHeight * vinfo.bits_per_pixel / 8;  
  109.     int fd;  
  110.     int data_size;  
  111.     int i,j,k;  
  112.     char *tmp_buf;  
  113.       
  114.     tmp_buf = (char *)malloc(length);  
  115.     if(tmp_buf == NULL)  
  116.     {  
  117.       
  118.         printf("tmp_buf alloc fail ");  
  119.         exit(EXIT_FAILURE);  
  120.     }  
  121.   
  122.     if(access("/udisk/camtest",0)!=0)  
  123.     {  
  124.         mkdir("/udisk/camtest", 0777);  
  125.     }  
  126.       
  127.     sprintf(picture_name,"/udisk/camtest/picture%d.bmp",num ++);  
  128.     printf("write image to sdcard:name:%s ",picture_name);  
  129.   
  130.   
  131.     data_size = length;  
  132.   
  133.     file_head.bfType = 0x4d42;  
  134.     file_head.bfSize = sizeof(file_head) + sizeof(info_head) + data_size;  
  135.     file_head.bfReserved1 = file_head.bfReserved2 = 0;  
  136.     file_head.bfOffBits = sizeof(file_head) + sizeof(info_head);  
  137.           
  138.     info_head.biSize = sizeof(info_head);  
  139.     info_head.biWidth = CapWidth;  
  140.     info_head.biHeight = CapHeight;  
  141.     info_head.biPlanes = 1;  
  142.     info_head.biBitCount = 32;  
  143.     info_head.biCompression = 0;  
  144.     info_head.biSizeImage = 0;  
  145.     info_head.biXPelsPerMeter = 0;  
  146.     info_head.biYPelsPerMeter = 0;  
  147.     info_head.biClrUsed = 0;  
  148.     info_head.biClrImportant = 0;  
  149.   
  150.   
  151.     fd = open(picture_name, O_RDWR | O_CREAT, 0644);  
  152.     if(fd < 0)  
  153.     {  
  154.         perror("create image error ");  
  155.         close (fd);  
  156.         exit(EXIT_FAILURE);  
  157.     }  
  158.   
  159.     write(fd, &file_head, sizeof(file_head));  
  160.       
  161.     write(fd, &info_head, sizeof(info_head));  
  162.   
  163.     int bmpLineLenth = CapWidth * vinfo.bits_per_pixel / 8;   
  164.     for(i = 0; i < length; i++)  
  165.     {  
  166.         tmp_buf[i] = fb_buf[(CapHeight - i/bmpLineLenth - 1) * finfo.line_length + i%bmpLineLenth];  
  167.     }  
  168.     for(i = 0; i < length; i++)  
  169.     {  
  170.         fb_buf[(i/bmpLineLenth) * finfo.line_length + i%bmpLineLenth + bmpLineLenth] = tmp_buf[i] ;  
  171.     }  
  172.       
  173.     write(fd, tmp_buf, length);  
  174.       
  175.     usleep(500);  
  176.     close(fd);  
  177.     return 0;  
  178. }  
  179. static void *capture_thread(void *pVoid)  
  180. {  
  181.     int ret;  
  182.     int key_change = 0;  
  183.     struct tsp_event tsp_value;  
  184. #define BTN_TOUCH       0x14a  
  185.     while(1)  
  186.     {  
  187.         printf("capture_thread ");  
  188.         ret = read(tsp_fd, &tsp_value, sizeof(struct tsp_event)); /* 如果无数据则休眠 */  
  189.           
  190.         if (ret < 0)  
  191.         {  
  192.         printf("fail to read ");  
  193.         return;  
  194.         }  
  195.         //如果触摸释放掉,则开始保存图片  
  196.         if((tsp_value.code == BTN_TOUCH) && (tsp_value.value == 0))  
  197.         save_image();  
  198.         printf("code:%04d,value:%04d ",tsp_value.code, tsp_value.value);  
  199.     }  
  200.   
  201. }  
  202. //打开摄像头设备  
  203. int open_camer_device()  
  204. {  
  205.     int fd;  
  206.   
  207. //非阻塞方式打开,如果打开错误,会立即返回  
  208.     if((fd = open("/dev/video0",O_RDWR | O_NONBLOCK)) < 0)  
  209.     {  
  210.         perror("Fail to open");  
  211.         exit(EXIT_FAILURE);  
  212.     }   
  213.   
  214.     printf("open cam success %d ",fd);  
  215.     return fd;  
  216. }  
  217.   
  218. //打开摄像头设备  
  219. int open_lcd_device()  
  220. {  
  221.     int fd;  
  222. //非阻塞方式打开,如果打开错误,会立即返回  
  223.     if((fd = open("/dev/fb0",O_RDWR | O_NONBLOCK)) < 0)  
  224.     {  
  225.         perror("Fail to open");  
  226.         exit(EXIT_FAILURE);  
  227.     }   
  228.     printf("open lcd success %d ",fd);  
  229.     return fd;  
  230. }  
  231.   
  232. //申请Camera Buf,并映射到用户空间,利用全局变量user_buf保存映射信息  
  233. int init_mmap(int lcd_fd, int cam_fd)  
  234. {  
  235.     int i = 0;  
  236.     int err;  
  237.     int ret;  
  238.     struct v4l2_control ctrl;  
  239.     struct v4l2_requestbuffers reqbuf;  
  240.   
  241.   
  242.     //mmap framebuffer      
  243.     fb_buf = (char *)mmap(  
  244.         NULL,  
  245.         lcd_buf_size,  
  246.         PROT_READ | PROT_WRITE,MAP_SHARED ,  
  247.         lcd_fd,   
  248.         0);      
  249.     if(NULL == fb_buf)  
  250.     {  
  251.         perror("Fail to mmap fb_buf");  
  252.         exit(EXIT_FAILURE);  
  253.     }  
  254.   
  255.     bzero(&reqbuf,sizeof(reqbuf));  
  256.     reqbuf.count = ReqButNum;  
  257.     reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  258.     reqbuf.memory = V4L2_MEMORY_MMAP;  
  259.     printf("start VIDIOC_REQBUFS ");  
  260.     //申请视频缓冲区(这个缓冲区位于内核空间,需要通过mmap映射)  
  261.     //这一步操作可能会修改reqbuf.count的值,修改为实际成功申请缓冲区个数  
  262.     if(-1 == ioctl(cam_fd,VIDIOC_REQBUFS,&reqbuf))  
  263.     {  
  264.         perror("Fail to ioctl 'VIDIOC_REQBUFS'");  
  265.         exit(EXIT_FAILURE);  
  266.     }  
  267.   
  268.     n_buffer = reqbuf.count;  
  269.   
  270.     user_buf = calloc(reqbuf.count,sizeof(*user_buf));  
  271.     if(user_buf == NULL){  
  272.         fprintf(stderr,"Out of memory ");  
  273.         exit(EXIT_FAILURE);  
  274.     }  
  275.   
  276.     //将内核缓冲区映射到用户进程空间  
  277.     for(i = 0; i < reqbuf.count; i ++)  
  278.     {  
  279.         struct v4l2_buffer buf;  
  280.           
  281.         bzero(&buf,sizeof(buf));  
  282.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  283.         buf.memory = V4L2_MEMORY_MMAP;  
  284.         buf.index = i;  
  285.         //查询申请到内核缓冲区的信息  
  286.         if(-1 == ioctl(cam_fd,VIDIOC_QUERYBUF,&buf))  
  287.         {  
  288.             perror("Fail to ioctl : VIDIOC_QUERYBUF");  
  289.             exit(EXIT_FAILURE);  
  290.         }  
  291.   
  292.         user_buf[i].length = buf.length;  
  293.         user_buf[i].start =   
  294.             mmap(  
  295.                     NULL,/*start anywhere*/  
  296.                     buf.length,  
  297.                     PROT_READ | PROT_WRITE,  
  298.                     MAP_SHARED,  
  299.                     cam_fd,buf.m.offset  
  300.                 );  
  301.           
  302.         if(MAP_FAILED == user_buf[i].start)  
  303.         {  
  304.             perror("Fail to mmap ");  
  305.             printf("%d ",i);  
  306.             exit(EXIT_FAILURE);  
  307.         }  
  308.     //  printf("start:08%lx ",user_buf[i].start);  
  309.     }     
  310.   
  311.     return 0;  
  312. }  
  313.   
  314.   
  315. //初始化视频设备  
  316. int init_device(int lcd_fd, int cam_fd)  
  317. {  
  318.     struct v4l2_fmtdesc fmt;  
  319.     struct v4l2_capability cap;  
  320.     struct v4l2_format stream_fmt;  
  321.     struct v4l2_input input;  
  322.     struct v4l2_control ctrl;  
  323.     struct v4l2_streamparm stream;  
  324.     int err;  
  325.     int ret;  
  326.   
  327.   
  328.   
  329.   
  330.     if(-1 == ioctl(lcd_fd,FBIOGET_FSCREENINFO,&finfo))  
  331.     {  
  332.         perror("Fail to ioctl:FBIOGET_FSCREENINFO ");  
  333.         exit(EXIT_FAILURE);  
  334.     }  
  335.     if (-1==ioctl(lcd_fd, FBIOGET_VSCREENINFO, &vinfo))   
  336.     {  
  337.         perror("Fail to ioctl:FBIOGET_VSCREENINFO ");  
  338.         exit(EXIT_FAILURE);  
  339.     }  
  340.     lcd_buf_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;    
  341.     printf("vinfo.xres:%d, vinfo.yres:%d, vinfo.bits_per_pixel:%d, lcd_buf_size:%d, finfo.line_length:%d ",vinfo.xres, vinfo.yres, vinfo.bits_per_pixel, lcd_buf_size, finfo.line_length);   
  342.   
  343.   
  344.   
  345.   
  346.   
  347.       
  348.     memset(&fmt,0,sizeof(fmt));  
  349.     fmt.index = 0;  
  350.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  351.       
  352. //枚举视频设置支持的格式  
  353.     while((ret = ioctl(cam_fd,VIDIOC_ENUM_FMT,&fmt)) == 0)  
  354.     {  
  355.         fmt.index ++ ;  
  356.         printf("{pixelformat = %c%c%c%c},description = '%s' ",  
  357.                 fmt.pixelformat & 0xff,(fmt.pixelformat >> 8)&0xff,  
  358.                 (fmt.pixelformat >> 16) & 0xff,(fmt.pixelformat >> 24)&0xff,  
  359.                 fmt.description);  
  360.     }  
  361. //查询视频设备支持的功能  
  362.     ret = ioctl(cam_fd,VIDIOC_QUERYCAP,&cap);  
  363.     if(ret < 0){  
  364.         perror("FAIL to ioctl VIDIOC_QUERYCAP");  
  365.         exit(EXIT_FAILURE);  
  366.     }  
  367.   
  368.   
  369.     if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))  
  370.     {  
  371.         printf("The Current device is not a video capture device ");  
  372.         exit(EXIT_FAILURE);  
  373.       
  374.     }  
  375.   
  376.     if(!(cap.capabilities & V4L2_CAP_STREAMING))  
  377.     {  
  378.         printf("The Current device does not support streaming i/o ");  
  379.         exit(EXIT_FAILURE);  
  380.     }  
  381.   
  382.     CLEAR(stream_fmt);  
  383. //设置摄像头采集数据格式,如设置采集数据的  
  384. //长,宽,图像格式(JPEG,YUYV,MJPEG等格式)  
  385.     stream_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  386.     stream_fmt.fmt.pix.width = CapWidth;  
  387.     stream_fmt.fmt.pix.height = CapHeight;  
  388.     stream_fmt.fmt.pix.pixelformat = PIXELFMT;  
  389.     stream_fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;  
  390.   
  391.     if(-1 == ioctl(cam_fd,VIDIOC_S_FMT,&stream_fmt))  
  392.     {  
  393.         printf("Can't set the fmt ");  
  394.         perror("Fail to ioctl ");  
  395.         exit(EXIT_FAILURE);  
  396.     }  
  397.     printf("VIDIOC_S_FMT successfully ");  
  398.   
  399.     init_mmap(lcd_fd, cam_fd);  
  400.       
  401. //通过S_PARM来设置FPS          
  402.     /* fimc_v4l2_s_parm */  
  403.   
  404.   CLEAR(stream);  
  405.     stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  406.     stream.parm.capture.capturemode = 0;  
  407.     stream.parm.capture.timeperframe.numerator = 1;  
  408.     stream.parm.capture.timeperframe.denominator = FPS;  
  409.   
  410.     err = ioctl(cam_fd, VIDIOC_S_PARM, &stream);  
  411.     if(err < 0)  
  412.     printf("FimcV4l2 start: error %d, VIDIOC_S_PARM", err);  
  413.   
  414.     return 0;  
  415. }  
  416.   
  417. int start_capturing(int cam_fd)  
  418. {  
  419.     unsigned int i;  
  420.     enum v4l2_buf_type type;  
  421.     //将申请的内核缓冲区放入一个队列中  
  422.     for(i = 0;i < n_buffer;i ++)  
  423.     {  
  424.         struct v4l2_buffer buf;  
  425.   
  426.   
  427.         bzero(&buf,sizeof(buf));  
  428.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  429.         buf.memory = V4L2_MEMORY_MMAP;  
  430.         buf.index = i;  
  431.           
  432.         if(-1 == ioctl(cam_fd,VIDIOC_QBUF,&buf))  
  433.         {  
  434.             perror("Fail to ioctl 'VIDIOC_QBUF'");  
  435.             exit(EXIT_FAILURE);  
  436.         }  
  437.     }  
  438.   
  439.   
  440.     //开始采集数据  
  441.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  442.     if(-1 == ioctl(cam_fd,VIDIOC_STREAMON,&type))  
  443.     {  
  444.         printf("i = %d. ",i);  
  445.         perror("Fail to ioctl 'VIDIOC_STREAMON'");  
  446.         exit(EXIT_FAILURE);  
  447.     }  
  448.     return 0;  
  449. }  
  450.   
  451. inline int clip(int value, int min, int max)   
  452. {      
  453.     return (value > max ? max : value < min ? min : value);   
  454. }  
  455. //将采集好的数据放到文件中  
  456. int process_image(void *addr,int length)  
  457. {  
  458.     unsigned char* in=(char*)addr;      
  459.     int width=CapWidth;      
  460.     int height=CapHeight;      
  461.     int istride=CapWidth *2;      
  462.     int x,y,j;     
  463.     int y0,u,y1,v,r,g,b;      
  464.     long location=0;   
  465.     //printf("vinfo.xoffset:%d,vinfo.yoffset:%d ",vinfo.xoffset,vinfo.yoffset);     
  466.     for ( y = 0; y < height; ++y)      
  467.     {          
  468.         for (j = 0, x=0; j < width * 2 ; j += 4,x +=2)         
  469.         {           
  470.             location = (x+display_x) * (vinfo.bits_per_pixel/8) + (y+display_y) * finfo.line_length;   
  471.             y0 = in[j];           
  472.             u = in[j + 1] - 128;  
  473.             y1 = in[j + 2];                    
  474.             v = in[j + 3] - 128;   
  475.             r = (298 * y0 + 409 * v + 128) >> 8;  
  476.             g = (298 * y0 - 100 * u - 208 * v + 128) >> 8;  
  477.             b = (298 * y0 + 516 * u + 128) >> 8;    
  478.             fb_buf[ location + 0] = clip(b, 0, 255);  
  479.             fb_buf[ location + 1] = clip(g, 0, 255);  
  480.             fb_buf[ location + 2] = clip(r, 0, 255);  
  481.             fb_buf[ location + 3] = 255;   
  482.             r = (298 * y1 + 409 * v + 128) >> 8;   
  483.             g = (298 * y1 - 100 * u - 208 * v + 128) >> 8;  
  484.             b = (298 * y1 + 516 * u + 128) >> 8;   
  485.             fb_buf[ location + 4] = clip(b, 0, 255);  
  486.             fb_buf[ location + 5] = clip(g, 0, 255);    
  487.             fb_buf[ location + 6] = clip(r, 0, 255);  
  488.             fb_buf[ location + 7] = 255;                
  489.         }        in +=istride;      }  
  490.       
  491. //  usleep(500);  
  492.     return 0;  
  493. }  
  494.   
  495.   
  496. int read_frame(int cam_fd)  
  497. {  
  498.     struct v4l2_buffer buf;  
  499.     unsigned int i;  
  500.       
  501.     bzero(&buf,sizeof(buf));  
  502.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  503.     buf.memory = V4L2_MEMORY_MMAP;  
  504. //从Camera buf中把数据拿出来  
  505.     if(-1 == ioctl(cam_fd,VIDIOC_DQBUF,&buf))  
  506.     {  
  507.         perror("Fail to ioctl 'VIDIOC_DQBUF'");  
  508.         exit(EXIT_FAILURE);  
  509.     }  
  510.   
  511.     assert(buf.index < n_buffer);  
  512.   
  513.     process_image(user_buf[buf.index].start,user_buf[buf.index].length);  
  514. //把处理过的Buf 重新入队   
  515.     if(-1 == ioctl(cam_fd,VIDIOC_QBUF,&buf))  
  516.     {  
  517.         perror("Fail to ioctl 'VIDIOC_QBUF'");  
  518.         exit(EXIT_FAILURE);  
  519.     }  
  520.     return 1;  
  521. }  
  522.   
  523. //利用select 进行超时处理  
  524. int mainloop(int cam_fd)  
  525. {   
  526.     int count = 1;//CapNum;  
  527.     clock_t startTime, finishTime;  
  528.     double selectTime, frameTime;  
  529.       
  530.     while(count++  > 0)  
  531.     {  
  532.         for(;;)  
  533.         {  
  534.             fd_set fds;  
  535.             struct timeval tv;  
  536.             int r;  
  537.         //  startTime = clock();  
  538.   
  539.               
  540.             FD_ZERO(&fds);  
  541.             FD_SET(cam_fd,&fds);  
  542.   
  543.   
  544.             /*Timeout*/  
  545.             tv.tv_sec = TimeOut;  
  546.             tv.tv_usec = 0;  
  547.           
  548.             r = select(cam_fd + 1,&fds,NULL,NULL,&tv);  
  549.   
  550.   
  551.             if(-1 == r)  
  552.             {  
  553.                 if(EINTR == errno)  
  554.                     continue;  
  555.                   
  556.                 perror("Fail to select");  
  557.                 exit(EXIT_FAILURE);  
  558.             }  
  559.   
  560.   
  561.             if(0 == r)  
  562.             {  
  563.                 fprintf(stderr,"select Timeout ");  
  564.                 exit(EXIT_FAILURE);  
  565.             }  
  566.             startTime = clock();  
  567.             if(read_frame(cam_fd))  
  568.             {  
  569.                 finishTime = clock();  
  570.         //      printf("delta:%dms ", (finishTime - startTime)/1000);  
  571.                 break;  
  572.             }  
  573.         }  
  574.             usleep(CapDelay);  
  575.     }  
  576.   
  577.   
  578.     return 0;  
  579. }  
  580.   
  581.   
  582. void stop_capturing(int cam_fd)  
  583. {  
  584.     enum v4l2_buf_type type;  
  585.       
  586.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  587.     if(-1 == ioctl(cam_fd,VIDIOC_STREAMOFF,&type))  
  588.     {  
  589.         perror("Fail to ioctl 'VIDIOC_STREAMOFF'");  
  590.         exit(EXIT_FAILURE);  
  591.     }  
  592.       
  593.     return;  
  594. }  
  595.   
  596.   
  597. void uninit_camer_device()  
  598. {  
  599.     unsigned int i;  
  600.   
  601.   
  602.     for(i = 0;i < n_buffer;i ++)  
  603.     {  
  604.         if(-1 == munmap(user_buf[i].start, user_buf[i].length))  
  605.         {  
  606.             exit(EXIT_FAILURE);  
  607.         }  
  608.     }  
  609.     if (-1 == munmap(fb_buf, lcd_buf_size))   
  610.     {            
  611.         perror(" Error: framebuffer device munmap() failed. ");            
  612.         exit (EXIT_FAILURE) ;         
  613.     }     
  614.     free(user_buf);  
  615.   
  616.   
  617.     return;  
  618. }  
  619.   
  620.   
  621. void close_camer_device(int lcd_fd, int cam_fd)  
  622. {  
  623.     if(-1 == close(lcd_fd))  
  624.     {  
  625.         perror("Fail to close lcd_fd");  
  626.         exit(EXIT_FAILURE);  
  627.     }  
  628.     if(-1 == close(cam_fd))  
  629.     {  
  630.         perror("Fail to close cam_fd");  
  631.         exit(EXIT_FAILURE);  
  632.     }  
  633.   
  634.     return;  
  635. }  
  636.   
  637.   
  638. int main()  
  639. {  
  640.    
  641.     int lcd_fd;  
  642.     int cam_fd;  
  643.     if((tsp_fd = open("/dev/event0", O_RDWR)) < 0)  
  644.     {  
  645.         printf("Fail to open");  
  646.         return -1;  
  647.     }   
  648.     lcd_fd = open_lcd_device();  
  649.     cam_fd = open_camer_device();  
  650.     pthread_create(&capture_tid,NULL,capture_thread,(void *)NULL);    
  651.     init_device(lcd_fd, cam_fd);  
  652. //  init_mmap(lcd_fd, cam_fd);  
  653.   
  654.     start_capturing(cam_fd);  
  655.   
  656.     mainloop(cam_fd);  
  657.       
  658.     stop_capturing(cam_fd);  
  659.   
  660.     uninit_camer_device();  
  661.   
  662.     close_camer_device(lcd_fd, cam_fd);  
  663.   
  664.   
  665.     return 0;  
原文地址:https://www.cnblogs.com/zym0805/p/4736754.html