xref: /haiku/src/bin/listusb/usb_video.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
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->assoc_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_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.focal_length_min);
115 		printf("                    Max. Focal length . %u\n",
116 			descriptor->camera.focal_length_min);
117 		printf("                    Focal length ...... %u\n",
118 			descriptor->camera.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->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_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 void
486 DumpVideoStreamCSInterfaceDescriptor(const usb_generic_descriptor* descriptor)
487 {
488 	uint8 subtype = descriptor->data[0];
489 	switch (subtype) {
490 		case USB_VIDEO_VS_INPUT_HEADER:
491 			DumpVideoStreamInputHeaderDescriptor(descriptor);
492 			break;
493 		case USB_VIDEO_VS_STILL_IMAGE_FRAME:
494 			DumpVideoStillImageDescriptor(descriptor);
495 			break;
496 		case USB_VIDEO_VS_FORMAT_UNCOMPRESSED:
497 		case USB_VIDEO_VS_FORMAT_MJPEG:
498 			DumpVideoFormatDescriptor(descriptor);
499 			break;
500 		case USB_VIDEO_VS_FRAME_UNCOMPRESSED:
501 		case USB_VIDEO_VS_FRAME_MJPEG:
502 			DumpVideoFrameDescriptor((usb_video_frame_descriptor*)descriptor);
503 			break;
504 		default:
505 			DumpDescriptorData(descriptor);
506 			break;
507 	}
508 }
509 
510 
511 
512 void
513 DumpVideoDescriptor(const usb_generic_descriptor* descriptor, int subclass)
514 {
515 	switch (subclass) {
516 		case USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS:
517 			switch (descriptor->descriptor_type) {
518 				case USB_VIDEO_CS_INTERFACE:
519 					DumpVideoControlCSInterfaceDescriptor(descriptor);
520 					break;
521 				case USB_VIDEO_CS_ENDPOINT:
522 					DumpVideoControlCSEndpointDescriptor(descriptor);
523 					break;
524 				default:
525 					DumpDescriptorData(descriptor);
526 					break;
527 			}
528 			break;
529 		case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS:
530 			switch (descriptor->descriptor_type) {
531 				case USB_VIDEO_CS_INTERFACE:
532 					DumpVideoStreamCSInterfaceDescriptor(descriptor);
533 					break;
534 				default:
535 					DumpDescriptorData(descriptor);
536 					break;
537 			}
538 			break;
539 		case USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS:
540 			switch (descriptor->descriptor_type) {
541 				case USB_VIDEO_CS_INTERFACE:
542 					// TODO
543 					DumpDescriptorData(descriptor);
544 					break;
545 				default:
546 					DumpDescriptorData(descriptor);
547 					break;
548 			}
549 			break;
550 		default:
551 			DumpDescriptorData(descriptor);
552 			break;
553 	}
554 }
555 
556