cleanup, added uvc descriptor structures, work in progress.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40352 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval
2011-02-03 20:37:41 +00:00
parent bc597290b9
commit 26a912cd34
3 changed files with 529 additions and 153 deletions
@@ -1,11 +1,12 @@
/* /*
* Copyright 2011, Haiku Inc. All Rights Reserved.
* Copyright 2009, Ithamar Adema, <[email protected]>. * Copyright 2009, Ithamar Adema, <[email protected]>.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _USB_VIDEO_H #ifndef _USB_VIDEO_H
#define _USB_VIDEO_H #define _USB_VIDEO_H
/* Class/Subclass/Protocol */ /* Class/Subclass/Protocol */
#define CC_VIDEO 0xE #define CC_VIDEO 0xE
#define SC_UNDEFINED 0x0 #define SC_UNDEFINED 0x0
@@ -89,4 +90,205 @@
#define CT_ROLL_RELATIVE_CONTROL 0x10 #define CT_ROLL_RELATIVE_CONTROL 0x10
#define CT_PRIVACY_CONTROL 0x11 #define CT_PRIVACY_CONTROL 0x11
typedef struct usbvc_class_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
} _PACKED usbvc_class_descriptor;
struct usbvc_input_header_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 numFormats;
uint16 totalLength;
uint8 endpointAddress;
uint8 info;
uint8 terminalLink;
uint8 stillCaptureMethod;
uint8 triggerSupport;
uint8 triggerUsage;
uint8 controlSize;
uint8 controls[0];
} _PACKED;
struct usbvc_output_header_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 numFormats;
uint16 totalLength;
uint8 endpointAddress;
uint8 terminalLink;
uint8 controlSize;
uint8 controls[0];
} _PACKED;
typedef uint8 usbvc_guid[16];
struct usbvc_format_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 formatIndex;
uint8 numFrameDescriptors;
union {
struct {
usbvc_guid format;
uint8 bytesPerPixel;
uint8 defaultFrameIndex;
uint8 aspectRatioX;
uint8 aspectRatioY;
uint8 interlaceFlags;
uint8 copyProtect;
} uncompressed;
struct {
uint8 flags;
uint8 defaultFrameIndex;
uint8 aspectRatioX;
uint8 aspectRatioY;
uint8 interlaceFlags;
uint8 copyProtect;
} mjpeg;
};
} _PACKED;
struct usbvc_frame_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 frameIndex;
uint8 capabilities;
uint16 width;
uint16 height;
uint32 minBitRate;
uint32 maxBitRate;
uint32 maxVideoFrameBufferSize;
uint32 defaultFrameInterval;
uint8 frameIntervalType;
union {
struct {
uint32 minFrameInterval;
uint32 maxFrameInterval;
uint32 frameIntervalStep;
} continuous;
uint32 discreteFrameIntervals[0];
};
} _PACKED;
typedef struct {
uint16 width;
uint16 height;
} _PACKED usbvc_image_size_pattern;
struct usbvc_still_image_frame_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 endpointAddress;
uint8 numImageSizePatterns;
usbvc_image_size_pattern imageSizePatterns[0];
uint8 NumCompressionPatterns() const { return *(CompressionPatterns() - 1); }
const uint8* CompressionPatterns() const {
return (const uint8*)(imageSizePatterns + sizeof(usbvc_image_size_pattern)
* numImageSizePatterns + sizeof(uint8));
}
} _PACKED;
struct usbvc_color_matching_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 colorPrimaries;
uint8 transferCharacteristics;
uint8 matrixCoefficients;
} _PACKED;
struct usbvc_interface_header_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint16 version;
uint16 totalLength;
uint32 clockFrequency;
uint8 numInterfacesNumbers;
uint8 interfaceNumbers[0];
} _PACKED;
struct usbvc_input_terminal_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 terminalID;
uint16 terminalType;
uint8 associatedTerminal;
uint8 terminal;
} _PACKED;
struct usbvc_output_terminal_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 terminalID;
uint16 terminalType;
uint8 associatedTerminal;
uint8 sourceID;
uint8 terminal;
} _PACKED;
struct usbvc_camera_terminal_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 terminalID;
uint16 terminalType;
uint8 associatedTerminal;
uint8 terminal;
uint16 objectiveFocalLengthMin;
uint16 objectiveFocalLengthMax;
uint16 ocularFocalLength;
uint8 controlSize;
uint8 controls[0];
} _PACKED;
struct usbvc_selector_unit_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 unitID;
uint8 numInputPins;
uint8 sourceID[0];
uint8 Selector() const { return sourceID[numInputPins]; }
} _PACKED;
struct usbvc_processing_unit_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 unitID;
uint8 sourceID;
uint16 maxMultiplier;
uint8 controlSize;
uint8 controls[0];
uint8 Processing() const { return controls[controlSize]; }
uint8 VideoStandards() const { return controls[controlSize+1]; }
} _PACKED;
struct usbvc_extension_unit_descriptor {
uint8 length;
uint8 descriptorType;
uint8 descriptorSubtype;
uint8 unitID;
usbvc_guid guidExtensionCode;
uint8 numControls;
uint8 numInputPins;
uint8 sourceID[0];
uint8 ControlSize() const { return sourceID[numInputPins]; }
const uint8* Controls() const { return &sourceID[numInputPins+1]; }
uint8 Extension() const
{ return sourceID[numInputPins + ControlSize() + 1]; }
} _PACKED;
#endif /* _USB_VIDEO_H */ #endif /* _USB_VIDEO_H */
@@ -1,11 +1,11 @@
/* /*
* Copyright 2011, Jérôme Duval, [email protected].
* Copyright 2009, Ithamar Adema, <[email protected]>. * Copyright 2009, Ithamar Adema, <[email protected]>.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include "UVCCamDevice.h" #include "UVCCamDevice.h"
#include "USB_video.h"
#include <stdio.h> #include <stdio.h>
@@ -37,52 +37,66 @@ usb_webcam_support_descriptor kSupportedDevices[] = {
}; };
/* Table 2-1 Compression Formats of USB Video Payload Uncompressed */ /* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
uint8 yuy2_guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, usbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}; 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
uint8 nv12_guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, usbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}; 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
static void static void
print_guid(const uint8* buf) print_guid(const usbvc_guid guid)
{ {
printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], "%02x:%02x:%02x", guid[0], guid[1], guid[2], guid[3], guid[4], guid[5],
buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); guid[6], guid[7], guid[8], guid[9], guid[10], guid[11], guid[12],
guid[13], guid[14], guid[15]);
} }
UVCCamDevice::UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) UVCCamDevice::UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
: CamDevice(_addon, _device) : CamDevice(_addon, _device)
{ {
const BUSBConfiguration* uc; const BUSBConfiguration* config;
const BUSBInterface* ui; const BUSBInterface* interface;
usb_descriptor *generic; usb_descriptor* generic;
uint32 cfg, intf, di;
uint8 buffer[1024]; uint8 buffer[1024];
generic = (usb_descriptor *)buffer; generic = (usb_descriptor *)buffer;
for (cfg=0; cfg < _device->CountConfigurations(); cfg++) { for (uint32 i = 0; i < _device->CountConfigurations(); i++) {
uc = _device->ConfigurationAt(cfg); config = _device->ConfigurationAt(i);
for (intf=0; intf < uc->CountInterfaces(); intf++) { for (uint32 j = 0; j < config->CountInterfaces(); j++) {
ui = uc->InterfaceAt(intf); interface = config->InterfaceAt(j);
if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOCONTROL) { if (interface->Class() == CC_VIDEO && interface->Subclass()
printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf); == SC_VIDEOCONTROL) {
printf("UVCCamDevice: (%lu,%lu): Found Video Control "
"interface.\n", i, j);
// look for class specific interface descriptors and parse them // look for class specific interface descriptors and parse them
for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di) for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE)) sizeof(buffer)) == B_OK; k++) {
ParseVideoControl(buffer, generic->generic.length); if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS
| USB_DESCRIPTOR_INTERFACE)) {
ParseVideoControl((const usbvc_class_descriptor*)generic,
generic->generic.length);
}
}
fInitStatus = B_OK; fInitStatus = B_OK;
} else if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOSTREAMING) { } else if (interface->Class() == CC_VIDEO && interface->Subclass()
printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf); == SC_VIDEOSTREAMING) {
printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n",
i, j);
// look for class specific interface descriptors and parse them // look for class specific interface descriptors and parse them
for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di) for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE)) sizeof(buffer)) == B_OK; k++) {
ParseVideoStreaming(buffer, generic->generic.length); if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS
| USB_DESCRIPTOR_INTERFACE)) {
ParseVideoStreaming((const usbvc_class_descriptor*)generic,
generic->generic.length);
}
}
} }
} }
} }
@@ -90,72 +104,112 @@ UVCCamDevice::UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
void void
UVCCamDevice::ParseVideoStreaming(const uint8* buffer, size_t len) UVCCamDevice::ParseVideoStreaming(const usbvc_class_descriptor* _descriptor,
size_t len)
{ {
int c, i, sz; switch(_descriptor->descriptorSubtype) {
switch(buffer[2]) {
case VS_INPUT_HEADER: case VS_INPUT_HEADER:
c = buffer[3]; {
printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", c, buffer[6]); const usbvc_input_header_descriptor* descriptor =
if (buffer[7] & 1) printf("\tDynamic Format Change supported\n"); (const usbvc_input_header_descriptor*)_descriptor;
printf("\toutput terminal id=%d\n", buffer[8]); printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", descriptor->numFormats,
printf("\tstill capture method=%d\n", buffer[9]); descriptor->endpointAddress);
if (buffer[10]) if (descriptor->info & 1)
printf("\ttrigger button fixed to still capture=%s\n", buffer[11] ? "no" : "yes"); printf("\tDynamic Format Change supported\n");
sz = buffer[12]; printf("\toutput terminal id=%d\n", descriptor->terminalLink);
for (i=0; i < c; i++) { printf("\tstill capture method=%d\n", descriptor->stillCaptureMethod);
if (descriptor->triggerSupport) {
printf("\ttrigger button fixed to still capture=%s\n",
descriptor->triggerUsage ? "no" : "yes");
}
const uint8 *controls = descriptor->controls;
for (uint8 i = 0; i < descriptor->numFormats; i++,
controls += descriptor->controlSize) {
printf("\tfmt%d: %s %s %s %s - %s %s\n", i, printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
(buffer[13+(sz*i)] & 1) ? "wKeyFrameRate" : "", (*controls & 1) ? "wKeyFrameRate" : "",
(buffer[13+(sz*i)] & 2) ? "wPFrameRate" : "", (*controls & 2) ? "wPFrameRate" : "",
(buffer[13+(sz*i)] & 4) ? "wCompQuality" : "", (*controls & 4) ? "wCompQuality" : "",
(buffer[13+(sz*i)] & 8) ? "wCompWindowSize" : "", (*controls & 8) ? "wCompWindowSize" : "",
(buffer[13+(sz*i)] & 16) ? "<Generate Key Frame>" : "", (*controls & 16) ? "<Generate Key Frame>" : "",
(buffer[13+(sz*i)] & 32) ? "<Update Frame Segment>" : ""); (*controls & 32) ? "<Update Frame Segment>" : "");
} }
break; break;
}
case VS_FORMAT_UNCOMPRESSED: case VS_FORMAT_UNCOMPRESSED:
c = buffer[4]; {
printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=", buffer[3], c); const usbvc_format_descriptor* descriptor =
print_guid(buffer+5); (const usbvc_format_descriptor*)_descriptor;
printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n", buffer[21], buffer[22], printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=",
buffer[23], buffer[24]); descriptor->formatIndex, descriptor->numFrameDescriptors);
print_guid(descriptor->uncompressed.format);
printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
descriptor->uncompressed.bytesPerPixel,
descriptor->uncompressed.defaultFrameIndex,
descriptor->uncompressed.aspectRatioX,
descriptor->uncompressed.aspectRatioY);
printf("\tbmInterlaceFlags:\n"); printf("\tbmInterlaceFlags:\n");
if (buffer[25] & 1) printf("\tInterlaced stream or variable\n"); if (descriptor->uncompressed.interlaceFlags & 1)
printf("\t%d fields per frame\n", (buffer[25] & 2) ? 1 : 2); printf("\tInterlaced stream or variable\n");
if (buffer[25] & 4) printf("\tField 1 first\n"); printf("\t%d fields per frame\n",
(descriptor->uncompressed.interlaceFlags & 2) ? 1 : 2);
if (descriptor->uncompressed.interlaceFlags & 4)
printf("\tField 1 first\n");
printf("\tField Pattern: "); printf("\tField Pattern: ");
switch((buffer[25] & 0x30) >> 4) { switch((descriptor->uncompressed.interlaceFlags & 0x30) >> 4) {
case 0: printf("Field 1 only\n"); break; case 0: printf("Field 1 only\n"); break;
case 1: printf("Field 2 only\n"); break; case 1: printf("Field 2 only\n"); break;
case 2: printf("Regular pattern of fields 1 and 2\n"); break; case 2: printf("Regular pattern of fields 1 and 2\n"); break;
case 3: printf("Random pattern of fields 1 and 2\n"); break; case 3: printf("Random pattern of fields 1 and 2\n"); break;
} }
if (buffer[26]) printf("\tRestrict duplication\n"); break; if (descriptor->uncompressed.copyProtect)
printf("\tRestrict duplication\n");
break; break;
}
case VS_FRAME_MJPEG:
printf("VS_FRAME_MJPEG:"); // fall through
case VS_FRAME_UNCOMPRESSED: case VS_FRAME_UNCOMPRESSED:
printf("VS_FRAME_UNCOMPRESSED:\tbFrameIdx=%d,stillsupported=%s,fixedfrmrate=%s\n", {
buffer[3], (buffer[4]&1)?"yes":"no", (buffer[4]&2)?"yes":"no"); if (_descriptor->descriptorSubtype == VS_FRAME_UNCOMPRESSED)
printf("VS_FRAME_UNCOMPRESSED:");
const usbvc_frame_descriptor* descriptor =
(const usbvc_frame_descriptor*)_descriptor;
printf("\tbFrameIdx=%d,stillsupported=%s,"
"fixedframerate=%s\n", descriptor->frameIndex,
(descriptor->capabilities & 1) ? "yes" : "no",
(descriptor->capabilities & 2) ? "yes" : "no");
printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n", printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n",
*(uint16*)(buffer+5), *(uint16*)(buffer+7), descriptor->width, descriptor->height,
*(uint32*)(buffer+9), *(uint32*)(buffer+13), descriptor->minBitRate, descriptor->maxBitRate,
*(uint32*)(buffer+17)); descriptor->maxVideoFrameBufferSize);
printf("\tframe interval: %lu, #intervals(0=cont): %d\n", *(uint32*)(buffer+21), buffer[25]); printf("\tdefault frame interval: %lu, #intervals(0=cont): %d\n",
//TODO print interval table descriptor->defaultFrameInterval, descriptor->frameIntervalType);
if (descriptor->frameIntervalType == 0) {
printf("min/max frame interval=%lu/%lu, step=%lu\n",
descriptor->continuous.minFrameInterval,
descriptor->continuous.maxFrameInterval,
descriptor->continuous.frameIntervalStep);
} else for (uint8 i = 0; i < descriptor->frameIntervalType; i++) {
printf("discrete frame interval: %lu\n",
descriptor->discreteFrameIntervals[i]);
}
break; break;
}
case VS_COLORFORMAT: case VS_COLORFORMAT:
{
const usbvc_color_matching_descriptor* descriptor =
(const usbvc_color_matching_descriptor*)_descriptor;
printf("VS_COLORFORMAT:\n\tbColorPrimaries: "); printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
switch(buffer[3]) { switch(descriptor->colorPrimaries) {
case 0: printf("Unspecified\n"); break; case 0: printf("Unspecified\n"); break;
case 1: printf("BT.709,sRGB\n"); break; case 1: printf("BT.709,sRGB\n"); break;
case 2: printf("BT.470-2(M)\n"); break; case 2: printf("BT.470-2(M)\n"); break;
case 3: printf("BT.470-2(B,G)\n"); break; case 3: printf("BT.470-2(B,G)\n"); break;
case 4: printf("SMPTE 170M\n"); break; case 4: printf("SMPTE 170M\n"); break;
case 5: printf("SMPTE 240M\n"); break; case 5: printf("SMPTE 240M\n"); break;
default: printf("Invalid (%d)\n", buffer[3]); default: printf("Invalid (%d)\n", descriptor->colorPrimaries);
} }
printf("\tbTransferCharacteristics: "); printf("\tbTransferCharacteristics: ");
switch(buffer[4]) { switch(descriptor->transferCharacteristics) {
case 0: printf("Unspecified\n"); break; case 0: printf("Unspecified\n"); break;
case 1: printf("BT.709\n"); break; case 1: printf("BT.709\n"); break;
case 2: printf("BT.470-2(M)\n"); break; case 2: printf("BT.470-2(M)\n"); break;
@@ -164,32 +218,87 @@ UVCCamDevice::ParseVideoStreaming(const uint8* buffer, size_t len)
case 5: printf("SMPTE 240M\n"); break; case 5: printf("SMPTE 240M\n"); break;
case 6: printf("Linear (V=Lc)\n"); break; case 6: printf("Linear (V=Lc)\n"); break;
case 7: printf("sRGB\n"); break; case 7: printf("sRGB\n"); break;
default: printf("Invalid (%d)\n", buffer[4]); default: printf("Invalid (%d)\n",
descriptor->transferCharacteristics);
} }
printf("\tbMatrixCoefficients: "); printf("\tbMatrixCoefficients: ");
switch(buffer[5]) { switch(descriptor->matrixCoefficients) {
case 0: printf("Unspecified\n"); break; case 0: printf("Unspecified\n"); break;
case 1: printf("BT.709\n"); break; case 1: printf("BT.709\n"); break;
case 2: printf("FCC\n"); break; case 2: printf("FCC\n"); break;
case 3: printf("BT.470-2(B,G)\n"); break; case 3: printf("BT.470-2(B,G)\n"); break;
case 4: printf("SMPTE 170M (BT.601)\n"); break; case 4: printf("SMPTE 170M (BT.601)\n"); break;
case 5: printf("SMPTE 240M\n"); break; case 5: printf("SMPTE 240M\n"); break;
default: printf("Invalid (%d)\n", buffer[5]); default: printf("Invalid (%d)\n", descriptor->matrixCoefficients);
} }
break; break;
}
case VS_OUTPUT_HEADER: case VS_OUTPUT_HEADER:
printf("VS_OUTPUT_HEADER:\t\n"); {
const usbvc_output_header_descriptor* descriptor =
(const usbvc_output_header_descriptor*)_descriptor;
printf("VS_OUTPUT_HEADER:\t#fmts=%d,ept=0x%x\n",
descriptor->numFormats, descriptor->endpointAddress);
printf("\toutput terminal id=%d\n", descriptor->terminalLink);
const uint8 *controls = descriptor->controls;
for (uint8 i = 0; i < descriptor->numFormats; i++,
controls += descriptor->controlSize) {
printf("\tfmt%d: %s %s %s %s\n", i,
(*controls & 1) ? "wKeyFrameRate" : "",
(*controls & 2) ? "wPFrameRate" : "",
(*controls & 4) ? "wCompQuality" : "",
(*controls & 8) ? "wCompWindowSize" : "");
}
break; break;
}
case VS_STILL_IMAGE_FRAME: case VS_STILL_IMAGE_FRAME:
printf("VS_STILL_IMAGE_FRAME:\t\n"); {
const usbvc_still_image_frame_descriptor* descriptor =
(const usbvc_still_image_frame_descriptor*)_descriptor;
printf("VS_STILL_IMAGE_FRAME:\t#imageSizes=%d,compressions=%d,"
"ept=0x%x\n", descriptor->numImageSizePatterns,
descriptor->NumCompressionPatterns(),
descriptor->endpointAddress);
for (uint8 i = 0; i < descriptor->numImageSizePatterns; i++) {
printf("imageSize%d: %dx%d\n", i,
descriptor->imageSizePatterns[i].width,
descriptor->imageSizePatterns[i].height);
}
for (uint8 i = 0; i < descriptor->NumCompressionPatterns(); i++) {
printf("compression%d: %d\n", i,
descriptor->CompressionPatterns()[i]);
}
break; break;
}
case VS_FORMAT_MJPEG: case VS_FORMAT_MJPEG:
printf("VS_FORMAT_MJPEG:\t\n"); {
break; const usbvc_format_descriptor* descriptor =
case VS_FRAME_MJPEG: (const usbvc_format_descriptor*)_descriptor;
printf("VS_FRAME_MJPEG:\t\n"); printf("VS_FORMAT_MJPEG:\tbFormatIdx=%d,#frmdesc=%d\n",
descriptor->formatIndex, descriptor->numFrameDescriptors);
printf("\t#flgs=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
descriptor->mjpeg.flags,
descriptor->mjpeg.defaultFrameIndex,
descriptor->mjpeg.aspectRatioX,
descriptor->mjpeg.aspectRatioY);
printf("\tbmInterlaceFlags:\n");
if (descriptor->mjpeg.interlaceFlags & 1)
printf("\tInterlaced stream or variable\n");
printf("\t%d fields per frame\n",
(descriptor->mjpeg.interlaceFlags & 2) ? 1 : 2);
if (descriptor->mjpeg.interlaceFlags & 4)
printf("\tField 1 first\n");
printf("\tField Pattern: ");
switch((descriptor->mjpeg.interlaceFlags & 0x30) >> 4) {
case 0: printf("Field 1 only\n"); break;
case 1: printf("Field 2 only\n"); break;
case 2: printf("Regular pattern of fields 1 and 2\n"); break;
case 3: printf("Random pattern of fields 1 and 2\n"); break;
}
if (descriptor->mjpeg.copyProtect)
printf("\tRestrict duplication\n");
break; break;
}
case VS_FORMAT_MPEG2TS: case VS_FORMAT_MPEG2TS:
printf("VS_FORMAT_MPEG2TS:\t\n"); printf("VS_FORMAT_MPEG2TS:\t\n");
break; break;
@@ -206,94 +315,148 @@ UVCCamDevice::ParseVideoStreaming(const uint8* buffer, size_t len)
printf("VS_FORMAT_STREAM_BASED:\t\n"); printf("VS_FORMAT_STREAM_BASED:\t\n");
break; break;
default: default:
printf("INVALID STREAM UNIT TYPE=%d!\n", buffer[2]); printf("INVALID STREAM UNIT TYPE=%d!\n",
_descriptor->descriptorSubtype);
} }
} }
void void
UVCCamDevice::ParseVideoControl(const uint8* buffer, size_t len) UVCCamDevice::ParseVideoControl(const usbvc_class_descriptor* _descriptor,
size_t len)
{ {
int c, i; switch(_descriptor->descriptorSubtype) {
switch(buffer[2]) {
case VC_HEADER: case VC_HEADER:
printf("VC_HEADER:\tUVC v%04x, clk %lu Hz\n", *(uint16*)(buffer+3), *(uint32*)(buffer+7)); {
c = (len >= 12) ? buffer[11] : 0; const usbvc_interface_header_descriptor* descriptor =
for (i=0; i < c; i++) (const usbvc_interface_header_descriptor*)_descriptor;
printf("\tStreaming Interface %d\n", buffer[12+i]); printf("VC_HEADER:\tUVC v%04x, clk %lu Hz\n", descriptor->version,
descriptor->clockFrequency);
for (uint8 i = 0; i < descriptor->numInterfacesNumbers; i++) {
printf("\tStreaming Interface %d\n",
descriptor->interfaceNumbers[i]);
}
break; break;
}
case VC_INPUT_TERMINAL: case VC_INPUT_TERMINAL:
printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal=%d\n", buffer[3], *(uint16*)(buffer+4), buffer[6]); {
printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[7])); const usbvc_input_terminal_descriptor* descriptor =
(const usbvc_input_terminal_descriptor*)_descriptor;
printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
"%d\n", descriptor->terminalID, descriptor->terminalType,
descriptor->associatedTerminal);
printf("\tDesc: %s\n",
fDevice->DecodeStringDescriptor(descriptor->terminal));
break; break;
}
case VC_OUTPUT_TERMINAL: case VC_OUTPUT_TERMINAL:
printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal=%d, src id=%d\n", buffer[3], *(uint16*)(buffer+4), buffer[6], buffer[7]); {
printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[8])); const usbvc_output_terminal_descriptor* descriptor =
(const usbvc_output_terminal_descriptor*)_descriptor;
printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
"%d, src id=%d\n", descriptor->terminalID,
descriptor->terminalType, descriptor->associatedTerminal,
descriptor->sourceID);
printf("\tDesc: %s\n",
fDevice->DecodeStringDescriptor(descriptor->terminal));
break; break;
}
case VC_SELECTOR_UNIT: case VC_SELECTOR_UNIT:
printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n", buffer[3], buffer[4]); {
const usbvc_selector_unit_descriptor* descriptor =
(const usbvc_selector_unit_descriptor*)_descriptor;
printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n",
descriptor->unitID, descriptor->numInputPins);
printf("\t"); printf("\t");
for (i=0; i < buffer[4]; i++) for (uint8 i = 0; i < descriptor->numInputPins; i++)
printf("%d ", buffer[5+i]); printf("%d ", descriptor->sourceID[i]);
printf("\n"); printf("\n");
printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[5+buffer[4]])); printf("\tDesc: %s\n",
fDevice->DecodeStringDescriptor(descriptor->Selector()));
break; break;
}
case VC_PROCESSING_UNIT: case VC_PROCESSING_UNIT:
printf("VC_PROCESSING_UNIT:\tid=%d,src id=%d, digmul=%d\n", buffer[3], buffer[4], *(uint16*)(buffer+5)); {
c = buffer[7]; const usbvc_processing_unit_descriptor* descriptor =
printf("\tbControlSize=%d\n", c); (const usbvc_processing_unit_descriptor*)_descriptor;
if (c >= 1) { printf("VC_PROCESSING_UNIT:\tid=%d,src id=%d, digmul=%d\n",
if (buffer[8] & 1) printf("\tBrightness\n"); descriptor->unitID, descriptor->sourceID,
if (buffer[8] & 2) printf("\tContrast\n"); descriptor->maxMultiplier);
if (buffer[8] & 4) printf("\tHue\n"); printf("\tbControlSize=%d\n", descriptor->controlSize);
if (buffer[8] & 8) printf("\tSaturation\n"); if (descriptor->controlSize >= 1) {
if (buffer[8] & 16) printf("\tSharpness\n"); if (descriptor->controls[0] & 1)
if (buffer[8] & 32) printf("\tGamma\n"); printf("\tBrightness\n");
if (buffer[8] & 64) printf("\tWhite Balance Temperature\n"); if (descriptor->controls[0] & 2)
if (buffer[8] & 128) printf("\tWhite Balance Component\n"); printf("\tContrast\n");
if (descriptor->controls[0] & 4)
printf("\tHue\n");
if (descriptor->controls[0] & 8)
printf("\tSaturation\n");
if (descriptor->controls[0] & 16)
printf("\tSharpness\n");
if (descriptor->controls[0] & 32)
printf("\tGamma\n");
if (descriptor->controls[0] & 64)
printf("\tWhite Balance Temperature\n");
if (descriptor->controls[0] & 128)
printf("\tWhite Balance Component\n");
} }
if (c >= 2) { if (descriptor->controlSize >= 2) {
if (buffer[9] & 1) printf("\tBacklight Compensation\n"); if (descriptor->controls[1] & 1)
if (buffer[9] & 2) printf("\tGain\n"); printf("\tBacklight Compensation\n");
if (buffer[9] & 4) printf("\tPower Line Frequency\n"); if (descriptor->controls[1] & 2)
if (buffer[9] & 8) printf("\t[AUTO] Hue\n"); printf("\tGain\n");
if (buffer[9] & 16) printf("\t[AUTO] White Balance Temperature\n"); if (descriptor->controls[1] & 4)
if (buffer[9] & 32) printf("\t[AUTO] White Balance Component\n"); printf("\tPower Line Frequency\n");
if (buffer[9] & 64) printf("\tDigital Multiplier\n"); if (descriptor->controls[1] & 8)
if (buffer[9] & 128) printf("\tDigital Multiplier Limit\n"); printf("\t[AUTO] Hue\n");
if (descriptor->controls[1] & 16)
printf("\t[AUTO] White Balance Temperature\n");
if (descriptor->controls[1] & 32)
printf("\t[AUTO] White Balance Component\n");
if (descriptor->controls[1] & 64)
printf("\tDigital Multiplier\n");
if (descriptor->controls[1] & 128)
printf("\tDigital Multiplier Limit\n");
} }
if (c >= 3) { if (descriptor->controlSize >= 3) {
if (buffer[10] & 1) printf("\tAnalog Video Standard\n"); if (descriptor->controls[2] & 1)
if (buffer[10] & 2) printf("\tAnalog Video Lock Status\n"); printf("\tAnalog Video Standard\n");
if (descriptor->controls[2] & 2)
printf("\tAnalog Video Lock Status\n");
} }
printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[8+c])); printf("\tDesc: %s\n",
i=buffer[9+c]; fDevice->DecodeStringDescriptor(descriptor->Processing()));
if (i & 2) printf("\tNTSC 525/60\n"); if (descriptor->VideoStandards() & 2)
if (i & 4) printf("\tPAL 625/50\n"); printf("\tNTSC 525/60\n");
if (i & 8) printf("\tSECAM 625/50\n"); if (descriptor->VideoStandards() & 4)
if (i & 16) printf("\tNTSC 625/50\n"); printf("\tPAL 625/50\n");
if (i & 32) printf("\tPAL 525/60\n"); if (descriptor->VideoStandards() & 8)
printf("\tSECAM 625/50\n");
if (descriptor->VideoStandards() & 16)
printf("\tNTSC 625/50\n");
if (descriptor->VideoStandards() & 32)
printf("\tPAL 525/60\n");
break; break;
}
case VC_EXTENSION_UNIT: case VC_EXTENSION_UNIT:
printf("VC_EXTENSION_UNIT:\tid=%d, guid=", buffer[3]); {
print_guid(buffer+4); const usbvc_extension_unit_descriptor* descriptor =
printf("\n\t#ctrls=%d, #pins=%d\n", buffer[20], buffer[21]); (const usbvc_extension_unit_descriptor*)_descriptor;
c = buffer[21]; printf("VC_EXTENSION_UNIT:\tid=%d, guid=", descriptor->unitID);
print_guid(descriptor->guidExtensionCode);
printf("\n\t#ctrls=%d, #pins=%d\n", descriptor->numControls,
descriptor->numInputPins);
printf("\t"); printf("\t");
for (i=0; i < c; i++) for (uint8 i = 0; i < descriptor->numInputPins; i++)
printf("%d ", buffer[22+i]); printf("%d ", descriptor->sourceID[i]);
printf("\n"); printf("\n");
printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[23+c+buffer[22+c]])); printf("\tDesc: %s\n",
fDevice->DecodeStringDescriptor(descriptor->Extension()));
break; break;
}
default: default:
printf("Unknown control %d\n", buffer[2]); printf("Unknown control %d\n", _descriptor->descriptorSubtype);
} }
} }
@@ -1,33 +1,44 @@
/* /*
* Copyright 2011, Jérôme Duval, [email protected].
* Copyright 2009, Ithamar Adema, <[email protected]>. * Copyright 2009, Ithamar Adema, <[email protected]>.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _UVC_CAM_DEVICE_H #ifndef _UVC_CAM_DEVICE_H
#define _UVC_CAM_DEVICE_H #define _UVC_CAM_DEVICE_H
#include "CamDevice.h" #include "CamDevice.h"
#include "USB_video.h"
class UVCCamDevice : public CamDevice { class UVCCamDevice : public CamDevice {
public: public:
UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device); UVCCamDevice(CamDeviceAddon &_addon,
~UVCCamDevice(); BUSBDevice* _device);
virtual ~UVCCamDevice();
virtual bool SupportsIsochronous(); virtual bool SupportsIsochronous();
virtual status_t StartTransfer(); virtual status_t StartTransfer();
virtual status_t StopTransfer(); virtual status_t StopTransfer();
private: private:
void ParseVideoControl(const uint8* buf, size_t len); void ParseVideoControl(
void ParseVideoStreaming(const uint8* buf, size_t len); const usbvc_class_descriptor* descriptor,
size_t len);
void ParseVideoStreaming(
const usbvc_class_descriptor* descriptor,
size_t len);
}; };
class UVCCamDeviceAddon : public CamDeviceAddon {
public:
UVCCamDeviceAddon(WebCamMediaAddOn* webcam);
virtual ~UVCCamDeviceAddon();
virtual const char *BrandName(); class UVCCamDeviceAddon : public CamDeviceAddon {
virtual UVCCamDevice *Instantiate(CamRoster &roster, BUSBDevice *from); public:
UVCCamDeviceAddon(WebCamMediaAddOn* webcam);
virtual ~UVCCamDeviceAddon();
virtual const char* BrandName();
virtual UVCCamDevice* Instantiate(CamRoster &roster,
BUSBDevice *from);
}; };
#endif /* _UVC_CAM_DEVICE_H */ #endif /* _UVC_CAM_DEVICE_H */