This is CameraController.m in view mode; [Download] [Up]
#import "CameraController.h"
#import "NDCInfo.h"
#import <misckit/MiscString.h>
#import <video/NXLiveVideoView.h>
static BOOL _NDIsGrabbing;
void handler( DPSTimedEntry teNumber, double now, void *userData )
{
id grabber;
if( _NDIsGrabbing ) return;
_NDIsGrabbing = YES;
grabber = (id)userData;
[grabber grab:nil];
}
@implementation CameraController
- init
{
id ourServer;
NXSize destSize = { 300, 225};
[super init];
_destRect.origin.x = 0;
_destRect.origin.y = 0;
_outputRect.origin.x = 0;
_outputRect.origin.y = 0;
_outputRect.size.width = 300;
_outputRect.size.height = 225;
// [outputView getFrame:&_outputRect];
currentImage = [NXImage new];
[currentImage setSize:&destSize];
outputImage = [NXImage new];
// [outputImage setSize:&(outRect.size)];
[outputImage setSize:&destSize];
// To allow outside remote grab-control ...puuh cool word :-)
// we install a plain DO entry.
ourServer = [NXConnection registerRoot:self
withName:"localhost/NDCamera"];
[ourServer runFromAppKitWithPriority:NX_MODALRESPTHRESHOLD];
return self;
}
- showInfo:sender
{
if( !info ) info = [NDCInfo new];
[info makeKeyAndOrderFront:self];
return self;
}
- start:sender
{
int i;
id aWindow;
_cameraOn = YES;
// Slide the button to open..
// I don't think we have to take care of timed animation because this
// app will always run on a NeXT Dimension which has fixed speed
// ...perhaps the Turbos a a little faster...who cares anyway.
aWindow = [onOffButton window];
for( i=0; i<7; i++ )
{
[onOffButton moveBy:0 :3];
[aWindow display];
}
[self adjustGrabRect:self];
[self _adjustOcularTitle];
[self adjustCameraSource:self];
[recButton setEnabled:YES];
[camera start:self];
[onOffButton setAction:@selector(stop:)];
[recButton setAction:@selector(startGrabbing:)];
// Grab an initial image...I know that grab will increase the count
// so lets start with something ueful.
_frameCount = -1;
[self grab:self];
return self;
}
- stop:sender
{
int i;
id aWindow;
_cameraOn = NO;
[recButton setEnabled:NO];
[self stopGrabbing:self];
[camera stop:self];
// Slide the button to close..
aWindow = [onOffButton window];
for( i=0; i<7; i++ )
{
[onOffButton moveBy:0 :-3];
[aWindow display];
}
[self adjustGrabRect:self];
[onOffButton setAction:@selector(start:)];
return self;
}
- grab:sender
{
_NDIsGrabbing = YES;
[camera grabIn:currentImage
fromRect:&_sourceRect
toRect:&_destRect];
_frameCount++;
[frameNumber setIntValue:_frameCount];
[currentImage setScalable:YES];
[outputImage lockFocus];
// One possible way of getting the image where we want it:
//
// [currentImage setSize:&(_outputRect.size)];
// [currentImage composite:NX_COPY toPoint:&aPoint];
// [currentImage setSize:&(_destRect.size)];
// Our way to do it
[currentImage drawRepresentation:[currentImage bestRepresentation]
inRect:&_outputRect];
// another way....
//
// aImageRep = [currentImage bestRepresentation];
// [aImageRep drawIn:&_outputRect];
[outputImage unlockFocus];
[outputView setImage:outputImage];
NXPing();
// Lets see if we have to save that stuff ??
if( grabOutput != nil )[self _saveCurrentFrame];
_NDIsGrabbing = NO;
return self;
}
- _saveCurrentFrame
{
id aString;
id filename;
FILE * dummyStream;
NXStream * aStream;
float compressionFactor;
filename = [grabOutput copy];
aString = [filename fileBasename];
[filename cat:"/"];
[filename concatenate:aString];
[filename cat:"."];
[aString setIntValue:_frameCount];
[filename concatenate:aString];
[filename cat:".tiff"];
NXLogError( [filename stringValue] );
// Well the streams won't truncate a file so we have to do it on
// our own.
// We should do a backup of existing files here if requested.
dummyStream = fopen( [filename stringValue], "w" );
if( dummyStream ) fclose( dummyStream );
aStream = NXMapFile( [filename stringValue], NX_WRITEONLY );
[outputImage writeTIFF:aStream
allRepresentations:NO
// usingCompression:NX_TIFF_COMPRESSION_LZW
usingCompression:NX_TIFF_COMPRESSION_NONE
andFactor:0];
NXSaveToFile( aStream, [filename stringValue] );
NXCloseMemory( aStream, NX_FREEBUFFER );
[aString free];
[filename free];
return self;
}
- startGrabbing:sender
{
// Now if we have to do autorecording lets init the timed entry...
if( [autoGrabButton state] == YES )
{
[self _startTimer];
[recButton setAction:@selector(stopGrabbing:)];
[recButton setState:1];
}
// otherwise we will just grab a single frame.
else
{
[recButton setState:1];
[self grab:self];
[recButton setState:0];
}
return self;
}
- adjustOutputFile:pathString
{
_frameCount = 0;
[frameNumber setIntValue:_frameCount];
if( !grabOutput )
grabOutput = [MiscString new];
[grabOutput takeStringValueFrom:pathString];
if( ![grabOutput isFileOfType:Misc_Directory] ||
[grabOutput isEmpty] )
{
[grabOutput free];
grabOutput = nil;
[grabOutputField setStringValue:""];
}
else
{
[grabOutputField setStringValue:[grabOutput stringValue]];
}
return self;
}
- stopGrabbing:sender
{
[self _stopTimer];
[recButton setAction:@selector(startGrabbing:)];
[recButton setState:0];
return self;
}
- (BOOL)isGrabbing
{
return (BOOL)[recButton state];
}
- adjustSpeed:sender
{
if( !_cameraOn ) return self;
[self stopGrabbing:self];
[self startGrabbing:self];
return self;
}
- _startTimer
{
double frameDelay;
float aBaseRate;
if( animateTE == 0 )
{
aBaseRate = [fpsBaseRateField floatValue];
if( aBaseRate < 0.001 ) aBaseRate = 0.001;
frameDelay = 1 / ([[speedMatrix selectedCell] tag] * aBaseRate);
animateTE = DPSAddTimedEntry( frameDelay, (DPSTimedEntryProc)handler,
self, NX_BASETHRESHOLD );
}
return self;
}
- _stopTimer
{
if( animateTE )
{
DPSRemoveTimedEntry( animateTE );
animateTE = 0;
}
return self;
}
- baseFpsRateChanged:sender
{
return self;
}
- adjustCameraSource:sender
{
[camera selectInput:[[inputMatrix selectedCell] tag]];
return self;
}
- adjustGrabRect:sender
{
[self _adjustGrabRect];
_refFrameSize.width = _sourceRect.size.width;
_refFrameSize.height = _sourceRect.size.height;
return self;
}
- _adjustGrabRect
{
// BUG: We really should make some sanity checks !!
_sourceRect.origin.x = [grabOriginXField intValue];
_sourceRect.origin.y = [grabOriginYField intValue];
_sourceRect.size.width = [grabSizeWidthField intValue];
_sourceRect.size.height = [grabSizeHeightField intValue];
// Lets get a new image with the right size...Remember that this size
// does not reflex the size of the saved image !! This has to be resized
// to reflect the different scale.
_destRect.size.width = _sourceRect.size.width;
_destRect.size.height = _sourceRect.size.height;
if( currentImage ) [currentImage free];
currentImage = [NXImage new];
[currentImage setSize:&(_destRect.size)];
return self;
}
- zoomIn:sender
{
float xInc;
float yInc;
// Be sure that there will be still a useful rect to see.
xInc = _refFrameSize.width / 100;
if( xInc < 2 ) xInc = 2;
yInc = _refFrameSize.height / 100;
if( yInc < 2 ) yInc = 2;
if( _sourceRect.size.width > 20 &&
_sourceRect.size.height > 20 )
{
[grabOriginXField setIntValue:_sourceRect.origin.x + xInc];
[grabOriginYField setIntValue:_sourceRect.origin.y + yInc];
[grabSizeWidthField setIntValue:_sourceRect.size.width - 2* xInc];
[grabSizeHeightField setIntValue:_sourceRect.size.height - 2* yInc];
}
[self _adjustGrabRect];
[self grab:self];
return self;
}
- zoomOut:sender
{
float xInc;
float yInc;
// lets not pass the lower left corner..
xInc = _refFrameSize.width / 100;
if( xInc < 2 ) xInc = 2;
yInc = _refFrameSize.height / 100;
if( yInc < 2 ) yInc = 2;
if( _sourceRect.origin.x > 4 &&
_sourceRect.origin.y > 4 )
{
[grabOriginXField setIntValue:_sourceRect.origin.x - xInc];
[grabOriginYField setIntValue:_sourceRect.origin.y - yInc];
[grabSizeWidthField setIntValue:_sourceRect.size.width + 2* xInc];
[grabSizeHeightField setIntValue:_sourceRect.size.height + 2* yInc];
}
[self _adjustGrabRect];
[self grab:self];
return self;
}
- openVideoControls:sender
{
int i;
int stepSize;
int direction;
id aWindow;
NXRect aFrame;
// opens and closes the controls area...the name is not very cleaver..
// but who cares.
[sender getFrame:&aFrame];
if( aFrame.origin.x < 100 )
direction = +1;
else direction = -1;
stepSize = 6 * direction;
aWindow = [sender window];
for( i=0; i<14; i++ )
{
[sender moveBy:stepSize :0];
[aWindow display];
}
stepSize = 3 * direction;
for( i=0; i<3; i++ )
{
[sender moveBy:stepSize :0];
[aWindow display];
}
return self;
}
- changeHue:sender
{
[camera setInputHue:
[camera inputHue] + ([sender tag] * 36.0)];
[sender setState:0];
// We lack any visual feedback for the single values...so we'll use the
// console...sorry...thats nasty; I know.
NXLogError( "Hue: %f", [camera inputHue] );
return self;
}
- changeBrightness:sender
{
[camera setInputBrightness:
[camera inputBrightness] + ([sender tag] / 10.0)];
[sender setState:0];
// We lack any visual feedback for the single values...so we'll use the
// console...sorry...thats nasty; I know.
NXLogError( "Brightness: %f", [camera inputBrightness] );
return self;
}
- changeSaturation:sender
{
[camera setInputSaturation:
[camera inputSaturation] + ([sender tag] / 10.0)];
[sender setState:0];
// We lack any visual feedback for the single values...so we'll use the
// console...sorry...thats nasty; I know.
NXLogError( "Saturation: %f", [camera inputSaturation] );
return self;
}
- changeGamma:sender
{
[camera setInputGamma:
[camera inputGamma] + ([sender tag] / 10.0)];
[sender setState:0];
// We lack any visual feedback for the single values...so we'll use the
// console...sorry...thats nasty; I know.
NXLogError( "Gamma: %f", [camera inputGamma] );
return self;
}
- changeSharpness:sender
{
[camera setInputSharpness:
[camera inputSharpness] + ([sender tag] / 10.0)];
[sender setState:0];
// We lack any visual feedback for the single values...so we'll use the
// console...sorry...thats nasty; I know.
NXLogError( "Sharpness: %f", [camera inputSharpness] );
return self;
}
- windowDidMove:sender
{
// If the window should stick together...we'll do it.
// if( !keepWindowsTogether ) return self;
return self;
}
- windowDidResize:sender
{
NXRect aFrame;
// If our ocular has changed we should adjust the title and the
// image grabbing area.
if( sender != [outputView window] ) return self;
[outputView getBounds:&aFrame];
[outputImage setSize:&(aFrame.size)];
_outputRect.size.width = aFrame.size.width;
_outputRect.size.height = aFrame.size.height;
[self _adjustOcularTitle];
// We should grab the image again...but it would be faster to just scale
// the old one...
// [self grab:self];
return self;
}
- _adjustOcularTitle
{
id ourWindow;
id aString;
id intString;
ourWindow = [outputView window];
aString = [MiscString newWithString:"("];
intString = [MiscString new];
[intString setIntValue:_outputRect.size.width];
[aString concatenate:intString];
[aString cat:" x "];
[intString setIntValue:_outputRect.size.height];
[aString concatenate:intString];
[aString cat:") Ocular"];
[ourWindow setTitle:[aString stringValue]];
[aString free];
[intString free];
return self;
}
@endThese are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.