The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

MyQuickDrawView.mm File Reference

#import <QuickTime/QuickTime.h>
#import <Carbon/Carbon.h>
#import "MyQuickDrawView.h"
#import "MyObject.h"

Include dependency graph for MyQuickDrawView.mm:

Include dependency graph

Go to the source code of this file.

Defines

#define BailErr(x)   {err = x; if(err != noErr) goto bail;}
#define BailIfNull(x)   {gSeqGrab = x; if(gSeqGrab == nil) goto bail;}

Functions

Rect boundsRect ()
ComponentResult decompToWindow ()
ImageSequence decomSeq ()
void doDecomp: (NSRect rect)
OSErr doSeqGrab: (NSRect grabRect)
void drawRect: (NSRect rect)
ImageSequence drawSeq ()
void endGrab ()
void FindFaces ()
GWorldPtr gworld ()
end pascal OSErr mySGDataProc (SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon)
void saveQDViewObjectForCallback (void *theObject)
SGChannel sgChanVideo ()
void sgIdleTimer: (id sender)

Variables

float gLastFps = 26
TimeValue gLastTime
TimeScale gTimeScale
MyQuickDrawViewmyQDViewObject


Define Documentation

implementation MyQuickDrawView define BailErr  )     {err = x; if(err != noErr) goto bail;}
 

Definition at line 36 of file MyQuickDrawView.mm.

Referenced by doSeqGrab:(), and mySGDataProc().

