Index: BaseTSReaderPlayer.cs
===================================================================
--- BaseTSReaderPlayer.cs	(revision 26887)
+++ BaseTSReaderPlayer.cs	(working copy)
@@ -680,30 +680,38 @@
       }
       OnProcess();
       CheckVideoResolutionChanges();
-      if (_speedRate != 10000)
+	    if ((_currentPos > (_duration-1.0)) && IsTimeShifting && (iSpeed != 1))
       {
-        DoFFRW();
+        Log.Info("TSReaderPlayer : timeshifting FFWD/REW : currentPos > duration-1");
+        MovieEnded();
       }
-      else
-      {
-        _lastFrameCounter = 0;
-        _FFRWtimer = DateTime.Now;
-      }
       if (_endOfFileDetected && IsTimeShifting)
       {
         UpdateDuration();
         UpdateCurrentPosition();
-        double pos = CurrentPosition;
+        double pos = _duration - 1.0; //Continue playing from end of file -1 seconds
         if (pos < 0)
         {
           pos = 0;
         }
         SeekAbsolute(pos);
+        Speed = 1; 
+        _endOfFileDetected = false;     
+        Log.Info("TSReaderPlayer : timeshift EOF - start play");
       }
-
+      if (_speedRate != 10000)
+      {
+        DoFFRW();
+      }
+      else
+      {
+        _lastFrameCounter = 0;
+        _FFRWtimer = DateTime.Now;
+      }
       // Workaround for Mantis issue: 0002698: Last frame can get stuck on the screen when TS file playback ends 
-	  if (_currentPos > _duration && !IsTimeShifting)
+	    if (_currentPos > _duration && !IsTimeShifting)
       {
+        Log.Info("TSReaderPlayer : currentPos > duration");
         MovieEnded();
       }
 
