00001
00002 #include <string.h>
00003 #include <sys/mman.h>
00004 #include <algorithm>
00005
00006 #include "FCam/Image.h"
00007 #include "FCam/Time.h"
00008 #include "FCam/Event.h"
00009 #include "Debug.h"
00010
00011 namespace FCam {
00012
00013 unsigned char *Image::Discard = (unsigned char *)(0);
00014 unsigned char *Image::AutoAllocate = (unsigned char *)(-1);
00015
00016 Image::Image()
00017 : _size(0, 0), _type(UNKNOWN), _bytesPerPixel(0), _bytesPerRow(0),
00018 data(Image::Discard), buffer(NULL), bytesAllocated(0),
00019 refCount(NULL), mutex(NULL),
00020 memMapped(false), holdingLock(false) {
00021 }
00022
00023 Image::Image(int w, int h, ImageFormat f)
00024 : _size(w, h),
00025 _type(f),
00026 _bytesPerPixel(FCam::bytesPerPixel(f)),
00027 _bytesPerRow(bytesPerPixel()*width()),
00028 data(NULL), buffer(NULL), bytesAllocated(0),
00029 refCount(NULL), mutex(NULL),
00030 memMapped(false),
00031 holdingLock(false) {
00032
00033 bytesAllocated = bytesPerRow()*height();
00034 setBuffer(new unsigned char[bytesAllocated]);
00035 refCount = new unsigned;
00036 *refCount = 1;
00037 mutex = new pthread_mutex_t;
00038 pthread_mutex_init(mutex, NULL);
00039 }
00040
00041 Image::Image(Size s, ImageFormat f)
00042 : _size(s),
00043 _type(f),
00044 _bytesPerPixel(FCam::bytesPerPixel(f)),
00045 _bytesPerRow(bytesPerPixel()*width()),
00046 data(NULL), buffer(NULL), bytesAllocated(0),
00047 refCount(NULL), mutex(NULL),
00048 memMapped(false),
00049 holdingLock(false) {
00050
00051 bytesAllocated = bytesPerRow()*height();
00052 setBuffer(new unsigned char[bytesAllocated]);
00053 refCount = new unsigned;
00054 *refCount = 1;
00055 mutex = new pthread_mutex_t;
00056 pthread_mutex_init(mutex, NULL);
00057 }
00058
00059 Image::Image(int fd, int offset, Size s, ImageFormat f, bool writeThrough)
00060 : _size(s),
00061 _type(f),
00062 _bytesPerPixel(FCam::bytesPerPixel(f)),
00063 _bytesPerRow(bytesPerPixel()*width()),
00064 data(NULL), buffer(NULL), bytesAllocated(0),
00065 refCount(NULL), mutex(NULL),
00066 memMapped(true),
00067 holdingLock(false) {
00068
00069 unsigned char *mappedBuffer;
00070 int flags;
00071 if (writeThrough) {
00072 flags = MAP_SHARED;
00073 } else {
00074 flags = MAP_PRIVATE;
00075 }
00076
00077 int pageSize = getpagesize();
00078 int startOfMap = (offset/pageSize)*pageSize;
00079 int mapOffset = offset-startOfMap;
00080
00081 int bytesToMap = bytesPerRow()*height()+mapOffset;
00082 bytesAllocated = ((bytesToMap-1)/pageSize+1) *pageSize;
00083 dprintf(5,
00084 "Image::Image(): Mapping image from file %d. "
00085 "Requsted start %x, length %x. "
00086 "Actual start: %x, offset %x, length %x\n",
00087 fd, offset, bytesPerRow()*height(),
00088 startOfMap, offset, bytesAllocated);
00089
00090 mappedBuffer = (unsigned char *)mmap(NULL,
00091 bytesAllocated,
00092 PROT_READ | PROT_WRITE,
00093 flags,
00094 fd,
00095 startOfMap);
00096
00097 if (mappedBuffer == MAP_FAILED) {
00098 error(Event::InternalError,
00099 "Image: Unable to memory map file descriptor %d at %d, length %d bytes: %s",
00100 fd, offset, bytesPerRow()*height(), strerror(errno)
00101 );
00102 return;
00103 }
00104
00105 int success;
00106
00107 #ifdef FCAM_PLATFORM_CYGWIN
00108
00109
00110
00111
00112
00113
00114
00115 success =0;
00116 #else
00117 success = madvise(mappedBuffer, bytesAllocated, MADV_SEQUENTIAL);
00118 if (success != 0) {
00119 warning(Event::InternalError,
00120 "Image: Unable to call madvise successfully. Performance may be impacted: %s", strerror(errno));
00121 }
00122 #endif
00123
00124 setBuffer(mappedBuffer, mappedBuffer+mapOffset);
00125 refCount = new unsigned;
00126 *refCount = 1;
00127 mutex = new pthread_mutex_t;
00128 pthread_mutex_init(mutex, NULL);
00129 }
00130
00131 Image::Image(Size s, ImageFormat f, unsigned char *d, int srcBytesPerRow)
00132 : _size(s),
00133 _type(f),
00134 _bytesPerPixel(FCam::bytesPerPixel(f)),
00135 data(NULL), buffer(NULL), bytesAllocated(0),
00136 refCount(NULL), mutex(NULL),
00137 memMapped(false),
00138 holdingLock(false) {
00139
00140 _bytesPerRow = (srcBytesPerRow == -1) ? (bytesPerPixel() * width()) : srcBytesPerRow;
00141 setBuffer(NULL, d);
00142
00143 if (valid()) {
00144 refCount = new unsigned;
00145 *refCount = 2;
00146 mutex = new pthread_mutex_t;
00147 pthread_mutex_init(mutex, NULL);
00148 }
00149 }
00150
00151 Image::Image(int w, int h, ImageFormat f, unsigned char *d, int srcBytesPerRow)
00152 : _size(w, h),
00153 _type(f),
00154 _bytesPerPixel(FCam::bytesPerPixel(f)),
00155 data(NULL), buffer(NULL), bytesAllocated(0),
00156 refCount(NULL), mutex(NULL),
00157 memMapped(false),
00158 holdingLock(false) {
00159
00160 _bytesPerRow = (srcBytesPerRow == -1) ? (bytesPerPixel() * width()) : srcBytesPerRow;
00161 setBuffer(NULL, d);
00162
00163 if (valid()) {
00164 refCount = new unsigned;
00165 *refCount = 2;
00166 mutex = new pthread_mutex_t;
00167 pthread_mutex_init(mutex, NULL);
00168 }
00169 }
00170
00171 Image::~Image() {
00172 setBuffer(NULL);
00173 }
00174
00175 Image::Image(const Image &other)
00176 : _size(other.size()),
00177 _type(other.type()),
00178 _bytesPerPixel(other.bytesPerPixel()),
00179 _bytesPerRow(other.bytesPerRow()),
00180 data(other.data), buffer(other.buffer),
00181 bytesAllocated(other.bytesAllocated),
00182 refCount(other.refCount),
00183 mutex(other.mutex),
00184 memMapped(other.memMapped),
00185 holdingLock(false) {
00186 if (refCount) {
00187 (*refCount)++;
00188 }
00189 };
00190
00191 const Image &Image::operator=(const Image &other) {
00192 if (this == &other) { return (*this); }
00193 if (refCount &&
00194 refCount == other.refCount &&
00195 data == other.data) {
00196 return (*this);
00197 }
00198
00199 _size = other.size();
00200 _type = other.type();
00201 _bytesPerPixel = other.bytesPerPixel();
00202 _bytesPerRow = other.bytesPerRow();
00203 setBuffer(other.buffer, other.data);
00204 bytesAllocated = other.bytesAllocated;
00205
00206 refCount = other.refCount;
00207 mutex = other.mutex;
00208 if (refCount) { (*refCount)++; }
00209 memMapped = other.memMapped;
00210 holdingLock = false;
00211
00212 return (*this);
00213 }
00214
00215 Image Image::subImage(unsigned int x, unsigned int y, Size s) const {
00216 Image sub;
00217
00218 if (!valid() ||
00219 x >= width() ||
00220 y >= height()) {
00221 return sub;
00222 }
00223
00224 if (x + s.width > width()) {
00225 s.width = width() - x;
00226 }
00227 if (y + s.height > height()) {
00228 s.height = height() - y;
00229 }
00230
00231 sub = Image(s, type(), Image::Discard, bytesPerRow());
00232
00233 unsigned int offset = x*bytesPerPixel()+y*bytesPerRow();
00234 sub.setBuffer(buffer, data+offset);
00235 sub.bytesAllocated = bytesAllocated;
00236 sub.refCount = refCount;
00237 sub.mutex = mutex;
00238 sub.memMapped = memMapped;
00239
00240 if (refCount) { (*refCount)++; }
00241
00242 return sub;
00243 }
00244
00245 Image Image::copy() const {
00246 Image duplicate;
00247 if (!valid()) {
00248
00249 duplicate = Image(size(), type(), data);
00250 } else {
00251
00252 duplicate = Image(size(), type());
00253 duplicate.copyFrom(*this);
00254 }
00255
00256 return duplicate;
00257 }
00258
00259 void Image::copyFrom(const Image &srcImage) {
00260 if (!valid()) { return; }
00261 int h = std::min(srcImage.height(),
00262 height());
00263 int widthBytes =
00264 std::min(srcImage.width()*srcImage.bytesPerPixel(),
00265 width()*bytesPerPixel());
00266
00267 unsigned char *src = srcImage.data;
00268 unsigned char *dst = data;
00269
00270 for (int y=0; y < h; y++) {
00271 memcpy(dst, src, widthBytes);
00272 dst += bytesPerRow();
00273 src += srcImage.bytesPerRow();
00274 }
00275 }
00276
00277 void Image::setBuffer(unsigned char *b, unsigned char *d) {
00278 if (holdingLock) { pthread_mutex_unlock(mutex); }
00279 holdingLock = false;
00280
00281 if (refCount) {
00282 (*refCount)--;
00283
00284 if (mutex && (*refCount == 0 || (weak() && *refCount == 1))) {
00285 pthread_mutex_destroy(mutex);
00286 delete mutex;
00287 mutex = NULL;
00288 }
00289
00290 if (*refCount == 0) {
00291 delete refCount;
00292 if (memMapped) {
00293 int success = munmap(buffer, bytesAllocated);
00294 if (success == -1) {
00295 error(Event::InternalError,
00296 "Image::setBuffer: Unable to unmap memory mapped region starting at %x of size %d: %s",
00297 buffer, bytesAllocated, strerror(errno));
00298 }
00299 } else {
00300 delete[] buffer;
00301 }
00302 }
00303 refCount = NULL;
00304 mutex = NULL;
00305 }
00306
00307 if (b == Image::Discard ||
00308 b == Image::AutoAllocate) {
00309 buffer = NULL;
00310 } else {
00311 buffer = b;
00312 }
00313 if (d == NULL) { d = b; }
00314
00315
00316 data = d;
00317 }
00318
00319 bool Image::lock(int timeout) {
00320 if (holdingLock) {
00321 error(Event::ImageLockError, "Image reference trying to acquire lock it's already "
00322 "holding. Make a separate image reference per thread.\n");
00323 } else if (!mutex) {
00324 error(Event::InternalError, "Locking an image with no mutex\n");
00325 holdingLock = false;
00326 } else if (timeout < 0) {
00327 pthread_mutex_lock(mutex);
00328 holdingLock = true;
00329 } else if (timeout == 0) {
00330 int ret = pthread_mutex_trylock(mutex);
00331 holdingLock = (ret == 0);
00332 } else {
00333 struct timespec t = (struct timespec)(Time::now() + timeout);
00335 #ifdef FCAM_ARCH_X86
00336 int ret = pthread_mutex_trylock(mutex);
00337 #else
00338 int ret = pthread_mutex_timedlock(mutex, &t);
00339 #endif
00340 holdingLock = (ret == 0);
00341 }
00342
00343 return holdingLock;
00344 }
00345
00346 void Image::unlock() {
00347 if (!holdingLock) {
00348 error(Event::ImageLockError, "Cannot unlock a lock not held by this image reference");
00349 return;
00350 }
00351 if (!mutex) {
00352 error(Event::InternalError, "Unlocking an image with no mutex");
00353 debug();
00354 return;
00355 }
00356 pthread_mutex_unlock(mutex);
00357 holdingLock = false;
00358 }
00359
00360 bool Image::operator==(const Image &other) const {
00361 if (data != other.data) { return false; }
00362 if (width() != other.width()) { return false; }
00363 if (height() != other.height()) { return false; }
00364 if (type() != other.type()) { return false; }
00365
00366 return true;
00367 }
00368
00369 void Image::debug(const char *name) const {
00370 printf("\tImage %s at %px with dimensions %d %d type %d\n"
00371 "\t bytes per pixel %d bytes per row %d\n"
00372 "\t data %px buffer %px\n"
00373 "\t refCount %px = (%d), mutex %llx, memmapped %s, holdingLock %s\n",
00374 name,
00375 this,
00376 width(), height(),
00377 type(),
00378 bytesPerPixel(),
00379 bytesPerRow(),
00380 data,
00381 buffer,
00382 refCount,
00383 refCount ? *refCount : 0,
00384 (long long unsigned)mutex,
00385 (memMapped ? "true" : "false"),
00386 (holdingLock ? "true" : "false"));
00387 }
00388
00389 }
00390
00391
00392
00393