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