00001
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;
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;
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;
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;
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
00134 if (!valid() ||
00135 x >= width() ||
00136 y >= height()) {
00137 return sub;
00138 }
00139
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
00163 duplicate = Image(size(), type(), data);
00164 } else {
00165
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
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);
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
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