From 602096d30437df5e8ef77c27eb9bbd93e633d167 Mon Sep 17 00:00:00 2001
From: Mark Calderbank <mark@vomp.tv>
Date: Sun, 7 May 2006 13:24:02 +0000
Subject: [PATCH] Demuxer redesign

---
 Makefile      |   3 +-
 demuxer.cc    | 516 ++++++++++----------------------------------------
 demuxer.h     | 144 ++++++--------
 demuxervdr.cc | 192 +++++++++++++++++++
 demuxervdr.h  |  43 +++++
 player.cc     |  48 ++---
 player.h      |   4 +-
 7 files changed, 429 insertions(+), 521 deletions(-)
 create mode 100644 demuxervdr.cc
 create mode 100644 demuxervdr.h

diff --git a/Makefile b/Makefile
index a3e55a3..926f887 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,8 @@ CROSSLIBS = ../jpeg-6b/libjpeg.a
 OBJECTS1 = main.o command.o log.o tcp.o dsock.o thread.o timers.o i18n.o               \
            message.o messagequeue.o                                                    \
            vdr.o recording.o channel.o rectimer.o event.o directory.o                  \
-           player.o demuxer.o stream.o vfeed.o afeed.o afeedr.o draintarget.o          \
+           player.o vfeed.o afeed.o afeedr.o                                           \
+					 demuxer.o demuxervdr.o stream.o draintarget.o                               \
            viewman.o box.o region.o colour.o view.o                                    \
            vinfo.o vwallpaper.o vvolume.o vrecordinglist.o vlivebanner.o vmute.o       \
            vtimerlist.o vtimeredit.o voptionsmenu.o vrecordingmenu.o vquestion.o       \
diff --git a/demuxer.cc b/demuxer.cc
index c379d93..e251e83 100644
--- a/demuxer.cc
+++ b/demuxer.cc
@@ -21,6 +21,12 @@
 #include "demuxer.h"
 #include <endian.h>
 
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define DEMUXER_SEQ_HEAD 0x000001B3
+#else
+#define DEMUXER_SEQ_HEAD 0xB3010000
+#endif
+
 const int Demuxer::FrameRates[9] = { 0, 23, 24, 25, 29, 30, 50, 59, 60 };
 
 Demuxer* Demuxer::instance = NULL;
@@ -29,7 +35,7 @@ Demuxer::Demuxer()
 {
   if (instance) return;
   instance = this;
-  initted = 0;
+  initted = false;
   callback = NULL;
   arcnt = 0;
 }
@@ -50,8 +56,7 @@ int Demuxer::init(Callback* tcallback)
   if (!initted)
   {
     if ( !videostream.init(demuxMemoryV) ||
-         !audiostream.init(demuxMemoryA) ||
-         !(local_frame = (UCHAR *) malloc(0x10000)))
+         !audiostream.init(demuxMemoryA))
     {
       Log::getInstance()->log("Demuxer", Log::CRIT, "Failed to initialize demuxer");
       shutdown();
@@ -64,7 +69,7 @@ int Demuxer::init(Callback* tcallback)
   }
 
   reset();
-  initted = 1;
+  initted = true;
   callback = tcallback;
   return 1;
 }
@@ -82,8 +87,7 @@ int Demuxer::shutdown()
 {
   videostream.shutdown();
   audiostream.shutdown();
-  free(local_frame);
-  initted = 0;
+  initted = false;
   return 1;
 }
 
@@ -91,7 +95,6 @@ void Demuxer::flush()
 {
   videostream.flush();
   audiostream.flush();
-  state_frametype = state_framepos = 0;
 }
 
 void Demuxer::flushAudio()
@@ -101,7 +104,7 @@ void Demuxer::flushAudio()
 
 void Demuxer::seek()
 {
-  vid_seeking = aud_seeking = 1;
+  vid_seeking = aud_seeking = true;
   video_pts = audio_pts = 0;
 }
 
@@ -152,446 +155,137 @@ int Demuxer::writeVideo(DrainTarget* dt)
 }
 #endif
 
-
-int Demuxer::scan(UCHAR *buf, int len)
+Demuxer::PESPacket::PESPacket()
 {
-  // Temporarily, just look for the lowest audio stream and return it
-  int ret = 0;
-  UCHAR byte;
-  int zeros = 0;
-  while (len > 1)
-  {
-    // We are searching for a string of bytes (0,0,1).
-    byte = *(buf++); --len;
-
-    if (byte == 0)
-    {
-      ++zeros; continue;
-    }
-    if (zeros < 2 || byte != 1)
-    {
-      zeros = 0; continue;
-    }
-    zeros = 0;
-    // We have found the pattern (0,0,1).
-    // Check the next byte for the sub-frame type.
-    byte = *(buf++); --len;
-    if (byte >= 0xc0 && byte <= 0xdf) // Audio
-      if (ret == 0 || ret > byte) ret = byte;
-  }
-  return ret;
+  data[0] = 0x00;
+  data[1] = 0x00;
+  data[2] = 0x01;
+  init(0);
 }
 
