(七) UVC框架分析



title: UVC框架分析
date: 2019/4/23 19:50:00
toc: true
---

UVC框架分析

源码的位置在drivers\media\video\uvc,查看下Makefile,我们可以从入口uvc_driver.c中分析

uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o                   uvc_status.o uvc_isight.o uvc_debugfs.o
ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
uvcvideo-objs  += uvc_entity.o
endif
obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o

入口函数

module_init(uvc_init);
    >usb_register(&uvc_driver.driver)

struct uvc_driver uvc_driver = {
    .driver = {
        .name       = "uvcvideo",
        .probe      = uvc_probe,
        .disconnect = uvc_disconnect,
        .suspend    = uvc_suspend,
        .resume     = uvc_resume,
        .reset_resume   = uvc_reset_resume,
        .id_table   = uvc_ids,
        .supports_autosuspend = 1,
    },
};

这里的id_table表示能够支持哪些设备,probe表示匹配到之后执行probe函数

uvc_probe

uvc_register_chains
    uvc_register_terms
        uvc_register_video
            uvc_video_init
            // 这里就是以前vivi中讲的 设置
            video_device_alloc
            vdev->v4l2_dev = &dev->vdev;
            vdev->fops = &uvc_fops;
            vdev->release = uvc_release;
            strlcpy(vdev->name, dev->name, sizeof vdev->name);
            //注册
            video_register_device(vdev, VFL_TYPE_GRABBER, -1);

文件ops

const struct v4l2_file_operations uvc_fops = {
    .owner      = THIS_MODULE,
    .open       = uvc_v4l2_open,
    .release    = uvc_v4l2_release,
    .unlocked_ioctl = uvc_v4l2_ioctl,
    .read       = uvc_v4l2_read,
    .mmap       = uvc_v4l2_mmap,
    .poll       = uvc_v4l2_poll,

};

UVC规格书一览

搜索下uvc Specification,链接在此,主要是USB_Video_Example 1.5.pdfUVC 1.5 Class specification.pdf

先来看下USB_Video_Example中的图

再来看下规格书的基本描述,参考链接,这个unit实际上就是一个个内部的功能模块,terminal是用于连接内外的功能模块.

Unit

Unit提供了基础模块来全面描述大部分的视频功能,一个Unit可以由一个或多个输入引脚和仅一个输出引脚(这里的每一个pin代表一个逻辑上的数据流) ,Unit可以通过pin引脚连接在一起,一个输出pin可以连接多个输入pin,但一个输入pin只能连接一个输出pin

Select Unit

这个就是多路选择unit

Processing Unit

处理Unit (PU)控制流经它的视频流图像属性。
User Controls

  • Brightness
  • Hue
  • Saturation
  • Sharpness
  • Gamma
  • Digital Multiplier (Zoom)

Auto Controls

  • White Balance Temperature
  • White Balance Component
  • Backlight Compensation
  • Contrast
  • Other

Gain

  • Power Line Frequency
  • Analog Video Standard
  • Analog Video Lock Status

Terminal

链接内外的功能模块,一个输入和一个输出

  • Input Terminal
  • Out Terminal
  • Camera Terminal 控制端点.有些设备可能没有
    • Scanning Mode扫描模式
    • Auto-Exposure Mode自动曝光模式
    • Auto-Exposure Priority自动曝光优先级
    • Exposure Time 曝光时间
    • Focus聚焦
    • Auto-Focus自动聚焦
    • Simple Focus简单聚焦
    • Iris红外
    • Zoom放大
    • Pan摇动
    • Roll滚动
    • Tilt倾斜
    • Digital Windowing数字窗口

总的来说就是一个摄像头,一定会有起码1个的VS视频流接口,但不一定有vs控制接口.通过VideoControl Interface来控制,通过VideoStreaming Interface来读视频数据,VC里含有多个Unit/Terminal等功能模块,可以通过访问这些模块进行控制,比如调亮度

APP使用UVC驱动过程

uvc_register_chains
    uvc_register_terms
        uvc_register_video
            uvc_video_init
            // 这里就是以前vivi中讲的 设置
            video_device_alloc
            vdev->v4l2_dev = &dev->vdev;
            vdev->fops = &uvc_fops;
            vdev->release = uvc_release;
            strlcpy(vdev->name, dev->name, sizeof vdev->name);
            //注册
            video_register_device(vdev, VFL_TYPE_GRABBER, -1);

APP调用过程
    open
        uvc_v4l2_open
    unlocked_ioctl
        uvc_v4l2_ioctl
            uvc_v4l2_do_ioctl
                case VIDIOC_QUERYCAP:
                    .....

VIDIOC_QUERYCAP
    //通过 stream->type 来设置,这个type 应该是在设备枚举时设置
        if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
            cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
                      | V4L2_CAP_STREAMING;
        else
            cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
                      | V4L2_CAP_STREAMING;

VIDIOC_ENUM_FMT
    //通过 stream->format
    format = &stream->format[fmt->index];
