Hi Harri,

here is a slightly revised patch. Could you please test it with your 
hardware ?

I'm a bit concerned about the MPEG format, which should be stream-based and 
not frame-based. Beside, the GUID doesn't seem to be defined anywhere, and is 
quite ambiguous. Could you please give me more information about the device 
you are targetting ?

Best regards,

Laurent Pinchart
Index: uvc_driver.c
===================================================================
--- uvc_driver.c	(revision 111)
+++ uvc_driver.c	(working copy)
@@ -54,13 +54,47 @@
 
 static struct uvc_format_desc uvc_fmts[] = {
 	{
+		.name		= "YUV 4:2:2 (YUYV)",
 		.guid		= UVC_GUID_FORMAT_YUY2,
 		.fcc		= V4L2_PIX_FMT_YUYV,
+		.flags		= 0,
 	},
 	{
+		.name		= "YUV 4:2:0 (NV12)",
 		.guid		= UVC_GUID_FORMAT_NV12,
 		.fcc		= V4L2_PIX_FMT_NV12,
+		.flags		= 0,
 	},
+	{
+		.name		= "MJPEG",
+		.guid		= UVC_GUID_FORMAT_MJPEG,
+		.fcc		= V4L2_PIX_FMT_MJPEG,
+		.flags		= UVC_FMT_FLAG_COMPRESSED,
+	},
+	{
+		.name		= "YVU 4:2:0 (YV12)",
+		.guid		= UVC_GUID_FORMAT_YV12,
+		.fcc		= V4L2_PIX_FMT_YVU420,
+		.flags		= 0,
+	},
+	{
+		.name		= "YUV 4:2:0 (I420)",
+		.guid		= UVC_GUID_FORMAT_I420,
+		.fcc		= V4L2_PIX_FMT_YUV420,
+		.flags		= 0,
+	},
+	{
+		.name		= "YUV 4:2:2 (UYVY)",
+		.guid		= UVC_GUID_FORMAT_UYVY,
+		.fcc		= V4L2_PIX_FMT_UYVY,
+		.flags		= 0,
+	},
+	{
+		.name		= "MPEG",
+		.guid		= UVC_GUID_FORMAT_MPEG,
+		.fcc		= V4L2_PIX_FMT_MPEG,
+		.flags		= UVC_FMT_FLAG_COMPRESSED,
+	},
 };
 
 #if 0
@@ -104,17 +138,17 @@
 	return NULL;
 }
 
-static __u32 uvc_guid_to_fcc(const __u8 guid[16])
+static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
 {
 	unsigned int len = ARRAY_SIZE(uvc_fmts);
 	unsigned int i;
 
 	for (i = 0; i < len; ++i) {
 		if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
-			return uvc_fmts[i].fcc;
+			return &uvc_fmts[i];
 	}
 
-	return -1;
+	return NULL;
 }
 
 static __u32 uvc_colorspace(const __u8 primaries)
