Ticket #8812: 8812-v2.patch

File 8812-v2.patch, 53.7 KB (added by danielk, 10 years ago)

Updated 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
     
    4443#define O_BINARY 0
    4544#endif
    4645
    47 const uint RingBuffer::kBufferSize = 3 * 1024 * 1024;
     46// about one second at 35mbit
     47const uint RingBuffer::kBufferSize = 4 * 1024 * 1024;
    4848
    4949#define CHUNK 32768 /* readblocksize increments */
    5050
     
    6565
    6666/*
    6767  Locking relations:
    68     rwlock->readAheadLock
    69           ->readsAllowedWaitMutex->readAheadRunningCondLock
    70           ->availWaitMutex
     68    rwlock->poslock->rbrlock->rbwlock
    7169
    7270  A child should never lock any of the parents without locking
    7371  the parent lock before the child lock.
    7472  void RingBuffer::Example1()
    7573  {
    76       QMutexLocker locker1(&readAheadRunningCondLock);
    77       QMutexLocker locker2(&readsAllowedWaitMutex); // error!
     74      poslock.lockForWrite();
     75      rwlock.lockForRead(); // error!
    7876      blah(); // <- does not implicitly aquire any locks
     77      rwlock.unlock();
     78      poslock.unlock();
    7979  }
    8080  void RingBuffer::Example2()
    8181  {
    82       QMutexLocker locker1(&readsAllowedWaitMutex);
    83       QMutexLocker locker2(&readAheadRunningCondLock); // ok!
     82      rwlock.lockForRead();
     83      rbrlock.lockForWrite(); // ok!
    8484      blah(); // <- does not implicitly aquire any locks
     85      rbrlock.unlock();
     86      rwlock.unlock();
    8587  }
    8688*/
    8789
     
    113115RingBuffer::RingBuffer(const QString &lfilename,
    114116                       bool write, bool readahead,
    115117                       uint read_retries)
    116     : filename(lfilename),      subtitlefilename(QString::null),
     118    : readpos(0),               writepos(0),
     119      internalreadpos(0),
     120      rbrpos(0),                rbwpos(0),
     121      stopreads(false),
     122      filename(lfilename),      subtitlefilename(QString::null),
    117123      tfw(NULL),                fd2(-1),
    118       writemode(false),
    119       readpos(0),               writepos(0),
    120       stopreads(false),         remotefile(NULL),
     124      writemode(false),         remotefile(NULL),
    121125      startreadahead(readahead),readAheadBuffer(NULL),
    122       readaheadrunning(false),  readaheadpaused(false),
    123       pausereadthread(false),
    124       rbrpos(0),                rbwpos(0),
    125       internalreadpos(0),       ateof(false),
    126       readsallowed(false),      wantseek(false), setswitchtonext(false),
     126      readaheadrunning(false),  reallyrunning(false),
     127      request_pause(false),     paused(false),
     128      ateof(false),             readsallowed(false),
     129      setswitchtonext(false),
    127130      rawbitrate(4000),         playspeed(1.0f),
    128131      fill_threshold(65536),    fill_min(-1),
    129132      readblocksize(CHUNK),     wanttoread(0),
     
    273276    VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2)")
    274277            .arg(lfilename).arg(retryCount));
    275278
     279    rwlock.lockForWrite();
     280
    276281    uint openAttempts = retryCount + 1;
    277282
    278283    filename = lfilename;
     
    414419    else if (is_dvd)
    415420    {
    416421        dvdPriv->OpenFile(filename);
    417         rwlock.lockForWrite();
    418422        readblocksize = DVD_BLOCK_SIZE * 62;
    419         rwlock.unlock();
    420423    }
    421424    else if (is_bd)
    422425    {
    423426        bdPriv->OpenFile(filename);
    424         rwlock.lockForWrite();
    425427        readblocksize = BD_BLOCK_SIZE * 62;
    426         rwlock.unlock();
    427428    }
    428429#endif // USING_FRONTEND
    429430    else
     
    478479    commserror = false;
    479480    numfailures = 0;
    480481
    481     UpdateRawBitrate(4000);
     482    rawbitrate = 4000;
     483    CalcReadAheadThresh();
     484
     485    rwlock.unlock();
    482486}
    483487
    484488/** \fn RingBuffer::IsOpen(void) const
     
    486490 */
    487491bool RingBuffer::IsOpen(void) const
    488492{
     493    rwlock.lockForRead();
     494    bool ret;
    489495#ifdef USING_FRONTEND
    490     return tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
     496    ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
    491497           (bdPriv && bdPriv->IsOpen());
    492498#else // if !USING_FRONTEND
    493     return tfw || (fd2 > -1) || remotefile;
     499    ret = tfw || (fd2 > -1) || remotefile;
    494500#endif // !USING_FRONTEND
     501    rwlock.unlock();
     502    return ret;
    495503}
    496504
    497505/** \fn RingBuffer::~RingBuffer(void)
     
    535543    rwlock.unlock();
    536544}
    537545
    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 
    551546/** \fn RingBuffer::Reset(bool, bool, bool)
    552547 *  \brief Resets the read-ahead thread and our position in the file
    553548 */
    554549void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal)
    555550{
    556     wantseek = true;
    557551    rwlock.lockForWrite();
    558     wantseek = false;
     552    poslock.lockForWrite();
     553
    559554    numfailures = 0;
    560555    commserror = false;
    561556    setswitchtonext = false;
     
    579574    if (resetInternal)
    580575        internalreadpos = readpos;
    581576
     577    generalWait.wakeAll();
     578    poslock.unlock();
    582579    rwlock.unlock();
    583580}
    584581
     
    674671        VERBOSE(VB_IMPORTANT, LOC_ERR +
    675672                "RingBuffer::safe_read(RemoteFile* ...): read failed");
    676673
     674        poslock.lockForRead();
    677675        rf->Seek(internalreadpos - readAdjust, SEEK_SET);
     676        poslock.unlock();
    678677        ret = 0;
    679678        numfailures++;
    680679     }
     
    695694    rwlock.unlock();
    696695}
    697696
    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 
    723697/** \fn RingBuffer::UpdatePlaySpeed(float)
    724698 *  \brief Set the play speed, to allow RingBuffer adjust effective bitrate.
    725699 *  \param play_speed Speed to set. (1.0 for normal speed)
     
    743717{
    744718    uint estbitrate = 0;
    745719
    746     wantseek       = false;
    747720    readsallowed   = false;
    748721    readblocksize  = CHUNK;
    749722
     
    785758            .arg(fill_min/1024).arg(readblocksize/1024));
    786759}
    787760
    788 /** \fn RingBuffer::ReadBufFree(void) const
    789  *  \brief Returns number of bytes available for reading into buffer.
    790  */
     761bool RingBuffer::IsNearEnd(double fps, uint vvf) const
     762{
     763    rwlock.lockForRead();
     764    int    sz  = ReadBufAvail();
     765    uint   rbs = readblocksize;
     766    // telecom kilobytes (i.e. 1000 per k not 1024)
     767    uint   tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
     768    uint   kbits_per_sec = min(rawbitrate * 3, tmp);
     769    rwlock.unlock();
     770
     771    // WARNING: readahead_frames can greatly overestimate or underestimate
     772    //          the number of frames available in the read ahead buffer
     773    //          when rh_frames is less than the keyframe distance.
     774    double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps;
     775    double readahead_frames = sz / bytes_per_frame;
     776
     777    bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5);
     778
     779    VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
     780            <<" br("<<(kbits_per_sec/8)<<"KB)"
     781            <<" sz("<<(sz / 1000)<<"KB)"
     782            <<" vfl("<<vvf<<")"
     783            <<" frh("<<((uint)readahead_frames)<<")"
     784            <<" ne:"<<near_end);
     785
     786    return near_end;
     787}
     788
     789/// \brief Returns number of bytes available for reading into buffer.
     790/// WARNING: Must be called with rwlock in locked state.
    791791int RingBuffer::ReadBufFree(void) const
    792792{
    793     QMutexLocker locker(&readAheadLock);
    794     return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     793    rbrlock.lockForRead();
     794    rbwlock.lockForRead();
     795    int ret = ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     796    rbwlock.unlock();
     797    rbrlock.unlock();
     798    return ret;
    795799}
    796800
    797 /** \fn RingBuffer::ReadBufAvail(void) const
    798  *  \brief Returns number of bytes available for reading from buffer.
    799  */
     801/// \brief Returns number of bytes available for reading from buffer.
     802/// WARNING: Must be called with rwlock in locked state.
    800803int RingBuffer::ReadBufAvail(void) const
    801804{
    802     QMutexLocker locker(&readAheadLock);
    803     return (rbwpos >= rbrpos) ?
    804         rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     805    rbrlock.lockForRead();
     806    rbwlock.lockForRead();
     807    int ret = (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     808    rbwlock.unlock();
     809    rbrlock.unlock();
     810    return ret;
    805811}
    806812
    807813/** \fn RingBuffer::ResetReadAhead(long long)
     
    811817 *   buffer doesn't contain any stale data, and so that it will read
    812818 *   any new data from the new position in the file.
    813819 *
    814  *   WARNING: Must be called with rwlock in write lock state.
     820 *   WARNING: Must be called with rwlock and poslock in write lock state.
    815821 *
    816822 *  \param newinternal Position in file to start reading data from
    817823 */
    818824void RingBuffer::ResetReadAhead(long long newinternal)
    819825{
    820     readAheadLock.lock();
     826    rbrlock.lockForWrite();
     827    rbwlock.lockForWrite();
     828
    821829    readblocksize = CHUNK;
    822830    rbrpos = 0;
    823831    rbwpos = 0;
     
    825833    ateof = false;
    826834    readsallowed = false;
    827835    setswitchtonext = false;
    828     readAheadLock.unlock();
     836    generalWait.wakeAll();
     837
     838    rbwlock.unlock();
     839    rbrlock.unlock();
    829840}
    830841
    831 /** \fn RingBuffer::StartupReadAheadThread(void)
    832  *  \brief Creates the read-ahead thread, and waits for it to start.
     842/**
     843 *  \brief Starts the read-ahead thread.
    833844 *
    834  *  \sa Start(void).
     845 *   If the RingBuffer constructor was not called with a usereadahead
     846 *   of true of if this was reset to false because we're dealing with
     847 *   a DVD the read ahead thread will not be started.
     848 *
     849 *   If this RingBuffer is in write-mode a warning will be printed and
     850 *   the read ahead thread will not be started.
     851 *
     852 *   If the read ahead thread is already running a warning will be printed
     853 *   and the read ahead thread will not be started.
     854 *
    835855 */
    836 void RingBuffer::StartupReadAheadThread(void)
     856void RingBuffer::Start(void)
    837857{
    838     readaheadrunning = false;
     858    VERBOSE(VB_IMPORTANT, LOC + "Start)");   
    839859
    840     readAheadRunningCondLock.lock();
     860    bool do_start = true;
     861
     862    rwlock.lockForWrite();
     863    if (!startreadahead)
     864    {
     865        do_start = false;
     866    }
     867    else if (writemode)
     868    {
     869        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     870                "this is a write only RingBuffer");
     871        do_start = false;
     872    }
     873    else if (readaheadrunning)
     874    {
     875        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     876                "already running");
     877        do_start = false;
     878    }
     879
     880    if (!do_start)
     881    {
     882        rwlock.unlock();
     883        return;
     884    }
     885
     886    StartReads();
     887
    841888    QThread::start();
    842     readAheadRunningCond.wait(&readAheadRunningCondLock);
    843     readAheadRunningCondLock.unlock();
     889
     890    while (readaheadrunning && !reallyrunning)
     891        generalWait.wait(&rwlock);
     892
     893    rwlock.unlock();
    844894}
    845895
    846896/** \fn RingBuffer::KillReadAheadThread(void)
     
    848898 */
    849899void RingBuffer::KillReadAheadThread(void)
    850900{
    851     if (!readaheadrunning)
    852         return;
     901    rwlock.lockForWrite();
     902    bool do_wait = readaheadrunning;
     903    readaheadrunning = false;
     904    StopReads();
     905    generalWait.wakeAll();
     906    rwlock.unlock();
    853907
    854     readaheadrunning = false;
    855     QThread::wait();
     908    if (do_wait)
     909        QThread::wait();
    856910}
    857911
    858912/** \fn RingBuffer::StopReads(void)
     
    862916void RingBuffer::StopReads(void)
    863917{
    864918    stopreads = true;
    865     availWait.wakeAll();
     919    generalWait.wakeAll();
    866920}
    867921
    868922/** \fn RingBuffer::StartReads(void)
     
    880934 */
    881935void RingBuffer::Pause(void)
    882936{
    883     pausereadthread = true;
    884937    StopReads();
     938
     939    rwlock.lockForWrite();
     940    request_pause = true;
     941    rwlock.unlock();
    885942}
    886943
    887944/** \fn RingBuffer::Unpause(void)
     
    891948void RingBuffer::Unpause(void)
    892949{
    893950    StartReads();
    894     pausereadthread = false;
     951
     952    rwlock.lockForWrite();
     953    request_pause = false;
     954    generalWait.wakeAll();
     955    rwlock.unlock();
    895956}
    896957
     958/// Returns false iff read-ahead is not running and read-ahead is not paused.
     959bool RingBuffer::isPaused(void) const
     960{
     961    rwlock.lockForRead();
     962    bool ret = !readaheadrunning || paused;
     963    rwlock.unlock();
     964    return ret;
     965}
     966
    897967/** \fn RingBuffer::WaitForPause(void)
    898968 *  \brief Waits for Pause(void) to take effect.
    899969 */
    900970void RingBuffer::WaitForPause(void)
    901971{
    902     if (!readaheadrunning)
    903         return;
     972    MythTimer t;
     973    t.start();
    904974
    905     if  (!readaheadpaused)
     975    rwlock.lockForRead();
     976    while (readaheadrunning && !paused && request_pause)
    906977    {
    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();
     978        generalWait.wait(&rwlock, 1000);
     979        if (readaheadrunning && !paused && request_pause && t.elapsed() > 1000)
     980        {
     981            VERBOSE(VB_IMPORTANT, LOC +
     982                    QString("Waited %1 ms for ringbuffer pause..")
     983                    .arg(t.elapsed()));
     984        }
     985    }
     986    rwlock.unlock();
     987}
    911988
    912         while (!pauseWait.wait(&mutex, 1000))
    913             VERBOSE(VB_IMPORTANT,
    914                     LOC + "Waited too long for ringbuffer pause..");
     989bool RingBuffer::PauseAndWait(void)
     990{
     991    const uint timeout = 500; // ms
     992
     993    if (request_pause)
     994    {
     995        if (!paused)
     996        {
     997            rwlock.unlock();
     998            rwlock.lockForWrite();
     999
     1000            if (request_pause)
     1001            {
     1002                paused = true;
     1003                generalWait.wakeAll();
     1004            }
     1005
     1006            rwlock.unlock();
     1007            rwlock.lockForRead();
     1008        }
     1009
     1010        if (request_pause && paused && readaheadrunning)
     1011            generalWait.wait(&rwlock, timeout);
    9151012    }
     1013
     1014    if (!request_pause && paused)
     1015    {
     1016        rwlock.unlock();
     1017        rwlock.lockForWrite();
     1018
     1019        if (!request_pause)
     1020        {
     1021            paused = false;
     1022            generalWait.wakeAll();
     1023        }
     1024
     1025        rwlock.unlock();
     1026        rwlock.lockForRead();
     1027    }
     1028
     1029    return request_pause || paused;
    9161030}
    9171031
    9181032void RingBuffer::run(void)
    9191033{
    920     long long totfree = 0;
    921     int ret = -1;
    922     int used = 0;
    923     int loops = 0;
    924 
     1034    // These variables are used to adjust the read block size
    9251035    struct timeval lastread, now;
    926     gettimeofday(&lastread, NULL);
    927     const int KB640 = 640*1024;
    9281036    int readtimeavg = 300;
    929     int readinterval;
     1037    bool ignore_for_read_timing = true;
    9301038
    931     pausereadthread = false;
     1039    gettimeofday(&lastread, NULL); // this is just to keep gcc happy
    9321040
    933     readAheadBuffer = new char[kBufferSize + KB640];
    934 
    9351041    rwlock.lockForWrite();
     1042    poslock.lockForWrite();
     1043    request_pause = false;
     1044    readAheadBuffer = new char[kBufferSize + 1024];
    9361045    ResetReadAhead(0);
     1046    readaheadrunning = true;
     1047    reallyrunning = true;
     1048    generalWait.wakeAll();
     1049    poslock.unlock();
    9371050    rwlock.unlock();
    9381051
    939     totfree = ReadBufFree();
     1052    // NOTE: this must loop at some point hold only
     1053    // a read lock on rwlock, so that other functions
     1054    // such as reset and seek can take priority.
    9401055
    941     readaheadrunning = true;
    942     readAheadRunningCondLock.lock();
    943     readAheadRunningCond.wakeAll();
    944     readAheadRunningCondLock.unlock();
     1056    rwlock.lockForRead();
    9451057    while (readaheadrunning)
    9461058    {
    947         if (pausereadthread || writemode)
     1059        if (PauseAndWait())
    9481060        {
    949             readaheadpaused = true;
    950             pauseWait.wakeAll();
    951             usleep(5000);
    952             totfree = ReadBufFree();
     1061            ignore_for_read_timing = true;
    9531062            continue;
    9541063        }
    9551064
    956         if (readaheadpaused)
     1065        long long totfree = ReadBufFree();
     1066
     1067        if (totfree < readblocksize)
    9571068        {
    958             totfree = ReadBufFree();
    959             readaheadpaused = false;
     1069            generalWait.wait(&rwlock, 1000);
     1070            continue;
    9601071        }
    9611072
    962         totfree = ReadBufFree();
    963         if (totfree < GetReadBlockSize())
     1073        // No point in trying to read if stopreads is set but do sleep
     1074        // a little so we don't get stuck in a tight busy loop here..
     1075        if (stopreads)
    9641076        {
    965             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;
     1077            ignore_for_read_timing = true;
     1078            generalWait.wait(&rwlock, 10);
     1079            continue;
    9721080        }
    973         loops = 0;
    9741081
    975         rwlock.lockForRead();
    976         if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
     1082        int read_return = -1;
     1083        if (totfree > readblocksize && !commserror &&
     1084            !ateof && !setswitchtonext)
    9771085        {
    9781086            // limit the read size
    9791087            totfree = readblocksize;
    9801088
    9811089            // adapt blocksize
    9821090            gettimeofday(&now, NULL);
    983             readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
    984                            (now.tv_usec - lastread.tv_usec) / 1000;
     1091            if (!ignore_for_read_timing)
     1092            {
     1093                int readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
     1094                    (now.tv_usec - lastread.tv_usec) / 1000;
     1095                readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    9851096
    986             readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    987 
    988             if (readtimeavg < 200 && readblocksize < KB640)
    989             {
    990                 readblocksize += CHUNK;
    991                 //VERBOSE(VB_PLAYBACK,
    992                 //    QString("Avg read interval was %1 msec. %2K block size")
    993                 //            .arg(readtimeavg).arg(readblocksize/1024));
    994                 readtimeavg = 300;
     1097                if (readtimeavg < 200 && (uint)readblocksize < (kBufferSize>>2))
     1098                {
     1099                    readblocksize *= 2;
     1100                    VERBOSE(VB_PLAYBACK,
     1101                            QString("Avg read interval was %1 msec. %2K block size")
     1102                            .arg(readtimeavg).arg(readblocksize/1024));
     1103                    readtimeavg = 300;
     1104                }
     1105                else if (readtimeavg > 400 && readblocksize > CHUNK)
     1106                {
     1107                    readblocksize -= CHUNK;
     1108                    VERBOSE(VB_PLAYBACK,
     1109                            QString("Avg read interval was %1 msec. %2K block size")
     1110                            .arg(readtimeavg).arg(readblocksize/1024));
     1111                    readtimeavg = 300;
     1112                }
    9951113            }
    996             else if (readtimeavg > 400 && readblocksize > CHUNK)
    997             {
    998                 readblocksize -= CHUNK;
    999                 //VERBOSE(VB_PLAYBACK,
    1000                 //    QString("Avg read interval was %1 msec. %2K block size")
    1001                 //            .arg(readtimeavg).arg(readblocksize/1024));
    1002                 readtimeavg = 300;
    1003             }
     1114            ignore_for_read_timing = false;
    10041115            lastread = now;
    10051116
     1117            rbwlock.lockForRead();
    10061118            if (rbwpos + totfree > kBufferSize)
    10071119                totfree = kBufferSize - rbwpos;
    10081120
     
    10141126                if (livetvchain && livetvchain->HasNext())
    10151127                    remotefile->SetTimeout(true);
    10161128
    1017                 ret = safe_read(remotefile, readAheadBuffer + rbwpos,
    1018                                 totfree);
    1019                 internalreadpos += ret;
     1129                read_return = safe_read(
     1130                    remotefile, readAheadBuffer + rbwpos, totfree);
    10201131            }
    10211132#ifdef USING_FRONTEND
    10221133            else if (dvdPriv)
    10231134            {
    1024                 ret = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1025                 internalreadpos += ret;
     1135                read_return = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    10261136            }
    10271137            else if (bdPriv)
    10281138            {
    1029                 ret = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1030                 internalreadpos += ret;
     1139                read_return = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    10311140            }
    10321141#endif // USING_FRONTEND
    10331142            else
    10341143            {
    1035                 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    1036                 internalreadpos += ret;
     1144                read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    10371145            }
     1146            rbwlock.unlock();
     1147        }
    10381148
    1039             readAheadLock.lock();
    1040             if (ret > 0 )
    1041                 rbwpos = (rbwpos + ret) % kBufferSize;
    1042             readAheadLock.unlock();
     1149        // If stopreads is set we toss the read data since we're probably
     1150        // doing a seek or opening a new file anyway.
     1151        if (stopreads)
     1152            continue;
    10431153
    1044             if (ret == 0 && !stopreads)
     1154        if (read_return >= 0)
     1155        {
     1156            poslock.lockForWrite();
     1157            rbwlock.lockForWrite();
     1158            internalreadpos += read_return;
     1159            rbwpos = (rbwpos + read_return) % kBufferSize;
     1160            rbwlock.unlock();
     1161            poslock.unlock();
     1162        }
     1163
     1164        int used = kBufferSize - ReadBufFree();
     1165
     1166        if ((0 == read_return) || (numfailures > 5) ||
     1167            (readsallowed != (used >= fill_min || ateof ||
     1168                              setswitchtonext || commserror)))
     1169        {
     1170            rwlock.unlock();
     1171            rwlock.lockForWrite();
     1172
     1173            commserror |= (numfailures > 5);
     1174
     1175            readsallowed = used >= fill_min || ateof ||
     1176                setswitchtonext || commserror;
     1177
     1178            if (0 == read_return)
    10451179            {
    10461180                if (livetvchain)
    10471181                {
     
    10531187                    }
    10541188                }
    10551189                else
     1190                {
    10561191                    ateof = true;
     1192                }
    10571193            }
    1058         }
    10591194
    1060         if (numfailures > 5)
    1061             commserror = true;
    1062 
    1063         totfree = ReadBufFree();
    1064         used = kBufferSize - totfree;
    1065 
    1066         if (ateof || commserror)
    1067         {
    1068             readsallowed = true;
    1069             totfree = 0;
     1195            rwlock.unlock();
     1196            rwlock.lockForRead();
     1197            used = kBufferSize - ReadBufFree();
    10701198        }
    10711199
    1072         if (!readsallowed && (used >= fill_min || setswitchtonext))
     1200        if (readsallowed || stopreads || commserror || ateof ||
     1201            setswitchtonext || (wanttoread <= used && wanttoread > 0))
    10731202        {
    1074             readsallowed = true;
    1075             //VERBOSE(VB_PLAYBACK, QString("reads allowed (%1 %2)").arg(used)
    1076             //                                                    .arg(fill_min));
     1203            generalWait.wakeAll();
     1204            rwlock.unlock();
     1205            usleep(5 * 1000);
     1206            rwlock.lockForRead();           
    10771207        }
    1078         //else if (!readsallowed)
    1079         //    VERBOSE(VB_PLAYBACK, QString("buffering (%1 %2 %3)").arg(used)
    1080         //                                                        .arg(fill_min)
    1081         //                                                        .arg(ret));
    1082 
    1083         if (readsallowed && used < fill_min && !ateof && !setswitchtonext)
     1208        else
    10841209        {
    1085             readsallowed = false;
    1086             //VERBOSE(VB_GENERAL, QString ("rebuffering (%1 %2)").arg(used)
    1087             //                                                   .arg(fill_min));
     1210            // yield if we have nothing to do...
     1211            if (!request_pause &&
     1212                (used >= fill_threshold || ateof || setswitchtonext))
     1213            {
     1214                generalWait.wait(&rwlock, 100);
     1215            }
    10881216        }
     1217    }
    10891218
    1090         readsAllowedWaitMutex.lock();
    1091         if (readsallowed || stopreads)
    1092             readsAllowedWait.wakeAll();
    1093         readsAllowedWaitMutex.unlock();
     1219    rwlock.unlock();
    10941220
    1095         availWaitMutex.lock();
    1096         if (commserror || ateof || stopreads || setswitchtonext ||
    1097             (wanttoread <= used && wanttoread > 0))
    1098         {
    1099             availWait.wakeAll();
    1100         }
    1101         availWaitMutex.unlock();
    1102 
    1103         rwlock.unlock();
    1104 
    1105         if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
    1106             !pausereadthread)
    1107         {
    1108             usleep(500);
    1109         }
    1110     }
    1111 
    11121221    delete [] readAheadBuffer;
    11131222    readAheadBuffer = NULL;
     1223
     1224    rwlock.lockForWrite();
     1225    rbrlock.lockForWrite();
     1226    rbwlock.lockForWrite();
    11141227    rbrpos = 0;
    11151228    rbwpos = 0;
     1229    reallyrunning = false;
     1230    rbwlock.unlock();
     1231    rbrlock.unlock();
     1232    rwlock.unlock();
    11161233}
    11171234
    11181235long long RingBuffer::SetAdjustFilesize(void)
    11191236{
     1237    rwlock.lockForWrite();
     1238    poslock.lockForRead();
    11201239    readAdjust += internalreadpos;
     1240    poslock.unlock();
     1241    rwlock.unlock();
    11211242    return readAdjust;
    11221243}
    11231244
    11241245int RingBuffer::Peek(void *buf, int count)
    11251246{
    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 
     1247    int ret = ReadPriv(buf, count, true);
    11661248    if (ret != count)
    11671249    {
    11681250        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    11721254    return ret;
    11731255}
    11741256
    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)
     1257bool RingBuffer::WaitForReadsAllowed(void)
    11841258{
    1185     if (commserror)
    1186         return 0;
     1259    MythTimer t;
     1260    t.start();
    11871261
    1188     bool readone = false;
    1189     int readErr = 0;
    1190 
    1191     if (readaheadpaused && stopreads)
     1262    while (!readsallowed && !stopreads &&
     1263           !request_pause && !commserror && readaheadrunning)
    11921264    {
    1193         readone = true;
    1194         Unpause();
    1195     }
    1196     else
    1197     {
    1198         QMutexLocker locker(&readsAllowedWaitMutex);
     1265        generalWait.wait(&rwlock, 1000);
     1266        if (!readsallowed && t.elapsed() > 1000)
     1267        {
     1268            VERBOSE(VB_IMPORTANT,
     1269                    LOC + "Taking too long to be allowed to read..");
    11991270
    1200         while (!readsallowed && !stopreads)
    1201         {
    1202             if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000))
     1271            if (t.elapsed() > 10000)
    12031272            {
    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                  }
     1273                VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
     1274                        "10 seconds to be allowed to read, aborting.");
     1275                return false;
    12241276            }
    12251277        }
    12261278    }
    12271279
     1280    return readsallowed;
     1281}
     1282
     1283bool RingBuffer::WaitForAvail(int count)
     1284{
    12281285    int avail = ReadBufAvail();
     1286    count = (ateof && avail < count) ? avail : count;
    12291287
    1230     if (ateof && avail < count)
    1231         count = avail;
    1232 
    12331288    MythTimer t;
    12341289    t.start();
    1235     while (avail < count && !stopreads)
     1290    while ((avail < count) && !stopreads &&
     1291           !request_pause && !commserror && readaheadrunning)
    12361292    {
    1237         availWaitMutex.lock();
    12381293        wanttoread = count;
    1239         if (!availWait.wait(&availWaitMutex, 250))
     1294        generalWait.wait(&rwlock, 250);
     1295        avail = ReadBufAvail();
     1296
     1297        if ((ateof || setswitchtonext) && avail < count)
     1298            count = avail;
     1299
     1300        if (avail < count)
    12401301        {
    12411302            int elapsed = t.elapsed();
    1242             if  (/*((elapsed > 500)  && (elapsed < 750))  ||*/
     1303            if  (((elapsed > 500)  && (elapsed < 750))  ||
    12431304                 ((elapsed > 1000) && (elapsed < 1250)) ||
    12441305                 ((elapsed > 2000) && (elapsed < 2250)) ||
    12451306                 ((elapsed > 4000) && (elapsed < 4250)) ||
    1246                  ((elapsed > 8000) && (elapsed < 8250)))
     1307                 ((elapsed > 8000) && (elapsed < 8250)) ||
     1308                 ((elapsed > 9000)))
    12471309            {
    12481310                VERBOSE(VB_IMPORTANT, LOC + "Waited " +
    12491311                        QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) +
     
    12701332                    VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to "
    12711333                            "impending livetv switch.");
    12721334
    1273                 ateof = true;
    1274                 wanttoread = 0;
    1275                 stopreads = true;
    1276                 availWaitMutex.unlock();
    1277                 return 0;
     1335                return false;
    12781336            }
    12791337        }
     1338    }
    12801339
     1340    wanttoread = 0;
     1341
     1342    return avail >= count;
     1343}
     1344
     1345int RingBuffer::ReadDirect(void *buf, int count, bool peek)
     1346{
     1347    long long old_pos = 0;
     1348    if (peek)
     1349    {
     1350        poslock.lockForRead();
     1351        old_pos = readpos;
     1352        poslock.unlock();
     1353    }
     1354
     1355    int ret;
     1356    if (remotefile)
     1357        ret = safe_read(remotefile, buf, count);
     1358#ifdef USING_FRONTEND
     1359    else if (dvdPriv)
     1360        ret = dvdPriv->safe_read(buf, count);
     1361    else if (bdPriv)
     1362        ret = bdPriv->safe_read(buf, count);
     1363#endif // USING_FRONTEND
     1364    else if (fd2 >= 0)
     1365        ret = safe_read(fd2, buf, count);
     1366    else
     1367    {
     1368        ret = -1;
     1369        errno = EBADF;
     1370    }
     1371
     1372    if (peek && ret > 0)
     1373    {
     1374        if (!dvdPriv && !bdPriv)
     1375        {
     1376            long long new_pos = Seek(old_pos, SEEK_SET, true);
     1377            if (new_pos != old_pos)
     1378            {
     1379                VERBOSE(VB_IMPORTANT, LOC_ERR +
     1380                        QString("Peek() Failed to return from new "
     1381                                "position %1 to old position %2, now "
     1382                                "at position %3")
     1383                        .arg(old_pos - ret).arg(old_pos).arg(new_pos));
     1384            }
     1385        }
     1386        else if (old_pos != 0)
     1387        {
     1388            VERBOSE(VB_IMPORTANT, LOC_ERR +
     1389                    "DVD and Blu-Ray do not support arbitrary "
     1390                    "peeks except when read-ahead is enabled."
     1391                    "\n\t\t\tWill seek to beginning of video.");
     1392        }
     1393#ifdef USING_FRONTEND
     1394        if (dvdPriv)
     1395        {
     1396            dvdPriv->NormalSeek(0);
     1397        }
     1398        else if (bdPriv)
     1399        {
     1400            bdPriv->Seek(0);
     1401        }
     1402#endif // USING_FRONTEND
     1403    }
     1404
     1405    return ret;
     1406}
     1407
     1408/** \brief When possible reads from the read-ahead buffer,
     1409 *         otherwise reads directly from the device.
     1410 *
     1411 *  \param buf   Pointer to where data will be written
     1412 *  \param count Number of bytes to read
     1413 *  \param peek  If true, don't increment read count
     1414 *  \return Returns number of bytes read
     1415 */
     1416int RingBuffer::ReadPriv(void *buf, int count, bool peek)
     1417{
     1418    rwlock.lockForRead();
     1419    if (writemode)
     1420    {
     1421        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1422                "Attempt to read from a write only file");
     1423        errno = EBADF;
     1424        rwlock.unlock();
     1425        return -1;
     1426    }
     1427
     1428    if (commserror)
     1429    {
     1430        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1431                "Attempt to read after commserror set");
     1432        errno = EIO;
     1433        rwlock.unlock();
     1434        return -1;
     1435    }
     1436
     1437    if (request_pause || stopreads || !readaheadrunning)
     1438    {
     1439        rwlock.unlock();
     1440        rwlock.lockForWrite();
     1441        // we need a write lock so the read-ahead thread
     1442        // can't start mucking with the read position.
     1443        // If the read ahead thread was started while we
     1444        // didn't hold the lock, we proceed with a normal
     1445        // read from the buffer, otherwise we read directly.
     1446        if (request_pause || stopreads || !readaheadrunning)
     1447        {
     1448            int ret = ReadDirect(buf, count, peek);
     1449            rwlock.unlock();
     1450            return ret;
     1451        }
     1452        rwlock.unlock();
     1453        rwlock.lockForRead();
     1454    }
     1455
     1456    if (!WaitForReadsAllowed())
     1457    {
     1458        VERBOSE(VB_FILE, LOC + "!WaitForReadsAllowed()");
     1459        rwlock.unlock();
     1460        rwlock.lockForWrite();
    12811461        wanttoread = 0;
    1282         availWaitMutex.unlock();
     1462        stopreads = true;
     1463        rwlock.unlock();
     1464        return 0;
     1465    }
    12831466
    1284         avail = ReadBufAvail();
    1285         if ((ateof || setswitchtonext) && avail < count)
    1286             count = avail;
     1467    if (!WaitForAvail(count))
     1468    {
     1469        VERBOSE(VB_FILE, LOC + "!WaitForAvail()");
     1470        rwlock.unlock();
     1471        rwlock.lockForWrite();
     1472        ateof = true;
     1473        wanttoread = 0;
     1474        stopreads = true;
     1475        rwlock.unlock();
     1476        return 0;
     1477    }
    12871478
    1288         if (commserror)
    1289             return 0;
     1479    count = min(ReadBufAvail(), count);
     1480
     1481    if (count <= 0)
     1482    {
     1483        rwlock.unlock();
     1484        return count;
    12901485    }
    12911486
    1292     if ((ateof || stopreads) && avail < count)
    1293         count = avail;
     1487    if (peek)
     1488        rbrlock.lockForRead();
     1489    else
     1490        rbrlock.lockForWrite();
    12941491
    12951492    if (rbrpos + count > (int) kBufferSize)
    12961493    {
     
    13051502
    13061503    if (!peek)
    13071504    {
    1308         readAheadLock.lock();
    13091505        rbrpos = (rbrpos + count) % kBufferSize;
    1310         readAheadLock.unlock();
     1506        generalWait.wakeAll();
    13111507    }
     1508    rbrlock.unlock();
     1509    rwlock.unlock();
    13121510
    1313     if (readone)
    1314     {
    1315         Pause();
    1316         WaitForPause();
    1317     }
    1318 
    13191511    return count;
    13201512}
    13211513
     
    13291521 */
    13301522int RingBuffer::Read(void *buf, int count)
    13311523{
    1332     int ret = -1;
    1333     if (writemode)
     1524    int ret = ReadPriv(buf, count, false);
     1525    if (ret > 0)
    13341526    {
    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);
     1527        poslock.lockForWrite();
    13701528        readpos += ret;
     1529        poslock.unlock();
    13711530    }
    1372 
    1373     rwlock.unlock();
    13741531    return ret;
    13751532}
    13761533
    13771534/** \fn RingBuffer::IsIOBound(void) const
    1378  *  \brief Returns true if a RingBuffer::Read(void*,int) is likely to block.
     1535 *  \brief Returns true if a RingBuffer::Write(void*,int) is likely to block.
    13791536 */
    13801537bool RingBuffer::IsIOBound(void) const
    13811538{
     
    14041561 */
    14051562int RingBuffer::Write(const void *buf, uint count)
    14061563{
    1407     int ret = -1;
     1564    rwlock.lockForRead();
     1565
    14081566    if (!writemode)
    14091567    {
    14101568        VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file.");
    1411         return ret;
     1569        rwlock.unlock();
     1570        return -1;
    14121571    }
    14131572
    14141573    if (!tfw && !remotefile)
    1415         return ret;
     1574    {
     1575        rwlock.unlock();
     1576        return -1;
     1577    }
    14161578
    1417     rwlock.lockForRead();
    1418 
     1579    int ret = -1;
    14191580    if (tfw)
    14201581        ret = tfw->Write(buf, count);
    14211582    else
    14221583        ret = remotefile->Write(buf, count);
    1423     writepos += ret;
    14241584
     1585    if (ret > 0)
     1586    {
     1587        poslock.lockForWrite();
     1588        writepos += ret;
     1589        poslock.unlock();
     1590    }
     1591
    14251592    rwlock.unlock();
     1593
    14261594    return ret;
    14271595}
    14281596
     
    14311599 */
    14321600void RingBuffer::Sync(void)
    14331601{
     1602    rwlock.lockForRead();
    14341603    if (tfw)
    14351604        tfw->Sync();
     1605    rwlock.unlock();
    14361606}
    14371607
    1438 /** \fn RingBuffer::Seek(long long, int)
    1439  *  \brief Seeks to a particular position in the file.
     1608/** \brief Seeks to a particular position in the file.
    14401609 */
    1441 long long RingBuffer::Seek(long long pos, int whence)
     1610long long RingBuffer::Seek(long long pos, int whence, bool has_lock)
    14421611{
     1612    long long ret = -1;
     1613
     1614    // lockForWrite takes priority over lockForRead, so this will
     1615    // take priority over the lockForRead in the read ahead thread.
     1616    if (!has_lock)
     1617        rwlock.lockForWrite();
     1618
    14431619    if (writemode)
    1444         return WriterSeek(pos, whence);
     1620    {
     1621        ret = WriterSeek(pos, whence, true);
     1622        if (!has_lock)
     1623            rwlock.unlock();
     1624        return ret;
     1625    }
    14451626
    1446     wantseek = true;
    1447     rwlock.lockForWrite();
    1448     wantseek = false;
     1627    poslock.lockForRead();
    14491628
    14501629    // optimize nop seeks
    14511630    if ((whence == SEEK_SET && pos == readpos) ||
    14521631        (whence == SEEK_CUR && pos == 0))
    14531632    {
    1454         rwlock.unlock();
    1455         return readpos;
     1633        ret = readpos;
     1634
     1635        poslock.unlock();
     1636        if (!has_lock)
     1637            rwlock.unlock();
     1638
     1639        return ret;
    14561640    }
    14571641
    14581642    errno = 0; // clear errno, in case of remotefile error
    14591643
    1460     long long ret = -1;
    14611644    if (remotefile)
     1645    {
    14621646        ret = remotefile->Seek(pos, whence, readpos);
     1647    }
    14631648#ifdef USING_FRONTEND
    14641649    else if (dvdPriv)
    14651650    {
     
    14911676        }
    14921677    }
    14931678
     1679    poslock.unlock();
     1680
     1681    poslock.lockForWrite();
     1682
    14941683    if (ret >= 0)
    14951684    {
    14961685        if (whence == SEEK_SET)
     
    15111700        VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
    15121701    }
    15131702
    1514     rwlock.unlock();
     1703    poslock.unlock();
    15151704
     1705    if (!has_lock)
     1706        rwlock.unlock();
     1707
    15161708    return ret;
    15171709}
    15181710
    1519 /** \fn RingBuffer::WriterSeek(long long, int)
    1520  *  \brief Calls ThreadedFileWriter::Seek(long long,int).
     1711/** \brief Calls ThreadedFileWriter::Seek(long long,int).
    15211712 */
    1522 long long RingBuffer::WriterSeek(long long pos, int whence)
     1713long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock)
    15231714{
    15241715    long long ret = -1;
    15251716
     1717    if (!has_lock)
     1718        rwlock.lockForRead();
     1719
     1720    poslock.lockForWrite();
     1721
    15261722    if (tfw)
    15271723    {
    15281724        ret = tfw->Seek(pos, whence);
    15291725        writepos = ret;
    15301726    }
    15311727
     1728    poslock.unlock();
     1729
     1730    if (!has_lock)
     1731        rwlock.unlock();
     1732
    15321733    return ret;
    15331734}
    15341735
     
    15381739 */
    15391740void RingBuffer::WriterFlush(void)
    15401741{
     1742    rwlock.lockForRead();
    15411743    if (tfw)
    15421744    {
    15431745        tfw->Flush();
    15441746        tfw->Sync();
    15451747    }
     1748    rwlock.unlock();
    15461749}
    15471750
    15481751/** \fn RingBuffer::SetWriteBufferSize(int)
     
    15501753 */
    15511754void RingBuffer::SetWriteBufferSize(int newSize)
    15521755{
     1756    rwlock.lockForRead();
    15531757    if (tfw)
    15541758        tfw->SetWriteBufferSize(newSize);
     1759    rwlock.unlock();
    15551760}
    15561761
    15571762/** \fn RingBuffer::SetWriteBufferMinWriteSize(int)
     
    15591764 */
    15601765void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize)
    15611766{
     1767    rwlock.lockForRead();
    15621768    if (tfw)
    15631769        tfw->SetWriteBufferMinWriteSize(newMinSize);
     1770    rwlock.unlock();
    15641771}
    15651772
    15661773/** \fn RingBuffer::GetReadPosition(void) const
     
    15681775 */
    15691776long long RingBuffer::GetReadPosition(void) const
    15701777{
     1778    rwlock.lockForRead();
     1779    poslock.lockForRead();
     1780    long long ret = readpos;
    15711781#ifdef USING_FRONTEND
    15721782    if (dvdPriv)
    1573         return dvdPriv->GetReadPosition();
     1783        ret = dvdPriv->GetReadPosition();
    15741784    else if (bdPriv)
    1575         return bdPriv->GetReadPosition();
     1785        ret = bdPriv->GetReadPosition();
    15761786#endif // USING_FRONTEND
    1577 
    1578     return readpos;
     1787    poslock.unlock();
     1788    rwlock.unlock();
     1789    return ret;
    15791790}
    15801791
    15811792/** \fn RingBuffer::GetWritePosition(void) const
     
    15831794 */
    15841795long long RingBuffer::GetWritePosition(void) const
    15851796{
    1586     return writepos;
     1797    poslock.lockForRead();
     1798    long long ret = writepos;
     1799    poslock.unlock();
     1800    return ret;
    15871801}
    15881802
    15891803/** \fn RingBuffer::GetRealFileSize(void) const
     
    15921806 */
    15931807long long RingBuffer::GetRealFileSize(void) const
    15941808{
     1809    rwlock.lockForRead();
     1810    long long ret = -1;
    15951811    if (remotefile)
    1596         return remotefile->GetFileSize();
    1597 
    1598     QFileInfo info(filename);
    1599     return info.size();
     1812        ret = remotefile->GetFileSize();
     1813    else
     1814        ret = QFileInfo(filename).size();
     1815    rwlock.unlock();
     1816    return ret;
    16001817}
    16011818
    16021819/** \fn RingBuffer::LiveMode(void) const
     
    16051822 */
    16061823bool RingBuffer::LiveMode(void) const
    16071824{
    1608     return (livetvchain);
     1825    rwlock.lockForRead();
     1826    bool ret = (livetvchain);
     1827    rwlock.unlock();
     1828    return ret;
    16091829}
    16101830
    16111831/** \fn RingBuffer::SetLiveMode(LiveTVChain*)
     
    16141834 */
    16151835void RingBuffer::SetLiveMode(LiveTVChain *chain)
    16161836{
     1837    rwlock.lockForWrite();
    16171838    livetvchain = chain;
     1839    rwlock.unlock();
    16181840}
    16191841
    16201842bool RingBuffer::InDVDMenuOrStillFrame(void)
    16211843{
     1844    rwlock.lockForRead();
     1845    bool ret = false;
    16221846#ifdef USING_FRONTEND
    16231847    if (dvdPriv)
    1624         return (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
     1848        ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
    16251849#endif // USING_FRONTEND
    1626     return false;
     1850    rwlock.unlock();
     1851    return ret;
    16271852}
    16281853
    16291854/* 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*/);
     
    6672               bool resetInternal = false);
    6773
    6874    // Seeks
    69     long long Seek(long long pos, int whence);
     75    long long Seek(long long pos, int whence, bool has_lock = false);
    7076
    7177    // Pause commands
    7278    void Pause(void);
     
    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);
    89100    bool IsIOBound(void) const;
    90101    void WriterFlush(void);
    91102    void Sync(void);
    92     long long WriterSeek(long long pos, int whence);
     103    long long WriterSeek(long long pos, int whence, bool has_lock = false);
    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
     153    long long internalreadpos;    // protected by poslock
     154    mutable QReadWriteLock rbrlock;
     155    int       rbrpos;             // protected by rbrlock
     156    mutable QReadWriteLock rbwlock;
     157    int       rbwpos;             // protected by rbwlock
    130158
    131     QString filename;             // not protected by a lock LR
    132     QString subtitlefilename;     // not protected by a lock LR
     159    // note should not go under rwlock..
     160    // this is used to break out of read_safe where rwlock is held
     161    volatile bool stopreads;
    133162
    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 
    144163    mutable QReadWriteLock rwlock;
    145164
    146     RemoteFile *remotefile;       // not protected by a lock LR
     165    QString filename;             // protected by rwlock
     166    QString subtitlefilename;     // protected by rwlock
    147167
    148     // this lock does not consistently protect anything,
    149     // but seems to be intented to protect rbrpos & rbwpos
    150     mutable QMutex readAheadLock;
     168    ThreadedFileWriter *tfw;      // protected by rwlock
     169    int fd2;                      // protected by rwlock
    151170
    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
     171    bool writemode;               // protected by rwlock
    164172
    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
     173    RemoteFile *remotefile;       // protected by rwlock
    170174
    171     QWaitCondition pauseWait;     // not protected by a lock HR
     175    bool      startreadahead;     // protected by rwlock
     176    char     *readAheadBuffer;    // protected by rwlock
     177    bool      readaheadrunning;   // protected by rwlock
     178    bool      reallyrunning;      // protected by rwlock
     179    bool      request_pause;      // protected by rwlock
     180    bool      paused;             // protected by rwlock
     181    bool      ateof;              // protected by rwlock
     182    bool      readsallowed;       // protected by rwlock
     183    bool      setswitchtonext;    // protected by rwlock
     184    uint      rawbitrate;         // protected by rwlock
     185    float     playspeed;          // protected by rwlock
     186    int       fill_threshold;     // protected by rwlock
     187    int       fill_min;           // protected by rwlock
     188    int       readblocksize;      // protected by rwlock
     189    int       wanttoread;         // protected by rwlock
     190    int       numfailures;        // protected by rwlock (see note 1)
     191    bool      commserror;         // protected by rwlock
    172192
    173     int wanttoread;               // not protected by a lock HR
    174     QWaitCondition availWait;     // protected by availWaitMutex
    175     QMutex availWaitMutex;
     193    DVDRingBufferPriv *dvdPriv;   // not protected by rwlock, when DVD() is used
     194    BDRingBufferPriv  *bdPriv;    // protected by rwlock
    176195
    177     QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex
    178     QMutex readsAllowedWaitMutex;
     196    bool oldfile;                 // protected by rwlock
    179197
    180     int numfailures;              // not protected by a lock MR
     198    LiveTVChain *livetvchain;     // protected by rwlock
     199    bool ignoreliveeof;           // protected by rwlock
    181200
    182     bool commserror;              // not protected by a lock MR
     201    long long readAdjust;         // protected by rwlock
    183202
    184     DVDRingBufferPriv *dvdPriv;   // not protected by a lock LR
    185     BDRingBufferPriv  *bdPriv;    // not protected by a lock LR
     203    // note 1: numfailures is modified with only a read lock in the
     204    // read ahead thread, but this is safe since all other places
     205    // that use it are protected by a write lock. But this is a
     206    // fragile state of affairs and care must be taken when modifying
     207    // code or locking around this variable.
    186208
    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 
    194209    /// Condition to signal that the read ahead thread is running
    195     QWaitCondition readAheadRunningCond;//protected by readAheadRunningCondLock
    196     QMutex readAheadRunningCondLock;
     210    QWaitCondition generalWait;         // protected by rwlock
    197211
    198212  public:
    199213    static QMutex subExtLock;
     
    206220    static const uint kReadTestSize;
    207221};
    208222
    209 #endif
     223#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.