@@ -791,7 +799,7 @@
           if (_CodecSupportsFastSeeking)
           {
             // Inform dshowhelper of playback rate changes
-            VMR9Util.g_vmr9.EVRProvidePlaybackRate((double)value);
+            if (VMR9Util.g_vmr9 != null) VMR9Util.g_vmr9.EVRProvidePlaybackRate((double)value);
               
             if (iSpeed != value)
             {
@@ -1338,6 +1346,7 @@
       else
       {
         _endOfFileDetected = true;
+        Log.Info("TSReaderPlayer timeshift EOF");
       }
     }
 
@@ -1831,14 +1840,14 @@
       {
         return;
       }
-      if ((_speedRate == 10000) || (_mediaSeeking == null))
+      if ((_speedRate == 10000) || (_mediaSeeking == null) || (_mediaCtrl == null))
       {
         return;
       }
       TimeSpan ts = DateTime.Now - _elapsedTimer;
-      if ((ts.TotalMilliseconds < 100) || (ts.TotalMilliseconds < Math.Abs(1000.0f / Speed)) ||
-          (VMR9Util.g_vmr9 != null && _lastFrameCounter == VMR9Util.g_vmr9.FreeFrameCounter) &&
-          (ts.TotalMilliseconds < 2000))
+      if ((ts.TotalMilliseconds < 200) || (ts.TotalMilliseconds < Math.Abs(1000.0f / Speed)) ||
+          ((VMR9Util.g_vmr9 != null && _lastFrameCounter == VMR9Util.g_vmr9.FreeFrameCounter) &&
+          (ts.TotalMilliseconds < 2000)))
       {
         // Ambass : Normally, 100 mS are enough to present the new frame, but sometimes the PC is thinking...and we launch a new seek
         return;
@@ -1860,7 +1869,10 @@
 
         // new time = current time + timerinterval * speed
         long lTimerInterval = (long)ts.TotalMilliseconds;
-
+        if (lTimerInterval > 1000)
+        {
+          lTimerInterval = 1000;
+        }
         rewind = (long)(current + ((long)(lTimerInterval) * Speed * 10000));
         int hr;
         pStop = 0;
@@ -1870,15 +1882,15 @@
         {
           _speedRate = 10000;
           rewind = earliest;
-          //Log.Info(" seek back:{0}",rewind/10000000);
-          hr = _mediaSeeking.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning,
+          Log.Info("TSReaderPlayer: timeshift SOF seek back:{0}",rewind/10000000);
+          hr = _mediaSeeking.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning | AMSeekingSeekingFlags.SeekToKeyFrame,
                                           new DsLong(pStop), AMSeekingSeekingFlags.NoPositioning);
-          _mediaCtrl.Run();
+          Speed = 1;      
           return;
         }
         // if we end up at the end of time then just
-        // start @ the end-100msec
-        long margin = (IsTimeShifting) ? 30000000 : 10000;
+        // start @ the end -1sec
+        long margin = (IsTimeShifting) ? 10000000 : 100000;
 
         if ((rewind > (latest - margin)) && (_speedRate > 0))
         {
@@ -1886,10 +1898,10 @@
           {
             _speedRate = 10000;
             rewind = latest - margin;
-            //Log.Info(" seek ff:{0} {1}",rewind,latest);
-            hr = _mediaSeeking.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning,
+            Log.Info("TSReaderPlayer: timeshift EOF seek ff:{0} {1}",rewind,latest);
+            hr = _mediaSeeking.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning | AMSeekingSeekingFlags.SeekToKeyFrame,
                                           new DsLong(pStop), AMSeekingSeekingFlags.NoPositioning);
-            _mediaCtrl.Run();
+            Speed = 1;      
           }
           else
           {
@@ -1900,11 +1912,16 @@
         }
         //seek to new moment in time
         //Log.Info(" seek :{0}",rewind/10000000);
-        if (VMR9Util.g_vmr9 != null) _lastFrameCounter = VMR9Util.g_vmr9.FreeFrameCounter;
-        hr = _mediaSeeking.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning, new DsLong(pStop),
-                                        AMSeekingSeekingFlags.NoPositioning);
+        if (VMR9Util.g_vmr9 != null)
+        {
+          _lastFrameCounter = VMR9Util.g_vmr9.FreeFrameCounter;
+          VMR9Util.g_vmr9.EVRProvidePlaybackRate(0.0);
+        }
+        hr = _mediaSeeking.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning | AMSeekingSeekingFlags.SeekToKeyFrame,
+                                        new DsLong(pStop), AMSeekingSeekingFlags.NoPositioning);
+        _mediaCtrl.Run();
         //according to ms documentation, this is the prefered way to do seeking
-        _mediaCtrl.StopWhenReady();
+       // _mediaCtrl.StopWhenReady();
         _elapsedTimer = DateTime.Now;
       }
     }
Index: VideoPlayerVMR7.cs
===================================================================
--- VideoPlayerVMR7.cs	(revision 26887)
+++ VideoPlayerVMR7.cs	(working copy)
@@ -158,6 +158,7 @@
     protected bool m_bFullScreen = true;
     protected PlayState m_state = PlayState.Init;
     protected int m_iVolume = 100;
+    protected int m_volumeBeforeSeeking = 0;
     protected IGraphBuilder graphBuilder;
     protected long m_speedRate = 10000;
     protected double m_dCurrentPos;
@@ -200,6 +201,7 @@
     protected double[] chapters = null;
     protected string[] chaptersname = null;
     private DateTime elapsedTimer = DateTime.Now;
+    protected int m_lastFrameCounter = 0;
 
     protected const string defaultLanguageCulture = "EN";
 
@@ -576,7 +578,7 @@
         return;
       }
       TimeSpan ts = DateTime.Now - updateTimer;
-      if (ts.TotalMilliseconds >= 800 || m_speedRate != 1)
+      if (ts.TotalMilliseconds >= 800 || m_speedRate != 10000)
       {
         if (mediaPos != null)
         {
@@ -606,10 +608,14 @@
         CheckVideoResolutionChanges();
         updateTimer = DateTime.Now;
       }
-      if (m_speedRate != 1)
+      if (m_speedRate != 10000)
       {
         DoFFRW();
       }
+      else
+      {
+        m_lastFrameCounter = 0;
+      }
       OnProcess();
     }
 
