Index: DeMultiplexer.cpp
===================================================================
--- DeMultiplexer.cpp	(revision 28131)
+++ DeMultiplexer.cpp	(working copy)
@@ -52,9 +52,7 @@
 // *** UNCOMMENT THE NEXT LINE TO ENABLE DYNAMIC VIDEO PIN HANDLING!!!! ******
 #define USE_DYNAMIC_PINS
 
-extern int ShowBuffer;
 
-
 CDeMultiplexer::CDeMultiplexer(CTsDuration& duration,CTsReaderFilter& filter)
 :m_duration(duration)
 ,m_filter(filter)
@@ -87,7 +85,12 @@
   m_iAudioReadCount = 0;
   m_lastVideoPTS.IsValid = false;
   m_lastAudioPTS.IsValid = false;
+  m_bFlushOnPTSJump = false;
+  m_bFlushOnPESError = false;
+  m_bHoldFileRead = false; 
   m_mpegParserTriggerFormatChange = false;
+  m_videoChanged=false;
+  m_audioChanged=false;
   SetMediaChanging(false);
   SetAudioChanging(false);
   m_DisableDiscontinuitiesFiltering = false;
@@ -397,13 +400,16 @@
   m_FirstVideoSample = 0x7FFFFFFF00000000LL;
   m_LastVideoSample = 0;
   m_lastVideoPTS.IsValid = false;
-  m_VideoValidPES = true;
+  m_VideoValidPES = false;
   m_mVideoValidPES = false;
   m_WaitHeaderPES=-1 ;
   m_bVideoAtEof=false;
   m_MinVideoDelta = 10.0 ;
   m_filter.m_bRenderingClockTooFast=false ;
-
+  m_bFlushOnPTSJump = false;
+  m_bFlushOnPESError = false;
+  m_bSetVideoDiscontinuity=true;
+  
   Reset();  // PacketSync reset.
 }
 
@@ -437,7 +443,10 @@
   m_bAudioAtEof = false;
   m_MinAudioDelta = 10.0;
   m_filter.m_bRenderingClockTooFast=false;
-
+  m_bFlushOnPTSJump = false;
+  m_bFlushOnPESError = false;
+  m_bSetAudioDiscontinuity=true;
+  
   Reset();  // PacketSync reset.
 }
 
@@ -461,6 +470,9 @@
 {
   LogDebug("demux:flushing");
 
+  m_bHoldFileRead = true; //Stop file reads in ReadFromFile()
+  CAutoLock lock (&m_sectionRead);
+
   m_iAudioReadCount = 0;
   m_LastDataFromRtsp = GetTickCount();
   bool holdAudio = HoldAudio();
@@ -475,6 +487,7 @@
   SetHoldAudio(holdAudio);
   SetHoldVideo(holdVideo);
   SetHoldSubtitle(holdSubtitle);
+  m_bHoldFileRead = false;
 }
 
 ///
@@ -620,6 +633,8 @@
   m_bStarting=true ;
   m_receivedPackets=0;
   m_mpegParserTriggerFormatChange=false;
+  m_videoChanged=false;
+  m_audioChanged=false;
   m_bEndOfFile=false;
   m_bHoldAudio=false;
   m_bHoldVideo=false;
@@ -633,6 +648,7 @@
   {
     int BytesRead =ReadFromFile(false,false);
     if (BytesRead==0) Sleep(10);
+	  // LogDebug("demux:Start() BytesRead:%d, BytesProcessed:%d", BytesRead, dwBytesProcessed);
     if (dwBytesProcessed>INITIAL_READ_SIZE || GetAudioStreamCount()>0)
     {
       #ifdef USE_DYNAMIC_PINS
@@ -647,6 +663,7 @@
       Flush();
       m_streamPcr.Reset();
       m_bStarting=false;
+	    LogDebug("demux:Start() end1 BytesProcessed:%d", dwBytesProcessed);
       return;
     }
     dwBytesProcessed+=BytesRead;
@@ -654,6 +671,7 @@
   m_streamPcr.Reset();
   m_iAudioReadCount=0;
   m_bStarting=false;
+	LogDebug("demux:Start() end2 BytesProcessed:%d", dwBytesProcessed);
 }
 
 void CDeMultiplexer::SetEndOfFile(bool bEndOfFile)
