--- ../vdr-1.3.30-orig/remux.h	2005-08-07 12:28:07.000000000 +0200
+++ remux.h	2005-08-21 17:22:16.000000000 +0200
@@ -15,6 +15,15 @@
 #include "ringbuffer.h"
 #include "tools.h"
 
+enum ePesHeader {
+  phNeedMoreData = -1,
+  phInvalid = 0,
+  phMPEG1 = 1,
+  phMPEG2 = 2
+  };
+
+ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader = 0);
+
 // Picture types:
 #define NO_PICTURE 0
 #define I_FRAME    1
--- ../vdr-1.3.30-orig/remux.c	2005-08-21 10:58:58.000000000 +0200
+++ remux.c	2005-08-23 00:04:46.000000000 +0200
@@ -20,49 +20,23 @@
 #include "thread.h"
 #include "tools.h"
 
-// --- cRepacker -------------------------------------------------------------
-
-class cRepacker {
-protected:
-  int maxPacketSize;
-  uint8_t subStreamId;
-  static void DroppedData(const char *Reason, int Count) { esyslog("%s (dropped %d bytes)", Reason, Count); }
-  static int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count)
-  {
-    int n = ResultBuffer->Put(Data, Count);
-    if (n != Count)
-       esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", Count - n, Count);
-    return n;
-  }
-  static int AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader = 0);
-public:
-  cRepacker(void) { maxPacketSize = 6 + 65535; subStreamId = 0; }
-  virtual ~cRepacker() {}
-  virtual void Reset(void) {}
-  virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) = 0;
-  virtual int BreakAt(const uchar *Data, int Count) = 0;
-  virtual int QuerySnoopSize(void) { return 0; }
-  void SetMaxPacketSize(int MaxPacketSize) { maxPacketSize = MaxPacketSize; }
-  void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; }
-  };
-
-int cRepacker::AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
+ePesHeader AnalyzePesHeader(const uchar *Data, int Count, int &PesPayloadOffset, bool *ContinuationHeader)
 {
   if (Count < 7)
-     return -1; // too short
+     return phNeedMoreData; // too short
 
   if ((Data[6] & 0xC0) == 0x80) { // MPEG 2
      if (Count < 9)
-        return -1; // too short
+        return phNeedMoreData; // too short
 
      PesPayloadOffset = 6 + 3 + Data[8];
      if (Count < PesPayloadOffset)
-        return -1; // too short
+        return phNeedMoreData; // too short
 
      if (ContinuationHeader)
         *ContinuationHeader = ((Data[6] == 0x80) && !Data[7] && !Data[8]);
 
-     return 2; // MPEG 2
+     return phMPEG2; // MPEG 2
      }
 
   // check for MPEG 1 ...
@@ -74,7 +48,7 @@ int cRepacker::AnalyzePesHeader(const uc
          break;
 
       if (Count <= ++PesPayloadOffset)
-         return -1; // too short
+         return phNeedMoreData; // too short
       }
 
   // skip STD_buffer_scale/size
@@ -82,7 +56,7 @@ int cRepacker::AnalyzePesHeader(const uc
      PesPayloadOffset += 2;
 
      if (Count <= PesPayloadOffset)
-        return -1; // too short
+        return phNeedMoreData; // too short
      }
 
   if (ContinuationHeader)
@@ -104,18 +78,49 @@ int cRepacker::AnalyzePesHeader(const uc
         *ContinuationHeader = true;
      }
   else
-     return 0; // unknown
+     return phInvalid; // unknown
 
   if (Count < PesPayloadOffset)
-     return -1; // too short
+     return phNeedMoreData; // too short
 
-  return 1; // MPEG 1
+  return phMPEG1; // MPEG 1
 }
 
-// --- cVideoRepacker --------------------------------------------------------
+// --- cRepacker -------------------------------------------------------------
 
