Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

SDLdisplay.H

Go to the documentation of this file.
00001 /*!@file GUI/SDLdisplay.H Fast full-screen displays using SDL */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2002   //
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: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/GUI/SDLdisplay.H $
00035 // $Id: SDLdisplay.H 11829 2009-10-10 00:01:18Z ilink $
00036 //
00037 
00038 #ifndef GUI_SDLDISPLAY_H_DEFINED
00039 #define GUI_SDLDISPLAY_H_DEFINED
00040 
00041 #ifdef HAVE_SDL_SDL_H
00042 
00043 #include "Component/ModelComponent.H"
00044 #include "Image/Image.H"
00045 #include "Image/Pixels.H"
00046 #include "Util/Timer.H"          // for Timer
00047 #include "Video/VideoFormat.H"
00048 #include "Component/EventLog.H"
00049 
00050 #include <list>
00051 #include <SDL/SDL.h>             // for SDL_Screen
00052 
00053 class VideoFrame;
00054 
00055 //! Class fo do various fast graphics displays
00056 /*! This class is to facilitate the display of various graphics
00057   stimuli, with an emphasis on strict real-time operation and in
00058   particular on playing movies at a controlled framerate with
00059   microsecond accuracy. Programs using this class, such as
00060   psycho-movie.C, should run as root if SCHED_FIFO scheduling is
00061   required (and I highly recommend it, as it will make timing
00062   reliable). The class uses the SDL library to do the displays. This
00063   class attempts to lock onto the display's vertical blanking for
00064   reliable timing of movie playing. Note that, as far as I know, SDL
00065   does not provide a way to select a screen refresh rate; instead, you
00066   need to specify the refresh rate in your X config. I used the
00067   modeline calculator at
00068   http://xtiming.sourceforge.net/cgi-bin/xtiming.pl to figure out good
00069   modelines for the refresh rates I wanted. For example: for a 120Hz
00070   640x480 display, I got:
00071 
00072   Modeline "640x480@120" 55.43 640 672 880 912 480 487 497 505
00073 
00074   which I added to the "Monitor" section of /etc/X11/XF86Config-4, and
00075   I also specified that this mode should be used by giving its name in
00076   the "Screen" section:
00077 
00078   Subsection "Display"
00079   Depth 24
00080   Modes "1280x1024" "1280x960" "1152x864" "1024x768" "800x600" "640x480@120"
00081   EndSubsection
00082 
00083   Always verify on the OSD info page of your monitor that you are
00084   actually getting the refresh rate you want.
00085 
00086   For 640x480 @ 60Hz doublescan, I use:
00087   Modeline "640x480@60d" 48.21 640 672 760 792 480 490 495 505 doublescan
00088 
00089   For 800x600 @ 60Hz (for LCD goggles):
00090   ModeLine "800x600@60" 40.0 800 840 968 1056 600 601 605 628 +hsync +vsync
00091 
00092   For standard VESA 640x480 @ 60Hz:
00093   Modeline "psycho"  25.2 640 656 752 800 480 490 492 525 -hsync -vsync
00094 */
00095 
00096 class SDLdisplay : public ModelComponent
00097 {
00098 public:
00099 
00100   /// Different types of inter-frame delay that can be requested
00101   enum DelayType
00102     {
00103       NO_WAIT,       ///< Don't wait at all between frames
00104       NEXT_VSYNC,    ///< Wait for the next vertical blanking period
00105       NEXT_FRAMETIME ///< Wait for the next frame time according to itsRefreshDelay
00106     };
00107 
00108   // ######################################################################
00109   /*! @name Constructors, destructor and initialization */
00110   //@{
00111 
00112   //! Constructor
00113   SDLdisplay(OptionManager& mgr,
00114              const std::string& descrName = "SDL Display",
00115              const std::string& tagName = "SDLdisplay");
00116 
00117   //! Destructor
00118   virtual ~SDLdisplay();
00119 
00120   //! Link us to an EventLog component
00121   /*! If an EventLog component is registered with us, we will send it
00122     lots of event messages, each time a frame or overlay is displayed,
00123     a key pressed, etc. */
00124   void setEventLog(nub::soft_ref<EventLog> elog);
00125 
00126   //@}
00127 
00128   // ######################################################################
00129   /*! @name General display property functions */
00130   //@{
00131 
00132   //! Get bytes per pixel
00133   inline int getBytesPerPixel() const;
00134 
00135   //! Get display dimensions, in pixels
00136   inline Dims getDims() const;
00137 
00138   //! Get display width, in pixels
00139   inline int getWidth() const;
00140 
00141   //! Get display height, in pixels
00142   inline int getHeight() const;
00143 
00144   //! Show or hide mouse pointer
00145   inline void showCursor(const bool showit);
00146 
00147   //@}
00148 
00149   // ######################################################################
00150   /*! @name Pixel-level functions */
00151   //@{
00152 
00153   //! Get the 32 bit color value corresponding to a given RGB pixel
00154   inline Uint32 getUint32color(const PixRGB<byte>& col) const;
00155 
00156   //! Get the RGB color triplet corresponding to a given Uint32 color
00157   inline PixRGB<byte> getRGBcolor(const Uint32 col) const;
00158 
00159   //@}
00160 
00161   // ######################################################################
00162   /*! @name Basic display and interaction functions */
00163   //@{
00164 
00165         //! open a SDL display
00166   void openDisplay();
00167 
00168         //! close a SDL display
00169   void closeDisplay();
00170 
00171   //! Lock the screen, as required before using some functions
00172   inline void lockScreen();
00173 
00174   //! Unlock the (previously locked) screen
00175   inline void unlockScreen();
00176 
00177   //! clear the screen
00178   /*! @param col the background color to use
00179       @param vsync will attempt to sync with vertical blanking if true */
00180   void clearScreen(const PixRGB<byte> col, const bool vsync = true);
00181 
00182   //! clear the video back buffer
00183   void clearBackBuffer();
00184 
00185   //! Return the pixel value at (x, y)
00186   // NOTE: The surface must be locked before calling this!
00187   Uint32 getPixel32(const int x, const int y) const;
00188 
00189   //! Set the pixel at (x, y) to the given value
00190   // NOTE: The surface must be locked before calling this!
00191   void putPixel32(const int x, const int y, const Uint32 pixel);
00192 
00193   //! show a text message
00194    /*! @param ind ind=0 displays the text in the middle of screen, ind =1 displays the text on top or the screen
00195    and ind = -1 displays the message at the buttom of the display
00196   */
00197   void displayText(const std::string& msg, const bool vsync,
00198                    const PixRGB<byte> txtcol, const PixRGB<byte> bgcol, int ind = 0 );
00199 
00200 //! show a text message in a given place
00201  void displayText(const std::string& msg,Point2D<int> p ,
00202                              const PixRGB<byte> txtcol,
00203                              const PixRGB<byte> bgcol,const bool vsync) ;
00204 
00205   //! Wait until start of the next vertical blanking, per our frame rate
00206   /*! The vertical blanking period is when the monitor's electron gun
00207     travels from the bottom of the screen back to the top. This
00208     function updates our itsLastSync data member with current time at
00209     start of vertical blanking pulse. Most display functions have a
00210     'vsync' argument and will call this function to perform the sync,
00211     so you usually never have to call this directly. It is provided
00212     here just in case. If checkdelay is true, we will log a warning if
00213     it has been more than one itsRefreshDelay period since the last
00214     time we were called. No logging is made if quiet is true,
00215     otherwise start and end times are logged.
00216 
00217     NOTE that this does not necessarily wait for just the next
00218     hardware vsync; instead we wait for the next hardware vsync that
00219     just precedes our next desired frame according to
00220     itsRefreshDelay. So even though your monitor may run at 60Hz or
00221     120Hz, if itsRefreshDelay is 33333us, your actual displayed frame
00222     rate will only be 30Hz when you use waitNextRequestedVsync(). */
00223   void waitNextRequestedVsync(const bool checkdelay = false,
00224                               const bool quiet = true);
00225 
00226   /// Wait for the next frame time, per our frame rate
00227   void waitNextRequestedFrameTime(const int frame,
00228                                   const bool checkdelay = false,
00229                                   const bool quiet = true);
00230 
00231   //! Wait for a number of frame periods
00232   /*! This just repeatedly calles waitNextRequestedVsync() */
00233   void waitFrames(const int n);
00234 
00235   //! Set a desired refresh delay in microseconds, and a fractional tolerance around that delay
00236   void setDesiredRefreshDelayUsec(float usec, float tol=0.05F);
00237   //@}
00238 
00239   // ######################################################################
00240   /*! @name Keyboard functions */
00241   //@{
00242 
00243   //! wait for a keypress and return character for key pressed
00244   /*!by default stdin is cleared try waitForKey(false) to keep stdin buffer */
00245   int waitForKey(bool doWait=true);
00246 
00247 //! wait for a mouseclick and return 1 for left button click and 2 for right button click
00248   /*!by default stdin is cleared try waitForMouseClick(false) to keep stdin buffer */
00249   int waitForMouseClick(bool doWait=true) ;
00250 long getTimerValue() ;
00251 
00252 int waitForMouseWheelEvent(bool doWait=true) ;
00253   //! check whether a mouseclick has occurred and return 1 for key left button clicked and 2 for right button clicked
00254   /*! a value of -1 is returned if no mouse click event occured */
00255   int checkForMouseClick() ;
00256 
00257   //! check whether a keypress has occurred and return char for key pressed
00258   /*! a value of -1 is returned if no keypress occured */
00259   int checkForKey();
00260 
00261 
00262   //! store the string of keypresses input by the user until the terminating character has been reached
00263   /*!  */
00264   std::string getString(char terminator);
00265 
00266 
00267   //@}
00268 
00269   // ######################################################################
00270   /*! @name Image blitting functions */
00271   //@{
00272 
00273   //! Display an image, centered over the screen area
00274   /*! If you want to display an image that is smaller than the display
00275     area at a well-defined location on the screen, see
00276     displayImagePatch(). This just calls makeBlittableSurface()
00277     followed by displaySurface(). It is often beneficial to use these
00278     other two functions for real-time applications, first preparing
00279     your surfaces when you have some extra available time, and then
00280     getting a faster blit. */
00281   void displayImage(const Image< PixRGB<byte> >& img,
00282                     const bool resiz = false,
00283                     const PixRGB<byte> bgcol = PixRGB<byte>(0, 0, 0),
00284                     const int frame = -1, const bool vsync = true);
00285 
00286   //! Make a blittable surface from an Image
00287   /*! The resulting surface can be displayed using displaySurface(). It
00288     should be freed using SDL_FreeSurface()
00289     @param img the image to be displayed
00290     @param resiz if true, the image will be resized such as to fill-up
00291            at least one dimension of the display (but aspect ratio
00292            will be maintained, and possible borders filled with bgcol)
00293     @param bgcol background color to use around image if image has
00294            different aspect ratio from screen */
00295   SDL_Surface *makeBlittableSurface(const Image< PixRGB<byte> >& img,
00296                                     const bool resiz = false,
00297                                     const PixRGB<byte> bgcol =
00298                                     PixRGB<byte>(0, 0, 0));
00299 
00300   //! Display an SDL surface that has been pre-formatted for fast blitting
00301   /*! @param img a pre-formatted image; no rescaling will be attempted
00302              and it will just be blitted into the screen. Suitable surfaces
00303              may be obtained by makeBlittableSurface()
00304       @param frame this is just used for the log messages; if it is -1 then
00305              no frame number/duration are logged; if it is -2 both the
00306              start and end of the function execution are logged
00307       @param vsync will attempt to sync with vertical blanking if true */
00308   void displaySurface(SDL_Surface *img, const int frame = -1,
00309                     const bool vsync = true);
00310 
00311 
00312   //! Display an image patch
00313   /*! @param image an image patch
00314       @param pos the position of the top-left corner of the image
00315       @param frame this is just used for the log messages; if it is -1 then
00316              no frame number/duration are logged; if it is -2 both the
00317              start and end of the function execution are logged
00318       @param vsync will attempt to sync with vertical blanking if true */
00319   void displayImagePatch(const Image< PixRGB<byte> >& image,
00320                          const Point2D<int>& pos, const int frame = -1,
00321                          const bool vsync = true, const bool flip = true);
00322 
00323   //@}
00324  // ######################################################################
00325  //! Display an SDLSurface patch on thescreen
00326   /*! @param surf a pointer to a SDL_Surface
00327       @param offset a pointer to a SDL_Rect which encapsulates the offset
00328       @param clip a pointer to a SDL_Rect which encapsulates the clip to be shown from surf
00329       @param frame this is just used for the log messages; if it is -1 then
00330              no frame number/duration are logged; if it is -2 both the
00331              start and end of the function execution are logged
00332       @param vsync will attempt to sync with vertical blanking if true
00333       @param flip will attempt to flip if true
00334  */
00335   void displaySDLSurfacePatch(SDL_Surface* surf , SDL_Rect* offset , SDL_Rect* clip , const int frame=-2,
00336                                    const bool vsync = true, const bool flip = true);
00337 
00338   // ######################################################################
00339   /*! @name YUV overlay functions */
00340   //@{
00341 
00342   //! Check whether somebody has already created a YUV overlay for this display
00343   bool hasYUVoverlay() const;
00344 
00345   //! create a YUV overlay of specified size
00346   /*! All the other overlay functions will throw a fatal error if no
00347     overlay has been created. */
00348   void createYUVoverlay(const Uint32 format, const int w, const int h);
00349 
00350   //! create a YUV overlay
00351   /*! All the other overlay functions will throw a fatal error if no
00352     overlay has been created. */
00353   void createYUVoverlay(const Uint32 format);
00354 
00355   //! destroy a previously-created YUV overlay
00356   /*! Overlay displays and normal displays don't mix well in SDL. So,
00357     typically, you would create the overlay just before playing a
00358     movie in YUV mode, then play the movie, then clear the screen and
00359     destroy the overlay, do a few normal displays (like a fixation
00360     cross, some text, etc), and loop. */
00361   void destroyYUVoverlay();
00362 
00363   //! Lock YUV overlay and get a pointer to it for direct access to pixel data
00364   /*! And what can you do with the pixel data? see psycho-movie.C and
00365     pvisionTCP3-master.C for examples of how to fill it from either
00366     raw MPEG movie frames or from an Image<PixRGB<byte> >. */
00367   SDL_Overlay* lockYUVoverlay();
00368 
00369   //! Unlock YUV overlay
00370   void unlockYUVoverlay();
00371 
00372   //! display current YUV overlay
00373   void displayYUVoverlay(const int frame, const DelayType dly, const int x,
00374                          const int y, const int w, const int h);
00375 
00376   //! display current YUV overlay
00377   void displayYUVoverlay(const int frame, const DelayType w);
00378 
00379   //! test whether we can do video overlays in the given frame format
00380   bool supportsVideoOverlay(const VideoFormat vidformat) const;
00381 
00382   //! create a YUV overlay of specific size from a video format
00383   /*! All the other overlay functions will throw a fatal error if no
00384     overlay has been created. */
00385   void createVideoOverlay(const VideoFormat vidformat,
00386                             const int w, const int h);
00387 
00388   //! create a YUV overlay from a video format
00389   /*! All the other overlay functions will throw a fatal error if no
00390     overlay has been created. */
00391   void createVideoOverlay(const VideoFormat vidformat);
00392 
00393   //! copy video data to the current YUV overlay, and display it
00394   void displayVideoOverlay(const VideoFrame& buf,
00395                            const int frame, const DelayType w);
00396 
00397   //! copy video data to the current YUV overlay, and display it
00398   //  at location x, y of the screen and new size rw, rh
00399   void displayVideoOverlay_pos(const VideoFrame& buf,
00400                            const int frame, const DelayType w,
00401                            const int x, const int y,
00402                            const int rw, const int rh);
00403 
00404   //! overlay an image onto a video, the copy it to the current YUV overlay, 
00405   //  displaying it
00406   void displayVideoOverlay_image(const VideoFrame& frame,
00407                                  const int framenum,
00408                                  const DelayType dly,
00409                                  const Image<PixRGB<byte> >& img, 
00410                                  const PixRGB<byte>& transpix,
00411                                  const uint threads = 1);
00412 
00413   //@}
00414 
00415   // ######################################################################
00416   /*! @name Event logging functions */
00417   //@{
00418 
00419   //! Pass-through to EventLog::pushEvent()
00420   /*! Note that this is a no-op if no EventLog has been registered
00421     with us through a call to setEventLog(). */
00422   inline void pushEvent(const std::string& msg);
00423 
00424   //! Pass-through to EventLog::pushEventBegin()
00425   /*! Note that this is a no-op if no EventLog has been registered
00426     with us through a call to setEventLog(). */
00427   inline void pushEventBegin(const std::string& msg);
00428 
00429   //! Pass-through to EventLog::pushEventEnd()
00430   /*! Note that this is a no-op if no EventLog has been registered
00431     with us through a call to setEventLog(). */
00432   inline void pushEventEnd(const std::string& msg);
00433 
00434   //@}
00435 
00436 protected:
00437   OModelParam<Dims> itsDims;      //!< screen resolution
00438   OModelParam<int> itsPriority;   //!< priority for SCHED_FIFO, or 0 for normal
00439   OModelParam<float> itsRefreshDelay; //!< desired refresh delay in usec
00440   OModelParam<bool> itsFullscreen; //!< whether to run in a fullscreen window
00441   NModelParam<bool> itsSlaveMode;  //!< slave mode (someone else opens screen)
00442 
00443   void start2();  //!< get started
00444   void stop1();   //!< get stopped
00445 
00446   Timer itsTimer;           // keep track of time
00447   uint64 itsLastSync;       // time of last screen sync
00448   uint64 itsLastOvlDisplay; // time of overlay display
00449 
00450   float itsRefreshTolerance;// fraction of refresh delay that we allow before marking frames as SLOW or FAST
00451 
00452   // update double-buffering and sync to vertical blanking:
00453   void syncScreen(const bool vsync = true, const bool checkdelay = false,
00454                   const bool quiet = false);
00455 
00456   // display stuff using SDL:
00457   SDL_Surface *itsScreen;
00458   SDL_Overlay *itsOverlay;
00459   SDL_Overlay *videoOverlay;
00460 
00461 private:
00462   // log stuff if desired:
00463   nub::soft_ref<EventLog> itsEventLog;
00464 };
00465 
00466 // ######################################################################
00467 // ######################################################################
00468 // ####################      Inlined functions       ####################
00469 // ######################################################################
00470 // ######################################################################
00471 
00472 // ######################################################################
00473 inline Dims SDLdisplay::getDims() const
00474 { return itsDims.getVal(); }
00475 
00476 // ######################################################################
00477 inline int SDLdisplay::getWidth() const
00478 { return itsDims.getVal().w(); }
00479 
00480 // ######################################################################
00481 inline int SDLdisplay::getHeight() const
00482 { return itsDims.getVal().h(); }
00483 
00484 // ######################################################################
00485 inline int SDLdisplay::getBytesPerPixel() const
00486 { return itsScreen->format->BytesPerPixel; }
00487 
00488 // ######################################################################
00489 inline Uint32 SDLdisplay::getUint32color(const PixRGB<byte>& col) const
00490 { return SDL_MapRGB(itsScreen->format, col.red(), col.green(), col.blue()); }
00491 
00492 // ######################################################################
00493 inline PixRGB<byte> SDLdisplay::getRGBcolor(const Uint32 col) const
00494 { LFATAL("unimplemented!"); return PixRGB<byte>(0,0,0); }
00495 
00496 // ######################################################################
00497 inline void SDLdisplay::showCursor(const bool showit)
00498 {
00499   if (showit) SDL_ShowCursor(SDL_ENABLE);
00500   else SDL_ShowCursor(SDL_DISABLE);
00501 }
00502 
00503 // ######################################################################
00504 inline void SDLdisplay::lockScreen()
00505 {
00506   if (SDL_MUSTLOCK(itsScreen))
00507     {
00508       if (SDL_LockSurface(itsScreen) < 0)
00509         LFATAL("Cannot lock screen: %s", SDL_GetError());
00510     }
00511 }
00512 // ######################################################################
00513 inline void SDLdisplay::unlockScreen()
00514 { if (SDL_MUSTLOCK(itsScreen)) SDL_UnlockSurface(itsScreen); }
00515 
00516 // ######################################################################
00517 inline void SDLdisplay::pushEvent(const std::string& msg)
00518 { if (itsEventLog.isValid()) itsEventLog->pushEvent(msg); }
00519 
00520 // ######################################################################
00521 inline void SDLdisplay::pushEventBegin(const std::string& msg)
00522 { if (itsEventLog.isValid()) itsEventLog->pushEventBegin(msg); }
00523 
00524 // ######################################################################
00525 inline void SDLdisplay::pushEventEnd(const std::string& msg)
00526 { if (itsEventLog.isValid()) itsEventLog->pushEventEnd(msg); }
00527 
00528 
00529 #endif // HAVE_SDL_SDL_H
00530 
00531 #endif
00532 
00533 // ######################################################################
00534 /* So things look consistent in everyone's emacs... */
00535 /* Local Variables: */
00536 /* indent-tabs-mode: nil */
00537 /* End: */

Generated on Sun Nov 22 13:42:08 2009 for iLab Neuromorphic Vision Toolkit by  doxygen 1.4.4