[PATCH] Rewrite of mpeg/ps2ts.cpp version 2 -- vls-cvs-ps2ts-2.patch

Andrew de Quincey <[email protected]> Tue, 12 Aug 2003 10:35:26 +0100
Newsgroups gmane.comp.video.videolan.vls.devel
Message-ID <[email protected]>
Whoops! forgot part of the patch. This one is the same as version 1, except:

tsstreamer.cpp now doesn't call WaitSendDate() the very first time. With the 
files I'm streaming, this was causing hangs 'cos the first time round, 
m_iLastTime is 0... so vls ends up sleeping for 57348557347843 seconds.
vls-cvs-ps2ts-2.patch (text/x-diff, 40.3 KB)
--- vls.orig/src/modules/ps2ts/ps2ts.cpp	2003-08-11 11:15:48.000000000 +0100
+++ vls/src/modules/ps2ts/ps2ts.cpp	2003-08-11 15:11:26.000000000 +0100
@@ -105,7 +105,8 @@
         C_MpegConverter(pModule, cConfig),
         m_cConverter(cConfig.m_pReader,
                      cConfig.m_pTsProvider, 2,
-                     cConfig.m_pBroadcast->GetOption("mpegversion").ToInt())
+                     cConfig.m_pBroadcast->GetOption("mpegversion").ToInt(),
+                     cConfig.m_pBroadcast->GetOption("loop").ToInt())
 {
   m_bPreParse = (cConfig.m_pBroadcast->GetOption("preparse") == "1");
 
@@ -133,14 +134,13 @@
   C_MpegConverter::InitWork();
 
   m_cConverter.Synch();
-
   if(m_bPreParse)
   {
     for(unsigned int i = 0; i < m_pReader->Size() / 188 / 256; i++)
     {
       // preparsing to make the PAT and the PMT
-      C_TsPacket* pPacket = m_cConverter.GetPacket();
-      ASSERT(pPacket);
+      C_TsPacket* pPacket = m_cConverter.GetPacket(true);
+      if (!pPacket) break;
       m_pTsProvider->ReleasePacket(pPacket);
     }
 
@@ -166,8 +166,9 @@
   switch(m_cConverter.GetStatus())
   {
   case 0:
-    if(!pPacket)
+    if(!pPacket) {
       iRc = MPEG_STREAMERROR;
+    }
     break;
   case -99:
     iRc = MPEG_ENDOFSTREAM;
--- vls.orig/src/modules/filereader/filereader.h	2003-08-11 11:15:48.000000000 +0100
+++ vls/src/modules/filereader/filereader.h	2003-08-11 13:00:04.000000000 +0100
@@ -49,6 +49,7 @@
   virtual s64 Seek(s64 iOffset, s64 bStartPos);
   virtual s64 Size();
   virtual s64 GetPos();
+  virtual void ResetEndOfStream();
 
 protected:
   C_File m_cFile;
--- vls.orig/src/modules/filereader/filereader.cpp	2003-08-11 11:15:48.000000000 +0100
+++ vls/src/modules/filereader/filereader.cpp	2003-08-11 16:49:10.000000000 +0100
@@ -80,7 +80,6 @@
                         m_cFile(pBroadcast->GetOption("filename"))
 {
   m_iLoop = pBroadcast->GetOption("loop").ToInt();
-  if(m_iLoop) m_iLoop--;
 
   if(pBroadcast->GetOption("end") == "1")
     m_bEnd = true;
@@ -123,13 +122,13 @@
   try 
   {
     s64 iRc = m_cFile.Read(pBuff, iSize);
-    // Loop on stream and set the discontinuity flag
-    if((iRc == FILE_EOF) && m_iLoop--)
-    {
-      m_cFile.Seek((s64)0, FILE_SEEK_BEGIN);
-      m_bDiscontinuity = true;
-      iRc = m_cFile.Read(pBuff, iSize);
+    
+    // check for end of stream
+    if ((iRc == FILE_EOF) || (iRc != iSize)) {
+      m_bEndOfStream = true;
+      iRc = 0;
     }
+    
     return iRc;
   }
   catch(E_File e)
@@ -138,6 +137,15 @@
   }
 }
 
+//------------------------------------------------------------------------------
+//
+//------------------------------------------------------------------------------
+void C_FileMpegReader::ResetEndOfStream()
+{
+  m_cFile.Seek((s64)0, FILE_SEEK_BEGIN);
+  m_bDiscontinuity = true;
+  m_bEndOfStream = false;
+}
 
 //------------------------------------------------------------------------------
 //
--- vls.orig/src/mpeg/reader.h	2003-08-11 11:15:48.000000000 +0100
+++ vls/src/mpeg/reader.h	2003-08-11 13:44:45.000000000 +0100
@@ -71,6 +71,11 @@
   void ResetDiscontinuity()
   { m_bDiscontinuity = false; };
 
+  virtual bool EndOfStream()
+  { return m_bEndOfStream; };
+  virtual void ResetEndOfStream()
+  { /* By default, this is not supported */ };
+   
 protected:
   C_Module* m_pModule;
 
@@ -80,6 +85,8 @@
 
   bool m_bDiscontinuity;
 
+  bool m_bEndOfStream;
+   
   handle m_hLog;
 };
 
--- vls.orig/src/mpeg/reader.cpp	2003-08-11 11:15:48.000000000 +0100
+++ vls/src/mpeg/reader.cpp	2003-08-11 16:48:55.000000000 +0100
@@ -63,6 +63,7 @@
   m_hLog = pModule->GetLogger();
 
   m_bDiscontinuity = false;
+  m_bEndOfStream = false;
 }
 
 
--- vls.orig/src/mpeg/ps2ts.cpp	2003-03-14 10:32:49.000000000 +0000
+++ vls/src/mpeg/ps2ts.cpp	2003-08-11 16:41:57.000000000 +0100
@@ -6,6 +6,7 @@
 *
 * Authors: Benoit Steiner <[email protected]>
 *          Arnaud de Bossoreille de Ribou <[email protected]>
+*          Andrew de Quincey <[email protected]>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
@@ -50,7 +51,8 @@
 template <class Reader, class TsProvider>
  C_Ps2Ts<Reader, TsProvider>::C_Ps2Ts(Reader* pReader, TsProvider* pTsProvider,
                                       unsigned int iMaxBufferedTs,
-                                      unsigned int iMpegVersion) :
+                                      unsigned int iMpegVersion,
+				      bool bLooping) :
                              m_cPgrmDescriptor(iMpegVersion),
                              m_cPat(0, 0, 0), m_cPmt(0, 0, 0, 0, 0x50),
                              m_cPendingTS(NO)
