USB webcam image capture in C++ WITHOUT openCV (LINUX)

Prem picture Prem · Feb 22, 2013 · Viewed 19.3k times · Source

How do I capture an image with my webcam using C++ and save it to disk? I cannot use OPENCV due to hardware problems. The usb webcam does work with other programs such as mplayer, cheese, gpicview, ffmpeg, etc.

I heard V4L is capable of doing this, but does it have any C++ libraries? Can anybody show me a C++ example on how to do this?

Answer

EGOrecords picture EGOrecords · Feb 22, 2013

It is quite easy, you can do read on a videodevice, after you have activated some ioctls to get the cam under your control.

You can use v4l2 for this job. You do this in those steps:

  1. Open the devicefile of the camera (usually "/dev/video0")
  2. Tell v4l2 that you want to know some capability of the device
  3. Tell v4l2 to read from the device
  4. Tell v4l2 wich format you want to use

Here is a implementation I use for this job. It will set the camera to capture a video in 320x240 Pixel, but you can read the resolutions, the camera is capable of from the v4l2_capability structure.

Also I haven't tested the code on different Cameras than my PS2 EyeToy, but it is mostly taken from a sample program named qv4l2 (you can get it from here). This program should solve all other issues you usually see there.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>              /* low-level i/o */
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>

#include <linux/videodev2.h>

static int xioctl(int fh, int request, void *arg)
{
    int r;
    do {
        r = ioctl(fh, request, arg);
    } while (-1 == r && EINTR == errno);
    return r;
}

int allocCamera(const char* file) 
{
    struct v4l2_capability cap;
    struct v4l2_crop crop;
    struct v4l2_format fmt;

    int camera_fd = open(file, O_RDONLY);

    if (-1 == xioctl (camera_fd, VIDIOC_QUERYCAP, &cap)) {
        if (EINVAL == errno) {
            fprintf (stderr, "%s is no V4L2 device\n", file);
            exit (EXIT_FAILURE);
        } else {
            printf("\nError in ioctl VIDIOC_QUERYCAP\n\n");
            exit(0);
        }
    }

    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
        fprintf (stderr, "%s is no video capture device\n", file);
        exit (EXIT_FAILURE);
    }

    if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
        fprintf (stderr, "%s does not support read i/o\n", file);
        exit (EXIT_FAILURE);
    }

    memset(&fmt, 0, sizeof(fmt));
    fmt.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width       = 320; 
    fmt.fmt.pix.height      = 240;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
    if (-1 == xioctl(camera_fd, VIDIOC_S_FMT, &fmt)) {
        printf("VIDIOC_S_FMT");
    }
    return camera_fd;
}