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