Skip to content

Commit

Permalink
Add vsync_delay_clock method to compensate for hardware vsync phase i…
Browse files Browse the repository at this point in the history
…ssues.

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

Patch by Mark Spieth.

Closes #7964.
  • Loading branch information
tralph committed Jan 8, 2011
1 parent 956b4f2 commit 3b10231
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 27 deletions.
20 changes: 13 additions & 7 deletions mythtv/libs/libmythtv/mythplayer.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand All @@ -1840,7 +1842,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
}
else
{
videosync->WaitForFrame(frameDelay);
vsync_delay_clock = videosync->WaitForFrame(frameDelay);
currentaudiotime = AVSyncGetAudiotime();
}

Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down
31 changes: 18 additions & 13 deletions mythtv/libs/libmythtv/vsync.cpp
Expand Up @@ -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;

Expand All @@ -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()
{
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -327,7 +328,7 @@ void DRMVideoSync::WaitForFrame(int sync_delay)
//cerr << " Delay " << m_delay << endl;
}

KeepPhase();
return m_delay;
}
#endif /* !_WIN32 */

Expand Down Expand Up @@ -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
Expand All @@ -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();

Expand All @@ -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 */
Expand Down Expand Up @@ -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;

Expand All @@ -494,6 +495,7 @@ void RTCVideoSync::WaitForFrame(int sync_delay)
if ((val < 0) && (m_delay > 0))
usleep(m_delay);
}
return 0;
}
#endif /* __linux__ */

Expand All @@ -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;
Expand All @@ -528,6 +530,7 @@ void VDPAUVideoSync::WaitForFrame(int sync_delay)

VideoOutputVDPAU *vo = (VideoOutputVDPAU *)(m_video_output);
vo->SetNextFrameDisplayTimeOffset(m_delay);
return 0;
}
#endif

Expand All @@ -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;
Expand Down Expand Up @@ -577,6 +580,7 @@ void BusyWaitVideoSync::WaitForFrame(int sync_delay)
if (cnt > 1)
m_cheat -= 200;
}
return 0;
}

USleepVideoSync::USleepVideoSync(VideoOutput *vo,
Expand All @@ -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;
}

15 changes: 8 additions & 7 deletions mythtv/libs/libmythtv/vsync.h
Expand Up @@ -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
Expand All @@ -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; }
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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:
};
Expand All @@ -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;
Expand All @@ -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.