00036                    {err = x; if(err != noErr) goto bail;}
00037 #define BailIfNull(x) {gSeqGrab = x; if(gSeqGrab == nil) goto bail;}
00038 
00039 
00040 
00042 //
00043 // setupDecomp
00044 //
00045 // Code to setup our decompresion sequences. We make
00046 // two, one to decompress to a gworld, and the other
00047 // to decompress to the window 
00048 //
00050 
00051 -(ComponentResult)setupDecomp
00052 {
00053         ComponentResult                 err = noErr;
00054     Rect                                        sourceRect = { 0, 0 }, bounds;
00055     MatrixRecord                        scaleMatrix;    
00056     ImageDescriptionHandle      imageDesc = (ImageDescriptionHandle)NewHandle(0);
00057     PixMapHandle                        hPixMap;
00058     
00059     // Create Face Finder
00060     gFaceFinder = [[FindFacesInGWorld alloc] init];
00061     
00062     /* Set up getting grabbed data into the GWorld */
00063     
00064     // retrieve a channelŐs current sample description, the channel returns a sample description that is
00065     // appropriate to the type of data being captured
00066     err = SGGetChannelSampleDescription(gSGChanVideo,(Handle)imageDesc);
00067     BailErr(err);
00068 
00069     /***** IMPORTANT NOTE *****
00070     
00071         Previous versions of this sample code made an incorrect decompression
00072         request.  Intending to draw the DV frame at quarter-size into a quarter-size
00073         offscreen GWorld, it made the call
00074 
00075         err = DecompressSequenceBegin(..., &rect, nil, ...);
00076 
00077         passing a quarter-size rectangle as the source rectangle.  The correct
00078         interpretation of this request is to draw the top-left corner of the DV
00079         frame cropped at normal size.  Unfortunately, a DV-specific bug in QuickTime
00080         5 caused it to misinterpret this request and scale the frame to fit.
00081 
00082         This bug will be fixed in QuickTime 6.  If your code behaves as intended
00083         because of the bug, you should fix your code to pass a matrix scaling the
00084         frame to fit the offscreen gworld:
00085 
00086         RectMatrix( & scaleMatrix, &dvFrameRect, &gworldBounds );
00087         err = DecompressSequenceBegin(..., nil, &scaleMatrix, ...);
00088     
00089         This approach will work in all versions of QuickTime.
00090                 
00091     **************************/
00092     
00093     // make a scaling matrix for the sequence
00094     sourceRect.right = (**imageDesc).width;
00095     sourceRect.bottom = (**imageDesc).height;
00096     RectMatrix(&scaleMatrix, &sourceRect, &gBoundsRect);
00097             
00098     // begin the process of decompressing a sequence of frames
00099     // this is a set-up call and is only called once for the sequence - the ICM will interrogate different codecs
00100     // and construct a suitable decompression chain, as this is a time consuming process we don't want to do this
00101     // once per frame (eg. by using DecompressImage)
00102     // for more information see Ice Floe #8 http://developer.apple.com/quicktime/icefloe/dispatch008.html
00103     // the destination is specified as the GWorld
00104     err = DecompressSequenceBegin(&gDecomSeq,   // pointer to field to receive unique ID for sequence
00105                                     imageDesc,          // handle to image description structure
00106                                     gPGWorld,           // port for the DESTINATION image
00107                                     NULL,                       // graphics device handle, if port is set, set to NULL
00108                                     NULL,                       // source rectangle defining the portion of the image to decompress
00109                                     &scaleMatrix,       // transformation matrix
00110                                     srcCopy,            // transfer mode specifier
00111                                     NULL,                       // clipping region in dest. coordinate system to use as a mask
00112                                     0,                                          // flags
00113                                     codecNormalQuality,         // accuracy in decompression
00114                                     bestSpeedCodec);            // compressor identifier or special identifiers ie. bestSpeedCodec
00115     BailErr(err);
00116     
00117     DisposeHandle((Handle)imageDesc);
00118     imageDesc = NULL;
00119     
00120     /* Set up getting grabbed data into the Window */
00121     hPixMap = GetGWorldPixMap(gPGWorld);
00122     GetPixBounds(hPixMap,&bounds);
00123     gDrawSeq = 0;
00124     
00125     // returns an image description for the GWorlds PixMap
00126     // on entry the imageDesc is NULL, on return it is correctly filled out
00127     // you are responsible for disposing it
00128     err = MakeImageDescriptionForPixMap(hPixMap, &imageDesc);
00129     BailErr(err);
00130     
00131     gImageSize = (GetPixRowBytes(hPixMap) * (*imageDesc)->height); // ((**hPixMap).rowBytes & 0x3fff) * (*desc)->height;
00132     
00133     // begin the process of decompressing a sequence of frames - see above notes on this call.
00134     // destination is specified as the QuickDraw port for our NSView
00135     err = DecompressSequenceBegin(&gDrawSeq,
00136                                     imageDesc,
00137                                     [self qdPort],      // Use the QuickDraw port for our NSView as destination!
00138                                     NULL,
00139                                     &bounds,
00140                                     NULL,
00141                                     ditherCopy,
00142                                     NULL,
00143                                     0,
00144                                     codecNormalQuality,
00145                                     anyCodec);
00146     BailErr(err);
00147 
00148 bail:
00149 
00150     if (imageDesc)
00151         DisposeHandle((Handle)imageDesc);
00152     
00153     return (err);
00154 }

#define BailIfNull  )     {gSeqGrab = x; if(gSeqGrab == nil) goto bail;}
 

Referenced by doSeqGrab:().


Function Documentation

Rect boundsRect  )  [virtual]
 

Definition at line 451 of file MyQuickDrawView.mm.

00452 {
00453     return gBoundsRect;
00454 }

ComponentResult decompToWindow  )  [virtual]
 

Definition at line 166 of file MyQuickDrawView.mm.

00167 {
00168         ComponentResult err = noErr;
00169     CodecFlags          ignore;
00170 
00171     err = DecompressSequenceFrameS(gDrawSeq,                                                    // sequence ID returned by DecompressSequenceBegin
00172                                 GetPixBaseAddr(GetGWorldPixMap(gPGWorld)),      // pointer to compressed image data
00173                                 gImageSize,                                                                     // size of the buffer
00174                                 0,                                                                                      // in flags
00175                                 &ignore,                                                                        // out flags
00176                                 NULL);                                                                          // async completion proc
00177     return err;
00178 }

ImageSequence decomSeq  )  [virtual]
 

Definition at line 412 of file MyQuickDrawView.mm.

Referenced by mySGDataProc().

00413 {
00414     return gDecomSeq;
00415 }

void doDecomp: NSRect  rect  )  [virtual]
 

Definition at line 189 of file MyQuickDrawView.mm.

