xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.cpp (revision 9c274ccd098ee3b2674efde2d1582d4e0c68d878)
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: (%" B_PRIu32 ",%" B_PRIu32 "): 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: (%" B_PRIu32 ",%" B_PRIu32 "): 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=%" B_PRIu32 "/%" B_PRIu32 ", maxbuf=%" B_PRIu32 "\n",
233 				descriptor->width, descriptor->height,
234 				descriptor->minBitRate, descriptor->maxBitRate,
235 				descriptor->maxVideoFrameBufferSize);
236 			printf("\tdefault frame interval: %" B_PRIu32 ", #intervals(0=cont): %d\n",
237 				descriptor->defaultFrameInterval, descriptor->frameIntervalType);
238 			if (descriptor->frameIntervalType == 0) {
239 				printf("min/max frame interval=%" B_PRIu32 "/%" B_PRIu32 ", step=%" B_PRIu32 "\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: %" B_PRIu32 "\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(%" B_PRIu32 ", %" B_PRIu32 ")\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(%" B_PRIu32 ", %" B_PRIu32 ")\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 = %" B_PRIu32 "\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:%" B_PRIu32 ""
689 		" maxPayloadTransferSize:%" B_PRIu32 "\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() %" B_PRIu32 "\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 	uint16 wValue = 0; // Control Selector
772 	float minValue = 0.0;
773 	float maxValue = 100.0;
774 	if (descriptor->controlSize >= 1) {
775 		if (descriptor->controls[0] & 1) {
776 			// debug_printf("\tBRIGHTNESS\n");
777 			fBrightness = _AddParameter(group, &subgroup, index,
778 				PU_BRIGHTNESS_CONTROL, "Brightness");
779 		}
780 		if (descriptor->controls[0] & 2) {
781 			// debug_printf("\tCONSTRAST\n");
782 			fContrast = _AddParameter(group, &subgroup, index + 1,
783 				PU_CONTRAST_CONTROL, "Contrast");
784 		}
785 		if (descriptor->controls[0] & 4) {
786 			// debug_printf("\tHUE\n");
787 			fHue = _AddParameter(group, &subgroup, index + 2,
788 				PU_HUE_CONTROL, "Hue");
789 			if (descriptor->controlSize >= 2) {
790 				if (descriptor->controls[1] & 8) {
791 					fHueAuto = _AddAutoParameter(subgroup, index + 3,
792 						PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
793 				}
794 			}
795 		}
796 		if (descriptor->controls[0] & 8) {
797 			// debug_printf("\tSATURATION\n");
798 			fSaturation = _AddParameter(group, &subgroup, index + 4,
799 				PU_SATURATION_CONTROL, "Saturation");
800 		}
801 		if (descriptor->controls[0] & 16) {
802 			// debug_printf("\tSHARPNESS\n");
803 			fSharpness = _AddParameter(group, &subgroup, index + 5,
804 				PU_SHARPNESS_CONTROL, "Sharpness");
805 		}
806 		if (descriptor->controls[0] & 32) {
807 			// debug_printf("\tGamma\n");
808 			fGamma = _AddParameter(group, &subgroup, index + 6,
809 				PU_GAMMA_CONTROL, "Gamma");
810 		}
811 		if (descriptor->controls[0] & 64) {
812 			// debug_printf("\tWHITE BALANCE TEMPERATURE\n");
813 			fWBTemp = _AddParameter(group, &subgroup, index + 7,
814 				PU_WHITE_BALANCE_TEMPERATURE_CONTROL, "WB Temperature");
815 			if (descriptor->controlSize >= 2) {
816 				if (descriptor->controls[1] & 16) {
817 					fWBTempAuto = _AddAutoParameter(subgroup, index + 8,
818 						PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
819 				}
820 			}
821 		}
822 		if (descriptor->controls[0] & 128) {
823 			// debug_printf("\tWhite Balance Component\n");
824 			fWBComponent = _AddParameter(group, &subgroup, index + 9,
825 				PU_WHITE_BALANCE_COMPONENT_CONTROL, "WB Component");
826 			if (descriptor->controlSize >= 2) {
827 				if (descriptor->controls[1] & 32) {
828 					fWBTempAuto = _AddAutoParameter(subgroup, index + 10,
829 						PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL);
830 				}
831 			}
832 		}
833 	}
834 	if (descriptor->controlSize >= 2) {
835 		if (descriptor->controls[1] & 1) {
836 			// debug_printf("\tBACKLIGHT COMPENSATION\n");
837 			int16 data;
838 			wValue = PU_BACKLIGHT_COMPENSATION_CONTROL << 8;
839 			fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
840 				GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data);
841 			maxValue = (float)data;
842 			fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
843 				GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data);
844 			minValue = (float)data;
845 			fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
846 				GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data);
847 			fBacklightCompensation = (float)data;
848 			subgroup = group->MakeGroup("Backlight Compensation");
849 			if (maxValue - minValue == 1) { // Binary Switch
850 				fBinaryBacklightCompensation = true;
851 				subgroup->MakeDiscreteParameter(index + 11,
852 					B_MEDIA_RAW_VIDEO, "Backlight Compensation",
853 					B_ENABLE);
854 			} else { // Range of values
855 				fBinaryBacklightCompensation = false;
856 				subgroup->MakeContinuousParameter(index + 11,
857 				B_MEDIA_RAW_VIDEO, "Backlight Compensation",
858 				B_GAIN, "", minValue, maxValue, 1.0 / (maxValue - minValue));
859 			}
860 		}
861 		if (descriptor->controls[1] & 2) {
862 			// debug_printf("\tGAIN\n");
863 			fGain = _AddParameter(group, &subgroup, index + 12, PU_GAIN_CONTROL,
864 				"Gain");
865 		}
866 		if (descriptor->controls[1] & 4) {
867 			// debug_printf("\tPOWER LINE FREQUENCY\n");
868 			wValue = PU_POWER_LINE_FREQUENCY_CONTROL << 8;
869 			int8 data;
870 			if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
871 				GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data) == sizeof(data)) {
872 				fPowerlineFrequency = data;
873 			}
874 			subgroup = group->MakeGroup("Power Line Frequency");
875 			subgroup->MakeContinuousParameter(index + 13,
876 				B_MEDIA_RAW_VIDEO, "Frequency", B_GAIN, "", 0, 60.0, 1.0 / 60.0);
877 		}
878 		// TODO Determine whether controls apply to these
879 		/*
880 		if (descriptor->controls[1] & 64)
881 			debug_printf("\tDigital Multiplier\n");
882 		if (descriptor->controls[1] & 128)
883 			debug_printf("\tDigital Multiplier Limit\n");
884 		*/
885 	}
886 	// TODO Determine whether controls apply to these
887 	/*
888 	if (descriptor->controlSize >= 3) {
889 		if (descriptor->controls[2] & 1)
890 			debug_printf("\tAnalog Video Standard\n");
891 		if (descriptor->controls[2] & 2)
892 			debug_printf("\tAnalog Video Lock Status\n");
893 	}
894 	*/
895 
896 }
897 
898 
899 
900 float
901 UVCCamDevice::_AddParameter(BParameterGroup* group,
902 	BParameterGroup** subgroup, int32 index, uint16 wValue, const char* name)
903 {
904 	float minValue = 0.0;
905 	float maxValue = 100.0;
906 	float currValue = 0.0;
907 	int16 data;
908 
909 	wValue <<= 8;
910 
911 	if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
912 		GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data)
913 		== sizeof(data)) {
914 		maxValue = (float)data;
915 	}
916 	if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
917 		GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data)
918 		== sizeof(data)) {
919 		minValue = (float)data;
920 	}
921 	if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
922 		GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
923 		== sizeof(data)) {
924 		currValue = (float)data;
925 	}
926 
927 	*subgroup = group->MakeGroup(name);
928 	(*subgroup)->MakeContinuousParameter(index,
929 		B_MEDIA_RAW_VIDEO, name, B_GAIN, "", minValue, maxValue,
930 		1.0 / (maxValue - minValue));
931 	return currValue;
932 }
933 
934 
935 uint8
936 UVCCamDevice::_AddAutoParameter(BParameterGroup* subgroup, int32 index,
937 	uint16 wValue)
938 {
939 	uint8 data;
940 	wValue <<= 8;
941 
942 	fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
943 		GET_CUR, wValue, fControlRequestIndex, 1, &data);
944 	subgroup->MakeDiscreteParameter(index, B_MEDIA_RAW_VIDEO, "Auto",
945 		B_ENABLE);
946 
947 	return data;
948 }
949 
950 
951 void
952 UVCCamDevice::AddParameters(BParameterGroup* group, int32& index)
953 {
954 	printf("UVCCamDevice::AddParameters()\n");
955 	fFirstParameterID = index;
956 //	debug_printf("fIndex = %d\n",fIndex);
957 	CamDevice::AddParameters(group, index);
958 
959 	const BUSBConfiguration* config;
960 	const BUSBInterface* interface;
961 	uint8 buffer[1024];
962 
963 	usb_descriptor* generic = (usb_descriptor*)buffer;
964 
965 	for (uint32 i = 0; i < fDevice->CountConfigurations(); i++) {
966 		config = fDevice->ConfigurationAt(i);
967 		if (config == NULL)
968 			continue;
969 		fDevice->SetConfiguration(config);
970 		for (uint32 j = 0; j < config->CountInterfaces(); j++) {
971 			interface = config->InterfaceAt(j);
972 			if (interface == NULL)
973 				continue;
974 			if (interface->Class() != CC_VIDEO || interface->Subclass()
975 				!= SC_VIDEOCONTROL)
976 				continue;
977 			for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
978 				sizeof(buffer)) == B_OK; k++) {
979 				if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
980 					| USB_DESCRIPTOR_INTERFACE))
981 					continue;
982 
983 				if (((const usbvc_class_descriptor*)generic)->descriptorSubtype
984 					== VC_PROCESSING_UNIT) {
985 					_AddProcessingParameter(group, index,
986 						(const usbvc_processing_unit_descriptor*)generic);
987 				}
988 			}
989 		}
990 	}
991 }
992 
993 
994 status_t
995 UVCCamDevice::GetParameterValue(int32 id, bigtime_t* last_change, void* value,
996 	size_t* size)
997 {
998 	printf("UVCCAmDevice::GetParameterValue(%" B_PRId32 ")\n", id - fFirstParameterID);
999 	float* currValue;
1000 	int* currValueInt;
1001 	int16 data;
1002 	uint16 wValue = 0;
1003 	switch (id - fFirstParameterID) {
1004 		case 0:
1005 			// debug_printf("\tBrightness:\n");
1006 			// debug_printf("\tValue = %f\n",fBrightness);
1007 			*size = sizeof(float);
1008 			currValue = (float*)value;
1009 			*currValue = fBrightness;
1010 			*last_change = fLastParameterChanges;
1011 			return B_OK;
1012 		case 1:
1013 			// debug_printf("\tContrast:\n");
1014 			// debug_printf("\tValue = %f\n",fContrast);
1015 			*size = sizeof(float);
1016 			currValue = (float*)value;
1017 			*currValue = fContrast;
1018 			*last_change = fLastParameterChanges;
1019 			return B_OK;
1020 		case 2:
1021 			// debug_printf("\tHue:\n");
1022 			// debug_printf("\tValue = %f\n",fHue);
1023 			*size = sizeof(float);
1024 			currValue = (float*)value;
1025 			*currValue = fHue;
1026 			*last_change = fLastParameterChanges;
1027 			return B_OK;
1028 		case 4:
1029 			// debug_printf("\tSaturation:\n");
1030 			// debug_printf("\tValue = %f\n",fSaturation);
1031 			*size = sizeof(float);
1032 			currValue = (float*)value;
1033 			*currValue = fSaturation;
1034 			*last_change = fLastParameterChanges;
1035 			return B_OK;
1036 		case 5:
1037 			// debug_printf("\tSharpness:\n");
1038 			// debug_printf("\tValue = %f\n",fSharpness);
1039 			*size = sizeof(float);
1040 			currValue = (float*)value;
1041 			*currValue = fSharpness;
1042 			*last_change = fLastParameterChanges;
1043 			return B_OK;
1044 		case 7:
1045 			// debug_printf("\tWB Temperature:\n");
1046 			*size = sizeof(float);
1047 			currValue = (float*)value;
1048 			wValue = PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8;
1049 			if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
1050 				GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
1051 				== sizeof(data)) {
1052 				fWBTemp = (float)data;
1053 			}
1054 			// debug_printf("\tValue = %f\n",fWBTemp);
1055 			*currValue = fWBTemp;
1056 			*last_change = fLastParameterChanges;
1057 			return B_OK;
1058 		case 8:
1059 			// debug_printf("\tWB Temperature Auto:\n");
1060 			// debug_printf("\tValue = %d\n",fWBTempAuto);
1061 			*size = sizeof(int);
1062 			currValueInt = ((int*)value);
1063 			*currValueInt = fWBTempAuto;
1064 			*last_change = fLastParameterChanges;
1065 			return B_OK;
1066 		case 11:
1067 			if (!fBinaryBacklightCompensation) {
1068 				// debug_printf("\tBacklight Compensation:\n");
1069 				// debug_printf("\tValue = %f\n",fBacklightCompensation);
1070 				*size = sizeof(float);
1071 				currValue = (float*)value;
1072 				*currValue = fBacklightCompensation;
1073 				*last_change = fLastParameterChanges;
1074 			} else {
1075 				// debug_printf("\tBacklight Compensation:\n");
1076 				// debug_printf("\tValue = %d\n",fBacklightCompensationBinary);
1077 				currValueInt = (int*)value;
1078 				*currValueInt = fBacklightCompensationBinary;
1079 				*last_change = fLastParameterChanges;
1080 			}
1081 			return B_OK;
1082 		case 12:
1083 			// debug_printf("\tGain:\n");
1084 			// debug_printf("\tValue = %f\n",fGain);
1085 			*size = sizeof(float);
1086 			currValue = (float*)value;
1087 			*currValue = fGain;
1088 			*last_change = fLastParameterChanges;
1089 			return B_OK;
1090 		case 13:
1091 			// debug_printf("\tPowerline Frequency:\n");
1092 			// debug_printf("\tValue = %d\n",fPowerlineFrequency);
1093 			*size = sizeof(float);
1094 			currValue = (float*)value;
1095 			switch (fPowerlineFrequency) {
1096 				case 0:
1097 					*currValue = 0.0;
1098 					break;
1099 				case 1:
1100 					*currValue = 50.0;
1101 					break;
1102 				case 2:
1103 					*currValue = 60.0;
1104 					break;
1105 			}
1106 			*last_change = fLastParameterChanges;
1107 			return B_OK;
1108 
1109 	}
1110 	return B_BAD_VALUE;
1111 }
1112 
1113 
1114 status_t
1115 UVCCamDevice::SetParameterValue(int32 id, bigtime_t when, const void* value,
1116 	size_t size)
1117 {
1118 	printf("UVCCamDevice::SetParameterValue(%" B_PRId32 ")\n", id - fFirstParameterID);
1119 	switch (id - fFirstParameterID) {
1120 		case 0:
1121 			// debug_printf("\tBrightness:\n");
1122 			if (!value || (size != sizeof(float)))
1123 				return B_BAD_VALUE;
1124 			fBrightness = *((float*)value);
1125 			fLastParameterChanges = when;
1126 			return _SetParameterValue(PU_BRIGHTNESS_CONTROL, (int16)fBrightness);
1127 		case 1:
1128 			// debug_printf("\tContrast:\n");
1129 			if (!value || (size != sizeof(float)))
1130 				return B_BAD_VALUE;
1131 			fContrast = *((float*)value);
1132 			fLastParameterChanges = when;
1133 			return _SetParameterValue(PU_CONTRAST_CONTROL, (int16)fContrast);
1134 		case 2:
1135 			// debug_printf("\tHue:\n");
1136 			if (!value || (size != sizeof(float)))
1137 				return B_BAD_VALUE;
1138 			fHue = *((float*)value);
1139 			fLastParameterChanges = when;
1140 			return _SetParameterValue(PU_HUE_CONTROL, (int16)fHue);
1141 		case 4:
1142 			// debug_printf("\tSaturation:\n");
1143 			if (!value || (size != sizeof(float)))
1144 				return B_BAD_VALUE;
1145 			fSaturation = *((float*)value);
1146 			fLastParameterChanges = when;
1147 			return _SetParameterValue(PU_SATURATION_CONTROL, (int16)fSaturation);
1148 		case 5:
1149 			// debug_printf("\tSharpness:\n");
1150 			if (!value || (size != sizeof(float)))
1151 				return B_BAD_VALUE;
1152 			fSharpness = *((float*)value);
1153 			fLastParameterChanges = when;
1154 			return _SetParameterValue(PU_SHARPNESS_CONTROL, (int16)fSharpness);
1155 		case 7:
1156 			if (fWBTempAuto)
1157 				return B_OK;
1158 			// debug_printf("\tWB Temperature:\n");
1159 			if (!value || (size != sizeof(float)))
1160 				return B_BAD_VALUE;
1161 			fWBTemp = *((float*)value);
1162 			fLastParameterChanges = when;
1163 			return _SetParameterValue(PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
1164 				(int16)fWBTemp);
1165 		case 8:
1166 			// debug_printf("\tWB Temperature Auto:\n");
1167 			if (!value || (size != sizeof(int)))
1168 				return B_BAD_VALUE;
1169 			fWBTempAuto = *((int*)value);
1170 			fLastParameterChanges = when;
1171 			return _SetParameterValue(
1172 				PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, (int8)fWBTempAuto);
1173 		case 11:
1174 			if (!fBinaryBacklightCompensation) {
1175 				// debug_printf("\tBacklight Compensation:\n");
1176 				if (!value || (size != sizeof(float)))
1177 					return B_BAD_VALUE;
1178 				fBacklightCompensation = *((float*)value);
1179 			} else {
1180 				// debug_printf("\tBacklight Compensation:\n");
1181 				if (!value || (size != sizeof(int)))
1182 					return B_BAD_VALUE;
1183 				fBacklightCompensationBinary = *((int*)value);
1184 			}
1185 			fLastParameterChanges = when;
1186 			return _SetParameterValue(PU_BACKLIGHT_COMPENSATION_CONTROL,
1187 				(int16)fBacklightCompensationBinary);
1188 		case 12:
1189 			// debug_printf("\tGain:\n");
1190 			if (!value || (size != sizeof(float)))
1191 				return B_BAD_VALUE;
1192 			fGain = *((float*)value);
1193 			fLastParameterChanges = when;
1194 			return _SetParameterValue(PU_GAIN_CONTROL, (int16)fGain);
1195 		case 13:
1196 			// debug_printf("\tPowerline Frequency:\n");
1197 			// debug_printf("\tValue = %f\n",*((float*)value));
1198 			if (!value || (size != sizeof(float)))
1199 				return B_BAD_VALUE;
1200 			float inValue = *((float*)value);
1201 			fPowerlineFrequency = 0;
1202 			if (inValue > 45.0 && inValue < 55.0) {
1203 				fPowerlineFrequency = 1;
1204 			}
1205 			if (inValue >= 55.0) {
1206 				fPowerlineFrequency = 2;
1207 			}
1208 			fLastParameterChanges = when;
1209 			return _SetParameterValue(PU_POWER_LINE_FREQUENCY_CONTROL,
1210 				(int8)fPowerlineFrequency);
1211 
1212 	}
1213 	return B_BAD_VALUE;
1214 }
1215 
1216 
1217 status_t
1218 UVCCamDevice::_SetParameterValue(uint16 wValue, int16 setValue)
1219 {
1220 	return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1221 		| USB_REQTYPE_INTERFACE_OUT, SET_CUR, wValue << 8, fControlRequestIndex,
1222 		sizeof(setValue), &setValue)) == sizeof(setValue);
1223 }
1224 
1225 
1226 status_t
1227 UVCCamDevice::_SetParameterValue(uint16 wValue, int8 setValue)
1228 {
1229 	return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1230 		| USB_REQTYPE_INTERFACE_OUT, SET_CUR, wValue << 8, fControlRequestIndex,
1231 		sizeof(setValue), &setValue)) == sizeof(setValue);
1232 }
1233 
1234 
1235 status_t
1236 UVCCamDevice::FillFrameBuffer(BBuffer* buffer, bigtime_t* stamp)
1237 {
1238 	memset(buffer->Data(), 0, buffer->SizeAvailable());
1239 	status_t err = fDeframer->WaitFrame(2000000);
1240 	if (err < B_OK) {
1241 		fprintf(stderr, "WaitFrame: %" B_PRIx32 "\n", err);
1242 		return err;
1243 	}
1244 
1245 	CamFrame* f;
1246 	err = fDeframer->GetFrame(&f, stamp);
1247 	if (err < B_OK) {
1248 		fprintf(stderr, "GetFrame: %" B_PRIx32 "\n", err);
1249 		return err;
1250 	}
1251 
1252 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
1253 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
1254 
1255 	if (buffer->SizeAvailable() >= (size_t)w * h * 4) {
1256 		// TODO: The Video Producer only outputs B_RGB32.  This is OK for most
1257 		// applications.  This could be leveraged if applications can
1258 		// consume B_YUV422.
1259 		_DecodeColor((unsigned char*)buffer->Data(),
1260 			(unsigned char*)f->Buffer(), w, h);
1261 	}
1262 	delete f;
1263 	return B_OK;
1264 }
1265 
1266 
1267 void
1268 UVCCamDevice::_DecodeColor(unsigned char* dst, unsigned char* src,
1269 	int32 width, int32 height)
1270 {
1271 	long int i;
1272 	unsigned char* rawpt, * scanpt;
1273 	long int size;
1274 
1275 	rawpt = src;
1276 	scanpt = dst;
1277 	size = width*height;
1278 
1279 	for ( i = 0; i < size; i++ ) {
1280 	if ( (i/width) % 2 == 0 ) {
1281 		if ( (i % 2) == 0 ) {
1282 		/* B */
1283 		if ( (i > width) && ((i % width) > 0) ) {
1284 			*scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1285 				+ *(rawpt+width-1)+*(rawpt+width+1))/4;	/* R */
1286 			*scanpt++ = (*(rawpt-1)+*(rawpt+1)
1287 				+ *(rawpt+width)+*(rawpt-width))/4;	/* G */
1288 			*scanpt++ = *rawpt;					/* B */
1289 		} else {
1290 			/* first line or left column */
1291 			*scanpt++ = *(rawpt+width+1);		/* R */
1292 			*scanpt++ = (*(rawpt+1)+*(rawpt+width))/2;	/* G */
1293 			*scanpt++ = *rawpt;				/* B */
1294 		}
1295 		} else {
1296 		/* (B)G */
1297 		if ( (i > width) && ((i % width) < (width-1)) ) {
1298 			*scanpt++ = (*(rawpt+width)+*(rawpt-width))/2;	/* R */
1299 			*scanpt++ = *rawpt;					/* G */
1300 			*scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
1301 		} else {
1302 			/* first line or right column */
1303 			*scanpt++ = *(rawpt+width);	/* R */
1304 			*scanpt++ = *rawpt;		/* G */
1305 			*scanpt++ = *(rawpt-1);	/* B */
1306 		}
1307 		}
1308 	} else {
1309 		if ( (i % 2) == 0 ) {
1310 		/* G(R) */
1311 		if ( (i < (width*(height-1))) && ((i % width) > 0) ) {
1312 			*scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
1313 			*scanpt++ = *rawpt;					/* G */
1314 			*scanpt++ = (*(rawpt+width)+*(rawpt-width))/2;	/* B */
1315 		} else {
1316 			/* bottom line or left column */
1317 			*scanpt++ = *(rawpt+1);		/* R */
1318 			*scanpt++ = *rawpt;			/* G */
1319 			*scanpt++ = *(rawpt-width);		/* B */
1320 		}
1321 		} else {
1322 		/* R */
1323 		if ( i < (width*(height-1)) && ((i % width) < (width-1)) ) {
1324 			*scanpt++ = *rawpt;					/* R */
1325 			*scanpt++ = (*(rawpt-1)+*(rawpt+1)
1326 				+ *(rawpt-width)+*(rawpt+width))/4;	/* G */
1327 			*scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1328 				+ *(rawpt+width-1)+*(rawpt+width+1))/4;	/* B */
1329 		} else {
1330 			/* bottom line or right column */
1331 			*scanpt++ = *rawpt;				/* R */
1332 			*scanpt++ = (*(rawpt-1)+*(rawpt-width))/2;	/* G */
1333 			*scanpt++ = *(rawpt-width-1);		/* B */
1334 		}
1335 		}
1336 	}
1337 	rawpt++;
1338 	}
1339 }
1340 
1341 
1342 
1343 
1344 UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)
1345 	: CamDeviceAddon(webcam)
1346 {
1347 	printf("UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)\n");
1348 	SetSupportedDevices(kSupportedDevices);
1349 }
1350 
1351 
1352 UVCCamDeviceAddon::~UVCCamDeviceAddon()
1353 {
1354 }
1355 
1356 
1357 const char *
1358 UVCCamDeviceAddon::BrandName()
1359 {
1360 	printf("UVCCamDeviceAddon::BrandName()\n");
1361 	return "USB Video Class";
1362 }
1363 
1364 
1365 UVCCamDevice *
1366 UVCCamDeviceAddon::Instantiate(CamRoster& roster, BUSBDevice* from)
1367 {
1368 	printf("UVCCamDeviceAddon::Instantiate()\n");
1369 	return new UVCCamDevice(*this, from);
1370 }
1371 
1372 
1373 extern "C" status_t
1374 B_WEBCAM_MKINTFUNC(uvccam)
1375 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
1376 {
1377 	*addon = new UVCCamDeviceAddon(webcam);
1378 	return B_OK;
1379 }
1380