转载于:http://www.cnblogs.com/blogs-of-lxl/p/5002692.html
UVC: USB Video Class
UVC驱动:drivers\media\video\uvc\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_open2. 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 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来获得(---end---)