VIDIOC_G_FMT
    // USB摄像头支持多种格式fromat, 每种格式下有多种frame(比如分辨率)
    uvc_v4l2_get_format(stream, arg)
        format = stream->cur_format;
        frame = stream->cur_frame;
        fmt->fmt.pix.pixelformat = format->fcc;
        fmt->fmt.pix.width = frame->wWidth;
        fmt->fmt.pix.height = frame->wHeight;
VIDIOC_TRY_FMT
    uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL)
        /* Check if the hardware supports the requested format. */
        // 根据 stream中的format 来比较
        format = &stream->format[i]
        if(format->fcc == fmt->fmt.pix.pixelformat)
        /* Find the closest image size */
        //找到最接近的图像大小
VIDIOC_S_FMT
    uvc_v4l2_set_format(stream, arg)
        // 只是尝试把参数保存,并没有发起usb传输
        uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame)

VIDIOC_REQBUFS
    uvc_alloc_buffers(&stream->queue, arg);
        vb2_reqbufs(&queue->queue, rb);

VIDIOC_QUERYBUF
    //查询buf
    uvc_query_buffer
        vb2_querybuf
            __fill_v4l2_buffer
mmap
    uvc_v4l2_mmap
        uvc_queue_mmap
            vb2_mmap

VIDIOC_QBUF
    uvc_queue_buffer
        vb2_qbuf

VIDIOC_STREAMON
    uvc_video_enable // 把所设置的参数发给硬件,然后启动摄像头
        uvc_queue_enable
            vb2_streamon
                q->streaming = 1;
        /* Commit the streaming parameters. */
        ret = uvc_commit_video(stream, &stream->ctrl);
            uvc_set_video_ctrl /* 设置格式fromat, frame */
                __uvc_query_ctrl
                    usb_control_msg //usb传输
        //启动urb传输
        uvc_init_video
            uvc_video_stats_start(stream);

            uvc_init_video_isoc
                    // 分配 设置 urb
                    uvc_alloc_urb_buffers
                    usb_fill_bulk_urb
                    urb->complete = uvc_video_complete;  // usb传输完成的函数,这里应该会去唤醒uvc驱动
            /* Submit the URBs. */
            usb_submit_urb
urb传输完成函数.这里会有wakeup
uvc_video_complete
    stream->decode(urb, stream, buf);  //此函数搜索下
        stream->decode = uvc_video_decode_isight;
        stream->decode = uvc_video_decode_isoc;
            uvc_queue_next_buffer
                vb2_buffer_done
                    wake_up(&q->done_wq);

poll
    uvc_v4l2_poll
        uvc_queue_poll
            vb2_poll
                poll_wait(file, &q->done_wq, wait);
                        //这里会接着判断状态
                        if (vb && (vb->state == VB2_BUF_STATE_DONE
                        || vb->state == VB2_BUF_STATE_ERROR)) {
                        return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM :
                            POLLIN | POLLRDNORM;

VIDIOC_DQBUF
        uvc_dequeue_buffer
            vb2_dqbuf
                list_del(&vb->queued_entry);

VIDIOC_STREAMOFF
        uvc_video_enable(video, 0);
            uvc_uninit_video
                usb_kill_urb(urb);
                usb_free_urb(urb);

分析设置亮度过程:
ioctl: VIDIOC_S_CTRL
            uvc_ctrl_set
            uvc_ctrl_commit
                __uvc_ctrl_commit(video, 0);
                    uvc_ctrl_commit_entity(video->dev, entity, rollback);
                            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);

小结

1. UVC设备有2个interface: VideoControl Interface, VideoStreaming Interface
2. VideoControl Interface用于控制,比如设置亮度。它内部有多个Unit/Terminal(在程序里Unit/Terminal都称为entity)
   可以通过类似的函数来访问:
                            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);
3. VideoStreaming Interface用于获得视频数据,也可以用来选择fromat/frame(VS可能有多种format, 一个format支持多种frame, frame用来表示分辨率等信 息)
   可以通过类似的函数来访问:
                        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);
4. 我们在设置FORMAT时只是简单的使用video->streaming->format[fmt->index]等数据,
   这些数据哪来的?
   应是设备被枚举时设置的,也就是分析它的描述符时设置的。

5. UVC驱动的重点在于:
   描述符的分析
   属性的控制: 通过VideoControl Interface来设置
   格式的选择:通过VideoStreaming Interface来设置
   数据的获得:通过VideoStreaming Interface的URB来获得

原文地址:https://www.cnblogs.com/zongzi10010/p/10764246.html

时间: 2024-08-12 21:58:37

(七) UVC框架分析的相关文章

Google Test测试框架分析

