Index: libs/libmythtv/dvbrecorder.cpp
===================================================================
--- libs/libmythtv/dvbrecorder.cpp	(revision 17481)
+++ libs/libmythtv/dvbrecorder.cpp	(working copy)
@@ -120,7 +120,7 @@
 
 void DVBRecorder::TeardownAll(void)
 {
-    // Make SURE that the device read thread is cleaned up -- John Poet
+    // Make SURE that the device read thread is cleaned up
     StopRecording();
 
     if (IsOpen())
Index: libs/libmythtv/dtvrecorder.h
===================================================================
--- libs/libmythtv/dtvrecorder.h	(revision 17481)
+++ libs/libmythtv/dtvrecorder.h	(working copy)
@@ -65,6 +65,10 @@
     bool FindH264Keyframes(const TSPacket* tspacket);
     void HandleH264Keyframe(void);
 
+    // PS support (Hauppauge PVR-x50/PVR-500)
+    void HandlePSKeyframe(void);
+    bool FindPSKeyFrames(unsigned char *buffer, int len);
+
     // For handling other (non audio/video) packets
     bool FindOtherKeyframes(const TSPacket *tspacket);
 
@@ -111,6 +115,8 @@
     unsigned long long _frames_seen_count;
     unsigned long long _frames_written_count;
 
+    int keyframedist;
+
     // constants
     /// If the number of regular frames detected since the last
     /// detected keyframe exceeds this value, then we begin marking
Index: libs/libmythtv/dtvrecorder.cpp
===================================================================
--- libs/libmythtv/dtvrecorder.cpp	(revision 17481)
+++ libs/libmythtv/dtvrecorder.cpp	(working copy)
@@ -14,7 +14,7 @@
 
 extern "C" {
 // from libavcodec
-extern const uint8_t *ff_find_start_code(const uint8_t * restrict p, const uint8_t *end, uint32_t * restrict state);
+    extern const uint8_t *ff_find_start_code(const uint8_t * restrict p, const uint8_t *end, uint32_t * restrict state);
 }
 
 #define LOC QString("DTVRec(%1): ").arg(tvrec->GetCaptureCardNum())
@@ -27,8 +27,8 @@
  *         handle MPEG-2, MPEG-4, MPEG-4 AVC, DVB and ATSC streams.
  *
  *  \sa DBox2Recorder, DVBRecorder, FirewireRecorder,
-        HDHRRecoreder, IPTVRecorder
- */
+ HDHRRecoreder, IPTVRecorder
+*/
 
 DTVRecorder::DTVRecorder(TVRec *rec) : 
     RecorderBase(rec),
@@ -54,9 +54,11 @@
     // keyframe TS buffer
     _buffer_packets(false),
     // statistics
-    _frames_seen_count(0),          _frames_written_count(0)
+    _frames_seen_count(0),          _frames_written_count(0),
+    keyframedist(15)
 {
     SetPositionMapType(MARK_GOP_BYFRAME);
+    _payload_buffer.reserve(TSPacket::SIZE * (50 + 1));
 }
 
 DTVRecorder::~DTVRecorder()
@@ -108,7 +110,7 @@
 {
     if (ringBuffer)
     {
-        if (_payload_buffer.size())
+        if (!_payload_buffer.empty())
         {
             ringBuffer->Write(&_payload_buffer[0], _payload_buffer.size());
             _payload_buffer.clear();
@@ -430,8 +432,10 @@
  */
 bool DTVRecorder::FindH264Keyframes(const TSPacket *tspacket)
 {
-    if (!ringBuffer)
+    if (!ringBuffer) {
+        VERBOSE(VB_IMPORTANT, LOC_ERR + "FindH264Keyframes: No ringbuffer");
         return false;
+    }
 
     bool haveBufferedData = !_payload_buffer.empty();
     if (!tspacket->HasPayload()) // no payload to scan
@@ -440,6 +444,7 @@
     const bool payloadStart = tspacket->PayloadStart();
     if (payloadStart)
     {
+        //VERBOSE(VB_RECORD, LOC_ERR + "FindH264Keyframes: payloadStart");
         // reset PES sync state
         _pes_synced = false;
         _start_code = 0xffffffff;
@@ -459,7 +464,8 @@
             if (i + 2 >= TSPacket::SIZE)
             {
                 VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    "PES packet start code may overflow to next TS packet, aborting keyframe search");
+                        "PES packet start code may overflow to next TS "
+                        "packet, aborting keyframe search");
                 break;
             }
 
@@ -469,7 +475,7 @@
                 tspacket->data()[i++] != 0x01)
             {
                 VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    "PES start code not found in TS packet with PUSI set");
+                        "PES start code not found in TS packet with PUSI set");
                 break;
             }
 
@@ -477,7 +483,8 @@
             if (i + 5 >= TSPacket::SIZE)
             {
                 VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    "PES packet headers overflow to next TS packet, aborting keyframe search");
+                        "PES packet headers overflow to next TS packet, "
+                        "aborting keyframe search");
                 break;
             }
 
@@ -493,12 +500,14 @@
             if ((i + 6 + pes_header_length) >= TSPacket::SIZE)
             {
                 VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    "PES packet headers overflow to next TS packet, aborting keyframe search");
+                        "PES packet headers overflow to next TS packet, "
+                        "aborting keyframe search");
                 break;
             }
 
-            // we now know where the PES payload is
-            // normally, we should have used 6, but use 5 because the for loop will bump i
+            // we now know where the PES payload is.
+            // normally, we should have used 6,
+            //        but use 5 because the for loop will bump i
             i += 5 + pes_header_length;
             _pes_synced = true;
 
@@ -511,9 +520,10 @@
             break;
 
         // scan for a NAL unit start code
-        uint32_t bytes_used = _h264_kf_seq.AddBytes(tspacket->data() + i,
-                                                   TSPacket::SIZE - i,
-                                                   ringBuffer->GetWritePosition());
+        uint32_t bytes_used = 
+            _h264_kf_seq.AddBytes(tspacket->data() + i,
+                                  TSPacket::SIZE - i,
+                                  ringBuffer->GetWritePosition());
         i += (bytes_used - 1);
 
         // special handling when we've synced to a NAL unit
@@ -535,12 +545,14 @@
 
     if (hasKeyFrame)
     {
+        //VERBOSE(VB_RECORD, LOC_ERR + "FindH264Keyframes: hasKeyFrame");
         _last_keyframe_seen = _frames_seen_count;
         HandleH264Keyframe();
     }
 
     if (hasFrame)
     {
+        //VERBOSE(VB_RECORD, LOC_ERR + "FindH264Keyframes: hasFrame");
         _frames_seen_count++;
         if (!_wait_for_keyframe_option || _first_keyframe >= 0)
             _frames_written_count++;
@@ -572,4 +584,110 @@
     CheckForRingBufferSwitch();
 }
 
