Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp.orig
+++ libs/libmythtv/NuppelVideoPlayer.cpp
@@ -254,6 +254,8 @@ NuppelVideoPlayer::NuppelVideoPlayer(boo
     for (int i = 0; i < MAXTBUFFER; i++)
         txtbuffers[i].buffer = new unsigned char[text_size + 1];
 
+    m_frame_show_idx = 0;
+
     memset(&CC708DelayedDeletes, 0, sizeof(CC708DelayedDeletes));
 }
 
@@ -1016,6 +1018,123 @@ void NuppelVideoPlayer::AutoDeint(VideoF
     m_scan_locked  = false;
 }
 
+void NuppelVideoPlayer::PredictFrameSkip(FrameScanType scan)
+{
+    m_frame_show.clear();
+
+    if (play_speed <= 1 || play_speed > 2 || scan != kScan_Progressive)
+        return;
+
+    // For every frame shown, what percent should be skipped?
+
+    switch ((int)(play_speed * 100.0 + 0.5))
+    {
+      case 105:
+        m_frame_show.push_back(20); // skip 5%, 20:1
+        break;
+      case 110:
+        m_frame_show.push_back(10); // skip 10%, 10:1
+        break;
+      case 115:
+        m_frame_show.push_back(7); // skip 15%
+        m_frame_show.push_back(7); // 20:3
+        m_frame_show.push_back(6);
+        break;
+      case 120:
+        m_frame_show.push_back(5); // skip 20%, 5:1
+        break;
+      case 125:
+        m_frame_show.push_back(4); // skip 25%, 4:1
+        break;
+      case 130:
+        m_frame_show.push_back(4); // skip 30%
+        m_frame_show.push_back(3); // 10:3
+        m_frame_show.push_back(3);
+        break;
+      case 135:
+        m_frame_show.push_back(4); // skip 35%
+        m_frame_show.push_back(3); // 20:7
+        m_frame_show.push_back(3); // round down 10:3
+        break;
+      case 140:
+        m_frame_show.push_back(3); // skip 40%
+        m_frame_show.push_back(2); // 5:2
+        break;
+      case 145:
+        m_frame_show.push_back(3); // skip 45%
+        m_frame_show.push_back(2); // 20:9, round down 5:2
+        break;
+      case 150:
+        m_frame_show.push_back(2);  // skip 50%, 2:1
+        break;
+      case 155:
+        m_frame_show.push_back(2); // skip 55%, 20:11, round down 2:1
+        break;
+      case 160:
+        m_frame_show.push_back(2); // skip 60%
+        m_frame_show.push_back(2); // 5:3
+        m_frame_show.push_back(1);
+        break;
+      case 165:
+        m_frame_show.push_back(2); // skip 65%
+        m_frame_show.push_back(2); // 20:13
+        m_frame_show.push_back(1); // round down 5:3
+        break;
+      case 170:
+        m_frame_show.push_back(2); // skip 70%
+        m_frame_show.push_back(2); // 10:7
+        m_frame_show.push_back(1); // round down 5:3
+        break;
+      case 175:
+        m_frame_show.push_back(2); // skip 75%
+        m_frame_show.push_back(1); // 4:3
+        m_frame_show.push_back(1);
+        break;
+      case 180:
+        m_frame_show.push_back(2); // skip 80%
+        m_frame_show.push_back(1); // 5:4
+        m_frame_show.push_back(1);
+        m_frame_show.push_back(1);
+        break;
+      case 185:
+        m_frame_show.push_back(2); // skip 85%
+        m_frame_show.push_back(1); // 20:17
+        m_frame_show.push_back(1); // round down 5:4
+        m_frame_show.push_back(1);
+        break;
+      case 190:
+        m_frame_show.push_back(2); // skip 90%
+        m_frame_show.push_back(1); // 10:9
+        m_frame_show.push_back(1); // round down 5:4
+        m_frame_show.push_back(1);
+        break;
+      case 195:
+        m_frame_show.push_back(2); // skip 95%
+        m_frame_show.push_back(1); // 20:19, round down 10:9, again 5:4
+        m_frame_show.push_back(1);
+        m_frame_show.push_back(1);
+        break;
+      case 200:
+        m_frame_show.push_back(1); // skip 100%, 1:1
+        break;
+    }
+
+    QString msg = QString("PredictFrameSkip: speed %1 ").arg(play_speed);
+    bool    delim = false;
+
+    for (m_frame_show_iter = m_frame_show.begin();
+         m_frame_show_iter != m_frame_show.end(); ++m_frame_show_iter)
+    {
+        msg += QString("%1%2").arg(delim ? ":" : "").arg(*m_frame_show_iter);
+        delim = true;
+    }
+
+    VERBOSE(VB_PLAYBACK, msg);
+
+    m_frame_show_iter = m_frame_show.begin();
+    m_frame_show_idx = 0;
+}
+
 void NuppelVideoPlayer::SetScanType(FrameScanType scan)
 {
     QMutexLocker locker(&videofiltersLock);
@@ -1039,6 +1158,7 @@ void NuppelVideoPlayer::SetScanType(Fram
     {
         m_scan = scan;
         videosync->SetFrameInterval(frame_interval, false);
+        PredictFrameSkip(scan);
         return;
     }
 
@@ -1086,6 +1206,9 @@ void NuppelVideoPlayer::SetScanType(Fram
             (frame_interval>>1) : frame_interval);
     }
 
+    if (m_scan != scan)
+        PredictFrameSkip(scan);
+
     m_scan = scan;
 }
 
