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