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 #include <Carbon/Carbon.h>
00082 #include <QuickTime/QuickTime.h>
00083 #include <CoreServices/CoreServices.h>
00084 #include <pthread.h>
00085 #include <sys/time.h>
00086 #include <unistd.h>
00087 #include <sys/types.h>
00088 #include <sys/sysctl.h>
00089 #include <AR/config.h>
00090 #include <AR/ar.h>
00091 #include <AR/video.h>
00092 #include "videoInternal.h"
00093
00094
00095
00096
00097
00098
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
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
00116
00117
00118 struct _VdigGrab
00119 {
00120
00121 int isPreflighted;
00122 int isGrabbing;
00123 int isRecording;
00124
00125
00126 SeqGrabComponent seqGrab;
00127 SGChannel sgchanVideo;
00128 ComponentInstance vdCompInst;
00129
00130
00131 ImageDescriptionHandle vdImageDesc;
00132 Rect vdDigitizerRect;
00133
00134
00135 CGrafPtr dstPort;
00136 ImageSequence dstImageSeq;
00137
00138
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;
00160 pthread_mutex_t bufMutex;
00161 pthread_cond_t condition;
00162 int threadRunning;
00163 long rowBytes;
00164 long bufSize;
00165 ARUint8* bufPixels;
00166 int bufCopyFlag;
00167 ARUint8* bufPixelsCopy1;
00168 ARUint8* bufPixelsCopy2;
00169 int grabber;
00170 MatrixRecordPtr scaleMatrixPtr;
00171 VdigGrabRef pVdg;
00172 long milliSecPerTimer;
00173 long milliSecPerFrame;
00174 Fixed frameRate;
00175 long bytesPerSecond;
00176 ImageDescriptionHandle vdImageDesc;
00177 };
00178 typedef struct _AR2VideoParamT *AR2VideoParamTRef;
00179
00180
00181
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
00194
00195
00196
00197
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
00209 cDesc.componentType = SeqGrabComponentType;
00210 cDesc.componentSubType = 0L;
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
00217
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
00228 if ((err = SGInitialize(seqGrab))) {
00229 fprintf(stderr, "MakeSequenceGrabber(): SGInitialize err=%ld\n", err);
00230 goto endFunc;
00231 }
00232
00233
00234 if ((err = SGSetGWorld(seqGrab, GetWindowPort(pWindow), NULL))) {
00235 fprintf(stderr, "MakeSequenceGrabber(): SGSetGWorld err=%ld\n", err);
00236 goto endFunc;
00237 }
00238
00239
00240
00241
00242
00243
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)) {
00251 CloseComponent(seqGrab);
00252 seqGrab = NULL;
00253 }
00254
00255 return (seqGrab);
00256 }
00257
00258
00259
00260
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
00277
00278
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
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
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
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
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
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;
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
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 VideoDigitizerError err;
00437 Rect maxRect;
00438
00439 DigitizerInfo info;
00440
00441
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;
00449 goto endFunc;
00450 }
00451 }
00452
00453
00454
00455
00456
00457 if ((err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureSetSettingsBegin))) {
00458 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00459
00460 }
00461
00462 if ((err = VDGetMaxSrcRect(pVdg->vdCompInst, currentIn, &maxRect))) {
00463 fprintf(stderr, "vdgPreflightGrabbing(): VDGetMaxSrcRect err=%ld (Ignored.)\n", err);
00464
00465 }
00466
00467
00468
00469
00470
00471 if (err = VDSetDigitizerRect( pVdg->vdCompInst, &maxRect)) {
00472 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetDigitizerRect err=%ld (Ignored.)\n", err);
00473
00474 }
00475
00476 if (err = VDSetCompressionOnOff( pVdg->vdCompInst, 1)) {
00477 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetCompressionOnOff err=%ld (Ignored.)\n", err);
00478
00479 }
00480
00481
00482 if (err = VDSetFrameRate(pVdg->vdCompInst, 0)) {
00483 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetFrameRate err=%ld (Ignored.)\n", err);
00484
00485 }
00486
00487
00488
00489
00490
00491
00492
00493
00494 if (err = VDSetCompression(pVdg->vdCompInst,
00495 0,
00496 0,
00497 &maxRect,
00498 0,
00499 0,
00500 0)) {
00501 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDSetCompression err=%ld (Ignored.)\n", err);
00502
00503 }
00504
00505 if (err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureLowLatency)) {
00506 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00507
00508 }
00509
00510
00511 if ((err = VDCaptureStateChanging(pVdg->vdCompInst, vdFlagCaptureSetSettingsEnd))) {
00512 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDCaptureStateChanging err=%ld (Ignored.)\n", err);
00513
00514 }
00515
00516 if ((err = VDResetCompressSequence( pVdg->vdCompInst))) {
00517 if (err != digiUnimpErr) fprintf(stderr, "vdgPreflightGrabbing(): VDResetCompressSequence err=%ld (Ignored.)\n", err);
00518
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
00525 }
00526
00527
00528 if ((err = VDGetDigitizerRect(pVdg->vdCompInst, &pVdg->vdDigitizerRect))) {
00529 fprintf(stderr, "vdgPreflightGrabbing(): VDGetDigitizerRect err=%ld (Ignored.)\n", err);
00530
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
00581
00582
00583
00584
00585 if ((*pVdg->vdImageDesc)->cType == FOUR_CHAR_CODE('yuv2'))
00586 (*pVdg->vdImageDesc)->cType = FOUR_CHAR_CODE('yuvu');
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599 if (err = DecompressSequenceBeginS( &pVdg->dstImageSeq,
00600 pVdg->vdImageDesc,
00601 0,
00602 0,
00603 dstPort,
00604 NULL,
00605 NULL,
00606 pDstScaleMatrix,
00607 srcCopy,
00608 (RgnHandle)NULL,
00609 0L,
00610 codecHighQuality,
00611 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,
00629 theData,
00630 dataSize,
00631 0,
00632 &ignore,
00633 NULL,
00634 NULL ))
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
00704 }
00705
00706 if (err = (VideoDigitizerError)vdgDecompressionSequenceEnd(pVdg))
00707 {
00708 fprintf(stderr, "vdgDecompressionSequenceEnd err=%ld\n", err);
00709
00710 }
00711
00712 pVdg->isGrabbing = 0;
00713
00714
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
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
00791 if ( !(err = vdgPoll( pVdg,
00792 &queuedFrameCount,
00793 &theData,
00794 &dataSize,
00795 &similarity,
00796 &time))
00797 && queuedFrameCount)
00798 {
00799 *pIsUpdated = 1;
00800
00801
00802 if (err = (VideoDigitizerError)vdgDecompressionSequenceWhen( pVdg,
00803 theData,
00804 dataSize))
00805 {
00806 fprintf(stderr, "vdgDecompressionSequenceWhen err=%ld\n", err);
00807
00808 }
00809
00810
00811 if(err = vdgReleaseBuffer(pVdg, theData))
00812 {
00813 fprintf(stderr, "vdgReleaseBuffer err=%ld\n", err);
00814
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
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
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
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
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));
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
00984
00985
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;
00999 struct timespec ts;
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
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
01015 pthread_cleanup_push(ar2VideoInternalThreadCleanup, arg);
01016
01017 vid = (AR2VideoParamT *)arg;
01018
01019
01020
01021
01022
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
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
01054
01055
01056
01057
01058
01059 fprintf(stderr, "vdgIdle err=%ld.\n", err);
01060 keepAlive = 0;
01061 break;
01062 }
01063
01064 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01065
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
01078 if (vid->showFPS) {
01079
01080
01081
01082
01083 char status[64];
01084
01085
01086
01087
01088
01089
01090
01091
01092 vid->frameCount++;
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
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
01128 }
01129
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
01138 vid->status |= AR_VIDEO_STATUS_BIT_READY;
01139 }
01140
01141
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
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
01204
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
01219
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
01281 if (!config_in || !(config_in[0])) {
01282
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
01297 a = config;
01298 if (a) {
01299 err_i = 0;
01300 for (;;) {
01301 while (*a == ' ' || *a == '\t') a++;
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);
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++;
01342 }
01343 }
01344
01345
01346 if (!pixFormat) {
01347 #if (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_2vuy)
01348 pixFormat = k2vuyPixelFormat;
01349 #elif (AR_DEFAULT_PIXEL_FORMAT == AR_PIXEL_FORMAT_yuvs)
01350 pixFormat = kYUVSPixelFormat;
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
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
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
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
01430
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
01443 arMalloc(vid, AR2VideoParamT, 1);
01444 memset(vid, 0, sizeof(AR2VideoParamT));
01445 vid->status = 0;
01446 vid->showFPS = showFPS;
01447 vid->frameCount = 0;
01448
01449
01450 vid->grabber = grabber;
01451 vid->bufCopyFlag = !singleBuffer;
01452
01453
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
01460
01461 } else {
01462 int native = is_pid_native(0);
01463
01464 if (native == 0) {
01465
01466 printf("Detected Intel CPU, but running PowerPC code under Rosetta.\n");
01467 } else if (native == 1) {
01468
01469 } else {
01470
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
01490
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
01497 }
01498 if (err == noErr) {
01499
01500 if ((vid->milliSecPerFrame == 0) && (vid->frameRate != 0)) {
01501 vid->milliSecPerFrame = (1000L << 16) / vid->frameRate;
01502 }
01503 }
01504
01505
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
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
01533
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
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
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
01569
01570
01571
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
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
01581 err_s = QTNewGWorldFromPtr(&(vid->pGWorld),
01582 pixFormat,
01583 &(vid->theRect),
01584 0,
01585 NULL,
01586 0,
01587 (void *)(vid->bufPixels),
01588 vid->rowBytes);
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
01595
01596
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
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
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
01629
01630 if ((err_i = pthread_mutex_init(&(vid->bufMutex), NULL)) != 0) {
01631 fprintf(stderr, "ar2VideoOpen(): Error %d creating mutex.\n", err_i);
01632 }
01633
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) {
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
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
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
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
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
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
01747 free (vid);
01748 gVidCount--;
01749
01750
01751 if (!gVidCount) {
01752 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01753
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
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
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
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
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;
01834 ComponentResult err = noErr;
01835
01836 if (vid->threadRunning) {
01837
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
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
01852 }
01853
01854 if (vid->pVdg) {
01855
01856 #ifdef AR_VIDEO_SUPPORT_OLD_QUICKTIME
01857
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
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
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
01912
01913
01914
01915 if (vid->status & AR_VIDEO_STATUS_BIT_READY) {
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927 if (vid->bufCopyFlag) {
01928
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;
01937 } else {
01938 memcpy((void *)(vid->bufPixelsCopy1), (void *)(vid->bufPixels), vid->bufSize);
01939 pix = vid->bufPixelsCopy1;
01940 vid->status |= AR_VIDEO_STATUS_BIT_BUFFER;
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;
01951
01952 }
01953
01954 return (pix);
01955 }