commit 08ce0149ce184d26173e34e0a6888543e981b830
Author: Mark Spieth <mspieth@digivation.com.au>
Date:   Sun Aug 15 17:35:09 2010 +1000

    vsync calc optimizations and pll out

diff --git a/mythtv/libs/libmythtv/vsync.cpp b/mythtv/libs/libmythtv/vsync.cpp
index 41d3736..ddedceb 100644
--- a/mythtv/libs/libmythtv/vsync.cpp
+++ b/mythtv/libs/libmythtv/vsync.cpp
@@ -128,29 +128,30 @@ VideoSync::VideoSync(VideoOutput *video_output,
                      bool halve_frame_interval) :
     m_video_output(video_output),   m_frame_interval(frameint),
     m_refresh_interval(refreshint), m_interlaced(halve_frame_interval),
-    m_delay(-1)
+    m_nexttrigger(0),
+    m_delay(-1),
+    m_synchronous(false)
 {
-    bzero(&m_nexttrigger, sizeof(m_nexttrigger));
+    int fieldint = frameint;
+    if (halve_frame_interval)
+        fieldint /= 2;
+    double sync_factor = fieldint * 2.0f / refreshint;
+    sync_factor = sync_factor - round(sync_factor);
+    m_synchronous = (sync_factor >= -0.005) && (sync_factor <= 0.005);
+    VERBOSE(VB_PLAYBACK, LOC + QString("Set video sync frame interval to %1 (synced:%2)")
+                                 .arg(m_frame_interval).arg(m_synchronous));
 }
 
-void VideoSync::Start(void)
+int64_t GetTime(void)
 {
-    gettimeofday(&m_nexttrigger, NULL); // now
+    struct timeval now_tv;
+    gettimeofday(&now_tv, NULL); // now
+    return now_tv.tv_sec * 1000000LL + now_tv.tv_usec;
 }
 
-void VideoSync::OffsetTimeval(struct timeval& tv, int offset)
+void VideoSync::Start(void)
 {
-    tv.tv_usec += offset;
-    while (tv.tv_usec > 999999)
-    {
-        tv.tv_sec++;
-        tv.tv_usec -= 1000000;
-    }
-    while (tv.tv_usec < 0)
-    {
-        tv.tv_sec--;
-        tv.tv_usec += 1000000;
-    }
+    m_nexttrigger = GetTime();
 }
 
 /** \fn VideoSync::CalcDelay()
@@ -166,13 +167,11 @@ void VideoSync::OffsetTimeval(struct timeval& tv, int offset)
  */
 int VideoSync::CalcDelay()
 {
-    struct timeval now;
-    gettimeofday(&now, NULL);
+    int64_t now = GetTime();
     //cout << "CalcDelay: next: " << timeval_str(m_nexttrigger) << " now "
     // << timeval_str(now) << endl;
 
-    int ret_val = (m_nexttrigger.tv_sec - now.tv_sec) * 1000000 +
-                  (m_nexttrigger.tv_usec - now.tv_usec);
+    int ret_val = m_nexttrigger - now;
 
     //cout << "delay " << ret_val << endl;
 
@@ -184,19 +183,17 @@ int VideoSync::CalcDelay()
             ret_val = m_frame_interval * 4;
 
         // set nexttrigger to our new target time
-        m_nexttrigger.tv_sec = now.tv_sec;
-        m_nexttrigger.tv_usec = now.tv_usec;
-        OffsetTimeval(m_nexttrigger, ret_val);
+        m_nexttrigger = now;
+        m_nexttrigger += ret_val;
     }
 
-    if (ret_val < -m_frame_interval)
+    if ((ret_val < -m_frame_interval) && (m_frame_interval >= m_refresh_interval))
     {
         ret_val = -m_frame_interval;
 
         // set nexttrigger to our new target time
-        m_nexttrigger.tv_sec = now.tv_sec;
-        m_nexttrigger.tv_usec = now.tv_usec;
-        OffsetTimeval(m_nexttrigger, ret_val);
+        m_nexttrigger = now;
+        m_nexttrigger += ret_val;
     }
 
     return ret_val;
