Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 7091)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -74,6 +74,7 @@
     void SetAudioSampleRate(int rate) { audio_samplerate = rate; }
 
     void SetAudioStretchFactor(float factor) { audio_stretchfactor = factor; }
+    float GetAudioStretchFactor() { return audio_stretchfactor; }
 
     void Pause(bool waitvideo = true);
     bool Play(float speed = 1.0, bool normal = true,
@@ -81,6 +82,7 @@
     bool GetPause(void);
     int GetFFRewSkip(void) { return ffrew_skip; }
     bool AtNormalSpeed(void) { return next_normal_speed; }
+    float GetNextPlaySpeed() { return next_play_speed; }
 
     bool FastForward(float seconds);
     bool Rewind(float seconds);
@@ -212,6 +214,9 @@
 
     long long CalcMaxFFTime(long long ff);
 
+    long long GetLiveTotalFrames();
+    bool IsLiveAndNearEnd(long long framesRemaining);
+
     bool IsErrored() { return errored; }
     bool InitVideo(void);
     VideoFrame* GetRawVideoFrame(long long frameNumber = -1);
@@ -389,6 +394,7 @@
     int totalLength;
     long long totalFrames;
 
+    long long liveTotalFrames;
     OSD *osd;
 
     bool using_null_videoout;
Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 7091)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -148,6 +148,7 @@
     next_play_speed = 1.0;
     next_normal_speed = true;
     videobuf_retries = 0;
+    liveTotalFrames = -1;
 
     using_null_videoout = disableaudio = false;
 
@@ -309,8 +312,6 @@
     decoder_lock.lock();
     next_play_speed = speed;
     next_normal_speed = normal;
-    if (normal)
-        audio_stretchfactor = speed;
     decoder_lock.unlock();
 
     return true;
@@ -911,8 +912,12 @@
             stop = framesPlayed <= keyframedist;
         }
         if (stop)
-            Play(audio_stretchfactor, true, true);
+            Play((ffrew_skip > 0)?1.0:audio_stretchfactor, true, true);
     }
+    else if ((audio_stretchfactor>1.0) && (IsLiveAndNearEnd((int)(video_frame_rate*2))))
+    {
+        Play(1.0, true, true);
+    }
 
     return true;
 }
@@ -2467,13 +2544,15 @@
     }
 #endif
 
+    liveTotalFrames = -1;   // force refetch of endframe, but only once for live only
     if (normal_speed && audioOutput)
     {
-        audioOutput->SetStretchFactor(play_speed);
+        audio_stretchfactor = play_speed;
+        audioOutput->SetStretchFactor(audio_stretchfactor);
 #ifdef USING_DIRECTX
         audioOutput->Reset();
 #endif
     }
 
     //cout << "setting unpaused" << endl << endl;
     paused = actuallypaused = false;
@@ -2531,7 +2615,7 @@
 
     if (livetv || (watchingrecording && nvr_enc && nvr_enc->IsValidRecorder()))
     {
-        long long behind = nvr_enc->GetFramesWritten() - framesPlayed;
+        long long behind = GetLiveTotalFrames() - framesPlayed;
         if (behind < maxtime) // if we're close, do nothing
             ret = 0;
         else if (behind - ff <= maxtime)
@@ -2555,6 +2639,78 @@
     return ret;
 }
 
