• Linux摄像头驱动学习之:(四)UVC-摄像头驱动框架分析


    UVC: USB Video Class
    UVC驱动:driversmediavideouvc

    uvc_driver.c分析:
    1. usb_register(&uvc_driver.driver);
    2. uvc_probe
            uvc_register_video
                vdev = video_device_alloc();
                vdev->fops = &uvc_fops;
                video_register_device

    在www.usb.org下载 uvc specification,
    UVC 1.5 Class specification.pdf : 有详细描述
    USB_Video_Example 1.5.pdf    : 有示例

    通过VideoControl Interface来控制,
    通过VideoStreaming Interface来读视频数据,
    VC里含有多个Unit/Terminal等功能模块,可以通过访问这些模块进行控制,比如调亮度
               
    分析UVC驱动调用过程:
    const struct v4l2_file_operations uvc_fops = {
     .owner  = THIS_MODULE,
     .open  = uvc_v4l2_open,
     .release = uvc_v4l2_release,
     .ioctl  = uvc_v4l2_ioctl,
     .read  = uvc_v4l2_read,
     .mmap  = uvc_v4l2_mmap,
     .poll  = uvc_v4l2_poll,
    };

    1. open:
            uvc_v4l2_open
    2. VIDIOC_QUERYCAP   // video->streaming->type 应该是在设备被枚举时分析描述符时设置的
      if (video->streaming->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;
    3. VIDIOC_ENUM_FMT // format数组应是在设备被枚举时设置的
            format = &video->streaming->format[fmt->index];
    4. VIDIOC_G_FMT
            uvc_v4l2_get_format  // USB摄像头支持多种格式fromat, 每种格式下有多种frame(比如分辨率)
                 struct uvc_format *format = video->streaming->cur_format;
                 struct uvc_frame *frame = video->streaming->cur_frame;
    5. VIDIOC_TRY_FMT
            uvc_v4l2_try_format
                /* Check if the hardware supports the requested format. */

             /* Find the closest image size. The distance between image sizes is
              * the size in pixels of the non-overlapping regions between the
              * requested size and the frame-specified size.
              */
    6. VIDIOC_S_FMT  // 只是把参数保存起来,还没有发给USB摄像头
            uvc_v4l2_set_format
                uvc_v4l2_try_format
             video->streaming->cur_format = format;
             video->streaming->cur_frame = frame;
    7. VIDIOC_REQBUFS
            uvc_alloc_buffers
                for (; nbuffers > 0; --nbuffers) {
              mem = vmalloc_32(nbuffers * bufsize);
              if (mem != NULL)
               break;
             }
    8. VIDIOC_QUERYBUF
            uvc_query_buffer
                __uvc_query_buffer
                    memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);  // 复制参数
    9. mmap
            uvc_v4l2_mmap
               
    10. VIDIOC_QBUF
            uvc_queue_buffer
             list_add_tail(&buf->stream, &queue->mainqueue);
             list_add_tail(&buf->queue, &queue->irqqueue);

    11. VIDIOC_STREAMON
            uvc_video_enable(video, 1)  // 把所设置的参数发给硬件,然后启动摄像头
                /* Commit the streaming parameters. */
                uvc_commit_video
                    uvc_set_video_ctrl  /* 设置格式fromat, 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);
                       
                /* 启动:Initialize isochronous/bulk URBs and allocate transfer buffers. */
                uvc_init_video(video, GFP_KERNEL);
                        uvc_init_video_isoc / uvc_init_video_bulk
                            urb->complete = uvc_video_complete; (收到数据后此函数被调用,它又调用video->decode(urb, video, buf); ==> uvc_video_decode_isoc/uvc_video_encode_bulk => uvc_queue_next_buffer => wake_up(&buf->wait);)
                           
                        usb_submit_urb                     
    12. poll
            uvc_v4l2_poll           
                uvc_queue_poll
                    poll_wait(file, &buf->wait, wait);  // 休眠等待有数据

    13. VIDIOC_DQBUF
            uvc_dequeue_buffer
             list_del(&buf->stream);

    14. VIDIOC_STREAMOFF           
            uvc_video_enable(video, 0);
          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来获得

    (---end---)

  • 相关阅读:
    Ignoring HTTPS certificates
    利用Httponly提升web应用程序安全性
    HttpUrlConnection java.net.SocketException: Software caused connection abort: recv failed
    DISPOSE_ON_CLOSE 和 EXIT_ON_CLOSE 的区别
    Swing多线程
    攒机知识积累
    数组最大子数组和
    fork()详解
    理解Socket编程【转载】
    STM32F407_LED代码
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/5002692.html
Copyright © 2020-2023  润新知