Ubuntu10.04中利用V4L2读取摄像头数据并保存成文件【转】

简介: 转自:http://blog.chinaunix.net/uid-29339876-id-4042245.html 利用V4L2读取UVC摄像头数据并保存成视频文件,主要参考http://linuxtv.

转自:http://blog.chinaunix.net/uid-29339876-id-4042245.html

利用V4L2读取UVC摄像头数据并保存成视频文件,主要参考http://linuxtv.org/downloads/v4l-dvb-apis/index.html中的示例Appendix D. Video Capture Example将读取的文件保存在当前目录下的file.yuv中,修改后的完成代码如下:
    

点击(此处)折叠或打开

  1. /*
  2.  * V4L2 video capture example
  3.  * AUTHOT : WANGTISHENG
  4.  * DATA : 2013-12-18
  5.  */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include <getopt.h> /* getopt_long() */
  11. #include <fcntl.h> /* low-level i/o */
  12. #include <unistd.h>
  13. #include <errno.h>
  14. #include <sys/stat.h>
  15. #include <sys/types.h>
  16. #include <sys/time.h>
  17. #include <sys/mman.h>
  18. #include <sys/ioctl.h>

  19. #include <linux/videodev2.h>

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

  21. struct buffer {
  22.         void *start;
  23.         size_t length;
  24. };

  25. static char *dev_name;
  26. static int fd = -1;        //DEVICE NUMBER
  27. struct buffer *buffers;
  28. static unsigned int n_buffers;
  29. static int frame_count = 70;
  30. FILE *fp;                                //FILE POINTOR

  31. static void errno_exit(const char *s)
  32. {
  33.         fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
  34.         exit(EXIT_FAILURE);
  35. }

  36. static int xioctl(int fh, int request, void *arg)
  37. {
  38.         int r;
  39.         do {
  40.                 r = ioctl(fh, request, arg);
  41.         } while (-1 == r && EINTR == errno);
  42.         return r;
  43. }
  44. //处理函数
  45. static void process_image(const void *p, int size)
  46. {
  47.         fwrite(p,size, 1, fp);
  48. }

  49. static int read_frame(FILE *fp)
  50. {
  51.         struct v4l2_buffer buf;
  52.         CLEAR(buf);

  53.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  54.         buf.memory = V4L2_MEMORY_MMAP;
  55.         
  56.         if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf))
  57.                 errno_exit("VIDIOC_DQBUF");
  58.         
  59.         process_image(buffers[buf.index].start, buf.bytesused);

  60.         if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  61.             errno_exit("VIDIOC_QBUF");

  62.         return 1;
  63. }

  64. static void mainloop(void)
  65. {
  66.         unsigned int count;
  67.         count = frame_count;
  68.         while (count-- > 0) {
  69.             printf("No.%d\n",frame_count - count);        //显示当前帧数目
  70.             read_frame(fp);
  71.         }
  72.         printf("\nREAD AND SAVE DONE!\n");
  73. }

  74. static void stop_capturing(void)
  75. {
  76.         enum v4l2_buf_type type;

  77.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  78.         if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
  79.             errno_exit("VIDIOC_STREAMOFF");
  80. }

  81. static void start_capturing(void)
  82. {
  83.         unsigned int i;
  84.         enum v4l2_buf_type type;

  85.         for (i = 0; i < n_buffers; ++i) {
  86.                 struct v4l2_buffer buf;

  87.                 CLEAR(buf);
  88.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  89.                 buf.memory = V4L2_MEMORY_MMAP;
  90.                 buf.index = i;

  91.                 if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  92.                         errno_exit("VIDIOC_QBUF");
  93.         }
  94.         type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  95.         if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
  96.                 errno_exit("VIDIOC_STREAMON");
  97. }

  98. static void uninit_device(void)
  99. {
  100.         unsigned int i;

  101.         for (i = 0; i < n_buffers; ++i)
  102.                 if (-1 == munmap(buffers[i].start, buffers[i].length))
  103.                         errno_exit("munmap");

  104.         free(buffers);
  105. }



  106. static void init_mmap(void)
  107. {
  108.         struct v4l2_requestbuffers req;

  109.         CLEAR(req);

  110.         req.count = 4;
  111.         req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  112.         req.memory = V4L2_MEMORY_MMAP;

  113.         if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
  114.                 if (EINVAL == errno) {
  115.                         fprintf(stderr, "%s does not support "
  116.                                  "memory mapping\n", dev_name);
  117.                         exit(EXIT_FAILURE);
  118.                 } else {
  119.                         errno_exit("VIDIOC_REQBUFS");
  120.                 }
  121.         }

  122.         if (req.count < 2) {
  123.                 fprintf(stderr, "Insufficient buffer memory on %s\n",
  124.                          dev_name);
  125.                 exit(EXIT_FAILURE);
  126.         }

  127.         buffers = calloc(req.count, sizeof(*buffers));

  128.         if (!buffers) {
  129.                 fprintf(stderr, "Out of memory\n");
  130.                 exit(EXIT_FAILURE);
  131.         }

  132.         for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
  133.                 struct v4l2_buffer buf;

  134.                 CLEAR(buf);

  135.                 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  136.                 buf.memory = V4L2_MEMORY_MMAP;
  137.                 buf.index = n_buffers;

  138.                 if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
  139.                         errno_exit("VIDIOC_QUERYBUF");

  140.                 buffers[n_buffers].length = buf.length;
  141.                 buffers[n_buffers].start =
  142.                         mmap(NULL /* start anywhere */,
  143.                               buf.length,
  144.                               PROT_READ | PROT_WRITE /* required */,
  145.                               MAP_SHARED /* recommended */,
  146.                               fd, buf.m.offset);

  147.                 if (MAP_FAILED == buffers[n_buffers].start)
  148.                         errno_exit("mmap");
  149.         }
  150. }


  151. static void init_device(void)
  152. {
  153.         struct v4l2_capability cap;
  154.         struct v4l2_format fmt;

  155.         if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {        //测试参数
  156.                 if (EINVAL == errno) {
  157.                         fprintf(stderr, "%s is no V4L2 device\n",
  158.                                  dev_name);
  159.                         exit(EXIT_FAILURE);
  160.                 } else {
  161.                         errno_exit("VIDIOC_QUERYCAP");
  162.                 }
  163.         }

  164.         if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
  165.                 fprintf(stderr, "%s is no video capture device\n",
  166.                          dev_name);
  167.                 exit(EXIT_FAILURE);
  168.         }

  169.         if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
  170.                 fprintf(stderr, "%s does not support streaming i/o\n",
  171.                     dev_name);
  172.                 exit(EXIT_FAILURE);
  173.         }




  174.         CLEAR(fmt);
  175.         fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  176.         fmt.fmt.pix.width = 640;
  177.         fmt.fmt.pix.height = 480;
  178.         fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  179.         fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

  180.         if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))        //设置格式
  181.                 errno_exit("VIDIOC_S_FMT");        
  182.         init_mmap();
  183. }

  184. static void close_device(void)
  185. {
  186.         if (-1 == close(fd))
  187.                 errno_exit("close");

  188.         fd = -1;
  189. }

  190. static void open_device(void)
  191. {
  192.         //加上O_NONBLOCK会出现如下错误
  193.         //VIDIOC_DQBUF error 11, Resource temporarily unavailable
  194.         fd = open(dev_name, O_RDWR /* required */ /*| O_NONBLOCK*/, 0);

  195.         if (-1 == fd) {
  196.                 fprintf(stderr, "Cannot open '%s': %d, %s\n",
  197.                          dev_name, errno, strerror(errno));
  198.                 exit(EXIT_FAILURE);
  199.         }
  200. }


  201. int main(int argc, char **argv)
  202. {
  203.         dev_name = "/dev/video0";
  204.         
  205.         if(argc != 2)
  206.         {
  207.             printf("usage :%s filename\n", argv[0]);
  208.             exit(0);
  209.         }
  210.         if ((fp = fopen(argv[1], "w")) == NULL) {
  211.             perror("Creat file failed");
  212.             exit(0);
  213.         }
  214.         open_device();
  215.         init_device();
  216.         start_capturing();
  217.         mainloop();                //主要处理均在该函数中实现
  218.         fclose(fp);
  219.         stop_capturing();
  220.         uninit_device();
  221.         close_device();
  222.         //fprintf(stderr, "\n");
  223.         return 0;
  224. }

