00001 /*!@file GUI/QtDisplayStream.C FrameOstream subclass that displays images in a QWidgetStack */ 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/GUI/QtDisplayStream4.C $ 00035 // $Id: QtDisplayStream4.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #include "GUI/QtDisplayStream4.H" 00039 00040 #include "Component/GlobalOpts.H" 00041 #include "Component/ModelOptionDef.H" 00042 #include "GUI/QtImageStack.qt.H" 00043 #include "Image/Image.H" 00044 #include "Image/Pixels.H" 00045 #include "QtUtil/ImageConvert4.H" 00046 #include "QtUtil/Util.H" // for argv2qt() 00047 #include "Raster/GenericFrame.H" 00048 #include "Transport/FrameInfo.H" 00049 #include "Transport/FrameOstreamFactory.H" 00050 #include "Transport/TransportOpts.H" 00051 #include "Util/sformat.H" 00052 00053 #include <QtGui/QApplication> 00054 #include <QtGui/QPixmap> 00055 #include <QtCore/QReadWriteLock> 00056 00057 // Used by: QtDisplayStream 00058 const ModelOptionDef OPT_QdisplayEcho = 00059 { MODOPT_ARG_STRING, "QdisplayEcho", &MOC_OUTPUT, OPTEXP_CORE, 00060 "Optional output destination for screen-grabs of the Qt display frames.", 00061 "qdisplay-echo", '\0', "<raster|display|mpeg|none>", "none" }; 00062 00063 // Used by: QtDisplayStream 00064 const ModelOptionDef OPT_QdisplayPrefDims = 00065 { MODOPT_ARG(Dims), "QdisplayPrefDims", &MOC_OUTPUT, OPTEXP_CORE, 00066 "Preferred scaled dimensions for Qt display frames, " 00067 "or 0x0 for no preference", 00068 "qdisplay-pref-dims", '\0', "<WxH>", "640x480" }; 00069 00070 // Used by: QtDisplayStream 00071 const ModelOptionDef OPT_QdisplayPrefMaxDims = 00072 { MODOPT_ARG(Dims), "QdisplayPrefMaxDims", &MOC_OUTPUT, OPTEXP_CORE, 00073 "If an image larger than these dimensions is sent to a Qt display " 00074 "frame, initially scale it down to smaller than these dimensions " 00075 "(you can always scale it up later by using the buttons on the " 00076 "Qt display widget", 00077 "qdisplay-pref-max-dims", '\0', "<WxH>", "1600x1200" }; 00078 00079 #define EVT_WRITEFRAME (QEvent::User) 00080 #define EVT_REMOVEFRAME ((QEvent::Type)(int(QEvent::User) + 1)) 00081 00082 namespace 00083 { 00084 // ###################################################################### 00085 void *qapp_thread_run(void *c) 00086 { 00087 QtDisplayStream *d = reinterpret_cast<QtDisplayStream *>(c); 00088 return d->run(); 00089 } 00090 00091 // ###################################################################### 00092 class QEventWriteFrame : public QEvent 00093 { 00094 public: 00095 QEventWriteFrame(const GenericFrame& fram, const std::string& shortnam, const FrameInfo& auxinf) 00096 : QEvent(EVT_WRITEFRAME), frame(fram), shortname(shortnam), auxinfo(auxinf) { } 00097 virtual ~QEventWriteFrame() { } 00098 00099 const GenericFrame frame; 00100 const std::string shortname; 00101 const FrameInfo auxinfo; 00102 }; 00103 00104 // ###################################################################### 00105 class QEventRemoveFrame : public QEvent 00106 { 00107 public: 00108 QEventRemoveFrame(const std::string& shortnam) : QEvent(EVT_REMOVEFRAME), shortname(shortnam) { } 00109 virtual ~QEventRemoveFrame() { } 00110 00111 const std::string shortname; 00112 }; 00113 } 00114 00115 // ###################################################################### 00116 //! class to filter events 00117 class EventFilt : public QObject { 00118 public: 00119 EventFilt(QtDisplayStream *master) : m(master) { } 00120 00121 virtual ~EventFilt() { } 00122 00123 protected: 00124 virtual bool eventFilter(QObject *obj, QEvent *event) 00125 { 00126 if (obj == m->itsWidget) { 00127 if (event->type() == EVT_WRITEFRAME) 00128 { 00129 QEventWriteFrame *e = static_cast<QEventWriteFrame*>(event); 00130 m->itsWidget->addFrame(e->frame, e->shortname, e->auxinfo); 00131 if (!m->itsShown && !m->itsTestMode.getVal()) { m->itsShown = true; m->itsWidget->show(); } 00132 return true; // the event queue will delete the event 00133 } 00134 else if (event->type() == EVT_REMOVEFRAME) 00135 { 00136 QEventRemoveFrame *e = static_cast<QEventRemoveFrame*>(event); 00137 m->itsWidget->removeFrame(e->shortname); 00138 return true; // the event queue will delete the event 00139 } 00140 else 00141 return false; 00142 } 00143 00144 // else, pass the event on to the parent class: 00145 return QObject::eventFilter(obj, event); 00146 } 00147 00148 private: 00149 QtDisplayStream *m; 00150 }; 00151 00152 00153 // ###################################################################### 00154 QtDisplayStream::QtDisplayStream(OptionManager& mgr, 00155 const std::string& descrName, 00156 const std::string& tagName) : 00157 FrameOstream(mgr, descrName, tagName), 00158 itsQtEcho(&OPT_QdisplayEcho, this), 00159 itsPreferredDims(&OPT_QdisplayPrefDims, this), 00160 itsPreferredMaxDims(&OPT_QdisplayPrefMaxDims, this), 00161 itsTestMode(&OPT_TestMode, this), 00162 itsWidget(0), itsFilter(0), 00163 itsShown(false), 00164 itsFrameNumber(-1), 00165 itsEcho(), itsReady(false) 00166 { } 00167 00168 // ###################################################################### 00169 void QtDisplayStream::start1() 00170 { 00171 // get our thread going and our app started: 00172 if (0 != pthread_create(&runner, NULL, &qapp_thread_run, this)) LFATAL("couldn't create thread for QApplication"); 00173 00174 while(itsReady == false) usleep(10000); 00175 } 00176 00177 // ###################################################################### 00178 QtDisplayStream::~QtDisplayStream() 00179 { 00180 itsWidget->deleteLater(); 00181 } 00182 00183 // ###################################################################### 00184 void* QtDisplayStream::run() 00185 { 00186 // this runs in a thread dedicated to handling the display and events 00187 const char* dpy = getenv("DISPLAY"); 00188 const bool havedpy = (dpy != 0 && dpy[0] != '\0'); 00189 if (!havedpy) { 00190 if (setenv("DISPLAY", ":0.0", 1) == 0) LINFO("DISPLAY environment variable not set; assuming DISPLAY=\":0.0\""); 00191 else LFATAL("DISPLAY environment variable not set; can't use Qt without a DISPLAY"); 00192 } 00193 00194 // create a QApplication: 00195 int argc = 1; const char* argv[1] = { "QtDisplayStream" }; 00196 QApplication *a = new QApplication(argc, argv2qt(argc, argv)); 00197 00198 // Create our widget: 00199 itsWidget = new QtImageStack; 00200 itsWidget->setPreferredDims(itsPreferredDims.getVal()); 00201 itsWidget->setPreferredMaxDims(itsPreferredMaxDims.getVal()); 00202 00203 // Install an event filter so that we get called (in this thread) when new images come in: 00204 itsFilter = new EventFilt(this); 00205 itsWidget->installEventFilter(itsFilter); 00206 00207 // ready to rock: 00208 itsReady = true; 00209 00210 // main loop for QApplication: 00211 const int result = a->exec(); 00212 LDEBUG("QApplication exit status %d", result); 00213 return reinterpret_cast<void*>(result); 00214 } 00215 00216 // ###################################################################### 00217 void QtDisplayStream::paramChanged(ModelParamBase* const param, 00218 const bool valueChanged, 00219 ParamClient::ChangeStatus* status) 00220 { 00221 FrameOstream::paramChanged(param, valueChanged, status); 00222 00223 if (param == &itsQtEcho && itsQtEcho.getVal().length() > 0) 00224 { 00225 if (itsQtEcho.getVal().compare("none") == 0) 00226 { 00227 if (itsEcho.is_valid()) this->removeSubComponent(*itsEcho); 00228 itsEcho = nub::soft_ref<FrameOstream>(); 00229 } 00230 else 00231 { 00232 itsEcho = makeFrameOstream(itsQtEcho.getVal(), this->getManager()); 00233 this->addSubComponent(itsEcho); 00234 itsEcho->exportOptions(MC_RECURSE); 00235 } 00236 } 00237 } 00238 00239 // ###################################################################### 00240 bool QtDisplayStream::setFrameNumber(int n) 00241 { 00242 if (itsFrameNumber != n) 00243 { 00244 if (itsEcho.is_valid()) 00245 { 00246 QPixmap pixmap = QPixmap::grabWidget(itsWidget); 00247 Image<PixRGB<byte> > img = convertToImage4(pixmap); 00248 itsEcho->setFrameNumber(n); 00249 itsEcho->writeRGB(img, "qtecho"); 00250 } 00251 00252 itsFrameNumber = n; 00253 } 00254 00255 return itsWidget->setFrameNumber(n); 00256 } 00257 00258 // ###################################################################### 00259 void QtDisplayStream::writeFrame(const GenericFrame& frame, 00260 const std::string& shortname, 00261 const FrameInfo& auxinfo) 00262 { 00263 QEventWriteFrame *event = new QEventWriteFrame(frame, shortname, auxinfo); 00264 QApplication::postEvent(itsWidget, event); 00265 } 00266 00267 // ###################################################################### 00268 bool QtDisplayStream::isVoid() const 00269 { 00270 return itsWidget->isClosed(); 00271 } 00272 00273 // ###################################################################### 00274 void QtDisplayStream::closeStream(const std::string& shortname) 00275 { 00276 QEventRemoveFrame *event = new QEventRemoveFrame(shortname); 00277 QApplication::postEvent(itsWidget, event); 00278 } 00279 00280 // ###################################################################### 00281 bool QtDisplayStream::isClosed() const 00282 { 00283 return itsWidget->isClosed(); 00284 } 00285 00286 // ###################################################################### 00287 /* So things look consistent in everyone's emacs... */ 00288 /* Local Variables: */ 00289 /* mode: c++ */ 00290 /* indent-tabs-mode: nil */ 00291 /* End: */