@@ -2379,110 +2502,128 @@ void NuppelVideoPlayer::AVSync(void)
         ps = kScan_Progressive;
 
     bool dropframe = false;
-    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), ")
-            .arg(-diverge);
 
-        // Reset A/V Sync
-        lastsync = true;
-
-        if (buffer && !using_null_videoout &&
-            videoOutput->hasHWAcceleration() &&
-           !videoOutput->IsSyncLocked())
-        {
-            // If we are using certain hardware decoders, so we've already done
-            // the decoding; display the frame, but don't wait for A/V Sync.
-            // Excludes HW decoder/render methods that are locked to
-            // the vertical sync (e.g. VDPAU)
-            videoOutput->PrepareFrame(buffer, kScan_Intr2ndField);
-            videoOutput->Show(kScan_Intr2ndField);
-            VERBOSE(VB_PLAYBACK, LOC + dbg + "skipping A/V wait.");
-        }
-        else
+    if (!m_frame_show.empty())
+    {
+        if (m_frame_show_idx++ == *m_frame_show_iter)
         {
-            // If we are using software decoding, skip this frame altogether.
-            VERBOSE(VB_PLAYBACK, LOC + dbg + "dropping frame to catch up.");
+            dropframe = true;
+
+            m_frame_show_idx = 0;
+            if (++m_frame_show_iter == m_frame_show.end())
+                m_frame_show_iter = m_frame_show.begin();
         }
     }
-    else if (!using_null_videoout)
-    {
-        // if we get here, we're actually going to do video output
-        if (buffer)
-            videoOutput->PrepareFrame(buffer, ps);
 
-        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
-                .arg(avsync_adjustment).arg(m_double_framerate));
-        videosync->WaitForFrame(avsync_adjustment + repeat_delay);
-        VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
-        if (!resetvideo)
-            videoOutput->Show(ps);
-
-        if (videoOutput->IsErrored())
+    if (!dropframe)
+    {
+        if (diverge < -MAXDIVERGE)
         {
-            VERBOSE(VB_IMPORTANT, "NVP: Error condition detected "
-                    "in videoOutput after Show(), aborting playback.");
-            SetErrored(QObject::tr("Serious error detected in Video Output"));
-            return;
+            dropframe = true;
+            // If video is way behind of audio, adjust for it...
+            QString dbg = QString("Video is %1 frames behind audio (too slow), ")
+                          .arg(-diverge);
+
+            // Reset A/V Sync
+            lastsync = true;
+
+            if (buffer && !using_null_videoout &&
+                videoOutput->hasHWAcceleration() &&
+                !videoOutput->IsSyncLocked())
+            {
+                // If we are using certain hardware decoders, so we've already done
+                // the decoding; display the frame, but don't wait for A/V Sync.
+                // Excludes HW decoder/render methods that are locked to
+                // the vertical sync (e.g. VDPAU)
+                videoOutput->PrepareFrame(buffer, kScan_Intr2ndField);
+                videoOutput->Show(kScan_Intr2ndField);
+                VERBOSE(VB_PLAYBACK, LOC + dbg + "skipping A/V wait.");
+            }
+            else
+            {
+                // If we are using software decoding, skip this frame altogether.
+                VERBOSE(VB_PLAYBACK, LOC + dbg + "dropping frame to catch up.");
+            }
         }
-
-        if (m_double_framerate)
+        else if (!using_null_videoout)
         {
-            //second stage of deinterlacer processing
-            ps = (kScan_Intr2ndField == ps) ?
-                kScan_Interlaced : kScan_Intr2ndField;
-
-            if (m_double_process && ps != kScan_Progressive)
-            {
-                videofiltersLock.lock();
-                if (player_ctx->buffer->isDVD() &&
-                    player_ctx->buffer->DVD()->InStillFrame() &&
-                    videoOutput->ValidVideoFrames() < 3)
-                {
-                    videoOutput->ProcessFrame(buffer, NULL, NULL,
-                                              pip_players, ps);
-                }
-                else
+            // if we get here, we're actually going to do video output
+            if (buffer)
+                videoOutput->PrepareFrame(buffer, ps);
+
+            VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2")
+                    .arg(avsync_adjustment).arg(m_double_framerate));
+            videosync->WaitForFrame(avsync_adjustment + repeat_delay);
+            VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show");
+            if (!resetvideo)
+                videoOutput->Show(ps);
+
+            if (videoOutput->IsErrored())
+            {
+                VERBOSE(VB_IMPORTANT, "NVP: Error condition detected "
+                        "in videoOutput after Show(), aborting playback.");
+                SetErrored(QObject::tr("Serious error detected in Video Output"));
+                return;
+            }
+
+            if (m_double_framerate)
+            {
+                //second stage of deinterlacer processing
+                ps = (kScan_Intr2ndField == ps) ?
+                     kScan_Interlaced : kScan_Intr2ndField;
+
+                if (m_double_process && ps != kScan_Progressive)
                 {
-                    videoOutput->ProcessFrame(
-                        buffer, osd, videoFilters, pip_players, ps);
+                    videofiltersLock.lock();
+                    if (player_ctx->buffer->isDVD() &&
+                        player_ctx->buffer->DVD()->InStillFrame() &&
+                        videoOutput->ValidVideoFrames() < 3)
+                    {
+                        videoOutput->ProcessFrame(buffer, NULL, NULL,
+                                                  pip_players, ps);
+                    }
+                    else
+                    {
+                        videoOutput->ProcessFrame
+                            (buffer, osd, videoFilters, pip_players, ps);
+                    }
+                    videofiltersLock.unlock();
                 }
-                videofiltersLock.unlock();
-            }
 
-            if (buffer)
-                videoOutput->PrepareFrame(buffer, ps);
+                if (buffer)
+                    videoOutput->PrepareFrame(buffer, ps);
 
-            // Display the second field
-            videosync->AdvanceTrigger();
+                // Display the second field
+                videosync->AdvanceTrigger();
 #ifdef NEW_AVSYNC
-            videosync->WaitForFrame(avsync_adjustment);
+                videosync->WaitForFrame(avsync_adjustment);
 #else
-            videosync->WaitForFrame(0);
+                videosync->WaitForFrame(0);
 #endif
-            if (!resetvideo)
-            {
-                videoOutput->Show(ps);
+                if (!resetvideo)
+                {
+                    videoOutput->Show(ps);
+                }
             }
-        }
 
-        repeat_delay = frame_interval * buffer->repeat_pict * 0.5;
+            repeat_delay = frame_interval * buffer->repeat_pict * 0.5;
 
-        if (repeat_delay)
-            VERBOSE(VB_TIMESTAMP, QString("A/V repeat_pict, adding %1 repeat "
-                    "delay").arg(repeat_delay));
-    }
-    else
-    {
-        videosync->WaitForFrame(0);
+            if (repeat_delay)
+                VERBOSE(VB_TIMESTAMP,
+                        QString("A/V repeat_pict, adding %1 repeat "
+                                "delay").arg(repeat_delay));
+        }
+        else
+        {
+            videosync->WaitForFrame(0);
+        }
     }
 
     if (output_jmeter && output_jmeter->RecordCycleTime())
     {
-        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, QString("A/V avsync_delay: %1, "
-                "avsync_avg: %2, warpfactor: %3, warpfactor_avg: %4")
+        VERBOSE(VB_PLAYBACK+VB_TIMESTAMP,
+                QString("A/V avsync_delay: %1, "
+                        "avsync_avg: %2, warpfactor: %3, warpfactor_avg: %4")
                 .arg(avsync_delay / 1000).arg(avsync_avg / 1000)
                 .arg(warpfactor).arg(warpfactor_avg));
     }
