Ticket #8812: 8812-v15.patch

File 8812-v15.patch, 94.6 KB (added by danielk, 9 years ago)

Just the ring buffer portion of the previous patch (sans mythversion bits)

  • libs/libmythtv/mythiowrapper.cpp

     
    256256    if (!m_filenames.contains(fileID))
    257257    {
    258258        m_fileWrapperLock.unlock();
    259         return -1;
     259        return fstat(fileID, buf);
    260260    }
    261261    QString filename = m_filenames[fileID];
    262262    m_fileWrapperLock.unlock();
  • libs/libmythtv/importrecorder.cpp

     
    104104    {
    105105        MythCommFlagPlayer *cfp = new MythCommFlagPlayer();
    106106        RingBuffer *rb = new RingBuffer(
    107             ringBuffer->GetFilename(), false, true, 6);
     107            ringBuffer->GetFilename(), false, true, 6000);
    108108
    109109        PlayerContext *ctx = new PlayerContext(kImportRecorderInUseID);
    110110        ctx->SetPlayingInfo(curRecording);
  • libs/libmythtv/mythplayer.h

     
    44#include <stdint.h>
    55
    66#include <sys/time.h>
     7#include <limits.h>
    78
    89#include <QObject>
    910#include <QEvent>
     
    3637}
    3738using namespace std;
    3839
     40#ifndef LLONG_MIN
     41#define LLONG_MIN LONG_LONG_MIN
     42#endif
     43
    3944class VideoOutput;
    4045class RemoteEncoder;
    4146class MythSqlDatabase;
     
    373378    int64_t ResetAudioTimecodeOffset(void)
    374379        { tc_wrap[TC_AUDIO] = 0LL; return tc_wrap[TC_AUDIO]; }
    375380    int64_t ResyncAudioTimecodeOffset(void)
    376         { tc_wrap[TC_AUDIO] = INT64_MIN; return 0L; }
     381        { tc_wrap[TC_AUDIO] = LLONG_MIN; return 0L; }
    377382    int64_t GetAudioTimecodeOffset(void) const
    378383        { return tc_wrap[TC_AUDIO]; }
    379384    void SaveAudioTimecodeOffset(int64_t v)
  • libs/libmythtv/RingBuffer.cpp

     
    55#include <cerrno>
    66
    77// POSIX C headers
     8#define _LARGEFILE53_SOURCE
    89#include <sys/types.h>
    910#include <sys/time.h>
    1011#include <unistd.h>
     
    1920
    2021using namespace std;
    2122
     23#include "mythcontext.h" // for VERBOSE
    2224#include "mythconfig.h"
    23 
    2425#include "exitcodes.h"
    2526#include "RingBuffer.h"
    2627#include "remotefile.h"
     
    3031#include "BDRingBuffer.h"
    3132#include "util.h"
    3233#include "compat.h"
    33 #include "mythverbose.h"
    3434
    3535#ifndef O_STREAMING
    3636#define O_STREAMING 0
     
    4444#define O_BINARY 0
    4545#endif
    4646
    47 const uint RingBuffer::kBufferSize = 3 * 1024 * 1024;
     47// about one second at 35mbit
     48const uint RingBuffer::kBufferSize = 4 * 1024 * 1024;
     49const int  RingBuffer::kDefaultOpenTimeout = 2000; // ms
    4850
    4951#define CHUNK 32768 /* readblocksize increments */
    5052
     
    6567
    6668/*
    6769  Locking relations:
    68     rwlock->readAheadLock
    69           ->readsAllowedWaitMutex->readAheadRunningCondLock
    70           ->availWaitMutex
     70    rwlock->poslock->rbrlock->rbwlock
    7171
    7272  A child should never lock any of the parents without locking
    7373  the parent lock before the child lock.
    7474  void RingBuffer::Example1()
    7575  {
    76       QMutexLocker locker1(&readAheadRunningCondLock);
    77       QMutexLocker locker2(&readsAllowedWaitMutex); // error!
     76      poslock.lockForWrite();
     77      rwlock.lockForRead(); // error!
    7878      blah(); // <- does not implicitly aquire any locks
     79      rwlock.unlock();
     80      poslock.unlock();
    7981  }
    8082  void RingBuffer::Example2()
    8183  {
    82       QMutexLocker locker1(&readsAllowedWaitMutex);
    83       QMutexLocker locker2(&readAheadRunningCondLock); // ok!
     84      rwlock.lockForRead();
     85      rbrlock.lockForWrite(); // ok!
    8486      blah(); // <- does not implicitly aquire any locks
     87      rbrlock.unlock();
     88      rwlock.unlock();
    8589  }
    8690*/
    8791
     
    96100 *
    97101 */
    98102
    99 /** \fn RingBuffer::RingBuffer(const QString&, bool, bool, uint)
    100  *  \brief Creates a RingBuffer instance.
     103/** \brief Creates a RingBuffer instance.
    101104 *
    102105 *   You can explicitly disable the readahead thread by setting
    103106 *   readahead to false, or by just not calling Start(void).
     
    107110 *  \param readahead    If false a call to Start(void) will not
    108111 *                      a pre-buffering thread, otherwise Start(void)
    109112 *                      will start a pre-buffering thread.
    110  *  \param read_retries How often to retry reading the file
    111  *                      before giving up.
     113 *  \param timeout_ms   if < 0, then we will not open the file.
     114 *                      Otherwise it's how long to try opening
     115 *                      the file after the first failure in
     116 *                      milliseconds before giving up.
    112117 */
    113118RingBuffer::RingBuffer(const QString &lfilename,
    114119                       bool write, bool readahead,
    115                        uint read_retries)
    116     : filename(lfilename),      subtitlefilename(QString::null),
     120                       int timeout_ms)
     121    : readpos(0),               writepos(0),
     122      internalreadpos(0),       ignorereadpos(-1),
     123      rbrpos(0),                rbwpos(0),
     124      stopreads(false),
     125      filename(lfilename),      subtitlefilename(QString::null),
    117126      tfw(NULL),                fd2(-1),
    118       writemode(false),
    119       readpos(0),               writepos(0),
    120       stopreads(false),         remotefile(NULL),
     127      writemode(false),         remotefile(NULL),
    121128      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),
    127       streamOnly(false),
    128       rawbitrate(4000),         playspeed(1.0f),
     129      readaheadrunning(false),  reallyrunning(false),
     130      request_pause(false),     paused(false),
     131      ateof(false),             readsallowed(false),
     132      setswitchtonext(false),   streamOnly(false),
     133      rawbitrate(8000),         playspeed(1.0f),
    129134      fill_threshold(65536),    fill_min(-1),
    130135      readblocksize(CHUNK),     wanttoread(0),
    131136      numfailures(0),           commserror(false),
     
    183188        return;
    184189    }
    185190
    186     if (read_retries != (uint)-1)
    187         OpenFile(filename, read_retries);
     191    if (timeout_ms >= 0)
     192        OpenFile(filename, timeout_ms);
    188193}
    189194
    190195/** \fn check_permissions(const QString&)
     
    263268    return QString::null;
    264269}
    265270
    266 /** \fn RingBuffer::OpenFile(const QString&, uint)
    267  *  \brief Opens a file for reading.
     271/** \brief Opens a file for reading.
    268272 *
    269273 *  \param lfilename  Name of file to read
    270  *  \param retryCount How often to retry reading the file before giving up
     274 *  \param retry_ms   How many ms to retry reading the file
     275 *                    after the first try before giving up.
    271276 */
    272 void RingBuffer::OpenFile(const QString &lfilename, uint retryCount)
     277void RingBuffer::OpenFile(const QString &lfilename, uint retry_ms)
    273278{
    274     VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2)")
    275             .arg(lfilename).arg(retryCount));
     279    VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 ms)")
     280            .arg(lfilename).arg(retry_ms));
    276281
    277     uint openAttempts = retryCount + 1;
     282    rwlock.lockForWrite();
    278283
    279284    filename = lfilename;
    280285
     
    365370    if (is_local)
    366371    {
    367372        char buf[kReadTestSize];
    368         int timetowait = 500 * openAttempts;
    369373        int lasterror = 0;
    370374
    371375        MythTimer openTimer;
    372376        openTimer.start();
    373377
    374         while (openTimer.elapsed() < timetowait)
     378        uint openAttempts = 0;
     379        do
    375380        {
     381            openAttempts++;
    376382            lasterror = 0;
    377383            QByteArray fname = filename.toLocal8Bit();
    378384            fd2 = open(fname.constData(),
     
    381387            if (fd2 < 0)
    382388            {
    383389                if (!check_permissions(filename))
     390                {
     391                    lasterror = 3;
    384392                    break;
     393                }
    385394
    386395                lasterror = 1;
    387                 usleep(1000);
     396                usleep(10 * 1000);
    388397            }
    389398            else
    390399            {
     
    394403                    lasterror = 2;
    395404                    close(fd2);
    396405                    fd2 = -1;
    397                     usleep(1000);
     406                    if (oldfile)
     407                        break; // if it's an old file it won't grow..
     408                    usleep(10 * 1000);
    398409                }
    399410                else
    400411                {
    401                     lseek(fd2, 0, SEEK_SET);
     412                    if (0 == lseek(fd2, 0, SEEK_SET))
     413                    {
    402414#if HAVE_POSIX_FADVISE
    403                     posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL);
     415                        posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL);
    404416#endif
    405                     openAttempts = 0;
    406                     break;
     417                        lasterror = 0;
     418                        break;
     419                    }
     420                    lasterror = 4;
     421                    close(fd2);
     422                    fd2 = -1;
    407423                }
    408424            }
    409425        }
     426        while ((uint)openTimer.elapsed() < retry_ms);
    410427
    411428        switch (lasterror)
    412429        {
     430            case 0:
     431            {
     432                QFileInfo fi(filename);
     433                oldfile = fi.lastModified()
     434                    .secsTo(QDateTime::currentDateTime()) > 60;
     435                QString extension = fi.completeSuffix().toLower();
     436                if (is_subtitle_possible(extension))
     437                    subtitlefilename = local_sub_filename(fi);
     438                break;
     439            }
    413440            case 1:
    414                 VERBOSE(VB_IMPORTANT, LOC +
    415                         QString("Could not open %1.").arg(filename));
     441                VERBOSE(VB_IMPORTANT, LOC_ERR +
     442                        QString("OpenFile(): Could not open."));
    416443                break;
    417444            case 2:
    418                 VERBOSE(VB_IMPORTANT, LOC +
    419                         QString("Invalid file (fd %1) when opening '%2'.")
    420                         .arg(fd2).arg(filename));
     445                VERBOSE(VB_IMPORTANT, LOC_ERR +
     446                        QString("OpenFile(): File too small (%1B).")
     447                        .arg(QFileInfo(filename).size()));
    421448                break;
     449            case 3:
     450                VERBOSE(VB_IMPORTANT, LOC_ERR +
     451                        "OpenFile(): Improper permissions.");
     452                break;
     453            case 4:
     454                VERBOSE(VB_IMPORTANT, LOC_ERR +
     455                        "OpenFile(): Can not seek in file.");
     456                break;
    422457            default:
    423458                break;
    424459        }
     460        VERBOSE(VB_FILE, LOC + QString("OpenFile() made %1 attempts in %2 ms")
     461                .arg(openAttempts).arg(openTimer.elapsed()));
    425462
    426 
    427         QFileInfo fileInfo(filename);
    428         if (fileInfo.lastModified().secsTo(QDateTime::currentDateTime()) >
    429             30 * 60)
    430         {
    431             oldfile = true;
    432         }
    433 
    434         QString extension = fileInfo.completeSuffix().toLower();
    435         if (is_subtitle_possible(extension))
    436             subtitlefilename = local_sub_filename(fileInfo);
    437463    }
    438464#ifdef USING_FRONTEND
    439465    else if (is_dvd)
    440466    {
    441467        dvdPriv->OpenFile(filename);
    442         rwlock.lockForWrite();
    443468        readblocksize = DVD_BLOCK_SIZE * 62;
    444         rwlock.unlock();
    445469    }
    446470    else if (is_bd)
    447471    {
    448472        bdPriv->OpenFile(filename);
    449         rwlock.lockForWrite();
    450473        readblocksize = BD_BLOCK_SIZE * 62;
    451         rwlock.unlock();
    452474    }
    453475#endif // USING_FRONTEND
    454476    else
     
    481503            }
    482504        }
    483505
    484         remotefile = new RemoteFile(filename, false, true, -1, &auxFiles);
     506        remotefile = new RemoteFile(filename, false, true,
     507                                    retry_ms, &auxFiles);
    485508        if (!remotefile->isOpen())
    486509        {
    487             VERBOSE(VB_IMPORTANT,
     510            VERBOSE(VB_IMPORTANT, LOC_ERR +
    488511                    QString("RingBuffer::RingBuffer(): Failed to open remote "
    489512                            "file (%1)").arg(filename));
    490513            delete remotefile;
     
    503526    commserror = false;
    504527    numfailures = 0;
    505528
    506     UpdateRawBitrate(4000);
     529    rawbitrate = 8000;
     530    CalcReadAheadThresh();
     531
     532    rwlock.unlock();
    507533}
    508534
    509535/** \fn RingBuffer::IsOpen(void) const
     
    511537 */
    512538bool RingBuffer::IsOpen(void) const
    513539{
     540    rwlock.lockForRead();
     541    bool ret;
    514542#ifdef USING_FRONTEND
    515     return tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
     543    ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
    516544           (bdPriv && bdPriv->IsOpen());
    517545#else // if !USING_FRONTEND
    518     return tfw || (fd2 > -1) || remotefile;
     546    ret = tfw || (fd2 > -1) || remotefile;
    519547#endif // !USING_FRONTEND
     548    rwlock.unlock();
     549    return ret;
    520550}
    521551
    522552/** \fn RingBuffer::~RingBuffer(void)
     
    557587    }
    558588#endif // USING_FRONTEND
    559589
     590    if (readAheadBuffer) // this only runs if thread is terminated
     591    {
     592        delete [] readAheadBuffer;
     593        readAheadBuffer = NULL;
     594    }
     595
    560596    rwlock.unlock();
    561597}
    562598
    563 /** \fn RingBuffer::Start(void)
    564  *  \brief Starts the read-ahead thread.
    565  *
    566  *   If this RingBuffer is not in write-mode, the RingBuffer constructor
    567  *   was called with a usereadahead of true, and the read-ahead thread
    568  *   is not already running.
    569  */
    570 void RingBuffer::Start(void)
    571 {
    572     if (!writemode && !readaheadrunning && startreadahead)
    573         StartupReadAheadThread();
    574 }
    575 
    576599/** \fn RingBuffer::Reset(bool, bool, bool)
    577600 *  \brief Resets the read-ahead thread and our position in the file
    578601 */
    579602void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal)
    580603{
    581     wantseek = true;
     604    VERBOSE(VB_FILE, LOC + QString("Reset(%1,%2,%3)")
     605            .arg(full).arg(toAdjust).arg(resetInternal));
     606
    582607    rwlock.lockForWrite();
    583     wantseek = false;
     608    poslock.lockForWrite();
     609
    584610    numfailures = 0;
    585611    commserror = false;
    586612    setswitchtonext = false;
     
    590616
    591617    if (readpos != 0)
    592618    {
    593         VERBOSE(VB_IMPORTANT, QString(
     619        VERBOSE(VB_IMPORTANT, LOC + QString(
    594620                "RingBuffer::Reset() nonzero readpos.  toAdjust: %1 readpos: %2"
    595621                " readAdjust: %3").arg(toAdjust).arg(readpos).arg(readAdjust));
    596622    }
     
    604630    if (resetInternal)
    605631        internalreadpos = readpos;
    606632
     633    generalWait.wakeAll();
     634    poslock.unlock();
    607635    rwlock.unlock();
    608636}
    609637
     
    625653    unsigned errcnt = 0;
    626654    unsigned zerocnt = 0;
    627655
    628     if (fd < 0)
     656    if (fd2 < 0)
    629657    {
    630658        VERBOSE(VB_IMPORTANT, LOC_ERR +
    631659                "Invalid file descriptor in 'safe_read()'");
     
    637665
    638666    while (tot < sz)
    639667    {
    640         ret = read(fd, (char *)data + tot, sz - tot);
     668        ret = read(fd2, (char *)data + tot, sz - tot);
    641669        if (ret < 0)
    642670        {
    643671            if (errno == EAGAIN)
     
    691719 */
    692720int RingBuffer::safe_read(RemoteFile *rf, void *data, uint sz)
    693721{
    694     int ret = 0;
    695 
    696     ret = rf->Read(data, sz);
     722    int ret = rf->Read(data, sz);
    697723    if (ret < 0)
    698724    {
    699725        VERBOSE(VB_IMPORTANT, LOC_ERR +
    700726                "RingBuffer::safe_read(RemoteFile* ...): read failed");
    701 
     727           
     728        poslock.lockForRead();
    702729        rf->Seek(internalreadpos - readAdjust, SEEK_SET);
    703         ret = 0;
     730        poslock.unlock();
    704731        numfailures++;
    705      }
     732    }
     733    else if (ret == 0)
     734    {
     735        VERBOSE(VB_FILE, LOC +
     736                "RingBuffer::safe_read(RemoteFile* ...): at EOF");
     737    }
    706738
    707739    return ret;
    708740}
     
    714746 */
    715747void RingBuffer::UpdateRawBitrate(uint raw_bitrate)
    716748{
     749    VERBOSE(VB_FILE, LOC + QString("UpdateRawBitrate(%1Kb)").arg(raw_bitrate));
     750    if (raw_bitrate < 2500)
     751    {
     752        VERBOSE(VB_FILE, LOC +
     753                QString("UpdateRawBitrate(%1Kb) - ignoring bitrate,")
     754                .arg(raw_bitrate) +
     755                "\n\t\t\tappears to be abnormally low.");
     756        return;
     757    }
     758
    717759    rwlock.lockForWrite();
    718760    rawbitrate = raw_bitrate;
    719761    CalcReadAheadThresh();
    720762    rwlock.unlock();
    721763}
    722764
    723 /** \fn RingBuffer::GetBitrate(void) const
    724  *  \brief Returns effective bits per second (in thousands).
    725  *
    726  *   NOTE: This is reported in telecom kilobytes, to get
    727  *         the bits per second multiply by 1000, not 1024.
    728  */
    729 uint RingBuffer::GetBitrate(void) const
    730 {
    731     rwlock.lockForRead();
    732     uint tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
    733     rwlock.unlock();
    734     return min(rawbitrate * 3, tmp);
    735 }
    736 
    737 /** \fn RingBuffer::GetReadBlockSize(void) const
    738  *  \brief Returns size of each disk read made by read ahead thread (in bytes).
    739  */
    740 uint RingBuffer::GetReadBlockSize(void) const
    741 {
    742     rwlock.lockForRead();
    743     uint tmp = readblocksize;
    744     rwlock.unlock();
    745     return tmp;
    746 }
    747 
    748765/** \fn RingBuffer::UpdatePlaySpeed(float)
    749766 *  \brief Set the play speed, to allow RingBuffer adjust effective bitrate.
    750767 *  \param play_speed Speed to set. (1.0 for normal speed)
     
    768785{
    769786    uint estbitrate = 0;
    770787
    771     wantseek       = false;
    772788    readsallowed   = false;
    773     readblocksize  = CHUNK;
     789    readblocksize  = max(readblocksize, CHUNK);
    774790
    775791    // loop without sleeping if the buffered data is less than this
    776     fill_threshold = CHUNK * 2;
    777     fill_min       = 1;
     792    fill_threshold = kBufferSize / 8;
    778793
    779 #ifdef USING_FRONTEND
    780     if (dvdPriv || bdPriv)
    781     {
    782         const uint KB32  =  32*1024;
    783         const uint KB64  =  64*1024;
    784         const uint KB128 = 128*1024;
    785         const uint KB256 = 256*1024;
    786         const uint KB512 = 512*1024;
     794    const uint KB32  =  32*1024;
     795    const uint KB64  =  64*1024;
     796    const uint KB128 = 128*1024;
     797    const uint KB256 = 256*1024;
     798    const uint KB512 = 512*1024;
    787799
    788         estbitrate     = (uint) max(abs(rawbitrate * playspeed),
    789                                     0.5f * rawbitrate);
    790         estbitrate     = min(rawbitrate * 3, estbitrate);
    791         readblocksize  = (estbitrate > 2500)  ? KB64  : KB32;
    792         readblocksize  = (estbitrate > 5000)  ? KB128 : readblocksize;
    793         readblocksize  = (estbitrate > 9000)  ? KB256 : readblocksize;
    794         readblocksize  = (estbitrate > 18000) ? KB512 : readblocksize;
     800    estbitrate     = (uint) max(abs(rawbitrate * playspeed),
     801                                0.5f * rawbitrate);
     802    estbitrate     = min(rawbitrate * 3, estbitrate);
     803    int rbs        = (estbitrate > 2500)  ? KB64  : KB32;
     804    rbs            = (estbitrate > 5000)  ? KB128 : rbs;
     805    rbs            = (estbitrate > 9000)  ? KB256 : rbs;
     806    rbs            = (estbitrate > 18000) ? KB512 : rbs;
     807    readblocksize  = max(rbs,readblocksize);
    795808
    796         // minumum seconds of buffering before allowing read
    797         float secs_min = 0.1;
     809    // minumum seconds of buffering before allowing read
     810    float secs_min = 0.25;
     811    // set the minimum buffering before allowing ffmpeg read
     812    fill_min        = (uint) ((estbitrate * secs_min) * 0.125f);
     813    // make this a multiple of ffmpeg block size..
     814    fill_min        = ((fill_min / KB32) + 1) * KB32;
    798815
    799         // set the minimum buffering before allowing ffmpeg read
    800         fill_min        = (uint) ((estbitrate * secs_min) * 0.125f);
    801         // make this a multiple of ffmpeg block size..
    802         fill_min        = ((fill_min / KB32) + 1) * KB32;
    803     }
    804 #endif // USING_FRONTEND
    805 
    806     VERBOSE(VB_PLAYBACK, LOC +
    807             QString("CalcReadAheadThresh(%1 KB)\n\t\t\t -> "
     816    VERBOSE(VB_FILE, LOC +
     817            QString("CalcReadAheadThresh(%1 Kb)\n\t\t\t -> "
    808818                    "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)")
    809819            .arg(estbitrate).arg(fill_threshold/1024)
    810820            .arg(fill_min/1024).arg(readblocksize/1024));
    811821}
    812822
    813 /** \fn RingBuffer::ReadBufFree(void) const
    814  *  \brief Returns number of bytes available for reading into buffer.
    815  */
     823bool RingBuffer::IsNearEnd(double fps, uint vvf) const
     824{
     825    rwlock.lockForRead();
     826    int    sz  = ReadBufAvail();
     827    uint   rbs = readblocksize;
     828    // telecom kilobytes (i.e. 1000 per k not 1024)
     829    uint   tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
     830    uint   kbits_per_sec = min(rawbitrate * 3, tmp);
     831    rwlock.unlock();
     832
     833    // WARNING: readahead_frames can greatly overestimate or underestimate
     834    //          the number of frames available in the read ahead buffer
     835    //          when rh_frames is less than the keyframe distance.
     836    double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps;
     837    double readahead_frames = sz / bytes_per_frame;
     838
     839    bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5);
     840
     841    VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
     842            <<" br("<<(kbits_per_sec/8)<<"KB)"
     843            <<" sz("<<(sz / 1000)<<"KB)"
     844            <<" vfl("<<vvf<<")"
     845            <<" frh("<<((uint)readahead_frames)<<")"
     846            <<" ne:"<<near_end);
     847
     848    return near_end;
     849}
     850
     851/// \brief Returns number of bytes available for reading into buffer.
     852/// WARNING: Must be called with rwlock in locked state.
    816853int RingBuffer::ReadBufFree(void) const
    817854{
    818     QMutexLocker locker(&readAheadLock);
    819     return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     855    rbrlock.lockForRead();
     856    rbwlock.lockForRead();
     857    int ret = ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     858    rbwlock.unlock();
     859    rbrlock.unlock();
     860    return ret;
    820861}
    821862
    822 /** \fn RingBuffer::ReadBufAvail(void) const
    823  *  \brief Returns number of bytes available for reading from buffer.
    824  */
     863/// \brief Returns number of bytes available for reading from buffer.
     864/// WARNING: Must be called with rwlock in locked state.
    825865int RingBuffer::ReadBufAvail(void) const
    826866{
    827     QMutexLocker locker(&readAheadLock);
    828     return (rbwpos >= rbrpos) ?
    829         rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     867    rbrlock.lockForRead();
     868    rbwlock.lockForRead();
     869    int ret = (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     870    rbwlock.unlock();
     871    rbrlock.unlock();
     872    return ret;
    830873}
    831874
    832875/** \fn RingBuffer::ResetReadAhead(long long)
     
    836879 *   buffer doesn't contain any stale data, and so that it will read
    837880 *   any new data from the new position in the file.
    838881 *
    839  *   WARNING: Must be called with rwlock in write lock state.
     882 *   WARNING: Must be called with rwlock and poslock in write lock state.
    840883 *
    841884 *  \param newinternal Position in file to start reading data from
    842885 */
    843886void RingBuffer::ResetReadAhead(long long newinternal)
    844887{
    845     readAheadLock.lock();
    846     readblocksize = CHUNK;
     888    VERBOSE(VB_FILE, LOC + QString("ResetReadAhead(internalreadpos = %1->%2)")
     889            .arg(internalreadpos).arg(newinternal));
     890
     891    rbrlock.lockForWrite();
     892    rbwlock.lockForWrite();
     893
     894    CalcReadAheadThresh();
    847895    rbrpos = 0;
    848896    rbwpos = 0;
    849897    internalreadpos = newinternal;
    850898    ateof = false;
    851899    readsallowed = false;
    852900    setswitchtonext = false;
    853     readAheadLock.unlock();
     901    generalWait.wakeAll();
     902
     903    rbwlock.unlock();
     904    rbrlock.unlock();
    854905}
    855906
    856 /** \fn RingBuffer::StartupReadAheadThread(void)
    857  *  \brief Creates the read-ahead thread, and waits for it to start.
     907/**
     908 *  \brief Starts the read-ahead thread.
    858909 *
    859  *  \sa Start(void).
     910 *   If the RingBuffer constructor was not called with a usereadahead
     911 *   of true of if this was reset to false because we're dealing with
     912 *   a DVD the read ahead thread will not be started.
     913 *
     914 *   If this RingBuffer is in write-mode a warning will be printed and
     915 *   the read ahead thread will not be started.
     916 *
     917 *   If the read ahead thread is already running a warning will be printed
     918 *   and the read ahead thread will not be started.
     919 *
    860920 */
    861 void RingBuffer::StartupReadAheadThread(void)
     921void RingBuffer::Start(void)
    862922{
    863     readaheadrunning = false;
     923    bool do_start = true;
    864924
    865     readAheadRunningCondLock.lock();
     925    rwlock.lockForWrite();
     926    if (!startreadahead)
     927    {
     928        do_start = false;
     929    }
     930    else if (writemode)
     931    {
     932        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     933                "this is a write only RingBuffer");
     934        do_start = false;
     935    }
     936    else if (readaheadrunning)
     937    {
     938        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     939                "already running");
     940        do_start = false;
     941    }
     942
     943    if (!do_start)
     944    {
     945        rwlock.unlock();
     946        return;
     947    }
     948
     949    StartReads();
     950
    866951    QThread::start();
    867     readAheadRunningCond.wait(&readAheadRunningCondLock);
    868     readAheadRunningCondLock.unlock();
     952
     953    while (readaheadrunning && !reallyrunning)
     954        generalWait.wait(&rwlock);
     955
     956    rwlock.unlock();
    869957}
    870958
    871959/** \fn RingBuffer::KillReadAheadThread(void)
     
    873961 */
    874962void RingBuffer::KillReadAheadThread(void)
    875963{
    876     if (!readaheadrunning)
    877         return;
    878 
    879     readaheadrunning = false;
    880     QThread::wait();
     964    while (isRunning())
     965    {
     966        rwlock.lockForWrite();
     967        bool do_wait = readaheadrunning;
     968        readaheadrunning = false;
     969        StopReads();
     970        generalWait.wakeAll();
     971        rwlock.unlock();
     972        QThread::wait(5000);
     973    }
    881974}
    882975
    883976/** \fn RingBuffer::StopReads(void)
     
    887980void RingBuffer::StopReads(void)
    888981{
    889982    stopreads = true;
    890     availWait.wakeAll();
     983    generalWait.wakeAll();
    891984}
    892985
    893986/** \fn RingBuffer::StartReads(void)
     
    897990void RingBuffer::StartReads(void)
    898991{
    899992    stopreads = false;
     993    generalWait.wakeAll();
    900994}
    901995
    902996/** \fn RingBuffer::Pause(void)
     
    905999 */
    9061000void RingBuffer::Pause(void)
    9071001{
    908     pausereadthread = true;
    9091002    StopReads();
     1003
     1004    rwlock.lockForWrite();
     1005    request_pause = true;
     1006    rwlock.unlock();
    9101007}
    9111008
    9121009/** \fn RingBuffer::Unpause(void)
     
    9161013void RingBuffer::Unpause(void)
    9171014{
    9181015    StartReads();
    919     pausereadthread = false;
     1016
     1017    rwlock.lockForWrite();
     1018    request_pause = false;
     1019    generalWait.wakeAll();
     1020    rwlock.unlock();
    9201021}
    9211022
     1023/// Returns false iff read-ahead is not running and read-ahead is not paused.
     1024bool RingBuffer::isPaused(void) const
     1025{
     1026    rwlock.lockForRead();
     1027    bool ret = !readaheadrunning || paused;
     1028    rwlock.unlock();
     1029    return ret;
     1030}
     1031
    9221032/** \fn RingBuffer::WaitForPause(void)
    9231033 *  \brief Waits for Pause(void) to take effect.
    9241034 */
    9251035void RingBuffer::WaitForPause(void)
    9261036{
    927     if (!readaheadrunning)
    928         return;
     1037    MythTimer t;
     1038    t.start();
    9291039
    930     if  (!readaheadpaused)
     1040    rwlock.lockForRead();
     1041    while (readaheadrunning && !paused && request_pause)
    9311042    {
    932         // Qt4 requires a QMutex as a parameter...
    933         // not sure if this is the best solution.  Mutex Must be locked before wait.
    934         QMutex mutex;
    935         mutex.lock();
     1043        generalWait.wait(&rwlock, 1000);
     1044        if (readaheadrunning && !paused && request_pause && t.elapsed() > 1000)
     1045        {
     1046            VERBOSE(VB_IMPORTANT, LOC_WARN +
     1047                    QString("Waited %1 ms for ringbuffer pause..")
     1048                    .arg(t.elapsed()));
     1049        }
     1050    }
     1051    rwlock.unlock();
     1052}
    9361053
    937         while (!pauseWait.wait(&mutex, 1000))
    938             VERBOSE(VB_IMPORTANT,
    939                     LOC + "Waited too long for ringbuffer pause..");
     1054bool RingBuffer::PauseAndWait(void)
     1055{
     1056    const uint timeout = 500; // ms
     1057
     1058    if (request_pause)
     1059    {
     1060        if (!paused)
     1061        {
     1062            rwlock.unlock();
     1063            rwlock.lockForWrite();
     1064
     1065            if (request_pause)
     1066            {
     1067                paused = true;
     1068                generalWait.wakeAll();
     1069            }
     1070
     1071            rwlock.unlock();
     1072            rwlock.lockForRead();
     1073        }
     1074
     1075        if (request_pause && paused && readaheadrunning)
     1076            generalWait.wait(&rwlock, timeout);
    9401077    }
     1078
     1079    if (!request_pause && paused)
     1080    {
     1081        rwlock.unlock();
     1082        rwlock.lockForWrite();
     1083
     1084        if (!request_pause)
     1085        {
     1086            paused = false;
     1087            generalWait.wakeAll();
     1088        }
     1089
     1090        rwlock.unlock();
     1091        rwlock.lockForRead();
     1092    }
     1093
     1094    return request_pause || paused;
    9411095}
    9421096
    9431097void RingBuffer::run(void)
    9441098{
    945     long long totfree = 0;
    946     int ret = -1;
    947     int used = 0;
    948     int loops = 0;
    949 
     1099    // These variables are used to adjust the read block size
    9501100    struct timeval lastread, now;
    951     gettimeofday(&lastread, NULL);
    952     const int KB640 = 640*1024;
    9531101    int readtimeavg = 300;
    954     int readinterval;
     1102    bool ignore_for_read_timing = true;
    9551103
    956     pausereadthread = false;
     1104    gettimeofday(&lastread, NULL); // this is just to keep gcc happy
    9571105
    958     readAheadBuffer = new char[kBufferSize + KB640];
    959 
    9601106    rwlock.lockForWrite();
     1107    poslock.lockForWrite();
     1108    request_pause = false;
     1109    readAheadBuffer = new char[kBufferSize + 1024];
    9611110    ResetReadAhead(0);
     1111    readaheadrunning = true;
     1112    reallyrunning = true;
     1113    generalWait.wakeAll();
     1114    poslock.unlock();
    9621115    rwlock.unlock();
    9631116
    964     totfree = ReadBufFree();
     1117    // NOTE: this must loop at some point hold only
     1118    // a read lock on rwlock, so that other functions
     1119    // such as reset and seek can take priority.
    9651120
    966     readaheadrunning = true;
    967     readAheadRunningCondLock.lock();
    968     readAheadRunningCond.wakeAll();
    969     readAheadRunningCondLock.unlock();
     1121    rwlock.lockForRead();
     1122
     1123    VERBOSE(VB_FILE, LOC + QString("Initial readblocksize %1K & fill_min %2K")
     1124            .arg(readblocksize/1024).arg(fill_min/1024));
     1125
    9701126    while (readaheadrunning)
    9711127    {
    972         if (pausereadthread || writemode)
     1128        if (PauseAndWait())
    9731129        {
    974             readaheadpaused = true;
    975             pauseWait.wakeAll();
    976             usleep(5000);
    977             totfree = ReadBufFree();
     1130            ignore_for_read_timing = true;
    9781131            continue;
    9791132        }
    9801133
    981         if (readaheadpaused)
     1134        long long totfree = ReadBufFree();
     1135
     1136        // These are conditions where we don't want to go through
     1137        // the loop if they are true.
     1138        if (((totfree < readblocksize) && readsallowed) ||
     1139            (ignorereadpos >= 0) || commserror || stopreads)
    9821140        {
    983             totfree = ReadBufFree();
    984             readaheadpaused = false;
     1141            ignore_for_read_timing |=
     1142                (ignorereadpos >= 0) || commserror || stopreads;
     1143            generalWait.wait(&rwlock, (stopreads) ? 50 : 1000);
     1144            continue;
    9851145        }
    9861146
    987         totfree = ReadBufFree();
    988         if (totfree < GetReadBlockSize())
     1147        // These are conditions where we want to sleep to allow
     1148        // other threads to do stuff.
     1149        if (setswitchtonext || (ateof && readsallowed))
    9891150        {
    990             usleep(50000);
     1151            ignore_for_read_timing = true;
     1152            generalWait.wait(&rwlock, 1000);
    9911153            totfree = ReadBufFree();
    992             ++loops;
    993             // break out if we've spent lots of time here, just in case things
    994             // are waiting on a wait condition that never got triggered.
    995             if (readsallowed && loops < 10)
    996                 continue;
    9971154        }
    998         loops = 0;
    9991155
    1000         rwlock.lockForRead();
    1001         if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
     1156        int read_return = -1;
     1157        if (totfree >= readblocksize && !commserror &&
     1158            !ateof && !setswitchtonext)
    10021159        {
    10031160            // limit the read size
    10041161            totfree = readblocksize;
    10051162
    10061163            // adapt blocksize
    10071164            gettimeofday(&now, NULL);
    1008             readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
    1009                            (now.tv_usec - lastread.tv_usec) / 1000;
     1165            if (!ignore_for_read_timing)
     1166            {
     1167                int readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
     1168                    (now.tv_usec - lastread.tv_usec) / 1000;
     1169                readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    10101170
    1011             readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    1012 
    1013             if (readtimeavg < 200 && readblocksize < KB640)
    1014             {
    1015                 readblocksize += CHUNK;
    1016                 //VERBOSE(VB_PLAYBACK,
    1017                 //    QString("Avg read interval was %1 msec. %2K block size")
    1018                 //            .arg(readtimeavg).arg(readblocksize/1024));
    1019                 readtimeavg = 300;
     1171                if (readtimeavg < 150 && (uint)readblocksize < (kBufferSize>>2))
     1172                {
     1173                    int old_block_size = readblocksize;
     1174                    readblocksize = 3 * readblocksize / 2;
     1175                    readblocksize = ((readblocksize+CHUNK-1) / CHUNK) * CHUNK;
     1176                    VERBOSE(VB_FILE, LOC +
     1177                            QString("Avg read interval was %1 msec. "
     1178                                    "%2K -> %3K block size")
     1179                            .arg(readtimeavg)
     1180                            .arg(old_block_size/1024)
     1181                            .arg(readblocksize/1024));
     1182                    readtimeavg = 225;
     1183                }
     1184                else if (readtimeavg > 300 && readblocksize > CHUNK)
     1185                {
     1186                    readblocksize -= CHUNK;
     1187                    VERBOSE(VB_FILE, LOC +
     1188                            QString("Avg read interval was %1 msec. "
     1189                                    "%2K -> %3K block size")
     1190                            .arg(readtimeavg)
     1191                            .arg((readblocksize+CHUNK)/1024)
     1192                            .arg(readblocksize/1024));
     1193                    readtimeavg = 225;
     1194                }
    10201195            }
    1021             else if (readtimeavg > 400 && readblocksize > CHUNK)
    1022             {
    1023                 readblocksize -= CHUNK;
    1024                 //VERBOSE(VB_PLAYBACK,
    1025                 //    QString("Avg read interval was %1 msec. %2K block size")
    1026                 //            .arg(readtimeavg).arg(readblocksize/1024));
    1027                 readtimeavg = 300;
    1028             }
     1196            ignore_for_read_timing = false;
    10291197            lastread = now;
    10301198
     1199            rbwlock.lockForRead();
    10311200            if (rbwpos + totfree > kBufferSize)
     1201            {
    10321202                totfree = kBufferSize - rbwpos;
     1203                VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1204                        "Shrinking read, near end of buffer");
     1205            }
    10331206
    10341207            if (internalreadpos == 0)
    1035                 totfree = fill_min;
     1208            {
     1209                totfree = max(fill_min, readblocksize);
     1210                VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1211                        "Reading enough data to start playback");
     1212            }
    10361213
     1214            VERBOSE(VB_FILE|VB_EXTRA,
     1215                    LOC + QString("safe_read(...@%1, %2) -- begin")
     1216                    .arg(rbwpos).arg(totfree));
    10371217            if (remotefile)
    10381218            {
    10391219                if (livetvchain && livetvchain->HasNext())
    10401220                    remotefile->SetTimeout(true);
    1041 
    1042                 ret = safe_read(remotefile, readAheadBuffer + rbwpos,
    1043                                 totfree);
    1044                 internalreadpos += ret;
     1221                read_return = safe_read(
     1222                    remotefile, readAheadBuffer + rbwpos, totfree);
    10451223            }
    10461224#ifdef USING_FRONTEND
    10471225            else if (dvdPriv)
    10481226            {
    1049                 ret = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1050                 internalreadpos += ret;
     1227                read_return = dvdPriv->safe_read(
     1228                    readAheadBuffer + rbwpos, totfree);
    10511229            }
    10521230            else if (bdPriv)
    10531231            {
    1054                 ret = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1055                 internalreadpos += ret;
     1232                read_return = bdPriv->safe_read(
     1233                    readAheadBuffer + rbwpos, totfree);
    10561234            }
    10571235#endif // USING_FRONTEND
    10581236            else
    10591237            {
    1060                 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    1061                 internalreadpos += ret;
     1238                read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    10621239            }
     1240            VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1241                    QString("safe_read(...@%1, %2) -> %3")
     1242                    .arg(rbwpos).arg(totfree).arg(read_return));
     1243            rbwlock.unlock();
     1244        }
    10631245
    1064             readAheadLock.lock();
    1065             if (ret > 0 )
    1066                 rbwpos = (rbwpos + ret) % kBufferSize;
    1067             readAheadLock.unlock();
     1246        if (read_return >= 0)
     1247        {
     1248            poslock.lockForWrite();
     1249            rbwlock.lockForWrite();
     1250            internalreadpos += read_return;
     1251            rbwpos = (rbwpos + read_return) % kBufferSize;
     1252            VERBOSE(VB_FILE|VB_EXTRA,
     1253                    LOC + QString("rbwpos += %1K requested %2K in read")
     1254                    .arg(read_return/1024,3).arg(totfree/1024,3));
     1255            rbwlock.unlock();
     1256            poslock.unlock();
     1257        }
    10681258
    1069             if (ret == 0 && !stopreads)
     1259        int used = kBufferSize - ReadBufFree();
     1260
     1261        if ((0 == read_return) || (numfailures > 5) ||
     1262            (readsallowed != (used >= fill_min || ateof ||
     1263                              setswitchtonext || commserror)))
     1264        {
     1265            // If readpos changes while the lock is released
     1266            // we should not handle the 0 read_return now.
     1267            long long old_readpos = readpos;
     1268
     1269            rwlock.unlock();
     1270            rwlock.lockForWrite();
     1271
     1272            commserror |= (numfailures > 5);
     1273
     1274            readsallowed = used >= fill_min || ateof ||
     1275                setswitchtonext || commserror;
     1276
     1277            if (0 == read_return && old_readpos == readpos)
    10701278            {
    10711279                if (livetvchain)
    10721280                {
     
    10781286                    }
    10791287                }
    10801288                else
     1289                {
     1290                    VERBOSE(VB_FILE|VB_EXTRA,
     1291                            LOC + "setting ateof (read_return == 0)");
    10811292                    ateof = true;
     1293                }
    10821294            }
    1083         }
    10841295
    1085         if (numfailures > 5)
    1086             commserror = true;
    1087 
    1088         totfree = ReadBufFree();
    1089         used = kBufferSize - totfree;
    1090 
    1091         if (ateof || commserror)
    1092         {
    1093             readsallowed = true;
    1094             totfree = 0;
     1296            rwlock.unlock();
     1297            rwlock.lockForRead();
     1298            used = kBufferSize - ReadBufFree();
    10951299        }
    10961300
    1097         if (!readsallowed && (used >= fill_min || setswitchtonext))
    1098         {
    1099             readsallowed = true;
    1100             //VERBOSE(VB_PLAYBACK, QString("reads allowed (%1 %2)").arg(used)
    1101             //                                                    .arg(fill_min));
    1102         }
    1103         //else if (!readsallowed)
    1104         //    VERBOSE(VB_PLAYBACK, QString("buffering (%1 %2 %3)").arg(used)
    1105         //                                                        .arg(fill_min)
    1106         //                                                        .arg(ret));
     1301        VERBOSE(VB_FILE|VB_EXTRA, LOC + "@ end of read ahead loop");
    11071302
    1108         if (readsallowed && used < fill_min && !ateof && !setswitchtonext)
    1109         {
    1110             readsallowed = false;
    1111             //VERBOSE(VB_GENERAL, QString ("rebuffering (%1 %2)").arg(used)
    1112             //                                                   .arg(fill_min));
    1113         }
    1114 
    1115         readsAllowedWaitMutex.lock();
    1116         if (readsallowed || stopreads)
    1117             readsAllowedWait.wakeAll();
    1118         readsAllowedWaitMutex.unlock();
    1119 
    1120         availWaitMutex.lock();
    1121         if (commserror || ateof || stopreads || setswitchtonext ||
     1303        if (readsallowed || commserror || ateof || setswitchtonext ||
    11221304            (wanttoread <= used && wanttoread > 0))
    11231305        {
    1124             availWait.wakeAll();
     1306            // To give other threads a good chance to handle these
     1307            // conditions, even if they are only requesting a read lock
     1308            // like us, yield (currently implemented with short usleep).
     1309            generalWait.wakeAll();
     1310            rwlock.unlock();
     1311            usleep(5 * 1000);
     1312            rwlock.lockForRead();           
    11251313        }
    1126         availWaitMutex.unlock();
    1127 
    1128         rwlock.unlock();
    1129 
    1130         if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
    1131             !pausereadthread)
     1314        else
    11321315        {
    1133             usleep(500);
     1316            // yield if we have nothing to do...
     1317            if (!request_pause &&
     1318                (used >= fill_threshold || ateof || setswitchtonext))
     1319            {
     1320                generalWait.wait(&rwlock, 1000);
     1321            }
    11341322        }
    11351323    }
    11361324
     1325    rwlock.unlock();
     1326
     1327    rwlock.lockForWrite();
     1328    rbrlock.lockForWrite();
     1329    rbwlock.lockForWrite();
     1330
     1331    rbrpos = 0;
     1332    rbwpos = 0;
     1333    reallyrunning = false;
     1334    readsallowed = false;
    11371335    delete [] readAheadBuffer;
     1336
    11381337    readAheadBuffer = NULL;
    1139     rbrpos = 0;
    1140     rbwpos = 0;
     1338    rbwlock.unlock();
     1339    rbrlock.unlock();
     1340    rwlock.unlock();
    11411341}
    11421342
    11431343long long RingBuffer::SetAdjustFilesize(void)
    11441344{
     1345    rwlock.lockForWrite();
     1346    poslock.lockForRead();
    11451347    readAdjust += internalreadpos;
    1146     return readAdjust;
     1348    long long ra = readAdjust;
     1349    poslock.unlock();
     1350    rwlock.unlock();
     1351    return ra;
    11471352}
    11481353
    11491354int RingBuffer::Peek(void *buf, int count)
    11501355{
    1151     long long ret = -1;
    1152 
    1153     if (!readaheadrunning)
    1154     {
    1155         long long old_pos = Seek(0, SEEK_CUR);
    1156 
    1157         ret = Read(buf, count);
    1158 #ifdef USING_FRONTEND
    1159         if (ret > 0 && dvdPriv)
    1160         {
    1161             // This is technically incorrect it we should seek
    1162             // back to exactly where we were, but we can't do
    1163             // that with the DVDRingBuffer
    1164             dvdPriv->NormalSeek(0);
    1165         }
    1166         else if (ret > 0 && bdPriv)
    1167         {
    1168             // No idea if this will work.
    1169             bdPriv->Seek(0);
    1170         }
    1171         else
    1172 #endif // USING_FRONTEND
    1173         if (ret > 0)
    1174         {
    1175             long long new_pos = Seek(-ret, SEEK_CUR);
    1176             if (new_pos != old_pos)
    1177             {
    1178                 VERBOSE(VB_IMPORTANT, LOC_ERR +
    1179                         QString("Peek() Failed to return from new "
    1180                                 "position %1 to old position %2, now "
    1181                                 "at position %3")
    1182                         .arg(old_pos - ret).arg(old_pos).arg(new_pos));
    1183             }
    1184         }
    1185     }
    1186     else
    1187     {
    1188         ret = ReadFromBuf(buf, count, true);
    1189     }
    1190 
     1356    int ret = ReadPriv(buf, count, true);
    11911357    if (ret != count)
    11921358    {
    11931359        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    11971363    return ret;
    11981364}
    11991365
    1200 /**
    1201  *  \brief Reads from the read-ahead buffer, this is called by
    1202  *         Read(void*, int) when the read-ahead thread is running.
    1203  *  \param buf   Pointer to where data will be written
    1204  *  \param count Number of bytes to read
    1205  *  \param peek  If true, don't increment read count
    1206  *  \return Returns number of bytes read
    1207  */
    1208 int RingBuffer::ReadFromBuf(void *buf, int count, bool peek)
     1366bool RingBuffer::WaitForReadsAllowed(void)
    12091367{
    1210     if (commserror)
    1211         return 0;
     1368    MythTimer t;
     1369    t.start();
    12121370
    1213     bool readone = false;
    1214     int readErr = 0;
    1215 
    1216     if (readaheadpaused && stopreads)
     1371    while (!readsallowed && !stopreads &&
     1372           !request_pause && !commserror && readaheadrunning)
    12171373    {
    1218         readone = true;
    1219         Unpause();
    1220     }
    1221     else
    1222     {
    1223         QMutexLocker locker(&readsAllowedWaitMutex);
     1374        generalWait.wait(&rwlock, 1000);
     1375        if (!readsallowed && t.elapsed() > 1000)
     1376        {
     1377            VERBOSE(VB_IMPORTANT, LOC_WARN +
     1378                    "Taking too long to be allowed to read..");
    12241379
    1225         while (!readsallowed && !stopreads)
    1226         {
    1227             if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000))
     1380            if (t.elapsed() > 10000)
    12281381            {
    1229                  VERBOSE(VB_IMPORTANT,
    1230                          LOC + "Taking too long to be allowed to read..");
    1231                  readErr++;
    1232 
    1233                  // HACK Sometimes the readhead thread gets borked on startup.
    1234                  if ((readErr > 4 && readErr % 2) && (rbrpos ==0))
    1235                  {
    1236                     VERBOSE(VB_IMPORTANT, "restarting readhead thread..");
    1237                     KillReadAheadThread();
    1238                     StartupReadAheadThread();
    1239                  }
    1240 
    1241                  if (readErr > 10)
    1242                  {
    1243                      VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
    1244                              "10 seconds to be allowed to read, aborting.");
    1245                      wanttoread = 0;
    1246                      stopreads = true;
    1247                      return 0;
    1248                  }
     1382                VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
     1383                        "10 seconds to be allowed to read, aborting.");
     1384                return false;
    12491385            }
    12501386        }
    12511387    }
    12521388
     1389    return readsallowed;
     1390}
     1391
     1392bool RingBuffer::WaitForAvail(int count)
     1393{
    12531394    int avail = ReadBufAvail();
     1395    count = (ateof && avail < count) ? avail : count;
    12541396
    1255     if (ateof && avail < count)
    1256         count = avail;
    1257 
    12581397    MythTimer t;
    12591398    t.start();
    1260     while (avail < count && !stopreads)
     1399    while ((avail < count) && !stopreads &&
     1400           !request_pause && !commserror && readaheadrunning)
    12611401    {
    1262         availWaitMutex.lock();
    12631402        wanttoread = count;
    1264         if (!availWait.wait(&availWaitMutex, 250))
     1403        generalWait.wait(&rwlock, 250);
     1404        avail = ReadBufAvail();
     1405
     1406        if ((ateof || setswitchtonext) && avail < count)
     1407            count = avail;
     1408
     1409        if (avail < count)
    12651410        {
    12661411            int elapsed = t.elapsed();
    1267             if  (/*((elapsed > 500)  && (elapsed < 750))  ||*/
     1412            if  (((elapsed > 250)  && (elapsed < 500))  ||
     1413                 ((elapsed > 500)  && (elapsed < 750))  ||
    12681414                 ((elapsed > 1000) && (elapsed < 1250)) ||
    12691415                 ((elapsed > 2000) && (elapsed < 2250)) ||
    12701416                 ((elapsed > 4000) && (elapsed < 4250)) ||
    1271                  ((elapsed > 8000) && (elapsed < 8250)))
     1417                 ((elapsed > 8000) && (elapsed < 8250)) ||
     1418                 ((elapsed > 9000)))
    12721419            {
    12731420                VERBOSE(VB_IMPORTANT, LOC + "Waited " +
    1274                         QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) +
    1275                         " seconds for data to become available...");
     1421                        QString("%1").arg((elapsed / 250) * 0.25f, 3, 'f', 1) +
     1422                        " seconds for data \n\t\t\tto become available..." +
     1423                        QString(" %2 < %3")
     1424                        .arg(avail).arg(count));
    12761425                if (livetvchain)
    12771426                {
    12781427                    VERBOSE(VB_IMPORTANT, "Checking to see if there's a "
     
    12951444                    VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to "
    12961445                            "impending livetv switch.");
    12971446
    1298                 ateof = true;
    1299                 wanttoread = 0;
    1300                 stopreads = true;
    1301                 availWaitMutex.unlock();
    1302                 return 0;
     1447                return false;
    13031448            }
    13041449        }
     1450    }
    13051451
     1452    wanttoread = 0;
     1453
     1454    return avail >= count;
     1455}
     1456
     1457int RingBuffer::ReadDirect(void *buf, int count, bool peek)
     1458{
     1459    long long old_pos = 0;
     1460    if (peek)
     1461    {
     1462        poslock.lockForRead();
     1463        old_pos = (ignorereadpos >= 0) ? ignorereadpos : readpos;
     1464        poslock.unlock();
     1465    }
     1466
     1467    int ret;
     1468    if (remotefile)
     1469        ret = safe_read(remotefile, buf, count);
     1470#ifdef USING_FRONTEND
     1471    else if (dvdPriv)
     1472        ret = dvdPriv->safe_read(buf, count);
     1473    else if (bdPriv)
     1474        ret = bdPriv->safe_read(buf, count);
     1475#endif // USING_FRONTEND
     1476    else if (fd2 >= 0)
     1477        ret = safe_read(fd2, buf, count);
     1478    else
     1479    {
     1480        ret = -1;
     1481        errno = EBADF;
     1482    }
     1483
     1484    poslock.lockForWrite();
     1485    if (ignorereadpos >= 0 && ret > 0)
     1486    {
     1487        if (peek)
     1488        {
     1489            // seek should always succeed since we were at this position
     1490            if (remotefile)
     1491                remotefile->Seek(old_pos, SEEK_SET);
     1492            else
     1493                lseek64(fd2, old_pos, SEEK_SET);
     1494        }
     1495        else
     1496        {
     1497            ignorereadpos += ret;
     1498        }
     1499        poslock.unlock();
     1500        return ret;
     1501    }
     1502    poslock.unlock();
     1503
     1504    if (peek && ret > 0)
     1505    {
     1506        if (!dvdPriv && !bdPriv)
     1507        {
     1508            long long new_pos = Seek(old_pos, SEEK_SET, true);
     1509            if (new_pos != old_pos)
     1510            {
     1511                VERBOSE(VB_IMPORTANT, LOC_ERR +
     1512                        QString("Peek() Failed to return from new "
     1513                                "position %1 to old position %2, now "
     1514                                "at position %3")
     1515                        .arg(old_pos - ret).arg(old_pos).arg(new_pos));
     1516            }
     1517        }
     1518        else if (old_pos != 0)
     1519        {
     1520            VERBOSE(VB_IMPORTANT, LOC_ERR +
     1521                    "DVD and Blu-Ray do not support arbitrary "
     1522                    "peeks except when read-ahead is enabled."
     1523                    "\n\t\t\tWill seek to beginning of video.");
     1524        }
     1525#ifdef USING_FRONTEND
     1526        if (dvdPriv)
     1527            dvdPriv->NormalSeek(old_pos);
     1528        else if (bdPriv)
     1529            bdPriv->Seek(old_pos);
     1530#endif // USING_FRONTEND
     1531    }
     1532
     1533    return ret;
     1534}
     1535
     1536/** \brief When possible reads from the read-ahead buffer,
     1537 *         otherwise reads directly from the device.
     1538 *
     1539 *  \param buf   Pointer to where data will be written
     1540 *  \param count Number of bytes to read
     1541 *  \param peek  If true, don't increment read count
     1542 *  \return Returns number of bytes read
     1543 */
     1544int RingBuffer::ReadPriv(void *buf, int count, bool peek)
     1545{
     1546    QString loc_desc =
     1547            QString("ReadPriv(..%1, %2)")
     1548        .arg(count).arg(peek?"peek":"normal");
     1549    VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc +
     1550            QString(" @%1 -- begin").arg(rbrpos));
     1551
     1552    rwlock.lockForRead();
     1553    if (writemode)
     1554    {
     1555        VERBOSE(VB_IMPORTANT, LOC_ERR + loc_desc +
     1556                ": Attempt to read from a write only file");
     1557        errno = EBADF;
     1558        rwlock.unlock();
     1559        return -1;
     1560    }
     1561
     1562    if (commserror)
     1563    {
     1564        VERBOSE(VB_IMPORTANT, LOC_ERR + loc_desc +
     1565                ": Attempt to read after commserror set");
     1566        errno = EIO;
     1567        rwlock.unlock();
     1568        return -1;
     1569    }
     1570
     1571    if (request_pause || stopreads || !readaheadrunning || (ignorereadpos>=0))
     1572    {
     1573        rwlock.unlock();
     1574        rwlock.lockForWrite();
     1575        // we need a write lock so the read-ahead thread
     1576        // can't start mucking with the read position.
     1577        // If the read ahead thread was started while we
     1578        // didn't hold the lock, we proceed with a normal
     1579        // read from the buffer, otherwise we read directly.
     1580        if (request_pause || stopreads ||
     1581            !readaheadrunning || (ignorereadpos >= 0))
     1582        {
     1583            int ret = ReadDirect(buf, count, peek);
     1584            VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc +
     1585                    QString(": ReadDirect checksum %1")
     1586                    .arg(qChecksum((char*)buf,count)));
     1587            rwlock.unlock();
     1588            return ret;
     1589        }
     1590        rwlock.unlock();
     1591        rwlock.lockForRead();
     1592    }
     1593
     1594    if (!WaitForReadsAllowed())
     1595    {
     1596        VERBOSE(VB_FILE, LOC + loc_desc + ": !WaitForReadsAllowed()");
     1597        rwlock.unlock();
     1598        rwlock.lockForWrite();
    13061599        wanttoread = 0;
    1307         availWaitMutex.unlock();
     1600        stopreads = true;
     1601        rwlock.unlock();
     1602        return 0;
     1603    }
    13081604
    1309         avail = ReadBufAvail();
    1310         if ((ateof || setswitchtonext) && avail < count)
    1311             count = avail;
     1605    if (!WaitForAvail(count))
     1606    {
     1607        VERBOSE(VB_FILE, LOC + loc_desc + ": !WaitForAvail()");
     1608        rwlock.unlock();
     1609        rwlock.lockForWrite();
     1610        ateof = true;
     1611        wanttoread = 0;
     1612        stopreads = true;
     1613        rwlock.unlock();
     1614        return 0;
     1615    }
    13121616
    1313         if (commserror)
    1314             return 0;
     1617    count = min(ReadBufAvail(), count);
     1618
     1619    if (count <= 0)
     1620    {
     1621        // this can happen under a few conditions but the most
     1622        // notable is an exit from the read ahead thread or
     1623        // the end of the file stream has been reached.
     1624        VERBOSE(VB_FILE, LOC + loc_desc + ": ReadBufAvail() == 0");
     1625        rwlock.unlock();
     1626        return count;
    13151627    }
    13161628
    1317     if ((ateof || stopreads) && avail < count)
    1318         count = avail;
     1629    if (peek)
     1630        rbrlock.lockForRead();
     1631    else
     1632        rbrlock.lockForWrite();
    13191633
     1634    VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + " -- copying data");
     1635
    13201636    if (rbrpos + count > (int) kBufferSize)
    13211637    {
    13221638        int firstsize = kBufferSize - rbrpos;
     
    13261642        memcpy((char *)buf + firstsize, readAheadBuffer, secondsize);
    13271643    }
    13281644    else
     1645    {
    13291646        memcpy(buf, readAheadBuffer + rbrpos, count);
     1647    }
     1648    VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + QString(" -- checksum %1")
     1649            .arg(qChecksum((char*)buf,count)));
    13301650
    13311651    if (!peek)
    13321652    {
    1333         readAheadLock.lock();
    13341653        rbrpos = (rbrpos + count) % kBufferSize;
    1335         readAheadLock.unlock();
     1654        generalWait.wakeAll();
    13361655    }
     1656    rbrlock.unlock();
     1657    rwlock.unlock();
    13371658
    1338     if (readone)
    1339     {
    1340         Pause();
    1341         WaitForPause();
    1342     }
    1343 
    13441659    return count;
    13451660}
    13461661
     
    13541669 */
    13551670int RingBuffer::Read(void *buf, int count)
    13561671{
    1357     int ret = -1;
    1358     if (writemode)
     1672    int ret = ReadPriv(buf, count, false);
     1673    if (ret > 0)
    13591674    {
    1360         VERBOSE(VB_IMPORTANT, LOC_ERR +
    1361                 "Attempt to read from a write only file");
    1362         return ret;
    1363     }
    1364 
    1365     rwlock.lockForRead();
    1366 
    1367     if (!readaheadrunning)
    1368     {
    1369         if (remotefile)
    1370         {
    1371             ret = safe_read(remotefile, buf, count);
    1372             readpos += ret;
    1373         }
    1374 #ifdef USING_FRONTEND
    1375         else if (dvdPriv)
    1376         {
    1377             ret = dvdPriv->safe_read(buf, count);
    1378             readpos += ret;
    1379         }
    1380         else if (bdPriv)
    1381         {
    1382             ret = bdPriv->safe_read(buf, count);
    1383             readpos += ret;
    1384         }
    1385 #endif // USING_FRONTEND
    1386         else
    1387         {
    1388             ret = safe_read(fd2, buf, count);
    1389             readpos += ret;
    1390         }
    1391     }
    1392     else
    1393     {
    1394         ret = ReadFromBuf(buf, count);
     1675        poslock.lockForWrite();
    13951676        readpos += ret;
     1677        poslock.unlock();
    13961678    }
    1397 
    1398     rwlock.unlock();
    13991679    return ret;
    14001680}
    14011681
    14021682/** \fn RingBuffer::IsIOBound(void) const
    1403  *  \brief Returns true if a RingBuffer::Read(void*,int) is likely to block.
     1683 *  \brief Returns true if a RingBuffer::Write(void*,int) is likely to block.
    14041684 */
    14051685bool RingBuffer::IsIOBound(void) const
    14061686{
     
    14291709 */
    14301710int RingBuffer::Write(const void *buf, uint count)
    14311711{
    1432     int ret = -1;
     1712    rwlock.lockForRead();
     1713
    14331714    if (!writemode)
    14341715    {
    14351716        VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file.");
    1436         return ret;
     1717        rwlock.unlock();
     1718        return -1;
    14371719    }
    14381720
    14391721    if (!tfw && !remotefile)
    1440         return ret;
     1722    {
     1723        rwlock.unlock();
     1724        return -1;
     1725    }
    14411726
    1442     rwlock.lockForRead();
    1443 
     1727    int ret = -1;
    14441728    if (tfw)
    14451729        ret = tfw->Write(buf, count);
    14461730    else
    14471731        ret = remotefile->Write(buf, count);
    1448     writepos += ret;
    14491732
     1733    if (ret > 0)
     1734    {
     1735        poslock.lockForWrite();
     1736        writepos += ret;
     1737        poslock.unlock();
     1738    }
     1739
    14501740    rwlock.unlock();
     1741
    14511742    return ret;
    14521743}
    14531744
     
    14561747 */
    14571748void RingBuffer::Sync(void)
    14581749{
     1750    rwlock.lockForRead();
    14591751    if (tfw)
    14601752        tfw->Sync();
     1753    rwlock.unlock();
    14611754}
    14621755
    1463 /** \fn RingBuffer::Seek(long long, int)
    1464  *  \brief Seeks to a particular position in the file.
     1756/** \brief Seeks to a particular position in the file.
    14651757 */
    1466 long long RingBuffer::Seek(long long pos, int whence)
     1758long long RingBuffer::Seek(long long pos, int whence, bool has_lock)
    14671759{
     1760    VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)")
     1761            .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET":
     1762                          ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END"))
     1763            .arg(has_lock?"locked":"unlocked"));
     1764
     1765    long long ret = -1;
     1766
     1767    StopReads();
     1768
     1769    // lockForWrite takes priority over lockForRead, so this will
     1770    // take priority over the lockForRead in the read ahead thread.
     1771    if (!has_lock)
     1772        rwlock.lockForWrite();
     1773
     1774    StartReads();
     1775
    14681776    if (writemode)
    1469         return WriterSeek(pos, whence);
     1777    {
     1778        ret = WriterSeek(pos, whence, true);
     1779        if (!has_lock)
     1780            rwlock.unlock();
     1781        return ret;
     1782    }
    14701783
    1471     wantseek = true;
    1472     rwlock.lockForWrite();
    1473     wantseek = false;
     1784    poslock.lockForWrite();
    14741785
    1475     // optimize nop seeks
    1476     if ((whence == SEEK_SET && pos == readpos) ||
    1477         (whence == SEEK_CUR && pos == 0))
     1786    // Optimize no-op seeks
     1787    if (readaheadrunning &&
     1788        ((whence == SEEK_SET && pos == readpos) ||
     1789         (whence == SEEK_CUR && pos == 0)))
    14781790    {
    1479         rwlock.unlock();
    1480         return readpos;
     1791        ret = readpos;
     1792
     1793        poslock.unlock();
     1794        if (!has_lock)
     1795            rwlock.unlock();
     1796
     1797        return ret;
    14811798    }
    14821799
    1483     errno = 0; // clear errno, in case of remotefile error
     1800    // only valid for SEEK_SET & SEEK_CUR
     1801    long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos;
    14841802
    1485     long long ret = -1;
     1803#if 1
     1804    // Optimize short seeks where the data for
     1805    // them is in our ringbuffer already.
     1806    if (readaheadrunning &&
     1807        (SEEK_SET==whence || SEEK_CUR==whence))
     1808    {
     1809        rbrlock.lockForWrite();
     1810        rbwlock.lockForRead();
     1811        VERBOSE(VB_FILE, LOC +
     1812                QString("Seek(): rbrpos: %1 rbwpos: %2"
     1813                        "\n\t\t\treadpos: %3 internalreadpos: %4")
     1814                .arg(rbrpos).arg(rbwpos)
     1815                .arg(readpos).arg(internalreadpos));
     1816        bool used_opt = false;
     1817        if ((new_pos < readpos))
     1818        {
     1819            int min_safety = max(fill_min, readblocksize);
     1820            int free = ((rbwpos >= rbrpos) ?
     1821                        rbrpos + kBufferSize : rbrpos) - rbwpos;
     1822            int internal_backbuf =
     1823                (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos;
     1824            internal_backbuf = min(internal_backbuf, free - min_safety);
     1825            long long sba = readpos - new_pos;
     1826            VERBOSE(VB_FILE, LOC +
     1827                    QString("Seek(): internal_backbuf: %1 sba: %2")
     1828                    .arg(internal_backbuf).arg(sba));
     1829            if (internal_backbuf >= sba)
     1830            {
     1831                rbrpos = (rbrpos>=sba) ? rbrpos - sba :
     1832                    kBufferSize + rbrpos - sba;
     1833                used_opt = true;
     1834                VERBOSE(VB_FILE, LOC +
     1835                        QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2"
     1836                                "\n\t\t\treadpos: %3 internalreadpos: %4")
     1837                        .arg(rbrpos).arg(rbwpos)
     1838                        .arg(new_pos).arg(internalreadpos));
     1839            }
     1840        }
     1841        else if ((new_pos >= readpos) && (new_pos <= internalreadpos))
     1842        {
     1843            rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize;
     1844            used_opt = true;
     1845            VERBOSE(VB_FILE, LOC +
     1846                    QString("Seek(): OPT2 rbrpos: %1 sba: %2")
     1847                    .arg(rbrpos).arg(readpos - new_pos));
     1848        }
     1849        rbwlock.unlock();
     1850        rbrlock.unlock();
     1851
     1852        if (used_opt)
     1853        {
     1854            if (ignorereadpos >= 0)
     1855            {
     1856                // seek should always succeed since we were at this position
     1857                int ret;
     1858                if (remotefile)
     1859                    ret = remotefile->Seek(internalreadpos, SEEK_SET);
     1860                else
     1861                    ret = lseek64(fd2, internalreadpos, SEEK_SET);
     1862                VERBOSE(VB_FILE, LOC +
     1863                        QString("Seek to %1 from ignore pos %2 returned %3")
     1864                        .arg(internalreadpos).arg(ignorereadpos).arg(ret));
     1865                ignorereadpos = -1;
     1866            }
     1867            readpos = new_pos;
     1868            poslock.unlock();
     1869            generalWait.wakeAll();
     1870            ateof = false;
     1871            readsallowed = false;
     1872            if (!has_lock)
     1873                rwlock.unlock();
     1874            return new_pos;
     1875        }
     1876    }
     1877#endif
     1878
     1879#if 1
     1880    // This optimizes the seek end-250000, read, seek 0, read portion
     1881    // of the pattern ffmpeg performs at the start of playback to
     1882    // determine the pts.
     1883    // If the seek is a SEEK_END or is a seek where the position
     1884    // changes over 100 MB we check the file size and if the
     1885    // destination point is within 300000 bytes of the end of
     1886    // the file we enter a special mode where the read ahead
     1887    // buffer stops reading data and all reads are made directly
     1888    // until another seek is performed. The point of all this is
     1889    // to avoid flushing out the buffer that still contains all
     1890    // the data the final seek 0, read will need just to read the
     1891    // last 250000 bytes. A further optimization would be to buffer
     1892    // the 250000 byte read, which is currently performed in 32KB
     1893    // blocks (inefficient with RemoteFile).
     1894    if ((remotefile || fd2 >= 0) && (ignorereadpos < 0))
     1895    {
     1896        long long off_end = 0xDEADBEEF;
     1897        if (SEEK_END == whence)
     1898        {
     1899            off_end = pos;
     1900            if (remotefile)
     1901            {
     1902                new_pos = remotefile->GetFileSize() - off_end;
     1903            }
     1904            else
     1905            {
     1906                QFileInfo fi(filename);
     1907                new_pos = fi.size() - off_end;
     1908            }
     1909        }
     1910        else if (abs(new_pos-readpos) > 100000000)
     1911        {
     1912            if (remotefile)
     1913            {
     1914                off_end = remotefile->GetFileSize() - new_pos;
     1915            }
     1916            else
     1917            {
     1918                QFileInfo fi(filename);
     1919                off_end = fi.size() - new_pos;
     1920            }
     1921        }
     1922        if (off_end < 300000)
     1923        {
     1924            VERBOSE(VB_FILE, LOC +
     1925                    QString("Seek(): offset from end: %1").arg(off_end) +
     1926                    "\n\t\t\t -- ignoring read ahead thread until next seek.");
     1927
     1928            ignorereadpos = new_pos;
     1929            errno = EINVAL;
     1930            int ret;
     1931            if (remotefile)
     1932                ret = remotefile->Seek(ignorereadpos, SEEK_SET);
     1933            else
     1934                ret = lseek64(fd2, ignorereadpos, SEEK_SET);
     1935
     1936            if (ret < 0)
     1937            {
     1938                int tmp_eno = errno;
     1939                QString cmd = QString("Seek(%1, %2) ign ")
     1940                    .arg(ignorereadpos)
     1941                    .arg((SEEK_SET == whence) ? "SEEK_SET" :
     1942                         ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));
     1943
     1944                ignorereadpos = -1;
     1945
     1946                VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
     1947
     1948                // try to return to former position..
     1949                if (remotefile)
     1950                    ret = remotefile->Seek(internalreadpos, SEEK_SET);
     1951                else
     1952                    ret = lseek64(fd2, internalreadpos, SEEK_SET);
     1953                if (ret < 0)
     1954                {
     1955                    QString cmd = QString("Seek(%1, %2) int ")
     1956                        .arg(internalreadpos)
     1957                        .arg((SEEK_SET == whence) ? "SEEK_SET" :
     1958                             ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));
     1959                    VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
     1960                }
     1961                else
     1962                {
     1963                    QString cmd = QString("Seek(%1, %2) int ")
     1964                        .arg(internalreadpos)
     1965                        .arg((SEEK_SET == whence) ? "SEEK_SET" :
     1966                             ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));
     1967                    VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " succeeded");
     1968                }
     1969                ret = -1;
     1970                errno = tmp_eno;
     1971            }
     1972            else
     1973            {
     1974                ateof = false;
     1975                readsallowed = false;
     1976            }
     1977
     1978            rbwlock.unlock();
     1979            rbrlock.unlock();
     1980            poslock.unlock();
     1981
     1982            generalWait.wakeAll();
     1983
     1984            if (!has_lock)
     1985                rwlock.unlock();
     1986
     1987            return ret;
     1988        }
     1989    }
     1990#endif
     1991
     1992    // Here we perform a normal seek. When successful we
     1993    // need to call ResetReadAhead(). A reset means we will
     1994    // need to refill the buffer, which takes some time.
    14861995    if (remotefile)
     1996    {
    14871997        ret = remotefile->Seek(pos, whence, readpos);
     1998        if (ret<0)
     1999            errno = EINVAL;
     2000    }
    14882001#ifdef USING_FRONTEND
     2002    else if ((dvdPriv || bdPriv) && (SEEK_END == whence))
     2003    {
     2004        errno = EINVAL;
     2005        ret = -1;
     2006    }
    14892007    else if (dvdPriv)
    14902008    {
    1491         dvdPriv->NormalSeek(pos);
    1492         ret = pos;
     2009        dvdPriv->NormalSeek(new_pos);
     2010        ret = new_pos;
    14932011    }
    14942012    else if (bdPriv)
    14952013    {
    1496         bdPriv->Seek(pos);
    1497         ret = pos;
     2014        bdPriv->Seek(new_pos);
     2015        ret = new_pos;
    14982016    }
    14992017#endif // USING_FRONTEND
    15002018    else
    15012019    {
    1502         if ((whence == SEEK_SET) || (whence == SEEK_END))
    1503 #ifdef USING_MINGW
    1504             ret = lseek64(fd2, pos, whence);
    1505 #else
    1506             ret = lseek(fd2, pos, whence);
    1507 #endif
    1508         else
    1509         {
    1510             long long realseek = readpos + pos;
    1511 #ifdef USING_MINGW
    1512             ret = lseek64(fd2, realseek, SEEK_SET);
    1513 #else
    1514             ret = lseek(fd2, realseek, SEEK_SET);
    1515 #endif
    1516         }
     2020        ret = lseek64(fd2, pos, whence);
    15172021    }
    15182022
    15192023    if (ret >= 0)
    15202024    {
    15212025        readpos = ret;
     2026       
     2027        ignorereadpos = -1;
    15222028
    15232029        if (readaheadrunning)
    15242030            ResetReadAhead(readpos);
     
    15332039        VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
    15342040    }
    15352041
    1536     rwlock.unlock();
     2042    poslock.unlock();
    15372043
     2044    generalWait.wakeAll();
     2045
     2046    if (!has_lock)
     2047        rwlock.unlock();
     2048
    15382049    return ret;
    15392050}
    15402051
    1541 /** \fn RingBuffer::WriterSeek(long long, int)
    1542  *  \brief Calls ThreadedFileWriter::Seek(long long,int).
     2052/** \brief Calls ThreadedFileWriter::Seek(long long,int).
    15432053 */
    1544 long long RingBuffer::WriterSeek(long long pos, int whence)
     2054long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock)
    15452055{
    15462056    long long ret = -1;
    15472057
     2058    if (!has_lock)
     2059        rwlock.lockForRead();
     2060
     2061    poslock.lockForWrite();
     2062
    15482063    if (tfw)
    15492064    {
    15502065        ret = tfw->Seek(pos, whence);
    15512066        writepos = ret;
    15522067    }
    15532068
     2069    poslock.unlock();
     2070
     2071    if (!has_lock)
     2072        rwlock.unlock();
     2073
    15542074    return ret;
    15552075}
    15562076
     
    15602080 */
    15612081void RingBuffer::WriterFlush(void)
    15622082{
     2083    rwlock.lockForRead();
    15632084    if (tfw)
    15642085    {
    15652086        tfw->Flush();
    15662087        tfw->Sync();
    15672088    }
     2089    rwlock.unlock();
    15682090}
    15692091
    15702092/** \fn RingBuffer::SetWriteBufferSize(int)
     
    15722094 */
    15732095void RingBuffer::SetWriteBufferSize(int newSize)
    15742096{
     2097    rwlock.lockForRead();
    15752098    if (tfw)
    15762099        tfw->SetWriteBufferSize(newSize);
     2100    rwlock.unlock();
    15772101}
    15782102
    15792103/** \fn RingBuffer::SetWriteBufferMinWriteSize(int)
     
    15812105 */
    15822106void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize)
    15832107{
     2108    rwlock.lockForRead();
    15842109    if (tfw)
    15852110        tfw->SetWriteBufferMinWriteSize(newMinSize);
     2111    rwlock.unlock();
    15862112}
    15872113
     2114/** \brief Tell RingBuffer if this is an old file or not.
     2115 *
     2116 *  Normally the RingBuffer determines that the file is old
     2117 *  if it has not been modified in the last minute. This
     2118 *  allows one to override that determination externally.
     2119 *
     2120 *  If for instance you are slowly writing to the file you
     2121 *  could call this with the value of false. If you just
     2122 *  finished writing the file you could call it with the
     2123 *  value true. Knowing that the file is old allows MythTV
     2124 *  to determine that a read at the end of the file is
     2125 *  really an end-of-file condition more quickly. But if
     2126 *  the file is growing it can also cause the RingBuffer to
     2127 *  report an end-of-file condition prematurely.
     2128 */
     2129void RingBuffer::SetOldFile(bool is_old)
     2130{
     2131    rwlock.lockForWrite();
     2132    oldfile = is_old;
     2133    rwlock.unlock();
     2134}
     2135
     2136// This appears to allow direct access to the DVD/BD device
     2137// when called with false (the default value), and enable
     2138// the ring buffer when called with true. But I'm not entirely
     2139// certain. -- dtk 2010-08-26
     2140void RingBuffer::SetStreamOnly(bool stream)
     2141{
     2142    rwlock.lockForWrite();
     2143    streamOnly = stream;
     2144    rwlock.unlock();
     2145}
     2146
     2147/// Returns name of file used by this RingBuffer
     2148QString RingBuffer::GetFilename(void) const
     2149{
     2150    rwlock.lockForRead();
     2151    QString tmp = filename;
     2152    tmp.detach();
     2153    rwlock.unlock();
     2154    return tmp;
     2155}
     2156
     2157QString RingBuffer::GetSubtitleFilename(void) const
     2158{
     2159    rwlock.lockForRead();
     2160    QString tmp = subtitlefilename;
     2161    tmp.detach();
     2162    rwlock.unlock();
     2163    return tmp;
     2164}
     2165
    15882166/** \fn RingBuffer::GetReadPosition(void) const
    15892167 *  \brief Returns how far into the file we have read.
    15902168 */
    15912169long long RingBuffer::GetReadPosition(void) const
    15922170{
     2171    rwlock.lockForRead();
     2172    poslock.lockForRead();
     2173    long long ret = readpos;
    15932174#ifdef USING_FRONTEND
    15942175    if (dvdPriv)
    1595         return dvdPriv->GetReadPosition();
     2176        ret = dvdPriv->GetReadPosition();
    15962177    else if (bdPriv)
    1597         return bdPriv->GetReadPosition();
     2178        ret = bdPriv->GetReadPosition();
    15982179#endif // USING_FRONTEND
    1599 
    1600     return readpos;
     2180    poslock.unlock();
     2181    rwlock.unlock();
     2182    return ret;
    16012183}
    16022184
    16032185/** \fn RingBuffer::GetWritePosition(void) const
     
    16052187 */
    16062188long long RingBuffer::GetWritePosition(void) const
    16072189{
    1608     return writepos;
     2190    poslock.lockForRead();
     2191    long long ret = writepos;
     2192    poslock.unlock();
     2193    return ret;
    16092194}
    16102195
    16112196/** \fn RingBuffer::GetRealFileSize(void) const
     
    16142199 */
    16152200long long RingBuffer::GetRealFileSize(void) const
    16162201{
     2202    rwlock.lockForRead();
     2203    long long ret = -1;
    16172204    if (remotefile)
    1618         return remotefile->GetFileSize();
    1619 
    1620     QFileInfo info(filename);
    1621     return info.size();
     2205        ret = remotefile->GetFileSize();
     2206    else
     2207        ret = QFileInfo(filename).size();
     2208    rwlock.unlock();
     2209    return ret;
    16222210}
    16232211
    16242212/** \fn RingBuffer::LiveMode(void) const
     
    16272215 */
    16282216bool RingBuffer::LiveMode(void) const
    16292217{
    1630     return (livetvchain);
     2218    rwlock.lockForRead();
     2219    bool ret = (livetvchain);
     2220    rwlock.unlock();
     2221    return ret;
    16312222}
    16322223
    16332224/** \fn RingBuffer::SetLiveMode(LiveTVChain*)
     
    16362227 */
    16372228void RingBuffer::SetLiveMode(LiveTVChain *chain)
    16382229{
     2230    rwlock.lockForWrite();
    16392231    livetvchain = chain;
     2232    rwlock.unlock();
    16402233}
    16412234
     2235/// Tells RingBuffer whether to igonre the end-of-file
     2236void RingBuffer::IgnoreLiveEOF(bool ignore)
     2237{
     2238    rwlock.lockForWrite();
     2239    ignoreliveeof = ignore;
     2240    rwlock.unlock();
     2241}
     2242
     2243/** \brief Returns true if this is a DVD backed RingBuffer.
     2244 *
     2245 * NOTE: This is not locked because ReadDirect calls
     2246 * DVD safe_read which sleeps with a write lock on
     2247 * rwlock in the DVDNAV_WAIT condition.
     2248 *
     2249 * Due to the lack of locking is only safe to call once OpenFile()
     2250 * has completed.
     2251 */
     2252bool RingBuffer::IsDVD(void) const
     2253{
     2254    //rwlock.lockForRead();
     2255    bool ret = dvdPriv;
     2256    //rwlock.unlock();
     2257    return ret;
     2258}
     2259
     2260/** \brief Returns true if this is a DVD backed RingBuffer.
     2261 *
     2262 * NOTE: This is not locked because ReadDirect calls
     2263 * DVD safe_read which sleeps with a write lock on
     2264 * rwlock in the DVDNAV_WAIT condition.
     2265 *
     2266 * Due to the lack of locking is only safe to call once OpenFile()
     2267 * has completed.
     2268 */
    16422269bool RingBuffer::InDVDMenuOrStillFrame(void)
    16432270{
     2271    //rwlock.lockForRead();
     2272    bool ret = false;
    16442273#ifdef USING_FRONTEND
    16452274    if (dvdPriv)
    1646         return (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
     2275        ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
    16472276#endif // USING_FRONTEND
    1648     return false;
     2277    //rwlock.unlock();
     2278    return ret;
    16492279}
    16502280
     2281/// Returns true if this is a Blu-ray backed RingBuffer.
     2282bool RingBuffer::IsBD(void) const
     2283{
     2284    //rwlock.lockForRead();
     2285    bool ret = bdPriv;
     2286    //rwlock.unlock();
     2287    return ret;
     2288}
     2289
    16512290/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/tv_play.cpp

     
    873873      switchToInputId(0),
    874874      wantsToQuit(true),
    875875      stretchAdjustment(false),
    876       audiosyncAdjustment(false), audiosyncBaseline(INT64_MIN),
     876      audiosyncAdjustment(false), audiosyncBaseline(LLONG_MIN),
    877877      editmode(false),     zoomMode(false),
    878878      sigMonMode(false),
    879879      endOfRecording(false),
     
    19711971                    .arg(playbackURL).arg(ctx->tvchain->GetCardType(-1)));
    19721972
    19731973            ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true,
    1974                                       opennow ? 12 : (uint)-1));
     1974                                              opennow ? 2000 : -1));
    19751975            ctx->buffer->SetLiveMode(ctx->tvchain);
    19761976        }
    19771977
     
    56445644
    56455645    bool res = false;
    56465646
    5647     if (INT64_MIN != audiosyncBaseline)
     5647    if (LLONG_MIN != audiosyncBaseline)
    56485648    {
    56495649        int64_t aud_tc = ctx->player->GetAudioTimecodeOffset();
    56505650        ctx->player->SaveAudioTimecodeOffset(aud_tc - audiosyncBaseline);
     
    63656365            QString playbackURL = ctx->playingInfo->GetPlaybackURL(true);
    63666366            bool opennow = (ctx->tvchain->GetCardType(-1) != "DUMMY");
    63676367            ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true,
    6368                                               opennow ? 12 : (uint)-1));
     6368                                              opennow ? 2000 : -1));
    63696369
    63706370            ctx->tvchain->SetProgram(*ctx->playingInfo);
    63716371            ctx->buffer->SetLiveMode(ctx->tvchain);
     
    80568056        return;
    80578057    }
    80588058
    8059     if (!audiosyncAdjustment && INT64_MIN == audiosyncBaseline)
     8059    if (!audiosyncAdjustment && LLONG_MIN == audiosyncBaseline)
    80608060        audiosyncBaseline = ctx->player->GetAudioTimecodeOffset();
    80618061
    80628062    audiosyncAdjustment = allowEdit;
  • 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>
     
    2727{
    2828  public:
    2929    RingBuffer(const QString &lfilename, bool write,
    30                bool usereadahead = true, uint read_retries = 12/*6*/);
     30               bool usereadahead = true,
     31               int timeout_ms = kDefaultOpenTimeout);
    3132   ~RingBuffer();
    3233
    3334    // Sets
    3435    void SetWriteBufferSize(int newSize);
    3536    void SetWriteBufferMinWriteSize(int newMinSize);
     37    void SetOldFile(bool is_old);
     38    void SetStreamOnly(bool stream);
    3639    void UpdateRawBitrate(uint rawbitrate);
    3740    void UpdatePlaySpeed(float playspeed);
    38     void SetStreamOnly(bool stream) { streamOnly = stream; }
    3941
    4042    // Gets
    41     /// Returns name of file used by this RingBuffer
    42     QString   GetFilename(void)      const { return filename; }
    43     QString   GetSubtitleFilename(void) const { return subtitlefilename; }
    44     /// Returns ReadBufAvail(void)
    45     int       DataInReadAhead(void)  const { return ReadBufAvail(); }
     43    QString   GetFilename(void)      const;
     44    QString   GetSubtitleFilename(void) const;
    4645    /// Returns value of stopreads
    4746    /// \sa StartReads(void), StopReads(void)
    4847    bool      GetStopReads(void)     const { return stopreads; }
    49     /// Returns false iff read-ahead is not
    50     /// running and read-ahead is not paused.
    51     bool      isPaused(void)         const
    52         { return (!readaheadrunning) ? true : readaheadpaused; }
     48    bool      isPaused(void)         const;
    5349    long long GetReadPosition(void)  const;
    5450    long long GetWritePosition(void) const;
    5551    long long GetRealFileSize(void)  const;
    56     uint      GetBitrate(void)       const;
    57     uint      GetReadBlockSize(void) const;
    5852    bool      IsOpen(void)           const;
     53    bool      IsNearEnd(double fps, uint vvf) const;
    5954
    6055    // General Commands
    61     void OpenFile(const QString &lfilename, uint retryCount = 12/*4*/);
     56    void OpenFile(const QString &lfilename,
     57                  uint retry_ms = kDefaultOpenTimeout);
    6258    int  Read(void *buf, int count);
    6359    int  Peek(void *buf, int count); // only works with readahead
    6460
     
    6763               bool resetInternal = false);
    6864
    6965    // Seeks
    70     long long Seek(long long pos, int whence);
     66    long long Seek(long long pos, int whence, bool has_lock = false);
    7167
    7268    // Pause commands
    7369    void Pause(void);
     
    8278    // LiveTVChain support
    8379    bool LiveMode(void) const;
    8480    void SetLiveMode(LiveTVChain *chain);
    85     /// Tells RingBuffer whether to igonre the end-of-file
    86     void IgnoreLiveEOF(bool ignore) { ignoreliveeof = ignore; }
     81    void IgnoreLiveEOF(bool ignore);
    8782
    8883    // ThreadedFileWriter proxies
    8984    int  Write(const void *buf, uint count);
    9085    bool IsIOBound(void) const;
    9186    void WriterFlush(void);
    9287    void Sync(void);
    93     long long WriterSeek(long long pos, int whence);
     88    long long WriterSeek(long long pos, int whence, bool has_lock = false);
    9489
    9590    // DVDRingBuffer proxies
    96     /// Returns true if this is a DVD backed RingBuffer.
    97     inline bool isDVD(void) const { return dvdPriv; }
    98     DVDRingBufferPriv *DVD() { return dvdPriv; }
     91    bool IsDVD(void) const;
    9992    bool InDVDMenuOrStillFrame(void);
    10093
    10194    // BDRingBuffer proxies
    102     /// Returns true if this is a Blu-ray backed RingBuffer.
    103     inline bool isBD(void) const { return bdPriv; }
    104     BDRingBufferPriv *BD() { return bdPriv; }
     95    bool IsBD(void) const;
    10596
    10697    long long SetAdjustFilesize(void);
    107     void SetTimeout(bool fast) { oldfile = fast; }
    10898
     99    /// Calls SetOldFile(), do not use
     100    void SetTimeout(bool is_old) MDEPRECATED { SetOldFile(is_old); }
     101    /// Calls IsDVD(), do not use
     102    bool isDVD(void) const MDEPRECATED { return IsDVD(); }
     103    /// Calls IsBD(), do not use
     104    bool isBD(void) const MDEPRECATED { return IsBD(); }
     105    /// Illicitly manipulating privates is ill advised!
     106    /// DO NOT USE
     107    DVDRingBufferPriv *DVD() MDEPRECATED
     108    {
     109        return dvdPriv;
     110    }
     111    /// Illicitly manipulating privates is ill advised!
     112    /// DO NOT USE
     113    BDRingBufferPriv *BD() MDEPRECATED
     114    {
     115        return bdPriv;
     116    }
     117
     118    static const int kDefaultOpenTimeout;
     119
    109120  protected:
    110121    void run(void); // QThread
    111122    void CalcReadAheadThresh(void);
     123    bool PauseAndWait(void);
    112124    int safe_read_bd(void *data, uint sz);
    113125    int safe_read_dvd(void *data, uint sz);
    114126    int safe_read(int fd, void *data, uint sz);
    115127    int safe_read(RemoteFile *rf, void *data, uint sz);
    116128
    117     int ReadFromBuf(void *buf, int count, bool peek = false);
     129    int ReadPriv(void *buf, int count, bool peek);
     130    int ReadDirect(void *buf, int count, bool peek);
     131    bool WaitForReadsAllowed(void);
     132    bool WaitForAvail(int count);
    118133
    119134    int ReadBufFree(void) const;
    120135    int ReadBufAvail(void) const;
    121136
    122     void StartupReadAheadThread(void);
    123137    void ResetReadAhead(long long newinternal);
    124138    void KillReadAheadThread(void);
    125139
    126140  private:
    127     // NR == trivial risk, not protected, but only modified in single thread
    128     // LR == low risk, not protected, but only modified on Open,Close,ctor,dtor
    129     // HR == high risk, likely to cause unexpected behaviour
    130     // MR == medium risk, unsafe methods unlikely to be called at wrong moment
     141    mutable QReadWriteLock poslock;
     142    long long readpos;            // protected by poslock
     143    long long writepos;           // protected by poslock
     144    long long internalreadpos;    // protected by poslock
     145    long long ignorereadpos;      // protected by poslock
     146    mutable QReadWriteLock rbrlock;
     147    int       rbrpos;             // protected by rbrlock
     148    mutable QReadWriteLock rbwlock;
     149    int       rbwpos;             // protected by rbwlock
    131150
    132     QString filename;             // not protected by a lock LR
    133     QString subtitlefilename;     // not protected by a lock LR
     151    // note should not go under rwlock..
     152    // this is used to break out of read_safe where rwlock is held
     153    volatile bool stopreads;
    134154
    135     ThreadedFileWriter *tfw;      // not protected by a lock LR
    136     int fd2;                      // not protected by a lock LR
    137 
    138     bool writemode;               // not protected by a lock LR
    139 
    140     long long readpos;            // not protected by a lock HR
    141     long long writepos;           // not protected by a lock HR
    142 
    143     bool stopreads;               // not protected by a lock HR
    144 
    145155    mutable QReadWriteLock rwlock;
    146156
    147     RemoteFile *remotefile;       // not protected by a lock LR
     157    QString filename;             // protected by rwlock
     158    QString subtitlefilename;     // protected by rwlock
    148159
    149     // this lock does not consistently protect anything,
    150     // but seems to be intented to protect rbrpos & rbwpos
    151     mutable QMutex readAheadLock;
     160    ThreadedFileWriter *tfw;      // protected by rwlock
     161    int fd2;                      // protected by rwlock
    152162
    153     bool startreadahead;          // not protected by a lock HR
    154     char *readAheadBuffer;        // not protected by a lock MR
    155     bool readaheadrunning;        // not protected by a lock HR
    156     bool readaheadpaused;         // not protected by a lock HR
    157     bool pausereadthread;         // not protected by a lock HR
    158     int rbrpos;                   // not protected by a lock HR
    159     int rbwpos;                   // not protected by a lock HR
    160     long long internalreadpos;    // not protected by a lock HR
    161     bool ateof;                   // not protected by a lock HR
    162     bool readsallowed;            // not protected by a lock HR
    163     volatile bool wantseek;       // not protected by a lock HR
    164     bool setswitchtonext;         // protected by rwlock
    165     bool streamOnly;
     163    bool writemode;               // protected by rwlock
    166164
    167     uint           rawbitrate;    // protected by rwlock
    168     float          playspeed;     // protected by rwlock
    169     int            fill_threshold;// not protected by a lock HR
    170     int            fill_min;      // protected by rwlock
    171     int            readblocksize; // protected by rwlock
     165    RemoteFile *remotefile;       // protected by rwlock
    172166
    173     QWaitCondition pauseWait;     // not protected by a lock HR
     167    bool      startreadahead;     // protected by rwlock
     168    char     *readAheadBuffer;    // protected by rwlock
     169    bool      readaheadrunning;   // protected by rwlock
     170    bool      reallyrunning;      // protected by rwlock
     171    bool      request_pause;      // protected by rwlock
     172    bool      paused;             // protected by rwlock
     173    bool      ateof;              // protected by rwlock
     174    bool      readsallowed;       // protected by rwlock
     175    bool      setswitchtonext;    // protected by rwlock
     176    bool      streamOnly;         // protected by rwlock
     177    bool      ignorereadahead;    // protected by rwlock
     178    uint      rawbitrate;         // protected by rwlock
     179    float     playspeed;          // protected by rwlock
     180    int       fill_threshold;     // protected by rwlock
     181    int       fill_min;           // protected by rwlock
     182    int       readblocksize;      // protected by rwlock
     183    int       wanttoread;         // protected by rwlock
     184    int       numfailures;        // protected by rwlock (see note 1)
     185    bool      commserror;         // protected by rwlock
    174186
    175     int wanttoread;               // not protected by a lock HR
    176     QWaitCondition availWait;     // protected by availWaitMutex
    177     QMutex availWaitMutex;
     187    // We should really subclass for these two sets of functionality..
     188    // current implementation is not thread-safe.
     189    DVDRingBufferPriv *dvdPriv; // NOT protected by a lock
     190    BDRingBufferPriv  *bdPriv;  // NOT protected by a lock
    178191
    179     QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex
    180     QMutex readsAllowedWaitMutex;
     192    bool oldfile;                 // protected by rwlock
    181193
    182     int numfailures;              // not protected by a lock MR
     194    LiveTVChain *livetvchain;     // protected by rwlock
     195    bool ignoreliveeof;           // protected by rwlock
    183196
    184     bool commserror;              // not protected by a lock MR
     197    long long readAdjust;         // protected by rwlock
    185198
    186     DVDRingBufferPriv *dvdPriv;   // not protected by a lock LR
    187     BDRingBufferPriv  *bdPriv;    // not protected by a lock LR
     199    // note 1: numfailures is modified with only a read lock in the
     200    // read ahead thread, but this is safe since all other places
     201    // that use it are protected by a write lock. But this is a
     202    // fragile state of affairs and care must be taken when modifying
     203    // code or locking around this variable.
    188204
    189     bool oldfile;                 // not protected by a lock LR
    190 
    191     LiveTVChain *livetvchain;     // not protected by a lock HR
    192     bool ignoreliveeof;           // not protected by a lock HR
    193 
    194     long long readAdjust;         // not protected by a lock HR
    195 
    196205    /// Condition to signal that the read ahead thread is running
    197     QWaitCondition readAheadRunningCond;//protected by readAheadRunningCondLock
    198     QMutex readAheadRunningCondLock;
     206    QWaitCondition generalWait;         // protected by rwlock
    199207
    200208  public:
    201209    static QMutex subExtLock;
     
    208216    static const uint kReadTestSize;
    209217};
    210218
    211 #endif
     219#endif // _RINGBUFFER_H_
  • libs/libmythtv/mythplayer.cpp

     
    892892
    893893void MythPlayer::OpenDummy(void)
    894894{
     895    VERBOSE(VB_IMPORTANT, LOC + "OpenDummy()");
     896
    895897    isDummy = true;
    896898
    897899    float displayAspect =
     
    935937    SetDecoder(NULL);
    936938    int testreadsize = 2048;
    937939
     940    MythTimer bigTimer; bigTimer.start();
     941    int timeout = (retries + 1) * 500;
    938942    while (testreadsize <= kDecoderProbeBufferSize)
    939943    {
    940         if (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize)
     944        MythTimer peekTimer; peekTimer.start();
     945        while (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize)
    941946        {
    942             VERBOSE(VB_IMPORTANT, LOC_ERR +
    943                     QString("OpenFile(): Error, couldn't read file: %1")
    944                     .arg(player_ctx->buffer->GetFilename()));
    945             return -1;
     947            if (peekTimer.elapsed() > 1000 || bigTimer.elapsed() > timeout)
     948            {
     949                VERBOSE(VB_IMPORTANT, LOC_ERR +
     950                        QString("OpenFile(): Could not read "
     951                                "first %1 bytes of '%2'")
     952                        .arg(testreadsize)
     953                        .arg(player_ctx->buffer->GetFilename()));
     954                return -1;
     955            }
     956            VERBOSE(VB_IMPORTANT, LOC_WARN + "OpenFile() waiting on data");
     957            usleep(50 * 1000);
    946958        }
    947959
    948960        player_ctx->LockPlayingInfo(__FILE__, __LINE__);
     
    959971                                           player_ctx->GetSpecialDecode()));
    960972        }
    961973        player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    962         if (GetDecoder())
     974        if (GetDecoder() || (bigTimer.elapsed() > timeout))
    963975            break;
    964976        testreadsize <<= 1;
    965977    }
     
    21672179        return;
    21682180    }
    21692181
    2170     uint retries = 10; // about 5 seconds of retries
    2171     player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL(), retries);
     2182    player_ctx->buffer->OpenFile(
     2183        pginfo->GetPlaybackURL(), RingBuffer::kDefaultOpenTimeout);
    21722184
    21732185    if (!player_ctx->buffer->IsOpen())
    21742186    {
    2175         VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed.");
     2187        VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed " +
     2188                QString("(card type: %1).")
     2189                .arg(player_ctx->tvchain->GetCardType(newid)));
     2190        VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
    21762191        eof = true;
    21772192        SetErrored(QObject::tr("Error opening switch program buffer"));
    21782193        delete pginfo;
     
    22892304
    22902305    SendMythSystemPlayEvent("PLAY_CHANGED", pginfo);
    22912306
    2292     player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL());
     2307    player_ctx->buffer->OpenFile(
     2308        pginfo->GetPlaybackURL(), RingBuffer::kDefaultOpenTimeout);
     2309
    22932310    if (!player_ctx->buffer->IsOpen())
    22942311    {
    2295         VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed.");
     2312        VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed " +
     2313                QString("(card type: %1).")
     2314                .arg(player_ctx->tvchain->GetCardType(newid)));
     2315        VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
     2316
    22962317        eof = true;
    22972318        SetErrored(QObject::tr("Error opening jump program file buffer"));
    22982319        delete pginfo;
     
    28842905
    28852906void MythPlayer::WrapTimecode(int64_t &timecode, TCTypes tc_type)
    28862907{
    2887     if ((tc_type == TC_AUDIO) && (tc_wrap[TC_AUDIO] == INT64_MIN))
     2908    if ((tc_type == TC_AUDIO) && (tc_wrap[TC_AUDIO] == LLONG_MIN))
    28882909    {
    28892910        int64_t newaudio;
    28902911        newaudio = tc_lastval[TC_VIDEO];
     
    31893210    if (!videoOutput)
    31903211        return false;
    31913212
    3192     int    sz              = player_ctx->buffer->DataInReadAhead();
    3193     uint   rbs             = player_ctx->buffer->GetReadBlockSize();
    3194     uint   kbits_per_sec   = player_ctx->buffer->GetBitrate();
    3195     uint   vvf             = videoOutput->ValidVideoFrames();
    3196     double inv_fps         = 1.0 / GetDecoder()->GetFPS();
    3197     double bytes_per_frame = kbits_per_sec * (1000.0/8.0) * inv_fps;
    3198     double rh_frames       = sz / bytes_per_frame;
    3199 
    3200     // WARNING: rh_frames can greatly overestimate or underestimate
    3201     //          the number of frames available in the read ahead buffer
    3202     //          when rh_frames is less than the keyframe distance.
    3203 
    3204     bool near_end = ((vvf + rh_frames) < 10.0) || (sz < rbs*1.5);
    3205 
    3206     VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
    3207             <<" br("<<(kbits_per_sec/8)<<"KB)"
    3208             <<" fps("<<((uint)(1.0/inv_fps))<<")"
    3209             <<" sz("<<(sz / 1000)<<"KB)"
    3210             <<" vfl("<<vvf<<")"
    3211             <<" frh("<<((uint)rh_frames)<<")"
    3212             <<" ne:"<<near_end);
    3213 
    3214     return near_end;
     3213    return player_ctx->buffer->IsNearEnd(
     3214        GetDecoder()->GetFPS(),
     3215        videoOutput->ValidVideoFrames());
    32153216}
    32163217
    32173218/** \brief Returns true iff near end of recording.
  • libs/libmythtv/subtitlescreen.cpp

     
    117117{
    118118    VideoOutput    *videoOut = m_player->getVideoOutput();
    119119    VideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : NULL;
    120     long long now = currentFrame ? currentFrame->timecode : INT64_MAX;
     120    long long now = currentFrame ? currentFrame->timecode : LLONG_MAX;
    121121    QMutableHashIterator<MythUIType*, long long> it(m_expireTimes);
    122122    while (it.hasNext())
    123123    {
  • libs/libmythdb/remotefile.h

     
    1717    RemoteFile(const QString &url = "",
    1818               bool write = false,
    1919               bool usereadahead = true,
    20                int retries = -1,
     20               int timeout_ms = 2000/*RingBuffer::kDefaultOpenTimeout*/,
    2121               const QStringList *possibleAuxiliaryFiles = NULL);
    2222   ~RemoteFile();
    2323
     
    5959
    6060    QString         path;
    6161    bool            usereadahead;
    62     int             retries;
     62    int             timeout_ms;
    6363    long long       filesize;
    6464    bool            timeoutisfast;
    6565    long long       readposition;
  • libs/libmythdb/remotefile.cpp

     
    1313#include "mythtimer.h"
    1414
    1515RemoteFile::RemoteFile(const QString &_path, bool write, bool useRA,
    16                        int _retries,
     16                       int _timeout_ms,
    1717                       const QStringList *possibleAuxiliaryFiles) :
    1818    path(_path),
    19     usereadahead(useRA),  retries(_retries),
     19    usereadahead(useRA),  timeout_ms(_timeout_ms),
    2020    filesize(-1),         timeoutisfast(false),
    2121    readposition(0),      recordernum(0),
    2222    lock(QMutex::NonRecursive),
     
    2727    if (writemode)
    2828    {
    2929        usereadahead = false;
    30         retries = -1;
     30        timeout_ms = -1;
    3131    }
    3232    else if (possibleAuxiliaryFiles)
    3333        possibleauxfiles = *possibleAuxiliaryFiles;
     
    107107    }
    108108    else
    109109    {
    110         strlist.append( QString("ANN FileTransfer %1 %2 %3 %4")
    111             .arg(hostname).arg(writemode).arg(usereadahead).arg(retries) );
     110        strlist.push_back(QString("ANN FileTransfer %1 %2 %3 %4")
     111                          .arg(hostname).arg(writemode)
     112                          .arg(usereadahead).arg(timeout_ms));
    112113        strlist << QString("%1").arg(dir);
    113114        strlist << sgroup;
    114115
  • programs/mythbackend/filetransfer.cpp

     
    99#include "programinfo.h"
    1010
    1111FileTransfer::FileTransfer(QString &filename, MythSocket *remote,
    12                            bool usereadahead, int retries) :
     12                           bool usereadahead, int timeout_ms) :
    1313    readthreadlive(true), readsLocked(false),
    14     rbuffer(new RingBuffer(filename, false, usereadahead, retries)),
     14    rbuffer(new RingBuffer(filename, false, usereadahead, timeout_ms)),
    1515    sock(remote), ateof(false), lock(QMutex::NonRecursive),
    1616    refLock(QMutex::NonRecursive), refCount(0), writemode(false)
    1717{
  • programs/mythbackend/mainserver.cpp

     
    12481248        FileTransfer *ft = NULL;
    12491249        bool writemode = false;
    12501250        bool usereadahead = true;
    1251         int retries = -1;
     1251        int timeout_ms = 2000;
    12521252        if (commands.size() > 3)
    12531253            writemode = commands[3].toInt();
    12541254
     
    12561256            usereadahead = commands[4].toInt();
    12571257
    12581258        if (commands.size() > 5)
    1259             retries = commands[5].toInt();
     1259            timeout_ms = commands[5].toInt();
    12601260
    12611261        if (writemode)
    12621262        {
     
    13121312            return;
    13131313        }
    13141314
    1315         if (retries < 0)
     1315        if (writemode)
    13161316            ft = new FileTransfer(filename, socket, writemode);
    13171317        else
    1318             ft = new FileTransfer(filename, socket, usereadahead, retries);
     1318            ft = new FileTransfer(filename, socket, usereadahead, timeout_ms);
    13191319
    13201320        sockListLock.lockForWrite();
    13211321        fileTransferList.push_back(ft);
  • programs/mythbackend/filetransfer.h

     
    2626
    2727  public:
    2828    FileTransfer(QString &filename, MythSocket *remote,
    29                  bool usereadahead, int retries);
     29                 bool usereadahead, int timeout_ms);
    3030    FileTransfer(QString &filename, MythSocket *remote, bool write);
    3131
    3232    MythSocket *getSocket() { return sock; }