-int Demuxer::put(UCHAR* buf, int len)
+void Demuxer::PESPacket::init(UCHAR type)
 {
-  int ret = 0;    // return number of bytes consumed
-  int parsed = 0; // number of bytes parsed by sub-function
-  int full;       // sub-function sets this to tell us to exit early
-  inbuf = buf;    // Initialize buffer pointer
-
-  while (len)
-  {
-    full = 0;
-
-    if (state_frametype == 0) // Search for frame
-    {
-      parsed = parse_find_frame(len);
-    }
-    else if ((state_frametype >= FRAMETYPE_VID0) && (state_frametype <= FRAMETYPE_VIDMAX))
-    {
-      parsed = parse_video_frame(len, &full);
-    }
-    else if ((state_frametype >= FRAMETYPE_AUD0) && (state_frametype <= FRAMETYPE_AUDMAX))
-    {
-      parsed = parse_audio_frame(len, &full);
-    }
-    else if (state_frametype == FRAMETYPE_PRIVATE_1)
-    {
-      parsed = parse_private1_frame(len, &full);
-    }
-
-    ret += parsed; len -= parsed;
-    if (full) // We have to exit early.
-      break; // out of while loop
-  }
-  //Log::getInstance()->log("Demuxer", Log::DEBUG, "Put %d; took %d", ret + len, ret);
-  return ret;
+  length = submitted = 0;
+  size = 6; closed = false;
+  data[3] = type;
+  data[4] = data[5] = 0;
+  packetType = type;
 }
 
-int Demuxer::parse_find_frame(int len)
+int Demuxer::PESPacket::write(UCHAR *buf, int len)
 {
-  int ret = 0; // return number of bytes parsed
-  UCHAR byte;
-
-  // In this function, state_framepos represents
-  // the number of fixed header bytes found so far.
-  if (state_framepos > 3 || state_framepos < 0)
-  {
-    // ERROR!
-    state_framepos = 0;
-  }
-
-  while (len)
-  {
-    byte = *inbuf++;
-    ++ret; --len;
-    switch (state_framepos)
-    {
-      case 0:
-      case 1:
-        if (byte == 0)
-          ++state_framepos;
-        else
-          state_framepos = 0;
-        break;
-      case 2:
-        if (byte == 1)
-          ++state_framepos;
-        else if (byte != 0)
-          state_framepos = 0;
-        break;
-      default:
-        state_framepos = 0; // Set initial state for the new frame
-
-        if (byte == 0)
-        {
-          state_framepos = 1; // Count this as a first header byte!
-        }
-        else if (  ((byte >= FRAMETYPE_VID0) && (byte <= FRAMETYPE_VIDMAX))
-                || ((byte >= FRAMETYPE_AUD0) && (byte <= FRAMETYPE_AUDMAX))
-                || byte==FRAMETYPE_PRIVATE_1 )
-        {
-          state_frametype = byte;
-          return ret;
-        }
-
-        // Not a recognised frame type. Go back to Old Kent Road.
-        break;
-    }
-  }
-  return ret;
+  if (closed) return 0;
+  if (length + len > 0xFFFA) return 0;
+  memcpy(data+length+6, buf, len);
+  length += len;
+  size += len;
+  data[4] = (length >> 8);
+  data[5] = (length & 0xFF);
+  return 1;
 }
 
