Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List available capture formats

New to V4L, I decided to start using the video4linux2 library in order to capture a frame from my camera in C (I am using the uvcvideo module with a Ricoh Co. camera). I followed several guides and tutorials, and managed to get a running program. My question is mainly about this usual code line :

struct v4l2_format format = {0};
format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
// ...

This is where I set the actual video format to use when capturing. As you can see, in this sample, I'm using MJPEG (http://lxr.free-electrons.com/source/include/uapi/linux/videodev2.h#L390). Even though this might be a great format and all, my application will probably require simple RGB formatting, pixel per pixel I guess. For this reason, I tried using RGB format constants such as V4L2_PIX_FMT_RGB24. Now for some reason... v4l2 doesn't like it. I'm guessing this is hardware-related, but I'd like to avoid MJPEG manipulations as much as possible. For testing purposes, I tried using other constants and formats, but no matter what I did, v4l2 kept changing the pixelformat field's value :

xioctl(fd, VIDIOC_S_FMT, &format); // This call succeeds with errno != EINTR.
if(format.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB24){
    // My program always enters this block when not using MJPEG.
    fprintf(stderr, "Format wasn't accepted by v4l2.");
    exit(4);
}

Now my question is : is there a way I could get a list of accepted video formats (and I mean, accepted by my camera/v4l2), from which I could pick something else than MJPEG ? If you think I have to stick with MJPEG, would you recommend me any library allowing me to manipulate it, and eventually, to draw back the capture in a GUI frame ?

Barbarian test code

I used the following trick to test all available formats on my hardware. First, some shell script to get a list of all formats...

grep 'V4L2_PIX_FMT' /usr/include/linux/videodev2.h | grep define | tr '\t' ' ' | cut -d' ' -f2 | sed 's/$/,/g'

... the output of which is used in this C program :

int formats[] = {/* result of above command */};
int i = 0;
struct v4l2_format format = {0};

for(i = 0; i < /* number of lines in previous command output */; i++){
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = 320;
    format.fmt.pix.height = 240;
    format.fmt.pix.pixelformat = formats[i];
    format.fmt.pix.field = V4L2_FIELD_NONE;
    if(xioctl(fd, VIDIOC_S_FMT, &format) != -1 && format.fmt.pix.pixelformat == formats[i])
        fprintf(stderr, "Accepted : %d\n", i);
}

This test reveals that only V4L2_PIX_FMT_YUYV and V4L2_PIX_FMT_MJPEG are functional. Any way I could improve this, or is it hardware-related ?

like image 976
John WH Smith Avatar asked Mar 21 '14 16:03

John WH Smith


People also ask

What are v4l2 devices?

Video4Linux (V4L for short) is a collection of device drivers and an API for supporting realtime video capture on Linux systems. It supports many USB webcams, TV tuners, and related devices, standardizing their output, so programmers can easily add video support to their applications. Video4Linux.

What is V4L utils?

v4l-utils is a set of utilities for handling media devices.


2 Answers

In Linux, command line utility v4l2-ctl displays all of a webcam's natively supported formats -- install it with sudo apt-get install v4l-utils, run it with v4l2-ctl -dX --list-formats-ext where X is the camera index as in /dev/videoX. These formats are reported to the v4l2 kernel module via uvcvideo module and they are supported natively by the webcam chipset. Only the listed formats are supported by v4l2, anything else would need to be coded by the user, and RGBs are very seldom provided, despite virtually all CCDs working in Bayer RGGB. The most common formats by far are YUV422 (YUYV or YUY2) and MJPEG, with a certain overlap: MJPEG achieve larger frame rates for large resolutions.

C++ code for listing the camera formats can be found in Chromium GetDeviceSupportedFormats() implementation for Linux here.

If you have to plug code to convert YUV to RGB I'd recommend libyuv which has been optimized for plenty of architectures.

like image 61
miguelao Avatar answered Oct 23 '22 17:10

miguelao


In order to enumerate the available format you can use ioctl VIDIOC_ENUM_FMT

To print descriptions of capture format supported by /dev/video0 you can process like this :

#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/videodev2.h>

int main()
{
    int fd = v4l2_open("/dev/video0", O_RDWR);
    if (fd != -1)
    {
        struct v4l2_fmtdesc fmtdesc;
        memset(&fmtdesc,0,sizeof(fmtdesc));
        fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        while (ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) == 0)
        {    
            printf("%s\n", fmtdesc.description);
            fmtdesc.index++;
        }
        v4l2_close(fd);
    }
}
like image 4
mpromonet Avatar answered Oct 23 '22 19:10

mpromonet