Makefile   

点击(此处)折叠或打开

  1. v4l2_capture_example:v4l2_capture_example.c
  2.     gcc -Wall -o $@ $<

  3. clean:
  4.     rm -rf v4l2_capture_example

make测试
    运行方法
        $ 
./v4l2_capture_example file.yuv
    
可完成摄像头数据的读取和保存。附上查看YUV格式的软件一枚~~~~~~~
YUV_Tools.rar

【作者】 张昺华
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
目录
相关文章
|
1月前
|
Shell Linux C语言
【Shell 命令集合 磁盘管理 】Linux 控制光驱或可移动媒体设备的弹出和关闭操作 eject命令使用教程
【Shell 命令集合 磁盘管理 】Linux 控制光驱或可移动媒体设备的弹出和关闭操作 eject命令使用教程
36 1
|
1月前
|
Shell Linux C语言
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 清除终端屏幕内容 clear命令 使用指南
【Shell 命令集合 系统设置 】⭐⭐⭐Linux 清除终端屏幕内容 clear命令 使用指南
32 0
Ubuntu18.04设置系统默认音频设备:使用pavucontrol命令
Ubuntu18.04设置系统默认音频设备:使用pavucontrol命令
1256 0
Ubuntu18.04设置系统默认音频设备:使用pavucontrol命令
|
1月前
|
存储 编解码 Shell
【Shell 命令集合 系统设置 】⭐Linux 设置和调整帧缓冲设备 fbset命令 使用指南
【Shell 命令集合 系统设置 】⭐Linux 设置和调整帧缓冲设备 fbset命令 使用指南
30 0
|
4月前
|
计算机视觉 索引 Python
OpenCV中读取、显示、保存摄像头视频讲解与实战(附Python源码)
OpenCV中读取、显示、保存摄像头视频讲解与实战(附Python源码)
47 0
|
4月前
|
Linux Shell 数据库
Linux中查看/编辑/查找/传输文件的那些命令
Linux中查看/编辑/查找/传输文件的那些命令
83 0
|
7月前
|
Linux
刻录cd(不同系统的方式)
刻录cd(不同系统的方式)
88 0
|
7月前
|
Linux
记录一个解决Arm Linux端U盘挂载时文件名显示乱码、Qt显示乱码的问题
记录一个解决Arm Linux端U盘挂载时文件名显示乱码、Qt显示乱码的问题
255 0
|
Linux
linux文件复制覆盖命令提示操作问题
解决文件复制覆盖提示操作问题
183 0
|
数据安全/隐私保护 Python Windows
安装无法继续,因为一个必需文件已损坏或不可用,请从原始源光盘活下载位置重新运行安装程序
了解安装无法继续,因为一个必需文件已损坏或不可用,请从原始源光盘活下载位置重新运行安装程序
832 0