Ticket #8812: 8812-v1.patch

File 8812-v1.patch, 43.7 KB (added by danielk, 10 years ago)

Initial patch

  • libs/libmythtv/RingBuffer.cpp

     
    1919
    2020using namespace std;
    2121
     22#include "mythcontext.h" // for VERBOSE
    2223#include "mythconfig.h"
    23 
    2424#include "exitcodes.h"
    2525#include "RingBuffer.h"
    2626#include "remotefile.h"
     
    3030#include "BDRingBuffer.h"
    3131#include "util.h"
    3232#include "compat.h"
    33 #include "mythverbose.h"
    3433
    3534#ifndef O_STREAMING
    3635#define O_STREAMING 0
     
    6564
    6665/*
    6766  Locking relations:
    68     rwlock->readAheadLock
    69           ->readsAllowedWaitMutex->readAheadRunningCondLock
    70           ->availWaitMutex
     67    rwlock->poslock
    7168
    7269  A child should never lock any of the parents without locking
    7370  the parent lock before the child lock.
     
    113110RingBuffer::RingBuffer(const QString &lfilename,
    114111                       bool write, bool readahead,
    115112                       uint read_retries)
    116     : filename(lfilename),      subtitlefilename(QString::null),
     113    : readpos(0),               writepos(0),
     114      stopreads(false),
     115      filename(lfilename),      subtitlefilename(QString::null),
    117116      tfw(NULL),                fd2(-1),
    118       writemode(false),
    119       readpos(0),               writepos(0),
    120       stopreads(false),         remotefile(NULL),
     117      writemode(false),         remotefile(NULL),
    121118      startreadahead(readahead),readAheadBuffer(NULL),
    122       readaheadrunning(false),  readaheadpaused(false),
    123       pausereadthread(false),
     119      readaheadrunning(false),
     120      request_pause(false),     paused(false),
    124121      rbrpos(0),                rbwpos(0),
    125122      internalreadpos(0),       ateof(false),
    126       readsallowed(false),      wantseek(false), setswitchtonext(false),
     123      readsallowed(false),
     124      setswitchtonext(false),
    127125      rawbitrate(4000),         playspeed(1.0f),
    128126      fill_threshold(65536),    fill_min(-1),
    129127      readblocksize(CHUNK),     wanttoread(0),
     
    273271    VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2)")
    274272            .arg(lfilename).arg(retryCount));
    275273
     274    rwlock.lockForWrite();
     275
    276276    uint openAttempts = retryCount + 1;
    277277
    278278    filename = lfilename;
     
    414414    else if (is_dvd)
    415415    {
    416416        dvdPriv->OpenFile(filename);
    417         rwlock.lockForWrite();
    418417        readblocksize = DVD_BLOCK_SIZE * 62;
    419         rwlock.unlock();
    420418    }
    421419    else if (is_bd)
    422420    {
    423421        bdPriv->OpenFile(filename);
    424         rwlock.lockForWrite();
    425422        readblocksize = BD_BLOCK_SIZE * 62;
    426         rwlock.unlock();
    427423    }
    428424#endif // USING_FRONTEND
    429425    else
     
    478474    commserror = false;
    479475    numfailures = 0;
    480476
    481     UpdateRawBitrate(4000);
     477    rawbitrate = 4000;
     478    CalcReadAheadThresh();
     479
     480    rwlock.unlock();
    482481}
    483482
    484483/** \fn RingBuffer::IsOpen(void) const
     
    486485 */
    487486bool RingBuffer::IsOpen(void) const
    488487{
     488    rwlock.lockForRead();
     489    bool ret;
    489490#ifdef USING_FRONTEND
    490     return tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
     491    ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
    491492           (bdPriv && bdPriv->IsOpen());
    492493#else // if !USING_FRONTEND
    493     return tfw || (fd2 > -1) || remotefile;
     494    ret = tfw || (fd2 > -1) || remotefile;
    494495#endif // !USING_FRONTEND
     496    rwlock.unlock();
     497    return ret;
    495498}
    496499
    497500/** \fn RingBuffer::~RingBuffer(void)
     
    535538    rwlock.unlock();
    536539}
    537540
    538 /** \fn RingBuffer::Start(void)
    539  *  \brief Starts the read-ahead thread.
    540  *
    541  *   If this RingBuffer is not in write-mode, the RingBuffer constructor
    542  *   was called with a usereadahead of true, and the read-ahead thread
    543  *   is not already running.
    544  */
    545 void RingBuffer::Start(void)
    546 {
    547     if (!writemode && !readaheadrunning && startreadahead)
    548         StartupReadAheadThread();
    549 }
    550 
    551541/** \fn RingBuffer::Reset(bool, bool, bool)
    552542 *  \brief Resets the read-ahead thread and our position in the file
    553543 */
    554544void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal)
    555545{
    556     wantseek = true;
    557546    rwlock.lockForWrite();
    558     wantseek = false;
     547    poslock.lockForWrite();
     548
    559549    numfailures = 0;
    560550    commserror = false;
    561551    setswitchtonext = false;
     
    579569    if (resetInternal)
    580570        internalreadpos = readpos;
    581571
     572    poslock.unlock();
    582573    rwlock.unlock();
    583574}
    584575
     
    695686    rwlock.unlock();
    696687}
    697688
    698 /** \fn RingBuffer::GetBitrate(void) const
    699  *  \brief Returns effective bits per second (in thousands).
    700  *
    701  *   NOTE: This is reported in telecom kilobytes, to get
    702  *         the bits per second multiply by 1000, not 1024.
    703  */
    704 uint RingBuffer::GetBitrate(void) const
    705 {
    706     rwlock.lockForRead();
    707     uint tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
    708     rwlock.unlock();
    709     return min(rawbitrate * 3, tmp);
    710 }
    711 
    712 /** \fn RingBuffer::GetReadBlockSize(void) const
    713  *  \brief Returns size of each disk read made by read ahead thread (in bytes).
    714  */
    715 uint RingBuffer::GetReadBlockSize(void) const
    716 {
    717     rwlock.lockForRead();
    718     uint tmp = readblocksize;
    719     rwlock.unlock();
    720     return tmp;
    721 }
    722 
    723689/** \fn RingBuffer::UpdatePlaySpeed(float)
    724690 *  \brief Set the play speed, to allow RingBuffer adjust effective bitrate.
    725691 *  \param play_speed Speed to set. (1.0 for normal speed)
     
    743709{
    744710    uint estbitrate = 0;
    745711
    746     wantseek       = false;
    747712    readsallowed   = false;
    748713    readblocksize  = CHUNK;
    749714
     
    785750            .arg(fill_min/1024).arg(readblocksize/1024));
    786751}
    787752
    788 /** \fn RingBuffer::ReadBufFree(void) const
    789  *  \brief Returns number of bytes available for reading into buffer.
    790  */
     753bool RingBuffer::IsNearEnd(double fps, uint vvf) const
     754{
     755    rwlock.lockForRead();
     756    int    sz  = ReadBufAvail();
     757    uint   rbs = readblocksize;
     758    // telecom kilobytes (i.e. 1000 per k not 1024)
     759    uint   tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
     760    uint   kbits_per_sec = min(rawbitrate * 3, tmp);
     761    rwlock.unlock();
     762
     763    // WARNING: readahead_frames can greatly overestimate or underestimate
     764    //          the number of frames available in the read ahead buffer
     765    //          when rh_frames is less than the keyframe distance.
     766    double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps;
     767    double readahead_frames = sz / bytes_per_frame;
     768
     769    bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5);
     770
     771    VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
     772            <<" br("<<(kbits_per_sec/8)<<"KB)"
     773            <<" sz("<<(sz / 1000)<<"KB)"
     774            <<" vfl("<<vvf<<")"
     775            <<" frh("<<((uint)readahead_frames)<<")"
     776            <<" ne:"<<near_end);
     777
     778    return near_end;
     779}
     780
     781/// \brief Returns number of bytes available for reading into buffer.
     782/// WARNING: Must be called with rwlock in locked state.
    791783int RingBuffer::ReadBufFree(void) const
    792784{
    793     QMutexLocker locker(&readAheadLock);
    794785    return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
    795786}
    796787
    797 /** \fn RingBuffer::ReadBufAvail(void) const
    798  *  \brief Returns number of bytes available for reading from buffer.
    799  */
     788/// \brief Returns number of bytes available for reading from buffer.
     789/// WARNING: Must be called with rwlock in locked state.
    800790int RingBuffer::ReadBufAvail(void) const
    801791{
    802     QMutexLocker locker(&readAheadLock);
    803     return (rbwpos >= rbrpos) ?
    804         rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     792    return (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
    805793}
    806794
    807795/** \fn RingBuffer::ResetReadAhead(long long)
     
    817805 */
    818806void RingBuffer::ResetReadAhead(long long newinternal)
    819807{
    820     readAheadLock.lock();
    821808    readblocksize = CHUNK;
    822809    rbrpos = 0;
    823810    rbwpos = 0;
     
    825812    ateof = false;
    826813    readsallowed = false;
    827814    setswitchtonext = false;
    828     readAheadLock.unlock();
    829815}
    830816
    831 /** \fn RingBuffer::StartupReadAheadThread(void)
    832  *  \brief Creates the read-ahead thread, and waits for it to start.
     817/**
     818 *  \brief Starts the read-ahead thread.
    833819 *
    834  *  \sa Start(void).
     820 *   If the RingBuffer constructor was not called with a usereadahead
     821 *   of true of if this was reset to false because we're dealing with
     822 *   a DVD the read ahead thread will not be started.
     823 *
     824 *   If this RingBuffer is in write-mode a warning will be printed and
     825 *   the read ahead thread will not be started.
     826 *
     827 *   If the read ahead thread is already running a warning will be printed
     828 *   and the read ahead thread will not be started.
     829 *
    835830 */
    836 void RingBuffer::StartupReadAheadThread(void)
     831void RingBuffer::Start(void)
    837832{
    838     readaheadrunning = false;
     833    VERBOSE(VB_IMPORTANT, LOC + "Start)");   
    839834
    840     readAheadRunningCondLock.lock();
     835    bool do_start = true;
     836
     837    rwlock.lockForWrite();
     838    if (!startreadahead)
     839    {
     840        do_start = false;
     841    }
     842    else if (writemode)
     843    {
     844        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     845                "this is a write only RingBuffer");
     846        do_start = false;
     847    }
     848    else if (readaheadrunning)
     849    {
     850        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     851                "already running");
     852        do_start = false;
     853    }
     854
     855    if (!do_start)
     856    {
     857        rwlock.unlock();
     858        return;
     859    }
     860
    841861    QThread::start();
    842     readAheadRunningCond.wait(&readAheadRunningCondLock);
    843     readAheadRunningCondLock.unlock();
     862    readAheadRunningWait.wait(&rwlock);
     863    rwlock.unlock();
    844864}
    845865
    846866/** \fn RingBuffer::KillReadAheadThread(void)
     
    848868 */
    849869void RingBuffer::KillReadAheadThread(void)
    850870{
    851     if (!readaheadrunning)
    852         return;
     871    rwlock.lockForWrite();
     872    bool do_wait = readaheadrunning;
     873    readaheadrunning = false;
     874    readsAllowedWait.wakeAll();
     875    pauseWait.wakeAll();
     876    unpauseWait.wakeAll();
     877    availWait.wakeAll();
     878    readsAllowedWait.wakeAll();
     879    rwlock.unlock();
    853880
    854     readaheadrunning = false;
    855     QThread::wait();
     881    if (do_wait)
     882        QThread::wait();
    856883}
    857884
    858885/** \fn RingBuffer::StopReads(void)
     
    880907 */
    881908void RingBuffer::Pause(void)
    882909{
    883     pausereadthread = true;
    884910    StopReads();
     911
     912    rwlock.lockForWrite();
     913    request_pause = true;
     914    rwlock.unlock();
    885915}
    886916
    887917/** \fn RingBuffer::Unpause(void)
     
    891921void RingBuffer::Unpause(void)
    892922{
    893923    StartReads();
    894     pausereadthread = false;
     924
     925    rwlock.lockForWrite();
     926    request_pause = false;
     927    unpauseWait.wakeAll();
     928    rwlock.unlock();
    895929}
    896930
     931/// Returns false iff read-ahead is not running and read-ahead is not paused.
     932bool RingBuffer::isPaused(void) const
     933{
     934    rwlock.lockForRead();
     935    bool ret = !readaheadrunning || paused;
     936    rwlock.unlock();
     937    return ret;
     938}
     939
    897940/** \fn RingBuffer::WaitForPause(void)
    898941 *  \brief Waits for Pause(void) to take effect.
    899942 */
    900943void RingBuffer::WaitForPause(void)
    901944{
    902     if (!readaheadrunning)
    903         return;
     945    MythTimer t;
     946    t.start();
    904947
    905     if  (!readaheadpaused)
     948    rwlock.lockForRead();
     949    while (readaheadrunning && !paused && request_pause)
    906950    {
    907         // Qt4 requires a QMutex as a parameter...
    908         // not sure if this is the best solution.  Mutex Must be locked before wait.
    909         QMutex mutex;
    910         mutex.lock();
     951        pauseWait.wait(&rwlock, 1000);
     952        if (readaheadrunning && !paused && request_pause)
     953        {
     954            VERBOSE(VB_IMPORTANT, LOC +
     955                    QString("Waited %1 ms for ringbuffer pause..")
     956                    .arg(t.elapsed()));
     957        }
     958    }
     959    rwlock.unlock();
     960}
    911961
    912         while (!pauseWait.wait(&mutex, 1000))
    913             VERBOSE(VB_IMPORTANT,
    914                     LOC + "Waited too long for ringbuffer pause..");
     962bool RingBuffer::PauseAndWait(void)
     963{
     964    const uint timeout = 500; // ms
     965
     966    if (request_pause)
     967    {
     968        if (!paused)
     969        {
     970            rwlock.unlock();
     971            rwlock.lockForWrite();
     972
     973            if (request_pause)
     974            {
     975                paused = true;
     976                pauseWait.wakeAll();
     977            }
     978
     979            rwlock.unlock();
     980            rwlock.lockForRead();
     981        }
     982
     983        if (request_pause && paused && readaheadrunning)
     984            unpauseWait.wait(&rwlock, timeout);
    915985    }
     986
     987    if (!request_pause && paused)
     988    {
     989        rwlock.unlock();
     990        rwlock.lockForWrite();
     991
     992        if (!request_pause)
     993        {
     994            paused = false;
     995            unpauseWait.wakeAll();
     996        }
     997
     998        rwlock.unlock();
     999        rwlock.lockForRead();
     1000    }
     1001
     1002    return request_pause || paused;
    9161003}
    9171004
    9181005void RingBuffer::run(void)
     
    9201007    long long totfree = 0;
    9211008    int ret = -1;
    9221009    int used = 0;
    923     int loops = 0;
    9241010
    9251011    struct timeval lastread, now;
    9261012    gettimeofday(&lastread, NULL);
     
    9281014    int readtimeavg = 300;
    9291015    int readinterval;
    9301016
    931     pausereadthread = false;
    932 
     1017    rwlock.lockForWrite();
     1018    request_pause = false;
    9331019    readAheadBuffer = new char[kBufferSize + KB640];
    934 
    935     rwlock.lockForWrite();
    9361020    ResetReadAhead(0);
     1021    readaheadrunning = true;
     1022    readAheadRunningWait.wakeAll();
    9371023    rwlock.unlock();
    9381024
    939     totfree = ReadBufFree();
     1025    // NOTE: this must loop at some point hold only
     1026    // a read lock on rwlock, so that other functions
     1027    // such as reset and seek can take priority.
    9401028
    941     readaheadrunning = true;
    942     readAheadRunningCondLock.lock();
    943     readAheadRunningCond.wakeAll();
    944     readAheadRunningCondLock.unlock();
     1029    rwlock.lockForRead();
    9451030    while (readaheadrunning)
    9461031    {
    947         if (pausereadthread || writemode)
    948         {
    949             readaheadpaused = true;
    950             pauseWait.wakeAll();
    951             usleep(5000);
    952             totfree = ReadBufFree();
     1032        if (PauseAndWait())
    9531033            continue;
    954         }
    9551034
    956         if (readaheadpaused)
    957         {
    958             totfree = ReadBufFree();
    959             readaheadpaused = false;
    960         }
     1035        totfree = ReadBufFree();
    9611036
    962         totfree = ReadBufFree();
    963         if (totfree < GetReadBlockSize())
     1037        if (totfree < readblocksize)
    9641038        {
     1039            rwlock.unlock();
    9651040            usleep(50000);
    966             totfree = ReadBufFree();
    967             ++loops;
    968             // break out if we've spent lots of time here, just in case things
    969             // are waiting on a wait condition that never got triggered.
    970             if (readsallowed && loops < 10)
    971                 continue;
     1041            rwlock.lockForRead();
     1042            continue;
    9721043        }
    973         loops = 0;
    9741044
    975         rwlock.lockForRead();
    976         if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
     1045        if (totfree > readblocksize && !commserror &&
     1046            !ateof && !setswitchtonext)
    9771047        {
    9781048            // limit the read size
    9791049            totfree = readblocksize;
     
    10361106                internalreadpos += ret;
    10371107            }
    10381108
    1039             readAheadLock.lock();
     1109            rwlock.unlock();
     1110
     1111            rwlock.lockForWrite();
    10401112            if (ret > 0 )
    10411113                rbwpos = (rbwpos + ret) % kBufferSize;
    1042             readAheadLock.unlock();
     1114            rwlock.unlock();
    10431115
     1116            rwlock.lockForRead();
     1117
    10441118            if (ret == 0 && !stopreads)
    10451119            {
    10461120                if (livetvchain)
     
    10531127                    }
    10541128                }
    10551129                else
     1130                {
     1131                    rwlock.unlock();
     1132                    rwlock.lockForWrite();
    10561133                    ateof = true;
     1134                    rwlock.unlock();
     1135                    rwlock.lockForRead();
     1136                }
    10571137            }
    10581138        }
    10591139
     1140        rwlock.unlock();
     1141        rwlock.lockForWrite();
     1142
    10601143        if (numfailures > 5)
    10611144            commserror = true;
    10621145
     
    10871170            //                                                   .arg(fill_min));
    10881171        }
    10891172
    1090         readsAllowedWaitMutex.lock();
    1091         if (readsallowed || stopreads)
     1173        if (readsallowed || stopreads || commserror)
    10921174            readsAllowedWait.wakeAll();
    1093         readsAllowedWaitMutex.unlock();
    10941175
    1095         availWaitMutex.lock();
    10961176        if (commserror || ateof || stopreads || setswitchtonext ||
    10971177            (wanttoread <= used && wanttoread > 0))
    10981178        {
    10991179            availWait.wakeAll();
    11001180        }
    1101         availWaitMutex.unlock();
    11021181
     1182        bool do_yield =
     1183            ((used >= fill_threshold || ateof || setswitchtonext) &&
     1184             !request_pause);
     1185
    11031186        rwlock.unlock();
    11041187
    1105         if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
    1106             !pausereadthread)
    1107         {
    1108             usleep(500);
    1109         }
     1188        if (do_yield)
     1189            usleep(5000);
     1190
     1191        rwlock.lockForRead();
    11101192    }
    11111193
     1194    rwlock.unlock();
     1195
    11121196    delete [] readAheadBuffer;
    11131197    readAheadBuffer = NULL;
     1198
     1199    rwlock.lockForWrite();
    11141200    rbrpos = 0;
    11151201    rbwpos = 0;
     1202    rwlock.unlock();
    11161203}
    11171204
    11181205long long RingBuffer::SetAdjustFilesize(void)
    11191206{
     1207    rwlock.lockForWrite();
    11201208    readAdjust += internalreadpos;
     1209    rwlock.unlock();
    11211210    return readAdjust;
    11221211}
    11231212
    11241213int RingBuffer::Peek(void *buf, int count)
    11251214{
    1126     long long ret = -1;
    1127 
    1128     if (!readaheadrunning)
    1129     {
    1130         long long old_pos = Seek(0, SEEK_CUR);
    1131 
    1132         ret = Read(buf, count);
    1133 #ifdef USING_FRONTEND
    1134         if (ret > 0 && dvdPriv)
    1135         {
    1136             // This is technically incorrect it we should seek
    1137             // back to exactly where we were, but we can't do
    1138             // that with the DVDRingBuffer
    1139             dvdPriv->NormalSeek(0);
    1140         }
    1141         else if (ret > 0 && bdPriv)
    1142         {
    1143             // No idea if this will work.
    1144             bdPriv->Seek(0);
    1145         }
    1146         else
    1147 #endif // USING_FRONTEND
    1148         if (ret > 0)
    1149         {
    1150             long long new_pos = Seek(-ret, SEEK_CUR);
    1151             if (new_pos != old_pos)
    1152             {
    1153                 VERBOSE(VB_IMPORTANT, LOC_ERR +
    1154                         QString("Peek() Failed to return from new "
    1155                                 "position %1 to old position %2, now "
    1156                                 "at position %3")
    1157                         .arg(old_pos - ret).arg(old_pos).arg(new_pos));
    1158             }
    1159         }
    1160     }
    1161     else
    1162     {
    1163         ret = ReadFromBuf(buf, count, true);
    1164     }
    1165 
     1215    rwlock.lockForWrite();
     1216    int ret = ReadPriv(buf, count, true);
    11661217    if (ret != count)
    11671218    {
    11681219        VERBOSE(VB_IMPORTANT, LOC_WARN +
    11691220                QString("Peek() requested %1 bytes, but only returning %2")
    11701221                .arg(count).arg(ret));
    11711222    }
     1223    rwlock.unlock();
    11721224    return ret;
    11731225}
    11741226
    1175 /**
    1176  *  \brief Reads from the read-ahead buffer, this is called by
    1177  *         Read(void*, int) when the read-ahead thread is running.
    1178  *  \param buf   Pointer to where data will be written
    1179  *  \param count Number of bytes to read
    1180  *  \param peek  If true, don't increment read count
    1181  *  \return Returns number of bytes read
    1182  */
    1183 int RingBuffer::ReadFromBuf(void *buf, int count, bool peek)
     1227bool RingBuffer::WaitForReadsAllowed(void)
    11841228{
    1185     if (commserror)
    1186         return 0;
     1229    MythTimer t;
     1230    t.start();
    11871231
    1188     bool readone = false;
    1189     int readErr = 0;
    1190 
    1191     if (readaheadpaused && stopreads)
     1232    while (!readsallowed && !stopreads &&
     1233           !request_pause && !commserror && readaheadrunning)
    11921234    {
    1193         readone = true;
    1194         Unpause();
    1195     }
    1196     else
    1197     {
    1198         QMutexLocker locker(&readsAllowedWaitMutex);
     1235        readsAllowedWait.wait(&rwlock, 500);
     1236        if (!readsallowed)
     1237        {
     1238            VERBOSE(VB_IMPORTANT,
     1239                    LOC + "Taking too long to be allowed to read..");
    11991240
    1200         while (!readsallowed && !stopreads)
    1201         {
    1202             if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000))
     1241            if (t.elapsed() > 10000)
    12031242            {
    1204                  VERBOSE(VB_IMPORTANT,
    1205                          LOC + "Taking too long to be allowed to read..");
    1206                  readErr++;
    1207 
    1208                  // HACK Sometimes the readhead thread gets borked on startup.
    1209                  if ((readErr > 4 && readErr % 2) && (rbrpos ==0))
    1210                  {
    1211                     VERBOSE(VB_IMPORTANT, "restarting readhead thread..");
    1212                     KillReadAheadThread();
    1213                     StartupReadAheadThread();
    1214                  }
    1215 
    1216                  if (readErr > 10)
    1217                  {
    1218                      VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
    1219                              "10 seconds to be allowed to read, aborting.");
    1220                      wanttoread = 0;
    1221                      stopreads = true;
    1222                      return 0;
    1223                  }
     1243                VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
     1244                        "10 seconds to be allowed to read, aborting.");
     1245                return false;
    12241246            }
    12251247        }
    12261248    }
    12271249
     1250    return readsallowed;
     1251}
     1252
     1253bool RingBuffer::WaitForAvail(int count)
     1254{
    12281255    int avail = ReadBufAvail();
     1256    count = (ateof && avail < count) ? avail : count;
    12291257
    1230     if (ateof && avail < count)
    1231         count = avail;
    1232 
    12331258    MythTimer t;
    12341259    t.start();
    1235     while (avail < count && !stopreads)
     1260    while ((avail < count) && !stopreads &&
     1261           !request_pause && !commserror && readaheadrunning)
    12361262    {
    1237         availWaitMutex.lock();
    12381263        wanttoread = count;
    1239         if (!availWait.wait(&availWaitMutex, 250))
     1264        availWait.wait(&rwlock, 250);
     1265        avail = ReadBufAvail();
     1266
     1267        if ((ateof || setswitchtonext) && avail < count)
     1268            count = avail;
     1269
     1270        if (avail < count)
    12401271        {
    12411272            int elapsed = t.elapsed();
    1242             if  (/*((elapsed > 500)  && (elapsed < 750))  ||*/
     1273            if  (((elapsed > 500)  && (elapsed < 750))  ||
    12431274                 ((elapsed > 1000) && (elapsed < 1250)) ||
    12441275                 ((elapsed > 2000) && (elapsed < 2250)) ||
    12451276                 ((elapsed > 4000) && (elapsed < 4250)) ||
    1246                  ((elapsed > 8000) && (elapsed < 8250)))
     1277                 ((elapsed > 8000) && (elapsed < 8250)) ||
     1278                 ((elapsed > 9000)))
    12471279            {
    12481280                VERBOSE(VB_IMPORTANT, LOC + "Waited " +
    12491281                        QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) +
     
    12701302                    VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to "
    12711303                            "impending livetv switch.");
    12721304
    1273                 ateof = true;
    1274                 wanttoread = 0;
    1275                 stopreads = true;
    1276                 availWaitMutex.unlock();
    1277                 return 0;
     1305                return false;
    12781306            }
    12791307        }
     1308    }
    12801309
    1281         wanttoread = 0;
    1282         availWaitMutex.unlock();
     1310    wanttoread = 0;
    12831311
    1284         avail = ReadBufAvail();
    1285         if ((ateof || setswitchtonext) && avail < count)
    1286             count = avail;
     1312    return avail >= count;
     1313}
    12871314
    1288         if (commserror)
    1289             return 0;
     1315int RingBuffer::ReadDirect(void *buf, int count, bool peek)
     1316{
     1317    long long old_pos = 0;
     1318    if (peek)
     1319    {
     1320        poslock.lockForRead();
     1321        old_pos = readpos;
     1322        poslock.unlock();
    12901323    }
    12911324
    1292     if ((ateof || stopreads) && avail < count)
    1293         count = avail;
     1325    int ret;
     1326    if (remotefile)
     1327        ret = safe_read(remotefile, buf, count);
     1328#ifdef USING_FRONTEND
     1329    else if (dvdPriv)
     1330        ret = dvdPriv->safe_read(buf, count);
     1331    else if (bdPriv)
     1332        ret = bdPriv->safe_read(buf, count);
     1333#endif // USING_FRONTEND
     1334    else if (fd2 >= 0)
     1335        ret = safe_read(fd2, buf, count);
     1336    else
     1337    {
     1338        ret = -1;
     1339        errno = EBADF;
     1340    }
    12941341
     1342    if (peek && ret > 0)
     1343    {
     1344#ifdef USING_FRONTEND
     1345        if (dvdPriv)
     1346        {
     1347            // This is technically incorrect it we should seek
     1348            // back to exactly where we were, but we can't do
     1349            // that with the DVDRingBuffer
     1350            dvdPriv->NormalSeek(0);
     1351        }
     1352        else if (bdPriv)
     1353        {
     1354            // No idea if this will work.
     1355            bdPriv->Seek(0);
     1356        }
     1357        else
     1358#endif // USING_FRONTEND
     1359        {
     1360            rwlock.unlock();
     1361            long long new_pos = Seek(-ret, SEEK_CUR);
     1362            rwlock.lockForWrite();
     1363            if (new_pos != old_pos)
     1364            {
     1365                VERBOSE(VB_IMPORTANT, LOC_ERR +
     1366                        QString("Peek() Failed to return from new "
     1367                                "position %1 to old position %2, now "
     1368                                "at position %3")
     1369                        .arg(old_pos - ret).arg(old_pos).arg(new_pos));
     1370            }
     1371        }
     1372    }
     1373
     1374    return ret;
     1375}
     1376
     1377/** \brief When possible reads from the read-ahead buffer,
     1378 *         otherwise reads directly from the device.
     1379 *
     1380 *   WARNING: Must be called with rwlock in write lock state.
     1381 *
     1382 *  \param buf   Pointer to where data will be written
     1383 *  \param count Number of bytes to read
     1384 *  \param peek  If true, don't increment read count
     1385 *  \return Returns number of bytes read
     1386 */
     1387int RingBuffer::ReadPriv(void *buf, int count, bool peek)
     1388{
     1389    if (writemode)
     1390    {
     1391        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1392                "Attempt to read from a write only file");
     1393        errno = EBADF;
     1394        return -1;
     1395    }
     1396
     1397    if (commserror)
     1398    {
     1399        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1400                "Attempt to read after commserror set");
     1401        errno = EIO;
     1402        return -1;
     1403    }
     1404
     1405    if (request_pause || stopreads || !readaheadrunning)
     1406    {
     1407        return ReadDirect(buf, count, peek);
     1408    }
     1409
     1410    if (!WaitForReadsAllowed())
     1411    {
     1412        VERBOSE(VB_FILE, LOC + "!WaitForReadsAllowed()");
     1413        wanttoread = 0;
     1414        stopreads = true;
     1415        return 0;
     1416    }
     1417
     1418    if (!WaitForAvail(count))
     1419    {
     1420        VERBOSE(VB_FILE, LOC + "!WaitForAvail()");
     1421        ateof = true;
     1422        wanttoread = 0;
     1423        stopreads = true;
     1424        return 0;
     1425    }
     1426
     1427    count = min(ReadBufAvail(), count);
     1428
     1429    if (count <= 0)
     1430        return count;
     1431
    12951432    if (rbrpos + count > (int) kBufferSize)
    12961433    {
    12971434        int firstsize = kBufferSize - rbrpos;
     
    13041441        memcpy(buf, readAheadBuffer + rbrpos, count);
    13051442
    13061443    if (!peek)
    1307     {
    1308         readAheadLock.lock();
    13091444        rbrpos = (rbrpos + count) % kBufferSize;
    1310         readAheadLock.unlock();
    1311     }
    13121445
    1313     if (readone)
    1314     {
    1315         Pause();
    1316         WaitForPause();
    1317     }
    1318 
    13191446    return count;
    13201447}
    13211448
     
    13291456 */
    13301457int RingBuffer::Read(void *buf, int count)
    13311458{
    1332     int ret = -1;
    1333     if (writemode)
     1459    rwlock.lockForWrite();
     1460    int ret = ReadPriv(buf, count, false);
     1461    if (ret > 0)
    13341462    {
    1335         VERBOSE(VB_IMPORTANT, LOC_ERR +
    1336                 "Attempt to read from a write only file");
    1337         return ret;
    1338     }
    1339 
    1340     rwlock.lockForRead();
    1341 
    1342     if (!readaheadrunning)
    1343     {
    1344         if (remotefile)
    1345         {
    1346             ret = safe_read(remotefile, buf, count);
    1347             readpos += ret;
    1348         }
    1349 #ifdef USING_FRONTEND
    1350         else if (dvdPriv)
    1351         {
    1352             ret = dvdPriv->safe_read(buf, count);
    1353             readpos += ret;
    1354         }
    1355         else if (bdPriv)
    1356         {
    1357             ret = bdPriv->safe_read(buf, count);
    1358             readpos += ret;
    1359         }
    1360 #endif // USING_FRONTEND
    1361         else
    1362         {
    1363             ret = safe_read(fd2, buf, count);
    1364             readpos += ret;
    1365         }
    1366     }
    1367     else
    1368     {
    1369         ret = ReadFromBuf(buf, count);
     1463        poslock.lockForWrite();
    13701464        readpos += ret;
     1465        poslock.unlock();
    13711466    }
    1372 
    13731467    rwlock.unlock();
    13741468    return ret;
    13751469}
    13761470
    13771471/** \fn RingBuffer::IsIOBound(void) const
    1378  *  \brief Returns true if a RingBuffer::Read(void*,int) is likely to block.
     1472 *  \brief Returns true if a RingBuffer::Write(void*,int) is likely to block.
    13791473 */
    13801474bool RingBuffer::IsIOBound(void) const
    13811475{
     
    14041498 */
    14051499int RingBuffer::Write(const void *buf, uint count)
    14061500{
    1407     int ret = -1;
     1501    rwlock.lockForRead();
     1502
    14081503    if (!writemode)
    14091504    {
    14101505        VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file.");
    1411         return ret;
     1506        rwlock.unlock();
     1507        return -1;
    14121508    }
    14131509
    14141510    if (!tfw && !remotefile)
    1415         return ret;
     1511    {
     1512        rwlock.unlock();
     1513        return -1;
     1514    }
    14161515
    1417     rwlock.lockForRead();
    1418 
     1516    int ret = -1;
    14191517    if (tfw)
    14201518        ret = tfw->Write(buf, count);
    14211519    else
    14221520        ret = remotefile->Write(buf, count);
    1423     writepos += ret;
    14241521
     1522    if (ret > 0)
     1523    {
     1524        poslock.lockForWrite();
     1525        writepos += ret;
     1526        poslock.unlock();
     1527    }
     1528
    14251529    rwlock.unlock();
     1530
    14261531    return ret;
    14271532}
    14281533
     
    14311536 */
    14321537void RingBuffer::Sync(void)
    14331538{
     1539    rwlock.lockForRead();
    14341540    if (tfw)
    14351541        tfw->Sync();
     1542    rwlock.unlock();
    14361543}
    14371544
    14381545/** \fn RingBuffer::Seek(long long, int)
     
    14401547 */
    14411548long long RingBuffer::Seek(long long pos, int whence)
    14421549{
     1550    long long ret = -1;
     1551
     1552    // lockForWrite takes priority over lockForRead, so this will
     1553    // take priority over the lockForRead in the read ahead thread.
     1554    rwlock.lockForWrite();
     1555
    14431556    if (writemode)
     1557    {
     1558        rwlock.unlock();
    14441559        return WriterSeek(pos, whence);
     1560    }
    14451561
    1446     wantseek = true;
    1447     rwlock.lockForWrite();
    1448     wantseek = false;
     1562    poslock.lockForRead();
    14491563
    14501564    // optimize nop seeks
    14511565    if ((whence == SEEK_SET && pos == readpos) ||
    14521566        (whence == SEEK_CUR && pos == 0))
    14531567    {
     1568        ret = readpos;
     1569
    14541570        rwlock.unlock();
    1455         return readpos;
     1571        poslock.unlock();
     1572
     1573        return ret;
    14561574    }
    14571575
    14581576    errno = 0; // clear errno, in case of remotefile error
    14591577
    1460     long long ret = -1;
    14611578    if (remotefile)
     1579    {
    14621580        ret = remotefile->Seek(pos, whence, readpos);
     1581    }
    14631582#ifdef USING_FRONTEND
    14641583    else if (dvdPriv)
    14651584    {
     
    14911610        }
    14921611    }
    14931612
     1613    poslock.unlock();
     1614
     1615    poslock.lockForWrite();
     1616
    14941617    if (ret >= 0)
    14951618    {
    14961619        if (whence == SEEK_SET)
     
    15111634        VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
    15121635    }
    15131636
     1637    poslock.unlock();
    15141638    rwlock.unlock();
    15151639
    15161640    return ret;
     
    15231647{
    15241648    long long ret = -1;
    15251649
     1650    rwlock.lockForRead();
     1651    poslock.lockForWrite();
     1652
    15261653    if (tfw)
    15271654    {
    15281655        ret = tfw->Seek(pos, whence);
    15291656        writepos = ret;
    15301657    }
    15311658
     1659    poslock.unlock();
     1660    rwlock.unlock();
     1661
    15321662    return ret;
    15331663}
    15341664
     
    15381668 */
    15391669void RingBuffer::WriterFlush(void)
    15401670{
     1671    rwlock.lockForRead();
    15411672    if (tfw)
    15421673    {
    15431674        tfw->Flush();
    15441675        tfw->Sync();
    15451676    }
     1677    rwlock.unlock();
    15461678}
    15471679
    15481680/** \fn RingBuffer::SetWriteBufferSize(int)
     
    15501682 */
    15511683void RingBuffer::SetWriteBufferSize(int newSize)
    15521684{
     1685    rwlock.lockForRead();
    15531686    if (tfw)
    15541687        tfw->SetWriteBufferSize(newSize);
     1688    rwlock.unlock();
    15551689}
    15561690
    15571691/** \fn RingBuffer::SetWriteBufferMinWriteSize(int)
     
    15591693 */
    15601694void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize)
    15611695{
     1696    rwlock.lockForRead();
    15621697    if (tfw)
    15631698        tfw->SetWriteBufferMinWriteSize(newMinSize);
     1699    rwlock.unlock();
    15641700}
    15651701
    15661702/** \fn RingBuffer::GetReadPosition(void) const
     
    15681704 */
    15691705long long RingBuffer::GetReadPosition(void) const
    15701706{
     1707    rwlock.lockForRead();
     1708    poslock.lockForRead();
     1709    long long ret = readpos;
    15711710#ifdef USING_FRONTEND
    15721711    if (dvdPriv)
    1573         return dvdPriv->GetReadPosition();
     1712        ret = dvdPriv->GetReadPosition();
    15741713    else if (bdPriv)
    1575         return bdPriv->GetReadPosition();
     1714        ret = bdPriv->GetReadPosition();
    15761715#endif // USING_FRONTEND
    1577 
    1578     return readpos;
     1716    poslock.unlock();
     1717    rwlock.unlock();
     1718    return ret;
    15791719}
    15801720
    15811721/** \fn RingBuffer::GetWritePosition(void) const
     
    15831723 */
    15841724long long RingBuffer::GetWritePosition(void) const
    15851725{
    1586     return writepos;
     1726    poslock.lockForRead();
     1727    long long ret = writepos;
     1728    poslock.unlock();
     1729    return ret;
    15871730}
    15881731
    15891732/** \fn RingBuffer::GetRealFileSize(void) const
     
    15921735 */
    15931736long long RingBuffer::GetRealFileSize(void) const
    15941737{
     1738    rwlock.lockForRead();
     1739    long long ret = -1;
    15951740    if (remotefile)
    1596         return remotefile->GetFileSize();
    1597 
    1598     QFileInfo info(filename);
    1599     return info.size();
     1741        ret = remotefile->GetFileSize();
     1742    else
     1743        ret = QFileInfo(filename).size();
     1744    rwlock.unlock();
     1745    return ret;
    16001746}
    16011747
    16021748/** \fn RingBuffer::LiveMode(void) const
     
    16051751 */
    16061752bool RingBuffer::LiveMode(void) const
    16071753{
    1608     return (livetvchain);
     1754    rwlock.lockForRead();
     1755    bool ret = (livetvchain);
     1756    rwlock.unlock();
     1757    return ret;
    16091758}
    16101759
    16111760/** \fn RingBuffer::SetLiveMode(LiveTVChain*)
     
    16141763 */
    16151764void RingBuffer::SetLiveMode(LiveTVChain *chain)
    16161765{
     1766    rwlock.lockForWrite();
    16171767    livetvchain = chain;
     1768    rwlock.unlock();
    16181769}
    16191770
    16201771bool RingBuffer::InDVDMenuOrStillFrame(void)
    16211772{
     1773    rwlock.lockForRead();
     1774    bool ret = false;
    16221775#ifdef USING_FRONTEND
    16231776    if (dvdPriv)
    1624         return (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
     1777        ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
    16251778#endif // USING_FRONTEND
    1626     return false;
     1779    rwlock.unlock();
     1780    return ret;
    16271781}
    16281782
    16291783/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/RingBuffer.h

     
    11// -*- Mode: c++ -*-
    22
    3 #ifndef RINGBUFFER
    4 #define RINGBUFFER
     3#ifndef _RINGBUFFER_H_
     4#define _RINGBUFFER_H_
    55
    66#include <QReadWriteLock>
    77#include <QWaitCondition>
     
    3838
    3939    // Gets
    4040    /// Returns name of file used by this RingBuffer
    41     QString   GetFilename(void)      const { return filename; }
    42     QString   GetSubtitleFilename(void) const { return subtitlefilename; }
    43     /// Returns ReadBufAvail(void)
    44     int       DataInReadAhead(void)  const { return ReadBufAvail(); }
     41    QString   GetFilename(void)      const
     42    {
     43        rwlock.lockForRead();
     44        QString tmp = filename; tmp.detach();
     45        rwlock.unlock();
     46        return tmp;
     47    }
     48    QString   GetSubtitleFilename(void) const
     49    {
     50        rwlock.lockForRead();
     51        QString tmp = subtitlefilename; tmp.detach();
     52        rwlock.unlock();
     53        return tmp;
     54    }
    4555    /// Returns value of stopreads
    4656    /// \sa StartReads(void), StopReads(void)
    4757    bool      GetStopReads(void)     const { return stopreads; }
    48     /// Returns false iff read-ahead is not
    49     /// running and read-ahead is not paused.
    50     bool      isPaused(void)         const
    51         { return (!readaheadrunning) ? true : readaheadpaused; }
     58    bool      isPaused(void)         const;
    5259    long long GetReadPosition(void)  const;
    5360    long long GetWritePosition(void) const;
    5461    long long GetRealFileSize(void)  const;
    55     uint      GetBitrate(void)       const;
    56     uint      GetReadBlockSize(void) const;
    5762    bool      IsOpen(void)           const;
     63    bool      IsNearEnd(double fps, uint vvf) const;
    5864
    5965    // General Commands
    6066    void OpenFile(const QString &lfilename, uint retryCount = 12/*4*/);
     
    8288    bool LiveMode(void) const;
    8389    void SetLiveMode(LiveTVChain *chain);
    8490    /// Tells RingBuffer whether to igonre the end-of-file
    85     void IgnoreLiveEOF(bool ignore) { ignoreliveeof = ignore; }
     91    void IgnoreLiveEOF(bool ignore)
     92    {
     93        rwlock.lockForWrite();
     94        ignoreliveeof = ignore;
     95        rwlock.unlock();
     96    }
    8697
    8798    // ThreadedFileWriter proxies
    8899    int  Write(const void *buf, uint count);
     
    93104
    94105    // DVDRingBuffer proxies
    95106    /// Returns true if this is a DVD backed RingBuffer.
    96     inline bool isDVD(void) const { return dvdPriv; }
    97     DVDRingBufferPriv *DVD() { return dvdPriv; }
     107    bool isDVD(void) const
     108    {
     109        rwlock.lockForRead();
     110        bool ret = dvdPriv;
     111        rwlock.unlock();
     112        return ret;
     113    }
     114    /// Illicitly manipulating privates is ill advised!
     115    DVDRingBufferPriv *DVD()
     116    {
     117        return dvdPriv;
     118    }
    98119    bool InDVDMenuOrStillFrame(void);
    99120
    100121    // BDRingBuffer proxies
     
    108129  protected:
    109130    void run(void); // QThread
    110131    void CalcReadAheadThresh(void);
     132    bool PauseAndWait(void);
    111133    int safe_read_bd(void *data, uint sz);
    112134    int safe_read_dvd(void *data, uint sz);
    113135    int safe_read(int fd, void *data, uint sz);
    114136    int safe_read(RemoteFile *rf, void *data, uint sz);
    115137
    116     int ReadFromBuf(void *buf, int count, bool peek = false);
     138    int ReadPriv(void *buf, int count, bool peek);
     139    int ReadDirect(void *buf, int count, bool peek);
     140    bool WaitForReadsAllowed(void);
     141    bool WaitForAvail(int count);
    117142
    118143    int ReadBufFree(void) const;
    119144    int ReadBufAvail(void) const;
    120145
    121     void StartupReadAheadThread(void);
    122146    void ResetReadAhead(long long newinternal);
    123147    void KillReadAheadThread(void);
    124148
    125149  private:
    126     // NR == trivial risk, not protected, but only modified in single thread
    127     // LR == low risk, not protected, but only modified on Open,Close,ctor,dtor
    128     // HR == high risk, likely to cause unexpected behaviour
    129     // MR == medium risk, unsafe methods unlikely to be called at wrong moment
     150    mutable QReadWriteLock poslock;
     151    long long readpos;            // protected by poslock
     152    long long writepos;           // protected by poslock
    130153
    131     QString filename;             // not protected by a lock LR
    132     QString subtitlefilename;     // not protected by a lock LR
     154    // note should not go under rwlock..
     155    // this is used to break out of read_safe where rwlock is held
     156    volatile bool stopreads;
    133157
    134     ThreadedFileWriter *tfw;      // not protected by a lock LR
    135     int fd2;                      // not protected by a lock LR
    136 
    137     bool writemode;               // not protected by a lock LR
    138 
    139     long long readpos;            // not protected by a lock HR
    140     long long writepos;           // not protected by a lock HR
    141 
    142     bool stopreads;               // not protected by a lock HR
    143 
    144158    mutable QReadWriteLock rwlock;
    145159
    146     RemoteFile *remotefile;       // not protected by a lock LR
     160    QString filename;             // protected by rwlock
     161    QString subtitlefilename;     // protected by rwlock
    147162
    148     // this lock does not consistently protect anything,
    149     // but seems to be intented to protect rbrpos & rbwpos
    150     mutable QMutex readAheadLock;
     163    ThreadedFileWriter *tfw;      // protected by rwlock
     164    int fd2;                      // protected by rwlock
    151165
    152     bool startreadahead;          // not protected by a lock HR
    153     char *readAheadBuffer;        // not protected by a lock MR
    154     bool readaheadrunning;        // not protected by a lock HR
    155     bool readaheadpaused;         // not protected by a lock HR
    156     bool pausereadthread;         // not protected by a lock HR
    157     int rbrpos;                   // not protected by a lock HR
    158     int rbwpos;                   // not protected by a lock HR
    159     long long internalreadpos;    // not protected by a lock HR
    160     bool ateof;                   // not protected by a lock HR
    161     bool readsallowed;            // not protected by a lock HR
    162     volatile bool wantseek;       // not protected by a lock HR
    163     bool setswitchtonext;         // protected by rwlock
     166    bool writemode;               // protected by rwlock
    164167
    165     uint           rawbitrate;    // protected by rwlock
    166     float          playspeed;     // protected by rwlock
    167     int            fill_threshold;// not protected by a lock HR
    168     int            fill_min;      // protected by rwlock
    169     int            readblocksize; // protected by rwlock
     168    RemoteFile *remotefile;       // protected by rwlock
    170169
    171     QWaitCondition pauseWait;     // not protected by a lock HR
     170    bool      startreadahead;     // protected by rwlock
     171    char     *readAheadBuffer;    // protected by rwlock
     172    bool      readaheadrunning;   // protected by rwlock
     173    bool      request_pause;      // protected by rwlock
     174    bool      paused;             // protected by rwlock
     175    int       rbrpos;             // protected by rwlock
     176    int       rbwpos;             // protected by rwlock
     177    long long internalreadpos;    // protected by rwlock (see note 1)
     178    bool      ateof;              // protected by rwlock
     179    bool      readsallowed;       // protected by rwlock
     180    bool      setswitchtonext;    // protected by rwlock
     181    uint      rawbitrate;         // protected by rwlock
     182    float     playspeed;          // protected by rwlock
     183    int       fill_threshold;     // protected by rwlock
     184    int       fill_min;           // protected by rwlock
     185    int       readblocksize;      // protected by rwlock
     186    int       wanttoread;         // protected by rwlock
     187    int       numfailures;        // protected by rwlock (see note 1)
     188    bool      commserror;         // protected by rwlock
    172189
    173     int wanttoread;               // not protected by a lock HR
    174     QWaitCondition availWait;     // protected by availWaitMutex
    175     QMutex availWaitMutex;
     190    DVDRingBufferPriv *dvdPriv;   // not protected by rwlock, when DVD() is used
     191    BDRingBufferPriv  *bdPriv;    // protected by rwlock
    176192
    177     QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex
    178     QMutex readsAllowedWaitMutex;
     193    bool oldfile;                 // protected by rwlock
    179194
    180     int numfailures;              // not protected by a lock MR
     195    LiveTVChain *livetvchain;     // protected by rwlock
     196    bool ignoreliveeof;           // protected by rwlock
    181197
    182     bool commserror;              // not protected by a lock MR
     198    long long readAdjust;         // protected by rwlock
    183199
    184     DVDRingBufferPriv *dvdPriv;   // not protected by a lock LR
    185     BDRingBufferPriv  *bdPriv;    // not protected by a lock LR
     200    // note 1: internalreadpos and numfailures are modified with only a
     201    // read lock in the read ahead thread, but this is safe since all other
     202    // places that use it are protected by a write lock. But this is
     203    // a fragile state of affairs and care must be taken when modifying
     204    // code or locking around these two variables.
    186205
    187     bool oldfile;                 // not protected by a lock LR
    188 
    189     LiveTVChain *livetvchain;     // not protected by a lock HR
    190     bool ignoreliveeof;           // not protected by a lock HR
    191 
    192     long long readAdjust;         // not protected by a lock HR
    193 
    194206    /// Condition to signal that the read ahead thread is running
    195     QWaitCondition readAheadRunningCond;//protected by readAheadRunningCondLock
    196     QMutex readAheadRunningCondLock;
     207    QWaitCondition readAheadRunningWait;// protected by rwlock
     208    QWaitCondition pauseWait;           // protected by rwlock
     209    QWaitCondition unpauseWait;         // protected by rwlock
     210    QWaitCondition availWait;           // protected by rwlock
     211    QWaitCondition readsAllowedWait;    // protected by rwlock
    197212
    198213  public:
    199214    static QMutex subExtLock;
     
    206221    static const uint kReadTestSize;
    207222};
    208223
    209 #endif
     224#endif // _RINGBUFFER_H_
  • libs/libmythtv/mythplayer.cpp

     
    31903190    if (!videoOutput)
    31913191        return false;
    31923192
    3193     int    sz              = player_ctx->buffer->DataInReadAhead();
    3194     uint   rbs             = player_ctx->buffer->GetReadBlockSize();
    3195     uint   kbits_per_sec   = player_ctx->buffer->GetBitrate();
    3196     uint   vvf             = videoOutput->ValidVideoFrames();
    3197     double inv_fps         = 1.0 / GetDecoder()->GetFPS();
    3198     double bytes_per_frame = kbits_per_sec * (1000.0/8.0) * inv_fps;
    3199     double rh_frames       = sz / bytes_per_frame;
    3200 
    3201     // WARNING: rh_frames can greatly overestimate or underestimate
    3202     //          the number of frames available in the read ahead buffer
    3203     //          when rh_frames is less than the keyframe distance.
    3204 
    3205     bool near_end = ((vvf + rh_frames) < 10.0) || (sz < rbs*1.5);
    3206 
    3207     VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
    3208             <<" br("<<(kbits_per_sec/8)<<"KB)"
    3209             <<" fps("<<((uint)(1.0/inv_fps))<<")"
    3210             <<" sz("<<(sz / 1000)<<"KB)"
    3211             <<" vfl("<<vvf<<")"
    3212             <<" frh("<<((uint)rh_frames)<<")"
    3213             <<" ne:"<<near_end);
    3214 
    3215     return near_end;
     3193    return player_ctx->buffer->IsNearEnd(
     3194        GetDecoder()->GetFPS(),
     3195        videoOutput->ValidVideoFrames());
    32163196}
    32173197
    32183198/** \brief Returns true iff near end of recording.