| 1 /* |
|
| 2 File: QTUtilities.c |
|
| 3 |
|
| 4 Description: Miscellaneous QuickTime utility routines. |
|
| 5 |
|
| 6 Copyright: © Copyright 2003 Apple Computer, Inc. All rights reserved. |
|
| 7 |
|
| 8 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
|
| 9 ("Apple") in consideration of your agreement to the following terms, and your |
|
| 10 use, installation, modification or redistribution of this Apple software |
|
| 11 constitutes acceptance of these terms. If you do not agree with these terms, |
|
| 12 please do not use, install, modify or redistribute this Apple software. |
|
| 13 |
|
| 14 In consideration of your agreement to abide by the following terms, and subject |
|
| 15 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s |
|
| 16 copyrights in this original Apple software (the "Apple Software"), to use, |
|
| 17 reproduce, modify and redistribute the Apple Software, with or without |
|
| 18 modifications, in source and/or binary forms; provided that if you redistribute |
|
| 19 the Apple Software in its entirety and without modifications, you must retain |
|
| 20 this notice and the following text and disclaimers in all such redistributions of |
|
| 21 the Apple Software. Neither the name, trademarks, service marks or logos of |
|
| 22 Apple Computer, Inc. may be used to endorse or promote products derived from the |
|
| 23 Apple Software without specific prior written permission from Apple. Except as |
|
| 24 expressly stated in this notice, no other rights or licenses, express or implied, |
|
| 25 are granted by Apple herein, including but not limited to any patent rights that |
|
| 26 may be infringed by your derivative works or by other works in which the Apple |
|
| 27 Software may be incorporated. |
|
| 28 |
|
| 29 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
|
| 30 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
|
| 31 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
| 32 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
|
| 33 COMBINATION WITH YOUR PRODUCTS. |
|
| 34 |
|
| 35 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
|
| 36 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
|
| 37 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
| 38 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
|
| 39 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
|
| 40 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
|
| 41 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
| 42 |
|
| 43 Change History (most recent first): |
|
| 44 |
|
| 45 */ |
|
| 46 |
|
| 47 #include "QTUtilities.h" |
|
| 48 #include "Utilities.h" |
|
| 49 |
|
| 50 #define BailErr(x) {if (x != noErr) goto bail;} |
|
| 51 |
|
| 52 ////////// |
|
| 53 // |
|
| 54 // GetMovieFromFile |
|
| 55 // Opens a movie file, then creates a new movie for the file |
|
| 56 // |
|
| 57 ////////// |
|
| 58 |
|
| 59 OSErr GetMovieFromFile(FSSpec *fsspecPtr, Movie *theMovie) |
|
| 60 { |
|
| 61 short resRefNum = -1; |
|
| 62 OSErr result; |
|
| 63 |
|
| 64 *theMovie = NULL; |
|
| 65 |
|
| 66 result = OpenMovieFile(fsspecPtr, &resRefNum, 0); |
|
| 67 if (result == noErr) |
|
| 68 { |
|
| 69 short actualResId = DoTheRightThing; |
|
| 70 |
|
| 71 result = NewMovieFromFile(theMovie, |
|
| 72 resRefNum, |
|
| 73 &actualResId, |
|
| 74 (unsigned char *) 0, |
|
| 75 0, |
|
| 76 (Boolean *) 0); |
|
| 77 CloseMovieFile(resRefNum); |
|
| 78 } |
|
| 79 |
|
| 80 return result; |
|
| 81 } |
|
| 82 |
|
| 83 ////////// |
|
| 84 // |
|
| 85 // GetAMovieFile |
|
| 86 // Prompt the user for a movie file, then open |
|
| 87 // the file and create a movie for it. |
|
| 88 // |
|
| 89 ////////// |
|
| 90 |
|
| 91 OSErr GetAMovieFile(Movie *theMovie) |
|
| 92 { |
|
| 93 OSType myTypeList[2] = {kQTFileTypeMovie, kQTFileTypeQuickTimeImage}; |
|
| 94 FSSpec theFSSpec; |
|
| 95 OSErr result = noErr; |
|
| 96 |
|
| 97 *theMovie = nil; |
|
| 98 |
|
| 99 result = GetOneFileWithPreview(2, myTypeList, &theFSSpec, NULL); |
|
| 100 if (result != userCanceledErr) |
|
| 101 { |
|
| 102 result = GetMovieFromFile(&theFSSpec, theMovie); |
|
| 103 } |
|
| 104 |
|
| 105 return result; |
|
| 106 } |
|
| 107 |
|
| 108 ////////// |
|
| 109 // |
|
| 110 // NormalizeMovieRect |
|
| 111 // |
|
| 112 ////////// |
|
| 113 |
|
| 114 void NormalizeMovieRect(Movie theMovie) |
|
| 115 { |
|
| 116 Rect movieBounds; |
|
| 117 |
|
| 118 GetMovieBox(theMovie, &movieBounds); |
|
| 119 OffsetRect(&movieBounds, -movieBounds.left, -movieBounds.top); |
|
| 120 movieBounds.right = movieBounds.left + 640; |
|
| 121 movieBounds.bottom = movieBounds.top + 480; |
|
| 122 SetMovieBox(theMovie, &movieBounds); |
|
| 123 } |
|
| 124 |
|
| 125 ////////// |
|
| 126 // |
|
| 127 // EraseRectAndAlpha |
|
| 128 // Zeros out a section of the GWorld, including alpha. |
|
| 129 // |
|
| 130 ////////// |
|
| 131 |
|
| 132 void EraseRectAndAlpha(GWorldPtr gWorld, Rect *pRect) |
|
| 133 { |
|
| 134 PixMapHandle pixMap = GetGWorldPixMap(gWorld); |
|
| 135 long rows; |
|
| 136 Ptr rowBaseAddr; |
|
| 137 |
|
| 138 |
|
| 139 LockPixels(pixMap); |
|
| 140 rows = pRect->bottom - pRect->top; |
|
| 141 |
|
| 142 rowBaseAddr = GetPixBaseAddr(pixMap) + (GetPixRowBytes(pixMap) & 0x3fff) * pRect->top + pRect->left * GetPixDepth(pixMap) / 8; |
|
| 143 do |
|
| 144 { |
|
| 145 long cols; |
|
| 146 UInt32 *baseAddr; |
|
| 147 |
|
| 148 cols = pRect->right - pRect->left; |
|
| 149 baseAddr = (UInt32*)rowBaseAddr; |
|
| 150 rowBaseAddr += (**pixMap).rowBytes & 0x3fff; |
|
| 151 do |
|
| 152 { |
|
| 153 *baseAddr++ = 0; |
|
| 154 } while (--cols); |
|
| 155 } while (--rows); |
|
| 156 |
|
| 157 UnlockPixels(pixMap); |
|
| 158 |
|
| 159 } // EraseRectAndAlpha |
|
| 160 |
|
| 161 ////////// |
|
| 162 // |
|
| 163 // CreateDecompSeqForSGChannelData |
|
| 164 // Create a decompression sequence for the passed |
|
| 165 // Sequence Grabber channel data |
|
| 166 // |
|
| 167 ////////// |
|
| 168 |
|
| 169 OSErr CreateDecompSeqForSGChannelData(SGChannel sgChannel, Rect *srcBounds, GWorldPtr imageDestination, ImageSequence *imageSeqID) |
|
| 170 { |
|
| 171 OSErr err = noErr; |
|
| 172 |
|
| 173 ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription)); |
|
| 174 if (imageDesc) |
|
| 175 { |
|
| 176 |
|
| 177 err = SGGetChannelSampleDescription(sgChannel,(Handle)imageDesc); |
|
| 178 // The original version of this code had a bug - it passed in a Crop Rect to DecompressSequenceBegin instead of a scaling matrix |
|
| 179 // This only worked because of another bug inside QT that reated the crop Rect as a destination rect for DV |
|
| 180 // the following code does the right thing in all cases. |
|
| 181 |
|
| 182 if (err == noErr) |
|
| 183 { |
|
| 184 MatrixRecord mr; |
|
| 185 Rect fromR; |
|
| 186 |
|
| 187 fromR.left = 0; |
|
| 188 fromR.top = 0; |
|
| 189 fromR.right = (**imageDesc).width; |
|
| 190 fromR.bottom = (**imageDesc).height; |
|
| 191 RectMatrix(&mr, &fromR, srcBounds); |
|
| 192 |
|
| 193 err = DecompressSequenceBegin(imageSeqID, imageDesc, imageDestination, 0, nil, &mr,srcCopy,nil,0, codecNormalQuality, bestSpeedCodec); |
|
| 194 } |
|
| 195 |
|
| 196 DisposeHandle((Handle)imageDesc); |
|
| 197 } |
|
| 198 else |
|
| 199 { |
|
| 200 err = MemError(); |
|
| 201 } |
|
| 202 |
|
| 203 return err; |
|
| 204 } |
|
| 205 |
|
| 206 |
|
| 207 ////////// |
|
| 208 // |
|
| 209 // CreateDecompSeqForGWorldData |
|
| 210 // Create a decompression sequence for the specified gworld data |
|
| 211 // |
|
| 212 ////////// |
|
| 213 |
|
| 214 OSErr CreateDecompSeqForGWorldData(GWorldPtr srcGWorld, Rect *srcBounds, MatrixRecordPtr mr, GWorldPtr imageDestination, ImageSequence *imageSeqID) |
|
| 215 { |
|
| 216 OSErr err; |
|
| 217 |
|
| 218 ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription)); |
|
| 219 if (imageDesc) |
|
| 220 { |
|
| 221 err = MakeImageDescriptionForPixMap (GetGWorldPixMap(srcGWorld), &imageDesc); |
|
| 222 err = DecompressSequenceBegin( imageSeqID, |
|
| 223 imageDesc, |
|
| 224 imageDestination, |
|
| 225 0, |
|
| 226 srcBounds, |
|
| 227 mr, |
|
| 228 srcCopy, |
|
| 229 nil, |
|
| 230 0, |
|
| 231 codecNormalQuality, |
|
| 232 bestSpeedCodec); |
|
| 233 DisposeHandle((Handle)imageDesc); |
|
| 234 } |
|
| 235 else |
|
| 236 { |
|
| 237 err = MemError(); |
|
| 238 } |
|
| 239 |
|
| 240 return err; |
|
| 241 } |
|
| 242 |
|
| 243 ////////// |
|
| 244 // |
|
| 245 // CreateNewSGChannelForRecording |
|
| 246 // - create a new Sequence Grabber video channel |
|
| 247 // - let the use configure the channel |
|
| 248 // - set the channel bounds, usage |
|
| 249 // - set a data proc for the channel |
|
| 250 // - start recording data |
|
| 251 // |
|
| 252 ////////// |
|
| 253 |
|
| 254 OSErr CreateNewSGChannelForRecording(ComponentInstance seqGrab, SGDataUPP dataProc, CGrafPtr drawPort, Rect *theRect, SGChannel *sgChannel, long refCon) |
|
| 255 { |
|
| 256 OSErr err = noErr; |
|
| 257 |
|
| 258 BailErr((err = SGInitialize(seqGrab))); |
|
| 259 |
|
| 260 // tell it we're not making a movie |
|
| 261 BailErr((err = SGSetDataRef(seqGrab,0,0,seqGrabDontMakeMovie))); |
|
| 262 // It wants a port, even if its not drawing to it |
|
| 263 BailErr((err = SGSetGWorld(seqGrab, drawPort, GetMainDevice()))); |
|
| 264 BailErr((err = SGNewChannel(seqGrab, VideoMediaType, sgChannel))); |
|
| 265 |
|
| 266 // let the user configure the video channel |
|
| 267 //BailErr((err = SGSettingsDialog(seqGrab, *sgChannel, 0, nil, 0, nil, 0))); // ************************ |
|
| 268 // ************************************************************ |
|
| 269 |
|
| 270 |
|
| 271 |
|
| 272 BailErr((err = SGSetChannelBounds(*sgChannel, theRect))); |
|
| 273 // set usage for new video channel to avoid playthrough |
|
| 274 BailErr((err = SGSetChannelUsage(*sgChannel, seqGrabRecord ))); //note we don't set seqGrabPlayDuringRecord |
|
| 275 BailErr((err = SGSetDataProc(seqGrab, dataProc, refCon))); |
|
| 276 BailErr((err = SGStartRecord(seqGrab))); |
|
| 277 |
|
| 278 bail: |
|
| 279 return err; |
|
| 280 } |
|
| 281 |
|
| 282 ////////// |
|
| 283 // |
|
| 284 // DoCloseSG |
|
| 285 // Terminate recording for our SG channel - dispose of the channel and |
|
| 286 // the associated SG component instance |
|
| 287 // |
|
| 288 ////////// |
|
| 289 |
|
| 290 void DoCloseSG(ComponentInstance seqGrab, SGChannel sgChannel, SGDataUPP dataProc) |
|
| 291 { |
|
| 292 if(seqGrab) |
|
| 293 { |
|
| 294 SGStop(seqGrab); |
|
| 295 SGSetDataProc(seqGrab, NULL ,NULL); |
|
| 296 if (dataProc) |
|
| 297 { |
|
| 298 DisposeSGDataUPP(dataProc); |
|
| 299 } |
|
| 300 |
|
| 301 SGDisposeChannel(seqGrab, sgChannel); |
|
| 302 CloseComponent(seqGrab); |
|
| 303 } |
|
| 304 } |
|
| 305 |
|
| 306 |
|