Index: AudioPin.cpp
===================================================================
--- AudioPin.cpp	(revision 27941)
+++ AudioPin.cpp	(working copy)
@@ -181,7 +181,6 @@
   return CSourceStream::BreakConnect();
 }
 
-extern int ShowBuffer;
 
 HRESULT CAudioPin::FillBuffer(IMediaSample *pSample)
 {
@@ -200,7 +199,7 @@
       //we dont try to read any packets, but simply return...
       if (m_pTsReaderFilter->IsSeeking() || m_pTsReaderFilter->IsStopping())// /*|| m_bSeeking*/ || m_pTsReaderFilter->IsSeekingToEof())
       {
-        //if (ShowBuffer) LogDebug("aud:isseeking");
+        //if (m_pTsReaderFilter->m_ShowBufferAudio) LogDebug("aud:isseeking");
         Sleep(20);
         pSample->SetTime(NULL,NULL);
         pSample->SetActualDataLength(0);
@@ -391,11 +390,11 @@
               float clock = (double)(RefClock-m_rtStart.m_time)/10000000.0 ;
               float fTime=(float)cRefTime.Millisecs()/1000.0f - clock ;
 
-              if (ShowBuffer || fTime < 0.030)
+              if (m_pTsReaderFilter->m_ShowBufferAudio || fTime < 0.030)
               {
                 LogDebug("Aud/Ref : %03.3f, Late              Compensated = %03.3f ( %0.3f A/V buffers=%02d/%02d), Clk : %f, State %d", (float)RefTime.Millisecs()/1000.0f, (float)cRefTime.Millisecs()/1000.0f, fTime,cntA,cntV, clock, m_pTsReaderFilter->State());
               }
-              if (ShowBuffer) ShowBuffer--;
+              if (m_pTsReaderFilter->m_ShowBufferAudio) m_pTsReaderFilter->m_ShowBufferAudio--;
             }
           }
           else
Index: DeMultiplexer.cpp
===================================================================
--- DeMultiplexer.cpp	(revision 27941)
+++ DeMultiplexer.cpp	(working copy)
@@ -802,7 +802,11 @@
   if (m_pids.PcrPid==0) return;
 
   if (header.Pid==0) return;
-  if (header.TScrambling) return;
+    
+  // 'TScrambling' check commented out - headers are never scrambled, 
+  // so it's safe to detect scrambled payload at PES level (in FillVideo()/FillAudio())
+  
+  //if (header.TScrambling) return;
 
   //skip any packets with errors in it
   if (header.TransportError) return;
@@ -896,7 +900,9 @@
     {
       CBuffer *Cbuf=*m_t_vecAudioBuffers.begin();
       byte *p = Cbuf->Data() ;
-      if ((p[0]==0) && (p[1]==0) && (p[2]==1))
+      if ((p[0]==0) && (p[1]==0) && (p[2]==1) //Valid start code
+          && ((p[3] & 0x80)!=0)  //Valid stream ID
+          && ((p[6] & 0xE0)==0x80)) //Valid marker bits and payload not scrambled
       {
         //get pts/dts from pes header
         CPcr pts;
@@ -1116,7 +1122,8 @@
       return;
     }  
     
-    if ((start[0]!=0) || (start[1]!=0) || (start[2]!=1))
+    if ((start[0]!=0) || (start[1]!=0) || (start[2]!=1) //Invalid start code
+        || ((start[3] & 0x80)==0)) //Invalid stream ID
     {
       LogDebug("Pes 0-0-1 fail");
       m_VideoValidPES=false;
@@ -1132,6 +1139,10 @@
       }
       else
       { // full PES header is available.
+      	if ((start[6] & 0xE0)==0xA0) //Valid marker bits and payload scrambled
+      	{
+          return;
+      	}
         CPcr pts;
         CPcr dts;
       
@@ -1414,7 +1425,8 @@
       return;
     }  
     
-    if ((start[0]!=0) || (start[1]!=0) || (start[2]!=1))
+    if ((start[0]!=0) || (start[1]!=0) || (start[2]!=1) //Invalid start code
+        || ((start[3] & 0x80)==0)) //Invalid stream ID
     {
       LogDebug("Pes 0-0-1 fail");
       m_VideoValidPES=false;
@@ -1430,6 +1442,10 @@
       }
       else
       { // full PES header is available.
+      	if ((start[6] & 0xE0)==0xA0) //Valid marker bits and payload scrambled
+      	{
+          return;
+      	}
         CPcr pts;
         CPcr dts;
       
@@ -1640,6 +1656,10 @@
               }
             }
           }  
