Advertisement
Guest User

Untitled

a guest
Oct 27th, 2010
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.91 KB | None | 0 0
  1. /*
  2.  *  V4L2 video capture example
  3.  *
  4.  *  This program can be used and distributed without restrictions.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <assert.h>
  11.  
  12. #include <getopt.h>             /* getopt_long() */
  13.  
  14. #include <fcntl.h>              /* low-level i/o */
  15. #include <unistd.h>
  16. #include <errno.h>
  17. #include <malloc.h>
  18. #include <sys/stat.h>
  19. #include <sys/types.h>
  20. #include <sys/time.h>
  21. #include <sys/mman.h>
  22. #include <sys/ioctl.h>
  23.  
  24. #include <asm/types.h>          /* for videodev2.h */
  25.  
  26. #include <linux/videodev2.h>
  27.  
  28. #include <iostream>
  29. #include <fstream>
  30. #include <sstream>
  31.  
  32. using namespace std;
  33.  
  34. int i = 0;
  35.  
  36. #define CLEAR(x) memset (&(x), 0, sizeof (x))
  37.  
  38. struct buffer {
  39.     void * start;
  40.     size_t length;
  41. };
  42.  
  43. static char * dev_name = NULL;
  44. static int fd = -1;
  45. struct buffer * buffers = NULL;
  46. static unsigned int n_buffers = 0;
  47.  
  48. static void errno_exit(const char * s) {
  49.     fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
  50.  
  51.     exit(EXIT_FAILURE);
  52. }
  53.  
  54. static int xioctl(int fd, int request, void * arg) {
  55.     int r;
  56.  
  57.     do
  58.         r = ioctl(fd, request, arg);
  59.     while (-1 == r && EINTR == errno);
  60.  
  61.     return r;
  62. }
  63.  
  64. static void process_image(const void * p) {
  65.     ++i;
  66.     fputc('.', stdout);
  67.     fflush(stdout);
  68.  
  69.     std::stringstream out;
  70.     out << "capt-" << i << ".raw";
  71.  
  72.     ofstream outfile(out.str().c_str(), ofstream::binary);
  73.     outfile.write((const char*) p, buffers[0].length);
  74.     outfile.close();
  75. }
  76.  
  77. static int read_frame(void) {
  78.     struct v4l2_buffer buf;
  79.  
  80.     CLEAR (buf);
  81.  
  82.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  83.     buf.memory = V4L2_MEMORY_MMAP;
  84.  
  85.     if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
  86.         switch (errno) {
  87.         case EAGAIN:
  88.             return 0;
  89.         case EIO:
  90.         default:
  91.             errno_exit("VIDIOC_DQBUF");
  92.         }
  93.     }
  94.  
  95.     assert (buf.index < n_buffers);
  96.  
  97.     process_image(buffers[buf.index].start);
  98.  
  99.     if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  100.         errno_exit("VIDIOC_QBUF");
  101.  
  102.     return 1;
  103. }
  104.  
  105. static void mainloop(void) {
  106.     unsigned int count;
  107.  
  108.     count = 100;
  109.  
  110.     while (count-- > 0) {
  111.         for (;;) {
  112.             fd_set fds;
  113.             struct timeval tv;
  114.             int r;
  115.  
  116.             FD_ZERO (&fds);
  117.             FD_SET (fd, &fds);
  118.  
  119.             /* Timeout. */
  120.             tv.tv_sec = 2;
  121.             tv.tv_usec = 0;
  122.  
  123.             r = select(fd + 1, &fds, NULL, NULL, &tv);
  124.  
  125.             if (-1 == r) {
  126.                 if (EINTR == errno)
  127.                     continue;
  128.  
  129.                 errno_exit("select");
  130.             }
  131.  
  132.             if (0 == r) {
  133.                 fprintf(stderr, "select timeout\n");
  134.                 exit(EXIT_FAILURE);
  135.             }
  136.  
  137.             if (read_frame())
  138.                 break;
  139.  
  140.             /* EAGAIN - continue select loop. */
  141.         }
  142.     }
  143. }
  144.  
  145. static void start_capturing(void) {
  146.     unsigned int i;
  147.     enum v4l2_buf_type type;
  148.  
  149.     for (i = 0; i < n_buffers; ++i) {
  150.         struct v4l2_buffer buf;
  151.  
  152.         CLEAR (buf);
  153.  
  154.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  155.         buf.memory = V4L2_MEMORY_MMAP;
  156.         buf.index = i;
  157.  
  158.         if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
  159.             errno_exit("VIDIOC_QBUF");
  160.     }
  161.  
  162.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  163.  
  164.     if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
  165.         errno_exit("VIDIOC_STREAMON");
  166. }
  167.  
  168. static void uninit_device(void) {
  169.     unsigned int i;
  170.  
  171.     for (i = 0; i < n_buffers; ++i)
  172.         if (-1 == munmap(buffers[i].start, buffers[i].length))
  173.             errno_exit("munmap");
  174.  
  175.     free(buffers);
  176. }
  177.  
  178. static void init_mmap(void) {
  179.     struct v4l2_requestbuffers req;
  180.  
  181.     CLEAR (req);
  182.  
  183.     req.count = 4;
  184.     req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  185.     req.memory = V4L2_MEMORY_MMAP;
  186.  
  187.     if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
  188.         if (EINVAL == errno) {
  189.             fprintf(stderr, "%s does not support "
  190.                 "memory mapping\n", dev_name);
  191.             exit(EXIT_FAILURE);
  192.         } else {
  193.             errno_exit("VIDIOC_REQBUFS");
  194.         }
  195.     }
  196.  
  197.     if (req.count < 2) {
  198.         fprintf(stderr, "Insufficient buffer memory on %s\n", dev_name);
  199.         exit(EXIT_FAILURE);
  200.     }
  201.  
  202.     buffers = (buffer*) calloc(req.count, sizeof(*buffers));
  203.  
  204.     if (!buffers) {
  205.         fprintf(stderr, "Out of memory\n");
  206.         exit(EXIT_FAILURE);
  207.     }
  208.  
  209.     for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
  210.         struct v4l2_buffer buf;
  211.  
  212.         CLEAR (buf);
  213.  
  214.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  215.         buf.memory = V4L2_MEMORY_MMAP;
  216.         buf.index = n_buffers;
  217.  
  218.         if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
  219.             errno_exit("VIDIOC_QUERYBUF");
  220.  
  221.         buffers[n_buffers].length = buf.length;
  222.         buffers[n_buffers].start = mmap(NULL /* start anywhere */, buf.length,
  223.                 PROT_READ | PROT_WRITE /* required */,
  224.                 MAP_SHARED /* recommended */, fd, buf.m.offset);
  225.  
  226.         if (MAP_FAILED == buffers[n_buffers].start)
  227.             errno_exit("mmap");
  228.     }
  229. }
  230.  
  231. static void init_device(void) {
  232.     struct v4l2_capability cap;
  233.     struct v4l2_cropcap cropcap;
  234.     struct v4l2_crop crop;
  235.     struct v4l2_format fmt;
  236.     unsigned int min;
  237.  
  238.     if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
  239.         if (EINVAL == errno) {
  240.             fprintf(stderr, "%s is no V4L2 device\n", dev_name);
  241.             exit(EXIT_FAILURE);
  242.         } else {
  243.             errno_exit("VIDIOC_QUERYCAP");
  244.         }
  245.     }
  246.  
  247.     if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
  248.         fprintf(stderr, "%s is no video capture device\n", dev_name);
  249.         exit(EXIT_FAILURE);
  250.     }
  251.  
  252.     /* Select video input, video standard and tune here. */
  253.  
  254.     CLEAR (cropcap);
  255.  
  256.     cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  257.  
  258.     if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
  259.         crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  260.         crop.c = cropcap.defrect; /* reset to default */
  261.  
  262.         if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
  263.             switch (errno) {
  264.             case EINVAL:
  265.                 /* Cropping not supported. */
  266.                 break;
  267.             default:
  268.                 /* Errors ignored. */
  269.                 break;
  270.             }
  271.         }
  272.     } else {
  273.         /* Errors ignored. */
  274.     }
  275.  
  276.     CLEAR (fmt);
  277.  
  278.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  279.     fmt.fmt.pix.width = 640;
  280.     fmt.fmt.pix.height = 480;
  281.     fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  282.     fmt.fmt.pix.field = V4L2_FIELD_ANY;
  283.  
  284.     if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
  285.         errno_exit("VIDIOC_S_FMT");
  286.  
  287.     /* Note VIDIOC_S_FMT may change width and height. */
  288.  
  289.     /* Buggy driver paranoia. */
  290.     min = fmt.fmt.pix.width * 2;
  291.     if (fmt.fmt.pix.bytesperline < min)
  292.         fmt.fmt.pix.bytesperline = min;
  293.     min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
  294.     if (fmt.fmt.pix.sizeimage < min)
  295.         fmt.fmt.pix.sizeimage = min;
  296.  
  297.     init_mmap();
  298.  
  299. }
  300.  
  301. static void close_device(void) {
  302.     if (-1 == close(fd))
  303.         errno_exit("close");
  304.  
  305.     fd = -1;
  306. }
  307.  
  308. static void open_device(void) {
  309.     struct stat st;
  310.  
  311.     if (-1 == stat(dev_name, &st)) {
  312.         fprintf(stderr, "Cannot identify '%s': %d, %s\n", dev_name, errno,
  313.                 strerror(errno));
  314.         exit(EXIT_FAILURE);
  315.     }
  316.  
  317.     if (!S_ISCHR (st.st_mode)) {
  318.         fprintf(stderr, "%s is no device\n", dev_name);
  319.         exit(EXIT_FAILURE);
  320.     }
  321.  
  322.     fd = open(dev_name, O_RDWR /* required */| O_NONBLOCK, 0);
  323.  
  324.     if (-1 == fd) {
  325.         fprintf(stderr, "Cannot open '%s': %d, %s\n", dev_name, errno,
  326.                 strerror(errno));
  327.         exit(EXIT_FAILURE);
  328.     }
  329. }
  330.  
  331. int main(int argc, char ** argv) {
  332.     dev_name = "/dev/video0";
  333.  
  334.     open_device();
  335.     init_device();
  336.     start_capturing();
  337.     mainloop();
  338.     uninit_device();
  339.     close_device();
  340.     exit(EXIT_SUCCESS);
  341.  
  342.     return 0;
  343. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement