if (-1 == ioctl (fd, VIDIOC_S_CTRL, &control)) {
perror ("VIDIOC_S_CTRL");
exit (EXIT_FAILURE);
}
}
memset (&control, 0, sizeof (control));
control.id = V4L2_CID_CONTRAST;
if (0 == ioctl (fd, VIDIOC_G_CTRL, &control)) {
control.value += 1;
/* The driver may clamp the value or return ERANGE, ignored here */
if (-1 == ioctl (fd, VIDIOC_S_CTRL, &control)
&& errno != ERANGE) {
perror ("VIDIOC_S_CTRL");
exit (EXIT_FAILURE);
}
/* Ignore if V4L2_CID_CONTRAST is unsupported */
} else if (errno != EINVAL) {
perror ("VIDIOC_G_CTRL");
exit (EXIT_FAILURE);
}
control.id = V4L2_CID_AUDIO_MUTE;
control.value = TRUE; /* silence */
/* Errors ignored */
ioctl (fd, VIDIOC_S_CTRL, &control);
1.9. Extended Controls
1.9.1. Introduction
The control mechanism as originally designed was meant to be used for user settings (brightness, saturation, etc). However, it turned out
to be a very useful model for implementing more complicated driver APIs where each driver implements only a subset of a larger API.
The MPEG encoding API was the driving force behind designing and implementing this extended control mechanism: the MPEG standard
is quite large and the currently supported hardware MPEG encoders each only implement a subset of this standard. Further more, many
parameters relating to how the video is encoded into an MPEG stream are specific to the MPEG encoding chip since the MPEG standard
only defines the format of the resulting MPEG stream, not how the video is actually encoded into that format.
Unfortunately, the original control API lacked some features needed for these new uses and so it was extended into the (not terribly
originally named) extended control API.
Even though the MPEG encoding API was the first effort to use the Extended Control API, nowadays there are also other classes of
Extended Controls, such as Camera Controls and FM Transmitter Controls. The Extended Controls API as well as all Extended Controls
classes are described in the following text.
1.9.2. The Extended Control API
Three new ioctls are available: VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS and VIDIOC_TRY_EXT_CTRLS. These ioctls act on arrays of controls (as
opposed to the VIDIOC_G_CTRL and VIDIOC_S_CTRL ioctls that act on a single control). This is needed since it is often required to atomically
change several controls at once.
Each of the new ioctls expects a pointer to a struct v4l2_ext_controls. This structure contains a pointer to the control array, a count of the
number of controls in that array and a control class. Control classes are used to group similar controls into a single class. For example,
control class V4L2_CTRL_CLASS_USER contains all user controls (i. e. all controls that can also be set using the old VIDIOC_S_CTRL ioctl). Control
class V4L2_CTRL_CLASS_MPEG contains all controls relating to MPEG encoding, etc.
All controls in the control array must belong to the specified control class. An error is returned if this is not the case.
It is also possible to use an empty control array (count == 0) to check whether the specified control class is supported.
The control array is a struct v4l2_ext_control array. The v4l2_ext_control structure is very similar to struct v4l2_control, except for the fact
that it also allows for 64-bit values and pointers to be passed.
It is important to realize that due to the flexibility of controls it is necessary to check whether the control you want to set actually is
supported in the driver and what the valid range of values is. So use the VIDIOC_QUERYCTRL and VIDIOC_QUERYMENU ioctls to check this. Also note
that it is possible that some of the menu indices in a control of type V4L2_CTRL_TYPE_MENU may not be supported (VIDIOC_QUERYMENU will return
an error). A good example is the list of supported MPEG audio bitrates. Some drivers only support one or two bitrates, others support a
wider range.
1.9.3. Enumerating Extended Controls
The recommended way to enumerate over the extended controls is by using VIDIOC_QUERYCTRL in combination with the
V4L2_CTRL_FLAG_NEXT_CTRL flag:
structv4l2_queryctrl qctrl;
qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
while (0 == ioctl (fd, VIDIOC_QUERYCTRL, &qctrl)) {
/* ... */