@@ -674,7 +692,8 @@
 {
 //  if (m_bWeos) return 0 ;
 //  if (IsAudioChanging()) return 0 ;          // Do not read any data during stream selection from MP C#
-  if (m_filter.IsSeeking()) return 0;       // Ambass : to check
+  if (m_filter.IsSeeking() || m_bHoldFileRead) return 0;       // Ambass : to check
+    
   CAutoLock lock (&m_sectionRead);
   if (m_reader==NULL) return false;
   byte buffer[READ_SIZE];
@@ -773,6 +792,7 @@
 ///  - decode any audio/video packets and put the PES packets in the appropiate buffers
 void CDeMultiplexer::OnTsPacket(byte* tsPacket)
 {
+  //LogDebug("OnTsPacket() start");
   CTsHeader header(tsPacket);
 
   m_patParser.OnTsPacket(tsPacket);
@@ -847,10 +867,16 @@
     return;
   }
 
+//  //process the ts packet further
+//  FillSubtitle(header,tsPacket);
+//  FillAudio(header,tsPacket);
+//  FillVideo(header,tsPacket);
+//  FillTeletext(header,tsPacket);
+
   //process the ts packet further
+  FillVideo(header,tsPacket);
+  FillAudio(header,tsPacket);
   FillSubtitle(header,tsPacket);
-  FillAudio(header,tsPacket);
-  FillVideo(header,tsPacket);
   FillTeletext(header,tsPacket);
 }
 
@@ -879,7 +905,10 @@
   if(!CheckContinuity(m_AudioPrevCC, header))
   {
     LogDebug("Audio Continuity error... %x ( prev %x )", header.ContinuityCounter, m_AudioPrevCC);
-    if (!m_DisableDiscontinuitiesFiltering) m_AudioValidPES=false;  
+    if (!m_DisableDiscontinuitiesFiltering) 
+    {
+      m_AudioValidPES=false;  
+    }
   }
 
   m_AudioPrevCC = header.ContinuityCounter;
