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.oifeq ($(CONFIG_MEDIA_CONTROLLER),y)uvcvideo-objs += uvc_entity.oendifobj-$(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.pdf
和UVC 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_buffermmap uvc_v4l2_mmap uvc_queue_mmap vb2_mmap VIDIOC_QBUF uvc_queue_buffer vb2_qbufVIDIOC_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_urburb传输完成函数.这里会有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 Interface2. 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来获得