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/QtDisplayStream.C $ 00035 // $Id: QtDisplayStream.C 12269 2009-12-17 01:23:34Z itti $ 00036 // 00037 00038 #ifndef GUI_QTDISPLAYSTREAM_C_DEFINED 00039 #define GUI_QTDISPLAYSTREAM_C_DEFINED 00040 00041 #ifdef INVT_HAVE_QT3 00042 00043 #include "GUI/QtDisplayStream.H" 00044 00045 #include "Component/GlobalOpts.H" 00046 #include "Component/ModelOptionDef.H" 00047 #include "GUI/QtImageStack.H" 00048 #include "Image/Image.H" 00049 #include "Image/Pixels.H" 00050 #include "QtUtil/ImageConvert.H" 00051 #include "QtUtil/Util.H" // for argv2qt() 00052 #include "Transport/FrameOstreamFactory.H" 00053 #include "Transport/TransportOpts.H" 00054 #include "Util/sformat.H" 00055 00056 #include <qapplication.h> 00057 #include <qpixmap.h> 00058 00059 // Used by: QtDisplayStream 00060 const ModelOptionDef OPT_QdisplayEcho = 00061 { MODOPT_ARG_STRING, "QdisplayEcho", &MOC_OUTPUT, OPTEXP_CORE, 00062 "Optional output destination for screen-grabs of the Qt display frames.", 00063 "qdisplay-echo", '\0', "<raster|display|mpeg|none>", "none" }; 00064 00065 // Used by: QtDisplayStream 00066 const ModelOptionDef OPT_QdisplayPrefDims = 00067 { MODOPT_ARG(Dims), "QdisplayPrefDims", &MOC_OUTPUT, OPTEXP_CORE, 00068 "Preferred scaled dimensions for Qt display frames, " 00069 "or 0x0 for no preference", 00070 "qdisplay-pref-dims", '\0', "<WxH>", "640x480" }; 00071 00072 // Used by: QtDisplayStream 00073 const ModelOptionDef OPT_QdisplayPrefMaxDims = 00074 { MODOPT_ARG(Dims), "QdisplayPrefMaxDims", &MOC_OUTPUT, OPTEXP_CORE, 00075 "If an image larger than these dimensions is sent to a Qt display " 00076 "frame, initially scale it down to smaller than these dimensions " 00077 "(you can always scale it up later by using the buttons on the " 00078 "Qt display widget", 00079 "qdisplay-pref-max-dims", '\0', "<WxH>", "1600x1200" }; 00080 00081 namespace 00082 { 00083 QApplication* qapp = 0; 00084 00085 pthread_once_t qapp_init_once = PTHREAD_ONCE_INIT; 00086 pthread_t qapp_thread; 00087 00088 void* qapp_thread_run(void* app) 00089 { 00090 QApplication* a = static_cast<QApplication*>(app); 00091 00092 //a->connect(a, SIGNAL(lastWindowClosed()), 00093 // a, SLOT(quit())); 00094 00095 const int result = a->exec(); 00096 LDEBUG("QApplication exit status %d", result); 00097 return reinterpret_cast<void*>(result); 00098 } 00099 00100 void qapp_thread_init() 00101 { 00102 ASSERT(qapp == 0); 00103 00104 const char* dpy = getenv("DISPLAY"); 00105 const bool havedpy = (dpy != 0 && dpy[0] != '\0'); 00106 if (!havedpy) 00107 { 00108 if (setenv("DISPLAY", ":0.0", 1) == 0) 00109 LINFO("the DISPLAY environment variable is not set; " 00110 "assuming DISPLAY=\":0.0\""); 00111 else 00112 LFATAL("the DISPLAY environment variable is not set; " 00113 "can't use Qt without a DISPLAY"); 00114 } 00115 00116 // NOTE, there is a QApplication constructor that takes a 'bool 00117 // usegui' parameter that specifies whether or not a DISPLAY is 00118 // available; however we can't just pass usegui=false here, 00119 // because we'd still need a way to avoid constructing any QWidget 00120 // objects 00121 00122 int argc = 1; 00123 const char* argv[2] = { "QtDisplayStream", 0 }; 00124 qapp = new QApplication(argc, argv2qt(argc, argv)); 00125 00126 if (0 != pthread_create(&qapp_thread, NULL, &qapp_thread_run, qapp)) 00127 LFATAL("couldn't create thread for QApplication"); 00128 } 00129 } 00130 00131 // ###################################################################### 00132 class QAppLockClass 00133 { 00134 public: 00135 QAppLockClass(QApplication* qapp) : itsApp(qapp) 00136 { 00137 itsApp->lock(); 00138 } 00139 00140 ~QAppLockClass() 00141 { 00142 itsApp->unlock(); 00143 } 00144 00145 private: 00146 QAppLockClass(const QAppLockClass&); 00147 QAppLockClass& operator=(const QAppLockClass&); 00148 00149 QApplication* itsApp; 00150 }; 00151 00152 // ###################################################################### 00153 #define QAPP_LOCK(qapp) QAppLockClass anonymous_qapp_lock_(qapp) 00154 00155 // ###################################################################### 00156 QtDisplayStream::QtDisplayStream(OptionManager& mgr, 00157 const std::string& descrName, 00158 const std::string& tagName) 00159 : 00160 FrameOstream(mgr, descrName, tagName), 00161 itsQtEcho(&OPT_QdisplayEcho, this), 00162 itsPreferredDims(&OPT_QdisplayPrefDims, this), 00163 itsPreferredMaxDims(&OPT_QdisplayPrefMaxDims, this), 00164 itsTestMode(&OPT_TestMode, this), 00165 itsWidget(0), 00166 itsShown(false), 00167 itsFrameNumber(-1), 00168 itsEcho() 00169 { 00170 pthread_once(&qapp_init_once, &qapp_thread_init); 00171 00172 ASSERT(qapp != 0); 00173 00174 QAPP_LOCK(qapp); 00175 itsWidget = new QtImageStack; 00176 } 00177 00178 // ###################################################################### 00179 QtDisplayStream::~QtDisplayStream() 00180 { 00181 itsWidget->deleteLater(); 00182 } 00183 00184 // ###################################################################### 00185 void QtDisplayStream::paramChanged(ModelParamBase* const param, 00186 const bool valueChanged, 00187 ParamClient::ChangeStatus* status) 00188 { 00189 FrameOstream::paramChanged(param, valueChanged, status); 00190 00191 if (param == &itsQtEcho && itsQtEcho.getVal().length() > 0) 00192 { 00193 if (itsQtEcho.getVal().compare("none") == 0) 00194 { 00195 if (itsEcho.is_valid()) 00196 this->removeSubComponent(*itsEcho); 00197 00198 itsEcho = nub::soft_ref<FrameOstream>(); 00199 } 00200 else 00201 { 00202 itsEcho = makeFrameOstream(itsQtEcho.getVal(), 00203 this->getManager()); 00204 this->addSubComponent(itsEcho); 00205 itsEcho->exportOptions(MC_RECURSE); 00206 } 00207 } 00208 else if (param == &itsPreferredDims) 00209 { 00210 itsWidget->setPreferredDims(itsPreferredDims.getVal()); 00211 } 00212 else if (param == &itsPreferredMaxDims) 00213 { 00214 itsWidget->setPreferredMaxDims(itsPreferredMaxDims.getVal()); 00215 } 00216 } 00217 00218 // ###################################################################### 00219 bool QtDisplayStream::setFrameNumber(int n) 00220 { 00221 if (itsFrameNumber != n) 00222 { 00223 if (itsEcho.is_valid()) 00224 { 00225 QAPP_LOCK(qapp); 00226 QPixmap pixmap = QPixmap::grabWidget(itsWidget); 00227 Image<PixRGB<byte> > img = convertToImage(pixmap); 00228 itsEcho->setFrameNumber(n); 00229 itsEcho->writeRGB(img, "qtecho"); 00230 } 00231 00232 itsFrameNumber = n; 00233 } 00234 00235 return itsWidget->setFrameNumber(n); 00236 } 00237 00238 // ###################################################################### 00239 void QtDisplayStream::writeFrame(const GenericFrame& frame, 00240 const std::string& shortname, 00241 const FrameInfo& auxinfo) 00242 { 00243 QAPP_LOCK(qapp); 00244 itsWidget->addFrame(frame, shortname, auxinfo); 00245 if (!itsShown && !itsTestMode.getVal()) 00246 { itsShown = true; itsWidget->show(); } 00247 } 00248 00249 // ###################################################################### 00250 bool QtDisplayStream::isVoid() const 00251 { 00252 return itsWidget->isClosed(); 00253 } 00254 00255 // ###################################################################### 00256 void QtDisplayStream::closeStream(const std::string& shortname) 00257 { 00258 QAPP_LOCK(qapp); 00259 itsWidget->removeFrame(shortname); 00260 } 00261 00262 // ###################################################################### 00263 bool QtDisplayStream::isClosed() const 00264 { 00265 return itsWidget->isClosed(); 00266 } 00267 00268 #endif // INVT_HAVE_QT3 00269 00270 // ###################################################################### 00271 /* So things look consistent in everyone's emacs... */ 00272 /* Local Variables: */ 00273 /* mode: c++ */ 00274 /* indent-tabs-mode: nil */ 00275 /* End: */ 00276 00277 #endif // GUI_QTDISPLAYSTREAM_C_DEFINED