7.uvc_parse_format 7.1 uvc格式描述符 [cpp] struct uvc_format_desc { //uvc格式描述符 char *name; //uvc格式描述符名字 __u8 guid[16];//全局唯一ID __u32 fcc; //壓縮格式 }; 7.2 uvc解析1個格式描述符 [cpp] static int uvc_parse_format(struct uvc_device *dev,struct uvc_streaming *streaming, struct uvc_format *format,__u32 **intervals, unsigned char *buffer, int buflen) { struct usb_interface *intf = streaming->intf; //獲取usb接口 struct usb_host_interface *alts = intf->cur_altsetting; //獲取usb_host_interface struct uvc_format_desc *fmtdesc; //uvc格式描述符 struct uvc_frame *frame; //uvc幀 const unsigned char *start = buffer; unsigned int interval; unsigned int i, n; __u8 ftype; format->type = buffer[2]; //uvc格式類型 format->index = buffer[3]; //uvc格式索引 switch (buffer[2]) { //uvc格式類型 case UVC_VS_FORMAT_UNCOMPRESSED: [cpp] case UVC_VS_FORMAT_FRAME_BASED: [cpp] n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28; //獲取描述符大小 if (buflen < n) { //檢驗buflen大小 uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber); return -EINVAL; } /* Find the format descriptor from its GUID. */ fmtdesc = uvc_format_by_guid(&buffer[5]); //獲取uvc格式描述符 if (fmtdesc != NULL) { //設置uvc格式編碼格式名字 strlcpy(format->name, fmtdesc->name,sizeof format->name); format->fcc = fmtdesc->fcc; //設置uvc格式的fcc(壓縮格式) } else { //不能識別的格式 uvc_printk(KERN_INFO, "Unknown video format %pUl\n",&buffer[5]); snprintf(format->name, sizeof(format->name), "%pUl\n",&buffer[5]); format->fcc = 0; } format->bpp = buffer[21]; //設置uvc格式bpp(每像素多少位) if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) { ftype = UVC_VS_FRAME_UNCOMPRESSED; //設置ftype(frame type) } else { ftype = UVC_VS_FRAME_FRAME_BASED; //設置ftype(frame type) if (buffer[27]) format->flags = UVC_FMT_FLAG_COMPRESSED; //設置uvc格式標志(壓縮的) } break; case UVC_VS_FORMAT_MJPEG: [cpp] if (buflen < 11) { //檢驗buflen大小 uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber); return -EINVAL; } strlcpy(format->name, "MJPEG", sizeof format->name); //設置uvc格式編碼格式名字“MJPEG” format->fcc = V4L2_PIX_FMT_MJPEG; //設置uvc格式的fcc(壓縮格式) format->flags = UVC_FMT_FLAG_COMPRESSED; //設置uvc格式標志(壓縮的) format->bpp = 0; //設置uvc格式bpp(每像素多少位) ftype = UVC_VS_FRAME_MJPEG; //設置ftype(frame type) break; case UVC_VS_FORMAT_DV: [cpp] if (buflen < 9) { //檢驗buflen大小 uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber); return -EINVAL; } switch (buffer[8] & 0x7f) { //bFormatType格式類型 case 0: //設置uvc格式編碼格式名字 "SD-DV" strlcpy(format->name, "SD-DV", sizeof format->name); break; case 1: //設置uvc格式編碼格式名字 "SDL-DV" strlcpy(format->name, "SDL-DV", sizeof format->name); break; case 2: //設置uvc格式編碼格式名字 "HD-DV" strlcpy(format->name, "HD-DV", sizeof format->name); break; default: uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d: unknown DV format %u\n",dev->udev->devnum,alts->desc.bInterfaceNumber, buffer[8]); return -EINVAL; } strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",sizeof format->name); //掃描格式eg("HD-DV 60Hz") format->fcc = V4L2_PIX_FMT_DV; //設置uvc格式的fcc(壓縮格式) format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM; //設置uvc格式標志(壓縮的|數據流) format->bpp = 0; //設置uvc格式bpp(每像素多少位) ftype = 0; //設置ftype(frame type) /* Create a dummy frame descriptor. 創建插入一個幀描述符*/ frame = &format->frame[0]; //獲取uvc格式的第一個幀地址 memset(&format->frame[0], 0, sizeof format->frame[0]); //初始化uvc幀 frame->bFrameIntervalType = 1; //uvc幀間隔類型 frame->dwDefaultFrameInterval = 1; //uvc幀默認間隔 frame->dwFrameInterval = *intervals; //uvc幀間隔 *(*intervals)++ = 1; //添加間隔 format->nframes = 1; //uvc格式的幀個數設置為1 break; case UVC_VS_FORMAT_MPEG2TS: case UVC_VS_FORMAT_STREAM_BASED: /* Not supported yet. */ default: uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d unsupported format %u\n",dev->udev->devnum, alts->desc.bInterfaceNumber,buffer[2]); return -EINVAL; } uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name); buflen -= buffer[0]; buffer += buffer[0]; //下一個描述符(uvc幀描述符) /* Parse the frame descriptors. Only uncompressed, MJPEG and frame based formats have frame descriptors.*/ while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == ftype) { //buffer[2]=bDescriptorSubtype==frame type? frame = &format->frame[format->nframes]; //獲取第二個uvc格式的uvc幀指針 //UVC_VS_FRAME_FRAME_BASED參看USB_Video_Payload_Frame_Based_1.5.pdf P15 if (ftype != UVC_VS_FRAME_FRAME_BASED) //獲取支持的不連續幀間隔數/連續幀間隔 n = buflen > 25 ? buffer[25] : 0; else n = buflen > 21 ? buffer[21] : 0; n = n ? n : 3; //支持不連續幀間隔?支持不連續幀間隔間隔數:連續幀間隔 if (buflen < 26 + 4*n) { //檢驗buflen大小 uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d FRAME error\n", dev->udev->devnum,alts->desc.bInterfaceNumber); return -EINVAL; } frame->bFrameIndex = buffer[3]; //獲取uvc幀索引 frame->bmCapabilities = buffer[4]; //獲取uvc幀兼容性 frame->wWidth = get_unaligned_le16(&buffer[5]); //解碼uvc視頻寬度 frame->wHeight = get_unaligned_le16(&buffer[7]); //解碼uvc視頻高度 frame->dwMinBitRate = get_unaligned_le32(&buffer[9]); //解碼uvc視頻最小位流 frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]); //解碼uvc視頻最大位流 if (ftype != UVC_VS_FRAME_FRAME_BASED) { frame->dwMaxVideoFrameBufferSize =get_unaligned_le32(&buffer[17]); //uvc最大視頻幀緩沖區大小 frame->dwDefaultFrameInterval =get_unaligned_le32(&buffer[21]); //uvc默認幀間隔 frame->bFrameIntervalType = buffer[25]; //uvc幀間隔類型 } else { frame->dwMaxVideoFrameBufferSize = 0; //uvc最大視頻幀緩沖區大小 frame->dwDefaultFrameInterval =get_unaligned_le32(&buffer[17]); //uvc默認幀間隔 frame->bFrameIntervalType = buffer[21]; //uvc幀間隔類型 } frame->dwFrameInterval = *intervals; //設置uvc幀間隔指針 if (!(format->flags & UVC_FMT_FLAG_COMPRESSED)) //uvc格式標志(壓縮的) frame->dwMaxVideoFrameBufferSize = format->bpp * frame->wWidth * frame->wHeight / 8; //計算uvc幀最大視頻格式緩沖去大小(byte) for (i = 0; i < n; ++i) { interval = get_unaligned_le32(&buffer[26+4*i]); //獲取uvc幀間隔 *(*intervals)++ = interval ? interval : 1; //調整uvc幀間隔大小 } /* Make sure that the default frame interval stays between the boundaries.*/ n -= frame->bFrameIntervalType ? 1 : 2; //uvc幀間隔邊界調整 frame->dwDefaultFrameInterval = min(frame->dwFrameInterval[n], max(frame->dwFrameInterval[0],frame->dwDefaultFrameInterval)); if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) { frame->bFrameIntervalType = 1; frame->dwFrameInterval[0] = frame->dwDefaultFrameInterval; } uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",frame->wWidth, frame->wHeight,10000000/frame->dwDefaultFrameInterval,(100000000/frame->dwDefaultFrameInterval)%10); format->nframes++; //調整uvc格式幀數 buflen -= buffer[0]; buffer += buffer[0]; //指向下一個描述符(uvc幀描述符) } if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == UVC_VS_STILL_IMAGE_FRAME) { //靜態圖像幀 buflen -= buffer[0]; buffer += buffer[0]; //跳過指向下一個描述符 } if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == UVC_VS_COLORFORMAT) { //顏色格式幀 if (buflen < 6) { uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface %d COLORFORMAT error\n",dev->udev->devnum,alts->desc.bInterfaceNumber); return -EINVAL; } format->colorspace = uvc_colorspace(buffer[3]); //buffer[3]=bColorPrimaries 設置顏色空間 buflen -= buffer[0]; buffer += buffer[0]; //指向下一描述符 } return buffer - start; //返回解析了的uvc格式描述符+所含的uvc幀描述符長度 }