Video4Linux2 part 7: Controls

With the completion of part 6 of this series , we now know how to set up a video device and transfer frames back and forth. It is a well known fact, however, that users can be hard to please; not content with being able to see video from their camera device, they immediately start asking if they can play with parameters like brightness, contrast, and more. These adjustments could be done in the video application, and sometimes they are, but there are advantages to doing them in the hardware itself when the hardware has that capability. A brightness adjustment, for example, might lose dynamic range if done after the fact, but a hardware-based adjustment may retain the full range that the sensor is capable of delivering. Hardware-based adjustments, obviously, will also be easier on the host processor.

Current hardware typically has a wide range of parameters which can be adjusted on the fly. Just how those parameters work varies widely from one device to the next, though. An adjustment as simple as "brightness" could involve a straightforward register setting, or it could require a rather more complex change to an obscure transformation matrix. It would be nice to hide as much of this detail from the application as possible, but there are limits to how much hiding can be done. An overly abstract interface might make it impossible to use the hardware's controls to their fullest potential.

The V4L2 control interface tries to simplify things as much as possible while allowing full use of the hardware. It starts by defining a set of standard control names; these include V4L2_CID_BRIGHTNESS , V4L2_CID_CONTRAST , V4L2_CID_SATURATION , and many more. There are boolean controls for features like white balance, horizontal and vertical mirroring, etc. See the V4L2 API spec for a full list of predefined control ID values. There is also a provision for driver-specific controls, but those, clearly, will generally only be usable by special-purpose applications. Private controls start at V4L2_CID_PRIVATE_BASE and go up from there.

In typical fashion, the V4L2 API provides a mechanism by which an application can enumerate the available controls. To that end, they will make ioctl() calls which end up in a V4L2 driver via the vidioc_queryctrl() callback:

 

    int (*vidioc_queryctrl)(struct file *file, void *private_data,
struct v4l2_queryctrl *qc);

The driver will normally fill in the structure qc with information about the control of interest, or return EINVAL if that control is not supported. This structure has a number of fields:

 

    struct v4l2_queryctrl
{
__u32 id;
enum v4l2_ctrl_type type;
__u8 name[32];
__s32 minimum;
__s32 maximum;
__s32 step;
__s32 default_value;
__u32 flags;
__u32 reserved[2];
};

The control being queried will be passed in via id . As a special case, the application can supply a control ID with the V4L2_CTRL_FLAG_NEXT_CTRL bit set; when this happens, the driver should return information about the next supported control ID higher than the one given by the application. In any case, id should be set to the ID of the control actually being described.

All of the other fields are set by the driver to describe the selected control. The data type of the control is given in type ; it can be V4L2_CTRL_TYPE_INTEGER , V4L2_CTRL_TYPE_BOOLEAN , V4L2_CTRL_TYPE_MENU (for a set of fixed choices), or V4L2_CTRL_TYPE_BUTTON (for a control which performs some action when set and which ignores any given value). name describes the control; it could be used in the interface presented to the user by the application. For integer controls (only), minimum and maximum describe the range of values implemented by the control, and step gives the granularity of that range. default_value is exactly what it sounds like - though it is only applicable to integer, boolean, and menu controls. Drivers should set control values to their default at initialization time only; like other device parameters, they should persist across open() and close() calls. As a result, default_value may well not be the current value of the control.

Inevitably, there is a set of flags which further describe a control. V4L2_CTRL_FLAG_DISABLED means that the control is disabled; the application should ignore it. V4L2_CTRL_FLAG_GRABBED means that the control, temporarily, cannot be changed, perhaps because another application has taken it over. V4L2_CTRL_FLAG_READ_ONLY marks controls which can be queried, but which cannot be changed. V4L2_CTRL_FLAG_UPDATE means that adjusting this control may affect the values of other controls. V4L2_CTRL_FLAG_INACTIVE marks a control which is not relevant to the current device configuration. And V4L2_CTRL_FLAG_SLIDER is a hint that applications should represent the control with a slider-like interface.

Applications might just query a few controls which have been specifically programmed in, or they may want to enumerate the entire set. In the latter case, they will start at V4L2_CID_BASE and step through V4L2_CID_LASTP1 , perhaps using the V4L2_CTRL_FLAG_NEXT_CTRL flag in the process. For controls of the menu variety (type V4L2_CTRL_TYPE_MENU ), applications will probably want to enumerate the possible values as well. The relevant callback is:

 

    int (*vidioc_querymenu)(struct file *file, void *private_data,
struct v4l2_querymenu *qm);

The v4l2_querymenu structure looks like:

 

    struct v4l2_querymenu
{
__u32 id;
__u32 index;
__u8 name[32];
__u32 reserved;
};

On input, id is the ID value for the menu control of interest, and index is the index value for a specific menu value. Index values start at zero and go up to the maximum value returned from vidioc_queryctrl() . The driver will fill in the name of the menu item; the reserved field should be set to zero.

Once the application knows about the available controls, it will likely set about querying and changing their values. The structure used in this case is relatively simple:

 

    struct v4l2_control
{
__u32 id;
__s32 value;
};

To query a specific control, an application will set id to the ID of the control and make a call which ends up in the driver as:

 

    int (*vidioc_g_ctrl)(struct file *file, void *private_data,
struct v4l2_control *ctrl);

The driver should set value to the current setting of the control. Of course, it should also be sure that it knows about this specific control and return EINVAL if the application attempts to query a nonexistent control. Attempts to query button controls should also return EINVAL .

A request to change a control ends up in:

 

    int (*vidioc_s_ctrl)(struct file *file, void *private_data,
struct v4l2_control *ctrl);

The driver should verify the id and make sure that value falls within the allowed range. If all is well, the new value should be set in the hardware.

Finally, it is worth noting that there is a separate extended controls interface supported with V4L2. This API is meant for relatively complex controls; in practice, its main use is for MPEG encoding and decoding parameters. Extended controls can be grouped into classes, and 64-bit integer values are supported. The interface is similar to the regular control interface; see the API specification for details.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值