Index: libmythtv/NuppelVideoPlayer.cpp
===================================================================
--- libmythtv/NuppelVideoPlayer.cpp	(revision 13416)
+++ libmythtv/NuppelVideoPlayer.cpp	(working copy)
@@ -1238,6 +1238,9 @@
 {
     bool stopFFREW = false;
 
+    if (ringBuffer->isDVD())
+        GetDecoder()->UpdateDVDFramesPlayed();
+
     if (ffrew_skip > 0)
     {
         long long delta = GetDecoder()->GetFramesRead() - framesPlayed;
@@ -1255,9 +1258,10 @@
         bool      toBegin   = -curFrame > ffrew_skip;
         long long real_skip = (toBegin) ? -curFrame : ffrew_skip;
         GetDecoder()->DoRewind(curFrame + real_skip, false);
-        stopFFREW = framesPlayed <= keyframedist;
         if (ringBuffer->isDVD())
             stopFFREW = (ringBuffer->DVD()->GetCurrentTime() < 2);
+        else
+            stopFFREW = framesPlayed <= keyframedist;
     }
 
     if (stopFFREW)
@@ -3835,8 +3839,7 @@
 #endif
 
         GetDecoder()->setExactSeeks(exactseeks && ffrew_skip == 1);
-        if (!ringBuffer->isDVD())
-            GetDecoder()->DoRewind(framesPlayed);
+        GetDecoder()->DoRewind(framesPlayed);
         ClearAfterSeek();
     }
 
@@ -4022,13 +4025,10 @@
             else if (behind - ff <= maxtime * 2)
                 ret = behind - maxtime * 2;
 
-            if (ringBuffer->isDVD())
+            if (ringBuffer->isDVD() &&
+                ringBuffer->DVD()->TitleTimeLeft() < 5)
             {
-                if (ringBuffer->DVD()->GetCurrentTime() >
-                    ringBuffer->DVD()->GetTotalTimeOfTitle() - 5)
-                {
-                    ret = 0;
-                }
+                ret = 0;
             }
         }
     }
Index: libmythtv/DVDRingBuffer.cpp
===================================================================
--- libmythtv/DVDRingBuffer.cpp	(revision 13416)
+++ libmythtv/DVDRingBuffer.cpp	(working copy)
@@ -55,11 +55,16 @@
       jumptotitle(true),
       seekpos(0), seekwhence(0), 
       dvdname(NULL), serialnumber(NULL),
-      seeking(false), seekTime(0),
+      seeking(false), seektime(0),
       currentTime(0),
       parent(0)
 {
     memset(&dvdMenuButton, 0, sizeof(AVSubtitle));
+    uint def[8] = { 3, 5, 10, 20, 30, 60, 120, 180 };
+    uint seekValues[8] = { 1, 2, 4, 8, 10, 15, 20, 60 };
+
+    for (uint i = 0; i < 8; i++)
+        seekSpeedMap.insert(def[i], seekValues[i]);
 }
 
 DVDRingBufferPriv::~DVDRingBufferPriv()
