uvc摄像头代码解析3
转 http://blog.****.net/orz415678659/article/details/10073683
6.uvc解析uvc视频流
6.1 重要结构体
6.1.1 uvc数据流
- struct uvc_streaming {
- struct list_head list; //uvc视频流链表头
- struct uvc_device *dev; //uvc设备
- struct video_device *vdev; //V4L2视频设备
- struct uvc_video_chain *chain; //uvc视频链
- atomic_t active;
- struct usb_interface *intf; //usb接口设备
- int intfnum; //usb接口号
- __u16 maxpsize; //最大包尺寸
- struct uvc_streaming_header header; //uvc视频流头部
- enum v4l2_buf_type type; //V4L2缓冲区类型 输入/输出
- unsigned int nformats; //uvc格式个数
- struct uvc_format *format; //uvc格式指针
- struct uvc_streaming_control ctrl; //uvc数据流控制
- struct uvc_format *cur_format; //当前uvc格式指针
- struct uvc_frame *cur_frame; //当前uvc帧指针
- struct mutex mutex;
- unsigned int frozen : 1;
- struct uvc_video_queue queue; //uvc视频队列
- void (*decode) (struct urb *urb, struct uvc_streaming *video,struct uvc_buffer *buf);//解码函数
- struct {
- __u8 header[256];
- unsigned int header_size;
- int skip_payload;
- __u32 payload_size;
- __u32 max_payload_size;
- } bulk;
- struct urb *urb[UVC_URBS];//urb数组
- char *urb_buffer[UVC_URBS]; //urb缓冲区
- dma_addr_t urb_dma[UVC_URBS];//urb DMA缓冲区
- unsigned int urb_size;
- __u32 sequence;
- __u8 last_fid;
- };
6.1.2 uvc格式
- struct uvc_format { //uvc格式
- __u8 type; //类型
- __u8 index; //索引
- __u8 bpp; //bits per pixel 每像素位数
- __u8 colorspace; //颜色空间
- __u32 fcc; //压缩格式
- __u32 flags; //标记
- char name[32]; //名字
- unsigned int nframes; //所含uvc帧个数
- struct uvc_frame *frame; //uvc帧指针
- };
6.1.3 uvc帧
- struct uvc_frame { //uvc帧
- __u8 bFrameIndex; //帧索引号
- __u8 bmCapabilities; //uvc帧兼容性
- __u16 wWidth; //宽度
- __u16 wHeight; //高度
- __u32 dwMinBitRate; //最新位流
- __u32 dwMaxBitRate; //最大位流
- __u32 dwMaxVideoFrameBufferSize; //最大视频帧缓冲区
- __u8 bFrameIntervalType; //间隙类型
- __u32 dwDefaultFrameInterval; //默认帧间隙
- __u32 *dwFrameInterval; //帧间隙指针
- };
6.2 uvc_parse_streaming函数
- static int uvc_parse_streaming(struct uvc_device *dev,struct usb_interface *intf)
- {
- struct uvc_streaming *streaming = NULL; //uvc数据流
- struct uvc_format *format; //uvc格式
- struct uvc_frame *frame; //uvc帧
- struct usb_host_interface *alts = &intf->altsetting[0]; //获取usb接口第一个usb_host_interface (Alt.Setting 0)
- unsigned char *_buffer, *buffer = alts->extra; //获取额外描述符
- int _buflen, buflen = alts->extralen; //获取额外描述符长度
- unsigned int nformats = 0, nframes = 0, nintervals = 0;
- unsigned int size, i, n, p;
- __u32 *interval;
- __u16 psize;
- int ret = -EINVAL;
- if (intf->cur_altsetting->desc.bInterfaceSubClass != UVC_SC_VIDEOSTREAMING) { //判读usb接口描述符子类是否为视频数据流接口子类
- uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a video streaming interface\n", dev->udev->devnum,intf->altsetting[0].desc.bInterfaceNumber);
- return -EINVAL;
- }
- if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) { //绑定uvc设备的usb驱动和usb接口
- uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already claimed\n", dev->udev->devnum,intf->altsetting[0].desc.bInterfaceNumber);
- return -EINVAL;
- }
- streaming = kzalloc(sizeof *streaming, GFP_KERNEL); //分配uvc数据流内存
- if (streaming == NULL) {
- usb_driver_release_interface(&uvc_driver.driver, intf);
- return -EINVAL;
- }
- mutex_init(&streaming->mutex);
- streaming->dev = dev; //uvc数据流和uvc设备捆绑
- streaming->intf = usb_get_intf(intf); //uvc数据流和usb接口捆绑,并增加引用计数
- streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; //设置接口号
- /* The Pico iMage webcam has its class-specific interface descriptors after the endpoint descriptors. */
- if (buflen == 0) { //Pico iMage webcam 特殊处理
- for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
- struct usb_host_endpoint *ep = &alts->endpoint[i];
- if (ep->extralen == 0)
- continue;
- if (ep->extralen > 2 && ep->extra[1] == USB_DT_CS_INTERFACE) {
- uvc_trace(UVC_TRACE_DESCR, "trying extra data from endpoint %u.\n", i);
- buffer = alts->endpoint[i].extra;
- buflen = alts->endpoint[i].extralen;
- break;
- }
- }
- }
- /* Skip the standard interface descriptors. 跳过标准的接口描述符*/
- while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
- buflen -= buffer[0];
- buffer += buffer[0];
- }
- if (buflen <= 2) {
- uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming interface descriptors found.\n");
- goto error;
- }
- /* Parse the header descriptor. 解析header描述符*/ //Class-specific VS Interface Input Header Descriptor
- switch (buffer[2]) { //bDescriptorSubtype
- case UVC_VS_OUTPUT_HEADER: //输出类型的视频流
- streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; //设置为V4L2视频buf输出
- size = 9;
- break;
- case UVC_VS_INPUT_HEADER: //输入类型的视频流
- streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //设置为V4L2视频buf输入
- size = 13;
- break;
- default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d HEADER descriptor not found.\n", dev->udev->devnum,alts->desc.bInterfaceNumber);
- goto error;
- }
- p = buflen >= 4 ? buffer[3] : 0; //bNumFormats uvc格式format个数
- n = buflen >= size ? buffer[size-1] : 0; //bControlSize 控制位域大小
- if (buflen < size + p*n) { //检测buflen长度是否合适
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d HEADER descriptor is invalid.\n",dev->udev->devnum, alts->desc.bInterfaceNumber);
- goto error;
- }
- //初始化uvc视频流头部
- streaming->header.bNumFormats = p; //uvc格式format格式个数
- streaming->header.bEndpointAddress = buffer[6]; //端点地址
- if (buffer[2] == UVC_VS_INPUT_HEADER) { //输入的视频流
- streaming->header.bmInfo = buffer[7]; //信息位图(兼容性)
- streaming->header.bTerminalLink = buffer[8]; //连接到的输出Terminal ID号
- streaming->header.bStillCaptureMethod = buffer[9]; //静态图像捕捉方法(Method 1、Method 2、Method 3)
- streaming->header.bTriggerSupport = buffer[10]; //硬件触发支持
- streaming->header.bTriggerUsage = buffer[11]; //触发用例
- }
- else {
- streaming->header.bTerminalLink = buffer[7]; //连接到的输入Terminal ID号
- }
- streaming->header.bControlSize = n; //控制位域大小
- streaming->header.bmaControls = kmemdup(&buffer[size], p * n,GFP_KERNEL); //初始化bmaControls(x)位图(大小=帧数*位域大小)
- if (streaming->header.bmaControls == NULL) {
- ret = -ENOMEM;
- goto error;
- }
- buflen -= buffer[0];
- buffer += buffer[0]; //指向下一个描述符
- _buffer = buffer;
- _buflen = buflen; //指向同一个描述符
解析完vs header后解析剩下的vs描述符
第一次解析描述符 统计uvc帧、uvc格式、间隔,并分配内存
- /* Count the format and frame descriptors. 计算格式描述符和帧描述符个数*/
- while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {
- switch (_buffer[2]) {
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_MJPEG:
- case UVC_VS_FORMAT_FRAME_BASED:
- nformats++;
- break;
- case UVC_VS_FORMAT_DV:
- /* DV format has no frame descriptor. We will create a dummy frame descriptor with a dummy frame interval. */
- nformats++;
- nframes++;
- nintervals++;
- break;
- case UVC_VS_FORMAT_MPEG2TS:
- case UVC_VS_FORMAT_STREAM_BASED:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT %u is not supported.\n",dev->udev->devnum,alts->desc.bInterfaceNumber, _buffer[2]);
- break;
- case UVC_VS_FRAME_UNCOMPRESSED:
- case UVC_VS_FRAME_MJPEG:
- nframes++;
- if (_buflen > 25)
- nintervals += _buffer[25] ? _buffer[25] : 3;
- break;
- case UVC_VS_FRAME_FRAME_BASED:
- nframes++;
- if (_buflen > 21)
- nintervals += _buffer[21] ? _buffer[21] : 3;
- break;
- } //计算uvc帧和uvc格式的个数及间隔个数
- _buflen -= _buffer[0];
- _buffer += _buffer[0]; //跳到下一个描述符
- }
- if (nformats == 0) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d has no supported formats defined.\n",dev->udev->devnum, alts->desc.bInterfaceNumber);
- goto error;
- }
- // uvc格式数 * uvc格式大小 + uvc帧 * uvc帧大小 + 间隔数 * 间隔大小
- size = nformats * sizeof *format + nframes * sizeof *frame+ nintervals * sizeof *interval;
- format = kzalloc(size, GFP_KERNEL); //分配uvc格式和uvc帧的内存
- if (format == NULL) {
- ret = -ENOMEM;
- goto error;
- }
- frame = (struct uvc_frame *)&format[nformats]; //uvc帧存放在uvc格式数组后面
- interval = (__u32 *)&frame[nframes]; //间隔放在帧后面
- streaming->format = format; //uvc视频流捆绑uvc格式结构体
- streaming->nformats = nformats; //uvc格式个数
第二次解析描述符
- /* Parse the format descriptors.解析格式描述符 */
- while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
- switch (buffer[2]) { //bDescriptorSubtype描述符类型
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_MJPEG:
- case UVC_VS_FORMAT_DV:
- case UVC_VS_FORMAT_FRAME_BASED:
- format->frame = frame; //uvc格式的帧指针 指向uvc帧地址
- ret = uvc_parse_format(dev, streaming, format,&interval, buffer, buflen); //7.解析uvc格式描述符
- if (ret < 0)
- goto error;
- frame += format->nframes; //uvc帧地址指向下一个uvc格式所属的uvc帧地址
- format++; //指向下一个uvc格式
- buflen -= ret;
- buffer += ret; //指向下一个uvc格式描述符
- continue;
- default:
- break;
- }
- buflen -= buffer[0];
- buffer += buffer[0]; //指向下一个描述符
- }
- if (buflen)
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d has %u bytes of trailing descriptor garbage.\n",dev->udev->devnum, alts->desc.bInterfaceNumber, buflen);
- /* Parse the alternate settings to find the maximum bandwidth. 解析设置并查找最大带宽*/
- for (i = 0; i < intf->num_altsetting; ++i) {
- struct usb_host_endpoint *ep; //声明usb_host_endpoint 指针
- alts = &intf->altsetting[i];//获取usb_host_interface数组
- ep = uvc_find_endpoint(alts,streaming->header.bEndpointAddress); //查找对应usb_host_endpoint
- if (ep == NULL)
- continue;
- psize = le16_to_cpu(ep->desc.wMaxPacketSize); //获取最大包尺寸
- psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); //换算
- if (psize > streaming->maxpsize)
- streaming->maxpsize = psize; //设置uvc视频流最大包尺寸对象
- }
- list_add_tail(&streaming->list, &dev->streams); //添加到uvc设备视频流链表
- return 0;
- error:
- usb_driver_release_interface(&uvc_driver.driver, intf);
- usb_put_intf(intf);
- kfree(streaming->format);
- kfree(streaming->header.bmaControls);
- kfree(streaming);
- return ret;
- }
list_add_tail(&streaming->list, &dev->streams);
相关推荐
- u-boot分析3:第二阶段代码分析2--命令解析过程及自定义命令
- 优达学城数据分析师纳米学位——P3项目知识点整理及代码分析 xml文件解析
- [强化学习-3] Devil 课程第二章解析+ 学生马尔可夫决策过程代码
- 基于opencv和QT的摄像头采集代码( GoQTtemplate3持续更新)
- YOLOv3网络架构以及代码细节解析(一)
- 阿里巴巴Java代码规约插件p3c-pmd使用指南与实现解析
- LSD-SLAM深入学习(3)-代码解析
- YOLO-V3代码解析系列(一) —— 整体结构概述
- 边缘检测项目: 摄像头配置模块ov7670_config代码解析
- OpenCV3源代码文件夹sources解析
- uvc摄像头代码解析1
- 摄像头原理