home *** CD-ROM | disk | FTP | other *** search
- #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;
- }
-
- @end