-
Notifications
You must be signed in to change notification settings - Fork 3
/
listing5.html
executable file
·993 lines (823 loc) · 37.3 KB
/
listing5.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
<html>
<head>
<!-- BEGIN META TAG INFO -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="home" href="http://developer.apple.com/">
<link rel="find" href="http://developer.apple.com/search/">
<link rel="stylesheet" type="text/css" href="../../documentation/css/adcstyle.css" title="fonts">
<script language="JavaScript" src="../../documentation/js/adc.js" type="text/javascript"></script>
<!-- END META TAG INFO -->
<!-- BEGIN TITLE -->
<title>SGDataProcSample - /SonOfMungGrab.c</title>
<!-- END TITLE -->
<script language="JavaScript">
function JumpToNewPage() {
window.location=document.scpopupmenu.gotop.value;
return true;
}
</script>
</head>
<!-- BEGIN BODY OPEN -->
<body>
<!--END BODY OPEN -->
<!-- START CENTER OPEN -->
<center>
<!-- END CENTER OPEN -->
<!-- BEGIN LOGO AND SEARCH -->
<!--#include virtual="/includes/adcnavbar"-->
<!-- END LOGO AND SEARCH -->
<!-- START BREADCRUMB -->
<div id="breadcrumb">
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr>
<td scope="row"><img width="340" height="10" src="images/1dot.gif" alt=""></td>
<td><img width="340" height="10" src="images/1dot.gif" alt=""></td>
</tr>
<tr valign="middle">
<td align="left" colspan="2">
<a href="http://developer.apple.com/">ADC Home</a> > <a href="../../referencelibrary/index.html">Reference Library</a> > <a href="../../samplecode/index.html">Sample Code</a> > <a href="../../samplecode/QuickTime/index.html">QuickTime</a> > <a href="../../samplecode/QuickTime/idxCompressionDecompression-date.html">Compression & Decompression</a> > <A HREF="javascript:location.replace('index.html');">SGDataProcSample</A> >
</td>
</tr>
<tr>
<td colspan="2" scope="row"><img width="680" height="35" src="images/1dot.gif" alt=""></td>
</tr>
</table>
</div>
<!-- END BREADCRUMB -->
<!-- START MAIN CONTENT -->
<!-- START TITLE GRAPHIC AND INTRO-->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr align="left" valign="top">
<td><h1><div id="pagehead">SGDataProcSample</div></h1></td>
</tr>
</table>
<!-- END TITLE GRAPHIC AND INTRO -->
<!-- START WIDE COLUMN -->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr align="left" valign="top">
<td id="scdetails">
<h2>/SonOfMungGrab.c</h2>
<form name="scpopupmenu" onSubmit="return false;" method=post>
<p><strong>View Source Code:</strong>
<select name="gotop" onChange="JumpToNewPage();" style="width:340px"><option selected value="ingnore">Select File</option>
<option value="listing1.html">/Minimung.c</option>
<option value="listing2.html">/Minimung.r</option>
<option value="listing3.html">/Munggrab.c</option>
<option value="listing4.html">/Munggrab.r</option>
<option value="listing5.html">/SonOfMungGrab.c</option>
<option value="listing6.html">/SonOfMunggrab.r</option>
<option value="listing7.html">/SonOfMunggrabPrefix.r</option></select>
</p>
</form>
<p><strong><a href="SGDataProcSample.zip">Download Sample</a></strong> (“SGDataProcSample.zip”, 89.3K)<BR>
<strong><a href="SGDataProcSample.dmg">Download Sample</a></strong> (“SGDataProcSample.dmg”, 159.7K)</p>
<!--
<p><strong><a href="#">Download Sample</a></strong> (“filename.sit”, 500K)</p>
-->
</td>
</tr>
<tr>
<td scope="row"><img width="680" height="10" src="images/1dot.gif" alt=""><br>
<img height="1" width="680" src="images/1dot_919699.gif" alt=""><br>
<img width="680" height="20" src="images/1dot.gif" alt=""></td>
</tr>
<tr>
<td scope="row">
<!--googleon: index -->
<pre class="sourcecodebox">/* File: SonOfMunggrab.c Description: This example shows how to run the Sequence Grabber in record mode and use a DataProc to get and modify the captured data. SonOfMunggrab calculates the frame rate using the time value stamp passed to the data proc then draws this rate onto the frame. This technique provides optimal performance, far better than using preview mode or bottlenecks. This code will help a lot when capturing from DV and should allow 30fps playthrough using DV capture on a G3. SonOfMunggrab is the offspring of Munggrab written by the illustrious Kevin Marks. While the techniques presented in the original Munggrab remain the same, this sample throws Carbon Events into the fray for better performance on Mac OS X. Author: km, era Copyright: © Copyright 2000 - 2001 Apple Computer, Inc. All rights reserved. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Change History (most recent first): <3> 3/28/02 DV source rect bug fix in DataProc <2> 7/08/01 carbonized and born as SonOfMunggrab <1> 1/13/00 initial release*/// NOTE: This is a CARBON sample and uses the Carbon Event Model.// For best results use CarbonLib 1.3.1, Universal Interfaces 3.4// QuickTime 5, a DV camera of some sort and a large polo-mallet.// build for carbon#define TARGET_API_MAC_CARBON 1#if __APPLE_CC__ #include <Carbon/Carbon.h> #include <QuickTime/QuickTime.h>#else #include <ConditionalMacros.h> #include <Carbon.h> #include <QuickTimeComponents.h> #include <stdio.h>#endif// defines#define BailErr(x) {err = x; if(err != noErr) goto bail;}#define DisplayAndBail(x, y) {pMungData->err = x; if(x != noErr) { DisplayError(pMungData->pWindow, y, x); goto bail;}}// constantsconst EventTime kTimerInterval = kEventDurationSecond / 60; // idle timer interval// mung data structtypedef struct { WindowRef pWindow; // window Rect bounds; // bounds rect GWorldPtr pGWorld; // offscreen SeqGrabComponent seqGrab; // sequence grabber ImageSequence decomSeq; // unique identifier for our decompression sequence ImageSequence drawSeq; // unique identifier for our draw sequence long drawSize; TimeValue lastTime; TimeScale timeScale; long frameCount; Boolean isGrabbing; EventLoopTimerRef timerRef; OSErr err;} MungDataRecord, *MungDataPtr;// globalsstatic BitMap gScreenbits;// --------------------// Initialize for Carbon & QuickTime//void InitializeApp(void);void InitializeApp(void){ long response = 0; InitCursor(); // draw a menu bar on X so Quit will be seen OSErr err = Gestalt(gestaltMenuMgrAttr, &response); if ((err == noErr) && (response & gestaltMenuMgrAquaLayoutMask)) { Handle menuBar = GetNewMBar(128); SetMenuBar(menuBar); DrawMenuBar(); } EnterMovies(); GetQDGlobalsScreenBits(&gScreenbits);}// --------------------// InitializeMungData//MungDataPtr InitializeMungData(WindowRef inWindow, Rect inBounds, SeqGrabComponent inSeqGrab);MungDataPtr InitializeMungData(WindowRef inWindow, Rect inBounds, SeqGrabComponent inSeqGrab){ MungDataPtr pMungData = NULL; CGrafPtr theOldPort; GDHandle theOldDevice; OSErr err = noErr; // allocate memory for the data pMungData = (MungDataPtr)NewPtrClear(sizeof(MungDataRecord)); if (MemError() || NULL == pMungData ) return NULL; // create a GWorld err = QTNewGWorld(&(pMungData->pGWorld), // returned GWorld k32ARGBPixelFormat, // pixel format &inBounds, // bounds 0, // color table NULL, // GDHandle 0); // flags BailErr(err); // lock the pixmap and make sure it's locked because // we can't decompress into an unlocked PixMap if(!LockPixels(GetGWorldPixMap(pMungData->pGWorld))) goto bail; GetGWorld(&theOldPort, &theOldDevice); SetGWorld(pMungData->pGWorld, NULL); BackColor(blackColor); ForeColor(whiteColor); EraseRect(&inBounds); SetGWorld(theOldPort, theOldDevice); pMungData->pWindow = inWindow; pMungData->bounds = inBounds; pMungData->seqGrab = inSeqGrab; pMungData->isGrabbing = false; return pMungData; bail: // something's bust, clean up and get out if (pMungData) { if (pMungData->pGWorld) DisposeGWorld(pMungData->pGWorld); DisposePtr((Ptr)pMungData); } return NULL;}// --------------------// MakeAWindow//OSErr MakeAWindow(WindowRef *outWindow);OSErr MakeAWindow(WindowRef *outWindow){ Rect windowRect = {0, 0, 240, 320}; Rect bestRect; WindowAttributes wAttributes = kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute; OSErr err = noErr; // figure out the best monitor for the window GetBestDeviceRect(NULL, &bestRect); // put the window in the top left corner of that monitor OffsetRect(&windowRect, bestRect.left + 10, bestRect.top + 50); BailErr(CreateNewWindow(kDocumentWindowClass, wAttributes, &windowRect, outWindow)); SetWTitle(*outWindow, "\pSonOfMunggrab"); ShowWindow(*outWindow); // set the port to the new window SetPortWindowPort(*outWindow);bail: return err;}// --------------------// DisposeMungData//void DisposeMungData(MungDataPtr pMungData);void DisposeMungData(MungDataPtr pMungData){ // clean up the bits if(pMungData) { if (pMungData->decomSeq) CDSequenceEnd(pMungData->decomSeq); if (pMungData->drawSeq) CDSequenceEnd(pMungData->drawSeq); if (pMungData->seqGrab) CloseComponent(pMungData->seqGrab); if (pMungData->pGWorld) { DisposeGWorld(pMungData->pGWorld); pMungData->pGWorld = NULL; } DisposePtr((Ptr)pMungData); pMungData = NULL; }}static void DisplayError(WindowRef inWindow, char inStr[], OSErr inError){ // set the window title to display the error char errMsg[64]; sprintf(errMsg, "%s: %d", inStr, inError); CopyCStringToPascal(errMsg, (unsigned char *)&errMsg); SetWTitle(inWindow, (unsigned char *)errMsg);}#pragma mark-// --------------------// MakeSequenceGrabber//SeqGrabComponent MakeSequenceGrabber(WindowRef pWindow);SeqGrabComponent MakeSequenceGrabber(WindowRef pWindow){ SeqGrabComponent seqGrab = NULL; OSErr err = noErr; // open the default sequence grabber seqGrab = OpenDefaultComponent(SeqGrabComponentType, 0); if (seqGrab != NULL) { // initialize the default sequence grabber component err = SGInitialize(seqGrab); if (err == noErr) // set its graphics world to the specified window err = SGSetGWorld(seqGrab, GetWindowPort(pWindow), NULL); if (err == noErr) // specify the destination data reference for a record operation // tell it we're not making a movie // if the flag seqGrabDontMakeMovie is used, the sequence grabber still calls // your data function, but does not write any data to the movie file // writeType will always be set to seqGrabWriteAppend err = SGSetDataRef(seqGrab, 0, 0, seqGrabDontMakeMovie); } if (err && (seqGrab != NULL)) { // clean up on failure CloseComponent(seqGrab); seqGrab = NULL; } return seqGrab;}// --------------------// MakeSequenceGrabChannel//OSErr MakeSequenceGrabChannel(SeqGrabComponent seqGrab, SGChannel *sgchanVideo, Rect const *rect);OSErr MakeSequenceGrabChannel(SeqGrabComponent seqGrab, SGChannel *sgchanVideo, Rect const *rect){ long flags = 0; OSErr err = noErr; err = SGNewChannel(seqGrab, VideoMediaType, sgchanVideo); if (err == noErr) { err = SGSetChannelBounds(*sgchanVideo, rect); if (err == noErr) // set usage for new video channel to avoid playthrough // note we don't set seqGrabPlayDuringRecord err = SGSetChannelUsage(*sgchanVideo, flags | seqGrabRecord); if (err != noErr) { // clean up on failure SGDisposeChannel(seqGrab, *sgchanVideo); *sgchanVideo = NULL; } } return err;}#pragma mark-// --------------------// MakeImageSequenceForGWorld//OSErr MakeImageSequenceForGWorld(GWorldPtr pGWorld, GWorldPtr pDest, long *imageSize, ImageSequence *seq);OSErr MakeImageSequenceForGWorld(GWorldPtr pGWorld, GWorldPtr pDest, long *imageSize, ImageSequence *seq){ ImageDescriptionHandle desc = NULL; PixMapHandle hPixMap = GetGWorldPixMap(pGWorld); Rect bounds; OSErr err = noErr; GetPixBounds(hPixMap, &bounds); *seq = NULL; // returns an image description for the GWorlds PixMap // on entry the imageDesc is NULL, on return it is correctly filled out // you are responsible for disposing it err = MakeImageDescriptionForPixMap(hPixMap, &desc); BailErr(err); *imageSize = (GetPixRowBytes(hPixMap) * (*desc)->height); // ((**hPixMap).rowBytes & 0x3fff) * (*desc)->height; // begin the process of decompressing a sequence of frames // the destination is the onscreen window err = DecompressSequenceBegin(seq, // pointer to field to receive unique ID for sequence desc, // handle to image description structure pDest, // port for the DESTINATION image NULL, // graphics device handle, if port is set, set to NULL &bounds, // source rectangle defining the portion of the image to decompress NULL, // transformation matrix ditherCopy, // transfer mode specifier (RgnHandle)NULL, // clipping region in dest. coordinate system to use as a mask 0, // flags codecNormalQuality, // accuracy in decompression anyCodec); // compressor identifier or special identifiers ie. bestSpeedCodecbail: if (desc) DisposeHandle((Handle)desc); return err;}/* ---------------------------------------------------------------------- *//* sequence grabber data procedure - this is where the work is done/* ---------------------------------------------------------------------- *//* MungGrabDataProc - the sequence grabber calls the data function whenever any of the grabber's channels write digitized data to the destination movie file. NOTE: We really mean any, if you have an audio and video channel then the DataProc will be called for either channel whenever data has been captured. Be sure to check which channel is being passed in. In this example we never create an audio channel so we know we're always dealing with video. This data function does two things, it first decompresses captured video data into an offscreen GWorld, draws some status information onto the frame then transfers the frame to an onscreen window. For more information refer to Inside Macintosh: QuickTime Components, page 5-120 c - the channel component that is writing the digitized data. p - a pointer to the digitized data. len - the number of bytes of digitized data. offset - a pointer to a field that may specify where you are to write the digitized data, and that is to receive a value indicating where you wrote the data. chRefCon - per channel reference constant specified using SGSetChannelRefCon. time - the starting time of the data, in the channel's time scale. writeType - the type of write operation being performed. seqGrabWriteAppend - Append new data. seqGrabWriteReserve - Do not write data. Instead, reserve space for the amount of data specified in the len parameter. seqGrabWriteFill - Write data into the location specified by offset. Used to fill the space previously reserved with seqGrabWriteReserve. The Sequence Grabber may call the DataProc several times to fill a single reserved location. refCon - the reference constant you specified when you assigned your data function to the sequence grabber.*/pascal OSErr MungGrabDataProc(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon);pascal OSErr MungGrabDataProc(SGChannel c, Ptr p, long len, long *offset, long chRefCon, TimeValue time, short writeType, long refCon){#pragma unused(offset,chRefCon,writeType) CGrafPtr theSavedPort; GDHandle theSavedDevice; CodecFlags ignore; float fps = 0, averagefps = 0; ComponentResult err = noErr; MungDataPtr pMungData = (MungDataPtr)refCon; if (NULL == pMungData) return -1; // reset frame and time counters after a stop/start if (pMungData->lastTime > time) { pMungData->lastTime = 0; pMungData->frameCount = 0; } pMungData->frameCount++; if (pMungData->timeScale == 0) { // first time here so set the time scale err = SGGetChannelTimeScale(c, &pMungData->timeScale); DisplayAndBail(err, "SGGetChannelTimeScale"); } if (pMungData->pGWorld) { if (pMungData->decomSeq == 0) { // Set up getting grabbed data into the GWorld Rect sourceRect = { 0, 0 }; MatrixRecord scaleMatrix; ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(0); // retrieve a channel's current sample description, the channel returns a sample description that is // appropriate to the type of data being captured err = SGGetChannelSampleDescription(c, (Handle)imageDesc); DisplayAndBail(err, "SGGetChannelSampleDescription"); /***** IMPORTANT NOTE ***** Previous versions of this sample code made an incorrect decompression request. Intending to draw the DV frame at quarter-size into a quarter-size offscreen GWorld, it made the call err = DecompressSequenceBegin(..., &rect, nil, ...); passing a quarter-size rectangle as the source rectangle. The correct interpretation of this request is to draw the top-left corner of the DV frame cropped at normal size. Unfortunately, a DV-specific bug in QuickTime 5 caused it to misinterpret this request and scale the frame to fit. This bug will be fixed in QuickTime 6. If your code behaves as intended because of the bug, you should fix your code to pass a matrix scaling the frame to fit the offscreen gworld: RectMatrix( & scaleMatrix, &dvFrameRect, &gworldBounds ); err = DecompressSequenceBegin(..., nil, &scaleMatrix, ...); This approach will work in all versions of QuickTime. **************************/ // make a scaling matrix for the sequence sourceRect.right = (**imageDesc).width; sourceRect.bottom = (**imageDesc).height; RectMatrix(&scaleMatrix, &sourceRect, &pMungData->bounds); // begin the process of decompressing a sequence of frames // this is a set-up call and is only called once for the sequence - the ICM will interrogate different codecs // and construct a suitable decompression chain, as this is a time consuming process we don't want to do this // once per frame (eg. by using DecompressImage) // for more information see Ice Floe #8 http://developer.apple.com/quicktime/icefloe/dispatch008.html // the destination is specified as the GWorld err = DecompressSequenceBegin(&pMungData->decomSeq, // pointer to field to receive unique ID for sequence imageDesc, // handle to image description structure pMungData->pGWorld, // port for the DESTINATION image NULL, // graphics device handle, if port is set, set to NULL NULL, // source rectangle defining the portion of the image to decompress &scaleMatrix, // transformation matrix srcCopy, // transfer mode specifier (RgnHandle)NULL, // clipping region in dest. coordinate system to use as a mask NULL, // flags codecNormalQuality, // accuracy in decompression bestSpeedCodec); // compressor identifier or special identifiers ie. bestSpeedCodec DisplayAndBail(err, "GWorldDecompressSequenceBegin"); DisposeHandle((Handle)imageDesc); // Set up getting grabbed data into the Window // create the image sequence for the offscreen err = MakeImageSequenceForGWorld(pMungData->pGWorld, GetWindowPort(pMungData->pWindow), &pMungData->drawSize, &pMungData->drawSeq); DisplayAndBail(err, "MakeImageSequenceForGWorld"); } // decompress a frame into the GWorld - can queue a frame for async decompression when passed in a completion proc err = DecompressSequenceFrameS(pMungData->decomSeq, // sequence ID returned by DecompressSequenceBegin p, // pointer to compressed image data len, // size of the buffer 0, // in flags &ignore, // out flags NULL); // async completion proc DisplayAndBail(err, "GWorldDecompressSequenceFrameS"); // Write status information onto the frame char status[64]; Str255 theString; GetGWorld(&theSavedPort, &theSavedDevice); SetGWorld(pMungData->pGWorld, NULL); TextSize(12); TextMode(srcCopy); MoveTo(pMungData->bounds.left +10, pMungData->bounds.bottom - 14); fps = (float)pMungData->timeScale / (float)(time - pMungData->lastTime); averagefps = ((float)pMungData->frameCount * (float)pMungData->timeScale) / (float)time; sprintf(status, "time stamp: %ld, fps:%5.1f average fps:%5.1f", time, fps, averagefps); CopyCStringToPascal(status, theString); DrawString(theString); SetGWorld(theSavedPort, theSavedDevice); // draw the frame to the destination, in this case the onscreen window err = DecompressSequenceFrameS(pMungData->drawSeq, // sequence ID GetPixBaseAddr(GetGWorldPixMap(pMungData->pGWorld)), // pointer image data pMungData->drawSize, // size of the buffer 0, // in flags &ignore, // out flags NULL); // can async help us? DisplayAndBail(err, "WindowDecompressSequenceFrameS"); } bail: pMungData->lastTime = time; return err;}// --------------------// DoUpdate//void DoUpdate(MungDataPtr pMungData);void DoUpdate(MungDataPtr pMungData){ CodecFlags ignore; // draw the last frame pMungData->err = DecompressSequenceFrameS(pMungData->drawSeq, GetPixBaseAddr(GetGWorldPixMap(pMungData->pGWorld)), pMungData->drawSize, 0, &ignore, NULL); if (pMungData->err) DisplayError(pMungData->pWindow, "DoUpdate", pMungData->err);}#pragma mark-// --------------------// MGIdleTimer//// Munggrab idle timer to idle the sequence grabber, call this at least// as much as the desired frame rate - more is betterstatic pascal void MGIdleTimer(EventLoopTimerRef inTimer, void *inUserData){#pragma unused(inTimer) MungDataPtr pMungData = MungDataPtr(inUserData); if (NULL == pMungData) return; OSErr err = SGIdle(pMungData->seqGrab); if (err && err != pMungData->err) { // some error specific to SGIdle occurred - any errors returned from the // data proc will also show up here and we don't want to write over them // in QT 4 you would always encounter a cDepthErr error after a user drags // the window, this failure condition has been greatly relaxed in QT 5 // it may still occur but should only apply to vDigs that really control // the screen // you don't always know where these errors originate from, some may come // from the VDig... DisplayError(pMungData->pWindow, "SGIdle", err); // ...to fix this we simply call SGStop and SGStartRecord again // calling stop allows the SG to release and re-prepare for grabbing // hopefully fixing any problems, this is obviously a very relaxed // approach SGStop(pMungData->seqGrab); SGStartRecord(pMungData->seqGrab); }}// --------------------// MGAppEventHandler//// Munggrab application event handlerstatic pascal OSStatus MGAppEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *inUserData){#pragma unused(nextHandler) OSStatus status = eventNotHandledErr; MungDataPtr pMungData = MungDataPtr(inUserData); if (NULL == pMungData) goto done; UInt32 eventKind; eventKind = GetEventKind(theEvent); switch (eventKind) { case kEventAppActivated: if (!pMungData->isGrabbing) { // switched in, if the window isn't collapsed start grabbing // if it is collapsed let the kEventWindowExpanded event // start things up again if (!IsWindowCollapsed(pMungData->pWindow)) { SGStartRecord(pMungData->seqGrab); SetEventLoopTimerNextFireTime(pMungData->timerRef, kEventDurationNoWait); pMungData->isGrabbing = true; } } status = noErr; break; case kEventAppDeactivated: if (pMungData->isGrabbing) { // switched out, stop grabbin' SGStop(pMungData->seqGrab); SetEventLoopTimerNextFireTime(pMungData->timerRef, kEventDurationForever); pMungData->isGrabbing = false; } status = noErr; break; default: break; }done: return status;}// --------------------// MGWindowEventHandler//// Munggrab window event handlerstatic pascal OSStatus MGWindowEventHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void *inUserData){#pragma unused(nextHandler) WindowRef theWindow; OSStatus status = eventNotHandledErr; MungDataPtr pMungData = MungDataPtr(inUserData); if (NULL == pMungData) goto done; UInt32 eventKind; eventKind = GetEventKind(theEvent); // we need the window ref or bail OSErr err; err = GetEventParameter(theEvent, kEventParamDirectObject, typeWindowRef, NULL, sizeof(theWindow), NULL, &theWindow); if (err) goto done; switch (eventKind) { case kEventWindowUpdate: if (pMungData->isGrabbing) { // inform the sequence grabber of the update RgnHandle theUpdateRgn = NewRgn(); GetWindowRegion(theWindow, kWindowUpdateRgn, theUpdateRgn); SGUpdate(pMungData->seqGrab, theUpdateRgn); DisposeRgn(theUpdateRgn); } else { DoUpdate(pMungData); } // swallow the update event BeginUpdate(theWindow); EndUpdate(theWindow); status = noErr; break; case kEventWindowHiding: // fall through, same action as kEventWindowCollapsed case kEventWindowCollapsed: // checking this here avoids codecNothingToBlitErr later if (pMungData->isGrabbing) { SGStop(pMungData->seqGrab); SetEventLoopTimerNextFireTime(pMungData->timerRef, kEventDurationForever); pMungData->isGrabbing = false; } status = noErr; break; case kEventWindowShown: // on 9.1 with CarbonLib 1.3.1 we DON'T get this event, when the window is shown // an update event is generated and we update; on X we DO receive this event but // receive NO update event, so we update ourselves DoUpdate(pMungData); status = noErr; break; case kEventWindowExpanded: // we stopped grabbing in the collapsed event so start grabbing on expanded if (!pMungData->isGrabbing) { SGStartRecord(pMungData->seqGrab); SetEventLoopTimerNextFireTime(pMungData->timerRef, kEventDurationNoWait); pMungData->isGrabbing = true; } status = noErr; break; case kEventWindowClickDragRgn: Point where; ICMAlignmentProcRecord apr; // we need the 'where' param from the Event for DragAlignedWindow err = GetEventParameter(theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(where), NULL, &where); if (err) goto done; SGGetAlignmentProc(pMungData->seqGrab, &apr); DragAlignedWindow(theWindow, where, &gScreenbits.bounds, NULL, &apr); status = noErr; break; case kEventWindowClose: // we're done RemoveEventLoopTimer(pMungData->timerRef); QuitApplicationEventLoop(); status = noErr; break; default: break; }done: return status;}// --------------------// HandleQuit AE//pascal OSErr HandleQuitAE(const AppleEvent *theAppleEvent, AppleEvent *reply, long inRefcon);pascal OSErr HandleQuitAE(const AppleEvent *theAppleEvent, AppleEvent *reply, long inRefcon){#pragma unused (theAppleEvent, reply) MungDataPtr pMungData = MungDataPtr(inRefcon); if (pMungData) RemoveEventLoopTimer(pMungData->timerRef); QuitApplicationEventLoop(); return noErr;}// --------------------// InstallEvenHandlers//// install carbon event handlers and timer// you can find more information about carbon events here:// http://developer.apple.com/techpubs/macosx/Carbon/carbon.html// http://developer.apple.com/sdk/index.htmlstatic OSErr InstallEvenHandlers(MungDataPtr inMungData){ OSStatus err = eventInternalErr; const EventTypeSpec appEventList[] = { kEventClassApplication, kEventAppActivated, kEventClassApplication, kEventAppDeactivated }; const EventTypeSpec windowEventList[] = { kEventClassWindow, kEventWindowUpdate, kEventClassWindow, kEventWindowCollapsed, kEventClassWindow, kEventWindowExpanded, kEventClassWindow, kEventWindowClickDragRgn, kEventClassWindow, kEventWindowClose, kEventClassWindow, kEventWindowShown, kEventClassWindow, kEventWindowHiding }; err = InstallEventLoopTimer(GetMainEventLoop(), kEventDurationNoWait, kTimerInterval, NewEventLoopTimerUPP(MGIdleTimer), inMungData, &inMungData->timerRef); BailErr(err); err = InstallApplicationEventHandler(NewEventHandlerUPP(MGAppEventHandler), 2, appEventList, inMungData, NULL); BailErr(err); err = InstallWindowEventHandler(inMungData->pWindow, NewEventHandlerUPP(MGWindowEventHandler), 7, windowEventList, inMungData, NULL); BailErr(err); err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(HandleQuitAE), (long)inMungData, false);bail: return err; }#pragma mark-// --------------------int main(void){ WindowRef pMainWindow = NULL; MungDataPtr pMungData = NULL; SeqGrabComponent seqGrab = 0; SGChannel sgchanVideo = 0; Rect portRect; OSErr err = noErr; InitializeApp(); // create the window err = MakeAWindow(&pMainWindow); BailErr(err); GetPortBounds(GetWindowPort(pMainWindow), &portRect); // create and initialize the sequence grabber seqGrab = MakeSequenceGrabber(pMainWindow); BailErr(NULL == seqGrab); // create the channel err = MakeSequenceGrabChannel(seqGrab, &sgchanVideo, &portRect); BailErr(err); // initialize our data that's going to be passed around pMungData = InitializeMungData(pMainWindow, portRect, seqGrab); BailErr(NULL == pMungData); // specify a sequence grabber data function err = SGSetDataProc(seqGrab, NewSGDataUPP(MungGrabDataProc), (long)pMungData); BailErr(err); // install carbon event handlers err = InstallEvenHandlers(pMungData); BailErr(err); // lights...camera... err = SGPrepare(seqGrab, false, true); BailErr(err); // ...action err = SGStartRecord(seqGrab); BailErr(err); pMungData->isGrabbing = true; // run the application RunApplicationEventLoop(); bail: // clean up if (pMainWindow) DisposeWindow(pMainWindow); DisposeMungData(pMungData); return 0;}</pre>
<!--googleoff: index -->
</td>
</tr>
</table>
<!-- END WIDE COLUMN -->
<!-- END MAIN CONTENT -->
<table width="680" border="0" cellpadding="0" cellspacing="0">
<tr>
<td><div style="width: 100%; height: 1px; background-color: #919699; margin-top: 5px; margin-bottom: 15px"></div></td>
</tr>
<tr>
<td align="center"><br/>
<table border="0" cellpadding="0" cellspacing="0" class="graybox">
<tr>
<th>Did this document help you?</th>
</tr>
<tr>
<td>
<div style="margin-bottom: 8px"><a href="http://developer.apple.com/feedback/?v=1&url=/samplecode/SGDataProcSample/listing5.html%3Fid%3DDTS10000807-1.0&media=dvd" target=_new>Yes</a>: Tell us what works for you.</div>
<div style="margin-bottom: 8px"><a href="http://developer.apple.com/feedback/?v=2&url=/samplecode/SGDataProcSample/listing5.html%3Fid%3DDTS10000807-1.0&media=dvd" target=_new>It’s good, but:</a> Report typos, inaccuracies, and so forth.</div>
<div><a href="http://developer.apple.com/feedback/?v=3&url=/samplecode/SGDataProcSample/listing5.html%3Fid%3DDTS10000807-1.0&media=dvd" target=_new>It wasn’t helpful</a>: Tell us what would have helped.</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- START BOTTOM APPLE NAVIGATION -->
<!--#include virtual="/includes/footer"-->
<!-- END BOTTOM APPLE NAVIGATION -->
<!-- START CENTER CLOSE -->
</center>
<!-- END CENTER CLOSE -->
</body>
</html>