-int Demuxer::parse_video_frame(int len, int* full)
+int Demuxer::PESPacket::submit()
 {
-  int ret = 0; // return number of bytes consumed
-  int bytes_remaining;
+  if (submitted >= size) return 0;
+  if (!closed) parseDetails();
 
-  switch(state_framepos)
-  {
-    case 0: // Brand new video frame. Set initial states.
-      state_stream_fill = 0; state_vid_parsed = 0;
-      // Create a local copy of the frame header
-      local_frame[0] = local_frame[1] = 0; local_frame[2] = 1;
-      local_frame[3] = state_frametype;
-      // If no video stream has been set, use this one.
-      if (video_current == -1) video_current = state_frametype;
-      // Get MSB of frame length and copy to local frame.
-      frame_length = *inbuf << 8;
-      local_frame[4] = *inbuf;
-      ++inbuf; ++state_framepos; ++ret; --len;
-      if (len == 0) return ret;
-      // FALL THROUGH TO NEXT BYTE IN STREAM
-    case 1: // Get LSB of frame length and copy to local frame.
-      frame_length += *inbuf;
-      local_frame[5] = *inbuf;
-      ++inbuf; ++state_framepos; ++ret; --len;
-      if (len == 0) return ret;
-  }
-  // We are in the frame data
-  bytes_remaining = 2 + frame_length - state_framepos;
-  if (video_current != state_frametype)
+  closed = true;
+  Demuxer* dx = Demuxer::getInstance();
+  int sent;
+  if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
   {
-    // We don't want this frame. Throw it away.
-    if (len >= bytes_remaining)
-    {
-      inbuf += bytes_remaining;
-      ret += bytes_remaining;
-      state_frametype = state_framepos = 0;
-      return ret;
-    }
+    if (dx->video_current == -1) dx->video_current = packetType;
+    if (dx->video_current == packetType && !dx->vid_seeking)
+      sent = dx->videostream.put(data+submitted, size-submitted);
     else
-    {
-      inbuf += len; ret += len;
-      state_framepos += len;
-      return ret;
-    }
-  } // No fall through here
-
-  if (bytes_remaining)   // There is data yet to copy to local_frame
-  {
-    if (len > bytes_remaining) len = bytes_remaining;
-    memcpy(local_frame + state_framepos + 4, inbuf, len);
-    inbuf += len; ret += len; state_framepos += len;
-    if (len < bytes_remaining)   // Not all arrived yet
-      return ret;
-    parse_video_details(local_frame+6, frame_length);
+      sent = size-submitted;
   }
-
-  if (!vid_seeking)
+  else if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
   {
-  // We have the whole frame in local_frame. Send it to the stream.
-  // We still support streams that might not consume all the data.
-    state_stream_fill += videostream.put(local_frame,
-                    6 + frame_length - state_stream_fill);
-    if (state_stream_fill < frame_length + 6)   // stream is full!
-    {
-      *full = 1; return ret;
-    }
-  }
-  state_frametype = state_framepos = 0;
-  return ret;
-}
-
-int Demuxer::parse_audio_frame(int len, int* full)
-{
-  int ret = 0; // return number of bytes consumed
-  int bytes_remaining;
-
-  switch(state_framepos)
-  {
-    case 0: // Brand new audio frame. Set initial states.
-      state_stream_fill = 0;
-      // Create a local copy of the frame header
-      local_frame[0] = local_frame[1] = 0; local_frame[2] = 1;
-      local_frame[3] = state_frametype;
-      // If no audio stream has been set, use this one.
-      if (audio_current == -1) audio_current = state_frametype;
-      // Get MSB of frame length and copy to local frame.
-      frame_length = *inbuf << 8;
-      local_frame[4] = *inbuf;
-      ++inbuf; ++state_framepos; ++ret; --len;
-      if (len == 0) return ret;
-      // FALL THROUGH TO NEXT BYTE IN STREAM
-    case 1: // Get LSB of frame length and copy to local frame.
-      frame_length += *inbuf;
-      local_frame[5] = *inbuf;
-      ++inbuf; ++state_framepos; ++ret; --len;
-      if (len == 0) return ret;
-  }
-  // We are in the frame data
-  bytes_remaining = 2 + frame_length - state_framepos;
-  if (audio_current != state_frametype)
-  {
-    // We don't want this frame. Throw it away.
-    if (len >= bytes_remaining)
-    {
-      inbuf += bytes_remaining;
-      ret += bytes_remaining;
-      state_frametype = state_framepos = 0;
-      return ret;
-    }
+    if (dx->audio_current == -1) dx->audio_current = packetType;
+    if (dx->audio_current == packetType & !dx->aud_seeking)
+      sent = dx->audiostream.put(data+submitted, size-submitted);
     else
-    {
-      inbuf += len; ret += len;
-      state_framepos += len;
-      return ret;
-    }
-  } // No fall through is allowed here
-
-  if (bytes_remaining)   // There is data yet to copy to local_frame
-  {
-    if (len > bytes_remaining) len = bytes_remaining;
-    memcpy(local_frame + state_framepos + 4, inbuf, len);
-    inbuf += len; ret += len; state_framepos += len;
-    if (len < bytes_remaining)   // Not all arrived yet
-      return ret;
-    parse_audio_details(local_frame+6, frame_length);
+      sent = size-submitted;
   }
-
-  if (!aud_seeking)
+  else
   {
-    // We have the whole frame in local_frame. Send it to the stream.
-    // We still support streams that might not consume all the data.
-    state_stream_fill += audiostream.put(local_frame,
-                    6 + frame_length - state_stream_fill);
-    if (state_stream_fill < frame_length + 6)   // stream is full!
-    {
-      *full = 1; return ret;
-    }
+    sent = size-submitted;
   }
-  state_frametype = state_framepos = 0;
-  return ret;
-}
-
-int Demuxer::parse_private1_frame(int len, int* full)
-{
-  int ret = 0; // return number of bytes consumed
-  int bytes_remaining;
 
-  switch(state_framepos)
-  {
-    case 0: // Brand new frame. Set initial states.
-      // Get MSB of frame length and copy to local frame.
-      frame_length = *inbuf << 8;
-      ++inbuf; ++state_framepos; ++ret; --len;
-      if (len == 0) return ret;
-      // FALL THROUGH TO NEXT BYTE IN STREAM
-    case 1: // Get LSB of frame length and copy to local frame.
-      frame_length += *inbuf;
-      local_frame[5] = *inbuf;
-      ++inbuf; ++state_framepos; ++ret; --len;
-      if (len == 0) return ret;
-  }
-  // We are in the frame data
-  bytes_remaining = 2 + frame_length - state_framepos;
-  // Temporary - just discard the frame.
-  if (len >= bytes_remaining)
-  {
-    inbuf += bytes_remaining;
-    ret += bytes_remaining;
-    state_frametype = state_framepos = 0;
-    return ret;
-  }
+  submitted += sent;
+  if (submitted < size) // Stream is full.
+    return 0;
   else
-  {
-    inbuf += len; ret += len;
-    state_framepos += len;
-    return ret;
-  }
+    return 1;
 }
 
