Using the Video4Linux/usbvc VIDIOC_ENUM_FMT ioctl to enumerate supported image formats/codecs
The man page for usbvc only gives a one-liner:
VIDIOC_ENUM_FMT
Enumerate the video formats supported by the device.
With no specific detail, we need to read the documentation which states:
"To enumerate image formats applications initialize the type and index field of struct v4l2_fmtdesc and call the VIDIOC_ENUM_FMT ioctl with a pointer to this structure. Drivers fill the rest of the structure or return an EINVAL error code. All formats are enumerable by beginning at index zero and incrementing by one until EINVAL is returned."
This is the v4l2_fmtdesc structure that we'll be using:
336 /*
337 * F O R M A T E N U M E R A T I O N
338 */
339 struct v4l2_fmtdesc
340 {
341 uint32_t index; /* Format number */
342 enum v4l2_buf_type type; /* buffer type */
343 uint32_t flags;
344 char description[32]; /* Description string */
345 uint32_t pixelformat; /* Format fourcc */
346 uint32_t reserved[4];
347 };
The documentation tells us to use increasing integer values for 'index' starting at zero and incrementing by one until the ioctl call returns EINVAL. That's just going to be a FOR loop so, nothing complicated there. We need to do this for each of the buffer types (v4l2_buf_type). These are the all the defined buffer types:
120 enum v4l2_buf_type {
121 V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
122 V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
123 V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
124 V4L2_BUF_TYPE_VBI_CAPTURE = 4,
125 V4L2_BUF_TYPE_VBI_OUTPUT = 5,
126 #if 1
127 /* Experimental Sliced VBI */
128 V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
129 V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7,
130 #endif
131 V4L2_BUF_TYPE_PRIVATE = 0x80
132 };However the documentation also states that only the following is actually supported by the VIDIOC_ENUM_FMT ioctl:
V4L2_BUF_TYPE_VIDEO_CAPTURE
V4L2_BUF_TYPE_VIDEO_OUTPUT
V4L2_BUF_TYPE_VIDEO_OVERLAY
and custom (driver defined) types with code V4L2_BUF_TYPE_PRIVATE and higher.
The flags parameter within the v4l2_fmtdesc struct only has one option at this time, namely V4L2_FMT_FLAG_COMPRESSED. If set then the current format is compressed else it's uncompressed.
The description paramter is just an ASCII name for the format and is based on the FourCC code.
The pixelformat parameter is a four character code that is calculated by the v4l2_fourcc macro:
73 /*
74 * M I S C E L L A N E O U S
75 */
76
77 /* Four-character-code (FOURCC) */
78 #define v4l2_fourcc(a, b, c, d) \
79 (((uint32_t)(a)<<0) | ((uint32_t)(b)<<8) | \
80 ((uint32_t)(c)<<16)|((uint32_t)(d)<<24))
The unique FOURCC value assigned to every compression format and pixel layout allows video frames to be passed between file and codec by ensuring the FOURCC of the source frame matches a FOURCC supported by the codec. To understand Fourcc further here's some reference material:
- http://en.wikipedia.org/wiki/FourCC
- http://www.fourcc.org/fcccodec.htm (has a long list of all known FourCC codec values)
/*
* get_supported_video_formats
*
* @cam - Pointer to a camera object
*
* Enumerate the video formats supported by the device using the
* VIDIOC_ENUM_FMT ioctl.
*/
void get_supported_video_formats(camera_t * cam){
/*
* To enumerate image formats we have to initialise the type and index field
* of struct v4l2_fmtdesc and call the VIDIOC_ENUM_FMT ioctl with a pointer
* to this structure. Drivers fill the rest of the structure or return an
* EINVAL error code. All formats are enumerable by beginning at index zero
* and incrementing by one until EINVAL is returned.
*
* Only these buffer types are valid within the format field:
* V4L2_BUF_TYPE_VIDEO_CAPTURE
* V4L2_BUF_TYPE_VIDEO_OUTPUT
* V4L2_BUF_TYPE_VIDEO_OVERLAY
* and custom (driver defined) types with code V4L2_BUF_TYPE_PRIVATE and higher.
*
* This function only implements the first buffer types, i.e. no customer/private types
*/struct v4l2_fmtdesc vid_fmtdesc; /* Enumerated video formats supported by the device */
memset(&vid_fmtdesc, 0, sizeof(vid_fmtdesc));
vid_fmtdesc.index = 0;
char *buf_types[] = {"VIDEO_CAPTURE","VIDEO_OUTPUT", "VIDEO_OVERLAY"}; /* Conversion between enumerated type & english */
char *flags[] = {"uncompressed", "compressed"};
fprintf(stdout, "\nDiscovering supported video formats:\n");/* For each of the supported v4l2_buf_type buffer types */
for (vid_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vid_fmtdesc.type < V4L2_BUF_TYPE_VIDEO_OVERLAY; vid_fmtdesc.type++)
{
/* Send the VIDIOC_ENUM_FM ioctl and print the results */
while( ioctl( cam->dev_fd, VIDIOC_ENUM_FMT, &vid_fmtdesc ) == 0 )
{/* We got a video format/codec back */
fprintf(stdout,"VIDIOC_ENUM_FMT(%d, %s)\n", vid_fmtdesc.index, buf_types[vid_fmtdesc.type-1]);
fprintf(stdout, " index :%d\n", vid_fmtdesc.ind
fprintf(stdout, " type :%s\n", buf_types[vid_fmtdesc.type-1]);
fprintf(stdout, " flags :%s\n", flags[vid_fmtdesc.flags]);
fprintf(stdout, " description :%s\n", vid_fmtdesc.description);/* Convert the pixelformat attributes from FourCC into 'human readable' format */
fprintf(stdout, " pixelformat :%c%c%c%c\n",
vid_fmtdesc.pixelformat & 0xFF, (vid_fmtdesc.pixelformat >> 8) & 0xFF,
(vid_fmtdesc.pixelformat >> 16) & 0xFF, (vid_fmtdesc.pixelformat >> 24) & 0xFF);/* Increment the index */
vid_fmtdesc.index++;}
}
}/* End of get_supported_video_formats() */
The output of the above using a Toshiba Tecra M5 with a Logitech QuickCam Pro 5000 yields the following output:
Discovering supported video formats:
VIDIOC_ENUM_FMT(0, VIDEO_CAPTURE)
index :0
type :VIDEO_CAPTURE
flags :compressed
description :MJPEG
pixelformat :MJPG
VIDIOC_ENUM_FMT(1, VIDEO_CAPTURE)
index :1
type :VIDEO_CAPTURE
flags :uncompressed
description :YUYV
pixelformat :YUYV
The Sun Studio 12 Project (includes all source code) can be downloaded from here.