00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 #ifdef __APPLE__
00083 # include <Carbon/Carbon.h>
00084 # include <QuickTime/QuickTime.h>
00085 # include <CoreServices/CoreServices.h>
00086 # include <unistd.h>
00087 # include <sys/types.h>
00088 # include <sys/sysctl.h>
00089 # include "videoInternal.h"
00090 #elif defined(_WIN32)
00091 # ifndef __MOVIES__
00092 # include <Movies.h>
00093 # endif
00094 # ifndef __QTML__
00095 # include <QTML.h>
00096 # endif
00097 # ifndef __GXMATH__
00098 # include <GXMath.h>
00099 # endif
00100 #else
00101 # error
00102 #endif
00103 #include <pthread.h>
00104 #include <string.h>
00105 #include <AR/config.h>
00106 #include <AR/ar.h>
00107 #include <AR/video.h>
00108
00109
00110
00111
00112 #ifdef _WIN32
00113 # define valloc malloc
00114 # define usleep(t) Sleep((DWORD)(t/1000u));
00115 #endif
00116
00117
00118
00119 #define AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MIN 20L
00120 #define AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MAX 100L
00121
00122 #define AR_VIDEO_STATUS_BIT_READY 0x01 // Clear when no new frame is ready, set when a new frame is ready.
00123 #define AR_VIDEO_STATUS_BIT_BUFFER 0x02 // Clear when buffer 1 is valid for writes, set when buffer 2 is valid for writes.
00124
00125
00126 #ifdef PTHREAD_CANCELED
00127 # define AR_PTHREAD_CANCELLED PTHREAD_CANCELED
00128 #else
00129 # define AR_PTHREAD_CANCELLED ((void *) 1);
00130 #endif
00131
00132
00133 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__)
00134 # ifndef ARVIDEO_APIENTRY
00135 # define ARVIDEO_APIENTRY __cdecl
00136 # endif
00137 #elif defined(__CYGWIN__) || defined(__MINGW32__)
00138 # ifndef ARVIDEO_APIENTRY
00139 # define ARVIDEO_APIENTRY __attribute__ ((__cdecl__))
00140 # endif
00141 #else // non-Win32 case.
00142 # ifndef ARVIDEO_APIENTRY
00143 # define ARVIDEO_APIENTRY
00144 # endif
00145 #endif
00146
00147
00148
00149
00150
00151 struct _VdigGrab
00152 {
00153
00154 int isPreflighted;
00155 int isGrabbing;
00156 int isRecording;
00157
00158
00159 SeqGrabComponent seqGrab;
00160 SGChannel sgchanVideo;
00161 ComponentInstance vdCompInst;
00162
00163
00164 ImageDescriptionHandle vdImageDesc;
00165 Rect vdDigitizerRect;
00166
00167
00168 CGrafPtr dstPort;
00169 ImageSequence dstImageSeq;
00170
00171
00172 short cpDepth;
00173 CompressorComponent cpCompressor;
00174 CodecQ cpSpatialQuality;
00175 CodecQ cpTemporalQuality;
00176 long cpKeyFrameRate;
00177 Fixed cpFrameRate;
00178 };
00179 typedef struct _VdigGrab VdigGrab;
00180 typedef struct _VdigGrab *VdigGrabRef;
00181
00182 struct _AR2VideoParamT {
00183 int width;
00184 int height;
00185 Rect theRect;
00186 GWorldPtr pGWorld;
00187 int status;
00188 int showFPS;
00189 TimeValue lastTime;
00190 long frameCount;
00191 TimeScale timeScale;
00192 pthread_t thread;
00193 pthread_mutex_t bufMutex;
00194 pthread_cond_t condition;
00195 int threadRunning;
00196 long rowBytes;
00197 long bufSize;
00198 ARUint8* bufPixels;
00199 int bufCopyFlag;
00200 ARUint8* bufPixelsCopy1;
00201 ARUint8* bufPixelsCopy2;
00202 int grabber;
00203 MatrixRecordPtr scaleMatrixPtr;
00204 VdigGrabRef pVdg;
00205 long milliSecPerTimer;
00206 long milliSecPerFrame;
00207 Fixed frameRate;
00208 long bytesPerSecond;
00209 ImageDescriptionHandle vdImageDesc;
00210 };
00211 typedef struct _AR2VideoParamT *AR2VideoParamTRef;
00212
00213
00214
00215
00216
00217 static AR2VideoParamT *gVid = NULL;
00218 static unsigned int gVidCount = 0;
00219 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
00220 static pthread_mutex_t gVidQuickTimeMutex;
00221 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
00222
00223 #pragma mark -
00224
00225
00226
00227
00228
00229
00230
00231
00232 static SeqGrabComponent MakeSequenceGrabber(WindowRef pWindow, const int grabber)
00233 {
00234 SeqGrabComponent seqGrab = NULL;
00235 ComponentResult err = noErr;
00236 ComponentDescription cDesc;
00237 long cCount;
00238 Component c;
00239 int i;
00240
00241
00242 cDesc.componentType = SeqGrabComponentType;
00243 cDesc.componentSubType = 0L;
00244 cDesc.componentManufacturer = cDesc.componentFlags = cDesc.componentFlagsMask = 0L;
00245 cCount = CountComponents(&cDesc);
00246 fprintf(stdout, "Opening sequence grabber %d of %ld.\n", grabber, cCount);
00247 c = 0;
00248 for (i = 1; (c = FindNextComponent(c, &cDesc)) != 0; i++) {
00249
00250
00251 if (i == grabber) {
00252 seqGrab = OpenComponent(c);
00253 }
00254 }
00255 if (!seqGrab) {
00256 fprintf(stderr, "MakeSequenceGrabber(): Failed to open a sequence grabber component.\n");
00257 goto endFunc;
00258 }
00259
00260
00261 if ((err = SGInitialize(seqGrab))) {
00262 fprintf(stderr, "MakeSequenceGrabber(): SGInitialize err=%ld\n", err);
00263 goto endFunc;
00264 }
00265
00266
00267 if ((err = SGSetGWorld(seqGrab, GetWindowPort(pWindow), NULL))) {
00268 fprintf(stderr, "MakeSequenceGrabber(): SGSetGWorld err=%ld\n", err);
00269 goto endFunc;
00270 }
00271
00272
00273
00274
00275
00276
00277 if ((err = SGSetDataRef(seqGrab, 0, 0, seqGrabDontMakeMovie))) {
00278 fprintf(stderr, "MakeSequenceGrabber(): SGSetDataRef err=%ld\n", err);
00279 goto endFunc;
00280 }
00281
00282 endFunc:
00283 if (err && (seqGrab != NULL)) {
00284 CloseComponent(seqGrab);
00285 seqGrab = NULL;
00286 }
00287
00288 return (seqGrab);
00289 }
00290
00291
00292
00293
00294
00295 static ComponentResult MakeSequenceGrabChannel(SeqGrabComponent seqGrab, SGChannel* psgchanVideo)
00296 {
00297 long flags = 0;
00298 ComponentResult err = noErr;
00299
00300 if ((err = SGNewChannel(seqGrab, VideoMediaType, psgchanVideo))) {
00301 if (err == couldntGetRequiredComponent) {
00302 printf("ERROR: No camera connected. Please connect a camera and re-try.\n");
00303 } else {
00304 fprintf(stderr, "MakeSequenceGrabChannel(): SGNewChannel err=%ld\n", err);
00305 }
00306 goto endFunc;
00307 }
00308
00309
00310
00311
00312 if ((err = SGSetChannelUsage(*psgchanVideo, flags | seqGrabRecord))) {
00313 fprintf(stderr, "MakeSequenceGrabChannel(): SGSetChannelUsage err=%ld\n", err);
00314 goto endFunc;
00315 }
00316
00317 endFunc:
00318 if ((err != noErr) && psgchanVideo) {
00319
00320 SGDisposeChannel(seqGrab, *psgchanVideo);
00321 *psgchanVideo = NULL;
00322 }
00323
00324 return err;
00325 }
00326
00327 static ComponentResult vdgGetSettings(VdigGrab* pVdg)
00328 {
00329 ComponentResult err;
00330
00331
00332 if (err = SGGetVideoCompressor (pVdg->sgchanVideo,
00333 &pVdg->cpDepth,
00334 &pVdg->cpCompressor,
00335 &pVdg->cpSpatialQuality,
00336 &pVdg->cpTemporalQuality,
00337 &pVdg->cpKeyFrameRate)) {
00338 fprintf(stderr, "SGGetVideoCompressor err=%ld\n", err);
00339 goto endFunc;
00340 }
00341
00342 if (err = SGGetFrameRate(pVdg->sgchanVideo, &pVdg->cpFrameRate)) {
00343 fprintf(stderr, "SGGetFrameRate err=%ld\n", err);
00344 goto endFunc;
00345 }
00346
00347
00348 if (!(pVdg->vdCompInst = SGGetVideoDigitizerComponent(pVdg->sgchanVideo))) {
00349 fprintf(stderr, "SGGetVideoDigitizerComponent error\n");
00350 goto endFunc;
00351 }
00352
00353 endFunc:
00354 return (err);
00355 }
00356
00357 #pragma mark -
00358
00359 VdigGrabRef vdgAllocAndInit(const int grabber)
00360 {
00361 VdigGrabRef pVdg = NULL;
00362 OSErr err;
00363
00364
00365 arMalloc(pVdg, VdigGrab, 1)
00366 memset(pVdg, 0, sizeof(VdigGrab));
00367
00368 if (!(pVdg->seqGrab = MakeSequenceGrabber(NULL, grabber))) {
00369 fprintf(stderr, "MakeSequenceGrabber error.\n");
00370 free(pVdg);
00371 return (NULL);
00372 }
00373
00374 if ((err = MakeSequenceGrabChannel(pVdg->seqGrab, &pVdg->sgchanVideo))) {
00375 if (err != couldntGetRequiredComponent) fprintf(stderr, "MakeSequenceGrabChannel err=%d.\n", err);
00376 free(pVdg);
00377 return (NULL);
00378 }
00379
00380 return (pVdg);
00381 }
00382
00383 static ComponentResult vdgRequestSettings(VdigGrab* pVdg, const int showDialog, const int standardDialog, const int inputIndex)
00384 {
00385 ComponentResult err;
00386
00387
00388 #ifdef __APPLE__
00389 if ((err = RequestSGSettings(inputIndex, pVdg->seqGrab, pVdg->sgchanVideo, showDialog, standardDialog) != noErr)) {
00390 fprintf(stderr, "RequestSGSettings err=%ld\n", err);
00391 goto endFunc;
00392 }
00393 #else
00394 if (showDialog) {
00395 if ((err = SGSettingsDialog(pVdg->seqGrab, pVdg->sgchanVideo, 0, 0, seqGrabSettingsPreviewOnly, NULL, 0L)) != noErr)) {
00396 fprintf(stderr, "SGSettingsDialog err=%ld\n", err);
00397 goto endFunc;
00398 }
00399 }
00400 #endif
00401
00402 if (err = vdgGetSettings(pVdg)) {
00403 fprintf(stderr, "vdgGetSettings err=%ld\n", err);
00404 goto endFunc;
00405 }
00406
00407 endFunc:
00408 return err;
00409 }
00410
00411 static VideoDigitizerError vdgGetDeviceNameAndFlags(VdigGrab* pVdg, char* szName, long* pBuffSize, UInt32* pVdFlags)
00412 {
00413 VideoDigitizerError err;
00414 Str255 vdName;
00415 UInt32 vdFlags;
00416
00417 if (!pBuffSize) {
00418 fprintf(stderr, "vdgGetDeviceName: NULL pointer error\n");
00419 err = (VideoDigitizerError)qtParamErr;
00420 goto endFunc;
00421 }
00422
00423 if (err = VDGetDeviceNameAndFlags( pVdg->vdCompInst,
00424 vdName,
00425 &vdFlags)) {
00426 fprintf(stderr, "VDGetDeviceNameAndFlags err=%ld\n", err);
00427 *pBuffSize = 0;
00428 goto endFunc;
00429 }
00430
00431 if (szName) {
00432 int copyLen = (*pBuffSize-1 < vdName[0] ? *pBuffSize-1 : vdName[0]);
00433
00434 strncpy(szName, (char *)vdName+1, copyLen);
00435 szName[copyLen] = '\0';
00436
00437 *pBuffSize = copyLen + 1;
00438 } else {
00439 *pBuffSize = vdName[0] + 1;
00440 }
00441
00442 if (pVdFlags)
00443 *pVdFlags = vdFlags;
00444
00445 endFunc:
00446 return err;
00447 }
00448
00449 static OSErr vdgSetDestination( VdigGrab* pVdg,
00450 CGrafPtr dstPort )
00451 {
00452 pVdg->dstPort = dstPort;
00453 return noErr;
00454 }
00455
00456 static VideoDigitizerError vdgPreflightGrabbing(VdigGrab* pVdg)
00457 {
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478 VideoDigitizerError err;
00479 Rect maxRect;
00480
00481 DigitizerInfo info;
00482
00483
00484 if ((err = VDGetDigitizerInfo(pVdg->vdCompInst, &info))) {
00485 fprintf(stderr, "vdgPreflightGrabbing(): VDGetDigitizerInfo err=%ld\n", err);
00486 goto endFunc;
00487 } else {
00488 if (!(info.outputCapabilityFlags & digiOutDoesCompress)) {
00489 fprintf(stderr, "vdgPreflightGrabbing(): VDGetDigitizerInfo reports device is not a compressed source.\n");
00490 err = digiUnimpErr;
00491 goto endFunc;
00492 }
00493 }
00494
00495
00496
00497
00498
00499 if ((err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureSetSettingsBegin))) {
00500 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00501
00502 }
00503
00504 if ((err = VDGetMaxSrcRect(pVdg->vdCompInst, currentIn, &maxRect))) {
00505 fprintf(stderr, "vdgPreflightGrabbing(): VDGetMaxSrcRect err=%ld (Ignored.)\n", err);
00506
00507 }
00508
00509
00510
00511
00512
00513 if (err = VDSetDigitizerRect( pVdg->vdCompInst, &maxRect)) {
00514 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetDigitizerRect err=%ld (Ignored.)\n", err);
00515
00516 }
00517
00518 if (err = VDSetCompressionOnOff( pVdg->vdCompInst, 1)) {
00519 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetCompressionOnOff err=%ld (Ignored.)\n", err);
00520
00521 }
00522
00523
00524 if (err = VDSetFrameRate(pVdg->vdCompInst, 0)) {
00525 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetFrameRate err=%ld (Ignored.)\n", err);
00526
00527 }
00528
00529
00530
00531
00532
00533
00534
00535
00536 if (err = VDSetCompression(pVdg->vdCompInst,
00537 0,
00538 0,
00539 &maxRect,
00540 0,
00541 0,
00542 0)) {
00543 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetCompression err=%ld (Ignored.)\n", err);
00544
00545 }
00546
00547 if (err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureLowLatency)) {
00548 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00549
00550 }
00551
00552
00553 if ((err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureSetSettingsEnd))) {
00554 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00555
00556 }
00557
00558 if ((err = VDResetCompressSequence( pVdg->vdCompInst))) {
00559 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDResetCompressSequence err=%ld (Ignored.)\n", err);
00560
00561 }
00562
00563 pVdg->vdImageDesc = (ImageDescriptionHandle)NewHandle(0);
00564 if ((err = VDGetImageDescription(pVdg->vdCompInst, pVdg->vdImageDesc))) {
00565 fprintf(stderr, "vdgPreflightGrabbing(): VDGetImageDescription err=%ld (Ignored.)\n", err);
00566
00567 }
00568
00569
00570 if ((err = VDGetDigitizerRect(pVdg->vdCompInst, &pVdg->vdDigitizerRect))) {
00571 fprintf(stderr, "vdgPreflightGrabbing(): VDGetDigitizerRect err=%ld (Ignored.)\n", err);
00572
00573 }
00574
00575 pVdg->isPreflighted = 1;
00576
00577 endFunc:
00578 return (err);
00579 }
00580
00581 static VideoDigitizerError vdgGetDataRate( VdigGrab* pVdg,
00582 long* pMilliSecPerFrame,
00583 Fixed* pFramesPerSecond,
00584 long* pBytesPerSecond)
00585 {
00586 VideoDigitizerError err;
00587
00588 if (err = VDGetDataRate( pVdg->vdCompInst,
00589 pMilliSecPerFrame,
00590 pFramesPerSecond,
00591 pBytesPerSecond)) {
00592 fprintf(stderr, "vdgGetDataRate(): VDGetDataRate err=%ld\n", err);
00593 goto endFunc;
00594 }
00595
00596 endFunc:
00597 return (err);
00598 }
00599
00600 static VideoDigitizerError vdgGetImageDescription( VdigGrab* pVdg,
00601 ImageDescriptionHandle vdImageDesc )
00602 {
00603 VideoDigitizerError err;
00604
00605 if (err = VDGetImageDescription( pVdg->vdCompInst, vdImageDesc))
00606 {
00607 fprintf(stderr, "VDGetImageDescription err=%ld\n", err);
00608 goto endFunc;
00609 }
00610
00611 endFunc:
00612 return err;
00613 }
00614
00615 static OSErr vdgDecompressionSequenceBegin( VdigGrab* pVdg,
00616 CGrafPtr dstPort,
00617 Rect* pDstRect,
00618 MatrixRecord* pDstScaleMatrix )
00619 {
00620 OSErr err;
00621
00622
00623
00624
00625
00626
00627 if ((*pVdg->vdImageDesc)->cType == FOUR_CHAR_CODE('yuv2'))
00628 (*pVdg->vdImageDesc)->cType = FOUR_CHAR_CODE('yuvu');
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641 if (err = DecompressSequenceBeginS( &pVdg->dstImageSeq,
00642 pVdg->vdImageDesc,
00643 0,
00644 0,
00645 dstPort,
00646 NULL,
00647 NULL,
00648 pDstScaleMatrix,
00649 srcCopy,
00650 (RgnHandle)NULL,
00651 0L,
00652 codecHighQuality,
00653 bestSpeedCodec))
00654 {
00655 fprintf(stderr, "DecompressSequenceBeginS err=%d\n", err);
00656 goto endFunc;
00657 }
00658
00659 endFunc:
00660 return err;
00661 }
00662
00663 static OSErr vdgDecompressionSequenceWhen( VdigGrab* pVdg,
00664 Ptr theData,
00665 long dataSize)
00666 {
00667 OSErr err;
00668 CodecFlags ignore = 0;
00669
00670 if(err = DecompressSequenceFrameWhen( pVdg->dstImageSeq,
00671 theData,
00672 dataSize,
00673 0,
00674 &ignore,
00675 NULL,
00676 NULL ))
00677 {
00678 fprintf(stderr, "DecompressSequenceFrameWhen err=%d\n", err);
00679 goto endFunc;
00680 }
00681
00682 endFunc:
00683 return err;
00684 }
00685
00686 static OSErr vdgDecompressionSequenceEnd( VdigGrab* pVdg )
00687 {
00688 OSErr err;
00689
00690 if (!pVdg->dstImageSeq)
00691 {
00692 fprintf(stderr, "vdgDestroyDecompressionSequence NULL sequence\n");
00693 err = qtParamErr;
00694 goto endFunc;
00695 }
00696
00697 if (err = CDSequenceEnd(pVdg->dstImageSeq))
00698 {
00699 fprintf(stderr, "CDSequenceEnd err=%d\n", err);
00700 goto endFunc;
00701 }
00702
00703 pVdg->dstImageSeq = 0;
00704
00705 endFunc:
00706 return err;
00707 }
00708
00709 static VideoDigitizerError vdgStartGrabbing(VdigGrab* pVdg, MatrixRecord* pDstScaleMatrix)
00710 {
00711 VideoDigitizerError err;
00712
00713 if (!pVdg->isPreflighted)
00714 {
00715 fprintf(stderr, "vdgStartGrabbing called without previous successful vdgPreflightGrabbing()\n");
00716 err = (VideoDigitizerError)badCallOrderErr;
00717 goto endFunc;
00718 }
00719
00720 if (err = VDCompressOneFrameAsync( pVdg->vdCompInst ))
00721 {
00722 fprintf(stderr, "VDCompressOneFrameAsync err=%ld\n", err);
00723 goto endFunc;
00724 }
00725
00726 if (err = vdgDecompressionSequenceBegin( pVdg, pVdg->dstPort, NULL, pDstScaleMatrix ))
00727 {
00728 fprintf(stderr, "vdgDecompressionSequenceBegin err=%ld\n", err);
00729 goto endFunc;
00730 }
00731
00732 pVdg->isGrabbing = 1;
00733
00734 endFunc:
00735 return err;
00736 }
00737
00738 static VideoDigitizerError vdgStopGrabbing(VdigGrab* pVdg)
00739 {
00740 VideoDigitizerError err;
00741
00742 if (err = VDSetCompressionOnOff( pVdg->vdCompInst, 0))
00743 {
00744 fprintf(stderr, "VDSetCompressionOnOff err=%ld\n", err);
00745
00746 }
00747
00748 if (err = (VideoDigitizerError)vdgDecompressionSequenceEnd(pVdg))
00749 {
00750 fprintf(stderr, "vdgDecompressionSequenceEnd err=%ld\n", err);
00751
00752 }
00753
00754 pVdg->isGrabbing = 0;
00755
00756
00757 return err;
00758 }
00759
00760 static bool vdgIsGrabbing(VdigGrab* pVdg)
00761 {
00762 return pVdg->isGrabbing;
00763 }
00764
00765 static VideoDigitizerError vdgPoll( VdigGrab* pVdg,
00766 UInt8* pQueuedFrameCount,
00767 Ptr* pTheData,
00768 long* pDataSize,
00769 UInt8* pSimilarity,
00770 TimeRecord* pTime )
00771 {
00772 VideoDigitizerError err;
00773
00774 if (!pVdg->isGrabbing)
00775 {
00776 fprintf(stderr, "vdgGetFrame error: not grabbing\n");
00777 err = (VideoDigitizerError)qtParamErr;
00778 goto endFunc;
00779 }
00780
00781 if (err = VDCompressDone( pVdg->vdCompInst,
00782 pQueuedFrameCount,
00783 pTheData,
00784 pDataSize,
00785 pSimilarity,
00786 pTime ))
00787 {
00788 fprintf(stderr, "VDCompressDone err=%ld\n", err);
00789 goto endFunc;
00790 }
00791
00792
00793 if (*pQueuedFrameCount)
00794 {
00795 if (err = VDCompressOneFrameAsync(pVdg->vdCompInst))
00796 {
00797 fprintf(stderr, "VDCompressOneFrameAsync err=%ld\n", err);
00798 goto endFunc;
00799 }
00800 }
00801
00802 endFunc:
00803 return err;
00804 }
00805
00806 static VideoDigitizerError vdgReleaseBuffer(VdigGrab* pVdg, Ptr theData)
00807 {
00808 VideoDigitizerError err;
00809
00810 if (err = VDReleaseCompressBuffer(pVdg->vdCompInst, theData))
00811 {
00812 fprintf(stderr, "VDReleaseCompressBuffer err=%ld\n", err);
00813 goto endFunc;
00814 }
00815
00816 endFunc:
00817 return err;
00818 }
00819
00820 static VideoDigitizerError vdgIdle(VdigGrab* pVdg, int* pIsUpdated)
00821 {
00822 VideoDigitizerError err;
00823
00824 UInt8 queuedFrameCount;
00825 Ptr theData;
00826 long dataSize;
00827 UInt8 similarity;
00828 TimeRecord time;
00829
00830 *pIsUpdated = 0;
00831
00832
00833 if ( !(err = vdgPoll( pVdg,
00834 &queuedFrameCount,
00835 &theData,
00836 &dataSize,
00837 &similarity,
00838 &time))
00839 && queuedFrameCount)
00840 {
00841 *pIsUpdated = 1;
00842
00843
00844 if (err = (VideoDigitizerError)vdgDecompressionSequenceWhen( pVdg,
00845 theData,
00846 dataSize))
00847 {
00848 fprintf(stderr, "vdgDecompressionSequenceWhen err=%ld\n", err);
00849
00850 }
00851
00852
00853 if(err = vdgReleaseBuffer(pVdg, theData))
00854 {
00855 fprintf(stderr, "vdgReleaseBuffer err=%ld\n", err);
00856
00857 }
00858 }
00859
00860 if (err)
00861 {
00862 fprintf(stderr, "vdgPoll err=%ld\n", err);
00863 goto endFunc;
00864 }
00865
00866 endFunc:
00867 return err;
00868 }
00869
00870 static ComponentResult vdgReleaseAndDealloc(VdigGrab* pVdg)
00871 {
00872 ComponentResult err = noErr;
00873
00874 if (pVdg->vdImageDesc) {
00875 DisposeHandle((Handle)pVdg->vdImageDesc);
00876 pVdg->vdImageDesc = NULL;
00877 }
00878
00879 if (pVdg->vdCompInst) {
00880 if (err = CloseComponent(pVdg->vdCompInst))
00881 fprintf(stderr, "CloseComponent err=%ld\n", err);
00882 pVdg->vdCompInst = NULL;
00883 }
00884
00885 if (pVdg->sgchanVideo) {
00886 if (err = SGDisposeChannel(pVdg->seqGrab, pVdg->sgchanVideo))
00887 fprintf(stderr, "SGDisposeChannel err=%ld\n", err);
00888 pVdg->sgchanVideo = NULL;
00889 }
00890
00891 if (pVdg->seqGrab) {
00892 if (err = CloseComponent(pVdg->seqGrab))
00893 fprintf(stderr, "CloseComponent err=%ld\n", err);
00894 pVdg->seqGrab = NULL;
00895 }
00896
00897 if (pVdg) {
00898 free(pVdg);
00899 pVdg = NULL;
00900 }
00901
00902 return err;
00903 }
00904
00905 #pragma mark -
00906
00907
00908 int arVideoDispOption(void)
00909 {
00910 return (ar2VideoDispOption());
00911 }
00912
00913 int arVideoOpen(char *config)
00914 {
00915 if (gVid != NULL) {
00916 fprintf(stderr, "arVideoOpen(): Error, device is already open.\n");
00917 return (-1);
00918 }
00919 gVid = ar2VideoOpen(config);
00920 if (gVid == NULL) return (-1);
00921
00922 return (0);
00923 }
00924
00925 int arVideoClose(void)
00926 {
00927 int result;
00928
00929 if (gVid == NULL) return (-1);
00930
00931 result = ar2VideoClose(gVid);
00932 gVid = NULL;
00933 return (result);
00934 }
00935
00936 int arVideoInqSize(int *x, int *y)
00937 {
00938 if (gVid == NULL) return (-1);
00939
00940 return (ar2VideoInqSize(gVid, x, y));
00941 }
00942
00943 ARUint8 *arVideoGetImage(void)
00944 {
00945 if (gVid == NULL) return (NULL);
00946
00947 return (ar2VideoGetImage(gVid));
00948 }
00949
00950 int arVideoCapStart(void)
00951 {
00952 if (gVid == NULL) return (-1);
00953
00954 return (ar2VideoCapStart(gVid));
00955 }
00956
00957 int arVideoCapStop(void)
00958 {
00959 if (gVid == NULL) return (-1);
00960
00961 return (ar2VideoCapStop(gVid));
00962 }
00963
00964 int arVideoCapNext(void)
00965 {
00966 if (gVid == NULL) return (-1);
00967
00968 return (ar2VideoCapNext(gVid));
00969 }
00970
00971 #pragma mark -
00972 static int ar2VideoInternalLock(pthread_mutex_t *mutex)
00973 {
00974 int err;
00975
00976
00977 if ((err = pthread_mutex_lock(mutex)) != 0) {
00978 perror("ar2VideoInternalLock(): Error locking mutex");
00979 return (0);
00980 }
00981 return (1);
00982 }
00983
00984 #if 0
00985 static int ar2VideoInternalTryLock(pthread_mutex_t *mutex)
00986 {
00987 int err;
00988
00989
00990 if ((err = pthread_mutex_trylock(mutex)) != 0) {
00991 if (err == EBUSY) return (-1);
00992 perror("ar2VideoInternalTryLock(): Error locking mutex");
00993 return (0);
00994 }
00995 return (1);
00996 }
00997 #endif
00998
00999 static int ar2VideoInternalUnlock(pthread_mutex_t *mutex)
01000 {
01001 int err;
01002
01003
01004 if ((err = pthread_mutex_unlock(mutex)) != 0) {
01005 perror("ar2VideoInternalUnlock(): Error unlocking mutex");
01006 return (0);
01007 }
01008 return (1);
01009 }
01010
01011 static void ARVIDEO_APIENTRY ar2VideoInternalThreadCleanup(void *arg)
01012 {
01013 AR2VideoParamT *vid;
01014
01015 vid = (AR2VideoParamT *)arg;
01016 ar2VideoInternalUnlock(&(vid->bufMutex));
01017 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01018 ExitMoviesOnThread();
01019 #else
01020 ar2VideoInternalUnlock(&gVidQuickTimeMutex);
01021 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
01022 }
01023
01024
01025
01026
01027
01028
01029 static void *ar2VideoInternalThread(void *arg)
01030 {
01031 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01032 OSErr err_o;
01033 #else
01034 int weLocked = 0;
01035 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
01036 AR2VideoParamT *vid;
01037 int keepAlive = 1;
01038
01039 ComponentResult err;
01040 int isUpdated = 0;
01041
01042
01043 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01044
01045 if ((err_o = EnterMoviesOnThread(0)) != noErr) {
01046 fprintf(stderr, "ar2VideoInternalThread(): Error %d initing QuickTime for this thread.\n", err_o);
01047 return (NULL);
01048 }
01049 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
01050
01051
01052 pthread_cleanup_push(ar2VideoInternalThreadCleanup, arg);
01053
01054 vid = (AR2VideoParamT *)arg;
01055
01056
01057
01058
01059
01060 if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01061 fprintf(stderr, "ar2VideoInternalThread(): Unable to lock mutex, exiting.\n");
01062 keepAlive = 0;
01063 }
01064
01065 while (keepAlive && vdgIsGrabbing(vid->pVdg)) {
01066
01067 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01068
01069 if (gVidCount > 1) {
01070 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01071 fprintf(stderr, "ar2VideoInternalThread(): Unable to lock mutex (for QuickTime), exiting.\n");
01072 keepAlive = 0;
01073 break;
01074 }
01075 weLocked = 1;
01076 }
01077 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01078
01079 if ((err = vdgIdle(vid->pVdg, &isUpdated)) != noErr) {
01080
01081
01082
01083
01084
01085
01086 fprintf(stderr, "vdgIdle err=%ld.\n", err);
01087 keepAlive = 0;
01088 break;
01089 }
01090
01091 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01092
01093 if (weLocked) {
01094 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01095 fprintf(stderr, "ar2VideoInternalThread(): Unable to unlock mutex (for QuickTime), exiting.\n");
01096 keepAlive = 0;
01097 break;
01098 }
01099 weLocked = 0;
01100 }
01101 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01102
01103 if (isUpdated) {
01104
01105 if (vid->showFPS) {
01106
01107
01108
01109
01110 char status[64];
01111
01112
01113
01114
01115
01116
01117
01118
01119 vid->frameCount++;
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131 sprintf(status, "frame: %ld", vid->frameCount);
01132 #if 0
01133 Str255 theString;
01134 CGrafPtr theSavedPort;
01135 GDHandle theSavedDevice;
01136 GetGWorld(&theSavedPort, &theSavedDevice);
01137 SetGWorld(vid->pGWorld, NULL);
01138 TextSize(12);
01139 TextMode(srcCopy);
01140 MoveTo(vid->theRect.left + 10, vid->theRect.bottom - 14);
01141 CopyCStringToPascal(status, theString);
01142 DrawString(theString);
01143 SetGWorld(theSavedPort, theSavedDevice);
01144 #else
01145 CGContextRef ctx;
01146 QDBeginCGContext(vid->pGWorld, &ctx);
01147 CFStringRef str = CFStringCreateWithCString(NULL, status, kCFStringEncodingMacRoman);
01148 CGContextSelectFont(ctx, "Monaco", 12, kCGEncodingMacRoman);
01149 CGContextSetTextDrawingMode(ctx, kCGTextFillStroke);
01150 CGContextShowTextAtPoint(ctx, 10, 10, status, strlen(status));
01151 CFRelease(str);
01152 QDEndCGContext(vid->pGWorld, &ctx);
01153 #endif
01154
01155 }
01156
01157 vid->status |= AR_VIDEO_STATUS_BIT_READY;
01158 }
01159
01160
01161 ar2VideoInternalUnlock(&(vid->bufMutex));
01162 usleep(vid->milliSecPerTimer * 1000);
01163 if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01164 fprintf(stderr, "ar2VideoInternalThread(): Unable to lock mutex, exiting.\n");
01165 keepAlive = 0;
01166 break;
01167 }
01168
01169 pthread_testcancel();
01170 }
01171
01172 pthread_cleanup_pop(1);
01173 return (NULL);
01174 }
01175
01176 #ifdef __APPLE__
01177 static int sysctlbyname_with_pid (const char *name, pid_t pid,
01178 void *oldp, size_t *oldlenp,
01179 void *newp, size_t newlen)
01180 {
01181 if (pid == 0) {
01182 if (sysctlbyname(name, oldp, oldlenp, newp, newlen) == -1) {
01183 fprintf(stderr, "sysctlbyname_with_pid(0): sysctlbyname failed:"
01184 "%s\n", strerror(errno));
01185 return -1;
01186 }
01187 } else {
01188 int mib[CTL_MAXNAME];
01189 size_t len = CTL_MAXNAME;
01190 if (sysctlnametomib(name, mib, &len) == -1) {
01191 fprintf(stderr, "sysctlbyname_with_pid: sysctlnametomib failed:"
01192 "%s\n", strerror(errno));
01193 return -1;
01194 }
01195 mib[len] = pid;
01196 len++;
01197 if (sysctl(mib, len, oldp, oldlenp, newp, newlen) == -1) {
01198 fprintf(stderr, "sysctlbyname_with_pid: sysctl failed:"
01199 "%s\n", strerror(errno));
01200 return -1;
01201 }
01202 }
01203 return 0;
01204 }
01205
01206
01207 static int is_pid_native (pid_t pid)
01208 {
01209 int ret = 0;
01210 size_t sz = sizeof(ret);
01211 if (sysctlbyname_with_pid("sysctl.proc_native", pid,
01212 &ret, &sz, NULL, 0) == -1) {
01213 if (errno == ENOENT) {
01214
01215
01216 return 1;
01217 }
01218 fprintf(stderr, "is_pid_native: sysctlbyname_with_pid failed:"
01219 "%s\n", strerror(errno));
01220 return -1;
01221 }
01222 return ret;
01223 }
01224 #endif // __APPLE__
01225
01226 #pragma mark -
01227
01228 int ar2VideoDispOption(void)
01229 {
01230
01231
01232 printf("ARVideo may be configured using one or more of the following options,\n");
01233 printf("separated by a space:\n\n");
01234 printf(" -nodialog\n");
01235 printf(" Don't display video settings dialog.\n");
01236 printf(" -width=w\n");
01237 printf(" Scale camera native image to width w.\n");
01238 printf(" -height=h\n");
01239 printf(" Scale camera native image to height h.\n");
01240 printf(" -fps\n");
01241 printf(" Overlay camera frame counter on image.\n");
01242 printf(" -grabber=n\n");
01243 printf(" With multiple QuickTime video grabber components installed,\n");
01244 printf(" use component n (default n=1).\n");
01245 printf(" N.B. It is NOT necessary to use this option if you have installed\n");
01246 printf(" more than one video input device (e.g. two cameras) as the default\n");
01247 printf(" QuickTime grabber can manage multiple video channels.\n");
01248 printf(" -pixelformat=cccc\n");
01249 printf(" Return images with pixels in format cccc, where cccc is either a\n");
01250 printf(" numeric pixel format number or a valid 4-character-code for a\n");
01251 printf(" pixel format.\n");
01252 printf(" The following numeric values are supported: \n");
01253 printf(" 24 (24-bit RGB), 32 (32-bit ARGB), 40 (8-bit grey)");
01254 printf(" The following 4-character-codes are supported: \n");
01255 printf(" BGRA, RGBA, ABGR, 24BG, 2vuy, yuvs.\n");
01256 printf(" (See http://developer.apple.com/quicktime/icefloe/dispatch020.html.)\n");
01257 printf(" -fliph\n");
01258 printf(" Flip camera image horizontally.\n");
01259 printf(" -flipv\n");
01260 printf(" Flip camera image vertically.\n");
01261 printf(" -singlebuffer\n");
01262 printf(" Use single buffering of captured video instead of triple-buffering.\n");
01263 printf("\n");
01264
01265 return (0);
01266 }
01267
01268
01269 AR2VideoParamT *ar2VideoOpen(char *config_in)
01270 {
01271 long qtVersion = 0L;
01272 int width = 0;
01273 int height = 0;
01274 int grabber = 1;
01275 int showFPS = 0;
01276 int showDialog = 1;
01277 int standardDialog = 0;
01278 int singleBuffer = 0;
01279 int flipH = 0, flipV = 0;
01280 OSErr err_s = noErr;
01281 ComponentResult err = noErr;
01282 int err_i = 0;
01283 AR2VideoParamT *vid = NULL;
01284 char *config, *a, line[256];
01285 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01286 int weLocked = 0;
01287 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01288 OSType pixFormat = (OSType)0;
01289 long bytesPerPixel;
01290 long cpuType;
01291
01292
01293 if (!config_in || !(config_in[0])) {
01294
01295 char *envconf = getenv ("ARTOOLKIT_CONFIG");
01296 if (envconf && envconf[0]) {
01297 config = envconf;
01298 printf ("Using video config from environment \"%s\".\n", envconf);
01299 } else {
01300 config = NULL;
01301 printf ("Using default video config.\n");
01302 }
01303 } else {
01304 config = config_in;
01305 printf ("Using supplied video config \"%s\".\n", config_in);
01306 }
01307
01308
01309 a = config;
01310 if (a) {
01311 err_i = 0;
01312 for (;;) {
01313 while (*a == ' ' || *a == '\t') a++;
01314 if (*a == '\0') break;
01315
01316 if (strncmp(a, "-width=", 7) == 0) {
01317 sscanf(a, "%s", line);
01318 if (strlen(line) <= 7 || sscanf(&line[7], "%d", &width) == 0) err_i = 1;
01319 } else if (strncmp(a, "-height=", 8) == 0) {
01320 sscanf(a, "%s", line);
01321 if (strlen(line) <= 8 || sscanf(&line[8], "%d", &height) == 0) err_i = 1;
01322 } else if (strncmp(a, "-grabber=", 9) == 0) {
01323 sscanf(a, "%s", line);
01324 if (strlen(line) <= 9 || sscanf(&line[9], "%d", &grabber) == 0) err_i = 1;
01325 } else if (strncmp(a, "-pixelformat=", 13) == 0) {
01326 sscanf(a, "%s", line);
01327 if (strlen(line) <= 13) err_i = 1;
01328 else {
01329 #ifdef AR_BIG_ENDIAN
01330 if (strlen(line) == 17) err_i = (sscanf(&line[13], "%4c", (char *)&pixFormat) < 1);
01331 #else
01332 if (strlen(line) == 17) err_i = (sscanf(&line[13], "%c%c%c%c", &(((char *)&pixFormat)[3]), &(((char *)&pixFormat)[2]), &(((char *)&pixFormat)[1]), &(((char *)&pixFormat)[0])) < 1);
01333 #endif
01334 else err_i = (sscanf(&line[13], "%li", (long *)&pixFormat) < 1);
01335 }
01336 } else if (strncmp(a, "-fps", 4) == 0) {
01337 showFPS = 1;
01338 } else if (strncmp(a, "-nodialog", 9) == 0) {
01339 showDialog = 0;
01340 } else if (strncmp(a, "-standarddialog", 15) == 0) {
01341 standardDialog = 1;
01342 } else if (strncmp(a, "-fliph", 6) == 0) {
01343 flipH = 1;
01344 } else if (strncmp(a, "-flipv", 6) == 0) {
01345 flipV = 1;
01346 } else if (strncmp(a, "-singlebuffer", 13) == 0) {
01347 singleBuffer = 1;
01348 } else {
01349 err_i = 1;
01350 }
01351
01352 if (err_i) {
01353 ar2VideoDispOption();
01354 return (NULL);
01355 }
01356
01357 while (*a != ' ' && *a != '\t' && *a != '\0') a++;
01358 }
01359 }
01360
01361
01362 if (!pixFormat) {
01363 #if (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_2vuy)
01364 pixFormat = k2vuyPixelFormat;
01365 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_yuvs)
01366 pixFormat = kYUVSPixelFormat;
01367 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_RGB)
01368 pixFormat = k24RGBPixelFormat;
01369 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGR)
01370 pixFormat = k24BGRPixelFormat;
01371 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_ARGB)
01372 pixFormat = k32ARGBPixelFormat;
01373 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_RGBA)
01374 pixFormat = k32RGBAPixelFormat;
01375 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_ABGR)
01376 pixFormat = k32ABGRPixelFormat;
01377 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_BGRA)
01378 pixFormat = k32BGRAPixelFormat;
01379 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_MONO)
01380 pixFormat = k8IndexedGrayPixelFormat;
01381 #else
01382 # error Unsupported default pixel format specified in config.h.
01383 #endif
01384 }
01385
01386 switch (pixFormat) {
01387 case k2vuyPixelFormat:
01388 case kYUVSPixelFormat:
01389 bytesPerPixel = 2l;
01390 break;
01391 case k24RGBPixelFormat:
01392 case k24BGRPixelFormat:
01393 bytesPerPixel = 3l;
01394 break;
01395 case k32ARGBPixelFormat:
01396 case k32BGRAPixelFormat:
01397 case k32ABGRPixelFormat:
01398 case k32RGBAPixelFormat:
01399 bytesPerPixel = 4l;
01400 break;
01401 case k8IndexedGrayPixelFormat:
01402 bytesPerPixel = 1l;
01403 break;
01404 default:
01405 fprintf(stderr, "ar2VideoOpen(): Unsupported pixel format requested: 0x%08x = %u = '%c%c%c%c'.\n", (unsigned int)pixFormat, (unsigned int)pixFormat,
01406 #ifdef AR_BIG_ENDIAN
01407 ((char *)&pixFormat)[0], ((char *)&pixFormat)[1], ((char *)&pixFormat)[2], ((char *)&pixFormat)[3]
01408 #else
01409 ((char *)&pixFormat)[3], ((char *)&pixFormat)[2], ((char *)&pixFormat)[1], ((char *)&pixFormat)[0]
01410 #endif
01411 );
01412 return(NULL);
01413 break;
01414 }
01415
01416
01417 if (gVidCount == 0) {
01418
01419 #ifdef _WIN32
01420 if ((err_s = InitializeQTML(0)) != noErr) {
01421 fprintf(stderr, "ar2VideoOpen(): OS error: QuickTime not installed.\n");
01422 return (NULL);
01423 }
01424 #endif // _WIN32
01425
01426 if ((err_s = Gestalt(gestaltQuickTimeVersion, &qtVersion)) != noErr) {
01427 fprintf(stderr, "ar2VideoOpen(): OS error: QuickTime not installed (%d).\n", err_s);
01428 return (NULL);
01429 }
01430
01431 #ifndef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01432 if ((qtVersion >> 16) < 0x640) {
01433 fprintf(stderr,"ar2VideoOpen(): QuickTime version 6.4 or newer is required by this program.\n");;
01434 return (NULL);
01435 }
01436 #else
01437 if ((qtVersion >> 16) < 0x400) {
01438 fprintf(stderr,"ar2VideoOpen(): QuickTime version 4.0 or newer is required by this program.\n");;
01439 return (NULL);
01440 }
01441 #endif // !AR_VIDEO_SUPPORT_OLD_QUICKTIME
01442
01443
01444 if ((err_s = EnterMovies()) != noErr) {
01445 fprintf(stderr,"ar2VideoOpen(): Unable to initialise Carbon/QuickTime (%d).\n", err_s);
01446 return (NULL);
01447 }
01448
01449 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01450
01451 if ((err_i = pthread_mutex_init(&gVidQuickTimeMutex, NULL)) != 0) {
01452 fprintf(stderr, "ar2VideoOpen(): Error %d creating mutex (for QuickTime).\n", err_i);
01453 return (NULL);
01454 }
01455 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01456 }
01457
01458 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01459
01460
01461 if (gVidCount > 0) {
01462 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01463 fprintf(stderr, "ar2VideoOpen(): Unable to lock mutex (for QuickTime).\n");
01464 return (NULL);
01465 }
01466 weLocked = 1;
01467 }
01468 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01469
01470 gVidCount++;
01471
01472
01473 arMalloc(vid, AR2VideoParamT, 1);
01474 memset(vid, 0, sizeof(AR2VideoParamT));
01475 vid->status = 0;
01476 vid->showFPS = showFPS;
01477 vid->frameCount = 0;
01478
01479
01480 vid->grabber = grabber;
01481 vid->bufCopyFlag = !singleBuffer;
01482
01483 #ifdef __APPLE__
01484
01485 if ((err_s = Gestalt(gestaltNativeCPUtype, &cpuType) != noErr)) {
01486 fprintf(stderr, "ar2VideoOpen(): Error getting native CPU type.\n");
01487 goto out1;
01488 }
01489 if (cpuType == gestaltCPUPentium) {
01490
01491
01492 } else {
01493 int native = is_pid_native(0);
01494
01495 if (native == 0) {
01496
01497 printf("Detected Intel CPU, but running PowerPC code under Rosetta.\n");
01498 } else if (native == 1) {
01499
01500 } else {
01501
01502 }
01503 }
01504 #endif // __APPLE__
01505
01506 if(!(vid->pVdg = vdgAllocAndInit(grabber))) {
01507 fprintf(stderr, "ar2VideoOpen(): vdgAllocAndInit returned error.\n");
01508 goto out1;
01509 }
01510
01511 if (err = vdgRequestSettings(vid->pVdg, showDialog, standardDialog, gVidCount)) {
01512 fprintf(stderr, "ar2VideoOpen(): vdgRequestSettings err=%ld.\n", err);
01513 goto out2;
01514 }
01515
01516 if (err = vdgPreflightGrabbing(vid->pVdg)) {
01517 fprintf(stderr, "ar2VideoOpen(): vdgPreflightGrabbing err=%ld.\n", err);
01518 goto out2;
01519 }
01520
01521
01522
01523 if (err = vdgGetDataRate( vid->pVdg,
01524 &vid->milliSecPerFrame,
01525 &vid->frameRate,
01526 &vid->bytesPerSecond)) {
01527 fprintf(stderr, "ar2VideoOpen(): vdgGetDataRate err=%ld.\n", err);
01528
01529 }
01530 if (err == noErr) {
01531
01532 if ((vid->milliSecPerFrame == 0) && (vid->frameRate != 0)) {
01533 vid->milliSecPerFrame = (1000L << 16) / vid->frameRate;
01534 }
01535 }
01536
01537
01538 vid->milliSecPerTimer = vid->milliSecPerFrame / 2;
01539 if (vid->milliSecPerTimer <= 0) {
01540 fprintf(stderr, "vid->milliSecPerFrame: %ld ", vid->milliSecPerFrame);
01541 vid->milliSecPerTimer = AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MIN;
01542 fprintf(stderr, "forcing timer period to %ldms\n", vid->milliSecPerTimer);
01543 }
01544 if (vid->milliSecPerTimer >= AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MAX) {
01545 fprintf(stderr, "vid->milliSecPerFrame: %ld ", vid->milliSecPerFrame);
01546 vid->milliSecPerFrame = AR_VIDEO_IDLE_INTERVAL_MILLISECONDS_MAX;
01547 fprintf(stderr, "forcing timer period to %ldms\n", vid->milliSecPerTimer);
01548 }
01549
01550 vid->vdImageDesc = (ImageDescriptionHandle)NewHandle(0);
01551 if (err = vdgGetImageDescription(vid->pVdg, vid->vdImageDesc)) {
01552 fprintf(stderr, "ar2VideoOpen(): vdgGetImageDescription err=%ld\n", err);
01553 goto out3;
01554 }
01555
01556
01557 printf("Video cType is %c%c%c%c, size is %dx%d.\n",
01558 (char)(((*(vid->vdImageDesc))->cType >> 24) & 0xFF),
01559 (char)(((*(vid->vdImageDesc))->cType >> 16) & 0xFF),
01560 (char)(((*(vid->vdImageDesc))->cType >> 8) & 0xFF),
01561 (char)(((*(vid->vdImageDesc))->cType >> 0) & 0xFF),
01562 ((*vid->vdImageDesc)->width), ((*vid->vdImageDesc)->height));
01563
01564
01565
01566 vid->width = (width ? width : (int)((*vid->vdImageDesc)->width));
01567 vid->height = (height ? height : (int)((*vid->vdImageDesc)->height));
01568 MacSetRect(&(vid->theRect), 0, 0, (short)vid->width, (short)vid->height);
01569
01570
01571 vid->scaleMatrixPtr = NULL;
01572 int doSourceScale;
01573 if (vid->width != (int)((*vid->vdImageDesc)->width) || vid->height != (int)((*vid->vdImageDesc)->height)) {
01574 arMalloc(vid->scaleMatrixPtr, MatrixRecord, 1);
01575 SetIdentityMatrix(vid->scaleMatrixPtr);
01576 Fixed scaleX, scaleY;
01577 scaleX = FixRatio(vid->width, (*vid->vdImageDesc)->width);
01578 scaleY = FixRatio(vid->height, (*vid->vdImageDesc)->height);
01579 ScaleMatrix(vid->scaleMatrixPtr, scaleX, scaleY, 0, 0);
01580 fprintf(stdout, "Video will be scaled to size %dx%d.\n", vid->width, vid->height);
01581 doSourceScale = 1;
01582 } else {
01583 doSourceScale = 0;
01584 }
01585
01586
01587 if (flipH || flipV) {
01588 Fixed scaleX, scaleY;
01589 if (flipH) scaleX = -fixed1;
01590 else scaleX = fixed1;
01591 if (flipV) scaleY = -fixed1;
01592 else scaleY = fixed1;
01593 if (!doSourceScale) {
01594 arMalloc(vid->scaleMatrixPtr, MatrixRecord, 1);
01595 SetIdentityMatrix(vid->scaleMatrixPtr);
01596 }
01597 ScaleMatrix(vid->scaleMatrixPtr, scaleX, scaleY, FloatToFixed((float)(vid->width) * 0.5f), FloatToFixed((float)(vid->height) * 0.5f));
01598 }
01599
01600
01601
01602
01603
01604 vid->rowBytes = vid->width * bytesPerPixel;
01605 vid->bufSize = vid->height * vid->rowBytes;
01606 if (!(vid->bufPixels = (ARUint8 *)valloc(vid->bufSize * sizeof(ARUint8)))) exit (1);
01607 if (vid->bufCopyFlag) {
01608
01609 if (!(vid->bufPixelsCopy1 = (ARUint8 *)valloc(vid->bufSize * sizeof(ARUint8)))) exit (1);
01610 if (!(vid->bufPixelsCopy2 = (ARUint8 *)valloc(vid->bufSize * sizeof(ARUint8)))) exit (1);
01611 }
01612
01613 err_s = QTNewGWorldFromPtr(&(vid->pGWorld),
01614 pixFormat,
01615 &(vid->theRect),
01616 0,
01617 NULL,
01618 0,
01619 (void *)(vid->bufPixels),
01620 vid->rowBytes);
01621 if (err_s != noErr) {
01622 fprintf(stderr,"ar2VideoOpen(): Unable to create offscreen buffer for sequence grabbing (%d).\n", err_s);
01623 goto out5;
01624 }
01625
01626
01627
01628
01629 err_i = (int)LockPixels(GetGWorldPixMap(vid->pGWorld));
01630 if (!err_i) {
01631 fprintf(stderr,"ar2VideoOpen(): Unable to lock buffer for sequence grabbing.\n");
01632 goto out6;
01633 }
01634
01635
01636 #ifdef __APPLE__
01637 CGContextRef ctx;
01638 QDBeginCGContext(vid->pGWorld, &ctx);
01639 CGContextSetRGBFillColor(ctx, 0, 0, 0, 1);
01640 CGContextFillRect(ctx, CGRectMake(0, 0, (vid->theRect).left - (vid->theRect).right, (vid->theRect).top - (vid->theRect).bottom));
01641 CGContextFlush(ctx);
01642 QDEndCGContext (vid->pGWorld, &ctx);
01643 #else
01644 CGrafPtr theSavedPort;
01645 GDHandle theSavedDevice;
01646 GetGWorld(&theSavedPort, &theSavedDevice);
01647 SetGWorld(vid->pGWorld, NULL);
01648 BackColor(blackColor);
01649 ForeColor(whiteColor);
01650 EraseRect(&(vid->theRect));
01651 SetGWorld(theSavedPort, theSavedDevice);
01652 #endif
01653
01654
01655 if (err_s = vdgSetDestination(vid->pVdg, vid->pGWorld)) {
01656 fprintf(stderr, "ar2VideoOpen(): vdgSetDestination err=%d\n", err_s);
01657 goto out6;
01658 }
01659
01660
01661
01662 if ((err_i = pthread_mutex_init(&(vid->bufMutex), NULL)) != 0) {
01663 fprintf(stderr, "ar2VideoOpen(): Error %d creating mutex.\n", err_i);
01664 }
01665
01666 if (err_i == 0) {
01667 if ((err_i = pthread_cond_init(&(vid->condition), NULL)) != 0) {
01668 fprintf(stderr, "ar2VideoOpen(): Error %d creating condition variable.\n", err_i);
01669 pthread_mutex_destroy(&(vid->bufMutex));
01670 }
01671 }
01672
01673 if (err_i != 0) {
01674 goto out6;
01675 }
01676
01677 goto out;
01678
01679 out6:
01680 DisposeGWorld(vid->pGWorld);
01681 out5:
01682 if (vid->bufCopyFlag) {
01683 free(vid->bufPixelsCopy2);
01684 free(vid->bufPixelsCopy1);
01685 }
01686 free(vid->bufPixels);
01687 if (vid->scaleMatrixPtr) free(vid->scaleMatrixPtr);
01688 out3:
01689 DisposeHandle((Handle)vid->vdImageDesc);
01690 out2:
01691 vdgReleaseAndDealloc(vid->pVdg);
01692 out1:
01693 free(vid);
01694 vid = NULL;
01695 gVidCount--;
01696 out:
01697 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01698
01699 if (weLocked) {
01700 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01701 fprintf(stderr, "ar2VideoOpen(): Unable to unlock mutex (for QuickTime).\n");
01702 }
01703 }
01704 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01705
01706 return (vid);
01707 }
01708
01709 int ar2VideoClose(AR2VideoParamT *vid)
01710 {
01711 int err_i;
01712 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01713 int weLocked = 0;
01714 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01715
01716 if( vid == NULL ) return -1;
01717
01718 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01719
01720 if (gVidCount > 1) {
01721 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01722 fprintf(stderr, "ar2VideoClose(): Unable to lock mutex (for QuickTime).\n");
01723 }
01724 weLocked = 1;
01725 }
01726 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01727
01728
01729 if ((err_i = pthread_cond_destroy(&(vid->condition))) != 0) {
01730 fprintf(stderr, "ar2VideoClose(): Error %d destroying condition variable.\n", err_i);
01731 }
01732
01733
01734 if ((err_i = pthread_mutex_destroy(&(vid->bufMutex))) != 0) {
01735 fprintf(stderr, "ar2VideoClose(): Error %d destroying mutex.\n", err_i);
01736 }
01737
01738 if (vid->pGWorld != NULL) {
01739 DisposeGWorld(vid->pGWorld);
01740 vid->pGWorld = NULL;
01741 }
01742
01743 if (vid->bufCopyFlag) {
01744 if (vid->bufPixelsCopy2) {
01745 free(vid->bufPixelsCopy2);
01746 vid->bufPixelsCopy2 = NULL;
01747 }
01748 if (vid->bufPixelsCopy1) {
01749 free(vid->bufPixelsCopy1);
01750 vid->bufPixelsCopy1 = NULL;
01751 }
01752 }
01753 if (vid->bufPixels) {
01754 free(vid->bufPixels);
01755 vid->bufPixels = NULL;
01756 }
01757
01758 if (vid->scaleMatrixPtr) {
01759 free(vid->scaleMatrixPtr);
01760 vid->scaleMatrixPtr = NULL;
01761 }
01762
01763 if (vid->vdImageDesc) {
01764 DisposeHandle((Handle)vid->vdImageDesc);
01765 vid->vdImageDesc = NULL;
01766 }
01767
01768 vdgReleaseAndDealloc(vid->pVdg);
01769
01770 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01771
01772 if (weLocked) {
01773 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01774 fprintf(stderr, "ar2VideoClose(): Unable to unlock mutex (for QuickTime).\n");
01775 }
01776 }
01777 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01778
01779
01780 free (vid);
01781 gVidCount--;
01782
01783
01784 if (!gVidCount) {
01785 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01786
01787 if ((err_i = pthread_mutex_destroy(&gVidQuickTimeMutex)) != 0) {
01788 fprintf(stderr, "ar2VideoClose(): Error %d destroying mutex (for QuickTime).\n", err_i);
01789 }
01790 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01791
01792
01793 ExitMovies();
01794 #ifdef _WIN32
01795 TerminateQTML();
01796 #endif // _WIN32
01797 }
01798
01799 return (0);
01800 }
01801
01802 int ar2VideoCapStart(AR2VideoParamT *vid)
01803 {
01804 ComponentResult err;
01805 int err_i = 0;
01806 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01807 int weLocked = 0;
01808 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01809
01810 if( vid == NULL ) return -1;
01811
01812 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01813
01814 if (gVidCount > 1) {
01815 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01816 fprintf(stderr, "ar2VideoCapStart(): Unable to lock mutex (for QuickTime).\n");
01817 return (-1);
01818 }
01819 weLocked = 1;
01820 }
01821 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01822
01823 vid->status = 0;
01824 if (!vid->pVdg->isPreflighted) {
01825 if (err = vdgPreflightGrabbing(vid->pVdg)) {
01826 fprintf(stderr, "ar2VideoCapStart(): vdgPreflightGrabbing err=%ld\n", err);
01827 err_i = (int)err;
01828 }
01829 }
01830
01831 if (err_i == 0) {
01832 if (err = vdgStartGrabbing(vid->pVdg, vid->scaleMatrixPtr)) {
01833 fprintf(stderr, "ar2VideoCapStart(): vdgStartGrabbing err=%ld\n", err);
01834 err_i = (int)err;
01835 }
01836 }
01837
01838 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01839
01840 if (weLocked) {
01841 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01842 fprintf(stderr, "ar2VideoCapStart(): Unable to unlock mutex (for QuickTime).\n");
01843 return (-1);
01844 }
01845 }
01846 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01847
01848 if (err_i == 0) {
01849
01850 vid->threadRunning = 1;
01851 if ((err_i = pthread_create(&(vid->thread), NULL, ar2VideoInternalThread, (void *)vid)) != 0) {
01852 vid->threadRunning = 0;
01853 fprintf(stderr, "ar2VideoCapStart(): Error %d detaching thread.\n", err_i);
01854 }
01855 }
01856
01857 return (err_i);
01858 }
01859
01860 int ar2VideoCapNext(AR2VideoParamT *vid)
01861 {
01862 return (0);
01863 }
01864
01865 int ar2VideoCapStop(AR2VideoParamT *vid)
01866 {
01867 int err_i = 0;
01868 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01869 int weLocked = 0;
01870 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01871 void *exit_status_p;
01872 ComponentResult err = noErr;
01873
01874 if( vid == NULL ) return -1;
01875
01876 if (vid->threadRunning) {
01877
01878 if ((err_i = pthread_cancel(vid->thread)) != 0) {
01879 fprintf(stderr, "ar2VideoCapStop(): Error %d cancelling ar2VideoInternalThread().\n", err_i);
01880 return (err_i);
01881 }
01882
01883
01884 if ((err_i = pthread_join(vid->thread, &exit_status_p)) != 0) {
01885 fprintf(stderr, "ar2VideoCapStop(): Error %d waiting for ar2VideoInternalThread() to finish.\n", err_i);
01886 return (err_i);
01887 }
01888 vid->threadRunning = 0;
01889 vid->thread = NULL;
01890
01891
01892 }
01893
01894 if (vid->pVdg) {
01895
01896 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01897
01898 if (gVidCount > 1) {
01899 if (!ar2VideoInternalLock(&gVidQuickTimeMutex)) {
01900 fprintf(stderr, "ar2VideoCapStop(): Unable to lock mutex (for QuickTime).\n");
01901 return (-1);
01902 }
01903 weLocked = 1;
01904 }
01905 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01906
01907 if ((err = vdgStopGrabbing(vid->pVdg)) != noErr) {
01908 fprintf(stderr, "vdgStopGrabbing err=%ld\n", err);
01909 err_i = (int)err;
01910 }
01911 vid->status = 0;
01912 vid->pVdg->isPreflighted = 0;
01913
01914 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01915
01916 if (weLocked) {
01917 if (!ar2VideoInternalUnlock(&gVidQuickTimeMutex)) {
01918 fprintf(stderr, "ar2VideoCapStop(): Unable to unlock mutex (for QuickTime).\n");
01919 return (-1);
01920 }
01921 }
01922 #endif // AR_VIDEO_SUPPORT_OLD_QUICKTIME
01923
01924 }
01925
01926 return (err_i);
01927 }
01928
01929 int ar2VideoInqSize(AR2VideoParamT *vid, int *x,int *y)
01930 {
01931 if( vid == NULL ) return -1;
01932
01933
01934 if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01935 fprintf(stderr, "ar2VideoInqSize(): Unable to lock mutex.\n");
01936 return (-1);
01937 }
01938
01939 *x = vid->width;
01940 *y = vid->height;
01941
01942 if (!ar2VideoInternalUnlock(&(vid->bufMutex))) {
01943 fprintf(stderr, "ar2VideoInqSize(): Unable to unlock mutex.\n");
01944 return (-1);
01945 }
01946 return (0);
01947 }
01948
01949 ARUint8 *ar2VideoGetImage(AR2VideoParamT *vid)
01950 {
01951 ARUint8 *pix = NULL;
01952
01953 if (vid == NULL) return (NULL);
01954
01955
01956
01957
01958
01959 if (vid->status & AR_VIDEO_STATUS_BIT_READY) {
01960
01961
01962
01963 if (vid->bufCopyFlag) {
01964
01965 if (!ar2VideoInternalLock(&(vid->bufMutex))) {
01966 fprintf(stderr, "ar2VideoGetImage(): Unable to lock mutex.\n");
01967 return (NULL);
01968 }
01969 if (vid->status & AR_VIDEO_STATUS_BIT_BUFFER) {
01970 memcpy((void *)(vid->bufPixelsCopy2), (void *)(vid->bufPixels), vid->bufSize);
01971 pix = vid->bufPixelsCopy2;
01972 vid->status &= ~AR_VIDEO_STATUS_BIT_BUFFER;
01973 } else {
01974 memcpy((void *)(vid->bufPixelsCopy1), (void *)(vid->bufPixels), vid->bufSize);
01975 pix = vid->bufPixelsCopy1;
01976 vid->status |= AR_VIDEO_STATUS_BIT_BUFFER;
01977 }
01978 if (!ar2VideoInternalUnlock(&(vid->bufMutex))) {
01979 fprintf(stderr, "ar2VideoGetImage(): Unable to unlock mutex.\n");
01980 return (NULL);
01981 }
01982 } else {
01983 pix = vid->bufPixels;
01984 }
01985
01986 vid->status &= ~AR_VIDEO_STATUS_BIT_READY;
01987
01988 }
01989
01990 return (pix);
01991 }