Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/osx/isight/CSGCamera.m
Views: 11779
//1// CSGCamera.m2// MotionTracker3//4// Created by Tim Omernick on 3/7/05.5// Copyright 2005 Tim Omernick. All rights reserved.6//78// Portions of this file were inspired by Apple Computer, Inc.'s Cocoa SGDataProc example, which can be found here:9// <http://developer.apple.com/samplecode/Cocoa_-_SGDataProc/Cocoa_-_SGDataProc.html>10// Also, I'd like to thank Chris Meyer for his excellent -imageFromGWorld: method, which he gave me permission to use for this framework.1112#import "CSGCamera.h"1314#import "CSGImage.h"1516@interface CSGCamera (Private)17- (void)_sequenceGrabberIdle;18- (BOOL)_setupDecompression;19- (void)_didUpdate;20- (CSGImage *)_imageFromGWorld:(GWorldPtr)gworld;21@end2223@interface CSGCamera (SequenceGrabber)24pascal OSErr CSGCameraSGDataProc(SGChannel channel, Ptr data, long dataLength, long *offset, long channelRefCon, TimeValue time, short writeType, long refCon);25@end2627@implementation CSGCamera2829// Init and dealloc3031- (void)dealloc;32{33[self stop];3435[delegate release];3637[super dealloc];38}3940// API4142- (void)setDelegate:(id)newDelegate;43{44if (delegate == newDelegate)45return;4647[delegate release];48delegate = [newDelegate retain];49}5051- (BOOL)startWithSize:(NSSize)frameSize;52{53OSErr theErr;5455timeScale = 0;56lastTime = 0;5758// Initialize movie toolbox59theErr = EnterMovies();60if (theErr != noErr) {61NSLog(@"EnterMovies() returned %ld", theErr);62return NO;63}6465// Open default sequence grabber component66component = OpenDefaultComponent(SeqGrabComponentType, 0);67if (!component) {68NSLog(@"Could not open sequence grabber component.");69return NO;70}7172// Initialize sequence grabber component73theErr = SGInitialize(component);74if (theErr != noErr) {75NSLog(@"SGInitialize() returned %ld", theErr);76return NO;77}7879// Don't make movie80theErr = SGSetDataRef(component, 0, 0, seqGrabDontMakeMovie);81if (theErr != noErr) {82NSLog(@"SGSetDataRef() returned %ld", theErr);83return NO;84}8586// Create sequence grabber video channel87theErr = SGNewChannel(component, VideoMediaType, &channel);88if (theErr != noErr) {89NSLog(@"SGNewChannel() returned %ld", theErr);90return NO;91}9293// Set the grabber's bounds94boundsRect.top = 0;95boundsRect.left = 0;96boundsRect.bottom = frameSize.height;97boundsRect.right = frameSize.width;9899// NSLog(@"boundsRect=(%d, %d, %d, %d)", boundsRect.top, boundsRect.left, boundsRect.bottom, boundsRect.right);100101theErr = SGSetChannelBounds(component, &boundsRect);102103// Create the GWorld104theErr = QTNewGWorld(&gWorld, k32ARGBPixelFormat, &boundsRect, 0, NULL, 0);105if (theErr != noErr) {106NSLog(@"QTNewGWorld() returned %ld", theErr);107return NO;108}109110// Lock the pixmap111if (!LockPixels(GetPortPixMap(gWorld))) {112NSLog(@"Could not lock pixels.");113return NO;114}115116// Set GWorld117theErr = SGSetGWorld(component, gWorld, GetMainDevice());118if (theErr != noErr) {119NSLog(@"SGSetGWorld() returned %ld", theErr);120return NO;121}122123// Set the channel's bounds124theErr = SGSetChannelBounds(channel, &boundsRect);125if (theErr != noErr) {126NSLog(@"SGSetChannelBounds(2) returned %ld", theErr);127return NO;128}129130// Set the channel usage to record131theErr = SGSetChannelUsage(channel, seqGrabRecord);132if (theErr != noErr) {133NSLog(@"SGSetChannelUsage() returned %ld", theErr);134return NO;135}136137// Set data proc138theErr = SGSetDataProc(component, NewSGDataUPP(&CSGCameraSGDataProc), (long)self);139if (theErr != noErr) {140NSLog(@"SGSetDataProc() returned %ld", theErr);141return NO;142}143144// Prepare145theErr = SGPrepare(component, false, true);146if (theErr != noErr) {147NSLog(@"SGPrepare() returned %ld", theErr);148return NO;149}150151// Start recording152theErr = SGStartRecord(component);153if (theErr != noErr) {154NSLog(@"SGStartRecord() returned %ld", theErr);155return NO;156}157158startTime = [NSDate timeIntervalSinceReferenceDate];159160// Set up decompression sequence (camera -> GWorld)161[self _setupDecompression];162163// Start frame timer164frameTimer = [[NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(_sequenceGrabberIdle) userInfo:nil repeats:YES] retain];165166[self retain]; // Matches autorelease in -stop167168return YES;169}170171- (BOOL)stop;172{173// Stop frame timer174if (frameTimer) {175[frameTimer invalidate];176[frameTimer release];177frameTimer = nil;178}179180// Stop recording181if (component)182SGStop(component);183184ComponentResult theErr;185186// End decompression sequence187if (decompressionSequence) {188theErr = CDSequenceEnd(decompressionSequence);189if (theErr != noErr) {190NSLog(@"CDSequenceEnd() returned %ld", theErr);191}192decompressionSequence = 0;193}194195// Close sequence grabber component196if (component) {197theErr = CloseComponent(component);198if (theErr != noErr) {199NSLog(@"CloseComponent() returned %ld", theErr);200}201component = NULL;202}203204// Dispose of GWorld205if (gWorld) {206DisposeGWorld(gWorld);207gWorld = NULL;208}209210[self autorelease]; // Matches retain in -start211212return YES;213}214215@end216217@implementation CSGCamera (Private)218219- (void)_sequenceGrabberIdle;220{221OSErr theErr;222223theErr = SGIdle(component);224if (theErr != noErr) {225NSLog(@"SGIdle returned %ld", theErr);226return;227}228}229230- (BOOL)_setupDecompression;231{232ComponentResult theErr;233234ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0);235theErr = SGGetChannelSampleDescription(channel, (Handle)imageDesc);236if (theErr != noErr) {237NSLog(@"SGGetChannelSampleDescription() returned %ld", theErr);238return NO;239}240241Rect sourceRect;242sourceRect.top = 0;243sourceRect.left = 0;244sourceRect.right = (**imageDesc).width;245sourceRect.bottom = (**imageDesc).height;246247MatrixRecord scaleMatrix;248RectMatrix(&scaleMatrix, &sourceRect, &boundsRect);249250theErr = DecompressSequenceBegin(&decompressionSequence, imageDesc, gWorld, NULL, NULL, &scaleMatrix, srcCopy, NULL, 0, codecNormalQuality, bestSpeedCodec);251if (theErr != noErr) {252NSLog(@"DecompressionSequenceBegin() returned %ld", theErr);253return NO;254}255256DisposeHandle((Handle)imageDesc);257258return YES;259}260261- (void)_didUpdate;262{263if ([delegate respondsToSelector:@selector(camera:didReceiveFrame:)]) {264CSGImage *frameImage = [self _imageFromGWorld:gWorld];265if (frameImage) {266[frameImage setSampleTime:startTime + ((double)lastTime / (double)timeScale)];267[delegate camera:self didReceiveFrame:frameImage];268}269}270}271272// Thanks to Chris Meyer from http://www.cocoadev.com/273- (CSGImage *)_imageFromGWorld:(GWorldPtr)gworld;274{275NSParameterAssert( gworld != NULL );276277PixMapHandle pixMapHandle = GetGWorldPixMap( gworld );278if ( LockPixels( pixMapHandle ) )279{280Rect portRect;281GetPortBounds( gworld, &portRect );282int pixels_wide = (portRect.right - portRect.left);283int pixels_high = (portRect.bottom - portRect.top);284285int bps = 8;286int spp = 4;287BOOL has_alpha = YES;288289NSBitmapImageRep *frameBitmap = [[[NSBitmapImageRep alloc]290initWithBitmapDataPlanes:NULL291pixelsWide:pixels_wide292pixelsHigh:pixels_high293bitsPerSample:bps294samplesPerPixel:spp295hasAlpha:has_alpha296isPlanar:NO297colorSpaceName:NSDeviceRGBColorSpace298bytesPerRow:0299bitsPerPixel:0] autorelease];300301CGColorSpaceRef dst_colorspaceref = CGColorSpaceCreateDeviceRGB();302303CGImageAlphaInfo dst_alphainfo = has_alpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNone;304305CGContextRef dst_contextref = CGBitmapContextCreate( [frameBitmap bitmapData],306pixels_wide,307pixels_high,308bps,309[frameBitmap bytesPerRow],310dst_colorspaceref,311dst_alphainfo );312313void *pixBaseAddr = GetPixBaseAddr(pixMapHandle);314315long pixmapRowBytes = GetPixRowBytes(pixMapHandle);316317CGDataProviderRef dataproviderref = CGDataProviderCreateWithData( NULL, pixBaseAddr, pixmapRowBytes * pixels_high, NULL );318319int src_bps = 8;320int src_spp = 4;321BOOL src_has_alpha = YES;322323CGColorSpaceRef src_colorspaceref = CGColorSpaceCreateDeviceRGB();324325CGImageAlphaInfo src_alphainfo = src_has_alpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNone;326327CGImageRef src_imageref = CGImageCreate( pixels_wide,328pixels_high,329src_bps,330src_bps * src_spp,331pixmapRowBytes,332src_colorspaceref,333src_alphainfo,334dataproviderref,335NULL,336NO, // shouldInterpolate337kCGRenderingIntentDefault );338339CGRect rect = CGRectMake( 0, 0, pixels_wide, pixels_high );340341CGContextDrawImage( dst_contextref, rect, src_imageref );342343CGImageRelease( src_imageref );344CGColorSpaceRelease( src_colorspaceref );345CGDataProviderRelease( dataproviderref );346CGContextRelease( dst_contextref );347CGColorSpaceRelease( dst_colorspaceref );348349UnlockPixels( pixMapHandle );350351CSGImage *image = [[CSGImage alloc] initWithSize:NSMakeSize(pixels_wide, pixels_high)];352[image addRepresentation:frameBitmap];353354return [image autorelease];355}356357return NULL;358}359360@end361362@implementation CSGCamera (SequenceGrabber)363364pascal OSErr CSGCameraSGDataProc(SGChannel channel, Ptr data, long dataLength, long *offset, long channelRefCon, TimeValue time, short writeType, long refCon)365{366CSGCamera *camera = (CSGCamera *)refCon;367ComponentResult theErr;368369if (camera->timeScale == 0) {370theErr = SGGetChannelTimeScale(camera->channel, &camera->timeScale);371if (theErr != noErr) {372NSLog(@"SGGetChannelTimeScale() returned %ld", theErr);373return theErr;374}375}376377if (camera->gWorld) {378CodecFlags ignore;379theErr = DecompressSequenceFrameS(camera->decompressionSequence, data, dataLength, 0, &ignore, NULL);380if (theErr != noErr) {381NSLog(@"DecompressSequenceFrameS() returned %ld", theErr);382return theErr;383}384}385386camera->lastTime = time;387388[camera _didUpdate];389390return noErr;391}392393@end394395396