@@ -277,6 +311,7 @@
 {
 	struct usb_interface *intf = streaming->intf;
 	struct usb_host_interface *alts = intf->cur_altsetting;
+	struct uvc_format_desc *fmtdesc;
 	struct uvc_frame *frame;
 	const unsigned char *start = buffer;
 	unsigned int interval;
@@ -288,6 +323,7 @@
 
 	switch (buffer[2]) {
 	case VS_FORMAT_UNCOMPRESSED:
+	case VS_FORMAT_FRAME_BASED:
 		if (buflen < 27) {
 			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
 			       "interface %d FORMAT error\n",
@@ -296,11 +332,23 @@
 			return -EINVAL;
 		}
 
-		strncpy(format->name, "Uncompressed", sizeof format->name);
-		format->fcc = uvc_guid_to_fcc(&buffer[5]);
-		format->flags = 0;
-		format->bpp = 16;
-		ftype = VS_FRAME_UNCOMPRESSED;
+		/* Find the format descriptor from its GUID. */
+		fmtdesc = uvc_format_by_guid(&buffer[5]);
+		if (fmtdesc == NULL) {
+			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+			       "interface %d unknown frame-based GUID\n",
+			       dev->udev->devnum, alts->desc.bInterfaceNumber);
+			return -EINVAL;
+		}
+
+		strncpy(format->name, fmtdesc->name, sizeof format->name);
+		format->fcc = fmtdesc->fcc;
+		format->flags = fmtdesc->flags;
+		format->bpp = buffer[21];
+		if (buffer[2] == VS_FORMAT_UNCOMPRESSED)
+			ftype = VS_FRAME_UNCOMPRESSED;
+		else
+			ftype = VS_FRAME_FRAME_BASED;
 		break;
 
 	case VS_FORMAT_MJPEG:
@@ -362,7 +410,6 @@
 		break;
 
 	case VS_FORMAT_MPEG2TS:
-	case VS_FORMAT_FRAME_BASED:
 	case VS_FORMAT_STREAM_BASED:
 		/* Not supported yet. */
 	default:
@@ -378,64 +425,70 @@
 	buflen -= buffer[0];
 	buffer += buffer[0];
 
+	/* Parse the frame descriptors. Only uncompressed, MJPEG and frame
+	 * based formats have frame descriptors.
+	 */
 	while (buflen > 2 && buffer[2] == ftype) {
 		frame = &format->frame[format->nframes];
 
-		switch (buffer[2]) {
-		case VS_FRAME_UNCOMPRESSED:
-		case VS_FRAME_MJPEG:
+		if (ftype != VS_FRAME_FRAME_BASED)
 			n = buflen > 25 ? buffer[25] : 0;
-			n = n ? n : 3;
+		else
+			n = buflen > 21 ? buffer[21] : 0;
 
-			if (buflen < 26 + 4*n) {
-				uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
-				       "interface %d FRAME error\n",
-				       dev->udev->devnum,
-				       alts->desc.bInterfaceNumber);
-				return -EINVAL;
-			}
+		n = n ? n : 3;
 
-			frame->bFrameIndex = buffer[3];
-			frame->bmCapabilities = buffer[4];
-			frame->wWidth = le16_to_cpup((__le16*)&buffer[5]);
-			frame->wHeight = le16_to_cpup((__le16*)&buffer[7]);
-			frame->dwMinBitRate = le32_to_cpup((__le32*)&buffer[9]);
-			frame->dwMaxBitRate = le32_to_cpup((__le32*)&buffer[13]);
-			frame->dwMaxVideoFrameBufferSize = le32_to_cpup((__le32*)&buffer[17]);
+		if (buflen < 26 + 4*n) {
+			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];
+		frame->bmCapabilities = buffer[4];
+		frame->wWidth = le16_to_cpup((__le16*)&buffer[5]);
+		frame->wHeight = le16_to_cpup((__le16*)&buffer[7]);
+		frame->dwMinBitRate = le32_to_cpup((__le32*)&buffer[9]);
+		frame->dwMaxBitRate = le32_to_cpup((__le32*)&buffer[13]);
+		if (ftype != VS_FRAME_FRAME_BASED) {
+			frame->dwMaxVideoFrameBufferSize =
+				le32_to_cpup((__le32*)&buffer[17]);
+			frame->dwDefaultFrameInterval = 
+				le32_to_cpup((__le32*)&buffer[21]);
 			frame->bFrameIntervalType = buffer[25];
-			frame->dwFrameInterval = *intervals;
+		} else {
+			frame->dwMaxVideoFrameBufferSize = 0;
+			frame->dwDefaultFrameInterval = 
+				le32_to_cpup((__le32*)&buffer[17]);
+			frame->bFrameIntervalType = buffer[21];
+		}
+		frame->dwFrameInterval = *intervals;
 
-			/* Some bogus devices report dwMinFrameInterval equal
-			 * to dwMaxFrameInterval and have dwFrameIntervalStep
-			 * set to zero. Setting all null intervals to 1 fixes
-			 * the problem and some other divisions by zero which
-			 * could happen.
-			 */
-			for (i = 0; i < n; ++i) {
-				interval = le32_to_cpup((__le32*)&buffer[26+4*i]);
-				*(*intervals)++ = interval ? interval : 1;
-			}
+		/* Some bogus devices report dwMinFrameInterval equal to
+		 * dwMaxFrameInterval and have dwFrameIntervalStep set to
+		 * zero. Setting all null intervals to 1 fixes the problem and
+		 * some other divisions by zero which could happen.
+		 */
+		for (i = 0; i < n; ++i) {
+			interval = le32_to_cpup((__le32*)&buffer[26+4*i]);
+			*(*intervals)++ = interval ? interval : 1;
+		}
 
-			/* Make sure that the default frame interval stays
-			 * between the boundaries.
-			 */
-			n -= frame->bFrameIntervalType ? 1 : 2;
-			interval = le32_to_cpup((__le32*)&buffer[21]);
-			if (interval < frame->dwFrameInterval[0])
-				interval = frame->dwFrameInterval[0];
-			else if (interval > frame->dwFrameInterval[n])
-				interval = frame->dwFrameInterval[n];
+		/* Make sure that the default frame interval stays between
+		 * the boundaries.
+		 */
+		n -= frame->bFrameIntervalType ? 1 : 2;
+		frame->dwDefaultFrameInterval =
+			min(frame->dwFrameInterval[n],
+			    max(frame->dwFrameInterval[0],
+				frame->dwDefaultFrameInterval));
 
-			frame->dwDefaultFrameInterval = interval;
+		uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
+			frame->wWidth, frame->wHeight,
+			10000000/frame->dwDefaultFrameInterval,
+			(100000000/frame->dwDefaultFrameInterval)%10);
 
-			uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
-				frame->wWidth, frame->wHeight,
-				10000000/frame->dwDefaultFrameInterval,
-				(100000000/frame->dwDefaultFrameInterval)%10);
-
-			break;
-		}
-
 		format->nframes++;
 		buflen -= buffer[0];
 		buffer += buffer[0];