@@ -2504,7 +2645,8 @@ void NuppelVideoPlayer::AVSync(void)
         lastsync = true;
         VERBOSE(VB_PLAYBACK, LOC +
                 QString("Video is %1 frames ahead of audio,\n"
-                        "\t\t\tdoubling video frame interval to slow down.").arg(diverge));
+                        "\t\t\tdoubling video frame interval to slow down.")
+                .arg(diverge));
     }
 
     audio_lock.lock();
@@ -2522,7 +2664,7 @@ void NuppelVideoPlayer::AVSync(void)
                 .arg(buffer->timecode - currentaudiotime)
                 .arg(avsync_avg)
                 .arg(tc_wrap[TC_AUDIO])
-                 );
+                );
 #endif
         if (currentaudiotime != 0 && buffer->timecode != 0)
         { // currentaudiotime == 0 after a seek
@@ -3552,8 +3694,11 @@ bool NuppelVideoPlayer::StartPlaying(boo
 
             play_speed = next_play_speed;
             normal_speed = next_normal_speed;
+
             VERBOSE(VB_PLAYBACK, LOC + "Changing speed to " << play_speed);
 
+            PredictFrameSkip(m_scan);
+
             if (play_speed == 0.0)
             {
                 DoPause();
Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h.orig
+++ libs/libmythtv/NuppelVideoPlayer.h
@@ -431,6 +431,7 @@ class MPUBLIC NuppelVideoPlayer : public
     FrameScanType detectInterlace(FrameScanType newScan, FrameScanType scan,
                                   float fps, int video_height);
     void AutoDeint(VideoFrame*);
+    void PredictFrameSkip(FrameScanType scan);
 
     // Private Sets
     void SetPlayingInfo(const ProgramInfo &pginfo);
@@ -805,6 +806,10 @@ class MPUBLIC NuppelVideoPlayer : public
     bool       audio_paused;
     int        repeat_delay;
 
+    QVector<int>  m_frame_show;
+    QVector<int>::iterator m_frame_show_iter;
+    int        m_frame_show_idx;
+
     // Audio warping stuff
     float      warpfactor;
     float      warpfactor_avg;