@@ -888,7 +917,26 @@
   //does tspacket contain the start of a pes packet?
   if (header.PayloadUnitStart)
   {
-    //yes packet contains start of a pes packet.
+    //Sanity check PES header
+    int posn=header.PayLoadStart;
+    if (
+           ((tsPacket[posn+0]!=0) || (tsPacket[posn+1]!=0) || (tsPacket[posn+2]!=1)) //Invalid start code
+        || ((tsPacket[posn+3] & 0x80)==0)     //Invalid stream ID
+        || ((tsPacket[posn+6] & 0xC0)!=0x80)  //Invalid marker bits
+        || ((tsPacket[posn+6] & 0x20)==0x20)  //Payload scrambled
+       )
+    {
+      //Discard this new/current PES packet
+      m_AudioValidPES=false;  
+      m_bSetAudioDiscontinuity=true;
+      LogDebug("PES audio 0-0-1 fail");
+      //Flushing is delegated to CTsReaderFilter::ThreadProc()
+      m_bFlushOnPESError = true;
+      m_filter.WakeThead();  
+      return;
+    }
+    
+    //yes, packet contains start of a pes packet.
     //does current buffer hold any data ?
     if (m_pCurrentAudioBuffer->Length() > 0)
     {
@@ -896,18 +944,17 @@
       m_pCurrentAudioBuffer = new CBuffer();
     }
 
-    if (m_t_vecAudioBuffers.size())
+    if (m_t_vecAudioBuffers.size()) //Process the previous PES packet
     {
       CBuffer *Cbuf=*m_t_vecAudioBuffers.begin();
       byte *p = Cbuf->Data() ;
-      if ((p[0]==0) && (p[1]==0) && (p[2]==1) //Valid start code
-          && ((p[3] & 0x80)!=0)     //Valid stream ID
-          && ((p[6] & 0xC0)==0x80)  //Valid marker bits
-          && ((p[6] & 0x20)!=0x20)) //Payload not scrambled
+
+      if (m_AudioValidPES)
       {
         //get pts/dts from pes header
         CPcr pts;
         CPcr dts;
+        
         if (CPcr::DecodeFromPesHeader(p,0,pts,dts))
         {
           double diff;
@@ -917,10 +964,16 @@
             diff=m_lastAudioPTS.ToClock()-pts.ToClock();
           else
             diff=pts.ToClock()-m_lastAudioPTS.ToClock();
-          if (diff>10.0)
+          if (diff>2.0)
           {
+            //Large PTS jump - flush the world...
             LogDebug("DeMultiplexer::FillAudio pts jump found : %f %f, %f", (float) diff, (float)pts.ToClock(), (float)m_lastAudioPTS.ToClock());
-            m_AudioValidPES=false;
+            m_lastAudioPTS.IsValid=false;
+            m_lastVideoPTS.IsValid=false;
+            m_bSetAudioDiscontinuity=true;
+            //Flushing is delegated to CTsReaderFilter::ThreadProc()
+            m_bFlushOnPTSJump = true;
+            m_filter.WakeThead();            
           }
           else
           {
@@ -960,14 +1013,9 @@
         else
         {
           LogDebug(" No data");
-          m_AudioValidPES=false;
+          m_AudioValidPES=false; //stop further processing
         }
       }
-      else
-      {
-        LogDebug("Pes header 0-0-1 fail");
-        m_AudioValidPES=false;
-      }
 
       if (m_AudioValidPES)
       {
@@ -1012,7 +1060,7 @@
           delete *it;
           m_t_vecAudioBuffers.erase(it);
         }
-        m_bSetAudioDiscontinuity = true;
+        m_bSetAudioDiscontinuity = true; //Next good packet will be discontinuous
       }
     }
     m_AudioValidPES = true;     
@@ -1056,7 +1104,10 @@
   if (!CheckContinuity(m_VideoPrevCC, header))
   {
     LogDebug("Video Continuity error... %x ( prev %x )", header.ContinuityCounter, m_VideoPrevCC);
-    if (!m_DisableDiscontinuitiesFiltering) m_VideoValidPES = false;  
+    if (!m_DisableDiscontinuitiesFiltering)
+    {
+      m_VideoValidPES = false;  
+    }
   }
 
   m_VideoPrevCC = header.ContinuityCounter;
@@ -1072,7 +1123,6 @@
   }
   else
   {
-    //ParseVideoH264(header, tsPacket);
     FillVideoH264(header, tsPacket);
   }
 }
@@ -1120,13 +1170,23 @@
       return;
     }
 