-void Demuxer::parse_audio_details(UCHAR* buf, int len)
+void Demuxer::PESPacket::parseDetails()
 {
-  // Extract audio PTS if it exists
-  if ( buf[1] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
+  Demuxer* dx = Demuxer::getInstance();
+  if (packetType >= PESTYPE_AUD0 && packetType <= PESTYPE_AUDMAX)
   {
-    audio_pts = ( (ULLONG)(buf[3] & 0x0E) << 29 ) |
-                ( (ULLONG)(buf[4])        << 22 ) |
-                ( (ULLONG)(buf[5] & 0xFE) << 14 ) |
-                ( (ULLONG)(buf[6])        <<  7 ) |
-                ( (ULLONG)(buf[7] & 0xFE) >>  1 );
-    if (aud_seeking && !vid_seeking && audio_pts >= video_pts_seek)
+    // Extract audio PTS if it exists
+    if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
     {
-      aud_seeking = 0;
-      Log::getInstance()->log("Demuxer", Log::DEBUG,
-          "Leaving  audio seek: Audio PTS = %llu", audio_pts);
+      dx->audio_pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) |
+                      ( (ULLONG)(data[10])        << 22 ) |
+                      ( (ULLONG)(data[11] & 0xFE) << 14 ) |
+                      ( (ULLONG)(data[12])        <<  7 ) |
+                      ( (ULLONG)(data[13] & 0xFE) >>  1 );
+      if (dx->aud_seeking && !dx->vid_seeking &&
+          dx->audio_pts >= dx->video_pts_seek)
+      {
+        dx->aud_seeking = 0;
+        Log::getInstance()->log("Demuxer", Log::DEBUG,
+            "Leaving  audio sync: Audio PTS = %llu", dx->audio_pts);
+      }
     }
   }
-}
-
-void Demuxer::parse_video_details(UCHAR* buf, int len)
-{
-  // Extract video PTS if it exists
-  if ( buf[1] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
+  else if (packetType >= PESTYPE_VID0 && packetType <= PESTYPE_VIDMAX)
   {
-    video_pts = ( (ULLONG)(buf[3] & 0x0E) << 29 ) |
-                ( (ULLONG)(buf[4])        << 22 ) |
-                ( (ULLONG)(buf[5] & 0xFE) << 14 ) |
-                ( (ULLONG)(buf[6])        <<  7 ) |
-                ( (ULLONG)(buf[7] & 0xFE) >>  1 );
-  }
-  // Now, scan for a GOP header and extract video information
-  UCHAR byte;
-  int zeros = 0;
-  while (len >= 8) // 8 is length of a GOP header
-  {
-    // We are searching for a string of bytes (0,0,1).
-    byte = *(buf++); --len;
-
-    if (byte == 0)
+    // Extract video PTS if it exists
+    if ( data[7] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
     {
-      ++zeros; continue;
+      dx->video_pts = ( (ULLONG)(data[9] & 0x0E) << 29 ) |
+                      ( (ULLONG)(data[10])        << 22 ) |
+                      ( (ULLONG)(data[11] & 0xFE) << 14 ) |
+                      ( (ULLONG)(data[12])        <<  7 ) |
+                      ( (ULLONG)(data[13] & 0xFE) >>  1 );
     }
-    if (zeros < 2 || byte != 1)
-    {
-      zeros = 0; continue;
-    }
-    zeros = 0;
-    // We have found the pattern (0,0,1).
-    // Check the next byte for the sub-frame type.
-    byte = *(buf++); --len;
-    switch (byte)
+
+    // Now, scan for a sequence header and extract information
+    UINT pos = 9; // Start searching from byte 9
+    while (pos < size - 5)
     {
-/*      case 0x00: // Picture header
-                 // 10 bits: temporal reference
-                 //  3 bits: coding type (I/P/B)
-                 //  ...
-        if (len < 2) return;
-        if ( (buf[1] & 0x38) == 0x08 ) // I-frame
-          seeking = 0;
-        buf += 4; // Minimum length of picture header
-        len -= 4;
-        break;
-*/
-      case 0xb3: // Sequence header
-                 // 12 bits: Horizontal size
-                 // 12 bits: Vertical size
-                 //  4 bits: Aspect ratio
-                 //  4 bits: Frame rate code
-                 // 18 bits: Bit rate value
-                 // ...
-        if (len < 7) return;
-        horizontal_size = ((int)buf[0] << 4) | ((int)buf[1] >> 4);
-        vertical_size = (((int)buf[1] & 0xf) << 8) | (int)buf[2];
-        setAspectRatio((enum AspectRatio)(buf[3] >> 4));
-        frame_rate = buf[3] & 0x0f;
-        if (frame_rate >= 1 && frame_rate <= 8)
-          frame_rate = FrameRates[frame_rate];
+      UINT pattern = *(UINT*)(data+pos);
+      if (pattern == DEMUXER_SEQ_HEAD)
+      {
+        pos += 4;
+        if (pos+6 >= size) return;
+        dx->horizontal_size = ((int)data[pos] << 4) | ((int)data[pos+1] >> 4);
+        dx->vertical_size = (((int)data[pos+1] & 0xf) << 8) | (int)data[pos+2];
+        dx->setAspectRatio((enum AspectRatio)(data[pos+3] >> 4));
+        dx->frame_rate = data[pos+3] & 0x0f;
+        if (dx->frame_rate >= 1 && dx->frame_rate <= 8)
+          dx->frame_rate = FrameRates[dx->frame_rate];
         else
-          frame_rate = 0;
-        bit_rate = ((int)buf[4] << 10) |
-                   ((int)buf[5] << 2) |
-                   ((int)buf[6] >> 6);
-        if (vid_seeking)
+          dx->frame_rate = 0;
+        dx->bit_rate = ((int)data[pos+4] << 10) |
+                   ((int)data[pos+5] << 2) |
+                   ((int)data[pos+6] >> 6);
+        if (dx->vid_seeking)
         {
-          vid_seeking = 0;
-          video_pts_seek = video_pts;
+          dx->vid_seeking = 0;
+          dx->video_pts_seek = dx->video_pts;
           Log::getInstance()->log("Demuxer", Log::DEBUG,
-              "Entering video seek: Video PTS = %llu", video_pts);
+              "Entering audio sync: Video PTS = %llu", dx->video_pts);
           Log::getInstance()->log("Demuxer", Log::DEBUG,
-              "Entering video seek: Audio PTS = %llu", audio_pts);
+              "Entering audio sync: Audio PTS = %llu", dx->audio_pts);
         }
-        buf += 8; // Minimum length of sequence header
-        len -= 8;
-        break;
-/*
-      case 0xb8: // Group header
-                 // We're not going to bother parsing anything.
-        seeking = 0;
-        buf += 4; // Minimum length of group header
-        len -= 4;
-        break;
-*/
-    }
-  }
-}
-
-int Demuxer::findVideoPTS(UCHAR* buf, int len, ULLONG* dest)
-{
-  while (len >= 14)
-  {
-    UINT pattern = *(UINT*)buf;
-    buf++; len--;
-#if __BYTE_ORDER == __BIG_ENDIAN
-    if (pattern < (0x100 | FRAMETYPE_VID0) ||
-        pattern > (0x100 | FRAMETYPE_VIDMAX)) continue;
-#else
-    if ((pattern & 0xFFFFFF) != 0x010000 ||
-         pattern < ((UINT)FRAMETYPE_VID0 << 24) ||
-         pattern > ((UINT)FRAMETYPE_VIDMAX << 24)) continue;
-#endif
-    if ((buf[5] & 0xC0) != 0x80) continue;
-
-    UINT framelength = ((UINT)buf[3] << 8) | buf[4];
-
-    if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
-    {
-      if ( (buf[8]  & 0x01) != 0x01 ||
-           (buf[10] & 0x01) != 0x01 ||
-           (buf[12] & 0x01) != 0x01) continue;
-
-      *dest = ( (ULLONG)(buf[8]  & 0x0E) << 29 ) |
-              ( (ULLONG)(buf[9])         << 22 ) |
-              ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
-              ( (ULLONG)(buf[11])        <<  7 ) |
-              ( (ULLONG)(buf[12] & 0xFE) >>  1 );
-      return 1;
+        return;
+      }
+      else pos++;
     }
-
-    buf += 5; len -= 5;
-    buf += framelength; len -= framelength;
   }
-  // No PTS found.
-  return 0;
 }