+          else
+          {
+            m_bSetVideoDiscontinuity = true;
+          }
           m_VideoValidPES=true ;                                    // We've just completed a frame, set flag until problem clears it 
           m_pl.RemoveAll() ;                                        
         }
@@ -1666,6 +1686,7 @@
 /// if so store it in the subtitle buffers
 void CDeMultiplexer::FillSubtitle(CTsHeader& header, byte* tsPacket)
 {
+  if (header.TScrambling) return;
   if (m_filter.GetSubtitlePin()->IsConnected()==false) return;
   if (m_iSubtitleStream<0 || m_iSubtitleStream>=m_subtitleStreams.size()) return;
 
@@ -1717,6 +1738,7 @@
 
 void CDeMultiplexer::FillTeletext(CTsHeader& header, byte* tsPacket)
 {
+  if (header.TScrambling) return;
   if (m_pids.TeletextPid==0) return;
   if (header.Pid!=m_pids.TeletextPid) return;
   if ( header.AdaptionFieldOnly() ) return;
Index: TsReader.cpp
===================================================================
--- TsReader.cpp	(revision 27941)
+++ TsReader.cpp	(working copy)
@@ -170,8 +170,9 @@
   TCHAR filename[1024];
   GetLogFile(filename);
   ::DeleteFile(filename);
-  LogDebug("--------- Fast forward debug ---------");
-  LogDebug("-------------- v0.4.7 ----------------");
+  LogDebug("---- FFDShow A/V sync fix ------------");
+  LogDebug("---- Relaxed scrambling mod ----------");
+  LogDebug("---------- v0.4.10 -------------------");
 
   m_fileReader=NULL;
   m_fileDuration=NULL;
@@ -223,6 +224,11 @@
   m_bForceSeekOnStop=false ;
   m_bForceSeekAfterRateChange=false ;
   m_bSeekAfterRcDone=false ;
+  m_videoDecoderCLSID=GUID_NULL;
+  m_bFastSyncFFDShow=false;
+  m_ShowBufferAudio = INIT_SHOWBUFFERAUDIO;
+  m_ShowBufferVideo = INIT_SHOWBUFFERVIDEO;
+  
   m_MPmainThreadID = GetCurrentThreadId() ;
 }
 
@@ -356,7 +362,7 @@
   return S_OK;
 }
 
-extern int ShowBuffer;
+
 STDMETHODIMP CTsReaderFilter::SetRelaxedMode(BOOL relaxedReading)
 {
   LogDebug("SetRelaxedMode");
@@ -415,7 +421,8 @@
     LogDebug("Elapsed time from pause to Audio/Video ( total zapping time ) : %d mS",GetTickCount()-m_lastPause);
   }
  
-  ShowBuffer=40;
+  m_ShowBufferVideo = INIT_SHOWBUFFERVIDEO;
+  m_ShowBufferAudio = INIT_SHOWBUFFERAUDIO;
 
   CAutoLock cObjectLock(m_pLock);
 
@@ -502,10 +509,13 @@
 {
   return m_bTimeShifting;
 }
-extern int ShowBuffer;
+
+
 STDMETHODIMP CTsReaderFilter::Pause()
 {
-  ShowBuffer=100 ;
+  //m_ShowBufferVideo = INIT_SHOWBUFFERVIDEO;
+  //m_ShowBufferAudio = INIT_SHOWBUFFERAUDIO;
+
   LogDebug("CTsReaderFilter::Pause() - IsTimeShifting = %d - state = %d", IsTimeShifting(), m_State);
   CAutoLock cObjectLock(m_pLock);
 
@@ -1550,6 +1560,29 @@
   *pMediaPos = (m_MediaPos + m_LastTime - m_BaseTime) ;
   return ; 
 }
