Ticket #1660: hdtvrec-drb.patch

File hdtvrec-drb.patch, 32.5 KB (added by danielk, 19 years ago)

Moved patch from #712 (a duplicate).

  • libs/libmythtv/hdtvrecorder.h

     
    33 *  HDTVRecorder
    44 *  Copyright (c) 2003-2004 by Brandon Beattie, Doug Larrick,
    55 *    Jason Hoos, and Daniel Thor Kristjansson
    6  *  Device ringbuffer added by John Poet
    76 *  Distributed as part of MythTV under GPL v2 and later.
    87 */
    98
     
    1211
    1312#include "dtvrecorder.h"
    1413#include "tsstats.h"
     14#include "DeviceReadBuffer.h"
    1515
    1616struct AVFormatContext;
    1717struct AVPacket;
     
    2828 *
    2929 *  \sa DTVRecorder, DVBRecorder
    3030 */
    31 class HDTVRecorder : public DTVRecorder
     31class HDTVRecorder : public DTVRecorder, private ReaderPausedCB
    3232{
    3333    Q_OBJECT
    3434    friend class ATSCStreamData;
    3535    friend class TSPacketProcessor;
    3636  public:
    37     enum {report_loops = 20000};
    38 
    3937    HDTVRecorder(TVRec *rec);
    4038   ~HDTVRecorder();
    4139
     
    4745    void StartRecording(void);
    4846    void StopRecording(void);
    4947
    50     void Pause(bool clear = false);
    51     bool IsPaused(void) const;
    52 
    5348    void Reset(void);
    5449
    5550    bool Open(void);
     
    6156    void deleteLater(void);
    6257
    6358  private:
     59    bool IsOpen(void) const { return _stream_fd >= 0; }
     60    bool Close(void);
     61
    6462    void TeardownAll(void);
    65     int ProcessData(unsigned char *buffer, int len);
     63    uint ProcessDataTS(unsigned char *buffer, uint len);
    6664    bool ProcessTSPacket(const TSPacket& tspacket);
    6765    void HandleVideo(const TSPacket* tspacket);
    6866    void HandleAudio(const TSPacket* tspacket);
    6967
    7068    int ResyncStream(unsigned char *buffer, int curr_pos, int len);
    7169
    72     static void *boot_ringbuffer(void *);
    73     void fill_ringbuffer(void);
    74     int ringbuf_read(unsigned char *buffer, size_t count);
     70    void ReaderPaused(int fd);
     71    bool PauseAndWait(int timeout = 100);
    7572
    76  private slots:
     73    bool readchan(int chanfd, unsigned char* buffer, int dlen);
     74    bool syncchan(int chanfd, int dlen, int keepsync);
     75
     76  private slots:
    7777    void WritePAT(ProgramAssociationTable*);
    7878    void WritePMT(ProgramMapTable*);
    7979    void ProcessMGT(const MasterGuideTable*);
    8080    void ProcessVCT(uint, const VirtualChannelTable*);
    81  private:
    82     ATSCStreamData* _atsc_stream_data;
    8381
     82  private:
     83    ATSCStreamData   *_atsc_stream_data;
     84    DeviceReadBuffer *_drb;
     85
    8486    // statistics
    85     TSStats _ts_stats;
    86     long long _resync_count;
    87     size_t loop;
     87    TSStats           _ts_stats;
     88    long long         _resync_count;
    8889
    89     // Data for managing the device ringbuffer
    90     struct {
    91         pthread_t        thread;
    92         mutable pthread_mutex_t lock;
    93         mutable pthread_mutex_t lock_stats;
    94 
    95         bool             run;
    96         bool             eof;
    97         bool             error;
    98         bool             request_pause;
    99         bool             paused;
    100         size_t           size;
    101         size_t           used;
    102         size_t           max_used;
    103         size_t           avg_used;
    104         size_t           avg_cnt;
    105         size_t           dev_read_size;
    106         size_t           min_read;
    107         unsigned char  * buffer;
    108         unsigned char  * readPtr;
    109         unsigned char  * writePtr;
    110         unsigned char  * endPtr;
    111     } ringbuf;
     90    /// unsynced packets to look at before giving up initially
     91    static const uint INIT_SYNC_WINDOW_SIZE;
     92    /// synced packets to require before starting recording
     93    static const uint INIT_MIN_NUM_SYNC_PACKETS;
    11294};
    11395
    11496#endif
  • libs/libmythtv/hdtvrecorder.cpp

     
    8484#include "atsctables.h"
    8585#include "atscstreamdata.h"
    8686#include "tv_rec.h"
     87#include "DeviceReadBuffer.h"
    8788
    8889// AVLib/FFMPEG includes
    8990#include "../libavcodec/avcodec.h"
    9091#include "../libavformat/avformat.h"
    9192#include "../libavformat/mpegts.h"
    9293
    93 #define REPORT_RING_STATS 1
     94#define LOC QString("HDTVRec(%1):").arg(videodevice)
     95#define LOC_ERR QString("HDTVRec(%1) Error:").arg(videodevice)
    9496
    9597#define DEFAULT_SUBCHANNEL 1
    9698
     
    109111        };
    110112#endif
    111113
     114const uint HDTVRecorder::INIT_SYNC_WINDOW_SIZE     = 50;
     115const uint HDTVRecorder::INIT_MIN_NUM_SYNC_PACKETS = 10;
     116
    112117HDTVRecorder::HDTVRecorder(TVRec *rec)
    113118    : DTVRecorder(rec, "HDTVRecorder"), _atsc_stream_data(0), _resync_count(0)
    114119{
     
    116121    connect(_atsc_stream_data, SIGNAL(UpdatePATSingleProgram(
    117122                                          ProgramAssociationTable*)),
    118123            this, SLOT(WritePAT(ProgramAssociationTable*)));
    119     connect(_atsc_stream_data, SIGNAL(UpdatePMTSingleProgram(ProgramMapTable*)),
    120             this, SLOT(WritePMT(ProgramMapTable*)));
     124    connect(_atsc_stream_data,
     125            SIGNAL(UpdatePMTSingleProgram(ProgramMapTable*)),
     126            this,
     127            SLOT(WritePMT(ProgramMapTable*)));
    121128    connect(_atsc_stream_data, SIGNAL(UpdateMGT(const MasterGuideTable*)),
    122129            this, SLOT(ProcessMGT(const MasterGuideTable*)));
    123130    connect(_atsc_stream_data,
     
    125132            this, SLOT(ProcessVCT(uint, const VirtualChannelTable*)));
    126133
    127134    _buffer_size = TSPacket::SIZE * 1500;
    128     if ((_buffer = new unsigned char[_buffer_size])) {
    129         // make valgrind happy, initialize buffer memory
     135    _buffer = new unsigned char[_buffer_size];
     136
     137    // make valgrind happy, initialize buffer memory
     138    if (_buffer)
    130139        memset(_buffer, 0xFF, _buffer_size);
    131     }
    132140
    133     VERBOSE(VB_RECORD, QString("HD buffer size %1 KB").arg(_buffer_size/1024));
     141    VERBOSE(VB_RECORD, LOC +
     142            QString("buffer size %1 KB").arg(_buffer_size/1024));
    134143
    135     ringbuf.run = false;
    136     ringbuf.buffer = 0;
    137     pthread_mutex_init(&ringbuf.lock, NULL);
    138     pthread_mutex_init(&ringbuf.lock_stats, NULL);
    139     loop = random() % (report_loops / 2);
     144    _drb = new DeviceReadBuffer(this);
    140145}
    141146
    142147void HDTVRecorder::TeardownAll(void)
    143148{
    144     // Make SURE that the ringbuffer thread is cleaned up
     149    // Make SURE that the device read thread is cleaned up -- John Poet
    145150    StopRecording();
    146151
    147     if (_stream_fd >= 0)
    148     {
    149         close(_stream_fd);
    150         _stream_fd = -1;
    151     }
     152    Close();
     153
    152154    if (_atsc_stream_data)
    153155    {
    154156        delete _atsc_stream_data;
     
    164166HDTVRecorder::~HDTVRecorder()
    165167{
    166168    TeardownAll();
    167     pthread_mutex_destroy(&ringbuf.lock);
    168     pthread_mutex_destroy(&ringbuf.lock_stats);
     169    delete _drb;
    169170}
    170171
    171172void HDTVRecorder::deleteLater(void)
     
    189190    SetOption("vbiformat", gContext->GetSetting("VbiFormat"));
    190191}
    191192
    192 bool HDTVRecorder::Open()
     193bool HDTVRecorder::Open(void)
    193194{
    194195    if (!_atsc_stream_data || !_buffer)
    195196        return false;
    196197
    197198#if FAKE_VIDEO
    198199    // open file instead of device
    199     if (_stream_fd >=0 && close(_stream_fd))
    200     {
    201         VERBOSE(VB_IMPORTANT,
    202                 QString("HDTVRecorder::Open(): Error, failed to close "
    203                         "existing fd (%1)").arg(strerror(errno)));
    204         return false;
    205     }
    206200
     201    Close(); // close old video file
    207202    _stream_fd = open(FAKE_VIDEO_FILES[fake_video_index], O_RDWR);
    208     VERBOSE(VB_IMPORTANT, QString("Opened fake video source %1").arg(FAKE_VIDEO_FILES[fake_video_index]));
    209     fake_video_index = (fake_video_index+1)%FAKE_VIDEO_NUM;
     203
     204    VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Opened fake video source '%1'")
     205            .arg(FAKE_VIDEO_FILES[fake_video_index]) + ENO);
     206
     207    fake_video_index = (fake_video_index + 1) % FAKE_VIDEO_NUM;
     208
    210209#else
    211     if (_stream_fd <= 0)
     210    if (!IsOpen())
    212211        _stream_fd = open(videodevice.ascii(), O_RDWR);
    213212#endif
    214     if (_stream_fd <= 0)
     213
     214    if (!IsOpen())
    215215    {
    216         VERBOSE(VB_IMPORTANT, QString("Can't open video device: %1 chanfd = %2")
    217                 .arg(videodevice).arg(_stream_fd));
    218         perror("open video:");
     216        VERBOSE(VB_IMPORTANT, LOC_ERR +
     217                QString("Couldn't open video device: '%1'")
     218                .arg(videodevice) + ENO);
    219219    }
    220     return (_stream_fd>0);
     220
     221    return IsOpen();
    221222}
    222223
     224bool HDTVRecorder::Close(void)
     225{
     226    if (IsOpen() && (0 != close(_stream_fd)))
     227    {
     228        VERBOSE(VB_IMPORTANT, LOC_ERR +
     229                "Failed to close file descriptor." + ENO);
     230        return false;
     231    }
     232    _stream_fd = -1;
     233    return true;
     234}
     235
    223236void HDTVRecorder::SetStreamData(ATSCStreamData *stream_data)
    224237{
    225238    if (stream_data == _atsc_stream_data)
     
    231244        delete old_data;
    232245}
    233246
    234 bool readchan(int chanfd, unsigned char* buffer, int dlen) {
     247bool HDTVRecorder::readchan(int chanfd, unsigned char* buffer, int dlen)
     248{
    235249    int len = read(chanfd, buffer, dlen); // read next byte
    236250    if (dlen != len)
    237251    {
    238252        if (len < 0)
    239253        {
    240             VERBOSE(VB_IMPORTANT, QString("HD1 error reading from device"));
    241             perror("read");
     254            VERBOSE(VB_IMPORTANT, LOC_ERR +
     255                    "Reading from device failed" + ENO);
    242256        }
    243257        else if (len == 0)
    244             VERBOSE(VB_IMPORTANT, QString("HD2 end of file found in packet"));
     258            VERBOSE(VB_IMPORTANT, LOC_ERR + "EOF found in TS packet");
    245259        else
    246             VERBOSE(VB_IMPORTANT, QString("HD3 partial read. This shouldn't happen!"));
     260            VERBOSE(VB_IMPORTANT, LOC_ERR +
     261                    "Partial read during initial TS sync phase");
    247262    }
    248263    return (dlen == len);
    249264}
    250265
    251 bool syncchan(int chanfd, int dlen, int keepsync) {
     266bool HDTVRecorder::syncchan(int chanfd, int dlen, int keepsync)
     267{
    252268    unsigned char b[188];
    253269    int i, j;
    254     for (i=0; i<dlen; i++) {
     270    for (i=0; i<dlen; i++)
     271    {
    255272        if (!readchan(chanfd, b, 1))
    256273            break;
    257274        if (SYNC_BYTE == b[0])
    258275        {
    259             if (readchan(chanfd, &b[1], TSPacket::SIZE-1)) {
     276            if (readchan(chanfd, &b[1], TSPacket::SIZE-1))
     277            {
    260278                i += (TSPacket::SIZE - 1);
    261279                for (j=0; j<keepsync; j++)
    262280                {
     
    268286                }
    269287                if (j==keepsync)
    270288                {
    271                     VERBOSE(VB_RECORD,
    272                             QString("HD4 obtained device stream sync after reading %1 bytes").
    273                             arg(dlen));
     289                    VERBOSE(VB_RECORD, LOC + "Obtained TS sync, "+
     290                            QString("after reading %1 bytes").arg(dlen));
    274291                    return true;
    275292                }
    276293                continue;
     
    278295            break;
    279296        }
    280297    }
    281     VERBOSE(VB_IMPORTANT, QString("HD5 Error: could not obtain sync"));
     298    VERBOSE(VB_IMPORTANT, LOC_ERR + "Could not obtain TS sync");
    282299    return false;
    283300}
    284301
    285 void * HDTVRecorder::boot_ringbuffer(void * arg)
    286 {
    287     HDTVRecorder *dtv = (HDTVRecorder *)arg;
    288     dtv->fill_ringbuffer();
    289     return NULL;
    290 }
     302#define SR_CHK(MSG) \
     303    if (!ok) { VERBOSE(VB_IMPORTANT, MSG); _error = true; return; }
    291304
    292 void HDTVRecorder::fill_ringbuffer(void)
     305void HDTVRecorder::StartRecording(void)
    293306{
    294     int       errcnt = 0;
    295     int       len;
    296     size_t    unused, used;
    297     size_t    contiguous;
    298     size_t    read_size;
    299     bool      run, request_pause, paused;
     307    bool ok        = true;
     308    uint len       = 0;
     309    uint remainder = 0;
    300310
    301     pthread_mutex_lock(&ringbuf.lock);
    302     ringbuf.run = true;
    303     pthread_mutex_unlock(&ringbuf.lock);
     311    VERBOSE(VB_RECORD, LOC + "StartRecording()");
    304312
    305     for (;;)
    306     {
    307         pthread_mutex_lock(&ringbuf.lock);
    308         run = ringbuf.run;
    309         unused = ringbuf.size - ringbuf.used;
    310         request_pause = ringbuf.request_pause;
    311         paused = ringbuf.paused;
    312         pthread_mutex_unlock(&ringbuf.lock);
     313    ok = Open();
     314    SR_CHK("Failed to open device.");
    313315
    314         if (!run)
    315             break;
     316    ok = _drb->Setup(videodevice, _stream_fd);
     317    SR_CHK("Failed to allocate device read buffer.");
    316318
    317         if (request_pause)
    318         {
    319             pthread_mutex_lock(&ringbuf.lock);
    320             ringbuf.paused = true;
    321             pthread_mutex_unlock(&ringbuf.lock);
     319    ok = syncchan(_stream_fd,
     320                  INIT_SYNC_WINDOW_SIZE * TSPacket::SIZE,
     321                  INIT_MIN_NUM_SYNC_PACKETS);
     322    SR_CHK("Failed to sync to transport stream to valid packet.");
    322323
    323             pauseWait.wakeAll();
    324             if (tvrec)
    325                 tvrec->RecorderPaused();
     324    _drb->Start();
    326325
    327             usleep(1000);
    328             continue;
    329         }
    330         else if (paused)
    331         {
    332             pthread_mutex_lock(&ringbuf.lock);
    333             ringbuf.writePtr = ringbuf.readPtr = ringbuf.buffer;
    334             ringbuf.used = 0;
    335             ringbuf.paused = false;
    336             pthread_mutex_unlock(&ringbuf.lock);
    337         }
    338 
    339         contiguous = ringbuf.endPtr - ringbuf.writePtr;
    340 
    341         while (unused < TSPacket::SIZE && contiguous > TSPacket::SIZE)
    342         {
    343             usleep(500);
    344 
    345             pthread_mutex_lock(&ringbuf.lock);
    346             unused = ringbuf.size - ringbuf.used;
    347             request_pause = ringbuf.request_pause;
    348             pthread_mutex_unlock(&ringbuf.lock);
    349 
    350             if (request_pause)
    351                 break;
    352         }
    353         if (request_pause)
    354             continue;
    355 
    356         read_size = unused > contiguous ? contiguous : unused;
    357         if (read_size > ringbuf.dev_read_size)
    358             read_size = ringbuf.dev_read_size;
    359 
    360         len = read(_stream_fd, ringbuf.writePtr, read_size);
    361 
    362         if (len < 0)
    363         {
    364             if (errno == EINTR)
    365                 continue;
    366 
    367             VERBOSE(VB_IMPORTANT, QString("HD7 error reading from %1")
    368                     .arg(videodevice));
    369             perror("read");
    370             if (++errcnt > 5)
    371             {
    372                 pthread_mutex_lock(&ringbuf.lock);
    373                 ringbuf.error = true;
    374                 pthread_mutex_unlock(&ringbuf.lock);
    375 
    376                 break;
    377             }
    378 
    379             usleep(500);
    380             continue;
    381         }
    382         else if (len == 0)
    383         {
    384             if (++errcnt > 5)
    385             {
    386                 VERBOSE(VB_IMPORTANT, QString("HD8 %1 end of file found.")
    387                         .arg(videodevice));
    388 
    389                 pthread_mutex_lock(&ringbuf.lock);
    390                 ringbuf.eof = true;
    391                 pthread_mutex_unlock(&ringbuf.lock);
    392 
    393                 break;
    394             }
    395             usleep(500);
    396             continue;
    397         }
    398 
    399         errcnt = 0;
    400 
    401         pthread_mutex_lock(&ringbuf.lock);
    402         ringbuf.used += len;
    403         used = ringbuf.used;
    404         ringbuf.writePtr += len;
    405         pthread_mutex_unlock(&ringbuf.lock);
    406 
    407 #ifdef REPORT_RING_STATS
    408         pthread_mutex_lock(&ringbuf.lock_stats);
    409 
    410         if (ringbuf.max_used < used)
    411             ringbuf.max_used = used;
    412 
    413         ringbuf.avg_used = ((ringbuf.avg_used * ringbuf.avg_cnt) + used)
    414                            / ++ringbuf.avg_cnt;
    415         pthread_mutex_unlock(&ringbuf.lock_stats);
    416 #endif
    417 
    418         if (ringbuf.writePtr == ringbuf.endPtr)
    419             ringbuf.writePtr = ringbuf.buffer;
    420     }
    421 
    422     close(_stream_fd);
    423     _stream_fd = -1;
    424 }
    425 
    426 /* read count bytes from ring into buffer */
    427 int HDTVRecorder::ringbuf_read(unsigned char *buffer, size_t count)
    428 {
    429     size_t          avail;
    430     size_t          cnt = count;
    431     size_t          min_read;
    432     unsigned char  *cPtr = buffer;
    433 
    434     bool            dev_error = false;
    435     bool            dev_eof = false;
    436 
    437     pthread_mutex_lock(&ringbuf.lock);
    438     avail = ringbuf.used;
    439     pthread_mutex_unlock(&ringbuf.lock);
    440 
    441     min_read = cnt < ringbuf.min_read ? cnt : ringbuf.min_read;
    442 
    443     while (min_read > avail)
    444     {
    445         usleep(50000);
    446 
    447         if (request_pause || dev_error || dev_eof)
    448             return 0;
    449 
    450         pthread_mutex_lock(&ringbuf.lock);
    451         dev_error = ringbuf.error;
    452         dev_eof = ringbuf.eof;
    453         avail = ringbuf.used;
    454         pthread_mutex_unlock(&ringbuf.lock);
    455     }
    456     if (cnt > avail)
    457         cnt = avail;
    458 
    459     if (ringbuf.readPtr + cnt > ringbuf.endPtr)
    460     {
    461         size_t      len;
    462 
    463         // Process as two pieces
    464         len = ringbuf.endPtr - ringbuf.readPtr;
    465         memcpy(cPtr, ringbuf.readPtr, len);
    466         cPtr += len;
    467         len = cnt - len;
    468 
    469         // Wrap arround to begining of buffer
    470         ringbuf.readPtr = ringbuf.buffer;
    471         memcpy(cPtr, ringbuf.readPtr, len);
    472         ringbuf.readPtr += len;
    473     }
    474     else
    475     {
    476         memcpy(cPtr, ringbuf.readPtr, cnt);
    477         ringbuf.readPtr += cnt;
    478     }
    479 
    480     pthread_mutex_lock(&ringbuf.lock);
    481     ringbuf.used -= cnt;
    482     pthread_mutex_unlock(&ringbuf.lock);
    483 
    484     if (ringbuf.readPtr == ringbuf.endPtr)
    485         ringbuf.readPtr = ringbuf.buffer;
    486     else
    487     {
    488 #ifdef REPORT_RING_STATS
    489         size_t samples, avg, max;
    490 
    491         if (++loop == report_loops)
    492         {
    493             loop = 0;
    494             pthread_mutex_lock(&ringbuf.lock_stats);
    495             avg = ringbuf.avg_used;
    496             samples = ringbuf.avg_cnt;
    497             max = ringbuf.max_used;
    498             ringbuf.avg_used = 0;
    499             ringbuf.avg_cnt = 0;
    500             ringbuf.max_used = 0;
    501             pthread_mutex_unlock(&ringbuf.lock_stats);
    502 
    503             VERBOSE(VB_IMPORTANT, QString("%1 ringbuf avg %2% max %3%"
    504                                           " samples %4")
    505                     .arg(videodevice)
    506                     .arg((static_cast<double>(avg)
    507                           / ringbuf.size) * 100.0)
    508                     .arg((static_cast<double>(max)
    509                           / ringbuf.size) * 100.0)
    510                     .arg(samples));
    511         }
    512         else
    513 #endif
    514             usleep(25);
    515     }
    516 
    517     return cnt;
    518 }
    519 
    520 void HDTVRecorder::StartRecording(void)
    521 {
    522     bool            pause;
    523     bool            dev_error, dev_eof;
    524     int             len;
    525 
    526     const int unsyncpackets = 50; // unsynced packets to look at before giving up
    527     const int syncpackets   = 10; // synced packets to require before starting recording
    528 
    529     VERBOSE(VB_RECORD, QString("StartRecording"));
    530 
    531     if (!Open())
    532     {
    533         _error = true;       
    534         return;
    535     }
    536 
    537326    _request_recording = true;
    538     _recording = true;
     327    _recording         = true;
    539328
    540     // Setup device ringbuffer
    541     delete[] ringbuf.buffer;
    542 
    543 //    ringbuf.size = 60 * 1024 * TSPacket::SIZE;
    544     ringbuf.size = gContext->GetNumSetting("HDRingbufferSize", 50*188);
    545     ringbuf.size *= 1024;
    546 
    547     if ((ringbuf.buffer =
    548          new unsigned char[ringbuf.size + TSPacket::SIZE]) == NULL)
     329    // Process packets while recording is requested
     330    while (_request_recording && !_error)
    549331    {
    550         VERBOSE(VB_IMPORTANT, "Failed to allocate HDTVRecorder ring buffer.");
    551         _error = true;
    552         return;
    553     }
    554 
    555     memset(ringbuf.buffer, 0xFF, ringbuf.size + TSPacket::SIZE);
    556     ringbuf.endPtr = ringbuf.buffer + ringbuf.size;
    557     ringbuf.readPtr = ringbuf.writePtr = ringbuf.buffer;
    558     ringbuf.dev_read_size = TSPacket::SIZE * 48;
    559     ringbuf.min_read = TSPacket::SIZE * 4;
    560     ringbuf.used = 0;
    561     ringbuf.max_used = 0;
    562     ringbuf.avg_used = 0;
    563     ringbuf.avg_cnt = 0;
    564     ringbuf.request_pause = false;
    565     ringbuf.paused = false;
    566     ringbuf.error = false;
    567     ringbuf.eof = false;
    568 
    569     VERBOSE(VB_RECORD, QString("HD ring buffer size %1 KB")
    570             .arg(ringbuf.size/1024));
    571 
    572     // sync device stream so it starts with a valid ts packet
    573     if (!syncchan(_stream_fd, TSPacket::SIZE*unsyncpackets, syncpackets))
    574     {
    575         _error = true;
    576         return;
    577     }
    578 
    579     // create thread to fill the ringbuffer
    580     pthread_create(&ringbuf.thread, NULL, boot_ringbuffer,
    581                    reinterpret_cast<void *>(this));
    582 
    583     int remainder = 0;
    584     // TRANSFER DATA
    585     while (_request_recording)
    586     {
    587         pthread_mutex_lock(&ringbuf.lock);
    588         dev_error = ringbuf.error;
    589         dev_eof = ringbuf.eof;
    590         pause = ringbuf.paused;
    591         pthread_mutex_unlock(&ringbuf.lock);
    592 
    593         if (request_pause)
    594         {
    595             pthread_mutex_lock(&ringbuf.lock);
    596             ringbuf.request_pause = true;
    597             pthread_mutex_unlock(&ringbuf.lock);
    598 
    599             usleep(1000);
     332        if (PauseAndWait())
    600333            continue;
    601         }
    602         else if (pause)
    603         {
    604             pthread_mutex_lock(&ringbuf.lock);
    605             ringbuf.request_pause = false;
    606             pthread_mutex_unlock(&ringbuf.lock);
    607334
    608             usleep(1500);
    609             continue;
    610         }
     335        len = _drb->Read(&(_buffer[remainder]), _buffer_size - remainder);
    611336
    612         if (dev_error)
    613         {
    614             VERBOSE(VB_IMPORTANT, "HDTV: device error detected");
    615             _error = true;
    616             break;
    617         }
    618 
    619         if (dev_eof)
    620             break;
    621 
    622         len = ringbuf_read(&(_buffer[remainder]), _buffer_size - remainder);
    623 
    624337        if (len == 0)
    625338            continue;
    626339
    627340        len += remainder;
    628         remainder = ProcessData(_buffer, len);
     341        remainder = ProcessDataTS(_buffer, len);
    629342        if (remainder > 0) // leftover bytes
    630343            memmove(_buffer, &(_buffer[_buffer_size - remainder]),
    631344                    remainder);
     345
     346        // Check for DRB errors
     347        if (_drb->IsErrored())
     348        {
     349            VERBOSE(VB_IMPORTANT, LOC_ERR + "Device error detected");
     350            _error = true;
     351        }
     352
     353        if (_drb->IsEOF())
     354        {
     355            VERBOSE(VB_IMPORTANT, LOC_ERR + "Device EOF detected");
     356            _error = true;
     357        }
    632358    }
    633359
    634360    FinishRecording();
    635361    _recording = false;
    636362}
     363#undef SR_CHK
    637364
    638365void HDTVRecorder::StopRecording(void)
    639366{
     
    649376
    650377    _request_recording = false;
    651378
    652     pthread_mutex_lock(&ringbuf.lock);
    653     bool run = ringbuf.run;
    654     ringbuf.run = false;
    655     pthread_mutex_unlock(&ringbuf.lock);
     379    if (_drb && _drb->IsRunning())
     380        _drb->Stop();
    656381
    657     if (run)
    658         pthread_join(ringbuf.thread, NULL);
     382    while (_recording)
     383        usleep(2000);
    659384
    660     if (!ok)
    661     {
    662         // Better to have a memory leak, then a segfault?
    663         VERBOSE(VB_IMPORTANT, "DTV ringbuffer not cleaned up!\n");
    664     }
    665     else
    666     {
    667         delete[] ringbuf.buffer;
    668         ringbuf.buffer = 0;
    669     }
    670385    tvrec = rec;
    671386}
    672387
    673 void HDTVRecorder::Pause(bool /*clear*/)
     388void HDTVRecorder::ReaderPaused(int /*fd*/)
    674389{
    675     pthread_mutex_lock(&ringbuf.lock);
    676     ringbuf.paused = false;
    677     pthread_mutex_unlock(&ringbuf.lock);
    678     request_pause = true;
     390    pauseWait.wakeAll();
     391    if (tvrec)
     392        tvrec->RecorderPaused();
    679393}
    680394
    681 bool HDTVRecorder::IsPaused(void) const
     395bool HDTVRecorder::PauseAndWait(int timeout)
    682396{
    683     pthread_mutex_lock(&ringbuf.lock);
    684     bool paused = ringbuf.paused;
    685     pthread_mutex_unlock(&ringbuf.lock);
     397#ifdef USE_DRB
     398    if (request_pause)
     399    {
     400        paused = true;
     401        if (!_drb->IsPaused())
     402            _drb->SetRequestPause(true);
    686403
     404        unpauseWait.wait(timeout);
     405    }
     406    else if (_drb->IsPaused())
     407    {
     408        _drb->SetRequestPause(false);
     409        _drb->WaitForUnpause(timeout);
     410        paused = _drb->IsPaused();
     411    }
     412    else
     413    {
     414        paused = false;
     415    }
    687416    return paused;
     417#else // if !USE_DRB
     418    return RecorderBase::PauseAndWait(timeout);
     419#endif // !USE_DRB
    688420}
    689421
    690422int HDTVRecorder::ResyncStream(unsigned char *buffer, int curr_pos, int len)
     
    695427    if (nextpos >= len)
    696428        return -1; // not enough bytes; caller should try again
    697429   
    698     while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE) {
     430    while (buffer[pos] != SYNC_BYTE || buffer[nextpos] != SYNC_BYTE)
     431    {
    699432        pos++;
    700433        nextpos++;
    701434        if (nextpos == len)
     
    707440
    708441void HDTVRecorder::WritePAT(ProgramAssociationTable *pat)
    709442{
     443    if (!pat)
     444        return;
     445
    710446    int next = (pat->tsheader()->ContinuityCounter()+1)&0xf;
    711447    pat->tsheader()->SetContinuityCounter(next);
    712448    ringBuffer->Write(pat->tsheader()->data(), TSPacket::SIZE);
    713449}
    714450
    715 #if WHACK_A_BUG_VIDEO
    716 static int WABV_base_pid     = 0x100;
    717 #define WABV_WAIT 60
    718 static int WABV_wait_a_while = WABV_WAIT;
    719 bool WABV_started = false;
    720 #endif
    721 
    722 #if WHACK_A_BUG_AUDIO
    723 static int WABA_base_pid     = 0x200;
    724 #define WABA_WAIT 60
    725 static int WABA_wait_a_while = WABA_WAIT;
    726 bool WABA_started = false;
    727 #endif
    728 
    729451void HDTVRecorder::WritePMT(ProgramMapTable* pmt)
    730452{
    731     if (pmt) {
    732         int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
    733         pmt->tsheader()->SetContinuityCounter(next);
     453    if (!pmt)
     454        return;
    734455
    735 #if WHACK_A_BUG_VIDEO
    736         WABV_wait_a_while--;
    737         if (WABV_wait_a_while<=0) {
    738             WABV_started = true;
    739             WABV_wait_a_while = WABV_WAIT;
    740             WABV_base_pid = (((WABV_base_pid-0x100)+1)%32)+0x100;
    741             if (StreamID::MPEG2Video != StreamData()->PMT()->StreamType(0))
    742             {
    743                 VERBOSE(VB_IMPORTANT, "HDTVRecorder::WritePMT(): Error,"
    744                         "Whack a Bug can not rewrite PMT, wrong stream type");
    745             }
    746             else
    747             {
    748                 VERBOSE(VB_IMPORTANT, QString("Whack a Bug: new video pid %1").
    749                         arg(WABV_base_pid));
    750                 // rewrite video pid
    751                 const uint old_video_pid=StreamData()->PMT()->StreamPID(0);
    752                 StreamData()->PMT()->SetStreamPID(0, WABV_base_pid);
    753                 if (StreamData()->PMT()->PCRPID() == old_video_pid)
    754                     StreamData()->PMT()->SetPCRPID(WABV_base_pid);
    755                 StreamData()->PMT()->SetCRC(StreamData()->PMT()->CalcCRC());
    756                 VERBOSE(VB_IMPORTANT, StreamData()->PMT()->toString());
    757             }
    758         }
    759 #endif
    760 #if WHACK_A_BUG_AUDIO
    761         WABA_wait_a_while--;
    762         if (WABA_wait_a_while<=0) {
    763             WABA_started = true;
    764             WABA_wait_a_while = WABA_WAIT;
    765             WABA_base_pid = (((WABA_base_pid-0x200)+1)%32)+0x200;
    766             VERBOSE(VB_IMPORTANT, QString("Whack a Bug: new audio BASE pid %1").arg(WABA_base_pid));
    767             // rewrite audio pids
    768             for (uint i=0; i<StreamData()->PMT()->StreamCount(); i++) {
    769                 if (StreamID::MPEG2Audio == StreamData()->PMT()->StreamType(i) ||
    770                     StreamID::MPEG2Audio == StreamData()->PMT()->StreamType(i)) {
    771                     const uint old_audio_pid = StreamData()->PMT()->StreamPID(i);
    772                     const uint new_audio_pid = WABA_base_pid + old_audio_pid;
    773                     StreamData()->PMT()->SetStreamPID(i, new_audio_pid);
    774                     if (StreamData()->PMT()->PCRPID() == old_audio_pid)
    775                         StreamData()->PMT()->SetPCRPID(new_audio_pid);
    776                     StreamData()->PMT()->SetCRC(StreamData()->PMT()->CalcCRC());
    777                     VERBOSE(VB_IMPORTANT, StreamData()->PMT()->toString());
    778                 }
    779             }
    780         }
    781 #endif
    782 
    783         ringBuffer->Write(pmt->tsheader()->data(), TSPacket::SIZE);
    784     }
     456    int next = (pmt->tsheader()->ContinuityCounter()+1)&0xf;
     457    pmt->tsheader()->SetContinuityCounter(next);
     458    ringBuffer->Write(pmt->tsheader()->data(), TSPacket::SIZE);
    785459}
    786460
    787461/** \fn HDTVRecorder::ProcessMGT(const MasterGuideTable*)
     
    820494        {
    821495            if (vct->ProgramNumber(i) != (uint)StreamData()->DesiredProgram())
    822496            {
    823                 VERBOSE(VB_RECORD,
    824                         QString("Resetting desired program from %1"
    825                                 " to %2")
     497                VERBOSE(VB_RECORD, LOC_ERR +
     498                        QString("Resetting desired program from %1 to %2")
    826499                        .arg(StreamData()->DesiredProgram())
    827500                        .arg(vct->ProgramNumber(i)));
    828501                // Do a (partial?) reset here if old desired
     
    834507    }
    835508    if (!found)
    836509    {
    837         VERBOSE(VB_IMPORTANT,
     510        VERBOSE(VB_IMPORTANT, LOC_ERR +
    838511                QString("Desired channel %1_%2 not found;"
    839512                        " using %3_%4 instead.")
    840513                .arg(StreamData()->DesiredMajorChannel())
    841514                .arg(StreamData()->DesiredMinorChannel())
    842515                .arg(vct->MajorChannel(0))
    843                 .arg(vct->MinorChannel(0)));
    844         VERBOSE(VB_IMPORTANT, vct->toString());
     516                .arg(vct->MinorChannel(0)) + "\n" + vct->toString());
     517
    845518        StreamData()->SetDesiredProgram(vct->ProgramNumber(0));
    846519    }
    847520}
     
    854527    if (_wait_for_keyframe && !_keyframe_seen)
    855528        return;
    856529
    857 #if WHACK_A_BUG_VIDEO
    858     if (WABV_started)
    859         ((TSPacket*)(tspacket))->SetPID(WABV_base_pid);
    860 #endif
    861 
    862530    ringBuffer->Write(tspacket->data(), TSPacket::SIZE);
    863531}
    864532
     
    868536    if (_wait_for_keyframe && !_keyframe_seen)
    869537        return;
    870538
    871 #if WHACK_A_BUG_AUDIO
    872     if (WABA_started)
    873         ((TSPacket*)(tspacket))->SetPID(WABA_base_pid+tspacket->PID());
    874 #endif
    875 
    876539    ringBuffer->Write(tspacket->data(), TSPacket::SIZE);
    877540}
    878541
     
    902565    return ok;
    903566}
    904567
    905 int HDTVRecorder::ProcessData(unsigned char *buffer, int len)
     568uint HDTVRecorder::ProcessDataTS(unsigned char *buffer, uint len)
    906569{
    907     int pos = 0;
     570    if (len < TSPacket::SIZE)
     571        return len;
    908572
    909     while (pos + 187 < len) // while we have a whole packet left
     573    uint pos = 0;
     574    uint end = len - TSPacket::SIZE;
     575    while (pos <= end) // while we have a whole packet left
    910576    {
    911577        if (buffer[pos] != SYNC_BYTE)
    912578        {
    913579            _resync_count++;
    914             if (25 == _resync_count)
    915                 VERBOSE(VB_RECORD, QString("Resyncing many of times, suppressing error messages"));
     580
     581            if (25 == _resync_count)
     582            {
     583                VERBOSE(VB_RECORD, LOC + "Resyncing many of times, "
     584                        "suppressing error messages");
     585            }
    916586            else if (25 > _resync_count)
    917                 VERBOSE(VB_RECORD, QString("Resyncing"));
     587            {
     588                VERBOSE(VB_RECORD, LOC + "Resyncing");
     589            }
     590
    918591            int newpos = ResyncStream(buffer, pos, len);
    919592            if (newpos == -1)
    920593                return len - pos;
     
    925598        }
    926599
    927600        const TSPacket *pkt = reinterpret_cast<const TSPacket*>(&buffer[pos]);
    928         if (ProcessTSPacket(*pkt)) {
    929             pos += TSPacket::SIZE; // Advance to next TS packet
     601        if (ProcessTSPacket(*pkt))
     602        {
     603            // Advance to next TS packet
     604            pos += TSPacket::SIZE;
     605
     606            // Take care of statistics
    930607            _ts_stats.IncrTSPacketCount();
    931             if (0 == _ts_stats.TSPacketCount()%1000000)
    932                 VERBOSE(VB_RECORD, _ts_stats.toString());
    933         } else // Let it resync in case of dropped bytes
    934             buffer[pos] = SYNC_BYTE+1;
     608            if (0 == _ts_stats.TSPacketCount() % 1000000)
     609                VERBOSE(VB_RECORD, LOC + "\n" + _ts_stats.toString());
     610
     611        }
     612        else
     613        {
     614            pos++; // Resync on invalid packet, in case of dropped bytes...
     615        }
    935616    }
    936617
    937618    return len - pos;
     
    939620
    940621void HDTVRecorder::Reset(void)
    941622{
    942     VERBOSE(VB_RECORD, "HDTVRecorder::Reset(void)");
     623    VERBOSE(VB_RECORD, LOC + "Reset(void)");
    943624    DTVRecorder::Reset();
    944625
    945626    _error = false;
     
    947628    _ts_stats.Reset();
    948629
    949630    if (curRecording)
    950     {
    951631        curRecording->ClearPositionMap(MARK_GOP_BYFRAME);
     632
     633    if (!IsOpen())
     634        return /* true */;
     635
     636    if (!IsPaused())
     637    {
     638        Pause();
     639        WaitForPause();
    952640    }
    953641
    954     if (_stream_fd >= 0)
     642    if (!Close())
     643        return /* false */;
     644
     645    if (Open())
    955646    {
    956         if (!IsPaused())
    957         {
    958             Pause();
    959             WaitForPause();
    960         }
    961         int ret = close(_stream_fd);
    962         if (ret < 0)
    963         {
    964             perror("close");
    965             return;
    966         }
    967 #if FAKE_VIDEO
    968         // open file instead of device
    969         _stream_fd = open(FAKE_VIDEO_FILES[fake_video_index], O_RDWR);
    970         VERBOSE(VB_IMPORTANT, QString("Opened fake video source %1").arg(FAKE_VIDEO_FILES[fake_video_index]));
    971         fake_video_index = (fake_video_index+1)%FAKE_VIDEO_NUM;
    972 #else
    973         _stream_fd = open(videodevice.ascii(), O_RDWR);
    974 #endif
    975         if (_stream_fd < 0)
    976         {
    977             VERBOSE(VB_IMPORTANT, QString("HD1 Can't open video device: %1 chanfd = %2").
    978                     arg(videodevice).arg(_stream_fd));
    979             perror("open video");
    980             return;
    981         }
    982         else
    983         {
    984             pthread_mutex_lock(&ringbuf.lock);
    985             ringbuf.used = 0;
    986             ringbuf.max_used = 0;
    987             ringbuf.readPtr = ringbuf.writePtr = ringbuf.buffer;
    988             pthread_mutex_unlock(&ringbuf.lock);
    989         }
     647        _drb->Reset(videodevice, _stream_fd);
    990648        Unpause();
     649        return /* true */;
    991650    }
     651
     652    VERBOSE(VB_IMPORTANT, LOC_ERR + "Couldn't open video device: " +
     653            QString("'%1'").arg(videodevice) + ENO);
     654    return /* false */;
    992655}