xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.cpp (revision e81a954787e50e56a7f06f72705b7859b6ab06d1)
1 /*
2  * Copyright 2011, Gabriel Hartmann, gabriel.hartmann@gmail.com.
3  * Copyright 2011, Jérôme Duval, korli@users.berlios.de.
4  * Copyright 2009, Ithamar Adema, <ithamar.adema@team-embedded.nl>.
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include "UVCCamDevice.h"
10 #include "UVCDeframer.h"
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ParameterWeb.h>
15 #include <media/Buffer.h>
16 
17 
18 usb_webcam_support_descriptor kSupportedDevices[] = {
19 	// ofcourse we support a generic UVC device...
20 	{{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "Generic UVC", "Video Class", "??" },
21 	// ...whilst the following IDs were 'stolen' from a recent Linux driver:
22 	{{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft",     "Lifecam NX-6000",                 "??" },
23 	{{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft",     "Lifecam VX-7000",                 "??" },
24 	{{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech",      "QuickCam Fusion",                 "??" },
25 	{{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech",      "QuickCam Orbit MP",               "??" },
26 	{{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech",      "QuickCam Pro for Notebook",       "??" },
27 	{{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech",      "QuickCam Pro 5000",               "??" },
28 	{{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech",      "QuickCam OEM Dell Notebook",      "??" },
29 	{{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech",      "QuickCam OEM Cisco VT Camera II", "??" },
30 	{{ 0, 0, 0, 0x046d, 0x0821, }, "Logitech",      "HD Pro Webcam C910",              "??" },
31 	{{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple",         "Built-In iSight",                 "??" },
32 	{{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera",               "??" },
33 	{{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A",           "MT6227",                          "??" },
34 	{{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek",        "(HP Spartan)",                    "??" },
35 	{{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek",        "(Samsung Q310)",                  "??" },
36 	{{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek",        "Asus F9SG",                       "??" },
37 	{{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek",        "Asus U3S",                        "??" },
38 	{{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A",           "Lenovo Thinkpad SL500",           "??" },
39 	{{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm",         "Pico iMage",                      "??" },
40 	{{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin",       "ProScopeHR",                      "??" },
41 	{{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro",   "USB Web Camera",                  "??" },
42 	{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
43 };
44 
45 /* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
46 usbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
47 	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
48 usbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
49 	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
50 
51 static void
52 print_guid(const usbvc_guid guid)
53 {
54 	if (!memcmp(guid, kYUY2Guid, sizeof(usbvc_guid)))
55 		printf("YUY2");
56 	else if (!memcmp(guid, kNV12Guid, sizeof(usbvc_guid)))
57 		printf("NV12");
58 	else {
59 		printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
60 			"%02x:%02x:%02x:%02x", guid[0], guid[1], guid[2], guid[3], guid[4],
61 			guid[5], guid[6], guid[7], guid[8], guid[9], guid[10], guid[11],
62 			guid[12], guid[13], guid[14], guid[15]);
63 	}
64 }
65 
66 
67 UVCCamDevice::UVCCamDevice(CamDeviceAddon& _addon, BUSBDevice* _device)
68 	: CamDevice(_addon, _device),
69 	fHeaderDescriptor(NULL),
70 	fInterruptIn(NULL),
71 	fUncompressedFormatIndex(1),
72 	fUncompressedFrameIndex(1)
73 {
74 	fDeframer = new UVCDeframer(this);
75 	SetDataInput(fDeframer);
76 
77 	const BUSBConfiguration* config;
78 	const BUSBInterface* interface;
79 	usb_descriptor* generic;
80 	uint8 buffer[1024];
81 
82 	generic = (usb_descriptor*)buffer;
83 
84 	for (uint32 i = 0; i < _device->CountConfigurations(); i++) {
85 		config = _device->ConfigurationAt(i);
86 		if (config == NULL)
87 			continue;
88 		_device->SetConfiguration(config);
89 		for (uint32 j = 0; j < config->CountInterfaces(); j++) {
90 			interface = config->InterfaceAt(j);
91 			if (interface == NULL)
92 				continue;
93 
94 			if (interface->Class() == CC_VIDEO && interface->Subclass()
95 				== SC_VIDEOCONTROL) {
96 				printf("UVCCamDevice: (%lu,%lu): Found Video Control "
97 					"interface.\n", i, j);
98 
99 				// look for class specific interface descriptors and parse them
100 				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
101 					sizeof(buffer)) == B_OK; k++) {
102 					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
103 						| USB_DESCRIPTOR_INTERFACE))
104 						continue;
105 					fControlIndex = interface->Index();
106 					_ParseVideoControl((const usbvc_class_descriptor*)generic,
107 						generic->generic.length);
108 				}
109 				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
110 					const BUSBEndpoint* e = interface->EndpointAt(i);
111 					if (e && e->IsInterrupt() && e->IsInput()) {
112 						fInterruptIn = e;
113 						break;
114 					}
115 				}
116 				fInitStatus = B_OK;
117 			} else if (interface->Class() == CC_VIDEO && interface->Subclass()
118 				== SC_VIDEOSTREAMING) {
119 				printf("UVCCamDevice: (%lu,%lu): Found Video Streaming "
120 					"interface.\n", i, j);
121 
122 				// look for class specific interface descriptors and parse them
123 				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
124 					sizeof(buffer)) == B_OK; k++) {
125 					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
126 						| USB_DESCRIPTOR_INTERFACE))
127 						continue;
128 					fStreamingIndex = interface->Index();
129 					_ParseVideoStreaming((const usbvc_class_descriptor*)generic,
130 						generic->generic.length);
131 				}
132 
133 				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
134 					const BUSBEndpoint* e = interface->EndpointAt(i);
135 					if (e && e->IsIsochronous() && e->IsInput()) {
136 						fIsoIn = e;
137 						break;
138 					}
139 				}
140 			}
141 		}
142 	}
143 }
144 
145 
146 UVCCamDevice::~UVCCamDevice()
147 {
148 	free(fHeaderDescriptor);
149 }
150 
151 
152 void
153 UVCCamDevice::_ParseVideoStreaming(const usbvc_class_descriptor* _descriptor,
154 	size_t len)
155 {
156 	switch (_descriptor->descriptorSubtype) {
157 		case VS_INPUT_HEADER:
158 		{
159 			const usbvc_input_header_descriptor* descriptor
160 				= (const usbvc_input_header_descriptor*)_descriptor;
161 			printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", descriptor->numFormats,
162 				descriptor->endpointAddress);
163 			if (descriptor->info & 1)
164 				printf("\tDynamic Format Change supported\n");
165 			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
166 			printf("\tstill capture method=%d\n", descriptor->stillCaptureMethod);
167 			if (descriptor->triggerSupport) {
168 				printf("\ttrigger button fixed to still capture=%s\n",
169 					descriptor->triggerUsage ? "no" : "yes");
170 			}
171 			const uint8* controls = descriptor->controls;
172 			for (uint8 i = 0; i < descriptor->numFormats; i++,
173 				controls += descriptor->controlSize) {
174 				printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
175 					(*controls & 1) ? "wKeyFrameRate" : "",
176 					(*controls & 2) ? "wPFrameRate" : "",
177 					(*controls & 4) ? "wCompQuality" : "",
178 					(*controls & 8) ? "wCompWindowSize" : "",
179 					(*controls & 16) ? "<Generate Key Frame>" : "",
180 					(*controls & 32) ? "<Update Frame Segment>" : "");
181 			}
182 			break;
183 		}
184 		case VS_FORMAT_UNCOMPRESSED:
185 		{
186 			const usbvc_format_descriptor* descriptor
187 				= (const usbvc_format_descriptor*)_descriptor;
188 			fUncompressedFormatIndex = descriptor->formatIndex;
189 			printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=",
190 				descriptor->formatIndex, descriptor->numFrameDescriptors);
191 			print_guid(descriptor->uncompressed.format);
192 			printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
193 				descriptor->uncompressed.bytesPerPixel,
194 				descriptor->uncompressed.defaultFrameIndex,
195 				descriptor->uncompressed.aspectRatioX,
196 				descriptor->uncompressed.aspectRatioY);
197 			printf("\tbmInterlaceFlags:\n");
198 			if (descriptor->uncompressed.interlaceFlags & 1)
199 				printf("\tInterlaced stream or variable\n");
200 			printf("\t%d fields per frame\n",
201 				(descriptor->uncompressed.interlaceFlags & 2) ? 1 : 2);
202 			if (descriptor->uncompressed.interlaceFlags & 4)
203 				printf("\tField 1 first\n");
204 			printf("\tField Pattern: ");
205 			switch ((descriptor->uncompressed.interlaceFlags & 0x30) >> 4) {
206 				case 0: printf("Field 1 only\n"); break;
207 				case 1: printf("Field 2 only\n"); break;
208 				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
209 				case 3: printf("Random pattern of fields 1 and 2\n"); break;
210 			}
211 			if (descriptor->uncompressed.copyProtect)
212 				printf("\tRestrict duplication\n");
213 			break;
214 		}
215 		case VS_FRAME_MJPEG:
216 		case VS_FRAME_UNCOMPRESSED:
217 		{
218 			const usbvc_frame_descriptor* descriptor
219 				= (const usbvc_frame_descriptor*)_descriptor;
220 			if (_descriptor->descriptorSubtype == VS_FRAME_UNCOMPRESSED) {
221 				printf("VS_FRAME_UNCOMPRESSED:");
222 				fUncompressedFrames.AddItem(
223 					new usbvc_frame_descriptor(*descriptor));
224 			} else {
225 				printf("VS_FRAME_MJPEG:");
226 				fMJPEGFrames.AddItem(new usbvc_frame_descriptor(*descriptor));
227 			}
228 			printf("\tbFrameIdx=%d,stillsupported=%s,"
229 				"fixedframerate=%s\n", descriptor->frameIndex,
230 				(descriptor->capabilities & 1) ? "yes" : "no",
231 				(descriptor->capabilities & 2) ? "yes" : "no");
232 			printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n",
233 				descriptor->width, descriptor->height,
234 				descriptor->minBitRate, descriptor->maxBitRate,
235 				descriptor->maxVideoFrameBufferSize);
236 			printf("\tdefault frame interval: %lu, #intervals(0=cont): %d\n",
237 				descriptor->defaultFrameInterval, descriptor->frameIntervalType);
238 			if (descriptor->frameIntervalType == 0) {
239 				printf("min/max frame interval=%lu/%lu, step=%lu\n",
240 					descriptor->continuous.minFrameInterval,
241 					descriptor->continuous.maxFrameInterval,
242 					descriptor->continuous.frameIntervalStep);
243 			} else for (uint8 i = 0; i < descriptor->frameIntervalType; i++) {
244 				printf("\tdiscrete frame interval: %lu\n",
245 					descriptor->discreteFrameIntervals[i]);
246 			}
247 			break;
248 		}
249 		case VS_COLORFORMAT:
250 		{
251 			const usbvc_color_matching_descriptor* descriptor
252 				= (const usbvc_color_matching_descriptor*)_descriptor;
253 			printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
254 			switch (descriptor->colorPrimaries) {
255 				case 0: printf("Unspecified\n"); break;
256 				case 1: printf("BT.709,sRGB\n"); break;
257 				case 2: printf("BT.470-2(M)\n"); break;
258 				case 3: printf("BT.470-2(B,G)\n"); break;
259 				case 4: printf("SMPTE 170M\n"); break;
260 				case 5: printf("SMPTE 240M\n"); break;
261 				default: printf("Invalid (%d)\n", descriptor->colorPrimaries);
262 			}
263 			printf("\tbTransferCharacteristics: ");
264 			switch (descriptor->transferCharacteristics) {
265 				case 0: printf("Unspecified\n"); break;
266 				case 1: printf("BT.709\n"); break;
267 				case 2: printf("BT.470-2(M)\n"); break;
268 				case 3: printf("BT.470-2(B,G)\n"); break;
269 				case 4: printf("SMPTE 170M\n"); break;
270 				case 5: printf("SMPTE 240M\n"); break;
271 				case 6: printf("Linear (V=Lc)\n"); break;
272 				case 7: printf("sRGB\n"); break;
273 				default: printf("Invalid (%d)\n",
274 					descriptor->transferCharacteristics);
275 			}
276 			printf("\tbMatrixCoefficients: ");
277 			switch (descriptor->matrixCoefficients) {
278 				case 0: printf("Unspecified\n"); break;
279 				case 1: printf("BT.709\n"); break;
280 				case 2: printf("FCC\n"); break;
281 				case 3: printf("BT.470-2(B,G)\n"); break;
282 				case 4: printf("SMPTE 170M (BT.601)\n"); break;
283 				case 5: printf("SMPTE 240M\n"); break;
284 				default: printf("Invalid (%d)\n", descriptor->matrixCoefficients);
285 			}
286 			break;
287 		}
288 		case VS_OUTPUT_HEADER:
289 		{
290 			const usbvc_output_header_descriptor* descriptor
291 				= (const usbvc_output_header_descriptor*)_descriptor;
292 			printf("VS_OUTPUT_HEADER:\t#fmts=%d,ept=0x%x\n",
293 				descriptor->numFormats, descriptor->endpointAddress);
294 			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
295 			const uint8* controls = descriptor->controls;
296 			for (uint8 i = 0; i < descriptor->numFormats; i++,
297 				controls += descriptor->controlSize) {
298 				printf("\tfmt%d: %s %s %s %s\n", i,
299 					(*controls & 1) ? "wKeyFrameRate" : "",
300 					(*controls & 2) ? "wPFrameRate" : "",
301 					(*controls & 4) ? "wCompQuality" : "",
302 					(*controls & 8) ? "wCompWindowSize" : "");
303 			}
304 			break;
305 		}
306 		case VS_STILL_IMAGE_FRAME:
307 		{
308 			const usbvc_still_image_frame_descriptor* descriptor
309 				= (const usbvc_still_image_frame_descriptor*)_descriptor;
310 			printf("VS_STILL_IMAGE_FRAME:\t#imageSizes=%d,compressions=%d,"
311 				"ept=0x%x\n", descriptor->numImageSizePatterns,
312 				descriptor->NumCompressionPatterns(),
313 				descriptor->endpointAddress);
314 			for (uint8 i = 0; i < descriptor->numImageSizePatterns; i++) {
315 				printf("imageSize%d: %dx%d\n", i,
316 					descriptor->imageSizePatterns[i].width,
317 					descriptor->imageSizePatterns[i].height);
318 			}
319 			for (uint8 i = 0; i < descriptor->NumCompressionPatterns(); i++) {
320 				printf("compression%d: %d\n", i,
321 					descriptor->CompressionPatterns()[i]);
322 			}
323 			break;
324 		}
325 		case VS_FORMAT_MJPEG:
326 		{
327 			const usbvc_format_descriptor* descriptor
328 				= (const usbvc_format_descriptor*)_descriptor;
329 			fMJPEGFormatIndex = descriptor->formatIndex;
330 			printf("VS_FORMAT_MJPEG:\tbFormatIdx=%d,#frmdesc=%d\n",
331 				descriptor->formatIndex, descriptor->numFrameDescriptors);
332 			printf("\t#flgs=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
333 				descriptor->mjpeg.flags,
334 				descriptor->mjpeg.defaultFrameIndex,
335 				descriptor->mjpeg.aspectRatioX,
336 				descriptor->mjpeg.aspectRatioY);
337 			printf("\tbmInterlaceFlags:\n");
338 			if (descriptor->mjpeg.interlaceFlags & 1)
339 				printf("\tInterlaced stream or variable\n");
340 			printf("\t%d fields per frame\n",
341 				(descriptor->mjpeg.interlaceFlags & 2) ? 1 : 2);
342 			if (descriptor->mjpeg.interlaceFlags & 4)
343 				printf("\tField 1 first\n");
344 			printf("\tField Pattern: ");
345 			switch ((descriptor->mjpeg.interlaceFlags & 0x30) >> 4) {
346 				case 0: printf("Field 1 only\n"); break;
347 				case 1: printf("Field 2 only\n"); break;
348 				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
349 				case 3: printf("Random pattern of fields 1 and 2\n"); break;
350 			}
351 			if (descriptor->mjpeg.copyProtect)
352 				printf("\tRestrict duplication\n");
353 			break;
354 		}
355 		case VS_FORMAT_MPEG2TS:
356 			printf("VS_FORMAT_MPEG2TS:\t\n");
357 			break;
358 		case VS_FORMAT_DV:
359 			printf("VS_FORMAT_DV:\t\n");
360 			break;
361 		case VS_FORMAT_FRAME_BASED:
362 			printf("VS_FORMAT_FRAME_BASED:\t\n");
363 			break;
364 		case VS_FRAME_FRAME_BASED:
365 			printf("VS_FRAME_FRAME_BASED:\t\n");
366 			break;
367 		case VS_FORMAT_STREAM_BASED:
368 			printf("VS_FORMAT_STREAM_BASED:\t\n");
369 			break;
370 		default:
371 			printf("INVALID STREAM UNIT TYPE=%d!\n",
372 				_descriptor->descriptorSubtype);
373 	}
374 }
375 
376 
377 void
378 UVCCamDevice::_ParseVideoControl(const usbvc_class_descriptor* _descriptor,
379 	size_t len)
380 {
381 	switch (_descriptor->descriptorSubtype) {
382 		case VC_HEADER:
383 		{
384 			if (fHeaderDescriptor != NULL) {
385 				printf("ERROR: multiple VC_HEADER! Skipping...\n");
386 				break;
387 			}
388 			fHeaderDescriptor = (usbvc_interface_header_descriptor*)malloc(len);
389 			memcpy(fHeaderDescriptor, _descriptor, len);
390 			printf("VC_HEADER:\tUVC v%x.%02x, clk %.5f MHz\n",
391 				fHeaderDescriptor->version >> 8,
392 				fHeaderDescriptor->version & 0xff,
393 				fHeaderDescriptor->clockFrequency / 1000000.0);
394 			for (uint8 i = 0; i < fHeaderDescriptor->numInterfacesNumbers; i++) {
395 				printf("\tStreaming Interface %d\n",
396 					fHeaderDescriptor->interfaceNumbers[i]);
397 			}
398 			break;
399 		}
400 		case VC_INPUT_TERMINAL:
401 		{
402 			const usbvc_input_terminal_descriptor* descriptor
403 				= (const usbvc_input_terminal_descriptor*)_descriptor;
404 			printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
405 				"%d\n", descriptor->terminalID, descriptor->terminalType,
406 				descriptor->associatedTerminal);
407 			printf("\tDesc: %s\n",
408 				fDevice->DecodeStringDescriptor(descriptor->terminal));
409 			if (descriptor->terminalType == 0x201) {
410 				const usbvc_camera_terminal_descriptor* desc
411 					= (const usbvc_camera_terminal_descriptor*)descriptor;
412 				printf("\tObjectiveFocalLength Min/Max %d/%d\n",
413 					desc->objectiveFocalLengthMin,
414 					desc->objectiveFocalLengthMax);
415 				printf("\tOcularFocalLength %d\n", desc->ocularFocalLength);
416 				printf("\tControlSize %d\n", desc->controlSize);
417 			}
418 			break;
419 		}
420 		case VC_OUTPUT_TERMINAL:
421 		{
422 			const usbvc_output_terminal_descriptor* descriptor
423 				= (const usbvc_output_terminal_descriptor*)_descriptor;
424 			printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
425 				"%d, src id=%d\n", descriptor->terminalID,
426 				descriptor->terminalType, descriptor->associatedTerminal,
427 				descriptor->sourceID);
428 			printf("\tDesc: %s\n",
429 				fDevice->DecodeStringDescriptor(descriptor->terminal));
430 			break;
431 		}
432 		case VC_SELECTOR_UNIT:
433 		{
434 			const usbvc_selector_unit_descriptor* descriptor
435 				= (const usbvc_selector_unit_descriptor*)_descriptor;
436 			printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n",
437 				descriptor->unitID, descriptor->numInputPins);
438 			printf("\t");
439 			for (uint8 i = 0; i < descriptor->numInputPins; i++)
440 				printf("%d ", descriptor->sourceID[i]);
441 			printf("\n");
442 			printf("\tDesc: %s\n",
443 				fDevice->DecodeStringDescriptor(descriptor->Selector()));
444 			break;
445 		}
446 		case VC_PROCESSING_UNIT:
447 		{
448 			const usbvc_processing_unit_descriptor* descriptor
449 				= (const usbvc_processing_unit_descriptor*)_descriptor;
450 			fControlRequestIndex = fControlIndex + (descriptor->unitID << 8);
451 			printf("VC_PROCESSING_UNIT:\t unit id=%d,src id=%d, digmul=%d\n",
452 				descriptor->unitID, descriptor->sourceID,
453 				descriptor->maxMultiplier);
454 			printf("\tbControlSize=%d\n", descriptor->controlSize);
455 			if (descriptor->controlSize >= 1) {
456 				if (descriptor->controls[0] & 1)
457 					printf("\tBrightness\n");
458 				if (descriptor->controls[0] & 2)
459 					printf("\tContrast\n");
460 				if (descriptor->controls[0] & 4)
461 					printf("\tHue\n");
462 				if (descriptor->controls[0] & 8)
463 					printf("\tSaturation\n");
464 				if (descriptor->controls[0] & 16)
465 					printf("\tSharpness\n");
466 				if (descriptor->controls[0] & 32)
467 					printf("\tGamma\n");
468 				if (descriptor->controls[0] & 64)
469 					printf("\tWhite Balance Temperature\n");
470 				if (descriptor->controls[0] & 128)
471 					printf("\tWhite Balance Component\n");
472 			}
473 			if (descriptor->controlSize >= 2) {
474 				if (descriptor->controls[1] & 1)
475 					printf("\tBacklight Compensation\n");
476 				if (descriptor->controls[1] & 2)
477 					printf("\tGain\n");
478 				if (descriptor->controls[1] & 4)
479 					printf("\tPower Line Frequency\n");
480 				if (descriptor->controls[1] & 8)
481 					printf("\t[AUTO] Hue\n");
482 				if (descriptor->controls[1] & 16)
483 					printf("\t[AUTO] White Balance Temperature\n");
484 				if (descriptor->controls[1] & 32)
485 					printf("\t[AUTO] White Balance Component\n");
486 				if (descriptor->controls[1] & 64)
487 					printf("\tDigital Multiplier\n");
488 				if (descriptor->controls[1] & 128)
489 					printf("\tDigital Multiplier Limit\n");
490 			}
491 			if (descriptor->controlSize >= 3) {
492 				if (descriptor->controls[2] & 1)
493 					printf("\tAnalog Video Standard\n");
494 				if (descriptor->controls[2] & 2)
495 					printf("\tAnalog Video Lock Status\n");
496 			}
497 			printf("\tDesc: %s\n",
498 				fDevice->DecodeStringDescriptor(descriptor->Processing()));
499 			if (descriptor->VideoStandards() & 2)
500 				printf("\tNTSC  525/60\n");
501 			if (descriptor->VideoStandards() & 4)
502 				printf("\tPAL   625/50\n");
503 			if (descriptor->VideoStandards() & 8)
504 				printf("\tSECAM 625/50\n");
505 			if (descriptor->VideoStandards() & 16)
506 				printf("\tNTSC  625/50\n");
507 			if (descriptor->VideoStandards() & 32)
508 				printf("\tPAL   525/60\n");
509 			break;
510 		}
511 		case VC_EXTENSION_UNIT:
512 		{
513 			const usbvc_extension_unit_descriptor* descriptor
514 				= (const usbvc_extension_unit_descriptor*)_descriptor;
515 			printf("VC_EXTENSION_UNIT:\tid=%d, guid=", descriptor->unitID);
516 			print_guid(descriptor->guidExtensionCode);
517 			printf("\n\t#ctrls=%d, #pins=%d\n", descriptor->numControls,
518 				descriptor->numInputPins);
519 			printf("\t");
520 			for (uint8 i = 0; i < descriptor->numInputPins; i++)
521 				printf("%d ", descriptor->sourceID[i]);
522 			printf("\n");
523 			printf("\tDesc: %s\n",
524 				fDevice->DecodeStringDescriptor(descriptor->Extension()));
525 			break;
526 		}
527 		default:
528 			printf("Unknown control %d\n", _descriptor->descriptorSubtype);
529 	}
530 }
531 
532 
533 bool
534 UVCCamDevice::SupportsIsochronous()
535 {
536 	return true;
537 }
538 
539 
540 status_t
541 UVCCamDevice::StartTransfer()
542 {
543 	if (_ProbeCommitFormat() != B_OK || _SelectBestAlternate() != B_OK)
544 		return B_ERROR;
545 	return CamDevice::StartTransfer();
546 }
547 
548 
549 status_t
550 UVCCamDevice::StopTransfer()
551 {
552 	_SelectIdleAlternate();
553 	return CamDevice::StopTransfer();
554 }
555 
556 
557 status_t
558 UVCCamDevice::SuggestVideoFrame(uint32& width, uint32& height)
559 {
560 	printf("UVCCamDevice::SuggestVideoFrame(%ld, %ld)\n", width, height);
561 	// As in AcceptVideoFrame(), the suggestion should probably just be the
562 	// first advertised uncompressed format, but current applications prefer
563 	// 320x240, so this is tried first here as a suggestion.
564 	width = 320;
565 	height = 240;
566 	if (!AcceptVideoFrame(width, height)) {
567 		const usbvc_frame_descriptor* descriptor
568 			= (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
569 		width  = (*descriptor).width;
570 		height = (*descriptor).height;
571 	}
572 	return B_OK;
573 }
574 
575 
576 status_t
577 UVCCamDevice::AcceptVideoFrame(uint32& width, uint32& height)
578 {
579 	printf("UVCCamDevice::AcceptVideoFrame(%ld, %ld)\n", width, height);
580 	if (width <= 0 || height <= 0) {
581 		// Uncomment below when applications support dimensions other than 320x240
582 		// This code selects the first listed available uncompressed frame format
583 		/*
584 		const usbvc_frame_descriptor* descriptor
585 			= (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
586 		width = (*descriptor).width;
587 		height = (*descriptor).height;
588 		SetVideoFrame(BRect(0, 0, width - 1, height - 1));
589 		return B_OK;
590 		*/
591 
592 		width  = 320;
593 		height = 240;
594 	}
595 
596 	for (int i = 0; i<fUncompressedFrames.CountItems(); i++) {
597 		const usbvc_frame_descriptor* descriptor
598 			= (const usbvc_frame_descriptor*)fUncompressedFrames.ItemAt(i);
599 		if ((*descriptor).width == width && (*descriptor).height == height) {
600 			fUncompressedFrameIndex = i;
601 			SetVideoFrame(BRect(0, 0, width - 1, height - 1));
602 			return B_OK;
603 		}
604 	}
605 
606 	fprintf(stderr, "UVCCamDevice::AcceptVideoFrame() Invalid frame dimensions"
607 		"\n");
608 	return B_ERROR;
609 }
610 
611 
612 status_t
613 UVCCamDevice::_ProbeCommitFormat()
614 {
615 	printf("UVCCamDevice::_ProbeCommitFormat()\n");
616 	printf("UVCCamDevice::fStreamingIndex = %ld\n", fStreamingIndex);
617 
618 	/*
619 	char error;
620 	printf("BEFORE ERROR CODE CHECK.\n");
621 	fDevice->ControlTransfer(
622 			USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_CUR,
623 			VS_STREAM_ERROR_CODE_CONTROL << 8, fStreamingIndex, 1, &error);
624 	printf("Error code = Ox%x\n", error);
625 	*/
626 
627 	usbvc_probecommit request;
628 	memset(&request, 0, sizeof(request));
629 	request.hint = 1;
630 	request.SetFrameInterval(333333);
631 	request.formatIndex = fUncompressedFormatIndex;
632 	request.frameIndex = fUncompressedFrameIndex;
633 	size_t length = fHeaderDescriptor->version > 0x100 ? 34 : 26;
634 	size_t actualLength = fDevice->ControlTransfer(
635 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
636 		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
637 	if (actualLength != length) {
638 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SET_CUR ProbeControl1"
639 			" failed %ld\n", actualLength);
640 		return B_ERROR;
641 	}
642 
643 	/*
644 	usbvc_probecommit response;
645 	actualLength = fDevice->ControlTransfer(
646 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_MAX,
647 		VS_PROBE_CONTROL << 8, fStreamingIndex, sizeof(response), &response);
648 	if (actualLength != sizeof(response)) {
649 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() GetMax ProbeControl"
650 			" failed\n");
651 		return B_ERROR;
652 	}
653 
654 	printf("usbvc_probecommit response.compQuality %d\n", response.compQuality);
655 	request.compQuality = response.compQuality;
656 	*/
657 
658 
659 	usbvc_probecommit response;
660 	memset(&response, 0, sizeof(response));
661 	actualLength = fDevice->ControlTransfer(
662 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_CUR,
663 		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &response);
664 
665 	/*
666 	actualLength = fDevice->ControlTransfer(
667 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
668 		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
669 	if (actualLength != length) {
670 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur ProbeControl2"
671 			" failed\n");
672 		return B_ERROR;
673 	}
674 	*/
675 
676 	actualLength = fDevice->ControlTransfer(
677 		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
678 		VS_COMMIT_CONTROL << 8, fStreamingIndex, length, &request);
679 	if (actualLength != length) {
680 		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur CommitControl"
681 			" failed\n");
682 		return B_ERROR;
683 	}
684 
685 
686 	fMaxVideoFrameSize = response.maxVideoFrameSize;
687 	fMaxPayloadTransferSize = response.maxPayloadTransferSize;
688 	printf("usbvc_probecommit setup done maxVideoFrameSize:%ld"
689 		" maxPayloadTransferSize:%ld\n", fMaxVideoFrameSize,
690 		fMaxPayloadTransferSize);
691 
692 	printf("UVCCamDevice::_ProbeCommitFormat()\n --> SUCCESSFUL\n");
693 	return B_OK;
694 }
695 
696 
697 status_t
698 UVCCamDevice::_SelectBestAlternate()
699 {
700 	printf("UVCCamDevice::_SelectBestAlternate()\n");
701 	const BUSBConfiguration* config = fDevice->ActiveConfiguration();
702 	const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
703 	if (streaming == NULL)
704 		return B_BAD_INDEX;
705 
706 	uint32 bestBandwidth = 0;
707 	uint32 alternateIndex = 0;
708 	uint32 endpointIndex = 0;
709 
710 	for (uint32 i = 0; i < streaming->CountAlternates(); i++) {
711 		const BUSBInterface* alternate = streaming->AlternateAt(i);
712 		for (uint32 j = 0; j < alternate->CountEndpoints(); j++) {
713 			const BUSBEndpoint* endpoint = alternate->EndpointAt(j);
714 			if (!endpoint->IsIsochronous() || !endpoint->IsInput())
715 				continue;
716 			if (fMaxPayloadTransferSize > endpoint->MaxPacketSize())
717 				continue;
718 			if (bestBandwidth != 0
719 				&& bestBandwidth < endpoint->MaxPacketSize())
720 				continue;
721 			bestBandwidth = endpoint->MaxPacketSize();
722 			endpointIndex = j;
723 			alternateIndex = i;
724 		}
725 	}
726 
727 	if (bestBandwidth == 0) {
728 		fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
729 			" couldn't find a valid alternate\n");
730 		return B_ERROR;
731 	}
732 
733 	printf("UVCCamDevice::_SelectBestAlternate() %ld\n", bestBandwidth);
734 	if (((BUSBInterface*)streaming)->SetAlternate(alternateIndex) != B_OK) {
735 		fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
736 			" selecting alternate failed\n");
737 		return B_ERROR;
738 	}
739 
740 	fIsoIn = streaming->EndpointAt(endpointIndex);
741 
742 	return B_OK;
743 }
744 
745 
746 status_t
747 UVCCamDevice::_SelectIdleAlternate()
748 {
749 	printf("UVCCamDevice::_SelectIdleAlternate()\n");
750 	const BUSBConfiguration* config = fDevice->ActiveConfiguration();
751 	const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
752 	if (streaming == NULL)
753 		return B_BAD_INDEX;
754 	if (((BUSBInterface*)streaming)->SetAlternate(0) != B_OK) {
755 		fprintf(stderr, "UVCCamDevice::_SelectIdleAlternate()"
756 			" selecting alternate failed\n");
757 		return B_ERROR;
758 	}
759 
760 	fIsoIn = NULL;
761 
762 	return B_OK;
763 }
764 
765 
766 void
767 UVCCamDevice::_AddProcessingParameter(BParameterGroup* group,
768 	int32 index, const usbvc_processing_unit_descriptor* descriptor)
769 {
770 	BParameterGroup* subgroup;
771 	BContinuousParameter* p;
772 	uint16 wValue = 0; // Control Selector
773 	float minValue = 0.0;
774 	float maxValue = 100.0;
775 	if (descriptor->controlSize >= 1) {
776 		if (descriptor->controls[0] & 1) {
777 			// debug_printf("\tBRIGHTNESS\n");
778 			fBrightness = _AddParameter(group, &subgroup, index,
779 				PU_BRIGHTNESS_CONTROL, "Brightness");
780 		}
781 		if (descriptor->controls[0] & 2) {
782 			// debug_printf("\tCONSTRAST\n");
783 			fContrast = _AddParameter(group, &subgroup, index + 1,
784 				PU_CONTRAST_CONTROL, "Contrast");
785 		}
786 		if (descriptor->controls[0] & 4) {
787 			// debug_printf("\tHUE\n");
788 			fHue = _AddParameter(group, &subgroup, index + 2,
789 				PU_HUE_CONTROL, "Hue");
790 			if (descriptor->controlSize >= 2) {
791 				if (descriptor->controls[1] & 8) {
792 					fHueAuto = _AddAutoParameter(subgroup, index + 3,
793 						PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
794 				}
795 			}
796 		}
797 		if (descriptor->controls[0] & 8) {
798 			// debug_printf("\tSATURATION\n");
799 			fSaturation = _AddParameter(group, &subgroup, index + 4,
800 				PU_SATURATION_CONTROL, "Saturation");
801 		}
802 		if (descriptor->controls[0] & 16) {
803 			// debug_printf("\tSHARPNESS\n");
804 			fSharpness = _AddParameter(group, &subgroup, index + 5,
805 				PU_SHARPNESS_CONTROL, "Sharpness");
806 		}
807 		if (descriptor->controls[0] & 32) {
808 			// debug_printf("\tGamma\n");
809 			fGamma = _AddParameter(group, &subgroup, index + 6,
810 				PU_GAMMA_CONTROL, "Gamma");
811 		}
812 		if (descriptor->controls[0] & 64) {
813 			// debug_printf("\tWHITE BALANCE TEMPERATURE\n");
814 			fWBTemp = _AddParameter(group, &subgroup, index + 7,
815 				PU_WHITE_BALANCE_TEMPERATURE_CONTROL, "WB Temperature");
816 			if (descriptor->controlSize >= 2) {
817 				if (descriptor->controls[1] & 16) {
818 					fWBTempAuto = _AddAutoParameter(subgroup, index + 8,
819 						PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
820 				}
821 			}
822 		}
823 		if (descriptor->controls[0] & 128) {
824 			// debug_printf("\tWhite Balance Component\n");
825 			fWBComponent = _AddParameter(group, &subgroup, index + 9,
826 				PU_WHITE_BALANCE_COMPONENT_CONTROL, "WB Component");
827 			if (descriptor->controlSize >= 2) {
828 				if (descriptor->controls[1] & 32) {
829 					fWBTempAuto = _AddAutoParameter(subgroup, index + 10,
830 						PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL);
831 				}
832 			}
833 		}
834 	}
835 	if (descriptor->controlSize >= 2) {
836 		if (descriptor->controls[1] & 1) {
837 			// debug_printf("\tBACKLIGHT COMPENSATION\n");
838 			int16 data;
839 			wValue = PU_BACKLIGHT_COMPENSATION_CONTROL << 8;
840 			fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
841 				GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data);
842 			maxValue = (float)data;
843 			fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
844 				GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data);
845 			minValue = (float)data;
846 			fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
847 				GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data);
848 			fBacklightCompensation = (float)data;
849 			subgroup = group->MakeGroup("Backlight Compensation");
850 			if (maxValue - minValue == 1) { // Binary Switch
851 				fBinaryBacklightCompensation = true;
852 				subgroup->MakeDiscreteParameter(index + 11,
853 					B_MEDIA_RAW_VIDEO, "Backlight Compensation",
854 					B_ENABLE);
855 			} else { // Range of values
856 				fBinaryBacklightCompensation = false;
857 				p = subgroup->MakeContinuousParameter(index + 11,
858 				B_MEDIA_RAW_VIDEO, "Backlight Compensation",
859 				B_GAIN, "", minValue, maxValue, 1.0 / (maxValue - minValue));
860 			}
861 		}
862 		if (descriptor->controls[1] & 2) {
863 			// debug_printf("\tGAIN\n");
864 			fGain = _AddParameter(group, &subgroup, index + 12, PU_GAIN_CONTROL,
865 				"Gain");
866 		}
867 		if (descriptor->controls[1] & 4) {
868 			// debug_printf("\tPOWER LINE FREQUENCY\n");
869 			wValue = PU_POWER_LINE_FREQUENCY_CONTROL << 8;
870 			int8 data;
871 			if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
872 				GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data) == sizeof(data)) {
873 				fPowerlineFrequency = data;
874 			}
875 			subgroup = group->MakeGroup("Power Line Frequency");
876 			p = subgroup->MakeContinuousParameter(index + 13,
877 				B_MEDIA_RAW_VIDEO, "Frequency", B_GAIN, "", 0, 60.0, 1.0 / 60.0);
878 		}
879 		// TODO Determine whether controls apply to these
880 		/*
881 		if (descriptor->controls[1] & 64)
882 			debug_printf("\tDigital Multiplier\n");
883 		if (descriptor->controls[1] & 128)
884 			debug_printf("\tDigital Multiplier Limit\n");
885 		*/
886 	}
887 	// TODO Determine whether controls apply to these
888 	/*
889 	if (descriptor->controlSize >= 3) {
890 		if (descriptor->controls[2] & 1)
891 			debug_printf("\tAnalog Video Standard\n");
892 		if (descriptor->controls[2] & 2)
893 			debug_printf("\tAnalog Video Lock Status\n");
894 	}
895 	*/
896 
897 }
898 
899 
900 
901 float
902 UVCCamDevice::_AddParameter(BParameterGroup* group,
903 	BParameterGroup** subgroup, int32 index, uint16 wValue, const char* name)
904 {
905 	float minValue = 0.0;
906 	float maxValue = 100.0;
907 	float currValue = 0.0;
908 	int16 data;
909 
910 	wValue <<= 8;
911 
912 	if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
913 		GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data)
914 		== sizeof(data)) {
915 		maxValue = (float)data;
916 	}
917 	if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
918 		GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data)
919 		== sizeof(data)) {
920 		minValue = (float)data;
921 	}
922 	if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
923 		GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
924 		== sizeof(data)) {
925 		currValue = (float)data;
926 	}
927 
928 	*subgroup = group->MakeGroup(name);
929 	BContinuousParameter* p = (*subgroup)->MakeContinuousParameter(index,
930 		B_MEDIA_RAW_VIDEO, name, B_GAIN, "", minValue, maxValue,
931 		1.0 / (maxValue - minValue));
932 	return currValue;
933 }
934 
935 
936 uint8
937 UVCCamDevice::_AddAutoParameter(BParameterGroup* subgroup, int32 index,
938 	uint16 wValue)
939 {
940 	uint8 data;
941 	wValue <<= 8;
942 
943 	fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
944 		GET_CUR, wValue, fControlRequestIndex, 1, &data);
945 	subgroup->MakeDiscreteParameter(index, B_MEDIA_RAW_VIDEO, "Auto",
946 		B_ENABLE);
947 
948 	return data;
949 }
950 
951 
952 void
953 UVCCamDevice::AddParameters(BParameterGroup* group, int32& index)
954 {
955 	printf("UVCCamDevice::AddParameters()\n");
956 	fFirstParameterID = index;
957 //	debug_printf("fIndex = %d\n",fIndex);
958 	CamDevice::AddParameters(group, index);
959 
960 	const BUSBConfiguration* config;
961 	const BUSBInterface* interface;
962 	uint8 buffer[1024];
963 
964 	usb_descriptor* generic = (usb_descriptor*)buffer;
965 
966 	for (uint32 i = 0; i < fDevice->CountConfigurations(); i++) {
967 		config = fDevice->ConfigurationAt(i);
968 		if (config == NULL)
969 			continue;
970 		fDevice->SetConfiguration(config);
971 		for (uint32 j = 0; j < config->CountInterfaces(); j++) {
972 			interface = config->InterfaceAt(j);
973 			if (interface == NULL)
974 				continue;
975 			if (interface->Class() != CC_VIDEO || interface->Subclass()
976 				!= SC_VIDEOCONTROL)
977 				continue;
978 			for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
979 				sizeof(buffer)) == B_OK; k++) {
980 				if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
981 					| USB_DESCRIPTOR_INTERFACE))
982 					continue;
983 
984 				if (((const usbvc_class_descriptor*)generic)->descriptorSubtype
985 					== VC_PROCESSING_UNIT) {
986 					_AddProcessingParameter(group, index,
987 						(const usbvc_processing_unit_descriptor*)generic);
988 				}
989 			}
990 		}
991 	}
992 }
993 
994 
995 status_t
996 UVCCamDevice::GetParameterValue(int32 id, bigtime_t* last_change, void* value,
997 	size_t* size)
998 {
999 	printf("UVCCAmDevice::GetParameterValue(%ld)\n", id - fFirstParameterID);
1000 	float* currValue;
1001 	int* currValueInt;
1002 	int16 data;
1003 	uint16 wValue = 0;
1004 	switch (id - fFirstParameterID) {
1005 		case 0:
1006 			// debug_printf("\tBrightness:\n");
1007 			// debug_printf("\tValue = %f\n",fBrightness);
1008 			*size = sizeof(float);
1009 			currValue = (float*)value;
1010 			*currValue = fBrightness;
1011 			*last_change = fLastParameterChanges;
1012 			return B_OK;
1013 		case 1:
1014 			// debug_printf("\tContrast:\n");
1015 			// debug_printf("\tValue = %f\n",fContrast);
1016 			*size = sizeof(float);
1017 			currValue = (float*)value;
1018 			*currValue = fContrast;
1019 			*last_change = fLastParameterChanges;
1020 			return B_OK;
1021 		case 2:
1022 			// debug_printf("\tHue:\n");
1023 			// debug_printf("\tValue = %f\n",fHue);
1024 			*size = sizeof(float);
1025 			currValue = (float*)value;
1026 			*currValue = fHue;
1027 			*last_change = fLastParameterChanges;
1028 			return B_OK;
1029 		case 4:
1030 			// debug_printf("\tSaturation:\n");
1031 			// debug_printf("\tValue = %f\n",fSaturation);
1032 			*size = sizeof(float);
1033 			currValue = (float*)value;
1034 			*currValue = fSaturation;
1035 			*last_change = fLastParameterChanges;
1036 			return B_OK;
1037 		case 5:
1038 			// debug_printf("\tSharpness:\n");
1039 			// debug_printf("\tValue = %f\n",fSharpness);
1040 			*size = sizeof(float);
1041 			currValue = (float*)value;
1042 			*currValue = fSharpness;
1043 			*last_change = fLastParameterChanges;
1044 			return B_OK;
1045 		case 7:
1046 			// debug_printf("\tWB Temperature:\n");
1047 			*size = sizeof(float);
1048 			currValue = (float*)value;
1049 			wValue = PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8;
1050 			if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
1051 				GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
1052 				== sizeof(data)) {
1053 				fWBTemp = (float)data;
1054 			}
1055 			// debug_printf("\tValue = %f\n",fWBTemp);
1056 			*currValue = fWBTemp;
1057 			*last_change = fLastParameterChanges;
1058 			return B_OK;
1059 		case 8:
1060 			// debug_printf("\tWB Temperature Auto:\n");
1061 			// debug_printf("\tValue = %d\n",fWBTempAuto);
1062 			*size = sizeof(int);
1063 			currValueInt = ((int*)value);
1064 			*currValueInt = fWBTempAuto;
1065 			*last_change = fLastParameterChanges;
1066 			return B_OK;
1067 		case 11:
1068 			if (!fBinaryBacklightCompensation) {
1069 				// debug_printf("\tBacklight Compensation:\n");
1070 				// debug_printf("\tValue = %f\n",fBacklightCompensation);
1071 				*size = sizeof(float);
1072 				currValue = (float*)value;
1073 				*currValue = fBacklightCompensation;
1074 				*last_change = fLastParameterChanges;
1075 			} else {
1076 				// debug_printf("\tBacklight Compensation:\n");
1077 				// debug_printf("\tValue = %d\n",fBacklightCompensationBinary);
1078 				currValueInt = (int*)value;
1079 				*currValueInt = fBacklightCompensationBinary;
1080 				*last_change = fLastParameterChanges;
1081 			}
1082 			return B_OK;
1083 		case 12:
1084 			// debug_printf("\tGain:\n");
1085 			// debug_printf("\tValue = %f\n",fGain);
1086 			*size = sizeof(float);
1087 			currValue = (float*)value;
1088 			*currValue = fGain;
1089 			*last_change = fLastParameterChanges;
1090 			return B_OK;
1091 		case 13:
1092 			// debug_printf("\tPowerline Frequency:\n");
1093 			// debug_printf("\tValue = %d\n",fPowerlineFrequency);
1094 			*size = sizeof(float);
1095 			currValue = (float*)value;
1096 			switch (fPowerlineFrequency) {
1097 				case 0:
1098 					*currValue = 0.0;
1099 					break;
1100 				case 1:
1101 					*currValue = 50.0;
1102 					break;
1103 				case 2:
1104 					*currValue = 60.0;
1105 					break;
1106 			}
1107 			*last_change = fLastParameterChanges;
1108 			return B_OK;
1109 
1110 	}
1111 	return B_BAD_VALUE;
1112 }
1113 
1114 
1115 status_t
1116 UVCCamDevice::SetParameterValue(int32 id, bigtime_t when, const void* value,
1117 	size_t size)
1118 {
1119 	printf("UVCCamDevice::SetParameterValue(%ld)\n", id - fFirstParameterID);
1120 	switch (id - fFirstParameterID) {
1121 		case 0:
1122 			// debug_printf("\tBrightness:\n");
1123 			if (!value || (size != sizeof(float)))
1124 				return B_BAD_VALUE;
1125 			fBrightness = *((float*)value);
1126 			fLastParameterChanges = when;
1127 			return _SetParameterValue(PU_BRIGHTNESS_CONTROL, (int16)fBrightness);
1128 		case 1:
1129 			// debug_printf("\tContrast:\n");
1130 			if (!value || (size != sizeof(float)))
1131 				return B_BAD_VALUE;
1132 			fContrast = *((float*)value);
1133 			fLastParameterChanges = when;
1134 			return _SetParameterValue(PU_CONTRAST_CONTROL, (int16)fContrast);
1135 		case 2:
1136 			// debug_printf("\tHue:\n");
1137 			if (!value || (size != sizeof(float)))
1138 				return B_BAD_VALUE;
1139 			fHue = *((float*)value);
1140 			fLastParameterChanges = when;
1141 			return _SetParameterValue(PU_HUE_CONTROL, (int16)fHue);
1142 		case 4:
1143 			// debug_printf("\tSaturation:\n");
1144 			if (!value || (size != sizeof(float)))
1145 				return B_BAD_VALUE;
1146 			fSaturation = *((float*)value);
1147 			fLastParameterChanges = when;
1148 			return _SetParameterValue(PU_SATURATION_CONTROL, (int16)fSaturation);
1149 		case 5:
1150 			// debug_printf("\tSharpness:\n");
1151 			if (!value || (size != sizeof(float)))
1152 				return B_BAD_VALUE;
1153 			fSharpness = *((float*)value);
1154 			fLastParameterChanges = when;
1155 			return _SetParameterValue(PU_SHARPNESS_CONTROL, (int16)fSharpness);
1156 		case 7:
1157 			if (fWBTempAuto)
1158 				return B_OK;
1159 			// debug_printf("\tWB Temperature:\n");
1160 			if (!value || (size != sizeof(float)))
1161 				return B_BAD_VALUE;
1162 			fWBTemp = *((float*)value);
1163 			fLastParameterChanges = when;
1164 			return _SetParameterValue(PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
1165 				(int16)fWBTemp);
1166 		case 8:
1167 			// debug_printf("\tWB Temperature Auto:\n");
1168 			if (!value || (size != sizeof(int)))
1169 				return B_BAD_VALUE;
1170 			fWBTempAuto = *((int*)value);
1171 			fLastParameterChanges = when;
1172 			return _SetParameterValue(
1173 				PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, (int8)fWBTempAuto);
1174 		case 11:
1175 			if (!fBinaryBacklightCompensation) {
1176 				// debug_printf("\tBacklight Compensation:\n");
1177 				if (!value || (size != sizeof(float)))
1178 					return B_BAD_VALUE;
1179 				fBacklightCompensation = *((float*)value);
1180 			} else {
1181 				// debug_printf("\tBacklight Compensation:\n");
1182 				if (!value || (size != sizeof(int)))
1183 					return B_BAD_VALUE;
1184 				fBacklightCompensationBinary = *((int*)value);
1185 			}
1186 			fLastParameterChanges = when;
1187 			return _SetParameterValue(PU_BACKLIGHT_COMPENSATION_CONTROL,
1188 				(int16)fBacklightCompensationBinary);
1189 		case 12:
1190 			// debug_printf("\tGain:\n");
1191 			if (!value || (size != sizeof(float)))
1192 				return B_BAD_VALUE;
1193 			fGain = *((float*)value);
1194 			fLastParameterChanges = when;
1195 			return _SetParameterValue(PU_GAIN_CONTROL, (int16)fGain);
1196 		case 13:
1197 			// debug_printf("\tPowerline Frequency:\n");
1198 			// debug_printf("\tValue = %f\n",*((float*)value));
1199 			if (!value || (size != sizeof(float)))
1200 				return B_BAD_VALUE;
1201 			float inValue = *((float*)value);
1202 			fPowerlineFrequency = 0;
1203 			if (inValue > 45.0 && inValue < 55.0) {
1204 				fPowerlineFrequency = 1;
1205 			}
1206 			if (inValue >= 55.0) {
1207 				fPowerlineFrequency = 2;
1208 			}
1209 			fLastParameterChanges = when;
1210 			return _SetParameterValue(PU_POWER_LINE_FREQUENCY_CONTROL,
1211 				(int8)fPowerlineFrequency);
1212 
1213 	}
1214 	return B_BAD_VALUE;
1215 }
1216 
1217 
1218 status_t
1219 UVCCamDevice::_SetParameterValue(uint16 wValue, int16 setValue)
1220 {
1221 	return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1222 		| USB_REQTYPE_INTERFACE_OUT, SET_CUR, wValue << 8, fControlRequestIndex,
1223 		sizeof(setValue), &setValue)) == sizeof(setValue);
1224 }
1225 
1226 
1227 status_t
1228 UVCCamDevice::_SetParameterValue(uint16 wValue, int8 setValue)
1229 {
1230 	return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1231 		| USB_REQTYPE_INTERFACE_OUT, SET_CUR, wValue << 8, fControlRequestIndex,
1232 		sizeof(setValue), &setValue)) == sizeof(setValue);
1233 }
1234 
1235 
1236 status_t
1237 UVCCamDevice::FillFrameBuffer(BBuffer* buffer, bigtime_t* stamp)
1238 {
1239 	memset(buffer->Data(), 0, buffer->SizeAvailable());
1240 	status_t err = fDeframer->WaitFrame(2000000);
1241 	if (err < B_OK) {
1242 		fprintf(stderr, "WaitFrame: %lx\n", err);
1243 		return err;
1244 	}
1245 
1246 	CamFrame* f;
1247 	err = fDeframer->GetFrame(&f, stamp);
1248 	if (err < B_OK) {
1249 		fprintf(stderr, "GetFrame: %lx\n", err);
1250 		return err;
1251 	}
1252 
1253 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
1254 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
1255 
1256 	if (buffer->SizeAvailable() >= (size_t)w * h * 4) {
1257 		// TODO: The Video Producer only outputs B_RGB32.  This is OK for most
1258 		// applications.  This could be leveraged if applications can
1259 		// consume B_YUV422.
1260 		_DecodeColor((unsigned char*)buffer->Data(),
1261 			(unsigned char*)f->Buffer(), w, h);
1262 	}
1263 	delete f;
1264 	return B_OK;
1265 }
1266 
1267 
1268 void
1269 UVCCamDevice::_DecodeColor(unsigned char* dst, unsigned char* src,
1270 	int32 width, int32 height)
1271 {
1272 	long int i;
1273 	unsigned char* rawpt, * scanpt;
1274 	long int size;
1275 
1276 	rawpt = src;
1277 	scanpt = dst;
1278 	size = width*height;
1279 
1280 	for ( i = 0; i < size; i++ ) {
1281 	if ( (i/width) % 2 == 0 ) {
1282 		if ( (i % 2) == 0 ) {
1283 		/* B */
1284 		if ( (i > width) && ((i % width) > 0) ) {
1285 			*scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1286 				+ *(rawpt+width-1)+*(rawpt+width+1))/4;	/* R */
1287 			*scanpt++ = (*(rawpt-1)+*(rawpt+1)
1288 				+ *(rawpt+width)+*(rawpt-width))/4;	/* G */
1289 			*scanpt++ = *rawpt;					/* B */
1290 		} else {
1291 			/* first line or left column */
1292 			*scanpt++ = *(rawpt+width+1);		/* R */
1293 			*scanpt++ = (*(rawpt+1)+*(rawpt+width))/2;	/* G */
1294 			*scanpt++ = *rawpt;				/* B */
1295 		}
1296 		} else {
1297 		/* (B)G */
1298 		if ( (i > width) && ((i % width) < (width-1)) ) {
1299 			*scanpt++ = (*(rawpt+width)+*(rawpt-width))/2;	/* R */
1300 			*scanpt++ = *rawpt;					/* G */
1301 			*scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
1302 		} else {
1303 			/* first line or right column */
1304 			*scanpt++ = *(rawpt+width);	/* R */
1305 			*scanpt++ = *rawpt;		/* G */
1306 			*scanpt++ = *(rawpt-1);	/* B */
1307 		}
1308 		}
1309 	} else {
1310 		if ( (i % 2) == 0 ) {
1311 		/* G(R) */
1312 		if ( (i < (width*(height-1))) && ((i % width) > 0) ) {
1313 			*scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
1314 			*scanpt++ = *rawpt;					/* G */
1315 			*scanpt++ = (*(rawpt+width)+*(rawpt-width))/2;	/* B */
1316 		} else {
1317 			/* bottom line or left column */
1318 			*scanpt++ = *(rawpt+1);		/* R */
1319 			*scanpt++ = *rawpt;			/* G */
1320 			*scanpt++ = *(rawpt-width);		/* B */
1321 		}
1322 		} else {
1323 		/* R */
1324 		if ( i < (width*(height-1)) && ((i % width) < (width-1)) ) {
1325 			*scanpt++ = *rawpt;					/* R */
1326 			*scanpt++ = (*(rawpt-1)+*(rawpt+1)
1327 				+ *(rawpt-width)+*(rawpt+width))/4;	/* G */
1328 			*scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1329 				+ *(rawpt+width-1)+*(rawpt+width+1))/4;	/* B */
1330 		} else {
1331 			/* bottom line or right column */
1332 			*scanpt++ = *rawpt;				/* R */
1333 			*scanpt++ = (*(rawpt-1)+*(rawpt-width))/2;	/* G */
1334 			*scanpt++ = *(rawpt-width-1);		/* B */
1335 		}
1336 		}
1337 	}
1338 	rawpt++;
1339 	}
1340 }
1341 
1342 
1343 
1344 
1345 UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)
1346 	: CamDeviceAddon(webcam)
1347 {
1348 	printf("UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)\n");
1349 	SetSupportedDevices(kSupportedDevices);
1350 }
1351 
1352 
1353 UVCCamDeviceAddon::~UVCCamDeviceAddon()
1354 {
1355 }
1356 
1357 
1358 const char *
1359 UVCCamDeviceAddon::BrandName()
1360 {
1361 	printf("UVCCamDeviceAddon::BrandName()\n");
1362 	return "USB Video Class";
1363 }
1364 
1365 
1366 UVCCamDevice *
1367 UVCCamDeviceAddon::Instantiate(CamRoster& roster, BUSBDevice* from)
1368 {
1369 	printf("UVCCamDeviceAddon::Instantiate()\n");
1370 	return new UVCCamDevice(*this, from);
1371 }
1372 
1373 
1374 extern "C" status_t
1375 B_WEBCAM_MKINTFUNC(uvccam)
1376 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
1377 {
1378 	*addon = new UVCCamDeviceAddon(webcam);
1379 	return B_OK;
1380 }
1381