+
+//----------------------------------------------------
+// Derived from FFDShow code
+CLSID CTsReaderFilter::GetCLSIDFromPin(IPin* pPin)
+{
+  if (!pPin) 
+  {
+    return GUID_NULL;
+  }
+  CLSID clsid=GUID_NULL;
+  PIN_INFO pi;
+  if (SUCCEEDED(pPin->QueryPinInfo(&pi))) 
+  {
+    if (pi.pFilter) // IBaseFilter pointer
+    {
+      pi.pFilter->GetClassID(&clsid);
+      pi.pFilter->Release();
+    }
+  }
+  return clsid;
+}
+
+
 ////////////////////////////////////////////////////////////////////////
 //
 // Exported entry points for registration and unregistration
Index: TsReader.h
===================================================================
--- TsReader.h	(revision 27941)
+++ TsReader.h	(working copy)
@@ -32,6 +32,10 @@
 #include "IAudioStream.h"
 #include "ITeletextSource.h"
 #include <map>
+
+#define INIT_SHOWBUFFERVIDEO 20
+#define INIT_SHOWBUFFERAUDIO 5
+
 using namespace std;
 
 class CSubtitlePin;
@@ -44,6 +48,15 @@
 DEFINE_GUID(IID_ITSReader, 0xb9559486, 0xe1bb, 0x45d3, 0xa2, 0xa2, 0x9a, 0x7a, 0xfe, 0x49, 0xb2, 0x4f);
 //DEFINE_GUID(IID_ITSReaderAudioChange, 0xb9559486, 0xe1bb, 0x45d3, 0xa2, 0xa2, 0x9a, 0x7a, 0xfe, 0x49, 0xb2, 0x5f);
 
+// CLSIDs used to identify connected filters
+// {04FE9017-F873-410e-871E-AB91661A4EF7}
+DEFINE_GUID(CLSID_FFDSHOWVIDEO, 0x04fe9017, 0xf873, 0x410e, 0x87, 0x1e, 0xab, 0x91, 0x66, 0x1a, 0x4e, 0xf7);
+// {0B390488-D80F-4a68-8408-48DC199F0E97}
+DEFINE_GUID(CLSID_FFDSHOWDXVA, 0xb0eff97, 0xc750, 0x462c, 0x94, 0x88, 0xb1, 0xe, 0x7d, 0x87, 0xf1, 0xa6);
+// {DBF9000E-F08C-4858-B769-C914A0FBB1D7}
+DEFINE_GUID(CLSID_FFDSHOWSUBTITLES, 0xdbf9000e, 0xf08c, 0x4858, 0xb7, 0x69, 0xc9, 0x14, 0xa0, 0xfb, 0xb1, 0xd7);
+
+
 DECLARE_INTERFACE_(ITSReaderCallback, IUnknown)
 {
 	STDMETHOD(OnMediaTypeChanged) (int mediaTypes)PURE;	
@@ -186,6 +199,14 @@
   bool            m_bForceSeekAfterRateChange;
   bool            m_bSeekAfterRcDone;
 
+  int             m_ShowBufferAudio;
+  int             m_ShowBufferVideo;
+
+  CLSID           m_videoDecoderCLSID;
+  bool            m_bFastSyncFFDShow;
+
+  CLSID           GetCLSIDFromPin(IPin* pPin);
+
 protected:
   void ThreadProc();
 
Index: VideoPin.cpp
===================================================================
--- VideoPin.cpp	(revision 27941)
+++ VideoPin.cpp	(working copy)
@@ -125,14 +125,32 @@
   //LogDebug("vid:CheckConnect()");
   return CBaseOutputPin::CheckConnect(pReceivePin);
 }
