7.uvc_parse_format
7.1 uvc格式描述符
- struct uvc_format_desc { //uvc格式描述符
- char *name; //uvc格式描述符名字
- __u8 guid[16];//全局唯一ID
- __u32 fcc; //压缩格式
- };
- 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:
- case UVC_VS_FORMAT_FRAME_BASED:
- 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:
- 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:
- 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帧描述符长度
- }
7.3 设置颜色空间
- static __u32 uvc_colorspace(const __u8 primaries)
- {
- static const __u8 colorprimaries[] = {
- 0,
- V4L2_COLORSPACE_SRGB,
- V4L2_COLORSPACE_470_SYSTEM_M,
- V4L2_COLORSPACE_470_SYSTEM_BG,
- V4L2_COLORSPACE_SMPTE170M,
- V4L2_COLORSPACE_SMPTE240M,
- };
- if (primaries < ARRAY_SIZE(colorprimaries))
- return colorprimaries[primaries]; //返回颜色空间数组项
- return 0;
- }