从零写UVC摄像头驱动(三)设置属性

5 篇文章 0 订阅
5 篇文章 1 订阅

一、先看APP确定需要实现哪些接口

xawtv.c:
    grabber_scan
        ng_vid_open
            v4l2_driver.open // v4l2_open
                get_device_capabilities(h);
                    // 调用VIDIOC_QUERYCTRL ioctl确定是否支持某个属性
                    /* controls */
                    for (i = 0; i < MAX_CTRL; i++) {
                    h->ctl[i].id = V4L2_CID_BASE+i;
                    if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) ||
                        (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED))
                        h->ctl[i].id = -1;
                    }
怎么去获得/设置属性?
看drv0-v4l2.c
可见这2个函数:
v4l2_read_attr  : VIDIOC_G_CTRL
v4l2_write_attr : VIDIOC_S_CTRL

所以: 视频驱动里要实现3个ioctl:
VIDIOC_QUERYCTRL
VIDIOC_G_CTRL
VIDIOC_S_CTRL


二. 硬件上怎么设置属性?

2.1 UVC规范里定义了哪些属性 :

uvc_ctrl.c里数组: static struct uvc_control_info uvc_ctrls[]

    {
        .entity        = UVC_GUID_UVC_PROCESSING, // 属于哪个entity(比如PU)
        .selector    = PU_BRIGHTNESS_CONTROL,   // 用于亮度
        .index        = 0,                       // 对应Processing Unit Descriptor的bmControls[0]
        .size        = 2,                       // 数据长度为2字节
        .flags        = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
                | UVC_CONTROL_RESTORE,
    },


 
2.2 我们的设备支持哪些属性

这需要去看描述符, 比如 Processing Unit Descriptor的bmControls的值为7f 14
    可知BIT0为1,表示支持BRIGHTNESS
    
    在代码里:
uvc_drvier.c
uvc_ctrl_init_device    
    // 对于每一个entity(IT,PU,SU,OT等)
    list_for_each_entry(entity, &dev->entities, list) {
        // 取出bmControls
        bmControls = ....
        
        // 计算bmControls里位值为1的个数,就是支持的属性个数
        ncontrols += hweight8(bmControls[i]);    
        
        // 为每一个属性分配一个struct uvc_control
        entity->controls = kzalloc..
        
        // 设置这些struct uvc_control
        ctrl = entity->controls;
        for (...)
        {
            ctrl->entity = entity;
            ctrl->index = i;
        }

        // 把uvc_control和uvc_control_info挂构
        uvc_ctrl_add_ctrl(dev, info);
            ctrl->info = 某个uvc_control_info数组项(同属于一个entity, index相同)

2.3 怎么去操作这些属性

 参考 uvc_query_v4l2_ctrl
    uvc_find_control
        找到一个uvc_control_mapping结构体: uvc_ctrl.c里有static struct uvc_control_mapping uvc_ctrl_mappings[] 
            {
                .id        = V4L2_CID_BRIGHTNESS,  // APP根据ID来找到对应的属性
                .name        = "Brightness",
                .entity        = UVC_GUID_UVC_PROCESSING,  // 属于哪了个entity(比如PU)
                .selector    = PU_BRIGHTNESS_CONTROL,    // 用于亮度
                .size        = 16,                       // 数据占多少位
                .offset        = 0,                        // 从哪位开始
                .v4l2_type    = V4L2_CTRL_TYPE_INTEGER,   // 属性类别
                .data_type    = UVC_CTRL_DATA_TYPE_SIGNED,// 数据类型
            },

         uvc_control_mapping结构体 用来更加细致地描述属性

    uvc_query_ctrl
        usb_control_msg


举例说明: 要设置亮度,怎么操作?
a. 根据PU的描述符的bmControls, 从它的bit0等于1知道它支持调节亮度
b. 在uvc_ctrls数组中根据entity和index找到这一项:
    {
        .entity        = UVC_GUID_UVC_PROCESSING,
        .selector    = PU_BRIGHTNESS_CONTROL,
        .index        = 0,
        .size        = 2,
        .flags        = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
                | UVC_CONTROL_RESTORE,
    },

知道了:这个设备支持SET_CUR, GET_CUR, GET_MIN等
要设置时,可以向PU的selector发数据, 发的数据是2字节

c. 在uvc_ctrl_mappings数组中根据ID找到对应的数组项
   从而知道了更加细致的信息,
   然后使用usb_control_msg读写数据
   

三、 怎么写代码?

实现3个ioctl: vidioc_queryctrl/vidioc_g_ctrl/vidioc_s_ctrl
vidioc_queryctrl : 发起USB控制传输获得亮度的最小值、最大值、默认值、步进值
vidioc_s_ctrl    : 把APP传入的亮度值通过USB传输发给硬件
vidioc_g_ctrl    : 发起USB传输获得当前亮度值

要点:数据发给谁?发给usb_device的
                          VideoControl Interface
                                    里面的Processing Unit 
                                            里面的PU_BRIGHTNESS_CONTROL

详细过程看这篇:Linux摄像头驱动2——UVC(转)_uvc协议分主从关系吗-CSDN博客

补充:

  • VideoControl Interface用于控制,比如设置亮度。

       它内部有多个Unit/Terminal(在程序里Unit/Terminal都称为entity)
       可以通过uvc_query_ctrl类似的函数来访问:

ret = uvc_query_ctrl(dev /*哪一个USB设备*/, SET_CUR, ctrl->entity->id /*哪一个unit/terminal*/, dev->intfnum /*哪一个接口:VC interface*/, ctrl->info->selector, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), ctrl->info->size);
  • VideoStreaming Interface用于获得视频数据,也可以用来选择fromat/frame(VS可能有多种format,一个format支持多种frame,frame用来表示分辨率等信息)

       可以通过__uvc_query_ctrl类似的函数来访问:

ret = __uvc_query_ctrl(video->dev /*哪一个USB设备*/, SET_CUR, 0, video->streaming->intfnum /*哪一个接口: VS*/, probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, uvc_timeout_param);

这里的参数VS_PROBE_CONTROL只是枚举尝试,并不是设置,真正要设置需要使用参数VS_COMMIT_CONTROL

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值