-    if ((start[0]!=0) || (start[1]!=0) || (start[2]!=1) //Invalid start code
-        || ((start[3] & 0x80)==0)) //Invalid stream ID
+    if (
+           ((start[0]!=0) || (start[1]!=0) || (start[2]!=1)) //Invalid start code
+        || ((start[3] & 0x80)==0)    //Invalid stream ID
+      	|| ((start[6] & 0xC0)!=0x80) //Invalid marker bits
+        || ((start[6] & 0x20)==0x20) //Payload scrambled
+       )
     {
-      LogDebug("Pes 0-0-1 fail");
+      LogDebug("Pes H264 0-0-1 fail");
       m_VideoValidPES=false;
+      m_mVideoValidPES = false;
       m_p->rtStart = Packet::INVALID_TIME;
       m_WaitHeaderPES = -1;
+      m_bSetVideoDiscontinuity=true;
+      //Flushing is delegated to CTsReaderFilter::ThreadProc()
+      m_bFlushOnPESError = true;
+      m_filter.WakeThead();
+      return;
     }
     else
     {
@@ -1137,11 +1197,6 @@
       }
       else
       { // full PES header is available.
-      	if ((start[6] & 0xC0)!=0x80   //Invalid marker bits
-          || (start[6] & 0x20)==0x20) //Payload scrambled
-        {
-          return;
-      	}
         CPcr pts;
         CPcr dts;
 
@@ -1155,14 +1210,19 @@
             diff=m_lastVideoPTS.ToClock()-pts.ToClock();
           else
             diff=pts.ToClock()-m_lastVideoPTS.ToClock();
-          if (diff>10.0)
+          if (diff>2.0)
           {
-            LogDebug("DeMultiplexer::FillVideo pts jump found : %f %f, %f", (float) diff, (float)pts.ToClock(), (float)m_lastVideoPTS.ToClock());
-            m_VideoValidPES=false;
+            //Large PTS jump - flush the world...
+            LogDebug("DeMultiplexer::FillVideoH264 pts jump found : %f %f, %f", (float) diff, (float)pts.ToClock(), (float)m_lastVideoPTS.ToClock());
+            m_lastAudioPTS.IsValid=false;
+            m_lastVideoPTS.IsValid=false;
+            //Flushing is delegated to CTsReaderFilter::ThreadProc()
+            m_bFlushOnPTSJump = true;
+            m_filter.WakeThead();
           }
           else
           {
-            // LogDebug("DeMultiplexer::FillVideo pts : %f ", (float)pts.ToClock());
+            //LogDebug("DeMultiplexer::FillVideoH264 pts diff : %f ", (float)pts.ToClock());
             m_lastVideoPTS=pts;
           }
         }
@@ -1323,26 +1383,45 @@
             LogDebug("DeMultiplexer: %x video format changed: res=%dx%d aspectRatio=%d:%d fps=%d isInterlaced=%d",header.Pid,m_mpegPesParser->basicVideoInfo.width,m_mpegPesParser->basicVideoInfo.height,m_mpegPesParser->basicVideoInfo.arx,m_mpegPesParser->basicVideoInfo.ary,m_mpegPesParser->basicVideoInfo.fps,m_mpegPesParser->basicVideoInfo.isInterlaced);
             if (m_mpegParserTriggerFormatChange)
             {
-              LogDebug("DeMultiplexer: OnMediaFormatChange triggered by mpeg2Parser");
+              LogDebug("DeMultiplexer: OnMediaFormatChange triggered by mpeg2Parser, aud %d, vid 1", m_audioChanged);
               SetMediaChanging(true);
-              m_filter.OnMediaTypeChanged(3);
+              if (m_audioChanged)
+                m_filter.OnMediaTypeChanged(3); //Video and audio
+              else
+                m_filter.OnMediaTypeChanged(2); //Video only
               m_mpegParserTriggerFormatChange=false;
             }
             LogDebug("DeMultiplexer: triggering OnVideoFormatChanged");
             m_filter.OnVideoFormatChanged(m_mpegPesParser->basicVideoInfo.streamType,m_mpegPesParser->basicVideoInfo.width,m_mpegPesParser->basicVideoInfo.height,m_mpegPesParser->basicVideoInfo.arx,m_mpegPesParser->basicVideoInfo.ary,15000000,m_mpegPesParser->basicVideoInfo.isInterlaced);
           }
-          else
+          else //video resolution is the unchanged, but there may be other format changes
           {
             if (m_mpegParserTriggerFormatChange && Gop)
             {
-              LogDebug("DeMultiplexer: Got GOP after the channel change was detected without correct mpeg header parsing, so we trigger the format change now.");
-              m_filter.OnMediaTypeChanged(3);
+              if (m_audioChanged || m_videoChanged)
+              {
+                SetMediaChanging(true);
+                LogDebug("DeMultiplexer: Got GOP after channel change detected, trigger format change, aud %d, vid %d", m_audioChanged, m_videoChanged);
+                if (m_audioChanged && m_videoChanged)
+                  m_filter.OnMediaTypeChanged(3);
+                else if (m_audioChanged)
+                  m_filter.OnMediaTypeChanged(1);
+                else
+                  m_filter.OnMediaTypeChanged(2);
+              }
+              else
+              {
+                SetMediaChanging(false);
+              }
               m_mpegParserTriggerFormatChange=false;
             }
           }
         }
         else