00189                :(NSRect)rect
00190 {    
00191     if(gPGWorld) 
00192     {
00193         if (gDecomSeq == 0) 
00194         {
00195             [self setupDecomp];
00196         }
00197         else
00198         {
00199             [self decompToWindow];
00200         }
00201     }
00202 }

OSErr doSeqGrab: NSRect  grabRect  )  [virtual]
 

Definition at line 280 of file MyQuickDrawView.mm.

References BailErr, BailIfNull, gLastTime, gTimeScale, and mySGDataProc().

00280                   :(NSRect)grabRect
00281 {
00282     // Setup Face Detector to find faces
00283     [gFaceFinder InitializeStreamWithWidth:grabRect.size.width Height:grabRect.size.height];
00284 
00285     OSErr       err = noErr;
00286     
00287     gTimeScale  = 0;
00288     gLastTime   = 0;
00289 
00290     /* initialize the movie toolbox */
00291     err = EnterMovies();
00292     BailErr(err);
00293     
00294     // open the sequence grabber component and initialize it
00295     gSeqGrab = OpenDefaultComponent(SeqGrabComponentType, 0);
00296     BailIfNull(gSeqGrab);
00297     
00298     err = SGInitialize(gSeqGrab);
00299     BailErr(err);
00300     
00301         // specify the destination data reference for a record operation
00302         // tell it we're not making a movie
00303         // if the flag seqGrabDontMakeMovie is used, the sequence grabber still calls
00304         // your data function, but does not write any data to the movie file
00305         // writeType will always be set to seqGrabWriteAppend
00306     err = SGSetDataRef(gSeqGrab, 0, 0, seqGrabDontMakeMovie);
00307     BailErr(err);
00308 
00309     // create a new sequence grabber video channel 
00310     err = SGNewChannel(gSeqGrab, VideoMediaType, &gSGChanVideo);
00311     BailErr(err); 
00312 
00313     gBoundsRect.top     = (short int)grabRect.origin.y;
00314     gBoundsRect.left    = (short int)grabRect.origin.x;
00315     gBoundsRect.bottom  = (short int)grabRect.size.height;
00316     gBoundsRect.right   = (short int)grabRect.size.width;
00317     err = SGSetChannelBounds(gSeqGrab, &gBoundsRect); 
00318     
00319     // create the GWorld
00320     err = QTNewGWorld(&gPGWorld,        // returned GWorld
00321                                   k32ARGBPixelFormat,           // pixel format
00322                                   &gBoundsRect,                         // bounding rectangle
00323                                   0,                                            // color table
00324                                   NULL,                                         // graphic device handle
00325                                   0);                                           // flags
00326     BailErr(err);
00327    
00328     // lock the pixmap and make sure it's locked because
00329     // we can't decompress into an unlocked PixMap
00330     if(!LockPixels(GetPortPixMap(gPGWorld)))
00331     {
00332         BailErr(-1);
00333     }
00334 
00335     err = SGSetGWorld(gSeqGrab, gPGWorld, GetMainDevice());
00336     BailErr(err);
00337 
00338     // set the bounds for the channel
00339     err = SGSetChannelBounds(gSGChanVideo, &gBoundsRect);
00340     BailErr(err);
00341     
00342     // set the usage for our new video channel to avoid playthrough
00343     // note: we do not set seqGrabPlayDuringRecord because if you set this flag
00344     // the data from the channel may be played during the record operation,
00345     // if the destination buffer is onscreen. However, playing the
00346     // data may affect the quality of the recorded sequence by causing frames 
00347     // to be dropped...something we definitely want to avoid
00348     err = SGSetChannelUsage(gSGChanVideo, seqGrabRecord);
00349     BailErr(err);
00350     
00351     // specify a data function for use by the sequence grabber
00352     // whenever any channel assigned to the sequence grabber writes data,
00353     // this data function is called and may then write the data to another destination
00354     err = SGSetDataProc(gSeqGrab,NewSGDataUPP(&mySGDataProc),NULL);
00355     BailErr(err);
00356 
00357     /* lights...camera... */
00358     err = SGPrepare(gSeqGrab,false,true);
00359     BailErr(err);
00360     
00361     // start recording!!
00362     err = SGStartRecord(gSeqGrab);
00363     BailErr(err);
00364 
00365     /* setup a timer to idle the sequence grabber */
00366     gMyTimer = // interval, 0.1 seconds// call this method[[NSTimer scheduledTimerWithTimeInterval:0.005f               
00367                         target:self
00368                         selector:@selector(sgIdleTimer:)                
00369                         userInfo:nil
00370                         repeats:YES] retain];                                   // repeat until we cancel it
00371     
00372 bail:
00373 
00374         return err;
00375 }