@@ -93,15 +98,28 @@
 
 long long DVDRingBufferPriv::Seek(long long time)
 {
-    seekTime = (uint64_t)time;
+    dvdnav_status_t dvdRet = DVDNAV_STATUS_OK;
+
     uint searchToCellStart = 1;
+    int seekSpeed = 0;
     int ffrewSkip = 1;
     if (parent)
         ffrewSkip = parent->GetFFRewSkip();
-    if (ffrewSkip != 1)
-        searchToCellStart = 0;
-    dvdnav_status_t dvdRet = 
-        dvdnav_time_search(this->dvdnav, seekTime, searchToCellStart);
+   
+    if (ffrewSkip != 1 && time != 0)
+    {
+        QMapConstIterator<uint, uint> it = seekSpeedMap.find(labs(time));
+        seekSpeed = it.data();
+        if (time < 0)
+            seekSpeed = -seekSpeed;
+        dvdRet = dvdnav_time_search_within_cell(this->dvdnav, seekSpeed);
+    }
+    else
+    {
+        seektime = (uint64_t)time;
+        dvdRet = dvdnav_time_search(this->dvdnav, seektime, searchToCellStart);
+    }
+
     if (dvdRet == DVDNAV_STATUS_ERR)
     {
         VERBOSE(VB_PLAYBACK, LOC_ERR + 
@@ -406,19 +424,20 @@
                 currentTime = cellStart +
                     (uint)(dvdnav_convert_time(&timeFromCellStart));
                 currentpos = GetReadPosition();
-                
+
                 if (seeking)
                 {
-                    uint relativeTime = (uint)((seekTime - currentTime)/ 90000);
-                    if (relativeTime == 0)
+                    
+                    int relativetime = (int)((seektime - currentTime)/ 90000);
+                    if (relativetime <= 0)
                     {
                         seeking = false;
-                        seekTime = 0;
+                        seektime = 0;
                     }
                     else
-                        dvdnav_time_search_within_cell(dvdnav, relativeTime);
+                        dvdnav_time_search_within_cell(dvdnav, relativetime * 2);
                 }
-                
+
                 if (blockBuf != dvdBlockWriteBuf)
                 {
                     dvdnav_free_cache_block(dvdnav, blockBuf);
@@ -1310,6 +1330,14 @@
 #endif
 }
 
+/**\brief returns seconds left in the title
+ */
+uint DVDRingBufferPriv::TitleTimeLeft(void)
+{
+    return (GetTotalTimeOfTitle() -
+            GetCurrentTime());
+}
+
 /** \brief converts palette values from YUV to RGB
  */
 void DVDRingBufferPriv::guess_palette(uint32_t *rgba_palette,uint8_t *palette,
Index: libmythtv/DVDRingBuffer.h
===================================================================
--- libmythtv/DVDRingBuffer.h	(revision 13416)
+++ libmythtv/DVDRingBuffer.h	(working copy)
@@ -95,6 +95,7 @@
     int NumMenuButtons(void) const;
     void IgnoreStillOrWait(bool skip) { skipstillorwait = skip; }
     uint GetCurrentTime(void) { return (currentTime / 90000); }
+    uint TitleTimeLeft(void);
     void  SetTrack(uint type, int trackNo);
     int   GetTrack(uint type);
     uint8_t GetNumAudioChannels(int id);
@@ -162,8 +163,9 @@
     QString        dvdname;
     QString        serialnumber;
     bool           seeking;
-    uint64_t       seekTime;
+    uint64_t       seektime;
     uint           currentTime;
+    QMap<uint, uint> seekSpeedMap;
 
     NuppelVideoPlayer *parent;
 
Index: libmythtv/decoderbase.cpp
===================================================================
--- libmythtv/decoderbase.cpp	(revision 13416)
+++ libmythtv/decoderbase.cpp	(working copy)
@@ -549,6 +549,11 @@
             .arg(desiredFrame).arg(framesPlayed)
             .arg((discardFrames) ? "do" : "don't"));
 
+    if (ringBuffer->isDVD() &&
+        ringBuffer->DVD()->TitleTimeLeft() < 5)
+    {
+        return false;
+    }
     // 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
@@ -723,8 +728,13 @@
     int diffTime = 0;
     long long desiredTimePos;
     int ffrewSkip = 1;
+    int current_speed = 0;
     if (GetNVP())
+    {
         ffrewSkip = GetNVP()->GetFFRewSkip();
+        current_speed = (int)GetNVP()->GetNextPlaySpeed();
+    }
+
     if (ffrewSkip == 1)
     {
         diffTime = (int)ceil((desiredFrame - framesPlayed) / fps);
@@ -737,10 +747,9 @@
 
         if (desiredTimePos < 0)
             desiredTimePos = 0;
+        return (desiredTimePos * 90000LL);
     }
-    else
-        desiredTimePos = (long long)ceil(desiredFrame / fps);
-    return (desiredTimePos * 90000LL);
+    return current_speed;
 } 
 
 
Index: libmythdvdnav/searching.c
===================================================================
--- libmythdvdnav/searching.c	(revision 13416)
+++ libmythdvdnav/searching.c	(working copy)
@@ -83,17 +83,18 @@
         } else {
           vobu_start = next_vobu;
         }
-        address ++;
+        address++;
       }
     }
     else {
       found = 0;
       first_address = 0;
       last_address  = admap->last_byte >> 2;
-      while ((!found) && first_address <= last_address)
+      while (first_address <= last_address)
       {
         address = (first_address + last_address) / 2;
         next_vobu = admap->vobu_start_sectors[address];
+        vobu_start = next_vobu;
         if (seekto_block > next_vobu)
           first_address = address + 1;
         else if (seekto_block < next_vobu)
@@ -103,7 +104,8 @@
         }
       }
       found = 1;
-      vobu_start = next_vobu;
+      if (next_vobu > seekto_block)
+        vobu_start = admap->vobu_start_sectors[last_address - 1];
     }
     if(found) {
       *vobu = vobu_start;
@@ -640,8 +642,14 @@
   return DVDNAV_STATUS_OK;
 }
 