+
+
 HRESULT CVideoPin::CompleteConnect(IPin *pReceivePin)
 {
-  //LogDebug("vid:CompleteConnect()");
   HRESULT hr = CBaseOutputPin::CompleteConnect(pReceivePin);
   if (SUCCEEDED(hr))
   {
+    CLSID &ref=m_pTsReaderFilter->GetCLSIDFromPin(pReceivePin);
+    m_pTsReaderFilter->m_videoDecoderCLSID = ref;
+    if (m_pTsReaderFilter->m_videoDecoderCLSID == CLSID_FFDSHOWVIDEO)
+    {
+      m_pTsReaderFilter->m_bFastSyncFFDShow=true;
+      LogDebug("vid:CompleteConnect() FFDShow Video Decoder connected, fast sync enabled");
+    }
+    else if (m_pTsReaderFilter->m_videoDecoderCLSID == CLSID_FFDSHOWDXVA)
+    {
+      m_pTsReaderFilter->m_bFastSyncFFDShow=true;
+      LogDebug("vid:CompleteConnect() FFDShow DXVA Video Decoder connected, fast sync enabled");
+    }
+    else
+    {
+      m_pTsReaderFilter->m_bFastSyncFFDShow=false;
+    }
+    
+    m_bConnected=true;    
     LogDebug("vid:CompleteConnect() done");
-    m_bConnected=true;
   }
   else
   {
@@ -245,7 +263,6 @@
   return S_FALSE;
 }
 
-int ShowBuffer=100;
 
 HRESULT CVideoPin::FillBuffer(IMediaSample *pSample)
 {
@@ -264,7 +281,7 @@
       //we dont try to read any packets, but simply return...
       if (m_pTsReaderFilter->IsSeeking() || m_pTsReaderFilter->IsStopping()) //|| m_bSeeking*/ || m_pTsReaderFilter->IsSeekingToEof())
       {
-        //if (ShowBuffer) LogDebug("vid:isseeking:%d %d",m_pTsReaderFilter->IsSeeking() ,m_bSeeking);
+        //if (m_pTsReaderFilter->m_ShowBufferVideo) LogDebug("vid:isseeking:%d %d",m_pTsReaderFilter->IsSeeking() ,m_bSeeking);
         Sleep(5);
         pSample->SetActualDataLength(0);
         return NOERROR;
@@ -304,30 +321,29 @@
           cRefTime -= m_rtStart;
           //adjust the timestamp with the compensation
           cRefTime -= m_pTsReaderFilter->Compensation;
-          cRefTime -= AddOffset;
-          cRefTime -= m_pTsReaderFilter->m_ClockOnStart.m_time;
 
-          CRefTime Dur;
-          Dur = (m_pTsReaderFilter->AddVideoComp.m_time * DRIFT_RATE);
+          //CRefTime Dur;
+          //Dur = (m_pTsReaderFilter->AddVideoComp.m_time * DRIFT_RATE);
 
-          if (cRefTime.m_time < (m_pTsReaderFilter->AddVideoComp.m_time * DRIFT_RATE))
+          if (!m_pTsReaderFilter->m_bFastSyncFFDShow && (cRefTime.m_time < (m_pTsReaderFilter->AddVideoComp.m_time * DRIFT_RATE)) )
           {
             // Ambass : try to stretch video after zapping
+            cRefTime -= AddOffset;
+            cRefTime -= m_pTsReaderFilter->m_ClockOnStart.m_time;
             AddOffset = cRefTime.m_time / DRIFT_RATE;
             // LogDebug("%03.3f, %03.3f, %03.3f", (float)AddOffset.Millisecs()/1000.0f,(float)cRefTime.Millisecs()/1000.0f, (float)m_pTsReaderFilter->AddVideoComp.Millisecs()/1000.0f);
             // m_pTsReaderFilter->AddVideoComp.m_time =0;
+            cRefTime += AddOffset;
+            cRefTime += m_pTsReaderFilter->m_ClockOnStart.m_time;
           }
-
-          cRefTime += AddOffset;
-          cRefTime += m_pTsReaderFilter->m_ClockOnStart.m_time;
                                                                       
           if (cRefTime.m_time >= 0)
+          {
             Sleep(1); // Ambass : avoid blocking audio FillBuffer method ( on audio/video starting ) by excessive video Fill buffer preemption
+          }
+
           m_bPresentSample = true;
-          //else
-          // Sample is too late.
-          //m_ShowSample = false ;
-       }
+        }
 
         if (m_bPresentSample)
         {
@@ -346,17 +362,44 @@
             //now we have the final timestamp, set timestamp in sample
             REFERENCE_TIME refTime=(REFERENCE_TIME)cRefTime;
             pSample->SetSyncPoint(TRUE);
+            
+            bool stsDiscon = TimestampDisconChecker(refTime); //Update with current timestamp
 
             refTime /= m_dRateSeeking;
             pSample->SetTime(&refTime,&refTime);
             if (m_dRateSeeking == 1.0)
             {
+              if (m_pTsReaderFilter->m_bFastSyncFFDShow)
+              {
+                if (stsDiscon || (pSample->IsDiscontinuity()==S_OK))
+                {
+                   pSample->SetDiscontinuity(TRUE);
+                   m_delayedDiscont = 2;
+                }
+  
+                if ((m_delayedDiscont > 0) && (buffer->GetFrameType() == 'I'))
+                {
+                  if ((buffer->GetVideoServiceType() == SERVICE_TYPE_VIDEO_MPEG1 ||
+                       buffer->GetVideoServiceType() == SERVICE_TYPE_VIDEO_MPEG2))
+                  {
+                     //Use delayed discontinuity
+                     pSample->SetDiscontinuity(TRUE);
+                     m_delayedDiscont--;
+                     LogDebug("vid:set I-frame discontinuity");
+                  }
+                  else
+                  {
+                     m_delayedDiscont = 0;
+                  }      
+                }                
+              }
+              
               REFERENCE_TIME RefClock = 0;
               m_pTsReaderFilter->GetMediaPosition(&RefClock) ;
               float clock = (double)(RefClock-m_rtStart.m_time)/10000000.0 ;
               float fTime=(float)cRefTime.Millisecs()/1000.0f - clock ;
 
-              if (ShowBuffer || fTime < 0.030)
+              if (m_pTsReaderFilter->m_ShowBufferVideo || fTime < 0.030)
               {
                 int cntA, cntV;
                 CRefTime firstAudio, lastAudio;
@@ -364,9 +407,10 @@
                 cntA = demux.GetAudioBufferPts(firstAudio, lastAudio); 
                 cntV = demux.GetVideoBufferPts(firstVideo, lastVideo) + 1;
 
-                LogDebug("Vid/Ref : %03.3f, Late %c-frame(%02d), Compensated = %03.3f ( %0.3f A/V buffers=%02d/%02d), Clk : %f, State %d", (float)RefTime.Millisecs()/1000.0f,buffer->GetFrameType(),buffer->GetFrameCount(), (float)cRefTime.Millisecs()/1000.0f, fTime, cntA,cntV,clock, m_pTsReaderFilter->State());
-								}
-              if (ShowBuffer) ShowBuffer--;
+                LogDebug("Vid/Ref : %03.3f, Late %c-frame(%02d), Compensated = %03.3f ( %0.3f A/V buffers=%02d/%02d), Clk : %f, State %d, TsMeanDiff %0.3f ms", (float)RefTime.Millisecs()/1000.0f,buffer->GetFrameType(),buffer->GetFrameCount(), (float)cRefTime.Millisecs()/1000.0f, fTime, cntA,cntV,clock, m_pTsReaderFilter->State(), (float)m_fMTDMean/10000.0f);
+              }
+              
+              if (m_pTsReaderFilter->m_ShowBufferVideo) m_pTsReaderFilter->m_ShowBufferVideo--;
             }
           }
           else