Google Test测试框架分析 一.简介 Google Test是由Google主导的一个开源的C++自动化测试框架,简称GTest.GTest基于xUnit单元测试体系,和CppUint类似,可以看作是JUnit.PyUnit等对C++的移植. 下图是GTest测试框架的测试过程,表示的是GTest的两种测试方式. 下面将使用一个极其简单的例子表示xUnit测试的主要过程.如对Hummer的CTXString类的成员方法GetLength进行测试.详见下面GTest代码和注释说明. //

Android Bitmap 开源图片框架分析(精华三)

主要介绍这三个框架,都挺有名的,其他的框架估计也差不多了 Android-Universal-Image-Loaderhttps://github.com/nostra13/Android-Universal-Image-Loader ImageLoaderhttps://github.com/novoda/ImageLoader Volley(综合框架,包含图片部分)https://github.com/mcxiaoke/android-volley 扯淡时间,可以跳过这段这些开源框架的源码还

Android系统中基于Binder的IPC流程框架分析

前言: Activity.Service.BroadcastReceiver.Content Provider是Android的四大应用程序组件,构成一个完整的应用程序的这些组件可以在同一个进程,也可以不在同一个进程,而当这些组件不在同一个进程,需要进行数据交互时就需要一种IPC(Inter-Process Communication)进程间通信机制来完成,而Binder就是提供了IPC功能的一个框架.实现IPC的整个Binder框架包含几个重要组成部分,它们分别是Binder Driver.C

二十四、V4L2框架分析和虚拟摄像头驱动编写

一.V4L2框架分析 V4L2(video for linux version 2),是内核中视频设备的驱动框架,为上层访问视频设备提供统一接口. V4L2整体框架如下图: 图中主要包括四个部分: 1. 字符设备驱动程序核心:V4L2本身就是一个字符设备,上层连接用户空间 2. V4L2驱动核心:构造通用的视频设备驱动框架,为上层操作提供统一接口 3. 平台V4L2驱动:在V4L2框架下,根据平台自身特性实现与平台相关的V4L2驱动部分,包括注册video_device和v4l2_dev 4.

Android Bitmap 开源图片框架分析(精华四)

disk缓存主要难点在于内存缓存,disk缓存其实比较简单,就是图片加载完成后把图片文件存到本地方便下次使用 同样,先贴一下官方主页的介绍(主页地址见文章最开始处)和内存缓存差不多,根据算法不同提供了几种类别,可以自行通过ImageLoaderConfiguration.discCache(..)设置<ignore_js_op> 硬盘缓存,保存是以文件的形式框架提供了4种类型,具体算法规则不同,看名字我们大概也能知道对应意思 UnlimitedDiscCache                

WisDom.Net 框架设计(七) 验证框架

WisDom.Net-验证框架 1.分类 这里我们将数据验证分为以下几种 数据类型校验      主要用于确保数据类型输入的正确  比如年龄一项输入 A岁 ,显然不合法 域检查               主要用于验证输入的数据的是否在取值范围  比如在年龄一项 输入 400 ,显然这里不合法 格式检查            主要用于检查数据格式是否正确, 比如Email 输入Ca 显然这里也是不合法 自定义检查,       自定义校验数据. 比如 校验数据格式是否合法等 2.简介      

Linux输入子系统框架分析(1)

在Linux下的输入设备键盘.触摸屏.鼠标等都可以用输入子系统来实现驱动.输入子系统分为三层,核心层和设备驱动层,事件层.核心层和事件层由Linux输入子系统本身实现,设备驱动层由我们实现.我们在设备驱动层将输入事件上报给核心层input.c,核心层找到匹配的事件层,将事件交给事件层处理,事件层处理完后传递到用户空间. 我们最终要搞清楚的是在用户空间调用open和read最终在内核中是怎样处理的,向内核上报的事件又是谁处理的,处理完后是怎样传递到用户空间的? 上面两个图是输入子系统的框架. 下面

TI BLE协议栈软件框架分析

看源代码的时候,一般都是从整个代码的入口处开始,TI  BLE 协议栈源码也不例外.它的入口main()函数就是整个程序的入口,由系统上电时自动调用. 它主要做了以下几件事情: (一)底层硬件初始化配置 (二)创建任务并初始化任务配置 (三)检测并执行有效的任务事件 Main() 函数源码如下: 一:底层硬件初始化设置 75行,设置系统时钟,使能内存缓冲功能. 78行,关中断,刚启动时,系统运行不稳定,一般会首先关中断. 81行,硬件相关的I/O 口配置. 84行,初始化mcu 内部的flash

开源学习--SlideExpandableListView中的列表项动画实现框架分析

前面的话 开源项目Android-SlideExpandableListView是一个简单的介绍列表项动画展示的小型项目,分析这个项目可以对自定义框架及列表类动画实现有个比较清晰的认识,工作中中时常根据需求扩展定义自己的适配器,虽然具体需求不同,但架构类似,本文把最近关于该开源项目的研究心得整理分享,共同学习~ 项目简介 github地址https://github.com/tjerkw/Android-SlideExpandableListView 这是个入门级的列表项动画展示框架,实现效果如