uvc攝像頭代碼解析4

7.uvc_parse_format

7.1 uvc格式描述符

struct uvc_format_desc { //uvc格式描述符
char *name; //uvc格式描述符名字
__u8 guid[16];//全局唯一ID
__u32 fcc; //壓縮格式
};
7.2 uvc解析1個格式描述符

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;
}
7.4 uvc格式/uvc幀/uvc視頻流







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章