+long long NuppelVideoPlayer::GetLiveTotalFrames()
+{
+    liveTotalFrames = nvr_enc->GetFramesWritten();
+    //liveTotalFramesRecordedPos = GetDecoder()->GetFramesRead();
+    return liveTotalFrames;
+}
+
+bool NuppelVideoPlayer::IsLiveAndNearEnd(long long nearEndFrameMargin)
+{
+    bool rv = false;
+    if (livetv || (watchingrecording && nvr_enc && nvr_enc->IsValidRecorder()))
+    {
+        // low DB access method
+        long long liveTotalFramesRecordedPos = GetDecoder()->GetFramesRead();
+        long long estFramesToEnd = liveTotalFrames - liveTotalFramesRecordedPos;
+        nearEndFrameMargin = (long long)(nearEndFrameMargin * audio_stretchfactor);
+        if (estFramesToEnd < nearEndFrameMargin)
+        {
+            // last known pos is updated as it was exceeded
+            GetLiveTotalFrames();
+            estFramesToEnd = liveTotalFrames - liveTotalFramesRecordedPos;
+        }
+        if (estFramesToEnd < nearEndFrameMargin)
+        {
+            rv = true;
+        }
+#if 0
+        int loopcount=0;
+        long long rem;
+        long long rem1=-1;
+        long long framesRead = GetDecoder()->GetFramesRead();
+        long long localLiveTotalFrames=liveTotalFrames;
+        long long localLiveTotalFramesRecordedPos = liveTotalFramesRecordedPos;
+        if (localLiveTotalFrames < 0)
+            loopcount++;
+        do
+        {
+            if (localLiveTotalFrames < 0)
+            {
+                localLiveTotalFrames = GetLiveTotalFrames();
+                localLiveTotalFramesRecordedPos = liveTotalFramesRecordedPos;
+                framesRead = GetDecoder()->GetFramesRead();
+            }
+            rem = localLiveTotalFrames - framesRead + 
+                    (long long)((framesRead-localLiveTotalFramesRecordedPos)/play_speed);
+            if ((rem1>=0) && (rem > (rem1+3)))
+            {
+                // skipping so is getting near end
+                rv = true;
+                break;
+            }
+            rv = (rem < framesRemaining);
+            if (!rv)
+                break;
+            localLiveTotalFrames = -1;   // force refetch of endframe, but only once
+            loopcount++;
+            rem1 = rem;
+        } while (loopcount<2);
+#endif
+#if 0
+        VERBOSE(VB_PLAYBACK, QString("tot %1 fp %2 rem %3 ltfrp %4 lc %5")
+                .arg(framesRead + (long long)((framesRead-localLiveTotalFramesRecordedPos)/play_speed))
+                .arg(framesRead)
+                .arg(rem)
+                .arg(localLiveTotalFramesRecordedPos)
+                .arg(loopcount)
+               );
+#endif
+    }
+    return rv;
+}
+
 bool NuppelVideoPlayer::DoFastForward(void)
 {
     long long number = fftime - 1;
@@ -2597,7 +2753,7 @@
     if ((livetv) ||
         (watchingrecording && nvr_enc && nvr_enc->IsValidRecorder()))
     {
-        if (nvr_enc->GetFramesWritten() < (framesPlayed + frames))
+        if (GetLiveTotalFrames() < (framesPlayed + frames))
             return 1;
     }
     else if ((totalFrames) && (totalFrames < (framesPlayed + frames)))
@@ -3738,7 +3894,7 @@
         (watchingrecording && nvr_enc &&
          nvr_enc->IsValidRecorder()))
     {
-        spos = 1000.0 * framesPlayed / nvr_enc->GetFramesWritten();
+        spos = 1000.0 * framesPlayed / GetLiveTotalFrames();
     }
     else if (totalFrames)
     {
@@ -3753,7 +3909,7 @@
     if (!nvr_enc)
         return 0;
 
-    long long written = nvr_enc->GetFramesWritten();
+    long long written = GetLiveTotalFrames();
     long long played = framesPlayed;
 
     if (played > written)
@@ -3776,7 +3932,7 @@
               ((float)ringBuffer->GetFileSize() - ringBuffer->GetSmudgeSize());
         ret *= 1000.0;
 
-        long long written = nvr_enc->GetFramesWritten();
+        long long written = GetLiveTotalFrames();
         long long played = framesPlayed;
 
         if (played > written)
@@ -3843,7 +3999,7 @@
     int playbackLen;
     if (watchingrecording && nvr_enc && nvr_enc->IsValidRecorder())
         playbackLen =
-            (int)(((float)nvr_enc->GetFramesWritten() / video_frame_rate));
+            (int)(((float)GetLiveTotalFrames() / video_frame_rate));
     else
         playbackLen = totalLength;
 
Index: libs/libmythtv/tv_play.cpp
===================================================================
--- libs/libmythtv/tv_play.cpp	(revision 7091)
+++ libs/libmythtv/tv_play.cpp	(working copy)
@@ -1340,14 +1340,21 @@
         }
 
         if ((doing_ff_rew || speed_index) && 
-            activenvp->AtNormalSpeed())
+            activenvp && activenvp->AtNormalSpeed())
         {
             speed_index = 0;
             doing_ff_rew = 0;
             ff_rew_index = kInitFFRWSpeed;
-            UpdatePosOSD(0.0, tr("Play"));
+            UpdatePosOSD(0.0, PlayMesg());
         }
 
+        if (activenvp && (activenvp->GetNextPlaySpeed() != normal_speed) &&
+            activenvp->AtNormalSpeed())
+        {
+            normal_speed = 1.0;     // got changed in nvp due to close to end of file
+            UpdatePosOSD(0.0, PlayMesg());
+        }
+
         if (++updatecheck >= 20)
         {
             OSDSet *oset;
@@ -2501,7 +2508,7 @@
     {
         case  2: speed = 3.0;      mesg = QString(tr("Speed 3X"));    break;
         case  1: speed = 2.0;      mesg = QString(tr("Speed 2X"));    break;
-        case  0: speed = 1.0;      mesg = QString(tr("Play"));        break;
+        case  0: speed = 1.0;      mesg = PlayMesg();                 break;
         case -1: speed = 1.0 / 3;  mesg = QString(tr("Speed 1/3X"));  break;
         case -2: speed = 1.0 / 8;  mesg = QString(tr("Speed 1/8X"));  break;
         case -3: speed = 1.0 / 16; mesg = QString(tr("Speed 1/16X")); break;
@@ -2509,7 +2516,7 @@
         default: speed_index = old_speed; return; break;
     }
 
-    if (!activenvp->Play(speed, (speed == 1.0)))
+    if (!activenvp->Play((speed_index==0)?normal_speed:speed, speed_index==0))
     {
         speed_index = old_speed;
         return;
