Index: libs/libmythtv/NuppelVideoPlayer.h
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.h	(revision 8420)
+++ 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 8420)
+++ libs/libmythtv/nuppeldecoder.cpp	(working copy)
@@ -25,6 +25,8 @@
 #include "bswap.h"
 #endif
 
+#define LOC QString("NVD: ")
+#define LOC_ERR QString("NVD Error: ")
 
 pthread_mutex_t avcodeclock = PTHREAD_MUTEX_INITIALIZER;
 
@@ -37,7 +39,8 @@
 #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),            decoded_video_frame(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 +569,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 +577,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 +590,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 +690,7 @@
     int compoff = 0;
 
     unsigned char *outbuf = frame->buf;
+    directframe = frame;
 
     if (!buf2)
     {
@@ -759,9 +767,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)
         {
@@ -896,6 +904,8 @@
     bool ret = false;
     int seeklen = 0;
 
+    decoded_video_frame = NULL;
+
     while (!gotvideo)
     {
         long long currentposition = ringBuffer->GetReadPosition();
@@ -1046,6 +1056,13 @@
 
             buf->frameNumber = framesPlayed;
             GetNVP()->ReleaseNextVideoFrame(buf, frameheader.timecode);
+            
+            // We need to make the frame available ourselves
+            // if we are not using ffmpeg/avlib.
+            if (directframe)
+                GetNVP()->getVideoOutput()->DeLimboFrame(buf);
+
+            decoded_video_frame = buf;
             gotvideo = 1;
             if (getrawframes && getrawvideo)
                 StoreRawData(strm);
@@ -1139,19 +1156,27 @@
 }
 
 void NuppelDecoder::SeekReset(long long newKey, uint skipFrames,
-                              bool needFlush, bool discardFrames)
+                              bool doFlush, bool discardFrames)
 {
-    DecoderBase::SeekReset(newKey, skipFrames, needFlush, discardFrames);
+    VERBOSE(VB_PLAYBACK, LOC +
+            QString("SeekReset(%1, %2, %3 flush, %4 discard)")
+            .arg(newKey).arg(skipFrames)
+            .arg((doFlush) ? "do" : "don't")
+            .arg((discardFrames) ? "do" : "don't"));
+    
+    DecoderBase::SeekReset(newKey, skipFrames, doFlush, discardFrames);
 
-    if (mpa_codec && needFlush)
+    if (mpa_codec && doFlush)
         avcodec_flush_buffers(mpa_ctx);
 
-    while (skipFrames > 0)
+    if (discardFrames)
+        GetNVP()->DiscardVideoFrames(doFlush);
+
+    for (;(skipFrames > 0) && !ateof; skipFrames--)
     {
         GetFrame(0);
-        if (ateof)
-            break;
-        skipFrames--;
+        if (decoded_video_frame)
+            GetNVP()->DiscardVideoFrame(decoded_video_frame);
     }
 }
 
Index: libs/libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libs/libmythtv/NuppelVideoPlayer.cpp	(revision 8420)
+++ libs/libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -804,11 +804,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)
 {
@@ -818,16 +834,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)
@@ -1659,7 +1689,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;
         }
@@ -3013,8 +3045,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 8420)
+++ 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;
         }
@@ -254,25 +325,28 @@
     return  ((lsb - base_ts)&mask);
 }
 
-bool AvFormatDecoder::DoRewind(long long desiredFrame, bool doflush)
+bool AvFormatDecoder::DoRewind(long long desiredFrame, bool discardFrames)
 {
     VERBOSE(VB_PLAYBACK, LOC + "DoRewind("
-            <<desiredFrame<<", "<<( doflush ? "do" : "don't" )<<" flush)");
+            <<desiredFrame<<", "
+            <<( discardFrames ? "do" : "don't" )<<" discard frames)");
 
     if (recordingHasPositionMap || livetv)
-        return DecoderBase::DoRewind(desiredFrame, doflush);
+        return DecoderBase::DoRewind(desiredFrame, discardFrames);
 
     // avformat-based seeking
-    return DoFastForward(desiredFrame, doflush);
+    return DoFastForward(desiredFrame, discardFrames);
 }
 
