Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 8406)
+++ libs/libmythtv/NuppelVideoPlayer.h	(working copy)
@@ -210,7 +210,7 @@
         { videoOutput->ReleaseFrame(GetNextVideoFrame(false)); }
     void ReleaseCurrentFrame(VideoFrame *frame);
     void DiscardVideoFrame(VideoFrame *buffer);
-    void DiscardVideoFrames(void);
+    void DiscardVideoFrames(bool next_frame_keyframe);
     void DrawSlice(VideoFrame *frame, int x, int y, int w, int h);
 
     // Reinit
Index: libs/libmythtv/nuppeldecoder.cpp
===================================================================
--- libs/libmythtv/nuppeldecoder.cpp	(revision 8406)
+++ libs/libmythtv/nuppeldecoder.cpp	(working copy)
@@ -37,7 +37,7 @@
 #endif
       ffmpeg_extradatasize(0), ffmpeg_extradata(0), usingextradata(false),
       disablevideo(false), totalLength(0), totalFrames(0), effdsp(0), 
-      directbuf(0), mpa_codec(0), mpa_ctx(0), directrendering(false),
+      directframe(NULL), mpa_codec(0), mpa_ctx(0), directrendering(false),
       lastct('1'), strm(0), buf(0), buf2(0), 
       videosizetotal(0), videoframesread(0), setreadahead(false)
 {
@@ -566,7 +566,7 @@
     int width = c->width;
     int height = c->height;
 
-    pic->data[0] = nd->directbuf;
+    pic->data[0] = nd->directframe->buf;
     pic->data[1] = pic->data[0] + width * height;
     pic->data[2] = pic->data[1] + width * height / 4;
 
@@ -574,7 +574,7 @@
     pic->linesize[1] = width / 2;
     pic->linesize[2] = width / 2;
 
-    pic->opaque = nd;
+    pic->opaque = nd->directframe;
     pic->type = FF_BUFFER_TYPE_USER;
 
     pic->age = 256 * 256 * 256 * 64;
@@ -587,6 +587,10 @@
     (void)c;
     assert(pic->type == FF_BUFFER_TYPE_USER);
 
+    NuppelDecoder *nd = (NuppelDecoder *)(c->opaque);
+    if (nd && nd->GetNVP() && nd->GetNVP()->getVideoOutput())
+        nd->GetNVP()->getVideoOutput()->DeLimboFrame((VideoFrame*)pic->opaque);
+
     int i;
     for (i = 0; i < 4; i++)
         pic->data[i] = NULL;
@@ -683,6 +687,7 @@
     int compoff = 0;
 
     unsigned char *outbuf = frame->buf;
+    directframe = frame;
 
     if (!buf2)
     {
@@ -759,9 +764,9 @@
         int gotpicture = 0;
         pthread_mutex_lock(&avcodeclock);
         // if directrendering, writes into buf
-        directbuf = outbuf;
         int ret = avcodec_decode_video(mpa_ctx, &mpa_pic, &gotpicture,
                                        lstrm, frameheader->packetlength);
+        directframe = NULL;
         pthread_mutex_unlock(&avcodeclock);
         if (ret < 0)
         {
@@ -1046,6 +1051,8 @@
 
             buf->frameNumber = framesPlayed;
             GetNVP()->ReleaseNextVideoFrame(buf, frameheader.timecode);
+            if (directframe)
+                GetNVP()->getVideoOutput()->DeLimboFrame(buf);
             gotvideo = 1;
             if (getrawframes && getrawvideo)
                 StoreRawData(strm);
@@ -1146,6 +1153,9 @@
     if (mpa_codec && needFlush)
         avcodec_flush_buffers(mpa_ctx);
 
+    if (discardFrames)
+        GetNVP()->DiscardVideoFrames(needFlush);
+
     while (skipFrames > 0)
     {
         GetFrame(0);
Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 8406)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -803,11 +803,27 @@
        MAXTBUFFER - 1. */
 }
 
+/** \fn NuppelVideoPlayer::GetNextVideoFrame(bool)
+ *  \brief Removes a frame from the available queue for decoding onto.
+ *
+ *   This places the frame in the limbo queue, from which frames are
+ *   removed if they are added to another queue. Normally a frame is
+ *   freed from limbo either by a ReleaseNextVideoFrame() or
+ *   DiscardVideoFrame() call; but limboed frames are also freed
+ *   during a seek reset.
+ *
+ *  \param allow_unsafe if true then a frame will be taken from the queue
+ *         of frames ready for display if we can't find a frame in the
+ *         available queue.
+ */
 VideoFrame *NuppelVideoPlayer::GetNextVideoFrame(bool allow_unsafe)
 {
     return videoOutput->GetNextFreeFrame(false, allow_unsafe);
 }
 
+/** \fn NuppelVideoPlayer::ReleaseNextVideoFrame(VideoFrame*,long long)
+ *  \brief Places frame on the queue of frames ready for display.
+ */
 void NuppelVideoPlayer::ReleaseNextVideoFrame(VideoFrame *buffer,
                                               long long timecode)
 {
@@ -817,16 +833,30 @@
     videoOutput->ReleaseFrame(buffer);
 }
 
+/** \fn NuppelVideoPlayer::DiscardVideoFrame(VideoFrame*)
+ *  \brief Places frame in the available frames queue.
+ */
 void NuppelVideoPlayer::DiscardVideoFrame(VideoFrame *buffer)
 {
     if (videoOutput)
         videoOutput->DiscardFrame(buffer);
 }
 
-void NuppelVideoPlayer::DiscardVideoFrames()
+/** \fn DiscardVideoFrames(bool)
+ *  \brief Places frames in the available frames queue.
+ *
+ *   If called with 'next_frame_keyframe' set to false then all frames
+ *   not in use by the decoder are made available for decoding. Otherwise,
+ *   all frames are made available for decoding; this is only safe if
+ *   the next frame is a keyframe.
+ *
+ *  \param next_frame_keyframe if this is true all frames are placed
+ *         in the available queue.
+ */
+void NuppelVideoPlayer::DiscardVideoFrames(bool next_frame_keyframe)
 {
     if (videoOutput)
-        videoOutput->DiscardFrames();
+        videoOutput->DiscardFrames(next_frame_keyframe);
 }
 
 void NuppelVideoPlayer::DrawSlice(VideoFrame *frame, int x, int y, int w, int h)
@@ -1658,7 +1688,9 @@
                 VERBOSE(VB_IMPORTANT, LOC + "Prebuffer wait timed out, and"
                         "\n\t\t\tthere are not enough free frames. "
                         "Discarding buffered frames.");
-                DiscardVideoFrames();
+                // This call will result in some ugly frames, but allows us
+                // to recover from serious problems if frames get leaked.
+                DiscardVideoFrames(true);
             }
             prebuffer_tries = 0;
         }