+/** \fn DTVRecorder::HandlePSKeyframe(void)
+ *  \brief This save the current frame to the position maps
+ *         and handles ringbuffer switching.
+ */
+void DTVRecorder::HandlePSKeyframe(void)
+{
+    if (!ringBuffer)
+        return;
+
+    unsigned long long frameNum = _last_gop_seen;
+
+    _first_keyframe = (_first_keyframe < 0) ? frameNum : _first_keyframe;
+
+    // Add key frame to position map
+    positionMapLock.lock();
+    if (!positionMap.contains(frameNum))
+    {
+        long long startpos = ringBuffer->GetWritePosition();
+        // FIXME: handle keyframes with start code spanning over two ts packets
+        startpos += _payload_buffer.size();
+//      VERBOSE(VB_RECORD, LOC + "mpHandleKeyframe frameNum: " << frameNum << ", startpos: " << startpos << " type " << positionMapType << "\n");
+        positionMapDelta[frameNum] = startpos;
+        positionMap[frameNum]      = startpos;
+    }
+    positionMapLock.unlock();
+
+    // Perform ringbuffer switch if needed.
+    CheckForRingBufferSwitch();
+}
+
+
+bool DTVRecorder::FindPSKeyFrames(unsigned char *buffer, int len)
+{
+    unsigned char *bufptr = buffer, *bufstart = buffer;
+    uint v = 0;
+    int leftlen = len;
+    bool hasKeyFrame = false;
+
+    while (bufptr < buffer + len)
+    {
+        v = *bufptr++;
+        if (_start_code == 0x000001)
+        {
+            _start_code = ((_start_code << 8) | v) & 0xFFFFFF;
+            const int stream_id = _start_code & 0x000000ff;
+
+            if (stream_id == PESStreamID::PackHeader)
+            {
+                _last_keyframe_seen = ringBuffer->GetWritePosition() +
+                                      _payload_buffer.size();
+
+                int curpos = bufptr - bufstart - 4;
+                if (curpos < 0)
+                {
+                    // header was split
+                    if (_payload_buffer.size() + curpos > 0)
+                        ringBuffer->Write(&_payload_buffer[0],
+                                          _payload_buffer.size() + curpos);
+
+                    _payload_buffer.resize(4);
+                    memcpy(&_payload_buffer[0], &_start_code, 4);
+
+                    leftlen = leftlen - curpos + 4;
+                    bufstart = bufptr;
+                }
+                else
+                {
+                    // header was entirely in this packet
+                    int idx = _payload_buffer.size();
+                    _payload_buffer.resize(idx + curpos);
+                    memcpy(&_payload_buffer[idx], bufstart, curpos);
+
+                    bufstart += curpos;
+                    leftlen -= curpos;
+
+                    if (_payload_buffer.size() > 0)
+                        ringBuffer->Write(&_payload_buffer[0],
+                                          _payload_buffer.size());
+                    _payload_buffer.clear();
+                }
+                _frames_seen_count++;
+            }
+            else if (stream_id == PESStreamID::SequenceStartCode)
+            {
+                _last_seq_seen = _last_keyframe_seen;
+            }
+            else if (stream_id == PESStreamID::GOPStartCode &&
+                     _last_seq_seen == _last_keyframe_seen)
+            {
+                _frames_written_count = _last_gop_seen * keyframedist;
+                _last_gop_seen++;
+                HandlePSKeyframe();
+            }
+        }
+        else
+            _start_code = ((_start_code << 8) | v) & 0xFFFFFF;
+    }
+
+    int idx = _payload_buffer.size();
+    _payload_buffer.resize(idx + leftlen);
+    memcpy(&_payload_buffer[idx], bufstart, leftlen);
+
+    return hasKeyFrame;
+}
+
+
 /* vim: set expandtab tabstop=4 shiftwidth=4: */
Index: libs/libmythtv/mpegrecorder.h
===================================================================
--- libs/libmythtv/mpegrecorder.h	(revision 17481)
+++ libs/libmythtv/mpegrecorder.h	(working copy)
@@ -3,12 +3,15 @@
 #ifndef MPEGRECORDER_H_
 #define MPEGRECORDER_H_
 
-#include "recorderbase.h"
+#include "dtvrecorder.h"
+#include "tspacket.h"
+#include "mpegstreamdata.h"
 
 struct AVFormatContext;
 struct AVPacket;
 
-class MpegRecorder : public RecorderBase
+class MpegRecorder : public DTVRecorder,
+                     public MPEGSingleProgramStreamListener
 {
   public:
     MpegRecorder(TVRec*);
@@ -33,22 +36,19 @@
     bool PauseAndWait(int timeout = 100);
 
     bool IsRecording(void) { return recording; }
-    bool IsErrored(void) { return errored; }
 
-    long long GetFramesWritten(void) { return framesWritten; }
-
     bool Open(void);
     int GetVideoFd(void) { return chanfd; }
 
-    long long GetKeyframePosition(long long desired);
+    // TS
+    virtual void SetStreamData(MPEGStreamData*);
+    virtual MPEGStreamData *GetStreamData(void) { return _stream_data; }
 
-    void SetNextRecording(const ProgramInfo*, RingBuffer*);
+    // implements MPEGSingleProgramStreamListener
+    void HandleSingleProgramPAT(ProgramAssociationTable *pat);
+    void HandleSingleProgramPMT(ProgramMapTable *pmt);
 
   private:
-    bool SetupRecording(void);
-    void FinishRecording(void);
-    void HandleKeyframe(void);
-
     void ProcessData(unsigned char *buffer, int len);
 
     bool OpenMpegFileAsInput(void);
@@ -60,9 +60,14 @@
     uint GetFilteredAudioSampleRate(void) const;
     uint GetFilteredAudioLayer(void) const;
     uint GetFilteredAudioBitRate(uint audio_layer) const;
+    void ProcessPSdata(unsigned char *buffer, uint len);
+    void ProcessTSdata(unsigned char * data, uint len, uint & leftover);
+    bool ProcessTSPacket(const TSPacket &tspacket);
 
     void ResetForNewFile(void);
 
+    inline bool CheckCC(uint pid, uint cc);
+
     bool deviceIsMpegFile;
     int bufferSize;
 
@@ -78,14 +83,10 @@
     // State
     bool recording;
     bool encoding;
-    bool errored;
 
     // Pausing state
     bool cleartimeonpause;
 
-    // Number of frames written
-    long long framesWritten;
-
     // Encoding info
     int width, height;
     int bitrate, maxbitrate, streamtype, aspectratio;
@@ -97,23 +98,34 @@
     int chanfd;
     int readfd;
 
-    // Keyframe tracking inforamtion
-    int keyframedist;
-    bool gopset;
-    unsigned int leftovers;
-    long long lastpackheaderpos;
-    long long lastseqstart;
-    long long numgops;
-
-    // buffer used for ...
-    unsigned char *buildbuffer;
-    unsigned int buildbuffersize;
-
     static const int   audRateL1[];
     static const int   audRateL2[];
     static const int   audRateL3[];
     static const char *streamType[];
     static const char *aspectRatio[];
     static const unsigned int kBuildBufferMaxSize;
+
+    // TS
+    MPEGStreamData *_stream_data;
+    unsigned char   _stream_id[0x1fff];
+    unsigned char   _pid_status[0x1fff];
+    unsigned char   _continuity_counter[0x1fff];
+    static const unsigned char kPayloadStartSeen = 0x2;
+
+    // Statistics
+    mutable uint        _continuity_error_count;
+    mutable uint        _stream_overflow_count;
+    mutable uint        _bad_packet_count;
 };
