2.15 V4L2 controls

V4L2 controls 用于控制和调整视频设备的各种参数。

2.15.2 Objects in the framework

struct v4l2_ctrl 描述了 control properties 和对应的 value.

struct v4l2_ctrl_handler 用来跟踪 v4l2_ctrl objects.

2.15.3 Basic usage for V4L2 and sub-device drivers

prepare the driver

通常把 v4l2_ctrl_handler 放在 top-level struct:

// v4l2 drvier:
struct foo_dev {
        ...
        struct v4l2_device v4l2_dev;
        ...
        struct v4l2_ctrl_handler ctrl_handler;
        ...
};

// sub-dev driver:
struct foo_dev {
        ...
        struct v4l2_subdev sd;
        ...
        struct v4l2_ctrl_handler ctrl_handler;
        ...
};

通过 v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls) 初始化 v4l2_ctrl_handler.

其中 nr_of_controls 表示这个 v4l2_ctrl_handler 控制多少个 v4l2_control.

再把 v4l2_ctrl_handler hook 到对应的结构体:

// v4l2 driver:
foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;
// sub-dev driver:
foo->sd.ctrl_handler = &foo->ctrl_handler;

清理:

v4l2_ctrl_handler_free(&foo->ctrl_handler);

add control

之后通过一系列 api 创建不同的 controls:

struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops,
			u32 id, s64 min, s64 max, u64 step, s64 def)
struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops,
			u32 id, u8 _max, u64 mask, u8 _def)
struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
			u64 mask, u8 _def, const char * const *qmenu)
struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
				const struct v4l2_ctrl_ops *ops, u32 id,
				const union v4l2_ctrl_ptr p_def)
struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops,
			u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_config *cfg, void *priv)

v4l2_ctrl_new_std(): add standard non-menu control. non-menu control 是一些数值的 control, 比如 brightness, contrast, saturation 等。

v4l2_ctrl_new_std_menu(): add standard menu control. menu control 是一些可供选择的 predefined options, 比如 input source, video format 等。

v4l2_ctrl_new_std_menu_items(): add standard menu control, 不过 menu 值是 driver 自定义的*qmenu, driver specific menu control.

v4l2_ctrl_new_std_compound(): 一些复合的 standard controls, 比如 mpeg2, h264, 这时候需要传入 v4l2_ctrl_ptr, 不同的结构体指针。

v4l2_ctrl_new_int_menu(): add standard menu control, 这里 control 的值是 integer.

v4l2_ctrl_new_custom(): add custom control. 不是 v4l2 规范的自定义 control.

这些函数通常紧跟在 v4l2_ctrl_handler_init() 初始化后。

force initial control setup

v4l2_ctrl_handler_setup(&foo->ctrl_handler) 强制对所有 v4l2_ctrl 调用 s_ctrl 来初始化。

实现 v4l2_ctrl_ops

通常只需要实现 .s_ctrl 回调。

static const struct v4l2_ctrl_ops foo_ctrl_ops = {
        .s_ctrl = foo_s_ctrl,
};

2.15.4 Inheriting Sub-device Controls

subdev driver 的 v4l2-controls 会自动的加入到 v4l2 driver.

如果 subdev 包含 v4l2 driver 已经有的 controls, 那么会被跳过。

2.15.5 Accessing Control Values

2.15.6 Menu Controls

2.15.7 Custom Controls

driver specific controls 可以通过 v4l2_ctrl_new_custom() 来创建。

需要传入一个 struct v4l2_ctrl_config:

struct v4l2_ctrl_config {
	const struct v4l2_ctrl_ops *ops;
	const struct v4l2_ctrl_type_ops *type_ops;
	u32 id;
	const char *name;
	enum v4l2_ctrl_type type;
	s64 min;
	s64 max;
	u64 step;
	s64 def;
	union v4l2_ctrl_ptr p_def;
	u32 dims[V4L2_CTRL_MAX_DIMS];
	u32 elem_size;
	u32 flags;
	u64 menu_skip_mask;
	const char * const *qmenu;
	const s64 *qmenu_int;
	unsigned int is_private:1;
};

ops: ctrl 操作回调函数。

type_ops: ctrl type ops, 目前看只有通过 v4l2_ctrl_new_custom() 创建的 controls 可以提供 type_ops。

id: control id。

name: control 名称。

type: control 类型。

min/max: control value 最大最小值。

step: control value 步进值。

def: control value 默认值。

p_def: compound control value 默认值。

dims: 每个维度的 size。

elem_size:

flags:

menu_skip_mask:

qmenu: const char* array, menu items 的名称,最后一个必须是 NULL。

qmenu_int: menu item, const s64 array, 在 type 是 V4L2_CTRL_TYPE_INTEGER_MENU 时设置。

is_private: 只能加到自己的 ctrl handler,不能加到其他 handler。

2.15.7 v4l2_ctrl functions and data structures

#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint);
void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl);
int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl);
void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
				  const char *prefix);

struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops,
			u32 id, s64 min, s64 max, u64 step, s64 def)
struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops,
			u32 id, u8 _max, u64 mask, u8 _def)
struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
			u64 mask, u8 _def, const char * const *qmenu)
struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
				const struct v4l2_ctrl_ops *ops, u32 id,
				const union v4l2_ctrl_ptr p_def)
struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_ops *ops,
			u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
			const struct v4l2_ctrl_config *cfg, void *priv)

int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
			  struct v4l2_ctrl_handler *add,
			  v4l2_ctrl_filter filter,
			  bool from_other_dev);

void v4l2_ctrl_cluster(unsigned int ncontrols, struct v4l2_ctrl **controls);
void v4l2_ctrl_auto_cluster(unsigned int ncontrols,
			    struct v4l2_ctrl **controls,
			    u8 manual_val, bool set_volatile);

struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id);
void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active);
static inline void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
static inline int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
					 s64 min, s64 max, u64 step, s64 def);
static inline int v4l2_ctrl_modify_dimensions(struct v4l2_ctrl *ctrl,
					      u32 dims[V4L2_CTRL_MAX_DIMS]);
void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify,
		      void *priv);

const char *v4l2_ctrl_get_name(u32 id);
const char * const *v4l2_ctrl_get_menu(u32 id);
const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len);
s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
static inline int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
static inline int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s);
static inline int v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
					    enum v4l2_ctrl_type type,
					    const void *p);