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