Here is the call graph for this function:

void drawRect: NSRect  rect  )  [virtual]
 

Definition at line 214 of file MyQuickDrawView.mm.

00214                :(NSRect)rect
00215 {
00216     [self doDecomp:rect];
00217 }

ImageSequence drawSeq  )  [virtual]
 

Definition at line 425 of file MyQuickDrawView.mm.

00426 {
00427     return gDrawSeq;
00428 }

void endGrab  )  [virtual]
 

Definition at line 464 of file MyQuickDrawView.mm.

00465 {
00466     ComponentResult result;
00467     OSErr                       err;
00468 
00469     // kill our sequence grabber idle timer first
00470     [gMyTimer invalidate];
00471     [gMyTimer release];
00472     
00473     // stop recording
00474     SGStop(gSeqGrab);
00475 
00476     // end our decompression sequences
00477     err = CDSequenceEnd(gDecomSeq);
00478     err = CDSequenceEnd(gDrawSeq);
00479 
00480     // finally, close our sequence grabber component
00481     result = CloseComponent(gSeqGrab);
00482     
00483     // get rid of our gworld
00484     DisposeGWorld(gPGWorld);
00485 }

void FindFaces  )  [virtual]
 

Definition at line 398 of file MyQuickDrawView.mm.

00399 {
00400     [gFaceFinder FindFaces:gPGWorld];
00401 }

GWorldPtr gworld  )  [virtual]
 

Definition at line 385 of file MyQuickDrawView.mm.

Referenced by mySGDataProc().

00386 {
00387     return gPGWorld;
00388 }

end pascal OSErr mySGDataProc SGChannel  c,
Ptr  p,
long  len,
long *  offset,
long  chRefCon,
TimeValue  time,
short  writeType,
long  refCon
 

Definition at line 523 of file MyQuickDrawView.mm.

References BailErr, MyQuickDrawView::boundsRect, decomSeq(), MyQuickDrawView::FindFaces, gLastFps, gLastTime, gTimeScale, gworld(), MyQuickDrawView::gworld, myQDViewObject, p, sgChanVideo(), and sprintf().

Referenced by doSeqGrab:().

00531 {
00532 #pragma unused(offset,chRefCon,time,writeType)
00533     
00534     CodecFlags          ignore;
00535     ComponentResult     err = noErr;
00536     CGrafPtr            theSavedPort;
00537     GDHandle            theSavedDevice;
00538     char                status[64];
00539     Str255              theString;
00540     Rect                bounds;
00541     float               fps;
00542     
00543     /* grab the time scale for use with our fps calculations - but this 
00544         needs to be done only once */
00545     if (gTimeScale == 0)
00546     {        
00547         err = SGGetChannelTimeScale([myQDViewObject sgChanVideo], &gTimeScale);
00548         BailErr(err);
00549     }
00550     
00551     if([myQDViewObject gworld]) 
00552     {
00553         // decompress a frame into the GWorld - can queue a frame for async decompression when passed in a completion proc
00554         // once the image is in the GWorld it can be manipulated at will
00555         err = DecompressSequenceFrameS([myQDViewObject decomSeq],       // sequence ID returned by DecompressSequenceBegin
00556                                                                         p,                                              // pointer to compressed image data
00557                                                                         len,                                    // size of the buffer
00558                                                                         0,                                              // in flags
00559                                                                         &ignore,                                // out flags
00560                                                                         NULL);                                  // async completion proc
00561         BailErr(err);
00562 
00563         // ******  IMAGE IS NOW IN THE GWORLD ****** //
00564 
00565         }
00566     
00567     /* compute and display frames-per-second */
00568     [myQDViewObject FindFaces];
00569     GetGWorld(&theSavedPort, &theSavedDevice);
00570     SetGWorld([myQDViewObject gworld], NULL);
00571     TextSize(12);
00572     TextMode(srcCopy);
00573     bounds = [myQDViewObject boundsRect];
00574     MoveTo(bounds.left, bounds.bottom-3);
00575     fps = (float)((float)gTimeScale / (float)(time - gLastTime));
00576     fps = 0.03f*fps + 0.97f*gLastFps;
00577     //sprintf(status, "fps:%5.1f", fps);
00578     sprintf(status, "fps:%2.0f", fps);
00579     CopyCStringToPascal(status, theString);
00580     DrawString(theString);
00581     SetGWorld(theSavedPort, theSavedDevice);
00582     
00583     /* remember current time, so next time this routine is called
00584         we can compute the frames-per-second */
00585     gLastTime = time;
00586     gLastFps = fps;
00587     /* calling the display method will invoke this NSView's lockFocus, drawRect and unlockFocus methods as necessary.
00588         Our drawRect method (above) is used to decompress one of a sequence of frames. This method draws the image
00589         back to the window from the GWorld and could be used as a "preview" */
00590     [myQDViewObject display];
00591 bail:
00592     
00593         return err;
00594 }