+        {
           m_bSetVideoDiscontinuity = !m_mVideoValidPES;
+        }
+        
         m_pl.RemoveAll();
           
         p2->bDiscontinuity = m_p->bDiscontinuity; m_p->bDiscontinuity = FALSE;
@@ -1421,13 +1500,23 @@
       return;
     }
 
-    if ((start[0]!=0) || (start[1]!=0) || (start[2]!=1) //Invalid start code
-        || ((start[3] & 0x80)==0)) //Invalid stream ID
+    if (
+           ((start[0]!=0) || (start[1]!=0) || (start[2]!=1)) //Invalid start code
+        || ((start[3] & 0x80)==0)    //Invalid stream ID
+      	|| ((start[6] & 0xC0)!=0x80) //Invalid marker bits
+        || ((start[6] & 0x20)==0x20) //Payload scrambled
+       )
     {
-      LogDebug("Pes 0-0-1 fail");
-      m_VideoValidPES=false;
+      LogDebug("Pes MPEG2 0-0-1 fail");
+      m_VideoValidPES = false;
+      m_mVideoValidPES = false;
       m_p->rtStart = Packet::INVALID_TIME;
       m_WaitHeaderPES = -1;
+      m_bSetVideoDiscontinuity=true;
+      //Flushing is delegated to CTsReaderFilter::ThreadProc()
+      m_bFlushOnPESError = true;
+      m_filter.WakeThead();    
+      return;        
     }
     else
     {
@@ -1438,15 +1527,10 @@
       }
       else
       { // full PES header is available.
-      	if ((start[6] & 0xC0)!=0x80   //Invalid marker bits
-          || (start[6] & 0x20)==0x20) //Payload scrambled
-        {
-          return;
-      	}
         CPcr pts;
         CPcr dts;
 
-//      m_VideoValidPES=true ;
+        m_VideoValidPES=true ;
         if (CPcr::DecodeFromPesHeader(start,0,pts,dts))
         {
           double diff;
@@ -1456,10 +1540,15 @@
             diff=m_lastVideoPTS.ToClock()-pts.ToClock();
           else
             diff=pts.ToClock()-m_lastVideoPTS.ToClock();
-          if (diff>10.0)
+          if (diff>2.0)
           {
-            LogDebug("DeMultiplexer::FillVideo pts jump found : %f %f, %f", (float) diff, (float)pts.ToClock(), (float)m_lastVideoPTS.ToClock());
-            m_VideoValidPES=false;
+            //Large PTS jump - flush the world...
+            LogDebug("DeMultiplexer::FillVideoMPEG2 pts jump found : %f %f, %f", (float) diff, (float)pts.ToClock(), (float)m_lastVideoPTS.ToClock());
+            m_lastAudioPTS.IsValid=false;
+            m_lastVideoPTS.IsValid=false;
+            //Flushing is delegated to CTsReaderFilter::ThreadProc()
+            m_bFlushOnPTSJump = true;
+            m_filter.WakeThead();
           }
           else
           {
@@ -1536,7 +1625,7 @@
           m_pl.AddTail(p2);
 //          LogDebug("DeMultiplexer::FillVideo Frame length : %d %x %x", size, *(DWORD*)start, *(DWORD*)next);
 
-          if (m_VideoValidPES)
+          if (m_mVideoValidPES)
           {
             CAutoPtr<Packet> p(new Packet());
             p = m_pl.RemoveHead();
@@ -1635,29 +1724,45 @@
               LogDebug("DeMultiplexer: %x video format changed: res=%dx%d aspectRatio=%d:%d fps=%d isInterlaced=%d",header.Pid,m_mpegPesParser->basicVideoInfo.width,m_mpegPesParser->basicVideoInfo.height,m_mpegPesParser->basicVideoInfo.arx,m_mpegPesParser->basicVideoInfo.ary,m_mpegPesParser->basicVideoInfo.fps,m_mpegPesParser->basicVideoInfo.isInterlaced);
               if (m_mpegParserTriggerFormatChange)
               {
-                LogDebug("DeMultiplexer: OnMediaFormatChange triggered by mpeg2Parser");
+                LogDebug("DeMultiplexer: OnMediaFormatChange triggered by mpeg2Parser, aud %d, vid 1", m_audioChanged);
                 SetMediaChanging(true);
-                m_filter.OnMediaTypeChanged(3);
+                if (m_audioChanged)
+                  m_filter.OnMediaTypeChanged(3); //Video and audio
+                else
+                  m_filter.OnMediaTypeChanged(2); //Video only
                 m_mpegParserTriggerFormatChange=false;
               }
               LogDebug("DeMultiplexer: triggering OnVideoFormatChanged");
               m_filter.OnVideoFormatChanged(m_mpegPesParser->basicVideoInfo.streamType,m_mpegPesParser->basicVideoInfo.width,m_mpegPesParser->basicVideoInfo.height,m_mpegPesParser->basicVideoInfo.arx,m_mpegPesParser->basicVideoInfo.ary,15000000,m_mpegPesParser->basicVideoInfo.isInterlaced);
             }
-            else
+            else //video resolution is the unchanged, but there may be other format changes
             {
               if (m_mpegParserTriggerFormatChange && Gop)
               {
-                LogDebug("DeMultiplexer: Got GOP after the channel change was detected without correct mpeg header parsing, so we trigger the format change now.");
-                m_filter.OnMediaTypeChanged(3);
+                if (m_audioChanged || m_videoChanged)
+                {
+                  SetMediaChanging(true);
+                  LogDebug("DeMultiplexer: Got GOP after channel change detected, trigger format change, aud %d, vid %d", m_audioChanged, m_videoChanged);
+                  if (m_audioChanged && m_videoChanged)
+                    m_filter.OnMediaTypeChanged(3);
+                  else if (m_audioChanged)
+                    m_filter.OnMediaTypeChanged(1);
+                  else
+                    m_filter.OnMediaTypeChanged(2);
+                }
+                else
+                {
+                  SetMediaChanging(false);
+                }
                 m_mpegParserTriggerFormatChange=false;
               }
             }
           }
           else
           {
-            m_bSetVideoDiscontinuity = true;
+            m_bSetVideoDiscontinuity = !m_mVideoValidPES;
           }
-          m_VideoValidPES=true ;                                    // We've just completed a frame, set flag until problem clears it 
+          //m_VideoValidPES=true ;                                    // We've just completed a frame, set flag until problem clears it 
           m_pl.RemoveAll() ;                                        
         }
         else                                                        // sequence_header_code
@@ -1772,6 +1877,8 @@
 {
   //CAutoLock lock (&m_section);
   CPidTable pids=info.PidTable;
+  
+  //LogDebug("OnNewChannel callback, pat version:%d->%d",m_iPatVersion, info.PatVersion);
 
   if (info.PatVersion != m_iPatVersion)
   {
@@ -1860,22 +1967,35 @@
   }
 
   bool changed=false;
-  bool videoChanged=false;
+  m_videoChanged=false;
+  m_audioChanged=false;
+
+  #ifdef USE_DYNAMIC_PINS
+  //Is the video pin connected?
+  if ((m_filter.GetVideoPin()->IsConnected()) && (m_pids.videoPids.size() > 0))
+  {
+    changed=true; //force a check in the mpeg parser
+    if (oldVideoServiceType != m_pids.videoPids[0].VideoServiceType)
+    {
+      m_videoChanged=true;
+    }
+  }
+  #else
   //did the video format change?
-  if (m_pids.videoPids.size() > 0 && oldVideoServiceType != m_pids.videoPids[0].VideoServiceType )
+  if (m_pids.videoPids.size() > 0 && oldVideoServiceType != m_pids.videoPids[0].VideoServiceType)
   {
     //yes, is the video pin connected?
     if (m_filter.GetVideoPin()->IsConnected())
     {
       changed=true;
-      videoChanged=true;
+      m_videoChanged=true;
     }
   }
-
+  #endif
+  
   m_iAudioStream = 0;
 
   LogDebug ("Setting initial audio index to : %i", m_iAudioStream);
-  bool audioChanged=false;
 
   //get the new audio format
   int newAudioStreamType=SERVICE_TYPE_AUDIO_MPEG2;
@@ -1891,7 +2011,7 @@
     if (m_filter.GetAudioPin()->IsConnected())
     {
       changed=true;
-      audioChanged=true;
+      m_audioChanged=true;
     }
   }
 
@@ -1899,10 +2019,10 @@
   if (changed)
   {
     #ifdef USE_DYNAMIC_PINS
-    // if we have a video stream and it's format changed, let the mpeg parser trigger the OnMediaTypeChanged
-    if (m_pids.videoPids.size() > 0 && m_pids.videoPids[0].Pid>0x1 && videoChanged)  
+    // if we have a video stream, let the mpeg parser trigger the OnMediaTypeChanged
+    if (m_pids.videoPids.size() > 0 && m_pids.videoPids[0].Pid>0x1)  
     {
-      LogDebug("DeMultiplexer: We detected a new media type change which has a video stream, so we let the mpegParser trigger the event");
+      LogDebug("DeMultiplexer: We have a video stream, so we let the mpegParser check/trigger format changes");
       m_receivedPackets=0;
       m_mpegParserTriggerFormatChange=true;
       SetMediaChanging(true);
@@ -1922,10 +2042,10 @@
       }
     }
     #else
-    if (audioChanged && videoChanged)
+    if (m_audioChanged && m_videoChanged)
       m_filter.OnMediaTypeChanged(3);
     else
-      if (audioChanged)
+      if (m_audioChanged)
         m_filter.OnMediaTypeChanged(1);
       else
         m_filter.OnMediaTypeChanged(2);
Index: DeMultiplexer.h
===================================================================
--- DeMultiplexer.h	(revision 28131)
+++ DeMultiplexer.h	(working copy)
@@ -133,6 +133,9 @@
   bool m_DisableDiscontinuitiesFiltering;
   DWORD m_LastDataFromRtsp;
   bool m_bAudioVideoReady;
+  bool m_bFlushOnPTSJump;
+  bool m_bFlushOnPESError;
+  bool m_bHoldFileRead;
 
 private:
   struct stAudioStream
@@ -219,6 +222,8 @@
   bool m_bStarting;
 
   bool m_mpegParserTriggerFormatChange;
+  bool m_videoChanged;
+  bool m_audioChanged;
   bool m_bSetAudioDiscontinuity;
   bool m_bSetVideoDiscontinuity;
   CPcr m_subtitlePcr;
Index: TsReader.cpp
===================================================================
--- TsReader.cpp	(revision 28131)
+++ TsReader.cpp	(working copy)
@@ -170,7 +170,8 @@
   TCHAR filename[1024];
   GetLogFile(filename);
   ::DeleteFile(filename);
-  LogDebug("---------- v0.4.12 -------------------");
+  LogDebug("----- Continue after corruption testing ---------");
+  LogDebug("---------- v0.4.19 XXX -------------------");
 
   m_fileReader=NULL;
   m_fileDuration=NULL;
@@ -1136,7 +1137,9 @@
 /// Every second it will check the stream or local file and determine the total duration of the file/stream
 /// The duration can/will grow if we are playing a timeshifting buffer/stream
 //  If the duration has changed it will update m_duration and send a EC_LENGTH_CHANGED event
-//  to the graph
+//  to the graph.
+//  Flushing after large video/audio PTS jump and PES '0-0-1 fail' errors 
+//  are also delegated to this thread.
 void CTsReaderFilter::ThreadProc()
 {
   LogDebug("CTsReaderFilter::ThreadProc start()");
@@ -1152,6 +1155,39 @@
     //since we're no longer playing
     if (m_demultiplexer.EndOfFile())
       break;
+
+    //Flushing after a PES '0-0-1 fail' error is delegated to this thread
+    if (m_demultiplexer.m_bFlushOnPESError)
+    {
+      LogDebug("CTsReaderFilter::ThreadProc FlushOnPESError start");
+      m_demultiplexer.m_bFlushOnPESError = false;
+
+      //Flush the internal data
+      m_demultiplexer.Flush();
+      m_bStreamCompensated=false ;
+      m_demultiplexer.m_bAudioVideoReady=false ;
+
+      LogDebug("CTsReaderFilter::ThreadProc FlushOnPESError end");
+      Sleep(400);
+      continue;
+    }
+    
+    //Flushing after large video/audio PTS jump is delegated to this thread
+    if (m_demultiplexer.m_bFlushOnPTSJump)
+    {
+      LogDebug("CTsReaderFilter::ThreadProc FlushOnPTSJump start");
+      m_demultiplexer.m_bFlushOnPTSJump = false;
+      
+      //Flush the internal data
+      m_demultiplexer.Flush();
+      m_bStreamCompensated=false ;
+      m_demultiplexer.m_bAudioVideoReady=false ;
+  
+      LogDebug("CTsReaderFilter::ThreadProc FlushOnPTSJump end");
+      Sleep(400);
+      continue;
+    }
+      
     //are we playing an RTSP stream?
     if (m_fileDuration!=NULL)
     {
@@ -1251,6 +1287,7 @@
         }
       }
     }
