controls for advanced topics and scenarios
2018-03-19 15:02
429 查看
Controls继承
当sub-device通过调用v4l2_device_register_subdev()注册时,v4l2_device 和v4l2_subdev的ctrl_handler字段都会设置,然后V4L2驱动程序中subdev的controls 也会有效。如果subdev驱动包含在V4L2驱动已存在的控制,那这些会跳过(所以V4L2驱动也可以重写一个subdev控制)。
v4l2_device_register_subdev()调用v4l2_ctrl_add_handler()添加subdev的controls到v4l2_device。
访问Control 值
v4l2_ctrl结构包含这两个联合体:/* The current control value. */ union { s32 val; s64 val64; char *string; } cur; /* The new control value. */ union { s32 val; s64 val64; char *string; };
你可以自由使用这些control ops。字符串指针指向长度为ctrl->maximum + 1的字符缓冲区,总是’\0’为结束符。
在大多数情况下,’cur’包含当前缓存的控制值。当你创建一个新control 该值与default 值相同。在调用v4l2_ctrl_handler_setup()后这个值提交到硬件。这是一般调用这个函数的方法。
每当设置新值时,新值将自动缓存。这意味着,大多数驱动不需要实现的g_volatile_ctrl()。
controls的异常是返回一个volatile register,例如连续变化的信号强度读数。在这种情况下,你将需要实现这样的g_volatile_ctrl:
static int foo_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: ctrl->val = read_reg(0x123); break; } }
注意在g_volatile_ctrl使用’new value’联合体,一般来说这需要实现g_volatile_ctrl controls是只读controls。
标志control为volatile,你要设置V4L2_CTRL_FLAG_VOLATILE:
ctrl = v4l2_ctrl_new_std(&sd->ctrl_handler, ...); if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
对于 try/s_ctrl被填充的新值(即是由用户通过),你可以修改它们通过try_ctrl或在s_ctrl设置。’cur’ 联合体包含可以使用(但不更改)的当前值。
如果s_ctrl返回0(OK),然后control framework将复制新的最终值的’cur’联合体。
而在g_volatile / S / try_ctrl可以访问相同handler 的所有控件,一旦handler的锁生效 。如果您需要访问其他handlers拥有的controls 的值,那么您必须非常小心以免引入死锁。
在control ops外,您必须通过帮助函数在驱动程序中安全地获取或设置一个单独的control 值:
s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl); int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
这些功能通过就像VIDIOC_G/S_CTRL ioctls一样的control framework执行。不要使用这些内部control ops g_volatile/s/try_ctrl,因为helpers锁住handler将导致死锁。
还可以自己处理handler :
mutex_lock(&state->ctrl_handler.lock); printk(KERN_INFO "String value is '%s'\n", ctrl1->cur.string); printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val); mutex_unlock(&state->ctrl_handler.lock);
菜单Controls
v4l2_ctrl结构体包含这个联合体:union { u32 step; u32 menu_skip_mask; };
菜单Controls经常使用menu_skip_mask。它允许你轻松排除某些菜单项。这是用在
VIDIOC_QUERYMENU 实现,可以返回-EINVAL如果某菜单项是不存在的。注意,对于菜单controls VIDIOC_QUERYCTRL 总是返回一个1。
一个很好的例子是在MPEG音频第二层码率菜单control, 菜单是一个标准化的可能的比特率。但实际上是硬件实现只支持其中的一个子集。通过设置跳过掩码,您可以告诉框架应该跳过哪些菜单项。将其设置为0意味着支持所有菜单项。
也可以通过custom control的v4l2_ctrl_config结构体掩盖,或者调用v4l2_ctrl_new_std_menu()。
Custom Controls
驱动程序特定的controls 可以使用v4l2_ctrl_new_custom()创建:static const struct v4l2_ctrl_config ctrl_filter = { .ops = &ctrl_custom_ops, .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, .name = "Spatial Filter", .type = V4L2_CTRL_TYPE_INTEGER, .flags = V4L2_CTRL_FLAG_SLIDER, .max = 15, .step = 1, }; ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_filter, NULL);
最后一个参数是一个可以设置为驱动程序特定的私有数据的指针。
v4l2_ctrl_config结构体也有一个字段用来设置is_private标志。
如果未设置名称字段,则框架将假定这是一个标准控件,并将相应地填入名称、类型和标志字段。
主动抓取Controls
如果Controls之间的关系更复杂,则可能需要激活和停用Controls。例如,如果色度AGC控制开启,则色度增益控制处于非活动状态。也就是说,您可以设置它,但只要自动增益控制在,硬件就不会使用该值。通常,用户界面可以禁用此类输入字段。你可以使用v4l2_ctrl_activate()设置“主动”状态。默认情况下,所有Controls都是活动的。注意,框架不检查此标志。它是纯粹的图形用户界面。该功能通常称为内s_ctrl。
另一面标志是’grabbed’标志。一个被抓住的Controls意味着你不能更改它,因为某些资源正在使用它。典型的例子是MPEG在捕获过程中不能更改比特率控制。
如果Controls使用v4l2_ctrl_grab()设置为 ‘grabbed’ ,如果尝试设置该控制那么框架将返回
-EBUSY。当开始或停止streaming,v4l2_ctrl_grab()函数通常被驱动调用。
Control集群
默认情况下,所有controls 都与其他controls 无关。但在更复杂的场景中,一个controls 依赖另一个controls 。在这种情况下,您需要“集群”它们:
struct foo { struct v4l2_ctrl_handler ctrl_handler; #define AUDIO_CL_VOLUME (0) #define AUDIO_CL_MUTE (1) struct v4l2_ctrl *audio_cluster[2]; ... }; state->audio_cluster[AUDIO_CL_VOLUME] = v4l2_ctrl_new_std(&state->ctrl_handler, ...); state->audio_cluster[AUDIO_CL_MUTE] = v4l2_ctrl_new_std(&state->ctrl_handler, ...); v4l2_ctrl_cluster(ARRAY_SIZE(state->audio_cluster), state->audio_cluster);
从现在开始,当一个或多个属于同一个群集的controls 被设置 (or ‘gotten’, or ‘tried’),只有第一个control ops(’volume’在这个例子中)被调用。这样有效地创建一个新的复合control。类似于
‘struct’在C的工作方式
所以当s_ctrl使用v4l2_cid_audio_volume作为参数,你应该设置两个属于audio_cluster的controls :
static int foo_s_ctrl(struct v4l2_ctrl *ctrl) { struct foo *state = container_of(ctrl->handler, struct foo, ctrl_handler); switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: { struct v4l2_ctrl *mute = ctrl->cluster[AUDIO_CL_MUTE]; write_reg(0x123, mute->val ? 0 : ctrl->val); break; } case V4L2_CID_CONTRAST: write_reg(0x456, ctrl->val); break; } return 0; }
在上面的例子等价于下面的内容:
ctrl == ctrl->cluster[AUDIO_CL_VOLUME] == state->audio_cluster[AUDIO_CL_VOLUME] ctrl->cluster[AUDIO_CL_MUTE] == state->audio_cluster[AUDIO_CL_MUTE]
实际上,使用这样的集群数组变得非常烦人。因此,使用下面的等效方法:
struct { /* audio cluster */ struct v4l2_ctrl *volume; struct v4l2_ctrl *mute; };
匿名结构体用于清楚地’cluster’这两个control 指针,但它没有其他用途。效果与创建带有两个控制指针的数组相同。所以你可以做:
state->volume = v4l2_ctrl_new_std(&state->ctrl_handler, ...); state->mute = v4l2_ctrl_new_std(&state->ctrl_handler, ...); v4l2_ctrl_cluster(2, &state->volume);
在foo_s_ctrl可以直接使用这些指针:state->mute->val。
注意,集群中的controls 可能为null。例如,如果由于某种原因没有添加静音(因为硬件不支持该特定功能),那么静音将为null。因此,在这种情况下,我们有2个controls 的集群,其中只有1个是实际实例化的。唯一的限制是必须始终存在集群的第一个controls ,因为这是集群的“主”controls 。主controls 识别集群,对v4l2_ctrl_ops结构体用于集群提供了指针。
显然,集群数组中的所有control必须初始化为有效control或null。
在少数情况下,您可能想知道用户实际上明确地确定了集群的哪些controls 。这个你可以检查每个control的’is_new’标志。例如,在一个音量/静音集群的情况下,如果用户调用VIDIOC_S_CTRL 静音,静音control ‘is_new’标志 将设置。如果用户为静音和音量controls调用VIDIOC_S_EXT_CTRLS ,那么两者’is_new’ 标志都为1。
当调用v4l2_ctrl_handler_setup()时,’is_new’标志始终是1。
处理自动增益/增益自动集群式Controls
一种常见的control 集群类型是处理“自动”类型的control 集群控制。典型的例子是自动增益、增益、自动曝光、曝光,自动白色 /红色/蓝色平衡平衡。在所有情况下,都有一个control 。它决定了另一个control 是由硬件自动处理的,还是由用户手动控制的。如果群集处于自动模式,则手动control 应标记为inactive和volatile。当volatile controls读取g_volatile_ctrl操作应该返回到硬件的自动模式自动设置的值。
如果集群处于手动模式,则手动control 应该成为active ,volatile 标志被清除(所g_volatile_ctrl不再称为在手动模式)。另外,在切换到手动模式之前,自动模式所确定的当前值被复制为新的手动值。
最后,V4L2_CTRL_FLAG_UPDATE 应设置为自动控制由于改变控制影响手动控制的控制标志。
为了简化,引进了一种v4l2_ctrl_cluster的变体:
void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,u8 manual_val, bool set_volatile);
前两个参数跟v4l2_ctrl_cluster相同。第三个参数告诉framework 将集群切换为手动模式的值。最后一个参数可以为非自动控制设置V4L2_CTRL_FLAG_VOLATILE 。如果它是错的,那么手动控制永远不会生效。如果硬件不给你通过自动方式的(如自动增益是,硬件不允许你获得的电流增益值)写回值选项,你通常就会使用这个选项。
集群的第一个control 被认为是“自动”control。
使用这个函数可以确保不需要处理所有复杂的标志和volatile 处理。
vidioc_log_status支持
这允许你dump ioctl驱动程序当前状态的内核日志。v4l2_ctrl_handler_log_status(ctrl_handler, prefix) 可以用来dump
给定处理程序对controls 的值到日志。你可以提供一个
前缀。如果前缀没有以空格结尾,则会为你添加“:”。
不同的视频节点的不同处理程序
通常,V4L2驱动只有一个对所有视频节点的全局control handler。但也可以为不同的视频节点指定不同的控件处理程序。你可以通过手动设置video_device ctrl_handler场的结构。如果没有subdevs是没有问题的。但如果有,那么你需要块自动合并subdev controls到control handler。只需要简单的设置v4l2_device结构体中ctrl_handler字段为NULL。现在v4l2_device_register_subdev()不再合并subdev controls。
每一次添加subdev后,你将不得不调用v4l2_ctrl_add_handler手动添加subdev control handler(SD—> ctrl_handler)所需的control handler。control handler可以具体到video_device或video_device的子集。例如:无线电设备节点只有音频的controls,而视频和VBI设备节点共享相同的对音频和视频controls的control handler。
如果一个handler(例如对于无线电设备节点)有另一个handler(例如对于视频设备节点)的子集,那么您应该首先添加controls到第一个handler,将第二个handler的其他controls,最后将第一个handler添加到第二个中。例如:
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_VOLUME, ...); v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...); v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...); v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...); v4l2_ctrl_add_handler(&video_ctrl_handler, &radio_ctrl_handler);
或者您可以向handler添加特定的controls :
volume = v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_AUDIO_VOLUME, ...); v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_BRIGHTNESS, ...); v4l2_ctrl_new_std(&video_ctrl_handler, &ops, V4L2_CID_CONTRAST, ...); v4l2_ctrl_add_ctrl(&radio_ctrl_handler, volume);
您不应该为两个handlers生成两个相同的controls 。
例如:
v4l2_ctrl_new_std(&radio_ctrl_handler, &radio_ops, V4L2_CID_AUDIO_MUTE, ...); v4l2_ctrl_new_std(&video_ctrl_handler, &video_ops, V4L2_CID_AUDIO_MUTE, ...);
一旦静音收音机不会改变视频静音control,就要有一个control 每个硬件可以旋转的旋钮。
查找Controls
通常,自己创建控件后,并且可以存储v4l2_ctrl结构体指针到你自己的结构。但有时需要从不属于自己的另一个handler 中找到一个control 。例如,如果你要从一个subdev找到音量control 。
你可以通过调用v4l2_ctrl_find来查找:
struct v4l2_ctrl *volume; volume = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_AUDIO_VOLUME); Since v4l2_ctrl_find will lock the handler you have to be careful where you use it. For example, this is not a good idea: struct v4l2_ctrl_handler ctrl_handler; v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_BRIGHTNESS, ...); v4l2_ctrl_new_std(&ctrl_handler, &video_ops, V4L2_CID_CONTRAST, ...);
在video_ops.s_ctrl:
case V4L2_CID_BRIGHTNESS: contrast = v4l2_find_ctrl(&ctrl_handler, V4L2_CID_CONTRAST); ...
当s_ctrl被framework调用,ctrl_handler.lock已经被设置,因此试图从相同的handler 序,找到另一个control 将死锁。
建议不要在control ops内使用此功能。
继承的Controls
当一个control handler添加到另一个使用v4l2_ctrl_add_handler时,然后从所有control默认都合并到另一个。但subdev可能有低层次的controls ,特别但当它被用在消费级硬件,例如一些先进的嵌入式系统。在这种情况下保持subdev中的那些低级controls ,你可以通过设置’is_private’标志为1:static const struct v4l2_ctrl_config ctrl_private = { .ops = &ctrl_custom_ops, .id = V4L2_CID_..., .name = "Some Private Control", .type = V4L2_CTRL_TYPE_INTEGER, .max = 15, .step = 1, .is_private = 1, }; ctrl = v4l2_ctrl_new_custom(&foo->ctrl_handler, &ctrl_private, NULL);
v4l2_ctrl_add_handler被调用时,这些controls 将被跳过。
V4L2_CTRL_TYPE_CTRL_CLASS Controls
这种类型的Controls 可以使用图形用户界面来获得control class的名称。功能齐全的GUI有一个对话框,每个选项卡包含属于特定control class的多个control 。
每个选项卡的名称可以通过查询一个带有ID < control class | 1 >的特殊control 找到。
驱动不必关心这件事。每当添加属于新control class的第一个控件时,framework 将自动添加一个control 。
扩展建议
对将来规范的扩展的一些想法:1)增加V4L2_CTRL_FLAG_HEX 使用十六进制而不是十进制值显示。例如有用video_mute_yuv。
2)增加control ID的以为,使得在controls 数组中可以标记成功写入和失败的controls 。
尽管如此,我不确定这是否值得。
相关文章推荐
- [Programming Visual C++]Chapter Six-Setting the Color for the Dialog Background and for Controls
- Security Tutorials系列文章第三章:Forms Authentication Configuration and Advanced Topics
- Security Tutorials系列文章第三章:Forms Authentication Configuration and Advanced Topics
- Advanced Graphics and Animations for iOS Apps
- WTL for MFC Programmers,Part IV - Dialogs and Controls
- Another List for Advanced Topics in Computer Vision in 2010
- WTL for MFC Programmers,Part IV - Dialogs and Controls
- Debian Networking for Basic and Advanced Users
- Reading Lists for Advanced Computer Vision in 2009 and 2010
- 033-Unit 10 Advanced Topics in Users ,Groups and Permissions
- WTL for MFC Programmers,Part IV - Dialogs and Controls
- How To Defeat Advanced Malware. New Tools for Protection and Forensics
- 2MULTI-DIMENSIONAL SIGNAL PROCESSING AND CIRCUITS FOR ADVANCED ELECTRONICALLY SCANNED ANTENNA ARRAYS
- Quantitative Risk Analysis Scenarios, Modeling, and Simulations for the PMP Certification Exam
- Reading Lists for Advanced Computer Vision in 2009 and 2010
- IT Compliance and Controls: Best Practices for Implementation
- Topics for Troubleshooting and Tuning
- ActiveX控件如何标记控件为安全(Safe Initialization and Scripting for ActiveX Controls)
- Advanced Graphics and Animations for iOS Apps(session 419)
- WTL for MFC Programmers,Part IV - Dialogs and Controls