-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 +407,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);
@@ -349,34 +423,33 @@
 void AvFormatDecoder::SeekReset(long long newKey, uint skipFrames,
                                 bool doflush, bool discardFrames)
 {
-    VERBOSE(VB_PLAYBACK, LOC + QString("SeekReset(%1, %2 flush, %3 discard)")
-            .arg(skipFrames).arg((doflush) ? "do" : "don't")
+    VERBOSE(VB_PLAYBACK, LOC +
+            QString("SeekReset(%1, %2, %3 flush, %4 discard)")
+            .arg(newKey).arg(skipFrames)
+            .arg((doflush) ? "do" : "don't")
             .arg((discardFrames) ? "do" : "don't"));
 
     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 +457,31 @@
             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;
+        framesPlayed = lastKey;
+        framesRead = lastKey;
     }
 
-    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 +495,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)
     {
@@ -2446,6 +2525,7 @@
                     {
                         AVPicture tmppicture;
  
+                        VideoFrame *xf = picframe;
                         picframe = GetNVP()->GetNextVideoFrame(false);
 
                         tmppicture.data[0] = picframe->buf;
@@ -2463,6 +2543,11 @@
                                     context->pix_fmt,
                                     context->width,
                                     context->height);
+
+                        xf->interlaced_frame = mpa_pic.interlaced_frame;
+                        xf->top_field_first = mpa_pic.top_field_first;
+                        xf->frameNumber = framesPlayed;
+                        GetNVP()->DiscardVideoFrame(xf);
                     }
 
                     long long temppts = pts;
@@ -2498,8 +2583,8 @@
 
                     picframe->frameNumber = framesPlayed;
                     GetNVP()->ReleaseNextVideoFrame(picframe, temppts);
-                    if (!directrendering)
-                        GetNVP()->DiscardVideoFrame(picframe);
+                    if (d->HasMPEG2Dec() && mpa_pic.data[3])
+                        context->release_buffer(context, &mpa_pic);
 
                     decoded_video_frame = picframe;
                     gotvideo = 1;
Index: libs/libmythtv/decoderbase.h
===================================================================
--- libs/libmythtv/decoderbase.h	(revision 8420)
+++ 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);
@@ -106,6 +105,7 @@
         long long adjFrame; // keyFrameAdjustTable adjusted frame number
         long long pos;      // position in stream
     } PosMapEntry;
+    long long GetKey(PosMapEntry &entry) const;
 
     NuppelVideoPlayer *m_parent;
     ProgramInfo *m_playbackinfo;
@@ -122,6 +122,7 @@
     long long framesRead;
     long long lastKey;
     int keyframedist;
+    long long indexOffset;
 
 
     bool ateof;
Index: libs/libmythtv/videooutbase.cpp
===================================================================
--- libs/libmythtv/videooutbase.cpp	(revision 8420)
+++ 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 8420)
+++ 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 8420)
+++ libs/libmythtv/nuppeldecoder.h	(working copy)
@@ -99,7 +99,8 @@
 
     int effdsp;
 
-    unsigned char *directbuf;
+    VideoFrame *directframe;
+    VideoFrame *decoded_video_frame;
 
     AVCodec *mpa_codec;
     AVCodecContext *mpa_ctx;
Index: libs/libmythtv/videoout_xv.cpp
===================================================================
--- libs/libmythtv/videoout_xv.cpp	(revision 8420)
+++ 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;
     }
 