@@ -402,6 +446,48 @@
   return NOERROR;
 }
 
+// Check for timestamp discontinuities
+bool CVideoPin::TimestampDisconChecker(REFERENCE_TIME timeStamp)
+{
+  bool mtdDiscontinuity = false;
+  REFERENCE_TIME stsDiff = timeStamp - m_llLastMTDts;
+  m_llLastMTDts = timeStamp;
+        
+    // Calculate the mean timestamp difference
+  if (m_nNextMTD >= NB_MTDSIZE)
+  {
+    m_fMTDMean = m_llMTDSumAvg / (REFERENCE_TIME)NB_MTDSIZE;
+  }
+  else if (m_nNextMTD > 0)
+  {
+    m_fMTDMean = m_llMTDSumAvg / (REFERENCE_TIME)m_nNextMTD;
+  }
+  else
+  {
+    m_fMTDMean = stsDiff;
+  }
+
+    // Check for discontinuity
+  if (stsDiff > (m_fMTDMean + (300 * 10000))) // diff - mean > 300ms
+  {
+    mtdDiscontinuity = true;
+    LogDebug("vid:Timestamp discontinuity, TsDiff %0.3f ms, TsMeanDiff %0.3f ms, samples %d", (float)stsDiff/10000.0f, (float)m_fMTDMean/10000.0f, m_nNextMTD);
+  }
+
+    // Update the rolling timestamp difference sum
+    // (these values are initialised in OnThreadStartPlay())
+  int tempNextMTD = (m_nNextMTD % NB_MTDSIZE);
+  m_llMTDSumAvg -= m_pllMTD[tempNextMTD];
+  m_pllMTD[tempNextMTD] = stsDiff;
+  m_llMTDSumAvg += stsDiff;
+  m_nNextMTD++;
+  
+  //LogDebug("vid:TimestampDisconChecker, nextMTD %d, TsMeanDiff %0.3f, stsDiff %0.3f", m_nNextMTD, (float)m_fMTDMean/10000.0f, (float)stsDiff/10000.0f);
+  
+  return mtdDiscontinuity;
+}
+
+
 //******************************************************
 /// Called when thread is about to start delivering data to the codec
 ///
