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