-class cVideoRepacker : public cRepacker {
-private:
+class cRepacker {
+protected:
+  int maxPacketSize;
+  uint8_t subStreamId;
+  static void DroppedData(const char *Reason, int Count) { esyslog("%s (dropped %d bytes)", Reason, Count); }
+public:
+  static int Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded);
+  cRepacker(void) { maxPacketSize = 6 + 65535; subStreamId = 0; }
+  virtual ~cRepacker() {}
+  virtual void Reset(void) {}
+  virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count) = 0;
+  virtual int BreakAt(const uchar *Data, int Count) = 0;
+  virtual int QuerySnoopSize(void) { return 0; }
+  void SetMaxPacketSize(int MaxPacketSize) { maxPacketSize = MaxPacketSize; }
+  void SetSubStreamId(uint8_t SubStreamId) { subStreamId = SubStreamId; }
+  };
+
+int cRepacker::Put(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count, int CapacityNeeded)
+{
+  if (CapacityNeeded >= Count && ResultBuffer->Free() < CapacityNeeded) {
+     esyslog("ERROR: possible result buffer overflow, dropped %d out of %d byte", CapacityNeeded, CapacityNeeded);
+     return 0;
+     }
+  int n = ResultBuffer->Put(Data, Count);
+  if (n != Count)
+     esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", Count - n, Count);
+  return n;
+}
+
+// --- cCommonRepacker --------------------------------------------------------
+
+class cCommonRepacker : public cRepacker {
+protected:
   int skippedBytes;
   int packetTodo;
   uchar fragmentData[6 + 65535 + 3];
@@ -125,40 +130,24 @@ private:
   uchar pesHeaderBackup[6 + 3 + 255];
   int pesHeaderBackupLen;
   uint32_t scanner;
-  enum eState {
-    syncing,
-    findPicture,
-    scanPicture
-    } state;
   uint32_t localScanner;
   int localStart;
   bool PushOutPacket(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
-public:
-  cVideoRepacker(void);
-  virtual void Reset(void);
-  virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
-  virtual int BreakAt(const uchar *Data, int Count);
   virtual int QuerySnoopSize() { return 4; }
+  virtual void Reset(void);
   };
 
-cVideoRepacker::cVideoRepacker(void)
-{
-  Reset();
-}
-
-void cVideoRepacker::Reset(void)
+void cCommonRepacker::Reset(void)
 {
   skippedBytes = 0;
   packetTodo = maxPacketSize - 6 - 3;
   fragmentLen = 0;
   pesHeaderLen = 0;
   pesHeaderBackupLen = 0;
-  scanner = 0xFFFFFFFF;
-  state = syncing;
   localStart = -1;
 }
 
-bool cVideoRepacker::PushOutPacket(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count)
+bool cCommonRepacker::PushOutPacket(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count)
 {
   // enter packet length into PES header ...
   if (fragmentLen > 0) { // ... which is contained in the fragment buffer
@@ -166,11 +155,17 @@ bool cVideoRepacker::PushOutPacket(cRing
      int PacketLen = fragmentLen + Count - 6;
      fragmentData[ 4 ] = PacketLen >> 8;
      fragmentData[ 5 ] = PacketLen & 0xFF;
+     // just skip packets with no payload
+     int PesPayloadOffset = 0;
+     if (AnalyzePesHeader(fragmentData, fragmentLen, PesPayloadOffset) <= phInvalid)
+        esyslog("cCommonRepacker: invalid PES packet encountered in fragment buffer!");
+     else if (6 + PacketLen <= PesPayloadOffset)
+        return true; // skip empty packet
      // amount of data to put into result buffer: a negative Count value means
      // to strip off any partially contained start code.
      int Bite = fragmentLen + (Count >= 0 ? 0 : Count);
      // put data into result buffer
-     int n = Put(ResultBuffer, fragmentData, Bite);
+     int n = Put(ResultBuffer, fragmentData, Bite, 6 + PacketLen);
      fragmentLen = 0;
      if (n != Bite)
         return false;
@@ -179,11 +174,17 @@ bool cVideoRepacker::PushOutPacket(cRing
      int PacketLen = pesHeaderLen + Count - 6;
      pesHeader[ 4 ] = PacketLen >> 8;
      pesHeader[ 5 ] = PacketLen & 0xFF;
+     // just skip packets with no payload
+     int PesPayloadOffset = 0;
+     if (AnalyzePesHeader(pesHeader, pesHeaderLen, PesPayloadOffset) <= phInvalid)
+        esyslog("cCommonRepacker: invalid PES packet encountered in header buffer!");
+     else if (6 + PacketLen <= PesPayloadOffset)
+        return true; // skip empty packet
      // amount of data to put into result buffer: a negative Count value means
      // to strip off any partially contained start code.
      int Bite = pesHeaderLen + (Count >= 0 ? 0 : Count);
      // put data into result buffer
-     int n = Put(ResultBuffer, pesHeader, Bite);
+     int n = Put(ResultBuffer, pesHeader, Bite, 6 + PacketLen);
      pesHeaderLen = 0;
      if (n != Bite)
         return false;
@@ -193,7 +194,7 @@ bool cVideoRepacker::PushOutPacket(cRing
      // amount of data to put into result buffer
      int Bite = Count;
      // put data into result buffer
-     int n = Put(ResultBuffer, Data, Bite);
+     int n = Put(ResultBuffer, Data, Bite, Bite);
      if (n != Bite)
         return false;
      }
@@ -201,6 +202,34 @@ bool cVideoRepacker::PushOutPacket(cRing
   return true;
 }
 
+// --- cVideoRepacker --------------------------------------------------------
+
+class cVideoRepacker : public cCommonRepacker {
+private:
+  enum eState {
+    syncing,
+    findPicture,
+    scanPicture
+    } state;
+public:
+  cVideoRepacker(void);
+  virtual void Reset(void);
+  virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
+  virtual int BreakAt(const uchar *Data, int Count);
+  };
+
+cVideoRepacker::cVideoRepacker(void)
+{
+  Reset();
+}
+
+void cVideoRepacker::Reset(void)
+{
+  cCommonRepacker::Reset();
+  scanner = 0xFFFFFFFF;
+  state = syncing;
+}
+
 void cVideoRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count)
 {
   // synchronisation is detected some bytes after frame start.
@@ -211,8 +240,8 @@ void cVideoRepacker::Repack(cRingBufferL
 
   int pesPayloadOffset = 0;
   bool continuationHeader = false;
-  int mpegLevel = AnalyzePesHeader(Data, Count, pesPayloadOffset, &continuationHeader);
-  if (mpegLevel <= 0) {
+  ePesHeader mpegLevel = AnalyzePesHeader(Data, Count, pesPayloadOffset, &continuationHeader);
+  if (mpegLevel <= phInvalid) {
      DroppedData("cVideoRepacker: no valid PES packet header found", Count);
      return;
      }
@@ -298,7 +327,7 @@ void cVideoRepacker::Repack(cRingBufferL
                         pesHeader[pesHeaderLen++] = 0x00; // length still unknown
                         pesHeader[pesHeaderLen++] = 0x00; // length still unknown
 
-                        if (mpegLevel == 2) {
+                        if (mpegLevel == phMPEG2) {
                            pesHeader[pesHeaderLen++] = 0x80;
                            pesHeader[pesHeaderLen++] = 0x00;
                            pesHeader[pesHeaderLen++] = 0x00;
@@ -392,7 +421,7 @@ void cVideoRepacker::Repack(cRingBufferL
               pesHeader[pesHeaderLen++] = 0x00; // length still unknown
               pesHeader[pesHeaderLen++] = 0x00; // length still unknown
 
-              if (mpegLevel == 2) {
+              if (mpegLevel == phMPEG2) {
                  pesHeader[pesHeaderLen++] = 0x80;
                  pesHeader[pesHeaderLen++] = 0x00;
                  pesHeader[pesHeaderLen++] = 0x00;
@@ -443,7 +472,7 @@ int cVideoRepacker::BreakAt(const uchar 
 {
   int PesPayloadOffset = 0;
 
-  if (AnalyzePesHeader(Data, Count, PesPayloadOffset) <= 0)
+  if (AnalyzePesHeader(Data, Count, PesPayloadOffset) <= phInvalid)
      return -1; // not enough data for test
 
   // just detect end of picture
@@ -475,6 +504,355 @@ int cVideoRepacker::BreakAt(const uchar 
   return PesPayloadOffset + packetTodo + 4;
 }
 
+// --- cAudioRepacker --------------------------------------------------------
+
+class cAudioRepacker : public cCommonRepacker {
+private:
+  static int bitRates[];
+  enum eState {
+    syncing,
+    scanFrame
+    } state;
+  int frameTodo;
+  int frameSize;
+  bool IsValidAudioHeader(uint32_t Header, int *FrameSize = 0);
+public:
+  cAudioRepacker(void);
+  virtual void Reset(void);
+  virtual void Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count);
+  virtual int BreakAt(const uchar *Data, int Count);
+  };
+
+int cAudioRepacker::bitRates[] = { // all values are specified as kbits/s
+  // Layer I
+    0,  32,  64,  96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1,
+  // Layer II
+    0,  32,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, -1,
+  // Layer III
+    0,  32,  40,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, -1
+  };
+
+cAudioRepacker::cAudioRepacker(void)
+{
+  Reset();
+}
+
+void cAudioRepacker::Reset(void)
+{
+  cCommonRepacker::Reset();
+  scanner = 0;
+  state = syncing;
+  frameTodo = 0;
+  frameSize = 0;
+}
+
+bool cAudioRepacker::IsValidAudioHeader(uint32_t Header, int *FrameSize)
+{
+  int syncword           = (Header & 0xFFF00000) >> 20;
+  int id                 = (Header & 0x00080000) >> 19;
+  int layer              = (Header & 0x00060000) >> 17;
+//int protection_bit     = (Header & 0x00010000) >> 16; 
+  int bitrate_index      = (Header & 0x0000F000) >> 12;
+  int sampling_frequency = (Header & 0x00000C00) >> 10;
+  int padding_bit        = (Header & 0x00000200) >>  9;
+//int private_bit        = (Header & 0x00000100) >>  8;
+//int mode               = (Header & 0x000000C0) >>  6;
+//int mode_extension     = (Header & 0x00000030) >>  4;
+//int copyright          = (Header & 0x00000008) >>  3;
+//int orignal_copy       = (Header & 0x00000004) >>  2;
+  int emphasis           = (Header & 0x00000003);
+
+  if (syncword != 0xFFF)
+    return false;
+
+  if (id == 0) // reserved
+    return false;
+
+  if (layer == 0) // reserved
+    return false;
+
+  if (bitrate_index == 0xF) // forbidden
+    return false;
+
+  if (sampling_frequency == 3) // reserved
+    return false;
+
+  if (emphasis == 2) // reserved
+    return false;
+
+  if (FrameSize) {
+     if (bitrate_index == 0)
+        *FrameSize = 0;
+     else {
+        static int samplingFrequencies[] = { 44100, 48000, 32000 }; // Hz
+
+        int br = 1000 * bitRates[ (3 - layer) * 0x10 + bitrate_index ]; // bits/s
+        int sf = samplingFrequencies[ sampling_frequency ];
+
+        bool layerI = (layer == 3);
+
+        int N = (layerI ? 12 : 144) * br / sf; // slots
+
+        *FrameSize = (N + padding_bit) * (layerI ? 4 : 1); // bytes
+        }
+     }
+
+  return true;
+}
+
+void cAudioRepacker::Repack(cRingBufferLinear *ResultBuffer, const uchar *Data, int Count)
+{
+  // synchronisation is detected some bytes after frame start.
+  const int SkippedBytesLimit = 4;
+
+  // reset local scanner
+  localStart = -1;
+
+  int pesPayloadOffset = 0;
+  bool continuationHeader = false;
+  ePesHeader mpegLevel = AnalyzePesHeader(Data, Count, pesPayloadOffset, &continuationHeader);
+  if (mpegLevel <= phInvalid) {
+     DroppedData("cAudioRepacker: no valid PES packet header found", Count);
+     return;
+     }
+  if (!continuationHeader) {
+    // backup PES header
+    pesHeaderBackupLen = pesPayloadOffset;
+    memcpy(pesHeaderBackup, Data, pesHeaderBackupLen);
+    }
+
+  // skip PES header
+  int done = pesPayloadOffset;
+  int todo = Count - done;
+  const uchar *data = Data + done;
+  // remember start of the data
+  const uchar *payload = data;
+
+  while (todo > 0) {
+        // collect number of skipped bytes while syncing
+        if (state <= syncing)
+           skippedBytes++;
+        else if (frameTodo > 0)
+           frameTodo--;
+        // did we reach an audio frame header?
+        scanner <<= 8;
+        scanner |= *data;
+        if ((scanner & 0xFFF00000) == 0xFFF00000) {
+           if (frameTodo <= 0 && IsValidAudioHeader(scanner, &frameSize)) {
+              if (state == scanFrame) {
+                 // as a new audio frame starts here, the previous one is done. So push
+                 // out the packet to start a new packet for the next audio frame. If
+                 // the byte count gets negative then the current buffer ends in a
+                 // partitial audio frame header that must be stripped off, as it shall
+                 // be put in the next packet.
+                 if (!PushOutPacket(ResultBuffer, payload, data - 3 - payload)) {
+                    DroppedData("cAudioRepacker: result buffer overflow", Count - (done - 3));
+                    return;
+                    }
+                 // go on with syncing to the next audio frame
+                 state = syncing;
+                 }
+              if (state == syncing) {
+                 // report that syncing dropped some bytes
+                 if (skippedBytes > SkippedBytesLimit)
+                    esyslog("cAudioRepacker: skipped %d bytes to sync on next audio frame", skippedBytes - SkippedBytesLimit);
+                 skippedBytes = 0;
+                 // if there is a PES header available, then use it ...
+                 if (pesHeaderBackupLen > 0) {
+                    // ISO 13818-1 says:
+                    // In the case of audio, if a PTS is present in a PES packet header
+                    // it shall refer to the access unit commencing in the PES packet. An
+                    // audio access unit commences in a PES packet if the first byte of
+                    // the audio access unit is present in the PES packet.
+                    memcpy(pesHeader, pesHeaderBackup, pesHeaderBackupLen);
+                    pesHeaderLen = pesHeaderBackupLen;
+                    pesHeaderBackupLen = 0;
+                    }
+                 else {
+                    // ... otherwise create a continuation PES header
+                    pesHeaderLen = 0;
+                    pesHeader[pesHeaderLen++] = 0x00;
+                    pesHeader[pesHeaderLen++] = 0x00;
+                    pesHeader[pesHeaderLen++] = 0x01;
+                    pesHeader[pesHeaderLen++] = Data[3]; // audio stream ID
+                    pesHeader[pesHeaderLen++] = 0x00; // length still unknown
+                    pesHeader[pesHeaderLen++] = 0x00; // length still unknown
+
+                    if (mpegLevel == phMPEG2) {
+                       pesHeader[pesHeaderLen++] = 0x80;
+                       pesHeader[pesHeaderLen++] = 0x00;
+                       pesHeader[pesHeaderLen++] = 0x00;
+                       }
+                    else
+                       pesHeader[pesHeaderLen++] = 0x0F;
+                    }
+                 // append the first three bytes of the audio frame header
+                 pesHeader[pesHeaderLen++] = 0xFF;
+                 pesHeader[pesHeaderLen++] = (scanner >> 16) & 0xFF;
+                 pesHeader[pesHeaderLen++] = (scanner >>  8) & 0xFF;
+                 // the next packet's payload will begin with the fourth byte of
+                 // the audio frame header (= the actual byte)
+                 payload = data;
+                 // as there is no length information available, assume the
+                 // maximum we can hold in one PES packet
+                 packetTodo = maxPacketSize - pesHeaderLen;
+                 // setup expected audio frame size to omit false audio header detection 
+                 frameTodo = frameSize;
+                 // go on with collecting the frame's data
+                 ((int &)state)++;
+                 }
+              }
+           }
+        data++;
+        done++;
+        todo--;
+        // do we have to start a new packet as there is no more space left?
+        if (--packetTodo <= 0) {
+           // we connot start a new packet here if the current might end in an audio
+           // frame header and this header shall possibly be put in the next packet. So
+           // overfill the current packet until we can safely detect that we won't
+           // break an audio frame header into pieces:
+           //
+           // A) the last four bytes were an audio frame header.
+           // B) the last three bytes introduce an audio frame header.
+           // C) the last two bytes introduce an audio frame header.
+           // D) the last byte introduces an audio frame header.
+           //
+           // Todo : Data                          : Rule : Result
+           // -----:-------------------------------:------:-------
+           //      : XX XX FF Fz zz zz|YY YY YY YY :      :
+           //    0 :                ^^|            : A    : push
+           // -----:-------------------------------:------:-------
+           //      : XX XX XX FF Fz zz|zz YY YY YY :      :
+           //    0 :                ^^|            : B    : wait
+           //   -1 :                  |^^          : A    : push
+           // -----:-------------------------------:------:-------
+           //      : XX XX XX XX FF Fz|zz zz YY YY :      :
+           //    0 :                ^^|            : C    : wait
+           //   -1 :                  |^^          : B    : wait
+           //   -2 :                  |   ^^       : A    : push
+           // -----:-------------------------------:------:-------
+           //      : XX XX XX XX XX FF|Fz zz zz YY :      :
+           //    0 :                ^^|            : D    : wait
+           //   -1 :                  |^^          : C    : wait
+           //   -2 :                  |   ^^       : B    : wait
+           //   -3 :                  |      ^^    : A    : push
+           // -----:-------------------------------:------:-------
+           bool A = ((scanner & 0xFFF00000) == 0xFFF00000);
+           bool B = ((scanner &   0xFFF000) ==   0xFFF000);
+           bool C = ((scanner &     0xFFF0) ==     0xFFF0);
+           bool D = ((scanner &       0xFF) ==       0xFF);
+           if (A || (!B && !C && !D)) {
+              // actually we cannot push out an overfull packet. So we'll have to
+              // adjust the byte count and payload start as necessary. If the byte
+              // count gets negative we'll have to append the excess from fragment's
+              // tail to the next PES header.
+              int bite = data + packetTodo - payload;
+              const uchar *excessData = fragmentData + fragmentLen + bite;
+              // a negative byte count means to drop some bytes from the current
+              // fragment's tail, to not exceed the maximum packet size.
+              if (!PushOutPacket(ResultBuffer, payload, bite)) {
+                 DroppedData("cAudioRepacker: result buffer overflow", Count - done);
+                 return;
+                 }
+              // create a continuation PES header
+              pesHeaderLen = 0;
+              pesHeader[pesHeaderLen++] = 0x00;
+              pesHeader[pesHeaderLen++] = 0x00;
+              pesHeader[pesHeaderLen++] = 0x01;
+              pesHeader[pesHeaderLen++] = Data[3]; // audio stream ID
+              pesHeader[pesHeaderLen++] = 0x00; // length still unknown
+              pesHeader[pesHeaderLen++] = 0x00; // length still unknown
+
+              if (mpegLevel == phMPEG2) {
+                 pesHeader[pesHeaderLen++] = 0x80;
+                 pesHeader[pesHeaderLen++] = 0x00;
+                 pesHeader[pesHeaderLen++] = 0x00;
+                 }
+              else
+                 pesHeader[pesHeaderLen++] = 0x0F;
+
+              // copy any excess data
+              while (bite++ < 0) {
+                    // append the excess data here
+                    pesHeader[pesHeaderLen++] = *excessData++;
+                    packetTodo++;
+                    }
+              // the next packet's payload will begin here
+              payload = data + packetTodo;
+              // as there is no length information available, assume the
+              // maximum we can hold in one PES packet
+              packetTodo += maxPacketSize - pesHeaderLen;
+              }
+           }
+        }
+  // the packet is done. Now store any remaining data into fragment buffer
+  // if we are no longer syncing.
+  if (state != syncing) {
+     // append the PES header ...
+     int bite = pesHeaderLen;
+     pesHeaderLen = 0;
+     if (bite > 0) {
+        memcpy(fragmentData + fragmentLen, pesHeader, bite);
+        fragmentLen += bite;
+        }
+     // append payload. It may contain part of an audio frame header at it's
+     // end, which will be removed when the next packet gets processed.
+     bite = data - payload;
+     if (bite > 0) {
+        memcpy(fragmentData + fragmentLen, payload, bite);
+        fragmentLen += bite;
+        }
+     }
+  // report that syncing dropped some bytes
+  if (skippedBytes > SkippedBytesLimit) {
+     esyslog("cAudioRepacker: skipped %d bytes while syncing on next audio frame", skippedBytes - SkippedBytesLimit);
+     skippedBytes = SkippedBytesLimit;
+     }
+}
+
+int cAudioRepacker::BreakAt(const uchar *Data, int Count)
+{
+  int PesPayloadOffset = 0;
+
+  if (AnalyzePesHeader(Data, Count, PesPayloadOffset) <= phInvalid)
+     return -1; // not enough data for test
+
+  // determine amount of data to fill up packet and to append next audio frame header
+  int packetRemainder = PesPayloadOffset + packetTodo + 4;
+
+  // just detect end of an audio frame
+  if (state == scanFrame) {
+     // when remaining audio frame size is known, then omit scanning
+     if (frameTodo > 0) {
+        // determine amount of data to fill up audio frame and to append next audio frame header
+        int remaining = PesPayloadOffset + frameTodo + 4;
+        if (remaining < packetRemainder)
+           return remaining;
+        return packetRemainder;
+        }
+     // setup local scanner
+     if (localStart < 0) {
+        localScanner = scanner;
+        localStart = 0;
+        }
+     // start where we've stopped at the last run
+     const uchar *data = Data + PesPayloadOffset + localStart;
+     const uchar *limit = Data + Count;
+     // scan data
+     while (data < limit) {
+           localStart++;
+           localScanner <<= 8;
+           localScanner |= *data++;
+           // check whether the next audio frame follows
+           if (((localScanner & 0xFFF00000) == 0xFFF00000) && IsValidAudioHeader(localScanner))
+              return data - Data;
+           }
+     }
+  // just fill up packet and append next audio frame header
+  return packetRemainder;
+}
+
 // --- cDolbyRepacker --------------------------------------------------------
 
 class cDolbyRepacker : public cRepacker {
@@ -587,7 +965,7 @@ bool cDolbyRepacker::FinishRemainder(cRi
      // output a previous fragment first
      if (fragmentLen > 0) {
         Bite = fragmentLen;
-        int n = Put(ResultBuffer, fragmentData, Bite);
+        int n = Put(ResultBuffer, fragmentData, Bite, fragmentLen + fragmentTodo);
         if (Bite != n) {
            Reset();
            return false;
@@ -595,7 +973,7 @@ bool cDolbyRepacker::FinishRemainder(cRi
         fragmentLen = 0;
         }
      Bite = fragmentTodo;
-     int n = Put(ResultBuffer, Data, Bite);
+     int n = Put(ResultBuffer, Data, Bite, Bite);
      if (Bite != n) {
         Reset();
         Done += n;
@@ -631,13 +1009,13 @@ bool cDolbyRepacker::StartNewPacket(cRin
   Bite = pesHeaderLen;
   // enough data available to put PES packet into buffer?
   if (packetLen - pesHeaderLen <= Todo) {
-     int n = Put(ResultBuffer, pesHeader, Bite);
+     int n = Put(ResultBuffer, pesHeader, Bite, packetLen);
      if (Bite != n) {
         Reset();
         return false;
         }
      Bite = packetLen - pesHeaderLen;
-     n = Put(ResultBuffer, Data, Bite);
+     n = Put(ResultBuffer, Data, Bite, Bite);
      if (Bite != n) {
         Reset();
         Done += n;
@@ -890,7 +1268,8 @@ private:
   uint8_t hlength;
   int mpeg;
   uint8_t check;
-  int which;
+  int mpeg1_required;
+  int mpeg1_stuffing;
   bool done;
   cRingBufferLinear *resultBuffer;
   int tsErrors;
@@ -956,11 +1335,8 @@ void cTS2PES::store(uint8_t *Data, int C
 {
   if (repacker)
      repacker->Repack(resultBuffer, Data, Count);
-  else {
-     int n = resultBuffer->Put(Data, Count);
-     if (n != Count)
-        esyslog("ERROR: result buffer overflow, dropped %d out of %d byte", Count - n, Count);
-     }
+  else
+     cRepacker::Put(resultBuffer, Data, Count, Count);
 }
 
 void cTS2PES::reset_ipack(void)
@@ -973,7 +1349,8 @@ void cTS2PES::reset_ipack(void)
   hlength = 0;
   mpeg = 0;
   check = 0;
-  which = 0;
+  mpeg1_required = 0;
+  mpeg1_stuffing = 0;
   done = false;
   count = 0;
 }
@@ -1057,7 +1434,7 @@ void cTS2PES::instant_repack(const uint8
 {
   int c = 0;
 
-  while (c < Count && (mpeg == 0 || (mpeg == 1 && found < 7) || (mpeg == 2 && found < 9)) && (found < 5 || !done)) {
+  while (c < Count && (mpeg == 0 || (mpeg == 1 && found < mpeg1_required) || (mpeg == 2 && found < 9)) && (found < 5 || !done)) {
         switch (found ) {
           case 0:
           case 1:
@@ -1103,6 +1480,7 @@ void cTS2PES::instant_repack(const uint8
                      plength = ntohs(*pl);
                      c += 2;
                      found += 2;
+                     mpeg1_stuffing = 0;
                      }
                   else {
                      plen[0] = Buf[c];
@@ -1115,32 +1493,53 @@ void cTS2PES::instant_repack(const uint8
                     unsigned short *pl = (unsigned short *)plen;
                     plength = ntohs(*pl);
                     found++;
+                    mpeg1_stuffing = 0;
                   }
                   break;
           case 6:
                   if (!done) {
                      flag1 = Buf[c++];
                      found++;
-                     if ((flag1 & 0xC0) == 0x80 )
-                        mpeg = 2;
-                     else {
-                        hlength = 0;
-                        which = 0;
-                        mpeg = 1;
-                        flag2 = 0;
+                     if (mpeg1_stuffing == 0) { // first stuffing iteration: determine MPEG level
+                        if ((flag1 & 0xC0) == 0x80)
+                           mpeg = 2;
+                        else
+                           mpeg = 1;
+                           mpeg1_required = 7;
+                        }
+                     if (mpeg == 1) {
+                        if (flag1 == 0xFF) { // MPEG1 stuffing
+                           if (++mpeg1_stuffing > 16)
+                              found = 0; // invalid MPEG1 header
+                           else { // ignore stuffing
+                              found--;
+                              if (plength > 0)
+                                 plength--;
+                              }
+                           }
+                        else if ((flag1 & 0xC0) == 0x40) // STD_buffer_scale/size
+                           mpeg1_required += 2;
+                        else if (flag1 != 0x0F && (flag1 & 0xF0) != 0x20 && (flag1 & 0xF0) != 0x30)
+                           found = 0; // invalid MPEG1 header
+                        else {
+                           flag2 = 0;
+                           hlength = 0;
+                           }
                         }
                      }
                   break;
           case 7:
-                  if (!done && mpeg == 2) {
+                  if (!done && (mpeg == 2 || mpeg1_required > 7)) {
                      flag2 = Buf[c++];
                      found++;
                      }
                   break;
           case 8:
-                  if (!done && mpeg == 2) {
+                  if (!done && (mpeg == 2 || mpeg1_required > 7)) {
                      hlength = Buf[c++];
                      found++;
+                     if (mpeg == 1 && hlength != 0x0F && (hlength & 0xF0) != 0x20 && (hlength & 0xF0) != 0x30)
+                        found = 0; // invalid MPEG1 header
                      }
                   break;
           default:
@@ -1151,7 +1550,7 @@ void cTS2PES::instant_repack(const uint8
   if (!plength)
      plength = MMAX_PLENGTH - 6;
 
-  if (done || ((mpeg == 2 && found >= 9) || (mpeg == 1 && found >= 7))) {
+  if (done || ((mpeg == 2 && found >= 9) || (mpeg == 1 && found >= mpeg1_required))) {
      switch (cid) {
        case AUDIO_STREAM_S ... AUDIO_STREAM_E:
        case VIDEO_STREAM_S ... VIDEO_STREAM_E:
@@ -1163,8 +1562,13 @@ void cTS2PES::instant_repack(const uint8
                write_ipack(&hlength, 1);
                }
 
-            if (mpeg == 1 && found == 7)
+            if (mpeg == 1 && found == mpeg1_required) {
                write_ipack(&flag1, 1);
+               if (mpeg1_required > 7) {
+                  write_ipack(&flag2, 1);
+                  write_ipack(&hlength, 1);
+                  }
+               }
 
             if (mpeg == 2 && (flag2 & PTS_ONLY) && found < 14) {
                while (c < Count && found < 14) {
@@ -1277,7 +1681,12 @@ cRemux::cRemux(int VPid, const int *APid
   if (APids) {
      int n = 0;
      while (*APids && numTracks < MAXTRACKS && n < MAXAPIDS)
+#define TEST_cAudioRepacker
+#ifdef TEST_cAudioRepacker
+           ts2pes[numTracks++] = new cTS2PES(*APids++, resultBuffer, IPACKS, 0xC0 + n++, 0x00, new cAudioRepacker);
+#else
            ts2pes[numTracks++] = new cTS2PES(*APids++, resultBuffer, IPACKS, 0xC0 + n++);
+#endif
      }
   if (DPids) {
      int n = 0;
@@ -1321,10 +1730,9 @@ int cRemux::ScanVideoPacket(const uchar 
   // If the return value is -1 the packet was not completely in the buffer.
   int Length = GetPacketLength(Data, Count, Offset);
   if (Length > 0) {
-     if (Length >= 8) {
-        int i = Offset + 8; // the minimum length of the video packet header
-        i += Data[i] + 1;   // possible additional header bytes
-        for (; i < Offset + Length - 5; i++) {
+     int PesPayloadOffset = 0;
+     if (AnalyzePesHeader(Data + Offset, Length, PesPayloadOffset) >= phMPEG1) {
+        for (int i = Offset + PesPayloadOffset; i < Offset + Length - 5; i++) {
             if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1) {
                switch (Data[i + 3]) {
                  case SC_PICTURE: PictureType = (Data[i + 5] >> 3) & 0x07;
@@ -1409,19 +1817,6 @@ uchar *cRemux::Get(int &Count, uchar *Pi
   return resultBuffer->Get(Count);
 #endif
 
-  // Special VPID case to enable recording radio channels:
-
-  if (isRadio) {
-     // XXX actually '0' should be enough, but '1' must be used with encrypted channels (driver bug?)
-     // XXX also allowing 0x1FFF to not break Michael Paar's original patch,
-     // XXX but it would probably be best to only use '0'
-     // Force syncing of radio channels to avoid "no useful data" error
-     synced = true;
-     if (PictureType)
-        *PictureType = I_FRAME;
-     return resultBuffer->Get(Count);
-     }
-
   // Check for frame borders:
 
   if (PictureType)
@@ -1466,6 +1861,18 @@ uchar *cRemux::Get(int &Count, uchar *Pi
                l = GetPacketLength(data, resultCount, i);
                if (l < 0)
                   return resultData;
+               if (isRadio) {
+                  if (!synced) {
+                     if (PictureType)
+                        *PictureType = I_FRAME;
+                     resultSkipped = i; // will drop everything before this position
+                     synced = true;
+                     }
+                  else if (Count)
+                     return resultData;
+                  else if (PictureType)
+                     *PictureType = I_FRAME;
+                  }
                }
             if (synced) {
                if (!Count)
@@ -1499,8 +1906,9 @@ void cRemux::Clear(void)
 
 void cRemux::SetBrokenLink(uchar *Data, int Length)
 {
-  if (Length > 9 && Data[0] == 0 && Data[1] == 0 && Data[2] == 1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
-     for (int i = Data[8] + 9; i < Length - 7; i++) { // +9 to skip video packet header
+  int PesPayloadOffset = 0;
+  if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
+     for (int i = PesPayloadOffset; i < Length - 7; i++) {
          if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
             if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed
                Data[i + 7] |= 0x20;