@@ -411,7 +497,14 @@
   //is not belonging to any previous data
   m_bDiscontinuity=TRUE;
   m_bPresentSample=false;
+  m_delayedDiscont = 0;
 
+  m_llLastMTDts = 0;
+  m_nNextMTD = 0;
+	m_fMTDMean = 0;
+	m_llMTDSumAvg = 0;
+  ZeroMemory((void*)&m_pllMTD, sizeof(REFERENCE_TIME) * NB_MTDSIZE);
+
   LogDebug("vid:OnThreadStartPlay(%f) %02.2f %d", (float)m_rtStart.Millisecs()/1000.0f,m_dRateSeeking,m_pTsReaderFilter->IsSeeking());
 
   //start playing
@@ -437,6 +530,12 @@
     m_dRateSeeking = 1.0;  // Reset to a reasonable value.
     return E_FAIL;
   }
+  if( m_dRateSeeking > 2.0 && m_pTsReaderFilter->m_videoDecoderCLSID == CLSID_FFDSHOWVIDEO)
+  {
+    //FFDShow video decoder doesn't handle rate > 2.0 properly
+    m_dRateSeeking = 1.0;  // Reset to a reasonable value.
+    return E_FAIL;
+  }
   LogDebug("vid: ChangeRate, m_dRateSeeking %f, Force seek done %d",(float)m_dRateSeeking, m_pTsReaderFilter->m_bSeekAfterRcDone);
   if (!m_pTsReaderFilter->m_bSeekAfterRcDone) //Don't force seek if another pin has already triggered it
   {
Index: VideoPin.h
===================================================================
--- VideoPin.h	(revision 27941)
+++ VideoPin.h	(working copy)
@@ -23,6 +23,8 @@
 #define __VideoPin_H
 #include "tsreader.h"
 
+#define NB_MTDSIZE 32
+
 class CVideoPin : public CSourceStream, public CSourceSeeking
 {
 public:
@@ -39,6 +41,7 @@
   HRESULT FillBuffer(IMediaSample *pSample);
   HRESULT BreakConnect();
 
+
   HRESULT DoBufferProcessingLoop(void);
 
   // CSourceSeeking
@@ -66,6 +69,17 @@
   bool      m_bPresentSample;
 
   FILTER_INFO m_filterInfo;
+  
+  int      m_delayedDiscont;
+ 
+  bool TimestampDisconChecker(REFERENCE_TIME timeStamp);
+    
+  REFERENCE_TIME  m_pllMTD [NB_MTDSIZE];   // timestamp buffer for average Video sample timestamp calculation
+  REFERENCE_TIME  m_llLastMTDts;
+  int             m_nNextMTD;
+	REFERENCE_TIME  m_fMTDMean;
+	REFERENCE_TIME  m_llMTDSumAvg;	
+
 };
 
 #endif