diff --git a/demuxer.h b/demuxer.h
index ff7e90b..e02c989 100644
--- a/demuxer.h
+++ b/demuxer.h
@@ -41,16 +41,32 @@ however, no code was copied verbatim.
 #include "audio.h"
 #include "video.h"
 
-
 class Demuxer
 {
+  class PESPacket
+  {
+    public:
+      PESPacket();
+      void init(UCHAR type);
+      int  write(UCHAR* buf, int len);
+      int  submit();
+    private:
+      UCHAR data[0x10000];
+      UINT length, size;
+      bool closed;
+      UCHAR packetType;
+      UINT submitted;
+      void parseDetails();
+  };
+  friend class PESPacket;
+
   public:
     Demuxer();
-    ~Demuxer();
+    virtual ~Demuxer();
     static Demuxer* getInstance();
     int init(Callback* callback);
     void reset();
-    void flush();
+    virtual void flush();
     void flushAudio();
     void seek();
     void setVideoStream(int id);
@@ -59,13 +75,13 @@ class Demuxer
     int writeAudio(int fd);
     int writeVideo(int fd);
 #else
-  int writeAudio(DrainTarget* dt);
+    int writeAudio(DrainTarget* dt);
     int writeVideo(DrainTarget* dt);
 #endif
 
-    int scan(UCHAR* buf, int len);
-    int findVideoPTS(UCHAR* buf, int len, ULLONG* dest);
-    int put(UCHAR* buf, int len);
+    virtual int scan(UCHAR* buf, int len) = 0;
+    virtual int findVideoPTS(UCHAR* buf, int len, ULLONG* dest) = 0;
+    virtual int put(UCHAR* buf, int len) = 0;
 
     int getHorizontalSize() { return horizontal_size; }
     int getVerticalSize() { return vertical_size; }
@@ -80,92 +96,21 @@ class Demuxer
       ASPECT_16_9 = 3
     };
 
-  private:
+  protected:
+    // General demuxer objects and status indicators
     static Demuxer* instance;
     Stream videostream;
     Stream audiostream;
     int shutdown();
-    int initted;
-    int vid_seeking;
-    int aud_seeking;
-    UCHAR* inbuf;
+    bool initted;
+    bool vid_seeking;
+    bool aud_seeking;
+    int video_current, audio_current;
 
+    // Video stream information
     void setAspectRatio(enum AspectRatio);
     Callback* callback;
 