+/** \brief Seeks the nearest VOBU to the relative_time within the cell
+ * relative_time is in seconds * 2. 
+ * If you want 5 seconds ahead relative time = +10. 
+ * If relative_time is negative, then 
+ * look backwards within the cell.
+ */
 dvdnav_status_t dvdnav_time_search_within_cell(dvdnav_t *this,
-                    uint relative_time)
+                    int relative_time)
 {
   if(!this) {
     printerr("Passed a NULL pointer.");
@@ -649,32 +657,83 @@
   }
 
   uint32_t cur_vobu, new_vobu, start, offset;
-  int current_cell, i;
+  uint32_t first_cell_nr, last_cell_nr, cell_nr;
+  cell_playback_t *cell;
+  int i, length, scan_admap;
   
   dsi_t * dsi;
   dvd_state_t *state;
   int stime[19] = { 240, 120, 60, 20, 15, 14, 13, 12, 11,
                     10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
   pthread_mutex_lock(&this->vm_lock);
+  length = relative_time;
+  state = &(this->vm->state);
+  cell_nr = state->cellN -1;
+  cell = &(state->pgc->cell_playback[cell_nr]);
   cur_vobu = this->vobu.vobu_start;
-  for (i = 0; i <= 19; i++) {
-    if (stime[i]/2.0 <= relative_time) {
-      dsi = dvdnav_get_current_nav_dsi(this);
-      offset = dsi->vobu_sri.fwda[i];
-      if (offset >> 31)
-        new_vobu = cur_vobu + (dsi->vobu_sri.fwda[i] & 0xfffff);
-      else
-        new_vobu = cur_vobu;
-      break;
+  scan_admap = 0;
+
+  if (this->pgc_based) {
+    first_cell_nr = 0;
+    last_cell_nr = state->pgc->nr_of_cells - 1;
+  } else { 
+    printerr("dvdnav_time_search_within_cell: works only if pgc_based is enabled");
+    return DVDNAV_STATUS_ERR;
+  }
+
+  if (length != 0)
+  {
+    dsi = dvdnav_get_current_nav_dsi(this);
+    if (length > 0) {
+      for (i = 0; i <= 19; i++) {
+        if (stime[i]/2.0 <= length/2.0) {
+          offset = dsi->vobu_sri.fwda[i];
+          if (offset >> 31) {
+            new_vobu = cur_vobu + (offset & 0xffff);
+          } else {
+            if (cell_nr == last_cell_nr) {
+              offset = state->pgc->cell_playback[last_cell_nr].last_sector;
+              scan_admap = 1;
+            } else {
+              cell_nr++;
+              new_vobu =  state->pgc->cell_playback[cell_nr].first_sector;
+            }
+          }
+          break;
+        }
+      }
+    } else {
+      for (i = 0; i <= 19; i++) {
+        if (stime[18 - i]/2.0 >= abs(length)/2.0)
+        {
+          offset = dsi->vobu_sri.bwda[i];
+          if (offset >> 31) {
+            new_vobu = cur_vobu - (offset & 0xffff);
+          } else {
+            if (cell_nr == first_cell_nr) {
+              new_vobu = 0;
+            } else {
+              cell_nr--;
+              offset = state->pgc->cell_playback[cell_nr].last_sector;
+              scan_admap = 1;
+            }
+          }
+          break;
+        }
+      } 
     }
   }
-  
-  state = &(this->vm->state);
-  current_cell = state->cellN;
-  start =  state->pgc->cell_playback[current_cell-1].first_sector;
-  if (vm_jump_cell_block(this->vm, state->cellN, new_vobu - start)) {
+
+  if (scan_admap)
+  {
+    if (dvdnav_scan_admap(this, state->domain, offset, &new_vobu) == DVDNAV_STATUS_ERR)
+      return DVDNAV_STATUS_ERR;
+  }
+  start =  state->pgc->cell_playback[cell_nr].first_sector;
+  if (vm_jump_cell_block(this->vm, cell_nr+1, new_vobu - start)) {
     this->vm->hop_channel += HOP_SEEK;
   }
   pthread_mutex_unlock(&this->vm_lock);
   return DVDNAV_STATUS_OK;
 }
+
Index: libmythdvdnav/dvdnav.h
===================================================================
--- libmythdvdnav/dvdnav.h	(revision 13416)
+++ libmythdvdnav/dvdnav.h	(working copy)
@@ -369,17 +369,13 @@
 dvdnav_status_t dvdnav_time_search(dvdnav_t *self, 
 				   uint64_t time, uint search_to_nearest_cell);
 
-/* Seeks the nearest VOBU to the relative_time within the cell
- * relative_time is in seconds
- */
-dvdnav_status_t dvdnav_time_search_within_cell(dvdnav_t *self,
-                   uint relative_time);
+int dvdnav_time_search_within_cell(dvdnav_t *self,
+                   int relative_time);
 /*
  * Stop playing current position and play the "GoUp"-program chain.
  * (which generally leads to the title menu or a higer-level menu).
  */
 dvdnav_status_t dvdnav_go_up(dvdnav_t *self);
-
 /*
  * Stop playing the current position and start playback at the
  * previous program (if it exists).