+
+inline bool MpegRecorder::CheckCC(uint pid, uint new_cnt)
+{
+    bool ok = ((((_continuity_counter[pid] + 1) & 0xf) == new_cnt) ||
+               (_continuity_counter[pid] == 0xFF));
+
+    _continuity_counter[pid] = new_cnt & 0xf;
+
+    return ok;
+}
+
 #endif
Index: libs/libmythtv/mpegrecorder.cpp
===================================================================
--- libs/libmythtv/mpegrecorder.cpp	(revision 17481)
+++ libs/libmythtv/mpegrecorder.cpp	(working copy)
@@ -34,6 +34,9 @@
 #include "util.h"
 #include "cardutil.h"
 
+// the audio and video PIDs are in the Program Map Table
+// the PID of the PMT are specified in the Program Association Table
+
 // ivtv header
 extern "C" {
 #include "ivtv_myth.h"
@@ -48,7 +51,7 @@
 const int MpegRecorder::audRateL1[] =
 {
     32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0
-};
+        };
 
 const int MpegRecorder::audRateL2[] =
 {
@@ -73,13 +76,9 @@
     "Square", "4:3", "16:9", "2.21:1", 0
 };
 
-const unsigned int MpegRecorder::kBuildBufferMaxSize = 1024 * 1024;
-
-MpegRecorder::MpegRecorder(TVRec *rec) :
-    RecorderBase(rec),
+MpegRecorder::MpegRecorder(TVRec *rec) : DTVRecorder(rec),
     // Debugging variables
     deviceIsMpegFile(false),
-    bufferSize(4096),
     // Driver info
     card(QString::null),      driver(QString::null),
     version(0),               usingv4l2(false),
@@ -87,11 +86,8 @@
     requires_special_pause(false),
     // State
     recording(false),         encoding(false),
-    errored(false),
     // Pausing state
     cleartimeonpause(false),
-    // Number of frames written
-    framesWritten(0),
     // Encoding info
     width(720),               height(480),
     bitrate(4500),            maxbitrate(6000),
@@ -102,13 +98,8 @@
     audvolume(80),            language(0),
     // Input file descriptors
     chanfd(-1),               readfd(-1),
-    // Keyframe tracking inforamtion
-    keyframedist(15),         gopset(false),
-    leftovers(0),             lastpackheaderpos(0),
-    lastseqstart(0),          numgops(0),
-    // buffer used for ...
-    buildbuffer(new unsigned char[kBuildBufferMaxSize + 1]),
-    buildbuffersize(0)
+    // TS packet handling
+    _stream_data(NULL)                                   
 {
     SetPositionMapType(MARK_GOP_START);
 }
@@ -116,11 +107,12 @@
 MpegRecorder::~MpegRecorder()
 {
     TeardownAll();
-    delete [] buildbuffer;
 }
 
 void MpegRecorder::TeardownAll(void)
 {
+    StopRecording();
+
     if (chanfd >= 0)
     {
         close(chanfd);
@@ -131,6 +123,7 @@
         close(readfd);
         readfd = -1;
     }
+
 }
 
 static int find_index(const int *audio_rate, int value)
@@ -332,17 +325,31 @@
 
     if (CardUtil::GetV4LInfo(chanfd, card, driver, version))
     {
+//      driver = "hdpvr";
+
         if (driver == "ivtv")
         {
+            bufferSize = 4096;
+
             usingv4l2     = (version >= IVTV_KERNEL_VERSION(0, 8, 0));
             has_v4l2_vbi  = (version >= IVTV_KERNEL_VERSION(0, 3, 8));
             has_buggy_vbi = true;
             requires_special_pause =
                 (version >= IVTV_KERNEL_VERSION(0, 10, 0));
         }
+        else if (driver == "hdpvr")
+        {
+            bufferSize = 1500 * TSPacket::SIZE;
+            usingv4l2 = true;
+            requires_special_pause = true;
+
+	    bzero(_stream_id,  sizeof(_stream_id));
+	    bzero(_pid_status, sizeof(_pid_status));
+	    memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
+        }
         else
         {
-            VERBOSE(VB_IMPORTANT, "\n\nNot ivtv driver??\n\n");
+            VERBOSE(VB_IMPORTANT, "\n\nNot ivtv or hdpvr driver??\n\n");
             usingv4l2 = has_v4l2_vbi = true;
             has_buggy_vbi = requires_special_pause = false;
         }
@@ -354,92 +361,94 @@
 
     struct v4l2_format vfmt;
     bzero(&vfmt, sizeof(vfmt));
-
+    
     vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
+    
     if (ioctl(chanfd, VIDIOC_G_FMT, &vfmt) < 0)
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR + "Error getting format" + ENO);
         return false;
     }
+        
+    if (driver != "hdpvr") {
+        vfmt.fmt.pix.width = width;
+        vfmt.fmt.pix.height = height;
+        
+        if (ioctl(chanfd, VIDIOC_S_FMT, &vfmt) < 0)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "Error setting format" + ENO);
+            return false;
+        }
 