@@ -2010,7 +2010,10 @@
 void VideoOutputXv::PrepareFrameXv(VideoFrame *frame)
 {
     if (!frame)
+    {
         frame = vbuffers.GetScratchFrame();
+        vbuffers.GetScratchFrame()->frameNumber = framesPlayed - 1LL;
+    }
 
     XvImage *image = NULL;
     {
@@ -2049,7 +2052,10 @@
 void VideoOutputXv::PrepareFrameMem(VideoFrame *buffer, FrameScanType /*scan*/)
 {
     if (!buffer)
+    {
         buffer = vbuffers.GetScratchFrame();
+        vbuffers.GetScratchFrame()->frameNumber = framesPlayed - 1LL;
+    }
 
     vbuffers.LockFrame(buffer, "PrepareFrameMem");
 
@@ -2532,6 +2538,7 @@
             vbuffers.TryLockFrame(vbuffers.GetScratchFrame(),
                                   "UpdatePauseFrame -- scratch"))
         {
+            vbuffers.GetScratchFrame()->frameNumber = framesPlayed - 1;
             CopyFrame(&av_pause_frame, vbuffers.GetScratchFrame());
             vbuffers.UnlockFrame(vbuffers.GetScratchFrame(),
                                  "UpdatePauseFrame -- scratch");
@@ -2789,6 +2796,7 @@
     if (!frame)
     {
         frame = vbuffers.GetScratchFrame();
+        frame->frameNumber = framesPlayed - 1LL;
         vector<const VideoFrame*> locks;
         locks.push_back(frame);
         locks.push_back(&av_pause_frame);
@@ -2948,12 +2956,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 8420)
+++ libs/libmythtv/decoderbase.cpp	(working copy)
@@ -20,6 +20,7 @@
       current_aspect(1.33333), fps(29.97),
 
       framesPlayed(0), framesRead(0), lastKey(0), keyframedist(-1),
+      indexOffset(0),
 
       ateof(false), exitafterdecoded(false), transcoding(false),
 
@@ -156,6 +157,7 @@
     {
         VERBOSE(VB_PLAYBACK, QString("Position map filled from DB to: %1")
                 .arg((long int) m_positionMap[m_positionMap.size()-1].index));
+        indexOffset = m_positionMap[0].index;
     }
 
     return true;
@@ -342,18 +344,18 @@
                                int &lower_bound, int &upper_bound)
 {
     // Binary search
-    int upper = m_positionMap.size(), lower = -1;
+    long long upper = m_positionMap.size(), lower = -1;
     if (!search_adjusted && keyframedist > 0)
         desired_value /= keyframedist;
 
     while (upper - 1 > lower) 
     {
-        int i = (upper + lower) / 2;
+        long long i = (upper + lower) / 2;
         long long value;
         if (search_adjusted)
             value = m_positionMap[i].adjFrame;
         else
-            value = m_positionMap[i].index;
+            value = m_positionMap[i].index - indexOffset;
         if (value == desired_value) 
         {
             // found it
@@ -368,27 +370,26 @@
     }
     // Did not find it exactly -- return bounds
 
-    if (search_adjusted) 
+    if (search_adjusted)
     {
         while (lower >= 0 && m_positionMap[lower].adjFrame > desired_value)
             lower--;
-        while (upper < (int)m_positionMap.size() &&
+        while (upper < m_positionMap.size() &&
                m_positionMap[upper].adjFrame > desired_value)
             upper++;
     }
     else
     {
-        while (lower >= 0 &&m_positionMap[lower].index > desired_value)
+        while (lower >= 0 &&
+               (m_positionMap[lower].index - indexOffset) > desired_value)
             lower--;
-        while (upper < (int)m_positionMap.size() && 
-               m_positionMap[upper].index < desired_value)
+        while (upper < m_positionMap.size() && 
+               (m_positionMap[upper].index - indexOffset) < desired_value)
             upper++;
     }
     // keep in bounds
-    if (lower < 0)
-        lower = 0;
-    if (upper >= (int)m_positionMap.size())
-        upper = (int)m_positionMap.size() - 1;
+    lower = max(lower, 0LL);
+    upper = min(upper, m_positionMap.size() - 1LL);
 
     upper_bound = upper;
     lower_bound = lower;
@@ -407,41 +408,31 @@
     }
 }
 
-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;
+    normalframes = max(normalframes, 0);
+    SeekReset(lastKey, normalframes, true, discardFrames);
 
-    // This shouldn't happen, but it's nasty if it does so prevent it
-    if (normalframes < 0)
-        normalframes = 0;
-
-    SeekReset(lastKey, normalframes, true, doflush);
-
-    // ???
-    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);
     }
@@ -449,24 +440,29 @@
     return true;
 }
 
-bool DecoderBase::DoRewindDVD(long long desiredFrame)
+long long DecoderBase::GetKey(PosMapEntry &e) const
 {
-    long long pos = DVDFindPosition(desiredFrame);
-    ringBuffer->Seek(pos, SEEK_SET);
-    lastKey = desiredFrame + 1;
-    return true;
+    long long kf  = (ringBuffer->isDVD()) ? 1LL : keyframedist;
+    return (hasKeyFrameAdjustTable) ? e.adjFrame :(e.index - indexOffset) * kf;
 }
 
-bool DecoderBase::DoRewindNormal(long long desiredFrame)
+bool DecoderBase::DoRewindSeek(long long desiredFrame)
 {
+    if (ringBuffer->isDVD())
+    {
+        long long pos = DVDFindPosition(desiredFrame);
+        ringBuffer->Seek(pos, SEEK_SET);
+        lastKey = desiredFrame + 1;
+        return true;
+    }
+
     // Find keyframe <= desiredFrame, store in lastKey (frames)
     int pre_idx, post_idx;
     FindPosition(desiredFrame, hasKeyFrameAdjustTable, pre_idx, post_idx);
 
-    bool useAdj   = hasKeyFrameAdjustTable;
     uint pos_idx  = min(pre_idx, post_idx);
     PosMapEntry e = m_positionMap[pos_idx];
-    lastKey = (useAdj) ? e.adjFrame : (e.index - 1) * keyframedist;
+    lastKey = GetKey(e);
 
     // ??? Don't rewind past the beginning of the file
     while (e.pos < 0)
@@ -476,7 +472,7 @@
             return false;
 
         e = m_positionMap[pos_idx];
-        lastKey = (useAdj) ? e.adjFrame : (e.index - 1) * keyframedist;
+        lastKey = GetKey(e);
     }
 
     ringBuffer->Seek(e.pos, SEEK_SET);
