Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

mythplayer: add most of the smooth sync code.

Adds most of the smooth sync code which provides predictive frames
drops when time stretch needs to playback faster than the displays
refesh rate. Some limited testing shows playback at 1.5x for 60fps
material is much smoother now.

Many smaller changes have been left out until further review.

Patch by Mark Spieth.

Refs #7964.
  • Loading branch information...
commit 49065221b40b3bc928bb372f57bb63b26077a871 1 parent 0db106f
@tralph tralph authored
View
62 mythtv/libs/libmythtv/mythplayer.cpp
@@ -238,6 +238,7 @@ MythPlayer::MythPlayer(bool muted)
// Audio and video synchronization stuff
videosync(NULL), avsync_delay(0),
avsync_adjustment(0), avsync_avg(0),
+ avsync_predictor(0), avsync_predictor_enabled(false),
refreshrate(0),
lastsync(false), repeat_delay(0),
disp_timecode(0),
@@ -874,7 +875,7 @@ void MythPlayer::SetVideoParams(int width, int height, double fps,
video_frame_rate = fps;
float temp_speed = (play_speed == 0.0f) ?
audio.GetStretchFactor() : play_speed;
- frame_interval = (int)(1000000.0f / video_frame_rate / temp_speed);
+ SetFrameInterval(kScan_Progressive, 1.0 / (video_frame_rate * temp_speed));
}
if (videoOutput)
@@ -1626,6 +1627,31 @@ int MythPlayer::NextCaptionTrack(int mode)
return NextCaptionTrack(nextmode);
}
+void MythPlayer::SetFrameInterval(FrameScanType scan, double frame_period)
+{
+ frame_interval = (int)(1000000.0f * frame_period + 0.5f);
+ if (!avsync_predictor_enabled)
+ avsync_predictor = 0;
+ avsync_predictor_enabled = false;
+
+ VERBOSE(VB_PLAYBACK, LOC + QString("SetFrameInterval ps:%1 scan:%2")
+ .arg(play_speed).arg(scan)
+ );
+ if (play_speed < 1 || play_speed > 2 || refreshrate <= 0)
+ return;
+
+ avsync_predictor_enabled = ((frame_interval-(frame_interval/200)) < refreshrate);
+}
+
+void MythPlayer::ResetAVSync(void)
+{
+ avsync_avg = 0;
+ if (!avsync_predictor_enabled || avsync_predictor >= refreshrate)
+ avsync_predictor = 0;
+ prevtc = 0;
+ VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + "A/V sync reset");
+}
+
void MythPlayer::InitAVSync(void)
{
videosync->Start();
@@ -1649,6 +1675,8 @@ void MythPlayer::InitAVSync(void)
.arg(1000000.0 / frame_interval, 0, 'f', 3);
VERBOSE(VB_PLAYBACK, LOC + msg);
+ SetFrameInterval(m_scan, 1.0 / (video_frame_rate * play_speed));
+
// try to get preferential scheduling, but ignore if we fail to.
myth_nice(-19);
}
@@ -1699,12 +1727,34 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
ps = kScan_Progressive;
+ bool dropframe = false;
+ QString dbg;
+
+ if (avsync_predictor_enabled)
+ {
+ avsync_predictor += frame_interval;
+ if (avsync_predictor >= refreshrate)
+ {
+ int refreshperiodsinframe = avsync_predictor/refreshrate;
+ avsync_predictor -= refreshrate * refreshperiodsinframe;
+ }
+ else
+ {
+ dropframe = true;
+ dbg = "A/V predict drop frame, ";
+ }
+ }
+
if (diverge < -MAXDIVERGE)
{
+ dropframe = true;
// If video is way behind of audio, adjust for it...
- QString dbg = QString("Video is %1 frames behind audio (too slow), ")
+ dbg = QString("Video is %1 frames behind audio (too slow), ")
.arg(-diverge);
+ }
+ if (dropframe)
+ {
// Reset A/V Sync
lastsync = true;
@@ -1801,13 +1851,16 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
int64_t currentaudiotime = audio.GetAudioTime();
VERBOSE(VB_TIMESTAMP, LOC + QString(
"A/V timecodes audio %1 video %2 frameinterval %3 "
- "avdel %4 avg %5 tcoffset %6")
+ "avdel %4 avg %5 tcoffset %6 "
+ "avp %7 avpen %8")
.arg(currentaudiotime)
.arg(timecode)
.arg(frame_interval)
.arg(timecode - currentaudiotime)
.arg(avsync_avg)
.arg(tc_wrap[TC_AUDIO])
+ .arg(avsync_predictor)
+ .arg(avsync_predictor_enabled)
);
if (currentaudiotime != 0 && timecode != 0)
{ // currentaudiotime == 0 after a seek
@@ -1853,7 +1906,7 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
}
else
{
- avsync_avg = 0;
+ ResetAVSync();
}
}
}
@@ -3491,6 +3544,7 @@ void MythPlayer::ClearAfterSeek(bool clearvideobuffers)
commBreakMap.SetTracker(framesPlayed);
commBreakMap.ResetLastSkip();
needNewPauseFrame = true;
+ ResetAVSync();
}
void MythPlayer::SetPlayerInfo(TV *tv, QWidget *widget,
View
4 mythtv/libs/libmythtv/mythplayer.h
@@ -513,6 +513,8 @@ class MPUBLIC MythPlayer
void WrapTimecode(int64_t &timecode, TCTypes tc_type);
void InitAVSync(void);
virtual void AVSync(VideoFrame *buffer, bool limit_delay = false);
+ void ResetAVSync(void);
+ void SetFrameInterval(FrameScanType scan, double speed);
void FallbackDeint(void);
void CheckExtraAudioDecode(void);
@@ -702,6 +704,8 @@ class MPUBLIC MythPlayer
int avsync_delay;
int avsync_adjustment;
int avsync_avg;
+ int avsync_predictor;
+ bool avsync_predictor_enabled;
int refreshrate;
bool lastsync;
bool decode_extra_audio;
Please sign in to comment.
Something went wrong with that request. Please try again.