Here is the call graph for this function:

void saveQDViewObjectForCallback void *  theObject  ) 
 

Definition at line 607 of file MyQuickDrawView.mm.

References myQDViewObject.

Referenced by MyObject::awakeFromNib.

00608 {
00609    myQDViewObject = (MyQuickDrawView *)theObject;
00610 }

SGChannel sgChanVideo  )  [virtual]
 

Definition at line 438 of file MyQuickDrawView.mm.

Referenced by mySGDataProc().

00439 {
00440     return gSGChanVideo;
00441 }

void sgIdleTimer: id  sender  )  [virtual]
 

Definition at line 230 of file MyQuickDrawView.mm.

00230                    :(id)sender
00231 {
00232     OSErr err;
00233 
00234     err = SGIdle(gSeqGrab);
00235     /* put up an error dialog to display any errors */
00236     if (err != noErr)
00237     {
00238         NSString *errorStr = [[NSString alloc] initWithFormat:@"%d" , err];
00239         int choice;
00240 
00241         // some error specific to SGIdle occurred - any errors returned from the
00242         // data proc will also show up here and we don't want to write over them
00243         
00244         // in QT 4 you would always encounter a cDepthErr error after a user drags
00245         // the window, this failure condition has been greatly relaxed in QT 5
00246         // it may still occur but should only apply to vDigs that really control
00247         // the screen
00248         
00249         // you don't always know where these errors originate from, some may come
00250         // from the VDig...
00251                         
00252         /* now display error dialog and quit */
00253         choice = NSRunAlertPanel(@"Error", errorStr, @"OK", nil, nil);
00254         [errorStr release];
00255                         
00256         // ...to fix this we simply call SGStop and SGStartRecord again
00257         // calling stop allows the SG to release and re-prepare for grabbing
00258         // hopefully fixing any problems, this is obviously a very relaxed
00259         // approach
00260 
00261         SGStop(gSeqGrab);
00262         SGStartRecord(gSeqGrab);
00263     }
00264 
00265 }


Variable Documentation

float gLastFps = 26 [static]
 

Definition at line 32 of file MyQuickDrawView.mm.

Referenced by mySGDataProc().

TimeValue gLastTime [static]
 

Definition at line 31 of file MyQuickDrawView.mm.

Referenced by doSeqGrab:(), and mySGDataProc().

TimeScale gTimeScale [static]
 

Definition at line 30 of file MyQuickDrawView.mm.

Referenced by doSeqGrab:(), and mySGDataProc().

MyQuickDrawView* myQDViewObject [static]
 

Definition at line 29 of file MyQuickDrawView.mm.

Referenced by mySGDataProc(), and saveQDViewObjectForCallback().


Generated on Mon Nov 8 17:08:15 2004 for MPT by  doxygen 1.3.9.1