00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <cstdlib>
00020 #include <cstdio>
00021 #include <cerrno>
00022 #include <cmath>
00023 #include <unistd.h>
00024 #include <fcntl.h>
00025
00026 #include <sys/types.h>
00027 #include <sys/stat.h>
00028 #include "compat.h"
00029
00030 #ifndef _WIN32
00031 #include <sys/ioctl.h>
00032 #include <sys/poll.h>
00033 #endif
00034
00035 #include <mythcontext.h>
00036 #include "mythdialogs.h"
00037 #ifdef USING_XV
00038 #include "videoout_xv.h"
00039 #endif
00040 #include "util-x11.h"
00041
00042 #ifdef USING_OPENGL_VSYNC
00043 #include "util-opengl.h"
00044 #endif // USING_OPENGL_VSYNC
00045
00046 #ifdef __linux__
00047 #include <linux/rtc.h>
00048 #endif
00049
00050 using namespace std;
00051 #include "vsync.h"
00052
00053 bool tryingVideoSync = false;
00054 int VideoSync::m_forceskip = 0;
00055
00056 #define TESTVIDEOSYNC(NAME) \
00057 do { if (++m_forceskip > skip) \
00058 { \
00059 trial = new NAME (video_output, frame_interval, \
00060 refresh_interval, halve_frame_interval); \
00061 if (trial->TryInit()) \
00062 { \
00063 m_forceskip = skip; \
00064 tryingVideoSync = false; \
00065 return trial; \
00066 } \
00067 delete trial; \
00068 } } while (false)
00069
00073 VideoSync *VideoSync::BestMethod(VideoOutput *video_output,
00074 uint frame_interval, uint refresh_interval,
00075 bool halve_frame_interval)
00076 {
00077 VideoSync *trial = NULL;
00078 tryingVideoSync = true;
00079 bool tryOpenGL = (gContext->GetNumSetting("UseOpenGLVSync", 1) &&
00080 (getenv("NO_OPENGL_VSYNC") == NULL));
00081
00082
00083
00084 int skip = 0;
00085 if (m_forceskip)
00086 {
00087 VERBOSE(VB_PLAYBACK, QString("A previous trial crashed,"
00088 " skipping %1").arg(m_forceskip));
00089
00090 skip = m_forceskip;
00091 m_forceskip = 0;
00092 }
00093
00094 #ifndef _WIN32
00095 TESTVIDEOSYNC(nVidiaVideoSync);
00096 TESTVIDEOSYNC(DRMVideoSync);
00097 if (tryOpenGL)
00098 TESTVIDEOSYNC(OpenGLVideoSync);
00099 #endif // _WIN32
00100 #ifdef __linux__
00101 TESTVIDEOSYNC(RTCVideoSync);
00102 #endif // __linux__
00103
00104 TESTVIDEOSYNC(BusyWaitVideoSync);
00105
00106 tryingVideoSync=false;
00107 return NULL;
00108 }
00109
00114 VideoSync::VideoSync(VideoOutput *video_output,
00115 int frameint, int refreshint,
00116 bool halve_frame_interval) :
00117 m_video_output(video_output),
00118 m_frame_interval(frameint), m_refresh_interval(refreshint),
00119 m_interlaced(halve_frame_interval)
00120 {
00121 if (m_interlaced && m_refresh_interval > m_frame_interval/2)
00122 m_interlaced = false;
00123
00124
00125 }
00126
00127 void VideoSync::Start(void)
00128 {
00129 gettimeofday(&m_nexttrigger, NULL);
00130 }
00131
00135 void VideoSync::SetFrameInterval(int fr, bool intr)
00136 {
00137 m_frame_interval = fr;
00138 m_interlaced = intr;
00139 if (m_interlaced && m_refresh_interval > m_frame_interval/2)
00140 m_interlaced = false;
00141
00142 VERBOSE(VB_PLAYBACK, QString("Set video sync frame interval to %1")
00143 .arg(m_frame_interval));
00144 }
00145
00146 void VideoSync::OffsetTimeval(struct timeval& tv, int offset)
00147 {
00148 tv.tv_usec += offset;
00149 while (tv.tv_usec > 999999)
00150 {
00151 tv.tv_sec++;
00152 tv.tv_usec -= 1000000;
00153 }
00154 while (tv.tv_usec < 0)
00155 {
00156 tv.tv_sec--;
00157 tv.tv_usec += 1000000;
00158 }
00159 }
00160
00166 void VideoSync::UpdateNexttrigger()
00167 {
00168
00169
00170 if (m_interlaced)
00171 OffsetTimeval(m_nexttrigger, m_frame_interval/2);
00172 else
00173 OffsetTimeval(m_nexttrigger, m_frame_interval);
00174 }
00175
00185 int VideoSync::CalcDelay()
00186 {
00187 struct timeval now;
00188 gettimeofday(&now, NULL);
00189
00190
00191
00192 int ret_val = (m_nexttrigger.tv_sec - now.tv_sec) * 1000000 +
00193 (m_nexttrigger.tv_usec - now.tv_usec);
00194
00195
00196
00197 if (ret_val > m_frame_interval * 2)
00198 {
00199 if (m_interlaced)
00200 ret_val = m_frame_interval;
00201 else
00202 ret_val = m_frame_interval * 2;
00203
00204
00205 m_nexttrigger.tv_sec = now.tv_sec;
00206 m_nexttrigger.tv_usec = now.tv_usec;
00207 OffsetTimeval(m_nexttrigger, ret_val);
00208 }
00209 return ret_val;
00210 }
00211
00220 void VideoSync::KeepPhase()
00221 {
00222
00223 if (m_delay < -(m_refresh_interval/2))
00224 OffsetTimeval(m_nexttrigger, 200);
00225 else if (m_delay > -500)
00226 OffsetTimeval(m_nexttrigger, -2000);
00227 }
00228
00229 #ifndef _WIN32
00230 #define DRM_VBLANK_RELATIVE 0x1;
00231
00232 struct drm_wait_vblank_request {
00233 int type;
00234 unsigned int sequence;
00235 unsigned long signal;
00236 };
00237
00238 struct drm_wait_vblank_reply {
00239 int type;
00240 unsigned int sequence;
00241 long tval_sec;
00242 long tval_usec;
00243 };
00244
00245 typedef union drm_wait_vblank {
00246 struct drm_wait_vblank_request request;
00247 struct drm_wait_vblank_reply reply;
00248 } drm_wait_vblank_t;
00249
00250 #define DRM_IOCTL_BASE 'd'
00251 #define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
00252
00253 #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
00254
00255 static int drmWaitVBlank(int fd, drm_wait_vblank_t *vbl)
00256 {
00257 int ret = -1;
00258
00259 do {
00260 ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
00261 vbl->request.type &= ~DRM_VBLANK_RELATIVE;
00262 } while (ret && errno == EINTR);
00263
00264 return ret;
00265 }
00266
00267 char *DRMVideoSync::sm_dri_dev = "/dev/dri/card0";
00268
00269 DRMVideoSync::DRMVideoSync(VideoOutput *vo, int fr, int ri, bool intl) :
00270 VideoSync(vo, fr, ri, intl)
00271 {
00272 m_dri_fd = -1;
00273 }
00274
00275 DRMVideoSync::~DRMVideoSync()
00276 {
00277 if (m_dri_fd >= 0)
00278 close(m_dri_fd);
00279 m_dri_fd = -1;
00280 }
00281
00282 bool DRMVideoSync::TryInit(void)
00283 {
00284 drm_wait_vblank_t blank;
00285
00286 m_dri_fd = open(sm_dri_dev, O_RDWR);
00287 if (m_dri_fd < 0)
00288 {
00289 VERBOSE(VB_PLAYBACK, QString("DRMVideoSync: Could not open device"
00290 " %1, %2").arg(sm_dri_dev).arg(strerror(errno)));
00291 return false;
00292 }
00293
00294 blank.request.type = DRM_VBLANK_RELATIVE;
00295 blank.request.sequence = 1;
00296 if (drmWaitVBlank(m_dri_fd, &blank))
00297 {
00298 VERBOSE(VB_PLAYBACK, QString("DRMVideoSync: VBlank ioctl did not work,"
00299 " unimplemented in this driver?"));
00300 return false;
00301 }
00302
00303 return true;
00304 }
00305
00306 void DRMVideoSync::Start(void)
00307 {
00308
00309 drm_wait_vblank_t blank;
00310 blank.request.type = DRM_VBLANK_RELATIVE;
00311 blank.request.sequence = 1;
00312 drmWaitVBlank(m_dri_fd, &blank);
00313 VideoSync::Start();
00314 }
00315
00316 void DRMVideoSync::WaitForFrame(int sync_delay)
00317 {
00318
00319 OffsetTimeval(m_nexttrigger, sync_delay);
00320
00321 m_delay = CalcDelay();
00322
00323
00324
00325 if (m_delay > -(m_refresh_interval/2))
00326 {
00327 drm_wait_vblank_t blank;
00328 blank.request.type = DRM_VBLANK_RELATIVE;
00329 blank.request.sequence = 1;
00330 drmWaitVBlank(m_dri_fd, &blank);
00331 m_delay = CalcDelay();
00332
00333 }
00334
00335
00336 if (m_delay > 0)
00337 {
00338
00339 int n = m_delay / m_refresh_interval + 1;
00340
00341 drm_wait_vblank_t blank;
00342 blank.request.type = DRM_VBLANK_RELATIVE;
00343 blank.request.sequence = n;
00344 drmWaitVBlank(m_dri_fd, &blank);
00345 m_delay = CalcDelay();
00346
00347
00348 }
00349 }
00350
00351 void DRMVideoSync::AdvanceTrigger(void)
00352 {
00353 KeepPhase();
00354 UpdateNexttrigger();
00355 }
00356 #endif
00357
00358 #ifndef _WIN32
00359 char *nVidiaVideoSync::sm_nvidia_dev = "/dev/nvidia0";
00360
00361 nVidiaVideoSync::nVidiaVideoSync(VideoOutput *vo,
00362 int fi, int ri, bool intr) :
00363 VideoSync(vo, fi, ri, intr)
00364 {
00365 }
00366
00367 nVidiaVideoSync::~nVidiaVideoSync()
00368 {
00369 if (m_nvidia_fd >= 0)
00370 close(m_nvidia_fd);
00371 }
00372
00373 bool nVidiaVideoSync::dopoll() const
00374 {
00375 int ret;
00376 struct pollfd polldata;
00377 polldata.fd = m_nvidia_fd;
00378 polldata.events = 0xff;
00379 polldata.revents = 0;
00380 ret = poll( &polldata, 1, 100 );
00381 if (!ret)
00382 return false;
00383 if (ret < 0)
00384 {
00385 perror("nVidiaVideoSync::");
00386 return false;
00387 }
00388 return true;
00389 }
00390
00391 bool nVidiaVideoSync::TryInit(void)
00392 {
00393 m_nvidia_fd = open(sm_nvidia_dev, O_RDONLY);
00394 if (m_nvidia_fd < 0)
00395 {
00396 VERBOSE(VB_PLAYBACK, QString("nVidiaVideoSync: Could not open device"
00397 " %1, %2").arg(sm_nvidia_dev).arg(strerror(errno)));
00398 return false;
00399 }
00400
00401 if (!dopoll())
00402 {
00403 VERBOSE(VB_PLAYBACK, QString("nVidiaVideoSync: VBlank ioctl did not work,"
00404 " unimplemented in this driver?"));
00405 close(m_nvidia_fd);
00406 return false;
00407 }
00408 return true;
00409 }
00410
00411 void nVidiaVideoSync::Start(void)
00412 {
00413 dopoll();
00414 VideoSync::Start();
00415 }
00416
00417 void nVidiaVideoSync::WaitForFrame(int sync_delay)
00418 {
00419 OffsetTimeval(m_nexttrigger, sync_delay);
00420
00421 m_delay = CalcDelay();
00422
00423
00424 if (m_delay > -(m_refresh_interval/2))
00425 {
00426 dopoll();
00427 m_delay = CalcDelay();
00428 }
00429
00430
00431 while (m_delay > 0)
00432 {
00433 dopoll();
00434 m_delay = CalcDelay();
00435 }
00436 }
00437
00438 void nVidiaVideoSync::AdvanceTrigger(void)
00439 {
00440 KeepPhase();
00441 UpdateNexttrigger();
00442 }
00443 #endif
00444
00445 #ifndef _WIN32
00446 OpenGLVideoSync::OpenGLVideoSync(VideoOutput *video_output,
00447 int frame_interval, int refresh_interval,
00448 bool interlaced)
00449 : VideoSync(video_output, frame_interval, refresh_interval, interlaced),
00450 m_drawable(0), m_context(0), m_lock(false)
00451 {
00452 VERBOSE(VB_IMPORTANT, "OpenGLVideoSync()");
00453 }
00454
00455 OpenGLVideoSync::~OpenGLVideoSync()
00456 {
00457 VERBOSE(VB_IMPORTANT, "~OpenGLVideoSync() -- begin");
00458 #ifdef USING_OPENGL_VSYNC
00459 QMutexLocker locker(&m_lock);
00460
00461 VideoOutputXv *vo = dynamic_cast<VideoOutputXv*>(m_video_output);
00462 if (vo && vo->XJ_disp)
00463 {
00464 VERBOSE(VB_IMPORTANT, "~OpenGLVideoSync() -- middle");
00465 Stop();
00466 if (m_context)
00467 X11S(glXDestroyContext(vo->XJ_disp, m_context));
00468 if (m_drawable)
00469 X11S(XDestroyWindow(vo->XJ_disp, m_drawable));
00470 }
00471 #endif
00472 VERBOSE(VB_IMPORTANT, "~OpenGLVideoSync() -- end");
00473 }
00474
00479 bool OpenGLVideoSync::TryInit(void)
00480 {
00481 #ifdef USING_OPENGL_VSYNC
00482 QMutexLocker locker(&m_lock);
00483
00484 VideoOutputXv *vo = dynamic_cast<VideoOutputXv*>(m_video_output);
00485 if (!vo)
00486 {
00487 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: No VideoOutput.");
00488 return false;
00489 }
00490
00491 if (!vo->XJ_disp)
00492 {
00493 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: "
00494 "VideoOutputXv does not have X Window Display.");
00495 return false;
00496 }
00497
00498
00499 uint major, minor;
00500 if (!init_opengl() || !get_glx_version(vo->XJ_disp, major, minor))
00501 {
00502 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: OpenGL extension not present.");
00503 return false;
00504 }
00505
00506
00507 const char *xt = NULL;
00508 X11S(xt = glXQueryExtensionsString(vo->XJ_disp, vo->XJ_screen_num));
00509 const QString glx_ext = xt;
00510 if (!has_glx_video_sync_support(glx_ext))
00511 {
00512 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: GLX Video Sync not available");
00513 return false;
00514 }
00515
00516 int attribList[] = {GLX_RGBA,
00517 GLX_RED_SIZE, 1,
00518 GLX_GREEN_SIZE, 1,
00519 GLX_BLUE_SIZE, 1,
00520 None};
00521 XVisualInfo *vis;
00522 XSetWindowAttributes swa;
00523 Window w;
00524
00525 X11S(vis = glXChooseVisual(vo->XJ_disp, vo->XJ_screen_num, attribList));
00526 if (vis == NULL)
00527 {
00528 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: No appropriate visual found");
00529 return false;
00530 }
00531 X11S(swa.colormap = XCreateColormap(vo->XJ_disp,
00532 RootWindow(vo->XJ_disp, vis->screen),
00533 vis->visual, AllocNone));
00534 if (swa.colormap == 0)
00535 {
00536 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: Failed to create colormap");
00537 return false;
00538 }
00539
00540 MythMainWindow *mainWindow = gContext->GetMainWindow();
00541 uint x = mainWindow->x() + (mainWindow->width()/2);
00542 uint y = mainWindow->y() + (mainWindow->height()/2);
00543 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: x,y -> "<<x<<", "<<y);
00544 X11S(w = XCreateWindow(vo->XJ_disp, RootWindow(vo->XJ_disp, vis->screen),
00545 x, y, 1 , 1 ,
00546 0 , vis->depth, InputOutput,
00547 vis->visual, CWColormap, &swa));
00548 if (w == 0)
00549 {
00550 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: Failed to create dummy window");
00551 return false;
00552 }
00553 m_drawable = w;
00554
00555 X11S(m_context = glXCreateContext(vo->XJ_disp, vis, None, GL_TRUE));
00556 if (m_context == NULL)
00557 {
00558 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: Failed to create GLX context");
00559 return false;
00560 }
00561
00562 int ret;
00563 X11S(ret = glXMakeCurrent(vo->XJ_disp, m_drawable, m_context));
00564 if (ret != False)
00565 {
00566 unsigned int count;
00567 X11S(ret = gMythGLXGetVideoSyncSGI(&count));
00568 if (ret == 0)
00569 {
00570 VERBOSE(VB_PLAYBACK, "Using OpenGLVideoSync");
00571 return true;
00572 }
00573 else if (GLX_BAD_CONTEXT == ret)
00574 VERBOSE(VB_PLAYBACK, "OpenGLVideoSync: Bad Context for VSync");
00575 else
00576 VERBOSE(VB_PLAYBACK, QString("OpenGLVideoSync: Could not get "
00577 "VSync support ret=%1").arg(ret));
00578 return false;
00579 }
00580 else
00581 {
00582 VERBOSE(VB_PLAYBACK,
00583 "OpenGLVideoSync: Failed to make GLX context current context");
00584 return false;
00585 }
00586 #else
00587 return false;
00588 #endif
00589 }
00590
00596 bool checkGLSyncError(const QString& hdr, int err)
00597 {
00598 (void) hdr;
00599 (void) err;
00600 #ifdef USING_OPENGL_VSYNC
00601 QString errStr("");
00602 switch (err)
00603 {
00604 case False:
00605 break;
00606 case GLX_BAD_CONTEXT:
00607 errStr = "Bad Context";
00608 break;
00609 case GLX_BAD_VALUE:
00610 errStr = "Bad Value";
00611 break;
00612 default:
00613 errStr = QString("Unknown Error 0x%1").arg(err,0,16);
00614 break;
00615 }
00616 if (errStr != "")
00617 {
00618 VERBOSE(VB_IMPORTANT, hdr+" reported error: "+errStr);
00619 return false;
00620 }
00621 return true;
00622 #else
00623 return false;
00624 #endif
00625 }
00626
00627 void OpenGLVideoSync::Start(void)
00628 {
00629 #ifdef USING_OPENGL_VSYNC
00630 QMutexLocker locker(&m_lock);
00631
00632 VideoOutputXv *vo = dynamic_cast<VideoOutputXv*>(m_video_output);
00633 if (!vo || !vo->XJ_disp)
00634 return;
00635
00636 int err;
00637
00638 X11S(err = glXMakeCurrent(vo->XJ_disp, m_drawable, m_context));
00639 if (err != True)
00640 {
00641 VERBOSE(VB_PLAYBACK,
00642 "OpenGLVideoSync::Start(): Failed to make GLX context "
00643 "current context. A/V Sync will probably fail.");
00644 }
00645
00646
00647 unsigned int count;
00648 X11S(err = gMythGLXGetVideoSyncSGI(&count));
00649 checkGLSyncError("OpenGLVideoSync::Start(): Frame Number Query", err);
00650 X11S(err = gMythGLXWaitVideoSyncSGI(2, (count+1)%2 ,&count));
00651 checkGLSyncError("OpenGLVideoSync::Start(): A/V Sync", err);
00652
00653 X11S(err = glXMakeCurrent(vo->XJ_disp, None, NULL));
00654
00655
00656 VideoSync::Start();
00657 #endif
00658 }
00659
00660 void OpenGLVideoSync::WaitForFrame(int sync_delay)
00661 {
00662 (void) sync_delay;
00663 #ifdef USING_OPENGL_VSYNC
00664 QMutexLocker locker(&m_lock);
00665
00666 const QString msg1("First A/V Sync"), msg2("Second A/V Sync");
00667 OffsetTimeval(m_nexttrigger, sync_delay);
00668
00669 VideoOutputXv *vo = dynamic_cast<VideoOutputXv*>(m_video_output);
00670
00671 int err;
00672 X11S(err = glXMakeCurrent(vo->XJ_disp, m_drawable, m_context));
00673
00674 unsigned int frameNum = 0;
00675 X11S(err = gMythGLXGetVideoSyncSGI(&frameNum));
00676 checkGLSyncError("Frame Number Query", err);
00677
00678
00679 if ((m_delay = CalcDelay()) > -(m_refresh_interval/2))
00680 {
00681 err = gMythGLXWaitVideoSyncSGI(2, (frameNum+1)%2 ,&frameNum);
00682 checkGLSyncError(msg1, err);
00683 m_delay = CalcDelay();
00684 }
00685
00686
00687 if (m_delay > 0)
00688 {
00689 uint n = m_delay / m_refresh_interval + 1;
00690 err = gMythGLXWaitVideoSyncSGI((n+1), (frameNum+n)%(n+1), &frameNum);
00691 checkGLSyncError(msg2, err);
00692 m_delay = CalcDelay();
00693 }
00694
00695 X11S(err = glXMakeCurrent(vo->XJ_disp, None, NULL));
00696 #endif
00697 }
00698
00699 void OpenGLVideoSync::AdvanceTrigger(void)
00700 {
00701 #ifdef USING_OPENGL_VSYNC
00702 QMutexLocker locker(&m_lock);
00703
00704 KeepPhase();
00705 UpdateNexttrigger();
00706 #endif
00707 }
00708 #endif
00709
00710 #ifdef __linux__
00711 #define RTCRATE 1024
00712 RTCVideoSync::RTCVideoSync(VideoOutput *vo, int fi, int ri, bool intr) :
00713 VideoSync(vo, fi, ri, intr)
00714 {
00715 m_rtcfd = -1;
00716 }
00717
00718 RTCVideoSync::~RTCVideoSync()
00719 {
00720 if (m_rtcfd >= 0)
00721 close(m_rtcfd);
00722 }
00723
00724 bool RTCVideoSync::TryInit(void)
00725 {
00726 m_rtcfd = open("/dev/rtc", O_RDONLY);
00727 if (m_rtcfd < 0)
00728 {
00729 VERBOSE(VB_PLAYBACK, QString("RTCVideoSync: Could not"
00730 " open /dev/rtc, %1.").arg(strerror(errno)));
00731 return false;
00732 }
00733
00734
00735 if ((ioctl(m_rtcfd, RTC_IRQP_SET, RTCRATE) < 0))
00736 {
00737 VERBOSE(VB_PLAYBACK, QString("RTCVideoSync: Could not"
00738 " set RTC frequency, %1.").arg(strerror(errno)));
00739 return false;
00740 }
00741
00742 if (ioctl(m_rtcfd, RTC_PIE_ON, 0) < 0)
00743 {
00744 VERBOSE(VB_PLAYBACK, QString("RTCVideoSync: Could not enable periodic "
00745 "timer interrupts, %1.").arg(strerror(errno)));
00746 return false;
00747 }
00748
00749 return true;
00750 }
00751
00752 void RTCVideoSync::WaitForFrame(int sync_delay)
00753 {
00754 OffsetTimeval(m_nexttrigger, sync_delay);
00755
00756 m_delay = CalcDelay();
00757
00758 unsigned long rtcdata;
00759 while (m_delay > 0)
00760 {
00761 read(m_rtcfd, &rtcdata, sizeof(rtcdata));
00762 m_delay = CalcDelay();
00763 }
00764 }
00765
00766 void RTCVideoSync::AdvanceTrigger(void)
00767 {
00768 UpdateNexttrigger();
00769 }
00770 #endif
00771
00772 BusyWaitVideoSync::BusyWaitVideoSync(VideoOutput *vo,
00773 int fr, int ri, bool intl) :
00774 VideoSync(vo, fr, ri, intl)
00775 {
00776 m_cheat = 5000;
00777 m_fudge = 0;
00778 }
00779
00780 BusyWaitVideoSync::~BusyWaitVideoSync()
00781 {
00782 }
00783
00784 bool BusyWaitVideoSync::TryInit(void)
00785 {
00786 return true;
00787 }
00788
00789 void BusyWaitVideoSync::WaitForFrame(int sync_delay)
00790 {
00791
00792 OffsetTimeval(m_nexttrigger, sync_delay);
00793
00794 m_delay = CalcDelay();
00795
00796 if (m_delay > 0)
00797 {
00798 int cnt = 0;
00799 m_cheat += 100;
00800
00801
00802 if (m_delay > (m_cheat - m_fudge))
00803 usleep(m_delay - (m_cheat - m_fudge));
00804
00805
00806
00807 m_delay = CalcDelay();
00808 while (m_delay + m_fudge > 0)
00809 {
00810 m_delay = CalcDelay();
00811 cnt++;
00812 }
00813 m_fudge = abs(m_delay / 2);
00814 if (cnt > 1)
00815 m_cheat -= 200;
00816 }
00817 }
00818
00819 void BusyWaitVideoSync::AdvanceTrigger(void)
00820 {
00821 UpdateNexttrigger();
00822 }
00823
00824 USleepVideoSync::USleepVideoSync(VideoOutput *vo,
00825 int fr, int ri, bool intl) :
00826 VideoSync(vo, fr, ri, intl)
00827 {
00828 }
00829
00830 USleepVideoSync::~USleepVideoSync()
00831 {
00832 }
00833
00834 bool USleepVideoSync::TryInit(void)
00835 {
00836 return true;
00837 }
00838
00839 void USleepVideoSync::WaitForFrame(int sync_delay)
00840 {
00841
00842 OffsetTimeval(m_nexttrigger, sync_delay);
00843
00844 m_delay = CalcDelay();
00845 if (m_delay > 0)
00846 usleep(m_delay);
00847 }
00848
00849 void USleepVideoSync::AdvanceTrigger(void)
00850 {
00851 UpdateNexttrigger();
00852 }