00001 /*!@file Raster/QuartzQuickTimeParser.C */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Raster/QuartzQuickTimeParser.C $ 00035 // $Id: QuartzQuickTimeParser.C 7958 2007-02-20 23:30:52Z rjpeters $ 00036 // 00037 00038 #ifndef RASTER_QUARTZQUICKTIMEPARSER_C_DEFINED 00039 #define RASTER_QUARTZQUICKTIMEPARSER_C_DEFINED 00040 00041 #include "Raster/QuartzQuickTimeParser.H" 00042 00043 #ifdef HAVE_QUICKTIME_QUICKTIME_H 00044 00045 #include "Raster/GenericFrame.H" 00046 #include "Util/Janitor.H" 00047 #include "Util/log.H" 00048 00049 #include <QuickTime/QuickTime.h> 00050 00051 struct QuartzQuickTimeParser::Rep 00052 { 00053 GenericFrame frame; 00054 }; 00055 00056 QuartzQuickTimeParser::QuartzQuickTimeParser(const char* filename) 00057 : 00058 rep(new Rep) 00059 { 00060 // Convert image path to CFString 00061 CFStringRef inPath = CFStringCreateWithCString(NULL, filename, 00062 CFStringGetSystemEncoding()); 00063 if (!inPath) 00064 LFATAL("Could not get CFString from %s", filename); 00065 00066 // create the data reference 00067 Handle myDataRef = NULL; 00068 OSType myDataRefType; 00069 OSErr result = 00070 QTNewDataReferenceFromFullPathCFString 00071 (inPath, (unsigned long) kQTNativeDefaultPathStyle, 00072 0, &myDataRef, &myDataRefType); 00073 00074 if (result != noErr) 00075 LFATAL("Could not get DataRef for %s (error %d)", filename, result); 00076 00077 Janitor<GraphicsImportComponent> importer(NULL, &CloseComponent); 00078 result = GetGraphicsImporterForDataRef(myDataRef, myDataRefType, &importer.it); 00079 00080 if (result != noErr) 00081 LFATAL("Could not get GraphicsImportComponent for %s (error %d)", 00082 filename, result); 00083 00084 unsigned long imageCount = 0; 00085 { 00086 ComponentResult res = GraphicsImportGetImageCount(importer.it, &imageCount); 00087 if (res != noErr) 00088 LFATAL("Could not get image count for %s (error %ld)", 00089 filename, res); 00090 } 00091 00092 if (imageCount == 0) 00093 LFATAL("Oops! No images found in %s", filename); 00094 00095 if (imageCount > 1) 00096 LFATAL("Oops! Found %lu images in %s, but can handle only 1", 00097 imageCount, filename); 00098 00099 ASSERT(imageCount == 1); 00100 00101 ImageDescriptionHandle desc; 00102 00103 { 00104 ComponentResult res = GraphicsImportGetImageDescription(importer.it, &desc); 00105 if (res != noErr) 00106 LFATAL("Could not get image description for %s (error %ld)", 00107 filename, res); 00108 } 00109 00110 LDEBUG("%s: dims are %dx%d, depth is %d, codec is '%4s'", 00111 filename, int((*desc)->width), int((*desc)->height), 00112 int((*desc)->depth), 00113 reinterpret_cast<const char*>(&(*desc)->cType)); 00114 00115 Rect bounds; 00116 { 00117 ComponentResult res = GraphicsImportGetNaturalBounds(importer.it, &bounds); 00118 if (res != noErr) 00119 LFATAL("Could not get image bounds for %s (error %ld)", 00120 filename, res); 00121 } 00122 00123 CGImageRef imageRef = 0; 00124 if (noErr != 00125 GraphicsImportCreateCGImage 00126 (importer.it, &imageRef, 00127 kGraphicsImportCreateCGImageUsingCurrentSettings)) 00128 LFATAL("Could not create CGImage"); 00129 00130 CGRect rect; 00131 rect.origin.x = 0; 00132 rect.origin.y = 0; 00133 rect.size.width = CGImageGetWidth(imageRef); 00134 rect.size.height = CGImageGetHeight(imageRef); 00135 00136 switch ((*desc)->depth) 00137 { 00138 case 1: case 2: case 4: case 8: case 16: case 24: case 32: // RGB 00139 { 00140 Janitor<CGColorSpaceRef> colorSpace 00141 (CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), 00142 &CGColorSpaceRelease); 00143 00144 if (NULL == colorSpace.it) 00145 LFATAL("couldn't create rgb color space"); 00146 00147 LDEBUG("rgb colorspace has %"ZU" components", 00148 CGColorSpaceGetNumberOfComponents(colorSpace.it)); 00149 00150 // Yuck. CoreGraphics won't let us render directly into 24-bit 00151 // RGB pixels; instead we have to render into 32-bit ARGB 00152 // pixels with an ignored alpha field, and then copy the data 00153 // a second time from there into our desired 24-bit result. 00154 00155 Image<byte> argb(4*CGImageGetWidth(imageRef), 00156 CGImageGetHeight(imageRef), 00157 NO_INIT); 00158 00159 // see http://developer.apple.com/qa/qa2001/qa1037.html for a 00160 // list of the parameter combinations that are supported by 00161 // CGBitmapContextCreate() 00162 00163 Janitor<CGContextRef> bitmapContext 00164 (CGBitmapContextCreate(argb.getArrayPtr(), 00165 argb.getWidth() / 4, 00166 argb.getHeight(), 00167 8, 00168 argb.getWidth(), 00169 colorSpace.it, 00170 kCGImageAlphaNoneSkipLast), 00171 &CFRelease); 00172 00173 if (NULL == bitmapContext.it) 00174 LFATAL("couldn't create rgb bitmap context"); 00175 00176 CGContextDrawImage(bitmapContext.it, rect, imageRef); 00177 00178 Image<PixRGB<byte> > rgb(CGImageGetWidth(imageRef), 00179 CGImageGetHeight(imageRef), 00180 NO_INIT); 00181 const byte* argbptr = argb.getArrayPtr(); 00182 byte* rgbptr = reinterpret_cast<byte*>(rgb.getArrayPtr()); 00183 const size_t n = rgb.getSize(); 00184 00185 for (size_t i = 0; i < n; ++i) 00186 { 00187 rgbptr[0] = argbptr[0]; 00188 rgbptr[1] = argbptr[1]; 00189 rgbptr[2] = argbptr[2]; 00190 rgbptr += 3; 00191 argbptr += 4; 00192 } 00193 00194 rep->frame = GenericFrame(rgb); 00195 } 00196 break; 00197 00198 case 34: case 36: case 40: // grayscale 00199 { 00200 // 34=>2-bit, 36=>4-bit, 40=>8-bit 00201 const int depth = (*desc)->depth - 32; 00202 (void) depth; 00203 00204 Janitor<CGColorSpaceRef> colorSpace 00205 (CGColorSpaceCreateWithName(kCGColorSpaceGenericGray), 00206 &CGColorSpaceRelease); 00207 00208 if (NULL == colorSpace.it) 00209 LFATAL("couldn't create grayscale color space"); 00210 00211 LDEBUG("grayscale colorspace has %"ZU" components", 00212 CGColorSpaceGetNumberOfComponents(colorSpace.it)); 00213 00214 Image<byte> gray(CGImageGetWidth(imageRef), 00215 CGImageGetHeight(imageRef), 00216 NO_INIT); 00217 00218 Janitor<CGContextRef> bitmapContext 00219 (CGBitmapContextCreate(gray.getArrayPtr(), 00220 gray.getWidth(), 00221 gray.getHeight(), 00222 8, 00223 gray.getWidth(), 00224 colorSpace.it, 00225 kCGImageAlphaNone), 00226 &CFRelease); 00227 00228 if (NULL == bitmapContext.it) 00229 LFATAL("couldn't create grayscale bitmap context"); 00230 00231 CGContextDrawImage(bitmapContext.it, rect, imageRef); 00232 00233 rep->frame = GenericFrame(gray); 00234 break; 00235 } 00236 } 00237 } 00238 00239 QuartzQuickTimeParser::~QuartzQuickTimeParser() 00240 { 00241 delete rep; 00242 } 00243 00244 GenericFrameSpec QuartzQuickTimeParser::getFrameSpec() const 00245 { 00246 return rep->frame.frameSpec(); 00247 } 00248 00249 std::string QuartzQuickTimeParser::getComments() const 00250 { 00251 return std::string(); 00252 } 00253 00254 uint QuartzQuickTimeParser::getTagCount() const 00255 { 00256 return 0; 00257 } 00258 00259 bool QuartzQuickTimeParser::getTag(uint tag, 00260 std::string &name, 00261 std::string &value) const 00262 { 00263 name = std::string(); 00264 value = std::string(); 00265 return false; 00266 } 00267 00268 GenericFrame QuartzQuickTimeParser::getFrame() 00269 { 00270 return rep->frame; 00271 } 00272 00273 #endif // HAVE_QUICKTIME_QUICKTIME_H 00274 00275 // ###################################################################### 00276 /* So things look consistent in everyone's emacs... */ 00277 /* Local Variables: */ 00278 /* mode: c++ */ 00279 /* indent-tabs-mode: nil */ 00280 /* End: */ 00281 00282 #endif // RASTER_QUARTZQUICKTIMEPARSER_C_DEFINED