Capturing a picture in c++ using v4l2, explaining the process

  c++, image-capture, v4l2

I have been struggling with making a c++ code for capturing a picture from web-camera. I successfully did it, but I would like some clarification about the process i took.

So my code can be described in 6 steps, i will write them here along with my questions:
I. step: Initialize the device and set image format.

    const char* dev_name = "/dev/video0";
    int width=320;
    int height=240;
    int fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
    struct v4l2_format format = {0};
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = width;
    format.fmt.pix.height = height;
    format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YUYV //V4L2_PIX_FMT_RGB24
    format.fmt.pix.field = V4L2_FIELD_NONE; //V4L2_FIELD_NONE
    xioctl(fd, VIDIOC_S_FMT, &format);

II. step: Request for a buffer.

    struct v4l2_requestbuffers req = {0};
    req.count = 2;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    xioctl(fd, VIDIOC_REQBUFS, &req);
  1. question: What exactly does this "request a buffer" do?
  2. question: Is this buffer physically located inside the camera or on my pc?

III. step: Query the buffer and mapping.

    struct v4l2_buffer buf;
    buffer* buffers;
    unsigned int i;
    buffers = (buffer*) calloc(req.count, sizeof(*buffers));
    for (i = 0; i < req.count; i++) {
    clear_memmory(&(buf));

    (buf).type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    (buf).memory      = V4L2_MEMORY_MMAP;
    (buf).index       = i;

    xioctl(fd, VIDIOC_QUERYBUF, &buf);

    buffers[i].length = (buf).length;
    printf("A buff has a len of: %in",buffers[i].length);
    buffers[i].start = v4l2_mmap(NULL, (buf).length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, (buf).m.offset);
    
    if (MAP_FAILED == buffers[i].start) {
        perror("Can not map the buffers.");
        exit(EXIT_FAILURE);
        }
    }
  1. question: I understand that i do some mapping here, but can somebody explain why is this needed and what exactly is mapped where. To me it sounds like actual buffer is somewhere else and then i mapp it into my own buffer so i can read things from my buffer. Is this correct and where is the actual buffer?

  2. question: Could i also avoid the mapping?

IV. step: Start streaming. Queue the buffer.

    for (i = 0; i < 1; i++) {
        clear_memmory(&(buf));
        (buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        (buf).memory = V4L2_MEMORY_MMAP;
        (buf).index = i;
        xioctl(fd,VIDIOC_QBUF, &(buf));
        }
    enum v4l2_buf_type type;
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    xioctl(fd,VIDIOC_STREAMON, &type);
  1. question: What does the VIDIOC_QBUF do? Please be very precise here and using mostly child words in answer to this since this is very confusing.
  2. question: Should VIDIOC_QBUF happen after VIDIOC_STREAMON? Does it matter?

V. step: DeQueue the buffer and save a frame.

    do {
        FD_ZERO(&fds);
        FD_SET(fd, &fds);

        // Timeout.
        tv.tv_sec = 2;
        tv.tv_usec = 0;

        r = select(fd + 1, &fds, NULL, NULL, &tv);
        } while ((r == -1 && (errno = EINTR)));
    if (r == -1) {
        perror("select");
        exit(EXIT_FAILURE);
        }

    clear_memmory(&(buf));
    (buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    (buf).memory = V4L2_MEMORY_MMAP;
    xioctl(fd,VIDIOC_DQBUF, &(buf));
    
    printf("Buff index: %in",(buf).index);
    sprintf(out_name, "image%03d.ppm",pic_count);
    fout = fopen(out_name, "w");
    if (!fout) {
        perror("Cannot open image");
        exit(EXIT_FAILURE);
        }
    fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
    fclose(fout);
    pic_count++;
  1. question: Why is VIDIOC_DQBUF needed and what does it do?
  2. question: If i want to capture 3 frames and if i have only 1 buffer for 1 picture, do i need to queue, dequeue 3 times?
  3. question: If i want 1000000 pictures, can I make that buffer big enough to hold them all? What is limiting the size of that buffer? Is that buffer on the camera and that means all this pictures would be sitting in it?
  4. question: If i want 10 pictures taken at moments I chose, and if i go with making a buffer large enough for 10 pictures. What should i call at the moment i want to take a picture? only VIDIOC_QBUF? VIDIOC_QBUF and VIDIOC_DQBUF?, only VIDIOC_DQBUF?

Please don’t point me to https://01.org/linuxgraphics/gfx-docs/drm/media/uapi/v4l/vidioc-qbuf.html or other sites, as I have read everything i was able to found and I am still left with above unclarity. I really want detailed explanations about these questions. I thank you in advance for all helpful answers.

Source: Windows Questions C++

LEAVE A COMMENT