@@ -65,20 +67,23 @@
   m_iMaxBufferedTs = iMaxBufferedTs;
 
   m_iDataType = UNKNOWN_DATA;
+  m_iPrivateId = 0;
   m_iStatus = NO_ERR;
-  m_pDelayedPacket = NULL;
   m_bDiscontinuity = false;
 
-  ZERO(m_pCurrentData);
-
-  m_bSendPSI = m_bGenPat = m_bGenPmt = m_bResetPSI = true;
+  m_bSendPSI = m_bGenPat = m_bGenPmt = true;
   m_iTSCounter = 0;
-  m_iPrevSCR = 0;
+  m_bNeedToSendPCR = true;
+  m_iNextPCR = 0;
+  m_iPrevPCR = 0;
+  m_bLooping = bLooping;
+  m_bInMiddleOfPES = false;
+  m_bJustSynched = false;
   
   if(iMpegVersion == 1)
-    m_iPackHeaderLen = MPEG1_PACK_HEADER_LEN;
+    m_iPackHeaderLen = MPEG1_PACK_HEADER_LEN - START_CODE_LEN;
   else
-    m_iPackHeaderLen = MPEG2_PACK_HEADER_LEN;
+    m_iPackHeaderLen = MPEG2_PACK_HEADER_LEN - START_CODE_LEN;
 }
 
 
@@ -89,62 +94,62 @@
  C_Ps2Ts<Reader, TsProvider>::~C_Ps2Ts()
 {
   // The packets belong to the netlist, so don't delete them twice
-  for(unsigned int i = 0; i < m_cPendingTS.Size(); i++)
+  while(m_cPendingTS.Size() > 0)
   {
     C_TsPacket* pPacket = m_cPendingTS.Remove(0);
-    ASSERT(pPacket);
+    if (pPacket) {
     m_pTsProvider->ReleasePacket(pPacket);
   }
+  }
 }
 
 
 //------------------------------------------------------------------------------
 //
 //------------------------------------------------------------------------------