@@ -751,13 +757,13 @@
       if (m_state == PlayState.Paused)
       {
         m_speedRate = 10000;
-        mediaCtrl.Run();
+        if (mediaCtrl != null) mediaCtrl.Run();
         m_state = PlayState.Playing;
       }
       else if (m_state == PlayState.Playing)
       {
         m_state = PlayState.Paused;
-        mediaCtrl.Pause();
+        if (mediaCtrl != null) mediaCtrl.Pause();
       }
     }
 
@@ -790,6 +796,7 @@
     {
       if (m_state != PlayState.Init)
       {
+        m_state = PlayState.Init;
         Log.Info("VideoPlayer:ended {0}", m_strCurrentFile);
         m_strCurrentFile = "";
         CloseInterfaces();
@@ -803,16 +810,28 @@
       m_speedRate = speed;
       if (mediaSeek != null)
       {
-        int hr = mediaSeek.SetRate(rate);
-        if (hr == 0)
+        if (rate > 0)
         {
-          Log.Debug("Successfully set rate to {0}", rate);
-          m_bRateSupport = true;
-          return;
+          int hr = mediaSeek.SetRate(rate);
+          if (hr == 0)
+          {
+            Log.Info("VideoPlayer:Successfully set rate to {0}", rate);
+            m_bRateSupport = true;
+            if (mediaCtrl != null) mediaCtrl.Run();
+            return;
+          }
+          else
+          {
+            Log.Info("VideoPlayer:Could not set rate to {0}, error: 0x{1:x}", rate, hr);
+          }
         }
-        Log.Debug("Could not set rate to {0}, error: 0x{1:x}", rate, hr);
+        else
+        {
+          int hr = mediaSeek.SetRate(1.0);
+        }
       }
       //fallback to skip steps
+      Log.Info("VideoPlayer:Using skip-step fast-forward/rewind, rate {0}", rate);
       m_bRateSupport = false;
     }
 
@@ -832,28 +851,28 @@
         {
           case -10000:
             return -1;
-          case -15000:
+          case -20000:
             return -2;
-          case -30000:
+          case -40000:
             return -4;
-          case -45000:
+          case -80000:
             return -8;
-          case -60000:
+          case -160000:
             return -16;
-          case -75000:
+          case -320000:
             return -32;
-          case 10000:
-            return 1;
-          case 15000:
+          case 20000:
             return 2;
-          case 30000:
+          case 40000:
             return 4;
-          case 45000:
+          case 80000:
             return 8;
-          case 60000:
+          case 160000:
             return 16;
+          case 320000:
+            return 32;
           default:
-            return 32;
+            return 1;
         }
       }
       set
@@ -868,44 +887,64 @@
                 TrySpeed(-1, -10000);
                 break;
               case -2:
-                TrySpeed(-2, -15000);
+                TrySpeed(-2, -20000);
                 break;
               case -4:
-                TrySpeed(-4, -30000);
+                TrySpeed(-4, -40000);
                 break;
               case -8:
-                TrySpeed(-8, -45000);
+                TrySpeed(-8, -80000);
                 break;
               case -16:
-                TrySpeed(-16, -60000);
+                TrySpeed(-16, -160000);
                 break;
               case -32:
-                TrySpeed(-32, -75000);
+                TrySpeed(-32, -320000);
                 break;
-              case 1:
-                TrySpeed(1, 10000);
-                mediaCtrl.Run();
-                break;
               case 2:
-                TrySpeed(2, 15000);
+                TrySpeed(2, 20000);
                 break;
               case 4:
-                TrySpeed(4, 30000);
+                TrySpeed(4, 40000);
                 break;
               case 8:
-                TrySpeed(8, 45000);
+                TrySpeed(8, 80000);
                 break;
               case 16:
-                TrySpeed(16, 60000);
+                TrySpeed(16, 160000);
                 break;
