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


    转自: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 ", 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 ",frame_count - count);        //显示当前帧数目
    70.             read_frame(fp);
    71.         }
    72.         printf(" READ AND SAVE DONE! ");
    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 ", 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 ",
    124.                          dev_name);
    125.                 exit(EXIT_FAILURE);
    126.         }

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

    128.         if (!buffers) {
    129.                 fprintf(stderr, "Out of memory ");
    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 ",
    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 ",
    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 ",
    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 ",
    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 ", 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, " ");
    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

  • 相关阅读:
    理解和解决MySQL乱码问题
    搞清字符集和字符编码
    linux下卸载mysql
    mysqldump备份
    mysql 数据类型
    微信对接HIS——微信可查检验结果
    Install Haskell on Ubuntu and CentOS
    php用类生成二维码
    UVA Team Queue
    总有一种正能量触动你的心灵,读刘丁宁的一封信
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/7115061.html
Copyright © 2020-2023  润新知