diff --git a/headers/os/drivers/usb/USB_video.h b/headers/os/drivers/usb/USB_video.h index 064e33ab58..2c3fb00f6e 100644 --- a/headers/os/drivers/usb/USB_video.h +++ b/headers/os/drivers/usb/USB_video.h @@ -52,6 +52,30 @@ enum { // Video Class-Specific VideoControl Interface descriptor subtypes }; +enum { // Video Class-Specific VideoStreaming Interface descriptor subtypes + USB_VIDEO_VS_UNDEFINED = 0x00, + USB_VIDEO_VS_INPUT_HEADER = 0x01, + USB_VIDEO_VS_OUTPUT_HEADER = 0x02, + USB_VIDEO_VS_STILL_IMAGE_FRAME = 0x03, + USB_VIDEO_VS_FORMAT_UNCOMPRESSED = 0x04, + USB_VIDEO_VS_FRAME_UNCOMPRESSED = 0x05, + USB_VIDEO_VS_FORMAT_MJPEG = 0x06, + USB_VIDEO_VS_FRAME_MJPEG = 0x07, + USB_VIDEO_VS_FORMAT_MPEG2TS = 0x0a, + USB_VIDEO_VS_FORMAT_DV = 0x0c, + USB_VIDEO_VS_COLORFORMAT = 0x0d, + USB_VIDEO_VS_FORMAT_FRAME_BASED = 0x10, + USB_VIDEO_VS_FRAME_FRAME_BASED = 0x11, + USB_VIDEO_VS_FORMAT_STREAM_BASED = 0x12, + USB_VIDEO_VS_FORMAT_H264 = 0x13, + USB_VIDEO_VS_FRAME_H264 = 0x14, + USB_VIDEO_VS_FORMAT_H264_SIMULCAST = 0x15, + USB_VIDEO_VS_FORMAT_VP8 = 0x16, + USB_VIDEO_VS_FRAME_VP8 = 0x17, + USB_VIDEO_VS_FORMAT_VP8_SIMULCAST = 0x18, +}; + + enum { // USB Terminal Types USB_VIDEO_VENDOR_USB_IO = 0x100, @@ -72,6 +96,14 @@ enum { }; +enum { + EP_SUBTYPE_UNDEFINED = 0x00, + EP_SUBTYPE_GENERAL = 0x01, + EP_SUBTYPE_ENDPOINT = 0x02, + EP_SUBTYPE_INTERRUPT = 0x03, +}; + + // Class Specific Video Control Interface Header // 1.5: Table 3-3 p.48 typedef struct { @@ -139,4 +171,28 @@ typedef struct { } _PACKED usb_video_processing_unit_descriptor; +struct usb_video_frame_descriptor { + uint8 length; + uint8 descriptor_type; + uint8 descriptor_subtype; + uint8 frame_index; + uint8 capabilities; + uint16 width; + uint16 height; + uint32 min_bit_rate; + uint32 max_bit_rate; + uint32 max_video_frame_buffer_size; + uint32 default_frame_interval; + uint8 frame_interval_type; + union { + struct { + uint32 min_frame_interval; + uint32 max_frame_tnterval; + uint32 frame_interval_step; + } continuous; + uint32 discrete_frame_intervals[0]; + }; +} _PACKED; + + #endif /* !USB_VIDEO_H */ diff --git a/src/bin/listusb/usb_video.cpp b/src/bin/listusb/usb_video.cpp index bab6996702..89a1559a44 100644 --- a/src/bin/listusb/usb_video.cpp +++ b/src/bin/listusb/usb_video.cpp @@ -275,7 +275,239 @@ DumpVideoControlCSInterfaceDescriptor(const usb_generic_descriptor* descriptor) void -DumpAudioStreamCSInterfaceDescriptor(const usb_generic_descriptor* descriptor); +DumpVideoControlCSInterruptEndpointDescriptor(const usb_generic_descriptor* descriptor) +{ + printf(" Type .............. 0x%02x (Endpoint)\n", + descriptor->descriptor_type); + printf(" Subtype ........... 0x%02x (Interrupt)\n", + (uint8)descriptor->data[0]); + printf(" Max Transfer Size . %u\n", + (uint16)((descriptor->data[1] << 8) | descriptor->data[2])); +} + + +void +DumpVideoControlCSEndpointDescriptor(const usb_generic_descriptor* descriptor) +{ + uint8 descriptorSubtype = descriptor->data[0]; + switch (descriptorSubtype) { + case EP_SUBTYPE_INTERRUPT: + DumpVideoControlCSInterruptEndpointDescriptor(descriptor); + break; + default: + DumpDescriptorData(descriptor); + } +} + + +void +DumpVideoStreamInputHeaderDescriptor(const usb_generic_descriptor* descriptor) +{ + printf(" Type .............. 0x%02x (VideoStream Interface)\n", + descriptor->descriptor_type); + printf(" Subtype ........... 0x%02x (Input header)\n", + (uint8)descriptor->data[0]); + printf(" Format count ...... %u\n", + (uint8)descriptor->data[1]); + printf(" Total length ...... %u\n", + (uint16)((descriptor->data[2] << 8) | descriptor->data[3])); + printf(" Endpoint .......... 0x%02x\n", + (uint8)descriptor->data[4]); + printf(" Info .............. 0x%02x\n", + (uint8)descriptor->data[5]); + printf(" Terminal Link ..... 0x%02x\n", + (uint8)descriptor->data[6]); + printf(" Still capture ..... 0x%02x\n", + (uint8)descriptor->data[7]); + printf(" Trigger support ... %u\n", + (uint8)descriptor->data[8]); + printf(" Trigger usage ..... %u\n", + (uint8)descriptor->data[9]); + + uint8 nformat = descriptor->data[1]; + uint8 formatsize = descriptor->data[10]; + uint8 i, j; + + for (i = 0; i < nformat; i++) + { + printf(" Format %2d ......... 0x", i); + for (j = 0; j < formatsize; j++) + printf("%02x", (uint8)descriptor->data[11 + i * formatsize + j]); + printf("\n"); + } +} + + +void +DumpVideoStillImageDescriptor(const usb_generic_descriptor* descriptor) +{ + printf(" Type .............. 0x%02x (VideoStream Interface)\n", + descriptor->descriptor_type); + printf(" Subtype ........... 0x%02x (Still Image)\n", + (uint8)descriptor->data[0]); + printf(" Endpoint .......... %u\n", + (uint8)descriptor->data[1]); + + uint8 npatterns = descriptor->data[2]; + uint8 i; + printf(" Resolutions ....... "); + for (i = 0; i < npatterns; i++) + { + // FIXME these are reverse-endian compared to everything else. + // Is my webcam wrong, or is it some quirk in the spec? + printf("%ux%u, ", + (uint16)((descriptor->data[i * 4 + 4] << 8) | (descriptor->data[i * 4 + 3])), + (uint16)((descriptor->data[i * 4 + 6] << 8) | (descriptor->data[i * 4 + 5]))); + } + printf("\n"); + + i = i * 4 + 3; + + npatterns = descriptor->data[i]; + while (npatterns > 0) + { + printf(" Compression ....... %u\n", + (uint8)descriptor->data[i]); + npatterns--; + } +} + + +static const char* +VSInterfaceString(int subtype) +{ + switch(subtype) { + case USB_VIDEO_VS_UNDEFINED: + return "Undefined"; + case USB_VIDEO_VS_INPUT_HEADER: + return "Input header"; + case USB_VIDEO_VS_OUTPUT_HEADER: + return "Output header"; + case USB_VIDEO_VS_STILL_IMAGE_FRAME: + return "Still image"; + case USB_VIDEO_VS_FORMAT_UNCOMPRESSED: + return "Uncompressed format"; + case USB_VIDEO_VS_FRAME_UNCOMPRESSED: + return "Uncompressed frame"; + case USB_VIDEO_VS_FORMAT_MJPEG: + return "MJPEG format"; + case USB_VIDEO_VS_FRAME_MJPEG: + return "MJPEG frame"; + case USB_VIDEO_VS_FORMAT_MPEG2TS: + return "MPEG2TS format"; + case USB_VIDEO_VS_FORMAT_DV: + return "DV format"; + case USB_VIDEO_VS_COLORFORMAT: + return "Color format"; + case USB_VIDEO_VS_FORMAT_FRAME_BASED: + return "Frame based format"; + case USB_VIDEO_VS_FRAME_FRAME_BASED: + return "Frame based frame"; + case USB_VIDEO_VS_FORMAT_STREAM_BASED: + return "Stream based format"; + case USB_VIDEO_VS_FORMAT_H264: + return "H264 format"; + case USB_VIDEO_VS_FRAME_H264: + return "H264 frame"; + case USB_VIDEO_VS_FORMAT_H264_SIMULCAST: + return "H264 simulcast"; + case USB_VIDEO_VS_FORMAT_VP8: + return "VP8 format"; + case USB_VIDEO_VS_FRAME_VP8: + return "VP8 frame"; + case USB_VIDEO_VS_FORMAT_VP8_SIMULCAST: + return "VP8 simulcast"; + default: + return "Unknown"; + }; +} + + +void +DumpVideoFormatDescriptor(const usb_generic_descriptor* descriptor) +{ + printf(" Type .............. 0x%02x (VideoStream Interface)\n", + descriptor->descriptor_type); + printf(" Subtype ........... 0x%02x (%s)\n", + (uint8)descriptor->data[0], VSInterfaceString(descriptor->data[0])); + printf(" Index ............. 0x%02x\n", + (uint8)descriptor->data[1]); + printf(" Frame number ...... 0x%02x\n", + (uint8)descriptor->data[2]); + + printf(" GUID .............. "); + for (uint8 i = 3; i < 16 + 3; i++) + printf("%02x ", descriptor->data[i]); + printf("\n"); + + printf(" Bits per pixel .... %u\n", + (uint8)descriptor->data[19]); + printf(" Default frame idx . 0x%02x\n", + (uint8)descriptor->data[20]); + printf(" Aspect ratio ...... %u:%u\n", + (uint8)descriptor->data[21], (uint8)descriptor->data[22]); + printf(" Interlace flags ... 0x%02x\n", + (uint8)descriptor->data[23]); + printf(" Copy protect ...... %u\n", + (uint8)descriptor->data[24]); +} + + +void +DumpVideoFrameDescriptor(const usb_video_frame_descriptor* descriptor) +{ + printf(" Type .............. 0x%02x (VideoStream Interface)\n", + descriptor->descriptor_type); + printf(" Subtype ........... 0x%02x (%s)\n", + descriptor->descriptor_subtype, + VSInterfaceString(descriptor->descriptor_subtype)); + printf(" Index ............. 0x%02x\n", + descriptor->frame_index); + printf(" Capabilities ...... 0x%02x\n", + descriptor->capabilities); + printf(" Resolution ........ %u x %u\n", + descriptor->width, descriptor->height); + printf(" Bit rates ......... %" B_PRIu32 " - %" B_PRIu32 "\n", + descriptor->min_bit_rate, descriptor->max_bit_rate); + printf(" Frame buffer size . %" B_PRIu32 "\n", + descriptor->max_video_frame_buffer_size); + printf(" Frame interval .... %.4fms\n", + descriptor->default_frame_interval / 10000.f); + for (uint8 i = 0; i < descriptor->frame_interval_type; i++) + { + printf(" Frame interval %2d . %.4fms\n", + i, descriptor->discrete_frame_intervals[i] / 10000.f); + } + // TODO if frame__interval_type is 0, dump continuous frame intervals +} + + +void +DumpVideoStreamCSInterfaceDescriptor(const usb_generic_descriptor* descriptor) +{ + uint8 subtype = descriptor->data[0]; + switch (subtype) { + case USB_VIDEO_VS_INPUT_HEADER: + DumpVideoStreamInputHeaderDescriptor(descriptor); + break; + case USB_VIDEO_VS_STILL_IMAGE_FRAME: + DumpVideoStillImageDescriptor(descriptor); + break; + case USB_VIDEO_VS_FORMAT_UNCOMPRESSED: + case USB_VIDEO_VS_FORMAT_MJPEG: + DumpVideoFormatDescriptor(descriptor); + break; + case USB_VIDEO_VS_FRAME_UNCOMPRESSED: + case USB_VIDEO_VS_FRAME_MJPEG: + DumpVideoFrameDescriptor((usb_video_frame_descriptor*)descriptor); + break; + default: + DumpDescriptorData(descriptor); + break; + } +} + + void DumpVideoDescriptor(const usb_generic_descriptor* descriptor, int subclass) @@ -286,6 +518,9 @@ DumpVideoDescriptor(const usb_generic_descriptor* descriptor, int subclass) case USB_VIDEO_CS_INTERFACE: DumpVideoControlCSInterfaceDescriptor(descriptor); break; + case USB_VIDEO_CS_ENDPOINT: + DumpVideoControlCSEndpointDescriptor(descriptor); + break; default: DumpDescriptorData(descriptor); break; @@ -294,7 +529,7 @@ DumpVideoDescriptor(const usb_generic_descriptor* descriptor, int subclass) case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS: switch (descriptor->descriptor_type) { case USB_VIDEO_CS_INTERFACE: - DumpAudioStreamCSInterfaceDescriptor(descriptor); + DumpVideoStreamCSInterfaceDescriptor(descriptor); break; default: DumpDescriptorData(descriptor);