+              case 32:
+                TrySpeed(32, 320000);
+                break;
               default:
-                TrySpeed(32, 75000);
+                TrySpeed(1, 10000);
+                // mediaCtrl.Run();
                 break;
             }
+            
+            if (VMR9Util.g_vmr9 != null) VMR9Util.g_vmr9.EVRProvidePlaybackRate((double)value);
+            Log.Info("VideoPlayer:SetRate to:{0}", value);
+            
+            if (value == 1.0)
+            {              
+              // unmute audio when speed returns to 1.0x
+              if (m_volumeBeforeSeeking != 0)
+              {
+                Volume = m_volumeBeforeSeeking;
+              }
+              m_volumeBeforeSeeking = 0;
+            }
+            else
+            {
+              // mute audio during > 1.0x playback
+              if (m_volumeBeforeSeeking == 0)
+              {
+                m_volumeBeforeSeeking = Volume;
+              }
+              Volume = 0;
+            }
           }
         }
-        VMR9Util.g_vmr9.EVRProvidePlaybackRate((double)value);
-        Log.Info("VideoPlayer:SetRate to:{0}", m_speedRate);
       }
     }
 
@@ -921,7 +960,7 @@
           {
             if (basicAudio != null)
             {
-              // Divide by 100 to get equivalent decibel value. For example, �10,000 is �100 dB. 
+              // Divide by 100 to get equivalent decibel value. For example, 10,000 is 100 dB. 
               float fPercent = (float)m_iVolume / 100.0f;
               int iVolume = (int)(5000.0f * fPercent);
               basicAudio.put_Volume((iVolume - 5000));
@@ -1099,69 +1138,82 @@
       } while (hr == 0);
     }
 