-    int video_current, audio_current;
-    int state_frametype, state_framepos;
-    int state_stream_fill, state_vid_parsed;
-    int frame_length;
-    int parse_find_frame(int len);
-    int parse_video_frame(int len, int* full);
-    int parse_audio_frame(int len, int* full);
-    int parse_private1_frame(int len, int* full);
-    void parse_video_details(UCHAR* buf, int len);
-    void parse_audio_details(UCHAR* buf, int len);
-
-    UCHAR* local_frame;
-    static const int demuxMemoryV = 2097152;
-    static const int demuxMemoryA = 524288;
-    static const int FrameRates[9];
-
-    enum FRAMETYPE
-    {
-      FRAMETYPE_PRIVATE_1 = 0xbd,
-
-      FRAMETYPE_AUD0 = 0xc0,
-      FRAMETYPE_AUD1,
-      FRAMETYPE_AUD2,
-      FRAMETYPE_AUD3,
-      FRAMETYPE_AUD4,
-      FRAMETYPE_AUD5,
-      FRAMETYPE_AUD6,
-      FRAMETYPE_AUD7,
-      FRAMETYPE_AUD8,
-      FRAMETYPE_AUD9,
-      FRAMETYPE_AUD10,
-      FRAMETYPE_AUD11,
-      FRAMETYPE_AUD12,
-      FRAMETYPE_AUD13,
-      FRAMETYPE_AUD14,
-      FRAMETYPE_AUD15,
-      FRAMETYPE_AUD16,
-      FRAMETYPE_AUD17,
-      FRAMETYPE_AUD18,
-      FRAMETYPE_AUD19,
-      FRAMETYPE_AUD20,
-      FRAMETYPE_AUD21,
-      FRAMETYPE_AUD22,
-      FRAMETYPE_AUD23,
-      FRAMETYPE_AUD24,
-      FRAMETYPE_AUD25,
-      FRAMETYPE_AUD26,
-      FRAMETYPE_AUD27,
-      FRAMETYPE_AUD28,
-      FRAMETYPE_AUD29,
-      FRAMETYPE_AUD30,
-      FRAMETYPE_AUD31,
-      FRAMETYPE_AUDMAX = FRAMETYPE_AUD31,
-
-      FRAMETYPE_VID0 = 0xe0,
-      FRAMETYPE_VID1,
-      FRAMETYPE_VID2,
-      FRAMETYPE_VID3,
-      FRAMETYPE_VID4,
-      FRAMETYPE_VID5,
-      FRAMETYPE_VID6,
-      FRAMETYPE_VID7,
-      FRAMETYPE_VID8,
-      FRAMETYPE_VID9,
-      FRAMETYPE_VID10,
-      FRAMETYPE_VID11,
-      FRAMETYPE_VID12,
-      FRAMETYPE_VID13,
-      FRAMETYPE_VID14,
-      FRAMETYPE_VID15,
-      FRAMETYPE_VIDMAX = FRAMETYPE_VID15
-    };
-
     int horizontal_size;
     int vertical_size;
     enum AspectRatio aspect_ratio;
@@ -175,6 +120,35 @@ class Demuxer
     ULLONG video_pts;
     ULLONG video_pts_seek;
     ULLONG audio_pts;
+
+    // Constants
+    static const int demuxMemoryV = 2097152;
+    static const int demuxMemoryA = 524288;
+    static const int FrameRates[9];
+
+    enum PESTYPE
+    {
+      PESTYPE_PRIVATE_1 = 0xBD,
+
+      PESTYPE_AUD0 = 0xC0,
+      PESTYPE_AUD1,  PESTYPE_AUD2,  PESTYPE_AUD3,  PESTYPE_AUD4,
+      PESTYPE_AUD5,  PESTYPE_AUD6,  PESTYPE_AUD7,  PESTYPE_AUD8,
+      PESTYPE_AUD9,  PESTYPE_AUD10, PESTYPE_AUD11, PESTYPE_AUD12,
+      PESTYPE_AUD13, PESTYPE_AUD14, PESTYPE_AUD15, PESTYPE_AUD16,
+      PESTYPE_AUD17, PESTYPE_AUD18, PESTYPE_AUD19, PESTYPE_AUD20,
+      PESTYPE_AUD21, PESTYPE_AUD22, PESTYPE_AUD23, PESTYPE_AUD24,
+      PESTYPE_AUD25, PESTYPE_AUD26, PESTYPE_AUD27, PESTYPE_AUD28,
+      PESTYPE_AUD29, PESTYPE_AUD30, PESTYPE_AUD31,
+      PESTYPE_AUDMAX = PESTYPE_AUD31,
+
+      PESTYPE_VID0 = 0xE0,
+      PESTYPE_VID1,  PESTYPE_VID2,  PESTYPE_VID3,  PESTYPE_VID4,
+      PESTYPE_VID5,  PESTYPE_VID6,  PESTYPE_VID7,  PESTYPE_VID8,
+      PESTYPE_VID9,  PESTYPE_VID10, PESTYPE_VID11, PESTYPE_VID12,
+      PESTYPE_VID13, PESTYPE_VID14, PESTYPE_VID15,
+      PESTYPE_VIDMAX = PESTYPE_VID15
+    };
+
 };
 
 #endif
