1242723Sjhibbits/*
2242723Sjhibbits * Copyright 2011, Gabriel Hartmann, gabriel.hartmann@gmail.com.
3242723Sjhibbits * Copyright 2011, J��r��me Duval, korli@users.berlios.de.
4242723Sjhibbits * Copyright 2009, Ithamar Adema, <ithamar.adema@team-embedded.nl>.
5242723Sjhibbits * Distributed under the terms of the MIT License.
6242723Sjhibbits */
7242723Sjhibbits
8242723Sjhibbits
9242723Sjhibbits#include "UVCCamDevice.h"
10242723Sjhibbits#include "UVCDeframer.h"
11242723Sjhibbits
12242723Sjhibbits#include <stdio.h>
13242723Sjhibbits#include <stdlib.h>
14242723Sjhibbits#include <ParameterWeb.h>
15242723Sjhibbits#include <media/Buffer.h>
16242723Sjhibbits
17242723Sjhibbits
18242723Sjhibbitsusb_webcam_support_descriptor kSupportedDevices[] = {
19242723Sjhibbits	// ofcourse we support a generic UVC device...
20242723Sjhibbits	{{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "Generic UVC", "Video Class", "??" },
21260670Sjhibbits	// ...whilst the following IDs were 'stolen' from a recent Linux driver:
22242723Sjhibbits	{{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft",     "Lifecam NX-6000",                 "??" },
23242723Sjhibbits	{{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft",     "Lifecam VX-7000",                 "??" },
24242723Sjhibbits	{{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech",      "QuickCam Fusion",                 "??" },
25242723Sjhibbits	{{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech",      "QuickCam Orbit MP",               "??" },
26242723Sjhibbits	{{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech",      "QuickCam Pro for Notebook",       "??" },
27260670Sjhibbits	{{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech",      "QuickCam Pro 5000",               "??" },
28260670Sjhibbits	{{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech",      "QuickCam OEM Dell Notebook",      "??" },
29260670Sjhibbits	{{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech",      "QuickCam OEM Cisco VT Camera II", "??" },
30260670Sjhibbits	{{ 0, 0, 0, 0x046d, 0x0821, }, "Logitech",      "HD Pro Webcam C910",              "??" },
31260670Sjhibbits	{{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple",         "Built-In iSight",                 "??" },
32260670Sjhibbits	{{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera",               "??" },
33260670Sjhibbits	{{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A",           "MT6227",                          "??" },
34260670Sjhibbits	{{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek",        "(HP Spartan)",                    "??" },
35260670Sjhibbits	{{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek",        "(Samsung Q310)",                  "??" },
36299003Smarkj	{{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek",        "Asus F9SG",                       "??" },
37260670Sjhibbits	{{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek",        "Asus U3S",                        "??" },
38242723Sjhibbits	{{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A",           "Lenovo Thinkpad SL500",           "??" },
39260670Sjhibbits	{{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm",         "Pico iMage",                      "??" },
40260670Sjhibbits	{{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin",       "ProScopeHR",                      "??" },
41260670Sjhibbits	{{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro",   "USB Web Camera",                  "??" },
42260670Sjhibbits	{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
43260670Sjhibbits};
44260670Sjhibbits
45260670Sjhibbits/* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
46260670Sjhibbitsusbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
47260670Sjhibbits	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
48260670Sjhibbitsusbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
49260670Sjhibbits	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
50260670Sjhibbits
51260670Sjhibbitsstatic void
52260670Sjhibbitsprint_guid(const usbvc_guid guid)
53260670Sjhibbits{
54260670Sjhibbits	if (!memcmp(guid, kYUY2Guid, sizeof(usbvc_guid)))
55260670Sjhibbits		printf("YUY2");
56260670Sjhibbits	else if (!memcmp(guid, kNV12Guid, sizeof(usbvc_guid)))
57260670Sjhibbits		printf("NV12");
58260670Sjhibbits	else {
59260670Sjhibbits		printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
60260670Sjhibbits			"%02x:%02x:%02x:%02x", guid[0], guid[1], guid[2], guid[3], guid[4],
61260670Sjhibbits			guid[5], guid[6], guid[7], guid[8], guid[9], guid[10], guid[11],
62260670Sjhibbits			guid[12], guid[13], guid[14], guid[15]);
63260670Sjhibbits	}
64269756Smarkj}
65260670Sjhibbits
66260670Sjhibbits
67260670SjhibbitsUVCCamDevice::UVCCamDevice(CamDeviceAddon& _addon, BUSBDevice* _device)
68260670Sjhibbits	: CamDevice(_addon, _device),
69260670Sjhibbits	fHeaderDescriptor(NULL),
70260670Sjhibbits	fInterruptIn(NULL),
71260670Sjhibbits	fUncompressedFormatIndex(1),
72260670Sjhibbits	fUncompressedFrameIndex(1)
73260670Sjhibbits{
74260670Sjhibbits	fDeframer = new UVCDeframer(this);
75260670Sjhibbits	SetDataInput(fDeframer);
76260670Sjhibbits
77260670Sjhibbits	const BUSBConfiguration* config;
78260670Sjhibbits	const BUSBInterface* interface;
79260670Sjhibbits	usb_descriptor* generic;
80260670Sjhibbits	uint8 buffer[1024];
81260670Sjhibbits
82260670Sjhibbits	generic = (usb_descriptor*)buffer;
83260670Sjhibbits
84260670Sjhibbits	for (uint32 i = 0; i < _device->CountConfigurations(); i++) {
85260670Sjhibbits		config = _device->ConfigurationAt(i);
86260670Sjhibbits		_device->SetConfiguration(config);
87260670Sjhibbits		for (uint32 j = 0; j < config->CountInterfaces(); j++) {
88260670Sjhibbits			interface = config->InterfaceAt(j);
89260670Sjhibbits
90260670Sjhibbits			if (interface->Class() == CC_VIDEO && interface->Subclass()
91260670Sjhibbits				== SC_VIDEOCONTROL) {
92260670Sjhibbits				printf("UVCCamDevice: (%lu,%lu): Found Video Control "
93260670Sjhibbits					"interface.\n", i, j);
94260670Sjhibbits
95260670Sjhibbits				// look for class specific interface descriptors and parse them
96260670Sjhibbits				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
97260670Sjhibbits					sizeof(buffer)) == B_OK; k++) {
98260670Sjhibbits					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
99260670Sjhibbits						| USB_DESCRIPTOR_INTERFACE))
100260670Sjhibbits						continue;
101260670Sjhibbits					fControlIndex = interface->Index();
102260670Sjhibbits					_ParseVideoControl((const usbvc_class_descriptor*)generic,
103260670Sjhibbits						generic->generic.length);
104260670Sjhibbits				}
105260670Sjhibbits				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
106260670Sjhibbits					const BUSBEndpoint* e = interface->EndpointAt(i);
107260670Sjhibbits					if (e && e->IsInterrupt() && e->IsInput()) {
108260670Sjhibbits						fInterruptIn = e;
109260670Sjhibbits						break;
110260670Sjhibbits					}
111260670Sjhibbits				}
112260670Sjhibbits				fInitStatus = B_OK;
113260670Sjhibbits			} else if (interface->Class() == CC_VIDEO && interface->Subclass()
114260670Sjhibbits				== SC_VIDEOSTREAMING) {
115260670Sjhibbits				printf("UVCCamDevice: (%lu,%lu): Found Video Streaming "
116260670Sjhibbits					"interface.\n", i, j);
117260670Sjhibbits
118260670Sjhibbits				// look for class specific interface descriptors and parse them
119260670Sjhibbits				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
120260670Sjhibbits					sizeof(buffer)) == B_OK; k++) {
121260670Sjhibbits					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
122260670Sjhibbits						| USB_DESCRIPTOR_INTERFACE))
123260670Sjhibbits						continue;
124260670Sjhibbits					fStreamingIndex = interface->Index();
125260670Sjhibbits					_ParseVideoStreaming((const usbvc_class_descriptor*)generic,
126260670Sjhibbits						generic->generic.length);
127260670Sjhibbits				}
128260670Sjhibbits
129260670Sjhibbits				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
130260670Sjhibbits					const BUSBEndpoint* e = interface->EndpointAt(i);
131260670Sjhibbits					if (e && e->IsIsochronous() && e->IsInput()) {
132260670Sjhibbits						fIsoIn = e;
133260670Sjhibbits						break;
134260670Sjhibbits					}
135260670Sjhibbits				}
136260670Sjhibbits			}
137260670Sjhibbits		}
138260670Sjhibbits	}
139260670Sjhibbits}
140260670Sjhibbits
141260670Sjhibbits
142260670SjhibbitsUVCCamDevice::~UVCCamDevice()
143260670Sjhibbits{
144260670Sjhibbits	free(fHeaderDescriptor);
145260670Sjhibbits}
146260670Sjhibbits
147260670Sjhibbits
148260670Sjhibbitsvoid
149260670SjhibbitsUVCCamDevice::_ParseVideoStreaming(const usbvc_class_descriptor* _descriptor,
150260670Sjhibbits	size_t len)
151260670Sjhibbits{
152260670Sjhibbits	switch (_descriptor->descriptorSubtype) {
153260670Sjhibbits		case VS_INPUT_HEADER:
154260670Sjhibbits		{
155260670Sjhibbits			const usbvc_input_header_descriptor* descriptor
156260670Sjhibbits				= (const usbvc_input_header_descriptor*)_descriptor;
157260670Sjhibbits			printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", descriptor->numFormats,
158260670Sjhibbits				descriptor->endpointAddress);
159260670Sjhibbits			if (descriptor->info & 1)
160260670Sjhibbits				printf("\tDynamic Format Change supported\n");
161260670Sjhibbits			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
162260670Sjhibbits			printf("\tstill capture method=%d\n", descriptor->stillCaptureMethod);
163260670Sjhibbits			if (descriptor->triggerSupport) {
164260670Sjhibbits				printf("\ttrigger button fixed to still capture=%s\n",
165260670Sjhibbits					descriptor->triggerUsage ? "no" : "yes");
166260670Sjhibbits			}
167260670Sjhibbits			const uint8* controls = descriptor->controls;
168260670Sjhibbits			for (uint8 i = 0; i < descriptor->numFormats; i++,
169260670Sjhibbits				controls += descriptor->controlSize) {
170260670Sjhibbits				printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
171260670Sjhibbits					(*controls & 1) ? "wKeyFrameRate" : "",
172260670Sjhibbits					(*controls & 2) ? "wPFrameRate" : "",
173260670Sjhibbits					(*controls & 4) ? "wCompQuality" : "",
174260670Sjhibbits					(*controls & 8) ? "wCompWindowSize" : "",
175260670Sjhibbits					(*controls & 16) ? "<Generate Key Frame>" : "",
176260670Sjhibbits					(*controls & 32) ? "<Update Frame Segment>" : "");
177260670Sjhibbits			}
178260670Sjhibbits			break;
179260670Sjhibbits		}
180260670Sjhibbits		case VS_FORMAT_UNCOMPRESSED:
181260670Sjhibbits		{
182260670Sjhibbits			const usbvc_format_descriptor* descriptor
183260670Sjhibbits				= (const usbvc_format_descriptor*)_descriptor;
184260670Sjhibbits			fUncompressedFormatIndex = descriptor->formatIndex;
185260670Sjhibbits			printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=",
186260670Sjhibbits				descriptor->formatIndex, descriptor->numFrameDescriptors);
187260670Sjhibbits			print_guid(descriptor->uncompressed.format);
188260670Sjhibbits			printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
189260670Sjhibbits				descriptor->uncompressed.bytesPerPixel,
190260670Sjhibbits				descriptor->uncompressed.defaultFrameIndex,
191260670Sjhibbits				descriptor->uncompressed.aspectRatioX,
192260670Sjhibbits				descriptor->uncompressed.aspectRatioY);
193260670Sjhibbits			printf("\tbmInterlaceFlags:\n");
194260670Sjhibbits			if (descriptor->uncompressed.interlaceFlags & 1)
195260670Sjhibbits				printf("\tInterlaced stream or variable\n");
196260670Sjhibbits			printf("\t%d fields per frame\n",
197260670Sjhibbits				(descriptor->uncompressed.interlaceFlags & 2) ? 1 : 2);
198260670Sjhibbits			if (descriptor->uncompressed.interlaceFlags & 4)
199260670Sjhibbits				printf("\tField 1 first\n");
200260670Sjhibbits			printf("\tField Pattern: ");
201260670Sjhibbits			switch ((descriptor->uncompressed.interlaceFlags & 0x30) >> 4) {
202260670Sjhibbits				case 0: printf("Field 1 only\n"); break;
203260670Sjhibbits				case 1: printf("Field 2 only\n"); break;
204260670Sjhibbits				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
205260670Sjhibbits				case 3: printf("Random pattern of fields 1 and 2\n"); break;
206260670Sjhibbits			}
207260670Sjhibbits			if (descriptor->uncompressed.copyProtect)
208260670Sjhibbits				printf("\tRestrict duplication\n");
209260670Sjhibbits			break;
210260670Sjhibbits		}
211260670Sjhibbits		case VS_FRAME_MJPEG:
212260670Sjhibbits		case VS_FRAME_UNCOMPRESSED:
213260670Sjhibbits		{
214260670Sjhibbits			const usbvc_frame_descriptor* descriptor
215260670Sjhibbits				= (const usbvc_frame_descriptor*)_descriptor;
216260670Sjhibbits			if (_descriptor->descriptorSubtype == VS_FRAME_UNCOMPRESSED) {
217260670Sjhibbits				printf("VS_FRAME_UNCOMPRESSED:");
218260670Sjhibbits				fUncompressedFrames.AddItem(
219260670Sjhibbits					new usbvc_frame_descriptor(*descriptor));
220260670Sjhibbits			} else {
221260670Sjhibbits				printf("VS_FRAME_MJPEG:");
222260670Sjhibbits				fMJPEGFrames.AddItem(new usbvc_frame_descriptor(*descriptor));
223260670Sjhibbits			}
224260670Sjhibbits			printf("\tbFrameIdx=%d,stillsupported=%s,"
225260670Sjhibbits				"fixedframerate=%s\n", descriptor->frameIndex,
226260670Sjhibbits				(descriptor->capabilities & 1) ? "yes" : "no",
227260670Sjhibbits				(descriptor->capabilities & 2) ? "yes" : "no");
228260670Sjhibbits			printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n",
229260670Sjhibbits				descriptor->width, descriptor->height,
230260670Sjhibbits				descriptor->minBitRate, descriptor->maxBitRate,
231260670Sjhibbits				descriptor->maxVideoFrameBufferSize);
232260670Sjhibbits			printf("\tdefault frame interval: %lu, #intervals(0=cont): %d\n",
233260670Sjhibbits				descriptor->defaultFrameInterval, descriptor->frameIntervalType);
234260670Sjhibbits			if (descriptor->frameIntervalType == 0) {
235260670Sjhibbits				printf("min/max frame interval=%lu/%lu, step=%lu\n",
236260670Sjhibbits					descriptor->continuous.minFrameInterval,
237260670Sjhibbits					descriptor->continuous.maxFrameInterval,
238260670Sjhibbits					descriptor->continuous.frameIntervalStep);
239260670Sjhibbits			} else for (uint8 i = 0; i < descriptor->frameIntervalType; i++) {
240260670Sjhibbits				printf("\tdiscrete frame interval: %lu\n",
241260670Sjhibbits					descriptor->discreteFrameIntervals[i]);
242260670Sjhibbits			}
243260670Sjhibbits			break;
244260670Sjhibbits		}
245260670Sjhibbits		case VS_COLORFORMAT:
246260670Sjhibbits		{
247260670Sjhibbits			const usbvc_color_matching_descriptor* descriptor
248260670Sjhibbits				= (const usbvc_color_matching_descriptor*)_descriptor;
249260670Sjhibbits			printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
250260670Sjhibbits			switch (descriptor->colorPrimaries) {
251260670Sjhibbits				case 0: printf("Unspecified\n"); break;
252260670Sjhibbits				case 1: printf("BT.709,sRGB\n"); break;
253260670Sjhibbits				case 2: printf("BT.470-2(M)\n"); break;
254260670Sjhibbits				case 3: printf("BT.470-2(B,G)\n"); break;
255260670Sjhibbits				case 4: printf("SMPTE 170M\n"); break;
256260670Sjhibbits				case 5: printf("SMPTE 240M\n"); break;
257260670Sjhibbits				default: printf("Invalid (%d)\n", descriptor->colorPrimaries);
258260670Sjhibbits			}
259260670Sjhibbits			printf("\tbTransferCharacteristics: ");
260260670Sjhibbits			switch (descriptor->transferCharacteristics) {
261260670Sjhibbits				case 0: printf("Unspecified\n"); break;
262260670Sjhibbits				case 1: printf("BT.709\n"); break;
263260670Sjhibbits				case 2: printf("BT.470-2(M)\n"); break;
264260670Sjhibbits				case 3: printf("BT.470-2(B,G)\n"); break;
265260670Sjhibbits				case 4: printf("SMPTE 170M\n"); break;
266260670Sjhibbits				case 5: printf("SMPTE 240M\n"); break;
267260670Sjhibbits				case 6: printf("Linear (V=Lc)\n"); break;
268260670Sjhibbits				case 7: printf("sRGB\n"); break;
269260670Sjhibbits				default: printf("Invalid (%d)\n",
270260670Sjhibbits					descriptor->transferCharacteristics);
271260670Sjhibbits			}
272260670Sjhibbits			printf("\tbMatrixCoefficients: ");
273260670Sjhibbits			switch (descriptor->matrixCoefficients) {
274260670Sjhibbits				case 0: printf("Unspecified\n"); break;
275260670Sjhibbits				case 1: printf("BT.709\n"); break;
276260670Sjhibbits				case 2: printf("FCC\n"); break;
277260670Sjhibbits				case 3: printf("BT.470-2(B,G)\n"); break;
278260670Sjhibbits				case 4: printf("SMPTE 170M (BT.601)\n"); break;
279260670Sjhibbits				case 5: printf("SMPTE 240M\n"); break;
280260670Sjhibbits				default: printf("Invalid (%d)\n", descriptor->matrixCoefficients);
281260670Sjhibbits			}
282260670Sjhibbits			break;
283260670Sjhibbits		}
284260670Sjhibbits		case VS_OUTPUT_HEADER:
285260670Sjhibbits		{
286260670Sjhibbits			const usbvc_output_header_descriptor* descriptor
287260670Sjhibbits				= (const usbvc_output_header_descriptor*)_descriptor;
288260670Sjhibbits			printf("VS_OUTPUT_HEADER:\t#fmts=%d,ept=0x%x\n",
289260670Sjhibbits				descriptor->numFormats, descriptor->endpointAddress);
290260670Sjhibbits			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
291260670Sjhibbits			const uint8* controls = descriptor->controls;
292260670Sjhibbits			for (uint8 i = 0; i < descriptor->numFormats; i++,
293260670Sjhibbits				controls += descriptor->controlSize) {
294260670Sjhibbits				printf("\tfmt%d: %s %s %s %s\n", i,
295260670Sjhibbits					(*controls & 1) ? "wKeyFrameRate" : "",
296260670Sjhibbits					(*controls & 2) ? "wPFrameRate" : "",
297260670Sjhibbits					(*controls & 4) ? "wCompQuality" : "",
298260670Sjhibbits					(*controls & 8) ? "wCompWindowSize" : "");
299260670Sjhibbits			}
300260670Sjhibbits			break;
301260670Sjhibbits		}
302260670Sjhibbits		case VS_STILL_IMAGE_FRAME:
303260670Sjhibbits		{
304260670Sjhibbits			const usbvc_still_image_frame_descriptor* descriptor
305260670Sjhibbits				= (const usbvc_still_image_frame_descriptor*)_descriptor;
306299003Smarkj			printf("VS_STILL_IMAGE_FRAME:\t#imageSizes=%d,compressions=%d,"
307260670Sjhibbits				"ept=0x%x\n", descriptor->numImageSizePatterns,
308260670Sjhibbits				descriptor->NumCompressionPatterns(),
309260670Sjhibbits				descriptor->endpointAddress);
310260670Sjhibbits			for (uint8 i = 0; i < descriptor->numImageSizePatterns; i++) {
311299003Smarkj				printf("imageSize%d: %dx%d\n", i,
312260670Sjhibbits					descriptor->imageSizePatterns[i].width,
313260670Sjhibbits					descriptor->imageSizePatterns[i].height);
314260670Sjhibbits			}
315260670Sjhibbits			for (uint8 i = 0; i < descriptor->NumCompressionPatterns(); i++) {
316260670Sjhibbits				printf("compression%d: %d\n", i,
317260670Sjhibbits					descriptor->CompressionPatterns()[i]);
318260670Sjhibbits			}
319260670Sjhibbits			break;
320260670Sjhibbits		}
321260670Sjhibbits		case VS_FORMAT_MJPEG:
322260670Sjhibbits		{
323260670Sjhibbits			const usbvc_format_descriptor* descriptor
324260670Sjhibbits				= (const usbvc_format_descriptor*)_descriptor;
325260670Sjhibbits			fMJPEGFormatIndex = descriptor->formatIndex;
326299003Smarkj			printf("VS_FORMAT_MJPEG:\tbFormatIdx=%d,#frmdesc=%d\n",
327260670Sjhibbits				descriptor->formatIndex, descriptor->numFrameDescriptors);
328260670Sjhibbits			printf("\t#flgs=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
329260670Sjhibbits				descriptor->mjpeg.flags,
330260670Sjhibbits				descriptor->mjpeg.defaultFrameIndex,
331260670Sjhibbits				descriptor->mjpeg.aspectRatioX,
332260670Sjhibbits				descriptor->mjpeg.aspectRatioY);
333260670Sjhibbits			printf("\tbmInterlaceFlags:\n");
334260670Sjhibbits			if (descriptor->mjpeg.interlaceFlags & 1)
335260670Sjhibbits				printf("\tInterlaced stream or variable\n");
336260670Sjhibbits			printf("\t%d fields per frame\n",
337260670Sjhibbits				(descriptor->mjpeg.interlaceFlags & 2) ? 1 : 2);
338260670Sjhibbits			if (descriptor->mjpeg.interlaceFlags & 4)
339260670Sjhibbits				printf("\tField 1 first\n");
340260670Sjhibbits			printf("\tField Pattern: ");
341260670Sjhibbits			switch ((descriptor->mjpeg.interlaceFlags & 0x30) >> 4) {
342260670Sjhibbits				case 0: printf("Field 1 only\n"); break;
343260670Sjhibbits				case 1: printf("Field 2 only\n"); break;
344299003Smarkj				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
345260670Sjhibbits				case 3: printf("Random pattern of fields 1 and 2\n"); break;
346260670Sjhibbits			}
347260670Sjhibbits			if (descriptor->mjpeg.copyProtect)
348260670Sjhibbits				printf("\tRestrict duplication\n");
349260670Sjhibbits			break;
350260670Sjhibbits		}
351260670Sjhibbits		case VS_FORMAT_MPEG2TS:
352260670Sjhibbits			printf("VS_FORMAT_MPEG2TS:\t\n");
353260670Sjhibbits			break;
354260670Sjhibbits		case VS_FORMAT_DV:
355260670Sjhibbits			printf("VS_FORMAT_DV:\t\n");
356260670Sjhibbits			break;
357260670Sjhibbits		case VS_FORMAT_FRAME_BASED:
358260670Sjhibbits			printf("VS_FORMAT_FRAME_BASED:\t\n");
359260670Sjhibbits			break;
360260670Sjhibbits		case VS_FRAME_FRAME_BASED:
361260670Sjhibbits			printf("VS_FRAME_FRAME_BASED:\t\n");
362260670Sjhibbits			break;
363260670Sjhibbits		case VS_FORMAT_STREAM_BASED:
364260670Sjhibbits			printf("VS_FORMAT_STREAM_BASED:\t\n");
365260670Sjhibbits			break;
366260670Sjhibbits		default:
367260670Sjhibbits			printf("INVALID STREAM UNIT TYPE=%d!\n",
368260670Sjhibbits				_descriptor->descriptorSubtype);
369260670Sjhibbits	}
370260670Sjhibbits}
371260670Sjhibbits
372260670Sjhibbits
373299003Smarkjvoid
374260670SjhibbitsUVCCamDevice::_ParseVideoControl(const usbvc_class_descriptor* _descriptor,
375260670Sjhibbits	size_t len)
376260670Sjhibbits{
377260670Sjhibbits	switch (_descriptor->descriptorSubtype) {
378260670Sjhibbits		case VC_HEADER:
379260670Sjhibbits		{
380260670Sjhibbits			if (fHeaderDescriptor != NULL) {
381260670Sjhibbits				printf("ERROR: multiple VC_HEADER! Skipping...\n");
382260670Sjhibbits				break;
383260670Sjhibbits			}
384260670Sjhibbits			fHeaderDescriptor = (usbvc_interface_header_descriptor*)malloc(len);
385260670Sjhibbits			memcpy(fHeaderDescriptor, _descriptor, len);
386260670Sjhibbits			printf("VC_HEADER:\tUVC v%x.%02x, clk %.5f MHz\n",
387260670Sjhibbits				fHeaderDescriptor->version >> 8,
388260670Sjhibbits				fHeaderDescriptor->version & 0xff,
389260670Sjhibbits				fHeaderDescriptor->clockFrequency / 1000000.0);
390260670Sjhibbits			for (uint8 i = 0; i < fHeaderDescriptor->numInterfacesNumbers; i++) {
391260670Sjhibbits				printf("\tStreaming Interface %d\n",
392260670Sjhibbits					fHeaderDescriptor->interfaceNumbers[i]);
393260670Sjhibbits			}
394260670Sjhibbits			break;
395260670Sjhibbits		}
396260670Sjhibbits		case VC_INPUT_TERMINAL:
397260670Sjhibbits		{
398260670Sjhibbits			const usbvc_input_terminal_descriptor* descriptor
399260670Sjhibbits				= (const usbvc_input_terminal_descriptor*)_descriptor;
400260670Sjhibbits			printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
401260670Sjhibbits				"%d\n", descriptor->terminalID, descriptor->terminalType,
402260670Sjhibbits				descriptor->associatedTerminal);
403260670Sjhibbits			printf("\tDesc: %s\n",
404299003Smarkj				fDevice->DecodeStringDescriptor(descriptor->terminal));
405260670Sjhibbits			if (descriptor->terminalType == 0x201) {
406260670Sjhibbits				const usbvc_camera_terminal_descriptor* desc
407260670Sjhibbits					= (const usbvc_camera_terminal_descriptor*)descriptor;
408260670Sjhibbits				printf("\tObjectiveFocalLength Min/Max %d/%d\n",
409260670Sjhibbits					desc->objectiveFocalLengthMin,
410260670Sjhibbits					desc->objectiveFocalLengthMax);
411260670Sjhibbits				printf("\tOcularFocalLength %d\n", desc->ocularFocalLength);
412260670Sjhibbits				printf("\tControlSize %d\n", desc->controlSize);
413260670Sjhibbits			}
414260670Sjhibbits			break;
415260670Sjhibbits		}
416260670Sjhibbits		case VC_OUTPUT_TERMINAL:
417260670Sjhibbits		{
418260670Sjhibbits			const usbvc_output_terminal_descriptor* descriptor
419260670Sjhibbits				= (const usbvc_output_terminal_descriptor*)_descriptor;
420260670Sjhibbits			printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
421260670Sjhibbits				"%d, src id=%d\n", descriptor->terminalID,
422260670Sjhibbits				descriptor->terminalType, descriptor->associatedTerminal,
423299003Smarkj				descriptor->sourceID);
424260670Sjhibbits			printf("\tDesc: %s\n",
425260670Sjhibbits				fDevice->DecodeStringDescriptor(descriptor->terminal));
426260670Sjhibbits			break;
427260670Sjhibbits		}
428260670Sjhibbits		case VC_SELECTOR_UNIT:
429260670Sjhibbits		{
430260670Sjhibbits			const usbvc_selector_unit_descriptor* descriptor
431260670Sjhibbits				= (const usbvc_selector_unit_descriptor*)_descriptor;
432260670Sjhibbits			printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n",
433260670Sjhibbits				descriptor->unitID, descriptor->numInputPins);
434260670Sjhibbits			printf("\t");
435260670Sjhibbits			for (uint8 i = 0; i < descriptor->numInputPins; i++)
436260670Sjhibbits				printf("%d ", descriptor->sourceID[i]);
437260670Sjhibbits			printf("\n");
438260670Sjhibbits			printf("\tDesc: %s\n",
439260670Sjhibbits				fDevice->DecodeStringDescriptor(descriptor->Selector()));
440260670Sjhibbits			break;
441260670Sjhibbits		}
442260670Sjhibbits		case VC_PROCESSING_UNIT:
443260670Sjhibbits		{
444260670Sjhibbits			const usbvc_processing_unit_descriptor* descriptor
445260670Sjhibbits				= (const usbvc_processing_unit_descriptor*)_descriptor;
446260670Sjhibbits			fControlRequestIndex = fControlIndex + (descriptor->unitID << 8);
447260670Sjhibbits			printf("VC_PROCESSING_UNIT:\t unit id=%d,src id=%d, digmul=%d\n",
448260670Sjhibbits				descriptor->unitID, descriptor->sourceID,
449260670Sjhibbits				descriptor->maxMultiplier);
450260670Sjhibbits			printf("\tbControlSize=%d\n", descriptor->controlSize);
451260670Sjhibbits			if (descriptor->controlSize >= 1) {
452260670Sjhibbits				if (descriptor->controls[0] & 1)
453260670Sjhibbits					printf("\tBrightness\n");
454260670Sjhibbits				if (descriptor->controls[0] & 2)
455260670Sjhibbits					printf("\tContrast\n");
456260670Sjhibbits				if (descriptor->controls[0] & 4)
457260670Sjhibbits					printf("\tHue\n");
458260670Sjhibbits				if (descriptor->controls[0] & 8)
459260670Sjhibbits					printf("\tSaturation\n");
460260670Sjhibbits				if (descriptor->controls[0] & 16)
461260670Sjhibbits					printf("\tSharpness\n");
462260670Sjhibbits				if (descriptor->controls[0] & 32)
463260670Sjhibbits					printf("\tGamma\n");
464260670Sjhibbits				if (descriptor->controls[0] & 64)
465260670Sjhibbits					printf("\tWhite Balance Temperature\n");
466260670Sjhibbits				if (descriptor->controls[0] & 128)
467260670Sjhibbits					printf("\tWhite Balance Component\n");
468260670Sjhibbits			}
469260670Sjhibbits			if (descriptor->controlSize >= 2) {
470260670Sjhibbits				if (descriptor->controls[1] & 1)
471260670Sjhibbits					printf("\tBacklight Compensation\n");
472260670Sjhibbits				if (descriptor->controls[1] & 2)
473260670Sjhibbits					printf("\tGain\n");
474260670Sjhibbits				if (descriptor->controls[1] & 4)
475260670Sjhibbits					printf("\tPower Line Frequency\n");
476260670Sjhibbits				if (descriptor->controls[1] & 8)
477299003Smarkj					printf("\t[AUTO] Hue\n");
478260670Sjhibbits				if (descriptor->controls[1] & 16)
479260670Sjhibbits					printf("\t[AUTO] White Balance Temperature\n");
480260670Sjhibbits				if (descriptor->controls[1] & 32)
481260670Sjhibbits					printf("\t[AUTO] White Balance Component\n");
482260670Sjhibbits				if (descriptor->controls[1] & 64)
483260670Sjhibbits					printf("\tDigital Multiplier\n");
484260670Sjhibbits				if (descriptor->controls[1] & 128)
485260670Sjhibbits					printf("\tDigital Multiplier Limit\n");
486260670Sjhibbits			}
487260670Sjhibbits			if (descriptor->controlSize >= 3) {
488260670Sjhibbits				if (descriptor->controls[2] & 1)
489260670Sjhibbits					printf("\tAnalog Video Standard\n");
490260670Sjhibbits				if (descriptor->controls[2] & 2)
491260670Sjhibbits					printf("\tAnalog Video Lock Status\n");
492260670Sjhibbits			}
493260670Sjhibbits			printf("\tDesc: %s\n",
494260670Sjhibbits				fDevice->DecodeStringDescriptor(descriptor->Processing()));
495260670Sjhibbits			if (descriptor->VideoStandards() & 2)
496260670Sjhibbits				printf("\tNTSC  525/60\n");
497260670Sjhibbits			if (descriptor->VideoStandards() & 4)
498260670Sjhibbits				printf("\tPAL   625/50\n");
499260670Sjhibbits			if (descriptor->VideoStandards() & 8)
500260670Sjhibbits				printf("\tSECAM 625/50\n");
501260670Sjhibbits			if (descriptor->VideoStandards() & 16)
502260670Sjhibbits				printf("\tNTSC  625/50\n");
503260670Sjhibbits			if (descriptor->VideoStandards() & 32)
504260670Sjhibbits				printf("\tPAL   525/60\n");
505260670Sjhibbits			break;
506260670Sjhibbits		}
507260670Sjhibbits		case VC_EXTENSION_UNIT:
508260670Sjhibbits		{
509260670Sjhibbits			const usbvc_extension_unit_descriptor* descriptor
510260670Sjhibbits				= (const usbvc_extension_unit_descriptor*)_descriptor;
511260670Sjhibbits			printf("VC_EXTENSION_UNIT:\tid=%d, guid=", descriptor->unitID);
512260670Sjhibbits			print_guid(descriptor->guidExtensionCode);
513260670Sjhibbits			printf("\n\t#ctrls=%d, #pins=%d\n", descriptor->numControls,
514260670Sjhibbits				descriptor->numInputPins);
515260670Sjhibbits			printf("\t");
516260670Sjhibbits			for (uint8 i = 0; i < descriptor->numInputPins; i++)
517260670Sjhibbits				printf("%d ", descriptor->sourceID[i]);
518260670Sjhibbits			printf("\n");
519260670Sjhibbits			printf("\tDesc: %s\n",
520260670Sjhibbits				fDevice->DecodeStringDescriptor(descriptor->Extension()));
521260670Sjhibbits			break;
522260670Sjhibbits		}
523260670Sjhibbits		default:
524260670Sjhibbits			printf("Unknown control %d\n", _descriptor->descriptorSubtype);
525260670Sjhibbits	}
526260670Sjhibbits}
527260670Sjhibbits
528260670Sjhibbits
529260670Sjhibbitsbool
530260670SjhibbitsUVCCamDevice::SupportsIsochronous()
531260670Sjhibbits{
532260670Sjhibbits	return true;
533260670Sjhibbits}
534260670Sjhibbits
535260670Sjhibbits
536260670Sjhibbitsstatus_t
537260670SjhibbitsUVCCamDevice::StartTransfer()
538260670Sjhibbits{
539260670Sjhibbits	if (_ProbeCommitFormat() != B_OK || _SelectBestAlternate() != B_OK)
540260670Sjhibbits		return B_ERROR;
541260670Sjhibbits	return CamDevice::StartTransfer();
542260670Sjhibbits}
543260670Sjhibbits
544260670Sjhibbits
545260670Sjhibbitsstatus_t
546260670SjhibbitsUVCCamDevice::StopTransfer()
547260670Sjhibbits{
548260670Sjhibbits	_SelectIdleAlternate();
549260670Sjhibbits	return CamDevice::StopTransfer();
550260670Sjhibbits}
551260670Sjhibbits
552260670Sjhibbits
553260670Sjhibbitsstatus_t
554260670SjhibbitsUVCCamDevice::SuggestVideoFrame(uint32& width, uint32& height)
555260670Sjhibbits{
556260670Sjhibbits	printf("UVCCamDevice::SuggestVideoFrame(%ld, %ld)\n", width, height);
557260670Sjhibbits	// As in AcceptVideoFrame(), the suggestion should probably just be the
558260670Sjhibbits	// first advertised uncompressed format, but current applications prefer
559260670Sjhibbits	// 320x240, so this is tried first here as a suggestion.
560260670Sjhibbits	width = 320;
561260670Sjhibbits	height = 240;
562260670Sjhibbits	if (!AcceptVideoFrame(width, height)) {
563260670Sjhibbits		const usbvc_frame_descriptor* descriptor
564260670Sjhibbits			= (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
565260670Sjhibbits		width  = (*descriptor).width;
566260670Sjhibbits		height = (*descriptor).height;
567260670Sjhibbits	}
568260670Sjhibbits	return B_OK;
569260670Sjhibbits}
570260670Sjhibbits
571260670Sjhibbits
572260670Sjhibbitsstatus_t
573260670SjhibbitsUVCCamDevice::AcceptVideoFrame(uint32& width, uint32& height)
574260670Sjhibbits{
575260670Sjhibbits	printf("UVCCamDevice::AcceptVideoFrame(%ld, %ld)\n", width, height);
576260670Sjhibbits	if (width <= 0 || height <= 0) {
577260670Sjhibbits		// Uncomment below when applications support dimensions other than 320x240
578260670Sjhibbits		// This code selects the first listed available uncompressed frame format
579260670Sjhibbits		/*
580260670Sjhibbits		const usbvc_frame_descriptor* descriptor
581260670Sjhibbits			= (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
582260670Sjhibbits		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