V4L2 CONTROLS

本文详细介绍了V4L2 CONTROLS机制的基本使用方法,包括控制变量的创建、关联和设置过程。通过实例代码展示了如何在驱动中实现V4L2控制变量,并解释了不同类型的控制变量(如声音、菜单、整数菜单等)的创建方法。文章还提供了一个实际应用示例——BTTV驱动,帮助开发者深入理解并实践V4L2 CONTROLS的使用。

欢迎转载,转载请注明出处


这是一篇关于V4L2 CONTROLS的基本使用方法介绍。

内核中相关的文件是:v4l2-ctrls.h  v4l2-ctrls.c

V4L2 CONTROLS机制主要提供了设置硬件的方法,包含两个主要的对象:

struct v4l2_ctrl

struct v4l2_ctrl_handler

struct v4l2_ctrl代表一个控制变量和它的值,例如:声音。

struct v4l2_ctrl_handler是用来管理v4l2_ctrl的。

使用v4l2 control的步骤:

1.将v4l2_ctrl_handler增加到驱动顶层结构体中:

struct foo_dev {

...

struct v4l2_ctrl_handler ctrl_handler;

...

};

struct foo_dev *foo;

2.初始化v4l2_ctrl_handler:

v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);

第二个参数nr_of_controls是你要使用的控制变量的个数。

3.关联v4l2_ctrl_handler和v4l2_device:

struct foo_dev {

...

struct v4l2_device v4l2_dev;

...

struct v4l2_ctrl_handler ctrl_handler;

...

};

foo->v4l2_dev.ctrl_handler = &foo->ctrl_handler;

然后从v4l2_ioctl_ops中移除所有的控制函数:vidioc_queryctrl, vidioc_querymenu, vidioc_g_ctrl, vidioc_s_ctrl,vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls。

对于子设备,我们这样做:

struct foo_dev {

...

struct v4l2_subdev sd;

...

struct v4l2_ctrl_handler ctrl_handler;

...

};

foo->sd.ctrl_handler = &foo->ctrl_handler;

然后对v4l2_subdev_core_ops结构增加函数支持:

.queryctrl = v4l2_subdev_queryctrl,

.querymenu = v4l2_subdev_querymenu,

.g_ctrl = v4l2_subdev_g_ctrl,

.s_ctrl = v4l2_subdev_s_ctrl,

.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,

.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,

.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,

4.在驱动退出的时候清除v4l2_ctrl_handler:

v4l2_ctrl_handler_free(&foo->ctrl_handler);

5.增加控制变量:

(1struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops,

u32 id, s32 min, s32 max, u32 step, s32 def);

这个函数用来增加非菜单式的控制变量,如声音等。min是最小值,max是最大值,step是步进长度,def是默认值。这个函数适用于在某一范围内均匀变化的控制变量。

例:v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,V4L2_CID_VOLUM, 0, 255, 1, 128);

2struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops,

u32 id, s32 max, s32 skip_mask, s32 def);

这个函数用来增加菜单式的控制变量,max是菜单最大值,skip_mask是屏蔽标志,比如它的值是0x4,就么就屏蔽菜单值为4的菜单选项,def是默认的菜单值。这个函数适用于从0开始,相邻变量值增加1的控制变量。

例:

enum{

BW_6M,

BW_7M,

BW_8M

}BW;

v4l2_ctrl_new_std_menu(&foo->ctrl_handler,&foo_ctrl_ops,V4L2_CID_BW,BW_8M

,0,BW_6M);

3struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops,

u32 id, s32 max, s32 def, const s64 *qmenu_int);

这个函数用来增加整数型菜单的控制变量,max是最大的菜单索引号,def是默认的菜单索引号,qmenu_int是菜单的数组指针。这个函数适用于变量值是不连续的无规则的整数的控制变量。

例:

static const s64 audio_sample_qmenu[] = {22100,44100,48000,96000};

v4l2_ctrl_new_int_menu(&foo->ctrl_handler,&foo_ctrl_ops,V4L2_CID_AUDIOSAMPLERATE,ARRAY_SIZE(audio_sample_qmenu)-1,1,audio_sample_qmenu);

4struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(

struct v4l2_ctrl_handler *hdl,

const struct v4l2_ctrl_ops *ops, u32 id, s32 max,

s32 skip_mask, s32 def, const char * const *qmenu);

这个函数用来增加一个驱动指定的菜单数组给控制变量,max是菜单最大索引号,skip_mask是需要跳过的菜单的索引号,def是默认菜单索引号,qmenu是菜单数组。