@@ -3014,8 +3046,8 @@
 /** \fn NuppelVideoPlayer::ClearAfterSeek(void)
  *  \brief This is to support seeking...
  *
- *   It can be very dangerous as it removes all frames from
- *   the videoOutput, so you can't restart playback immediately.
+ *   This resets the output classes and discards all
+ *   frames no longer being used by the decoder class.
  *
  *   Note: caller should not hold any locks
  */
Index: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp	(revision 8406)
+++ libs/libmythtv/avformatdecoder.cpp	(working copy)
@@ -65,6 +65,8 @@
     height = (height + 15) & (~0xf);
 }
 
+typedef MythDeque<AVFrame*> avframe_q;
+
 class AvFormatDecoderPrivate
 {
   public:
@@ -83,6 +85,7 @@
   private:
     mpeg2dec_t *mpeg2dec;
     bool        allow_mpeg2dec;
+    avframe_q   partialFrames;
 };
 
 bool AvFormatDecoderPrivate::InitMPEG2()
@@ -103,14 +106,28 @@
 void AvFormatDecoderPrivate::DestroyMPEG2()
 {
     if (mpeg2dec)
+    {
         mpeg2_close(mpeg2dec);
-    mpeg2dec = NULL;
+        mpeg2dec = NULL;
+
+        avframe_q::iterator it = partialFrames.begin();
+        for (; it != partialFrames.end(); ++it)
+            delete (*it);
+        partialFrames.clear();
+    }
 }
 
 void AvFormatDecoderPrivate::ResetMPEG2()
 {
     if (mpeg2dec)
+    {
         mpeg2_reset(mpeg2dec, 0);
+
+        avframe_q::iterator it = partialFrames.begin();
+        for (; it != partialFrames.end(); ++it)
+            delete (*it);
+        partialFrames.clear();
+    }
 }
 
 int AvFormatDecoderPrivate::DecodeMPEG2Video(AVCodecContext *avctx,
@@ -145,28 +162,82 @@
                 mpeg2_set_buf(mpeg2dec, picture->data, picture->opaque);
                 break;
             case STATE_BUFFER:
-                // We're supposed to wait for STATE_SLICE, but
-                // STATE_BUFFER is returned first. Since we handed
-                // libmpeg2 a full frame, we know it should be
-                // done once it's finished with the data.
-                if (info->display_fbuf)
+                // We're finished with the buffer...
+                if (partialFrames.size())
                 {
-                    picture->data[0] = info->display_fbuf->buf[0];
-                    picture->data[1] = info->display_fbuf->buf[1];
-                    picture->data[2] = info->display_fbuf->buf[2];
-                    picture->opaque  = info->display_fbuf->id;
+                    AVFrame *frm = partialFrames.dequeue();
                     *got_picture_ptr = 1;
-                    picture->top_field_first = !!(info->display_picture->flags &
-                                                  PIC_FLAG_TOP_FIELD_FIRST);
-                    picture->interlaced_frame = !(info->display_picture->flags &
-                                                  PIC_FLAG_PROGRESSIVE_FRAME);
+                    *picture = *frm;
+                    delete frm;
+#if 0
+                    QString msg("");
+                    AvFormatDecoder *nd = (AvFormatDecoder *)(avctx->opaque);
+                    if (nd && nd->GetNVP() && nd->GetNVP()->getVideoOutput())
+                        msg = nd->GetNVP()->getVideoOutput()->GetFrameStatus();
+
+                    VERBOSE(VB_IMPORTANT, "ret frame: "<<picture->opaque
+                            <<"           "<<msg);
+#endif
                 }
                 return buf_size;
             case STATE_INVALID:
                 // This is the error state. The decoder must be
                 // reset on an error.
-                mpeg2_reset(mpeg2dec, 0);
+                ResetMPEG2();
                 return -1;
+
+            case STATE_SLICE:
+            case STATE_END:
+            case STATE_INVALID_END:
+                if (info->display_fbuf)
+                {
+                    bool exists = false;
+                    avframe_q::iterator it = partialFrames.begin();
+                    for (; it != partialFrames.end(); ++it)
+                        if ((*it)->opaque == info->display_fbuf->id)
+                            exists = true;
+
+                    if (!exists)
+                    {
+                        AVFrame *frm = new AVFrame();
+                        frm->data[0] = info->display_fbuf->buf[0];
+                        frm->data[1] = info->display_fbuf->buf[1];
+                        frm->data[2] = info->display_fbuf->buf[2];
+                        frm->data[3] = NULL;
+                        frm->opaque  = info->display_fbuf->id;
+                        frm->type    = FF_BUFFER_TYPE_USER;
+                        frm->top_field_first =
+                            !!(info->display_picture->flags &
+                               PIC_FLAG_TOP_FIELD_FIRST);
+                        frm->interlaced_frame =
+                            !(info->display_picture->flags &
+                              PIC_FLAG_PROGRESSIVE_FRAME);
+                        partialFrames.enqueue(frm);
+                        
+                    }
+                }
+                if (info->discard_fbuf)
+                {
+                    bool exists = false;
+                    avframe_q::iterator it = partialFrames.begin();
+                    for (; it != partialFrames.end(); ++it)
+                    {
+                        if ((*it)->opaque == info->discard_fbuf->id)
+                        {
+                            exists = true;
+                            (*it)->data[3] = (unsigned char*) 1;
+                        }
+                    }
+
+                    if (!exists)
+                    {
+                        AVFrame frame;
+                        frame.opaque = info->discard_fbuf->id;
+                        frame.type   = FF_BUFFER_TYPE_USER;
+                        avctx->release_buffer(avctx, &frame);
+                    }
+                }
+                break;
             default:
                 break;
         }
