video.c
Go to the documentation of this file.
00001 /*
00002  *      Video capture subrutine for Linux/libdc1394 devices
00003  *      author: Kiyoshi Kiyokawa ( kiyo@crl.go.jp )
00004  *              Hirokazu Kato ( kato@sys.im.hiroshima-cu.ac.jp )
00005  *
00006  *      Revision: 1.0   Date: 2002/01/01
00007  *
00008  */
00009 /*
00010  *      Copyright (c) 2003-2007 Philip Lamb (PRL) phil@eden.net.nz. All rights reserved.
00011  *      
00012  *      Rev             Date            Who             Changes
00013  *      1.1.0   2003-09-09      PRL             Based on Apple "Son of MungGrab" sample code for QuickTime 6.
00014  *                                                              Added config option "-fps" to superimpose frame counter on video.
00015  *                                                              Returns aligned data in ARGB pixel format.
00016  *  1.2.0   2004-04-28  PRL             Now one thread per video source. Versions of QuickTime
00017  *                                                              prior to 6.4 are NOT thread safe, and with these earlier
00018  *                                                              versions, QuickTime toolbox access will be serialised.
00019  *      1.2.1   2004-06-28  PRL         Support for 2vuy and yuvs pixel formats.
00020  *  1.3.0   2004-07-13  PRL             Code from Daniel Heckenberg to directly access vDig.
00021  *  1.3.1   2004-12-07  PRL             Added config option "-pixelformat=" to support pixel format
00022  *                                                              specification at runtime, with default determined at compile time.
00023  *      1.4.0   2005-03-08      PRL             Video input settings now saved and restored.
00024  *  1.4.1   2005-03-15  PRL     QuickTime 6.4 or newer is now required by default. In order
00025  *                                                              to allow earlier versions, AR_VIDEO_SUPPORT_OLD_QUICKTIME must
00026  *                                                              be uncommented at compile time.
00027  *
00028  */
00029 /*
00030  * 
00031  * This file is part of ARToolKit.
00032  * 
00033  * ARToolKit is free software; you can redistribute it and/or modify
00034  * it under the terms of the GNU General Public License as published by
00035  * the Free Software Foundation; either version 2 of the License, or
00036  * (at your option) any later version.
00037  * 
00038  * ARToolKit is distributed in the hope that it will be useful,
00039  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00040  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00041  * GNU General Public License for more details.
00042  * 
00043  * You should have received a copy of the GNU General Public License
00044  * along with ARToolKit; if not, write to the Free Software
00045  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00046  * 
00047  */
00048 /*
00049  *  
00050  * The functions beginning with names "vdg" adapted with changes from
00051  * vdigGrab.c, part of the seeSaw project by Daniel Heckenberg.
00052  *
00053  * Created by Daniel Heckenberg.
00054  * Copyright (c) 2004 Daniel Heckenberg. All rights reserved.
00055  * (danielh.seeSaw<at>cse<dot>unsw<dot>edu<dot>au)
00056  *  
00057  * Permission is hereby granted, free of charge, to any person obtaining a 
00058  * copy of this software and associated documentation files (the "Software"),
00059  * to deal in the Software without restriction, including without limitation
00060  * the right to use, copy, modify, merge, publish, communicate, sublicence, 
00061  * and/or sell copies of the Software, and to permit persons to whom the 
00062  * Software is furnished to do so, subject to the following conditions:
00063  * 
00064  * The above copyright notice and this permission notice shall be included 
00065  * in all copies or substantial portions of the Software.
00066  * 
00067  * TO THE EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED 
00068  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
00069  * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
00070  * PURPOSE AND NON-INFRINGEMENT.Ê IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
00071  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00072  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
00073  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00074  *
00075  */
00076 
00077 // ============================================================================
00078 //      Private includes
00079 // ============================================================================
00080 
00081 #include <Carbon/Carbon.h>
00082 #include <QuickTime/QuickTime.h>
00083 #include <CoreServices/CoreServices.h>                  // Gestalt()
00084 #include <pthread.h>
00085 #include <sys/time.h>
00086 #include <unistd.h>             // usleep()
00087 #include <sys/types.h>  // sysctlbyname()
00088 #include <sys/sysctl.h> // sysctlbyname()
00089 #include <AR/config.h>
00090 #include <AR/ar.h>
00091 #include <AR/video.h>
00092 #include "videoInternal.h"
00093 
00094 // ============================================================================
00095 //      Private definitions
00096 // ============================================================================
00097 
00098 //#define AR_VIDEO_SUPPORT_OLD_QUICKTIME                // Uncomment to allow use of non-thread safe QuickTime (pre-6.4).
00099 #define AR_VIDEO_DEBUG_FIX_DUAL_PROCESSOR_RACE
00100 
00101 #define AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MIN         20L
00102 #define AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MAX         100L
00103 
00104 #define AR_VIDEO_STATUS_BIT_READY   0x01                        // Clear when no new frame is ready, set when a new frame is ready.
00105 #define AR_VIDEO_STATUS_BIT_BUFFER  0x02                        // Clear when buffer 1 is valid for writes, set when buffer 2 is valid for writes. 
00106 
00107 // Early Mac OS X implementations of pthreads failed to define PTHREAD_CANCELED.
00108 #ifdef PTHREAD_CANCELED
00109 #  define AR_PTHREAD_CANCELLED PTHREAD_CANCELED
00110 #else
00111 #  define AR_PTHREAD_CANCELLED ((void *) 1);
00112 #endif
00113 
00114 // ============================================================================
00115 //      Private types
00116 // ============================================================================
00117 
00118 struct _VdigGrab
00119 {
00120         // State
00121         int                                     isPreflighted;
00122         int                                     isGrabbing;
00123         int                                     isRecording;
00124         
00125         // QT Components
00126         SeqGrabComponent        seqGrab; 
00127         SGChannel                       sgchanVideo;
00128         ComponentInstance   vdCompInst;
00129         
00130         // Device settings
00131         ImageDescriptionHandle  vdImageDesc;
00132         Rect                                    vdDigitizerRect;                
00133         
00134         // Destination Settings
00135         CGrafPtr                                dstPort;
00136         ImageSequence                   dstImageSeq;
00137         
00138         // Compression settings
00139         short                           cpDepth;
00140         CompressorComponent cpCompressor;
00141         CodecQ                          cpSpatialQuality;
00142         CodecQ                          cpTemporalQuality;
00143         long                            cpKeyFrameRate;
00144         Fixed                           cpFrameRate;
00145 };
00146 typedef struct _VdigGrab VdigGrab;
00147 typedef struct _VdigGrab *VdigGrabRef;
00148 
00149 struct _AR2VideoParamT {
00150     int                                         width;
00151     int                                         height;
00152     Rect                                        theRect;
00153     GWorldPtr                           pGWorld;
00154     int                                         status;
00155         int                                             showFPS;
00156         TimeValue                               lastTime;
00157         long                                    frameCount;
00158         TimeScale                               timeScale;
00159         pthread_t                               thread;                 // PRL.
00160         pthread_mutex_t                 bufMutex;               // PRL.
00161         pthread_cond_t                  condition;              // PRL.
00162         int                                             threadRunning;  // PRL.
00163         long                                    rowBytes;               // PRL.
00164         long                                    bufSize;                // PRL.
00165         ARUint8*                                bufPixels;              // PRL.
00166         int                                             bufCopyFlag;    // PRL
00167         ARUint8*                                bufPixelsCopy1; // PRL.
00168         ARUint8*                                bufPixelsCopy2; // PRL.
00169         int                                             grabber;                        // PRL.
00170         MatrixRecordPtr                 scaleMatrixPtr; // PRL.
00171         VdigGrabRef                             pVdg;                   // DH (seeSaw).
00172         long                                    milliSecPerTimer; // DH (seeSaw).
00173         long                                    milliSecPerFrame; // DH (seeSaw).
00174         Fixed                                   frameRate;              // DH (seeSaw).
00175         long                                    bytesPerSecond; // DH (seeSaw).
00176         ImageDescriptionHandle  vdImageDesc;    // DH (seeSaw).
00177 };
00178 typedef struct _AR2VideoParamT *AR2VideoParamTRef;
00179 
00180 // ============================================================================
00181 //      Private global variables
00182 // ============================================================================
00183 
00184 static AR2VideoParamT   *gVid = NULL;
00185 static unsigned int             gVidCount = 0;
00186 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
00187 static pthread_mutex_t  gVidQuickTimeMutex;
00188 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
00189 
00190 #pragma mark -
00191 
00192 // ============================================================================
00193 //      Private functions
00194 // ============================================================================
00195 
00196 // --------------------
00197 // MakeSequenceGrabber  (adapted from Apple mung sample)
00198 //
00199 static SeqGrabComponent MakeSequenceGrabber(WindowRef pWindow, const int grabber)
00200 {
00201         SeqGrabComponent        seqGrab = NULL;
00202         ComponentResult         err = noErr;
00203         ComponentDescription cDesc;
00204         long                            cCount;
00205         Component                       c;
00206         int                                     i;
00207         
00208         // Open the sequence grabber.
00209         cDesc.componentType = SeqGrabComponentType;
00210         cDesc.componentSubType = 0L; // Could use subtype vdSubtypeIIDC for IIDC-only cameras (i.e. exclude DV and other cameras.)
00211         cDesc.componentManufacturer = cDesc.componentFlags = cDesc.componentFlagsMask = 0L;
00212         cCount = CountComponents(&cDesc);
00213         fprintf(stdout, "Opening sequence grabber %d of %ld.\n", grabber, cCount);
00214         c = 0;
00215         for (i = 1; (c = FindNextComponent(c, &cDesc)) != 0; i++) {
00216                 // Could call GetComponentInfo() here to get more info on this SeqGrabComponentType component.
00217                 // Is this the grabber requested?
00218                 if (i == grabber) {
00219                         seqGrab = OpenComponent(c);
00220                 }
00221         }
00222     if (!seqGrab) {
00223                 fprintf(stderr, "MakeSequenceGrabber(): Failed to open a sequence grabber component.\n");
00224                 goto endFunc;
00225         }
00226         
00227         // initialize the default sequence grabber component
00228         if ((err = SGInitialize(seqGrab))) {
00229                 fprintf(stderr, "MakeSequenceGrabber(): SGInitialize err=%ld\n", err);
00230                 goto endFunc;
00231         }
00232         
00233         // This should be defaulted to the current port according to QT doco
00234         if ((err = SGSetGWorld(seqGrab, GetWindowPort(pWindow), NULL))) {
00235                 fprintf(stderr, "MakeSequenceGrabber(): SGSetGWorld err=%ld\n", err);
00236                 goto endFunc;
00237         }
00238         
00239         // specify the destination data reference for a record operation
00240         // tell it we're not making a movie
00241         // if the flag seqGrabDontMakeMovie is used, the sequence grabber still calls
00242         // your data function, but does not write any data to the movie file
00243         // writeType will always be set to seqGrabWriteAppend
00244         if ((err = SGSetDataRef(seqGrab, 0, 0, seqGrabDontMakeMovie))) {
00245                 fprintf(stderr, "MakeSequenceGrabber(): SGSetDataRef err=%ld\n", err);
00246                 goto endFunc;
00247         }
00248         
00249 endFunc:        
00250         if (err && (seqGrab != NULL)) { // clean up on failure
00251                 CloseComponent(seqGrab);
00252                 seqGrab = NULL;
00253         }
00254     
00255         return (seqGrab);
00256 }
00257 
00258 
00259 // --------------------
00260 // MakeSequenceGrabChannel (adapted from Apple mung sample)
00261 //
00262 static ComponentResult MakeSequenceGrabChannel(SeqGrabComponent seqGrab, SGChannel* psgchanVideo)
00263 {
00264     long  flags = 0;
00265     ComponentResult err = noErr;
00266     
00267     if ((err = SGNewChannel(seqGrab, VideoMediaType, psgchanVideo))) {
00268                 if (err == couldntGetRequiredComponent) {
00269                         printf("ERROR: No camera connected. Please connect a camera and re-try.\n");
00270                 } else {
00271                         fprintf(stderr, "MakeSequenceGrabChannel(): SGNewChannel err=%ld\n", err);
00272                 }
00273                 goto endFunc;
00274         }
00275         
00276         //err = SGSetChannelBounds(*sgchanVideo, rect);
00277         // set usage for new video channel to avoid playthrough
00278         // note we don't set seqGrabPlayDuringRecord
00279         if ((err = SGSetChannelUsage(*psgchanVideo, flags | seqGrabRecord))) {
00280                 fprintf(stderr, "MakeSequenceGrabChannel(): SGSetChannelUsage err=%ld\n", err);
00281                 goto endFunc;
00282         }
00283         
00284 endFunc:
00285         if ((err != noErr) && psgchanVideo) {
00286                 // clean up on failure
00287                 SGDisposeChannel(seqGrab, *psgchanVideo);
00288                 *psgchanVideo = NULL;
00289         }
00290         
00291         return err;
00292 }
00293 
00294 static ComponentResult vdgGetSettings(VdigGrab* pVdg)
00295 {       
00296         ComponentResult err;
00297         
00298         // Extract information from the SG
00299     if (err = SGGetVideoCompressor (pVdg->sgchanVideo, 
00300                                                                         &pVdg->cpDepth,
00301                                                                         &pVdg->cpCompressor,
00302                                                                         &pVdg->cpSpatialQuality, 
00303                                                                         &pVdg->cpTemporalQuality, 
00304                                                                         &pVdg->cpKeyFrameRate)) {
00305                 fprintf(stderr, "SGGetVideoCompressor err=%ld\n", err);
00306                 goto endFunc;
00307         }
00308     
00309         if (err = SGGetFrameRate(pVdg->sgchanVideo, &pVdg->cpFrameRate)) {
00310                 fprintf(stderr, "SGGetFrameRate err=%ld\n", err);
00311                 goto endFunc;
00312         }
00313         
00314         // Get the selected vdig from the SG
00315     if (!(pVdg->vdCompInst = SGGetVideoDigitizerComponent(pVdg->sgchanVideo))) {
00316                 fprintf(stderr, "SGGetVideoDigitizerComponent error\n");
00317                 goto endFunc;
00318         }
00319         
00320 endFunc:
00321         return (err);
00322 }
00323 
00324 #pragma mark -
00325 
00326 VdigGrabRef vdgAllocAndInit(const int grabber)
00327 {
00328         VdigGrabRef pVdg = NULL;
00329         OSErr err;
00330         
00331         // Allocate the grabber structure
00332         arMalloc(pVdg, VdigGrab, 1)
00333         memset(pVdg, 0, sizeof(VdigGrab));      
00334         
00335         if (!(pVdg->seqGrab = MakeSequenceGrabber(NULL, grabber))) {
00336                 fprintf(stderr, "MakeSequenceGrabber error.\n"); 
00337                 free(pVdg);
00338                 return (NULL);
00339         }
00340         
00341         if ((err = MakeSequenceGrabChannel(pVdg->seqGrab, &pVdg->sgchanVideo))) {
00342                 if (err != couldntGetRequiredComponent) fprintf(stderr, "MakeSequenceGrabChannel err=%d.\n", err); 
00343                 free(pVdg);
00344                 return (NULL);
00345         }
00346         
00347         return (pVdg);
00348 }
00349 
00350 static ComponentResult vdgRequestSettings(VdigGrab* pVdg, const int showDialog, const int standardDialog, const int inputIndex)
00351 {
00352         ComponentResult err;
00353         
00354         // Use the SG Dialog to allow the user to select device and compression settings
00355         if (err = RequestSGSettings(inputIndex, pVdg->seqGrab, pVdg->sgchanVideo, showDialog, standardDialog)) {
00356                 fprintf(stderr, "RequestSGSettings err=%ld\n", err); 
00357                 goto endFunc;
00358         }       
00359 
00360         if (err = vdgGetSettings(pVdg)) {
00361                 fprintf(stderr, "vdgGetSettings err=%ld\n", err); 
00362                 goto endFunc;
00363         }
00364         
00365 endFunc:
00366                 return err;
00367 }
00368 
00369 static VideoDigitizerError vdgGetDeviceNameAndFlags(VdigGrab* pVdg, char* szName, long* pBuffSize, UInt32* pVdFlags)
00370 {
00371         VideoDigitizerError err;
00372         Str255  vdName; // Pascal string (first byte is string length).
00373     UInt32      vdFlags;
00374         
00375         if (!pBuffSize) {
00376                 fprintf(stderr, "vdgGetDeviceName: NULL pointer error\n");
00377                 err = (VideoDigitizerError)qtParamErr; 
00378                 goto endFunc;
00379         }
00380         
00381         if (err = VDGetDeviceNameAndFlags(  pVdg->vdCompInst,
00382                                                                                 vdName,
00383                                                                                 &vdFlags)) {
00384                 fprintf(stderr, "VDGetDeviceNameAndFlags err=%ld\n", err);
00385                 *pBuffSize = 0; 
00386                 goto endFunc;
00387         }
00388         
00389         if (szName) {
00390                 int copyLen = (*pBuffSize-1 < vdName[0] ? *pBuffSize-1 : vdName[0]);
00391                 
00392                 strncpy(szName, (char *)vdName+1, copyLen);
00393                 szName[copyLen] = '\0';
00394                 
00395                 *pBuffSize = copyLen + 1;
00396         } else {
00397                 *pBuffSize = vdName[0] + 1;
00398         } 
00399         
00400         if (pVdFlags)
00401                 *pVdFlags = vdFlags;
00402         
00403 endFunc:
00404                 return err;
00405 }
00406 
00407 static OSErr vdgSetDestination(  VdigGrab* pVdg,
00408                                         CGrafPtr  dstPort )
00409 {
00410         pVdg->dstPort = dstPort;
00411         return noErr;
00412 }
00413 
00414 static VideoDigitizerError vdgPreflightGrabbing(VdigGrab* pVdg)
00415 {
00416         /* from Steve Sisak (on quicktime-api list):
00417         A much more optimal case, if you're doing it yourself is:
00418         
00419         VDGetDigitizerInfo() // make sure this is a compressed source only
00420         VDGetCompressTypes() // tells you the supported types
00421         VDGetMaxSourceRect() // returns full-size rectangle (sensor size)
00422         VDSetDigitizerRect() // determines cropping
00423         
00424         VDSetCompressionOnOff(true)
00425         
00426     VDSetFrameRate()         // set to 0 for default
00427     VDSetCompression()       // compresstype=0 means default
00428     VDGetImageDescription()  // find out image format
00429     VDGetDigitizerRect()     // find out if vdig is cropping for you
00430     VDResetCompressSequence()
00431         
00432     (grab frames here)
00433         
00434         VDSetCompressionOnOff(false)
00435         */
00436         VideoDigitizerError err;
00437     Rect maxRect;
00438         
00439         DigitizerInfo info;
00440         
00441         // make sure this is a compressed source only
00442         if ((err = VDGetDigitizerInfo(pVdg->vdCompInst, &info))) {
00443                 fprintf(stderr, "vdgPreflightGrabbing(): VDGetDigitizerInfo err=%ld\n", err);
00444                 goto endFunc;
00445         } else {
00446                 if (!(info.outputCapabilityFlags & digiOutDoesCompress)) {
00447                         fprintf(stderr, "vdgPreflightGrabbing(): VDGetDigitizerInfo reports device is not a compressed source.\n");
00448                         err = digiUnimpErr; // We don't support non-compressed sources.
00449                         goto endFunc;
00450                 }
00451         }
00452         
00453         //  VDGetCompressTypes() // tells you the supported types
00454         
00455         // Tell the vDig we're starting to change several settings.
00456         // Apple's SoftVDig doesn't seem to like these calls.
00457         if ((err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureSetSettingsBegin))) {
00458                 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00459                 //goto endFunc;
00460         }
00461 
00462         if ((err = VDGetMaxSrcRect(pVdg->vdCompInst, currentIn, &maxRect))) {
00463                 fprintf(stderr, "vdgPreflightGrabbing(): VDGetMaxSrcRect err=%ld (Ignored.)\n", err);
00464                 //goto endFunc;
00465         }
00466         
00467         // Try to set maximum capture size ... is this necessary as we're setting the 
00468         // rectangle in the VDSetCompression call later?  I suppose that it is, as
00469         // we're setting digitization size rather than compression size here...
00470         // Apple vdigs don't like this call     
00471         if (err = VDSetDigitizerRect( pVdg->vdCompInst, &maxRect)) {
00472                 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetDigitizerRect err=%ld (Ignored.)\n", err);
00473                 //goto endFunc;         
00474         }
00475         
00476         if (err = VDSetCompressionOnOff( pVdg->vdCompInst, 1)) {
00477                 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetCompressionOnOff err=%ld (Ignored.)\n", err);
00478                 //goto endFunc;         
00479         }
00480         
00481         // We could try to force the frame rate here... necessary for ASC softvdig
00482         if (err = VDSetFrameRate(pVdg->vdCompInst, 0)) {
00483                 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetFrameRate err=%ld (Ignored.)\n", err);
00484                 //goto endFunc;         
00485         }
00486         
00487         // try to set a format that matches our target
00488         // necessary for ASC softvdig (even if it doesn't support
00489         // the requested codec)
00490         // note that for the Apple IIDC vdig in 10.3 if we request yuv2 explicitly
00491         // we'll get 320x240 frames returned but if we leave codecType as 0
00492         // we'll get 640x480 frames returned instead (which use 4:1:1 encoding on
00493         // the wire rather than 4:2:2)
00494     if (err = VDSetCompression(pVdg->vdCompInst,
00495                                                            0, //'yuv2'
00496                                                            0,   
00497                                                            &maxRect, 
00498                                                            0, //codecNormalQuality,
00499                                                            0, //codecNormalQuality,
00500                                                            0)) {
00501                 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetCompression err=%ld (Ignored.)\n", err);
00502                 //goto endFunc;                 
00503         }
00504         
00505         if (err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureLowLatency)) {
00506                 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00507                 //goto endFunc;    
00508         }
00509 
00510         // Tell the vDig we've finished changing settings.
00511         if ((err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureSetSettingsEnd))) {
00512                 if (err != digiUnimpErr)  fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00513                 //goto endFunc;    
00514         }
00515 
00516         if ((err = VDResetCompressSequence( pVdg->vdCompInst))) {
00517                 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDResetCompressSequence err=%ld (Ignored.)\n", err);
00518                 //goto endFunc;    
00519         }
00520         
00521         pVdg->vdImageDesc = (ImageDescriptionHandle)NewHandle(0);
00522         if ((err = VDGetImageDescription(pVdg->vdCompInst, pVdg->vdImageDesc))) {
00523                 fprintf(stderr, "vdgPreflightGrabbing(): VDGetImageDescription err=%ld (Ignored.)\n", err);
00524                 //goto endFunc;    
00525         }
00526         
00527         // From Steve Sisak: find out if Digitizer is cropping for you.
00528         if ((err = VDGetDigitizerRect(pVdg->vdCompInst, &pVdg->vdDigitizerRect))) {
00529                 fprintf(stderr, "vdgPreflightGrabbing(): VDGetDigitizerRect err=%ld (Ignored.)\n", err);
00530                 //goto endFunc;
00531         }
00532         
00533         pVdg->isPreflighted = 1;
00534         
00535 endFunc:
00536         return (err);
00537 }
00538 
00539 static VideoDigitizerError vdgGetDataRate( VdigGrab*   pVdg, 
00540                                 long*           pMilliSecPerFrame,
00541                                 Fixed*      pFramesPerSecond,
00542                                 long*       pBytesPerSecond)
00543 {
00544         VideoDigitizerError err;
00545         
00546         if (err = VDGetDataRate( pVdg->vdCompInst, 
00547                                                          pMilliSecPerFrame,
00548                                                          pFramesPerSecond,
00549                                                          pBytesPerSecond)) {
00550                 fprintf(stderr, "vdgGetDataRate(): VDGetDataRate err=%ld\n", err);
00551                 goto endFunc;           
00552         }
00553         
00554 endFunc:        
00555         return (err);
00556 }
00557 
00558 static VideoDigitizerError vdgGetImageDescription( VdigGrab* pVdg,
00559                                                 ImageDescriptionHandle vdImageDesc )
00560 {
00561         VideoDigitizerError err;
00562         
00563         if (err = VDGetImageDescription( pVdg->vdCompInst, vdImageDesc))
00564         {
00565                 fprintf(stderr, "VDGetImageDescription err=%ld\n", err);
00566                 goto endFunc;           
00567         }
00568         
00569 endFunc:        
00570                 return err;
00571 }
00572 
00573 static OSErr vdgDecompressionSequenceBegin(  VdigGrab* pVdg,
00574                                                                 CGrafPtr dstPort, 
00575                                                                 Rect* pDstRect,
00576                                                                 MatrixRecord* pDstScaleMatrix )
00577 {
00578         OSErr err;
00579         
00580         //      Rect                               sourceRect = pMungData->bounds;
00581         //      MatrixRecord               scaleMatrix; 
00582         
00583         // !HACK! Different conversions are used for these two equivalent types
00584         // so we force the cType so that the more efficient path is used
00585         if ((*pVdg->vdImageDesc)->cType == FOUR_CHAR_CODE('yuv2'))
00586                 (*pVdg->vdImageDesc)->cType = FOUR_CHAR_CODE('yuvu'); // kYUVUPixelFormat
00587         
00588         // make a scaling matrix for the sequence
00589         //      sourceRect.right = (*pVdg->vdImageDesc)->width;
00590         //      sourceRect.bottom = (*pVdg->vdImageDesc)->height;
00591         //      RectMatrix(&scaleMatrix, &sourceRect, &pMungData->bounds);
00592         
00593     // begin the process of decompressing a sequence of frames
00594     // this is a set-up call and is only called once for the sequence - the ICM will interrogate different codecs
00595     // and construct a suitable decompression chain, as this is a time consuming process we don't want to do this
00596     // once per frame (eg. by using DecompressImage)
00597     // for more information see Ice Floe #8 http://developer.apple.com/quicktime/icefloe/dispatch008.html
00598     // the destination is specified as the GWorld
00599         if (err = DecompressSequenceBeginS(    &pVdg->dstImageSeq,      // pointer to field to receive unique ID for sequence.
00600                                                                                    pVdg->vdImageDesc,   // handle to image description structure.
00601                                                                                    0,                                   // pointer to compressed image data.
00602                                                                                    0,                                   // size of the buffer.
00603                                                                                    dstPort,                             // port for the DESTINATION image
00604                                                                                    NULL,                                // graphics device handle, if port is set, set to NULL
00605                                                                                    NULL, //&sourceRect  // source rectangle defining the portion of the image to decompress 
00606                                                                                    pDstScaleMatrix,             // transformation matrix
00607                                                                                    srcCopy,                             // transfer mode specifier
00608                                                                                    (RgnHandle)NULL,             // clipping region in dest. coordinate system to use as a mask
00609                                                                                    0L,                                  // flags
00610                                                                                    codecHighQuality, //codecNormalQuality   // accuracy in decompression
00611                                                                                    bestSpeedCodec)) //anyCodec  bestSpeedCodec  // compressor identifier or special identifiers ie. bestSpeedCodec
00612         {
00613                 fprintf(stderr, "DecompressSequenceBeginS err=%d\n", err);
00614                 goto endFunc;
00615         }
00616                   
00617 endFunc:        
00618                 return err;
00619 }
00620 
00621 static OSErr vdgDecompressionSequenceWhen(   VdigGrab* pVdg,
00622                                                                 Ptr theData,
00623                                                                 long dataSize)
00624 {
00625         OSErr err;
00626         CodecFlags      ignore = 0;
00627         
00628         if(err = DecompressSequenceFrameWhen(   pVdg->dstImageSeq,      // sequence ID returned by DecompressSequenceBegin.
00629                                                                                         theData,                        // pointer to compressed image data.
00630                                                                                         dataSize,                       // size of the buffer.
00631                                                                                         0,                                      // in flags.
00632                                                                                         &ignore,                        // out flags.
00633                                                                                         NULL,                           // async completion proc.
00634                                                                                         NULL ))                         // frame timing information.
00635         {
00636                 fprintf(stderr, "DecompressSequenceFrameWhen err=%d\n", err);
00637                 goto endFunc;
00638         }
00639         
00640 endFunc:
00641                 return err;
00642 }
00643 
00644 static OSErr vdgDecompressionSequenceEnd( VdigGrab* pVdg )
00645 {
00646         OSErr err;
00647         
00648         if (!pVdg->dstImageSeq)
00649         {
00650                 fprintf(stderr, "vdgDestroyDecompressionSequence NULL sequence\n");
00651                 err = qtParamErr; 
00652                 goto endFunc;
00653         }
00654         
00655         if (err = CDSequenceEnd(pVdg->dstImageSeq))
00656         {
00657                 fprintf(stderr, "CDSequenceEnd err=%d\n", err);
00658                 goto endFunc;
00659         }
00660         
00661         pVdg->dstImageSeq = 0;
00662         
00663 endFunc:
00664                 return err;
00665 }
00666 
00667 static VideoDigitizerError vdgStartGrabbing(VdigGrab*   pVdg, MatrixRecord* pDstScaleMatrix)
00668 {
00669         VideoDigitizerError err;
00670         
00671         if (!pVdg->isPreflighted)
00672         {
00673                 fprintf(stderr, "vdgStartGrabbing called without previous successful vdgPreflightGrabbing()\n");
00674                 err = (VideoDigitizerError)badCallOrderErr; 
00675                 goto endFunc;   
00676         }
00677         
00678     if (err = VDCompressOneFrameAsync( pVdg->vdCompInst ))
00679         {
00680                 fprintf(stderr, "VDCompressOneFrameAsync err=%ld\n", err);
00681                 goto endFunc;   
00682         }
00683         
00684         if (err = vdgDecompressionSequenceBegin( pVdg, pVdg->dstPort, NULL, pDstScaleMatrix ))
00685         {
00686                 fprintf(stderr, "vdgDecompressionSequenceBegin err=%ld\n", err);
00687                 goto endFunc;   
00688         }
00689         
00690         pVdg->isGrabbing = 1;
00691         
00692 endFunc:
00693                 return err;
00694 }
00695 
00696 static VideoDigitizerError vdgStopGrabbing(VdigGrab* pVdg)
00697 {
00698         VideoDigitizerError err;
00699         
00700         if (err = VDSetCompressionOnOff( pVdg->vdCompInst, 0))
00701         {
00702                 fprintf(stderr, "VDSetCompressionOnOff err=%ld\n", err);
00703                 //              goto endFunc;           
00704         }
00705         
00706         if (err = (VideoDigitizerError)vdgDecompressionSequenceEnd(pVdg))
00707         {
00708                 fprintf(stderr, "vdgDecompressionSequenceEnd err=%ld\n", err);
00709                 //              goto endFunc;
00710         }
00711         
00712         pVdg->isGrabbing = 0;
00713         
00714         //endFunc:
00715         return err;
00716 }
00717 
00718 static bool vdgIsGrabbing(VdigGrab* pVdg)
00719 {
00720         return pVdg->isGrabbing;
00721 }
00722 
00723 static VideoDigitizerError vdgPoll(     VdigGrab*   pVdg,
00724                                                                         UInt8*          pQueuedFrameCount,
00725                                                                         Ptr*            pTheData,
00726                                                                         long*           pDataSize,
00727                                                                         UInt8*          pSimilarity,
00728                                                                         TimeRecord*     pTime )
00729 {
00730         VideoDigitizerError err;
00731         
00732         if (!pVdg->isGrabbing)
00733         { 
00734                 fprintf(stderr, "vdgGetFrame error: not grabbing\n");
00735                 err = (VideoDigitizerError)qtParamErr; 
00736                 goto endFunc;
00737         }
00738         
00739     if (err = VDCompressDone(   pVdg->vdCompInst,
00740                                                                 pQueuedFrameCount,
00741                                                                 pTheData,
00742                                                                 pDataSize,
00743                                                                 pSimilarity,
00744                                                                 pTime ))
00745         {
00746                 fprintf(stderr, "VDCompressDone err=%ld\n", err);
00747                 goto endFunc;
00748         }
00749         
00750         // Overlapped grabbing
00751     if (*pQueuedFrameCount)
00752     {
00753                 if (err = VDCompressOneFrameAsync(pVdg->vdCompInst))
00754                 {
00755                         fprintf(stderr, "VDCompressOneFrameAsync err=%ld\n", err);
00756                         goto endFunc;           
00757                 }
00758         }
00759         
00760 endFunc:
00761                 return err;
00762 }
00763 
00764 static VideoDigitizerError vdgReleaseBuffer(VdigGrab*   pVdg, Ptr theData)
00765 {
00766         VideoDigitizerError err;
00767         
00768         if (err = VDReleaseCompressBuffer(pVdg->vdCompInst, theData))
00769         {
00770                 fprintf(stderr, "VDReleaseCompressBuffer err=%ld\n", err);
00771                 goto endFunc;           
00772         }
00773         
00774 endFunc:
00775                 return err;
00776 }
00777 
00778 static VideoDigitizerError vdgIdle(VdigGrab* pVdg, int*  pIsUpdated)
00779 {
00780         VideoDigitizerError err;
00781         
00782     UInt8               queuedFrameCount;
00783     Ptr                 theData;
00784     long                dataSize;
00785     UInt8               similarity;
00786     TimeRecord  time;
00787         
00788         *pIsUpdated = 0;
00789         
00790         // should be while?
00791         if ( !(err = vdgPoll( pVdg,
00792                                                   &queuedFrameCount,
00793                                                   &theData,
00794                                                   &dataSize,
00795                                                   &similarity,
00796                                                   &time))
00797                  && queuedFrameCount)
00798         {
00799                 *pIsUpdated = 1;
00800                 
00801                 // Decompress the sequence
00802                 if (err = (VideoDigitizerError)vdgDecompressionSequenceWhen( pVdg,
00803                                                                                                 theData,
00804                                                                                                 dataSize))
00805                 {
00806                         fprintf(stderr, "vdgDecompressionSequenceWhen err=%ld\n", err);
00807                         //                      goto endFunc;   
00808                 }
00809                 
00810                 // return the buffer
00811                 if(err = vdgReleaseBuffer(pVdg, theData))
00812                 {
00813                         fprintf(stderr, "vdgReleaseBuffer err=%ld\n", err);
00814                         //                      goto endFunc;
00815                 }
00816         }
00817         
00818         if (err)
00819         {
00820                 fprintf(stderr, "vdgPoll err=%ld\n", err);
00821                 goto endFunc;
00822         }
00823         
00824 endFunc:
00825                 return err;
00826 }
00827 
00828 static ComponentResult vdgReleaseAndDealloc(VdigGrab* pVdg)
00829 {
00830         ComponentResult err = noErr;            
00831         
00832         if (pVdg->vdImageDesc) {
00833                 DisposeHandle((Handle)pVdg->vdImageDesc);
00834                 pVdg->vdImageDesc = NULL;
00835         }
00836         
00837         if (pVdg->vdCompInst) {
00838                 if (err = CloseComponent(pVdg->vdCompInst))
00839                         fprintf(stderr, "CloseComponent err=%ld\n", err);               
00840                 pVdg->vdCompInst = NULL;
00841         }
00842         
00843         if (pVdg->sgchanVideo) {
00844                 if (err = SGDisposeChannel(pVdg->seqGrab, pVdg->sgchanVideo))
00845                         fprintf(stderr, "SGDisposeChannel err=%ld\n", err);     
00846                 pVdg->sgchanVideo = NULL;
00847         }
00848         
00849         if (pVdg->seqGrab) {
00850                 if (err = CloseComponent(pVdg->seqGrab))
00851                         fprintf(stderr, "CloseComponent err=%ld\n", err);               
00852                 pVdg->seqGrab = NULL;
00853         }
00854 
00855         if (pVdg) {
00856                 free(pVdg);
00857                 pVdg = NULL;
00858         }
00859 
00860         return err;
00861 }
00862 
00863 #pragma mark -
00864 //  Functions.
00865 
00866 int arVideoDispOption(void)
00867 {
00868     return (ar2VideoDispOption());
00869 }
00870 
00871 int arVideoOpen(char *config)
00872 {
00873     if (gVid != NULL) {
00874         fprintf(stderr, "arVideoOpen(): Error, device is already open.\n");
00875         return (-1);
00876     }
00877     gVid = ar2VideoOpen(config);
00878     if (gVid == NULL) return (-1);
00879 
00880     return (0);
00881 }
00882 
00883 int arVideoClose(void)
00884 {
00885         int result;
00886         
00887     if (gVid == NULL) return (-1);
00888         
00889         result = ar2VideoClose(gVid);
00890         gVid = NULL;
00891     return (result);
00892 }  
00893     
00894 int arVideoInqSize(int *x, int *y)
00895 {
00896     if (gVid == NULL) return (-1);
00897  
00898     return (ar2VideoInqSize(gVid, x, y));
00899 }       
00900         
00901 ARUint8 *arVideoGetImage(void)
00902 {   
00903     if (gVid == NULL) return (NULL);
00904 
00905     return (ar2VideoGetImage(gVid));
00906 }
00907  
00908 int arVideoCapStart(void)
00909 {
00910     if (gVid == NULL) return (-1);
00911   
00912     return (ar2VideoCapStart(gVid));
00913 }  
00914     
00915 int arVideoCapStop(void)
00916 {
00917     if (gVid == NULL) return (-1);
00918  
00919     return (ar2VideoCapStop(gVid));
00920 }       
00921         
00922 int arVideoCapNext(void)
00923 {   
00924     if (gVid == NULL) return (-1);  
00925 
00926     return (ar2VideoCapNext(gVid)); 
00927 }
00928 
00929 #pragma mark -
00930 static int ar2VideoInternalLock(pthread_mutex_t *mutex)
00931 {
00932         int err;
00933         
00934         // Ready to access data, so lock access to the data.
00935         if ((err = pthread_mutex_lock(mutex)) != 0) {
00936                 perror("ar2VideoInternalLock(): Error locking mutex");
00937                 return (0);
00938         }
00939         return (1);
00940 }
00941 
00942 #if 0
00943 static int ar2VideoInternalTryLock(pthread_mutex_t *mutex)
00944 {
00945         int err;
00946         
00947         // Ready to access data, so lock access to the data.
00948         if ((err = pthread_mutex_trylock(mutex)) != 0) {
00949                 if (err == EBUSY) return (-1);
00950                 perror("ar2VideoInternalTryLock(): Error locking mutex");
00951                 return (0);
00952         }
00953         return (1);
00954 }
00955 #endif
00956 
00957 static int ar2VideoInternalUnlock(pthread_mutex_t *mutex)
00958 {
00959         int err;
00960         
00961         // Our access is done, so unlock access to the data.
00962         if ((err = pthread_mutex_unlock(mutex)) != 0) {
00963                 perror("ar2VideoInternalUnlock(): Error unlocking mutex");
00964                 return (0);
00965         }
00966         return (1);
00967 }
00968 
00969 static void ar2VideoInternalThreadCleanup(void *arg)
00970 {
00971         AR2VideoParamT *vid;
00972         
00973         vid = (AR2VideoParamT *)arg;
00974         ar2VideoInternalUnlock(&(vid->bufMutex)); // A cancelled thread shouldn't leave mutexes locked.
00975 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
00976         ExitMoviesOnThread();
00977 #else
00978         ar2VideoInternalUnlock(&gVidQuickTimeMutex);
00979 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
00980 }
00981 
00982 //
00983 // This function will run in a separate pthread.
00984 // Its sole function is to call vdgIdle() on a regular basis during a capture operation.
00985 // It should be terminated by a call pthread_cancel() from the instantiating thread.
00986 //
00987 static void *ar2VideoInternalThread(void *arg)
00988 {
00989 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
00990         OSErr                           err_o;
00991 #else
00992         int                                     weLocked = 0;
00993 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
00994         AR2VideoParamT          *vid;
00995         int                                     keepAlive = 1;
00996 
00997 #ifndef AR_VIDEO_DEBUG_FIX_DUAL_PROCESSOR_RACE
00998         struct timeval          tv;  // Seconds and microseconds since Jan 1, 1970.
00999         struct timespec         ts;  // Seconds and nanoseconds since Jan 1, 1970.
01000         int                                     err_i;
01001 #endif // !AR_VIDEO_DEBUG_FIX_DUAL_PROCESSOR_RACE
01002         ComponentResult         err;
01003         int                                     isUpdated = 0;
01004 
01005         
01006 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01007         // Signal to QuickTime that this is a separate thread.
01008         if ((err_o = EnterMoviesOnThread(0)) != noErr) {
01009                 fprintf(stderr, "ar2VideoInternalThread(): Error %d initing QuickTime for this thread.\n", err_o);
01010                 return (NULL);
01011         }
01012 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
01013 
01014         // Register our cleanup function, with arg as arg.
01015         pthread_cleanup_push(ar2VideoInternalThreadCleanup, arg);
01016         
01017         vid = (AR2VideoParamT *)arg;            // Cast the thread start arg to the correct type.
01018         
01019         // Have to get the lock now, to guarantee vdgIdle() exclusive access to *vid.
01020         // The lock is released while we are blocked inside pthread_cond_timedwait(),
01021         // and during that time ar2VideoGetImage() (and therefore OpenGL) can access
01022         // *vid exclusively.
01023         if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01024                 fprintf(stderr, "ar2VideoInternalThread(): Unable to lock mutex, exiting.\n");
01025                 keepAlive = 0;
01026         }
01027         
01028         while (keepAlive && vdgIsGrabbing(vid->pVdg)) {
01029                 
01030 #ifndef AR_VIDEO_DEBUG_FIX_DUAL_PROCESSOR_RACE
01031                 gettimeofday(&tv, NULL);
01032                 ts.tv_sec = tv.tv_sec;
01033                 ts.tv_nsec = tv.tv_usec * 1000 + vid->milliSecPerTimer * 1000000;
01034                 if (ts.tv_nsec >= 1000000000) {
01035                         ts.tv_nsec -= 1000000000;
01036                         ts.tv_sec += 1;
01037                 }
01038 #endif // AR_VIDEO_DEBUG_FIX_DUAL_PROCESSOR_RACE
01039                 
01040 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01041                 // Get a lock to access QuickTime (for SGIdle()), but only if more than one thread is running.
01042                 if (gVidCount > 1) {
01043                         if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01044                                 fprintf(stderr, "ar2VideoInternalThread(): Unable to lock mutex (for QuickTime), exiting.\n");
01045                                 keepAlive = 0;
01046                                 break;
01047                         }
01048                         weLocked = 1;
01049                 }
01050 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01051                 
01052                 if ((err = vdgIdle(vid->pVdg, &isUpdated)) != noErr) {
01053                         // In QT 4 you would always encounter a cDepthErr error after a user drags
01054                         // the window, this failure condition has been greatly relaxed in QT 5
01055                         // it may still occur but should only apply to vDigs that really control
01056                         // the screen.
01057                         // You don't always know where these errors originate from, some may come
01058                         // from the VDig.
01059                         fprintf(stderr, "vdgIdle err=%ld.\n", err);
01060                         keepAlive = 0;
01061                         break;
01062                 }
01063                 
01064 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01065                 // vdgIdle() is done, unlock our hold on QuickTime if we locked it.
01066                 if (weLocked) {
01067                         if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01068                                 fprintf(stderr, "ar2VideoInternalThread(): Unable to unlock mutex (for QuickTime), exiting.\n");
01069                                 keepAlive = 0;
01070                                 break;
01071                         }
01072                         weLocked = 0;
01073                 }
01074 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01075                 
01076                 if (isUpdated) {
01077                         // Write status information onto the frame if so desired.
01078                         if (vid->showFPS) {
01079                                 
01080                                 // Variables for fps counter.
01081                                 //float                         fps = 0;
01082                                 //float                         averagefps = 0;
01083                                 char                            status[64];
01084                                 
01085                                 // Reset frame and time counters after a stop/start.
01086                                 /*
01087                                  if (vid->lastTime > time) {
01088                                         vid->lastTime = 0;
01089                                         vid->frameCount = 0;
01090                                 }
01091                                 */
01092                                 vid->frameCount++;
01093                                 // If first time here, get the time scale.
01094                                 /*
01095                                 if (vid->timeScale == 0) {
01096                                         if ((err = SGGetChannelTimeScale(c, &vid->timeScale)) != noErr) {
01097                                                 fprintf(stderr, "SGGetChannelTimeScale err=%ld.\n", err);
01098                                         }
01099                                 }
01100                                 */
01101                                 //fps = (float)vid->timeScale / (float)(time - vid->lastTime);
01102                                 //averagefps = (float)vid->frameCount * (float)vid->timeScale / (float)time;
01103                                 //sprintf(status, "time: %ld, fps:%5.1f avg fps:%5.1f", time, fps, averagefps);
01104                                 sprintf(status, "frame: %ld", vid->frameCount);
01105 #if 0
01106                                 Str255 theString;
01107                                 CGrafPtr theSavedPort;
01108                                 GDHandle theSavedDevice;
01109                                 GetGWorld(&theSavedPort, &theSavedDevice);
01110                                 SetGWorld(vid->pGWorld, NULL);
01111                                 TextSize(12);
01112                                 TextMode(srcCopy);
01113                                 MoveTo(vid->theRect.left + 10, vid->theRect.bottom - 14);
01114                                 CopyCStringToPascal(status, theString);
01115                                 DrawString(theString);
01116                                 SetGWorld(theSavedPort, theSavedDevice);
01117 #else
01118                                 CGContextRef ctx;
01119                                 QDBeginCGContext(vid->pGWorld, &ctx);
01120                                 CFStringRef str = CFStringCreateWithCString(NULL, status, kCFStringEncodingMacRoman);
01121                                 CGContextSelectFont(ctx, "Monaco", 12, kCGEncodingMacRoman);
01122                                 CGContextSetTextDrawingMode(ctx, kCGTextFillStroke);
01123                                 CGContextShowTextAtPoint(ctx, 10, 10, status, strlen(status));
01124                                 CFRelease(str);
01125                                 QDEndCGContext(vid->pGWorld, &ctx);
01126 #endif
01127                                 //vid->lastTime = time;
01128                         }
01129                         // Now copy the frame (if double-buffering).
01130                         if (vid->bufCopyFlag) {
01131                                 if (vid->status & AR_VIDEO_STATUS_BIT_BUFFER) {
01132                                         memcpy((void *)(vid->bufPixelsCopy2), (void *)(vid->bufPixels), vid->bufSize);
01133                                 } else {
01134                                         memcpy((void *)(vid->bufPixelsCopy1), (void *)(vid->bufPixels), vid->bufSize);
01135                                 }
01136                         }
01137                         // Mark status to indicate we have a frame available.
01138                         vid->status |= AR_VIDEO_STATUS_BIT_READY;                       
01139                 }
01140                 
01141                 // All done. Wewease Wodger!
01142 #ifndef AR_VIDEO_DEBUG_FIX_DUAL_PROCESSOR_RACE          
01143                 err_i = pthread_cond_timedwait(&(vid->condition), &(vid->bufMutex), &ts);
01144                 if (err_i != 0 && err_i != ETIMEDOUT) {
01145                         fprintf(stderr, "ar2VideoInternalThread(): Error %d waiting for condition.\n", err_i);
01146                         keepAlive = 0;
01147                         break;
01148                 }
01149 #else
01150                 ar2VideoInternalUnlock(&(vid->bufMutex));
01151                 usleep(vid->milliSecPerTimer * 1000);
01152                 if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01153                         fprintf(stderr, "ar2VideoInternalThread(): Unable to lock mutex, exiting.\n");
01154                         keepAlive = 0;
01155                         break;
01156                 }
01157 #endif // AR_VIDEO_DEBUG_FIX_DUAL_PROCESSOR_RACE
01158                 
01159                 pthread_testcancel();
01160         }
01161         
01162         pthread_cleanup_pop(1);
01163         return (NULL);
01164 }
01165 
01166 static int sysctlbyname_with_pid (const char *name, pid_t pid,
01167                                                                   void *oldp, size_t *oldlenp,
01168                                                                   void *newp, size_t newlen)
01169 {
01170     if (pid == 0) {
01171         if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1)  {
01172             fprintf(stderr, "sysctlbyname_with_pid(0): sysctlbyname  failed:"
01173                                         "%s\n", strerror(errno));
01174             return -1;
01175         }
01176     } else {
01177         int mib[CTL_MAXNAME];
01178         size_t len = CTL_MAXNAME;
01179         if (sysctlnametomib(name, mib, &len) == -1) {
01180             fprintf(stderr, "sysctlbyname_with_pid: sysctlnametomib  failed:"
01181                                         "%s\n", strerror(errno));
01182             return -1;
01183         }
01184         mib[len] = pid;
01185         len++;
01186         if (sysctl(mib, len, oldp, oldlenp, newp, newlen) == -1)  {
01187             fprintf(stderr, "sysctlbyname_with_pid: sysctl  failed:"
01188                     "%s\n", strerror(errno));
01189             return -1;
01190         }
01191     }
01192     return 0;
01193 }
01194 
01195 // Pass 0 to use current PID.
01196 int is_pid_native (pid_t pid)
01197 {
01198     int ret = 0;
01199     size_t sz = sizeof(ret);
01200         if (sysctlbyname_with_pid("sysctl.proc_native", pid,
01201                                                           &ret, &sz, NULL, 0) == -1) {
01202                 if (errno == ENOENT) {
01203             // sysctl doesn't exist, which means that this version of Mac OS
01204             // pre-dates Rosetta, so the application must be native.
01205             return 1;
01206         }
01207         fprintf(stderr, "is_pid_native: sysctlbyname_with_pid  failed:"
01208                 "%s\n", strerror(errno));
01209         return -1;
01210     }
01211     return ret;
01212 }
01213 
01214 #pragma mark -
01215 
01216 int ar2VideoDispOption(void)
01217 {
01218         //     0         1         2         3         4         5         6         7
01219         //     0123456789012345678901234567890123456789012345678901234567890123456789012
01220     printf("ARVideo may be configured using one or more of the following options,\n");
01221     printf("separated by a space:\n\n");
01222     printf(" -nodialog\n");
01223     printf("    Don't display video settings dialog.\n");
01224     printf(" -width=w\n");
01225     printf("    Scale camera native image to width w.\n");
01226     printf(" -height=h\n");
01227     printf("    Scale camera native image to height h.\n");
01228     printf(" -fps\n");
01229     printf("    Overlay camera frame counter on image.\n");
01230     printf(" -grabber=n\n");
01231     printf("    With multiple QuickTime video grabber components installed,\n");
01232         printf("    use component n (default n=1).\n");
01233         printf("    N.B. It is NOT necessary to use this option if you have installed\n");
01234         printf("    more than one video input device (e.g. two cameras) as the default\n");
01235         printf("    QuickTime grabber can manage multiple video channels.\n");
01236         printf(" -pixelformat=cccc\n");
01237     printf("    Return images with pixels in format cccc, where cccc is either a\n");
01238     printf("    numeric pixel format number or a valid 4-character-code for a\n");
01239     printf("    pixel format.\n");
01240         printf("    The following numeric values are supported: \n");
01241         printf("    24 (24-bit RGB), 32 (32-bit ARGB), 40 (8-bit grey)");
01242         printf("    The following 4-character-codes are supported: \n");
01243     printf("    BGRA, RGBA, ABGR, 24BG, 2vuy, yuvs.\n");
01244     printf("    (See http://developer.apple.com/quicktime/icefloe/dispatch020.html.)\n");
01245     printf(" -fliph\n");
01246     printf("    Flip camera image horizontally.\n");
01247     printf(" -flipv\n");
01248     printf("    Flip camera image vertically.\n");
01249     printf(" -singlebuffer\n");
01250     printf("    Use single buffering of captured video instead of triple-buffering.\n");
01251     printf("\n");
01252 
01253     return (0);
01254 }
01255 
01256 
01257 AR2VideoParamT *ar2VideoOpen(char *config_in)
01258 {
01259         long                            qtVersion = 0L;
01260         int                                     width = 0;
01261         int                                     height = 0;
01262         int                                     grabber = 1;
01263         int                                     showFPS = 0;
01264         int                                     showDialog = 1;
01265         int                                     standardDialog = 0;
01266         int                                     singleBuffer = 0;
01267         int                                     flipH = 0, flipV = 0;
01268     OSErr                               err_s = noErr;
01269         ComponentResult         err = noErr;
01270         int                                     err_i = 0;
01271     AR2VideoParamT              *vid = NULL;
01272     char                                *config, *a, line[256];
01273 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01274         int                                     weLocked = 0;
01275 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01276         OSType                          pixFormat = (OSType)0;
01277         long                            bytesPerPixel;
01278         long                            cpuType;
01279         
01280         /* If no config string is supplied, we should use the environment variable, otherwise set a sane default */
01281         if (!config_in || !(config_in[0])) {
01282                 /* None suppplied, lets see if the user supplied one from the shell */
01283                 char *envconf = getenv ("ARTOOLKIT_CONFIG");
01284                 if (envconf && envconf[0]) {
01285                         config = envconf;
01286                         printf ("Using video config from environment \"%s\".\n", envconf);
01287                 } else {
01288                         config = NULL;
01289                         printf ("Using default video config.\n");
01290                 }
01291         } else {
01292                 config = config_in;
01293                 printf ("Using supplied video config \"%s\".\n", config_in);
01294         }
01295 
01296         // Process configuration options.
01297         a = config;
01298     if (a) {
01299                 err_i = 0;
01300         for (;;) {
01301             while (*a == ' ' || *a == '\t') a++; // Skip whitespace.
01302             if (*a == '\0') break;
01303 
01304             if (strncmp(a, "-width=", 7) == 0) {
01305                 sscanf(a, "%s", line);
01306                 if (strlen(line) <= 7 || sscanf(&line[7], "%d", &width) == 0) err_i = 1;
01307             } else if (strncmp(a, "-height=", 8) == 0) {
01308                 sscanf(a, "%s", line);
01309                 if (strlen(line) <= 8 || sscanf(&line[8], "%d", &height) == 0) err_i = 1;
01310             } else if (strncmp(a, "-grabber=", 9) == 0) {
01311                 sscanf(a, "%s", line);
01312                 if (strlen(line) <= 9 || sscanf(&line[9], "%d", &grabber) == 0) err_i = 1;
01313             } else if (strncmp(a, "-pixelformat=", 13) == 0) {
01314                 sscanf(a, "%s", line);
01315                                 if (strlen(line) <= 13) err_i = 1;
01316                                 else {
01317                                         if (strlen(line) == 17) err_i = (sscanf(&line[13], "%4c", (char *)&pixFormat) < 1);
01318                                         else err_i = (sscanf(&line[13], "%li", (long *)&pixFormat) < 1); // Integer.
01319                                 }
01320             } else if (strncmp(a, "-fps", 4) == 0) {
01321                 showFPS = 1;
01322             } else if (strncmp(a, "-nodialog", 9) == 0) {
01323                 showDialog = 0;
01324             } else if (strncmp(a, "-standarddialog", 15) == 0) {
01325                 standardDialog = 1;
01326             } else if (strncmp(a, "-fliph", 6) == 0) {
01327                 flipH = 1;
01328             } else if (strncmp(a, "-flipv", 6) == 0) {
01329                 flipV = 1;
01330             } else if (strncmp(a, "-singlebuffer", 13) == 0) {
01331                 singleBuffer = 1;
01332             } else {
01333                 err_i = 1;
01334             }
01335                         
01336                         if (err_i) {
01337                                 ar2VideoDispOption();
01338                                 return (NULL);
01339                         }
01340             
01341                         while (*a != ' ' && *a != '\t' && *a != '\0') a++; // Skip to next whitespace.
01342         }
01343     }
01344         // If no pixel format was specified in command-line options,
01345         // assign the one specified at compile-time as the default.
01346         if (!pixFormat) {
01347 #if (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_2vuy)
01348                 pixFormat = k2vuyPixelFormat;           // k422YpCbCr8CodecType, k422YpCbCr8PixelFormat
01349 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_yuvs)
01350                 pixFormat = kYUVSPixelFormat;           // kComponentVideoUnsigned
01351 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_RGB)
01352                 pixFormat = k24RGBPixelFormat;
01353 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGR)
01354                 pixFormat = k24BGRPixelFormat;
01355 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_ARGB)
01356                 pixFormat = k32ARGBPixelFormat;
01357 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_RGBA)
01358                 pixFormat = k32RGBAPixelFormat;
01359 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_ABGR)
01360                 pixFormat = k32ABGRPixelFormat;
01361 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGRA)
01362                 pixFormat = k32BGRAPixelFormat;
01363 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_MONO)
01364                 pixFormat = k8IndexedGrayPixelFormat;
01365 #else
01366 #  error Unsupported default pixel format specified in config.h.
01367 #endif
01368         }
01369         
01370         switch (pixFormat) {
01371                 case k2vuyPixelFormat:
01372                 case kYUVSPixelFormat:
01373                         bytesPerPixel = 2l;
01374                         break; 
01375                 case k24RGBPixelFormat:
01376                 case k24BGRPixelFormat:
01377                         bytesPerPixel = 3l;
01378                         break;
01379                 case k32ARGBPixelFormat:
01380                 case k32BGRAPixelFormat:
01381                 case k32ABGRPixelFormat:
01382                 case k32RGBAPixelFormat:
01383                         bytesPerPixel = 4l;
01384                         break;
01385                 case k8IndexedGrayPixelFormat:
01386                         bytesPerPixel = 1l;
01387                 default:
01388                         fprintf(stderr, "ar2VideoOpen(): Unsupported pixel format requested.\n");
01389                         return(NULL);
01390                         break;                  
01391         }
01392         
01393         // If there are no active grabbers, init QuickTime.
01394         if (gVidCount == 0) {
01395         
01396                 if ((err_s = Gestalt(gestaltQuickTimeVersion, &qtVersion)) != noErr) {
01397                         fprintf(stderr,"ar2VideoOpen(): QuickTime not installed (%d).\n", err_s);
01398                         return (NULL);
01399                 }
01400                 
01401 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01402                 if ((qtVersion >> 16) < 0x640) {
01403                         fprintf(stderr,"ar2VideoOpen(): QuickTime version 6.4 or newer is required by this program.\n");;
01404                         return (NULL);
01405                 }
01406 #else
01407                 if ((qtVersion >> 16) < 0x400) {
01408                         fprintf(stderr,"ar2VideoOpen(): QuickTime version 4.0 or newer is required by this program.\n");;
01409                         return (NULL);
01410                 }
01411 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
01412                 
01413                 // Initialise QuickTime (a.k.a. Movie Toolbox).
01414                 if ((err_s = EnterMovies()) != noErr) {
01415                         fprintf(stderr,"ar2VideoOpen(): Unable to initialise Carbon/QuickTime (%d).\n", err_s);
01416                         return (NULL);
01417                 }
01418                 
01419 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01420                 // Init the QuickTime access mutex.             
01421                 if ((err_i = pthread_mutex_init(&gVidQuickTimeMutex, NULL)) != 0) {
01422                         fprintf(stderr, "ar2VideoOpen(): Error %d creating mutex (for QuickTime).\n", err_i);
01423                         return (NULL);
01424                 }
01425 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01426         }
01427         
01428 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01429         // Get a hold on the QuickTime toolbox.
01430         // Need to unlock this mutex before returning, so any errors should goto bail;
01431         if (gVidCount > 0) {
01432                 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01433                         fprintf(stderr, "ar2VideoOpen(): Unable to lock mutex (for QuickTime).\n");
01434                         return (NULL);
01435                 }
01436                 weLocked = 1;
01437         }
01438 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01439                 
01440         gVidCount++;
01441         
01442         // Allocate the parameters structure and fill it in.
01443         arMalloc(vid, AR2VideoParamT, 1);
01444         memset(vid, 0, sizeof(AR2VideoParamT));
01445     vid->status         = 0;
01446         vid->showFPS            = showFPS;
01447         vid->frameCount         = 0;
01448         //vid->lastTime         = 0;
01449         //vid->timeScale        = 0;
01450         vid->grabber            = grabber;
01451         vid->bufCopyFlag        = !singleBuffer;
01452         
01453         // Find out if we are running on an Intel Mac.
01454         if ((err_s = Gestalt(gestaltNativeCPUtype, &cpuType) != noErr)) {
01455                 fprintf(stderr, "ar2VideoOpen(): Error getting native CPU type.\n");
01456                 goto out1;
01457         }
01458         if (cpuType == gestaltCPUPentium) {
01459                 // We are running native on an Intel-based Mac.
01460                 //printf("Detected Intel CPU.\n");
01461         } else {
01462                 int native = is_pid_native(0);
01463                 // We are not. But are we running under Rosetta?
01464                 if (native == 0) {
01465                         // We're running under Rosetta.
01466                         printf("Detected Intel CPU, but running PowerPC code under Rosetta.\n");
01467                 } else if (native == 1) {
01468                         //printf("Detected PowerPC CPU.\n");
01469                 } else {
01470                         // Error.
01471                 }
01472         }
01473 
01474         if(!(vid->pVdg = vdgAllocAndInit(grabber))) {
01475                 fprintf(stderr, "ar2VideoOpen(): vdgAllocAndInit returned error.\n");
01476                 goto out1;
01477         }
01478         
01479         if (err = vdgRequestSettings(vid->pVdg, showDialog, standardDialog, gVidCount)) {
01480                 fprintf(stderr, "ar2VideoOpen(): vdgRequestSettings err=%ld.\n", err);
01481                 goto out2;
01482         }
01483         
01484         if (err = vdgPreflightGrabbing(vid->pVdg)) {
01485                 fprintf(stderr, "ar2VideoOpen(): vdgPreflightGrabbing err=%ld.\n", err);
01486                 goto out2;
01487         }
01488         
01489         // Set the timer frequency from the Vdig's Data Rate
01490         // ASC soft vdig fails this call
01491         if (err = vdgGetDataRate(   vid->pVdg, 
01492                                                                 &vid->milliSecPerFrame,
01493                                                                 &vid->frameRate,
01494                                                                 &vid->bytesPerSecond)) {
01495                 fprintf(stderr, "ar2VideoOpen(): vdgGetDataRate err=%ld.\n", err);
01496                 //goto out2; 
01497         }
01498         if (err == noErr) {
01499                 // Some vdigs do return the frameRate but not the milliSecPerFrame
01500                 if ((vid->milliSecPerFrame == 0) && (vid->frameRate != 0)) {
01501                         vid->milliSecPerFrame = (1000L << 16) / vid->frameRate;
01502                 } 
01503         }
01504         
01505         // Poll the vdig at twice the frame rate or between sensible limits
01506         vid->milliSecPerTimer = vid->milliSecPerFrame / 2;
01507         if (vid->milliSecPerTimer <= 0) {
01508                 fprintf(stderr, "vid->milliSecPerFrame: %ld ", vid->milliSecPerFrame);
01509                 vid->milliSecPerTimer = AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MIN;
01510                 fprintf(stderr, "forcing timer period to %ldms\n", vid->milliSecPerTimer);
01511         }
01512         if (vid->milliSecPerTimer >= AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MAX) {
01513                 fprintf(stderr, "vid->milliSecPerFrame: %ld ", vid->milliSecPerFrame);
01514                 vid->milliSecPerFrame = AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MAX;
01515                 fprintf(stderr, "forcing timer period to %ldms\n", vid->milliSecPerTimer);
01516         }
01517         
01518     vid->vdImageDesc = (ImageDescriptionHandle)NewHandle(0);
01519         if (err = vdgGetImageDescription(vid->pVdg, vid->vdImageDesc)) {
01520                 fprintf(stderr, "ar2VideoOpen(): vdgGetImageDescription err=%ld\n", err);
01521                 goto out3;
01522         }
01523         
01524         // Report video size and compression type.
01525         printf("Video cType is %c%c%c%c, size is %dx%d.\n",
01526                         (char)(((*(vid->vdImageDesc))->cType >> 24) & 0xFF),
01527                         (char)(((*(vid->vdImageDesc))->cType >> 16) & 0xFF),
01528                         (char)(((*(vid->vdImageDesc))->cType >>  8) & 0xFF),
01529                         (char)(((*(vid->vdImageDesc))->cType >>  0) & 0xFF),
01530                         ((*vid->vdImageDesc)->width), ((*vid->vdImageDesc)->height));
01531         
01532         // If a particular size was requested, set the size of the GWorld to
01533         // the request, otherwise set it to the size of the incoming video.
01534         vid->width = (width ? width : (int)((*vid->vdImageDesc)->width));
01535         vid->height = (height ? height : (int)((*vid->vdImageDesc)->height));
01536         SetRect(&(vid->theRect), 0, 0, (short)vid->width, (short)vid->height);  
01537 
01538         // Make a scaling matrix for the sequence if size of incoming video differs from GWorld dimensions.
01539         vid->scaleMatrixPtr = NULL;
01540         int doSourceScale;
01541         if (vid->width != (int)((*vid->vdImageDesc)->width) || vid->height != (int)((*vid->vdImageDesc)->height)) {
01542                 arMalloc(vid->scaleMatrixPtr, MatrixRecord, 1);
01543                 SetIdentityMatrix(vid->scaleMatrixPtr);
01544                 Fixed scaleX, scaleY;
01545                 scaleX = FixRatio(vid->width, (*vid->vdImageDesc)->width);
01546                 scaleY = FixRatio(vid->height, (*vid->vdImageDesc)->height);
01547                 ScaleMatrix(vid->scaleMatrixPtr, scaleX, scaleY, 0, 0);
01548                 fprintf(stdout, "Video will be scaled to size %dx%d.\n", vid->width, vid->height);
01549                 doSourceScale = 1;
01550         } else {
01551                 doSourceScale = 0;
01552         }
01553         
01554         // If a flip was requested, add a scaling matrix for it.
01555         if (flipH || flipV) {
01556                 Fixed scaleX, scaleY;
01557                 if (flipH) scaleX = -fixed1;
01558                 else scaleX = fixed1;
01559                 if (flipV) scaleY = -fixed1;
01560                 else scaleY = fixed1;
01561                 if (!doSourceScale) {
01562                         arMalloc(vid->scaleMatrixPtr, MatrixRecord, 1);
01563                         SetIdentityMatrix(vid->scaleMatrixPtr);
01564                 }
01565                 ScaleMatrix(vid->scaleMatrixPtr, scaleX, scaleY, FloatToFixed((float)(vid->width) * 0.5f), FloatToFixed((float)(vid->height) * 0.5f));
01566         }
01567 
01568         // Allocate buffer for the grabber to write pixel data into, and use
01569         // QTNewGWorldFromPtr() to wrap an offscreen GWorld structure around
01570         // it. We do it in these two steps rather than using QTNewGWorld()
01571         // to guarantee that we don't get padding bytes at the end of rows.
01572         vid->rowBytes = vid->width * bytesPerPixel;
01573         vid->bufSize = vid->height * vid->rowBytes;
01574         if (!(vid->bufPixels = (ARUint8 *)valloc(vid->bufSize * sizeof(ARUint8)))) exit (1);
01575         if (vid->bufCopyFlag) {
01576                 // And another two buffers for OpenGL to read out of.
01577                 if (!(vid->bufPixelsCopy1 = (ARUint8 *)valloc(vid->bufSize * sizeof(ARUint8)))) exit (1);
01578                 if (!(vid->bufPixelsCopy2 = (ARUint8 *)valloc(vid->bufSize * sizeof(ARUint8)))) exit (1);
01579         }
01580         // Wrap a GWorld around the pixel buffer.
01581         err_s = QTNewGWorldFromPtr(&(vid->pGWorld),                     // returned GWorld
01582                                                            pixFormat,                           // format of pixels
01583                                                            &(vid->theRect),                     // bounds
01584                                                            0,                                           // color table
01585                                                            NULL,                                        // GDHandle
01586                                                            0,                                           // flags
01587                                                            (void *)(vid->bufPixels), // pixel base addr
01588                                                            vid->rowBytes);                      // bytes per row
01589         if (err_s != noErr) {
01590                 fprintf(stderr,"ar2VideoOpen(): Unable to create offscreen buffer for sequence grabbing (%d).\n", err_s);
01591                 goto out5;
01592         }
01593         
01594         // Lock the pixmap and make sure it's locked because
01595         // we can't decompress into an unlocked PixMap, 
01596         // and open the default sequence grabber.
01597         err_i = (int)LockPixels(GetGWorldPixMap(vid->pGWorld));
01598         if (!err_i) {
01599                 fprintf(stderr,"ar2VideoOpen(): Unable to lock buffer for sequence grabbing.\n");
01600                 goto out6;
01601         }
01602         
01603         // Erase to black.
01604 #if 1
01605         CGContextRef ctx;
01606         QDBeginCGContext(vid->pGWorld, &ctx);
01607         CGContextSetRGBFillColor(ctx, 0, 0, 0, 1);               
01608         CGContextFillRect(ctx, CGRectMake(0, 0, (vid->theRect).left - (vid->theRect).right, (vid->theRect).top - (vid->theRect).bottom));
01609         CGContextFlush(ctx);
01610         QDEndCGContext (vid->pGWorld, &ctx);
01611 #else
01612         CGrafPtr                        theSavedPort;
01613         GDHandle                        theSavedDevice;
01614     GetGWorld(&theSavedPort, &theSavedDevice);    
01615     SetGWorld(vid->pGWorld, NULL);
01616     BackColor(blackColor);
01617     ForeColor(whiteColor);
01618     EraseRect(&(vid->theRect));
01619     SetGWorld(theSavedPort, theSavedDevice);
01620 #endif
01621         
01622         // Set the decompression destination to the offscreen GWorld.
01623         if (err_s = vdgSetDestination(vid->pVdg, vid->pGWorld)) {
01624                 fprintf(stderr, "ar2VideoOpen(): vdgSetDestination err=%d\n", err_s);
01625                 goto out6;      
01626         }
01627         
01628         // Initialise per-vid pthread variables.
01629         // Create a mutex to protect access to data structures.
01630         if ((err_i = pthread_mutex_init(&(vid->bufMutex), NULL)) != 0) {
01631                 fprintf(stderr, "ar2VideoOpen(): Error %d creating mutex.\n", err_i);
01632         }
01633         // Create condition variable.
01634         if (err_i == 0) {
01635                 if ((err_i = pthread_cond_init(&(vid->condition), NULL)) != 0) {
01636                         fprintf(stderr, "ar2VideoOpen(): Error %d creating condition variable.\n", err_i);
01637                         pthread_mutex_destroy(&(vid->bufMutex));
01638                 }
01639         }
01640                 
01641         if (err_i != 0) { // Clean up component on failure to init per-vid pthread variables.
01642                 goto out6;
01643         }
01644 
01645         goto out;
01646         
01647 out6:
01648         DisposeGWorld(vid->pGWorld);
01649 out5:
01650         if (vid->bufCopyFlag) {
01651                 free(vid->bufPixelsCopy2);
01652                 free(vid->bufPixelsCopy1);
01653         }
01654         free(vid->bufPixels);
01655         if (vid->scaleMatrixPtr) free(vid->scaleMatrixPtr);
01656 out3:
01657         DisposeHandle((Handle)vid->vdImageDesc);
01658 out2:   
01659         vdgReleaseAndDealloc(vid->pVdg);
01660 out1:   
01661         free(vid);
01662         vid = NULL;
01663         gVidCount--;
01664 out:
01665 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01666         // Release our hold on the QuickTime toolbox.
01667         if (weLocked) {
01668                 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01669                         fprintf(stderr, "ar2VideoOpen(): Unable to unlock mutex (for QuickTime).\n");
01670                         return (NULL);
01671                 }
01672         }
01673 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01674         
01675         return (vid);
01676 }
01677 
01678 int ar2VideoClose(AR2VideoParamT *vid)
01679 {
01680         int err_i;
01681 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01682         int weLocked = 0;
01683 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01684         
01685 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01686         // Get a hold on the QuickTime toolbox.
01687         if (gVidCount > 1) {
01688                 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01689                         fprintf(stderr, "ar2VideoClose(): Unable to lock mutex (for QuickTime).\n");
01690                 }
01691                 weLocked = 1;
01692         }
01693 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01694         
01695         // Destroy the condition variable.
01696         if ((err_i = pthread_cond_destroy(&(vid->condition))) != 0) {
01697                 fprintf(stderr, "ar2VideoClose(): Error %d destroying condition variable.\n", err_i);
01698         }
01699         
01700         // Destroy the mutex.
01701         if ((err_i = pthread_mutex_destroy(&(vid->bufMutex))) != 0) {
01702                 fprintf(stderr, "ar2VideoClose(): Error %d destroying mutex.\n", err_i);
01703         }
01704             
01705     if (vid->pGWorld != NULL) {
01706         DisposeGWorld(vid->pGWorld);
01707         vid->pGWorld = NULL;
01708     }
01709         
01710         if (vid->bufCopyFlag) {
01711                 if (vid->bufPixelsCopy2) {
01712                         free(vid->bufPixelsCopy2);
01713                         vid->bufPixelsCopy2 = NULL;
01714                 }
01715                 if (vid->bufPixelsCopy1) {
01716                         free(vid->bufPixelsCopy1);
01717                         vid->bufPixelsCopy1 = NULL;
01718                 }
01719         }
01720         if (vid->bufPixels) {
01721                 free(vid->bufPixels);
01722                 vid->bufPixels = NULL;
01723         }
01724         
01725         if (vid->scaleMatrixPtr) {
01726                 free(vid->scaleMatrixPtr);
01727                 vid->scaleMatrixPtr = NULL;
01728         }
01729         
01730         if (vid->vdImageDesc) {
01731                 DisposeHandle((Handle)vid->vdImageDesc);
01732                 vid->vdImageDesc = NULL;
01733         }
01734         
01735         vdgReleaseAndDealloc(vid->pVdg);
01736         
01737 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01738         // Release our hold on the QuickTime toolbox.
01739         if (weLocked) {
01740                 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01741                         fprintf(stderr, "ar2VideoClose(): Unable to unlock mutex (for QuickTime).\n");
01742                 }
01743         }
01744 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01745         
01746         // Count one less grabber running.
01747         free (vid);
01748         gVidCount--;
01749 
01750         // If we're the last to close, clean up after everybody.
01751         if (!gVidCount) {
01752 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01753                 // Destroy the mutex.
01754                 if ((err_i = pthread_mutex_destroy(&gVidQuickTimeMutex)) != 0) {
01755                         fprintf(stderr, "ar2VideoClose(): Error %d destroying mutex (for QuickTime).\n", err_i);
01756                 }
01757 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01758                 
01759                 // Probably a good idea to close down QuickTime.
01760                 ExitMovies();
01761         }
01762         
01763     return (0);
01764 }
01765 
01766 int ar2VideoCapStart(AR2VideoParamT *vid)
01767 {
01768         ComponentResult err;
01769         int err_i = 0;
01770 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01771         int weLocked = 0;
01772 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01773         
01774 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01775         // Get a hold on the QuickTime toolbox.
01776         if (gVidCount > 1) {
01777                 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01778                         fprintf(stderr, "ar2VideoCapStart(): Unable to lock mutex (for QuickTime).\n");
01779                         return (1);
01780                 }
01781                 weLocked = 1;
01782         }
01783 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01784         
01785     vid->status = 0;
01786         if (!vid->pVdg->isPreflighted) {
01787                 if (err = vdgPreflightGrabbing(vid->pVdg)) {
01788                         fprintf(stderr, "ar2VideoCapStart(): vdgPreflightGrabbing err=%ld\n", err);
01789                         err_i = (int)err;
01790                 }               
01791         }
01792         
01793         if (err_i == 0) {
01794                 if (err = vdgStartGrabbing(vid->pVdg, vid->scaleMatrixPtr)) {
01795                         fprintf(stderr, "ar2VideoCapStart(): vdgStartGrabbing err=%ld\n", err);
01796                         err_i = (int)err;
01797                 }
01798         }
01799         
01800 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01801         // Release our hold on the QuickTime toolbox.
01802         if (weLocked) {
01803                 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01804                         fprintf(stderr, "ar2VideoCapStart(): Unable to unlock mutex (for QuickTime).\n");
01805                         return (1);
01806                 }
01807         }
01808 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01809         
01810         if (err_i == 0) {
01811                 // Create the new thread - no attr, vid as user data.
01812                 vid->threadRunning = 1;
01813                 if ((err_i = pthread_create(&(vid->thread), NULL, ar2VideoInternalThread, (void *)vid)) != 0) {
01814                         vid->threadRunning = 0;
01815                         fprintf(stderr, "ar2VideoCapStart(): Error %d detaching thread.\n", err_i);
01816                 }
01817         }
01818 
01819         return (err_i);
01820 }
01821 
01822 int ar2VideoCapNext(AR2VideoParamT *vid)
01823 {
01824         return (0);
01825 }
01826 
01827 int ar2VideoCapStop(AR2VideoParamT *vid)
01828 {
01829         int err_i = 0;
01830 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01831         int weLocked = 0;
01832 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01833         void *exit_status_p; // Pointer to return value from thread, will be filled in by pthread_join().
01834         ComponentResult err = noErr;
01835         
01836         if (vid->threadRunning) {
01837                 // Cancel thread.
01838                 if ((err_i = pthread_cancel(vid->thread)) != 0) {
01839                         fprintf(stderr, "ar2VideoCapStop(): Error %d cancelling ar2VideoInternalThread().\n", err_i);
01840                         return (err_i);
01841                 }
01842                 
01843                 // Wait for join.
01844                 if ((err_i = pthread_join(vid->thread, &exit_status_p)) != 0) {
01845                         fprintf(stderr, "ar2VideoCapStop(): Error %d waiting for ar2VideoInternalThread() to finish.\n", err_i);
01846                         return (err_i);
01847                 }
01848                 vid->threadRunning = 0;
01849                 vid->thread = NULL;
01850                 
01851                 // Exit status is ((exit_status_p == AR_PTHREAD_CANCELLED) ? 0 : *(ERROR_t *)(exit_status_p))
01852         }
01853         
01854     if (vid->pVdg) {
01855                 
01856 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01857                 // Get a hold on the QuickTime toolbox.
01858                 if (gVidCount > 1) {
01859                         if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01860                                 fprintf(stderr, "ar2VideoCapStop(): Unable to lock mutex (for QuickTime).\n");
01861                                 return (1);
01862                         }
01863                         weLocked = 1;
01864                 }
01865 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01866                 
01867                 if ((err = vdgStopGrabbing(vid->pVdg)) != noErr) {
01868                         fprintf(stderr, "vdgStopGrabbing err=%ld\n", err);
01869                         err_i = (int)err;
01870                 }
01871                 vid->status = 0;
01872                 vid->pVdg->isPreflighted = 0;
01873 
01874 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01875                 // Release our hold on the QuickTime toolbox.
01876                 if (weLocked) {
01877                         if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01878                                 fprintf(stderr, "ar2VideoCapStop(): Unable to unlock mutex (for QuickTime).\n");
01879                                 return (1);
01880                         }
01881                 }
01882 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01883                 
01884         }
01885         
01886         return (err_i);
01887 }
01888 
01889 int ar2VideoInqSize(AR2VideoParamT *vid, int *x,int *y)
01890 {
01891         // Need lock to guarantee exclusive access to vid.
01892         if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01893                 fprintf(stderr, "ar2VideoInqSize(): Unable to lock mutex.\n");
01894                 return (1);
01895         }
01896         
01897     *x = vid->width;
01898     *y = vid->height;
01899 
01900         if (!ar2VideoInternalUnlock(&(vid->bufMutex))) {
01901                 fprintf(stderr, "ar2VideoInqSize(): Unable to unlock mutex.\n");
01902                 return (1);
01903         }
01904     return (0);
01905 }
01906 
01907 ARUint8 *ar2VideoGetImage(AR2VideoParamT *vid)
01908 {
01909         ARUint8 *pix = NULL;
01910 
01911         // ar2VideoGetImage() used to block waiting for a frame.
01912         // This locked the OpenGL frame rate to the camera frame rate.
01913         // Now, if no frame is currently available then we won't wait around for one.
01914         // So, do we have a new frame from the sequence grabber?        
01915         if (vid->status & AR_VIDEO_STATUS_BIT_READY) {
01916                 
01917                 //fprintf(stderr, "For vid @ %p got frame %ld.\n", vid, vid->frameCount);
01918                 
01919                 // Prior Mac versions of ar2VideoInternal added 1 to the pixmap base address
01920                 // returned to the caller to cope with the fact that neither
01921                 // arDetectMarker() or argDispImage() knew how to cope with
01922                 // pixel data with ARGB (Apple) or ABGR (SGI) byte ordering.
01923                 // Adding 1 had the effect of passing a pointer to the first byte
01924                 // of non-alpha data. This was an awful hack which caused all sorts
01925                 // of problems and which can now be avoided after rewriting the
01926                 // various bits of the toolkit to cope.
01927                 if (vid->bufCopyFlag) {
01928                         // Need lock to guarantee this thread exclusive access to vid.
01929                         if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01930                                 fprintf(stderr, "ar2VideoGetImage(): Unable to lock mutex.\n");
01931                                 return (NULL);
01932                         }
01933                         if (vid->status & AR_VIDEO_STATUS_BIT_BUFFER) {
01934                                 memcpy((void *)(vid->bufPixelsCopy2), (void *)(vid->bufPixels), vid->bufSize);
01935                                 pix = vid->bufPixelsCopy2;
01936                                 vid->status &= ~AR_VIDEO_STATUS_BIT_BUFFER; // Clear buffer bit.
01937                         } else {
01938                                 memcpy((void *)(vid->bufPixelsCopy1), (void *)(vid->bufPixels), vid->bufSize);
01939                                 pix = vid->bufPixelsCopy1;
01940                                 vid->status |= AR_VIDEO_STATUS_BIT_BUFFER; // Set buffer bit.
01941                         }
01942                         if (!ar2VideoInternalUnlock(&(vid->bufMutex))) {
01943                                 fprintf(stderr, "ar2VideoGetImage(): Unable to unlock mutex.\n");
01944                                 return (NULL);
01945                         }
01946                 } else {
01947                         pix = vid->bufPixels;
01948                 }
01949 
01950                 vid->status &= ~AR_VIDEO_STATUS_BIT_READY; // Clear ready bit.
01951                 
01952         }
01953         
01954         return (pix);
01955 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines


ar_recog
Author(s): Graylin Trevor Jay and Christopher Crick
autogenerated on Fri Jan 25 2013 12:15:00