@@ -213,10 +210,20 @@ int VideoSync::CalcDelay()
 void VideoSync::KeepPhase()
 {
     // cerr << m_delay << endl;
-    if (m_delay < -(m_refresh_interval/2))
-        OffsetTimeval(m_nexttrigger, 200);
-    else if (m_delay > -500)
-        OffsetTimeval(m_nexttrigger, -2000);
+    if (m_synchronous)
+    {
+        if (m_delay < -(m_refresh_interval - 500))
+            m_nexttrigger += 200;
+        else if (m_delay > -500)
+            m_nexttrigger += -2000;
+    }
+    else
+    {
+        if (m_delay < -(m_refresh_interval + 500))
+            m_nexttrigger += 200;
+        else if (m_delay >= 0)
+            m_nexttrigger += -2000;
+    }
 }
 
 #ifndef _WIN32
@@ -306,10 +313,10 @@ void DRMVideoSync::Start(void)
     VideoSync::Start();
 }
 
-void DRMVideoSync::WaitForFrame(int sync_delay)
+int DRMVideoSync::WaitForFrame(int sync_delay)
 {
     // Offset for externally-provided A/V sync delay
-    OffsetTimeval(m_nexttrigger, sync_delay);
+    m_nexttrigger += sync_delay;
 
     m_delay = CalcDelay();
     //cerr << "WaitForFrame at : " << m_delay;
@@ -329,7 +336,7 @@ void DRMVideoSync::WaitForFrame(int sync_delay)
     if (m_delay > 0)
     {
         // Wait for any remaining retrace intervals in one pass.
-        int n = m_delay / m_refresh_interval + 1;
+        int n = (m_delay + m_refresh_interval - 1) / m_refresh_interval;
 
         drm_wait_vblank_t blank;
         blank.request.type = DRM_VBLANK_RELATIVE;
@@ -339,6 +346,7 @@ void DRMVideoSync::WaitForFrame(int sync_delay)
         //cerr << "Wait " << n << " intervals. Count " << blank.request.sequence;
         //cerr  << " Delay " << m_delay << endl;
     }
+    return m_delay;
 
     KeepPhase();
 }
@@ -409,42 +417,83 @@ void OpenGLVideoSync::Start(void)
 #endif /* USING_OPENGL_VSYNC */
 }
 
-void OpenGLVideoSync::WaitForFrame(int sync_delay)
+int OpenGLVideoSync::WaitForFrame(int sync_delay)
 {
     (void) sync_delay;
 #ifdef USING_OPENGL_VSYNC
+//#define GLVSYNCDEBUG
+#ifdef GLVSYNCDEBUG
+    int refreshcount = 0;
+#endif
     const QString msg1("First A/V Sync"), msg2("Second A/V Sync");
-    OffsetTimeval(m_nexttrigger, sync_delay);
+    m_nexttrigger += sync_delay;
 
     if (m_video_output && m_video_output->IsEmbedding())
     {
         m_delay = CalcDelay();
         if (m_delay > 0)
             usleep(m_delay);
-        return;
+        return 0;
     }
 
     if (!m_context)
-        return;
+        return 0;
 
     unsigned int frameNum = m_context->GetVideoSyncCount();
 
+#ifdef GLVSYNCDEBUG
+    int delay1 = m_delay;
+    int delay2;
+#endif
     // Always sync to the next retrace execpt when we are very late.
     if ((m_delay = CalcDelay()) > -(m_refresh_interval/2))
     {
+#ifdef GLVSYNCDEBUG
+        delay2 = m_delay;
+#endif
         m_context->WaitForVideoSync(2, (frameNum+1)%2 ,&frameNum);
         m_delay = CalcDelay();
+#ifdef GLVSYNCDEBUG
+        refreshcount++;
+#endif
     }
+#ifdef GLVSYNCDEBUG
+    else
+        delay2 = m_delay;
+#endif
 
+#ifdef GLVSYNCDEBUG
+    int delay3 = m_delay;
+#endif
     // Wait for any remaining retrace intervals in one pass.
     if (m_delay > 0)
     {
-        uint n = m_delay / m_refresh_interval + 1;
+        //uint n = m_delay / m_refresh_interval + 1;
+        uint n = (m_delay + m_refresh_interval - 1) / m_refresh_interval;
         m_context->WaitForVideoSync((n+1), (frameNum+n)%(n+1), &frameNum);
+#ifdef GLVSYNCDEBUG
+        refreshcount += (int)n;
+#endif
         m_delay = CalcDelay();
     }
+#ifdef GLVSYNCDEBUG
+    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, QString("VS: WFF: ri:%1 fi:%2 delay1:%3 delay2:%4 delay3:%5 skip:%6 finaldelay:%7")
+            .arg(m_refresh_interval)
+            .arg(m_frame_interval)
+            .arg(delay1)
+            .arg(delay2)
+            .arg(delay3)
+            .arg(refreshcount)
+            .arg(m_delay)
+           );
+#endif
+
+    return m_delay;
 
     KeepPhase();
