00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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>
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
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
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 switch (vidformat)
00099 {
00100
00101
00102
00103
00104
00105
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;
00115 case VIDFMT_GREY: break;
00116 case VIDFMT_RAW: break;
00117 case VIDFMT_RGB24: break;
00118 case VIDFMT_RGB32: break;
00119 case VIDFMT_RGB555: break;
00120 case VIDFMT_RGB565: break;
00121 case VIDFMT_YUV410: break;
00122 case VIDFMT_YUV410P: break;
00123 case VIDFMT_YUV411: break;
00124 case VIDFMT_YUV411P: break;
00125 case VIDFMT_YUV420: break;
00126 case VIDFMT_YUV422P: break;
00127 case VIDFMT_YUV24: break;
00128 case VIDFMT_YUV444: break;
00129 case VIDFMT_YUV444P: break;
00130 case VIDFMT_HM12: break;
00131 case VIDFMT_BAYER_GB: break;
00132 case VIDFMT_BAYER_GR: break;
00133 case VIDFMT_BAYER_RG: break;
00134 case VIDFMT_BAYER_BG: break;
00135 case VIDFMT_BAYER_GB12: break;
00136 case VIDFMT_BAYER_GR12: break;
00137 case VIDFMT_BAYER_RG12: break;
00138 case VIDFMT_BAYER_BG12: break;
00139 case VIDFMT_MJPEG: break;
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
00154 LFATAL("No SDL overlay mode matching VideoFormat %s (%d)",
00155 convertToString(vidformat).c_str(), int(vidformat));
00156 return 0;
00157 }
00158
00159
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
00188 byte* outy = ovl->pixels[0];
00189 byte* outu = ovl->pixels[1];
00190 byte* outv = ovl->pixels[2];
00191
00192
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;
00200
00201
00202 outy += x + w*y;
00203 outu += cpos;
00204 outv += cpos;
00205
00206
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
00232 for (int j = 0; j < data->h; j += 2)
00233 {
00234
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
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
00265
00266
00267
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
00290
00291 }
00292
00293
00294 for (int i = 0; i < data->w; i += 2)
00295 {
00296
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
00319
00320
00321
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
00345
00346
00347 if (count[i] > 0)
00348 {
00349
00350 double ut = *data->vidu++;
00351 double vt = *data->vidv++;
00352
00353
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 }
00374 }
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),
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),
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
00402
00403
00404
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
00418
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
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
00449 int pri = itsPriority.getVal();
00450 if (pri)
00451 {
00452
00453
00454
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
00461 if (setuid(0) == -1)
00462 PLFATAL("I need to run as root when --sdl-priority is non-zero (%d)", pri);
00463
00464
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, ¶ms) == -1)
00473 PLFATAL("Cannot switch to SCHED_FIFO scheduling and priority %d", pri);
00474
00475
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
00492
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
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
00510 char vname[256]; SDL_VideoDriverName(vname, 256);
00511 LINFO("Using SDL video driver '%s'", vname);
00512
00513
00514 SDL_EnableUNICODE(1);
00515
00516
00517
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
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
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
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
00567 if (itsOverlay) { destroyYUVoverlay(); itsOverlay = NULL; }
00568
00569
00570 if (itsSlaveMode.getVal() == false && itsScreen)
00571 { LINFO("Closing down SDL..."); SDL_Quit(); itsScreen = NULL; }
00572
00573
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
00581 struct sched_param params; params.sched_priority = 0;
00582 if (sched_setscheduler(0, SCHED_OTHER, ¶ms) == -1)
00583 PLFATAL("Cannot switch back to SCHED_OTHER");
00584
00585
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
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
00625 lockScreen();
00626
00627
00628 int bpp = getBytesPerPixel();
00629 memset(itsScreen->pixels, 0, itsDims.getVal().sz() * bpp);
00630
00631
00632 unlockScreen();
00633 }
00634
00635
00636 int SDLdisplay::waitForKeyTimeout(double timeout, bool doWait)
00637 {
00638
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
00656 if (key == 27) LFATAL("Aborting on [ESC] key");
00657
00658 return key;
00659 }
00660
00661
00662 int SDLdisplay::waitForKey(bool doWait)
00663 {
00664
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
00677 if (key == 27) LFATAL("Aborting on [ESC] key");
00678
00679 return key;
00680 }
00681
00682
00683 int SDLdisplay::waitForMouseClick(bool doWait)
00684 {
00685
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;
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
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;
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
00744 if (key == 27) LFATAL("Aborting on [ESC] key");
00745
00746 return key;
00747 }
00748
00749 }
00750
00751
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
00774 }
00775
00776
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
00810
00811
00812
00813
00814
00815 if (this->itsDims.getVal() != img.getDims())
00816 {
00817 image = Image< PixRGB<byte> >(itsDims.getVal(), NO_INIT);
00818
00819 if (resiz)
00820 {
00821
00822 inplaceEmbed(image, img, image.getBounds(), bgcol, true);
00823 }
00824 else
00825 {
00826
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
00841 drawFilledRect(image, itsSync, PixRGB<byte>(255,255,255));
00842 }
00843
00844
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
00860 if (frame == -2) pushEventBegin("displayImage");
00861
00862
00863
00864 if (vsync && frame == 0)
00865 waitNextRequestedVsync(false, false);
00866
00867
00868 if (SDL_BlitSurface(img, NULL, itsScreen, NULL) == -1)
00869 SDLFATAL("Blit failed");
00870
00871
00872 syncScreen(vsync, (frame >= 0), false);
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
00885 if (frame == -2) pushEventBegin("displaySurfacePatch");
00886
00887
00888
00889 if (vsync && frame == 0)
00890 waitNextRequestedVsync(false, false);
00891
00892 if (SDL_BlitSurface(surf, NULL, itsScreen, offset) == -1)
00893 SDLFATAL("Blit failed");
00894
00895
00896
00897 if (flip) syncScreen(vsync, (frame >= 0), false);
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
00910 if (frame == -2) pushEventBegin("displayImagePatch");
00911
00912
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
00922
00923 if (vsync && frame == 0)
00924 waitNextRequestedVsync(false, false);
00925
00926
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
00934 if (flip) syncScreen(vsync, (frame >= 0), false);
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
01017 switch (dly)
01018 {
01019 case NO_WAIT:
01020 {
01021
01022 if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01023 SDLFATAL("Overlay blit failed");
01024
01025
01026
01027
01028
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
01054
01055 if (frame == 0)
01056 waitNextRequestedVsync(false, false);
01057
01058
01059 if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01060 SDLFATAL("Overlay blit failed");
01061
01062
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
01073 waitNextRequestedFrameTime(frame, (frame >= 0), false);
01074
01075
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
01093 switch (dly)
01094 {
01095 case NO_WAIT:
01096 {
01097
01098 if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01099 SDLFATAL("Overlay blit failed");
01100
01101
01102
01103
01104
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
01130
01131 if (frame == 0)
01132 waitNextRequestedVsync(false, false);
01133
01134
01135 if (SDL_DisplayYUVOverlay(itsOverlay, &r) == -1)
01136 SDLFATAL("Overlay blit failed");
01137
01138
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
01149 waitNextRequestedFrameTime(frame, (frame >= 0), false);
01150
01151
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:
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:
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
01228
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:
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:
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:
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
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:
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:
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
01309
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:
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:
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:
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
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
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
01382 const byte* src = reinterpret_cast<const byte*>(img.getArrayPtr());
01383
01384
01385 SDL_Overlay* ovl = this->lockYUVoverlay();
01386
01387
01388 byte* outy = NULL;
01389 byte* outu = NULL;
01390 byte* outv = NULL;
01391
01392 switch (sdlformat)
01393 {
01394 case SDL_IYUV_OVERLAY:
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:
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
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
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
01443 pthread_create(&threadArray[i], NULL, &RgbYuvOverlay, (void*)info[i]);
01444
01445
01446 py += w * rows;
01447 puv += ((w+1)/2) * ((rows+1)/2);
01448 prgb += w*rows*3;
01449 }
01450
01451
01452 for (uint i = 0; i < threads; ++i)
01453 {
01454 pthread_join(threadArray[i],NULL);
01455 delete info[i];
01456 }
01457
01458
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
01498 SDL_Overlay* ovl = this->lockYUVoverlay();
01499
01500
01501 byte* outy = NULL;
01502 byte* outu = NULL;
01503 byte* outv = NULL;
01504
01505
01506 switch (sdlformat)
01507 {
01508 case SDL_IYUV_OVERLAY:
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:
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
01535
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
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
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
01579 Image< PixRGB<byte> > img(itsDims.getVal(), NO_INIT);
01580 img.clear(bgcol);
01581
01582
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
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
01614 Image< PixRGB<byte> > img(itsDims.getVal(), NO_INIT);
01615 img.clear(bgcol);
01616
01617
01618 writeText(img, p, msg.c_str(), txtcol, bgcol);
01619
01620
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
01636 if (vsync)
01637 waitNextRequestedVsync(checkdelay, quiet);
01638
01639
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
01657
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
01666
01667
01668
01669 const float refresh2 = itsRefreshDelay.getVal() - 5000.0F;
01670 while(float(itsTimer.get() - itsLastSync) < refresh2) ;
01671
01672
01673
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
01680
01681
01682
01683
01684
01685
01686 if (!(inb(0x3cc) & 1))
01687 {
01688
01689
01690 while (!(inb(0x3ba) & 0x8)) ;
01691
01692 while ((inb(0x3ba) & 0x8)) ;
01693
01694 }
01695 else
01696 {
01697
01698
01699 while (!(inb(0x3da) & 0x8)) ;
01700
01701 while ((inb(0x3da) & 0x8)) ;
01702
01703 }
01704 #endif // HAVE_SYS_IO_H
01705 }
01706 }
01707
01708
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
01753
01754
01755
01756 const int nbits =
01757 int(ceil(log(double(itsRefreshDelay.getVal())) / log(2))
01758 + ceil(log(double(frame)) / log(2)));
01759
01760
01761
01762
01763
01764
01765
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
01778 while (itsTimer.get() < wait_until)
01779 { }
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
01829 Uint32 SDLdisplay::getPixel32(const int x, const int y) const
01830 {
01831
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;
01854 }
01855 }
01856
01857
01858
01859 void SDLdisplay::putPixel32(const int x, const int y, const Uint32 pixel)
01860 {
01861
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
01903
01904
01905