Ticket #1660: hdtvrec-drb.patch

File hdtvrec-drb.patch, 32.5 KB (added by danielk, 6 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}