+#ifdef GLVSYNCDEBUG
+    VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, "VS: AdvanceTrigger");
+#endif
 #endif /* USING_OPENGL_VSYNC */
 }
 #endif /* !_WIN32 */
@@ -491,9 +540,9 @@ bool RTCVideoSync::TryInit(void)
     return true;
 }
 
-void RTCVideoSync::WaitForFrame(int sync_delay)
+int RTCVideoSync::WaitForFrame(int sync_delay)
 {
-    OffsetTimeval(m_nexttrigger, sync_delay);
+    m_nexttrigger += sync_delay;
 
     m_delay = CalcDelay();
 
@@ -506,6 +555,7 @@ void RTCVideoSync::WaitForFrame(int sync_delay)
         if ((val < 0) && (m_delay > 0))
             usleep(m_delay);
     }
+    return 0;
 }
 #endif /* __linux__ */
 
@@ -529,10 +579,10 @@ bool VDPAUVideoSync::TryInit(void)
     return true;
 }
 
-void VDPAUVideoSync::WaitForFrame(int sync_delay)
+int VDPAUVideoSync::WaitForFrame(int sync_delay)
 {
     // Offset for externally-provided A/V sync delay
-    OffsetTimeval(m_nexttrigger, sync_delay);
+    m_nexttrigger += sync_delay;
     m_delay = CalcDelay();
 
     if (m_delay < 0)
@@ -540,6 +590,7 @@ void VDPAUVideoSync::WaitForFrame(int sync_delay)
 
     VideoOutputVDPAU *vo = (VideoOutputVDPAU *)(m_video_output);
     vo->SetNextFrameDisplayTimeOffset(m_delay);
+    return 0;
 }
 #endif
 
@@ -560,10 +611,10 @@ bool BusyWaitVideoSync::TryInit(void)
     return true;
 }
 
-void BusyWaitVideoSync::WaitForFrame(int sync_delay)
+int BusyWaitVideoSync::WaitForFrame(int sync_delay)
 {
     // Offset for externally-provided A/V sync delay
-    OffsetTimeval(m_nexttrigger, sync_delay);
+    m_nexttrigger += sync_delay;
 
     m_delay = CalcDelay();
 
@@ -589,6 +640,7 @@ void BusyWaitVideoSync::WaitForFrame(int sync_delay)
         if (cnt > 1)
             m_cheat -= 200;
     }
+    return 0;
 }
 
 USleepVideoSync::USleepVideoSync(VideoOutput *vo,
@@ -606,13 +658,14 @@ bool USleepVideoSync::TryInit(void)
     return true;
 }
 
