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; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.