xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.cpp (revision b46615c55ad2c8fe6de54412055a0713da3d610a)
1 /*
2  * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
3  * Copyright 2009, Ithamar Adema, <ithamar.adema@team-embedded.nl>.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "UVCCamDevice.h"
9 
10 #include <stdio.h>
11 
12 #include "CamStreamingDeframer.h"
13 
14 
15 usb_webcam_support_descriptor kSupportedDevices[] = {
16 	// ofcourse we support a generic UVC device...
17 	{{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "USB", "Video Class", "??" },
18 	// ...whilst the following IDs were 'stolen' from a recent Linux driver:
19 	{{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft",     "Lifecam NX-6000",                 "??" },
20 	{{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft",     "Lifecam VX-7000",                 "??" },
21 	{{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech",      "QuickCam Fusion",                 "??" },
22 	{{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech",      "QuickCam Orbit MP",               "??" },
23 	{{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech",      "QuickCam Pro for Notebook",       "??" },
24 	{{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech",      "QuickCam Pro 5000",               "??" },
25 	{{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech",      "QuickCam OEM Dell Notebook",      "??" },
26 	{{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech",      "QuickCam OEM Cisco VT Camera II", "??" },
27 	{{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple",         "Built-In iSight",                 "??" },
28 	{{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera",               "??" },
29 	{{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A",           "MT6227",                          "??" },
30 	{{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek",        "(HP Spartan)",                    "??" },
31 	{{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek",        "(Samsung Q310)",                  "??" },
32 	{{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek",        "Asus F9SG",                       "??" },
33 	{{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek",        "Asus U3S",                        "??" },
34 	{{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A",           "Lenovo Thinkpad SL500",           "??" },
35 	{{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm",         "Pico iMage",                      "??" },
36 	{{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin",       "ProScopeHR",                      "??" },
37 	{{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro",   "USB Web Camera",                  "??" },
38 	{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
39 };
40 
41 /* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
42 usbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
43 	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
44 usbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
45 	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
46 
47 static void
48 print_guid(const usbvc_guid guid)
49 {
50 	if (!memcmp(guid, kYUY2Guid, sizeof(usbvc_guid)))
51 		printf("YUY2");
52 	else if (!memcmp(guid, kNV12Guid, sizeof(usbvc_guid)))
53 		printf("NV12");
54 	else {
55 		printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
56 			"%02x:%02x:%02x:%02x", guid[0], guid[1], guid[2], guid[3], guid[4],
57 			guid[5], guid[6], guid[7], guid[8], guid[9], guid[10], guid[11],
58 			guid[12], guid[13], guid[14], guid[15]);
59 	}
60 }
61 
62 
63 // TODO dumb sof_marks and eof_marks
64 static const uint8 sof_mark_1[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00 };
65 static const uint8 sof_mark_2[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01 };
66 static const uint8 *sof_marks[] = { sof_mark_1, sof_mark_2 };
67 
68 static const uint8 eof_mark_1[] = { 0x00, 0x00, 0x00, 0x00 };
69 static const uint8 eof_mark_2[] = { 0x40, 0x00, 0x00, 0x00 };
70 static const uint8 eof_mark_3[] = { 0x80, 0x00, 0x00, 0x00 };
71 static const uint8 eof_mark_4[] = { 0xc0, 0x00, 0x00, 0x00 };
72 static const uint8 *eof_marks[] = { eof_mark_1, eof_mark_2, eof_mark_3, eof_mark_4 };
73 
74 
75 
76 UVCCamDevice::UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
77 	: CamDevice(_addon, _device),
78 	fHeaderDescriptor(NULL),
79 	fInterruptIn(NULL)
80 {
81 	fDeframer = new CamStreamingDeframer(this);
82 	fDeframer->RegisterSOFTags(sof_marks, 2, sizeof(sof_mark_1), 12);
83 	fDeframer->RegisterEOFTags(eof_marks, 4, sizeof(eof_mark_1), sizeof(eof_mark_1));
84 	SetDataInput(fDeframer);
85 
86 	const BUSBConfiguration* config;
87 	const BUSBInterface* interface;
88 	usb_descriptor* generic;
89 	uint8 buffer[1024];
90 
91 	generic = (usb_descriptor *)buffer;
92 
93 	for (uint32 i = 0; i < _device->CountConfigurations(); i++) {
94 		config = _device->ConfigurationAt(i);
95 		_device->SetConfiguration(config);
96 		for (uint32 j = 0; j < config->CountInterfaces(); j++) {
97 			interface = config->InterfaceAt(j);
98 
99 			if (interface->Class() == CC_VIDEO && interface->Subclass()
100 				== SC_VIDEOCONTROL) {
101 				printf("UVCCamDevice: (%lu,%lu): Found Video Control "
102 					"interface.\n", i, j);
103 
104 				// look for class specific interface descriptors and parse them
105 				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
106 					sizeof(buffer)) == B_OK; k++) {
107 					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
108 						| USB_DESCRIPTOR_INTERFACE))
109 						continue;
110 					fControlIndex = interface->Index();
111 					_ParseVideoControl((const usbvc_class_descriptor*)generic,
112 						generic->generic.length);
113 				}
114 
115 				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
116 					const BUSBEndpoint *e = interface->EndpointAt(i);
117 					if (e && e->IsInterrupt() && e->IsInput()) {
118 						fInterruptIn = e;
119 						break;
120 					}
121 				}
122 				fInitStatus = B_OK;
123 			} else if (interface->Class() == CC_VIDEO && interface->Subclass()
124 				== SC_VIDEOSTREAMING) {
125 				printf("UVCCamDevice: (%lu,%lu): Found Video Streaming "
126 					"interface.\n", i, j);
127 
128 				// look for class specific interface descriptors and parse them
129 				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
130 					sizeof(buffer)) == B_OK; k++) {
131 					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
132 						| USB_DESCRIPTOR_INTERFACE))
133 						continue;
134 					fStreamingIndex = interface->Index();
135 					_ParseVideoStreaming((const usbvc_class_descriptor*)generic,
136 						generic->generic.length);
137 				}
138 
139 				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
140 					const BUSBEndpoint *e = interface->EndpointAt(i);
141 					if (e && e->IsIsochronous() && e->IsInput()) {
142 						fIsoIn = e;
143 						break;
144 					}
145 				}
146 			}
147 		}
148 	}
149 }
150 
151 
152 UVCCamDevice::~UVCCamDevice()
153 {
154 }
155 
156 
157 void
158 UVCCamDevice::_ParseVideoStreaming(const usbvc_class_descriptor* _descriptor,
159 	size_t len)
160 {
161 	switch(_descriptor->descriptorSubtype) {
162 		case VS_INPUT_HEADER:
163 		{
164 			const usbvc_input_header_descriptor* descriptor =
165 				(const usbvc_input_header_descriptor*)_descriptor;
166 			printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", descriptor->numFormats,
167 				descriptor->endpointAddress);
168 			if (descriptor->info & 1)
169 				printf("\tDynamic Format Change supported\n");
170 			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
171 			printf("\tstill capture method=%d\n", descriptor->stillCaptureMethod);
172 			if (descriptor->triggerSupport) {
173 				printf("\ttrigger button fixed to still capture=%s\n",
174 					descriptor->triggerUsage ? "no" : "yes");
175 			}
176 			const uint8 *controls = descriptor->controls;
177 			for (uint8 i = 0; i < descriptor->numFormats; i++,
178 				controls += descriptor->controlSize) {
179 				printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
180 					(*controls & 1) ? "wKeyFrameRate" : "",
181 					(*controls & 2) ? "wPFrameRate" : "",
182 					(*controls & 4) ? "wCompQuality" : "",
183 					(*controls & 8) ? "wCompWindowSize" : "",
184 					(*controls & 16) ? "<Generate Key Frame>" : "",
185 					(*controls & 32) ? "<Update Frame Segment>" : "");
186 			}
187 			break;
188 		}
189 		case VS_FORMAT_UNCOMPRESSED:
190 		{
191 			const usbvc_format_descriptor* descriptor =
192 				(const usbvc_format_descriptor*)_descriptor;
193 			printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=",
194 				descriptor->formatIndex, descriptor->numFrameDescriptors);
195 			print_guid(descriptor->uncompressed.format);
196 			printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
197 				descriptor->uncompressed.bytesPerPixel,
198 				descriptor->uncompressed.defaultFrameIndex,
199 				descriptor->uncompressed.aspectRatioX,
200 				descriptor->uncompressed.aspectRatioY);
201 			printf("\tbmInterlaceFlags:\n");
202 			if (descriptor->uncompressed.interlaceFlags & 1)
203 				printf("\tInterlaced stream or variable\n");
204 			printf("\t%d fields per frame\n",
205 				(descriptor->uncompressed.interlaceFlags & 2) ? 1 : 2);
206 			if (descriptor->uncompressed.interlaceFlags & 4)
207 				printf("\tField 1 first\n");
208 			printf("\tField Pattern: ");
209 			switch((descriptor->uncompressed.interlaceFlags & 0x30) >> 4) {
210 				case 0: printf("Field 1 only\n"); break;
211 				case 1: printf("Field 2 only\n"); break;
212 				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
213 				case 3: printf("Random pattern of fields 1 and 2\n"); break;
214 			}
215 			if (descriptor->uncompressed.copyProtect)
216 				printf("\tRestrict duplication\n");
217 			break;
218 		}
219 		case VS_FRAME_MJPEG:
220 			printf("VS_FRAME_MJPEG:");	// fall through
221 		case VS_FRAME_UNCOMPRESSED:
222 		{
223 			if (_descriptor->descriptorSubtype == VS_FRAME_UNCOMPRESSED)
224 				printf("VS_FRAME_UNCOMPRESSED:");
225 			const usbvc_frame_descriptor* descriptor =
226 				(const usbvc_frame_descriptor*)_descriptor;
227 			printf("\tbFrameIdx=%d,stillsupported=%s,"
228 				"fixedframerate=%s\n", descriptor->frameIndex,
229 				(descriptor->capabilities & 1) ? "yes" : "no",
230 				(descriptor->capabilities & 2) ? "yes" : "no");
231 			printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n",
232 				descriptor->width, descriptor->height,
233 				descriptor->minBitRate, descriptor->maxBitRate,
234 				descriptor->maxVideoFrameBufferSize);
235 			printf("\tdefault frame interval: %lu, #intervals(0=cont): %d\n",
236 				descriptor->defaultFrameInterval, descriptor->frameIntervalType);
237 			if (descriptor->frameIntervalType == 0) {
238 				printf("min/max frame interval=%lu/%lu, step=%lu\n",
239 					descriptor->continuous.minFrameInterval,
240 					descriptor->continuous.maxFrameInterval,
241 					descriptor->continuous.frameIntervalStep);
242 			} else for (uint8 i = 0; i < descriptor->frameIntervalType; i++) {
243 				printf("discrete frame interval: %lu\n",
244 					descriptor->discreteFrameIntervals[i]);
245 			}
246 			break;
247 		}
248 		case VS_COLORFORMAT:
249 		{
250 			const usbvc_color_matching_descriptor* descriptor =
251 				(const usbvc_color_matching_descriptor*)_descriptor;
252 			printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
253 			switch(descriptor->colorPrimaries) {
254 				case 0: printf("Unspecified\n"); break;
255 				case 1: printf("BT.709,sRGB\n"); break;
256 				case 2: printf("BT.470-2(M)\n"); break;
257 				case 3: printf("BT.470-2(B,G)\n"); break;
258 				case 4: printf("SMPTE 170M\n"); break;
259 				case 5: printf("SMPTE 240M\n"); break;
260 				default: printf("Invalid (%d)\n", descriptor->colorPrimaries);
261 			}
262 			printf("\tbTransferCharacteristics: ");
263 			switch(descriptor->transferCharacteristics) {
264 				case 0: printf("Unspecified\n"); break;
265 				case 1: printf("BT.709\n"); break;
266 				case 2: printf("BT.470-2(M)\n"); break;
267 				case 3: printf("BT.470-2(B,G)\n"); break;
268 				case 4: printf("SMPTE 170M\n"); break;
269 				case 5: printf("SMPTE 240M\n"); break;
270 				case 6: printf("Linear (V=Lc)\n"); break;
271 				case 7: printf("sRGB\n"); break;
272 				default: printf("Invalid (%d)\n",
273 					descriptor->transferCharacteristics);
274 			}
275 			printf("\tbMatrixCoefficients: ");
276 			switch(descriptor->matrixCoefficients) {
277 				case 0: printf("Unspecified\n"); break;
278 				case 1: printf("BT.709\n"); break;
279 				case 2: printf("FCC\n"); break;
280 				case 3: printf("BT.470-2(B,G)\n"); break;
281 				case 4: printf("SMPTE 170M (BT.601)\n"); break;
282 				case 5: printf("SMPTE 240M\n"); break;
283 				default: printf("Invalid (%d)\n", descriptor->matrixCoefficients);
284 			}
285 			break;
286 		}
287 		case VS_OUTPUT_HEADER:
288 		{
289 			const usbvc_output_header_descriptor* descriptor =
290 				(const usbvc_output_header_descriptor*)_descriptor;
291 			printf("VS_OUTPUT_HEADER:\t#fmts=%d,ept=0x%x\n",
292 				descriptor->numFormats, descriptor->endpointAddress);
293 			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
294 			const uint8 *controls = descriptor->controls;
295 			for (uint8 i = 0; i < descriptor->numFormats; i++,
296 				controls += descriptor->controlSize) {
297 				printf("\tfmt%d: %s %s %s %s\n", i,
298 					(*controls & 1) ? "wKeyFrameRate" : "",
299 					(*controls & 2) ? "wPFrameRate" : "",
300 					(*controls & 4) ? "wCompQuality" : "",
301 					(*controls & 8) ? "wCompWindowSize" : "");
302 			}
303 			break;
304 		}
305 		case VS_STILL_IMAGE_FRAME:
306 		{
307 			const usbvc_still_image_frame_descriptor* descriptor =
308 				(const usbvc_still_image_frame_descriptor*)_descriptor;
309 			printf("VS_STILL_IMAGE_FRAME:\t#imageSizes=%d,compressions=%d,"
310 				"ept=0x%x\n", descriptor->numImageSizePatterns,
311 				descriptor->NumCompressionPatterns(),
312 				descriptor->endpointAddress);
313 			for (uint8 i = 0; i < descriptor->numImageSizePatterns; i++) {
314 				printf("imageSize%d: %dx%d\n", i,
315 					descriptor->imageSizePatterns[i].width,
316 					descriptor->imageSizePatterns[i].height);
317 			}
318 			for (uint8 i = 0; i < descriptor->NumCompressionPatterns(); i++) {
319 				printf("compression%d: %d\n", i,
320 					descriptor->CompressionPatterns()[i]);
321 			}
322 			break;
323 		}
324 		case VS_FORMAT_MJPEG:
325 		{
326 			const usbvc_format_descriptor* descriptor =
327 				(const usbvc_format_descriptor*)_descriptor;
328 			printf("VS_FORMAT_MJPEG:\tbFormatIdx=%d,#frmdesc=%d\n",
329 				descriptor->formatIndex, descriptor->numFrameDescriptors);
330 			printf("\t#flgs=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
331 				descriptor->mjpeg.flags,
332 				descriptor->mjpeg.defaultFrameIndex,
333 				descriptor->mjpeg.aspectRatioX,
334 				descriptor->mjpeg.aspectRatioY);
335 			printf("\tbmInterlaceFlags:\n");
336 			if (descriptor->mjpeg.interlaceFlags & 1)
337 				printf("\tInterlaced stream or variable\n");
338 			printf("\t%d fields per frame\n",
339 				(descriptor->mjpeg.interlaceFlags & 2) ? 1 : 2);
340 			if (descriptor->mjpeg.interlaceFlags & 4)
341 				printf("\tField 1 first\n");
342 			printf("\tField Pattern: ");
343 			switch((descriptor->mjpeg.interlaceFlags & 0x30) >> 4) {
344 				case 0: printf("Field 1 only\n"); break;
345 				case 1: printf("Field 2 only\n"); break;
346 				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
347 				case 3: printf("Random pattern of fields 1 and 2\n"); break;
348 			}
349 			if (descriptor->mjpeg.copyProtect)
350 				printf("\tRestrict duplication\n");
351 			break;
352 		}
353 		case VS_FORMAT_MPEG2TS:
354 			printf("VS_FORMAT_MPEG2TS:\t\n");
355 			break;
356 		case VS_FORMAT_DV:
357 			printf("VS_FORMAT_DV:\t\n");
358 			break;
359 		case VS_FORMAT_FRAME_BASED:
360 			printf("VS_FORMAT_FRAME_BASED:\t\n");
361 			break;
362 		case VS_FRAME_FRAME_BASED:
363 			printf("VS_FRAME_FRAME_BASED:\t\n");
364 			break;
365 		case VS_FORMAT_STREAM_BASED:
366 			printf("VS_FORMAT_STREAM_BASED:\t\n");
367 			break;
368 		default:
369 			printf("INVALID STREAM UNIT TYPE=%d!\n",
370 				_descriptor->descriptorSubtype);
371 	}
372 }
373 
374 
375 void
376 UVCCamDevice::_ParseVideoControl(const usbvc_class_descriptor* _descriptor,
377 	size_t len)
378 {
379 	switch(_descriptor->descriptorSubtype) {
380 		case VC_HEADER:
381 		{
382 			fHeaderDescriptor = (usbvc_interface_header_descriptor*)_descriptor;
383 			printf("VC_HEADER:\tUVC v%x.%02x, clk %.5f MHz\n",
384 				fHeaderDescriptor->version >> 8,
385 				fHeaderDescriptor->version & 0xff,
386 				fHeaderDescriptor->clockFrequency / 1000000.0);
387 			for (uint8 i = 0; i < fHeaderDescriptor->numInterfacesNumbers; i++) {
388 				printf("\tStreaming Interface %d\n",
389 					fHeaderDescriptor->interfaceNumbers[i]);
390 			}
391 			break;
392 		}
393 		case VC_INPUT_TERMINAL:
394 		{
395 			const usbvc_input_terminal_descriptor* descriptor =
396 				(const usbvc_input_terminal_descriptor*)_descriptor;
397 			printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
398 				"%d\n", descriptor->terminalID, descriptor->terminalType,
399 				descriptor->associatedTerminal);
400 			printf("\tDesc: %s\n",
401 				fDevice->DecodeStringDescriptor(descriptor->terminal));
402 			if (descriptor->terminalType == 0x201) {
403 				const usbvc_camera_terminal_descriptor* desc =
404 					(const usbvc_camera_terminal_descriptor*)descriptor;
405 				printf("\tObjectiveFocalLength Min/Max %d/%d\n",
406 					desc->objectiveFocalLengthMin,
407 					desc->objectiveFocalLengthMax);
408 				printf("\tOcularFocalLength %d\n", desc->ocularFocalLength);
409 				printf("\tControlSize %d\n", desc->controlSize);
410 			}
411 			break;
412 		}
413 		case VC_OUTPUT_TERMINAL:
414 		{
415 			const usbvc_output_terminal_descriptor* descriptor =
416 				(const usbvc_output_terminal_descriptor*)_descriptor;
417 			printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
418 				"%d, src id=%d\n", descriptor->terminalID,
419 				descriptor->terminalType, descriptor->associatedTerminal,
420 				descriptor->sourceID);
421 			printf("\tDesc: %s\n",
422 				fDevice->DecodeStringDescriptor(descriptor->terminal));
423 			break;
424 		}
425 		case VC_SELECTOR_UNIT:
426 		{
427 			const usbvc_selector_unit_descriptor* descriptor =
428 				(const usbvc_selector_unit_descriptor*)_descriptor;
429 			printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n",
430 				descriptor->unitID, descriptor->numInputPins);
431 			printf("\t");
432 			for (uint8 i = 0; i < descriptor->numInputPins; i++)
433 				printf("%d ", descriptor->sourceID[i]);
434 			printf("\n");
435 			printf("\tDesc: %s\n",
436 				fDevice->DecodeStringDescriptor(descriptor->Selector()));
437 			break;
438 		}
439 		case VC_PROCESSING_UNIT:
440 		{
441 			const usbvc_processing_unit_descriptor* descriptor =
442 				(const usbvc_processing_unit_descriptor*)_descriptor;
443 			printf("VC_PROCESSING_UNIT:\tid=%d,src id=%d, digmul=%d\n",
444 				descriptor->unitID, descriptor->sourceID,
445 				descriptor->maxMultiplier);
446 			printf("\tbControlSize=%d\n", descriptor->controlSize);
447 			if (descriptor->controlSize >= 1) {
448 				if (descriptor->controls[0] & 1)
449 					printf("\tBrightness\n");
450 				if (descriptor->controls[0] & 2)
451 					printf("\tContrast\n");
452 				if (descriptor->controls[0] & 4)
453 					printf("\tHue\n");
454 				if (descriptor->controls[0] & 8)
455 					printf("\tSaturation\n");
456 				if (descriptor->controls[0] & 16)
457 					printf("\tSharpness\n");
458 				if (descriptor->controls[0] & 32)
459 					printf("\tGamma\n");
460 				if (descriptor->controls[0] & 64)
461 					printf("\tWhite Balance Temperature\n");
462 				if (descriptor->controls[0] & 128)
463 					printf("\tWhite Balance Component\n");
464 			}
465 			if (descriptor->controlSize >= 2) {
466 				if (descriptor->controls[1] & 1)
467 					printf("\tBacklight Compensation\n");
468 				if (descriptor->controls[1] & 2)
469 					printf("\tGain\n");
470 				if (descriptor->controls[1] & 4)
471 					printf("\tPower Line Frequency\n");
472 				if (descriptor->controls[1] & 8)
473 					printf("\t[AUTO] Hue\n");
474 				if (descriptor->controls[1] & 16)
475 					printf("\t[AUTO] White Balance Temperature\n");
476 				if (descriptor->controls[1] & 32)
477 					printf("\t[AUTO] White Balance Component\n");
478 				if (descriptor->controls[1] & 64)
479 					printf("\tDigital Multiplier\n");
480 				if (descriptor->controls[1] & 128)
481 					printf("\tDigital Multiplier Limit\n");
482 			}
483 			if (descriptor->controlSize >= 3) {
484 				if (descriptor->controls[2] & 1)
485 					printf("\tAnalog Video Standard\n");
486 				if (descriptor->controls[2] & 2)
487 					printf("\tAnalog Video Lock Status\n");
488 			}
489 			printf("\tDesc: %s\n",
490 				fDevice->DecodeStringDescriptor(descriptor->Processing()));
491 			if (descriptor->VideoStandards() & 2)
492 				printf("\tNTSC  525/60\n");
493 			if (descriptor->VideoStandards() & 4)
494 				printf("\tPAL   625/50\n");
495 			if (descriptor->VideoStandards() & 8)
496 				printf("\tSECAM 625/50\n");
497 			if (descriptor->VideoStandards() & 16)
498 				printf("\tNTSC  625/50\n");
499 			if (descriptor->VideoStandards() & 32)
500 				printf("\tPAL   525/60\n");
501 			break;
502 		}
503 		case VC_EXTENSION_UNIT:
504 		{
505 			const usbvc_extension_unit_descriptor* descriptor =
506 				(const usbvc_extension_unit_descriptor*)_descriptor;
507 			printf("VC_EXTENSION_UNIT:\tid=%d, guid=", descriptor->unitID);
508 			print_guid(descriptor->guidExtensionCode);
509 			printf("\n\t#ctrls=%d, #pins=%d\n", descriptor->numControls,
510 				descriptor->numInputPins);
511 			printf("\t");
512 			for (uint8 i = 0; i < descriptor->numInputPins; i++)
513 				printf("%d ", descriptor->sourceID[i]);
514 			printf("\n");
515 			printf("\tDesc: %s\n",
516 				fDevice->DecodeStringDescriptor(descriptor->Extension()));
517 			break;
518 		}
519 		default:
520 			printf("Unknown control %d\n", _descriptor->descriptorSubtype);
521 	}
522 }
523 
524 
525 bool
526 UVCCamDevice::SupportsIsochronous()
527 {
528 	return true;
529 }
530 
531 
532 status_t
533 UVCCamDevice::StartTransfer()
534 {
535 	if (_ProbeCommitFormat() != B_OK || _SelectBestAlternate() != B_OK)
536 		return B_ERROR;
537 	return CamDevice::StartTransfer();
538 }
539 
540 
541 status_t
542 UVCCamDevice::StopTransfer()
543 {
544 	_SelectIdleAlternate();
545 	return CamDevice::StopTransfer();
546 }
547 
548 
549 status_t
550 UVCCamDevice::SuggestVideoFrame(uint32 &width, uint32 &height)
551 {
552 	width = 320;
553 	height = 240;
554 	return B_OK;
555 }
556 
557 
558 status_t
559 UVCCamDevice::AcceptVideoFrame(uint32 &width, uint32 &height)
560 {
561 	width = 320;
562 	height = 240;
563 
564 	SetVideoFrame(BRect(0, 0, width - 1, height - 1));
565 	return B_OK;
566 }
567 
568 
569 status_t
570 UVCCamDevice::_ProbeCommitFormat()
571 {
572 	usbvc_probecommit request;
573 	memset(&request, 0, sizeof(request));
574 	request.hint = 1 << 8;
575 	request.SetFrameInterval(333333);
576 	request.formatIndex = 1;
577 	request.frameIndex = 3;
578 	size_t length = fHeaderDescriptor->version > 0x100 ? 34 : 26;
579 	size_t actualLength = fDevice->ControlTransfer(
580 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
581 		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
582 	if (actualLength != length) {
583 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SET_CUR ProbeControl1"
584 			" failed %ld\n", actualLength);
585 		return B_ERROR;
586 	}
587 
588 	usbvc_probecommit response;
589 	actualLength = fDevice->ControlTransfer(
590 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_MAX,
591 		VS_PROBE_CONTROL << 8, fStreamingIndex, sizeof(response), &response);
592 	if (actualLength != sizeof(response)) {
593 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() GetMax ProbeControl"
594 			" failed\n");
595 		return B_ERROR;
596 	}
597 
598 	printf("usbvc_probecommit response.compQuality %d\n", response.compQuality);
599 	request.compQuality = response.compQuality;
600 
601 	actualLength = fDevice->ControlTransfer(
602 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
603 		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
604 	if (actualLength != length) {
605 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur ProbeControl2"
606 			" failed\n");
607 		return B_ERROR;
608 	}
609 
610 	actualLength = fDevice->ControlTransfer(
611 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
612 		VS_COMMIT_CONTROL << 8, fStreamingIndex, length, &request);
613 	if (actualLength != length) {
614 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur CommitControl"
615 			" failed\n");
616 		return B_ERROR;
617 	}
618 
619 	fMaxVideoFrameSize = response.maxVideoFrameSize;
620 	fMaxPayloadTransferSize = response.maxPayloadTransferSize;
621 	printf("usbvc_probecommit setup done maxVideoFrameSize:%ld"
622 		" maxPayloadTransferSize:%ld\n", fMaxVideoFrameSize,
623 		fMaxPayloadTransferSize);
624 
625 	return B_OK;
626 }
627 
628 
629 status_t
630 UVCCamDevice::_SelectBestAlternate()
631 {
632 	const BUSBConfiguration *config = fDevice->ActiveConfiguration();
633 	const BUSBInterface *streaming = config->InterfaceAt(fStreamingIndex);
634 
635 	uint32 bestBandwidth = 0;
636 	uint32 alternateIndex = 0;
637 	uint32 endpointIndex = 0;
638 
639 	for (uint32 i = 0; i < streaming->CountAlternates(); i++) {
640 		const BUSBInterface *alternate = streaming->AlternateAt(i);
641 		for (uint32 j = 0; j < alternate->CountEndpoints(); j++) {
642 			const BUSBEndpoint *endpoint = alternate->EndpointAt(j);
643 			if (!endpoint->IsIsochronous() || !endpoint->IsInput())
644 				continue;
645 			if (fMaxPayloadTransferSize > endpoint->MaxPacketSize())
646 				continue;
647 			if (bestBandwidth != 0
648 				&& bestBandwidth < endpoint->MaxPacketSize())
649 				continue;
650 			bestBandwidth = endpoint->MaxPacketSize();
651 			endpointIndex = j;
652 			alternateIndex = i;
653 		}
654 	}
655 
656 	if (bestBandwidth == 0) {
657 		fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
658 			" couldn't find a valid alternate\n");
659 		return B_ERROR;
660 	}
661 
662 	printf("UVCCamDevice::_SelectBestAlternate() %ld\n", bestBandwidth);
663 	if (((BUSBInterface *)streaming)->SetAlternate(alternateIndex) != B_OK) {
664 		fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
665 			" selecting alternate failed\n");
666 		return B_ERROR;
667 	}
668 
669 	fIsoIn = streaming->EndpointAt(endpointIndex);
670 
671 	return B_OK;
672 }
673 
674 
675 status_t
676 UVCCamDevice::_SelectIdleAlternate()
677 {
678 	const BUSBConfiguration *config = fDevice->ActiveConfiguration();
679 	const BUSBInterface *streaming = config->InterfaceAt(fStreamingIndex);
680 	if (((BUSBInterface *)streaming)->SetAlternate(0) != B_OK) {
681 		fprintf(stderr, "UVCCamDevice::_SelectIdleAlternate()"
682 			" selecting alternate failed\n");
683 		return B_ERROR;
684 	}
685 
686 	fIsoIn = NULL;
687 
688 	return B_OK;
689 }
690 
691 
692 UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)
693 	: CamDeviceAddon(webcam)
694 {
695 	SetSupportedDevices(kSupportedDevices);
696 }
697 
698 
699 UVCCamDeviceAddon::~UVCCamDeviceAddon()
700 {
701 }
702 
703 
704 const char *
705 UVCCamDeviceAddon::BrandName()
706 {
707 	return "USB Video Class";
708 }
709 
710 
711 UVCCamDevice *
712 UVCCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
713 {
714 	return new UVCCamDevice(*this, from);
715 }
716 
717 
718 extern "C" status_t
719 B_WEBCAM_MKINTFUNC(uvccam)
720 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
721 {
722 	*addon = new UVCCamDeviceAddon(webcam);
723 	return B_OK;
724 }
725