例:

static const char * const test_pattern[] = {

"Disabled",

"Vertical Bars",

"Solid Black",

"Solid White",

};

v4l2_ctrl_new_std_menu_items(&foo->ctrl_handler, &foo_ctrl_ops,

V4L2_CID_TEST_PATTERN, ARRAY_SIZE(test_pattern) - 1, 0,

0, test_pattern);

设置变量的值一般是在初始化了v4l2_ctrl_handler之后进行,在最后需要检查一下有没有错误 :

if (foo->ctrl_handler.error) {

int err = foo->ctrl_handler.error;

v4l2_ctrl_handler_free(&foo->ctrl_handler);

return err;

}

6.(可选,推荐使用)使用控制变量的默认值初始化所有硬件:

v4l2_ctrl_handler_setup(&foo->ctrl_handler);

这个函数会调用s_ctrl设置每个控制变量到硬件或其他地方。

7.最后,实现v4l2_ctrl_ops结构体:

static const struct v4l2_ctrl_ops foo_ctrl_ops = {

.s_ctrl = foo_s_ctrl,

};

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_BRIGHTNESS:

write_reg(0x123, ctrl->val);

break;

case V4L2_CID_CONTRAST:

write_reg(0x456, ctrl->val);

break;

}

return 0;

}

上面就是V4L2框架提供的基本的控制变量的使用方法,下面是bttv驱动的实例代码:

struct bttv {

......

/* controls */

struct v4l2_ctrl_handler   ctrl_handler;

struct v4l2_ctrl_handler   radio_ctrl_handler;

......

};

static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)

{

......

hdl = &btv->ctrl_handler;

v4l2_ctrl_handler_init(hdl, 20);

btv->c.v4l2_dev.ctrl_handler = hdl;

v4l2_ctrl_handler_init(&btv->radio_ctrl_handler, 6);

......

v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,

V4L2_CID_BRIGHTNESS, 0, 0xff00, 0x100, 32768);

v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,

V4L2_CID_CONTRAST, 0, 0xff80, 0x80, 0x6c00);

v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops,

V4L2_CID_SATURATION, 0, 0xff80, 0x80, 32768);

......

v4l2_ctrl_handler_setup(hdl);

......

}

static const struct v4l2_ctrl_ops bttv_ctrl_ops = {

.s_ctrl = bttv_s_ctrl,

};

static int bttv_s_ctrl(struct v4l2_ctrl *c)

{

struct bttv *btv = container_of(c->handler, struct bttv, ctrl_handler);

int val;

switch (c->id) {

case V4L2_CID_BRIGHTNESS:

bt848_bright(btv, c->val);

break;

case V4L2_CID_HUE:

bt848_hue(btv, c->val);

break;

......

}

在 Linux 系统下,使用 Qt 框架开发应用程序时,常常需要与硬件设备交互,例如摄像头。而 v4l2(Video for Linux Two)是 Linux 中用于访问视频设备的标准接口,它支持多种功能,包括 MJPEG、YUV 等编码格式以及多路视频流处理。v4l2 提供了内核驱动程序和用户空间 API,方便应用程序访问和控制视频设备。 如果要在 Qt 中结合 v4l2 实现摄像头数据采集并在界面上显示,首先需要了解 v4l2 的基础知识。v4l2 是 Video for Linux 的升级版本,功能更强大。在开发过程中,需要包含一些必要的头文件,如#include <fcntl.h>、#include <sys/ioctl.h>、#include <unistd.h>和#include <linux/v4l2-controls.h>等,并且要确保链接了-lQt5Gui和-lQt5Core库,因为 Qt 的图形界面和核心功能依赖这些库。 接下来,通过open()函数打开摄像头设备。在 Linux 中,摄像头设备通常以/dev/videoX的形式存在,其中 X 是设备编号。例如,可以用int fd = open("/dev/video0", O_RDWR | O_NONBLOCK);来打开编号为 0 的摄像头设备。 然后,使用ioctl()函数调用 v4l2 的控制接口来设置摄像头参数,比如分辨率、帧率等。例如,要设置分辨率为 64480 的 VGA 格式,可以这样操作: 之后,需要分配缓冲区并开始捕获视频数据。通过v4l2_requestbuffers结构体创建缓冲区,并利用VIDIOC_REQBUFS、VIDIOC_QBUF和VIDIOC_DQBUF等操作来管理缓冲区队列。 为了在 Qt 界面上显示视频流,可以创建一个QImage对象。将从摄像头读取的 YUV
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值