-    vfmt.fmt.pix.width = width;
-    vfmt.fmt.pix.height = height;
-
-    if (ioctl(chanfd, VIDIOC_S_FMT, &vfmt) < 0)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "Error setting format" + ENO);
-        return false;
-    }
-
-    // Set audio language mode
-    bool do_audmode_set = true;
-    struct v4l2_tuner vt;
-    bzero(&vt, sizeof(struct v4l2_tuner));
-    if (ioctl(chanfd, VIDIOC_G_TUNER, &vt) < 0)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to get audio mode" + ENO);
-        do_audmode_set = false;
-    }
-
-    switch (language)
-    {
-        case 0:
+        // Set audio language mode
+        bool do_audmode_set = true;
+        struct v4l2_tuner vt;
+        bzero(&vt, sizeof(struct v4l2_tuner));
+        if (ioctl(chanfd, VIDIOC_G_TUNER, &vt) < 0)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to get audio mode" + ENO);
+            do_audmode_set = false;
+        }
+        
+        switch (language)
+        {
+          case 0:
             vt.audmode = V4L2_TUNER_MODE_LANG1;
             break;
-        case 1:
+          case 1:
             vt.audmode = V4L2_TUNER_MODE_LANG2;
             break;
-        case 2:
+          case 2:
             if (usingv4l2)
                 vt.audmode = V4L2_TUNER_MODE_LANG1_LANG2;
             else
                 vt.audmode = V4L2_TUNER_MODE_STEREO;
             break;
-        default:
+          default:
             vt.audmode = V4L2_TUNER_MODE_LANG1;
-    }
+        }
 
-    int audio_layer = GetFilteredAudioLayer();
-    if (do_audmode_set && (2 == language) && (1 == audio_layer))
-    {
-        VERBOSE(VB_GENERAL, "Dual audio mode incompatible with Layer I audio."
-                "\n\t\t\tFalling back to Main Language");
-        vt.audmode = V4L2_TUNER_MODE_LANG1;
-    }
+        int audio_layer = GetFilteredAudioLayer();
+        if (do_audmode_set && (2 == language) && (1 == audio_layer))
+        {
+            VERBOSE(VB_GENERAL, "Dual audio mode incompatible with Layer I audio."
+                    "\n\t\t\tFalling back to Main Language");
+            vt.audmode = V4L2_TUNER_MODE_LANG1;
+        }
 
-    if (do_audmode_set && ioctl(chanfd, VIDIOC_S_TUNER, &vt) < 0)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set audio mode" + ENO);
-    }
+        if (do_audmode_set && ioctl(chanfd, VIDIOC_S_TUNER, &vt) < 0)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set audio mode" + ENO);
+        }
 
-    // Get volume min/max values
-    struct v4l2_queryctrl qctrl;
-    qctrl.id = V4L2_CID_AUDIO_VOLUME;
-    if (ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl) < 0)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_WARN +
-                "Unable to get recording volume parameters(max/min)" + ENO +
-                "\n\t\t\tusing default range [0,65535].");
-        qctrl.maximum = 65535;
-        qctrl.minimum = 0;
-    }
+        // Get volume min/max values
+        struct v4l2_queryctrl qctrl;
+        qctrl.id = V4L2_CID_AUDIO_VOLUME;
+        if (ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl) < 0)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_WARN +
+                    "Unable to get recording volume parameters(max/min)" + ENO +
+                    "\n\t\t\tusing default range [0,65535].");
+            qctrl.maximum = 65535;
+            qctrl.minimum = 0;
+        }
 
-    // calculate volume in card units.
-    int range = qctrl.maximum - qctrl.minimum;
-    int value = (int) ((range * audvolume * 0.01f) + qctrl.minimum);
-    int ctrl_volume = min(qctrl.maximum, max(qctrl.minimum, value));
+        // calculate volume in card units.
+        int range = qctrl.maximum - qctrl.minimum;
+        int value = (int) ((range * audvolume * 0.01f) + qctrl.minimum);
+        int ctrl_volume = min(qctrl.maximum, max(qctrl.minimum, value));
 
-    // Set recording volume
-    struct v4l2_control ctrl;
-    ctrl.id = V4L2_CID_AUDIO_VOLUME;
-    ctrl.value = ctrl_volume;
+        // Set recording volume
+        struct v4l2_control ctrl;
+        ctrl.id = V4L2_CID_AUDIO_VOLUME;
+        ctrl.value = ctrl_volume;
 
-    if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) < 0)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_WARN +
-                "Unable to set recording volume" + ENO + "\n\t\t\t" +
-                "If you are using an AverMedia M179 card this is normal.");
+        if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) < 0)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_WARN +
+                    "Unable to set recording volume" + ENO + "\n\t\t\t" +
+                    "If you are using an AverMedia M179 card this is normal.");
+        }
     }
 
     bool ok = true;
@@ -457,7 +466,12 @@
 
     SetVBIOptions(chanfd);
 
