Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1576666
  • 博文数量: 239
  • 博客积分: 1760
  • 博客等级: 上尉
  • 技术积分: 1595
  • 用 户 组: 普通用户
  • 注册时间: 2011-01-08 23:53
文章分类

全部博文(239)

文章存档

2016年(1)

2015年(28)

2014年(53)

2013年(42)

2012年(50)

2011年(65)

分类: LINUX

2011-11-12 11:40:15

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <assert.h>

  5. #include <getopt.h>

  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. #include <errno.h>
  9. #include <malloc.h>
  10. #include <sys/stat.h>
  11. #include <sys/types.h>
  12. #include <sys/time.h>
  13. #include <sys/mman.h>
  14. #include <sys/ioctl.h>

  15. #include <asm/types.h>
  16. #include <linux/videodev2.h>

  17. #define CLEAR(x) memset (&(x), 0, sizeof (x))

  18. struct buffer {
  19. void * start;
  20. size_t length;
  21. };

  22. static char * dev_name = "/dev/video0";//摄像头设备名
  23. static int fd = -1;
  24. struct buffer * buffers = NULL;
  25. static unsigned int n_buffers = 0;

  26. FILE *file_fd;
  27. static unsigned long file_length;
  28. static unsigned char *file_name;
  29. //////////////////////////////////////////////////////
  30. //获取一帧数据
  31. //////////////////////////////////////////////////////
  32. static int read_frame (void)
  33. {
  34.     struct v4l2_buffer buf;
  35.     unsigned int i;

  36.     CLEAR (buf);
  37.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  38.     buf.memory = V4L2_MEMORY_MMAP;

  39.     ioctl (fd, VIDIOC_DQBUF, &buf); //出列采集的帧缓冲

  40.     assert (buf.index < n_buffers);
  41.     printf ("buf.index dq is %d,\n",buf.index);

  42.     fwrite(buffers[buf.index].start, buf.bytesused, 1, file_fd); //将其写入文件中

  43.     ioctl (fd, VIDIOC_QBUF, &buf); //再将其入列

  44.     return 1;
  45. }

  46. int main (int argc,char ** argv)
  47. {
  48.     struct v4l2_capability cap;
  49.     struct v4l2_format fmt;
  50.     unsigned int i;
  51.     enum v4l2_buf_type type;

  52.     file_fd = fopen("test-mmap.jpg", "w");//图片文件名

  53.     fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);//打开设备

  54.     ioctl (fd, VIDIOC_QUERYCAP, &cap);//获取摄像头参数

  55.     CLEAR (fmt);
  56.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  57.     fmt.fmt.pix.width = 320;
  58.     fmt.fmt.pix.height = 240;
  59.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  60.     fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
  61.     ioctl (fd, VIDIOC_S_FMT, &fmt); //设置图像格式

  62.     file_length = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; //计算图片大小

  63.     struct v4l2_requestbuffers req;
  64.     CLEAR (req);
  65.     req.count = 4;
  66.     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  67.     req.memory = V4L2_MEMORY_MMAP;

  68.     ioctl (fd, VIDIOC_REQBUFS, &req); //申请缓冲,count是申请的数量

  69.     if (req.count < 2)
  70.         printf("Insufficient buffer memory\n");

  71.     buffers = calloc (req.count, sizeof (*buffers));//内存中建立对应空间

  72.     for (n_buffers = 0; n_buffers < req.count; ++n_buffers)
  73.     {
  74.         struct v4l2_buffer buf; //驱动中的一帧
  75.         CLEAR (buf);
  76.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  77.         buf.memory = V4L2_MEMORY_MMAP;
  78.         buf.index = n_buffers;

  79.         if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) //映射用户空间
  80.             printf ("VIDIOC_QUERYBUF error\n");

  81.         buffers[n_buffers].length = buf.length;
  82.         buffers[n_buffers].start = mmap (NULL /* start anywhere */, //通过mmap建立映射关系
  83.                             buf.length,
  84.                             PROT_READ | PROT_WRITE /* required */,
  85.                             MAP_SHARED /* recommended */,
  86.                             fd, buf.m.offset);

  87.         if (MAP_FAILED == buffers[n_buffers].start)
  88.             printf ("mmap failed\n");
  89.     }

  90.     for (i = 0; i < n_buffers; ++i)
  91.     {
  92.         struct v4l2_buffer buf;
  93.         CLEAR (buf);

  94.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  95.         buf.memory = V4L2_MEMORY_MMAP;
  96.         buf.index = i;

  97.         if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))//申请到的缓冲进入列队
  98.             printf ("VIDIOC_QBUF failed\n");
  99.     }

  100.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

  101.     if (-1 == ioctl (fd, VIDIOC_STREAMON, &type)) //开始捕捉图像数据
  102.         printf ("VIDIOC_STREAMON failed\n");

  103.     for (i = 0; i < 1; i++) //这一段涉及到异步IO
  104.     {
  105.         fd_set fds;
  106.         struct timeval tv;
  107.         int r;

  108.         FD_ZERO (&fds);//将指定的文件描述符集清空
  109.         FD_SET (fd, &fds);//在文件描述符集合中增加一个新的文件描述符

  110.         /* Timeout. */
  111.         tv.tv_sec = 2;
  112.         tv.tv_usec = 0;

  113.         r = select (fd + 1, &fds, NULL, NULL, &tv);//判断是否可读(即摄像头是否准备好),tv是定时

  114.         if (-1 == r) {
  115.             if (EINTR == errno)
  116.                 continue;
  117.             printf ("select err\n");
  118.         }
  119.         if (0 == r) {
  120.             fprintf (stderr, "select timeout\n");
  121.             exit (EXIT_FAILURE);
  122.         }

  123.         if (read_frame ())//如果可读,执行read_frame ()函数,并跳出循环
  124.             break;
  125.     }

  126. unmap:
  127.     for (i = 0; i < n_buffers; ++i)
  128.         if (-1 == munmap (buffers[i].start, buffers[i].length))
  129.             printf ("munmap error");
  130.     close (fd);
  131.     fclose (file_fd);
  132.     exit (EXIT_SUCCESS);
  133.     return 0;
  134. }

转载自:http://daimajishu.iteye.com/blog/1085484

阅读(7297) | 评论(2) | 转发(1) |
给主人留下些什么吧!~~

transistor02011-11-29 22:24:04

恩,这代码确实有这问题,我自己的需要拔插一下摄像头的usb接口,其实有一个v4l2的调用例子,那个蛮好用,uvccapture。

2011-11-26 11:26:57

楼主,你好,我用了你的代码,可是保存的图片里边是空的,请问为什么啊,是和摄像头有关啊,还请赐教。717605600这是我的q,希望能多和您请教,谢谢