overte-HifiExperiments/interface/external/UVCCameraControl/src/UVCCameraControl.m
2013-06-19 11:29:50 -07:00

393 lines
12 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// This code was written by Dominic Szablewski: http://phoboslab.org/log/2009/07/uvc-camera-control-for-mac-os-x
//
// It is in the public domain:
//
// "Consider this as public domain. Do whatever you want with it. I'm not responsible if your camera explodes or
// for any other damages this software might cause!"
//
#import "UVCCameraControl.h"
#import "UVCCameraControl.hpp"
void configureCamera(int vendorID, int productID, int autoExposure, float exposure, float contrast,
float saturation, float sharpness, int autoWhiteBalance, float whiteBalance) {
UVCCameraControl* cameraControl = [[UVCCameraControl alloc] initWithVendorID:0x05ac productID:0x8510];
[cameraControl setAutoExposure:autoExposure];
[cameraControl setExposure:exposure];
[cameraControl setContrast:contrast];
[cameraControl setSaturation:saturation];
[cameraControl setSharpness:sharpness];
[cameraControl setAutoWhiteBalance:autoWhiteBalance];
[cameraControl setWhiteBalance:whiteBalance];
}
const uvc_controls_t uvc_controls = {
.autoExposure = {
.unit = UVC_INPUT_TERMINAL_ID,
.selector = 0x02,
.size = 1,
},
.exposure = {
.unit = UVC_INPUT_TERMINAL_ID,
.selector = 0x04,
.size = 4,
},
.brightness = {
.unit = UVC_PROCESSING_UNIT_ID,
.selector = 0x02,
.size = 2,
},
.contrast = {
.unit = UVC_PROCESSING_UNIT_ID,
.selector = 0x03,
.size = 2,
},
.gain = {
.unit = UVC_PROCESSING_UNIT_ID,
.selector = 0x04,
.size = 2,
},
.saturation = {
.unit = UVC_PROCESSING_UNIT_ID,
.selector = 0x07,
.size = 2,
},
.sharpness = {
.unit = UVC_PROCESSING_UNIT_ID,
.selector = 0x08,
.size = 2,
},
.whiteBalance = {
.unit = UVC_PROCESSING_UNIT_ID,
.selector = 0x0A,
.size = 2,
},
.autoWhiteBalance = {
.unit = UVC_PROCESSING_UNIT_ID,
.selector = 0x0B,
.size = 1,
},
};
@implementation UVCCameraControl
- (id)initWithLocationID:(UInt32)locationID {
if( self = [super init] ) {
interface = NULL;
// Find All USB Devices, get their locationId and check if it matches the requested one
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
io_iterator_t serviceIterator;
IOServiceGetMatchingServices( kIOMasterPortDefault, matchingDict, &serviceIterator );
io_service_t camera;
while( camera = IOIteratorNext(serviceIterator) ) {
// Get DeviceInterface
IOUSBDeviceInterface **deviceInterface = NULL;
IOCFPlugInInterface **plugInInterface = NULL;
SInt32 score;
kern_return_t kr = IOCreatePlugInInterfaceForService( camera, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score );
if( (kIOReturnSuccess != kr) || !plugInInterface ) {
NSLog( @"CameraControl Error: IOCreatePlugInInterfaceForService returned 0x%08x.", kr );
continue;
}
HRESULT res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &deviceInterface );
(*plugInInterface)->Release(plugInInterface);
if( res || deviceInterface == NULL ) {
NSLog( @"CameraControl Error: QueryInterface returned %d.\n", (int)res );
continue;
}
UInt32 currentLocationID = 0;
(*deviceInterface)->GetLocationID(deviceInterface, &currentLocationID);
if( currentLocationID == locationID ) {
// Yep, this is the USB Device that was requested!
interface = [self getControlInferaceWithDeviceInterface:deviceInterface];
return self;
}
} // end while
}
return self;
}
- (id)initWithVendorID:(long)vendorID productID:(long)productID {
if( self = [super init] ) {
interface = NULL;
// Find USB Device
CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
CFNumberRef numberRef;
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendorID);
CFDictionarySetValue( matchingDict, CFSTR(kUSBVendorID), numberRef );
CFRelease(numberRef);
numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &productID);
CFDictionarySetValue( matchingDict, CFSTR(kUSBProductID), numberRef );
CFRelease(numberRef);
io_service_t camera = IOServiceGetMatchingService( kIOMasterPortDefault, matchingDict );
// Get DeviceInterface
IOUSBDeviceInterface **deviceInterface = NULL;
IOCFPlugInInterface **plugInInterface = NULL;
SInt32 score;
kern_return_t kr = IOCreatePlugInInterfaceForService( camera, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score );
if( (kIOReturnSuccess != kr) || !plugInInterface ) {
NSLog( @"CameraControl Error: IOCreatePlugInInterfaceForService returned 0x%08x.", kr );
return self;
}
HRESULT res = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &deviceInterface );
(*plugInInterface)->Release(plugInInterface);
if( res || deviceInterface == NULL ) {
NSLog( @"CameraControl Error: QueryInterface returned %d.\n", (int)res );
return self;
}
interface = [self getControlInferaceWithDeviceInterface:deviceInterface];
}
return self;
}
- (IOUSBInterfaceInterface190 **)getControlInferaceWithDeviceInterface:(IOUSBDeviceInterface **)deviceInterface {
IOUSBInterfaceInterface190 **controlInterface;
io_iterator_t interfaceIterator;
IOUSBFindInterfaceRequest interfaceRequest;
interfaceRequest.bInterfaceClass = UVC_CONTROL_INTERFACE_CLASS;
interfaceRequest.bInterfaceSubClass = UVC_CONTROL_INTERFACE_SUBCLASS;
interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
interfaceRequest.bAlternateSetting = kIOUSBFindInterfaceDontCare;
IOReturn success = (*deviceInterface)->CreateInterfaceIterator( deviceInterface, &interfaceRequest, &interfaceIterator );
if( success != kIOReturnSuccess ) {
return NULL;
}
io_service_t usbInterface;
HRESULT result;
if( usbInterface = IOIteratorNext(interfaceIterator) ) {
IOCFPlugInInterface **plugInInterface = NULL;
//Create an intermediate plug-in
SInt32 score;
kern_return_t kr = IOCreatePlugInInterfaceForService( usbInterface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score );
//Release the usbInterface object after getting the plug-in
kr = IOObjectRelease(usbInterface);
if( (kr != kIOReturnSuccess) || !plugInInterface ) {
NSLog( @"CameraControl Error: Unable to create a plug-in (%08x)\n", kr );
return NULL;
}
//Now create the device interface for the interface
result = (*plugInInterface)->QueryInterface( plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID *) &controlInterface );
//No longer need the intermediate plug-in
(*plugInInterface)->Release(plugInInterface);
if( result || !controlInterface ) {
NSLog( @"CameraControl Error: Couldnt create a device interface for the interface (%08x)", (int) result );
return NULL;
}
return controlInterface;
}
return NULL;
}
- (BOOL)sendControlRequest:(IOUSBDevRequest)controlRequest {
if( !interface ){
NSLog( @"CameraControl Error: No interface to send request" );
return NO;
}
//Now open the interface. This will cause the pipes associated with
//the endpoints in the interface descriptor to be instantiated
kern_return_t kr = (*interface)->ControlRequest( interface, 0, &controlRequest );
if( kr != kIOReturnSuccess ) {
NSLog( @"CameraControl Error: Control request failed: %08x", kr );
return NO;
}
return YES;
}
- (BOOL)setData:(long)value withLength:(int)length forSelector:(int)selector at:(int)unitId {
IOUSBDevRequest controlRequest;
controlRequest.bmRequestType = USBmakebmRequestType( kUSBOut, kUSBClass, kUSBInterface );
controlRequest.bRequest = UVC_SET_CUR;
controlRequest.wValue = (selector << 8) | 0x00;
controlRequest.wIndex = (unitId << 8) | 0x00;
controlRequest.wLength = length;
controlRequest.wLenDone = 0;
controlRequest.pData = &value;
return [self sendControlRequest:controlRequest];
}
- (long)getDataFor:(int)type withLength:(int)length fromSelector:(int)selector at:(int)unitId {
long value = 0;
IOUSBDevRequest controlRequest;
controlRequest.bmRequestType = USBmakebmRequestType( kUSBIn, kUSBClass, kUSBInterface );
controlRequest.bRequest = type;
controlRequest.wValue = (selector << 8) | 0x00;
controlRequest.wIndex = (unitId << 8) | 0x00;
controlRequest.wLength = length;
controlRequest.wLenDone = 0;
controlRequest.pData = &value;
BOOL success = [self sendControlRequest:controlRequest];
return ( success ? value : 0 );
}
// Get Range (min, max)
- (uvc_range_t)getRangeForControl:(uvc_control_info_t *)control {
uvc_range_t range = { 0, 0 };
range.min = [self getDataFor:UVC_GET_MIN withLength:control->size fromSelector:control->selector at:control->unit];
range.max = [self getDataFor:UVC_GET_MAX withLength:control->size fromSelector:control->selector at:control->unit];
return range;
}
// Used to de-/normalize values
- (float)mapValue:(float)value fromMin:(float)fromMin max:(float)fromMax toMin:(float)toMin max:(float)toMax {
return toMin + (toMax - toMin) * ((value - fromMin) / (fromMax - fromMin));
}
// Get a normalized value
- (float)getValueForControl:(uvc_control_info_t *)control {
// TODO: Cache the range somewhere?
uvc_range_t range = [self getRangeForControl:control];
int intval = [self getDataFor:UVC_GET_CUR withLength:control->size fromSelector:control->selector at:control->unit];
return [self mapValue:intval fromMin:range.min max:range.max toMin:0 max:1];
}
// Set a normalized value
- (BOOL)setValue:(float)value forControl:(uvc_control_info_t *)control {
// TODO: Cache the range somewhere?
uvc_range_t range = [self getRangeForControl:control];
int intval = [self mapValue:value fromMin:0 max:1 toMin:range.min max:range.max];
return [self setData:intval withLength:control->size forSelector:control->selector at:control->unit];
}
// ================================================================
// Set/Get the actual values for the camera
//
- (BOOL)setAutoExposure:(BOOL)enabled {
int intval = (enabled ? 0x08 : 0x01); // "auto exposure modes" ar NOT boolean (on|off) as it seems
return [self setData:intval
withLength:uvc_controls.autoExposure.size
forSelector:uvc_controls.autoExposure.selector
at:uvc_controls.autoExposure.unit];
}
- (BOOL)getAutoExposure {
int intval = [self getDataFor:UVC_GET_CUR
withLength:uvc_controls.autoExposure.size
fromSelector:uvc_controls.autoExposure.selector
at:uvc_controls.autoExposure.unit];
return ( intval == 0x08 ? YES : NO );
}
- (BOOL)setExposure:(float)value {
value = 1 - value;
return [self setValue:value forControl:&uvc_controls.exposure];
}
- (float)getExposure {
float value = [self getValueForControl:&uvc_controls.exposure];
return 1 - value;
}
- (BOOL)setGain:(float)value {
return [self setValue:value forControl:&uvc_controls.gain];
}
- (float)getGain {
return [self getValueForControl:&uvc_controls.gain];
}
- (BOOL)setBrightness:(float)value {
return [self setValue:value forControl:&uvc_controls.brightness];
}
- (float)getBrightness {
return [self getValueForControl:&uvc_controls.brightness];
}
- (BOOL)setContrast:(float)value {
return [self setValue:value forControl:&uvc_controls.contrast];
}
- (float)getContrast {
return [self getValueForControl:&uvc_controls.contrast];
}
- (BOOL)setSaturation:(float)value {
return [self setValue:value forControl:&uvc_controls.saturation];
}
- (float)getSaturation {
return [self getValueForControl:&uvc_controls.saturation];
}
- (BOOL)setSharpness:(float)value {
return [self setValue:value forControl:&uvc_controls.sharpness];
}
- (float)getSharpness {
return [self getValueForControl:&uvc_controls.sharpness];
}
- (BOOL)setAutoWhiteBalance:(BOOL)enabled {
int intval = (enabled ? 0x01 : 0x00);
return [self setData:intval
withLength:uvc_controls.autoWhiteBalance.size
forSelector:uvc_controls.autoWhiteBalance.selector
at:uvc_controls.autoWhiteBalance.unit];
}
- (BOOL)getAutoWhiteBalance {
int intval = [self getDataFor:UVC_GET_CUR
withLength:uvc_controls.autoWhiteBalance.size
fromSelector:uvc_controls.autoWhiteBalance.selector
at:uvc_controls.autoWhiteBalance.unit];
return ( intval ? YES : NO );
}
- (BOOL)setWhiteBalance:(float)value {
return [self setValue:value forControl:&uvc_controls.whiteBalance];
}
- (float)getWhiteBalance {
return [self getValueForControl:&uvc_controls.whiteBalance];
}
@end