-    readfd = open(videodevice.ascii(), O_RDWR | O_NONBLOCK);
+    // hdpvr driver does not like NONBLOCK mode with select
+    if (driver == "hdpvr")
+        readfd = open(videodevice.ascii(), O_RDWR);
+    else
+        readfd = open(videodevice.ascii(), O_RDWR | O_NONBLOCK);
+
     if (readfd < 0)
     {
         VERBOSE(VB_IMPORTANT, LOC_ERR + "Can't open video device." + ENO);
@@ -475,15 +489,29 @@
     {
         switch (st)
         {
-            case 2:  st = 2;  break;
-            case 10:
-            case 13:
-            case 14: st = 10; break;
-            case 11: st = 11; break;
-            case 12: st = 12; break;
-            default: st = 0;  break;   
+          case 2:  st = 2;  break;
+          case 10:
+          case 13:
+          case 14: st = 10; break;
+          case 11: st = 11; break;
+          case 12: st = 12; break;
+          default: st = 0;  break;   
         }
     }
+    else if (driver == "hdpvr")
+    {
+        // FIX ME!  // I have no idea what to put here
+        switch (st)
+        {
+          case 2:  st = 2;  break;
+          case 10:
+          case 13:
+          case 14: st = 10; break;
+          case 11: st = 11; break;
+          case 12: st = 12; break;
+          default: st = 0;  break;   
+        }
+    }
 
     if (st != (uint) streamtype)
     {
@@ -502,6 +530,9 @@
 
     sr = (driver == "ivtv") ? 48000 : sr; // only 48kHz works properly.
 
+    // hdpvr ?
+
+
     if (sr != (uint) audsamplerate)
     {
         VERBOSE(VB_IMPORTANT, LOC_WARN +
@@ -512,10 +543,10 @@
 
     switch (sr)
     {
-        case 32000: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000;
-        case 44100: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100;
-        case 48000: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
-        default:    return V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+      case 32000: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000;
+      case 44100: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100;
+      case 48000: return V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+      default:    return V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
     }
 }
 
@@ -527,6 +558,9 @@
 
     layer = (driver == "ivtv") ? 2 : layer;
 
+    // hdpvr?
+
+
     if (layer != (uint) audtype)
     {
         VERBOSE(VB_IMPORTANT, LOC_WARN +
@@ -587,24 +621,24 @@
 {
     switch (st)
     {
-        case 0:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
-        case 1:  return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
-        case 2:  return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD;
-        case 3:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;  /* PES A/V    */
-        case 5:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;  /* PES V      */
-        case 7:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;  /* PES A      */
-        case 10: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
-        case 11: return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD; /* VCD */
-        case 12: return V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD;
-        case 13: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD; /* DVD-Special 1 */
-        case 14: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD; /* DVD-Special 2 */
-        default: return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+      case 0:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
+      case 1:  return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+      case 2:  return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD;
+      case 3:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;  /* PES A/V    */
+      case 5:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;  /* PES V      */
+      case 7:  return V4L2_MPEG_STREAM_TYPE_MPEG2_PS;  /* PES A      */
+      case 10: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
+      case 11: return V4L2_MPEG_STREAM_TYPE_MPEG1_VCD; /* VCD */
+      case 12: return V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD;
+      case 13: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD; /* DVD-Special 1 */
+      case 14: return V4L2_MPEG_STREAM_TYPE_MPEG2_DVD; /* DVD-Special 2 */
+      default: return V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
     }
 }
 
 bool MpegRecorder::SetV4L2DeviceOptions(int chanfd)
 {
-    static const uint kNumControls = 7;
+   static const uint kNumControls = 7;
     struct v4l2_ext_controls ctrls;
     struct v4l2_ext_control ext_ctrl[kNumControls];
     QString control_description[kNumControls] =
@@ -625,60 +659,66 @@
     uint audio_layer = GetFilteredAudioLayer();
     uint audbitrate  = GetFilteredAudioBitRate(audio_layer);
 
-    ext_ctrl[0].id    = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
-    ext_ctrl[0].value = GetFilteredAudioSampleRate();
+    if (driver != "hdpvr") {
+        ext_ctrl[0].id    = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
+        ext_ctrl[0].value = GetFilteredAudioSampleRate();
+        
+        ext_ctrl[1].id    = V4L2_CID_MPEG_VIDEO_ASPECT;
+        ext_ctrl[1].value = aspectratio - 1;
+        
+        ext_ctrl[2].id    = V4L2_CID_MPEG_AUDIO_ENCODING;
+        ext_ctrl[2].value = audio_layer - 1;
+        
+        ext_ctrl[3].id    = V4L2_CID_MPEG_AUDIO_L2_BITRATE;
+        ext_ctrl[3].value = audbitrate - 1;
 
-    ext_ctrl[1].id    = V4L2_CID_MPEG_VIDEO_ASPECT;
-    ext_ctrl[1].value = aspectratio - 1;
+        ext_ctrl[4].id    = V4L2_CID_MPEG_STREAM_TYPE;
+        ext_ctrl[4].value = streamtype_ivtv_to_v4l2(GetFilteredStreamType());
+    }
 
-    ext_ctrl[2].id    = V4L2_CID_MPEG_AUDIO_ENCODING;
-    ext_ctrl[2].value = audio_layer - 1;
+    ext_ctrl[5].id    = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK;
+    ext_ctrl[5].value = maxbitrate * 1000;
 
-    ext_ctrl[3].id    = V4L2_CID_MPEG_AUDIO_L2_BITRATE;
-    ext_ctrl[3].value = audbitrate - 1;
+    ext_ctrl[6].id    = V4L2_CID_MPEG_VIDEO_BITRATE;
+    ext_ctrl[6].value = (bitrate = min(bitrate, maxbitrate)) * 1000;
 
-    ext_ctrl[4].id    = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK;
-    ext_ctrl[4].value = maxbitrate * 1000;
-
-    ext_ctrl[5].id    = V4L2_CID_MPEG_VIDEO_BITRATE;
-    ext_ctrl[5].value = (bitrate = min(bitrate, maxbitrate)) * 1000;
-
-    ext_ctrl[6].id    = V4L2_CID_MPEG_STREAM_TYPE;
-    ext_ctrl[6].value = streamtype_ivtv_to_v4l2(GetFilteredStreamType());
-
     for (uint i = 0; i < kNumControls; i++)
     {
         int value = ext_ctrl[i].value;
 
+        if (value != 0) {
+            ctrls.ctrl_class  = V4L2_CTRL_CLASS_MPEG;
+            ctrls.count       = 1;
+            ctrls.controls    = ext_ctrl + i;
+            
+            if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
+            {
+                VERBOSE(VB_IMPORTANT, LOC_ERR +
+                        QString("Could not set %1 to %2")
+                        .arg(control_description[i]).arg(value) + ENO);
+            }
+        }
+    }
+
+    if (driver != "hdpvr") {
+        // Get controls
+        ext_ctrl[0].id    = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
+        ext_ctrl[0].value = 0;
+        
         ctrls.ctrl_class  = V4L2_CTRL_CLASS_MPEG;
         ctrls.count       = 1;
-        ctrls.controls    = ext_ctrl + i;
-
-        if (ioctl(chanfd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
+        ctrls.controls    = ext_ctrl;
+        
+        if (ioctl(chanfd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
         {
-            VERBOSE(VB_IMPORTANT, LOC_ERR +
-                    QString("Could not set %1 to %2")
-                    .arg(control_description[i]).arg(value) + ENO);
+            VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to get "
+                    "V4L2_CID_MPEG_VIDEO_GOP_SIZE, defaulting to 12" + ENO);
+            ext_ctrl[0].value = 12;
         }
+        
+        keyframedist = ext_ctrl[0].value;
     }
 
-    // Get controls
-    ext_ctrl[0].id    = V4L2_CID_MPEG_VIDEO_GOP_SIZE;
-    ext_ctrl[0].value = 0;
-
-    ctrls.ctrl_class  = V4L2_CTRL_CLASS_MPEG;
-    ctrls.count       = 1;
-    ctrls.controls    = ext_ctrl;
-
-    if (ioctl(chanfd, VIDIOC_G_EXT_CTRLS, &ctrls) < 0)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to get "
-                "V4L2_CID_MPEG_VIDEO_GOP_SIZE, defaulting to 12" + ENO);
-        ext_ctrl[0].value = 12;
-    }
-
-    keyframedist = ext_ctrl[0].value;
-
     return true;
 }
 
@@ -687,6 +727,9 @@
     if (!vbimode)
         return true;
 
+    if (driver == "hdpvr")
+        return true;
+
     if (has_buggy_vbi)
     {
         cout<<" *********************** WARNING ***********************"<<endl;
@@ -717,8 +760,8 @@
 
         if (ioctl(chanfd, IVTV_IOC_G_VBI_MODE, &vbifmt) >= 0)
         {
-            VERBOSE(VB_RECORD, LOC + QString(
-                        "VBI service:%1, packet size:%2, io size:%3")
+            VERBOSE(VB_RECORD,
+                    LOC + QString("VBI service:%1, packet size:%2, io size:%3")
                     .arg(vbifmt.service_set).arg(vbifmt.packet_size)
                     .arg(vbifmt.io_size));
         }
@@ -733,7 +776,7 @@
         bzero(&vbifmt, sizeof(struct v4l2_format));
         vbifmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
         vbifmt.fmt.sliced.service_set |= (1 == vbimode) ?
-            V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+               V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
 
         if (ioctl(chanfd, VIDIOC_S_FMT, &vbifmt) < 0)
         {
@@ -809,22 +852,44 @@
 {
     if (!Open())
     {
-	errored = true;
-	return;
+        _error = true;
+        return;
     }
 
-    if (!SetupRecording())
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to setup recording.");
-	errored = true;
-	return;
+    _start_code = 0xffffffff;
+    _last_gop_seen = 0;
+    _frames_written_count = 0;
+
+    if (driver == "hdpvr") {
+        SetPositionMapType(MARK_GOP_BYFRAME);
+
+        if (_stream_data == NULL) {
+            MPEGStreamData *sd = new MPEGStreamData(1, true);
+	    sd->Reset();
+	    sd->SetRecordingType(_recording_type);
+            SetStreamData(sd);
+        }
+	else
+	    _stream_data->Reset(1);
+
+	// Make sure the first things in the file are a PAT & PMT
+	_wait_for_keyframe_option = false;
+	HandleSingleProgramPAT(_stream_data->PATSingleProgram());
+	HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
+	_wait_for_keyframe_option = true;
     }
+    else {
+        SetPositionMapType(MARK_GOP_START);
+    }
 
     encoding = true;
     recording = true;
+
     unsigned char *buffer = new unsigned char[bufferSize + 1];
-    int ret;
+    uint remainder = 0;
 
+    int len;
+
     MythTimer elapsedTimer;
     float elapsed;
 
@@ -839,10 +904,10 @@
         if (PauseAndWait(100))
             continue;
 
-        if ((deviceIsMpegFile) && (framesWritten))
+        if ((deviceIsMpegFile) && (GetFramesWritten()))
         {
             elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
-            while ((framesWritten / elapsed) > 30)
+            while ((GetFramesWritten() / elapsed) > 30)
             {
                 usleep(50000);
                 elapsed = (elapsedTimer.elapsed() / 1000.0) + 1;
@@ -852,178 +917,213 @@
         if (readfd < 0)
             readfd = open(videodevice.ascii(), O_RDWR);
 
-        tv.tv_sec = 5;
-        tv.tv_usec = 0;
-        FD_ZERO(&rdset);
-        FD_SET(readfd, &rdset);
-
 #if defined(__FreeBSD__)
         // HACK. FreeBSD PVR150/500 driver doesn't currently support select()
 #else
-        switch (select(readfd + 1, &rdset, NULL, NULL, &tv))
-        {
-            case -1:
+        // hdpvr driver does not like NONBLOCK mode with select
+        if (driver != "hdpvr") {
+            tv.tv_sec = 5;
+            tv.tv_usec = 0;
+            FD_ZERO(&rdset);
+            FD_SET(readfd, &rdset);
+
+            switch (select(readfd + 1, &rdset, NULL, NULL, &tv))
+            {
+              case -1:
                 if (errno == EINTR)
                     continue;
-
+                
                 VERBOSE(VB_IMPORTANT, LOC_ERR + "Select error" + ENO);
                 continue;
-
-            case 0:
+                
+              case 0:
                 VERBOSE(VB_IMPORTANT, LOC_ERR + "select timeout - "
                         "ivtv driver has stopped responding");
-
+                
                 if (close(readfd) != 0)
                 {
                     VERBOSE(VB_IMPORTANT, LOC_ERR + "Close error" + ENO);
                 }
-
+                
                 readfd = -1; // Force PVR card to be reopened on next iteration
                 continue;
-
-           default: break;
+                
+              default: break;
+            }
         }
 #endif
 
-        ret = read(readfd, buffer, bufferSize);
+	if (remainder)
+	    VERBOSE(VB_RECORD, LOC + QString("Remainder %1, Reading %2 bytes")
+		    .arg(remainder).arg(bufferSize - remainder));
+        len = read(readfd, &(buffer[remainder]), bufferSize - remainder);
 
-        if ((ret == 0) &&
-            (deviceIsMpegFile))
+        if ((len == 0) && (deviceIsMpegFile))
         {
             close(readfd);
             readfd = open(videodevice.ascii(), O_RDONLY);
 
             if (readfd >= 0)
-                ret = read(readfd, buffer, bufferSize);
-            if (ret <= 0)
+                len = read(readfd, &(buffer[remainder]),
+			   bufferSize - remainder);
+            if (len <= 0)
             {
                 encoding = false;
                 continue;
             }
         }
-        else if (ret < 0 && errno != EAGAIN)
+        else if (len < 0 && errno != EAGAIN)
         {
             VERBOSE(VB_IMPORTANT, LOC_ERR + QString("error reading from: %1")
                     .arg(videodevice) + ENO);
-
             continue;
         }
-        else if (ret > 0)
+        else if (len > 0)
         {
-            ProcessData(buffer, ret);
+	    len += remainder;
+
+            if (driver == "hdpvr")
+                ProcessTSdata(buffer, len, remainder);
+            else
+                ProcessPSdata(buffer, len);
         }
     }
 
     FinishRecording();
+    TeardownAll();
 
     delete[] buffer;
     recording = false;
 }
 
-bool MpegRecorder::SetupRecording(void)
+void MpegRecorder::ProcessPSdata(unsigned char *buffer, uint len)
 {
-    leftovers = 0xFFFFFFFF;
-    numgops = 0;
-    lastseqstart = 0;
-    return true;
+    FindPSKeyFrames(buffer, len);
 }
 
-void MpegRecorder::FinishRecording(void)
+void MpegRecorder::ProcessTSdata(unsigned char * buffer, uint len,
+				 uint & remainder)
 {
-    ringBuffer->WriterFlush();
+    uint idx, pos;
+    int       synced_cnt = 0;
 
-    if (curRecording)
-    {
-        curRecording->SetFilesize(ringBuffer->GetRealFileSize());
-        SavePositionMap(true);
-    }
-    positionMapLock.lock();
-    positionMap.clear();
-    positionMapDelta.clear();
-    positionMapLock.unlock();
-}
+#if 0
+    VERBOSE(VB_RECORD, LOC + QString("idx: %1, end: %2, remainder: %3, len: %4")
+	    .arg(TSPacket::SIZE - remainder)
+	    .arg(end)
+	    .arg(remainder)
+	    .arg(len));
+#endif
+    for (idx = 0; idx < len; ) {
+        // Find header
+        for (pos = idx; pos < len; ++pos) {
+            if (buffer[pos] == SYNC_BYTE )
+                break;
+        }
 
-#define PACK_HEADER   0x000001BA
-#define GOP_START     0x000001B8
-#define SEQ_START     0x000001B3
-#define SLICE_MIN     0x00000101
-#define SLICE_MAX     0x000001af
+        if (pos == len) {
+            VERBOSE(VB_IMPORTANT, LOC_ERR + "No TS header.");
+            break;
+        }
 
-void MpegRecorder::ProcessData(unsigned char *buffer, int len)
-{
-    unsigned char *bufptr = buffer, *bufstart = buffer;
-    unsigned int state = leftovers, v = 0;
-    int leftlen = len;
+        if (pos > idx) {
+            VERBOSE(VB_IMPORTANT, LOC_ERR +
+                    QString("TS packet at %1 not in sync, after %2")
+		    .arg(pos).arg(synced_cnt));
+	    synced_cnt = 0;
+        }
+	else
+	    ++synced_cnt;
 
-    while (bufptr < buffer + len)
-    {
-        v = *bufptr++;
-        if (state == 0x000001)
-        {
-            state = ((state << 8) | v) & 0xFFFFFF;
-            
-            if (state == PACK_HEADER)
-            {
-                long long startpos = ringBuffer->GetWritePosition();
-                startpos += buildbuffersize + bufptr - bufstart - 4;
-                lastpackheaderpos = startpos;
+        if ((len - pos) < TSPacket::SIZE) {
+            remainder = len - pos;
+            memmove(buffer, &buffer[pos], remainder);
+            VERBOSE(VB_RECORD, LOC_ERR +
+                    QString("TS packet at %1 stradles end of buffer.")
+                    .arg(pos));
+	    VERBOSE(VB_RECORD, LOC +
+		    QString("remainder: %1, idx: %2, pos: %3")
+		    .arg(remainder)
+		    .arg(idx)
+		    .arg(pos));
+            return;
+        }
 
-                int curpos = bufptr - bufstart - 4;
-                if (curpos < 0)
-                {
-                    // header was split
-                    buildbuffersize += curpos;
-                    if (buildbuffersize > 0)
-                        ringBuffer->Write(buildbuffer, buildbuffersize);
+        ProcessTSPacket(* reinterpret_cast<const TSPacket *>(buffer + pos));
 
-                    buildbuffersize = 4;
-                    memcpy(buildbuffer, &state, 4);
+        // Next packet
+        idx = pos + TSPacket::SIZE;
+    }
 
-                    leftlen = leftlen - curpos + 4;
-                    bufstart = bufptr;
-                }
-                else
-                {
-                    // header was entirely in this packet
-                    memcpy(buildbuffer + buildbuffersize, bufstart, curpos);
-                    buildbuffersize += curpos;
-                    bufstart += curpos;
-                    leftlen -= curpos;
+    remainder = 0;
+    return;
+}
 
-                    if (buildbuffersize > 0)
-                        ringBuffer->Write(buildbuffer, buildbuffersize);
+bool MpegRecorder::ProcessTSPacket(const TSPacket &tspacket)
+{
+    if (!_stream_data) {
+	VERBOSE(VB_RECORD, "ProcessTSPacket: !_stream_data");
+        return false;
+    }
 
-                    buildbuffersize = 0;
-                }
-            }
+    if (tspacket.TransportError() || tspacket.ScramplingControl())
+        return false;
 
-            if (state == SEQ_START)
-            {
-                lastseqstart = lastpackheaderpos;
-            }
+    if (tspacket.HasAdaptationField())
+        _stream_data->HandleAdaptationFieldControl(&tspacket);
 
-            if (state == GOP_START && lastseqstart == lastpackheaderpos)
-            {
-                framesWritten = numgops * keyframedist;
-                numgops++;
-                HandleKeyframe();
-            }
+    if (tspacket.HasPayload())
+    {
+        const unsigned int lpid = tspacket.PID();
+
+        // Pass or reject packets based on PID, and parse info from them
+        if (lpid == _stream_data->VideoPIDSingleProgram())
+        {
+            _buffer_packets = !FindH264Keyframes(&tspacket);
+
+            if (!_seen_sps)
+                return true;
         }
-        else
-            state = ((state << 8) | v) & 0xFFFFFF;
-    }
+        else if (_stream_data->IsAudioPID(lpid))
+        {
+            _buffer_packets = !FindAudioKeyframes(&tspacket);
+        }
+        else if (GetStreamData()->IsListeningPID(lpid))
+            GetStreamData()->HandleTSTables(&tspacket);
+        else if (GetStreamData()->IsWritingPID(lpid))
+            BufferedWrite(tspacket);
 
-    leftovers = state;
-
-    if (buildbuffersize + leftlen > kBuildBufferMaxSize)
-    {
-        ringBuffer->Write(buildbuffer, buildbuffersize);
-        buildbuffersize = 0;
+	const uint pid = tspacket.PID();
+	
+	// Check continuity counter
+	if ((pid != 0x1fff) && !CheckCC(pid, tspacket.ContinuityCounter()))
+	{
+	    VERBOSE(VB_RECORD, LOC +
+		    QString("PID 0x%1 discontinuity detected").arg(pid,0,16));
+	    _continuity_error_count++;
+	}
+	
+	// Sync recording start to first keyframe
+	if (_wait_for_keyframe_option && _first_keyframe < 0)
+	    return true;
+	
+	// Sync streams to the first Payload Unit Start Indicator
+	// _after_ first keyframe iff _wait_for_keyframe_option is true
+	if (!(_pid_status[pid] & kPayloadStartSeen) && tspacket.HasPayload())
+	{
+	    if (!tspacket.PayloadStart())
+		return true; // not payload start - drop packet
+	    
+	    VERBOSE(VB_RECORD,
+		    QString("PID 0x%1 Found Payload Start").arg(pid,0,16));
+	    
+	    _pid_status[pid] |= kPayloadStartSeen;
+	}
+	
+	BufferedWrite(tspacket);
     }
 
-    // copy remaining..
-    memcpy(buildbuffer + buildbuffersize, bufstart, leftlen);
-    buildbuffersize += leftlen;
+    return true;
 }
 
 void MpegRecorder::StopRecording(void)
@@ -1033,24 +1133,28 @@
 
 void MpegRecorder::ResetForNewFile(void)
 {
-    errored = false;
-    framesWritten = 0;
-    numgops = 0;
-    lastseqstart = lastpackheaderpos = 0;
+    DTVRecorder::ResetForNewFile();
 
-    positionMap.clear();
-    positionMapDelta.clear();
+    bzero(_stream_id,  sizeof(_stream_id));
+    bzero(_pid_status, sizeof(_pid_status));
+    memset(_continuity_counter, 0xff, sizeof(_continuity_counter));
 }
 
 void MpegRecorder::Reset(void)
 {
+    VERBOSE(VB_RECORD, LOC + "Reset(void)");
     ResetForNewFile();
 
-    leftovers = 0xFFFFFFFF;
-    buildbuffersize = 0;
+    _start_code = 0xffffffff;
 
-    if (curRecording)
-        curRecording->ClearPositionMap(MARK_GOP_START);
+    if (curRecording) {
+        if (driver == "hdpvr") {
+            curRecording->ClearPositionMap(MARK_GOP_BYFRAME);
+        }
+        else {
+            curRecording->ClearPositionMap(MARK_GOP_START);
+        }
+    }
 }
 
 void MpegRecorder::Pause(bool clear)
@@ -1095,58 +1199,108 @@
                 command.cmd = V4L2_ENC_CMD_START;
                 ioctl(readfd, VIDIOC_ENCODER_CMD, &command);
             }
+
+            if (_stream_data)
+                _stream_data->Reset(_stream_data->DesiredProgram());
         }
         paused = false;
     }
     return paused;
 }
 
-long long MpegRecorder::GetKeyframePosition(long long desired)
+void MpegRecorder::SetStreamData(MPEGStreamData *data)
 {
-    QMutexLocker locker(&positionMapLock);
-    long long ret = -1;
+    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- begin");
 
-    if (positionMap.find(desired) != positionMap.end())
-        ret = positionMap[desired];
+    if (data == _stream_data)
+    {
+        VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 0");
 
-    return ret;
+        return;
+    }
+
+    MPEGStreamData *old_data = _stream_data;
+    _stream_data = data;
+    if (old_data)
+        delete old_data;
+
+    if (data)
+        data->AddMPEGSPListener(this);
+
+    data->SetDesiredProgram(1);
+
+    VERBOSE(VB_RECORD, LOC + "SetStreamData("<<data<<") -- end 1");
 }
 
-// documented in recorderbase.h
-void MpegRecorder::SetNextRecording(const ProgramInfo *progInf, RingBuffer *rb)
+void MpegRecorder::HandleSingleProgramPAT(ProgramAssociationTable *pat)
 {
-    // First we do some of the time consuming stuff we can do now
-    SavePositionMap(true);
-    ringBuffer->WriterFlush();
-	if (curRecording)
-        curRecording->SetFilesize(ringBuffer->GetRealFileSize());
+    if (!pat)
+    {
+        VERBOSE(VB_RECORD, LOC + "HandleSingleProgramPAT(NULL)");
+        return;
+    }
 
-    // Then we set the next info
+    if (!ringBuffer)
+        return;
+
+    uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
+
+    uint next_cc = (pat->tsheader()->ContinuityCounter()+1)&0xf;
+    pat->tsheader()->SetContinuityCounter(next_cc);
+    DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(pat->tsheader())));
+
+    uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
+
+#if 0
+    if (posB[0] + posB[1] * TSPacket::SIZE > 
+        posA[0] + posA[1] * TSPacket::SIZE)
     {
-        QMutexLocker locker(&nextRingBufferLock);
-        nextRecording = NULL;
-        if (progInf)
-            nextRecording = new ProgramInfo(*progInf);
-        nextRingBuffer = rb;
+        VERBOSE(VB_RECORD, LOC + "Wrote PAT @"
+                << posA[0] << " + " << (posA[1] * TSPacket::SIZE));
     }
+    else
+    {
+        VERBOSE(VB_RECORD, LOC + "Saw PAT but did not write to disk yet");
+    }
+#endif
 }
 
-/** \fn MpegRecorder::HandleKeyframe(void)
- *  \brief This save the current frame to the position maps
- *         and handles ringbuffer switching.
- */
-void MpegRecorder::HandleKeyframe(void)
+void MpegRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
 {
-    // Add key frame to position map
-    positionMapLock.lock();
-    if (!positionMap.contains(numgops))
+    if (!pmt) {
+        return;
+    }
+
+    // collect stream types for H.264 (MPEG-4 AVC) keyframe detection
+    for (uint i = 0; i < pmt->StreamCount(); i++)
+        _stream_id[pmt->StreamPID(i)] = pmt->StreamType(i);
+
+    if (!ringBuffer)
+        return;
+
+    unsigned char buf[8 * 1024];
+    uint next_cc = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
+    pmt->tsheader()->SetContinuityCounter(next_cc);
+    uint size = pmt->WriteAsTSPackets(buf, next_cc);
+
+    uint posA[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
+
+    for (uint i = 0; i < size ; i += TSPacket::SIZE)
+        DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
+
+    uint posB[2] = { ringBuffer->GetWritePosition(), _payload_buffer.size() };
+
+#if 1
+    if (posB[0] + posB[1] * TSPacket::SIZE > 
+        posA[0] + posA[1] * TSPacket::SIZE)
     {
-        positionMapDelta[numgops] = lastpackheaderpos;
-        positionMap[numgops]      = lastpackheaderpos;
+        VERBOSE(VB_RECORD, LOC + "Wrote PMT @"
+                << posA[0] << " + " << (posA[1] * TSPacket::SIZE));
     }
-    positionMapLock.unlock();
-
-    // Perform ringbuffer switch if needed.
-    CheckForRingBufferSwitch();
+    else
+    {
+        VERBOSE(VB_RECORD, LOC + "Saw PMT but did not write to disk yet");
+    }
+#endif
 }
 
