In the previous blog entry we looked at how to obtain the video controls using the VIDIOC_QUERYCTRL & VIDIOC_QUERYMENU ioctls.  Now we'll take a look at how to use the VIDIOC_ENUM_FMT ioctl to enumerate image formats and codecs supported by the camera/capture device.

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:
With the understanding of what needs to be done, we can now implement the following function to grab all supported formats/codecs.  get_supported_video_formats() is implemented within webcam.c to grab the video formats and codecs supported by the video camera/capture device.

/*
* 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.
Comments:

Post a Comment:
  • HTML Syntax: NOT allowed

This blog copyright 2009 by Steve Scargall