/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2012 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLIO/src/SharedMemoryGrabber.cpp ** ** Module : ICLIO ** ** Authors: Christof Elbrechter, Viktor Richter ** ** ** ** ** ** Commercial License ** ** ICL can be used commercially, please refer to our website ** ** www.iclcv.org for more details. ** ** ** ** GNU General Public License Usage ** ** Alternatively, this file may be used under the terms of the ** ** GNU General Public License version 3.0 as published by the ** ** Free Software Foundation and appearing in the file LICENSE.GPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the GNU General Public License ** ** version 3.0 requirements will be met: ** ** http://www.gnu.org/copyleft/gpl.html. ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** *********************************************************************/ #include #include #include #include #include #include #include #include #include using namespace icl::utils; using namespace icl::core; namespace icl{ namespace io{ struct SharedMemoryGrabberImpl::Data{ Data():acquireMutex(QMutex::Recursive){} QSharedMemory mem; ImgBase *image; ImgBase *converted_image; bool omitDoubledFrames; // todo implement this feature! Time lastImageTimeStamp; Time lastValidImageGrabbed; ImageCompressor compressor; bool isNew(const Time &t, Grabber &g){ if(t == Time::null){ WARNING_LOG("SharedMemoryGrabber received image with null-TimeStamp while \"omit-doubled-frames\" feature was activated. Deactivating \"omit-doubled-frames\"-feature to avoid dead-locks!"); g.setPropertyValue("omit-doubled-frames", false); lastValidImageGrabbed = Time::now(); return true; }else if(lastImageTimeStamp == Time::null){ lastImageTimeStamp = t; lastValidImageGrabbed = Time::now(); return true; }else if(lastImageTimeStamp > t){ WARNING_LOG("SharedMemoryGrabber received an image with an older timestamp than the last one. Deactivating \"omit-doubled-frames\"-feature to avoid dead-locks!"); lastValidImageGrabbed = Time::now(); return true; }else if( (Time::now() - lastValidImageGrabbed).toSeconds() > 5){ WARNING_LOG("SharedMemoryGrabber alread waited 5 seconds for a new image which might be caused by an image source that does not provide usefull timestamps. Therefore the 'omit-doubled-frames'-property is deactivated automatically!"); g.setPropertyValue("omit-doubled-frames",false); return false; }else if(t == lastImageTimeStamp){ return false; }else{ lastValidImageGrabbed = Time::now(); lastImageTimeStamp = t; return true; } } QMutex acquireMutex; bool callbacksEnabled; struct CallbackCaller : public QThread{ SharedMemoryGrabberImpl *impl; SharedMemoryGrabberImpl::Data *data; CallbackCaller(SharedMemoryGrabberImpl *impl, SharedMemoryGrabberImpl::Data *data): impl(impl),data(data){ start(); } virtual void run(){ while(true){ while(!data->callbacksEnabled){ Thread::sleep(100); } impl->notifyNewImageAvailable(impl->acquireImage()); } } } *caller; }; SharedMemoryGrabberImpl::SharedMemoryGrabberImpl(const std::string &sharedMemorySegmentID) throw(ICLException): m_data(new Data){ m_data->image = 0; m_data->converted_image = 0; m_data->omitDoubledFrames = true; m_data->callbacksEnabled = false; m_data->caller = new Data::CallbackCaller(this,m_data); if(sharedMemorySegmentID.length()){ m_data->mem.setKey(sharedMemorySegmentID.c_str()); if(!m_data->mem.attach(QSharedMemory::ReadOnly)){ throw ICLException(str(__FUNCTION__)+": unable to connect to shared memory segment \"" + sharedMemorySegmentID + "\""); } } addProperty("format", "info", "RGB", "", 0, ""); addProperty("size", "info", "", "", 0, ""); addProperty("omit-doubled-frames", "flag", "", m_data->omitDoubledFrames, 0, ""); addProperty("enable-callbacks", "flag", "", m_data->callbacksEnabled, 0, ""); Configurable::registerCallback(utils::function(this,&SharedMemoryGrabberImpl::processPropertyChange)); } void SharedMemoryGrabberImpl::init(const std::string &sharedMemorySegmentID) throw (ICLException){ if(m_data->mem.isAttached()){ m_data->mem.lock(); m_data->mem.detach(); m_data->mem.setKey(sharedMemorySegmentID.c_str()); if(!m_data->mem.attach(QSharedMemory::ReadOnly)){ throw ICLException(str(__FUNCTION__)+": unable to connect to shared memory segment \"" + sharedMemorySegmentID + "\""); } m_data->mem.unlock(); }else{ m_data->mem.lock(); m_data->mem.setKey(sharedMemorySegmentID.c_str()); if(!m_data->mem.attach(QSharedMemory::ReadOnly)){ throw ICLException(str(__FUNCTION__)+": unable to connect to shared memory segment \"" + sharedMemorySegmentID + "\""); } m_data->mem.unlock(); } } SharedMemoryGrabberImpl::~SharedMemoryGrabberImpl(){ ICL_DELETE(m_data->image); ICL_DELETE(m_data->converted_image); delete m_data; } const std::vector &SharedMemoryGrabberImpl::getDeviceList(bool rescan){ static std::vector deviceList; if(rescan){ deviceList.clear(); QSharedMemory mem("icl-shared-mem-grabbers"); if(!mem.attach(QSharedMemory::ReadOnly)) { return deviceList; } mem.lock(); const char* list = (const char*)mem.constData(); icl32s num = *(icl32s*)list; list +=sizeof(icl32s); for(icl32s i=0;iacquireMutex); if(!m_data->mem.isAttached()) throw ICLException(str(__FUNCTION__)+": grabber is currently not attached to shared memory segment"); m_data->mem.lock(); while(m_data->omitDoubledFrames && // WAIT FOR NEW IMAGE LOOP !m_data->isNew(m_data->compressor.pickTimeStamp((const icl8u*)m_data->mem.constData()),*this) ){ m_data->mem.unlock(); Thread::msleep(1); m_data->mem.lock(); } m_data->compressor.uncompress((const icl8u*)m_data->mem.constData(), m_data->mem.size(), &m_data->image); m_data->mem.unlock(); setPropertyValue("size", m_data->image->getSize()); return m_data->image; } void SharedMemoryGrabber::resetBus(){ QSharedMemory mem("icl-shared-mem-grabbers"); if(mem.attach(QSharedMemory::ReadWrite)) { mem.lock(); *(icl32s*)mem.data() = 0; mem.unlock(); }else{ WARNING_LOG("No shared memory segment named 'icl-shared-mem-grabbers' found"); } #ifdef SYSTEM_LINUX static const std::string QT_SHARED_MEM_PREFIX = "0x51"; QStringList l; l << "-m"; QProcess ipcs; ipcs.start("ipcs",l); bool ok = ipcs.waitForFinished(); if(!ok) throw icl::ICLException("unable to call ipcm -m"); QString stdout = ipcs.readAllStandardOutput(); std::vector lines = icl::tok(stdout.toLatin1().data(),"\n"); for(unsigned int i=0;i ts = icl::tok(lines[i]," "); if(ts.size() > 3 && ts[3] == "666" && ts[0].substr(0,4) == QT_SHARED_MEM_PREFIX){ QProcess ipcrm; QStringList l2; l2 << "-m" << ts[1].c_str(); std::cout << "releasing shared memory segment key:" << ts[0] << " shmid:" << ts[1] << std::endl; ipcrm.start("ipcrm",l2); bool ok = ipcrm.waitForFinished(); if(!ok) throw icl::ICLException("unable to call ipcrm -m"); } } #endif } // callback for changed configurable properties void SharedMemoryGrabberImpl::processPropertyChange(const utils::Configurable::Property &prop){ if(prop.name == "omit-doubled-frames"){ m_data->omitDoubledFrames = parse(prop.value); if(!m_data->omitDoubledFrames && m_data->callbacksEnabled){ WARNING_LOG("setting omitDoubledFrames to false will also set callbacksEnabled to false"); setPropertyValue("enable-callbacks", false); } } else if(prop.name == "enable-callbacks"){ if(parse(prop.value) && !m_data->omitDoubledFrames) { WARNING_LOG("enabling enable-callbacks will also enable omitDoubledFrames"); setPropertyValue("omit-doubled-frames", true); } else { m_data->callbacksEnabled = parse(prop.value); } } } REGISTER_CONFIGURABLE(SharedMemoryGrabber, return new SharedMemoryGrabber("")); } // namespace io }