-void USleepVideoSync::WaitForFrame(int sync_delay)
+int USleepVideoSync::WaitForFrame(int sync_delay)
 {
     // Offset for externally-provided A/V sync delay
-    OffsetTimeval(m_nexttrigger, sync_delay);
+    m_nexttrigger += sync_delay;
 
     m_delay = CalcDelay();
     if (m_delay > 0)
         usleep(m_delay);
+    return 0;
 }
 
diff --git a/mythtv/libs/libmythtv/vsync.h b/mythtv/libs/libmythtv/vsync.h
index f3f267f..47b75c0 100644
--- a/mythtv/libs/libmythtv/vsync.h
+++ b/mythtv/libs/libmythtv/vsync.h
@@ -64,6 +64,7 @@ class VideoSync
     virtual void Start(void);
 
     /** \brief Waits for next a frame or field.
+     *   Returns delay to real frame timing in usec
      *
      *   Start(void), WaitForFrame(void), and Stop(void) should
      *   always be called from same thread, to prevent bad
@@ -72,7 +73,7 @@ class VideoSync
      *  \param sync_delay time until the desired frame or field
      *  \sa CalcDelay(void), KeepPhase(void)
      */
-    virtual void WaitForFrame(int sync_delay) = 0;
+    virtual int WaitForFrame(int sync_delay) = 0;
 
     /// \brief Returns the (minimum) refresh interval of the output device.
     int getRefreshInterval(void) const { return m_refresh_interval; }
@@ -90,7 +91,6 @@ class VideoSync
                                  uint frame_interval, uint refresh_interval,
                                  bool interlaced);
   protected:
-    static void OffsetTimeval(struct timeval& tv, int offset);
     int CalcDelay(void);
     void KeepPhase(void);
 
@@ -98,8 +98,9 @@ class VideoSync
     int m_frame_interval; // of video
     int m_refresh_interval; // of display
     bool m_interlaced;
-    struct timeval m_nexttrigger;
+    int64_t m_nexttrigger;
     int m_delay;
+    bool m_synchronous;
     
     static int m_forceskip;
 };
@@ -121,7 +122,7 @@ class DRMVideoSync : public VideoSync
     QString getName(void) const { return QString("DRM"); }
     bool TryInit(void);
     void Start(void);
-    void WaitForFrame(int sync_delay);
+    int WaitForFrame(int sync_delay);
 
   private:
     int m_dri_fd;
@@ -162,7 +163,7 @@ class OpenGLVideoSync : public VideoSync
     QString getName(void) const { return QString("SGI OpenGL"); }
     bool TryInit(void);
     void Start(void);
-    void WaitForFrame(int sync_delay);
+    int WaitForFrame(int sync_delay);
 
   private:
     MythRenderOpenGL  *m_context;
@@ -190,7 +191,7 @@ class RTCVideoSync : public VideoSync
 
     QString getName(void) const { return QString("RTC"); }
     bool TryInit(void);
-    void WaitForFrame(int sync_delay);
+    int WaitForFrame(int sync_delay);
 
   private:
     int m_rtcfd;
@@ -210,7 +211,7 @@ class VDPAUVideoSync : public VideoSync
 
     QString getName(void) const { return QString("VDPAU"); }
     bool TryInit(void);
-    void WaitForFrame(int sync_delay);
+    int WaitForFrame(int sync_delay);
 
   private:
 };
@@ -237,7 +238,7 @@ class BusyWaitVideoSync : public VideoSync
 
     QString getName(void) const { return QString("USleep with busy wait"); }
     bool TryInit(void);
-    void WaitForFrame(int sync_delay);
+    int WaitForFrame(int sync_delay);
 
   private:
     int m_cheat;
@@ -264,6 +265,6 @@ class USleepVideoSync : public VideoSync
 
     QString getName(void) const { return QString("USleep"); }
     bool TryInit(void);
-    void WaitForFrame(int sync_delay);
+    int WaitForFrame(int sync_delay);
 };
 #endif /* VSYNC_H_INCLUDED */