diff --git a/demuxervdr.cc b/demuxervdr.cc
new file mode 100644
index 0000000..a278456
--- /dev/null
+++ b/demuxervdr.cc
@@ -0,0 +1,192 @@
+/*
+    Copyright 2005-2006 Mark Calderbank
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "demuxervdr.h"
+#include <endian.h>
+
+DemuxerVDR::DemuxerVDR() {}
+
+void DemuxerVDR::flush()
+{
+  state = 0;
+  submitting = false;
+  Demuxer::flush();
+}
+
+int DemuxerVDR::scan(UCHAR *buf, int len)
+{
+  // Temporarily, just look for the lowest audio stream and return it
+  UCHAR HiByte = PESTYPE_AUDMAX;
+  int ret = 0;
+
+  while (len >= 4)
+  {
+    UINT pattern = *(UINT*)buf;
+    buf++; len--;
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+    if (pattern < (UINT)(0x100 | PESTYPE_AUD0) ||
+        pattern > (UINT)(0x100 | HiByte)) continue;
+    HiByte = pattern & 0xFF;
+#else
+    if ((pattern & 0xFFFFFF) != 0x010000 ||
+         pattern < ((UINT)PESTYPE_AUD0 << 24) ||
+         pattern > ((UINT)HiByte << 24)) continue;
+    HiByte = pattern >> 24;
+#endif
+    ret = HiByte;
+    if (HiByte == PESTYPE_AUD0) break;
+  }
+  return ret;
+}
+    
+int DemuxerVDR::findVideoPTS(UCHAR* buf, int len, ULLONG* dest)
+{
+  while (len >= 14)
+  {
+    UINT pattern = *(UINT*)buf;
+    buf++; len--;
+#if __BYTE_ORDER == __BIG_ENDIAN
+    if (pattern < (0x100 | PESTYPE_VID0) ||
+        pattern > (0x100 | PESTYPE_VIDMAX)) continue;
+#else
+    if ((pattern & 0xFFFFFF) != 0x010000 ||
+         pattern < ((UINT)PESTYPE_VID0 << 24) ||
+         pattern > ((UINT)PESTYPE_VIDMAX << 24)) continue;
+#endif
+    if ((buf[5] & 0xC0) != 0x80) continue;
+
+    UINT packetlength = ((UINT)buf[3] << 8) | buf[4];
+
+    if ( buf[6] & 0x80 ) // PTS_DTS_flags indicate that PTS is present
+    {
+      if ( (buf[8]  & 0x01) != 0x01 ||
+           (buf[10] & 0x01) != 0x01 ||
+           (buf[12] & 0x01) != 0x01) continue;
+
+      *dest = ( (ULLONG)(buf[8]  & 0x0E) << 29 ) |
+              ( (ULLONG)(buf[9])         << 22 ) |
+              ( (ULLONG)(buf[10] & 0xFE) << 14 ) |
+              ( (ULLONG)(buf[11])        <<  7 ) |
+              ( (ULLONG)(buf[12] & 0xFE) >>  1 );
+      return 1;
+    }
+
+    buf += 5; len -= 5;
+    buf += packetlength; len -= packetlength;
+  }
+  // No PTS found.
+  return 0;
+}
+
+int DemuxerVDR::put(UCHAR* buf, int len)
+{
+  int ret = 0;    // return number of bytes consumed
+
+  if (submitting)
+  {
+    if (packet.submit() == 0) // Still full!
+      return ret;
+    else
+      submitting = false;
+  }
+
+  if (state > 0) // We are half way through a PES packet.
+  {
+    if (len >= state) // The remainder of the packet is available.
+    {
+      packet.write(buf, state);
+      buf += state; len -= state; ret += state;
+      state = 0;
+      if (packet.submit() == 0) // Stream is full.
+      {
+        submitting = true;
+        return ret;
+      }
+    }
+    else // Write what we have, then exit.
+    {
+      packet.write(buf, len);
+      state -= len;
+      return len;
+    }
+  }
+
+  while (len >= 0)
+  {
+    switch (state)
+    {
+      case  0:
+      case -1:
+        if (*buf == 0x00) state--; else state = 0;
+        break;
+      case -2:
+        if (*buf == 0x01) state--; else if (*buf != 0x00) state = 0;
+        break;
+      case -3:
+        if ((*buf >= PESTYPE_VID0 && *buf <= PESTYPE_VIDMAX) ||
+            (*buf >= PESTYPE_AUD0 && *buf <= PESTYPE_AUDMAX) ||
+            (*buf == PESTYPE_PRIVATE_1))
+        {
+          packet.init(*buf);
+          state--;
+          break;
+        }
+        else if (*buf == 0x00)
+          state = -1;
+        else
+          state = 0;
+        break;
+      case -4:
+        packetLength = ((UINT)*buf) << 8;
+        state--;
+        break;
+      case -5:
+        packetLength += *buf;
+        state--;
+        break;
+    }
+
+    buf++; len--; ret++;
+
+    if (state == -6) // Packet header complete
+    {
+      if (len >= packetLength) // The entire packet is available.
+      {
+        packet.write(buf, packetLength);
+        buf += packetLength; len -= packetLength; ret += packetLength;
+        state = 0;
+        if (packet.submit() == 0) // Stream is full.
+        {
+          submitting = true;
+          return ret;
+        }
+      }
+      else // Write what we have.
+      {
+        packet.write(buf, len);
+        state = packetLength - len;
+        ret += len;
+        len = 0;
+      }
+    }
+  }
+  return ret;
+}
diff --git a/demuxervdr.h b/demuxervdr.h
new file mode 100644
index 0000000..1f2d90e
--- /dev/null
+++ b/demuxervdr.h
@@ -0,0 +1,43 @@
+/*
+    Copyright 2005-2006 Mark Calderbank
+
+    This file is part of VOMP.
+
+    VOMP is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    VOMP is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with VOMP; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef DEMUXERVDR_H
+#define DEMUXERVDR_H
+
+#include "demuxer.h"
+#include "defines.h"
+
+class DemuxerVDR : public Demuxer
+{
+  public:
+    DemuxerVDR();
+    void flush();
+    int scan(UCHAR* buf, int len);
+    int findVideoPTS(UCHAR* buf, int len, ULLONG* dest);
+    int put(UCHAR* buf, int len);
+
+  private:
+    int state;
+    bool submitting;
+    int packetLength;
+    PESPacket packet;
+};
+
+#endif
diff --git a/player.cc b/player.cc
index ecdaf36..0449c13 100644
--- a/player.cc
+++ b/player.cc
@@ -63,13 +63,18 @@ Player::Player(MessageQueue* messageQueue, bool tIsRecording, bool tIsRadio)
 Player::~Player()
 {
   if (initted) shutdown();
+  if (demuxer != NULL) delete demuxer;
 }
 
 int Player::init()
 {
   if (initted) return 0;
 
-  if (!demuxer.init(this))
+  demuxer = new DemuxerVDR;
+
+  if (demuxer == NULL) return 0;
+
+  if (!demuxer->init(this))
   {
     logger->log("Player", Log::ERR, "Demuxer failed to init");
     shutdown();
@@ -105,10 +110,9 @@ int Player::shutdown()
     video->blank();
     audio->stop();
     vfeed.stop();
-
     afeed.stop();
     video->reset();
-    demuxer.reset();
+    demuxer->reset();
     feedPosition = 0;
   }
 
@@ -150,8 +154,8 @@ int Player::play()
 
   audio->reset();
   video->reset();
-  demuxer.reset();
-  if (!isRadio) demuxer.seek();
+  demuxer->reset();
+  if (!isRadio) demuxer->seek();
 
   videoStartup = true;
   threadStart();
@@ -207,7 +211,7 @@ void Player::stop()
   audio->stop();
   audio->unPause();
   video->reset();
-  demuxer.reset();
+  demuxer->reset();
 
   feedPosition = 0;
 }
@@ -265,8 +269,8 @@ void Player::restartAt(ULLONG timecode)
   video->stop();
   video->reset();
   audio->reset();
-  demuxer.flush();
-  if (!isRadio) demuxer.seek();
+  demuxer->flush();
+  if (!isRadio) demuxer->seek();
   feedPosition = newPosition;
   videoStartup = true;
   afeed.start();
@@ -322,8 +326,8 @@ void Player::toggleFastForward()
     audio->stop();
     video->reset();
     audio->reset();
-    demuxer.flush();
-    if (!isRadio) demuxer.seek();
+    demuxer->flush();
+    if (!isRadio) demuxer->seek();
 
     videoStartup = true;
     afeed.enable();
@@ -377,8 +381,8 @@ void Player::toggleFastBackward()
     feedMode = MODE_BACKWARDS;
     video->reset();
     video->play();
-    demuxer.flush();
-    if (!isRadio) demuxer.seek();
+    demuxer->flush();
+    if (!isRadio) demuxer->seek();
 
     threadStart();
   }
@@ -401,7 +405,7 @@ ULLONG Player::getEndTS()
 
 void Player::call(void* caller)
 {
-  if (caller == &demuxer)
+  if (caller == demuxer)
   {
     logger->log("Player", Log::DEBUG, "Callback from demuxer");
 
@@ -411,7 +415,7 @@ void Player::call(void* caller)
       return;
     }
 
-    int dxCurrentAspect = demuxer.getAspectRatio();
+    int dxCurrentAspect = demuxer->getAspectRatio();
     if (dxCurrentAspect == Demuxer::ASPECT_4_3)
     {
       logger->log("Player", Log::DEBUG, "Demuxer said video is 4:3 aspect, switching TV");
@@ -518,8 +522,8 @@ void Player::threadMethod()
 
     if (startup)
     {
-      int a_stream = demuxer.scan(threadBuffer, thisRead);
-      demuxer.setAudioStream(a_stream);
+      int a_stream = demuxer->scan(threadBuffer, thisRead);
+      demuxer->setAudioStream(a_stream);
       logger->log("Player", Log::DEBUG, "Startup Audio stream chosen %x", a_stream);
 
       setStartTS(thisRead);
@@ -558,7 +562,7 @@ void Player::threadMethod()
       if (feedPosition >= blockSize)
       {
         feedPosition -= blockSize;
-        if (!isRadio) demuxer.seek();
+        if (!isRadio) demuxer->seek();
       }
       else
       {
@@ -571,14 +575,14 @@ void Player::threadMethod()
 
     while(writeLength < thisRead)
     {
-      thisWrite = demuxer.put(threadBuffer + writeLength, thisRead - writeLength);
+      thisWrite = demuxer->put(threadBuffer + writeLength, thisRead - writeLength);
       writeLength += thisWrite;
 //      logger->log("Player", Log::DEBUG, "Put %i to demuxer", thisWrite);
 
       if (!thisWrite)
       {
 //        logger->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
-        // demuxer is full and cant take anymore
+        // demuxer is full and can't take any more
         threadLock();
         threadWaitForSignal();
         threadUnlock();
@@ -626,12 +630,12 @@ void Player::setStartTS(UINT dataInBuffer)
     UCHAR* tempBuffer = VDR::getInstance()->getBlock(0, 100000, &thisRead);
     if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
     if (!tempBuffer) return;
-    if (thisRead) demuxer.findVideoPTS(tempBuffer, thisRead, &startTS);
+    if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &startTS);
     free(tempBuffer);
   }
   else
   {
-    demuxer.findVideoPTS(threadBuffer, dataInBuffer, &startTS);
+    demuxer->findVideoPTS(threadBuffer, dataInBuffer, &startTS);
   }
 }
 
@@ -643,7 +647,7 @@ void Player::setEndTS()
   UCHAR* tempBuffer = VDR::getInstance()->getBlock((streamLength - 100000), 100000, &thisRead);
   if (!tempBuffer && !VDR::getInstance()->isConnected()) { doConnectionLost(); return; }
   if (!tempBuffer) return;
-  if (thisRead) demuxer.findVideoPTS(tempBuffer, thisRead, &endTS);
+  if (thisRead) demuxer->findVideoPTS(tempBuffer, thisRead, &endTS);
   free(tempBuffer);
   logger->log("Player", Log::DEBUG, "Set end TS");
 }
diff --git a/player.h b/player.h
index 75ff782..6b632b0 100644
--- a/player.h
+++ b/player.h
@@ -25,7 +25,7 @@
 
 #include "audio.h"
 #include "video.h"
-#include "demuxer.h"
+#include "demuxervdr.h"
 #include "vfeed.h"
 #include "afeed.h"
 #include "remote.h"
@@ -86,7 +86,7 @@ class Player : public Thread_TYPE, public Callback
     Log* logger;
     Audio* audio;
     Video* video;
-    Demuxer demuxer;
+    Demuxer* demuxer;
     VFeed vfeed;
     AFeed afeed;
 
-- 
2.39.5