// // FastCamController.m // FastCam // // Created by Simon Urbanek on 11/30/07. // Copyright 2007 Simon Urbanek. All rights reserved. // #import "FastCamController.h" #import "Camera.h" @implementation FastCamController - (id) init { self = [super init]; if (self) { frameNo = 0; aoiY1 = 0; aoiY2 = 491; shutter = 405; brightness = 800; gain = 192; status = @"Looking for cameras ..."; cam = nil; isRecording = ready = saveFrames = NO; frames = [[NSMutableArray alloc] init]; recDelay = 0; recDuration = 0; // fake test picture { char fr[656*256]; int i=0; while (iaoiY2)?aoiY1:aoiY2, 656, ((aoiY1aoiY2)?aoiY1:aoiY2), 656, ((aoiY1aoiY2)?aoiY1:aoiY2), 656, ((aoiY1 0) { if (recDelay > 1) { NSBeep(); [NSThread sleepForTimeInterval:recDelay-1]; } NSBeep(); [NSThread sleepForTimeInterval:1]; NSBeep(); } if (ready && [cam start]) { int fc = 0; NSLog(@" - capturing"); self.isRecording = YES; self.status = @"capturing ..."; while (isRecording) { Frame *frame = [cam dequeue]; if (frame) { BOOL showThis = YES; if (saveFrames) { NSData *data; [frames addObject:data=[NSData dataWithBytes:FRAME_DATA(frame) length:FRAME_DATASIZE(frame)]]; maxFrame++; if ((maxFrame&15)==0) [view updateMonoWithData:data atOffset: (491 - ((aoiY1>aoiY2)?aoiY1:aoiY2))*656]; /* skip frames in display to make sure we're fast enough */ } else if (showThis) [view updateMono:(char*)FRAME_DATA(frame) offset: (491 - ((aoiY1>aoiY2)?aoiY1:aoiY2))*656 length:FRAME_DATASIZE(frame)]; [cam enqueue:frame]; fc++; if (recDuration > 0 && fc >recDuration) // timed stop [self stop:self]; } NSEvent *event; while ((event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES])) [NSApp sendEvent:event]; } self.status = @"Camera is ready"; self.maxFrame = maxFrame; // to update UI } } - (void) setFrameNo: (int) newValue { int i = [frames count]; if (newValue < i) { NSData *data = [frames objectAtIndex:newValue]; frameNo = newValue; [view updateMonoWithData: data]; } } - (IBAction)stop:(id)sender { if (ready) [cam stop]; self.isRecording = NO; } - (IBAction)reset:(id)sender { [frames removeAllObjects]; if (!saveFrames) self.maxFrame = 0; } - (void)windowWillClose:(NSNotification *)notification { if (cam) { [cam stop]; [cam disableCapture]; [cam release]; cam=nil; } } #include /* RVF1 (Raw Video Frame format) [ ] ... id = 0x52564631 - defines endianness of width and height 4 MSB of width and height are reserved: width 4 MSB: bpp = avg bytes per pixel in a frame (1+x/2 => 0=1, 1=1.5, 2=2, 3=2.5, 4=3, 6=4) height 4 MSB: ; (format: 0=mono, 1=RGB, 2=RGBA) - if the origin bit (MSB) is set then x and y are included */ - (BOOL) readFramesFromFile: (NSString*) fn { unsigned int i[3]; BOOL swap = NO; NSMutableData *md; FILE *f = fopen([fn UTF8String], "rb"); NSLog(@"open f=%p", f); if (!f) return NO; NSLog(@"- read header"); if (fread(i, sizeof(int), 1, f) != 1) { fclose(f); return NO; } NSLog(@"- check magic"); if (i[0] != 0x52564631 && i[0] != 0x31465652) { fclose(f); return NO; } if (i[0] == 0x31465652) swap = YES; md = [[NSMutableData alloc] initWithCapacity: 656*491]; while (!feof(f)) { int n; NSLog(@"- read frame header (swap=%d)", swap); n = fread(i, sizeof(int), 2, f); if (n == 0 || feof(f)) break; if (n != 2) { fclose(f); [md release]; return NO; } if (swap) { i[0] = (i[0] << 24) | ((i[0]&0xff00) << 8) | ((i[0]&0xff0000) >> 8) | (i[0] >> 24); i[1] = (i[1] << 24) | ((i[1]&0xff00) << 8) | ((i[1]&0xff0000) >> 8) | (i[1] >> 24); } NSLog(@"- w=%d, h=%d", i[0], i[1]); if (((i[0]&0xf000)>0)||((i[1]&0xf000)>0)) { fclose(f); [md release]; return NO; } /* we handle plain 8-bit mono without origin only */ { unsigned int len = i[0]*i[1]; [md setLength:len]; if (fread([md mutableBytes], 1, len, f) != len) { fclose(f); [md release]; self.maxFrame=[frames count]-1; return NO; } [frames addObject:[NSData dataWithData:md]]; } } NSLog(@"- done"); fclose(f); [md release]; self.maxFrame=[frames count]-1; return YES; } - (BOOL) writeFramesToFile: (NSString*) fn { unsigned int i[3] = { 656, 491, 0x52564631 }, j = 0, k = [frames count]; FILE *f = fopen([fn UTF8String], "wb"); if (!f) return NO; if (fwrite(i+2, sizeof(int), 1, f) != 1) { fclose(f); return NO; } while (j < k) { NSData *data = (NSData*) [frames objectAtIndex:j]; if (data) { i[1] = [data length] / i[0]; // get the height based on the width if (fwrite(i, sizeof(int), 2, f) != 2) { fclose(f); return NO; } if (fwrite([data bytes], 1, i[1]*i[0], f) != i[1]*i[0]) { fclose(f); return NO; } } j++; } fclose(f); return YES; } - (IBAction) openDocument: (id)sender { NSOpenPanel *op; int runResult; op = [NSOpenPanel openPanel]; [op setRequiredFileType:@"rvf"]; [op setCanChooseDirectories: NO]; [op setAllowsMultipleSelection: NO]; if (!lastFilePath) lastFilePath = NSHomeDirectory(); runResult = [op runModalForDirectory:lastFilePath file:@"video"]; if (runResult == NSOKButton) { lastFilePath = [op directory]; if (![self readFramesFromFile:lastFileName=[op filename]]) NSBeep(); } } - (IBAction) saveDocumentAs: (id)sender { NSSavePanel *sp; int runResult; sp = [NSSavePanel savePanel]; //[sp setAccessoryView:nil]; [sp setRequiredFileType:@"rvf"]; if (!lastFilePath) lastFilePath = NSHomeDirectory(); runResult = [sp runModalForDirectory:lastFilePath file:@"video"]; if (runResult == NSOKButton) { lastFilePath = [sp directory]; if (![self writeFramesToFile:lastFileName=[sp filename]]) NSBeep(); } } - (IBAction) saveDocument: (id)sender { if (!lastFileName) [self saveDocumentAs:sender]; else if (![self writeFramesToFile:lastFileName]) NSBeep(); } @end