+    
   }
   while (!ThreadIsStopping(1000)) ;
   LogDebug("CTsReaderFilter::ThreadProc stopped()");
Index: TSThread.cpp
===================================================================
--- TSThread.cpp	(revision 28131)
+++ TSThread.cpp	(working copy)
@@ -51,6 +51,7 @@
 {
 	m_hStopEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
 	m_hDoneEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+	m_hWakeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); //Auto-reset
 	m_threadHandle = INVALID_HANDLE_VALUE;
   m_bThreadRunning=FALSE;
 }
@@ -60,6 +61,7 @@
 	StopThread();
 	CloseHandle(m_hStopEvent);
 	CloseHandle(m_hDoneEvent);
+	CloseHandle(m_hWakeEvent);
 }
 
 
@@ -102,10 +104,34 @@
 	return hr;
 }
 
+void TSThread::WakeThead()
+{
+  if (m_bThreadRunning)
+  {
+	  SetEvent(m_hWakeEvent);
+	}  
+}
+
 BOOL TSThread::ThreadIsStopping(DWORD dwTimeoutMilliseconds)
 {
-	DWORD result = WaitForSingleObject(m_hStopEvent, dwTimeoutMilliseconds);
-	return (result != WAIT_TIMEOUT);
+  HANDLE hEvts[] = {m_hStopEvent, m_hWakeEvent};
+
+	DWORD result = WaitForMultipleObjects(2, hEvts, FALSE, dwTimeoutMilliseconds);
+  switch (result)
+  {
+    case WAIT_OBJECT_0 : //m_hStopEvent
+	    return true;
+      break;
+    case WAIT_OBJECT_0 + 1 : //m_hWakeEvent
+	    ResetEvent(m_hWakeEvent);
+	    return false;
+      break;
+    case WAIT_TIMEOUT : //Timeout
+	    return false;
+      break;
+    default : //Error conditions
+	    return true;      
+  }
 }
 
 void TSThread::InternalThreadProc()
Index: TSThread.h
===================================================================
--- TSThread.h	(revision 28131)
+++ TSThread.h	(working copy)
@@ -36,6 +36,7 @@
 	virtual void ThreadProc() = 0;
 	HRESULT StartThread();
 	HRESULT StopThread(DWORD dwTimeoutMilliseconds = 1000);
+  void WakeThead();
 
 	BOOL ThreadIsStopping(DWORD dwTimeoutMilliseconds = 10);
   BOOL IsThreadRunning();
@@ -43,6 +44,7 @@
 	virtual void InternalThreadProc();
 	HANDLE m_hDoneEvent;
 	HANDLE m_hStopEvent;
+	HANDLE m_hWakeEvent;
 
 private:
   BOOL   m_bThreadRunning;
