PageRenderTime 85ms CodeModel.GetById 19ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 0ms

/filesystems/procfs/sequencegrab/CSGCamera.m

http://macfuse.googlecode.com/
Objective C | 394 lines | 273 code | 86 blank | 35 comment | 52 complexity | 765be65e04626eaba271d5479686a5b5 MD5 | raw file
  1//
  2//  CSGCamera.m
  3//  MotionTracker
  4//
  5//  Created by Tim Omernick on 3/7/05.
  6//  Copyright 2005 Tim Omernick. All rights reserved.
  7//
  8
  9// Portions of this file were inspired by Apple Computer, Inc.'s Cocoa SGDataProc example, which can be found here:
 10// <http://developer.apple.com/samplecode/Cocoa_-_SGDataProc/Cocoa_-_SGDataProc.html>
 11// Also, I'd like to thank Chris Meyer for his excellent -imageFromGWorld: method, which he gave me permission to use for this framework.
 12
 13#import "CSGCamera.h"
 14
 15#import "CSGImage.h"
 16
 17@interface CSGCamera (Private)
 18- (void)_sequenceGrabberIdle;
 19- (BOOL)_setupDecompression;
 20- (void)_didUpdate;
 21- (CSGImage *)_imageFromGWorld:(GWorldPtr)gworld;
 22@end
 23
 24@interface CSGCamera (SequenceGrabber)
 25pascal OSErr CSGCameraSGDataProc(SGChannel channel, Ptr data, long dataLength, long *offset, long channelRefCon, TimeValue time, short writeType, long refCon);
 26@end
 27
 28@implementation CSGCamera
 29
 30// Init and dealloc
 31
 32- (void)dealloc;
 33{
 34	[self stop];
 35	
 36	[delegate release];
 37	
 38	[super dealloc];
 39}
 40
 41// API
 42
 43- (void)setDelegate:(id)newDelegate;
 44{
 45    if (delegate == newDelegate)
 46        return;
 47        
 48    [delegate release];
 49    delegate = [newDelegate retain];
 50}
 51
 52- (BOOL)startWithSize:(NSSize)frameSize;
 53{
 54    OSErr theErr;
 55    
 56    timeScale = 0;
 57    lastTime = 0;
 58    
 59    // Initialize movie toolbox
 60    theErr = EnterMovies();
 61    if (theErr != noErr) {
 62        NSLog(@"EnterMovies() returned %ld", theErr);
 63        return NO;
 64    }
 65    
 66    // Open default sequence grabber component
 67    component = OpenDefaultComponent(SeqGrabComponentType, 0);
 68    if (!component) {
 69        NSLog(@"Could not open sequence grabber component.");
 70        return NO;
 71    }
 72    
 73    // Initialize sequence grabber component
 74    theErr = SGInitialize(component);
 75    if (theErr != noErr) {
 76        NSLog(@"SGInitialize() returned %ld", theErr);
 77        return NO;
 78    }
 79    
 80    // Don't make movie
 81    theErr = SGSetDataRef(component, 0, 0, seqGrabDontMakeMovie);
 82    if (theErr != noErr) {
 83        NSLog(@"SGSetDataRef() returned %ld", theErr);
 84        return NO;
 85    }
 86    
 87    // Create sequence grabber video channel
 88    theErr = SGNewChannel(component, VideoMediaType, &channel);
 89    if (theErr != noErr) {
 90        NSLog(@"SGNewChannel() returned %ld", theErr);
 91        return NO;
 92    }
 93    
 94    // Set the grabber's bounds
 95    boundsRect.top = 0;
 96    boundsRect.left = 0;
 97    boundsRect.bottom = frameSize.height;
 98    boundsRect.right = frameSize.width;
 99	
100//    NSLog(@"boundsRect=(%d, %d, %d, %d)", boundsRect.top, boundsRect.left, boundsRect.bottom, boundsRect.right);
101    
102    theErr = SGSetChannelBounds(component, &boundsRect);
103    
104    // Create the GWorld
105    theErr = QTNewGWorld(&gWorld, k32ARGBPixelFormat, &boundsRect, 0, NULL, 0);
106    if (theErr != noErr) {
107        NSLog(@"QTNewGWorld() returned %ld", theErr);
108        return NO;
109    }
110    
111    // Lock the pixmap
112    if (!LockPixels(GetPortPixMap(gWorld))) {
113        NSLog(@"Could not lock pixels.");
114        return NO;
115    }
116    
117    // Set GWorld
118    theErr = SGSetGWorld(component, gWorld, GetMainDevice());
119    if (theErr != noErr) {
120        NSLog(@"SGSetGWorld() returned %ld", theErr);
121        return NO;
122    }
123    
124    // Set the channel's bounds
125    theErr = SGSetChannelBounds(channel, &boundsRect);
126    if (theErr != noErr) {
127        NSLog(@"SGSetChannelBounds(2) returned %ld", theErr);
128        return NO;
129    }
130    
131    // Set the channel usage to record
132    theErr = SGSetChannelUsage(channel, seqGrabRecord);
133    if (theErr != noErr) {
134        NSLog(@"SGSetChannelUsage() returned %ld", theErr);
135        return NO;
136    }
137    
138    // Set data proc
139    theErr = SGSetDataProc(component, NewSGDataUPP(&CSGCameraSGDataProc), (long)self);
140    if (theErr != noErr) {
141        NSLog(@"SGSetDataProc() returned %ld", theErr);
142        return NO;
143    }
144    
145    // Prepare
146    theErr = SGPrepare(component, false, true);
147    if (theErr != noErr) {
148        NSLog(@"SGPrepare() returned %ld", theErr);
149        return NO;
150    }
151    
152    // Start recording
153    theErr = SGStartRecord(component);
154    if (theErr != noErr) {
155        NSLog(@"SGStartRecord() returned %ld", theErr);
156        return NO;
157    }
158
159	startTime = [NSDate timeIntervalSinceReferenceDate];
160	
161    // Set up decompression sequence (camera -> GWorld)
162    [self _setupDecompression];
163    
164    // Start frame timer
165    frameTimer = [[NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(_sequenceGrabberIdle) userInfo:nil repeats:YES] retain];
166        
167    [self retain]; // Matches autorelease in -stop
168    
169    return YES;
170}
171
172- (BOOL)stop;
173{    
174    // Stop frame timer
175	if (frameTimer) {
176		[frameTimer invalidate];
177		[frameTimer release];
178		frameTimer = nil;
179	}
180    
181    // Stop recording
182	if (component)
183		SGStop(component);
184    
185    ComponentResult theErr;
186
187    // End decompression sequence
188	if (decompressionSequence) {
189		theErr = CDSequenceEnd(decompressionSequence);
190		if (theErr != noErr) {
191			NSLog(@"CDSequenceEnd() returned %ld", theErr);
192		}
193		decompressionSequence = 0;
194	}
195    
196    // Close sequence grabber component
197	if (component) {
198		theErr = CloseComponent(component);
199		if (theErr != noErr) {
200			NSLog(@"CloseComponent() returned %ld", theErr);
201		}
202		component = NULL;
203	}
204    
205    // Dispose of GWorld
206	if (gWorld) {
207		DisposeGWorld(gWorld);
208		gWorld = NULL;
209	}
210    
211    [self autorelease]; // Matches retain in -start
212    
213    return YES;
214}
215
216@end
217
218@implementation CSGCamera (Private)
219
220- (void)_sequenceGrabberIdle;
221{
222    OSErr theErr;
223    
224    theErr = SGIdle(component);
225    if (theErr != noErr) {
226        NSLog(@"SGIdle returned %ld", theErr);
227        return;
228    }
229}
230
231- (BOOL)_setupDecompression;
232{
233    ComponentResult theErr;
234    
235    ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0);
236    theErr = SGGetChannelSampleDescription(channel, (Handle)imageDesc);
237    if (theErr != noErr) {
238        NSLog(@"SGGetChannelSampleDescription() returned %ld", theErr);
239        return NO;
240    }
241    
242    Rect sourceRect;
243    sourceRect.top = 0;
244    sourceRect.left = 0;
245    sourceRect.right = (**imageDesc).width;
246    sourceRect.bottom = (**imageDesc).height;
247    
248    MatrixRecord scaleMatrix;
249    RectMatrix(&scaleMatrix, &sourceRect, &boundsRect);
250    
251    theErr = DecompressSequenceBegin(&decompressionSequence, imageDesc, gWorld, NULL, NULL, &scaleMatrix, srcCopy, NULL, 0, codecNormalQuality, bestSpeedCodec);
252    if (theErr != noErr) {
253        NSLog(@"DecompressionSequenceBegin() returned %ld", theErr);
254        return NO;
255    }
256    
257    DisposeHandle((Handle)imageDesc);
258	
259	return YES;
260}
261
262- (void)_didUpdate;
263{
264    if ([delegate respondsToSelector:@selector(camera:didReceiveFrame:)]) {
265        CSGImage *frameImage = [self _imageFromGWorld:gWorld];
266        if (frameImage) {
267            [frameImage setSampleTime:startTime + ((double)lastTime / (double)timeScale)];
268            [delegate camera:self didReceiveFrame:frameImage];
269        }
270    }
271}
272
273// Thanks to Chris Meyer from http://www.cocoadev.com/
274- (CSGImage *)_imageFromGWorld:(GWorldPtr)gworld;
275{
276    NSParameterAssert( gworld != NULL );
277
278    PixMapHandle pixMapHandle = GetGWorldPixMap( gworld );
279    if ( LockPixels( pixMapHandle ) )
280    {
281        Rect portRect;
282        GetPortBounds( gworld, &portRect );
283        int pixels_wide = (portRect.right - portRect.left);
284        int pixels_high = (portRect.bottom - portRect.top);
285
286        int bps = 8;
287        int spp = 4;
288        BOOL has_alpha = YES;
289
290        NSBitmapImageRep *frameBitmap = [[[NSBitmapImageRep alloc]
291            initWithBitmapDataPlanes:NULL
292                          pixelsWide:pixels_wide
293                          pixelsHigh:pixels_high
294                       bitsPerSample:bps
295                     samplesPerPixel:spp
296                            hasAlpha:has_alpha
297                            isPlanar:NO
298                      colorSpaceName:NSDeviceRGBColorSpace
299                         bytesPerRow:0
300                        bitsPerPixel:0] autorelease];
301        
302        CGColorSpaceRef dst_colorspaceref = CGColorSpaceCreateDeviceRGB();
303
304        CGImageAlphaInfo dst_alphainfo = has_alpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNone;
305
306        CGContextRef dst_contextref = CGBitmapContextCreate( [frameBitmap bitmapData],
307                                                             pixels_wide,
308                                                             pixels_high,
309                                                             bps,
310                                                             [frameBitmap bytesPerRow],
311                                                             dst_colorspaceref,
312                                                             dst_alphainfo );
313
314        void *pixBaseAddr = GetPixBaseAddr(pixMapHandle);
315
316        long pixmapRowBytes = GetPixRowBytes(pixMapHandle);
317
318        CGDataProviderRef dataproviderref = CGDataProviderCreateWithData( NULL, pixBaseAddr, pixmapRowBytes * pixels_high, NULL );
319
320        int src_bps = 8;
321        int src_spp = 4;
322        BOOL src_has_alpha = YES;
323
324        CGColorSpaceRef src_colorspaceref = CGColorSpaceCreateDeviceRGB();
325
326        CGImageAlphaInfo src_alphainfo = src_has_alpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNone;
327
328        CGImageRef src_imageref = CGImageCreate( pixels_wide,
329                                                 pixels_high,
330                                                 src_bps,
331                                                 src_bps * src_spp,
332                                                 pixmapRowBytes,
333                                                 src_colorspaceref,
334                                                 src_alphainfo,
335                                                 dataproviderref,
336                                                 NULL,
337                                                 NO, // shouldInterpolate
338                                                 kCGRenderingIntentDefault );
339
340        CGRect rect = CGRectMake( 0, 0, pixels_wide, pixels_high );
341
342        CGContextDrawImage( dst_contextref, rect, src_imageref );
343
344        CGImageRelease( src_imageref );
345        CGColorSpaceRelease( src_colorspaceref );
346        CGDataProviderRelease( dataproviderref );
347        CGContextRelease( dst_contextref );
348        CGColorSpaceRelease( dst_colorspaceref );
349
350        UnlockPixels( pixMapHandle );
351
352        CSGImage *image = [[CSGImage alloc] initWithSize:NSMakeSize(pixels_wide, pixels_high)];
353        [image addRepresentation:frameBitmap];
354        
355        return [image autorelease];
356    }
357    
358    return NULL;
359}
360
361@end
362
363@implementation CSGCamera (SequenceGrabber)
364
365pascal OSErr CSGCameraSGDataProc(SGChannel channel, Ptr data, long dataLength, long *offset, long channelRefCon, TimeValue time, short writeType, long refCon)
366{
367    CSGCamera *camera = (CSGCamera *)refCon;
368    ComponentResult theErr;
369    
370    if (camera->timeScale == 0) {
371        theErr = SGGetChannelTimeScale(camera->channel, &camera->timeScale);
372        if (theErr != noErr) {
373            NSLog(@"SGGetChannelTimeScale() returned %ld", theErr);
374            return theErr;
375        }
376    }
377    
378    if (camera->gWorld) {
379        CodecFlags ignore;
380        theErr = DecompressSequenceFrameS(camera->decompressionSequence, data, dataLength, 0, &ignore, NULL);
381        if (theErr != noErr) {
382            NSLog(@"DecompressSequenceFrameS() returned %ld", theErr);
383            return theErr;
384        }
385    }
386    
387    camera->lastTime = time;
388    
389    [camera _didUpdate];
390    
391    return noErr;
392}
393
394@end