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
18usb_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 */
46usbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
47	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
48usbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
49	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
50
51static void
52print_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
67UVCCamDevice::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
146UVCCamDevice::~UVCCamDevice()
147{
148	free(fHeaderDescriptor);
149}
150
151
152void
153UVCCamDevice::_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
377void
378UVCCamDevice::_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
533bool
534UVCCamDevice::SupportsIsochronous()
535{
536	return true;
537}
538
539
540status_t
541UVCCamDevice::StartTransfer()
542{
543	if (_ProbeCommitFormat() != B_OK || _SelectBestAlternate() != B_OK)
544		return B_ERROR;
545	return CamDevice::StartTransfer();
546}
547
548
549status_t
550UVCCamDevice::StopTransfer()
551{
552	_SelectIdleAlternate();
553	return CamDevice::StopTransfer();
554}
555
556
557status_t
558UVCCamDevice::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
576status_t
577UVCCamDevice::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
612status_t
613UVCCamDevice::_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
697status_t
698UVCCamDevice::_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
746status_t
747UVCCamDevice::_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
766void
767UVCCamDevice::_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
900float
901UVCCamDevice::_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
935uint8
936UVCCamDevice::_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
951void
952UVCCamDevice::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
994status_t
995UVCCamDevice::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
1114status_t
1115UVCCamDevice::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
1217status_t
1218UVCCamDevice::_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
1226status_t
1227UVCCamDevice::_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
1235status_t
1236UVCCamDevice::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
1267void
1268UVCCamDevice::_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
1344UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)
1345	: CamDeviceAddon(webcam)
1346{
1347	printf("UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)\n");
1348	SetSupportedDevices(kSupportedDevices);
1349}
1350
1351
1352UVCCamDeviceAddon::~UVCCamDeviceAddon()
1353{
1354}
1355
1356
1357const char *
1358UVCCamDeviceAddon::BrandName()
1359{
1360	printf("UVCCamDeviceAddon::BrandName()\n");
1361	return "USB Video Class";
1362}
1363
1364
1365UVCCamDevice *
1366UVCCamDeviceAddon::Instantiate(CamRoster& roster, BUSBDevice* from)
1367{
1368	printf("UVCCamDeviceAddon::Instantiate()\n");
1369	return new UVCCamDevice(*this, from);
1370}
1371
1372
1373extern "C" status_t
1374B_WEBCAM_MKINTFUNC(uvccam)
1375(WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
1376{
1377	*addon = new UVCCamDeviceAddon(webcam);
1378	return B_OK;
1379}
1380