@@ -487,9 +483,8 @@
 long long DecoderBase::GetLastFrameInPosMap(long long desiredFrame)
 {
     long long last_frame = 0;
-    uint mult = (uint) (ringBuffer->isDVD()) ? 1 : keyframedist;
     if (!m_positionMap.empty())
-        last_frame = mult * m_positionMap.back().index;
+        last_frame = GetKey(m_positionMap.back());
 
     // Resync keyframe map if we are trying to seek to a frame
     // not yet in out map and then check for last frame again.
@@ -503,7 +498,7 @@
         SyncPositionMap();
 
         if (!m_positionMap.empty())
-            last_frame = mult * m_positionMap.back().index;
+            last_frame = GetKey(m_positionMap.back());
 
         if (desiredFrame > last_frame)
         {
@@ -533,9 +528,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;
@@ -629,10 +629,9 @@
     uint pos_idx = (exactseeks) ? pre_idx : max(pre_idx, post_idx);
 
     PosMapEntry e = m_positionMap[pos_idx];
-    lastKey = (hasKeyFrameAdjustTable) ? e.adjFrame : e.index * keyframedist;
+    lastKey = GetKey(e);
 
-    // 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/ivtvdecoder.cpp
===================================================================
--- libs/libmythtv/ivtvdecoder.cpp	(revision 8420)
+++ libs/libmythtv/ivtvdecoder.cpp	(working copy)
@@ -20,6 +20,9 @@
 #include "videoout_ivtv.h"
 #include "videodev_myth.h"
 
+#define LOC QString("IVD: ")
+#define LOC_ERR QString("IVD Error: ")
+
 bool IvtvDecoder::ntsc = true;
 
 IvtvDecoder::IvtvDecoder(NuppelVideoPlayer *parent, ProgramInfo *pginfo)
@@ -53,6 +56,10 @@
 void IvtvDecoder::SeekReset(long long newkey, uint skipframes,
                             bool needFlush, bool discardFrames)
 {
+    VERBOSE(VB_PLAYBACK, LOC + QString("SeekReset(%1, %2 flush, %3 discard)")
+            .arg(skipframes).arg((needFlush) ? "do" : "don't")
+            .arg((discardFrames) ? "do" : "don't"));
+
     DecoderBase::SeekReset(newkey, skipframes, needFlush, discardFrames);
 
     if (!exactseeks)
@@ -77,7 +84,7 @@
         vidframes = 0;
         queuedlist.clear();
 
-        videoout->Stop(false);
+        videoout->Stop(false /* hide */);
         videoout->Flush();
 
         videoout->Start(0, skipframes+5);
Index: libs/libmythtv/videooutbase.h
===================================================================
--- libs/libmythtv/videooutbase.h	(revision 8420)
+++ 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 8420)
+++ 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 8420)
+++ 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();
 }
 
@@ -441,10 +448,9 @@
     frame_queue_t *q = queue(type);
     if (q)
     {
-        global_lock.lock();
-        VideoFrame *frame = q->head();
-        global_lock.unlock();
-        return frame;
+        QMutexLocker locker(&global_lock);
+        if (q->size())
+            return q->head();
     }
     return NULL;
 }
@@ -454,10 +460,9 @@
     frame_queue_t *q = queue(type);
     if (q)
     {
-        global_lock.lock();
-        VideoFrame *frame = q->tail();
-        global_lock.unlock();
-        return frame;
+        QMutexLocker locker(&global_lock);
+        if (q->size())
+            return q->tail();
     }
     return NULL;
 }
@@ -592,15 +597,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 +662,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,21 +1220,28 @@
         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;
+            QString tmp("");
             if (a & mask)
-                str += "A";
-            else if (u & mask)
-                str += "U";
-            else if (d & mask)
-                str += "d";
-            else if (l & mask)
-                str += "L";
-            else if (p & mask)
-                str += "p";
+                tmp += (x & mask) ? "a" : "A";
+            if (u & mask)
+                tmp += (x & mask) ? "u" : "U";
+            if (d & mask)
+                tmp += (x & mask) ? "d" : "D";
+            if (l & mask)
+                tmp += (x & mask) ? "l" : "L";
+            if (p & mask)
+                tmp += (x & mask) ? "p" : "P";
+
+            if (0 == tmp.length())
+                str += " ";
+            else if (1 == tmp.length())
+                str += tmp;
             else
-                str += " ";
+                str += "(" + tmp + ")";
         }
         global_lock.unlock();
     }