-// The data in the buffer can be anything: only rely on DataType and DataLen
+// The data in the buffer can be anything: only rely on DataType
 //------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
    int C_Ps2Ts<Reader, TsProvider>::Synch()
 {
-  int iRc = m_pReader->Read(m_bBuff, START_CODE_LEN);
-  ASSERT(iRc >= 0);
-  m_iStatus = (iRc != START_CODE_LEN);
-
-  unsigned int iPos = START_CODE_LEN;
-
-  // Check the last bytes read to look for a start code
-  while((U32_AT(m_bBuff[iPos-START_CODE_LEN]) != PES_H_PACK_HEADER) &&
-        !m_iStatus)
-  {
-    iRc = m_pReader->Read(m_bBuff+iPos, 1);
-    ASSERT(iRc >= 0);
-    m_iStatus = (iRc != 1);
+  int iRc;
+  u8 headerCode[4];
+  u64 startPos;
+   
+  // prefill the headercode
+  startPos = m_pReader->GetPos();
+  if (iRc = ReadData(headerCode, 3)) {
+    m_iStatus = iRc;
+    return m_iStatus;
+  }
 
-    iPos++;
-    if(iPos >= sizeof(m_bBuff))
-    {
-      printf("Looping in Synch !!!!!!!!! (buffer size=%d)\n", sizeof(m_bBuff));
-      memcpy(m_bBuff, &m_bBuff[sizeof(m_bBuff)-(START_CODE_LEN-1)],
-             (START_CODE_LEN-1));
-      iPos = START_CODE_LEN-1;
+  // loop, trying to find a PES_H_PACK_HEADER
+  while(true) {
+    // read the last byte of the headercode
+    if (iRc = ReadData(headerCode+3, 1)) {
+      m_iStatus = iRc;
+      break;
     }
+    
+    // found it?
+    if (U32_AT(headerCode) == PES_H_PACK_HEADER) {
+      m_bInMiddleOfPES = false;
+      m_bJustSynched = true;
+      m_bNeedToSendPCR = false;
+      m_iNextPCR = 0;
+      m_iPrevPCR = 0;
+      break;
   }
 
-  // Check the last bytes read to detect why we left the loop
-  if(U32_AT(m_bBuff[iPos-START_CODE_LEN]) != PES_H_PACK_HEADER)
-  {
-    // We left the while loop because of a read error
+    // OK, move the topmost 3 bytes into position
+    memcpy(headerCode, headerCode+1, 3);
+    
+    // just give up if we haven't found one within a reasonable distance
+    if ((m_pReader->GetPos() - startPos) > 1024 * 1024) {
+      printf("Failed to find a PACK_HEADER within 1Mb.\n");
     m_iStatus = GEN_ERR;
+      break;
   }
-  else
-  {
-    printf("Synchronised with PS stream\n");
-    m_iDataType = PES_H_PACK_HEADER;
-    iRc =  m_pReader->Read(m_bBuff+iPos, PES_SIZE_LEN);
-    ASSERT(iRc >= 0);
-    m_iStatus = (iRc != PES_SIZE_LEN);
-    m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
-    m_iDataLen = U16_AT(m_bBuff[iPos]);
   }
 
   return m_iStatus;
@@ -155,58 +160,44 @@
 //
 //------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
-   C_TsPacket* C_Ps2Ts<Reader, TsProvider>::GetPacket()
+   C_TsPacket* C_Ps2Ts<Reader, TsProvider>::GetPacket(bool bPreparsing)
 {
-  if(m_cPendingTS.Size() == 0)
-  {
-    if(!m_bSendPSI)
-    {
-      if(m_pDelayedPacket)
-      {
-        m_cPendingTS.PushEnd(m_pDelayedPacket);
-        m_pDelayedPacket = NULL;
-      }
-      else
-      {
-        int iRc = FetchPackets();
-        if(iRc && !m_bSendPSI)
-        {
-          do
-          {
-            if(iRc == UNKNOWN_DATA)
-            {
-              iRc = Synch();
-              if(!iRc)
-                iRc = FetchPackets();
-            }
-            else if(iRc == SKIPPED_DATA)
-              iRc = FetchPackets();
-          }
-          while((iRc == SKIPPED_DATA || iRc == UNKNOWN_DATA) && !m_bSendPSI);
-        }
-        else if(!m_bSendPSI)
-        {
-          // Check if we will have to insert PSI on the next iteration: we
-          // add the PSI in the stream every half second
-          // (For 1.5 Mbps streams, about 1000 TS packets are sent every second)
-          m_bSendPSI = m_bResetPSI = (m_iTSCounter % 500 <= m_iMaxBufferedTs);
-//          printf("mitscounter: %d\n", m_iTSCounter);
+  int iRc;
+  bool bStreamLooped = false;
+   
+  // if there's nothing left in the buffer. we need to fill it
+  if (m_cPendingTS.Size() == 0) {
+    
+    // keep looping until the buffer is full
+    while((m_cPendingTS.Size() < m_iMaxBufferedTs) && (!bStreamLooped)) {
+      
+      // If we're not already sending PSI, check if we need to send it again
+      if ((!m_bSendPSI) && (!bPreparsing)) {
+	// check if resend interval is up
+	if (m_bSendPSI = (m_iTSCounter % 500 <= m_iMaxBufferedTs)) {
+	  m_cPat.TsReset();
+	  m_cPmt.TsReset();
         }
+	
+	// check if a new PMT has appeared
+	if (m_cPgrmDescriptor.m_bNewPmt) {
+	  m_bSendPSI = true;
+	  m_bGenPmt = true;
+	  m_cPgrmDescriptor.m_bNewPmt = false;
       }
     }
 
-    if(m_bSendPSI)
-    {
-      if(m_bGenPat)
-      {
+      // Send PSI packets if necessary
+      if ((m_bSendPSI) && (!bPreparsing)) {
+	// first of all regenerate any of the PSI information necessary
+	if(m_bGenPat) {
         *m_cPat.GetLowLevelPat() = m_cPgrmDescriptor.m_sPat;
         m_cPat.Generate();
         m_cPat.GetLowLevelPat()->p_first_program = NULL;
         m_bGenPat = false;
+	  m_cPat.TsReset();
       }
-
-      if(m_bGenPmt)
-      {
+	if(m_bGenPmt) {
         m_cPgrmDescriptor.m_sPmt.i_version =
                         (m_cPgrmDescriptor.m_sPmt.i_version + 1) & 0x1f;
         *m_cPmt.GetLowLevelPmt() = m_cPgrmDescriptor.m_sPmt;
@@ -214,50 +205,85 @@
         m_cPmt.GetLowLevelPmt()->p_first_es = NULL;
         m_cPmt.GetLowLevelPmt()->p_first_descriptor = NULL;
         m_bGenPmt = false;
-      }
-
-      if(m_bResetPSI)
-      {
-        m_cPat.TsReset();
         m_cPmt.TsReset();
-        m_bResetPSI = false;
       }
 
-      for(unsigned int i = m_cPendingTS.Size(); i < m_iMaxBufferedTs; i++)
-      {
+	// output PSI information as necessary
+        if (m_cPat.TsHasNext()) {
         C_TsPacket* pPacket = m_pTsProvider->GetPacket();
-        ASSERT(pPacket);
+	  if (pPacket == NULL) {
+	    m_iStatus = GEN_ERR;
+	    break;
+	  }
 
-        if(m_cPat.TsHasNext())
-        {
           m_cPat.TsWrite(pPacket);
           m_cPendingTS.PushEnd(pPacket);
           m_iTSCounter++;
+        } else if (m_cPmt.TsHasNext()) {
+	  C_TsPacket* pPacket = m_pTsProvider->GetPacket();
+	  if (pPacket == NULL) {
+	    m_iStatus = GEN_ERR;
+	    break;
         }
-        else if(m_cPmt.TsHasNext())
-        {
+	  
           m_cPmt.TsWrite(pPacket);
           m_cPendingTS.PushEnd(pPacket);
           m_iTSCounter++;
-        }
-        else
-        {
+        } else {
+	  // we've finished sending PSI for this time
           m_bSendPSI = false;
-          m_pTsProvider->ReleasePacket(pPacket);
-          if(m_pDelayedPacket)
-          {
-            m_cPendingTS.PushEnd(m_pDelayedPacket);
-            m_pDelayedPacket = NULL;
           }
         }
-        if(!m_cPat.TsHasNext() && !m_cPmt.TsHasNext())
-          m_bSendPSI = false;
+      
+      // not sending PSI => grab some REAL data packets
+      if ((!m_bSendPSI) || (bPreparsing)) {
+	// fetch some packets
+	if (iRc = FetchPackets(bPreparsing)) {
+	  // special handling for some return codes
+	  switch(iRc) {
+	  case UNKNOWN_DATA:
+	    iRc = Synch();
+	    break;
+	    
+	  case SKIPPED_DATA:
+	    iRc = 0;
+	    break;
+	    
+	  case END_OF_STREAM:
+	    if (m_bLooping) {
+	      // try and reset the stream
+	      m_pReader->ResetEndOfStream();
+	      
+	      // if that failed, the reader must not support 
+	      // resetting the end of stream. We have to stop.
+	      if (m_pReader->EndOfStream()) {
+		break;
       }
+	      
+	      // OK, synch with the stream again
+	      iRc = Synch();
+	      m_bSendPSI = true;
+	      m_bGenPat = true;
+	      m_bGenPmt = true;
+	      bStreamLooped = true;
     }
+	    break;
   }
 
-  ASSERT(m_cPendingTS.Size() > 0);
-  ASSERT(m_cPendingTS.Size() <= m_iMaxBufferedTs);
+	  // OK, was there really a problem?
+	  if (iRc) {
+	    m_iStatus = iRc;
+	    break;
+	  }
+	}
+	
+	// if we're preparsing, exit as soon as we have one packet
+	if (bPreparsing && m_cPendingTS.Size()) {
+	  break;
+	}
+      }
+    }
+  }
 
   // Return the first packet
   if(m_cPendingTS.Size() > 0)
@@ -271,83 +297,58 @@
 //
 //------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
-   int C_Ps2Ts<Reader, TsProvider>::FetchPackets()
+   int C_Ps2Ts<Reader, TsProvider>::FetchPackets(bool bPreparsing)
 {
-  ASSERT(!m_iStatus || m_iStatus == SKIPPED_DATA || m_iStatus == UNKNOWN_DATA);
-
-  u8 iPosInTs = 0;
-  C_TsPacket* pPacket = m_pTsProvider->GetPacket();
-  ASSERT(pPacket);
-
-  // Handle the pack header if any at the current position in the stream
-  if(m_iDataType == PES_H_PACK_HEADER)
-  {
-    m_iStatus = ParsePackHeader(pPacket, &iPosInTs);
+  int iRc;
 
-    // There also can be a system header following the pack header
-    if(m_iDataType == PES_H_SYSTEM_HEADER && !m_iStatus)
-    {
-      m_iStatus = ParseSystemHeader(pPacket, &iPosInTs);
+  // if we're in the middle of parsing a PES packet,
+  // just do that immediately with no further ado
+  if (m_bInMiddleOfPES) {
+    return ParsePES(bPreparsing);
     }
 
-    // Leave now if something wrong occured
-    if(m_iStatus != NO_ERR)
-      return GEN_ERR;
+  // attempt to read in the start code/ data type
+  if (!m_bJustSynched) {
+    if (iRc = ReadData(m_bBuff, START_CODE_LEN)) {
+      return iRc;
   }
-
-  // No we must have reached the beginning of a PES packet or the end of
-  // the stream
-  if(IsDataPesHeader(m_iDataType))
-  {
-    // This is a data PES
-    m_iStatus = ParsePES(pPacket, &iPosInTs);
+    m_iDataType = U32_AT(m_bBuff);
+  } else {
+    // if we've just synched we _know_ we're just after a 
+    // PACK_HEADER start code.
+    m_bJustSynched = false;
+    return ParsePackHeader(bPreparsing);
   }
-  else
-  {
-    // This is a control PES
-    switch(m_iDataType)
-    {
+   
+  // OK, process the packet
+  switch(m_iDataType) {
+  case PES_H_PACK_HEADER:
+    return ParsePackHeader(bPreparsing);
+    
+  case PES_H_SYSTEM_HEADER:
+    return ParseSystemHeader();
+    
       case PES_H_PADDING:
-      {
-//        printf("Padding pes encountered\n");
-        //m_iStatus = ParsePadding(pPacket, &iPosInTs);
-        m_iStatus = ParsePES(pPacket, &iPosInTs);
-        break;
-      }
+    return ParsePES(bPreparsing);
+
       case PES_H_PGRM_MAP:
-      {
-//        printf("Program map pes encountered\n");
-        m_iStatus = ParsePgrmMap(pPacket, &iPosInTs);
-        // A foutre dans parse pgrm_map_pes quand le pes est completement fini
-        m_bSendPSI = m_bResetPSI = true;
-        break;
-      }
       case PES_H_PRIVATE_2:
       case PES_H_PGRM_DIR:
-      {
-        // Not interessting -> Trash
-//        printf("not interesting pes encountered -> trash \n");
-        m_iStatus = SkipPES(pPacket, &iPosInTs);
-        break;
-      }
+    return SkipPES();
+    
       case PES_H_END_OF_PS:
-      {
-        // Just return NULL
-//        printf("end of ps encountered\n");
-        m_pTsProvider->ReleasePacket(pPacket);
-        m_iStatus = END_OF_STREAM;
-        break;
-      }
+    return END_OF_STREAM;
+        
       default:
-      {
-//        printf("unknown packet (%x) encoutered\n", m_iDataType);
-        m_pTsProvider->ReleasePacket(pPacket);
-        m_iStatus = UNKNOWN_DATA;
-      }
+    if (IsDataPesHeader(m_iDataType)) {
+      return ParsePES(bPreparsing);
+    } else {
+      return UNKNOWN_DATA;
     }
   }
   
-  return m_iStatus;
+  // should never get here
+  return GEN_ERR;
 }
 
 
@@ -355,88 +356,62 @@
 //
 //------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
-   int C_Ps2Ts<Reader, TsProvider>::ParsePackHeader(C_TsPacket* pPacket, u8* pPosInTs)
+   int C_Ps2Ts<Reader, TsProvider>::ParsePackHeader(bool bPreparsing)
 {
-  ASSERT(pPacket);
-
-//  printf("Parsing PACK_HEADER\n");
+  int iRc;
 
-  int iRc = m_pReader->Read(m_bBuff+LOOK_AHEAD_LEN, m_iPackHeaderLen);
-  ASSERT(iRc >= 0);
-  iRc = (iRc != m_iPackHeaderLen);
+  // try to read in the data for the pack header
+  if (iRc = ReadData(m_bBuff, m_iPackHeaderLen)) {
+    return iRc;
+  }
 
-  // No stuffing by default
-  u8 iStuffLen = 0;
+  // don't bother doing anything more if we're preparsing
+  if (bPreparsing) {
+    return iRc;
+  }
 
   if(m_iPackHeaderLen == MPEG1_PACK_HEADER_LEN)
   {
     // Parse the SCR (MPEG1 format)
-    u64 iHighBits = m_bBuff[START_CODE_LEN] & 0x0E;
-    u64 iMiddleBits = U16_AT(m_bBuff[START_CODE_LEN+1]) & 0xFFFE;
-    u64 iLowBits = U16_AT(m_bBuff[START_CODE_LEN+3]) & 0xFFFE;
-    ASSERT((m_bBuff[START_CODE_LEN] & 0x01));
-    ASSERT((m_bBuff[START_CODE_LEN+2] & 0x01));
-    ASSERT((m_bBuff[START_CODE_LEN+4] & 0x01));
-   
-    u64 iSCR = iHighBits << 29 | iMiddleBits << 14 | iLowBits >> 1;
-//    printf("Date mpeg1: %Ld\n", iSCR);
- 
-    // Build the TS header to put this date
-    *pPosInTs = pPacket->BuildAdaptionField(iSCR);
+    u64 iHighBits = m_bBuff[0] & 0x0E;
+    u64 iMiddleBits = U16_AT(m_bBuff[1]) & 0xFFFE;
+    u64 iLowBits = U16_AT(m_bBuff[3]) & 0xFFFE;
+    ASSERT((m_bBuff[0] & 0x01));
+    ASSERT((m_bBuff[2] & 0x01));
+    ASSERT((m_bBuff[4] & 0x01));
+   
+    // store it for when we need to output it
+    m_iNextPCR = iHighBits << 29 | iMiddleBits << 14 | iLowBits >> 1;
+    m_bNeedToSendPCR = true;
   }
   else
   {
     // Parse the SCR (MPEG2 format)
-    u64 iHighBits = m_bBuff[START_CODE_LEN] & 0x38;
-    u64 iMiddleBits = U32_AT(m_bBuff[START_CODE_LEN]) & 0x03FFF800;
-    u64 iLowBits = U32_AT(m_bBuff[START_CODE_LEN+2]) & 0x03FFF800;
-    ASSERT((m_bBuff[START_CODE_LEN] & 0x4));
-    ASSERT((m_bBuff[START_CODE_LEN+2] & 0x4));
-    ASSERT((m_bBuff[START_CODE_LEN+4] & 0x4));
-
-    u64 iSCR = iHighBits << 27 | iMiddleBits << 4 | iLowBits >> 11;
-
-    // Kludge pour tester horloge
-//    struct timeval sTimeval;
-//    gettimeofday(&sTimeval, NULL);
-//    printf("Date mpeg2: %Ld, date systeme %d (en s)\n", iSCR, sTimeval.tv_sec);
-    
-    // Build the TS header to put this date
-    *pPosInTs = pPacket->BuildAdaptionField(iSCR);
-
-//    if(iSCR - m_iPrevSCR > 800)
-//      printf("time : %Ld ; delta : %Ld\n", iSCR, iSCR - m_iPrevSCR);
-    if(m_iPrevSCR >= iSCR)
-    {
-      printf("Time discontinuity in PS stream\n");
-      m_bDiscontinuity = true;
+    u64 iHighBits = m_bBuff[0] & 0x38;
+    u64 iMiddleBits = U32_AT(m_bBuff[0]) & 0x03FFF800;
+    u64 iLowBits = U32_AT(m_bBuff[2]) & 0x03FFF800;
+    ASSERT((m_bBuff[0] & 0x4));
+    ASSERT((m_bBuff[2] & 0x4));
+    ASSERT((m_bBuff[4] & 0x4));
+
+    // store it for when we need to output it
+    m_iNextPCR = iHighBits << 27 | iMiddleBits << 4 | iLowBits >> 11;
+    m_bNeedToSendPCR = true;
+    
+    // Read additional stuffing bytes if any
+    int iStuffLen = m_bBuff[m_iPackHeaderLen-1] & 0x7;
+    if (iStuffLen) {
+      iRc = SkipData(iStuffLen);
     }
-    m_iPrevSCR = iSCR;
-  
-    // Read additional stuffing bytes if any (MPEG2 only)
-    if(m_iPackHeaderLen == 10 + START_CODE_LEN)
-    {
-      iStuffLen = m_bBuff[m_iPackHeaderLen-1] & 0x7;
-      if(iStuffLen && !iRc)
-      {
-        iRc = m_pReader->Read(m_bBuff+LOOK_AHEAD_LEN+m_iPackHeaderLen, iStuffLen);
-        ASSERT(iRc >= 0);
-        iRc = (iRc != iStuffLen);
       }
 
-//      printf("Stuffing of size %d found: actual length is: %d\n", iStuffLen, m_iPackHeaderLen+iStuffLen);
-    }
+  // check for discontinuity
+  if (m_iPrevPCR >= m_iNextPCR) {
+    m_bDiscontinuity = true;
   }
+  m_iPrevPCR = m_iNextPCR;
   
-  // Look Ahead of 6
-  m_iDataType = U32_AT(m_bBuff[m_iPackHeaderLen+iStuffLen]);
-  m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
-  m_iDataLen = U16_AT(m_bBuff[m_iPackHeaderLen+iStuffLen+START_CODE_LEN]);
-  m_bPESStart = true;
-
-  //printf("Next data will be: %X (len: %d)\n",  m_iNextData, m_iNextLength);
-//  printf("Next data will be: %X (len: %d)\n",  m_iDataType, m_iDataLen);
-
+  // finished
   return iRc;
 }
 
@@ -445,21 +420,17 @@
 //
 //------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
-   int C_Ps2Ts<Reader, TsProvider>::ParseSystemHeader(C_TsPacket* pPacket, u8* iPosInTs)
+   int C_Ps2Ts<Reader, TsProvider>::ParseSystemHeader()
 {
-//  printf("Parsing SYSTEM_HEADER\n"); 
-
-  int iRc = m_pReader->Read(m_bBuff, m_iDataLen+LOOK_AHEAD_LEN);
-  ASSERT(iRc >= 0);
-  iRc = (iRc != m_iDataLen+LOOK_AHEAD_LEN);
-
-//  printf("Length: %d\n", m_iDataLen);
-
-  m_iDataType = U32_AT(m_bBuff[m_iDataLen]);
-  m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
-  m_iDataLen = U16_AT(m_bBuff[m_iDataLen+START_CODE_LEN]);
+  int iRc;
 
+  // read size of the system header
+  if (iRc = ReadDataLength(&m_iDataLen)) {
   return iRc;
+  }
+   
+  // skip the data
+  return SkipData(m_iDataLen);
 }
 
 
@@ -467,242 +438,170 @@
 //
 //------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
-   int C_Ps2Ts<Reader, TsProvider>::ParsePES(C_TsPacket* pPacket, u8* pPosInTs)
+   int C_Ps2Ts<Reader, TsProvider>::ParsePES(bool bPreparsing)
 {
-  ASSERT(pPacket);
-  ASSERT(pPosInTs);
-
-  // Pour le debug uniquement
-//  if(m_bPESStart)
-//  {
-//    printf("Parsing PES of type %x\n", m_iDataType);
-//    printf("PES Length: %d (without the 6 first bytes)\n", m_iDataLen);
-//  }
-//  else
-//    printf("Continuing to parse PES (remaining length: %d)\n", m_iDataLen);
-
-
-  // This variable only exists to speed up the process of looking the value of
-  // pPosInTs
-  u8 iPos;
-
-  // Write the data in the TS that depends on our position in the PES
-  if(m_bPESStart)
-  {
-    // Write the header with the bUnitStart flag set to true
-    ASSERT(m_pCurrentData);
-    ASSERT(m_pCurrentData->GetId() == (m_iDataType&0xFF));
-    u8 iCounter = m_pCurrentData->GetCounter();
-    u16 iPid =  m_pCurrentData->GetPid();
-    iPos = pPacket->BuildHeader(iPid, true, iCounter);
+  int iPos = 0;
+  int iPesPos = 0;
+  int iRc;
+
+  // read size of the PES packet
+  if (!m_bInMiddleOfPES) {
+    if (iRc = ReadDataLength(&m_iDataLen)) {
+      return iRc;
+    }
+  }
 
-    // We can have parsed an adaption field if the PES comes just after a
-    // pack header
-    if(iPos < *pPosInTs)
-    {
-      if(iPid == m_cPgrmDescriptor.GetPcrPid())
-      {
-      // The adaption_field_control has been overwritten so that the bit
-      // which indicates an adaption_field is no more set to 1
-      byte* pTsPayload = (byte*)(*pPacket);
-      pTsPayload[iPos-1] |= 0x20;
+  // Extract the current TS descriptor.
+  C_ElementDescriptor* curDesc;
+  if ((m_iDataType & 0xff) != PES_ID_PRIVATE_1) {
+    curDesc = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
+  } else { 
+    // Is an encapsulated MPEG1 stream.. special handling needed
+    // if we're at the start of a PES packet, read (and cache) the 
+    // header and find the MPEG1 stream ID
+    if (!m_bInMiddleOfPES) {
+      // read in the start of the PES header
+      if (iRc = ReadData(m_bCache, 3)) {
+	return iRc;
+      }
+      m_iCacheLen = 3;
 
-      // Set the right position
-      iPos = *pPosInTs;
-      if(m_bDiscontinuity)
-      {
-        ASSERT(pPacket->HasPCR());
-        ASSERT(pPacket->SetDiscontinuityFlag());
-        pPacket->SetDiscontinuityFlag();
-        m_bDiscontinuity = false;
+      // read in the rest of the PES header
+      if (iRc = ReadData(m_bCache + m_iCacheLen, m_bCache[2])) {
+	return iRc;
       }
+      m_iCacheLen += m_bCache[2];
+      
+      // read in the start of the MPEG1 header
+      u8* mpeg1Header = m_bCache + m_iCacheLen;
+      if (iRc = ReadData(m_bCache + m_iCacheLen, 4)) {
+	return iRc;
       }
+      m_iCacheLen += 4;
+      
+      // finally, grab the mpeg1 header stream id
+      m_iPrivateId = mpeg1Header[3];
     }
     
-    // Write the beginning of the PES packet (corresponds to the look ahead)
-    byte* pTsPayload = (byte*)(*pPacket);
-    SET_U32_TO(pTsPayload[iPos], m_iDataType);
-    SET_U16_TO(pTsPayload[iPos+START_CODE_LEN], m_iDataLen);
-    iPos += START_CODE_LEN + PES_SIZE_LEN;
+    // get the descriptor taking into account the MPEG1 stream id
+    curDesc = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF, m_iPrivateId);
   }
-  else
-  {
-    // We shouldn't have any adaption field
-    ASSERT(*pPosInTs == 0);
 
-    // Write the header with the bUnitStart flag set to false
-    ASSERT(m_pCurrentData);
-    ASSERT(m_pCurrentData->GetId() == (m_iDataType&0xFF));   
-    u8 iCounter = m_pCurrentData->GetCounter();
-    u16 iPid =  m_pCurrentData->GetPid();
-    iPos = pPacket->BuildHeader(iPid, false, iCounter);
+  // process the PES data
+  while((m_iDataLen > 0) && (m_cPendingTS.Size() < m_iMaxBufferedTs)) {
+    // check if a new PMT has appeared. If so, just exit this loop.
+    // The caller will take care of generating it and possibly calling us
+    // again to add in more PES data
+    if ((!bPreparsing) && (m_cPgrmDescriptor.m_bNewPmt)) {
+      break;
   }
 
+    // Grab a new TS packet to use
+    C_TsPacket* pPacket = m_pTsProvider->GetPacket();
 
-  // Now read the data carried in the PES
-  for(unsigned int i = 0; i < m_iMaxBufferedTs; i++)
-  {
-    // Fill the Ts packet
-    if(m_iDataLen >= TS_PACKET_LEN - iPos)
-    {
-      // Fill the remaining payload of the TS packet
-      m_iStatus = m_pReader->Read(((byte*)(*pPacket)+iPos), TS_PACKET_LEN-iPos);
-      ASSERT(m_iStatus >= 0);
-      m_iStatus = (m_iStatus != TS_PACKET_LEN-iPos);
+    // build the start of the TS packet
+    if(!m_bInMiddleOfPES) { // we're at the start of the PES packet
+      // build the header
+      u16 iPid =  curDesc->GetPid();
+      u8 iCounter = curDesc->GetCounter();
+      iPos = pPacket->BuildHeader(iPid, true, iCounter);
 
-      m_iDataLen -= (TS_PACKET_LEN-iPos);
+      // if we need to send the PCR, and we're sending a packet for the stream
+      // which contains the PCR, do it!
+      if ((m_bNeedToSendPCR) && (iPid == m_cPgrmDescriptor.GetPcrPid())) {
+	// build the adaptation field
+	iPos = pPacket->BuildAdaptionField(m_iNextPCR);
+	m_bNeedToSendPCR = false;
 
-      //-----------------
-      if(m_bPESStart)
-      {
-      if(*((byte*)(*pPacket) + iPos - 3) == PES_ID_PRIVATE_1)
-      {
-//      printf("Id : 0x%x", *((byte*)(*pPacket) + iPos - 3));
-        u8 iOffset = *((byte*)(*pPacket) + iPos + 2);
-//        printf(" Offset : 0x%x", iOffset);
-        u8 iPrivateId = *((byte*)(*pPacket) + iPos + 3 + iOffset);
-//        printf(" PrivateId : 0x%x", iPrivateId);
-/*        if((iPrivateId & 0xf0) == 0x80)
-        {*/
-          m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF,
-                                                           iPrivateId);
-          u16 iPid =  m_pCurrentData->GetPid();
-          u16 iData = U16_AT(*((byte*)(pPacket) + 1));
-//          printf(" Data : 0x%x", iData);
-          iPid = (iPid & 0x1fff) | (iData & 0xe000);
-//          printf(" NewPid : 0x%x", iPid);
-          SET_U16_TO(*((byte*)(pPacket) + 1), iPid);
-          *((byte*)(pPacket) + 3) = (m_pCurrentData->GetCounter() & 0x0f) |
-                                    (*((byte*)(pPacket) + 3) & 0xf0);
-/*        }*/
-//      printf("\n");
-      }
+	// handle any discontinuity
+	if(m_bDiscontinuity) {
+	  pPacket->SetDiscontinuityFlag();
+	  m_bDiscontinuity = false;
       }
-      //-----------------
     }
-    else
-    {
-      // m_iDataLen shouldn't be null
-      ASSERT(m_iDataLen > 0);
 
-//      printf("Stuffing needed: iPos=%d, DataLen=%d\n", iPos, m_iDataLen);
+      // write the beginning of the PES packet (since we've already read it)
+      byte* pTsPayload = (byte*)(*pPacket);
+      SET_U32_TO(pTsPayload[iPos], m_iDataType);
+      SET_U16_TO(pTsPayload[iPos+START_CODE_LEN], m_iDataLen);
+      iPesPos = START_CODE_LEN + PES_SIZE_LEN;
+      iPos += iPesPos;
+    } else {
+      // somewhere in the middle of a PES packet
+      u16 iPid = curDesc->GetPid();
+      u8 iCounter = curDesc->GetCounter();
+      iPos = pPacket->BuildHeader(iPid, false, iCounter);
+      iPesPos = 0;
+    }
 
-      // Write the end of the PES packet in the TS packet
+    // calculate how much data we can send
+    int readSize = TS_PACKET_LEN - iPos;
 
-      if(m_bPESStart)
-      {
-        // We have already written the PES start code and the pes length at the
-        // beginning of the TS packet, which will be erased by the stuffing bytes:
-        // we must rewrite them
-        iPos = pPacket->AddStuffingBytes(m_iDataLen+START_CODE_LEN+PES_SIZE_LEN);
+    // If there is not enough data to completely fill the TS packet, 
+    // add stuffing bytes
+    if((m_iDataLen+iPesPos) < readSize) {
+      // add enough stuffing bytes
+      iPos = pPacket->AddStuffingBytes(m_iDataLen+iPesPos);
+      readSize = m_iDataLen;
+      
+      // if we're at the start of a PES packet,
+      // we'll need to rewrite the start of it again as it has moved
+      if (!m_bInMiddleOfPES) {
         byte* pTsPayload = (byte*)(*pPacket);
         SET_U32_TO(pTsPayload[iPos], m_iDataType);
         SET_U16_TO(pTsPayload[iPos+START_CODE_LEN], m_iDataLen);        
-        iPos += START_CODE_LEN+PES_SIZE_LEN;
+	iPos += START_CODE_LEN + PES_SIZE_LEN;
       }
-      else
-      {
-        // Simply add the stuffing bytes at the end of the TS header
-        iPos = pPacket->AddStuffingBytes(m_iDataLen);
       }
       
-      m_iStatus = m_pReader->Read(((byte*)(*pPacket)+iPos), m_iDataLen);
-      ASSERT(m_iStatus >= 0);
-      m_iStatus = (m_iStatus != m_iDataLen);
-        
-      //-----------------
-      if(m_bPESStart)
-      {
-      if(*((byte*)(*pPacket) + iPos - 3) == PES_ID_PRIVATE_1)
-      {
-//      printf("Id : 0x%x", *((byte*)(*pPacket) + iPos - 3));
-        u8 iOffset = *((byte*)(*pPacket) + iPos + 2);
-//        printf(" Offset : 0x%x", iOffset);
-        u8 iPrivateId = *((byte*)(*pPacket) + iPos + 3 + iOffset);
-//        printf(" PrivateId : 0x%x", iPrivateId);
-/*        if((iPrivateId & 0xf0) == 0x80)
-        {*/
-          m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF,
-                                                           iPrivateId);
-          u16 iPid =  m_pCurrentData->GetPid();
-          u16 iData = U16_AT(*((byte*)(pPacket) + 1));
-//          printf(" Data : 0x%x", iData);
-          iPid = (iPid & 0x1fff) | (iData & 0xe000);
-//          printf(" NewPid : 0x%x", iPid);
-          SET_U16_TO(*((byte*)(pPacket) + 1), iPid);
-          *((byte*)(pPacket) + 3) = (m_pCurrentData->GetCounter() & 0x0f) |
-                                    (*((byte*)(pPacket) + 3) & 0xf0);
-/*        }*/
-//      printf("\n");
-      }
-      }
-      //-----------------
-
-      // All data have been read
-      m_iDataLen = 0;
+    // first of all copy any data we've cached across
+    if (m_iCacheLen) {
+      // work out how much to read from the cache
+      int cacheReadSize = m_iCacheLen;
+      if (cacheReadSize > readSize) {
+	cacheReadSize = readSize;
+      }
+
+      // copy it across and update
+      memcpy(((byte*)(*pPacket)+iPos), m_bCache, cacheReadSize);
+      readSize -= cacheReadSize;
+      iPos += cacheReadSize;
+      m_iDataLen -= cacheReadSize;
+      m_iCacheLen -= cacheReadSize;
+    }
+    
+    // OK, read the data from the stream into the TS packet
+    if (readSize) {
+      if (iRc = ReadData(((byte*)(*pPacket)+iPos), readSize)) {
+	m_pTsProvider->ReleasePacket(pPacket);
+	return iRc;
     }
-
-    // We are no more at the beginning of the PES yet
-    m_bPESStart = false;
-
-    // Increase the number of TS packets that have been build
-    m_pCurrentData->IncreaseCounter();
-    m_iTSCounter++;
-
-    if(m_cPgrmDescriptor.m_bNewPmt)
-    {
-      // Delay this packet to send PSI first
-      ASSERT(!m_pDelayedPacket);
-      m_pDelayedPacket = pPacket;
-      m_bSendPSI = m_bGenPmt = m_bResetPSI = true;
-      m_cPgrmDescriptor.m_bNewPmt = false;
-      i = m_iMaxBufferedTs - 1;
+      m_iDataLen -= readSize;
     }
-    else
-    {
+
       // Put the TS packet in the list of pending TS
       m_cPendingTS.PushEnd(pPacket);
-    }
-    ZERO(pPacket);
 
-    // Prepare the next iteration if we must loop
-    if(m_iDataLen > 0)
-    {
-      // There is a second condition for looping since we don't read
-      // the complete PES in a single operation
-      if(i < m_iMaxBufferedTs - 1)
-      {   
-        // Get another TS packet to fill
-        pPacket = m_pTsProvider->GetPacket();
-        ASSERT(pPacket);
-
-        // Build the new TS header
-        ASSERT(m_pCurrentData);
-        ASSERT(m_pCurrentData->GetId() == (m_iDataType&0xFF));
-        u8 iCounter = m_pCurrentData->GetCounter();
-        u16 iPid =  m_pCurrentData->GetPid();
-        iPos = pPacket->BuildHeader(iPid, false, iCounter);
-      }
+    // Update TS counters
+    if (!bPreparsing) {
+      curDesc->IncreaseCounter();
+      m_iTSCounter++;
     }
-    else
-    {
-      // Look ahead for next iteration
-      m_iStatus = m_pReader->Read(m_bBuff, LOOK_AHEAD_LEN);
-      ASSERT(m_iStatus >= 0);
-      m_iStatus = (m_iStatus != LOOK_AHEAD_LEN);
-      m_iDataType = U32_AT(m_bBuff[0]);
-      m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
-      m_iDataLen = U16_AT(m_bBuff[4]);
-      m_bPESStart = true;
 
-//      printf("Next data will be: %x (len = %d)\n", m_iDataType, m_iDataLen);
+    // Update the flag to show we're in the middle of a PES packet 
+    m_bInMiddleOfPES = true;
       
-      // Don't loop
-      break;
+    // if we're preparsing, we only ever deal with one packet at a time
+    if (bPreparsing) break;
     }
+
+  // if we're NOT still in the middle of a PES, clear the flag
+  if (!m_iDataLen) {
+    m_bInMiddleOfPES = false;
   }
   
-  return m_iStatus;
+  // if we get here, there isn't a problem
+  return NO_ERR;
 }
 
 
@@ -710,54 +609,66 @@
 //
 //------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
-   int C_Ps2Ts<Reader, TsProvider>::SkipPES(C_TsPacket* pPacket, u8* iPosInTs)
+   int C_Ps2Ts<Reader, TsProvider>::SkipPES()
 {
-  // Release the TS packet, we won't need it
-  m_pTsProvider->ReleasePacket(pPacket);
+  int iRc;
 
-  int iRc = m_pReader->Seek(m_iDataLen, SEEK_CUR);
-  if(iRc)
-    m_iStatus = FILE_ERR;
-  else
-  {
-    // Look ahead for next iteration
-    m_iStatus = m_pReader->Read(m_bBuff, LOOK_AHEAD_LEN);
-    ASSERT(m_iStatus >= 0);
-    m_iStatus = (m_iStatus != LOOK_AHEAD_LEN);
-    m_iDataType = U32_AT(m_bBuff[0]);
-    m_pCurrentData = m_cPgrmDescriptor.GetDescriptor(m_iDataType & 0xFF);
-    m_iDataLen = U16_AT(m_bBuff[4]);
-    m_bPESStart = true;
-//    printf("Next data will be: %x (len = %d)\n", m_iDataType, m_iDataLen);
-
-    if(m_iStatus == NO_ERR)
-      m_iStatus = SKIPPED_DATA;
+  // read size of the PS packet
+  if (iRc = ReadDataLength(&m_iDataLen)) {
+    return iRc;
   }
   
-  return m_iStatus;
+  // skip it
+  return SkipData(m_iDataLen);
 }
 
 
-//------------------------------------------------------------------------------
-//
-//------------------------------------------------------------------------------
 template <class Reader, class TsProvider>
-   int C_Ps2Ts<Reader, TsProvider>::ParsePgrmMap(C_TsPacket* pPacket, u8* iPosInTs)
+  int C_Ps2Ts<Reader, TsProvider>::ReadData(u8* buf, int length) 
 {
-//  printf("Parsing pgrm map PES: WARNING, code never tested\n");
+  int iRc;
 
-//  printf("Pgrm map length: %d\n", m_iDataLen);
+  // try to read the data
+  iRc = m_pReader->Read(buf, length);
+  if (iRc < 0) return iRc;
 
-  ASSERT(false);
+  // check for lack of data
+  if (m_pReader->EndOfStream()) return END_OF_STREAM;
 
-  while(m_iDataLen >= sizeof(m_bBuff))
-  {
-/*    int iRc = */m_pReader->Read(m_bBuff, sizeof(m_bBuff));
-    m_iDataLen -= sizeof(m_bBuff);
-  }
+  // success
+  return 0;
+}
 
-  //  push PAT et PMT dans la liste des pendingpackets 
-  return NO_ERR;
+template <class Reader, class TsProvider>
+  int C_Ps2Ts<Reader, TsProvider>::SkipData(int length) 
+{
+  int iRc;
+   
+  // try to skip
+  iRc = m_pReader->Seek(length, FILE_SEEK_CURRENT);
+  if (iRc < 0) return iRc;
+   
+  // check for lack of data
+  if (m_pReader->EndOfStream()) return END_OF_STREAM;
+
+  // success
+  return 0;
 }
 
+template <class Reader, class TsProvider>
+  int C_Ps2Ts<Reader, TsProvider>::ReadDataLength(u16* lengthDest)
+{
+  int iRc;
+  u8 buf[2];
 
+  // try to skip  
+  iRc = m_pReader->Read(buf, 2);
+  if (iRc < 0) return iRc;
+  *lengthDest = U16_AT(buf);
+   
+  // check for lack of data
+  if (m_pReader->EndOfStream()) return END_OF_STREAM;
+
+  // success
+  return 0;
+}
--- vls.orig/src/mpeg/ps2ts.h	2002-05-14 23:10:08.000000000 +0100
+++ vls/src/mpeg/ps2ts.h	2003-08-11 15:38:04.000000000 +0100
@@ -37,29 +37,31 @@
 {
  public:
   C_Ps2Ts(Reader* pReader, TsProvider* pTsProvider, unsigned int iMaxBufferedTs,
-          unsigned int iMpegVersion);
+          unsigned int iMpegVersion, bool bLooping);
   ~C_Ps2Ts();
   
   // Find the first pack header in the stream
   int Synch();
 
   // 
-  C_TsPacket* GetPacket();
+  C_TsPacket* GetPacket(bool bPreparsing = false);
+   
   // To check whenever GetPacket returns NULL
   int GetStatus() { return m_iStatus; };
 
   C_ProgramDescriptor* GetPgrmDescriptor() { return &m_cPgrmDescriptor; };
 
  protected:
-  int FetchPackets();
-
-  int ParsePackHeader(C_TsPacket* pPacket, u8* iPosInTs);
-  int ParseSystemHeader(C_TsPacket* pPacket, u8* iPosInTs);
-  int ParsePrivate1Header(C_TsPacket* pPacket, u8* iPosInTs);
-  int ParsePES(C_TsPacket* pPacket, u8* iPosInTs);
-  int ParsePgrmMap(C_TsPacket* pPacket, u8* iPosInTs);
+  int FetchPackets(bool bPreparsing);
 
-  int SkipPES(C_TsPacket* pPacket, u8* iPosInTs);
+  int ParsePackHeader(bool bPreparsing);
+  int ParseSystemHeader();
+  int ParsePES(bool bPreparsing);
+  int SkipPES();
+
+  int ReadData(u8* buf, int length);
+  int SkipData(int length);
+  int ReadDataLength(u16* lengthDest);
 
  private:
   Reader* m_pReader;
@@ -72,8 +74,10 @@
   // Parser state
   u32 m_iDataType;
   u16 m_iDataLen;
+  u8 m_iPrivateId;
   bool m_bPESStart;
   byte m_bBuff[TS_PACKET_LEN];
+  bool m_bJustSynched;
 
   // Output state
   u32 m_iTSCounter;  
@@ -81,7 +85,6 @@
   bool m_bGenPat;
   bool m_bGenPmt;
   bool m_bResetPSI;
-  C_ElementDescriptor* m_pCurrentData;
   C_ProgramDescriptor m_cPgrmDescriptor;
 
   C_DvbPsiPat m_cPat;
@@ -93,9 +96,16 @@
 
   // Global status
   int m_iStatus;
+  u64 m_iNextPCR;
+  bool m_bNeedToSendPCR;
+  bool m_bLooping;
+   
+  u8 m_bCache[512];
+  int m_iCacheLen;
+  bool m_bInMiddleOfPES;
 
   // discontinuity management
-  u64 m_iPrevSCR;
+  u64 m_iPrevPCR;
   bool m_bDiscontinuity;
 };
 
--- vls.orig/src/server/tsstreamer.cpp	2003-08-11 11:15:48.000000000 +0100
+++ vls/src/server/tsstreamer.cpp	2003-08-12 10:28:38.000000000 +0100
@@ -188,6 +188,7 @@
       // buffer is ready to be send
       if(m_iHowMany == m_pOutput->GetBuffCapacity())
       {
+	if (!m_bFirstPCR) 
         WaitSendDate();
         m_iHowMany = 0;
       }