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
DumpVideoCSInterfaceDescriptorHeader(const usb_videocontrol_header_descriptor * descriptor)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*
TerminalTypeName(uint16 terminalType)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
DumpVideoCSInterfaceDescriptorOutputTerminal(const usb_video_output_terminal_descriptor * descriptor)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
DumpVideoCSInterfaceDescriptorInputTerminal(const usb_video_camera_input_terminal_descriptor * descriptor)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*
ProcessingControlString(int index)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
DumpVideoCSInterfaceDescriptorProcessingUnit(const usb_video_processing_unit_descriptor * descriptor)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
DumpVideoCSInterfaceDescriptorExtensionUnit(const usb_generic_descriptor * descriptor)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
DumpVideoControlCSInterfaceDescriptor(const usb_generic_descriptor * descriptor)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
DumpVideoControlCSInterruptEndpointDescriptor(const usb_generic_descriptor * descriptor)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
DumpVideoControlCSEndpointDescriptor(const usb_generic_descriptor * descriptor)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
DumpVideoStreamInputHeaderDescriptor(const usb_generic_descriptor * descriptor)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
DumpVideoStillImageDescriptor(const usb_generic_descriptor * descriptor)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*
VSInterfaceString(int subtype)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
DumpVideoFormatDescriptor(const usb_generic_descriptor * descriptor)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
DumpVideoFrameDescriptor(const usb_video_frame_descriptor * descriptor)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*
ColorPrimariesString(uint8_t value)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*
TransferCharacteristicsString(uint8_t value)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*
MatrixCoefficientsString(uint8_t value)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
DumpVideoStreamColorFormatDescriptor(const usb_video_color_matching_descriptor * descriptor)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
DumpVideoStreamCSInterfaceDescriptor(const usb_generic_descriptor * descriptor)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
DumpVideoDescriptor(const usb_generic_descriptor * descriptor,int subclass)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