@@ -563,6 +616,7 @@
 		switch (_buffer[2]) {
 		case VS_FORMAT_UNCOMPRESSED:
 		case VS_FORMAT_MJPEG:
+		case VS_FORMAT_FRAME_BASED:
 			nformats++;
 			break;
 
@@ -576,7 +630,6 @@
 			break;
 
 		case VS_FORMAT_MPEG2TS:
-		case VS_FORMAT_FRAME_BASED:
 		case VS_FORMAT_STREAM_BASED:
 			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
 				"interface %d FORMAT %u is not supported.\n",
@@ -627,6 +680,7 @@
 		case VS_FORMAT_UNCOMPRESSED:
 		case VS_FORMAT_MJPEG:
 		case VS_FORMAT_DV:
+		case VS_FORMAT_FRAME_BASED:
 			format->frame = frame;
 			ret = uvc_parse_format(dev, streaming, format,
 				&interval, buffer, buflen);
Index: uvcvideo.h
===================================================================
--- uvcvideo.h	(revision 110)
+++ uvcvideo.h	(working copy)
@@ -218,6 +218,14 @@
 				 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 #define UVC_GUID_FORMAT_NV12	{0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, \
 				 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_YV12	{ 'Y',  'V',  '1',  '2', 0x00, 0x00, 0x10, 0x00, \
+				 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_I420	{ 'I',  '4',  '2',  '0', 0x00, 0x00, 0x10, 0x00, \
+				 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_UYVY	{ 'U',  'Y',  'V',  'Y', 0x00, 0x00, 0x10, 0x00, \
+				 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_MPEG	{ 'M',  'P',  'E',  'G', 0x00, 0x00, 0x10, 0x00, \
+				 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
 
 
 /* ------------------------------------------------------------------------
@@ -332,8 +340,10 @@
 };
 
 struct uvc_format_desc {
+	char *name;
 	__u8 guid[16];
 	__u32 fcc;
+	__u32 flags;
 };
 
 /* The term 'entity' refers to both UVC units and UVC terminals.
_______________________________________________
Linux-uvc-devel mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/linux-uvc-devel

Reply via email to