1 /* 2 * Copyright 2009, Ithamar Adema, <ithamar.adema@team-embedded.nl>. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "UVCCamDevice.h" 8 #include "USB_video.h" 9 10 #include <stdio.h> 11 12 13 usb_webcam_support_descriptor kSupportedDevices[] = { 14 // ofcourse we support a generic UVC device... 15 {{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "USB", "Video Class", "??" }, 16 // ...whilst the following IDs were 'stolen' from a recent Linux driver: 17 {{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft", "Lifecam NX-6000", "??" }, 18 {{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft", "Lifecam VX-7000", "??" }, 19 {{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech", "QuickCam Fusion", "??" }, 20 {{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech", "QuickCam Orbit MP", "??" }, 21 {{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech", "QuickCam Pro for Notebook", "??" }, 22 {{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech", "QuickCam Pro 5000", "??" }, 23 {{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech", "QuickCam OEM Dell Notebook", "??" }, 24 {{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech", "QuickCam OEM Cisco VT Camera II", "??" }, 25 {{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple", "Built-In iSight", "??" }, 26 {{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera", "??" }, 27 {{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A", "MT6227", "??" }, 28 {{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek", "(HP Spartan)", "??" }, 29 {{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek", "(Samsung Q310)", "??" }, 30 {{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek", "Asus F9SG", "??" }, 31 {{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek", "Asus U3S", "??" }, 32 {{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A", "Lenovo Thinkpad SL500", "??" }, 33 {{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm", "Pico iMage", "??" }, 34 {{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin", "ProScopeHR", "??" }, 35 {{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro", "USB Web Camera", "??" }, 36 {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL } 37 }; 38 39 /* Table 2-1 Compression Formats of USB Video Payload Uncompressed */ 40 uint8 yuy2_guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 41 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}; 42 uint8 nv12_guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 43 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}; 44 45 static void 46 print_guid(const uint8* buf) 47 { 48 printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 49 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], 50 buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); 51 } 52 53 54 UVCCamDevice::UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) 55 : CamDevice(_addon, _device) 56 { 57 const BUSBConfiguration* uc; 58 const BUSBInterface* ui; 59 usb_descriptor *generic; 60 uint32 cfg, intf, di; 61 uint8 buffer[1024]; 62 63 generic = (usb_descriptor *)buffer; 64 65 for (cfg=0; cfg < _device->CountConfigurations(); cfg++) { 66 uc = _device->ConfigurationAt(cfg); 67 for (intf=0; intf < uc->CountInterfaces(); intf++) { 68 ui = uc->InterfaceAt(intf); 69 70 if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOCONTROL) { 71 printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf); 72 73 // look for class specific interface descriptors and parse them 74 for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di) 75 if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE)) 76 ParseVideoControl(buffer, generic->generic.length); 77 78 fInitStatus = B_OK; 79 } else if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOSTREAMING) { 80 printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf); 81 82 // look for class specific interface descriptors and parse them 83 for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di) 84 if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE)) 85 ParseVideoStreaming(buffer, generic->generic.length); 86 } 87 } 88 } 89 } 90 91 92 void 93 UVCCamDevice::ParseVideoStreaming(const uint8* buffer, size_t len) 94 { 95 int c, i, sz; 96 97 switch(buffer[2]) { 98 case VS_INPUT_HEADER: 99 c = buffer[3]; 100 printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", c, buffer[6]); 101 if (buffer[7] & 1) printf("\tDynamic Format Change supported\n"); 102 printf("\toutput terminal id=%d\n", buffer[8]); 103 printf("\tstill capture method=%d\n", buffer[9]); 104 if (buffer[10]) 105 printf("\ttrigger button fixed to still capture=%s\n", buffer[11] ? "no" : "yes"); 106 sz = buffer[12]; 107 for (i=0; i < c; i++) { 108 printf("\tfmt%d: %s %s %s %s - %s %s\n", i, 109 (buffer[13+(sz*i)] & 1) ? "wKeyFrameRate" : "", 110 (buffer[13+(sz*i)] & 2) ? "wPFrameRate" : "", 111 (buffer[13+(sz*i)] & 4) ? "wCompQuality" : "", 112 (buffer[13+(sz*i)] & 8) ? "wCompWindowSize" : "", 113 (buffer[13+(sz*i)] & 16) ? "<Generate Key Frame>" : "", 114 (buffer[13+(sz*i)] & 32) ? "<Update Frame Segment>" : ""); 115 } 116 break; 117 case VS_FORMAT_UNCOMPRESSED: 118 c = buffer[4]; 119 printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=", buffer[3], c); 120 print_guid(buffer+5); 121 printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n", buffer[21], buffer[22], 122 buffer[23], buffer[24]); 123 printf("\tbmInterlaceFlags:\n"); 124 if (buffer[25] & 1) printf("\tInterlaced stream or variable\n"); 125 printf("\t%d fields per frame\n", (buffer[25] & 2) ? 1 : 2); 126 if (buffer[25] & 4) printf("\tField 1 first\n"); 127 printf("\tField Pattern: "); 128 switch((buffer[25] & 0x30) >> 4) { 129 case 0: printf("Field 1 only\n"); break; 130 case 1: printf("Field 2 only\n"); break; 131 case 2: printf("Regular pattern of fields 1 and 2\n"); break; 132 case 3: printf("Random pattern of fields 1 and 2\n"); break; 133 } 134 if (buffer[26]) printf("\tRestrict duplication\n"); break; 135 break; 136 case VS_FRAME_UNCOMPRESSED: 137 printf("VS_FRAME_UNCOMPRESSED:\tbFrameIdx=%d,stillsupported=%s,fixedfrmrate=%s\n", 138 buffer[3], (buffer[4]&1)?"yes":"no", (buffer[4]&2)?"yes":"no"); 139 printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n", 140 *(uint16*)(buffer+5), *(uint16*)(buffer+7), 141 *(uint32*)(buffer+9), *(uint32*)(buffer+13), 142 *(uint32*)(buffer+17)); 143 printf("\tframe interval: %lu, #intervals(0=cont): %d\n", *(uint32*)(buffer+21), buffer[25]); 144 //TODO print interval table 145 break; 146 case VS_COLORFORMAT: 147 printf("VS_COLORFORMAT:\n\tbColorPrimaries: "); 148 switch(buffer[3]) { 149 case 0: printf("Unspecified\n"); break; 150 case 1: printf("BT.709,sRGB\n"); break; 151 case 2: printf("BT.470-2(M)\n"); break; 152 case 3: printf("BT.470-2(B,G)\n"); break; 153 case 4: printf("SMPTE 170M\n"); break; 154 case 5: printf("SMPTE 240M\n"); break; 155 default: printf("Invalid (%d)\n", buffer[3]); 156 } 157 printf("\tbTransferCharacteristics: "); 158 switch(buffer[4]) { 159 case 0: printf("Unspecified\n"); break; 160 case 1: printf("BT.709\n"); break; 161 case 2: printf("BT.470-2(M)\n"); break; 162 case 3: printf("BT.470-2(B,G)\n"); break; 163 case 4: printf("SMPTE 170M\n"); break; 164 case 5: printf("SMPTE 240M\n"); break; 165 case 6: printf("Linear (V=Lc)\n"); break; 166 case 7: printf("sRGB\n"); break; 167 default: printf("Invalid (%d)\n", buffer[4]); 168 } 169 printf("\tbMatrixCoefficients: "); 170 switch(buffer[5]) { 171 case 0: printf("Unspecified\n"); break; 172 case 1: printf("BT.709\n"); break; 173 case 2: printf("FCC\n"); break; 174 case 3: printf("BT.470-2(B,G)\n"); break; 175 case 4: printf("SMPTE 170M (BT.601)\n"); break; 176 case 5: printf("SMPTE 240M\n"); break; 177 default: printf("Invalid (%d)\n", buffer[5]); 178 } 179 break; 180 181 case VS_OUTPUT_HEADER: 182 printf("VS_OUTPUT_HEADER:\t\n"); 183 break; 184 case VS_STILL_IMAGE_FRAME: 185 printf("VS_STILL_IMAGE_FRAME:\t\n"); 186 break; 187 case VS_FORMAT_MJPEG: 188 printf("VS_FORMAT_MJPEG:\t\n"); 189 break; 190 case VS_FRAME_MJPEG: 191 printf("VS_FRAME_MJPEG:\t\n"); 192 break; 193 case VS_FORMAT_MPEG2TS: 194 printf("VS_FORMAT_MPEG2TS:\t\n"); 195 break; 196 case VS_FORMAT_DV: 197 printf("VS_FORMAT_DV:\t\n"); 198 break; 199 case VS_FORMAT_FRAME_BASED: 200 printf("VS_FORMAT_FRAME_BASED:\t\n"); 201 break; 202 case VS_FRAME_FRAME_BASED: 203 printf("VS_FRAME_FRAME_BASED:\t\n"); 204 break; 205 case VS_FORMAT_STREAM_BASED: 206 printf("VS_FORMAT_STREAM_BASED:\t\n"); 207 break; 208 default: 209 printf("INVALID STREAM UNIT TYPE=%d!\n", buffer[2]); 210 } 211 } 212 213 214 void 215 UVCCamDevice::ParseVideoControl(const uint8* buffer, size_t len) 216 { 217 int c, i; 218 219 switch(buffer[2]) { 220 case VC_HEADER: 221 printf("VC_HEADER:\tUVC v%04x, clk %lu Hz\n", *(uint16*)(buffer+3), *(uint32*)(buffer+7)); 222 c = (len >= 12) ? buffer[11] : 0; 223 for (i=0; i < c; i++) 224 printf("\tStreaming Interface %d\n", buffer[12+i]); 225 break; 226 227 case VC_INPUT_TERMINAL: 228 printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal=%d\n", buffer[3], *(uint16*)(buffer+4), buffer[6]); 229 printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[7])); 230 break; 231 232 case VC_OUTPUT_TERMINAL: 233 printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal=%d, src id=%d\n", buffer[3], *(uint16*)(buffer+4), buffer[6], buffer[7]); 234 printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[8])); 235 break; 236 237 case VC_SELECTOR_UNIT: 238 printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n", buffer[3], buffer[4]); 239 printf("\t"); 240 for (i=0; i < buffer[4]; i++) 241 printf("%d ", buffer[5+i]); 242 printf("\n"); 243 printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[5+buffer[4]])); 244 break; 245 246 case VC_PROCESSING_UNIT: 247 printf("VC_PROCESSING_UNIT:\tid=%d,src id=%d, digmul=%d\n", buffer[3], buffer[4], *(uint16*)(buffer+5)); 248 c = buffer[7]; 249 printf("\tbControlSize=%d\n", c); 250 if (c >= 1) { 251 if (buffer[8] & 1) printf("\tBrightness\n"); 252 if (buffer[8] & 2) printf("\tContrast\n"); 253 if (buffer[8] & 4) printf("\tHue\n"); 254 if (buffer[8] & 8) printf("\tSaturation\n"); 255 if (buffer[8] & 16) printf("\tSharpness\n"); 256 if (buffer[8] & 32) printf("\tGamma\n"); 257 if (buffer[8] & 64) printf("\tWhite Balance Temperature\n"); 258 if (buffer[8] & 128) printf("\tWhite Balance Component\n"); 259 } 260 if (c >= 2) { 261 if (buffer[9] & 1) printf("\tBacklight Compensation\n"); 262 if (buffer[9] & 2) printf("\tGain\n"); 263 if (buffer[9] & 4) printf("\tPower Line Frequency\n"); 264 if (buffer[9] & 8) printf("\t[AUTO] Hue\n"); 265 if (buffer[9] & 16) printf("\t[AUTO] White Balance Temperature\n"); 266 if (buffer[9] & 32) printf("\t[AUTO] White Balance Component\n"); 267 if (buffer[9] & 64) printf("\tDigital Multiplier\n"); 268 if (buffer[9] & 128) printf("\tDigital Multiplier Limit\n"); 269 } 270 if (c >= 3) { 271 if (buffer[10] & 1) printf("\tAnalog Video Standard\n"); 272 if (buffer[10] & 2) printf("\tAnalog Video Lock Status\n"); 273 } 274 printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[8+c])); 275 i=buffer[9+c]; 276 if (i & 2) printf("\tNTSC 525/60\n"); 277 if (i & 4) printf("\tPAL 625/50\n"); 278 if (i & 8) printf("\tSECAM 625/50\n"); 279 if (i & 16) printf("\tNTSC 625/50\n"); 280 if (i & 32) printf("\tPAL 525/60\n"); 281 break; 282 283 case VC_EXTENSION_UNIT: 284 printf("VC_EXTENSION_UNIT:\tid=%d, guid=", buffer[3]); 285 print_guid(buffer+4); 286 printf("\n\t#ctrls=%d, #pins=%d\n", buffer[20], buffer[21]); 287 c = buffer[21]; 288 printf("\t"); 289 for (i=0; i < c; i++) 290 printf("%d ", buffer[22+i]); 291 printf("\n"); 292 printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[23+c+buffer[22+c]])); 293 break; 294 295 default: 296 printf("Unknown control %d\n", buffer[2]); 297 } 298 } 299 300 301 UVCCamDevice::~UVCCamDevice() 302 { 303 } 304 305 306 bool 307 UVCCamDevice::SupportsIsochronous() 308 { 309 return true; 310 } 311 312 313 status_t 314 UVCCamDevice::StartTransfer() 315 { 316 return CamDevice::StartTransfer(); 317 } 318 319 320 status_t 321 UVCCamDevice::StopTransfer() 322 { 323 return CamDevice::StopTransfer(); 324 } 325 326 327 UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam) 328 : CamDeviceAddon(webcam) 329 { 330 SetSupportedDevices(kSupportedDevices); 331 } 332 333 334 UVCCamDeviceAddon::~UVCCamDeviceAddon() 335 { 336 } 337 338 339 const char * 340 UVCCamDeviceAddon::BrandName() 341 { 342 return "USB Video Class"; 343 } 344 345 346 UVCCamDevice * 347 UVCCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from) 348 { 349 return new UVCCamDevice(*this, from); 350 } 351 352 353 extern "C" status_t 354 B_WEBCAM_MKINTFUNC(uvccam) 355 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon) 356 { 357 *addon = new UVCCamDeviceAddon(webcam); 358 return B_OK; 359 } 360