• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/Image.cpp

00001 //#include <stdlib.h>
00002 #include <string.h>
00003 #include <algorithm>
00004 
00005 #include "FCam/Image.h"
00006 #include "FCam/Time.h"
00007 #include "FCam/Event.h"
00008 #include "Debug.h"
00009 
00010 namespace FCam {
00011 
00012     unsigned char *Image::Discard = (unsigned char *)(0);
00013     unsigned char *Image::AutoAllocate = (unsigned char *)(-1);
00014 
00015     Image::Image()
00016         : _size(0, 0), _type(UNKNOWN), _bytesPerPixel(0), _bytesPerRow(0), 
00017           data(Image::Discard), buffer(NULL),
00018           refCount(NULL), mutex(NULL), holdingLock(false) {                
00019     }
00020     
00021     Image::Image(int w, int h, ImageFormat f) 
00022         : _size(w, h), 
00023           _type(f), 
00024           _bytesPerPixel(FCam::bytesPerPixel(f)), 
00025           _bytesPerRow(bytesPerPixel()*width()),
00026           data(NULL), buffer(NULL),
00027           refCount(NULL), mutex(NULL), 
00028           holdingLock(false) {
00029         
00030         setBuffer(new unsigned char[bytesPerRow()*height()*bytesPerPixel()]);
00031         refCount = new unsigned;
00032         *refCount = 1; // only I know about this data
00033         mutex = new pthread_mutex_t;
00034         pthread_mutex_init(mutex, NULL);
00035     }
00036     
00037     Image::Image(Size s, ImageFormat f) 
00038         : _size(s), 
00039           _type(f), 
00040           _bytesPerPixel(FCam::bytesPerPixel(f)), 
00041           _bytesPerRow(bytesPerPixel()*width()),
00042           data(NULL), buffer(NULL), 
00043           refCount(NULL), mutex(NULL), 
00044           holdingLock(false) {
00045         
00046         setBuffer(new unsigned char[bytesPerRow()*height()*bytesPerPixel()]);
00047         refCount = new unsigned;
00048         *refCount = 1; // only I know about this data
00049         mutex = new pthread_mutex_t;
00050         pthread_mutex_init(mutex, NULL);
00051     }
00052 
00053     Image::Image(Size s, ImageFormat f, unsigned char *d, int srcBytesPerRow) 
00054         : _size(s), 
00055           _type(f), 
00056           _bytesPerPixel(FCam::bytesPerPixel(f)), 
00057           data(NULL), buffer(NULL),
00058           refCount(NULL), mutex(NULL), 
00059           holdingLock(false) {
00060 
00061         _bytesPerRow = (srcBytesPerRow == -1) ? (bytesPerPixel() * width()) : srcBytesPerRow;
00062         setBuffer(NULL, d);
00063 
00064         if (valid()) {
00065             refCount = new unsigned;
00066             *refCount = 2; // there's me, and then there's the real owner of this data
00067             mutex = new pthread_mutex_t;
00068             pthread_mutex_init(mutex, NULL);
00069         }
00070     }
00071     
00072     Image::Image(int w, int h, ImageFormat f, unsigned char *d, int srcBytesPerRow) 
00073         : _size(w, h), 
00074           _type(f), 
00075           _bytesPerPixel(FCam::bytesPerPixel(f)),
00076           data(NULL), buffer(NULL),
00077           refCount(NULL), mutex(NULL), 
00078           holdingLock(false) {
00079 
00080         _bytesPerRow = (srcBytesPerRow == -1) ? (bytesPerPixel() * width()) : srcBytesPerRow;
00081         setBuffer(NULL, d);
00082 
00083         if (valid()) {
00084             refCount = new unsigned;
00085             *refCount = 2; // there's me, and then there's the real owner of this data
00086             mutex = new pthread_mutex_t;
00087             pthread_mutex_init(mutex, NULL);
00088         }
00089     }
00090 
00091     Image::~Image() {
00092         setBuffer(NULL);        
00093     }
00094 
00095     Image::Image(const Image &other) 
00096         : _size(other.size()), 
00097           _type(other.type()), 
00098           _bytesPerPixel(other.bytesPerPixel()),
00099           _bytesPerRow(other.bytesPerRow()),
00100           data(other.data), buffer(other.buffer),
00101           refCount(other.refCount),
00102           mutex(other.mutex), holdingLock(false) {
00103         if (refCount) {
00104             (*refCount)++;
00105         }
00106     };
00107 
00108     const Image &Image::operator=(const Image &other) {
00109         if (this == &other) return (*this);
00110         if (refCount && 
00111             refCount == other.refCount &&
00112             data == other.data) {
00113             return (*this);
00114         }
00115 
00116         _size = other.size();
00117         _type = other.type();
00118         _bytesPerPixel = other.bytesPerPixel();
00119         _bytesPerRow = other.bytesPerRow();
00120 
00121         setBuffer(other.buffer, other.data);
00122         
00123         refCount = other.refCount;
00124         mutex = other.mutex;
00125         if (refCount) (*refCount)++;
00126         holdingLock = false;
00127 
00128         return (*this);
00129     }
00130 
00131     Image Image::subImage(unsigned int x, unsigned int y, Size s) const {
00132         Image sub;
00133         // Check bounds
00134         if (!valid() ||
00135             x >= width() ||
00136             y >= height()) {
00137             return sub;
00138         }
00139         // Clip size to edges of image
00140         if (x + s.width > width()) {
00141             s.width = width() - x;
00142         }
00143         if (y + s.height > height()) {
00144             s.height = height() - y;
00145         }
00146 
00147         sub = Image(s, type(), Image::Discard, bytesPerRow());
00148 
00149         unsigned int offset = x*bytesPerPixel()+y*bytesPerRow();
00150         sub.setBuffer(buffer, data+offset);
00151 
00152         sub.refCount = refCount;
00153         sub.mutex = mutex;
00154         if (refCount) (*refCount)++;
00155         
00156         return sub;
00157     }
00158 
00159     Image Image::copy() const {
00160         Image duplicate;
00161         if (!valid()) {
00162             // Data is either Discard or AutoAllocate
00163             duplicate = Image(size(), type(), data);
00164         } else {
00165             // Got real data, allocate an image
00166             duplicate = Image(size(), type());
00167             duplicate.copyFrom(*this);
00168         }
00169 
00170         return duplicate;
00171     }
00172 
00173     void Image::copyFrom(const Image &srcImage) {
00174         if (!valid()) return;
00175         int h = std::min(srcImage.height(), 
00176                          height());
00177         int widthBytes = 
00178             std::min(srcImage.width()*srcImage.bytesPerPixel(), 
00179                      width()*bytesPerPixel());
00180 
00181         unsigned char *src = srcImage.data;
00182         unsigned char *dst = data;
00183 
00184         for (int y=0; y < h; y++) {
00185             memcpy(dst, src, widthBytes);
00186             dst += bytesPerRow();
00187             src += srcImage.bytesPerRow();
00188         }
00189     }
00190 
00191     void Image::setBuffer(unsigned char *b, unsigned char *d) {
00192         if (holdingLock) pthread_mutex_unlock(mutex);
00193         holdingLock = false;
00194 
00195         if (mutex && refCount && (*refCount == 0 || (weak() && *refCount == 1))) {
00196             pthread_mutex_destroy(mutex);
00197             delete mutex;
00198             mutex = NULL;
00199         }
00200 
00201         if (refCount) {
00202             (*refCount)--;
00203 
00204             if (*refCount == 0) {
00205                 delete refCount;
00206                 delete[] buffer;
00207             }
00208             refCount = NULL;
00209             mutex = NULL;
00210         }
00211 
00212         if (b == Image::Discard ||
00213             b == Image::AutoAllocate) {
00214             buffer = NULL;
00215         } else {
00216             buffer = b;
00217         } 
00218         if (d == NULL) d = b;
00219 
00220         // This is the only place we're allowed to set the data field
00221         data = d;
00222     }
00223 
00224     bool Image::lock(int timeout) {
00225         if (holdingLock) {
00226             error(Event::ImageLockError, "Image reference trying to acquire lock it's already "
00227                   "holding. Make a separate image reference per thread.\n");
00228         } else if (!mutex) {
00229             error(Event::InternalError, "Locking an image with no mutex\n");
00230             holdingLock = false;
00231         } else if (timeout < 0) {
00232             pthread_mutex_lock(mutex);
00233             holdingLock = true;
00234         } else if (timeout == 0) {
00235             int ret = pthread_mutex_trylock(mutex);
00236             holdingLock = (ret == 0);
00237         } else {
00238             struct timespec t = (struct timespec)(Time::now() + timeout);
00240 #ifdef FCAM_ARCH_X86 
00241             int ret = pthread_mutex_trylock(mutex); // Temporary hack to compile on Cygwin, breaks semantics
00242 #else
00243             int ret = pthread_mutex_timedlock(mutex, &t);
00244 #endif
00245             holdingLock = (ret == 0);
00246         }
00247 
00248         return holdingLock;
00249     }
00250 
00251     void Image::unlock() {
00252         if (!holdingLock) {
00253             error(Event::ImageLockError, "Cannot unlock a lock not held by this image reference");
00254             return;
00255         }
00256         if (!mutex) {
00257             error(Event::InternalError, "Unlocking an image with no mutex");
00258             debug();
00259             return;
00260         }
00261         pthread_mutex_unlock(mutex);
00262         holdingLock = false;
00263     }
00264 
00265     bool Image::operator==(const Image &other) const {
00266         if (data != other.data) return false;
00267         if (width() != other.width()) return false;
00268         if (height() != other.height()) return false;
00269         if (type() != other.type()) return false;
00270         /* bytesPerPixel, bytesPerRow, and buffer must match if the above do */
00271         return true;
00272     }
00273 
00274     void Image::debug(const char *name) const {
00275         printf("\tImage %s at %llx with dimensions %d %d type %d\n\t  bytes per pixel %d bytes per row %d\n\t  data %llx buffer %llx\n\t  refCount %llx = (%d), mutex %llx, holdingLock %d\n",
00276                name,
00277                (long long unsigned)this,
00278                width(), height(),
00279                type(),
00280                bytesPerPixel(),
00281                bytesPerRow(),
00282                (long long unsigned)data,
00283                (long long unsigned)buffer,
00284                (long long unsigned)refCount,
00285                refCount ? *refCount : 0,
00286                (long long unsigned)mutex,
00287                (holdingLock ? 1 : 0));
00288     }
00289    
00290 }
00291 
00292 
00293 
00294 

Generated on Thu Jul 15 2010 17:51:28 for FCam by  doxygen 1.7.1