1 /* 2 * Copyright 2016, Adrien Destugues, pulkomandy@pulkomandy.tk 3 * Distributed under terms of the MIT license. 4 */ 5 6 #include <stdio.h> 7 8 #include <usb/USB_video.h> 9 10 #include "listusb.h" 11 12 13 void 14 DumpVideoCSInterfaceDescriptorHeader( 15 const usb_videocontrol_header_descriptor* descriptor) 16 { 17 printf(" Type .............. 0x%02x\n", 18 descriptor->descriptor_type); 19 printf(" Subtype ........... 0x%02x (Header)\n", 20 descriptor->descriptor_subtype); 21 printf(" UVC Release ....... %d.%d\n", 22 descriptor->bcd_release_no >> 8, descriptor->bcd_release_no & 0xFF); 23 printf(" Total Length ...... %u\n", 24 descriptor->total_length); 25 printf(" Clock Frequency ... %" B_PRIu32 "\n", 26 descriptor->clock_frequency); 27 printf(" Interfaces ........ "); 28 29 for (uint8 i = 0; i < descriptor->in_collection; i++) 30 printf("%u, ", descriptor->interface_numbers[i]); 31 printf("\n"); 32 } 33 34 35 static const char* 36 TerminalTypeName(uint16 terminalType) 37 { 38 switch (terminalType) { 39 case USB_VIDEO_VENDOR_USB_IO: 40 return "Vendor specific"; 41 case USB_VIDEO_STREAMING_USB_IO: 42 return "Streaming"; 43 44 case USB_VIDEO_VENDOR_IN: 45 return "Vendor specific input"; 46 case USB_VIDEO_CAMERA_IN: 47 return "Camera"; 48 case USB_VIDEO_MEDIA_TRANSPORT_IN: 49 return "Media transport input"; 50 51 case USB_VIDEO_VENDOR_OUT: 52 return "Vendor specific output"; 53 case USB_VIDEO_DISPLAY_OUT: 54 return "Display"; 55 case USB_VIDEO_MEDIA_TRANSPORT_OUT: 56 return "Media transport output"; 57 58 case USB_VIDEO_VENDOR_EXT: 59 return "Vendor specific format"; 60 case USB_VIDEO_COMPOSITE_EXT: 61 return "Composite"; 62 case USB_VIDEO_SVIDEO_EXT: 63 return "S-Video"; 64 case USB_VIDEO_COMPONENT_EXT: 65 return "Component"; 66 67 default: 68 return "Unknown"; 69 } 70 } 71 72 73 void 74 DumpVideoCSInterfaceDescriptorOutputTerminal( 75 const usb_video_output_terminal_descriptor* descriptor) 76 { 77 printf(" Type .............. 0x%02x\n", 78 descriptor->descriptor_type); 79 printf(" Subtype ........... 0x%02x (Output Terminal)\n", 80 descriptor->descriptor_subtype); 81 printf(" Terminal ID ....... %u\n", 82 descriptor->terminal_id); 83 printf(" Terminal Type ..... 0x%04x (%s)\n", 84 descriptor->terminal_type, 85 TerminalTypeName(descriptor->terminal_type)); 86 printf(" Associated Terminal %u\n", 87 descriptor->associated_terminal); 88 printf(" Source ID ......... %u\n", 89 descriptor->source_id); 90 printf(" Terminal .......... %u\n", 91 descriptor->terminal); 92 } 93 94 95 void 96 DumpVideoCSInterfaceDescriptorInputTerminal( 97 const usb_video_camera_input_terminal_descriptor* descriptor) 98 { 99 printf(" Type .............. 0x%02x\n", 100 descriptor->descriptor_type); 101 printf(" Subtype ........... 0x%02x (Input Terminal)\n", 102 descriptor->descriptor_subtype); 103 printf(" Terminal ID ....... %u\n", 104 descriptor->terminal_id); 105 printf(" Terminal Type ..... 0x%04x (%s)\n", 106 descriptor->terminal_type, 107 TerminalTypeName(descriptor->terminal_type)); 108 printf(" Terminal .......... %u\n", 109 descriptor->terminal); 110 111 if (descriptor->terminal_type == USB_VIDEO_CAMERA_IN) 112 { 113 printf(" Min. Focal length . %u\n", 114 descriptor->camera.objective_focal_length_min); 115 printf(" Max. Focal length . %u\n", 116 descriptor->camera.objective_focal_length_min); 117 printf(" Focal length ...... %u\n", 118 descriptor->camera.ocular_focal_length); 119 printf(" Controls .......... %02x%02x%02x\n", 120 descriptor->camera.controls[0], 121 descriptor->camera.controls[1], 122 descriptor->camera.controls[2]); 123 } 124 } 125 126 127 static const char* 128 ProcessingControlString(int index) 129 { 130 switch(index) 131 { 132 case 0: 133 return "Brightness, "; 134 case 1: 135 return "Contrast, "; 136 case 2: 137 return "Hue, "; 138 case 3: 139 return "Saturation, "; 140 case 4: 141 return "Sharpness, "; 142 case 5: 143 return "Gamma, "; 144 case 6: 145 return "White balance temp., "; 146 case 7: 147 return "White balance component, "; 148 case 8: 149 return "Backlight compensation, "; 150 case 9: 151 return "Gain, "; 152 case 10: 153 return "Power line frequency, "; 154 case 11: 155 return "Automatic hue, "; 156 case 12: 157 return "Automatic white balance temp., "; 158 case 13: 159 return "Automatic white balance component, "; 160 case 14: 161 return "Digital multiplier, "; 162 case 15: 163 return "Digital multiplier limit, "; 164 case 16: 165 return "Analog video standard, "; 166 case 17: 167 return "Analog video lock status, "; 168 case 18: 169 return "Automatic contrast, "; 170 default: 171 return "Unknown, "; 172 } 173 } 174 175 176 void 177 DumpVideoCSInterfaceDescriptorProcessingUnit( 178 const usb_video_processing_unit_descriptor* descriptor) 179 { 180 printf(" Type .............. 0x%02x\n", 181 descriptor->descriptor_type); 182 printf(" Subtype ........... 0x%02x (Processing unit)\n", 183 descriptor->descriptor_subtype); 184 printf(" Unit ID ........... %u\n", 185 descriptor->unit_id); 186 printf(" Source ID ......... %u\n", 187 descriptor->source_id); 188 printf(" Max Multiplier .... %f\n", 189 descriptor->max_multiplier / 100.f); 190 printf(" Controls .......... "); 191 uint32_t controls = (descriptor->controls[0] << 16) 192 | (descriptor->controls[1] << 8) 193 | descriptor->controls[2]; 194 for (int i = 0; i < 19; i++) 195 { 196 if (controls & (1 << (23 - i))) { 197 fputs(ProcessingControlString(i), stdout); 198 } 199 } 200 printf("\n"); 201 printf(" Processing ........ %u\n", 202 descriptor->Processing()); 203 printf(" Video Standards ... 0x%02x\n", 204 descriptor->VideoStandards().video_standards); 205 } 206 207 208 void 209 DumpVideoCSInterfaceDescriptorExtensionUnit( 210 const usb_generic_descriptor* descriptor) 211 { 212 uint8 i = 0; 213 214 printf(" Type .............. 0x%02x\n", 215 descriptor->descriptor_type); 216 printf(" Subtype ........... 0x%02x (Extension unit)\n", 217 (uint8)descriptor->data[i++]); 218 printf(" Unit ID ........... %u\n", 219 (uint8)descriptor->data[i++]); 220 221 printf(" GUID .............. "); 222 for (i = 2; i < 16 + 2; i++) 223 printf("%02x ", descriptor->data[i]); 224 printf("\n"); 225 226 printf(" Control count ..... %u\n", 227 (uint8)descriptor->data[i++]); 228 229 printf(" Input pins ........ "); 230 i = 20; // Skip the input pin count 231 for (; i - 20 < descriptor->data[19]; i++) 232 printf("%u, ", descriptor->data[i]); 233 printf("\n"); 234 235 printf(" Controls .......... "); 236 uint8_t end = descriptor->data[i++]; 237 uint8_t start = i; 238 for (; i - start < end; i++) 239 printf("%02x", (uint8)descriptor->data[i]); 240 printf("\n"); 241 242 printf(" Extension ......... %u\n", 243 (uint8)descriptor->data[i++]); 244 } 245 246 247 void 248 DumpVideoControlCSInterfaceDescriptor(const usb_generic_descriptor* descriptor) 249 { 250 uint8 descriptorSubtype = descriptor->data[0]; 251 switch (descriptorSubtype) { 252 case USB_VIDEO_VC_HEADER: 253 DumpVideoCSInterfaceDescriptorHeader( 254 (usb_videocontrol_header_descriptor*)descriptor); 255 break; 256 case USB_VIDEO_VC_INPUT_TERMINAL: 257 DumpVideoCSInterfaceDescriptorInputTerminal( 258 (usb_video_camera_input_terminal_descriptor*)descriptor); 259 break; 260 case USB_VIDEO_VC_OUTPUT_TERMINAL: 261 DumpVideoCSInterfaceDescriptorOutputTerminal( 262 (usb_video_output_terminal_descriptor*)descriptor); 263 break; 264 case USB_VIDEO_VC_PROCESSING_UNIT: 265 DumpVideoCSInterfaceDescriptorProcessingUnit( 266 (usb_video_processing_unit_descriptor*)descriptor); 267 break; 268 case USB_VIDEO_VC_EXTENSION_UNIT: 269 DumpVideoCSInterfaceDescriptorExtensionUnit(descriptor); 270 break; 271 default: 272 DumpDescriptorData(descriptor); 273 } 274 } 275 276 277 void 278 DumpVideoControlCSInterruptEndpointDescriptor(const usb_generic_descriptor* descriptor) 279 { 280 printf(" Type .............. 0x%02x (Endpoint)\n", 281 descriptor->descriptor_type); 282 printf(" Subtype ........... 0x%02x (Interrupt)\n", 283 (uint8)descriptor->data[0]); 284 printf(" Max Transfer Size . %u\n", 285 (uint16)((descriptor->data[1] << 8) | descriptor->data[2])); 286 } 287 288 289 void 290 DumpVideoControlCSEndpointDescriptor(const usb_generic_descriptor* descriptor) 291 { 292 uint8 descriptorSubtype = descriptor->data[0]; 293 switch (descriptorSubtype) { 294 case EP_SUBTYPE_INTERRUPT: 295 DumpVideoControlCSInterruptEndpointDescriptor(descriptor); 296 break; 297 default: 298 DumpDescriptorData(descriptor); 299 } 300 } 301 302 303 void 304 DumpVideoStreamInputHeaderDescriptor(const usb_generic_descriptor* descriptor) 305 { 306 printf(" Type .............. 0x%02x (VideoStream Interface)\n", 307 descriptor->descriptor_type); 308 printf(" Subtype ........... 0x%02x (Input header)\n", 309 (uint8)descriptor->data[0]); 310 printf(" Format count ...... %u\n", 311 (uint8)descriptor->data[1]); 312 printf(" Total length ...... %u\n", 313 (uint16)((descriptor->data[2] << 8) | descriptor->data[3])); 314 printf(" Endpoint .......... 0x%02x\n", 315 (uint8)descriptor->data[4]); 316 printf(" Info .............. 0x%02x\n", 317 (uint8)descriptor->data[5]); 318 printf(" Terminal Link ..... 0x%02x\n", 319 (uint8)descriptor->data[6]); 320 printf(" Still capture ..... 0x%02x\n", 321 (uint8)descriptor->data[7]); 322 printf(" Trigger support ... %u\n", 323 (uint8)descriptor->data[8]); 324 printf(" Trigger usage ..... %u\n", 325 (uint8)descriptor->data[9]); 326 327 uint8 nformat = descriptor->data[1]; 328 uint8 formatsize = descriptor->data[10]; 329 uint8 i, j; 330 331 for (i = 0; i < nformat; i++) 332 { 333 printf(" Format %2d ......... 0x", i); 334 for (j = 0; j < formatsize; j++) 335 printf("%02x", (uint8)descriptor->data[11 + i * formatsize + j]); 336 printf("\n"); 337 } 338 } 339 340 341 void 342 DumpVideoStillImageDescriptor(const usb_generic_descriptor* descriptor) 343 { 344 printf(" Type .............. 0x%02x (VideoStream Interface)\n", 345 descriptor->descriptor_type); 346 printf(" Subtype ........... 0x%02x (Still Image)\n", 347 (uint8)descriptor->data[0]); 348 printf(" Endpoint .......... %u\n", 349 (uint8)descriptor->data[1]); 350 351 uint8 npatterns = descriptor->data[2]; 352 uint8 i; 353 printf(" Resolutions ....... "); 354 for (i = 0; i < npatterns; i++) 355 { 356 // FIXME these are reverse-endian compared to everything else. 357 // Is my webcam wrong, or is it some quirk in the spec? 358 printf("%ux%u, ", 359 (uint16)((descriptor->data[i * 4 + 4] << 8) | (descriptor->data[i * 4 + 3])), 360 (uint16)((descriptor->data[i * 4 + 6] << 8) | (descriptor->data[i * 4 + 5]))); 361 } 362 printf("\n"); 363 364 i = i * 4 + 3; 365 366 npatterns = descriptor->data[i]; 367 while (npatterns > 0) 368 { 369 printf(" Compression ....... %u\n", 370 (uint8)descriptor->data[i]); 371 npatterns--; 372 } 373 } 374 375 376 static const char* 377 VSInterfaceString(int subtype) 378 { 379 switch(subtype) { 380 case USB_VIDEO_VS_UNDEFINED: 381 return "Undefined"; 382 case USB_VIDEO_VS_INPUT_HEADER: 383 return "Input header"; 384 case USB_VIDEO_VS_OUTPUT_HEADER: 385 return "Output header"; 386 case USB_VIDEO_VS_STILL_IMAGE_FRAME: 387 return "Still image"; 388 case USB_VIDEO_VS_FORMAT_UNCOMPRESSED: 389 return "Uncompressed format"; 390 case USB_VIDEO_VS_FRAME_UNCOMPRESSED: 391 return "Uncompressed frame"; 392 case USB_VIDEO_VS_FORMAT_MJPEG: 393 return "MJPEG format"; 394 case USB_VIDEO_VS_FRAME_MJPEG: 395 return "MJPEG frame"; 396 case USB_VIDEO_VS_FORMAT_MPEG2TS: 397 return "MPEG2TS format"; 398 case USB_VIDEO_VS_FORMAT_DV: 399 return "DV format"; 400 case USB_VIDEO_VS_COLORFORMAT: 401 return "Color format"; 402 case USB_VIDEO_VS_FORMAT_FRAME_BASED: 403 return "Frame based format"; 404 case USB_VIDEO_VS_FRAME_FRAME_BASED: 405 return "Frame based frame"; 406 case USB_VIDEO_VS_FORMAT_STREAM_BASED: 407 return "Stream based format"; 408 case USB_VIDEO_VS_FORMAT_H264: 409 return "H264 format"; 410 case USB_VIDEO_VS_FRAME_H264: 411 return "H264 frame"; 412 case USB_VIDEO_VS_FORMAT_H264_SIMULCAST: 413 return "H264 simulcast"; 414 case USB_VIDEO_VS_FORMAT_VP8: 415 return "VP8 format"; 416 case USB_VIDEO_VS_FRAME_VP8: 417 return "VP8 frame"; 418 case USB_VIDEO_VS_FORMAT_VP8_SIMULCAST: 419 return "VP8 simulcast"; 420 default: 421 return "Unknown"; 422 }; 423 } 424 425 426 void 427 DumpVideoFormatDescriptor(const usb_generic_descriptor* descriptor) 428 { 429 printf(" Type .............. 0x%02x (VideoStream Interface)\n", 430 descriptor->descriptor_type); 431 printf(" Subtype ........... 0x%02x (%s)\n", 432 (uint8)descriptor->data[0], VSInterfaceString(descriptor->data[0])); 433 printf(" Index ............. 0x%02x\n", 434 (uint8)descriptor->data[1]); 435 printf(" Frame number ...... 0x%02x\n", 436 (uint8)descriptor->data[2]); 437 438 printf(" GUID .............. "); 439 for (uint8 i = 3; i < 16 + 3; i++) 440 printf("%02x ", descriptor->data[i]); 441 printf("\n"); 442 443 printf(" Bits per pixel .... %u\n", 444 (uint8)descriptor->data[19]); 445 printf(" Default frame idx . 0x%02x\n", 446 (uint8)descriptor->data[20]); 447 printf(" Aspect ratio ...... %u:%u\n", 448 (uint8)descriptor->data[21], (uint8)descriptor->data[22]); 449 printf(" Interlace flags ... 0x%02x\n", 450 (uint8)descriptor->data[23]); 451 printf(" Copy protect ...... %u\n", 452 (uint8)descriptor->data[24]); 453 } 454 455 456 void 457 DumpVideoFrameDescriptor(const usb_video_frame_descriptor* descriptor) 458 { 459 printf(" Type .............. 0x%02x (VideoStream Interface)\n", 460 descriptor->descriptor_type); 461 printf(" Subtype ........... 0x%02x (%s)\n", 462 descriptor->descriptor_subtype, 463 VSInterfaceString(descriptor->descriptor_subtype)); 464 printf(" Index ............. 0x%02x\n", 465 descriptor->frame_index); 466 printf(" Capabilities ...... 0x%02x\n", 467 descriptor->capabilities); 468 printf(" Resolution ........ %u x %u\n", 469 descriptor->width, descriptor->height); 470 printf(" Bit rates ......... %" B_PRIu32 " - %" B_PRIu32 "\n", 471 descriptor->min_bit_rate, descriptor->max_bit_rate); 472 printf(" Frame buffer size . %" B_PRIu32 "\n", 473 descriptor->max_video_frame_buffer_size); 474 printf(" Frame interval .... %.4fms\n", 475 descriptor->default_frame_interval / 10000.f); 476 for (uint8 i = 0; i < descriptor->frame_interval_type; i++) 477 { 478 printf(" Frame interval %2d . %.4fms\n", 479 i, descriptor->discrete_frame_intervals[i] / 10000.f); 480 } 481 // TODO if frame__interval_type is 0, dump continuous frame intervals 482 } 483 484 485 static const char* 486 ColorPrimariesString(uint8_t value) 487 { 488 switch (value) { 489 case 0: 490 return "Unspecified"; 491 case 1: 492 return "BT.709, sRGB"; 493 case 2: 494 return "BT.470-2 (M)"; 495 case 3: 496 return "BT.470-2 (B, G)"; 497 case 4: 498 return "SMPTE 170M"; 499 case 5: 500 return "SMPTE 240M"; 501 default: 502 return "??"; 503 } 504 } 505 506 507 static const char* 508 TransferCharacteristicsString(uint8_t value) 509 { 510 switch (value) { 511 case 0: 512 return "Unspecified"; 513 case 1: 514 return "BT.709"; 515 case 2: 516 return "BT.470-2 (M)"; 517 case 3: 518 return "BT.470-2 (B, G)"; 519 case 4: 520 return "SMPTE 170M"; 521 case 5: 522 return "SMPTE 240M"; 523 case 6: 524 return "Linear (V = Lc)"; 525 case 7: 526 return "sRGB"; 527 default: 528 return "??"; 529 } 530 } 531 532 static const char* 533 MatrixCoefficientsString(uint8_t value) 534 { 535 switch (value) { 536 case 0: 537 return "Unspecified"; 538 case 1: 539 return "BT.709"; 540 case 2: 541 return "FCC"; 542 case 3: 543 return "BT.470-2 (B, G)"; 544 case 4: 545 return "SMPTE 170M (BT.601)"; 546 case 5: 547 return "SMPTE 240M"; 548 default: 549 return "??"; 550 } 551 } 552 553 554 static void 555 DumpVideoStreamColorFormatDescriptor(const usb_video_color_matching_descriptor* descriptor) 556 { 557 printf(" Type ..................... 0x%02x (VideoStream Interface)\n", 558 descriptor->descriptor_type); 559 printf(" Subtype .................. 0x%02x (%s)\n", 560 descriptor->descriptor_sub_type, 561 VSInterfaceString(descriptor->descriptor_sub_type)); 562 printf(" Color Primaries .......... 0x%02x (%s)\n", 563 descriptor->color_primaries, 564 ColorPrimariesString(descriptor->color_primaries)); 565 printf(" Transfer characteristics . 0x%02x (%s)\n", 566 descriptor->transfer_characteristics, 567 TransferCharacteristicsString(descriptor->transfer_characteristics)); 568 printf(" Matrix coefficients ...... 0x%02x (%s)\n", 569 descriptor->matrix_coefficients, 570 MatrixCoefficientsString(descriptor->matrix_coefficients)); 571 } 572 573 574 void 575 DumpVideoStreamCSInterfaceDescriptor(const usb_generic_descriptor* descriptor) 576 { 577 uint8 subtype = descriptor->data[0]; 578 switch (subtype) { 579 case USB_VIDEO_VS_INPUT_HEADER: 580 DumpVideoStreamInputHeaderDescriptor(descriptor); 581 break; 582 case USB_VIDEO_VS_STILL_IMAGE_FRAME: 583 DumpVideoStillImageDescriptor(descriptor); 584 break; 585 case USB_VIDEO_VS_FORMAT_UNCOMPRESSED: 586 case USB_VIDEO_VS_FORMAT_MJPEG: 587 DumpVideoFormatDescriptor(descriptor); 588 break; 589 case USB_VIDEO_VS_FRAME_UNCOMPRESSED: 590 case USB_VIDEO_VS_FRAME_MJPEG: 591 DumpVideoFrameDescriptor((usb_video_frame_descriptor*)descriptor); 592 break; 593 case USB_VIDEO_VS_COLORFORMAT: 594 DumpVideoStreamColorFormatDescriptor((usb_video_color_matching_descriptor*)descriptor); 595 break; 596 default: 597 DumpDescriptorData(descriptor); 598 break; 599 } 600 } 601 602 603 604 void 605 DumpVideoDescriptor(const usb_generic_descriptor* descriptor, int subclass) 606 { 607 switch (subclass) { 608 case USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS: 609 switch (descriptor->descriptor_type) { 610 case USB_VIDEO_CS_INTERFACE: 611 DumpVideoControlCSInterfaceDescriptor(descriptor); 612 break; 613 case USB_VIDEO_CS_ENDPOINT: 614 DumpVideoControlCSEndpointDescriptor(descriptor); 615 break; 616 default: 617 DumpDescriptorData(descriptor); 618 break; 619 } 620 break; 621 case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS: 622 switch (descriptor->descriptor_type) { 623 case USB_VIDEO_CS_INTERFACE: 624 DumpVideoStreamCSInterfaceDescriptor(descriptor); 625 break; 626 default: 627 DumpDescriptorData(descriptor); 628 break; 629 } 630 break; 631 case USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS: 632 switch (descriptor->descriptor_type) { 633 case USB_VIDEO_CS_INTERFACE: 634 // TODO 635 DumpDescriptorData(descriptor); 636 break; 637 default: 638 DumpDescriptorData(descriptor); 639 break; 640 } 641 break; 642 default: 643 DumpDescriptorData(descriptor); 644 break; 645 } 646 } 647 648