@@ -266,13 +337,15 @@
     return DoFastForward(desiredFrame, doflush);
 }
 
-bool AvFormatDecoder::DoFastForward(long long desiredFrame, bool doflush)
+bool AvFormatDecoder::DoFastForward(long long desiredFrame, bool discardFrames)
 {
-    VERBOSE(VB_PLAYBACK, LOC + "DoFastForward("
-            <<desiredFrame<<", "<<( doflush ? "do" : "don't" )<<" flush)");
+    VERBOSE(VB_PLAYBACK, LOC +
+            QString("DoFastForward(%1 (%2), %3 discard frames)")
+            .arg(desiredFrame).arg(framesPlayed)
+            .arg((discardFrames) ? "do" : "don't"));
 
     if (recordingHasPositionMap || livetv)
-        return DecoderBase::DoFastForward(desiredFrame, doflush);
+        return DecoderBase::DoFastForward(desiredFrame, discardFrames);
 
     bool oldrawstate = getrawframes;
     getrawframes = false;
@@ -333,9 +406,9 @@
 
     int normalframes = desiredFrame - framesPlayed;
 
-    SeekReset(lastKey, normalframes, doflush, doflush);
+    SeekReset(lastKey, normalframes, discardFrames, discardFrames);
 
-    if (doflush)
+    if (discardFrames)
     {
         GetNVP()->SetFramesPlayed(framesPlayed + 1);
         GetNVP()->getVideoOutput()->SetFramesPlayed(framesPlayed + 1);
@@ -355,28 +428,25 @@
 
     DecoderBase::SeekReset(newKey, skipFrames, doflush, discardFrames);
 
-    lastapts = 0;
-    lastvpts = 0;
-    lastccptsu = 0;
-    save_cctc[0] = save_cctc[1] = 0;
+    if (doflush)
+    {
+        lastapts = 0;
+        lastvpts = 0;
+        lastccptsu = 0;
+        save_cctc[0] = save_cctc[1] = 0;
+        av_read_frame_flush(ic);
 
-    av_read_frame_flush(ic);
-    
-    d->ResetMPEG2();
+        // Only reset the internal state if we're using our seeking,
+        // not when using libavformat's seeking
+        if (recordingHasPositionMap || livetv)
+        {
+            ic->pb.pos = ringBuffer->GetReadPosition();
+            ic->pb.buf_ptr = ic->pb.buffer;
+            ic->pb.buf_end = ic->pb.buffer;
+            ic->pb.eof_reached = 0;
+        }
 
-    // Only reset the internal state if we're using our seeking,
-    // not when using libavformat's seeking
-    if (recordingHasPositionMap || livetv)
-    {
-        ic->pb.pos = ringBuffer->GetReadPosition();
-        ic->pb.buf_ptr = ic->pb.buffer;
-        ic->pb.buf_end = ic->pb.buffer;
-        ic->pb.eof_reached = 0;
-    }
-
-    // Flush the avcodec buffers
-    if (doflush)
-    {
+        // Flush the avcodec buffers
         VERBOSE(VB_PLAYBACK, LOC + "SeekReset() flushing");
         for (int i = 0; i < ic->nb_streams; i++)
         {
@@ -384,25 +454,29 @@
             if (enc->codec)
                 avcodec_flush_buffers(enc);
         }
+        d->ResetMPEG2();
     }
 
     // Discard all the queued up decoded frames
     if (discardFrames)
-        GetNVP()->DiscardVideoFrames();
+        GetNVP()->DiscardVideoFrames(doflush);
 
-    // Free up the stored up packets
-    while (doflush && storedPackets.count() > 0)
+    if (doflush)
     {
-        AVPacket *pkt = storedPackets.first();
-        storedPackets.removeFirst();
-        av_free_packet(pkt);
-        delete pkt;
+        // Free up the stored up packets
+        while (storedPackets.count() > 0)
+        {
+            AVPacket *pkt = storedPackets.first();
+            storedPackets.removeFirst();
+            av_free_packet(pkt);
+            delete pkt;
+        }
+
+        prevgoppos = 0;
+        gopset = false;
     }
 
-    prevgoppos = 0;
-    gopset = false;
-
-     // Skip all the desired number of skipFrames
+    // Skip all the desired number of skipFrames
     for (;skipFrames > 0 && !ateof; skipFrames--)
     {
 	GetFrame(0);
@@ -416,7 +490,7 @@
     VERBOSE(VB_PLAYBACK, LOC + QString("Reset(%1, %2)")
             .arg(reset_video_data).arg(seek_reset));
     if (seek_reset)
-        SeekReset(0, 0, true, true);
+        SeekReset(0, 0, true, false);
 
     if (reset_video_data)
     {
@@ -2498,6 +2572,8 @@
 
                     picframe->frameNumber = framesPlayed;
                     GetNVP()->ReleaseNextVideoFrame(picframe, temppts);
+                    if (d->HasMPEG2Dec() && mpa_pic.data[3])
+                        context->release_buffer(context, &mpa_pic);
                     if (!directrendering)
                         GetNVP()->DiscardVideoFrame(picframe);
 
Index: libs/libmythtv/decoderbase.h
===================================================================
--- libs/libmythtv/decoderbase.h	(revision 8406)
+++ libs/libmythtv/decoderbase.h	(working copy)
@@ -94,8 +94,7 @@
   protected:
     void FileChanged(void);
 
-    bool DoRewindDVD(long long desiredFrame);
-    bool DoRewindNormal(long long desiredFrame);
+    bool DoRewindSeek(long long desiredFrame);
     void DoFastForwardSeek(long long desiredFrame, bool &needflush);
 
     long long GetLastFrameInPosMap(long long desiredFrame);
Index: libs/libmythtv/videooutbase.cpp
===================================================================
--- libs/libmythtv/videooutbase.cpp	(revision 8406)
+++ libs/libmythtv/videooutbase.cpp	(working copy)
@@ -422,7 +422,7 @@
     XJ_height = height;
     SetVideoAspectRatio(aspect);
     
-    DiscardFrames();
+    DiscardFrames(true);
 }
 
 /**
Index: libs/libmythtv/videoout_xv.h
===================================================================
--- libs/libmythtv/videoout_xv.h	(revision 8406)
+++ libs/libmythtv/videoout_xv.h	(working copy)
@@ -103,7 +103,7 @@
 
     VideoFrame *GetNextFreeFrame(bool allow_unsafe);
     void DiscardFrame(VideoFrame*);
-    void DiscardFrames(void);
+    void DiscardFrames(bool kf);
     void DoneDisplayingFrame(void);
 
     void ProcessFrameXvMC(VideoFrame *frame, OSD *osd);
Index: libs/libmythtv/nuppeldecoder.h
===================================================================
--- libs/libmythtv/nuppeldecoder.h	(revision 8406)
+++ libs/libmythtv/nuppeldecoder.h	(working copy)
@@ -99,7 +99,7 @@
 
     int effdsp;
 
-    unsigned char *directbuf;
+    VideoFrame *directframe;
 
     AVCodec *mpa_codec;
     AVCodecContext *mpa_ctx;
Index: libs/libmythtv/videoout_xv.cpp
===================================================================
--- libs/libmythtv/videoout_xv.cpp	(revision 8406)
+++ libs/libmythtv/videoout_xv.cpp	(working copy)
@@ -1642,7 +1642,7 @@
 void VideoOutputXv::DeleteBuffers(VOSType subtype, bool delete_pause_frame)
 {
     (void) subtype;
-    DiscardFrames();
+    DiscardFrames(true);
 
 #ifdef USING_XVMC
     // XvMC buffers
@@ -1651,7 +1651,7 @@
         xvmc_vo_surf_t *surf = (xvmc_vo_surf_t*) xvmc_surfs[i];
         X11S(XvMCHideSurface(XJ_disp, &(surf->surface)));
     }
-    DiscardFrames();
+    DiscardFrames(true);
     for (uint i=0; i<xvmc_surfs.size(); i++)
     {
         xvmc_vo_surf_t *surf = (xvmc_vo_surf_t*) xvmc_surfs[i];
@@ -1824,7 +1824,7 @@
 void VideoOutputXv::ClearAfterSeek(void)
 {
     VERBOSE(VB_PLAYBACK, LOC + "ClearAfterSeek()");
-    DiscardFrames();
+    DiscardFrames(false);
 #ifdef USING_XVMC
     if (VideoOutputSubType() > XVideo)
     {
@@ -1833,7 +1833,7 @@
             xvmc_vo_surf_t *surf = (xvmc_vo_surf_t*) xvmc_surfs[i];
             X11S(XvMCHideSurface(XJ_disp, &(surf->surface)));
         }
-        DiscardFrames();
+        DiscardFrames(true);
     }
 #endif
 }
@@ -1844,11 +1844,11 @@
         vbuffers.end_lock(); \
     } while (0)
 
-void VideoOutputXv::DiscardFrames(void)
+void VideoOutputXv::DiscardFrames(bool next_frame_keyframe)
 { 
     if (VideoOutputSubType() <= XVideo)
     {
-        vbuffers.DiscardFrames();
+        vbuffers.DiscardFrames(next_frame_keyframe);
         return;
     }
 
@@ -2948,12 +2948,13 @@
             frame_queue_t children = vbuffers.Children(pframe);
             if (!children.empty())
             {
+#if 0
                 VERBOSE(VB_PLAYBACK, LOC + QString(
                             "Frame %1 w/children: %2 is being held for later "
                             "discarding.")
                         .arg(DebugString(pframe, true))
                         .arg(DebugString(children)));
-
+#endif
                 frame_queue_t::iterator cit;
                 for (cit = children.begin(); cit != children.end(); ++cit)
                 {
Index: libs/libmythtv/decoderbase.cpp
===================================================================
--- libs/libmythtv/decoderbase.cpp	(revision 8406)
+++ libs/libmythtv/decoderbase.cpp	(working copy)
@@ -407,36 +407,30 @@
     }
 }
 
-bool DecoderBase::DoRewind(long long desiredFrame, bool doflush)
+bool DecoderBase::DoRewind(long long desiredFrame, bool discardFrames)
 {
-    VERBOSE(VB_PLAYBACK, LOC + "DoRewind("
-            <<desiredFrame<<", "<<( doflush ? "do" : "don't" )<<" flush)");
+    VERBOSE(VB_PLAYBACK, LOC +
+            QString("DoRewind(%1 (%2), %3 discard frames)")
+            .arg(desiredFrame).arg(framesPlayed)
+            .arg((discardFrames) ? "do" : "don't"));
 
     if (m_positionMap.empty())
         return false;
 
-    {
-        bool ok = true;
-        if (ringBuffer->isDVD())
-            ok = DoRewindDVD(desiredFrame);
-        else
-            ok = DoRewindNormal(desiredFrame);
+    if (!DoRewindSeek(desiredFrame))
+        return false;
 
-        if (!ok)
-            return false;
-    }
-
     framesPlayed = lastKey;
     framesRead = lastKey;
 
     // Do any Extra frame-by-frame seeking for exactseeks mode
     // And flush pre-seek frame if we are allowed to and need to..
     int normalframes = (exactseeks) ? desiredFrame - framesPlayed : 0;
-    SeekReset(lastKey, normalframes, true, doflush);
+    SeekReset(lastKey, normalframes, true, discardFrames);
 
-    // ???
-    if (doflush)
+    if (discardFrames)
     {
+        // We need to tell the NVP and VideoOutput what frame we're on.
         GetNVP()->SetFramesPlayed(framesPlayed+1);
         GetNVP()->getVideoOutput()->SetFramesPlayed(framesPlayed+1);
     }
@@ -444,16 +438,16 @@
     return true;
 }
 
-bool DecoderBase::DoRewindDVD(long long desiredFrame)
+bool DecoderBase::DoRewindSeek(long long desiredFrame)
 {
-    long long pos = DVDFindPosition(desiredFrame);
-    ringBuffer->Seek(pos, SEEK_SET);
-    lastKey = desiredFrame + 1;
-    return true;
-}
+    if (ringBuffer->isDVD())
+    {
+        long long pos = DVDFindPosition(desiredFrame);
+        ringBuffer->Seek(pos, SEEK_SET);
+        lastKey = desiredFrame + 1;
+        return true;
+    }
 
-bool DecoderBase::DoRewindNormal(long long desiredFrame)
-{
     // Find keyframe <= desiredFrame, store in lastKey (frames)
     int pre_idx, post_idx;
     FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
@@ -528,9 +522,14 @@
             .arg(desiredFrame).arg(framesPlayed)
             .arg((discardFrames) ? "do" : "don't"));
 
-    // Rewind if we have already played the desiredFrame.
-    if (desiredFrame < framesPlayed)
+    // Rewind if we have already played the desiredFrame. The +1 is for
+    // MPEG4 NUV files, which need to decode an extra frame sometimes.
+    // This shouldn't effect how this works in general because this is
+    // only triggered on the first keyframe/frame skip when paused. At
+    // that point the decoding is more than one frame ahead of display.
+    if (desiredFrame+1 < framesPlayed)
         return DoRewind(desiredFrame, discardFrames);
+    desiredFrame = max(desiredFrame, framesPlayed);
 
     // Save rawframe state, for later restoration...
     bool oldrawstate = getrawframes;
@@ -627,7 +626,7 @@
     lastKey = (hasKeyFrameAdjustTable) ? e.adjFrame : e.index * keyframedist;
 
     // if commented out as a temporary fix for #868.
-    //if (framesPlayed < lastKey)
+    if (framesPlayed < lastKey)
     {
         ringBuffer->Seek(e.pos, SEEK_SET);
         needflush    = true;
Index: libs/libmythtv/videooutbase.h
===================================================================
--- libs/libmythtv/videooutbase.h	(revision 8406)
+++ libs/libmythtv/videooutbase.h	(working copy)
@@ -253,7 +253,7 @@
     virtual void DiscardFrame(VideoFrame *frame) { vbuffers.DiscardFrame(frame); }
     /// \brief Releases all frames not being actively displayed from any queue
     ///        onto the queue of frames ready for decoding onto.
-    virtual void DiscardFrames(void) { vbuffers.DiscardFrames(); }
+    virtual void DiscardFrames(bool kf) { vbuffers.DiscardFrames(kf); }
 
     /// \bug not implemented correctly. vpos is not updated.
     VideoFrame *GetLastDecodedFrame(void) { return vbuffers.GetLastDecodedFrame(); }
Index: libs/libmythtv/videobuffers.h
===================================================================
--- libs/libmythtv/videobuffers.h	(revision 8406)
+++ libs/libmythtv/videobuffers.h	(working copy)
@@ -59,7 +59,7 @@
     void DeleteBuffers(void);
 
     void Reset(void);
-    void DiscardFrames(void);
+    void DiscardFrames(bool next_frame_keyframe);
     void ClearAfterSeek(void);
 
     void SetPrebuffering(bool normal);
@@ -137,7 +137,7 @@
     frame_queue_t         *queue(BufferType type);
     const frame_queue_t   *queue(BufferType type) const;
 
-    frame_queue_t          available, used, limbo, pause, displayed;
+    frame_queue_t          available, used, limbo, pause, displayed, decode;
     vbuffer_map_t          vbufferMap; // videobuffers to buffer's index
     frame_vector_t         buffers;
     uchar_vector_t         allocated_structs; // for DeleteBuffers
Index: libs/libmythtv/videobuffers.cpp
===================================================================
--- libs/libmythtv/videobuffers.cpp	(revision 8406)
+++ libs/libmythtv/videobuffers.cpp	(working copy)
@@ -221,6 +221,15 @@
         success = false;
         global_lock.lock();
         frame = available.dequeue();
+
+        // Try to get a frame not being used by the decoder
+        for (uint i = 0; i <= available.size() && decode.contains(frame); i++)
+        {
+            if (!available.contains(frame))
+                available.enqueue(frame);
+            frame = available.dequeue();
+        }
+
         while (frame && used.contains(frame))
         {
             VERBOSE(VB_IMPORTANT,
@@ -243,17 +252,13 @@
         }
         if (frame)
         {
-            frame_queue_t *q = queue(enqueue_to);
-            if (q)
-                q->enqueue(frame);
+            safeEnqueue(enqueue_to, frame);
+
             success = true;
             if (with_lock)
                 success = TryLockFrame(frame, "GetNextFreeFrame");
             if (!success)
-            {
-                available.enqueue(frame);
-                q->remove(frame);
-            }
+                safeEnqueue(kVideoBuffer_avail, frame);
         }
 
         global_lock.unlock();
@@ -283,7 +288,7 @@
                         QString("GetNextFreeFrame() unable to "
                         "lock frame %1 times. Discarding Frames.")
                         .arg(TRY_LOCK_SPINS));
-                DiscardFrames();
+                DiscardFrames(true);
             }
         }
     }
@@ -302,6 +307,7 @@
     global_lock.lock();
     vpos = vbufferMap[frame];
     limbo.remove(frame);
+    decode.enqueue(frame);
     used.enqueue(frame);
     global_lock.unlock();
 }
@@ -319,6 +325,7 @@
         limbo.remove(frame);
         available.enqueue(frame);
     }
+    decode.remove(frame);
     global_lock.unlock();
 }
 
@@ -592,15 +599,38 @@
 }
 
 /**
- * \fn VideoBuffers::DiscardFrames(void)
+ * \fn VideoBuffers::DiscardFrames(bool)
  *  Mark all used frames as ready to be reused, this is for seek.
  */
-void VideoBuffers::DiscardFrames(void)
+void VideoBuffers::DiscardFrames(bool next_frame_keyframe)
 {
-    global_lock.lock();
-    VERBOSE(VB_PLAYBACK, QString("VideoBuffers::DiscardFrames(): %1")
-            .arg(GetStatus()));
+    QMutexLocker locker(&global_lock);
+    VERBOSE(VB_PLAYBACK, QString("VideoBuffers::DiscardFrames(%1): %2")
+            .arg(next_frame_keyframe).arg(GetStatus()));
 
+    if (!next_frame_keyframe)
+    {
+        for (bool change = true; change;)
+        {
+            change = false;
+            frame_queue_t ula(used);
+            frame_queue_t::iterator it = ula.begin();
+            for (; it != ula.end(); ++it)
+            {
+                if (!HasChildren(*it))
+                {
+                    RemoveInheritence(*it);
+                    DiscardFrame(*it);
+                    change = true;
+                }
+            }
+        }
+        VERBOSE(VB_PLAYBACK,
+                QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
+                .arg(next_frame_keyframe).arg(GetStatus()));
+        return;
+    }
+
     // Remove inheritence of all frames not in displayed or pause
     frame_queue_t ula(used);
     ula.insert(ula.end(), limbo.begin(), limbo.end());
@@ -634,10 +664,17 @@
         }
     }
 
-    VERBOSE(VB_PLAYBACK, QString("VideoBuffers::DiscardFrames(): %1 -- done()")
-            .arg(GetStatus()));
+    // Make sure frames used by decoder are last...
+    // This is for libmpeg2 which still uses the frames after a reset.
+    for (it = decode.begin(); it != decode.end(); ++it)
+        remove(kVideoBuffer_all, *it);
+    for (it = decode.begin(); it != decode.end(); ++it)
+        available.enqueue(*it);
+    decode.clear();
 
-    global_lock.unlock();
+    VERBOSE(VB_PLAYBACK,
+            QString("VideoBuffers::DiscardFrames(%1): %2 -- done")
+            .arg(next_frame_keyframe).arg(GetStatus()));
 }
 
 void VideoBuffers::ClearAfterSeek(void)
@@ -1185,19 +1222,20 @@
         unsigned long long d = to_bitmap(displayed);
         unsigned long long l = to_bitmap(limbo);
         unsigned long long p = to_bitmap(pause);
+        unsigned long long x = to_bitmap(decode);
         for (uint i=0; i<(uint)n; i++)
         {
             unsigned long long mask = 1<<i;
             if (a & mask)
-                str += "A";
+                str += (x & mask) ? "a" : "A";
             else if (u & mask)
-                str += "U";
+                str += (x & mask) ? "u" : "U";
             else if (d & mask)
-                str += "d";
+                str += (x & mask) ? "d" : "D";
             else if (l & mask)
-                str += "L";
+                str += (x & mask) ? "l" : "L";
             else if (p & mask)
-                str += "p";
+                str += (x & mask) ? "p" : "P";
             else
                 str += " ";
         }