+
     protected void DoFFRW()
     {
-      if (!Playing)
+      if (!Playing || m_bRateSupport == true)
       {
         return;
       }
-      if ((m_speedRate == 10000) || (mediaSeek == null) || m_bRateSupport == true)
+      if ((m_speedRate == 10000) || (mediaSeek == null) || (mediaCtrl == null))
       {
         return;
       }
       TimeSpan ts = DateTime.Now - elapsedTimer;
-      //max out at 10 seeks per second
-      if (ts.TotalMilliseconds < 100)
+      //max out at 5 seeks per second
+      //if (ts.TotalMilliseconds < 200)
+      if ((ts.TotalMilliseconds < 200) || (ts.TotalMilliseconds < Math.Abs(10000000.0f / m_speedRate)) ||
+          ((VMR9Util.g_vmr9 != null && m_lastFrameCounter == VMR9Util.g_vmr9.FreeFrameCounter) &&
+          (ts.TotalMilliseconds < 2000)))  // It's good to verify a new frame has been presented.
       {
         return;
       }
-      elapsedTimer = DateTime.Now;
       long earliest, latest, current, stop, rewind, pStop;
-      mediaSeek.GetAvailable(out earliest, out latest);
-      mediaSeek.GetPositions(out current, out stop);
-      // Log.Info("earliest:{0} latest:{1} current:{2} stop:{3} speed:{4}, total:{5}",
-      //         earliest/10000000,latest/10000000,current/10000000,stop/10000000,m_speedRate, (latest-earliest)/10000000);
-      //earliest += + 30 * 10000000;
-      // new time = current time + 2*timerinterval* (speed)
-      long lTimerInterval = (long)ts.TotalMilliseconds;
-      if (lTimerInterval > 300)
+      lock (mediaCtrl)
       {
-        lTimerInterval = 300;
-      }
-      lTimerInterval = 300;
-      rewind = (long)(current + (2 * (long)(lTimerInterval) * m_speedRate));
-      int hr;
-      pStop = 0;
-      // if we end up before the first moment of time then just
-      // start @ the beginning
-      if ((rewind < earliest) && (m_speedRate < 0))
-      {
-        m_speedRate = 10000;
-        rewind = earliest;
-        //Log.Info(" seek back:{0}",rewind/10000000);
-        hr = mediaSeek.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning, new DsLong(pStop),
-                                    AMSeekingSeekingFlags.NoPositioning);
+        elapsedTimer = DateTime.Now;
+        mediaSeek.GetAvailable(out earliest, out latest);
+        mediaSeek.GetPositions(out current, out stop);
+        // Log.Info("earliest:{0} latest:{1} current:{2} stop:{3} speed:{4}, total:{5}",
+        //         earliest/10000000,latest/10000000,current/10000000,stop/10000000,m_speedRate, (latest-earliest)/10000000);
+        //earliest += + 30 * 10000000;
+        // new time = current time + 2*timerinterval* (speed)
+        long lTimerInterval = (long)ts.TotalMilliseconds;
+        if (lTimerInterval > 1000)
+        {
+          lTimerInterval = 1000;
+        }
+        //rewind = (long)(current + (2 * (long)(lTimerInterval) * m_speedRate));
+        rewind = (current + (lTimerInterval * m_speedRate));
+        int hr;
+        pStop = 0;
+        // if we end up before the first moment of time then just
+        // start @ the beginning
+        if ((rewind < earliest) && (m_speedRate < 0))
+        {
+          m_speedRate = 10000;
+          rewind = earliest;
+          Log.Info("VideoPlayer: timeshift SOF seek rew:{0} {1}",rewind,earliest);
+          hr = mediaSeek.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning | AMSeekingSeekingFlags.SeekToKeyFrame, 
+                                      new DsLong(pStop), AMSeekingSeekingFlags.NoPositioning);
+          Speed = 1;      
+          return;
+        }
+        // if we end up at the end of time then just
+        // start @ the end-100msec
+        if ((rewind > (latest - 1000000)) && (m_speedRate > 0))
+        {
+          m_speedRate = 10000;
+          rewind = latest - 1000000;
+          Log.Info("VideoPlayer: timeshift EOF seek ff:{0} {1}",rewind,latest);
+          hr = mediaSeek.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning | AMSeekingSeekingFlags.SeekToKeyFrame, 
+                                      new DsLong(pStop), AMSeekingSeekingFlags.NoPositioning);
+          Speed = 1;      
+          return;
+        }
+        //seek to new moment in time
+        //Log.Info(" seek :{0}",rewind/10000);
+        if (VMR9Util.g_vmr9 != null)
+        {
+          m_lastFrameCounter = VMR9Util.g_vmr9.FreeFrameCounter;
+          VMR9Util.g_vmr9.EVRProvidePlaybackRate(0.0);
+        }
+        hr = mediaSeek.SetPositions(new DsLong(rewind),
+                                    AMSeekingSeekingFlags.AbsolutePositioning | AMSeekingSeekingFlags.SeekToKeyFrame,
+                                    new DsLong(pStop), AMSeekingSeekingFlags.NoPositioning);
         mediaCtrl.Run();
-        return;
+        //mediaCtrl.StopWhenReady();
       }
-      // if we end up at the end of time then just
-      // start @ the end-100msec
-      if ((rewind > (latest - 100000)) && (m_speedRate > 0))
-      {
-        m_speedRate = 10000;
-        rewind = latest - 100000;
-        //Log.Info(" seek ff:{0}",rewind/10000000);
-        hr = mediaSeek.SetPositions(new DsLong(rewind), AMSeekingSeekingFlags.AbsolutePositioning, new DsLong(pStop),
-                                    AMSeekingSeekingFlags.NoPositioning);
-        mediaCtrl.Run();
-        return;
-      }
-      //seek to new moment in time
-      //Log.Info(" seek :{0}",rewind/10000);
-      hr = mediaSeek.SetPositions(new DsLong(rewind),
-                                  AMSeekingSeekingFlags.AbsolutePositioning | AMSeekingSeekingFlags.SeekToKeyFrame,
-                                  new DsLong(pStop), AMSeekingSeekingFlags.NoPositioning);
-      mediaCtrl.StopWhenReady();
     }
 
     protected virtual void OnInitialized() { }
