SDLdisplay.C

Go to the documentation of this file.
00001 /*!@file GUI/SDLdisplay.C 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.C $
00035 // $Id: SDLdisplay.C 14170 2010-10-27 07:04:19Z ilink $
00036 //
00037 
00038 #ifdef HAVE_SDL_SDL_H
00039 
00040 #include "GUI/SDLdisplay.H"
00041 
00042 #include "Component/ModelOptionDef.H"
00043 #include "Component/OptionManager.H"
00044 #include "GUI/GUIOpts.H"
00045 #include "Image/Image.H"
00046 #include "Image/ColorOps.H"
00047 #include "Image/CutPaste.H"
00048 #include "Image/DrawOps.H"
00049 #include "Image/Pixels.H"
00050 #include "Image/Point2D.H"
00051 #include "Util/MathFunctions.H"
00052 #include "Video/VideoFrame.H"
00053 #include "Video/RgbConversion.H"
00054 #include "rutz/unixcall.h"
00055 #include "Util/sformat.H"
00056 
00057 #include <ctime>
00058 #include <fstream>
00059 #include <sched.h>
00060 #include <pthread.h>
00061 #ifdef HAVE_SYS_IO_H
00062 #include <sys/io.h>       // for iopl()
00063 #endif
00064 #include <sys/mman.h>
00065 #include <sys/types.h>
00066 #include <unistd.h>
00067 
00068 #ifdef MACHINE_OS_DARWIN
00069 #include <dlfcn.h>
00070 #endif
00071 
00072 //! Special log function for SDL-related fatal errors
00073 #define SDLFATAL(f, x...) \
00074   LFATAL("%s", (sformat(f , ## x) + \
00075                 " (" + std::string(SDL_GetError()) + ")").c_str());
00076 
00077 namespace
00078 {
00079   // ######################################################################
00080   bool tryvidformat2sdlmode(const VideoFormat vidformat,
00081                             Uint32* result)
00082   {
00083     // copied from SDL/SDL_video.h:
00084 
00085     /* The most common video overlay formats.
00086        For an explanation of these pixel formats, see:
00087        http://www.webartz.com/fourcc/indexyuv.htm
00088 
00089        For information on the relationship between color spaces, see:
00090        http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html
00091     */
00092     // SDL_YV12_OVERLAY  Planar mode: Y + V + U  (3 planes)
00093     // SDL_IYUV_OVERLAY  Planar mode: Y + U + V  (3 planes)
00094     // SDL_YUY2_OVERLAY  Packed mode: Y0+U0+Y1+V0 (1 plane)
00095     // SDL_UYVY_OVERLAY  Packed mode: U0+Y0+V0+Y1 (1 plane)
00096     // SDL_YVYU_OVERLAY  Packed mode: Y0+V0+Y1+U0 (1 plane)
00097 
00098     switch (vidformat)
00099       {
00100         // NOTE: SDL_IYUV_OVERLAY might seem a more natural choice for
00101         // VIDFMT_YUV420P, since with SDL_YV12_OVERLAY we have to swap
00102         // the U and V components (see displayVideoOverlay() below);
00103         // BUT, it seems that SDL_IYUV_OVERLAY gives bogus results, in
00104         // that black pixels end up rendered as medium gray, with the
00105         // rest of the image looking correspondingly washed out.
00106 
00107       case VIDFMT_YUV420P:  *result = SDL_YV12_OVERLAY; return true;
00108 
00109       case VIDFMT_UYVY:     *result = SDL_UYVY_OVERLAY; return true;
00110       case VIDFMT_YUV422:   *result = SDL_UYVY_OVERLAY; return true;
00111 
00112       case VIDFMT_YUYV:     *result = SDL_YUY2_OVERLAY; return true;
00113 
00114       case VIDFMT_AUTO:     break; /* unsupported mode, fall-through */
00115       case VIDFMT_GREY:     break; /* unsupported mode, fall-through */
00116       case VIDFMT_RAW:      break; /* unsupported mode, fall-through */
00117       case VIDFMT_RGB24:    break; /* unsupported mode, fall-through */
00118       case VIDFMT_RGB32:    break; /* unsupported mode, fall-through */
00119       case VIDFMT_RGB555:   break; /* unsupported mode, fall-through */
00120       case VIDFMT_RGB565:   break; /* unsupported mode, fall-through */
00121       case VIDFMT_YUV410:   break; /* unsupported mode, fall-through */
00122       case VIDFMT_YUV410P:  break; /* unsupported mode, fall-through */
00123       case VIDFMT_YUV411:   break; /* unsupported mode, fall-through */
00124       case VIDFMT_YUV411P:  break; /* unsupported mode, fall-through */
00125       case VIDFMT_YUV420:   break; /* unsupported mode, fall-through */
00126       case VIDFMT_YUV422P:  break; /* unsupported mode, fall-through */
00127       case VIDFMT_YUV24:    break; /* unsupported mode, fall-through */
00128       case VIDFMT_YUV444:   break; /* unsupported mode, fall-through */
00129       case VIDFMT_YUV444P:  break; /* unsupported mode, fall-through */
00130       case VIDFMT_HM12:  break; /* unsupported mode, fall-through */
00131       case VIDFMT_BAYER_GB: break;  /* unsupported mode, fall-through */
00132       case VIDFMT_BAYER_GR: break;  /* unsupported mode, fall-through */
00133       case VIDFMT_BAYER_RG: break;  /* unsupported mode, fall-through */
00134       case VIDFMT_BAYER_BG: break;  /* unsupported mode, fall-through */
00135       case VIDFMT_BAYER_GB12: break;  /* unsupported mode, fall-through */
00136       case VIDFMT_BAYER_GR12: break;  /* unsupported mode, fall-through */
00137       case VIDFMT_BAYER_RG12: break;  /* unsupported mode, fall-through */
00138       case VIDFMT_BAYER_BG12: break;  /* unsupported mode, fall-through */
00139       case VIDFMT_MJPEG: break;  /* unsupported mode, fall-through */
00140       }
00141 
00142     return false;
00143   }
00144 
00145 // ######################################################################
00146   Uint32 vidformat2sdlmode(const VideoFormat vidformat)
00147   {
00148     Uint32 res;
00149 
00150     if (tryvidformat2sdlmode(vidformat, &res))
00151       return res;
00152 
00153     // else... the conversion failed, so give up:
00154     LFATAL("No SDL overlay mode matching VideoFormat %s (%d)",
00155            convertToString(vidformat).c_str(), int(vidformat));
00156     /* can't happen */ return 0;
00157   }
00158 
00159   //struct to hold video info for a pthread
00160   struct RgbYuvOverlayStruct
00161   {
00162     RgbYuvOverlayStruct(const byte *VidY, const byte *VidU, const byte *VidV,
00163                         byte *OutY, byte *OutU, byte *OutV,
00164                         const byte *Rgb,
00165                         const byte Tr, const byte Tg, const byte Tb,
00166                         const int W, const int H) :
00167       vidy(VidY), vidu(VidU), vidv(VidV),
00168       outy(OutY), outu(OutU), outv(OutV),
00169       src(Rgb), tr(Tr), tg(Tg), tb(Tb), w(W), h(H) { };
00170 
00171     const byte *vidy, *vidu, *vidv;
00172     byte  *outy, *outu, *outv;
00173     const byte *src, tr, tg, tb;
00174     const int w, h;
00175   };
00176 
00177 // ######################################################################
00178   void addSyncRect(SDL_Overlay const* ovl, const Dims& dims, 
00179                    const Rectangle& rect, const int frame, 
00180                    const Uint32 sdlformat)
00181   {
00182     if (rect.isValid())
00183       {
00184         if ((sdlformat == SDL_IYUV_OVERLAY) || (sdlformat == SDL_YV12_OVERLAY))
00185           {
00186 
00187             //pointers to image components
00188             byte* outy = ovl->pixels[0];
00189             byte* outu = ovl->pixels[1];
00190             byte* outv = ovl->pixels[2];
00191             
00192             //position and size variables
00193             const int x(rect.left()), y(rect.top());
00194             const int w(dims.w());
00195             const int dw(rect.width()), dh(rect.height());
00196             const int cpos = x/2+1 + (w/2)*(y/2);
00197             const int dw2 = dw/2;
00198             const int w2 = w/2;
00199             const int val = frame % 2 == 0 ? 255 : 0; //fill value
00200 
00201             //put image data pointers to patches patches position 
00202             outy += x  + w*y;
00203             outu += cpos;
00204             outv += cpos;
00205 
00206             //set the pixel data for each row
00207             for (int ii = 0; ii < dh; ++ii)
00208               {
00209                 memset(outy, val, dw);
00210                 if (ii % 2 == 0)
00211                   {
00212                     memset(outu, 128, dw2);
00213                     memset(outv, 128, dw2);
00214                     outu += w2;
00215                     outv += w2;
00216                   }
00217                 outy += w;
00218               }
00219           }
00220         else 
00221           LFATAL("Cannot add syncing patch to this video format");
00222       }
00223   }
00224 
00225 // ######################################################################
00226   void *RgbYuvOverlay(void *arg)
00227   {
00228     RgbYuvOverlayStruct *data = (RgbYuvOverlayStruct*)arg;
00229     int count[data->w], rsum[data->w], gsum[data->w], bsum[data->w];
00230 
00231     //loop through through our macroblocks, rows
00232     for (int j = 0; j < data->h; j += 2)
00233       {
00234         //!loop over macroblock columns
00235         for (int i = 0; i < data->w; i += 2)
00236           {
00237             count[i] = 0;
00238             rsum[i] = 0;
00239             gsum[i] = 0;
00240             bsum[i] = 0;
00241 
00242             //first pixel in macro block
00243             byte br = *data->src++;
00244             byte bg = *data->src++;
00245             byte bb = *data->src++;
00246 
00247             if ( (br == data->tr) && (bg == data->tg) && (bb == data->tb) )
00248               *data->outy++ = *data->vidy++;
00249             else
00250               {
00251                 double r = double(br);
00252                 double g = double(bg);
00253                 double b = double(bb);
00254 
00255                 double yf = VIDEOYUV_Y_R*r + VIDEOYUV_Y_G*g + VIDEOYUV_Y_B*b;
00256                 *data->outy++ = clamped_rounded_convert<byte>(yf);
00257                 data->vidy++;
00258 
00259                 rsum[i] += (int)r;
00260                 gsum[i] += (int)g;
00261                 bsum[i] += (int)b;
00262                 count[i]++;
00263               }
00264             //end first element of block
00265 
00266 
00267             //second pixel in macro block
00268             br = *data->src++;
00269             bg = *data->src++;
00270             bb = *data->src++;
00271 
00272             if ( (br == data->tr) && (bg == data->tg) && (bb == data->tb) )
00273               *data->outy++ = *data->vidy++;
00274             else
00275               {
00276                 double r = double(br);
00277                 double g = double(bg);
00278                 double b = double(bb);
00279 
00280                 double yf = VIDEOYUV_Y_R*r + VIDEOYUV_Y_G*g + VIDEOYUV_Y_B*b;
00281                 *data->outy++ = clamped_rounded_convert<byte>(yf);
00282                 data->vidy++;
00283 
00284                 rsum[i] += (int)r;
00285                 gsum[i] += (int)g;
00286                 bsum[i] += (int)b;
00287                 count[i]++;
00288               }
00289             //end second element of block
00290 
00291           }
00292 
00293         // second row of each block
00294         for (int i = 0; i < data->w; i += 2)
00295           {
00296             //first pixel in second row of macro block
00297             byte br = *data->src++;
00298             byte bg = *data->src++;
00299             byte bb = *data->src++;
00300 
00301             if ( (br == data->tr) && (bg == data->tg) && (bb == data->tb) )
00302               *data->outy++ = *data->vidy++;
00303             else
00304               {
00305                 double r = double(br);
00306                 double g = double(bg);
00307                 double b = double(bb);
00308 
00309                 double yf = VIDEOYUV_Y_R*r + VIDEOYUV_Y_G*g + VIDEOYUV_Y_B*b;
00310                 *data->outy++ = clamped_rounded_convert<byte>(yf);
00311                 data->vidy++;
00312 
00313                 rsum[i] += (int)r;
00314                 gsum[i] += (int)g;
00315                 bsum[i] += (int)b;
00316                 count[i]++;
00317               }
00318             //end first element of second row of block
00319 
00320 
00321             //second pixel in second row of macro block
00322             br = *data->src++;
00323             bg = *data->src++;
00324             bb = *data->src++;
00325 
00326             if ( (br == data->tr) && (bg == data->tg) && (bb == data->tb) )
00327               *data->outy++ = *data->vidy++;
00328             else
00329               {
00330                 double r = double(br);
00331                 double g = double(bg);
00332                 double b = double(bb);
00333 
00334                 double yf = VIDEOYUV_Y_R*r + VIDEOYUV_Y_G*g + VIDEOYUV_Y_B*b;
00335                 *data->outy++ = clamped_rounded_convert<byte>(yf);
00336                 data->vidy++;
00337 
00338                 rsum[i] += (int)r;
00339                 gsum[i] += (int)g;
00340                 bsum[i] += (int)b;
00341                 count[i]++;
00342               }
00343 
00344             //end second element of second row of block
00345 
00346             //average color data;
00347             if (count[i] > 0)
00348               {
00349                 //get the vide frame color of the macroblock
00350                 double ut = *data->vidu++;
00351                 double vt = *data->vidv++;
00352 
00353                 //get the average rgb color in the block and convert to YUV
00354                 double r = rsum[i] / count[i];
00355                 double g = gsum[i] / count[i];
00356                 double b = bsum[i] / count[i];
00357                 double uf = VIDEOYUV_U_R*r + VIDEOYUV_U_G*g
00358                   + VIDEOYUV_U_B*b + VIDEOYUV_UV_OFFSET;
00359                 double vf = VIDEOYUV_V_R*r + VIDEOYUV_V_G*g
00360                   + VIDEOYUV_V_B*b + VIDEOYUV_UV_OFFSET;
00361 
00362                 uf = uf * count[i]/4.0 + ut * (4-count[i])/4.0;
00363                 vf = vf * count[i]/4.0 + vt * (4-count[i])/4.0;
00364 
00365                 *data->outu++ =  clamped_rounded_convert<byte>(uf);
00366                 *data->outv++ =  clamped_rounded_convert<byte>(vf);
00367               }
00368             else
00369               {
00370                 *data->outu++ = *data->vidu++;
00371                 *data->outv++ = *data->vidv++;
00372               }
00373           }//end loop over send row of macro block
00374       }//end loop over vertical pixels
00375     return NULL;
00376   }
00377 }
00378 
00379 // ######################################################################
00380 SDLdisplay::SDLdisplay(OptionManager& mgr, const std::string& descrName,
00381                              const std::string& tagName) :
00382   ModelComponent(mgr, descrName, tagName),
00383   itsDims(&OPT_SDLdisplayDims, this), // see Psycho/PsychoOpts.{H,C}
00384   itsPriority(&OPT_SDLdisplayPriority, this),
00385   itsRefreshDelay(&OPT_SDLdisplayRefreshUsec, this),
00386   itsFullscreen(&OPT_SDLdisplayFullscreen, this),
00387   itsSlaveMode("SDLslaveMode", this, false),
00388   itsVBlankKludge(&OPT_SDLdisplayVBlankKludge, this),
00389   itsSyncRect(&OPT_SDLdisplaySyncRect, this),
00390   itsTimer(1000000),  // use microsecond resolution
00391   itsLastSync(0ULL), itsLastOvlDisplay(0ULL),
00392   itsRefreshTolerance(0.05F),
00393   itsScreen(0), itsOverlay(NULL), 
00394   itsSync(),
00395   itsEventLog()
00396 {  }
00397 
00398 // ######################################################################
00399 SDLdisplay::~SDLdisplay()
00400 {
00401   // make sure we closedown SDL (and switch out of full-screen mode if
00402   // applicable) even in cases our stop1() function is not properly
00403   // called, for example because we are quitting on an LFATAL or other
00404   // exception:
00405   if (itsScreen) { LINFO("Closing down SDL..."); SDL_Quit(); }
00406 }
00407 
00408 // ######################################################################
00409 void SDLdisplay::setEventLog(nub::soft_ref<EventLog> elog)
00410 { itsEventLog = elog; }
00411 
00412 // ######################################################################
00413 void SDLdisplay::openDisplay()
00414 {
00415 
00416 #ifdef MACHINE_OS_DARWIN
00417   // on MacOS X we need to get the cocoa framework started before
00418   // we init SDL. See http://www.ogre3d.org/wiki/index.php/MacLibrary
00419   void* cocoa_lib = dlopen("/System/Library/Frameworks/Cocoa.framework/Cocoa",RTLD_LAZY);
00420   void (*nsappload)(void) = (void(*)())dlsym(cocoa_lib, "NSApplicationLoad");
00421   nsappload();
00422 #endif
00423 
00424   // open a screen and show a black image:
00425   if (SDL_Init(SDL_INIT_VIDEO) < 0) SDLFATAL("SDL init failed");
00426 
00427   uint32 flags = SDL_SWSURFACE | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL;
00428   if (itsFullscreen.getVal()) flags |= SDL_FULLSCREEN;
00429   itsScreen = SDL_SetVideoMode(itsDims.getVal().w(), itsDims.getVal().h(), 32, flags);
00430 
00431   if (itsScreen == NULL) SDLFATAL("Cannot open screen");
00432 
00433   itsLastSync = 0ULL;
00434   clearScreen(PixRGB<byte>(0));
00435   showCursor(false);
00436 }
00437 
00438 
00439 // ######################################################################
00440 void SDLdisplay::start2()
00441 {
00442   if (itsRefreshDelay.getVal() <= 0.0f)
00443     LFATAL("--%s should be strictly greater than zero, but got --%s=%f",
00444            itsRefreshDelay.getOptionDef()->longoptname,
00445            itsRefreshDelay.getOptionDef()->longoptname,
00446            itsRefreshDelay.getVal());
00447 
00448   // switch to SCHED_FIFO scheduling?
00449   int pri = itsPriority.getVal();
00450   if (pri)
00451     {
00452       // high-priority mode will also trigger hard polling on the VGA registers to sync our displays with the vertical
00453       // blanking. On recent versions of Linux, this only works when we are in fullscreen mode, otherwise the polling
00454       // just blocks forever and never finds a vertical blanking. So let's here enforce that we should use fullscreen:
00455       if (itsFullscreen.getVal() == false) LFATAL("non-zero --sdl-priority only works in fullscreen mode (--fs)");
00456 
00457 #ifndef HAVE_SYS_IO_H
00458       LFATAL("this configuration lacks <sys/io.h>, so it does not support non-zero --sdl-priority");
00459 #else
00460       // become root:
00461       if (setuid(0) == -1)
00462         PLFATAL("I need to run as root when --sdl-priority is non-zero (%d)", pri);
00463 
00464       // set our scheduler policy and priority:
00465       struct sched_param params;
00466       int minpri = sched_get_priority_min(SCHED_FIFO);
00467       int maxpri = sched_get_priority_max(SCHED_FIFO);
00468       if (pri < minpri || pri > maxpri)
00469         LFATAL("Invalid priority %d, range [%d..%d]", pri, minpri, maxpri);
00470       params.sched_priority = pri;
00471 
00472       if (sched_setscheduler(0, SCHED_FIFO, &params) == -1)
00473         PLFATAL("Cannot switch to SCHED_FIFO scheduling and priority %d", pri);
00474 
00475       // avoid getting swapped around:
00476       if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1)
00477         PLFATAL("Cannot lock memory and prevent swapping");
00478 
00479       LINFO("Process priority set to %d and swap locked.", pri);
00480 #endif // HAVE_SYS_IO_H
00481     }
00482 
00483   if (itsSlaveMode.getVal())
00484     {
00485       LINFO("Running in slave mode...");
00486       itsScreen = SDL_GetVideoSurface();
00487     }
00488   else
00489     {
00490 #ifdef MACHINE_OS_DARWIN
00491       // on MacOS X we need to get the cocoa framework started before
00492       // we init SDL. See http://www.ogre3d.org/wiki/index.php/MacLibrary
00493       void* cocoa_lib = dlopen("/System/Library/Frameworks/Cocoa.framework/Cocoa",RTLD_LAZY);
00494       void (*nsappload)(void) = (void(*)())dlsym(cocoa_lib, "NSApplicationLoad");
00495       nsappload();
00496 #endif
00497 
00498       // open a screen and show a flat grey image:
00499       if (SDL_Init(SDL_INIT_VIDEO) < 0) SDLFATAL("SDL init failed");
00500 
00501       uint32 flags = SDL_SWSURFACE | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL;
00502       if (itsFullscreen.getVal()) flags |= SDL_FULLSCREEN;
00503       itsScreen = SDL_SetVideoMode(itsDims.getVal().w(), itsDims.getVal().h(), 32, flags);
00504       if (itsScreen == NULL) SDLFATAL("Cannot open screen");
00505 
00506       itsLastSync = 0ULL;
00507     }
00508 
00509   // get name of video driver and display it:
00510   char vname[256]; SDL_VideoDriverName(vname, 256);
00511   LINFO("Using SDL video driver '%s'", vname);
00512 
00513   // Enable keycode translations:
00514   SDL_EnableUNICODE(1);
00515 
00516   // switch to max I/O privilege for waitNextRequestedVsync() to work, unless
00517   // using the VBlank kludge, in which case we don't need I/O privileges:
00518   if (pri) {
00519     if (itsVBlankKludge.getVal() == 0) {
00520 #ifndef HAVE_SYS_IO_H
00521       LFATAL("this configuration lacks <sys/io.h>, so it does not support non-zero --sdl-priority");
00522 #else
00523       if (iopl(3)) PLFATAL("cannot iopl(3)");
00524 #endif
00525     } else
00526       LINFO("Using Vertical-Blanking workaround with a delay of %u microseconds", itsVBlankKludge.getVal());
00527     }
00528 
00529   //check to see if our blinking rectangle used to sync the video is off screen
00530   if (itsSyncRect.getVal().area() > 0)
00531     {
00532       Rectangle r = itsSyncRect.getVal();
00533       if ( (r.left() < 0) || (r.rightO() > itsDims.getVal().w()) ) 
00534         LFATAL("The rectangle (%d-%d) set using --sdl-sync-rect is "
00535                "horizontally off the screen(%d-%d)", r.left(), r.rightO(), 
00536                0, itsDims.getVal().w());
00537       if ( (r.top() < 0) || (r.bottomO() > itsDims.getVal().h()) ) 
00538         LFATAL("The rectangle (%d-%d) set using --sdl-sync-rect is "
00539                "vertically off the screen(%d-%d)", r.top(), r.bottomO(), 
00540                0, itsDims.getVal().h());
00541 
00542       itsSync = itsSyncRect.getVal();
00543     }
00544 
00545 
00546   
00547   // the epoch is now:
00548   itsTimer.reset();
00549   char buf1[100], buf2[100];
00550   time_t ti = time(NULL);
00551   strncpy(buf1, ctime(&ti), sizeof(buf1));
00552   buf1[sizeof(buf1)-1] = '\0';
00553   // kill a trailing '\n' on the ctime() string, if it exists
00554   if (buf1[strlen(buf1)-1] == '\n') buf1[strlen(buf1)-1] = '\0';
00555   snprintf(buf2, sizeof(buf2), "##### START %s #####", buf1);
00556   pushEvent(buf2);
00557 
00558   itsLastSync = 0ULL;
00559   clearScreen(PixRGB<byte>(0, 0, 0));
00560   showCursor(false);
00561 }
00562 
00563 // ######################################################################
00564 void SDLdisplay::closeDisplay()
00565 {
00566   // destro any eisting overlay:
00567   if (itsOverlay) { destroyYUVoverlay(); itsOverlay = NULL; }
00568 
00569   // close the screen:
00570   if (itsSlaveMode.getVal() == false && itsScreen)
00571     { LINFO("Closing down SDL..."); SDL_Quit(); itsScreen = NULL; }
00572 
00573   // if running at high priority, do some related cleanup:
00574   if (itsPriority.getVal())
00575     {
00576 #ifndef HAVE_SYS_IO_H
00577       LFATAL("this configuration lacks <sys/io.h>, so it does not support "
00578              "non-zero --sdl-priority");
00579 #else
00580       // get back to normal scheduling and zero priority:
00581       struct sched_param params; params.sched_priority = 0;
00582       if (sched_setscheduler(0, SCHED_OTHER, &params) == -1)
00583         PLFATAL("Cannot switch back to SCHED_OTHER");
00584 
00585       // allow swapping:
00586       if (munlockall() == -1) PLFATAL("Cannot unlock memory");
00587 #endif // HAVE_SYS_IO_H
00588     }
00589 }
00590 
00591 // ######################################################################
00592 void SDLdisplay::stop1()
00593 {
00594   closeDisplay();
00595 }
00596 
00597 // ######################################################################
00598 void SDLdisplay::clearScreen(const PixRGB<byte> col, const bool vsync)
00599 {
00600   pushEventBegin("clearScreen");
00601 
00602   SDL_Rect rect;
00603   rect.x = 0; rect.y = 0; rect.w = getWidth(); rect.h = getHeight();
00604 
00605   SDL_FillRect(itsScreen, &rect, getUint32color(col));
00606 
00607   //also paint a black patch if external syncing is requested
00608   if (itsSync.isValid())
00609     {
00610       SDL_Rect r;
00611       r.x = itsSync.left(); r.y = itsSync.top(); 
00612       r.w = itsSync.width(); r.h = itsSync.height();
00613       SDL_FillRect(itsScreen, &r, getUint32color(PixRGB<byte>(0)));
00614     }
00615 
00616   syncScreen(vsync, false, true);
00617 
00618   pushEventEnd("clearScreen");
00619 }
00620 
00621 // ######################################################################
00622 void SDLdisplay::clearBackBuffer()
00623 {
00624   // Lock the screen for direct access to the pixels
00625   lockScreen();
00626 
00627   // brutally clear the screen:
00628   int bpp = getBytesPerPixel();
00629   memset(itsScreen->pixels, 0, itsDims.getVal().sz() * bpp);
00630 
00631   // unlock the screen:
00632   unlockScreen();
00633 }
00634 
00635 // ######################################################################
00636 int SDLdisplay::waitForKeyTimeout(double timeout, bool doWait)
00637 {
00638   // clear the input buffer before we get started if doWait is set to true
00639   if (doWait) while (checkForKey() != -1) ;
00640 
00641   pushEventBegin("waitForKeyTimeout");
00642 
00643         Timer tt;
00644         double ttime;
00645         timeout = timeout/1000;
00646         int key;
00647   do {
00648                 key = checkForKey();    
00649                 ttime = tt.getSecs();
00650         } while (key == -1 && ttime < timeout);
00651 
00652   char c; if (key >= 32 && key < 128) c = char(key); else c = '?';
00653   pushEventEnd(sformat("waitForKeyTimeout - got %d (%c), time %f ms", key, c, ttime*1000));
00654 
00655   // abort if it was ESC:
00656   if (key == 27) LFATAL("Aborting on [ESC] key");
00657 
00658   return key;
00659 }
00660 
00661 // ######################################################################
00662 int SDLdisplay::waitForKey(bool doWait)
00663 {
00664   // clear the input buffer before we get started if doWait is set to true
00665   if (doWait) while (checkForKey() != -1) ;
00666 
00667   pushEventBegin("waitForKey");
00668   SDL_Event event;
00669 
00670   do { SDL_WaitEvent(&event); } while (event.type != SDL_KEYDOWN);
00671 
00672   int key = event.key.keysym.unicode;
00673   char c; if (key >= 32 && key < 128) c = char(key); else c = '?';
00674   pushEventEnd(sformat("waitForKey - got %d (%c)", key, c));
00675 
00676   // abort if it was ESC:
00677   if (key == 27) LFATAL("Aborting on [ESC] key");
00678 
00679   return key;
00680 }
00681 
00682 // ######################################################################
00683 int SDLdisplay::waitForMouseClick(bool doWait)
00684 {
00685   // clear the input buffer before we get started if doWait is set to true
00686   if (doWait) while (checkForMouseClick() != -1) ;
00687 
00688   pushEventBegin("waitForMouseClick");
00689   SDL_Event event;
00690 
00691   do { SDL_WaitEvent(&event); } while (event.type != SDL_MOUSEBUTTONDOWN);
00692 
00693   int i = 0;  // will be returned if any other button than left or right
00694   if (event.button.button == SDL_BUTTON_LEFT) {
00695     pushEvent(sformat("waitForMouseClick - got left button clicked"));
00696     i = 1 ;
00697   }
00698   if (event.button.button == SDL_BUTTON_RIGHT) {
00699     pushEvent(sformat("checkForMouseClick - got right button clicked"));
00700     i = 2 ;
00701   }
00702 
00703   return i;
00704 }
00705 
00706 // ######################################################################
00707 int SDLdisplay::waitForMouseWheelEvent(bool doWait)
00708 {
00709   // clear the input buffer before we get started if doWait is set to true
00710   if (doWait) while (checkForMouseClick() != -1) ;
00711 
00712   pushEventBegin("waitForMouseWheelEvent");
00713   SDL_Event event;
00714 
00715   do { SDL_WaitEvent(&event); } while (event.button.button != SDL_BUTTON_MIDDLE);
00716 
00717   int i = 0;  // will be returned if any other button than left or right
00718   if (event.type == SDL_MOUSEBUTTONDOWN) {
00719     pushEvent(sformat("waitForMouseClick - got left button clicked"));
00720     i = 1 ;
00721   }
00722   if (event.type == SDL_MOUSEBUTTONUP) {
00723     pushEvent(sformat("checkForMouseClick - got right button clicked"));
00724     i = 2 ;
00725   }
00726 
00727   return i;
00728 }
00729 
00730 // ######################################################################
00731 int SDLdisplay::checkForKey()
00732 {
00733   SDL_Event event;
00734 
00735   while(SDL_PollEvent(&event))
00736     {
00737       if (event.type == SDL_KEYDOWN)
00738         {
00739           int key = event.key.keysym.unicode;
00740           char c; if (key >= 32 && key < 128) c = char(key); else c = '?';
00741           pushEvent(sformat("checkForKey - got %d (%c)", key, c));
00742 
00743           // abort if it was ESC:
00744           if (key == 27) LFATAL("Aborting on [ESC] key");
00745 
00746           return key;
00747         }
00748       // ignore other events
00749     }
00750 
00751   // there was no event in the event queue:
00752   return -1;
00753 }
00754 
00755 // ######################################################################
00756 int SDLdisplay::checkForMouseClick()
00757 {
00758   SDL_Event event;
00759 
00760   while(SDL_PollEvent(&event))
00761     {
00762       if (event.type == SDL_MOUSEBUTTONDOWN)
00763         {
00764           if(event.button.button == SDL_BUTTON_LEFT) {
00765             pushEvent(sformat("checkForMouseClick - left button clicked"));
00766             return 1 ;
00767           }
00768           if(event.button.button == SDL_BUTTON_RIGHT) {
00769             pushEvent(sformat("checkForMouseClick - right button clicked"));
00770             return 2 ;
00771           }
00772         }
00773       // ignore other events
00774     }
00775 
00776   // there was no event in the event queue:
00777   return -1;
00778 }
00779 // #####################################################################
00780 std::string SDLdisplay::getString(char terminator ='\n')
00781 {
00782   std::string inputString;
00783   int k;
00784   do { k = waitForKey();
00785     inputString += k;
00786     LINFO("%d, %c %d", k, char(k), int(terminator));
00787   } while(k != 13);
00788   LINFO("gotString %s", inputString.c_str());
00789 
00790   return inputString;
00791 }
00792 
00793 // ######################################################################
00794 void SDLdisplay::displayImage(const Image< PixRGB<byte> >& img,
00795                               const bool resiz, const PixRGB<byte> bgcol,
00796                               const int frame, const bool vsync)
00797 {
00798   SDL_Surface* surf = makeBlittableSurface(img, resiz, bgcol);
00799   displaySurface(surf, frame, vsync);
00800   SDL_FreeSurface(surf);
00801 }
00802 
00803 // ######################################################################
00804 SDL_Surface*
00805 SDLdisplay::makeBlittableSurface(const Image< PixRGB<byte> >& img,
00806                                  const bool resiz, const PixRGB<byte> bgcol)
00807 {
00808   Image< PixRGB<byte> > image;
00809   //LINFO("image: w, h : %d, %d",image.getWidth(),image.getHeight());
00810   //LINFO("img  : w, h : %d, %d",img.getWidth(),img.getHeight());
00811   //LINFO("pt: (%d,%d)", (getWidth() - img.getWidth()) / 2,
00812   //                              (getHeight() - img.getHeight()) / 2);
00813 
00814   // resize/embed if necessary:
00815   if (this->itsDims.getVal() != img.getDims())
00816     {
00817       image = Image< PixRGB<byte> >(itsDims.getVal(), NO_INIT);
00818 
00819       if (resiz)
00820         {
00821           // stretch and embed:
00822           inplaceEmbed(image, img, image.getBounds(), bgcol, true);
00823         }
00824       else
00825         {
00826           // center the image on the screen:
00827           image.clear(bgcol);
00828           inplacePaste(image, img,
00829                        Point2D<int>( (getWidth() - img.getWidth()) / 2,
00830                                 (getHeight() - img.getHeight()) / 2));
00831         }
00832     }
00833   else
00834     image = img;
00835 
00836   ASSERT(image.getDims() == this->itsDims.getVal());
00837 
00838   if (itsSync.isValid())
00839     {
00840       //! Draw a filled rectangle with white
00841       drawFilledRect(image, itsSync, PixRGB<byte>(255,255,255));
00842     }
00843 
00844   // create an SDL_Surface suitable for a direct blit:
00845   SDL_Surface *tmpsurf =
00846     SDL_CreateRGBSurfaceFrom(image.getArrayPtr(), image.getWidth(),
00847                              image.getHeight(), 24, 3 * image.getWidth(),
00848                              0x0000ff, 0x00ff00, 0xff0000, 0x0);
00849   SDL_Surface *surf = SDL_DisplayFormat(tmpsurf);
00850   SDL_FreeSurface(tmpsurf);
00851 
00852   return surf;
00853 }
00854 
00855 // ######################################################################
00856 void SDLdisplay::displaySurface(SDL_Surface *img, const int frame,
00857                                 const bool vsync)
00858 {
00859   // special frame -2 is to log both start and end of this function:
00860   if (frame == -2) pushEventBegin("displayImage");
00861 
00862   // if this is our first frame of a movie, let's start fresh with a
00863   // sync to vertical blanking:
00864   if (vsync && frame == 0)
00865     waitNextRequestedVsync(false, false); // will update itsLastSync
00866 
00867   // let's blit the image into our back buffer:
00868   if (SDL_BlitSurface(img, NULL, itsScreen, NULL) == -1)
00869     SDLFATAL("Blit failed");
00870 
00871   // swap the buffers & wait for vertical blanking pulse:
00872   syncScreen(vsync, (frame >= 0), false); // will update itsLastSync
00873 
00874   if (frame >= 0) pushEvent(sformat("displayImage - frame %d", frame));
00875   else if (frame == -2) pushEventEnd("displayImage");
00876 }
00877 
00878 
00879 // ######################################################################
00880 void SDLdisplay::displaySDLSurfacePatch(SDL_Surface* surf, SDL_Rect* offset,
00881                                         SDL_Rect* clip, const int frame,
00882                                         const bool vsync, const bool flip)
00883 {
00884   // special frame -2 is to log both start and end of this function:
00885   if (frame == -2) pushEventBegin("displaySurfacePatch");
00886 
00887   // if this is our first frame of a movie, let's start fresh with a
00888   // sync to vertical blanking:
00889   if (vsync && frame == 0)
00890     waitNextRequestedVsync(false, false); // will update itsLastSync
00891 
00892   if (SDL_BlitSurface(surf, NULL, itsScreen, offset) == -1)
00893     SDLFATAL("Blit failed");
00894 
00895 
00896   // swap the buffers & wait for vertical blanking pulse:
00897   if (flip) syncScreen(vsync, (frame >= 0), false); // will update itsLastSync
00898 
00899   if (frame >= 0) pushEvent(sformat("displaySurfacePatch - frame %d", frame));
00900   else if (frame == -2) pushEventEnd("displaySurfacePatch");
00901 }
00902 
00903 
00904 // ######################################################################
00905 void SDLdisplay::displayImagePatch(const Image< PixRGB<byte> >& image,
00906                                    const Point2D<int>& pos, const int frame,
00907                                    const bool vsync, const bool flip)
00908 {
00909   // special frame -2 is to log both start and end of this function:
00910   if (frame == -2) pushEventBegin("displayImagePatch");
00911 
00912   // create an SDL_Surface suitable for a direct blit:
00913   SDL_Surface *tmpsurf =
00914     SDL_CreateRGBSurfaceFrom(const_cast<Image< PixRGB<byte> >& >(image).
00915                              getArrayPtr(), image.getWidth(),
00916                              image.getHeight(), 24, 3 * image.getWidth(),
00917                              0x0000ff, 0x00ff00, 0xff0000, 0x0);
00918   SDL_Surface *surf = SDL_DisplayFormat(tmpsurf);
00919   SDL_FreeSurface(tmpsurf);
00920 
00921   // if this is our first frame of a movie, let's start fresh with a
00922   // sync to vertical blanking:
00923   if (vsync && frame == 0)
00924     waitNextRequestedVsync(false, false); // will update itsLastSync
00925 
00926   // let's blit the image into our back buffer:
00927   SDL_Rect r; r.x = pos.i; r.y = pos.j;
00928   r.w = image.getWidth(); r.h = image.getHeight();
00929   if (SDL_BlitSurface(surf, NULL, itsScreen, &r) == -1)
00930     SDLFATAL("Blit failed");
00931   SDL_FreeSurface(surf);
00932 
00933   // swap the buffers & wait for vertical blanking pulse:
00934   if (flip) syncScreen(vsync, (frame >= 0), false); // will update itsLastSync
00935 
00936   if (frame >= 0) pushEvent(sformat("displayImagePatch - frame %d", frame));
00937   else if (frame == -2) pushEventEnd("displayImagePatch");
00938 }
00939 
00940 // ######################################################################
00941 bool SDLdisplay::hasYUVoverlay() const
00942 {
00943   return (itsOverlay != 0);
00944 }
00945 
00946 // ######################################################################
00947 void SDLdisplay::createYUVoverlay(const Uint32 format,
00948                                   const int w, const int h)
00949 {
00950   if (itsOverlay) destroyYUVoverlay();
00951 
00952   if (format != SDL_YV12_OVERLAY &&
00953       format != SDL_IYUV_OVERLAY &&
00954       format != SDL_YUY2_OVERLAY &&
00955       format != SDL_UYVY_OVERLAY &&
00956       format != SDL_YVYU_OVERLAY)
00957     LFATAL("Invalid SDL overlay format");
00958 
00959   itsOverlay = SDL_CreateYUVOverlay(w, h,
00960                                     format, itsScreen);
00961   if (itsOverlay == NULL) SDLFATAL("Cannot create YUV overlay");
00962   itsLastOvlDisplay = 0ULL;
00963 }
00964 
00965 // ######################################################################
00966 void SDLdisplay::createYUVoverlay(const Uint32 format)
00967 {
00968   if (itsOverlay) destroyYUVoverlay();
00969 
00970   if (format != SDL_YV12_OVERLAY &&
00971       format != SDL_IYUV_OVERLAY &&
00972       format != SDL_YUY2_OVERLAY &&
00973       format != SDL_UYVY_OVERLAY &&
00974       format != SDL_YVYU_OVERLAY)
00975     LFATAL("Invalid SDL overlay format");
00976 
00977 
00978   itsOverlay = SDL_CreateYUVOverlay(getWidth(), getHeight(),
00979                                     format, itsScreen);
00980   if (itsOverlay == NULL) SDLFATAL("Cannot create YUV overlay");
00981   itsLastOvlDisplay = 0ULL;
00982 }
00983 
00984 // ######################################################################
00985 void SDLdisplay::destroyYUVoverlay()
00986 {
00987   if (itsOverlay == NULL) LFATAL("I don't have a YUV overlay");
00988   SDL_FreeYUVOverlay(itsOverlay);
00989   itsOverlay = NULL;
00990 }
00991 
00992 // ######################################################################
00993 SDL_Overlay* SDLdisplay::lockYUVoverlay()
00994 {
00995   if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
00996   SDL_LockYUVOverlay(itsOverlay);
00997   return itsOverlay;
00998 }
00999 
01000 // ######################################################################
01001 void SDLdisplay::unlockYUVoverlay()
01002 {
01003   if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
01004   SDL_UnlockYUVOverlay(itsOverlay);
01005 }
01006 
01007 // ######################################################################
01008 void SDLdisplay::displayYUVoverlay(const int frame, const DelayType dly,
01009                                    const int x, const int y,
01010                                    const int w, const int h)
01011 {
01012   if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
01013 
01014   SDL_Rect r; r.x = x; r.y = y; r.w = w; r.h = h;
01015 
01016   // sync and log an event:
01017   switch (dly)
01018     {
01019     case NO_WAIT:
01020       {
01021         // display the overlay:
01022         if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01023           SDLFATAL("Overlay blit failed");
01024 
01025         // if we are not vsync'ing, probably our timing is controlled
01026         // by something else, e.g., a video frame grabber in
01027         // psycho-video.C In this case, let's use itsLastOvlDisplay to
01028         // check framerate:
01029         const uint64 tim = itsTimer.get();
01030         const float usec = float(tim - itsLastOvlDisplay);
01031         if (frame > 0)
01032           {
01033             const float toolong =
01034               itsRefreshDelay.getVal() * (1.0F + itsRefreshTolerance);
01035             const float tooshort =
01036               itsRefreshDelay.getVal() * (1.0F - itsRefreshTolerance);
01037 
01038             pushEvent(sformat("displayYUVoverlay - frame %d - %.3fms%s",
01039                               frame,
01040                               usec / 1000.0F,
01041                               usec > toolong ? " ***** SLOW FRAME? *****"
01042                               : usec < tooshort ? " ***** FAST FRAME? *****"
01043                               : ""));
01044           }
01045         else
01046           pushEvent(sformat("displayYUVoverlay - frame %d", frame));
01047         itsLastOvlDisplay = tim;
01048       }
01049       break;
01050 
01051     case NEXT_VSYNC:
01052       {
01053         // if this is our first frame of a movie, let's start fresh
01054         // with a sync to vertical blanking:
01055         if (frame == 0)
01056           waitNextRequestedVsync(false, false); // will update itsLastSync
01057 
01058         // display the overlay:
01059         if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01060           SDLFATAL("Overlay blit failed");
01061 
01062         // wait until we enter the vertical blanking:
01063         waitNextRequestedVsync((frame >= 0), false);
01064 
01065         if (frame >= 0) pushEvent(sformat("displayYUVoverlay - frame %d",frame));
01066         else pushEvent("displayYUVoverlay");
01067       }
01068       break;
01069 
01070     case NEXT_FRAMETIME:
01071       {
01072         // wait until we reach the next frame time:
01073         waitNextRequestedFrameTime(frame, (frame >= 0), false);
01074 
01075         // display the overlay:
01076         if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01077           SDLFATAL("Overlay blit failed");
01078 
01079         if (frame >= 0) pushEvent(sformat("displayYUVoverlay - frame %d",frame));
01080         else pushEvent("displayYUVoverlay");
01081       }
01082     }
01083 }
01084 
01085 // ######################################################################
01086 void SDLdisplay::displayYUVoverlay(const int frame, const DelayType dly)
01087 {
01088   if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
01089 
01090   SDL_Rect r; r.x = 0; r.y = 0; r.w = getWidth(); r.h = getHeight();
01091 
01092   // sync and log an event:
01093   switch (dly)
01094     {
01095     case NO_WAIT:
01096       {
01097         // display the overlay:
01098         if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01099           SDLFATAL("Overlay blit failed");
01100 
01101         // if we are not vsync'ing, probably our timing is controlled
01102         // by something else, e.g., a video frame grabber in
01103         // psycho-video.C In this case, let's use itsLastOvlDisplay to
01104         // check framerate:
01105         const uint64 tim = itsTimer.get();
01106         const float usec = float(tim - itsLastOvlDisplay);
01107         if (frame > 0)
01108           {
01109             const float toolong =
01110               itsRefreshDelay.getVal() * (1.0F + itsRefreshTolerance);
01111             const float tooshort =
01112               itsRefreshDelay.getVal() * (1.0F - itsRefreshTolerance);
01113 
01114             pushEvent(sformat("displayYUVoverlay - frame %d - %.3fms%s",
01115                               frame,
01116                               usec / 1000.0F,
01117                               usec > toolong ? " ***** SLOW FRAME? *****"
01118                               : usec < tooshort ? " ***** FAST FRAME? *****"
01119                               : ""));
01120           }
01121         else
01122           pushEvent(sformat("displayYUVoverlay - frame %d", frame));
01123         itsLastOvlDisplay = tim;
01124       }
01125       break;
01126 
01127     case NEXT_VSYNC:
01128       {
01129         // if this is our first frame of a movie, let's start fresh
01130         // with a sync to vertical blanking:
01131         if (frame == 0)
01132           waitNextRequestedVsync(false, false); // will update itsLastSync
01133 
01134         // display the overlay:
01135         if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01136           SDLFATAL("Overlay blit failed");
01137 
01138         // wait until we enter the vertical blanking:
01139         waitNextRequestedVsync((frame >= 0), false);
01140 
01141         if (frame >= 0) pushEvent(sformat("displayYUVoverlay - frame %d",frame));
01142         else pushEvent("displayYUVoverlay");
01143       }
01144       break;
01145 
01146     case NEXT_FRAMETIME:
01147       {
01148         // wait until we reach the next frame time:
01149         waitNextRequestedFrameTime(frame, (frame >= 0), false);
01150 
01151         // display the overlay:
01152         if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01153           SDLFATAL("Overlay blit failed");
01154 
01155         if (frame >= 0) pushEvent(sformat("displayYUVoverlay - frame %d",frame));
01156         else pushEvent("displayYUVoverlay");
01157       }
01158     }
01159 }
01160 
01161 // ######################################################################
01162 bool SDLdisplay::supportsVideoOverlay(const VideoFormat vidformat) const
01163 {
01164   Uint32 sdlformat;
01165   return tryvidformat2sdlmode(vidformat, &sdlformat);
01166 }
01167 
01168 // ######################################################################
01169 void SDLdisplay::createVideoOverlay(const VideoFormat vidformat,
01170                                          const int w, const int h)
01171 {
01172   const Uint32 sdlformat = vidformat2sdlmode(vidformat);
01173 
01174   this->createYUVoverlay(sdlformat, w, h);
01175 }
01176 
01177 // ######################################################################
01178 void SDLdisplay::createVideoOverlay(const VideoFormat vidformat)
01179 {
01180   const Uint32 sdlformat = vidformat2sdlmode(vidformat);
01181 
01182   this->createYUVoverlay(sdlformat);
01183 }
01184 
01185 // ######################################################################
01186 void SDLdisplay::displayVideoOverlay(const VideoFrame& frame,
01187                                      const int framenum,
01188                                      const DelayType dly)
01189 {
01190   if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
01191 
01192   const Uint32 sdlformat = vidformat2sdlmode(frame.getMode());
01193 
01194   if (sdlformat != itsOverlay->format)
01195     LFATAL("video frame format does not match SDL overlay format");
01196 
01197   const int w = frame.getDims().w();
01198   const int h = frame.getDims().h();
01199 
01200   if (w != itsOverlay->w)
01201     LFATAL("video frame width does not match SDL overlay width");
01202 
01203   if (h != itsOverlay->h)
01204     LFATAL("video frame height does not match SDL overlay height");
01205 
01206   SDL_Overlay* ovl = this->lockYUVoverlay();
01207   switch (sdlformat)
01208     {
01209     case SDL_IYUV_OVERLAY:  // Planar mode: Y + U + V  (3 planes)
01210       if (ovl->planes != 3)       LFATAL("IYUV overlay must have 3 planes");
01211       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01212       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01213       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01214 
01215       memcpy(ovl->pixels[0], frame.getBuffer(), w * h);
01216       memcpy(ovl->pixels[1], frame.getBuffer() + w * h, ((w+1)/2) * ((h+1)/2));
01217       memcpy(ovl->pixels[2], frame.getBuffer() + w * h + ((w+1)/2) * ((h+1)/2),
01218              ((w+1)/2) * ((h+1)/2));
01219       break;
01220 
01221     case SDL_YV12_OVERLAY:  // Planar mode: Y + V + U  (3 planes)
01222       if (ovl->planes != 3)       LFATAL("YV12 overlay must have 3 planes");
01223       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01224       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01225       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01226       memcpy(ovl->pixels[0], frame.getBuffer(), w * h);
01227       // NOTE U+V are swapped here, since we're assuming the buffer is
01228       // in VIDFMT_YUV420P format:
01229       memcpy(ovl->pixels[2], frame.getBuffer() + w * h, ((w+1)/2) * ((h+1)/2));
01230       memcpy(ovl->pixels[1], frame.getBuffer() + w * h + ((w+1)/2) * ((h+1)/2),
01231              ((w+1)/2) * ((h+1)/2));
01232       break;
01233 
01234     case SDL_YUY2_OVERLAY:  // Packed mode: Y0+U0+Y1+V0 (1 plane)
01235       if (ovl->planes != 1)       LFATAL("YUY2 overlay must have 1 plane");
01236       if (ovl->pitches[0] != w*2) LFATAL("bogus pitches[0] in SDL overlay");
01237       memcpy(ovl->pixels[0], frame.getBuffer(), w * h * 2);
01238       break;
01239 
01240     case SDL_UYVY_OVERLAY:  // Packed mode: U0+Y0+V0+Y1 (1 plane)
01241       if (ovl->planes != 1)       LFATAL("UYVY overlay must have 1 plane");
01242       if (ovl->pitches[0] != w*2) LFATAL("bogus pitches[0] in SDL overlay");
01243       memcpy(ovl->pixels[0], frame.getBuffer(), w * h * 2);
01244       break;
01245 
01246     case SDL_YVYU_OVERLAY:  // Packed mode: Y0+V0+Y1+U0 (1 plane)
01247       if (ovl->planes != 1)       LFATAL("YVYU overlay must have 1 plane");
01248       if (ovl->pitches[0] != w*2) LFATAL("bogus pitches[0] in SDL overlay");
01249       memcpy(ovl->pixels[0], frame.getBuffer(), w * h * 2);
01250       break;
01251 
01252     default:
01253       LFATAL("Unknown SDL overlay format");
01254     }
01255 
01256   //if a valid rectangle, add a patch for external syncing with a photodiode
01257   addSyncRect(ovl, getDims(), itsSync, framenum, sdlformat);
01258   
01259   this->unlockYUVoverlay();
01260   this->displayYUVoverlay(framenum, dly);
01261 }
01262 
01263 
01264 // ######################################################################
01265 void SDLdisplay::displayVideoOverlay_pos(const VideoFrame& frame,
01266                                          const int framenum,
01267                                          const DelayType dly,
01268                                          const int x, const int y,
01269                                          const int rw, const int rh)
01270 {
01271   if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
01272 
01273   const Uint32 sdlformat = vidformat2sdlmode(frame.getMode());
01274 
01275   if (sdlformat != itsOverlay->format)
01276     LFATAL("video frame format does not match SDL overlay format");
01277 
01278   const int w = frame.getDims().w();
01279   const int h = frame.getDims().h();
01280 
01281   if (w != itsOverlay->w)
01282     LFATAL("video frame width does not match SDL overlay width");
01283 
01284   if (h != itsOverlay->h)
01285     LFATAL("video frame height does not match SDL overlay height");
01286 
01287   SDL_Overlay* ovl = this->lockYUVoverlay();
01288   switch (sdlformat)
01289     {
01290     case SDL_IYUV_OVERLAY:  // Planar mode: Y + U + V  (3 planes)
01291       if (ovl->planes != 3)       LFATAL("IYUV overlay must have 3 planes");
01292       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01293       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01294       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01295 
01296       memcpy(ovl->pixels[0], frame.getBuffer(), w * h);
01297       memcpy(ovl->pixels[1], frame.getBuffer() + w * h, ((w+1)/2) * ((h+1)/2));
01298       memcpy(ovl->pixels[2], frame.getBuffer() + w * h + ((w+1)/2) * ((h+1)/2),
01299              ((w+1)/2) * ((h+1)/2));
01300       break;
01301 
01302     case SDL_YV12_OVERLAY:  // Planar mode: Y + V + U  (3 planes)
01303       if (ovl->planes != 3)       LFATAL("YV12 overlay must have 3 planes");
01304       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01305       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01306       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01307       memcpy(ovl->pixels[0], frame.getBuffer(), w * h);
01308       // NOTE U+V are swapped here, since we're assuming the buffer is
01309       // in VIDFMT_YUV420P format:
01310       memcpy(ovl->pixels[2], frame.getBuffer() + w * h, ((w+1)/2) * ((h+1)/2));
01311       memcpy(ovl->pixels[1], frame.getBuffer() + w * h + ((w+1)/2) * ((h+1)/2),
01312              ((w+1)/2) * ((h+1)/2));
01313       break;
01314 
01315     case SDL_YUY2_OVERLAY:  // Packed mode: Y0+U0+Y1+V0 (1 plane)
01316       if (ovl->planes != 1)       LFATAL("YUY2 overlay must have 1 plane");
01317       if (ovl->pitches[0] != w*2) LFATAL("bogus pitches[0] in SDL overlay");
01318       memcpy(ovl->pixels[0], frame.getBuffer(), w * h * 2);
01319       break;
01320 
01321     case SDL_UYVY_OVERLAY:  // Packed mode: U0+Y0+V0+Y1 (1 plane)
01322       if (ovl->planes != 1)       LFATAL("UYVY overlay must have 1 plane");
01323       if (ovl->pitches[0] != w*2) LFATAL("bogus pitches[0] in SDL overlay");
01324       memcpy(ovl->pixels[0], frame.getBuffer(), w * h * 2);
01325       break;
01326 
01327     case SDL_YVYU_OVERLAY:  // Packed mode: Y0+V0+Y1+U0 (1 plane)
01328       if (ovl->planes != 1)       LFATAL("YVYU overlay must have 1 plane");
01329       if (ovl->pitches[0] != w*2) LFATAL("bogus pitches[0] in SDL overlay");
01330       memcpy(ovl->pixels[0], frame.getBuffer(), w * h * 2);
01331       break;
01332 
01333     default:
01334       LFATAL("Unknown SDL overlay format");
01335     }
01336 
01337   //if a valid rectangle, add a patch for external syncing with a photodiode
01338   addSyncRect(ovl, getDims(), itsSync, framenum, sdlformat);
01339 
01340   this->unlockYUVoverlay();
01341   this->displayYUVoverlay(framenum, dly, x, y, rw, rh);
01342 }
01343 
01344 // ######################################################################
01345 void SDLdisplay::displayVideoOverlay_image(const VideoFrame& frame,
01346                                            const int framenum,
01347                                            const DelayType dly,
01348                                            const Image<PixRGB<byte> >& img,
01349                                            const PixRGB<byte>& transpix,
01350                                            const uint threads)
01351 {
01352   // NOTE: this code will probably not work with odd image sizes
01353   if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
01354 
01355   const Uint32 sdlformat = vidformat2sdlmode(frame.getMode());
01356 
01357   if (sdlformat != itsOverlay->format)
01358     LFATAL("video frame format does not match SDL overlay format");
01359 
01360   const int w = frame.getDims().w();
01361   const int h = frame.getDims().h();
01362 
01363   if (w != itsOverlay->w)
01364     LFATAL("video frame width does not match SDL overlay width");
01365 
01366   if (h != itsOverlay->h)
01367     LFATAL("video frame height does not match SDL overlay height");
01368 
01369   if (w != img.getWidth())
01370     LFATAL("video frame width (%d) does not match the overlay image width (%d)",
01371            w, img.getWidth());
01372 
01373   if (h != img.getHeight())
01374     LFATAL("video frame height (%d) does not match overlay image height (%d)",
01375            h, img.getHeight());
01376 
01377   if (h % threads != 0)
01378     LFATAL("Image height should be a multiple of the number of requested"
01379            " threads");
01380 
01381   //get our image data
01382   const byte* src = reinterpret_cast<const byte*>(img.getArrayPtr());
01383 
01384   //lock the display
01385   SDL_Overlay* ovl = this->lockYUVoverlay();
01386 
01387   //get YUV bytes from the overlay, we will fill these
01388   byte* outy = NULL;
01389   byte* outu = NULL;
01390   byte* outv = NULL;
01391 
01392   switch (sdlformat)
01393     {
01394     case SDL_IYUV_OVERLAY:  // Planar mode: Y + U + V  (3 planes)
01395       if (ovl->planes != 3)       LFATAL("IYUV overlay must have 3 planes");
01396       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01397       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01398       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01399 
01400       outy = ovl->pixels[0];
01401       outu = ovl->pixels[1];
01402       outv = ovl->pixels[2];
01403 
01404       break;
01405 
01406     case SDL_YV12_OVERLAY:  // Planar mode: Y + V + U  (3 planes)
01407       if (ovl->planes != 3)       LFATAL("YV12 overlay must have 3 planes");
01408       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01409       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01410       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01411 
01412       outy = ovl->pixels[0];
01413       outu = ovl->pixels[2];
01414       outv = ovl->pixels[1];
01415       break;
01416 
01417     default:
01418       LFATAL("Unknown/Unsupported SDL format for overlay with image");
01419     }
01420 
01421   //get indexes into our data array.
01422   const byte* vidy = frame.getBuffer();
01423   const byte* vidu = frame.getBuffer() + w * h;
01424   const byte* vidv = frame.getBuffer() + w * h + ((w+1)/2) * ((h+1)/2);
01425 
01426   const byte tr = transpix.red();
01427   const byte tg = transpix.green();
01428   const byte tb = transpix.blue();
01429 
01430   //setup some threads
01431   pthread_t threadArray[threads];
01432   const uint rows = h / threads;
01433   uint py(0), puv(0), prgb(0);
01434   RgbYuvOverlayStruct *info[threads];
01435 
01436   for (uint i = 0; i < threads; ++i)
01437     {
01438       info[i] = new RgbYuvOverlayStruct(&vidy[py], &vidu[puv], &vidv[puv],
01439                                         &outy[py], &outu[puv], &outv[puv],
01440                                         &src[prgb], tr, tg, tb, w, rows);
01441 
01442       //create a pthread
01443       pthread_create(&threadArray[i], NULL, &RgbYuvOverlay, (void*)info[i]);
01444 
01445       //increment array positions
01446       py += w * rows;
01447       puv += ((w+1)/2) * ((rows+1)/2);
01448       prgb += w*rows*3;
01449     }
01450 
01451   //wait for all our threads to exit
01452   for (uint i = 0; i < threads; ++i)
01453     {
01454       pthread_join(threadArray[i],NULL);
01455       delete info[i];
01456     }
01457 
01458   //if a valid rectangle, add a patch for external syncing with a photodiode
01459   addSyncRect(ovl, getDims(), itsSync, framenum, sdlformat);
01460 
01461   this->unlockYUVoverlay();
01462   this->displayYUVoverlay(framenum, dly);
01463 }
01464 
01465 // ######################################################################
01466 void SDLdisplay::displayVideoOverlay_patch(const VideoFrame& frame,
01467                                                 const int framenum,
01468                                                 const DelayType dly,
01469                                                 const uint x,
01470                                                 const uint y,
01471                                                 const Image<PixRGB<byte> >& img)
01472 {
01473  if (itsOverlay == NULL) LFATAL("You need to call createYUVoverlay() first");
01474 
01475   const Uint32 sdlformat = vidformat2sdlmode(frame.getMode());
01476 
01477   if (sdlformat != itsOverlay->format)
01478     LFATAL("video frame format does not match SDL overlay format");
01479 
01480   const int w = frame.getDims().w();
01481   const int h = frame.getDims().h();
01482 
01483   if (w != itsOverlay->w)
01484     LFATAL("video frame width does not match SDL overlay width");
01485 
01486   if (h != itsOverlay->h)
01487     LFATAL("video frame height does not match SDL overlay height");
01488 
01489   if (w < img.getWidth())
01490     LFATAL("video frame width (%d) is smaller than the patch width (%d)",
01491            w, img.getWidth());
01492 
01493   if (h < img.getHeight())
01494     LFATAL("video frame height (%d) is small than the patch height (%d)",
01495            h, img.getHeight());
01496 
01497   //lock the display
01498   SDL_Overlay* ovl = this->lockYUVoverlay();
01499 
01500   //get YUV bytes from the overlay, we will fill these in a bit
01501   byte* outy = NULL;
01502   byte* outu = NULL;
01503   byte* outv = NULL;
01504 
01505   //perform the overlay
01506   switch (sdlformat)
01507     {
01508     case SDL_IYUV_OVERLAY:  // Planar mode: Y + U + V  (3 planes)
01509       if (ovl->planes != 3)       LFATAL("IYUV overlay must have 3 planes");
01510       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01511       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01512       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01513 
01514       outy = ovl->pixels[0];
01515       outu = ovl->pixels[1];
01516       outv = ovl->pixels[2];
01517 
01518       memcpy(outy, frame.getBuffer(), w * h);
01519       memcpy(outu, frame.getBuffer() + w * h, ((w+1)/2) * ((h+1)/2));
01520       memcpy(outv, frame.getBuffer() + w * h + ((w+1)/2) * ((h+1)/2),
01521              ((w+1)/2) * ((h+1)/2));
01522       break;
01523     case SDL_YV12_OVERLAY:  // Planar mode: Y + V + U  (3 planes)
01524       if (ovl->planes != 3)       LFATAL("YV12 overlay must have 3 planes");
01525       if (ovl->pitches[0] != w)   LFATAL("bogus pitches[0] in SDL overlay");
01526       if (ovl->pitches[1] != w/2) LFATAL("bogus pitches[1] in SDL overlay");
01527       if (ovl->pitches[2] != w/2) LFATAL("bogus pitches[2] in SDL overlay");
01528 
01529       outy = ovl->pixels[0];
01530       outu = ovl->pixels[2];
01531       outv = ovl->pixels[1];
01532 
01533       memcpy(outy, frame.getBuffer(), w * h);
01534       // NOTE U+V are swapped here, since we're assuming the buffer is
01535       // in VIDFMT_YUV420P format:
01536       memcpy(outu, frame.getBuffer() + w * h, ((w+1)/2) * ((h+1)/2));
01537       memcpy(outv, frame.getBuffer() + w * h + ((w+1)/2) * ((h+1)/2),
01538              ((w+1)/2) * ((h+1)/2));
01539       break;
01540     default:
01541       LFATAL("Unknown/Unsupported SDL format for overlay with patch");
01542     }
01543 
01544   //copy our patch
01545   outy += x  + w*y;
01546   outu += x/2+1 + (w/2)*(y/2);
01547   outv += x/2+1 + (w/2)*(y/2);
01548   if (x % 2 == 0)
01549     {
01550       --outu;
01551       --outv;
01552     }
01553 
01554   int wp = img.getWidth();
01555   int yt = w - wp;
01556   if (wp % 2 != 0)
01557     yt-=1;
01558   const int ystep = yt;
01559   const int ustep = (ystep+1) / 2;
01560   const int vstep = (ystep+1) / 2;
01561 
01562   toVideoYUV422(img, outy, outu, outv, ystep,ustep,vstep);
01563 
01564   //if a valid rectangle, add a patch for external syncing with a photodiode
01565   addSyncRect(ovl, getDims(), itsSync, framenum, sdlformat);
01566   
01567   this->unlockYUVoverlay();
01568   this->displayYUVoverlay(framenum, dly);
01569 
01570 }
01571 
01572 // ######################################################################
01573 void SDLdisplay::displayText(const std::string& msg, const bool vsync,
01574                              const PixRGB<byte> txtcol,
01575                              const PixRGB<byte> bgcol, int ind,
01576                                                                                                                  const int fontsize)
01577 {
01578   // let's get a white image:
01579   Image< PixRGB<byte> > img(itsDims.getVal(), NO_INIT);
01580   img.clear(bgcol);
01581 
01582   // HACK: Image::writeText uses a font width of 10 pixels:
01583   Point2D<int> p; p.i = itsDims.getVal().w() / 2 - (msg.length() / 2 * 10);
01584   switch(ind) {
01585           case 0 : p.j = itsDims.getVal().h() / 2 - 10; break ;
01586           case 1 : p.j = 25 ; break ;
01587           case -1 : p.j = itsDims.getVal().h() - 25; break ;
01588           case -2 :
01589             p.j = (rand()%(itsDims.getVal().h()-40))+20;
01590             p.i = rand()%(itsDims.getVal().w() - (msg.length()-10)) + 5;
01591             break ;
01592           default :  p.j = itsDims.getVal().h() / 2 - 10; break ;
01593   }
01594   if (p.i < 0) LERROR("Text '%s' does not fit on screen!", msg.c_str());
01595 
01596   writeText(img, p, msg.c_str(), txtcol, bgcol, SimpleFont::FIXED(fontsize));
01597 
01598   // let's convert it to something we can blit:
01599   SDL_Surface *surf =
01600     SDL_CreateRGBSurfaceFrom(img.getArrayPtr(), img.getWidth(),
01601                              img.getHeight(), 24, 3 * img.getWidth(),
01602                              0x0000ff, 0x00ff00, 0xff0000, 0x0);
01603   SDL_Surface *surf2 = SDL_DisplayFormat(surf);
01604   SDL_FreeSurface(surf);
01605   displaySurface(surf2, -1, vsync);
01606   SDL_FreeSurface(surf2);
01607 }
01608 // ######################################################################
01609 void SDLdisplay::displayText(const std::string& msg,Point2D<int> p ,
01610                              const PixRGB<byte> txtcol,
01611                              const PixRGB<byte> bgcol,const bool vsync)
01612 {
01613   // let's get a white image:
01614   Image< PixRGB<byte> > img(itsDims.getVal(), NO_INIT);
01615   img.clear(bgcol);
01616 
01617   // HACK: Image::writeText uses a font width of 10 pixels:
01618   writeText(img, p, msg.c_str(), txtcol, bgcol);
01619 
01620   // let's convert it to something we can blit:
01621   SDL_Surface *surf =
01622     SDL_CreateRGBSurfaceFrom(img.getArrayPtr(), img.getWidth(),
01623                              img.getHeight(), 24, 3 * img.getWidth(),
01624                              0x0000ff, 0x00ff00, 0xff0000, 0x0);
01625   SDL_Surface *surf2 = SDL_DisplayFormat(surf);
01626   SDL_FreeSurface(surf);
01627   displaySurface(surf2, -1, vsync);
01628   SDL_FreeSurface(surf2);
01629 }
01630 
01631 // ######################################################################
01632 void SDLdisplay::syncScreen(const bool vsync, const bool checkdelay,
01633                             const bool quiet)
01634 {
01635   // sync to the vertical blanking pulse:
01636   if (vsync)
01637     waitNextRequestedVsync(checkdelay, quiet); // will update itsLastSync
01638 
01639   // swap the buffers:
01640   if (itsScreen->flags & SDL_DOUBLEBUF) SDL_Flip(itsScreen);
01641   else SDL_UpdateRect(itsScreen, 0, 0, 0, 0);
01642 }
01643 //#####################################################################
01644 long SDLdisplay::getTimerValue()
01645 {
01646   return itsTimer.get() ;
01647 }
01648 
01649 // ######################################################################
01650 void SDLdisplay::waitNextRequestedVsync(const bool checkdelay,
01651                                            const bool quiet)
01652 {
01653   if (quiet == false) pushEventBegin("waitVsync");
01654   uint64 prev = itsLastSync;
01655 
01656   // are we using hardware where vblank cannot be detected by polling
01657   // the VGA registers? If so, let's just do some hard waiting:
01658   if (itsVBlankKludge.getVal() > 0)
01659     {
01660       const float refresh2 = itsRefreshDelay.getVal() - float(itsVBlankKludge.getVal());
01661       while(float(itsTimer.get() - itsLastSync) < refresh2)   ;
01662     }
01663   else
01664     {
01665       // since we typically refresh at 120Hz but play frames at 30Hz, make
01666       // sure we catch the correct pulse for our given itsRefresh rate; to
01667       // this end, let's do a slow wait until 5ms before the pulse is
01668       // expected:
01669       const float refresh2 = itsRefreshDelay.getVal() - 5000.0F; // fast access to value
01670       while(float(itsTimer.get() - itsLastSync) < refresh2)   ;
01671 
01672       // we can't access the VGA registers unless we were able to do our
01673       // iopl(3) during init:
01674       if (itsPriority.getVal())
01675         {
01676 #ifndef HAVE_SYS_IO_H
01677           LFATAL("this configuration lacks <sys/io.h>, so it does not support non-zero --sdl-priority");
01678 #else
01679           // this code inspired from directfb-dev; see www.directfb.org.
01680           // Brutal poll of VGA registers; when the bit we poll for is set to
01681           // 1, we are in the vertical blanking interval (for more info on VGA
01682           // registers, see http://www.osdever.net/FreeVGA/vga/portidx.htm).
01683           // Apparently, when in SCHED_FIFO mode, short usleep() calls (10ms
01684           // or less) are implemented as busy waits; so here we don't even
01685           // bother calling usleep and do the busy-waiting ourselves:
01686           if (!(inb(0x3cc) & 1)) // we are in MDA (mono) emulation mode
01687             {
01688               // wait until end of blanking in case we are called so fast that
01689               // we still are in the previous blanking:
01690               while (!(inb(0x3ba) & 0x8)) ;
01691               // wait until start of blanking:
01692               while ((inb(0x3ba) & 0x8)) ;
01693               // we are in blanking NOW
01694             }
01695           else                   // we are in CGA (color) emulation mode
01696             {
01697               // wait until end of blanking in case we are called so fast that
01698               // we still are in the previous blanking:
01699               while (!(inb(0x3da) & 0x8)) ;
01700               // wait until start of blanking:
01701               while ((inb(0x3da) & 0x8)) ;
01702               // we are in blanking NOW
01703             }
01704 #endif // HAVE_SYS_IO_H
01705         }
01706     }
01707 
01708   // update itsLastSync to current time:
01709   itsLastSync = itsTimer.get();
01710   if (quiet == false)
01711     {
01712       if (checkdelay)
01713         {
01714           const float usec = float(itsLastSync - prev);
01715 
01716           const float toolong = itsRefreshDelay.getVal() * (1.0F + itsRefreshTolerance);
01717           const float tooshort = itsRefreshDelay.getVal() * (1.0F - itsRefreshTolerance);
01718 
01719           pushEventEnd(sformat("waitVsync - %.3fms%s",
01720                                usec / 1000.0F,
01721                                usec > toolong ? " ***** SLOW FRAME? *****"
01722                                : usec < tooshort ? " ***** FAST FRAME? *****"
01723                                : ""));
01724         }
01725       else
01726         pushEventEnd("waitVsync");
01727     }
01728 }
01729 
01730 // ######################################################################
01731 void SDLdisplay::waitNextRequestedFrameTime(const int frame,
01732                                             const bool checkdelay,
01733                                             const bool quiet)
01734 {
01735   if (frame < 0)
01736     LFATAL("frame number must be non-negative");
01737 
01738   if (quiet == false) pushEventBegin("waitFrameTime");
01739 
01740   uint64 prev = itsLastSync;
01741 
01742   if (frame == 0)
01743     {
01744       itsTimer.reset();
01745       itsLastSync = 0;
01746       prev = 0;
01747     }
01748   else
01749     {
01750       ASSERT(itsRefreshDelay.getVal() > 0.0f);
01751 
01752       // check how many bits will be used when we multiply
01753       // itsRefreshDelay by the frame number; we want to make sure we
01754       // can hold that many bits in a double without rounding, since
01755       // otherwise we will lose precision:
01756       const int nbits =
01757         int(ceil(log(double(itsRefreshDelay.getVal())) / log(2))
01758             + ceil(log(double(frame)) / log(2)));
01759 
01760       // if double has 53 bits in the mantissa, and the frame numbers
01761       // run from 0-999999, using ~20 bits, then that leaves ~33 bits
01762       // for itsRefreshDelay, which should be plenty since typical
01763       // delays are in the 16000-33000us range, using ~15 bits for the
01764       // integral portion, and leaving ~18 bits for the fractional
01765       // portion:
01766       if (nbits > std::numeric_limits<double>::digits)
01767         LERROR("Oops! Loss of precision in our frame time calculations!");
01768 
01769       const uint64 target_time =
01770         uint64(double(itsRefreshDelay.getVal()) * frame);
01771 
01772       const uint64 min_time =
01773         prev + uint64(0.5 * itsRefreshDelay.getVal());
01774 
01775       const uint64 wait_until = std::max(target_time, min_time);
01776 
01777       // now do a slow wait until the frame delay is finished:
01778       while (itsTimer.get() < wait_until)
01779         { /* busy loop */ }
01780 
01781       itsLastSync = itsTimer.get();
01782 
01783       ASSERT(itsLastSync >= target_time);
01784     }
01785 
01786   if (quiet == false)
01787     {
01788       if (checkdelay)
01789         {
01790           const double hertz =
01791             itsLastSync == 0
01792             ? 0.0
01793             : ((double(frame) * 1000000.0) / itsLastSync);
01794 
01795           const float usec = float(itsLastSync - prev);
01796 
01797           const float toolong =
01798             itsRefreshDelay.getVal() * (1.0F + itsRefreshTolerance);
01799           const float tooshort =
01800             itsRefreshDelay.getVal() * (1.0F - itsRefreshTolerance);
01801 
01802           pushEventEnd(sformat("waitFrameTime - %.3fms - %.3fHz%s",
01803                                usec / 1000.0F, hertz,
01804                                usec > toolong ? " ***** SLOW FRAME? *****"
01805                                : usec < tooshort ? " ***** FAST FRAME? *****"
01806                                : ""));
01807         }
01808       else
01809         pushEventEnd("waitFrameTime");
01810     }
01811 }
01812 
01813 // ######################################################################
01814 void SDLdisplay::waitFrames(const int n)
01815 {
01816   for (int i = 0; i < n; ++i) waitNextRequestedVsync();
01817 }
01818 
01819 // ######################################################################
01820 void SDLdisplay::setDesiredRefreshDelayUsec(float usec, float tol)
01821 {
01822   itsRefreshDelay.setVal(usec);
01823   itsRefreshTolerance = tol;
01824 }
01825 
01826 
01827 // ######################################################################
01828 // from SDL manual (http://sdldoc.csn.ul.ie/guidevideo.php#GUIDEVIDEOINTRO)
01829 Uint32 SDLdisplay::getPixel32(const int x, const int y) const
01830 {
01831   // Compute the address to the pixel we want to retrieve:
01832   int bpp = getBytesPerPixel();
01833   Uint8 *p = (Uint8 *)(itsScreen->pixels) + y * itsScreen->pitch + x * bpp;
01834 
01835   switch(bpp)
01836     {
01837     case 1:
01838       return *p;
01839 
01840     case 2:
01841       return *(Uint16 *)p;
01842 
01843     case 3:
01844       if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
01845         return p[0] << 16 | p[1] << 8 | p[2];
01846       else
01847         return p[0] | p[1] << 8 | p[2] << 16;
01848 
01849     case 4:
01850       return *(Uint32 *)p;
01851 
01852     default:
01853       return 0;       // shouldn't happen, but avoids warnings
01854     }
01855 }
01856 
01857 // ######################################################################
01858 // from SDL manual (http://sdldoc.csn.ul.ie/guidevideo.php#GUIDEVIDEOINTRO)
01859 void SDLdisplay::putPixel32(const int x, const int y, const Uint32 pixel)
01860 {
01861   // Compute the address to the pixel we want to set:
01862   int bpp = getBytesPerPixel();
01863   Uint8 *p = (Uint8 *)(itsScreen->pixels) + y * itsScreen->pitch + x * bpp;
01864 
01865   switch(bpp)
01866     {
01867     case 1:
01868       *p = pixel;
01869       break;
01870 
01871     case 2:
01872       *(Uint16 *)p = pixel;
01873       break;
01874 
01875     case 3:
01876       if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
01877         {
01878           p[0] = (pixel >> 16) & 0xff;
01879           p[1] = (pixel >> 8) & 0xff;
01880           p[2] = pixel & 0xff;
01881         }
01882       else
01883         {
01884           p[0] = pixel & 0xff;
01885           p[1] = (pixel >> 8) & 0xff;
01886           p[2] = (pixel >> 16) & 0xff;
01887         }
01888       break;
01889 
01890     case 4:
01891       *(Uint32 *)p = pixel;
01892       break;
01893 
01894     default:
01895       LFATAL("Cannot handle pixels with %dbpp", bpp);
01896     }
01897 }
01898 
01899 #endif // HAVE_SDL_SDL_H
01900 
01901 // ######################################################################
01902 /* So things look consistent in everyone's emacs... */
01903 /* Local Variables: */
01904 /* indent-tabs-mode: nil */
01905 /* End: */
Generated on Sun May 8 08:04:48 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3