Ticket #8812: 8812-v13.patch

File 8812-v13.patch, 89.9 KB (added by danielk, 10 years ago)

Update patch

  • 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/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)
     
    560590    rwlock.unlock();
    561591}
    562592
    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 
    576593/** \fn RingBuffer::Reset(bool, bool, bool)
    577594 *  \brief Resets the read-ahead thread and our position in the file
    578595 */
    579596void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal)
    580597{
    581     wantseek = true;
     598    VERBOSE(VB_FILE, LOC + QString("Reset(%1,%2,%3)")
     599            .arg(full).arg(toAdjust).arg(resetInternal));
     600
    582601    rwlock.lockForWrite();
    583     wantseek = false;
     602    poslock.lockForWrite();
     603
    584604    numfailures = 0;
    585605    commserror = false;
    586606    setswitchtonext = false;
     
    590610
    591611    if (readpos != 0)
    592612    {
    593         VERBOSE(VB_IMPORTANT, QString(
     613        VERBOSE(VB_IMPORTANT, LOC + QString(
    594614                "RingBuffer::Reset() nonzero readpos.  toAdjust: %1 readpos: %2"
    595615                " readAdjust: %3").arg(toAdjust).arg(readpos).arg(readAdjust));
    596616    }
     
    604624    if (resetInternal)
    605625        internalreadpos = readpos;
    606626
     627    generalWait.wakeAll();
     628    poslock.unlock();
    607629    rwlock.unlock();
    608630}
    609631
     
    625647    unsigned errcnt = 0;
    626648    unsigned zerocnt = 0;
    627649
    628     if (fd < 0)
     650    if (fd2 < 0)
    629651    {
    630652        VERBOSE(VB_IMPORTANT, LOC_ERR +
    631653                "Invalid file descriptor in 'safe_read()'");
     
    637659
    638660    while (tot < sz)
    639661    {
    640         ret = read(fd, (char *)data + tot, sz - tot);
     662        ret = read(fd2, (char *)data + tot, sz - tot);
    641663        if (ret < 0)
    642664        {
    643665            if (errno == EAGAIN)
     
    691713 */
    692714int RingBuffer::safe_read(RemoteFile *rf, void *data, uint sz)
    693715{
    694     int ret = 0;
    695 
    696     ret = rf->Read(data, sz);
     716    int ret = rf->Read(data, sz);
    697717    if (ret < 0)
    698718    {
    699719        VERBOSE(VB_IMPORTANT, LOC_ERR +
    700720                "RingBuffer::safe_read(RemoteFile* ...): read failed");
    701 
     721           
     722        poslock.lockForRead();
    702723        rf->Seek(internalreadpos - readAdjust, SEEK_SET);
    703         ret = 0;
     724        poslock.unlock();
    704725        numfailures++;
    705      }
     726    }
     727    else if (ret == 0)
     728    {
     729        VERBOSE(VB_FILE, LOC +
     730                "RingBuffer::safe_read(RemoteFile* ...): at EOF");
     731    }
    706732
    707733    return ret;
    708734}
     
    714740 */
    715741void RingBuffer::UpdateRawBitrate(uint raw_bitrate)
    716742{
     743    VERBOSE(VB_FILE, LOC + QString("UpdateRawBitrate(%1Kb)").arg(raw_bitrate));
     744    if (raw_bitrate < 2500)
     745    {
     746        VERBOSE(VB_FILE, LOC +
     747                QString("UpdateRawBitrate(%1Kb) - ignoring bitrate,")
     748                .arg(raw_bitrate) +
     749                "\n\t\t\tappears to be abnormally low.");
     750        return;
     751    }
     752
    717753    rwlock.lockForWrite();
    718754    rawbitrate = raw_bitrate;
    719755    CalcReadAheadThresh();
    720756    rwlock.unlock();
    721757}
    722758
    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 
    748759/** \fn RingBuffer::UpdatePlaySpeed(float)
    749760 *  \brief Set the play speed, to allow RingBuffer adjust effective bitrate.
    750761 *  \param play_speed Speed to set. (1.0 for normal speed)
     
    768779{
    769780    uint estbitrate = 0;
    770781
    771     wantseek       = false;
    772782    readsallowed   = false;
    773     readblocksize  = CHUNK;
     783    readblocksize  = max(readblocksize, CHUNK);
    774784
    775785    // loop without sleeping if the buffered data is less than this
    776     fill_threshold = CHUNK * 2;
    777     fill_min       = 1;
     786    fill_threshold = kBufferSize / 8;
    778787
    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;
     788    const uint KB32  =  32*1024;
     789    const uint KB64  =  64*1024;
     790    const uint KB128 = 128*1024;
     791    const uint KB256 = 256*1024;
     792    const uint KB512 = 512*1024;
    787793
    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;
     794    estbitrate     = (uint) max(abs(rawbitrate * playspeed),
     795                                0.5f * rawbitrate);
     796    estbitrate     = min(rawbitrate * 3, estbitrate);
     797    int rbs        = (estbitrate > 2500)  ? KB64  : KB32;
     798    rbs            = (estbitrate > 5000)  ? KB128 : rbs;
     799    rbs            = (estbitrate > 9000)  ? KB256 : rbs;
     800    rbs            = (estbitrate > 18000) ? KB512 : rbs;
     801    readblocksize  = max(rbs,readblocksize);
    795802
    796         // minumum seconds of buffering before allowing read
    797         float secs_min = 0.1;
     803    // minumum seconds of buffering before allowing read
     804    float secs_min = 0.25;
     805    // set the minimum buffering before allowing ffmpeg read
     806    fill_min        = (uint) ((estbitrate * secs_min) * 0.125f);
     807    // make this a multiple of ffmpeg block size..
     808    fill_min        = ((fill_min / KB32) + 1) * KB32;
    798809
    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 -> "
     810    VERBOSE(VB_FILE, LOC +
     811            QString("CalcReadAheadThresh(%1 Kb)\n\t\t\t -> "
    808812                    "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)")
    809813            .arg(estbitrate).arg(fill_threshold/1024)
    810814            .arg(fill_min/1024).arg(readblocksize/1024));
    811815}
    812816
    813 /** \fn RingBuffer::ReadBufFree(void) const
    814  *  \brief Returns number of bytes available for reading into buffer.
    815  */
     817bool RingBuffer::IsNearEnd(double fps, uint vvf) const
     818{
     819    rwlock.lockForRead();
     820    int    sz  = ReadBufAvail();
     821    uint   rbs = readblocksize;
     822    // telecom kilobytes (i.e. 1000 per k not 1024)
     823    uint   tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
     824    uint   kbits_per_sec = min(rawbitrate * 3, tmp);
     825    rwlock.unlock();
     826
     827    // WARNING: readahead_frames can greatly overestimate or underestimate
     828    //          the number of frames available in the read ahead buffer
     829    //          when rh_frames is less than the keyframe distance.
     830    double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps;
     831    double readahead_frames = sz / bytes_per_frame;
     832
     833    bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5);
     834
     835    VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
     836            <<" br("<<(kbits_per_sec/8)<<"KB)"
     837            <<" sz("<<(sz / 1000)<<"KB)"
     838            <<" vfl("<<vvf<<")"
     839            <<" frh("<<((uint)readahead_frames)<<")"
     840            <<" ne:"<<near_end);
     841
     842    return near_end;
     843}
     844
     845/// \brief Returns number of bytes available for reading into buffer.
     846/// WARNING: Must be called with rwlock in locked state.
    816847int RingBuffer::ReadBufFree(void) const
    817848{
    818     QMutexLocker locker(&readAheadLock);
    819     return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     849    rbrlock.lockForRead();
     850    rbwlock.lockForRead();
     851    int ret = ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     852    rbwlock.unlock();
     853    rbrlock.unlock();
     854    return ret;
    820855}
    821856
    822 /** \fn RingBuffer::ReadBufAvail(void) const
    823  *  \brief Returns number of bytes available for reading from buffer.
    824  */
     857/// \brief Returns number of bytes available for reading from buffer.
     858/// WARNING: Must be called with rwlock in locked state.
    825859int RingBuffer::ReadBufAvail(void) const
    826860{
    827     QMutexLocker locker(&readAheadLock);
    828     return (rbwpos >= rbrpos) ?
    829         rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     861    rbrlock.lockForRead();
     862    rbwlock.lockForRead();
     863    int ret = (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     864    rbwlock.unlock();
     865    rbrlock.unlock();
     866    return ret;
    830867}
    831868
    832869/** \fn RingBuffer::ResetReadAhead(long long)
     
    836873 *   buffer doesn't contain any stale data, and so that it will read
    837874 *   any new data from the new position in the file.
    838875 *
    839  *   WARNING: Must be called with rwlock in write lock state.
     876 *   WARNING: Must be called with rwlock and poslock in write lock state.
    840877 *
    841878 *  \param newinternal Position in file to start reading data from
    842879 */
    843880void RingBuffer::ResetReadAhead(long long newinternal)
    844881{
    845     readAheadLock.lock();
    846     readblocksize = CHUNK;
     882    VERBOSE(VB_FILE, LOC + QString("ResetReadAhead(internalreadpos = %1->%2)")
     883            .arg(internalreadpos).arg(newinternal));
     884
     885    rbrlock.lockForWrite();
     886    rbwlock.lockForWrite();
     887
     888    CalcReadAheadThresh();
    847889    rbrpos = 0;
    848890    rbwpos = 0;
    849891    internalreadpos = newinternal;
    850892    ateof = false;
    851893    readsallowed = false;
    852894    setswitchtonext = false;
    853     readAheadLock.unlock();
     895    generalWait.wakeAll();
     896
     897    rbwlock.unlock();
     898    rbrlock.unlock();
    854899}
    855900
    856 /** \fn RingBuffer::StartupReadAheadThread(void)
    857  *  \brief Creates the read-ahead thread, and waits for it to start.
     901/**
     902 *  \brief Starts the read-ahead thread.
    858903 *
    859  *  \sa Start(void).
     904 *   If the RingBuffer constructor was not called with a usereadahead
     905 *   of true of if this was reset to false because we're dealing with
     906 *   a DVD the read ahead thread will not be started.
     907 *
     908 *   If this RingBuffer is in write-mode a warning will be printed and
     909 *   the read ahead thread will not be started.
     910 *
     911 *   If the read ahead thread is already running a warning will be printed
     912 *   and the read ahead thread will not be started.
     913 *
    860914 */
    861 void RingBuffer::StartupReadAheadThread(void)
     915void RingBuffer::Start(void)
    862916{
    863     readaheadrunning = false;
     917    bool do_start = true;
    864918
    865     readAheadRunningCondLock.lock();
     919    rwlock.lockForWrite();
     920    if (!startreadahead)
     921    {
     922        do_start = false;
     923    }
     924    else if (writemode)
     925    {
     926        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     927                "this is a write only RingBuffer");
     928        do_start = false;
     929    }
     930    else if (readaheadrunning)
     931    {
     932        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     933                "already running");
     934        do_start = false;
     935    }
     936
     937    if (!do_start)
     938    {
     939        rwlock.unlock();
     940        return;
     941    }
     942
     943    StartReads();
     944
    866945    QThread::start();
    867     readAheadRunningCond.wait(&readAheadRunningCondLock);
    868     readAheadRunningCondLock.unlock();
     946
     947    while (readaheadrunning && !reallyrunning)
     948        generalWait.wait(&rwlock);
     949
     950    rwlock.unlock();
    869951}
    870952
    871953/** \fn RingBuffer::KillReadAheadThread(void)
     
    873955 */
    874956void RingBuffer::KillReadAheadThread(void)
    875957{
    876     if (!readaheadrunning)
    877         return;
     958    rwlock.lockForWrite();
     959    bool do_wait = readaheadrunning;
     960    readaheadrunning = false;
     961    StopReads();
     962    generalWait.wakeAll();
     963    rwlock.unlock();
    878964
    879     readaheadrunning = false;
    880     QThread::wait();
     965    if (do_wait)
     966        QThread::wait();
    881967}
    882968
    883969/** \fn RingBuffer::StopReads(void)
     
    887973void RingBuffer::StopReads(void)
    888974{
    889975    stopreads = true;
    890     availWait.wakeAll();
     976    generalWait.wakeAll();
    891977}
    892978
    893979/** \fn RingBuffer::StartReads(void)
     
    897983void RingBuffer::StartReads(void)
    898984{
    899985    stopreads = false;
     986    generalWait.wakeAll();
    900987}
    901988
    902989/** \fn RingBuffer::Pause(void)
     
    905992 */
    906993void RingBuffer::Pause(void)
    907994{
    908     pausereadthread = true;
    909995    StopReads();
     996
     997    rwlock.lockForWrite();
     998    request_pause = true;
     999    rwlock.unlock();
    9101000}
    9111001
    9121002/** \fn RingBuffer::Unpause(void)
     
    9161006void RingBuffer::Unpause(void)
    9171007{
    9181008    StartReads();
    919     pausereadthread = false;
     1009
     1010    rwlock.lockForWrite();
     1011    request_pause = false;
     1012    generalWait.wakeAll();
     1013    rwlock.unlock();
    9201014}
    9211015
     1016/// Returns false iff read-ahead is not running and read-ahead is not paused.
     1017bool RingBuffer::isPaused(void) const
     1018{
     1019    rwlock.lockForRead();
     1020    bool ret = !readaheadrunning || paused;
     1021    rwlock.unlock();
     1022    return ret;
     1023}
     1024
    9221025/** \fn RingBuffer::WaitForPause(void)
    9231026 *  \brief Waits for Pause(void) to take effect.
    9241027 */
    9251028void RingBuffer::WaitForPause(void)
    9261029{
    927     if (!readaheadrunning)
    928         return;
     1030    MythTimer t;
     1031    t.start();
    9291032
    930     if  (!readaheadpaused)
     1033    rwlock.lockForRead();
     1034    while (readaheadrunning && !paused && request_pause)
    9311035    {
    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();
     1036        generalWait.wait(&rwlock, 1000);
     1037        if (readaheadrunning && !paused && request_pause && t.elapsed() > 1000)
     1038        {
     1039            VERBOSE(VB_IMPORTANT, LOC_WARN +
     1040                    QString("Waited %1 ms for ringbuffer pause..")
     1041                    .arg(t.elapsed()));
     1042        }
     1043    }
     1044    rwlock.unlock();
     1045}
    9361046
    937         while (!pauseWait.wait(&mutex, 1000))
    938             VERBOSE(VB_IMPORTANT,
    939                     LOC + "Waited too long for ringbuffer pause..");
     1047bool RingBuffer::PauseAndWait(void)
     1048{
     1049    const uint timeout = 500; // ms
     1050
     1051    if (request_pause)
     1052    {
     1053        if (!paused)
     1054        {
     1055            rwlock.unlock();
     1056            rwlock.lockForWrite();
     1057
     1058            if (request_pause)
     1059            {
     1060                paused = true;
     1061                generalWait.wakeAll();
     1062            }
     1063
     1064            rwlock.unlock();
     1065            rwlock.lockForRead();
     1066        }
     1067
     1068        if (request_pause && paused && readaheadrunning)
     1069            generalWait.wait(&rwlock, timeout);
    9401070    }
     1071
     1072    if (!request_pause && paused)
     1073    {
     1074        rwlock.unlock();
     1075        rwlock.lockForWrite();
     1076
     1077        if (!request_pause)
     1078        {
     1079            paused = false;
     1080            generalWait.wakeAll();
     1081        }
     1082
     1083        rwlock.unlock();
     1084        rwlock.lockForRead();
     1085    }
     1086
     1087    return request_pause || paused;
    9411088}
    9421089
    9431090void RingBuffer::run(void)
    9441091{
    945     long long totfree = 0;
    946     int ret = -1;
    947     int used = 0;
    948     int loops = 0;
    949 
     1092    // These variables are used to adjust the read block size
    9501093    struct timeval lastread, now;
    951     gettimeofday(&lastread, NULL);
    952     const int KB640 = 640*1024;
    9531094    int readtimeavg = 300;
    954     int readinterval;
     1095    bool ignore_for_read_timing = true;
    9551096
    956     pausereadthread = false;
     1097    gettimeofday(&lastread, NULL); // this is just to keep gcc happy
    9571098
    958     readAheadBuffer = new char[kBufferSize + KB640];
    959 
    9601099    rwlock.lockForWrite();
     1100    poslock.lockForWrite();
     1101    request_pause = false;
     1102    readAheadBuffer = new char[kBufferSize + 1024];
    9611103    ResetReadAhead(0);
     1104    readaheadrunning = true;
     1105    reallyrunning = true;
     1106    generalWait.wakeAll();
     1107    poslock.unlock();
    9621108    rwlock.unlock();
    9631109
    964     totfree = ReadBufFree();
     1110    // NOTE: this must loop at some point hold only
     1111    // a read lock on rwlock, so that other functions
     1112    // such as reset and seek can take priority.
    9651113
    966     readaheadrunning = true;
    967     readAheadRunningCondLock.lock();
    968     readAheadRunningCond.wakeAll();
    969     readAheadRunningCondLock.unlock();
     1114    rwlock.lockForRead();
     1115
     1116    VERBOSE(VB_FILE, LOC + QString("Initial readblocksize %1K & fill_min %2K")
     1117            .arg(readblocksize/1024).arg(fill_min/1024));
     1118
    9701119    while (readaheadrunning)
    9711120    {
    972         if (pausereadthread || writemode)
     1121        if (PauseAndWait())
    9731122        {
    974             readaheadpaused = true;
    975             pauseWait.wakeAll();
    976             usleep(5000);
    977             totfree = ReadBufFree();
     1123            ignore_for_read_timing = true;
    9781124            continue;
    9791125        }
    9801126
    981         if (readaheadpaused)
     1127        long long totfree = ReadBufFree();
     1128
     1129        if (totfree < readblocksize)
    9821130        {
    983             totfree = ReadBufFree();
    984             readaheadpaused = false;
     1131            generalWait.wait(&rwlock, 1000);
     1132            continue;
    9851133        }
    9861134
    987         totfree = ReadBufFree();
    988         if (totfree < GetReadBlockSize())
     1135        if (ignorereadpos >= 0 || commserror || ateof || setswitchtonext)
    9891136        {
    990             usleep(50000);
    991             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;
     1137            generalWait.wait(&rwlock, 1000);
     1138            continue;
    9971139        }
    998         loops = 0;
    9991140
    1000         rwlock.lockForRead();
    1001         if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
     1141        // No point in trying to read if stopreads is set but do sleep
     1142        // a little so we don't get stuck in a tight busy loop here..
     1143        if (stopreads)
    10021144        {
     1145            ignore_for_read_timing = true;
     1146            generalWait.wait(&rwlock, 1000);
     1147            continue;
     1148        }
     1149
     1150        int read_return = -1;
     1151        if (totfree >= readblocksize && !commserror &&
     1152            !ateof && !setswitchtonext)
     1153        {
    10031154            // limit the read size
    10041155            totfree = readblocksize;
    10051156
    10061157            // adapt blocksize
    10071158            gettimeofday(&now, NULL);
    1008             readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
    1009                            (now.tv_usec - lastread.tv_usec) / 1000;
     1159            if (!ignore_for_read_timing)
     1160            {
     1161                int readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
     1162                    (now.tv_usec - lastread.tv_usec) / 1000;
     1163                readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    10101164
    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;
     1165                if (readtimeavg < 150 && (uint)readblocksize < (kBufferSize>>2))
     1166                {
     1167                    int old_block_size = readblocksize;
     1168                    readblocksize = 3 * readblocksize / 2;
     1169                    readblocksize = ((readblocksize+CHUNK-1) / CHUNK) * CHUNK;
     1170                    VERBOSE(VB_FILE, LOC +
     1171                            QString("Avg read interval was %1 msec. "
     1172                                    "%2K -> %3K block size")
     1173                            .arg(readtimeavg)
     1174                            .arg(old_block_size/1024)
     1175                            .arg(readblocksize/1024));
     1176                    readtimeavg = 225;
     1177                }
     1178                else if (readtimeavg > 300 && readblocksize > CHUNK)
     1179                {
     1180                    readblocksize -= CHUNK;
     1181                    VERBOSE(VB_FILE, LOC +
     1182                            QString("Avg read interval was %1 msec. "
     1183                                    "%2K -> %3K block size")
     1184                            .arg(readtimeavg)
     1185                            .arg((readblocksize+CHUNK)/1024)
     1186                            .arg(readblocksize/1024));
     1187                    readtimeavg = 225;
     1188                }
    10201189            }
    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             }
     1190            ignore_for_read_timing = false;
    10291191            lastread = now;
    10301192
     1193            rbwlock.lockForRead();
    10311194            if (rbwpos + totfree > kBufferSize)
     1195            {
    10321196                totfree = kBufferSize - rbwpos;
     1197                VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1198                        "Shrinking read, near end of buffer");
     1199            }
    10331200
    10341201            if (internalreadpos == 0)
    1035                 totfree = fill_min;
     1202            {
     1203                totfree = max(fill_min, readblocksize);
     1204                VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1205                        "Reading enough data to start playback");
     1206            }
    10361207
     1208            VERBOSE(VB_FILE|VB_EXTRA,
     1209                    LOC + QString("safe_read(...@%1, %2) -- begin")
     1210                    .arg(rbwpos).arg(totfree));
    10371211            if (remotefile)
    10381212            {
    10391213                if (livetvchain && livetvchain->HasNext())
    10401214                    remotefile->SetTimeout(true);
    1041 
    1042                 ret = safe_read(remotefile, readAheadBuffer + rbwpos,
    1043                                 totfree);
    1044                 internalreadpos += ret;
     1215                read_return = safe_read(
     1216                    remotefile, readAheadBuffer + rbwpos, totfree);
    10451217            }
    10461218#ifdef USING_FRONTEND
    10471219            else if (dvdPriv)
    10481220            {
    1049                 ret = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1050                 internalreadpos += ret;
     1221                read_return = dvdPriv->safe_read(
     1222                    readAheadBuffer + rbwpos, totfree);
    10511223            }
    10521224            else if (bdPriv)
    10531225            {
    1054                 ret = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1055                 internalreadpos += ret;
     1226                read_return = bdPriv->safe_read(
     1227                    readAheadBuffer + rbwpos, totfree);
    10561228            }
    10571229#endif // USING_FRONTEND
    10581230            else
    10591231            {
    1060                 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    1061                 internalreadpos += ret;
     1232                read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    10621233            }
     1234            VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1235                    QString("safe_read(...@%1, %2) -> %3")
     1236                    .arg(rbwpos).arg(totfree).arg(read_return));
     1237            rbwlock.unlock();
     1238        }
    10631239
    1064             readAheadLock.lock();
    1065             if (ret > 0 )
    1066                 rbwpos = (rbwpos + ret) % kBufferSize;
    1067             readAheadLock.unlock();
     1240        if (read_return >= 0)
     1241        {
     1242            poslock.lockForWrite();
     1243            rbwlock.lockForWrite();
     1244            internalreadpos += read_return;
     1245            rbwpos = (rbwpos + read_return) % kBufferSize;
     1246            VERBOSE(VB_FILE|VB_EXTRA,
     1247                    LOC + QString("rbwpos += %1K requested %2K in read")
     1248                    .arg(read_return/1024,3).arg(totfree/1024,3));
     1249            rbwlock.unlock();
     1250            poslock.unlock();
     1251        }
    10681252
    1069             if (ret == 0 && !stopreads)
     1253        int used = kBufferSize - ReadBufFree();
     1254
     1255        if ((0 == read_return) || (numfailures > 5) ||
     1256            (readsallowed != (used >= fill_min || ateof ||
     1257                              setswitchtonext || commserror)))
     1258        {
     1259            // If readpos changes while the lock is released
     1260            // we should not handle the 0 read_return now.
     1261            long long old_readpos = readpos;
     1262
     1263            rwlock.unlock();
     1264            rwlock.lockForWrite();
     1265
     1266            commserror |= (numfailures > 5);
     1267
     1268            readsallowed = used >= fill_min || ateof ||
     1269                setswitchtonext || commserror;
     1270
     1271            if (0 == read_return && old_readpos == readpos)
    10701272            {
    10711273                if (livetvchain)
    10721274                {
     
    10781280                    }
    10791281                }
    10801282                else
     1283                {
     1284                    VERBOSE(VB_FILE|VB_EXTRA,
     1285                            LOC + "setting ateof (read_return == 0)");
    10811286                    ateof = true;
     1287                }
    10821288            }
    1083         }
    10841289
    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;
     1290            rwlock.unlock();
     1291            rwlock.lockForRead();
     1292            used = kBufferSize - ReadBufFree();
    10951293        }
    10961294
    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));
     1295        VERBOSE(VB_FILE|VB_EXTRA, LOC + "@ end of read ahead loop");
    11071296
    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 ||
     1297        if (readsallowed || commserror || ateof || setswitchtonext ||
    11221298            (wanttoread <= used && wanttoread > 0))
    11231299        {
    1124             availWait.wakeAll();
     1300            // To give other threads a good chance to handle these
     1301            // conditions, even if they are only requesting a read lock
     1302            // like us, yield (currently implemented with short usleep).
     1303            generalWait.wakeAll();
     1304            rwlock.unlock();
     1305            usleep(5 * 1000);
     1306            rwlock.lockForRead();           
    11251307        }
    1126         availWaitMutex.unlock();
    1127 
    1128         rwlock.unlock();
    1129 
    1130         if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
    1131             !pausereadthread)
     1308        else
    11321309        {
    1133             usleep(500);
     1310            // yield if we have nothing to do...
     1311            if (!request_pause &&
     1312                (used >= fill_threshold || ateof || setswitchtonext))
     1313            {
     1314                generalWait.wait(&rwlock, 1000);
     1315            }
    11341316        }
    11351317    }
    11361318
     1319    rwlock.unlock();
     1320
     1321    rwlock.lockForWrite();
     1322    rbrlock.lockForWrite();
     1323    rbwlock.lockForWrite();
     1324
     1325    rbrpos = 0;
     1326    rbwpos = 0;
     1327    reallyrunning = false;
     1328    readsallowed = false;
    11371329    delete [] readAheadBuffer;
     1330
    11381331    readAheadBuffer = NULL;
    1139     rbrpos = 0;
    1140     rbwpos = 0;
     1332    rbwlock.unlock();
     1333    rbrlock.unlock();
     1334    rwlock.unlock();
    11411335}
    11421336
    11431337long long RingBuffer::SetAdjustFilesize(void)
    11441338{
     1339    rwlock.lockForWrite();
     1340    poslock.lockForRead();
    11451341    readAdjust += internalreadpos;
    1146     return readAdjust;
     1342    long long ra = readAdjust;
     1343    poslock.unlock();
     1344    rwlock.unlock();
     1345    return ra;
    11471346}
    11481347
    11491348int RingBuffer::Peek(void *buf, int count)
    11501349{
    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 
     1350    int ret = ReadPriv(buf, count, true);
    11911351    if (ret != count)
    11921352    {
    11931353        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    11971357    return ret;
    11981358}
    11991359
    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)
     1360bool RingBuffer::WaitForReadsAllowed(void)
    12091361{
    1210     if (commserror)
    1211         return 0;
     1362    MythTimer t;
     1363    t.start();
    12121364
    1213     bool readone = false;
    1214     int readErr = 0;
    1215 
    1216     if (readaheadpaused && stopreads)
     1365    while (!readsallowed && !stopreads &&
     1366           !request_pause && !commserror && readaheadrunning)
    12171367    {
    1218         readone = true;
    1219         Unpause();
    1220     }
    1221     else
    1222     {
    1223         QMutexLocker locker(&readsAllowedWaitMutex);
     1368        generalWait.wait(&rwlock, 1000);
     1369        if (!readsallowed && t.elapsed() > 1000)
     1370        {
     1371            VERBOSE(VB_IMPORTANT, LOC_WARN +
     1372                    "Taking too long to be allowed to read..");
    12241373
    1225         while (!readsallowed && !stopreads)
    1226         {
    1227             if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000))
     1374            if (t.elapsed() > 10000)
    12281375            {
    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                  }
     1376                VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
     1377                        "10 seconds to be allowed to read, aborting.");
     1378                return false;
    12491379            }
    12501380        }
    12511381    }
    12521382
     1383    return readsallowed;
     1384}
     1385
     1386bool RingBuffer::WaitForAvail(int count)
     1387{
    12531388    int avail = ReadBufAvail();
     1389    count = (ateof && avail < count) ? avail : count;
    12541390
    1255     if (ateof && avail < count)
    1256         count = avail;
    1257 
    12581391    MythTimer t;
    12591392    t.start();
    1260     while (avail < count && !stopreads)
     1393    while ((avail < count) && !stopreads &&
     1394           !request_pause && !commserror && readaheadrunning)
    12611395    {
    1262         availWaitMutex.lock();
    12631396        wanttoread = count;
    1264         if (!availWait.wait(&availWaitMutex, 250))
     1397        generalWait.wait(&rwlock, 250);
     1398        avail = ReadBufAvail();
     1399
     1400        if ((ateof || setswitchtonext) && avail < count)
     1401            count = avail;
     1402
     1403        if (avail < count)
    12651404        {
    12661405            int elapsed = t.elapsed();
    1267             if  (/*((elapsed > 500)  && (elapsed < 750))  ||*/
     1406            if  (((elapsed > 250)  && (elapsed < 500))  ||
     1407                 ((elapsed > 500)  && (elapsed < 750))  ||
    12681408                 ((elapsed > 1000) && (elapsed < 1250)) ||
    12691409                 ((elapsed > 2000) && (elapsed < 2250)) ||
    12701410                 ((elapsed > 4000) && (elapsed < 4250)) ||
    1271                  ((elapsed > 8000) && (elapsed < 8250)))
     1411                 ((elapsed > 8000) && (elapsed < 8250)) ||
     1412                 ((elapsed > 9000)))
    12721413            {
    12731414                VERBOSE(VB_IMPORTANT, LOC + "Waited " +
    1274                         QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) +
    1275                         " seconds for data to become available...");
     1415                        QString("%1").arg((elapsed / 250) * 0.25f, 3, 'f', 1) +
     1416                        " seconds for data \n\t\t\tto become available..." +
     1417                        QString(" %2 < %3")
     1418                        .arg(avail).arg(count));
    12761419                if (livetvchain)
    12771420                {
    12781421                    VERBOSE(VB_IMPORTANT, "Checking to see if there's a "
     
    12951438                    VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to "
    12961439                            "impending livetv switch.");
    12971440
    1298                 ateof = true;
    1299                 wanttoread = 0;
    1300                 stopreads = true;
    1301                 availWaitMutex.unlock();
    1302                 return 0;
     1441                return false;
    13031442            }
    13041443        }
     1444    }
    13051445
     1446    wanttoread = 0;
     1447
     1448    return avail >= count;
     1449}
     1450
     1451int RingBuffer::ReadDirect(void *buf, int count, bool peek)
     1452{
     1453    long long old_pos = 0;
     1454    if (peek)
     1455    {
     1456        poslock.lockForRead();
     1457        old_pos = (ignorereadpos >= 0) ? ignorereadpos : readpos;
     1458        poslock.unlock();
     1459    }
     1460
     1461    int ret;
     1462    if (remotefile)
     1463        ret = safe_read(remotefile, buf, count);
     1464#ifdef USING_FRONTEND
     1465    else if (dvdPriv)
     1466        ret = dvdPriv->safe_read(buf, count);
     1467    else if (bdPriv)
     1468        ret = bdPriv->safe_read(buf, count);
     1469#endif // USING_FRONTEND
     1470    else if (fd2 >= 0)
     1471        ret = safe_read(fd2, buf, count);
     1472    else
     1473    {
     1474        ret = -1;
     1475        errno = EBADF;
     1476    }
     1477
     1478    poslock.lockForWrite();
     1479    if (ignorereadpos >= 0 && ret > 0)
     1480    {
     1481        if (peek)
     1482        {
     1483            // seek should always succeed since we were at this position
     1484            if (remotefile)
     1485                remotefile->Seek(old_pos, SEEK_SET);
     1486            else
     1487                lseek64(fd2, old_pos, SEEK_SET);
     1488        }
     1489        else
     1490        {
     1491            ignorereadpos += ret;
     1492        }
     1493        poslock.unlock();
     1494        return ret;
     1495    }
     1496    poslock.unlock();
     1497
     1498    if (peek && ret > 0)
     1499    {
     1500        if (!dvdPriv && !bdPriv)
     1501        {
     1502            long long new_pos = Seek(old_pos, SEEK_SET, true);
     1503            if (new_pos != old_pos)
     1504            {
     1505                VERBOSE(VB_IMPORTANT, LOC_ERR +
     1506                        QString("Peek() Failed to return from new "
     1507                                "position %1 to old position %2, now "
     1508                                "at position %3")
     1509                        .arg(old_pos - ret).arg(old_pos).arg(new_pos));
     1510            }
     1511        }
     1512        else if (old_pos != 0)
     1513        {
     1514            VERBOSE(VB_IMPORTANT, LOC_ERR +
     1515                    "DVD and Blu-Ray do not support arbitrary "
     1516                    "peeks except when read-ahead is enabled."
     1517                    "\n\t\t\tWill seek to beginning of video.");
     1518        }
     1519#ifdef USING_FRONTEND
     1520        if (dvdPriv)
     1521        {
     1522            dvdPriv->NormalSeek(0);
     1523        }
     1524        else if (bdPriv)
     1525        {
     1526            bdPriv->Seek(0);
     1527        }
     1528#endif // USING_FRONTEND
     1529    }
     1530
     1531    return ret;
     1532}
     1533
     1534/** \brief When possible reads from the read-ahead buffer,
     1535 *         otherwise reads directly from the device.
     1536 *
     1537 *  \param buf   Pointer to where data will be written
     1538 *  \param count Number of bytes to read
     1539 *  \param peek  If true, don't increment read count
     1540 *  \return Returns number of bytes read
     1541 */
     1542int RingBuffer::ReadPriv(void *buf, int count, bool peek)
     1543{
     1544    QString loc_desc =
     1545            QString("ReadPriv(..%1, %2)")
     1546        .arg(count).arg(peek?"peek":"normal");
     1547    VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc +
     1548            QString(" @%1 -- begin").arg(rbrpos));
     1549
     1550    rwlock.lockForRead();
     1551    if (writemode)
     1552    {
     1553        VERBOSE(VB_IMPORTANT, LOC_ERR + loc_desc +
     1554                ": Attempt to read from a write only file");
     1555        errno = EBADF;
     1556        rwlock.unlock();
     1557        return -1;
     1558    }
     1559
     1560    if (commserror)
     1561    {
     1562        VERBOSE(VB_IMPORTANT, LOC_ERR + loc_desc +
     1563                ": Attempt to read after commserror set");
     1564        errno = EIO;
     1565        rwlock.unlock();
     1566        return -1;
     1567    }
     1568
     1569    if (request_pause || stopreads || !readaheadrunning || (ignorereadpos>=0))
     1570    {
     1571        rwlock.unlock();
     1572        rwlock.lockForWrite();
     1573        // we need a write lock so the read-ahead thread
     1574        // can't start mucking with the read position.
     1575        // If the read ahead thread was started while we
     1576        // didn't hold the lock, we proceed with a normal
     1577        // read from the buffer, otherwise we read directly.
     1578        if (request_pause || stopreads ||
     1579            !readaheadrunning || (ignorereadpos >= 0))
     1580        {
     1581            int ret = ReadDirect(buf, count, peek);
     1582            VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc +
     1583                    QString(": ReadDirect checksum %1")
     1584                    .arg(qChecksum((char*)buf,count)));
     1585            rwlock.unlock();
     1586            return ret;
     1587        }
     1588        rwlock.unlock();
     1589        rwlock.lockForRead();
     1590    }
     1591
     1592    if (!WaitForReadsAllowed())
     1593    {
     1594        VERBOSE(VB_FILE, LOC + loc_desc + ": !WaitForReadsAllowed()");
     1595        rwlock.unlock();
     1596        rwlock.lockForWrite();
    13061597        wanttoread = 0;
    1307         availWaitMutex.unlock();
     1598        stopreads = true;
     1599        rwlock.unlock();
     1600        return 0;
     1601    }
    13081602
    1309         avail = ReadBufAvail();
    1310         if ((ateof || setswitchtonext) && avail < count)
    1311             count = avail;
     1603    if (!WaitForAvail(count))
     1604    {
     1605        VERBOSE(VB_FILE, LOC + loc_desc + ": !WaitForAvail()");
     1606        rwlock.unlock();
     1607        rwlock.lockForWrite();
     1608        ateof = true;
     1609        wanttoread = 0;
     1610        stopreads = true;
     1611        rwlock.unlock();
     1612        return 0;
     1613    }
    13121614
    1313         if (commserror)
    1314             return 0;
     1615    count = min(ReadBufAvail(), count);
     1616
     1617    if (count <= 0)
     1618    {
     1619        // this can happen under a few conditions but the most
     1620        // notable is an exit from the read ahead thread or
     1621        // the end of the file stream has been reached.
     1622        VERBOSE(VB_FILE, LOC + loc_desc + ": ReadBufAvail() == 0");
     1623        rwlock.unlock();
     1624        return count;
    13151625    }
    13161626
    1317     if ((ateof || stopreads) && avail < count)
    1318         count = avail;
     1627    if (peek)
     1628        rbrlock.lockForRead();
     1629    else
     1630        rbrlock.lockForWrite();
    13191631
     1632    VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + " -- copying data");
     1633
    13201634    if (rbrpos + count > (int) kBufferSize)
    13211635    {
    13221636        int firstsize = kBufferSize - rbrpos;
     
    13261640        memcpy((char *)buf + firstsize, readAheadBuffer, secondsize);
    13271641    }
    13281642    else
     1643    {
    13291644        memcpy(buf, readAheadBuffer + rbrpos, count);
     1645    }
     1646    VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + QString(" -- checksum %1")
     1647            .arg(qChecksum((char*)buf,count)));
    13301648
    13311649    if (!peek)
    13321650    {
    1333         readAheadLock.lock();
    13341651        rbrpos = (rbrpos + count) % kBufferSize;
    1335         readAheadLock.unlock();
     1652        generalWait.wakeAll();
    13361653    }
     1654    rbrlock.unlock();
     1655    rwlock.unlock();
    13371656
    1338     if (readone)
    1339     {
    1340         Pause();
    1341         WaitForPause();
    1342     }
    1343 
    13441657    return count;
    13451658}
    13461659
     
    13541667 */
    13551668int RingBuffer::Read(void *buf, int count)
    13561669{
    1357     int ret = -1;
    1358     if (writemode)
     1670    int ret = ReadPriv(buf, count, false);
     1671    if (ret > 0)
    13591672    {
    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);
     1673        poslock.lockForWrite();
    13951674        readpos += ret;
     1675        poslock.unlock();
    13961676    }
    1397 
    1398     rwlock.unlock();
    13991677    return ret;
    14001678}
    14011679
    14021680/** \fn RingBuffer::IsIOBound(void) const
    1403  *  \brief Returns true if a RingBuffer::Read(void*,int) is likely to block.
     1681 *  \brief Returns true if a RingBuffer::Write(void*,int) is likely to block.
    14041682 */
    14051683bool RingBuffer::IsIOBound(void) const
    14061684{
     
    14291707 */
    14301708int RingBuffer::Write(const void *buf, uint count)
    14311709{
    1432     int ret = -1;
     1710    rwlock.lockForRead();
     1711
    14331712    if (!writemode)
    14341713    {
    14351714        VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file.");
    1436         return ret;
     1715        rwlock.unlock();
     1716        return -1;
    14371717    }
    14381718
    14391719    if (!tfw && !remotefile)
    1440         return ret;
     1720    {
     1721        rwlock.unlock();
     1722        return -1;
     1723    }
    14411724
    1442     rwlock.lockForRead();
    1443 
     1725    int ret = -1;
    14441726    if (tfw)
    14451727        ret = tfw->Write(buf, count);
    14461728    else
    14471729        ret = remotefile->Write(buf, count);
    1448     writepos += ret;
    14491730
     1731    if (ret > 0)
     1732    {
     1733        poslock.lockForWrite();
     1734        writepos += ret;
     1735        poslock.unlock();
     1736    }
     1737
    14501738    rwlock.unlock();
     1739
    14511740    return ret;
    14521741}
    14531742
     
    14561745 */
    14571746void RingBuffer::Sync(void)
    14581747{
     1748    rwlock.lockForRead();
    14591749    if (tfw)
    14601750        tfw->Sync();
     1751    rwlock.unlock();
    14611752}
    14621753
    1463 /** \fn RingBuffer::Seek(long long, int)
    1464  *  \brief Seeks to a particular position in the file.
     1754/** \brief Seeks to a particular position in the file.
    14651755 */
    1466 long long RingBuffer::Seek(long long pos, int whence)
     1756long long RingBuffer::Seek(long long pos, int whence, bool has_lock)
    14671757{
     1758    VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)")
     1759            .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET":
     1760                          ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END"))
     1761            .arg(has_lock?"locked":"unlocked"));
     1762
     1763    long long ret = -1;
     1764
     1765    StopReads();
     1766
     1767    // lockForWrite takes priority over lockForRead, so this will
     1768    // take priority over the lockForRead in the read ahead thread.
     1769    if (!has_lock)
     1770        rwlock.lockForWrite();
     1771
     1772    StartReads();
     1773
    14681774    if (writemode)
    1469         return WriterSeek(pos, whence);
     1775    {
     1776        ret = WriterSeek(pos, whence, true);
     1777        if (!has_lock)
     1778            rwlock.unlock();
     1779        return ret;
     1780    }
    14701781
    1471     wantseek = true;
    1472     rwlock.lockForWrite();
    1473     wantseek = false;
     1782    poslock.lockForWrite();
    14741783
    1475     // optimize nop seeks
    1476     if ((whence == SEEK_SET && pos == readpos) ||
    1477         (whence == SEEK_CUR && pos == 0))
     1784    // Optimize no-op seeks
     1785    if (readaheadrunning &&
     1786        ((whence == SEEK_SET && pos == readpos) ||
     1787         (whence == SEEK_CUR && pos == 0)))
    14781788    {
    1479         rwlock.unlock();
    1480         return readpos;
     1789        ret = readpos;
     1790
     1791        poslock.unlock();
     1792        if (!has_lock)
     1793            rwlock.unlock();
     1794
     1795        return ret;
    14811796    }
    14821797
    1483     errno = 0; // clear errno, in case of remotefile error
     1798    // only valid for SEEK_SET & SEEK_CUR
     1799    long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos;
    14841800
    1485     long long ret = -1;
     1801    // Optimize short seeks where the data for
     1802    // them is in our ringbuffer already.
     1803    if (readaheadrunning &&
     1804        (SEEK_SET==whence || SEEK_CUR==whence))
     1805    {
     1806        rbrlock.lockForWrite();
     1807        rbwlock.lockForRead();
     1808        VERBOSE(VB_FILE, LOC +
     1809                QString("Seek(): rbrpos: %1 rbwpos: %2"
     1810                        "\n\t\t\treadpos: %3 internalreadpos: %4")
     1811                .arg(rbrpos).arg(rbwpos)
     1812                .arg(readpos).arg(internalreadpos));
     1813        bool used_opt = false;
     1814        if ((new_pos < readpos))
     1815        {
     1816            int min_safety = max(fill_min, readblocksize);
     1817            int free = ((rbwpos >= rbrpos) ?
     1818                        rbrpos + kBufferSize : rbrpos) - rbwpos;
     1819            int internal_backbuf =
     1820                (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos;
     1821            internal_backbuf = min(internal_backbuf, free - min_safety);
     1822            long long sba = readpos - new_pos;
     1823            VERBOSE(VB_FILE, LOC +
     1824                    QString("Seek(): internal_backbuf: %1 sba: %2")
     1825                    .arg(internal_backbuf).arg(sba));
     1826            if (internal_backbuf >= sba)
     1827            {
     1828                rbrpos = (rbrpos>=sba) ? rbrpos - sba :
     1829                    kBufferSize + rbrpos - sba;
     1830                used_opt = true;
     1831                VERBOSE(VB_FILE, LOC +
     1832                        QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2"
     1833                                "\n\t\t\treadpos: %3 internalreadpos: %4")
     1834                        .arg(rbrpos).arg(rbwpos)
     1835                        .arg(new_pos).arg(internalreadpos));
     1836            }
     1837        }
     1838        else if ((new_pos >= readpos) && (new_pos <= internalreadpos))
     1839        {
     1840            rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize;
     1841            used_opt = true;
     1842            VERBOSE(VB_FILE, LOC +
     1843                    QString("Seek(): OPT2 rbrpos: %1 sba: %2")
     1844                    .arg(rbrpos).arg(readpos - new_pos));
     1845        }
     1846        rbwlock.unlock();
     1847        rbrlock.unlock();
     1848
     1849        if (used_opt)
     1850        {
     1851            if (ignorereadpos >= 0)
     1852            {
     1853                // seek should always succeed since we were at this position
     1854                int ret;
     1855                if (remotefile)
     1856                    ret = remotefile->Seek(internalreadpos, SEEK_SET);
     1857                else
     1858                    ret = lseek64(fd2, internalreadpos, SEEK_SET);
     1859                VERBOSE(VB_FILE, LOC +
     1860                        QString("Seek to %1 from ignore pos %2 returned %3")
     1861                        .arg(internalreadpos).arg(ignorereadpos).arg(ret));
     1862                ignorereadpos = -1;
     1863            }
     1864            readpos = new_pos;
     1865            poslock.unlock();
     1866            generalWait.wakeAll();
     1867            ateof = false;
     1868            readsallowed = false;
     1869            if (!has_lock)
     1870                rwlock.unlock();
     1871            return new_pos;
     1872        }
     1873    }
     1874
     1875    // This optimizes the seek end-250000, read, seek 0, read portion
     1876    // of the pattern ffmpeg performs at the start of playback to
     1877    // determine the pts.
     1878    // If the seek is a SEEK_END or is a seek where the position
     1879    // changes over 100 MB we check the file size and if the
     1880    // destination point is within 300000 bytes of the end of
     1881    // the file we enter a special mode where the read ahead
     1882    // buffer stops reading data and all reads are made directly
     1883    // until another seek is performed. The point of all this is
     1884    // to avoid flushing out the buffer that still contains all
     1885    // the data the final seek 0, read will need just to read the
     1886    // last 250000 bytes. A further optimization would be to buffer
     1887    // the 250000 byte read, which is currently performed in 32KB
     1888    // blocks (inefficient with RemoteFile).
     1889    if ((remotefile || fd2 >= 0) && (ignorereadpos < 0))
     1890    {
     1891        long long off_end = 0xDEADBEEF;
     1892        if (SEEK_END == whence)
     1893        {
     1894            off_end = pos;
     1895            if (remotefile)
     1896            {
     1897                new_pos = remotefile->GetFileSize() - off_end;
     1898            }
     1899            else
     1900            {
     1901                QFileInfo fi(filename);
     1902                new_pos = fi.size() - off_end;
     1903            }
     1904        }
     1905        else if (abs(new_pos-readpos) > 100000000)
     1906        {
     1907            if (remotefile)
     1908            {
     1909                off_end = remotefile->GetFileSize() - new_pos;
     1910            }
     1911            else
     1912            {
     1913                QFileInfo fi(filename);
     1914                off_end = fi.size() - new_pos;
     1915            }
     1916        }
     1917        if (off_end < 300000)
     1918        {
     1919            VERBOSE(VB_FILE, LOC +
     1920                    QString("Seek(): offset from end: %1").arg(off_end) +
     1921                    "\n\t\t\t -- ignoring read ahead thread until next seek.");
     1922
     1923            ignorereadpos = new_pos;
     1924            errno = EINVAL;
     1925            int ret;
     1926            if (remotefile)
     1927                ret = remotefile->Seek(ignorereadpos, SEEK_SET);
     1928            else
     1929                ret = lseek64(fd2, ignorereadpos, SEEK_SET);
     1930
     1931            if (ret < 0)
     1932            {
     1933                ignorereadpos = -1;
     1934                QString cmd = QString("Seek(%1, %2) ign ").arg(ignorereadpos)
     1935                    .arg((SEEK_SET == whence) ? "SEEK_SET" :
     1936                         ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));
     1937                VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
     1938                // try to return to former position..
     1939                if (remotefile)
     1940                    ret = remotefile->Seek(internalreadpos, SEEK_SET);
     1941                else
     1942                    ret = lseek64(fd2, internalreadpos, SEEK_SET);
     1943                if (ret < 0)
     1944                {
     1945                    QString cmd = QString("Seek(%1, %2) int ")
     1946                        .arg(internalreadpos)
     1947                        .arg((SEEK_SET == whence) ? "SEEK_SET" :
     1948                             ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));
     1949                    VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
     1950                }
     1951            }
     1952
     1953            rbwlock.unlock();
     1954            rbrlock.unlock();
     1955            poslock.unlock();
     1956
     1957            generalWait.wakeAll();
     1958
     1959            ateof = false;
     1960            readsallowed = false;
     1961
     1962            if (!has_lock)
     1963                rwlock.unlock();
     1964
     1965            return ret;
     1966        }
     1967    }
     1968
     1969    // Here we perform a normal seek. When successful we
     1970    // need to call ResetReadAhead(). A reset means we will
     1971    // need to refill the buffer, which takes some time.
    14861972    if (remotefile)
     1973    {
    14871974        ret = remotefile->Seek(pos, whence, readpos);
     1975        if (ret<0)
     1976            errno = EINVAL;
     1977    }
    14881978#ifdef USING_FRONTEND
     1979    else if ((dvdPriv || bdPriv) && (SEEK_END == whence))
     1980    {
     1981        errno = EINVAL;
     1982        ret = -1;
     1983    }
    14891984    else if (dvdPriv)
    14901985    {
    1491         dvdPriv->NormalSeek(pos);
    1492         ret = pos;
     1986        dvdPriv->NormalSeek(new_pos);
     1987        ret = new_pos;
    14931988    }
    14941989    else if (bdPriv)
    14951990    {
    1496         bdPriv->Seek(pos);
    1497         ret = pos;
     1991        bdPriv->Seek(new_pos);
     1992        ret = new_pos;
    14981993    }
    14991994#endif // USING_FRONTEND
    15001995    else
    15011996    {
    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         }
     1997        ret = lseek64(fd2, pos, whence);
    15171998    }
    15181999
    15192000    if (ret >= 0)
    15202001    {
    15212002        readpos = ret;
     2003       
     2004        ignorereadpos = -1;
    15222005
    15232006        if (readaheadrunning)
    15242007            ResetReadAhead(readpos);
     
    15332016        VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
    15342017    }
    15352018
    1536     rwlock.unlock();
     2019    poslock.unlock();
    15372020
     2021    generalWait.wakeAll();
     2022
     2023    if (!has_lock)
     2024        rwlock.unlock();
     2025
    15382026    return ret;
    15392027}
    15402028
    1541 /** \fn RingBuffer::WriterSeek(long long, int)
    1542  *  \brief Calls ThreadedFileWriter::Seek(long long,int).
     2029/** \brief Calls ThreadedFileWriter::Seek(long long,int).
    15432030 */
    1544 long long RingBuffer::WriterSeek(long long pos, int whence)
     2031long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock)
    15452032{
    15462033    long long ret = -1;
    15472034
     2035    if (!has_lock)
     2036        rwlock.lockForRead();
     2037
     2038    poslock.lockForWrite();
     2039
    15482040    if (tfw)
    15492041    {
    15502042        ret = tfw->Seek(pos, whence);
    15512043        writepos = ret;
    15522044    }
    15532045
     2046    poslock.unlock();
     2047
     2048    if (!has_lock)
     2049        rwlock.unlock();
     2050
    15542051    return ret;
    15552052}
    15562053
     
    15602057 */
    15612058void RingBuffer::WriterFlush(void)
    15622059{
     2060    rwlock.lockForRead();
    15632061    if (tfw)
    15642062    {
    15652063        tfw->Flush();
    15662064        tfw->Sync();
    15672065    }
     2066    rwlock.unlock();
    15682067}
    15692068
    15702069/** \fn RingBuffer::SetWriteBufferSize(int)
     
    15722071 */
    15732072void RingBuffer::SetWriteBufferSize(int newSize)
    15742073{
     2074    rwlock.lockForRead();
    15752075    if (tfw)
    15762076        tfw->SetWriteBufferSize(newSize);
     2077    rwlock.unlock();
    15772078}
    15782079
    15792080/** \fn RingBuffer::SetWriteBufferMinWriteSize(int)
     
    15812082 */
    15822083void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize)
    15832084{
     2085    rwlock.lockForRead();
    15842086    if (tfw)
    15852087        tfw->SetWriteBufferMinWriteSize(newMinSize);
     2088    rwlock.unlock();
    15862089}
    15872090
     2091/** \brief Tell RingBuffer if this is an old file or not.
     2092 *
     2093 *  Normally the RingBuffer determines that the file is old
     2094 *  if it has not been modified in the last minute. This
     2095 *  allows one to override that determination externally.
     2096 *
     2097 *  If for instance you are slowly writing to the file you
     2098 *  could call this with the value of false. If you just
     2099 *  finished writing the file you could call it with the
     2100 *  value true. Knowing that the file is old allows MythTV
     2101 *  to determine that a read at the end of the file is
     2102 *  really an end-of-file condition more quickly. But if
     2103 *  the file is growing it can also cause the RingBuffer to
     2104 *  report an end-of-file condition prematurely.
     2105 */
     2106void RingBuffer::SetOldFile(bool is_old)
     2107{
     2108    rwlock.lockForWrite();
     2109    oldfile = is_old;
     2110    rwlock.unlock();
     2111}
     2112
     2113// This appears to allow direct access to the DVD/BD device
     2114// when called with false (the default value), and enable
     2115// the ring buffer when called with true. But I'm not entirely
     2116// certain. -- dtk 2010-08-26
     2117void RingBuffer::SetStreamOnly(bool stream)
     2118{
     2119    rwlock.lockForWrite();
     2120    streamOnly = stream;
     2121    rwlock.unlock();
     2122}
     2123
     2124/// Returns name of file used by this RingBuffer
     2125QString RingBuffer::GetFilename(void) const
     2126{
     2127    rwlock.lockForRead();
     2128    QString tmp = filename;
     2129    tmp.detach();
     2130    rwlock.unlock();
     2131    return tmp;
     2132}
     2133
     2134QString RingBuffer::GetSubtitleFilename(void) const
     2135{
     2136    rwlock.lockForRead();
     2137    QString tmp = subtitlefilename;
     2138    tmp.detach();
     2139    rwlock.unlock();
     2140    return tmp;
     2141}
     2142
    15882143/** \fn RingBuffer::GetReadPosition(void) const
    15892144 *  \brief Returns how far into the file we have read.
    15902145 */
    15912146long long RingBuffer::GetReadPosition(void) const
    15922147{
     2148    rwlock.lockForRead();
     2149    poslock.lockForRead();
     2150    long long ret = readpos;
    15932151#ifdef USING_FRONTEND
    15942152    if (dvdPriv)
    1595         return dvdPriv->GetReadPosition();
     2153        ret = dvdPriv->GetReadPosition();
    15962154    else if (bdPriv)
    1597         return bdPriv->GetReadPosition();
     2155        ret = bdPriv->GetReadPosition();
    15982156#endif // USING_FRONTEND
    1599 
    1600     return readpos;
     2157    poslock.unlock();
     2158    rwlock.unlock();
     2159    return ret;
    16012160}
    16022161
    16032162/** \fn RingBuffer::GetWritePosition(void) const
     
    16052164 */
    16062165long long RingBuffer::GetWritePosition(void) const
    16072166{
    1608     return writepos;
     2167    poslock.lockForRead();
     2168    long long ret = writepos;
     2169    poslock.unlock();
     2170    return ret;
    16092171}
    16102172
    16112173/** \fn RingBuffer::GetRealFileSize(void) const
     
    16142176 */
    16152177long long RingBuffer::GetRealFileSize(void) const
    16162178{
     2179    rwlock.lockForRead();
     2180    long long ret = -1;
    16172181    if (remotefile)
    1618         return remotefile->GetFileSize();
    1619 
    1620     QFileInfo info(filename);
    1621     return info.size();
     2182        ret = remotefile->GetFileSize();
     2183    else
     2184        ret = QFileInfo(filename).size();
     2185    rwlock.unlock();
     2186    return ret;
    16222187}
    16232188
    16242189/** \fn RingBuffer::LiveMode(void) const
     
    16272192 */
    16282193bool RingBuffer::LiveMode(void) const
    16292194{
    1630     return (livetvchain);
     2195    rwlock.lockForRead();
     2196    bool ret = (livetvchain);
     2197    rwlock.unlock();
     2198    return ret;
    16312199}
    16322200
    16332201/** \fn RingBuffer::SetLiveMode(LiveTVChain*)
     
    16362204 */
    16372205void RingBuffer::SetLiveMode(LiveTVChain *chain)
    16382206{
     2207    rwlock.lockForWrite();
    16392208    livetvchain = chain;
     2209    rwlock.unlock();
    16402210}
    16412211
     2212/// Tells RingBuffer whether to igonre the end-of-file
     2213void RingBuffer::IgnoreLiveEOF(bool ignore)
     2214{
     2215    rwlock.lockForWrite();
     2216    ignoreliveeof = ignore;
     2217    rwlock.unlock();
     2218}
     2219
     2220/// Returns true if this is a DVD backed RingBuffer.
     2221bool RingBuffer::IsDVD(void) const
     2222{
     2223    rwlock.lockForRead();
     2224    bool ret = dvdPriv;
     2225    rwlock.unlock();
     2226    return ret;
     2227}
     2228
    16422229bool RingBuffer::InDVDMenuOrStillFrame(void)
    16432230{
     2231    rwlock.lockForRead();
     2232    bool ret = false;
    16442233#ifdef USING_FRONTEND
    16452234    if (dvdPriv)
    1646         return (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
     2235        ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
    16472236#endif // USING_FRONTEND
    1648     return false;
     2237    rwlock.unlock();
     2238    return ret;
    16492239}
    16502240
     2241/// Returns true if this is a Blu-ray backed RingBuffer.
     2242bool RingBuffer::IsBD(void) const
     2243{
     2244    rwlock.lockForRead();
     2245    bool ret = bdPriv;
     2246    rwlock.unlock();
     2247    return ret;
     2248}
     2249
    16512250/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/tv_play.cpp

     
    19701970                    .arg(playbackURL).arg(ctx->tvchain->GetCardType(-1)));
    19711971
    19721972            ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true,
    1973                                       opennow ? 12 : (uint)-1));
     1973                                              opennow ? 2000 : -1));
    19741974            ctx->buffer->SetLiveMode(ctx->tvchain);
    19751975        }
    19761976
     
    63646364            QString playbackURL = ctx->playingInfo->GetPlaybackURL(true);
    63656365            bool opennow = (ctx->tvchain->GetCardType(-1) != "DUMMY");
    63666366            ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true,
    6367                                               opennow ? 12 : (uint)-1));
     6367                                              opennow ? 2000 : -1));
    63686368
    63696369            ctx->tvchain->SetProgram(*ctx->playingInfo);
    63706370            ctx->buffer->SetLiveMode(ctx->tvchain);
  • 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    DVDRingBufferPriv *dvdPriv;   // not protected by rwlock, when DVD() is used
     188    BDRingBufferPriv  *bdPriv;    // protected by rwlock
    178189
    179     QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex
    180     QMutex readsAllowedWaitMutex;
     190    bool oldfile;                 // protected by rwlock
    181191
    182     int numfailures;              // not protected by a lock MR
     192    LiveTVChain *livetvchain;     // protected by rwlock
     193    bool ignoreliveeof;           // protected by rwlock
    183194
    184     bool commserror;              // not protected by a lock MR
     195    long long readAdjust;         // protected by rwlock
    185196
    186     DVDRingBufferPriv *dvdPriv;   // not protected by a lock LR
    187     BDRingBufferPriv  *bdPriv;    // not protected by a lock LR
     197    // note 1: numfailures is modified with only a read lock in the
     198    // read ahead thread, but this is safe since all other places
     199    // that use it are protected by a write lock. But this is a
     200    // fragile state of affairs and care must be taken when modifying
     201    // code or locking around this variable.
    188202
    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 
    196203    /// Condition to signal that the read ahead thread is running
    197     QWaitCondition readAheadRunningCond;//protected by readAheadRunningCondLock
    198     QMutex readAheadRunningCondLock;
     204    QWaitCondition generalWait;         // protected by rwlock
    199205
    200206  public:
    201207    static QMutex subExtLock;
     
    208214    static const uint kReadTestSize;
    209215};
    210216
    211 #endif
     217#endif // _RINGBUFFER_H_
  • libs/libmythtv/mythplayer.cpp

     
    893893
    894894void MythPlayer::OpenDummy(void)
    895895{
     896    VERBOSE(VB_IMPORTANT, LOC + "OpenDummy()");
     897
    896898    isDummy = true;
    897899
    898900    float displayAspect =
     
    936938    SetDecoder(NULL);
    937939    int testreadsize = 2048;
    938940
     941    MythTimer bigTimer; bigTimer.start();
     942    int timeout = (retries + 1) * 500;
    939943    while (testreadsize <= kDecoderProbeBufferSize)
    940944    {
    941         if (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize)
     945        MythTimer peekTimer; peekTimer.start();
     946        while (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize)
    942947        {
    943             VERBOSE(VB_IMPORTANT, LOC_ERR +
    944                     QString("OpenFile(): Error, couldn't read file: %1")
    945                     .arg(player_ctx->buffer->GetFilename()));
    946             return -1;
     948            if (peekTimer.elapsed() > 1000 || bigTimer.elapsed() > timeout)
     949            {
     950                VERBOSE(VB_IMPORTANT, LOC_ERR +
     951                        QString("OpenFile(): Could not read "
     952                                "first %1 bytes of '%2'")
     953                        .arg(testreadsize)
     954                        .arg(player_ctx->buffer->GetFilename()));
     955                return -1;
     956            }
     957            VERBOSE(VB_IMPORTANT, LOC_WARN + "OpenFile() waiting on data");
     958            usleep(50 * 1000);
    947959        }
    948960
    949961        player_ctx->LockPlayingInfo(__FILE__, __LINE__);
     
    960972                                           player_ctx->GetSpecialDecode()));
    961973        }
    962974        player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    963         if (GetDecoder())
     975        if (GetDecoder() || (bigTimer.elapsed() > timeout))
    964976            break;
    965977        testreadsize <<= 1;
    966978    }
     
    21682180        return;
    21692181    }
    21702182
    2171     uint retries = 10; // about 5 seconds of retries
    2172     player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL(), retries);
     2183    player_ctx->buffer->OpenFile(
     2184        pginfo->GetPlaybackURL(), RingBuffer::kDefaultOpenTimeout);
    21732185
    21742186    if (!player_ctx->buffer->IsOpen())
    21752187    {
    2176         VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed.");
     2188        VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed " +
     2189                QString("(card type: %1).")
     2190                .arg(player_ctx->tvchain->GetCardType(newid)));
     2191        VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
    21772192        eof = true;
    21782193        SetErrored(QObject::tr("Error opening switch program buffer"));
    21792194        delete pginfo;
     
    22902305
    22912306    SendMythSystemPlayEvent("PLAY_CHANGED", pginfo);
    22922307
    2293     player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL());
     2308    player_ctx->buffer->OpenFile(
     2309        pginfo->GetPlaybackURL(), RingBuffer::kDefaultOpenTimeout);
     2310
    22942311    if (!player_ctx->buffer->IsOpen())
    22952312    {
    2296         VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed.");
     2313        VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed " +
     2314                QString("(card type: %1).")
     2315                .arg(player_ctx->tvchain->GetCardType(newid)));
     2316        VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
     2317
    22972318        eof = true;
    22982319        SetErrored(QObject::tr("Error opening jump program file buffer"));
    22992320        delete pginfo;
     
    31903211    if (!videoOutput)
    31913212        return false;
    31923213
    3193     int    sz              = player_ctx->buffer->DataInReadAhead();
    3194     uint   rbs             = player_ctx->buffer->GetReadBlockSize();
    3195     uint   kbits_per_sec   = player_ctx->buffer->GetBitrate();
    3196     uint   vvf             = videoOutput->ValidVideoFrames();
    3197     double inv_fps         = 1.0 / GetDecoder()->GetFPS();
    3198     double bytes_per_frame = kbits_per_sec * (1000.0/8.0) * inv_fps;
    3199     double rh_frames       = sz / bytes_per_frame;
    3200 
    3201     // WARNING: rh_frames can greatly overestimate or underestimate
    3202     //          the number of frames available in the read ahead buffer
    3203     //          when rh_frames is less than the keyframe distance.
    3204 
    3205     bool near_end = ((vvf + rh_frames) < 10.0) || (sz < rbs*1.5);
    3206 
    3207     VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
    3208             <<" br("<<(kbits_per_sec/8)<<"KB)"
    3209             <<" fps("<<((uint)(1.0/inv_fps))<<")"
    3210             <<" sz("<<(sz / 1000)<<"KB)"
    3211             <<" vfl("<<vvf<<")"
    3212             <<" frh("<<((uint)rh_frames)<<")"
    3213             <<" ne:"<<near_end);
    3214 
    3215     return near_end;
     3214    return player_ctx->buffer->IsNearEnd(
     3215        GetDecoder()->GetFPS(),
     3216        videoOutput->ValidVideoFrames());
    32163217}
    32173218
    32183219/** \brief Returns true iff near end of recording.
  • 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

     
    1212#include "compat.h"
    1313
    1414RemoteFile::RemoteFile(const QString &_path, bool write, bool useRA,
    15                        int _retries,
     15                       int _timeout_ms,
    1616                       const QStringList *possibleAuxiliaryFiles) :
    1717    path(_path),
    18     usereadahead(useRA),  retries(_retries),
     18    usereadahead(useRA),  timeout_ms(_timeout_ms),
    1919    filesize(-1),         timeoutisfast(false),
    2020    readposition(0),      recordernum(0),
    2121    lock(QMutex::NonRecursive),
     
    2626    if (writemode)
    2727    {
    2828        usereadahead = false;
    29         retries = -1;
     29        timeout_ms = -1;
    3030    }
    3131    else if (possibleAuxiliaryFiles)
    3232        possibleauxfiles = *possibleAuxiliaryFiles;
     
    106106    }
    107107    else
    108108    {
    109         strlist.append( QString("ANN FileTransfer %1 %2 %3 %4")
    110             .arg(hostname).arg(writemode).arg(usereadahead).arg(retries) );
     109        strlist.push_back(QString("ANN FileTransfer %1 %2 %3 %4")
     110                          .arg(hostname).arg(writemode)
     111                          .arg(usereadahead).arg(timeout_ms));
    111112        strlist << QString("%1").arg(dir);
    112113        strlist << sgroup;
    113114
  • 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

     
    12451245        FileTransfer *ft = NULL;
    12461246        bool writemode = false;
    12471247        bool usereadahead = true;
    1248         int retries = -1;
     1248        int timeout_ms = 2000;
    12491249        if (commands.size() > 3)
    12501250            writemode = commands[3].toInt();
    12511251
     
    12531253            usereadahead = commands[4].toInt();
    12541254
    12551255        if (commands.size() > 5)
    1256             retries = commands[5].toInt();
     1256            timeout_ms = commands[5].toInt();
    12571257
    12581258        if (writemode)
    12591259        {
     
    12981298        else
    12991299            filename = LocalFilePath(qurl, wantgroup);
    13001300
    1301         if (retries < 0)
    1302             ft = new FileTransfer(filename, socket, writemode);
    1303         else
    1304             ft = new FileTransfer(filename, socket, usereadahead, retries);
     1301        ft = new FileTransfer(filename, socket, usereadahead, timeout_ms);
    13051302
    13061303        sockListLock.lockForWrite();
    13071304        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; }