Skip to content
Browse files

Add vsync_delay_clock method to compensate for hardware vsync phase i…

…ssues.

This also deprecates the use of KeepPhase in favor of handling this in AVSync.

Patch by Mark Spieth.

Closes #7964.
  • Loading branch information...
1 parent 956b4f2 commit 3b102319c7ffa89fc1169079151ac6670909f79c @tralph tralph committed Jan 8, 2011
Showing with 39 additions and 27 deletions.
  1. +13 −7 mythtv/libs/libmythtv/mythplayer.cpp
  2. +18 −13 mythtv/libs/libmythtv/vsync.cpp
  3. +8 −7 mythtv/libs/libmythtv/vsync.h
View
20 mythtv/libs/libmythtv/mythplayer.cpp
@@ -1708,6 +1708,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
float diverge = 0.0f;
int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval;
+ int vsync_delay_clock = 0;
int64_t currentaudiotime = 0;
// attempt to reduce fps for standalone PIP
@@ -1798,7 +1799,8 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
osdLock.unlock();
VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("AVSync waitforframe %1 %2")
.arg(avsync_adjustment).arg(m_double_framerate));
- videosync->WaitForFrame(frameDelay + avsync_adjustment + repeat_delay);
+ vsync_delay_clock = videosync->WaitForFrame
+ (frameDelay + avsync_adjustment + repeat_delay);
currentaudiotime = AVSyncGetAudiotime();
VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + "AVSync show");
videoOutput->Show(ps);
@@ -1828,7 +1830,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
videoOutput->PrepareFrame(buffer, ps, osd);
osdLock.unlock();
// Display the second field
- videosync->WaitForFrame(frameDelay + avsync_adjustment);
+ vsync_delay_clock = videosync->WaitForFrame(frameDelay + avsync_adjustment);
videoOutput->Show(ps);
}
@@ -1840,7 +1842,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
}
else
{
- videosync->WaitForFrame(frameDelay);
+ vsync_delay_clock = videosync->WaitForFrame(frameDelay);
currentaudiotime = AVSyncGetAudiotime();
}
@@ -1869,19 +1871,22 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
if (audio.HasAudioOut() && normal_speed)
{
+ // must be sampled here due to Show delays
int64_t currentaudiotime = audio.GetAudioTime();
- VERBOSE(VB_TIMESTAMP, LOC + QString(
+ VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString(
"A/V timecodes audio %1 video %2 frameinterval %3 "
"avdel %4 avg %5 tcoffset %6 "
- "avp %7 avpen %8")
+ "avp %7 avpen %8 avdc %9")
.arg(currentaudiotime)
.arg(timecode)
.arg(frame_interval)
- .arg(timecode - currentaudiotime)
+ .arg(timecode - currentaudiotime -
+ (int)(vsync_delay_clock*audio.GetStretchFactor()+500)/1000)
.arg(avsync_avg)
.arg(tc_wrap[TC_AUDIO])
.arg(avsync_predictor)
.arg(avsync_predictor_enabled)
+ .arg(vsync_delay_clock)
);
if (currentaudiotime != 0 && timecode != 0)
{ // currentaudiotime == 0 after a seek
@@ -1903,7 +1908,8 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
prevtc = timecode;
prevrp = repeat_pict;
- avsync_delay = (timecode - currentaudiotime) * 1000;//usec
+ avsync_delay = (timecode - currentaudiotime) * 1000 -
+ (int)(vsync_delay_clock*audio.GetStretchFactor()); //usec
// prevents major jitter when pts resets during dvd title
if (avsync_delay > 2000000 && limit_delay)
avsync_delay = 90000;
View
31 mythtv/libs/libmythtv/vsync.cpp
@@ -178,7 +178,7 @@ int VideoSync::CalcDelay()
m_nexttrigger = now + 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;
@@ -196,6 +196,7 @@ int VideoSync::CalcDelay()
* delay > 0 which would cause continous rapid fire stuttering.
* This method is only useful for those sync methods where WaitForFrame
* targets hardware retrace rather than targeting nexttrigger.
+ * NOTE: deprecated in favor of handling phase issues in mythplayer's AVSync.
*/
void VideoSync::KeepPhase()
{
@@ -293,7 +294,7 @@ 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
m_nexttrigger += sync_delay;
@@ -316,7 +317,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;
@@ -327,7 +328,7 @@ void DRMVideoSync::WaitForFrame(int sync_delay)
//cerr << " Delay " << m_delay << endl;
}
- KeepPhase();
+ return m_delay;
}
#endif /* !_WIN32 */
@@ -397,7 +398,7 @@ 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
@@ -409,11 +410,11 @@ void OpenGLVideoSync::WaitForFrame(int sync_delay)
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();
@@ -427,12 +428,12 @@ void OpenGLVideoSync::WaitForFrame(int sync_delay)
// 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) / m_refresh_interval;
m_context->WaitForVideoSync((n+1), (frameNum+n)%(n+1), &frameNum);
m_delay = CalcDelay();
}
- KeepPhase();
+ return m_delay;
#endif /* USING_OPENGL_VSYNC */
}
#endif /* !_WIN32 */
@@ -479,7 +480,7 @@ bool RTCVideoSync::TryInit(void)
return true;
}
-void RTCVideoSync::WaitForFrame(int sync_delay)
+int RTCVideoSync::WaitForFrame(int sync_delay)
{
m_nexttrigger += sync_delay;
@@ -494,6 +495,7 @@ void RTCVideoSync::WaitForFrame(int sync_delay)
if ((val < 0) && (m_delay > 0))
usleep(m_delay);
}
+ return 0;
}
#endif /* __linux__ */
@@ -517,7 +519,7 @@ 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
m_nexttrigger += sync_delay;
@@ -528,6 +530,7 @@ void VDPAUVideoSync::WaitForFrame(int sync_delay)
VideoOutputVDPAU *vo = (VideoOutputVDPAU *)(m_video_output);
vo->SetNextFrameDisplayTimeOffset(m_delay);
+ return 0;
}
#endif
@@ -548,7 +551,7 @@ 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
m_nexttrigger += sync_delay;
@@ -577,6 +580,7 @@ void BusyWaitVideoSync::WaitForFrame(int sync_delay)
if (cnt > 1)
m_cheat -= 200;
}
+ return 0;
}
USleepVideoSync::USleepVideoSync(VideoOutput *vo,
@@ -594,13 +598,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
m_nexttrigger += sync_delay;
m_delay = CalcDelay();
if (m_delay > 0)
usleep(m_delay);
+ return 0;
}
View
15 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; }
@@ -123,7 +124,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;
@@ -164,7 +165,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;
@@ -192,7 +193,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;
@@ -212,7 +213,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:
};
@@ -239,7 +240,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;
@@ -266,6 +267,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 */

0 comments on commit 3b10231

Please sign in to comment.
Something went wrong with that request. Please try again.