Ticket #8812: 8812-v10.patch

File 8812-v10.patch, 77.7 KB (added by danielk, 10 years ago)

Updated patch

  • 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;
    4849
    4950#define CHUNK 32768 /* readblocksize increments */
    5051
     
    6566
    6667/*
    6768  Locking relations:
    68     rwlock->readAheadLock
    69           ->readsAllowedWaitMutex->readAheadRunningCondLock
    70           ->availWaitMutex
     69    rwlock->poslock->rbrlock->rbwlock
    7170
    7271  A child should never lock any of the parents without locking
    7372  the parent lock before the child lock.
    7473  void RingBuffer::Example1()
    7574  {
    76       QMutexLocker locker1(&readAheadRunningCondLock);
    77       QMutexLocker locker2(&readsAllowedWaitMutex); // error!
     75      poslock.lockForWrite();
     76      rwlock.lockForRead(); // error!
    7877      blah(); // <- does not implicitly aquire any locks
     78      rwlock.unlock();
     79      poslock.unlock();
    7980  }
    8081  void RingBuffer::Example2()
    8182  {
    82       QMutexLocker locker1(&readsAllowedWaitMutex);
    83       QMutexLocker locker2(&readAheadRunningCondLock); // ok!
     83      rwlock.lockForRead();
     84      rbrlock.lockForWrite(); // ok!
    8485      blah(); // <- does not implicitly aquire any locks
     86      rbrlock.unlock();
     87      rwlock.unlock();
    8588  }
    8689*/
    8790
     
    113116RingBuffer::RingBuffer(const QString &lfilename,
    114117                       bool write, bool readahead,
    115118                       uint read_retries)
    116     : filename(lfilename),      subtitlefilename(QString::null),
     119    : readpos(0),               writepos(0),
     120      internalreadpos(0),       ignorereadpos(-1),
     121      rbrpos(0),                rbwpos(0),
     122      stopreads(false),
     123      filename(lfilename),      subtitlefilename(QString::null),
    117124      tfw(NULL),                fd2(-1),
    118       writemode(false),
    119       readpos(0),               writepos(0),
    120       stopreads(false),         remotefile(NULL),
     125      writemode(false),         remotefile(NULL),
    121126      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),
     127      readaheadrunning(false),  reallyrunning(false),
     128      request_pause(false),     paused(false),
     129      ateof(false),             readsallowed(false),
     130      setswitchtonext(false),   streamOnly(false),
     131      rawbitrate(8000),         playspeed(1.0f),
    129132      fill_threshold(65536),    fill_min(-1),
    130133      readblocksize(CHUNK),     wanttoread(0),
    131134      numfailures(0),           commserror(false),
     
    263266    return QString::null;
    264267}
    265268
    266 /** \fn RingBuffer::OpenFile(const QString&, uint)
    267  *  \brief Opens a file for reading.
     269/** \brief Opens a file for reading.
    268270 *
    269271 *  \param lfilename  Name of file to read
    270  *  \param retryCount How often to retry reading the file before giving up
     272 *  \param retryTime  How many ms to retry reading the file before giving up
    271273 */
    272 void RingBuffer::OpenFile(const QString &lfilename, uint retryCount)
     274void RingBuffer::OpenFile(const QString &lfilename, uint retry_ms)
    273275{
    274     VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2)")
    275             .arg(lfilename).arg(retryCount));
     276    VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 ms)")
     277            .arg(lfilename).arg(retry_ms));
    276278
    277     uint openAttempts = retryCount + 1;
     279    rwlock.lockForWrite();
    278280
    279281    filename = lfilename;
    280282
     
    365367    if (is_local)
    366368    {
    367369        char buf[kReadTestSize];
    368         int timetowait = 500 * openAttempts;
    369370        int lasterror = 0;
    370371
    371372        MythTimer openTimer;
    372373        openTimer.start();
    373374
    374         while (openTimer.elapsed() < timetowait)
     375        uint openAttempts = 0;
     376        while ((uint)openTimer.elapsed() < retry_ms)
    375377        {
     378            openAttempts++;
    376379            lasterror = 0;
    377380            QByteArray fname = filename.toLocal8Bit();
    378381            fd2 = open(fname.constData(),
     
    381384            if (fd2 < 0)
    382385            {
    383386                if (!check_permissions(filename))
     387                {
     388                    lasterror = 3;
    384389                    break;
     390                }
    385391
    386392                lasterror = 1;
    387                 usleep(1000);
     393                usleep(10 * 1000);
    388394            }
    389395            else
    390396            {
     
    394400                    lasterror = 2;
    395401                    close(fd2);
    396402                    fd2 = -1;
    397                     usleep(1000);
     403                    usleep(10 * 1000);
    398404                }
    399405                else
    400406                {
    401                     lseek(fd2, 0, SEEK_SET);
     407                    if (0 == lseek(fd2, 0, SEEK_SET))
     408                    {
    402409#if HAVE_POSIX_FADVISE
    403                     posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL);
     410                        posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL);
    404411#endif
    405                     openAttempts = 0;
    406                     break;
     412                        lasterror = 0;
     413                        break;
     414                    }
     415                    close(fd2);
     416                    fd2 = -1;
    407417                }
    408418            }
    409419        }
    410420
    411421        switch (lasterror)
    412422        {
     423            case 0:
     424            {
     425                QFileInfo fi(filename);
     426                oldfile = fi.lastModified()
     427                    .secsTo(QDateTime::currentDateTime()) > 60;
     428                QString extension = fi.completeSuffix().toLower();
     429                if (is_subtitle_possible(extension))
     430                    subtitlefilename = local_sub_filename(fi);
     431                break;
     432            }
    413433            case 1:
    414                 VERBOSE(VB_IMPORTANT, LOC +
    415                         QString("Could not open %1.").arg(filename));
     434                VERBOSE(VB_IMPORTANT, LOC_ERR +
     435                        QString("OpenFile(): Could not open."));
    416436                break;
    417437            case 2:
    418                 VERBOSE(VB_IMPORTANT, LOC +
    419                         QString("Invalid file (fd %1) when opening '%2'.")
    420                         .arg(fd2).arg(filename));
     438                VERBOSE(VB_IMPORTANT, LOC_ERR +
     439                        QString("OpenFile(): File too small (%1B).")
     440                        .arg(QFileInfo(filename).size()));
    421441                break;
     442            case 3:
     443                VERBOSE(VB_IMPORTANT, LOC_ERR +
     444                        "OpenFile(): Improper permissions.");
     445                break;
    422446            default:
    423447                break;
    424448        }
     449        VERBOSE(VB_FILE, LOC + QString("OpenFile() made %1 attempts in %2 ms")
     450                .arg(openAttempts).arg(openTimer.elapsed()));
    425451
    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);
    437452    }
    438453#ifdef USING_FRONTEND
    439454    else if (is_dvd)
    440455    {
    441456        dvdPriv->OpenFile(filename);
    442         rwlock.lockForWrite();
    443457        readblocksize = DVD_BLOCK_SIZE * 62;
    444         rwlock.unlock();
    445458    }
    446459    else if (is_bd)
    447460    {
    448461        bdPriv->OpenFile(filename);
    449         rwlock.lockForWrite();
    450462        readblocksize = BD_BLOCK_SIZE * 62;
    451         rwlock.unlock();
    452463    }
    453464#endif // USING_FRONTEND
    454465    else
     
    484495        remotefile = new RemoteFile(filename, false, true, -1, &auxFiles);
    485496        if (!remotefile->isOpen())
    486497        {
    487             VERBOSE(VB_IMPORTANT,
     498            VERBOSE(VB_IMPORTANT, LOC_ERR +
    488499                    QString("RingBuffer::RingBuffer(): Failed to open remote "
    489500                            "file (%1)").arg(filename));
    490501            delete remotefile;
     
    503514    commserror = false;
    504515    numfailures = 0;
    505516
    506     UpdateRawBitrate(4000);
     517    rawbitrate = 8000;
     518    CalcReadAheadThresh();
     519
     520    rwlock.unlock();
    507521}
    508522
    509523/** \fn RingBuffer::IsOpen(void) const
     
    511525 */
    512526bool RingBuffer::IsOpen(void) const
    513527{
     528    rwlock.lockForRead();
     529    bool ret;
    514530#ifdef USING_FRONTEND
    515     return tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
     531    ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
    516532           (bdPriv && bdPriv->IsOpen());
    517533#else // if !USING_FRONTEND
    518     return tfw || (fd2 > -1) || remotefile;
     534    ret = tfw || (fd2 > -1) || remotefile;
    519535#endif // !USING_FRONTEND
     536    rwlock.unlock();
     537    return ret;
    520538}
    521539
    522540/** \fn RingBuffer::~RingBuffer(void)
     
    560578    rwlock.unlock();
    561579}
    562580
    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 
    576581/** \fn RingBuffer::Reset(bool, bool, bool)
    577582 *  \brief Resets the read-ahead thread and our position in the file
    578583 */
    579584void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal)
    580585{
    581     wantseek = true;
     586    VERBOSE(VB_FILE, LOC + QString("Reset(%1,%2,%3)")
     587            .arg(full).arg(toAdjust).arg(resetInternal));
     588
    582589    rwlock.lockForWrite();
    583     wantseek = false;
     590    poslock.lockForWrite();
     591
    584592    numfailures = 0;
    585593    commserror = false;
    586594    setswitchtonext = false;
     
    590598
    591599    if (readpos != 0)
    592600    {
    593         VERBOSE(VB_IMPORTANT, QString(
     601        VERBOSE(VB_IMPORTANT, LOC + QString(
    594602                "RingBuffer::Reset() nonzero readpos.  toAdjust: %1 readpos: %2"
    595603                " readAdjust: %3").arg(toAdjust).arg(readpos).arg(readAdjust));
    596604    }
     
    604612    if (resetInternal)
    605613        internalreadpos = readpos;
    606614
     615    generalWait.wakeAll();
     616    poslock.unlock();
    607617    rwlock.unlock();
    608618}
    609619
     
    625635    unsigned errcnt = 0;
    626636    unsigned zerocnt = 0;
    627637
    628     if (fd < 0)
     638    if (fd2 < 0)
    629639    {
    630640        VERBOSE(VB_IMPORTANT, LOC_ERR +
    631641                "Invalid file descriptor in 'safe_read()'");
     
    637647
    638648    while (tot < sz)
    639649    {
    640         ret = read(fd, (char *)data + tot, sz - tot);
     650        ret = read(fd2, (char *)data + tot, sz - tot);
    641651        if (ret < 0)
    642652        {
    643653            if (errno == EAGAIN)
     
    699709        VERBOSE(VB_IMPORTANT, LOC_ERR +
    700710                "RingBuffer::safe_read(RemoteFile* ...): read failed");
    701711
     712        poslock.lockForRead();
    702713        rf->Seek(internalreadpos - readAdjust, SEEK_SET);
     714        poslock.unlock();
    703715        ret = 0;
    704716        numfailures++;
    705717     }
     
    714726 */
    715727void RingBuffer::UpdateRawBitrate(uint raw_bitrate)
    716728{
     729    VERBOSE(VB_FILE, LOC + QString("UpdateRawBitrate(%1Kb)").arg(raw_bitrate));
     730    if (raw_bitrate < 2500)
     731    {
     732        VERBOSE(VB_FILE, LOC +
     733                QString("UpdateRawBitrate(%1Kb) - ignoring bitrate,")
     734                .arg(raw_bitrate) +
     735                "\n\t\t\tappears to be abnormally low.");
     736        return;
     737    }
     738
    717739    rwlock.lockForWrite();
    718740    rawbitrate = raw_bitrate;
    719741    CalcReadAheadThresh();
    720742    rwlock.unlock();
    721743}
    722744
    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 
    748745/** \fn RingBuffer::UpdatePlaySpeed(float)
    749746 *  \brief Set the play speed, to allow RingBuffer adjust effective bitrate.
    750747 *  \param play_speed Speed to set. (1.0 for normal speed)
     
    768765{
    769766    uint estbitrate = 0;
    770767
    771     wantseek       = false;
    772768    readsallowed   = false;
    773     readblocksize  = CHUNK;
     769    readblocksize  = max(readblocksize, CHUNK);
    774770
    775771    // loop without sleeping if the buffered data is less than this
    776     fill_threshold = CHUNK * 2;
    777     fill_min       = 1;
     772    fill_threshold = kBufferSize / 8;
    778773
    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;
     774    const uint KB32  =  32*1024;
     775    const uint KB64  =  64*1024;
     776    const uint KB128 = 128*1024;
     777    const uint KB256 = 256*1024;
     778    const uint KB512 = 512*1024;
    787779
    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;
     780    estbitrate     = (uint) max(abs(rawbitrate * playspeed),
     781                                0.5f * rawbitrate);
     782    estbitrate     = min(rawbitrate * 3, estbitrate);
     783    int rbs        = (estbitrate > 2500)  ? KB64  : KB32;
     784    rbs            = (estbitrate > 5000)  ? KB128 : rbs;
     785    rbs            = (estbitrate > 9000)  ? KB256 : rbs;
     786    rbs            = (estbitrate > 18000) ? KB512 : rbs;
     787    readblocksize  = max(rbs,readblocksize);
    795788
    796         // minumum seconds of buffering before allowing read
    797         float secs_min = 0.1;
     789    // minumum seconds of buffering before allowing read
     790    float secs_min = 0.25;
     791    // set the minimum buffering before allowing ffmpeg read
     792    fill_min        = (uint) ((estbitrate * secs_min) * 0.125f);
     793    // make this a multiple of ffmpeg block size..
     794    fill_min        = ((fill_min / KB32) + 1) * KB32;
    798795
    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 -> "
     796    VERBOSE(VB_FILE, LOC +
     797            QString("CalcReadAheadThresh(%1 Kb)\n\t\t\t -> "
    808798                    "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)")
    809799            .arg(estbitrate).arg(fill_threshold/1024)
    810800            .arg(fill_min/1024).arg(readblocksize/1024));
    811801}
    812802
    813 /** \fn RingBuffer::ReadBufFree(void) const
    814  *  \brief Returns number of bytes available for reading into buffer.
    815  */
     803bool RingBuffer::IsNearEnd(double fps, uint vvf) const
     804{
     805    rwlock.lockForRead();
     806    int    sz  = ReadBufAvail();
     807    uint   rbs = readblocksize;
     808    // telecom kilobytes (i.e. 1000 per k not 1024)
     809    uint   tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
     810    uint   kbits_per_sec = min(rawbitrate * 3, tmp);
     811    rwlock.unlock();
     812
     813    // WARNING: readahead_frames can greatly overestimate or underestimate
     814    //          the number of frames available in the read ahead buffer
     815    //          when rh_frames is less than the keyframe distance.
     816    double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps;
     817    double readahead_frames = sz / bytes_per_frame;
     818
     819    bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5);
     820
     821    VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
     822            <<" br("<<(kbits_per_sec/8)<<"KB)"
     823            <<" sz("<<(sz / 1000)<<"KB)"
     824            <<" vfl("<<vvf<<")"
     825            <<" frh("<<((uint)readahead_frames)<<")"
     826            <<" ne:"<<near_end);
     827
     828    return near_end;
     829}
     830
     831/// \brief Returns number of bytes available for reading into buffer.
     832/// WARNING: Must be called with rwlock in locked state.
    816833int RingBuffer::ReadBufFree(void) const
    817834{
    818     QMutexLocker locker(&readAheadLock);
    819     return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     835    rbrlock.lockForRead();
     836    rbwlock.lockForRead();
     837    int ret = ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     838    rbwlock.unlock();
     839    rbrlock.unlock();
     840    return ret;
    820841}
    821842
    822 /** \fn RingBuffer::ReadBufAvail(void) const
    823  *  \brief Returns number of bytes available for reading from buffer.
    824  */
     843/// \brief Returns number of bytes available for reading from buffer.
     844/// WARNING: Must be called with rwlock in locked state.
    825845int RingBuffer::ReadBufAvail(void) const
    826846{
    827     QMutexLocker locker(&readAheadLock);
    828     return (rbwpos >= rbrpos) ?
    829         rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     847    rbrlock.lockForRead();
     848    rbwlock.lockForRead();
     849    int ret = (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     850    rbwlock.unlock();
     851    rbrlock.unlock();
     852    return ret;
    830853}
    831854
    832855/** \fn RingBuffer::ResetReadAhead(long long)
     
    836859 *   buffer doesn't contain any stale data, and so that it will read
    837860 *   any new data from the new position in the file.
    838861 *
    839  *   WARNING: Must be called with rwlock in write lock state.
     862 *   WARNING: Must be called with rwlock and poslock in write lock state.
    840863 *
    841864 *  \param newinternal Position in file to start reading data from
    842865 */
    843866void RingBuffer::ResetReadAhead(long long newinternal)
    844867{
    845     readAheadLock.lock();
    846     readblocksize = CHUNK;
     868    VERBOSE(VB_FILE, LOC + QString("ResetReadAhead(internalreadpos = %1->%2)")
     869            .arg(internalreadpos).arg(newinternal));
     870
     871    rbrlock.lockForWrite();
     872    rbwlock.lockForWrite();
     873
     874    CalcReadAheadThresh();
    847875    rbrpos = 0;
    848876    rbwpos = 0;
    849877    internalreadpos = newinternal;
    850878    ateof = false;
    851879    readsallowed = false;
    852880    setswitchtonext = false;
    853     readAheadLock.unlock();
     881    generalWait.wakeAll();
     882
     883    rbwlock.unlock();
     884    rbrlock.unlock();
    854885}
    855886
    856 /** \fn RingBuffer::StartupReadAheadThread(void)
    857  *  \brief Creates the read-ahead thread, and waits for it to start.
     887/**
     888 *  \brief Starts the read-ahead thread.
    858889 *
    859  *  \sa Start(void).
     890 *   If the RingBuffer constructor was not called with a usereadahead
     891 *   of true of if this was reset to false because we're dealing with
     892 *   a DVD the read ahead thread will not be started.
     893 *
     894 *   If this RingBuffer is in write-mode a warning will be printed and
     895 *   the read ahead thread will not be started.
     896 *
     897 *   If the read ahead thread is already running a warning will be printed
     898 *   and the read ahead thread will not be started.
     899 *
    860900 */
    861 void RingBuffer::StartupReadAheadThread(void)
     901void RingBuffer::Start(void)
    862902{
    863     readaheadrunning = false;
     903    bool do_start = true;
    864904
    865     readAheadRunningCondLock.lock();
     905    rwlock.lockForWrite();
     906    if (!startreadahead)
     907    {
     908        do_start = false;
     909    }
     910    else if (writemode)
     911    {
     912        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     913                "this is a write only RingBuffer");
     914        do_start = false;
     915    }
     916    else if (readaheadrunning)
     917    {
     918        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     919                "already running");
     920        do_start = false;
     921    }
     922
     923    if (!do_start)
     924    {
     925        rwlock.unlock();
     926        return;
     927    }
     928
     929    StartReads();
     930
    866931    QThread::start();
    867     readAheadRunningCond.wait(&readAheadRunningCondLock);
    868     readAheadRunningCondLock.unlock();
     932
     933    while (readaheadrunning && !reallyrunning)
     934        generalWait.wait(&rwlock);
     935
     936    rwlock.unlock();
    869937}
    870938
    871939/** \fn RingBuffer::KillReadAheadThread(void)
     
    873941 */
    874942void RingBuffer::KillReadAheadThread(void)
    875943{
    876     if (!readaheadrunning)
    877         return;
     944    rwlock.lockForWrite();
     945    bool do_wait = readaheadrunning;
     946    readaheadrunning = false;
     947    StopReads();
     948    generalWait.wakeAll();
     949    rwlock.unlock();
    878950
    879     readaheadrunning = false;
    880     QThread::wait();
     951    if (do_wait)
     952        QThread::wait();
    881953}
    882954
    883955/** \fn RingBuffer::StopReads(void)
     
    887959void RingBuffer::StopReads(void)
    888960{
    889961    stopreads = true;
    890     availWait.wakeAll();
     962    generalWait.wakeAll();
    891963}
    892964
    893965/** \fn RingBuffer::StartReads(void)
     
    905977 */
    906978void RingBuffer::Pause(void)
    907979{
    908     pausereadthread = true;
    909980    StopReads();
     981
     982    rwlock.lockForWrite();
     983    request_pause = true;
     984    rwlock.unlock();
    910985}
    911986
    912987/** \fn RingBuffer::Unpause(void)
     
    916991void RingBuffer::Unpause(void)
    917992{
    918993    StartReads();
    919     pausereadthread = false;
     994
     995    rwlock.lockForWrite();
     996    request_pause = false;
     997    generalWait.wakeAll();
     998    rwlock.unlock();
    920999}
    9211000
     1001/// Returns false iff read-ahead is not running and read-ahead is not paused.
     1002bool RingBuffer::isPaused(void) const
     1003{
     1004    rwlock.lockForRead();
     1005    bool ret = !readaheadrunning || paused;
     1006    rwlock.unlock();
     1007    return ret;
     1008}
     1009
    9221010/** \fn RingBuffer::WaitForPause(void)
    9231011 *  \brief Waits for Pause(void) to take effect.
    9241012 */
    9251013void RingBuffer::WaitForPause(void)
    9261014{
    927     if (!readaheadrunning)
    928         return;
     1015    MythTimer t;
     1016    t.start();
    9291017
    930     if  (!readaheadpaused)
     1018    rwlock.lockForRead();
     1019    while (readaheadrunning && !paused && request_pause)
    9311020    {
    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();
     1021        generalWait.wait(&rwlock, 1000);
     1022        if (readaheadrunning && !paused && request_pause && t.elapsed() > 1000)
     1023        {
     1024            VERBOSE(VB_IMPORTANT, LOC_WARN +
     1025                    QString("Waited %1 ms for ringbuffer pause..")
     1026                    .arg(t.elapsed()));
     1027        }
     1028    }
     1029    rwlock.unlock();
     1030}
    9361031
    937         while (!pauseWait.wait(&mutex, 1000))
    938             VERBOSE(VB_IMPORTANT,
    939                     LOC + "Waited too long for ringbuffer pause..");
     1032bool RingBuffer::PauseAndWait(void)
     1033{
     1034    const uint timeout = 500; // ms
     1035
     1036    if (request_pause)
     1037    {
     1038        if (!paused)
     1039        {
     1040            rwlock.unlock();
     1041            rwlock.lockForWrite();
     1042
     1043            if (request_pause)
     1044            {
     1045                paused = true;
     1046                generalWait.wakeAll();
     1047            }
     1048
     1049            rwlock.unlock();
     1050            rwlock.lockForRead();
     1051        }
     1052
     1053        if (request_pause && paused && readaheadrunning)
     1054            generalWait.wait(&rwlock, timeout);
    9401055    }
     1056
     1057    if (!request_pause && paused)
     1058    {
     1059        rwlock.unlock();
     1060        rwlock.lockForWrite();
     1061
     1062        if (!request_pause)
     1063        {
     1064            paused = false;
     1065            generalWait.wakeAll();
     1066        }
     1067
     1068        rwlock.unlock();
     1069        rwlock.lockForRead();
     1070    }
     1071
     1072    return request_pause || paused;
    9411073}
    9421074
    9431075void RingBuffer::run(void)
    9441076{
    945     long long totfree = 0;
    946     int ret = -1;
    947     int used = 0;
    948     int loops = 0;
    949 
     1077    // These variables are used to adjust the read block size
    9501078    struct timeval lastread, now;
    951     gettimeofday(&lastread, NULL);
    952     const int KB640 = 640*1024;
    9531079    int readtimeavg = 300;
    954     int readinterval;
     1080    bool ignore_for_read_timing = true;
    9551081
    956     pausereadthread = false;
     1082    gettimeofday(&lastread, NULL); // this is just to keep gcc happy
    9571083
    958     readAheadBuffer = new char[kBufferSize + KB640];
    959 
    9601084    rwlock.lockForWrite();
     1085    poslock.lockForWrite();
     1086    request_pause = false;
     1087    readAheadBuffer = new char[kBufferSize + 1024];
    9611088    ResetReadAhead(0);
     1089    readaheadrunning = true;
     1090    reallyrunning = true;
     1091    generalWait.wakeAll();
     1092    poslock.unlock();
    9621093    rwlock.unlock();
    9631094
    964     totfree = ReadBufFree();
     1095    // NOTE: this must loop at some point hold only
     1096    // a read lock on rwlock, so that other functions
     1097    // such as reset and seek can take priority.
    9651098
    966     readaheadrunning = true;
    967     readAheadRunningCondLock.lock();
    968     readAheadRunningCond.wakeAll();
    969     readAheadRunningCondLock.unlock();
     1099    rwlock.lockForRead();
     1100
     1101    VERBOSE(VB_FILE, LOC + QString("Initial readblocksize %1K & fill_min %2K")
     1102            .arg(readblocksize/1024).arg(fill_min/1024));
     1103
    9701104    while (readaheadrunning)
    9711105    {
    972         if (pausereadthread || writemode)
     1106        if (PauseAndWait())
    9731107        {
    974             readaheadpaused = true;
    975             pauseWait.wakeAll();
    976             usleep(5000);
    977             totfree = ReadBufFree();
     1108            ignore_for_read_timing = true;
    9781109            continue;
    9791110        }
    9801111
    981         if (readaheadpaused)
     1112        long long totfree = ReadBufFree();
     1113
     1114        if (totfree < readblocksize)
    9821115        {
    983             totfree = ReadBufFree();
    984             readaheadpaused = false;
     1116            generalWait.wait(&rwlock, 1000);
     1117            continue;
    9851118        }
    9861119
    987         totfree = ReadBufFree();
    988         if (totfree < GetReadBlockSize())
     1120        if (ignorereadpos >= 0)
    9891121        {
    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;
     1122            generalWait.wait(&rwlock, 1000);
     1123            continue;
    9971124        }
    998         loops = 0;
    9991125
    1000         rwlock.lockForRead();
    1001         if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
     1126        // No point in trying to read if stopreads is set but do sleep
     1127        // a little so we don't get stuck in a tight busy loop here..
     1128        if (stopreads)
    10021129        {
     1130            ignore_for_read_timing = true;
     1131            generalWait.wait(&rwlock, 10);
     1132            continue;
     1133        }
     1134
     1135        int read_return = -1;
     1136        if (totfree >= readblocksize && !commserror &&
     1137            !ateof && !setswitchtonext)
     1138        {
    10031139            // limit the read size
    10041140            totfree = readblocksize;
    10051141
    10061142            // adapt blocksize
    10071143            gettimeofday(&now, NULL);
    1008             readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
    1009                            (now.tv_usec - lastread.tv_usec) / 1000;
     1144            if (!ignore_for_read_timing)
     1145            {
     1146                int readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
     1147                    (now.tv_usec - lastread.tv_usec) / 1000;
     1148                readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    10101149
    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;
     1150                if (readtimeavg < 150 && (uint)readblocksize < (kBufferSize>>2))
     1151                {
     1152                    int old_block_size = readblocksize;
     1153                    readblocksize = 3 * readblocksize / 2;
     1154                    readblocksize = ((readblocksize+CHUNK-1) / CHUNK) * CHUNK;
     1155                    VERBOSE(VB_FILE, LOC +
     1156                            QString("Avg read interval was %1 msec. "
     1157                                    "%2K -> %3K block size")
     1158                            .arg(readtimeavg)
     1159                            .arg(old_block_size/1024)
     1160                            .arg(readblocksize/1024));
     1161                    readtimeavg = 225;
     1162                }
     1163                else if (readtimeavg > 300 && readblocksize > CHUNK)
     1164                {
     1165                    readblocksize -= CHUNK;
     1166                    VERBOSE(VB_FILE, LOC +
     1167                            QString("Avg read interval was %1 msec. "
     1168                                    "%2K -> %3K block size")
     1169                            .arg(readtimeavg)
     1170                            .arg((readblocksize+CHUNK)/1024)
     1171                            .arg(readblocksize/1024));
     1172                    readtimeavg = 225;
     1173                }
    10201174            }
    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             }
     1175            ignore_for_read_timing = false;
    10291176            lastread = now;
    10301177
     1178            rbwlock.lockForRead();
    10311179            if (rbwpos + totfree > kBufferSize)
     1180            {
    10321181                totfree = kBufferSize - rbwpos;
     1182                VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1183                        "Shrinking read, near end of buffer");
     1184            }
    10331185
    10341186            if (internalreadpos == 0)
    1035                 totfree = fill_min;
     1187            {
     1188                totfree = max(fill_min, readblocksize);
     1189                VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1190                        "Reading enough data to start playback");
     1191            }
    10361192
     1193            VERBOSE(VB_FILE|VB_EXTRA,
     1194                    LOC + QString("safe_read(...@%1, %2) -- begin")
     1195                    .arg(rbwpos).arg(totfree));
    10371196            if (remotefile)
    10381197            {
    10391198                if (livetvchain && livetvchain->HasNext())
    10401199                    remotefile->SetTimeout(true);
    1041 
    1042                 ret = safe_read(remotefile, readAheadBuffer + rbwpos,
    1043                                 totfree);
    1044                 internalreadpos += ret;
     1200                read_return = safe_read(
     1201                    remotefile, readAheadBuffer + rbwpos, totfree);
    10451202            }
    10461203#ifdef USING_FRONTEND
    10471204            else if (dvdPriv)
    10481205            {
    1049                 ret = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1050                 internalreadpos += ret;
     1206                read_return = dvdPriv->safe_read(
     1207                    readAheadBuffer + rbwpos, totfree);
    10511208            }
    10521209            else if (bdPriv)
    10531210            {
    1054                 ret = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1055                 internalreadpos += ret;
     1211                read_return = bdPriv->safe_read(
     1212                    readAheadBuffer + rbwpos, totfree);
    10561213            }
    10571214#endif // USING_FRONTEND
    10581215            else
    10591216            {
    1060                 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    1061                 internalreadpos += ret;
     1217                read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    10621218            }
     1219            VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1220                    QString("safe_read(...@%1, %2) -> %3")
     1221                    .arg(rbwpos).arg(totfree).arg(read_return));
     1222            rbwlock.unlock();
     1223        }
    10631224
    1064             readAheadLock.lock();
    1065             if (ret > 0 )
    1066                 rbwpos = (rbwpos + ret) % kBufferSize;
    1067             readAheadLock.unlock();
     1225        // If stopreads is set we toss the read data since we're probably
     1226        // doing a seek or opening a new file anyway.
     1227        if (stopreads)
     1228        {
     1229            VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1230                    "Saw stopreads.. dropping recently read data.");
     1231            continue;
     1232        }
    10681233
    1069             if (ret == 0 && !stopreads)
     1234        if (read_return >= 0)
     1235        {
     1236            poslock.lockForWrite();
     1237            rbwlock.lockForWrite();
     1238            internalreadpos += read_return;
     1239            rbwpos = (rbwpos + read_return) % kBufferSize;
     1240            VERBOSE(VB_FILE|VB_EXTRA,
     1241                    LOC + QString("rbwpos += %1K requested %2K in read")
     1242                    .arg(read_return/1024,3).arg(totfree/1024,3));
     1243            rbwlock.unlock();
     1244            poslock.unlock();
     1245        }
     1246
     1247        int used = kBufferSize - ReadBufFree();
     1248
     1249        if ((0 == read_return) || (numfailures > 5) ||
     1250            (readsallowed != (used >= fill_min || ateof ||
     1251                              setswitchtonext || commserror)))
     1252        {
     1253            // If readpos changes while the lock is released
     1254            // we should not handle the 0 read_return now.
     1255            long long old_readpos = readpos;
     1256
     1257            rwlock.unlock();
     1258            rwlock.lockForWrite();
     1259
     1260            commserror |= (numfailures > 5);
     1261
     1262            readsallowed = used >= fill_min || ateof ||
     1263                setswitchtonext || commserror;
     1264
     1265            if (0 == read_return && old_readpos == readpos)
    10701266            {
    10711267                if (livetvchain)
    10721268                {
     
    10781274                    }
    10791275                }
    10801276                else
     1277                {
    10811278                    ateof = true;
     1279                }
    10821280            }
    1083         }
    10841281
    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;
     1282            rwlock.unlock();
     1283            rwlock.lockForRead();
     1284            used = kBufferSize - ReadBufFree();
    10951285        }
    10961286
    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));
     1287        VERBOSE(VB_FILE|VB_EXTRA, LOC + "@ end of read ahead loop");
    11071288
    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 ||
     1289        if (readsallowed || commserror || ateof || setswitchtonext ||
    11221290            (wanttoread <= used && wanttoread > 0))
    11231291        {
    1124             availWait.wakeAll();
     1292            // To give other threads a good chance to handle these
     1293            // conditions, even if they are only requesting a read lock
     1294            // like us, yield (currently implemented with short usleep).
     1295            generalWait.wakeAll();
     1296            rwlock.unlock();
     1297            usleep(5 * 1000);
     1298            rwlock.lockForRead();           
    11251299        }
    1126         availWaitMutex.unlock();
    1127 
    1128         rwlock.unlock();
    1129 
    1130         if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
    1131             !pausereadthread)
     1300        else
    11321301        {
    1133             usleep(500);
     1302            // yield if we have nothing to do...
     1303            if (!request_pause &&
     1304                (used >= fill_threshold || ateof || setswitchtonext))
     1305            {
     1306                generalWait.wait(&rwlock, 100);
     1307            }
    11341308        }
    11351309    }
    11361310
     1311    rwlock.unlock();
     1312
     1313    rwlock.lockForWrite();
     1314    rbrlock.lockForWrite();
     1315    rbwlock.lockForWrite();
     1316
     1317    rbrpos = 0;
     1318    rbwpos = 0;
     1319    reallyrunning = false;
     1320    readsallowed = false;
    11371321    delete [] readAheadBuffer;
     1322
    11381323    readAheadBuffer = NULL;
    1139     rbrpos = 0;
    1140     rbwpos = 0;
     1324    rbwlock.unlock();
     1325    rbrlock.unlock();
     1326    rwlock.unlock();
    11411327}
    11421328
    11431329long long RingBuffer::SetAdjustFilesize(void)
    11441330{
     1331    rwlock.lockForWrite();
     1332    poslock.lockForRead();
    11451333    readAdjust += internalreadpos;
     1334    poslock.unlock();
     1335    rwlock.unlock();
    11461336    return readAdjust;
    11471337}
    11481338
    11491339int RingBuffer::Peek(void *buf, int count)
    11501340{
    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 
     1341    int ret = ReadPriv(buf, count, true);
    11911342    if (ret != count)
    11921343    {
    11931344        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    11971348    return ret;
    11981349}
    11991350
    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)
     1351bool RingBuffer::WaitForReadsAllowed(void)
    12091352{
    1210     if (commserror)
    1211         return 0;
     1353    MythTimer t;
     1354    t.start();
    12121355
    1213     bool readone = false;
    1214     int readErr = 0;
    1215 
    1216     if (readaheadpaused && stopreads)
     1356    while (!readsallowed && !stopreads &&
     1357           !request_pause && !commserror && readaheadrunning)
    12171358    {
    1218         readone = true;
    1219         Unpause();
    1220     }
    1221     else
    1222     {
    1223         QMutexLocker locker(&readsAllowedWaitMutex);
     1359        generalWait.wait(&rwlock, 1000);
     1360        if (!readsallowed && t.elapsed() > 1000)
     1361        {
     1362            VERBOSE(VB_IMPORTANT, LOC_WARN +
     1363                    "Taking too long to be allowed to read..");
    12241364
    1225         while (!readsallowed && !stopreads)
    1226         {
    1227             if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000))
     1365            if (t.elapsed() > 10000)
    12281366            {
    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                  }
     1367                VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
     1368                        "10 seconds to be allowed to read, aborting.");
     1369                return false;
    12491370            }
    12501371        }
    12511372    }
    12521373
     1374    return readsallowed;
     1375}
     1376
     1377bool RingBuffer::WaitForAvail(int count)
     1378{
    12531379    int avail = ReadBufAvail();
     1380    count = (ateof && avail < count) ? avail : count;
    12541381
    1255     if (ateof && avail < count)
    1256         count = avail;
    1257 
    12581382    MythTimer t;
    12591383    t.start();
    1260     while (avail < count && !stopreads)
     1384    while ((avail < count) && !stopreads &&
     1385           !request_pause && !commserror && readaheadrunning)
    12611386    {
    1262         availWaitMutex.lock();
    12631387        wanttoread = count;
    1264         if (!availWait.wait(&availWaitMutex, 250))
     1388        generalWait.wait(&rwlock, 250);
     1389        avail = ReadBufAvail();
     1390
     1391        if ((ateof || setswitchtonext) && avail < count)
     1392            count = avail;
     1393
     1394        if (avail < count)
    12651395        {
    12661396            int elapsed = t.elapsed();
    1267             if  (/*((elapsed > 500)  && (elapsed < 750))  ||*/
     1397            if  (((elapsed > 250)  && (elapsed < 500))  ||
     1398                 ((elapsed > 500)  && (elapsed < 750))  ||
    12681399                 ((elapsed > 1000) && (elapsed < 1250)) ||
    12691400                 ((elapsed > 2000) && (elapsed < 2250)) ||
    12701401                 ((elapsed > 4000) && (elapsed < 4250)) ||
    1271                  ((elapsed > 8000) && (elapsed < 8250)))
     1402                 ((elapsed > 8000) && (elapsed < 8250)) ||
     1403                 ((elapsed > 9000)))
    12721404            {
    12731405                VERBOSE(VB_IMPORTANT, LOC + "Waited " +
    1274                         QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) +
    1275                         " seconds for data to become available...");
     1406                        QString("%1").arg((elapsed / 250) * 0.25f, 3, 'f', 1) +
     1407                        " seconds for data \n\t\t\tto become available..." +
     1408                        QString(" %2 < %3")
     1409                        .arg(avail).arg(count));
    12761410                if (livetvchain)
    12771411                {
    12781412                    VERBOSE(VB_IMPORTANT, "Checking to see if there's a "
     
    12951429                    VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to "
    12961430                            "impending livetv switch.");
    12971431
    1298                 ateof = true;
    1299                 wanttoread = 0;
    1300                 stopreads = true;
    1301                 availWaitMutex.unlock();
    1302                 return 0;
     1432                return false;
    13031433            }
    13041434        }
     1435    }
    13051436
     1437    wanttoread = 0;
     1438
     1439    return avail >= count;
     1440}
     1441
     1442int RingBuffer::ReadDirect(void *buf, int count, bool peek)
     1443{
     1444    long long old_pos = 0;
     1445    if (peek)
     1446    {
     1447        poslock.lockForRead();
     1448        old_pos = (ignorereadpos >= 0) ? ignorereadpos : readpos;
     1449        poslock.unlock();
     1450    }
     1451
     1452    int ret;
     1453    if (remotefile)
     1454        ret = safe_read(remotefile, buf, count);
     1455#ifdef USING_FRONTEND
     1456    else if (dvdPriv)
     1457        ret = dvdPriv->safe_read(buf, count);
     1458    else if (bdPriv)
     1459        ret = bdPriv->safe_read(buf, count);
     1460#endif // USING_FRONTEND
     1461    else if (fd2 >= 0)
     1462        ret = safe_read(fd2, buf, count);
     1463    else
     1464    {
     1465        ret = -1;
     1466        errno = EBADF;
     1467    }
     1468
     1469    poslock.lockForWrite();
     1470    if (ignorereadpos >= 0 && ret > 0)
     1471    {
     1472        if (peek)
     1473        {
     1474            // seek should always succeed since we were at this position
     1475            if (remotefile)
     1476                remotefile->Seek(old_pos, SEEK_SET);
     1477            else
     1478                lseek64(fd2, old_pos, SEEK_SET);
     1479        }
     1480        else
     1481        {
     1482            ignorereadpos += ret;
     1483        }
     1484        poslock.unlock();
     1485        return ret;
     1486    }
     1487    poslock.unlock();
     1488
     1489    if (peek && ret > 0)
     1490    {
     1491        if (!dvdPriv && !bdPriv)
     1492        {
     1493            long long new_pos = Seek(old_pos, SEEK_SET, true);
     1494            if (new_pos != old_pos)
     1495            {
     1496                VERBOSE(VB_IMPORTANT, LOC_ERR +
     1497                        QString("Peek() Failed to return from new "
     1498                                "position %1 to old position %2, now "
     1499                                "at position %3")
     1500                        .arg(old_pos - ret).arg(old_pos).arg(new_pos));
     1501            }
     1502        }
     1503        else if (old_pos != 0)
     1504        {
     1505            VERBOSE(VB_IMPORTANT, LOC_ERR +
     1506                    "DVD and Blu-Ray do not support arbitrary "
     1507                    "peeks except when read-ahead is enabled."
     1508                    "\n\t\t\tWill seek to beginning of video.");
     1509        }
     1510#ifdef USING_FRONTEND
     1511        if (dvdPriv)
     1512        {
     1513            dvdPriv->NormalSeek(0);
     1514        }
     1515        else if (bdPriv)
     1516        {
     1517            bdPriv->Seek(0);
     1518        }
     1519#endif // USING_FRONTEND
     1520    }
     1521
     1522    return ret;
     1523}
     1524
     1525/** \brief When possible reads from the read-ahead buffer,
     1526 *         otherwise reads directly from the device.
     1527 *
     1528 *  \param buf   Pointer to where data will be written
     1529 *  \param count Number of bytes to read
     1530 *  \param peek  If true, don't increment read count
     1531 *  \return Returns number of bytes read
     1532 */
     1533int RingBuffer::ReadPriv(void *buf, int count, bool peek)
     1534{
     1535    VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1536            QString("ReadPriv(*, %1, %2) @%3 -- begin")
     1537            .arg(count).arg(peek?"peek":"normal").arg(rbrpos));
     1538
     1539    rwlock.lockForRead();
     1540    if (writemode)
     1541    {
     1542        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1543                "Attempt to read from a write only file");
     1544        errno = EBADF;
     1545        rwlock.unlock();
     1546        return -1;
     1547    }
     1548
     1549    if (commserror)
     1550    {
     1551        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1552                "Attempt to read after commserror set");
     1553        errno = EIO;
     1554        rwlock.unlock();
     1555        return -1;
     1556    }
     1557
     1558    if (request_pause || stopreads || !readaheadrunning || (ignorereadpos>=0))
     1559    {
     1560        rwlock.unlock();
     1561        rwlock.lockForWrite();
     1562        // we need a write lock so the read-ahead thread
     1563        // can't start mucking with the read position.
     1564        // If the read ahead thread was started while we
     1565        // didn't hold the lock, we proceed with a normal
     1566        // read from the buffer, otherwise we read directly.
     1567        if (request_pause || stopreads ||
     1568            !readaheadrunning || (ignorereadpos >= 0))
     1569        {
     1570            int ret = ReadDirect(buf, count, peek);
     1571            VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1572                    QString("ReadPriv(*, %1, %2) @%3 -- RD checksum %4")
     1573                    .arg(count).arg(peek?"peek":"normal").arg(rbrpos)
     1574                    .arg(qChecksum((char*)buf,count)));
     1575            rwlock.unlock();
     1576            return ret;
     1577        }
     1578        rwlock.unlock();
     1579        rwlock.lockForRead();
     1580    }
     1581
     1582    if (!WaitForReadsAllowed())
     1583    {
     1584        VERBOSE(VB_FILE, LOC + "!WaitForReadsAllowed()");
     1585        rwlock.unlock();
     1586        rwlock.lockForWrite();
    13061587        wanttoread = 0;
    1307         availWaitMutex.unlock();
     1588        stopreads = true;
     1589        rwlock.unlock();
     1590        return 0;
     1591    }
    13081592
    1309         avail = ReadBufAvail();
    1310         if ((ateof || setswitchtonext) && avail < count)
    1311             count = avail;
     1593    if (!WaitForAvail(count))
     1594    {
     1595        VERBOSE(VB_FILE, LOC + "!WaitForAvail()");
     1596        rwlock.unlock();
     1597        rwlock.lockForWrite();
     1598        ateof = true;
     1599        wanttoread = 0;
     1600        stopreads = true;
     1601        rwlock.unlock();
     1602        return 0;
     1603    }
    13121604
    1313         if (commserror)
    1314             return 0;
     1605    count = min(ReadBufAvail(), count);
     1606
     1607    if (count <= 0)
     1608    {
     1609        // this can happen under a few conditions but the most
     1610        // notable is an exit from the read ahead thread.
     1611        rwlock.unlock();
     1612        return count;
    13151613    }
    13161614
    1317     if ((ateof || stopreads) && avail < count)
    1318         count = avail;
     1615    if (peek)
     1616        rbrlock.lockForRead();
     1617    else
     1618        rbrlock.lockForWrite();
    13191619
     1620    VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1621            QString("ReadPriv(*, %1, %2) @%3 -- copying data")
     1622            .arg(count).arg(peek?"peek":"normal").arg(rbrpos));
     1623
    13201624    if (rbrpos + count > (int) kBufferSize)
    13211625    {
    13221626        int firstsize = kBufferSize - rbrpos;
     
    13261630        memcpy((char *)buf + firstsize, readAheadBuffer, secondsize);
    13271631    }
    13281632    else
     1633    {
    13291634        memcpy(buf, readAheadBuffer + rbrpos, count);
     1635        VERBOSE(VB_FILE|VB_EXTRA, LOC +
     1636                QString("ReadPriv(*, %1, %2) @%3 -- checksum %4")
     1637                .arg(count).arg(peek?"peek":"normal").arg(rbrpos)
     1638                .arg(qChecksum(readAheadBuffer+rbrpos,count)));
     1639    }
    13301640
    13311641    if (!peek)
    13321642    {
    1333         readAheadLock.lock();
    13341643        rbrpos = (rbrpos + count) % kBufferSize;
    1335         readAheadLock.unlock();
     1644        generalWait.wakeAll();
    13361645    }
     1646    rbrlock.unlock();
     1647    rwlock.unlock();
    13371648
    1338     if (readone)
    1339     {
    1340         Pause();
    1341         WaitForPause();
    1342     }
    1343 
    13441649    return count;
    13451650}
    13461651
     
    13541659 */
    13551660int RingBuffer::Read(void *buf, int count)
    13561661{
    1357     int ret = -1;
    1358     if (writemode)
     1662    int ret = ReadPriv(buf, count, false);
     1663    if (ret > 0)
    13591664    {
    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);
     1665        poslock.lockForWrite();
    13951666        readpos += ret;
     1667        poslock.unlock();
    13961668    }
    1397 
    1398     rwlock.unlock();
    13991669    return ret;
    14001670}
    14011671
    14021672/** \fn RingBuffer::IsIOBound(void) const
    1403  *  \brief Returns true if a RingBuffer::Read(void*,int) is likely to block.
     1673 *  \brief Returns true if a RingBuffer::Write(void*,int) is likely to block.
    14041674 */
    14051675bool RingBuffer::IsIOBound(void) const
    14061676{
     
    14291699 */
    14301700int RingBuffer::Write(const void *buf, uint count)
    14311701{
    1432     int ret = -1;
     1702    rwlock.lockForRead();
     1703
    14331704    if (!writemode)
    14341705    {
    14351706        VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file.");
    1436         return ret;
     1707        rwlock.unlock();
     1708        return -1;
    14371709    }
    14381710
    14391711    if (!tfw && !remotefile)
    1440         return ret;
     1712    {
     1713        rwlock.unlock();
     1714        return -1;
     1715    }
    14411716
    1442     rwlock.lockForRead();
    1443 
     1717    int ret = -1;
    14441718    if (tfw)
    14451719        ret = tfw->Write(buf, count);
    14461720    else
    14471721        ret = remotefile->Write(buf, count);
    1448     writepos += ret;
    14491722
     1723    if (ret > 0)
     1724    {
     1725        poslock.lockForWrite();
     1726        writepos += ret;
     1727        poslock.unlock();
     1728    }
     1729
    14501730    rwlock.unlock();
     1731
    14511732    return ret;
    14521733}
    14531734
     
    14561737 */
    14571738void RingBuffer::Sync(void)
    14581739{
     1740    rwlock.lockForRead();
    14591741    if (tfw)
    14601742        tfw->Sync();
     1743    rwlock.unlock();
    14611744}
    14621745
    1463 /** \fn RingBuffer::Seek(long long, int)
    1464  *  \brief Seeks to a particular position in the file.
     1746/** \brief Seeks to a particular position in the file.
    14651747 */
    1466 long long RingBuffer::Seek(long long pos, int whence)
     1748long long RingBuffer::Seek(long long pos, int whence, bool has_lock)
    14671749{
     1750    VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)")
     1751            .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET":
     1752                          ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END"))
     1753            .arg(has_lock?"locked":"unlocked"));
     1754
     1755    long long ret = -1;
     1756
     1757    stopreads = true;
     1758
     1759    // lockForWrite takes priority over lockForRead, so this will
     1760    // take priority over the lockForRead in the read ahead thread.
     1761    if (!has_lock)
     1762        rwlock.lockForWrite();
     1763
     1764    stopreads = false;
     1765
    14681766    if (writemode)
    1469         return WriterSeek(pos, whence);
     1767    {
     1768        ret = WriterSeek(pos, whence, true);
     1769        if (!has_lock)
     1770            rwlock.unlock();
     1771        return ret;
     1772    }
    14701773
    1471     wantseek = true;
    1472     rwlock.lockForWrite();
    1473     wantseek = false;
     1774    poslock.lockForWrite();
    14741775
    1475     // optimize nop seeks
    1476     if ((whence == SEEK_SET && pos == readpos) ||
    1477         (whence == SEEK_CUR && pos == 0))
     1776    // Optimize no-op seeks
     1777    if (readaheadrunning &&
     1778        ((whence == SEEK_SET && pos == readpos) ||
     1779         (whence == SEEK_CUR && pos == 0)))
    14781780    {
    1479         rwlock.unlock();
    1480         return readpos;
     1781        ret = readpos;
     1782
     1783        poslock.unlock();
     1784        if (!has_lock)
     1785            rwlock.unlock();
     1786
     1787        return ret;
    14811788    }
    14821789
    1483     errno = 0; // clear errno, in case of remotefile error
     1790    // only valid for SEEK_SET & SEEK_CUR
     1791    long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos;
    14841792
    1485     long long ret = -1;
     1793    // Optimize short seeks where the data for
     1794    // them is in our ringbuffer already.
     1795    if (readaheadrunning &&
     1796        (SEEK_SET==whence || SEEK_CUR==whence))
     1797    {
     1798        rbrlock.lockForWrite();
     1799        rbwlock.lockForRead();
     1800        VERBOSE(VB_FILE, LOC +
     1801                QString("Seek(): rbrpos: %1 rbwpos: %2"
     1802                        "\n\t\t\treadpos: %3 internalreadpos: %4")
     1803                .arg(rbrpos).arg(rbwpos)
     1804                .arg(readpos).arg(internalreadpos));
     1805        bool used_opt = false;
     1806        if ((new_pos < readpos))
     1807        {
     1808            int min_safety = max(fill_min, readblocksize);
     1809            int free = ((rbwpos >= rbrpos) ?
     1810                        rbrpos + kBufferSize : rbrpos) - rbwpos;
     1811            int internal_backbuf =
     1812                (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos;
     1813            internal_backbuf = min(internal_backbuf, free - min_safety);
     1814            long long sba = readpos - new_pos;
     1815            VERBOSE(VB_FILE, LOC +
     1816                    QString("Seek(): internal_backbuf: %1 sba: %2")
     1817                    .arg(internal_backbuf).arg(sba));
     1818            if (internal_backbuf >= sba)
     1819            {
     1820                rbrpos = (rbrpos>=sba) ? rbrpos - sba :
     1821                    kBufferSize + rbrpos - sba;
     1822                used_opt = true;
     1823                VERBOSE(VB_FILE, LOC +
     1824                        QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2"
     1825                                "\n\t\t\treadpos: %3 internalreadpos: %4")
     1826                        .arg(rbrpos).arg(rbwpos)
     1827                        .arg(new_pos).arg(internalreadpos));
     1828            }
     1829        }
     1830        else if ((new_pos >= readpos) && (new_pos <= internalreadpos))
     1831        {
     1832            rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize;
     1833            used_opt = true;
     1834            VERBOSE(VB_IMPORTANT, LOC +
     1835                    QString("Seek(): OPT2 rbrpos: %1 sba: %2")
     1836                    .arg(rbrpos).arg(readpos - new_pos));
     1837        }
     1838        rbwlock.unlock();
     1839        rbrlock.unlock();
     1840
     1841        if (used_opt)
     1842        {
     1843            if (ignorereadpos >= 0)
     1844            {
     1845                // seek should always succeed since we were at this position
     1846                if (remotefile)
     1847                    remotefile->Seek(internalreadpos, SEEK_SET);
     1848                else
     1849                    lseek64(fd2, internalreadpos, SEEK_SET);
     1850                ignorereadpos = -1;
     1851            }
     1852            readpos = new_pos;
     1853            poslock.unlock();
     1854            generalWait.wakeAll();
     1855            if (!has_lock)
     1856                rwlock.unlock();
     1857            return new_pos;
     1858        }
     1859    }
     1860
     1861    // This optimizes the seek end-250000, read, seek 0, read portion
     1862    // of the pattern ffmpeg performs at the start of playback to
     1863    // determine the pts.
     1864    // If the seek is a SEEK_END or is a seek where the position
     1865    // changes over 100 MB we check the file size and if the
     1866    // destination point is within 300000 bytes of the end of
     1867    // the file we enter a special mode where the read ahead
     1868    // buffer stops reading data and all reads are made directly
     1869    // until another seek is performed. The point of all this is
     1870    // to avoid flushing out the buffer that still contains all
     1871    // the data the final seek 0, read will need just to read the
     1872    // last 250000 bytes. A further optimization would be to buffer
     1873    // the 250000 byte read, which is currently performed in 32KB
     1874    // blocks (inefficient with RemoteFile).
     1875    if ((remotefile || fd2 >= 0) && (ignorereadpos < 0))
     1876    {
     1877        long long off_end = 0xDEADBEEF;
     1878        if (SEEK_END == whence)
     1879        {
     1880            off_end = pos;
     1881            if (remotefile)
     1882            {
     1883                new_pos = remotefile->GetFileSize() - off_end;
     1884            }
     1885            else
     1886            {
     1887                QFileInfo fi(filename);
     1888                new_pos = fi.size() - off_end;
     1889            }
     1890        }
     1891        else if (abs(new_pos-readpos) > 100000000)
     1892        {
     1893            if (remotefile)
     1894            {
     1895                off_end = remotefile->GetFileSize() - new_pos;
     1896            }
     1897            else
     1898            {
     1899                QFileInfo fi(filename);
     1900                off_end = fi.size() - new_pos;
     1901            }
     1902        }
     1903        if (off_end < 300000)
     1904        {
     1905            VERBOSE(VB_FILE, LOC +
     1906                    QString("Seek(): offset from end: %1").arg(off_end) +
     1907                    "\n\t\t\t -- ignoring read ahead thread until next seek.");
     1908
     1909            ignorereadpos = new_pos;
     1910            errno = EINVAL;
     1911            int ret;
     1912            if (remotefile)
     1913                ret = remotefile->Seek(ignorereadpos, SEEK_SET);
     1914            else
     1915                ret = lseek64(fd2, ignorereadpos, SEEK_SET);
     1916
     1917            if (ret < 0)
     1918            {
     1919                ignorereadpos = -1;
     1920                QString cmd = QString("Seek(%1, %2)").arg(pos)
     1921                    .arg((SEEK_SET == whence) ? "SEEK_SET" :
     1922                         ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));
     1923                VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
     1924            }
     1925
     1926            rbwlock.unlock();
     1927            rbrlock.unlock();
     1928            poslock.unlock();
     1929
     1930            generalWait.wakeAll();
     1931
     1932            if (!has_lock)
     1933                rwlock.unlock();
     1934
     1935            return ret;
     1936        }
     1937    }
     1938
     1939    // Here we perform a normal seek. When successful we
     1940    // need to call ResetReadAhead(). A reset means we will
     1941    // need to refill the buffer, which takes some time.
    14861942    if (remotefile)
     1943    {
    14871944        ret = remotefile->Seek(pos, whence, readpos);
     1945        if (ret<0)
     1946            errno = EINVAL;
     1947    }
    14881948#ifdef USING_FRONTEND
     1949    else if ((dvdPriv || bdPriv) && (SEEK_END == whence))
     1950    {
     1951        errno = EINVAL;
     1952        ret = -1;
     1953    }
    14891954    else if (dvdPriv)
    14901955    {
    1491         dvdPriv->NormalSeek(pos);
    1492         ret = pos;
     1956        dvdPriv->NormalSeek(new_pos);
     1957        ret = new_pos;
    14931958    }
    14941959    else if (bdPriv)
    14951960    {
    1496         bdPriv->Seek(pos);
    1497         ret = pos;
     1961        bdPriv->Seek(new_pos);
     1962        ret = new_pos;
    14981963    }
    14991964#endif // USING_FRONTEND
    15001965    else
    15011966    {
    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         }
     1967        ret = lseek64(fd2, pos, whence);
    15171968    }
    15181969
    15191970    if (ret >= 0)
    15201971    {
    15211972        readpos = ret;
     1973       
     1974        ignorereadpos = -1;
    15221975
    15231976        if (readaheadrunning)
    15241977            ResetReadAhead(readpos);
     
    15331986        VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
    15341987    }
    15351988
    1536     rwlock.unlock();
     1989    poslock.unlock();
    15371990
     1991    generalWait.wakeAll();
     1992
     1993    if (!has_lock)
     1994        rwlock.unlock();
     1995
    15381996    return ret;
    15391997}
    15401998
    1541 /** \fn RingBuffer::WriterSeek(long long, int)
    1542  *  \brief Calls ThreadedFileWriter::Seek(long long,int).
     1999/** \brief Calls ThreadedFileWriter::Seek(long long,int).
    15432000 */
    1544 long long RingBuffer::WriterSeek(long long pos, int whence)
     2001long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock)
    15452002{
    15462003    long long ret = -1;
    15472004
     2005    if (!has_lock)
     2006        rwlock.lockForRead();
     2007
     2008    poslock.lockForWrite();
     2009
    15482010    if (tfw)
    15492011    {
    15502012        ret = tfw->Seek(pos, whence);
    15512013        writepos = ret;
    15522014    }
    15532015
     2016    poslock.unlock();
     2017
     2018    if (!has_lock)
     2019        rwlock.unlock();
     2020
    15542021    return ret;
    15552022}
    15562023
     
    15602027 */
    15612028void RingBuffer::WriterFlush(void)
    15622029{
     2030    rwlock.lockForRead();
    15632031    if (tfw)
    15642032    {
    15652033        tfw->Flush();
    15662034        tfw->Sync();
    15672035    }
     2036    rwlock.unlock();
    15682037}
    15692038
    15702039/** \fn RingBuffer::SetWriteBufferSize(int)
     
    15722041 */
    15732042void RingBuffer::SetWriteBufferSize(int newSize)
    15742043{
     2044    rwlock.lockForRead();
    15752045    if (tfw)
    15762046        tfw->SetWriteBufferSize(newSize);
     2047    rwlock.unlock();
    15772048}
    15782049
    15792050/** \fn RingBuffer::SetWriteBufferMinWriteSize(int)
     
    15812052 */
    15822053void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize)
    15832054{
     2055    rwlock.lockForRead();
    15842056    if (tfw)
    15852057        tfw->SetWriteBufferMinWriteSize(newMinSize);
     2058    rwlock.unlock();
    15862059}
    15872060
    15882061/** \fn RingBuffer::GetReadPosition(void) const
     
    15902063 */
    15912064long long RingBuffer::GetReadPosition(void) const
    15922065{
     2066    rwlock.lockForRead();
     2067    poslock.lockForRead();
     2068    long long ret = readpos;
    15932069#ifdef USING_FRONTEND
    15942070    if (dvdPriv)
    1595         return dvdPriv->GetReadPosition();
     2071        ret = dvdPriv->GetReadPosition();
    15962072    else if (bdPriv)
    1597         return bdPriv->GetReadPosition();
     2073        ret = bdPriv->GetReadPosition();
    15982074#endif // USING_FRONTEND
    1599 
    1600     return readpos;
     2075    poslock.unlock();
     2076    rwlock.unlock();
     2077    return ret;
    16012078}
    16022079
    16032080/** \fn RingBuffer::GetWritePosition(void) const
     
    16052082 */
    16062083long long RingBuffer::GetWritePosition(void) const
    16072084{
    1608     return writepos;
     2085    poslock.lockForRead();
     2086    long long ret = writepos;
     2087    poslock.unlock();
     2088    return ret;
    16092089}
    16102090
    16112091/** \fn RingBuffer::GetRealFileSize(void) const
     
    16142094 */
    16152095long long RingBuffer::GetRealFileSize(void) const
    16162096{
     2097    rwlock.lockForRead();
     2098    long long ret = -1;
    16172099    if (remotefile)
    1618         return remotefile->GetFileSize();
    1619 
    1620     QFileInfo info(filename);
    1621     return info.size();
     2100        ret = remotefile->GetFileSize();
     2101    else
     2102        ret = QFileInfo(filename).size();
     2103    rwlock.unlock();
     2104    return ret;
    16222105}
    16232106
    16242107/** \fn RingBuffer::LiveMode(void) const
     
    16272110 */
    16282111bool RingBuffer::LiveMode(void) const
    16292112{
    1630     return (livetvchain);
     2113    rwlock.lockForRead();
     2114    bool ret = (livetvchain);
     2115    rwlock.unlock();
     2116    return ret;
    16312117}
    16322118
    16332119/** \fn RingBuffer::SetLiveMode(LiveTVChain*)
     
    16362122 */
    16372123void RingBuffer::SetLiveMode(LiveTVChain *chain)
    16382124{
     2125    rwlock.lockForWrite();
    16392126    livetvchain = chain;
     2127    rwlock.unlock();
    16402128}
    16412129
    16422130bool RingBuffer::InDVDMenuOrStillFrame(void)
    16432131{
     2132    rwlock.lockForRead();
     2133    bool ret = false;
    16442134#ifdef USING_FRONTEND
    16452135    if (dvdPriv)
    1646         return (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
     2136        ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
    16472137#endif // USING_FRONTEND
    1648     return false;
     2138    rwlock.unlock();
     2139    return ret;
    16492140}
    16502141
    16512142/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/RingBuffer.h

     
    11// -*- Mode: c++ -*-
    22
    3 #ifndef RINGBUFFER
    4 #define RINGBUFFER
     3#ifndef _RINGBUFFER_H_
     4#define _RINGBUFFER_H_
    55
    66#include <QReadWriteLock>
    77#include <QWaitCondition>
     
    3535    void SetWriteBufferMinWriteSize(int newMinSize);
    3636    void UpdateRawBitrate(uint rawbitrate);
    3737    void UpdatePlaySpeed(float playspeed);
    38     void SetStreamOnly(bool stream) { streamOnly = stream; }
     38    void SetStreamOnly(bool stream)
     39    {
     40        rwlock.lockForWrite();
     41        streamOnly = stream;
     42        rwlock.unlock();
     43    }
    3944
    4045    // Gets
    4146    /// 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(); }
     47    QString   GetFilename(void)      const
     48    {
     49        rwlock.lockForRead();
     50        QString tmp = filename; tmp.detach();
     51        rwlock.unlock();
     52        return tmp;
     53    }
     54    QString   GetSubtitleFilename(void) const
     55    {
     56        rwlock.lockForRead();
     57        QString tmp = subtitlefilename; tmp.detach();
     58        rwlock.unlock();
     59        return tmp;
     60    }
    4661    /// Returns value of stopreads
    4762    /// \sa StartReads(void), StopReads(void)
    4863    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; }
     64    bool      isPaused(void)         const;
    5365    long long GetReadPosition(void)  const;
    5466    long long GetWritePosition(void) const;
    5567    long long GetRealFileSize(void)  const;
    56     uint      GetBitrate(void)       const;
    57     uint      GetReadBlockSize(void) const;
    5868    bool      IsOpen(void)           const;
     69    bool      IsNearEnd(double fps, uint vvf) const;
    5970
    6071    // General Commands
    61     void OpenFile(const QString &lfilename, uint retryCount = 12/*4*/);
     72    void OpenFile(const QString &lfilename, uint retry_ms = 2000);
    6273    int  Read(void *buf, int count);
    6374    int  Peek(void *buf, int count); // only works with readahead
    6475
     
    6778               bool resetInternal = false);
    6879
    6980    // Seeks
    70     long long Seek(long long pos, int whence);
     81    long long Seek(long long pos, int whence, bool has_lock = false);
    7182
    7283    // Pause commands
    7384    void Pause(void);
     
    8394    bool LiveMode(void) const;
    8495    void SetLiveMode(LiveTVChain *chain);
    8596    /// Tells RingBuffer whether to igonre the end-of-file
    86     void IgnoreLiveEOF(bool ignore) { ignoreliveeof = ignore; }
     97    void IgnoreLiveEOF(bool ignore)
     98    {
     99        rwlock.lockForWrite();
     100        ignoreliveeof = ignore;
     101        rwlock.unlock();
     102    }
    87103
    88104    // ThreadedFileWriter proxies
    89105    int  Write(const void *buf, uint count);
    90106    bool IsIOBound(void) const;
    91107    void WriterFlush(void);
    92108    void Sync(void);
    93     long long WriterSeek(long long pos, int whence);
     109    long long WriterSeek(long long pos, int whence, bool has_lock = false);
    94110
    95111    // DVDRingBuffer proxies
    96112    /// Returns true if this is a DVD backed RingBuffer.
    97     inline bool isDVD(void) const { return dvdPriv; }
    98     DVDRingBufferPriv *DVD() { return dvdPriv; }
     113    bool isDVD(void) const
     114    {
     115        rwlock.lockForRead();
     116        bool ret = dvdPriv;
     117        rwlock.unlock();
     118        return ret;
     119    }
     120    /// Illicitly manipulating privates is ill advised!
     121    DVDRingBufferPriv *DVD()
     122    {
     123        return dvdPriv;
     124    }
    99125    bool InDVDMenuOrStillFrame(void);
    100126
    101127    // BDRingBuffer proxies
     
    109135  protected:
    110136    void run(void); // QThread
    111137    void CalcReadAheadThresh(void);
     138    bool PauseAndWait(void);
    112139    int safe_read_bd(void *data, uint sz);
    113140    int safe_read_dvd(void *data, uint sz);
    114141    int safe_read(int fd, void *data, uint sz);
    115142    int safe_read(RemoteFile *rf, void *data, uint sz);
    116143
    117     int ReadFromBuf(void *buf, int count, bool peek = false);
     144    int ReadPriv(void *buf, int count, bool peek);
     145    int ReadDirect(void *buf, int count, bool peek);
     146    bool WaitForReadsAllowed(void);
     147    bool WaitForAvail(int count);
    118148
    119149    int ReadBufFree(void) const;
    120150    int ReadBufAvail(void) const;
    121151
    122     void StartupReadAheadThread(void);
    123152    void ResetReadAhead(long long newinternal);
    124153    void KillReadAheadThread(void);
    125154
    126155  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
     156    mutable QReadWriteLock poslock;
     157    long long readpos;            // protected by poslock
     158    long long writepos;           // protected by poslock
     159    long long internalreadpos;    // protected by poslock
     160    long long ignorereadpos;      // protected by poslock
     161    mutable QReadWriteLock rbrlock;
     162    int       rbrpos;             // protected by rbrlock
     163    mutable QReadWriteLock rbwlock;
     164    int       rbwpos;             // protected by rbwlock
    131165
    132     QString filename;             // not protected by a lock LR
    133     QString subtitlefilename;     // not protected by a lock LR
     166    // note should not go under rwlock..
     167    // this is used to break out of read_safe where rwlock is held
     168    volatile bool stopreads;
    134169
    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 
    145170    mutable QReadWriteLock rwlock;
    146171
    147     RemoteFile *remotefile;       // not protected by a lock LR
     172    QString filename;             // protected by rwlock
     173    QString subtitlefilename;     // protected by rwlock
    148174
    149     // this lock does not consistently protect anything,
    150     // but seems to be intented to protect rbrpos & rbwpos
    151     mutable QMutex readAheadLock;
     175    ThreadedFileWriter *tfw;      // protected by rwlock
     176    int fd2;                      // protected by rwlock
    152177
    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;
     178    bool writemode;               // protected by rwlock
    166179
    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
     180    RemoteFile *remotefile;       // protected by rwlock
    172181
    173     QWaitCondition pauseWait;     // not protected by a lock HR
     182    bool      startreadahead;     // protected by rwlock
     183    char     *readAheadBuffer;    // protected by rwlock
     184    bool      readaheadrunning;   // protected by rwlock
     185    bool      reallyrunning;      // protected by rwlock
     186    bool      request_pause;      // protected by rwlock
     187    bool      paused;             // protected by rwlock
     188    bool      ateof;              // protected by rwlock
     189    bool      readsallowed;       // protected by rwlock
     190    bool      setswitchtonext;    // protected by rwlock
     191    bool      streamOnly;         // protected by rwlock
     192    bool      ignorereadahead;    // protected by rwlock
     193    uint      rawbitrate;         // protected by rwlock
     194    float     playspeed;          // protected by rwlock
     195    int       fill_threshold;     // protected by rwlock
     196    int       fill_min;           // protected by rwlock
     197    int       readblocksize;      // protected by rwlock
     198    int       wanttoread;         // protected by rwlock
     199    int       numfailures;        // protected by rwlock (see note 1)
     200    bool      commserror;         // protected by rwlock
    174201
    175     int wanttoread;               // not protected by a lock HR
    176     QWaitCondition availWait;     // protected by availWaitMutex
    177     QMutex availWaitMutex;
     202    DVDRingBufferPriv *dvdPriv;   // not protected by rwlock, when DVD() is used
     203    BDRingBufferPriv  *bdPriv;    // protected by rwlock
    178204
    179     QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex
    180     QMutex readsAllowedWaitMutex;
     205    bool oldfile;                 // protected by rwlock
    181206
    182     int numfailures;              // not protected by a lock MR
     207    LiveTVChain *livetvchain;     // protected by rwlock
     208    bool ignoreliveeof;           // protected by rwlock
    183209
    184     bool commserror;              // not protected by a lock MR
     210    long long readAdjust;         // protected by rwlock
    185211
    186     DVDRingBufferPriv *dvdPriv;   // not protected by a lock LR
    187     BDRingBufferPriv  *bdPriv;    // not protected by a lock LR
     212    // note 1: numfailures is modified with only a read lock in the
     213    // read ahead thread, but this is safe since all other places
     214    // that use it are protected by a write lock. But this is a
     215    // fragile state of affairs and care must be taken when modifying
     216    // code or locking around this variable.
    188217
    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 
    196218    /// Condition to signal that the read ahead thread is running
    197     QWaitCondition readAheadRunningCond;//protected by readAheadRunningCondLock
    198     QMutex readAheadRunningCondLock;
     219    QWaitCondition generalWait;         // protected by rwlock
    199220
    200221  public:
    201222    static QMutex subExtLock;
     
    208229    static const uint kReadTestSize;
    209230};
    210231
    211 #endif
     232#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(pginfo->GetPlaybackURL(), 2000 /*ms*/);
    21732184
    21742185    if (!player_ctx->buffer->IsOpen())
    21752186    {
    2176         VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed.");
     2187        VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed " +
     2188                QString("(card type: %1).")
     2189                .arg(player_ctx->tvchain->GetCardType(newid)));
     2190        VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
    21772191        eof = true;
    21782192        SetErrored(QObject::tr("Error opening switch program buffer"));
    21792193        delete pginfo;
     
    22902304
    22912305    SendMythSystemPlayEvent("PLAY_CHANGED", pginfo);
    22922306
    2293     player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL());
     2307    player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL(), 2000 /*ms*/);
    22942308    if (!player_ctx->buffer->IsOpen())
    22952309    {
    2296         VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed.");
     2310        VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed " +
     2311                QString("(card type: %1).")
     2312                .arg(player_ctx->tvchain->GetCardType(newid)));
     2313        VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
     2314
    22972315        eof = true;
    22982316        SetErrored(QObject::tr("Error opening jump program file buffer"));
    22992317        delete pginfo;
     
    31903208    if (!videoOutput)
    31913209        return false;
    31923210
    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;
     3211    return player_ctx->buffer->IsNearEnd(
     3212        GetDecoder()->GetFPS(),
     3213        videoOutput->ValidVideoFrames());
    32163214}
    32173215
    32183216/** \brief Returns true iff near end of recording.