Ticket #8812: 8812-v4.patch

File 8812-v4.patch, 67.2 KB (added by danielk, 9 years ago)

This patch adds some optimizations

  • 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       rawbitrate(4000),         playspeed(1.0f),
     127      readaheadrunning(false),  reallyrunning(false),
     128      request_pause(false),     paused(false),
     129      ateof(false),             readsallowed(false),
     130      setswitchtonext(false),
     131      rawbitrate(8000),        playspeed(1.0f),
    128132      fill_threshold(65536),    fill_min(-1),
    129133      readblocksize(CHUNK),     wanttoread(0),
    130134      numfailures(0),           commserror(false),
     
    273277    VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2)")
    274278            .arg(lfilename).arg(retryCount));
    275279
     280    rwlock.lockForWrite();
     281
    276282    uint openAttempts = retryCount + 1;
    277283
    278284    filename = lfilename;
     
    391397                break;
    392398            case 2:
    393399                VERBOSE(VB_IMPORTANT, LOC +
    394                         QString("Invalid file (fd %1) when opening '%2'.")
     400                        QString("Invalid file (fd2 %1) when opening '%2'.")
    395401                        .arg(fd2).arg(filename));
    396402                break;
    397403            default:
     
    414420    else if (is_dvd)
    415421    {
    416422        dvdPriv->OpenFile(filename);
    417         rwlock.lockForWrite();
    418423        readblocksize = DVD_BLOCK_SIZE * 62;
    419         rwlock.unlock();
    420424    }
    421425    else if (is_bd)
    422426    {
    423427        bdPriv->OpenFile(filename);
    424         rwlock.lockForWrite();
    425428        readblocksize = BD_BLOCK_SIZE * 62;
    426         rwlock.unlock();
    427429    }
    428430#endif // USING_FRONTEND
    429431    else
     
    478480    commserror = false;
    479481    numfailures = 0;
    480482
    481     UpdateRawBitrate(4000);
     483    rawbitrate = 8000;
     484    CalcReadAheadThresh();
     485
     486    rwlock.unlock();
    482487}
    483488
    484489/** \fn RingBuffer::IsOpen(void) const
     
    486491 */
    487492bool RingBuffer::IsOpen(void) const
    488493{
     494    rwlock.lockForRead();
     495    bool ret;
    489496#ifdef USING_FRONTEND
    490     return tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
     497    ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||
    491498           (bdPriv && bdPriv->IsOpen());
    492499#else // if !USING_FRONTEND
    493     return tfw || (fd2 > -1) || remotefile;
     500    ret = tfw || (fd2 > -1) || remotefile;
    494501#endif // !USING_FRONTEND
     502    rwlock.unlock();
     503    return ret;
    495504}
    496505
    497506/** \fn RingBuffer::~RingBuffer(void)
     
    535544    rwlock.unlock();
    536545}
    537546
    538 /** \fn RingBuffer::Start(void)
    539  *  \brief Starts the read-ahead thread.
    540  *
    541  *   If this RingBuffer is not in write-mode, the RingBuffer constructor
    542  *   was called with a usereadahead of true, and the read-ahead thread
    543  *   is not already running.
    544  */
    545 void RingBuffer::Start(void)
    546 {
    547     if (!writemode && !readaheadrunning && startreadahead)
    548         StartupReadAheadThread();
    549 }
    550 
    551547/** \fn RingBuffer::Reset(bool, bool, bool)
    552548 *  \brief Resets the read-ahead thread and our position in the file
    553549 */
    554550void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal)
    555551{
    556     wantseek = true;
     552    VERBOSE(VB_IMPORTANT, LOC + QString("Reset(%1,%2,%3)")
     553            .arg(full).arg(toAdjust).arg(resetInternal));
     554
    557555    rwlock.lockForWrite();
    558     wantseek = false;
     556    poslock.lockForWrite();
     557
    559558    numfailures = 0;
    560559    commserror = false;
    561560    setswitchtonext = false;
     
    579578    if (resetInternal)
    580579        internalreadpos = readpos;
    581580
     581    generalWait.wakeAll();
     582    poslock.unlock();
    582583    rwlock.unlock();
    583584}
    584585
     
    600601    unsigned errcnt = 0;
    601602    unsigned zerocnt = 0;
    602603
    603     if (fd < 0)
     604    if (fd2 < 0)
    604605    {
    605606        VERBOSE(VB_IMPORTANT, LOC_ERR +
    606607                "Invalid file descriptor in 'safe_read()'");
     
    612613
    613614    while (tot < sz)
    614615    {
    615         ret = read(fd, (char *)data + tot, sz - tot);
     616        ret = read(fd2, (char *)data + tot, sz - tot);
    616617        if (ret < 0)
    617618        {
    618619            if (errno == EAGAIN)
     
    674675        VERBOSE(VB_IMPORTANT, LOC_ERR +
    675676                "RingBuffer::safe_read(RemoteFile* ...): read failed");
    676677
     678        poslock.lockForRead();
    677679        rf->Seek(internalreadpos - readAdjust, SEEK_SET);
     680        poslock.unlock();
    678681        ret = 0;
    679682        numfailures++;
    680683     }
     
    689692 */
    690693void RingBuffer::UpdateRawBitrate(uint raw_bitrate)
    691694{
     695    VERBOSE(VB_FILE, LOC + QString("UpdateRawBitrate(%1Kb)").arg(raw_bitrate));
     696    if (raw_bitrate < 2500)
     697    {
     698        VERBOSE(VB_FILE, LOC +
     699                QString("UpdateRawBitrate(%1Kb) - ignoring bitrate,")
     700                .arg(raw_bitrate) +
     701                "\n\t\t\tappears to be abnormally low.");
     702        return;
     703    }
     704
    692705    rwlock.lockForWrite();
    693706    rawbitrate = raw_bitrate;
    694707    CalcReadAheadThresh();
    695708    rwlock.unlock();
    696709}
    697710
    698 /** \fn RingBuffer::GetBitrate(void) const
    699  *  \brief Returns effective bits per second (in thousands).
    700  *
    701  *   NOTE: This is reported in telecom kilobytes, to get
    702  *         the bits per second multiply by 1000, not 1024.
    703  */
    704 uint RingBuffer::GetBitrate(void) const
    705 {
    706     rwlock.lockForRead();
    707     uint tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
    708     rwlock.unlock();
    709     return min(rawbitrate * 3, tmp);
    710 }
    711 
    712 /** \fn RingBuffer::GetReadBlockSize(void) const
    713  *  \brief Returns size of each disk read made by read ahead thread (in bytes).
    714  */
    715 uint RingBuffer::GetReadBlockSize(void) const
    716 {
    717     rwlock.lockForRead();
    718     uint tmp = readblocksize;
    719     rwlock.unlock();
    720     return tmp;
    721 }
    722 
    723711/** \fn RingBuffer::UpdatePlaySpeed(float)
    724712 *  \brief Set the play speed, to allow RingBuffer adjust effective bitrate.
    725713 *  \param play_speed Speed to set. (1.0 for normal speed)
     
    743731{
    744732    uint estbitrate = 0;
    745733
    746     wantseek       = false;
    747734    readsallowed   = false;
    748     readblocksize  = CHUNK;
     735    readblocksize  = max(readblocksize, CHUNK);
    749736
    750737    // loop without sleeping if the buffered data is less than this
    751     fill_threshold = CHUNK * 2;
    752     fill_min       = 1;
     738    fill_threshold = kBufferSize / 8;
    753739
    754 #ifdef USING_FRONTEND
    755     if (dvdPriv || bdPriv)
    756     {
    757         const uint KB32  =  32*1024;
    758         const uint KB64  =  64*1024;
    759         const uint KB128 = 128*1024;
    760         const uint KB256 = 256*1024;
    761         const uint KB512 = 512*1024;
     740    const uint KB32  =  32*1024;
     741    const uint KB64  =  64*1024;
     742    const uint KB128 = 128*1024;
     743    const uint KB256 = 256*1024;
     744    const uint KB512 = 512*1024;
    762745
    763         estbitrate     = (uint) max(abs(rawbitrate * playspeed),
    764                                     0.5f * rawbitrate);
    765         estbitrate     = min(rawbitrate * 3, estbitrate);
    766         readblocksize  = (estbitrate > 2500)  ? KB64  : KB32;
    767         readblocksize  = (estbitrate > 5000)  ? KB128 : readblocksize;
    768         readblocksize  = (estbitrate > 9000)  ? KB256 : readblocksize;
    769         readblocksize  = (estbitrate > 18000) ? KB512 : readblocksize;
     746    estbitrate     = (uint) max(abs(rawbitrate * playspeed),
     747                                0.5f * rawbitrate);
     748    estbitrate     = min(rawbitrate * 3, estbitrate);
     749    int rbs        = (estbitrate > 2500)  ? KB64  : KB32;
     750    rbs            = (estbitrate > 5000)  ? KB128 : rbs;
     751    rbs            = (estbitrate > 9000)  ? KB256 : rbs;
     752    rbs            = (estbitrate > 18000) ? KB512 : rbs;
     753    readblocksize  = max(rbs,readblocksize);
    770754
    771         // minumum seconds of buffering before allowing read
    772         float secs_min = 0.1;
     755    // minumum seconds of buffering before allowing read
     756    float secs_min = 0.25;
     757    // set the minimum buffering before allowing ffmpeg read
     758    fill_min        = (uint) ((estbitrate * secs_min) * 0.125f);
     759    // make this a multiple of ffmpeg block size..
     760    fill_min        = ((fill_min / KB32) + 1) * KB32;
    773761
    774         // set the minimum buffering before allowing ffmpeg read
    775         fill_min        = (uint) ((estbitrate * secs_min) * 0.125f);
    776         // make this a multiple of ffmpeg block size..
    777         fill_min        = ((fill_min / KB32) + 1) * KB32;
    778     }
    779 #endif // USING_FRONTEND
    780 
    781     VERBOSE(VB_PLAYBACK, LOC +
    782             QString("CalcReadAheadThresh(%1 KB)\n\t\t\t -> "
     762    VERBOSE(VB_FILE, LOC +
     763            QString("CalcReadAheadThresh(%1 Kb)\n\t\t\t -> "
    783764                    "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)")
    784765            .arg(estbitrate).arg(fill_threshold/1024)
    785766            .arg(fill_min/1024).arg(readblocksize/1024));
    786767}
    787768
    788 /** \fn RingBuffer::ReadBufFree(void) const
    789  *  \brief Returns number of bytes available for reading into buffer.
    790  */
     769bool RingBuffer::IsNearEnd(double fps, uint vvf) const
     770{
     771    rwlock.lockForRead();
     772    int    sz  = ReadBufAvail();
     773    uint   rbs = readblocksize;
     774    // telecom kilobytes (i.e. 1000 per k not 1024)
     775    uint   tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);
     776    uint   kbits_per_sec = min(rawbitrate * 3, tmp);
     777    rwlock.unlock();
     778
     779    // WARNING: readahead_frames can greatly overestimate or underestimate
     780    //          the number of frames available in the read ahead buffer
     781    //          when rh_frames is less than the keyframe distance.
     782    double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps;
     783    double readahead_frames = sz / bytes_per_frame;
     784
     785    bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5);
     786
     787    VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()"
     788            <<" br("<<(kbits_per_sec/8)<<"KB)"
     789            <<" sz("<<(sz / 1000)<<"KB)"
     790            <<" vfl("<<vvf<<")"
     791            <<" frh("<<((uint)readahead_frames)<<")"
     792            <<" ne:"<<near_end);
     793
     794    return near_end;
     795}
     796
     797/// \brief Returns number of bytes available for reading into buffer.
     798/// WARNING: Must be called with rwlock in locked state.
    791799int RingBuffer::ReadBufFree(void) const
    792800{
    793     QMutexLocker locker(&readAheadLock);
    794     return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     801    rbrlock.lockForRead();
     802    rbwlock.lockForRead();
     803    int ret = ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1;
     804    rbwlock.unlock();
     805    rbrlock.unlock();
     806    return ret;
    795807}
    796808
    797 /** \fn RingBuffer::ReadBufAvail(void) const
    798  *  \brief Returns number of bytes available for reading from buffer.
    799  */
     809/// \brief Returns number of bytes available for reading from buffer.
     810/// WARNING: Must be called with rwlock in locked state.
    800811int RingBuffer::ReadBufAvail(void) const
    801812{
    802     QMutexLocker locker(&readAheadLock);
    803     return (rbwpos >= rbrpos) ?
    804         rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     813    rbrlock.lockForRead();
     814    rbwlock.lockForRead();
     815    int ret = (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos;
     816    rbwlock.unlock();
     817    rbrlock.unlock();
     818    return ret;
    805819}
    806820
    807821/** \fn RingBuffer::ResetReadAhead(long long)
     
    811825 *   buffer doesn't contain any stale data, and so that it will read
    812826 *   any new data from the new position in the file.
    813827 *
    814  *   WARNING: Must be called with rwlock in write lock state.
     828 *   WARNING: Must be called with rwlock and poslock in write lock state.
    815829 *
    816830 *  \param newinternal Position in file to start reading data from
    817831 */
    818832void RingBuffer::ResetReadAhead(long long newinternal)
    819833{
    820     readAheadLock.lock();
    821     readblocksize = CHUNK;
     834    VERBOSE(VB_FILE, LOC + QString("ResetReadAhead(internalreadpos = %1->%2)")
     835            .arg(internalreadpos).arg(newinternal));
     836
     837    rbrlock.lockForWrite();
     838    rbwlock.lockForWrite();
     839
     840    CalcReadAheadThresh();
    822841    rbrpos = 0;
    823842    rbwpos = 0;
    824843    internalreadpos = newinternal;
    825844    ateof = false;
    826845    readsallowed = false;
    827846    setswitchtonext = false;
    828     readAheadLock.unlock();
     847    generalWait.wakeAll();
     848
     849    rbwlock.unlock();
     850    rbrlock.unlock();
    829851}
    830852
    831 /** \fn RingBuffer::StartupReadAheadThread(void)
    832  *  \brief Creates the read-ahead thread, and waits for it to start.
     853/**
     854 *  \brief Starts the read-ahead thread.
    833855 *
    834  *  \sa Start(void).
     856 *   If the RingBuffer constructor was not called with a usereadahead
     857 *   of true of if this was reset to false because we're dealing with
     858 *   a DVD the read ahead thread will not be started.
     859 *
     860 *   If this RingBuffer is in write-mode a warning will be printed and
     861 *   the read ahead thread will not be started.
     862 *
     863 *   If the read ahead thread is already running a warning will be printed
     864 *   and the read ahead thread will not be started.
     865 *
    835866 */
    836 void RingBuffer::StartupReadAheadThread(void)
     867void RingBuffer::Start(void)
    837868{
    838     readaheadrunning = false;
     869    bool do_start = true;
    839870
    840     readAheadRunningCondLock.lock();
     871    rwlock.lockForWrite();
     872    if (!startreadahead)
     873    {
     874        do_start = false;
     875    }
     876    else if (writemode)
     877    {
     878        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     879                "this is a write only RingBuffer");
     880        do_start = false;
     881    }
     882    else if (readaheadrunning)
     883    {
     884        VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, "
     885                "already running");
     886        do_start = false;
     887    }
     888
     889    if (!do_start)
     890    {
     891        rwlock.unlock();
     892        return;
     893    }
     894
     895    StartReads();
     896
    841897    QThread::start();
    842     readAheadRunningCond.wait(&readAheadRunningCondLock);
    843     readAheadRunningCondLock.unlock();
     898
     899    while (readaheadrunning && !reallyrunning)
     900        generalWait.wait(&rwlock);
     901
     902    rwlock.unlock();
    844903}
    845904
    846905/** \fn RingBuffer::KillReadAheadThread(void)
     
    848907 */
    849908void RingBuffer::KillReadAheadThread(void)
    850909{
    851     if (!readaheadrunning)
    852         return;
     910    rwlock.lockForWrite();
     911    bool do_wait = readaheadrunning;
     912    readaheadrunning = false;
     913    StopReads();
     914    generalWait.wakeAll();
     915    rwlock.unlock();
    853916
    854     readaheadrunning = false;
    855     QThread::wait();
     917    if (do_wait)
     918        QThread::wait();
    856919}
    857920
    858921/** \fn RingBuffer::StopReads(void)
     
    862925void RingBuffer::StopReads(void)
    863926{
    864927    stopreads = true;
    865     availWait.wakeAll();
     928    generalWait.wakeAll();
    866929}
    867930
    868931/** \fn RingBuffer::StartReads(void)
     
    880943 */
    881944void RingBuffer::Pause(void)
    882945{
    883     pausereadthread = true;
    884946    StopReads();
     947
     948    rwlock.lockForWrite();
     949    request_pause = true;
     950    rwlock.unlock();
    885951}
    886952
    887953/** \fn RingBuffer::Unpause(void)
     
    891957void RingBuffer::Unpause(void)
    892958{
    893959    StartReads();
    894     pausereadthread = false;
     960
     961    rwlock.lockForWrite();
     962    request_pause = false;
     963    generalWait.wakeAll();
     964    rwlock.unlock();
    895965}
    896966
     967/// Returns false iff read-ahead is not running and read-ahead is not paused.
     968bool RingBuffer::isPaused(void) const
     969{
     970    rwlock.lockForRead();
     971    bool ret = !readaheadrunning || paused;
     972    rwlock.unlock();
     973    return ret;
     974}
     975
    897976/** \fn RingBuffer::WaitForPause(void)
    898977 *  \brief Waits for Pause(void) to take effect.
    899978 */
    900979void RingBuffer::WaitForPause(void)
    901980{
    902     if (!readaheadrunning)
    903         return;
     981    MythTimer t;
     982    t.start();
    904983
    905     if  (!readaheadpaused)
     984    rwlock.lockForRead();
     985    while (readaheadrunning && !paused && request_pause)
    906986    {
    907         // Qt4 requires a QMutex as a parameter...
    908         // not sure if this is the best solution.  Mutex Must be locked before wait.
    909         QMutex mutex;
    910         mutex.lock();
     987        generalWait.wait(&rwlock, 1000);
     988        if (readaheadrunning && !paused && request_pause && t.elapsed() > 1000)
     989        {
     990            VERBOSE(VB_IMPORTANT, LOC +
     991                    QString("Waited %1 ms for ringbuffer pause..")
     992                    .arg(t.elapsed()));
     993        }
     994    }
     995    rwlock.unlock();
     996}
    911997
    912         while (!pauseWait.wait(&mutex, 1000))
    913             VERBOSE(VB_IMPORTANT,
    914                     LOC + "Waited too long for ringbuffer pause..");
     998bool RingBuffer::PauseAndWait(void)
     999{
     1000    const uint timeout = 500; // ms
     1001
     1002    if (request_pause)
     1003    {
     1004        if (!paused)
     1005        {
     1006            rwlock.unlock();
     1007            rwlock.lockForWrite();
     1008
     1009            if (request_pause)
     1010            {
     1011                paused = true;
     1012                generalWait.wakeAll();
     1013            }
     1014
     1015            rwlock.unlock();
     1016            rwlock.lockForRead();
     1017        }
     1018
     1019        if (request_pause && paused && readaheadrunning)
     1020            generalWait.wait(&rwlock, timeout);
    9151021    }
     1022
     1023    if (!request_pause && paused)
     1024    {
     1025        rwlock.unlock();
     1026        rwlock.lockForWrite();
     1027
     1028        if (!request_pause)
     1029        {
     1030            paused = false;
     1031            generalWait.wakeAll();
     1032        }
     1033
     1034        rwlock.unlock();
     1035        rwlock.lockForRead();
     1036    }
     1037
     1038    return request_pause || paused;
    9161039}
    9171040
    9181041void RingBuffer::run(void)
    9191042{
    920     long long totfree = 0;
    921     int ret = -1;
    922     int used = 0;
    923     int loops = 0;
    924 
     1043    // These variables are used to adjust the read block size
    9251044    struct timeval lastread, now;
    926     gettimeofday(&lastread, NULL);
    927     const int KB640 = 640*1024;
    9281045    int readtimeavg = 300;
    929     int readinterval;
     1046    bool ignore_for_read_timing = true;
    9301047
    931     pausereadthread = false;
     1048    gettimeofday(&lastread, NULL); // this is just to keep gcc happy
    9321049
    933     readAheadBuffer = new char[kBufferSize + KB640];
    934 
    9351050    rwlock.lockForWrite();
     1051    poslock.lockForWrite();
     1052    request_pause = false;
     1053    readAheadBuffer = new char[kBufferSize + 1024];
    9361054    ResetReadAhead(0);
     1055    readaheadrunning = true;
     1056    reallyrunning = true;
     1057    generalWait.wakeAll();
     1058    poslock.unlock();
    9371059    rwlock.unlock();
    9381060
    939     totfree = ReadBufFree();
     1061    // NOTE: this must loop at some point hold only
     1062    // a read lock on rwlock, so that other functions
     1063    // such as reset and seek can take priority.
    9401064
    941     readaheadrunning = true;
    942     readAheadRunningCondLock.lock();
    943     readAheadRunningCond.wakeAll();
    944     readAheadRunningCondLock.unlock();
     1065    rwlock.lockForRead();
     1066
     1067    VERBOSE(VB_FILE, LOC + QString("Initial readblocksize %1K & fill_min %2K")
     1068            .arg(readblocksize/1024).arg(fill_min/1024));
     1069
    9451070    while (readaheadrunning)
    9461071    {
    947         if (pausereadthread || writemode)
     1072        if (PauseAndWait())
    9481073        {
    949             readaheadpaused = true;
    950             pauseWait.wakeAll();
    951             usleep(5000);
    952             totfree = ReadBufFree();
     1074            ignore_for_read_timing = true;
    9531075            continue;
    9541076        }
    9551077
    956         if (readaheadpaused)
     1078        long long totfree = ReadBufFree();
     1079
     1080        if (totfree < readblocksize)
    9571081        {
    958             totfree = ReadBufFree();
    959             readaheadpaused = false;
     1082            generalWait.wait(&rwlock, 1000);
     1083            continue;
    9601084        }
    9611085
    962         totfree = ReadBufFree();
    963         if (totfree < GetReadBlockSize())
     1086        if (ignorereadpos >= 0)
    9641087        {
    965             usleep(50000);
    966             totfree = ReadBufFree();
    967             ++loops;
    968             // break out if we've spent lots of time here, just in case things
    969             // are waiting on a wait condition that never got triggered.
    970             if (readsallowed && loops < 10)
    971                 continue;
     1088            generalWait.wait(&rwlock, 1000);
     1089            continue;
    9721090        }
    973         loops = 0;
    9741091
    975         rwlock.lockForRead();
    976         if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext)
     1092        // No point in trying to read if stopreads is set but do sleep
     1093        // a little so we don't get stuck in a tight busy loop here..
     1094        if (stopreads)
    9771095        {
     1096            ignore_for_read_timing = true;
     1097            generalWait.wait(&rwlock, 10);
     1098            continue;
     1099        }
     1100
     1101        int read_return = -1;
     1102        if (totfree >= readblocksize && !commserror &&
     1103            !ateof && !setswitchtonext)
     1104        {
    9781105            // limit the read size
    9791106            totfree = readblocksize;
    9801107
    9811108            // adapt blocksize
    9821109            gettimeofday(&now, NULL);
    983             readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
    984                            (now.tv_usec - lastread.tv_usec) / 1000;
     1110            if (!ignore_for_read_timing)
     1111            {
     1112                int readinterval = (now.tv_sec  - lastread.tv_sec ) * 1000 +
     1113                    (now.tv_usec - lastread.tv_usec) / 1000;
     1114                readtimeavg = (readtimeavg * 9 + readinterval) / 10;
    9851115
    986             readtimeavg = (readtimeavg * 9 + readinterval) / 10;
     1116                if (readtimeavg < 200 && (uint)readblocksize < (kBufferSize>>2))
     1117                {
     1118                    readblocksize = 3 * readblocksize / 2;
     1119                    readblocksize = ((readblocksize+CHUNK-1) / CHUNK) * CHUNK;
    9871120
    988             if (readtimeavg < 200 && readblocksize < KB640)
    989             {
    990                 readblocksize += CHUNK;
    991                 //VERBOSE(VB_PLAYBACK,
    992                 //    QString("Avg read interval was %1 msec. %2K block size")
    993                 //            .arg(readtimeavg).arg(readblocksize/1024));
    994                 readtimeavg = 300;
     1121                    VERBOSE(VB_FILE, LOC +
     1122                            QString("Avg read interval was %1 msec. "
     1123                                    "%2K -> %3K block size")
     1124                            .arg(readtimeavg)
     1125                            .arg(readblocksize/2048)
     1126                            .arg(readblocksize/1024));
     1127                    readtimeavg = 300;
     1128                }
     1129                else if (readtimeavg > 400 && readblocksize > CHUNK)
     1130                {
     1131                    readblocksize -= CHUNK;
     1132                    VERBOSE(VB_FILE, LOC +
     1133                            QString("Avg read interval was %1 msec. "
     1134                                    "%2K -> %3K block size")
     1135                            .arg(readtimeavg)
     1136                            .arg((readblocksize+CHUNK)/1024)
     1137                            .arg(readblocksize/1024));
     1138                    readtimeavg = 300;
     1139                }
    9951140            }
    996             else if (readtimeavg > 400 && readblocksize > CHUNK)
    997             {
    998                 readblocksize -= CHUNK;
    999                 //VERBOSE(VB_PLAYBACK,
    1000                 //    QString("Avg read interval was %1 msec. %2K block size")
    1001                 //            .arg(readtimeavg).arg(readblocksize/1024));
    1002                 readtimeavg = 300;
    1003             }
     1141            ignore_for_read_timing = false;
    10041142            lastread = now;
    10051143
     1144            rbwlock.lockForRead();
    10061145            if (rbwpos + totfree > kBufferSize)
     1146            {
    10071147                totfree = kBufferSize - rbwpos;
     1148                VERBOSE(VB_FILE, LOC + "totfree = kBufferSize - rbwpos");
     1149            }
    10081150
    10091151            if (internalreadpos == 0)
    1010                 totfree = fill_min;
     1152            {
     1153                totfree = max(fill_min, readblocksize);
     1154                VERBOSE(VB_FILE, LOC +
     1155                        "totfree = max(fill_min,readblocksize)");
     1156            }
    10111157
    10121158            if (remotefile)
    10131159            {
     1160                VERBOSE(VB_FILE, LOC + QString("safe_read(*, @%1, %2) -- begin")
     1161                        .arg(rbwpos).arg(totfree));
    10141162                if (livetvchain && livetvchain->HasNext())
    10151163                    remotefile->SetTimeout(true);
    1016 
    1017                 ret = safe_read(remotefile, readAheadBuffer + rbwpos,
    1018                                 totfree);
    1019                 internalreadpos += ret;
     1164                read_return = safe_read(
     1165                    remotefile, readAheadBuffer + rbwpos, totfree);
     1166                VERBOSE(VB_FILE, LOC + QString("safe_read(*, @%1, %2) -> %3")
     1167                        .arg(rbwpos).arg(totfree).arg(read_return));
    10201168            }
    10211169#ifdef USING_FRONTEND
    10221170            else if (dvdPriv)
    10231171            {
    1024                 ret = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1025                 internalreadpos += ret;
     1172                read_return = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    10261173            }
    10271174            else if (bdPriv)
    10281175            {
    1029                 ret = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    1030                 internalreadpos += ret;
     1176                read_return = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);
    10311177            }
    10321178#endif // USING_FRONTEND
    10331179            else
    10341180            {
    1035                 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    1036                 internalreadpos += ret;
     1181                read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree);
    10371182            }
     1183            rbwlock.unlock();
     1184        }
    10381185
    1039             readAheadLock.lock();
    1040             if (ret > 0 )
    1041                 rbwpos = (rbwpos + ret) % kBufferSize;
    1042             readAheadLock.unlock();
     1186        // If stopreads is set we toss the read data since we're probably
     1187        // doing a seek or opening a new file anyway.
     1188        if (stopreads)
     1189        {
     1190            VERBOSE(VB_FILE, LOC + " -- stopreads");
     1191            continue;
     1192        }
    10431193
    1044             if (ret == 0 && !stopreads)
     1194        if (read_return >= 0)
     1195        {
     1196            poslock.lockForWrite();
     1197            rbwlock.lockForWrite();
     1198            internalreadpos += read_return;
     1199            rbwpos = (rbwpos + read_return) % kBufferSize;
     1200            VERBOSE(VB_FILE, LOC + QString("rbwpos += %1K totfree = %2K")
     1201                    .arg(read_return/1024,3).arg(totfree/1024,3));
     1202            rbwlock.unlock();
     1203            poslock.unlock();
     1204        }
     1205
     1206        int used = kBufferSize - ReadBufFree();
     1207
     1208        if ((0 == read_return) || (numfailures > 5) ||
     1209            (readsallowed != (used >= fill_min || ateof ||
     1210                              setswitchtonext || commserror)))
     1211        {
     1212            rwlock.unlock();
     1213            rwlock.lockForWrite();
     1214
     1215            commserror |= (numfailures > 5);
     1216
     1217            readsallowed = used >= fill_min || ateof ||
     1218                setswitchtonext || commserror;
     1219
     1220            if (0 == read_return)
    10451221            {
    10461222                if (livetvchain)
    10471223                {
     
    10531229                    }
    10541230                }
    10551231                else
     1232                {
    10561233                    ateof = true;
     1234                }
    10571235            }
    1058         }
    10591236
    1060         if (numfailures > 5)
    1061             commserror = true;
    1062 
    1063         totfree = ReadBufFree();
    1064         used = kBufferSize - totfree;
    1065 
    1066         if (ateof || commserror)
    1067         {
    1068             readsallowed = true;
    1069             totfree = 0;
     1237            rwlock.unlock();
     1238            rwlock.lockForRead();
     1239            used = kBufferSize - ReadBufFree();
    10701240        }
    10711241
    1072         if (!readsallowed && (used >= fill_min || setswitchtonext))
    1073         {
    1074             readsallowed = true;
    1075             //VERBOSE(VB_PLAYBACK, QString("reads allowed (%1 %2)").arg(used)
    1076             //                                                    .arg(fill_min));
    1077         }
    1078         //else if (!readsallowed)
    1079         //    VERBOSE(VB_PLAYBACK, QString("buffering (%1 %2 %3)").arg(used)
    1080         //                                                        .arg(fill_min)
    1081         //                                                        .arg(ret));
     1242        VERBOSE(VB_FILE, LOC + " -- end of loop");
    10821243
    1083         if (readsallowed && used < fill_min && !ateof && !setswitchtonext)
     1244        if (readsallowed || stopreads || commserror || ateof ||
     1245            setswitchtonext || (wanttoread <= used && wanttoread > 0))
    10841246        {
    1085             readsallowed = false;
    1086             //VERBOSE(VB_GENERAL, QString ("rebuffering (%1 %2)").arg(used)
    1087             //                                                   .arg(fill_min));
     1247            generalWait.wakeAll();
     1248            rwlock.unlock();
     1249            usleep(5 * 1000);
     1250            rwlock.lockForRead();           
    10881251        }
    1089 
    1090         readsAllowedWaitMutex.lock();
    1091         if (readsallowed || stopreads)
    1092             readsAllowedWait.wakeAll();
    1093         readsAllowedWaitMutex.unlock();
    1094 
    1095         availWaitMutex.lock();
    1096         if (commserror || ateof || stopreads || setswitchtonext ||
    1097             (wanttoread <= used && wanttoread > 0))
     1252        else
    10981253        {
    1099             availWait.wakeAll();
     1254            // yield if we have nothing to do...
     1255            if (!request_pause &&
     1256                (used >= fill_threshold || ateof || setswitchtonext))
     1257            {
     1258                generalWait.wait(&rwlock, 100);
     1259            }
    11001260        }
    1101         availWaitMutex.unlock();
     1261    }
    11021262
    1103         rwlock.unlock();
     1263    rwlock.unlock();
    11041264
    1105         if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&
    1106             !pausereadthread)
    1107         {
    1108             usleep(500);
    1109         }
    1110     }
    1111 
    11121265    delete [] readAheadBuffer;
    11131266    readAheadBuffer = NULL;
     1267
     1268    rwlock.lockForWrite();
     1269    rbrlock.lockForWrite();
     1270    rbwlock.lockForWrite();
    11141271    rbrpos = 0;
    11151272    rbwpos = 0;
     1273    reallyrunning = false;
     1274    rbwlock.unlock();
     1275    rbrlock.unlock();
     1276    rwlock.unlock();
    11161277}
    11171278
    11181279long long RingBuffer::SetAdjustFilesize(void)
    11191280{
     1281    rwlock.lockForWrite();
     1282    poslock.lockForRead();
    11201283    readAdjust += internalreadpos;
     1284    poslock.unlock();
     1285    rwlock.unlock();
    11211286    return readAdjust;
    11221287}
    11231288
    11241289int RingBuffer::Peek(void *buf, int count)
    11251290{
    1126     long long ret = -1;
    1127 
    1128     if (!readaheadrunning)
    1129     {
    1130         long long old_pos = Seek(0, SEEK_CUR);
    1131 
    1132         ret = Read(buf, count);
    1133 #ifdef USING_FRONTEND
    1134         if (ret > 0 && dvdPriv)
    1135         {
    1136             // This is technically incorrect it we should seek
    1137             // back to exactly where we were, but we can't do
    1138             // that with the DVDRingBuffer
    1139             dvdPriv->NormalSeek(0);
    1140         }
    1141         else if (ret > 0 && bdPriv)
    1142         {
    1143             // No idea if this will work.
    1144             bdPriv->Seek(0);
    1145         }
    1146         else
    1147 #endif // USING_FRONTEND
    1148         if (ret > 0)
    1149         {
    1150             long long new_pos = Seek(-ret, SEEK_CUR);
    1151             if (new_pos != old_pos)
    1152             {
    1153                 VERBOSE(VB_IMPORTANT, LOC_ERR +
    1154                         QString("Peek() Failed to return from new "
    1155                                 "position %1 to old position %2, now "
    1156                                 "at position %3")
    1157                         .arg(old_pos - ret).arg(old_pos).arg(new_pos));
    1158             }
    1159         }
    1160     }
    1161     else
    1162     {
    1163         ret = ReadFromBuf(buf, count, true);
    1164     }
    1165 
     1291    int ret = ReadPriv(buf, count, true);
    11661292    if (ret != count)
    11671293    {
    11681294        VERBOSE(VB_IMPORTANT, LOC_WARN +
     
    11721298    return ret;
    11731299}
    11741300
    1175 /**
    1176  *  \brief Reads from the read-ahead buffer, this is called by
    1177  *         Read(void*, int) when the read-ahead thread is running.
    1178  *  \param buf   Pointer to where data will be written
    1179  *  \param count Number of bytes to read
    1180  *  \param peek  If true, don't increment read count
    1181  *  \return Returns number of bytes read
    1182  */
    1183 int RingBuffer::ReadFromBuf(void *buf, int count, bool peek)
     1301bool RingBuffer::WaitForReadsAllowed(void)
    11841302{
    1185     if (commserror)
    1186         return 0;
     1303    MythTimer t;
     1304    t.start();
    11871305
    1188     bool readone = false;
    1189     int readErr = 0;
    1190 
    1191     if (readaheadpaused && stopreads)
     1306    while (!readsallowed && !stopreads &&
     1307           !request_pause && !commserror && readaheadrunning)
    11921308    {
    1193         readone = true;
    1194         Unpause();
    1195     }
    1196     else
    1197     {
    1198         QMutexLocker locker(&readsAllowedWaitMutex);
     1309        generalWait.wait(&rwlock, 1000);
     1310        if (!readsallowed && t.elapsed() > 1000)
     1311        {
     1312            VERBOSE(VB_IMPORTANT,
     1313                    LOC + "Taking too long to be allowed to read..");
    11991314
    1200         while (!readsallowed && !stopreads)
    1201         {
    1202             if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000))
     1315            if (t.elapsed() > 10000)
    12031316            {
    1204                  VERBOSE(VB_IMPORTANT,
    1205                          LOC + "Taking too long to be allowed to read..");
    1206                  readErr++;
    1207 
    1208                  // HACK Sometimes the readhead thread gets borked on startup.
    1209                  if ((readErr > 4 && readErr % 2) && (rbrpos ==0))
    1210                  {
    1211                     VERBOSE(VB_IMPORTANT, "restarting readhead thread..");
    1212                     KillReadAheadThread();
    1213                     StartupReadAheadThread();
    1214                  }
    1215 
    1216                  if (readErr > 10)
    1217                  {
    1218                      VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
    1219                              "10 seconds to be allowed to read, aborting.");
    1220                      wanttoread = 0;
    1221                      stopreads = true;
    1222                      return 0;
    1223                  }
     1317                VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than "
     1318                        "10 seconds to be allowed to read, aborting.");
     1319                return false;
    12241320            }
    12251321        }
    12261322    }
    12271323
     1324    return readsallowed;
     1325}
     1326
     1327bool RingBuffer::WaitForAvail(int count)
     1328{
    12281329    int avail = ReadBufAvail();
     1330    count = (ateof && avail < count) ? avail : count;
    12291331
    1230     if (ateof && avail < count)
    1231         count = avail;
    1232 
    12331332    MythTimer t;
    12341333    t.start();
    1235     while (avail < count && !stopreads)
     1334    while ((avail < count) && !stopreads &&
     1335           !request_pause && !commserror && readaheadrunning)
    12361336    {
    1237         availWaitMutex.lock();
    12381337        wanttoread = count;
    1239         if (!availWait.wait(&availWaitMutex, 250))
     1338        generalWait.wait(&rwlock, 250);
     1339        avail = ReadBufAvail();
     1340
     1341        if ((ateof || setswitchtonext) && avail < count)
     1342            count = avail;
     1343
     1344        if (avail < count)
    12401345        {
    12411346            int elapsed = t.elapsed();
    1242             if  (/*((elapsed > 500)  && (elapsed < 750))  ||*/
     1347            if  (((elapsed > 250)  && (elapsed < 500))  ||
     1348                 ((elapsed > 500)  && (elapsed < 750))  ||
    12431349                 ((elapsed > 1000) && (elapsed < 1250)) ||
    12441350                 ((elapsed > 2000) && (elapsed < 2250)) ||
    12451351                 ((elapsed > 4000) && (elapsed < 4250)) ||
    1246                  ((elapsed > 8000) && (elapsed < 8250)))
     1352                 ((elapsed > 8000) && (elapsed < 8250)) ||
     1353                 ((elapsed > 9000)))
    12471354            {
    12481355                VERBOSE(VB_IMPORTANT, LOC + "Waited " +
    1249                         QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) +
    1250                         " seconds for data to become available...");
     1356                        QString("%1").arg((elapsed / 250) * 0.25f, 3, 'f', 1) +
     1357                        " seconds for data \n\t\t\tto become available..." +
     1358                        QString(" %2 < %3")
     1359                        .arg(avail).arg(count));
    12511360                if (livetvchain)
    12521361                {
    12531362                    VERBOSE(VB_IMPORTANT, "Checking to see if there's a "
     
    12701379                    VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to "
    12711380                            "impending livetv switch.");
    12721381
    1273                 ateof = true;
    1274                 wanttoread = 0;
    1275                 stopreads = true;
    1276                 availWaitMutex.unlock();
    1277                 return 0;
     1382                return false;
    12781383            }
    12791384        }
     1385    }
    12801386
     1387    wanttoread = 0;
     1388
     1389    return avail >= count;
     1390}
     1391
     1392int RingBuffer::ReadDirect(void *buf, int count, bool peek)
     1393{
     1394    long long old_pos = 0;
     1395    if (peek)
     1396    {
     1397        poslock.lockForRead();
     1398        old_pos = (ignorereadpos >= 0) ? ignorereadpos : readpos;
     1399        poslock.unlock();
     1400    }
     1401
     1402    int ret;
     1403    if (remotefile)
     1404        ret = safe_read(remotefile, buf, count);
     1405#ifdef USING_FRONTEND
     1406    else if (dvdPriv)
     1407        ret = dvdPriv->safe_read(buf, count);
     1408    else if (bdPriv)
     1409        ret = bdPriv->safe_read(buf, count);
     1410#endif // USING_FRONTEND
     1411    else if (fd2 >= 0)
     1412        ret = safe_read(fd2, buf, count);
     1413    else
     1414    {
     1415        ret = -1;
     1416        errno = EBADF;
     1417    }
     1418
     1419    poslock.lockForWrite();
     1420    if (ignorereadpos >= 0 && ret > 0)
     1421    {
     1422        if (peek)
     1423        {
     1424            if (remotefile)
     1425                remotefile->Seek(old_pos, SEEK_SET);
     1426            else
     1427                lseek64(fd2, old_pos, SEEK_SET);
     1428        }
     1429        else
     1430        {
     1431            ignorereadpos += ret;
     1432        }
     1433        poslock.unlock();
     1434        return ret;
     1435    }
     1436    poslock.unlock();
     1437
     1438    if (peek && ret > 0)
     1439    {
     1440        if (!dvdPriv && !bdPriv)
     1441        {
     1442            long long new_pos = Seek(old_pos, SEEK_SET, true);
     1443            if (new_pos != old_pos)
     1444            {
     1445                VERBOSE(VB_IMPORTANT, LOC_ERR +
     1446                        QString("Peek() Failed to return from new "
     1447                                "position %1 to old position %2, now "
     1448                                "at position %3")
     1449                        .arg(old_pos - ret).arg(old_pos).arg(new_pos));
     1450            }
     1451        }
     1452        else if (old_pos != 0)
     1453        {
     1454            VERBOSE(VB_IMPORTANT, LOC_ERR +
     1455                    "DVD and Blu-Ray do not support arbitrary "
     1456                    "peeks except when read-ahead is enabled."
     1457                    "\n\t\t\tWill seek to beginning of video.");
     1458        }
     1459#ifdef USING_FRONTEND
     1460        if (dvdPriv)
     1461        {
     1462            dvdPriv->NormalSeek(0);
     1463        }
     1464        else if (bdPriv)
     1465        {
     1466            bdPriv->Seek(0);
     1467        }
     1468#endif // USING_FRONTEND
     1469    }
     1470
     1471    return ret;
     1472}
     1473
     1474/** \brief When possible reads from the read-ahead buffer,
     1475 *         otherwise reads directly from the device.
     1476 *
     1477 *  \param buf   Pointer to where data will be written
     1478 *  \param count Number of bytes to read
     1479 *  \param peek  If true, don't increment read count
     1480 *  \return Returns number of bytes read
     1481 */
     1482int RingBuffer::ReadPriv(void *buf, int count, bool peek)
     1483{
     1484    VERBOSE(VB_FILE, LOC + QString("ReadPriv(*, %1, %2) @%3 -- begin")
     1485            .arg(count).arg(peek?"peek":"normal").arg(rbrpos));
     1486
     1487    rwlock.lockForRead();
     1488    if (writemode)
     1489    {
     1490        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1491                "Attempt to read from a write only file");
     1492        errno = EBADF;
     1493        rwlock.unlock();
     1494        return -1;
     1495    }
     1496
     1497    if (commserror)
     1498    {
     1499        VERBOSE(VB_IMPORTANT, LOC_ERR +
     1500                "Attempt to read after commserror set");
     1501        errno = EIO;
     1502        rwlock.unlock();
     1503        return -1;
     1504    }
     1505
     1506    if (request_pause || stopreads || !readaheadrunning || (ignorereadpos>=0))
     1507    {
     1508        rwlock.unlock();
     1509        rwlock.lockForWrite();
     1510        // we need a write lock so the read-ahead thread
     1511        // can't start mucking with the read position.
     1512        // If the read ahead thread was started while we
     1513        // didn't hold the lock, we proceed with a normal
     1514        // read from the buffer, otherwise we read directly.
     1515        if (request_pause || stopreads ||
     1516            !readaheadrunning || (ignorereadpos >= 0))
     1517        {
     1518            int ret = ReadDirect(buf, count, peek);
     1519            VERBOSE(VB_FILE, LOC + QString("ReadPriv(*, %1, %2) @%3 -- RD checksum %4")
     1520                    .arg(count).arg(peek?"peek":"normal").arg(rbrpos)
     1521                    .arg(qChecksum((char*)buf,count)));
     1522            rwlock.unlock();
     1523            return ret;
     1524        }
     1525        rwlock.unlock();
     1526        rwlock.lockForRead();
     1527    }
     1528
     1529    if (!WaitForReadsAllowed())
     1530    {
     1531        VERBOSE(VB_FILE, LOC + "!WaitForReadsAllowed()");
     1532        rwlock.unlock();
     1533        rwlock.lockForWrite();
    12811534        wanttoread = 0;
    1282         availWaitMutex.unlock();
     1535        stopreads = true;
     1536        rwlock.unlock();
     1537        return 0;
     1538    }
    12831539
    1284         avail = ReadBufAvail();
    1285         if ((ateof || setswitchtonext) && avail < count)
    1286             count = avail;
     1540    if (!WaitForAvail(count))
     1541    {
     1542        VERBOSE(VB_FILE, LOC + "!WaitForAvail()");
     1543        rwlock.unlock();
     1544        rwlock.lockForWrite();
     1545        ateof = true;
     1546        wanttoread = 0;
     1547        stopreads = true;
     1548        rwlock.unlock();
     1549        return 0;
     1550    }
    12871551
    1288         if (commserror)
    1289             return 0;
     1552    count = min(ReadBufAvail(), count);
     1553
     1554    if (count <= 0)
     1555    {
     1556        rwlock.unlock();
     1557        return count;
    12901558    }
    12911559
    1292     if ((ateof || stopreads) && avail < count)
    1293         count = avail;
     1560    if (peek)
     1561        rbrlock.lockForRead();
     1562    else
     1563        rbrlock.lockForWrite();
    12941564
     1565    VERBOSE(VB_FILE, LOC + QString("ReadPriv(*, %1, %2) @%3 -- copying data")
     1566            .arg(count).arg(peek?"peek":"normal").arg(rbrpos));
     1567
    12951568    if (rbrpos + count > (int) kBufferSize)
    12961569    {
    12971570        int firstsize = kBufferSize - rbrpos;
     
    13011574        memcpy((char *)buf + firstsize, readAheadBuffer, secondsize);
    13021575    }
    13031576    else
     1577    {
    13041578        memcpy(buf, readAheadBuffer + rbrpos, count);
     1579        VERBOSE(VB_FILE, LOC + QString("ReadPriv(*, %1, %2) @%3 -- checksum %4")
     1580                .arg(count).arg(peek?"peek":"normal").arg(rbrpos)
     1581                .arg(qChecksum(readAheadBuffer+rbrpos,count)));
     1582    }
    13051583
    13061584    if (!peek)
    13071585    {
    1308         readAheadLock.lock();
    13091586        rbrpos = (rbrpos + count) % kBufferSize;
    1310         readAheadLock.unlock();
     1587        generalWait.wakeAll();
    13111588    }
     1589    rbrlock.unlock();
     1590    rwlock.unlock();
    13121591
    1313     if (readone)
    1314     {
    1315         Pause();
    1316         WaitForPause();
    1317     }
    1318 
    13191592    return count;
    13201593}
    13211594
     
    13291602 */
    13301603int RingBuffer::Read(void *buf, int count)
    13311604{
    1332     int ret = -1;
    1333     if (writemode)
     1605    int ret = ReadPriv(buf, count, false);
     1606    if (ret > 0)
    13341607    {
    1335         VERBOSE(VB_IMPORTANT, LOC_ERR +
    1336                 "Attempt to read from a write only file");
    1337         return ret;
    1338     }
    1339 
    1340     rwlock.lockForRead();
    1341 
    1342     if (!readaheadrunning)
    1343     {
    1344         if (remotefile)
    1345         {
    1346             ret = safe_read(remotefile, buf, count);
    1347             readpos += ret;
    1348         }
    1349 #ifdef USING_FRONTEND
    1350         else if (dvdPriv)
    1351         {
    1352             ret = dvdPriv->safe_read(buf, count);
    1353             readpos += ret;
    1354         }
    1355         else if (bdPriv)
    1356         {
    1357             ret = bdPriv->safe_read(buf, count);
    1358             readpos += ret;
    1359         }
    1360 #endif // USING_FRONTEND
    1361         else
    1362         {
    1363             ret = safe_read(fd2, buf, count);
    1364             readpos += ret;
    1365         }
    1366     }
    1367     else
    1368     {
    1369         ret = ReadFromBuf(buf, count);
     1608        poslock.lockForWrite();
    13701609        readpos += ret;
     1610        poslock.unlock();
    13711611    }
    1372 
    1373     rwlock.unlock();
    13741612    return ret;
    13751613}
    13761614
    13771615/** \fn RingBuffer::IsIOBound(void) const
    1378  *  \brief Returns true if a RingBuffer::Read(void*,int) is likely to block.
     1616 *  \brief Returns true if a RingBuffer::Write(void*,int) is likely to block.
    13791617 */
    13801618bool RingBuffer::IsIOBound(void) const
    13811619{
     
    14041642 */
    14051643int RingBuffer::Write(const void *buf, uint count)
    14061644{
    1407     int ret = -1;
     1645    rwlock.lockForRead();
     1646
    14081647    if (!writemode)
    14091648    {
    14101649        VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file.");
    1411         return ret;
     1650        rwlock.unlock();
     1651        return -1;
    14121652    }
    14131653
    14141654    if (!tfw && !remotefile)
    1415         return ret;
     1655    {
     1656        rwlock.unlock();
     1657        return -1;
     1658    }
    14161659
    1417     rwlock.lockForRead();
    1418 
     1660    int ret = -1;
    14191661    if (tfw)
    14201662        ret = tfw->Write(buf, count);
    14211663    else
    14221664        ret = remotefile->Write(buf, count);
    1423     writepos += ret;
    14241665
     1666    if (ret > 0)
     1667    {
     1668        poslock.lockForWrite();
     1669        writepos += ret;
     1670        poslock.unlock();
     1671    }
     1672
    14251673    rwlock.unlock();
     1674
    14261675    return ret;
    14271676}
    14281677
     
    14311680 */
    14321681void RingBuffer::Sync(void)
    14331682{
     1683    rwlock.lockForRead();
    14341684    if (tfw)
    14351685        tfw->Sync();
     1686    rwlock.unlock();
    14361687}
    14371688
    1438 /** \fn RingBuffer::Seek(long long, int)
    1439  *  \brief Seeks to a particular position in the file.
     1689/** \brief Seeks to a particular position in the file.
    14401690 */
    1441 long long RingBuffer::Seek(long long pos, int whence)
     1691long long RingBuffer::Seek(long long pos, int whence, bool has_lock)
    14421692{
     1693    VERBOSE(VB_IMPORTANT, LOC + QString("Seek(%1,%2,%3)")
     1694            .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET":
     1695                          ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END"))
     1696            .arg(has_lock?"locked":"unlocked"));
     1697
     1698    long long ret = -1;
     1699
     1700    stopreads = true;
     1701
     1702    // lockForWrite takes priority over lockForRead, so this will
     1703    // take priority over the lockForRead in the read ahead thread.
     1704    if (!has_lock)
     1705        rwlock.lockForWrite();
     1706
     1707    stopreads = false;
     1708
    14431709    if (writemode)
    1444         return WriterSeek(pos, whence);
     1710    {
     1711        ret = WriterSeek(pos, whence, true);
     1712        if (!has_lock)
     1713            rwlock.unlock();
     1714        return ret;
     1715    }
    14451716
    1446     wantseek = true;
    1447     rwlock.lockForWrite();
    1448     wantseek = false;
     1717    poslock.lockForWrite();
    14491718
    1450     // optimize nop seeks
    1451     if ((whence == SEEK_SET && pos == readpos) ||
    1452         (whence == SEEK_CUR && pos == 0))
     1719    // Optimize no-op seeks
     1720    if (readaheadrunning &&
     1721        ((whence == SEEK_SET && pos == readpos) ||
     1722         (whence == SEEK_CUR && pos == 0)))
    14531723    {
    1454         rwlock.unlock();
    1455         return readpos;
     1724        VERBOSE(VB_IMPORTANT, "no-op seek");
     1725        ret = readpos;
     1726
     1727        poslock.unlock();
     1728        if (!has_lock)
     1729            rwlock.unlock();
     1730
     1731        return ret;
    14561732    }
    14571733
    1458     errno = 0; // clear errno, in case of remotefile error
     1734    // only valid for SEEK_SET & SEEK_CUR
     1735    long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos;
    14591736
    1460     long long ret = -1;
     1737    // Optimize short seeks where the data for
     1738    // them is in our ringbuffer already.
     1739#if 1
     1740    if (readaheadrunning &&
     1741        (SEEK_SET==whence || SEEK_CUR==whence))
     1742    {
     1743        rbrlock.lockForWrite();
     1744        rbwlock.lockForRead();
     1745        VERBOSE(VB_IMPORTANT, LOC +
     1746                QString("Seek(): rbrpos: %1 rbwpos: %2"
     1747                        "\n\t\t\treadpos: %3 internalreadpos: %4")
     1748                .arg(rbrpos).arg(rbwpos)
     1749                .arg(readpos).arg(internalreadpos));
     1750        bool used_opt = false;
     1751        if ((new_pos < readpos))
     1752        {
     1753            int min_safety = max(fill_min, readblocksize);
     1754            int free = ((rbwpos >= rbrpos) ?
     1755                        rbrpos + kBufferSize : rbrpos) - rbwpos;
     1756            int internal_backbuf =
     1757                (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos;
     1758            internal_backbuf = min(internal_backbuf, free - min_safety);
     1759            long long sba = readpos - new_pos;
     1760            VERBOSE(VB_IMPORTANT,
     1761                    QString("Seek(): internal_backbuf: %1 sba: %2")
     1762                    .arg(internal_backbuf).arg(sba));
     1763            if (internal_backbuf >= sba)
     1764            {
     1765                rbrpos = (rbrpos>=sba) ? rbrpos - sba :
     1766                    kBufferSize + rbrpos - sba;
     1767                used_opt = true;
     1768                VERBOSE(VB_IMPORTANT,
     1769                        QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2"
     1770                                "\n\t\t\treadpos: %3 internalreadpos: %4")
     1771                        .arg(rbrpos).arg(rbwpos)
     1772                        .arg(new_pos).arg(internalreadpos));
     1773            }
     1774        }
     1775        else if ((new_pos >= readpos) && (new_pos <= internalreadpos))
     1776        {
     1777            rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize;
     1778            used_opt = true;
     1779            VERBOSE(VB_IMPORTANT,
     1780                    QString("Seek(): OPT2 rbrpos: %1 sba: %2")
     1781                    .arg(rbrpos).arg(readpos - new_pos));
     1782        }
     1783        rbwlock.unlock();
     1784        rbrlock.unlock();
     1785
     1786        if (used_opt)
     1787        {
     1788            if (ignorereadpos >= 0)
     1789            {
     1790                if (remotefile)
     1791                    remotefile->Seek(internalreadpos, SEEK_SET);
     1792                else
     1793                    lseek64(fd2, internalreadpos, SEEK_SET);
     1794                ignorereadpos = -1;
     1795            }
     1796            readpos = new_pos;
     1797            poslock.unlock();
     1798            generalWait.wakeAll();
     1799            if (!has_lock)
     1800                rwlock.unlock();
     1801            return new_pos;
     1802        }
     1803    }
     1804#endif
     1805
     1806#if 1
     1807    if (remotefile || fd2 >= 0)
     1808    {
     1809        long long off_end = 0xDEADBEEF;
     1810        if (SEEK_END == whence)
     1811        {
     1812            off_end = pos;
     1813            if (remotefile)
     1814            {
     1815                new_pos = remotefile->GetFileSize() - off_end;
     1816            }
     1817            else
     1818            {
     1819                QFileInfo fi(filename);
     1820                new_pos = fi.size() - off_end;
     1821            }
     1822        }
     1823        else if (abs(new_pos-readpos) > 100000000)
     1824        {
     1825            if (remotefile)
     1826            {
     1827                off_end = remotefile->GetFileSize() - new_pos;
     1828            }
     1829            else
     1830            {
     1831                QFileInfo fi(filename);
     1832                off_end = fi.size() - new_pos;
     1833            }
     1834        }
     1835        if (off_end < 300000)
     1836        {
     1837            VERBOSE(VB_FILE, LOC +
     1838                    QString("Seek(): offset from end: %1").arg(off_end) +
     1839                    "\n\t\t\t -- ignoring read ahead thread until next seek.");
     1840
     1841            rbwlock.unlock();
     1842            rbrlock.unlock();
     1843
     1844            ignorereadpos = new_pos;
     1845            if (remotefile)
     1846                remotefile->Seek(ignorereadpos, SEEK_SET);
     1847            else
     1848                lseek64(fd2, ignorereadpos, SEEK_SET);
     1849
     1850            poslock.unlock();
     1851
     1852            generalWait.wakeAll();
     1853
     1854            if (!has_lock)
     1855                rwlock.unlock();
     1856
     1857            return new_pos;
     1858        }
     1859    }
     1860#endif
     1861
    14611862    if (remotefile)
     1863    {
    14621864        ret = remotefile->Seek(pos, whence, readpos);
     1865        if (ret<0)
     1866            errno = EINVAL;
     1867    }
    14631868#ifdef USING_FRONTEND
     1869    else if ((dvdPriv || bdPriv) && (SEEK_END == whence))
     1870    {
     1871        errno = EINVAL;
     1872        ret = -1;
     1873    }
    14641874    else if (dvdPriv)
    14651875    {
    1466         dvdPriv->NormalSeek(pos);
    1467         ret = pos;
     1876        dvdPriv->NormalSeek(new_pos);
     1877        ret = new_pos;
    14681878    }
    14691879    else if (bdPriv)
    14701880    {
    1471         bdPriv->Seek(pos);
    1472         ret = pos;
     1881        bdPriv->Seek(new_pos);
     1882        ret = new_pos;
    14731883    }
    14741884#endif // USING_FRONTEND
    14751885    else
    14761886    {
    1477         if (whence == SEEK_SET)
    1478 #ifdef USING_MINGW
    1479             ret = lseek64(fd2, pos, whence);
    1480 #else
    1481             ret = lseek(fd2, pos, whence);
    1482 #endif
    1483         else
    1484         {
    1485             long long realseek = readpos + pos;
    1486 #ifdef USING_MINGW
    1487             ret = lseek64(fd2, realseek, SEEK_SET);
    1488 #else
    1489             ret = lseek(fd2, realseek, SEEK_SET);
    1490 #endif
    1491         }
     1887        ret = lseek64(fd2, pos, whence);
    14921888    }
    14931889
    14941890    if (ret >= 0)
    14951891    {
    1496         if (whence == SEEK_SET)
    1497             readpos = pos;
    1498         else if (whence == SEEK_CUR)
    1499             readpos += pos;
     1892        readpos = ret;
     1893       
     1894        ignorereadpos = -1;
    15001895
    15011896        if (readaheadrunning)
    15021897            ResetReadAhead(readpos);
     
    15111906        VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);
    15121907    }
    15131908
    1514     rwlock.unlock();
     1909    poslock.unlock();
    15151910
     1911    generalWait.wakeAll();
     1912
     1913    if (!has_lock)
     1914        rwlock.unlock();
     1915
    15161916    return ret;
    15171917}
    15181918
    1519 /** \fn RingBuffer::WriterSeek(long long, int)
    1520  *  \brief Calls ThreadedFileWriter::Seek(long long,int).
     1919/** \brief Calls ThreadedFileWriter::Seek(long long,int).
    15211920 */
    1522 long long RingBuffer::WriterSeek(long long pos, int whence)
     1921long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock)
    15231922{
    15241923    long long ret = -1;
    15251924
     1925    if (!has_lock)
     1926        rwlock.lockForRead();
     1927
     1928    poslock.lockForWrite();
     1929
    15261930    if (tfw)
    15271931    {
    15281932        ret = tfw->Seek(pos, whence);
    15291933        writepos = ret;
    15301934    }
    15311935
     1936    poslock.unlock();
     1937
     1938    if (!has_lock)
     1939        rwlock.unlock();
     1940
    15321941    return ret;
    15331942}
    15341943
     
    15381947 */
    15391948void RingBuffer::WriterFlush(void)
    15401949{
     1950    rwlock.lockForRead();
    15411951    if (tfw)
    15421952    {
    15431953        tfw->Flush();
    15441954        tfw->Sync();
    15451955    }
     1956    rwlock.unlock();
    15461957}
    15471958
    15481959/** \fn RingBuffer::SetWriteBufferSize(int)
     
    15501961 */
    15511962void RingBuffer::SetWriteBufferSize(int newSize)
    15521963{
     1964    rwlock.lockForRead();
    15531965    if (tfw)
    15541966        tfw->SetWriteBufferSize(newSize);
     1967    rwlock.unlock();
    15551968}
    15561969
    15571970/** \fn RingBuffer::SetWriteBufferMinWriteSize(int)
     
    15591972 */
    15601973void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize)
    15611974{
     1975    rwlock.lockForRead();
    15621976    if (tfw)
    15631977        tfw->SetWriteBufferMinWriteSize(newMinSize);
     1978    rwlock.unlock();
    15641979}
    15651980
    15661981/** \fn RingBuffer::GetReadPosition(void) const
     
    15681983 */
    15691984long long RingBuffer::GetReadPosition(void) const
    15701985{
     1986    rwlock.lockForRead();
     1987    poslock.lockForRead();
     1988    long long ret = readpos;
    15711989#ifdef USING_FRONTEND
    15721990    if (dvdPriv)
    1573         return dvdPriv->GetReadPosition();
     1991        ret = dvdPriv->GetReadPosition();
    15741992    else if (bdPriv)
    1575         return bdPriv->GetReadPosition();
     1993        ret = bdPriv->GetReadPosition();
    15761994#endif // USING_FRONTEND
    1577 
    1578     return readpos;
     1995    poslock.unlock();
     1996    rwlock.unlock();
     1997    return ret;
    15791998}
    15801999
    15812000/** \fn RingBuffer::GetWritePosition(void) const
     
    15832002 */
    15842003long long RingBuffer::GetWritePosition(void) const
    15852004{
    1586     return writepos;
     2005    poslock.lockForRead();
     2006    long long ret = writepos;
     2007    poslock.unlock();
     2008    return ret;
    15872009}
    15882010
    15892011/** \fn RingBuffer::GetRealFileSize(void) const
     
    15922014 */
    15932015long long RingBuffer::GetRealFileSize(void) const
    15942016{
     2017    rwlock.lockForRead();
     2018    long long ret = -1;
    15952019    if (remotefile)
    1596         return remotefile->GetFileSize();
    1597 
    1598     QFileInfo info(filename);
    1599     return info.size();
     2020        ret = remotefile->GetFileSize();
     2021    else
     2022        ret = QFileInfo(filename).size();
     2023    rwlock.unlock();
     2024    return ret;
    16002025}
    16012026
    16022027/** \fn RingBuffer::LiveMode(void) const
     
    16052030 */
    16062031bool RingBuffer::LiveMode(void) const
    16072032{
    1608     return (livetvchain);
     2033    rwlock.lockForRead();
     2034    bool ret = (livetvchain);
     2035    rwlock.unlock();
     2036    return ret;
    16092037}
    16102038
    16112039/** \fn RingBuffer::SetLiveMode(LiveTVChain*)
     
    16142042 */
    16152043void RingBuffer::SetLiveMode(LiveTVChain *chain)
    16162044{
     2045    rwlock.lockForWrite();
    16172046    livetvchain = chain;
     2047    rwlock.unlock();
    16182048}
    16192049
    16202050bool RingBuffer::InDVDMenuOrStillFrame(void)
    16212051{
     2052    rwlock.lockForRead();
     2053    bool ret = false;
    16222054#ifdef USING_FRONTEND
    16232055    if (dvdPriv)
    1624         return (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
     2056        ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame());
    16252057#endif // USING_FRONTEND
    1626     return false;
     2058    rwlock.unlock();
     2059    return ret;
    16272060}
    16282061
    16292062/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/RingBuffer.h

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

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