diff --git a/src/add-ons/media/media-add-ons/usb_webcam/Jamfile b/src/add-ons/media/media-add-ons/usb_webcam/Jamfile index 4cd55aa3ca..7532a2f48f 100644 --- a/src/add-ons/media/media-add-ons/usb_webcam/Jamfile +++ b/src/add-ons/media/media-add-ons/usb_webcam/Jamfile @@ -16,6 +16,7 @@ if $(TARGET_PLATFORM_HAIKU_COMPATIBLE) { local sourceDirs = addons/quickcam addons/sonix + addons/uvc addons cstransforms sensors @@ -29,7 +30,7 @@ for sourceDir in $(sourceDirs) { ## addon sources local addonSources ; -addonSources = QuickCamDevice.cpp SonixCamDevice.cpp NW80xCamDevice.cpp ; +addonSources = QuickCamDevice.cpp SonixCamDevice.cpp NW80xCamDevice.cpp UVCCamDevice.cpp ; ## colorspace transforms sources local csTransformsSources ; diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/USB_video.h b/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/USB_video.h new file mode 100644 index 0000000000..0a14141d4c --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/USB_video.h @@ -0,0 +1,92 @@ +/* + * Copyright 2009, Ithamar Adema, . + * Distributed under the terms of the MIT License. + */ + +#ifndef _USB_VIDEO_H +#define _USB_VIDEO_H + +/* Class/Subclass/Protocol */ +#define CC_VIDEO 0xE +#define SC_UNDEFINED 0x0 +#define SC_VIDEOCONTROL 0x1 +#define SC_VIDEOSTREAMING 0x2 +#define SC_VIDEO_INTERFACE_COLLECTION 0x3 +#define PC_PROTOCOL_UNDEFINED 0x0 + +#define CS_UNDEFINED 0x20 +#define CS_DEVICE 0x21 +#define CS_CONFIGURATION 0x22 +#define CS_STRING 0x23 +#define CS_INTERFACE 0x24 +#define CS_ENDPOINT 0x25 + +/* Video Control Class Descriptors */ +#define VC_DESCRIPTOR_UNDEFINED 0x0 +#define VC_HEADER 0x1 +#define VC_INPUT_TERMINAL 0x2 +#define VC_OUTPUT_TERMINAL 0x3 +#define VC_SELECTOR_UNIT 0x4 +#define VC_PROCESSING_UNIT 0x5 +#define VC_EXTENSION_UNIT 0x6 + +/* Video Streaming Class Descriptors */ +#define VS_UNDEFINED 0x00 +#define VS_INPUT_HEADER 0x01 +#define VS_OUTPUT_HEADER 0x02 +#define VS_STILL_IMAGE_FRAME 0x03 +#define VS_FORMAT_UNCOMPRESSED 0x04 +#define VS_FRAME_UNCOMPRESSED 0x05 +#define VS_FORMAT_MJPEG 0x06 +#define VS_FRAME_MJPEG 0x07 +#define VS_FORMAT_MPEG2TS 0x0a +#define VS_FORMAT_DV 0x0c +#define VS_COLORFORMAT 0x0d +#define VS_FORMAT_FRAME_BASED 0x10 +#define VS_FRAME_FRAME_BASED 0x11 +#define VS_FORMAT_STREAM_BASED 0x12 + +#define EP_UNDEFINED 0x0 +#define EP_GENERAL 0x1 +#define EP_ENDPOINT 0x2 +#define EP_INTERRUPT 0x3 + +#define RC_UNDEFINED 0x00 +#define SET_CUR 0x01 +#define GET_CUR 0x81 +#define GET_MIN 0x82 +#define GET_MAX 0x83 +#define GET_RES 0x84 +#define GET_LEN 0x85 +#define GET_INFO 0x86 +#define GET_DEF 0x87 + +#define VC_CONTROL_UNDEFINED 0x0 +#define VC_VIDEO_POWER_MODE_CONTROL 0x1 +#define VC_REQUEST_ERROR_CODE_CONTROL 0x2 + +#define TE_CONTROL_UNDEFINED 0x0 + +#define SU_CONTROL_UNDEFINED 0x0 +#define SU_INPUT_SELECT_CONTROL 0x1 + +#define CT_CONTROL_UNDEFINED 0x0 +#define CT_SCANNING_MODE_CONTROL 0x1 +#define CT_AE_MODE_CONTROL 0x2 +#define CT_AE_PRIORITY_CONTROL 0x3 +#define CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x4 +#define CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x5 +#define CT_FOCUS_ABSOLUTE_CONTROL 0x6 +#define CT_FOCUS_RELATIVE_CONTROL 0x7 +#define CT_FOCUS_AUTO_CONTROL 0x8 +#define CT_IRIS_ABSOLUTE_CONTROL 0x9 +#define CT_IRIS_RELATIVE_CONTROL 0xa +#define CT_ZOOM_ABSOLUTE_CONTROL 0xb +#define CT_ZOOM_RELATIVE_CONTROL 0xc +#define CT_PANTILT_ABSOLUTE_CONTROL 0xd +#define CT_PANTILT_RELATIVE_CONTROL 0xe +#define CT_ROLL_ABSOLUTE_CONTROL 0xf +#define CT_ROLL_RELATIVE_CONTROL 0x10 +#define CT_PRIVACY_CONTROL 0x11 + +#endif /* _USB_VIDEO_H */ diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.cpp b/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.cpp new file mode 100644 index 0000000000..f0e5c90fc9 --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.cpp @@ -0,0 +1,329 @@ +/* + * Copyright 2009, Ithamar Adema, . + * Distributed under the terms of the MIT License. + */ + +#include "UVCCamDevice.h" +#include "USB_video.h" +#include + +usb_webcam_support_descriptor kSupportedDevices[] = { + // ofcourse we support a generic UVC device... + {{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "USB", "Video Class", "??" }, + // ...whilst the following IDs were 'stolen' from a recent Linux driver: + {{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft", "Lifecam NX-6000", "??" }, + {{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft", "Lifecam VX-7000", "??" }, + {{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech", "QuickCam Fusion", "??" }, + {{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech", "QuickCam Orbit MP", "??" }, + {{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech", "QuickCam Pro for Notebook", "??" }, + {{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech", "QuickCam Pro 5000", "??" }, + {{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech", "QuickCam OEM Dell Notebook", "??" }, + {{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech", "QuickCam OEM Cisco VT Camera II", "??" }, + {{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple", "Built-In iSight", "??" }, + {{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera", "??" }, + {{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A", "MT6227", "??" }, + {{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek", "(HP Spartan)", "??" }, + {{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek", "(Samsung Q310)", "??" }, + {{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek", "Asus F9SG", "??" }, + {{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek", "Asus U3S", "??" }, + {{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A", "Lenovo Thinkpad SL500", "??" }, + {{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm", "Pico iMage", "??" }, + {{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin", "ProScopeHR", "??" }, + {{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro", "USB Web Camera", "??" }, + {{ 0, 0, 0, 0, 0}, NULL, NULL, NULL } +}; + +static void print_guid(const uint8* buf) +{ + printf("%02x:%02x:%02x:%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], + buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); +} + + +UVCCamDevice::UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device) + : CamDevice(_addon, _device) +{ + const BUSBConfiguration* uc; + const BUSBInterface* ui; + usb_descriptor *generic; + uint32 cfg, intf, di; + uint8 buffer[1024]; + + generic = (usb_descriptor *)buffer; + + for (cfg=0; cfg < _device->CountConfigurations(); cfg++) { + uc = _device->ConfigurationAt(cfg); + for (intf=0; intf < uc->CountInterfaces(); intf++) { + ui = uc->InterfaceAt(intf); + + if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOCONTROL) { + printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf); + + // look for class specific interface descriptors and parse them + for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di) + if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE)) + ParseVideoControl(buffer, generic->generic.length); + + fInitStatus = B_OK; + } else if (ui->Class() == CC_VIDEO && ui->Subclass() == SC_VIDEOSTREAMING) { + printf("UVCCamDevice: (%lu,%lu): Found Video Control interface.\n", cfg, intf); + + // look for class specific interface descriptors and parse them + for (di=0; ui->OtherDescriptorAt(di,generic,sizeof(buffer)) == B_OK; ++di) + if (generic->generic.descriptor_type == (USB_REQTYPE_CLASS | USB_DESCRIPTOR_INTERFACE)) + ParseVideoStreaming(buffer, generic->generic.length); + } + } + } +} + +void UVCCamDevice::ParseVideoStreaming(const uint8* buffer, size_t len) +{ + int c, i, sz; + + switch(buffer[2]) { + case VS_INPUT_HEADER: + c = buffer[3]; + printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", c, buffer[6]); + if (buffer[7] & 1) printf("\tDynamic Format Change supported\n"); + printf("\toutput terminal id=%d\n", buffer[8]); + printf("\tstill capture method=%d\n", buffer[9]); + if (buffer[10]) + printf("\ttrigger button fixed to still capture=%s\n", buffer[11] ? "no" : "yes"); + sz = buffer[12]; + for (i=0; i < c; i++) { + printf("\tfmt%d: %s %s %s %s - %s %s\n", i, + (buffer[13+(sz*i)] & 1) ? "wKeyFrameRate" : "", + (buffer[13+(sz*i)] & 2) ? "wPFrameRate" : "", + (buffer[13+(sz*i)] & 4) ? "wCompQuality" : "", + (buffer[13+(sz*i)] & 8) ? "wCompWindowSize" : "", + (buffer[13+(sz*i)] & 16) ? "" : "", + (buffer[13+(sz*i)] & 32) ? "" : ""); + } + break; + case VS_FORMAT_UNCOMPRESSED: + c = buffer[4]; + printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=", buffer[3], c); + print_guid(buffer+5); + printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n", buffer[21], buffer[22], + buffer[23], buffer[24]); + printf("\tbmInterlaceFlags:\n"); + if (buffer[25] & 1) printf("\tInterlaced stream or variable\n"); + printf("\t%d fields per frame\n", (buffer[25] & 2) ? 1 : 2); + if (buffer[25] & 4) printf("\tField 1 first\n"); + printf("\tField Pattern: "); + switch((buffer[25] & 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 (buffer[26]) printf("\tRestrict duplication\n"); break; + break; + 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"); + printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n", + *(uint16*)(buffer+5), *(uint16*)(buffer+7), + *(uint32*)(buffer+9), *(uint32*)(buffer+13), + *(uint32*)(buffer+17)); + printf("\tframe interval: %lu, #intervals(0=cont): %d\n", *(uint32*)(buffer+21), buffer[25]); + //TODO print interval table + break; + case VS_COLORFORMAT: + printf("VS_COLORFORMAT:\n\tbColorPrimaries: "); + switch(buffer[3]) { + case 0: printf("Unspecified\n"); break; + case 1: printf("BT.709,sRGB\n"); break; + case 2: printf("BT.470-2(M)\n"); break; + case 3: printf("BT.470-2(B,G)\n"); break; + case 4: printf("SMPTE 170M\n"); break; + case 5: printf("SMPTE 240M\n"); break; + default: printf("Invalid (%d)\n", buffer[3]); + } + printf("\tbTransferCharacteristics: "); + switch(buffer[4]) { + case 0: printf("Unspecified\n"); break; + case 1: printf("BT.709\n"); break; + case 2: printf("BT.470-2(M)\n"); break; + case 3: printf("BT.470-2(B,G)\n"); break; + case 4: printf("SMPTE 170M\n"); break; + case 5: printf("SMPTE 240M\n"); break; + case 6: printf("Linear (V=Lc)\n"); break; + case 7: printf("sRGB\n"); break; + default: printf("Invalid (%d)\n", buffer[4]); + } + printf("\tbMatrixCoefficients: "); + switch(buffer[5]) { + case 0: printf("Unspecified\n"); break; + case 1: printf("BT.709\n"); break; + case 2: printf("FCC\n"); break; + case 3: printf("BT.470-2(B,G)\n"); break; + case 4: printf("SMPTE 170M (BT.601)\n"); break; + case 5: printf("SMPTE 240M\n"); break; + default: printf("Invalid (%d)\n", buffer[5]); + } + break; + + case VS_OUTPUT_HEADER: + printf("VS_OUTPUT_HEADER:\t\n"); + break; + case VS_STILL_IMAGE_FRAME: + printf("VS_STILL_IMAGE_FRAME:\t\n"); + break; + case VS_FORMAT_MJPEG: + printf("VS_FORMAT_MJPEG:\t\n"); + break; + case VS_FRAME_MJPEG: + printf("VS_FRAME_MJPEG:\t\n"); + break; + case VS_FORMAT_MPEG2TS: + printf("VS_FORMAT_MPEG2TS:\t\n"); + break; + case VS_FORMAT_DV: + printf("VS_FORMAT_DV:\t\n"); + break; + case VS_FORMAT_FRAME_BASED: + printf("VS_FORMAT_FRAME_BASED:\t\n"); + break; + case VS_FRAME_FRAME_BASED: + printf("VS_FRAME_FRAME_BASED:\t\n"); + break; + case VS_FORMAT_STREAM_BASED: + printf("VS_FORMAT_STREAM_BASED:\t\n"); + break; + default: + printf("INVALID STREAM UNIT TYPE=%d!\n", buffer[2]); + } +} + +void UVCCamDevice::ParseVideoControl(const uint8* buffer, size_t len) +{ + int c, i; + + switch(buffer[2]) { + 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; + for (i=0; i < c; i++) + printf("\tStreaming Interface %d\n", buffer[12+i]); + break; + + 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])); + break; + + 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])); + break; + + case VC_SELECTOR_UNIT: + printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n", buffer[3], buffer[4]); + printf("\t"); + for (i=0; i < buffer[4]; i++) + printf("%d ", buffer[5+i]); + printf("\n"); + printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[5+buffer[4]])); + break; + + 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]; + printf("\tbControlSize=%d\n", c); + if (c >= 1) { + if (buffer[8] & 1) printf("\tBrightness\n"); + if (buffer[8] & 2) printf("\tContrast\n"); + if (buffer[8] & 4) printf("\tHue\n"); + if (buffer[8] & 8) printf("\tSaturation\n"); + if (buffer[8] & 16) printf("\tSharpness\n"); + if (buffer[8] & 32) printf("\tGamma\n"); + if (buffer[8] & 64) printf("\tWhite Balance Temperature\n"); + if (buffer[8] & 128) printf("\tWhite Balance Component\n"); + } + if (c >= 2) { + if (buffer[9] & 1) printf("\tBacklight Compensation\n"); + if (buffer[9] & 2) printf("\tGain\n"); + if (buffer[9] & 4) printf("\tPower Line Frequency\n"); + if (buffer[9] & 8) printf("\t[AUTO] Hue\n"); + if (buffer[9] & 16) printf("\t[AUTO] White Balance Temperature\n"); + if (buffer[9] & 32) printf("\t[AUTO] White Balance Component\n"); + if (buffer[9] & 64) printf("\tDigital Multiplier\n"); + if (buffer[9] & 128) printf("\tDigital Multiplier Limit\n"); + } + if (c >= 3) { + if (buffer[10] & 1) printf("\tAnalog Video Standard\n"); + if (buffer[10] & 2) printf("\tAnalog Video Lock Status\n"); + } + printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[8+c])); + i=buffer[9+c]; + if (i & 2) printf("\tNTSC 525/60\n"); + if (i & 4) printf("\tPAL 625/50\n"); + if (i & 8) printf("\tSECAM 625/50\n"); + if (i & 16) printf("\tNTSC 625/50\n"); + if (i & 32) printf("\tPAL 525/60\n"); + break; + + case VC_EXTENSION_UNIT: + printf("VC_EXTENSION_UNIT:\tid=%d, guid=", buffer[3]); + print_guid(buffer+4); + printf("\n\t#ctrls=%d, #pins=%d\n", buffer[20], buffer[21]); + c = buffer[21]; + printf("\t"); + for (i=0; i < c; i++) + printf("%d ", buffer[22+i]); + printf("\n"); + printf("\tDesc: %s\n", fDevice->DecodeStringDescriptor(buffer[23+c+buffer[22+c]])); + break; + + default: + printf("Unknown control %d\n", buffer[2]); + } +} + +UVCCamDevice::~UVCCamDevice() +{ +} + +bool UVCCamDevice::SupportsIsochronous() +{ + return true; +} + +status_t UVCCamDevice::StartTransfer() +{ + return CamDevice::StartTransfer(); +} + +status_t UVCCamDevice::StopTransfer() +{ + return CamDevice::StopTransfer(); +} + +UVCCamDeviceAddon::UVCCamDeviceAddon(WebCamMediaAddOn* webcam) + : CamDeviceAddon(webcam) +{ + SetSupportedDevices(kSupportedDevices); +} + + +UVCCamDeviceAddon::~UVCCamDeviceAddon() +{ +} + +UVCCamDevice * +UVCCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from) +{ + return new UVCCamDevice(*this, from); +} + + +extern "C" status_t +B_WEBCAM_MKINTFUNC(uvccam) +(WebCamMediaAddOn* webcam, CamDeviceAddon **addon) +{ + *addon = new UVCCamDeviceAddon(webcam); + return B_OK; +} diff --git a/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.h b/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.h new file mode 100644 index 0000000000..a827ee5c1d --- /dev/null +++ b/src/add-ons/media/media-add-ons/usb_webcam/addons/uvc/UVCCamDevice.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Ithamar Adema, . + * Distributed under the terms of the MIT License. + */ + +#ifndef _UVC_CAM_DEVICE_H +#define _UVC_CAM_DEVICE_H + +#include "CamDevice.h" + +class UVCCamDevice : public CamDevice +{ +public: + UVCCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device); + ~UVCCamDevice(); + + virtual bool SupportsIsochronous(); + virtual status_t StartTransfer(); + virtual status_t StopTransfer(); +private: + void ParseVideoControl(const uint8* buf, size_t len); + void ParseVideoStreaming(const uint8* buf, size_t len); +}; + +class UVCCamDeviceAddon : public CamDeviceAddon +{ + public: + UVCCamDeviceAddon(WebCamMediaAddOn* webcam); + virtual ~UVCCamDeviceAddon(); + + virtual UVCCamDevice *Instantiate(CamRoster &roster, BUSBDevice *from); +}; + +#endif /* _UVC_CAM_DEVICE_H */