vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / media-add-ons / usb_webcam / addons / uvc / UVCCamDevice.cpp
blobe383206c17a08bfbf9ad7bf59c4012869daa27fe
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 */
9 #include "UVCCamDevice.h"
10 #include "UVCDeframer.h"
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <ParameterWeb.h>
15 #include <media/Buffer.h>
18 usb_webcam_support_descriptor kSupportedDevices[] = {
19 // ofcourse we support a generic UVC device...
20 {{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "Generic UVC", "Video Class", "??" },
21 // ...whilst the following IDs were 'stolen' from a recent Linux driver:
22 {{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft", "Lifecam NX-6000", "??" },
23 {{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft", "Lifecam VX-7000", "??" },
24 {{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech", "QuickCam Fusion", "??" },
25 {{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech", "QuickCam Orbit MP", "??" },
26 {{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech", "QuickCam Pro for Notebook", "??" },
27 {{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech", "QuickCam Pro 5000", "??" },
28 {{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech", "QuickCam OEM Dell Notebook", "??" },
29 {{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech", "QuickCam OEM Cisco VT Camera II", "??" },
30 {{ 0, 0, 0, 0x046d, 0x0821, }, "Logitech", "HD Pro Webcam C910", "??" },
31 {{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple", "Built-In iSight", "??" },
32 {{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera", "??" },
33 {{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A", "MT6227", "??" },
34 {{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek", "(HP Spartan)", "??" },
35 {{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek", "(Samsung Q310)", "??" },
36 {{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek", "Asus F9SG", "??" },
37 {{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek", "Asus U3S", "??" },
38 {{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A", "Lenovo Thinkpad SL500", "??" },
39 {{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm", "Pico iMage", "??" },
40 {{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin", "ProScopeHR", "??" },
41 {{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro", "USB Web Camera", "??" },
42 {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
45 /* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
46 usbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
47 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
48 usbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
49 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
51 static void
52 print_guid(const usbvc_guid guid)
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]);
67 UVCCamDevice::UVCCamDevice(CamDeviceAddon& _addon, BUSBDevice* _device)
68 : CamDevice(_addon, _device),
69 fHeaderDescriptor(NULL),
70 fInterruptIn(NULL),
71 fUncompressedFormatIndex(1),
72 fUncompressedFrameIndex(1)
74 fDeframer = new UVCDeframer(this);
75 SetDataInput(fDeframer);
77 const BUSBConfiguration* config;
78 const BUSBInterface* interface;
79 usb_descriptor* generic;
80 uint8 buffer[1024];
82 generic = (usb_descriptor*)buffer;
84 for (uint32 i = 0; i < _device->CountConfigurations(); i++) {
85 config = _device->ConfigurationAt(i);
86 if (config == NULL)
87 continue;
88 _device->SetConfiguration(config);
89 for (uint32 j = 0; j < config->CountInterfaces(); j++) {
90 interface = config->InterfaceAt(j);
91 if (interface == NULL)
92 continue;
94 if (interface->Class() == CC_VIDEO && interface->Subclass()
95 == SC_VIDEOCONTROL) {
96 printf("UVCCamDevice: (%lu,%lu): Found Video Control "
97 "interface.\n", i, j);
99 // look for class specific interface descriptors and parse them
100 for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
101 sizeof(buffer)) == B_OK; k++) {
102 if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
103 | USB_DESCRIPTOR_INTERFACE))
104 continue;
105 fControlIndex = interface->Index();
106 _ParseVideoControl((const usbvc_class_descriptor*)generic,
107 generic->generic.length);
109 for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
110 const BUSBEndpoint* e = interface->EndpointAt(i);
111 if (e && e->IsInterrupt() && e->IsInput()) {
112 fInterruptIn = e;
113 break;
116 fInitStatus = B_OK;
117 } else if (interface->Class() == CC_VIDEO && interface->Subclass()
118 == SC_VIDEOSTREAMING) {
119 printf("UVCCamDevice: (%lu,%lu): Found Video Streaming "
120 "interface.\n", i, j);
122 // look for class specific interface descriptors and parse them
123 for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
124 sizeof(buffer)) == B_OK; k++) {
125 if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
126 | USB_DESCRIPTOR_INTERFACE))
127 continue;
128 fStreamingIndex = interface->Index();
129 _ParseVideoStreaming((const usbvc_class_descriptor*)generic,
130 generic->generic.length);
133 for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
134 const BUSBEndpoint* e = interface->EndpointAt(i);
135 if (e && e->IsIsochronous() && e->IsInput()) {
136 fIsoIn = e;
137 break;
146 UVCCamDevice::~UVCCamDevice()
148 free(fHeaderDescriptor);
152 void
153 UVCCamDevice::_ParseVideoStreaming(const usbvc_class_descriptor* _descriptor,
154 size_t len)
156 switch (_descriptor->descriptorSubtype) {
157 case VS_INPUT_HEADER:
159 const usbvc_input_header_descriptor* descriptor
160 = (const usbvc_input_header_descriptor*)_descriptor;
161 printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", descriptor->numFormats,
162 descriptor->endpointAddress);
163 if (descriptor->info & 1)
164 printf("\tDynamic Format Change supported\n");
165 printf("\toutput terminal id=%d\n", descriptor->terminalLink);
166 printf("\tstill capture method=%d\n", descriptor->stillCaptureMethod);
167 if (descriptor->triggerSupport) {
168 printf("\ttrigger button fixed to still capture=%s\n",
169 descriptor->triggerUsage ? "no" : "yes");
171 const uint8* controls = descriptor->controls;
172 for (uint8 i = 0; i < descriptor->numFormats; i++,
173 controls += descriptor->controlSize) {
174 printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
175 (*controls & 1) ? "wKeyFrameRate" : "",
176 (*controls & 2) ? "wPFrameRate" : "",
177 (*controls & 4) ? "wCompQuality" : "",
178 (*controls & 8) ? "wCompWindowSize" : "",
179 (*controls & 16) ? "<Generate Key Frame>" : "",
180 (*controls & 32) ? "<Update Frame Segment>" : "");
182 break;
184 case VS_FORMAT_UNCOMPRESSED:
186 const usbvc_format_descriptor* descriptor
187 = (const usbvc_format_descriptor*)_descriptor;
188 fUncompressedFormatIndex = descriptor->formatIndex;
189 printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=",
190 descriptor->formatIndex, descriptor->numFrameDescriptors);
191 print_guid(descriptor->uncompressed.format);
192 printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
193 descriptor->uncompressed.bytesPerPixel,
194 descriptor->uncompressed.defaultFrameIndex,
195 descriptor->uncompressed.aspectRatioX,
196 descriptor->uncompressed.aspectRatioY);
197 printf("\tbmInterlaceFlags:\n");
198 if (descriptor->uncompressed.interlaceFlags & 1)
199 printf("\tInterlaced stream or variable\n");
200 printf("\t%d fields per frame\n",
201 (descriptor->uncompressed.interlaceFlags & 2) ? 1 : 2);
202 if (descriptor->uncompressed.interlaceFlags & 4)
203 printf("\tField 1 first\n");
204 printf("\tField Pattern: ");
205 switch ((descriptor->uncompressed.interlaceFlags & 0x30) >> 4) {
206 case 0: printf("Field 1 only\n"); break;
207 case 1: printf("Field 2 only\n"); break;
208 case 2: printf("Regular pattern of fields 1 and 2\n"); break;
209 case 3: printf("Random pattern of fields 1 and 2\n"); break;
211 if (descriptor->uncompressed.copyProtect)
212 printf("\tRestrict duplication\n");
213 break;
215 case VS_FRAME_MJPEG:
216 case VS_FRAME_UNCOMPRESSED:
218 const usbvc_frame_descriptor* descriptor
219 = (const usbvc_frame_descriptor*)_descriptor;
220 if (_descriptor->descriptorSubtype == VS_FRAME_UNCOMPRESSED) {
221 printf("VS_FRAME_UNCOMPRESSED:");
222 fUncompressedFrames.AddItem(
223 new usbvc_frame_descriptor(*descriptor));
224 } else {
225 printf("VS_FRAME_MJPEG:");
226 fMJPEGFrames.AddItem(new usbvc_frame_descriptor(*descriptor));
228 printf("\tbFrameIdx=%d,stillsupported=%s,"
229 "fixedframerate=%s\n", descriptor->frameIndex,
230 (descriptor->capabilities & 1) ? "yes" : "no",
231 (descriptor->capabilities & 2) ? "yes" : "no");
232 printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n",
233 descriptor->width, descriptor->height,
234 descriptor->minBitRate, descriptor->maxBitRate,
235 descriptor->maxVideoFrameBufferSize);
236 printf("\tdefault frame interval: %lu, #intervals(0=cont): %d\n",
237 descriptor->defaultFrameInterval, descriptor->frameIntervalType);
238 if (descriptor->frameIntervalType == 0) {
239 printf("min/max frame interval=%lu/%lu, step=%lu\n",
240 descriptor->continuous.minFrameInterval,
241 descriptor->continuous.maxFrameInterval,
242 descriptor->continuous.frameIntervalStep);
243 } else for (uint8 i = 0; i < descriptor->frameIntervalType; i++) {
244 printf("\tdiscrete frame interval: %lu\n",
245 descriptor->discreteFrameIntervals[i]);
247 break;
249 case VS_COLORFORMAT:
251 const usbvc_color_matching_descriptor* descriptor
252 = (const usbvc_color_matching_descriptor*)_descriptor;
253 printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
254 switch (descriptor->colorPrimaries) {
255 case 0: printf("Unspecified\n"); break;
256 case 1: printf("BT.709,sRGB\n"); break;
257 case 2: printf("BT.470-2(M)\n"); break;
258 case 3: printf("BT.470-2(B,G)\n"); break;
259 case 4: printf("SMPTE 170M\n"); break;
260 case 5: printf("SMPTE 240M\n"); break;
261 default: printf("Invalid (%d)\n", descriptor->colorPrimaries);
263 printf("\tbTransferCharacteristics: ");
264 switch (descriptor->transferCharacteristics) {
265 case 0: printf("Unspecified\n"); break;
266 case 1: printf("BT.709\n"); break;
267 case 2: printf("BT.470-2(M)\n"); break;
268 case 3: printf("BT.470-2(B,G)\n"); break;
269 case 4: printf("SMPTE 170M\n"); break;
270 case 5: printf("SMPTE 240M\n"); break;
271 case 6: printf("Linear (V=Lc)\n"); break;
272 case 7: printf("sRGB\n"); break;
273 default: printf("Invalid (%d)\n",
274 descriptor->transferCharacteristics);
276 printf("\tbMatrixCoefficients: ");
277 switch (descriptor->matrixCoefficients) {
278 case 0: printf("Unspecified\n"); break;
279 case 1: printf("BT.709\n"); break;
280 case 2: printf("FCC\n"); break;
281 case 3: printf("BT.470-2(B,G)\n"); break;
282 case 4: printf("SMPTE 170M (BT.601)\n"); break;
283 case 5: printf("SMPTE 240M\n"); break;
284 default: printf("Invalid (%d)\n", descriptor->matrixCoefficients);
286 break;
288 case VS_OUTPUT_HEADER:
290 const usbvc_output_header_descriptor* descriptor
291 = (const usbvc_output_header_descriptor*)_descriptor;
292 printf("VS_OUTPUT_HEADER:\t#fmts=%d,ept=0x%x\n",
293 descriptor->numFormats, descriptor->endpointAddress);
294 printf("\toutput terminal id=%d\n", descriptor->terminalLink);
295 const uint8* controls = descriptor->controls;
296 for (uint8 i = 0; i < descriptor->numFormats; i++,
297 controls += descriptor->controlSize) {
298 printf("\tfmt%d: %s %s %s %s\n", i,
299 (*controls & 1) ? "wKeyFrameRate" : "",
300 (*controls & 2) ? "wPFrameRate" : "",
301 (*controls & 4) ? "wCompQuality" : "",
302 (*controls & 8) ? "wCompWindowSize" : "");
304 break;
306 case VS_STILL_IMAGE_FRAME:
308 const usbvc_still_image_frame_descriptor* descriptor
309 = (const usbvc_still_image_frame_descriptor*)_descriptor;
310 printf("VS_STILL_IMAGE_FRAME:\t#imageSizes=%d,compressions=%d,"
311 "ept=0x%x\n", descriptor->numImageSizePatterns,
312 descriptor->NumCompressionPatterns(),
313 descriptor->endpointAddress);
314 for (uint8 i = 0; i < descriptor->numImageSizePatterns; i++) {
315 printf("imageSize%d: %dx%d\n", i,
316 descriptor->imageSizePatterns[i].width,
317 descriptor->imageSizePatterns[i].height);
319 for (uint8 i = 0; i < descriptor->NumCompressionPatterns(); i++) {
320 printf("compression%d: %d\n", i,
321 descriptor->CompressionPatterns()[i]);
323 break;
325 case VS_FORMAT_MJPEG:
327 const usbvc_format_descriptor* descriptor
328 = (const usbvc_format_descriptor*)_descriptor;
329 fMJPEGFormatIndex = descriptor->formatIndex;
330 printf("VS_FORMAT_MJPEG:\tbFormatIdx=%d,#frmdesc=%d\n",
331 descriptor->formatIndex, descriptor->numFrameDescriptors);
332 printf("\t#flgs=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
333 descriptor->mjpeg.flags,
334 descriptor->mjpeg.defaultFrameIndex,
335 descriptor->mjpeg.aspectRatioX,
336 descriptor->mjpeg.aspectRatioY);
337 printf("\tbmInterlaceFlags:\n");
338 if (descriptor->mjpeg.interlaceFlags & 1)
339 printf("\tInterlaced stream or variable\n");
340 printf("\t%d fields per frame\n",
341 (descriptor->mjpeg.interlaceFlags & 2) ? 1 : 2);
342 if (descriptor->mjpeg.interlaceFlags & 4)
343 printf("\tField 1 first\n");
344 printf("\tField Pattern: ");
345 switch ((descriptor->mjpeg.interlaceFlags & 0x30) >> 4) {
346 case 0: printf("Field 1 only\n"); break;
347 case 1: printf("Field 2 only\n"); break;
348 case 2: printf("Regular pattern of fields 1 and 2\n"); break;
349 case 3: printf("Random pattern of fields 1 and 2\n"); break;
351 if (descriptor->mjpeg.copyProtect)
352 printf("\tRestrict duplication\n");
353 break;
355 case VS_FORMAT_MPEG2TS:
356 printf("VS_FORMAT_MPEG2TS:\t\n");
357 break;
358 case VS_FORMAT_DV:
359 printf("VS_FORMAT_DV:\t\n");
360 break;
361 case VS_FORMAT_FRAME_BASED:
362 printf("VS_FORMAT_FRAME_BASED:\t\n");
363 break;
364 case VS_FRAME_FRAME_BASED:
365 printf("VS_FRAME_FRAME_BASED:\t\n");
366 break;
367 case VS_FORMAT_STREAM_BASED:
368 printf("VS_FORMAT_STREAM_BASED:\t\n");
369 break;
370 default:
371 printf("INVALID STREAM UNIT TYPE=%d!\n",
372 _descriptor->descriptorSubtype);
377 void
378 UVCCamDevice::_ParseVideoControl(const usbvc_class_descriptor* _descriptor,
379 size_t len)
381 switch (_descriptor->descriptorSubtype) {
382 case VC_HEADER:
384 if (fHeaderDescriptor != NULL) {
385 printf("ERROR: multiple VC_HEADER! Skipping...\n");
386 break;
388 fHeaderDescriptor = (usbvc_interface_header_descriptor*)malloc(len);
389 memcpy(fHeaderDescriptor, _descriptor, len);
390 printf("VC_HEADER:\tUVC v%x.%02x, clk %.5f MHz\n",
391 fHeaderDescriptor->version >> 8,
392 fHeaderDescriptor->version & 0xff,
393 fHeaderDescriptor->clockFrequency / 1000000.0);
394 for (uint8 i = 0; i < fHeaderDescriptor->numInterfacesNumbers; i++) {
395 printf("\tStreaming Interface %d\n",
396 fHeaderDescriptor->interfaceNumbers[i]);
398 break;
400 case VC_INPUT_TERMINAL:
402 const usbvc_input_terminal_descriptor* descriptor
403 = (const usbvc_input_terminal_descriptor*)_descriptor;
404 printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
405 "%d\n", descriptor->terminalID, descriptor->terminalType,
406 descriptor->associatedTerminal);
407 printf("\tDesc: %s\n",
408 fDevice->DecodeStringDescriptor(descriptor->terminal));
409 if (descriptor->terminalType == 0x201) {
410 const usbvc_camera_terminal_descriptor* desc
411 = (const usbvc_camera_terminal_descriptor*)descriptor;
412 printf("\tObjectiveFocalLength Min/Max %d/%d\n",
413 desc->objectiveFocalLengthMin,
414 desc->objectiveFocalLengthMax);
415 printf("\tOcularFocalLength %d\n", desc->ocularFocalLength);
416 printf("\tControlSize %d\n", desc->controlSize);
418 break;
420 case VC_OUTPUT_TERMINAL:
422 const usbvc_output_terminal_descriptor* descriptor
423 = (const usbvc_output_terminal_descriptor*)_descriptor;
424 printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
425 "%d, src id=%d\n", descriptor->terminalID,
426 descriptor->terminalType, descriptor->associatedTerminal,
427 descriptor->sourceID);
428 printf("\tDesc: %s\n",
429 fDevice->DecodeStringDescriptor(descriptor->terminal));
430 break;
432 case VC_SELECTOR_UNIT:
434 const usbvc_selector_unit_descriptor* descriptor
435 = (const usbvc_selector_unit_descriptor*)_descriptor;
436 printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n",
437 descriptor->unitID, descriptor->numInputPins);
438 printf("\t");
439 for (uint8 i = 0; i < descriptor->numInputPins; i++)
440 printf("%d ", descriptor->sourceID[i]);
441 printf("\n");
442 printf("\tDesc: %s\n",
443 fDevice->DecodeStringDescriptor(descriptor->Selector()));
444 break;
446 case VC_PROCESSING_UNIT:
448 const usbvc_processing_unit_descriptor* descriptor
449 = (const usbvc_processing_unit_descriptor*)_descriptor;
450 fControlRequestIndex = fControlIndex + (descriptor->unitID << 8);
451 printf("VC_PROCESSING_UNIT:\t unit id=%d,src id=%d, digmul=%d\n",
452 descriptor->unitID, descriptor->sourceID,
453 descriptor->maxMultiplier);
454 printf("\tbControlSize=%d\n", descriptor->controlSize);
455 if (descriptor->controlSize >= 1) {
456 if (descriptor->controls[0] & 1)
457 printf("\tBrightness\n");
458 if (descriptor->controls[0] & 2)
459 printf("\tContrast\n");
460 if (descriptor->controls[0] & 4)
461 printf("\tHue\n");
462 if (descriptor->controls[0] & 8)
463 printf("\tSaturation\n");
464 if (descriptor->controls[0] & 16)
465 printf("\tSharpness\n");
466 if (descriptor->controls[0] & 32)
467 printf("\tGamma\n");
468 if (descriptor->controls[0] & 64)
469 printf("\tWhite Balance Temperature\n");
470 if (descriptor->controls[0] & 128)
471 printf("\tWhite Balance Component\n");
473 if (descriptor->controlSize >= 2) {
474 if (descriptor->controls[1] & 1)
475 printf("\tBacklight Compensation\n");
476 if (descriptor->controls[1] & 2)
477 printf("\tGain\n");
478 if (descriptor->controls[1] & 4)
479 printf("\tPower Line Frequency\n");
480 if (descriptor->controls[1] & 8)
481 printf("\t[AUTO] Hue\n");
482 if (descriptor->controls[1] & 16)
483 printf("\t[AUTO] White Balance Temperature\n");
484 if (descriptor->controls[1] & 32)
485 printf("\t[AUTO] White Balance Component\n");
486 if (descriptor->controls[1] & 64)
487 printf("\tDigital Multiplier\n");
488 if (descriptor->controls[1] & 128)
489 printf("\tDigital Multiplier Limit\n");
491 if (descriptor->controlSize >= 3) {
492 if (descriptor->controls[2] & 1)
493 printf("\tAnalog Video Standard\n");
494 if (descriptor->controls[2] & 2)
495 printf("\tAnalog Video Lock Status\n");
497 printf("\tDesc: %s\n",
498 fDevice->DecodeStringDescriptor(descriptor->Processing()));
499 if (descriptor->VideoStandards() & 2)
500 printf("\tNTSC 525/60\n");
501 if (descriptor->VideoStandards() & 4)
502 printf("\tPAL 625/50\n");
503 if (descriptor->VideoStandards() & 8)
504 printf("\tSECAM 625/50\n");
505 if (descriptor->VideoStandards() & 16)
506 printf("\tNTSC 625/50\n");
507 if (descriptor->VideoStandards() & 32)
508 printf("\tPAL 525/60\n");
509 break;
511 case VC_EXTENSION_UNIT:
513 const usbvc_extension_unit_descriptor* descriptor
514 = (const usbvc_extension_unit_descriptor*)_descriptor;
515 printf("VC_EXTENSION_UNIT:\tid=%d, guid=", descriptor->unitID);
516 print_guid(descriptor->guidExtensionCode);
517 printf("\n\t#ctrls=%d, #pins=%d\n", descriptor->numControls,
518 descriptor->numInputPins);
519 printf("\t");
520 for (uint8 i = 0; i < descriptor->numInputPins; i++)
521 printf("%d ", descriptor->sourceID[i]);
522 printf("\n");
523 printf("\tDesc: %s\n",
524 fDevice->DecodeStringDescriptor(descriptor->Extension()));
525 break;
527 default:
528 printf("Unknown control %d\n", _descriptor->descriptorSubtype);
533 bool
534 UVCCamDevice::SupportsIsochronous()
536 return true;
540 status_t
541 UVCCamDevice::StartTransfer()
543 if (_ProbeCommitFormat() != B_OK || _SelectBestAlternate() != B_OK)
544 return B_ERROR;
545 return CamDevice::StartTransfer();
549 status_t
550 UVCCamDevice::StopTransfer()
552 _SelectIdleAlternate();
553 return CamDevice::StopTransfer();
557 status_t
558 UVCCamDevice::SuggestVideoFrame(uint32& width, uint32& height)
560 printf("UVCCamDevice::SuggestVideoFrame(%ld, %ld)\n", width, height);
561 // As in AcceptVideoFrame(), the suggestion should probably just be the
562 // first advertised uncompressed format, but current applications prefer
563 // 320x240, so this is tried first here as a suggestion.
564 width = 320;
565 height = 240;
566 if (!AcceptVideoFrame(width, height)) {
567 const usbvc_frame_descriptor* descriptor
568 = (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
569 width = (*descriptor).width;
570 height = (*descriptor).height;
572 return B_OK;
576 status_t
577 UVCCamDevice::AcceptVideoFrame(uint32& width, uint32& height)
579 printf("UVCCamDevice::AcceptVideoFrame(%ld, %ld)\n", width, height);
580 if (width <= 0 || height <= 0) {
581 // Uncomment below when applications support dimensions other than 320x240
582 // This code selects the first listed available uncompressed frame format
584 const usbvc_frame_descriptor* descriptor
585 = (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
586 width = (*descriptor).width;
587 height = (*descriptor).height;
588 SetVideoFrame(BRect(0, 0, width - 1, height - 1));
589 return B_OK;
592 width = 320;
593 height = 240;
596 for (int i = 0; i<fUncompressedFrames.CountItems(); i++) {
597 const usbvc_frame_descriptor* descriptor
598 = (const usbvc_frame_descriptor*)fUncompressedFrames.ItemAt(i);
599 if ((*descriptor).width == width && (*descriptor).height == height) {
600 fUncompressedFrameIndex = i;
601 SetVideoFrame(BRect(0, 0, width - 1, height - 1));
602 return B_OK;
606 fprintf(stderr, "UVCCamDevice::AcceptVideoFrame() Invalid frame dimensions"
607 "\n");
608 return B_ERROR;
612 status_t
613 UVCCamDevice::_ProbeCommitFormat()
615 printf("UVCCamDevice::_ProbeCommitFormat()\n");
616 printf("UVCCamDevice::fStreamingIndex = %ld\n", fStreamingIndex);
619 char error;
620 printf("BEFORE ERROR CODE CHECK.\n");
621 fDevice->ControlTransfer(
622 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_CUR,
623 VS_STREAM_ERROR_CODE_CONTROL << 8, fStreamingIndex, 1, &error);
624 printf("Error code = Ox%x\n", error);
627 usbvc_probecommit request;
628 memset(&request, 0, sizeof(request));
629 request.hint = 1;
630 request.SetFrameInterval(333333);
631 request.formatIndex = fUncompressedFormatIndex;
632 request.frameIndex = fUncompressedFrameIndex;
633 size_t length = fHeaderDescriptor->version > 0x100 ? 34 : 26;
634 size_t actualLength = fDevice->ControlTransfer(
635 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
636 VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
637 if (actualLength != length) {
638 fprintf(stderr, "UVCCamDevice::_ProbeFormat() SET_CUR ProbeControl1"
639 " failed %ld\n", actualLength);
640 return B_ERROR;
644 usbvc_probecommit response;
645 actualLength = fDevice->ControlTransfer(
646 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_MAX,
647 VS_PROBE_CONTROL << 8, fStreamingIndex, sizeof(response), &response);
648 if (actualLength != sizeof(response)) {
649 fprintf(stderr, "UVCCamDevice::_ProbeFormat() GetMax ProbeControl"
650 " failed\n");
651 return B_ERROR;
654 printf("usbvc_probecommit response.compQuality %d\n", response.compQuality);
655 request.compQuality = response.compQuality;
659 usbvc_probecommit response;
660 memset(&response, 0, sizeof(response));
661 actualLength = fDevice->ControlTransfer(
662 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_CUR,
663 VS_PROBE_CONTROL << 8, fStreamingIndex, length, &response);
666 actualLength = fDevice->ControlTransfer(
667 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
668 VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
669 if (actualLength != length) {
670 fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur ProbeControl2"
671 " failed\n");
672 return B_ERROR;
676 actualLength = fDevice->ControlTransfer(
677 USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
678 VS_COMMIT_CONTROL << 8, fStreamingIndex, length, &request);
679 if (actualLength != length) {
680 fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur CommitControl"
681 " failed\n");
682 return B_ERROR;
686 fMaxVideoFrameSize = response.maxVideoFrameSize;
687 fMaxPayloadTransferSize = response.maxPayloadTransferSize;
688 printf("usbvc_probecommit setup done maxVideoFrameSize:%ld"
689 " maxPayloadTransferSize:%ld\n", fMaxVideoFrameSize,
690 fMaxPayloadTransferSize);
692 printf("UVCCamDevice::_ProbeCommitFormat()\n --> SUCCESSFUL\n");
693 return B_OK;
697 status_t
698 UVCCamDevice::_SelectBestAlternate()
700 printf("UVCCamDevice::_SelectBestAlternate()\n");
701 const BUSBConfiguration* config = fDevice->ActiveConfiguration();
702 const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
703 if (streaming == NULL)
704 return B_BAD_INDEX;
706 uint32 bestBandwidth = 0;
707 uint32 alternateIndex = 0;
708 uint32 endpointIndex = 0;
710 for (uint32 i = 0; i < streaming->CountAlternates(); i++) {
711 const BUSBInterface* alternate = streaming->AlternateAt(i);
712 for (uint32 j = 0; j < alternate->CountEndpoints(); j++) {
713 const BUSBEndpoint* endpoint = alternate->EndpointAt(j);
714 if (!endpoint->IsIsochronous() || !endpoint->IsInput())
715 continue;
716 if (fMaxPayloadTransferSize > endpoint->MaxPacketSize())
717 continue;
718 if (bestBandwidth != 0
719 && bestBandwidth < endpoint->MaxPacketSize())
720 continue;
721 bestBandwidth = endpoint->MaxPacketSize();
722 endpointIndex = j;
723 alternateIndex = i;
727 if (bestBandwidth == 0) {
728 fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
729 " couldn't find a valid alternate\n");
730 return B_ERROR;
733 printf("UVCCamDevice::_SelectBestAlternate() %ld\n", bestBandwidth);
734 if (((BUSBInterface*)streaming)->SetAlternate(alternateIndex) != B_OK) {
735 fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
736 " selecting alternate failed\n");
737 return B_ERROR;
740 fIsoIn = streaming->EndpointAt(endpointIndex);
742 return B_OK;
746 status_t
747 UVCCamDevice::_SelectIdleAlternate()
749 printf("UVCCamDevice::_SelectIdleAlternate()\n");
750 const BUSBConfiguration* config = fDevice->ActiveConfiguration();
751 const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
752 if (streaming == NULL)
753 return B_BAD_INDEX;
754 if (((BUSBInterface*)streaming)->SetAlternate(0) != B_OK) {
755 fprintf(stderr, "UVCCamDevice::_SelectIdleAlternate()"
756 " selecting alternate failed\n");
757 return B_ERROR;
760 fIsoIn = NULL;
762 return B_OK;
766 void
767 UVCCamDevice::_AddProcessingParameter(BParameterGroup* group,
768 int32 index, const usbvc_processing_unit_descriptor* descriptor)
770 BParameterGroup* subgroup;
771 BContinuousParameter* p;
772 uint16 wValue = 0; // Control Selector
773 float minValue = 0.0;
774 float maxValue = 100.0;
775 if (descriptor->controlSize >= 1) {
776 if (descriptor->controls[0] & 1) {
777 // debug_printf("\tBRIGHTNESS\n");
778 fBrightness = _AddParameter(group, &subgroup, index,
779 PU_BRIGHTNESS_CONTROL, "Brightness");
781 if (descriptor->controls[0] & 2) {
782 // debug_printf("\tCONSTRAST\n");
783 fContrast = _AddParameter(group, &subgroup, index + 1,
784 PU_CONTRAST_CONTROL, "Contrast");
786 if (descriptor->controls[0] & 4) {
787 // debug_printf("\tHUE\n");
788 fHue = _AddParameter(group, &subgroup, index + 2,
789 PU_HUE_CONTROL, "Hue");
790 if (descriptor->controlSize >= 2) {
791 if (descriptor->controls[1] & 8) {
792 fHueAuto = _AddAutoParameter(subgroup, index + 3,
793 PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
797 if (descriptor->controls[0] & 8) {
798 // debug_printf("\tSATURATION\n");
799 fSaturation = _AddParameter(group, &subgroup, index + 4,
800 PU_SATURATION_CONTROL, "Saturation");
802 if (descriptor->controls[0] & 16) {
803 // debug_printf("\tSHARPNESS\n");
804 fSharpness = _AddParameter(group, &subgroup, index + 5,
805 PU_SHARPNESS_CONTROL, "Sharpness");
807 if (descriptor->controls[0] & 32) {
808 // debug_printf("\tGamma\n");
809 fGamma = _AddParameter(group, &subgroup, index + 6,
810 PU_GAMMA_CONTROL, "Gamma");
812 if (descriptor->controls[0] & 64) {
813 // debug_printf("\tWHITE BALANCE TEMPERATURE\n");
814 fWBTemp = _AddParameter(group, &subgroup, index + 7,
815 PU_WHITE_BALANCE_TEMPERATURE_CONTROL, "WB Temperature");
816 if (descriptor->controlSize >= 2) {
817 if (descriptor->controls[1] & 16) {
818 fWBTempAuto = _AddAutoParameter(subgroup, index + 8,
819 PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
823 if (descriptor->controls[0] & 128) {
824 // debug_printf("\tWhite Balance Component\n");
825 fWBComponent = _AddParameter(group, &subgroup, index + 9,
826 PU_WHITE_BALANCE_COMPONENT_CONTROL, "WB Component");
827 if (descriptor->controlSize >= 2) {
828 if (descriptor->controls[1] & 32) {
829 fWBTempAuto = _AddAutoParameter(subgroup, index + 10,
830 PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL);
835 if (descriptor->controlSize >= 2) {
836 if (descriptor->controls[1] & 1) {
837 // debug_printf("\tBACKLIGHT COMPENSATION\n");
838 int16 data;
839 wValue = PU_BACKLIGHT_COMPENSATION_CONTROL << 8;
840 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
841 GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data);
842 maxValue = (float)data;
843 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
844 GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data);
845 minValue = (float)data;
846 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
847 GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data);
848 fBacklightCompensation = (float)data;
849 subgroup = group->MakeGroup("Backlight Compensation");
850 if (maxValue - minValue == 1) { // Binary Switch
851 fBinaryBacklightCompensation = true;
852 subgroup->MakeDiscreteParameter(index + 11,
853 B_MEDIA_RAW_VIDEO, "Backlight Compensation",
854 B_ENABLE);
855 } else { // Range of values
856 fBinaryBacklightCompensation = false;
857 p = subgroup->MakeContinuousParameter(index + 11,
858 B_MEDIA_RAW_VIDEO, "Backlight Compensation",
859 B_GAIN, "", minValue, maxValue, 1.0 / (maxValue - minValue));
862 if (descriptor->controls[1] & 2) {
863 // debug_printf("\tGAIN\n");
864 fGain = _AddParameter(group, &subgroup, index + 12, PU_GAIN_CONTROL,
865 "Gain");
867 if (descriptor->controls[1] & 4) {
868 // debug_printf("\tPOWER LINE FREQUENCY\n");
869 wValue = PU_POWER_LINE_FREQUENCY_CONTROL << 8;
870 int8 data;
871 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
872 GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data) == sizeof(data)) {
873 fPowerlineFrequency = data;
875 subgroup = group->MakeGroup("Power Line Frequency");
876 p = subgroup->MakeContinuousParameter(index + 13,
877 B_MEDIA_RAW_VIDEO, "Frequency", B_GAIN, "", 0, 60.0, 1.0 / 60.0);
879 // TODO Determine whether controls apply to these
881 if (descriptor->controls[1] & 64)
882 debug_printf("\tDigital Multiplier\n");
883 if (descriptor->controls[1] & 128)
884 debug_printf("\tDigital Multiplier Limit\n");
887 // TODO Determine whether controls apply to these
889 if (descriptor->controlSize >= 3) {
890 if (descriptor->controls[2] & 1)
891 debug_printf("\tAnalog Video Standard\n");
892 if (descriptor->controls[2] & 2)
893 debug_printf("\tAnalog Video Lock Status\n");
901 float
902 UVCCamDevice::_AddParameter(BParameterGroup* group,
903 BParameterGroup** subgroup, int32 index, uint16 wValue, const char* name)
905 float minValue = 0.0;
906 float maxValue = 100.0;
907 float currValue = 0.0;
908 int16 data;
910 wValue <<= 8;
912 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
913 GET_MAX, wValue, fControlRequestIndex, sizeof(data), &data)
914 == sizeof(data)) {
915 maxValue = (float)data;
917 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
918 GET_MIN, wValue, fControlRequestIndex, sizeof(data), &data)
919 == sizeof(data)) {
920 minValue = (float)data;
922 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
923 GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
924 == sizeof(data)) {
925 currValue = (float)data;
928 *subgroup = group->MakeGroup(name);
929 BContinuousParameter* p = (*subgroup)->MakeContinuousParameter(index,
930 B_MEDIA_RAW_VIDEO, name, B_GAIN, "", minValue, maxValue,
931 1.0 / (maxValue - minValue));
932 return currValue;
936 uint8
937 UVCCamDevice::_AddAutoParameter(BParameterGroup* subgroup, int32 index,
938 uint16 wValue)
940 uint8 data;
941 wValue <<= 8;
943 fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
944 GET_CUR, wValue, fControlRequestIndex, 1, &data);
945 subgroup->MakeDiscreteParameter(index, B_MEDIA_RAW_VIDEO, "Auto",
946 B_ENABLE);
948 return data;
952 void
953 UVCCamDevice::AddParameters(BParameterGroup* group, int32& index)
955 printf("UVCCamDevice::AddParameters()\n");
956 fFirstParameterID = index;
957 // debug_printf("fIndex = %d\n",fIndex);
958 CamDevice::AddParameters(group, index);
960 const BUSBConfiguration* config;
961 const BUSBInterface* interface;
962 uint8 buffer[1024];
964 usb_descriptor* generic = (usb_descriptor*)buffer;
966 for (uint32 i = 0; i < fDevice->CountConfigurations(); i++) {
967 config = fDevice->ConfigurationAt(i);
968 if (config == NULL)
969 continue;
970 fDevice->SetConfiguration(config);
971 for (uint32 j = 0; j < config->CountInterfaces(); j++) {
972 interface = config->InterfaceAt(j);
973 if (interface == NULL)
974 continue;
975 if (interface->Class() != CC_VIDEO || interface->Subclass()
976 != SC_VIDEOCONTROL)
977 continue;
978 for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
979 sizeof(buffer)) == B_OK; k++) {
980 if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
981 | USB_DESCRIPTOR_INTERFACE))
982 continue;
984 if (((const usbvc_class_descriptor*)generic)->descriptorSubtype
985 == VC_PROCESSING_UNIT) {
986 _AddProcessingParameter(group, index,
987 (const usbvc_processing_unit_descriptor*)generic);
995 status_t
996 UVCCamDevice::GetParameterValue(int32 id, bigtime_t* last_change, void* value,
997 size_t* size)
999 printf("UVCCAmDevice::GetParameterValue(%ld)\n", id - fFirstParameterID);
1000 float* currValue;
1001 int* currValueInt;
1002 int16 data;
1003 uint16 wValue = 0;
1004 switch (id - fFirstParameterID) {
1005 case 0:
1006 // debug_printf("\tBrightness:\n");
1007 // debug_printf("\tValue = %f\n",fBrightness);
1008 *size = sizeof(float);
1009 currValue = (float*)value;
1010 *currValue = fBrightness;
1011 *last_change = fLastParameterChanges;
1012 return B_OK;
1013 case 1:
1014 // debug_printf("\tContrast:\n");
1015 // debug_printf("\tValue = %f\n",fContrast);
1016 *size = sizeof(float);
1017 currValue = (float*)value;
1018 *currValue = fContrast;
1019 *last_change = fLastParameterChanges;
1020 return B_OK;
1021 case 2:
1022 // debug_printf("\tHue:\n");
1023 // debug_printf("\tValue = %f\n",fHue);
1024 *size = sizeof(float);
1025 currValue = (float*)value;
1026 *currValue = fHue;
1027 *last_change = fLastParameterChanges;
1028 return B_OK;
1029 case 4:
1030 // debug_printf("\tSaturation:\n");
1031 // debug_printf("\tValue = %f\n",fSaturation);
1032 *size = sizeof(float);
1033 currValue = (float*)value;
1034 *currValue = fSaturation;
1035 *last_change = fLastParameterChanges;
1036 return B_OK;
1037 case 5:
1038 // debug_printf("\tSharpness:\n");
1039 // debug_printf("\tValue = %f\n",fSharpness);
1040 *size = sizeof(float);
1041 currValue = (float*)value;
1042 *currValue = fSharpness;
1043 *last_change = fLastParameterChanges;
1044 return B_OK;
1045 case 7:
1046 // debug_printf("\tWB Temperature:\n");
1047 *size = sizeof(float);
1048 currValue = (float*)value;
1049 wValue = PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8;
1050 if (fDevice->ControlTransfer(USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN,
1051 GET_CUR, wValue, fControlRequestIndex, sizeof(data), &data)
1052 == sizeof(data)) {
1053 fWBTemp = (float)data;
1055 // debug_printf("\tValue = %f\n",fWBTemp);
1056 *currValue = fWBTemp;
1057 *last_change = fLastParameterChanges;
1058 return B_OK;
1059 case 8:
1060 // debug_printf("\tWB Temperature Auto:\n");
1061 // debug_printf("\tValue = %d\n",fWBTempAuto);
1062 *size = sizeof(int);
1063 currValueInt = ((int*)value);
1064 *currValueInt = fWBTempAuto;
1065 *last_change = fLastParameterChanges;
1066 return B_OK;
1067 case 11:
1068 if (!fBinaryBacklightCompensation) {
1069 // debug_printf("\tBacklight Compensation:\n");
1070 // debug_printf("\tValue = %f\n",fBacklightCompensation);
1071 *size = sizeof(float);
1072 currValue = (float*)value;
1073 *currValue = fBacklightCompensation;
1074 *last_change = fLastParameterChanges;
1075 } else {
1076 // debug_printf("\tBacklight Compensation:\n");
1077 // debug_printf("\tValue = %d\n",fBacklightCompensationBinary);
1078 currValueInt = (int*)value;
1079 *currValueInt = fBacklightCompensationBinary;
1080 *last_change = fLastParameterChanges;
1082 return B_OK;
1083 case 12:
1084 // debug_printf("\tGain:\n");
1085 // debug_printf("\tValue = %f\n",fGain);
1086 *size = sizeof(float);
1087 currValue = (float*)value;
1088 *currValue = fGain;
1089 *last_change = fLastParameterChanges;
1090 return B_OK;
1091 case 13:
1092 // debug_printf("\tPowerline Frequency:\n");
1093 // debug_printf("\tValue = %d\n",fPowerlineFrequency);
1094 *size = sizeof(float);
1095 currValue = (float*)value;
1096 switch (fPowerlineFrequency) {
1097 case 0:
1098 *currValue = 0.0;
1099 break;
1100 case 1:
1101 *currValue = 50.0;
1102 break;
1103 case 2:
1104 *currValue = 60.0;
1105 break;
1107 *last_change = fLastParameterChanges;
1108 return B_OK;
1111 return B_BAD_VALUE;
1115 status_t
1116 UVCCamDevice::SetParameterValue(int32 id, bigtime_t when, const void* value,
1117 size_t size)
1119 printf("UVCCamDevice::SetParameterValue(%ld)\n", id - fFirstParameterID);
1120 switch (id - fFirstParameterID) {
1121 case 0:
1122 // debug_printf("\tBrightness:\n");
1123 if (!value || (size != sizeof(float)))
1124 return B_BAD_VALUE;
1125 fBrightness = *((float*)value);
1126 fLastParameterChanges = when;
1127 return _SetParameterValue(PU_BRIGHTNESS_CONTROL, (int16)fBrightness);
1128 case 1:
1129 // debug_printf("\tContrast:\n");
1130 if (!value || (size != sizeof(float)))
1131 return B_BAD_VALUE;
1132 fContrast = *((float*)value);
1133 fLastParameterChanges = when;
1134 return _SetParameterValue(PU_CONTRAST_CONTROL, (int16)fContrast);
1135 case 2:
1136 // debug_printf("\tHue:\n");
1137 if (!value || (size != sizeof(float)))
1138 return B_BAD_VALUE;
1139 fHue = *((float*)value);
1140 fLastParameterChanges = when;
1141 return _SetParameterValue(PU_HUE_CONTROL, (int16)fHue);
1142 case 4:
1143 // debug_printf("\tSaturation:\n");
1144 if (!value || (size != sizeof(float)))
1145 return B_BAD_VALUE;
1146 fSaturation = *((float*)value);
1147 fLastParameterChanges = when;
1148 return _SetParameterValue(PU_SATURATION_CONTROL, (int16)fSaturation);
1149 case 5:
1150 // debug_printf("\tSharpness:\n");
1151 if (!value || (size != sizeof(float)))
1152 return B_BAD_VALUE;
1153 fSharpness = *((float*)value);
1154 fLastParameterChanges = when;
1155 return _SetParameterValue(PU_SHARPNESS_CONTROL, (int16)fSharpness);
1156 case 7:
1157 if (fWBTempAuto)
1158 return B_OK;
1159 // debug_printf("\tWB Temperature:\n");
1160 if (!value || (size != sizeof(float)))
1161 return B_BAD_VALUE;
1162 fWBTemp = *((float*)value);
1163 fLastParameterChanges = when;
1164 return _SetParameterValue(PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
1165 (int16)fWBTemp);
1166 case 8:
1167 // debug_printf("\tWB Temperature Auto:\n");
1168 if (!value || (size != sizeof(int)))
1169 return B_BAD_VALUE;
1170 fWBTempAuto = *((int*)value);
1171 fLastParameterChanges = when;
1172 return _SetParameterValue(
1173 PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, (int8)fWBTempAuto);
1174 case 11:
1175 if (!fBinaryBacklightCompensation) {
1176 // debug_printf("\tBacklight Compensation:\n");
1177 if (!value || (size != sizeof(float)))
1178 return B_BAD_VALUE;
1179 fBacklightCompensation = *((float*)value);
1180 } else {
1181 // debug_printf("\tBacklight Compensation:\n");
1182 if (!value || (size != sizeof(int)))
1183 return B_BAD_VALUE;
1184 fBacklightCompensationBinary = *((int*)value);
1186 fLastParameterChanges = when;
1187 return _SetParameterValue(PU_BACKLIGHT_COMPENSATION_CONTROL,
1188 (int16)fBacklightCompensationBinary);
1189 case 12:
1190 // debug_printf("\tGain:\n");
1191 if (!value || (size != sizeof(float)))
1192 return B_BAD_VALUE;
1193 fGain = *((float*)value);
1194 fLastParameterChanges = when;
1195 return _SetParameterValue(PU_GAIN_CONTROL, (int16)fGain);
1196 case 13:
1197 // debug_printf("\tPowerline Frequency:\n");
1198 // debug_printf("\tValue = %f\n",*((float*)value));
1199 if (!value || (size != sizeof(float)))
1200 return B_BAD_VALUE;
1201 float inValue = *((float*)value);
1202 fPowerlineFrequency = 0;
1203 if (inValue > 45.0 && inValue < 55.0) {
1204 fPowerlineFrequency = 1;
1206 if (inValue >= 55.0) {
1207 fPowerlineFrequency = 2;
1209 fLastParameterChanges = when;
1210 return _SetParameterValue(PU_POWER_LINE_FREQUENCY_CONTROL,
1211 (int8)fPowerlineFrequency);
1214 return B_BAD_VALUE;
1218 status_t
1219 UVCCamDevice::_SetParameterValue(uint16 wValue, int16 setValue)
1221 return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1222 | USB_REQTYPE_INTERFACE_OUT, SET_CUR, wValue << 8, fControlRequestIndex,
1223 sizeof(setValue), &setValue)) == sizeof(setValue);
1227 status_t
1228 UVCCamDevice::_SetParameterValue(uint16 wValue, int8 setValue)
1230 return (fDevice->ControlTransfer(USB_REQTYPE_CLASS
1231 | USB_REQTYPE_INTERFACE_OUT, SET_CUR, wValue << 8, fControlRequestIndex,
1232 sizeof(setValue), &setValue)) == sizeof(setValue);
1236 status_t
1237 UVCCamDevice::FillFrameBuffer(BBuffer* buffer, bigtime_t* stamp)
1239 memset(buffer->Data(), 0, buffer->SizeAvailable());
1240 status_t err = fDeframer->WaitFrame(2000000);
1241 if (err < B_OK) {
1242 fprintf(stderr, "WaitFrame: %lx\n", err);
1243 return err;
1246 CamFrame* f;
1247 err = fDeframer->GetFrame(&f, stamp);
1248 if (err < B_OK) {
1249 fprintf(stderr, "GetFrame: %lx\n", err);
1250 return err;
1253 long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
1254 long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
1256 if (buffer->SizeAvailable() >= (size_t)w * h * 4) {
1257 // TODO: The Video Producer only outputs B_RGB32. This is OK for most
1258 // applications. This could be leveraged if applications can
1259 // consume B_YUV422.
1260 _DecodeColor((unsigned char*)buffer->Data(),
1261 (unsigned char*)f->Buffer(), w, h);
1263 delete f;
1264 return B_OK;
1268 void
1269 UVCCamDevice::_DecodeColor(unsigned char* dst, unsigned char* src,
1270 int32 width, int32 height)
1272 long int i;
1273 unsigned char* rawpt, * scanpt;
1274 long int size;
1276 rawpt = src;
1277 scanpt = dst;
1278 size = width*height;
1280 for ( i = 0; i < size; i++ ) {
1281 if ( (i/width) % 2 == 0 ) {
1282 if ( (i % 2) == 0 ) {
1283 /* B */
1284 if ( (i > width) && ((i % width) > 0) ) {
1285 *scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1286 + *(rawpt+width-1)+*(rawpt+width+1))/4; /* R */
1287 *scanpt++ = (*(rawpt-1)+*(rawpt+1)
1288 + *(rawpt+width)+*(rawpt-width))/4; /* G */
1289 *scanpt++ = *rawpt; /* B */
1290 } else {
1291 /* first line or left column */
1292 *scanpt++ = *(rawpt+width+1); /* R */
1293 *scanpt++ = (*(rawpt+1)+*(rawpt+width))/2; /* G */
1294 *scanpt++ = *rawpt; /* B */
1296 } else {
1297 /* (B)G */
1298 if ( (i > width) && ((i % width) < (width-1)) ) {
1299 *scanpt++ = (*(rawpt+width)+*(rawpt-width))/2; /* R */
1300 *scanpt++ = *rawpt; /* G */
1301 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */
1302 } else {
1303 /* first line or right column */
1304 *scanpt++ = *(rawpt+width); /* R */
1305 *scanpt++ = *rawpt; /* G */
1306 *scanpt++ = *(rawpt-1); /* B */
1309 } else {
1310 if ( (i % 2) == 0 ) {
1311 /* G(R) */
1312 if ( (i < (width*(height-1))) && ((i % width) > 0) ) {
1313 *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */
1314 *scanpt++ = *rawpt; /* G */
1315 *scanpt++ = (*(rawpt+width)+*(rawpt-width))/2; /* B */
1316 } else {
1317 /* bottom line or left column */
1318 *scanpt++ = *(rawpt+1); /* R */
1319 *scanpt++ = *rawpt; /* G */
1320 *scanpt++ = *(rawpt-width); /* B */
1322 } else {
1323 /* R */
1324 if ( i < (width*(height-1)) && ((i % width) < (width-1)) ) {
1325 *scanpt++ = *rawpt; /* R */
1326 *scanpt++ = (*(rawpt-1)+*(rawpt+1)
1327 + *(rawpt-width)+*(rawpt+width))/4; /* G */
1328 *scanpt++ = (*(rawpt-width-1)+*(rawpt-width+1)
1329 + *(rawpt+width-1)+*(rawpt+width+1))/4; /* B */
1330 } else {
1331 /* bottom line or right column */
1332 *scanpt++ = *rawpt; /* R */
1333 *scanpt++ = (*(rawpt-1)+*(rawpt-width))/2; /* G */
1334 *scanpt++ = *(rawpt-width-1); /* B */
1338 rawpt++;
1345 UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)
1346 : CamDeviceAddon(webcam)
1348 printf("UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam)\n");
1349 SetSupportedDevices(kSupportedDevices);
1353 UVCCamDeviceAddon::~UVCCamDeviceAddon()
1358 const char *
1359 UVCCamDeviceAddon::BrandName()
1361 printf("UVCCamDeviceAddon::BrandName()\n");
1362 return "USB Video Class";
1366 UVCCamDevice *
1367 UVCCamDeviceAddon::Instantiate(CamRoster& roster, BUSBDevice* from)
1369 printf("UVCCamDeviceAddon::Instantiate()\n");
1370 return new UVCCamDevice(*this, from);
1374 extern "C" status_t
1375 B_WEBCAM_MKINTFUNC(uvccam)
1376 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
1378 *addon = new UVCCamDeviceAddon(webcam);
1379 return B_OK;