Ticket #8812: 8812-v4.patch
File 8812-v4.patch, 67.2 KB (added by , 14 years ago) |
---|
-
libs/libmythtv/RingBuffer.cpp
5 5 #include <cerrno> 6 6 7 7 // POSIX C headers 8 #define _LARGEFILE53_SOURCE 8 9 #include <sys/types.h> 9 10 #include <sys/time.h> 10 11 #include <unistd.h> … … 19 20 20 21 using namespace std; 21 22 23 #include "mythcontext.h" // for VERBOSE 22 24 #include "mythconfig.h" 23 24 25 #include "exitcodes.h" 25 26 #include "RingBuffer.h" 26 27 #include "remotefile.h" … … 30 31 #include "BDRingBuffer.h" 31 32 #include "util.h" 32 33 #include "compat.h" 33 #include "mythverbose.h"34 34 35 35 #ifndef O_STREAMING 36 36 #define O_STREAMING 0 … … 44 44 #define O_BINARY 0 45 45 #endif 46 46 47 const uint RingBuffer::kBufferSize = 3 * 1024 * 1024; 47 // about one second at 35mbit 48 const uint RingBuffer::kBufferSize = 4 * 1024 * 1024; 48 49 49 50 #define CHUNK 32768 /* readblocksize increments */ 50 51 … … 65 66 66 67 /* 67 68 Locking relations: 68 rwlock->readAheadLock 69 ->readsAllowedWaitMutex->readAheadRunningCondLock 70 ->availWaitMutex 69 rwlock->poslock->rbrlock->rbwlock 71 70 72 71 A child should never lock any of the parents without locking 73 72 the parent lock before the child lock. 74 73 void RingBuffer::Example1() 75 74 { 76 QMutexLocker locker1(&readAheadRunningCondLock);77 QMutexLocker locker2(&readsAllowedWaitMutex); // error!75 poslock.lockForWrite(); 76 rwlock.lockForRead(); // error! 78 77 blah(); // <- does not implicitly aquire any locks 78 rwlock.unlock(); 79 poslock.unlock(); 79 80 } 80 81 void RingBuffer::Example2() 81 82 { 82 QMutexLocker locker1(&readsAllowedWaitMutex);83 QMutexLocker locker2(&readAheadRunningCondLock); // ok!83 rwlock.lockForRead(); 84 rbrlock.lockForWrite(); // ok! 84 85 blah(); // <- does not implicitly aquire any locks 86 rbrlock.unlock(); 87 rwlock.unlock(); 85 88 } 86 89 */ 87 90 … … 113 116 RingBuffer::RingBuffer(const QString &lfilename, 114 117 bool write, bool readahead, 115 118 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), 117 124 tfw(NULL), fd2(-1), 118 writemode(false), 119 readpos(0), writepos(0), 120 stopreads(false), remotefile(NULL), 125 writemode(false), remotefile(NULL), 121 126 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), 128 132 fill_threshold(65536), fill_min(-1), 129 133 readblocksize(CHUNK), wanttoread(0), 130 134 numfailures(0), commserror(false), … … 273 277 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2)") 274 278 .arg(lfilename).arg(retryCount)); 275 279 280 rwlock.lockForWrite(); 281 276 282 uint openAttempts = retryCount + 1; 277 283 278 284 filename = lfilename; … … 391 397 break; 392 398 case 2: 393 399 VERBOSE(VB_IMPORTANT, LOC + 394 QString("Invalid file (fd %1) when opening '%2'.")400 QString("Invalid file (fd2 %1) when opening '%2'.") 395 401 .arg(fd2).arg(filename)); 396 402 break; 397 403 default: … … 414 420 else if (is_dvd) 415 421 { 416 422 dvdPriv->OpenFile(filename); 417 rwlock.lockForWrite();418 423 readblocksize = DVD_BLOCK_SIZE * 62; 419 rwlock.unlock();420 424 } 421 425 else if (is_bd) 422 426 { 423 427 bdPriv->OpenFile(filename); 424 rwlock.lockForWrite();425 428 readblocksize = BD_BLOCK_SIZE * 62; 426 rwlock.unlock();427 429 } 428 430 #endif // USING_FRONTEND 429 431 else … … 478 480 commserror = false; 479 481 numfailures = 0; 480 482 481 UpdateRawBitrate(4000); 483 rawbitrate = 8000; 484 CalcReadAheadThresh(); 485 486 rwlock.unlock(); 482 487 } 483 488 484 489 /** \fn RingBuffer::IsOpen(void) const … … 486 491 */ 487 492 bool RingBuffer::IsOpen(void) const 488 493 { 494 rwlock.lockForRead(); 495 bool ret; 489 496 #ifdef USING_FRONTEND 490 ret urntfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||497 ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) || 491 498 (bdPriv && bdPriv->IsOpen()); 492 499 #else // if !USING_FRONTEND 493 ret urntfw || (fd2 > -1) || remotefile;500 ret = tfw || (fd2 > -1) || remotefile; 494 501 #endif // !USING_FRONTEND 502 rwlock.unlock(); 503 return ret; 495 504 } 496 505 497 506 /** \fn RingBuffer::~RingBuffer(void) … … 535 544 rwlock.unlock(); 536 545 } 537 546 538 /** \fn RingBuffer::Start(void)539 * \brief Starts the read-ahead thread.540 *541 * If this RingBuffer is not in write-mode, the RingBuffer constructor542 * was called with a usereadahead of true, and the read-ahead thread543 * is not already running.544 */545 void RingBuffer::Start(void)546 {547 if (!writemode && !readaheadrunning && startreadahead)548 StartupReadAheadThread();549 }550 551 547 /** \fn RingBuffer::Reset(bool, bool, bool) 552 548 * \brief Resets the read-ahead thread and our position in the file 553 549 */ 554 550 void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal) 555 551 { 556 wantseek = true; 552 VERBOSE(VB_IMPORTANT, LOC + QString("Reset(%1,%2,%3)") 553 .arg(full).arg(toAdjust).arg(resetInternal)); 554 557 555 rwlock.lockForWrite(); 558 wantseek = false; 556 poslock.lockForWrite(); 557 559 558 numfailures = 0; 560 559 commserror = false; 561 560 setswitchtonext = false; … … 579 578 if (resetInternal) 580 579 internalreadpos = readpos; 581 580 581 generalWait.wakeAll(); 582 poslock.unlock(); 582 583 rwlock.unlock(); 583 584 } 584 585 … … 600 601 unsigned errcnt = 0; 601 602 unsigned zerocnt = 0; 602 603 603 if (fd < 0)604 if (fd2 < 0) 604 605 { 605 606 VERBOSE(VB_IMPORTANT, LOC_ERR + 606 607 "Invalid file descriptor in 'safe_read()'"); … … 612 613 613 614 while (tot < sz) 614 615 { 615 ret = read(fd , (char *)data + tot, sz - tot);616 ret = read(fd2, (char *)data + tot, sz - tot); 616 617 if (ret < 0) 617 618 { 618 619 if (errno == EAGAIN) … … 674 675 VERBOSE(VB_IMPORTANT, LOC_ERR + 675 676 "RingBuffer::safe_read(RemoteFile* ...): read failed"); 676 677 678 poslock.lockForRead(); 677 679 rf->Seek(internalreadpos - readAdjust, SEEK_SET); 680 poslock.unlock(); 678 681 ret = 0; 679 682 numfailures++; 680 683 } … … 689 692 */ 690 693 void RingBuffer::UpdateRawBitrate(uint raw_bitrate) 691 694 { 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 692 705 rwlock.lockForWrite(); 693 706 rawbitrate = raw_bitrate; 694 707 CalcReadAheadThresh(); 695 708 rwlock.unlock(); 696 709 } 697 710 698 /** \fn RingBuffer::GetBitrate(void) const699 * \brief Returns effective bits per second (in thousands).700 *701 * NOTE: This is reported in telecom kilobytes, to get702 * the bits per second multiply by 1000, not 1024.703 */704 uint RingBuffer::GetBitrate(void) const705 {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) const713 * \brief Returns size of each disk read made by read ahead thread (in bytes).714 */715 uint RingBuffer::GetReadBlockSize(void) const716 {717 rwlock.lockForRead();718 uint tmp = readblocksize;719 rwlock.unlock();720 return tmp;721 }722 723 711 /** \fn RingBuffer::UpdatePlaySpeed(float) 724 712 * \brief Set the play speed, to allow RingBuffer adjust effective bitrate. 725 713 * \param play_speed Speed to set. (1.0 for normal speed) … … 743 731 { 744 732 uint estbitrate = 0; 745 733 746 wantseek = false;747 734 readsallowed = false; 748 readblocksize = CHUNK;735 readblocksize = max(readblocksize, CHUNK); 749 736 750 737 // 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; 753 739 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; 762 745 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); 770 754 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; 773 761 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 -> " 783 764 "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)") 784 765 .arg(estbitrate).arg(fill_threshold/1024) 785 766 .arg(fill_min/1024).arg(readblocksize/1024)); 786 767 } 787 768 788 /** \fn RingBuffer::ReadBufFree(void) const 789 * \brief Returns number of bytes available for reading into buffer. 790 */ 769 bool 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. 791 799 int RingBuffer::ReadBufFree(void) const 792 800 { 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; 795 807 } 796 808 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. 800 811 int RingBuffer::ReadBufAvail(void) const 801 812 { 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; 805 819 } 806 820 807 821 /** \fn RingBuffer::ResetReadAhead(long long) … … 811 825 * buffer doesn't contain any stale data, and so that it will read 812 826 * any new data from the new position in the file. 813 827 * 814 * WARNING: Must be called with rwlock in write lock state.828 * WARNING: Must be called with rwlock and poslock in write lock state. 815 829 * 816 830 * \param newinternal Position in file to start reading data from 817 831 */ 818 832 void RingBuffer::ResetReadAhead(long long newinternal) 819 833 { 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(); 822 841 rbrpos = 0; 823 842 rbwpos = 0; 824 843 internalreadpos = newinternal; 825 844 ateof = false; 826 845 readsallowed = false; 827 846 setswitchtonext = false; 828 readAheadLock.unlock(); 847 generalWait.wakeAll(); 848 849 rbwlock.unlock(); 850 rbrlock.unlock(); 829 851 } 830 852 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. 833 855 * 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 * 835 866 */ 836 void RingBuffer::Start upReadAheadThread(void)867 void RingBuffer::Start(void) 837 868 { 838 readaheadrunning = false;869 bool do_start = true; 839 870 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 841 897 QThread::start(); 842 readAheadRunningCond.wait(&readAheadRunningCondLock); 843 readAheadRunningCondLock.unlock(); 898 899 while (readaheadrunning && !reallyrunning) 900 generalWait.wait(&rwlock); 901 902 rwlock.unlock(); 844 903 } 845 904 846 905 /** \fn RingBuffer::KillReadAheadThread(void) … … 848 907 */ 849 908 void RingBuffer::KillReadAheadThread(void) 850 909 { 851 if (!readaheadrunning) 852 return; 910 rwlock.lockForWrite(); 911 bool do_wait = readaheadrunning; 912 readaheadrunning = false; 913 StopReads(); 914 generalWait.wakeAll(); 915 rwlock.unlock(); 853 916 854 readaheadrunning = false;855 QThread::wait();917 if (do_wait) 918 QThread::wait(); 856 919 } 857 920 858 921 /** \fn RingBuffer::StopReads(void) … … 862 925 void RingBuffer::StopReads(void) 863 926 { 864 927 stopreads = true; 865 availWait.wakeAll();928 generalWait.wakeAll(); 866 929 } 867 930 868 931 /** \fn RingBuffer::StartReads(void) … … 880 943 */ 881 944 void RingBuffer::Pause(void) 882 945 { 883 pausereadthread = true;884 946 StopReads(); 947 948 rwlock.lockForWrite(); 949 request_pause = true; 950 rwlock.unlock(); 885 951 } 886 952 887 953 /** \fn RingBuffer::Unpause(void) … … 891 957 void RingBuffer::Unpause(void) 892 958 { 893 959 StartReads(); 894 pausereadthread = false; 960 961 rwlock.lockForWrite(); 962 request_pause = false; 963 generalWait.wakeAll(); 964 rwlock.unlock(); 895 965 } 896 966 967 /// Returns false iff read-ahead is not running and read-ahead is not paused. 968 bool RingBuffer::isPaused(void) const 969 { 970 rwlock.lockForRead(); 971 bool ret = !readaheadrunning || paused; 972 rwlock.unlock(); 973 return ret; 974 } 975 897 976 /** \fn RingBuffer::WaitForPause(void) 898 977 * \brief Waits for Pause(void) to take effect. 899 978 */ 900 979 void RingBuffer::WaitForPause(void) 901 980 { 902 if (!readaheadrunning)903 return;981 MythTimer t; 982 t.start(); 904 983 905 if (!readaheadpaused) 984 rwlock.lockForRead(); 985 while (readaheadrunning && !paused && request_pause) 906 986 { 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 } 911 997 912 while (!pauseWait.wait(&mutex, 1000)) 913 VERBOSE(VB_IMPORTANT, 914 LOC + "Waited too long for ringbuffer pause.."); 998 bool 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); 915 1021 } 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; 916 1039 } 917 1040 918 1041 void RingBuffer::run(void) 919 1042 { 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 925 1044 struct timeval lastread, now; 926 gettimeofday(&lastread, NULL);927 const int KB640 = 640*1024;928 1045 int readtimeavg = 300; 929 int readinterval;1046 bool ignore_for_read_timing = true; 930 1047 931 pausereadthread = false;1048 gettimeofday(&lastread, NULL); // this is just to keep gcc happy 932 1049 933 readAheadBuffer = new char[kBufferSize + KB640];934 935 1050 rwlock.lockForWrite(); 1051 poslock.lockForWrite(); 1052 request_pause = false; 1053 readAheadBuffer = new char[kBufferSize + 1024]; 936 1054 ResetReadAhead(0); 1055 readaheadrunning = true; 1056 reallyrunning = true; 1057 generalWait.wakeAll(); 1058 poslock.unlock(); 937 1059 rwlock.unlock(); 938 1060 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. 940 1064 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 945 1070 while (readaheadrunning) 946 1071 { 947 if ( pausereadthread || writemode)1072 if (PauseAndWait()) 948 1073 { 949 readaheadpaused = true; 950 pauseWait.wakeAll(); 951 usleep(5000); 952 totfree = ReadBufFree(); 1074 ignore_for_read_timing = true; 953 1075 continue; 954 1076 } 955 1077 956 if (readaheadpaused) 1078 long long totfree = ReadBufFree(); 1079 1080 if (totfree < readblocksize) 957 1081 { 958 totfree = ReadBufFree();959 readaheadpaused = false;1082 generalWait.wait(&rwlock, 1000); 1083 continue; 960 1084 } 961 1085 962 totfree = ReadBufFree(); 963 if (totfree < GetReadBlockSize()) 1086 if (ignorereadpos >= 0) 964 1087 { 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; 972 1090 } 973 loops = 0;974 1091 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) 977 1095 { 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 { 978 1105 // limit the read size 979 1106 totfree = readblocksize; 980 1107 981 1108 // adapt blocksize 982 1109 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; 985 1115 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; 987 1120 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 } 995 1140 } 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; 1004 1142 lastread = now; 1005 1143 1144 rbwlock.lockForRead(); 1006 1145 if (rbwpos + totfree > kBufferSize) 1146 { 1007 1147 totfree = kBufferSize - rbwpos; 1148 VERBOSE(VB_FILE, LOC + "totfree = kBufferSize - rbwpos"); 1149 } 1008 1150 1009 1151 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 } 1011 1157 1012 1158 if (remotefile) 1013 1159 { 1160 VERBOSE(VB_FILE, LOC + QString("safe_read(*, @%1, %2) -- begin") 1161 .arg(rbwpos).arg(totfree)); 1014 1162 if (livetvchain && livetvchain->HasNext()) 1015 1163 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)); 1020 1168 } 1021 1169 #ifdef USING_FRONTEND 1022 1170 else if (dvdPriv) 1023 1171 { 1024 ret = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree); 1025 internalreadpos += ret; 1172 read_return = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree); 1026 1173 } 1027 1174 else if (bdPriv) 1028 1175 { 1029 ret = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree); 1030 internalreadpos += ret; 1176 read_return = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree); 1031 1177 } 1032 1178 #endif // USING_FRONTEND 1033 1179 else 1034 1180 { 1035 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree); 1036 internalreadpos += ret; 1181 read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree); 1037 1182 } 1183 rbwlock.unlock(); 1184 } 1038 1185 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 } 1043 1193 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) 1045 1221 { 1046 1222 if (livetvchain) 1047 1223 { … … 1053 1229 } 1054 1230 } 1055 1231 else 1232 { 1056 1233 ateof = true; 1234 } 1057 1235 } 1058 }1059 1236 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(); 1070 1240 } 1071 1241 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"); 1082 1243 1083 if (readsallowed && used < fill_min && !ateof && !setswitchtonext) 1244 if (readsallowed || stopreads || commserror || ateof || 1245 setswitchtonext || (wanttoread <= used && wanttoread > 0)) 1084 1246 { 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(); 1088 1251 } 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 1098 1253 { 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 } 1100 1260 } 1101 availWaitMutex.unlock();1261 } 1102 1262 1103 1263 rwlock.unlock(); 1104 1264 1105 if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) &&1106 !pausereadthread)1107 {1108 usleep(500);1109 }1110 }1111 1112 1265 delete [] readAheadBuffer; 1113 1266 readAheadBuffer = NULL; 1267 1268 rwlock.lockForWrite(); 1269 rbrlock.lockForWrite(); 1270 rbwlock.lockForWrite(); 1114 1271 rbrpos = 0; 1115 1272 rbwpos = 0; 1273 reallyrunning = false; 1274 rbwlock.unlock(); 1275 rbrlock.unlock(); 1276 rwlock.unlock(); 1116 1277 } 1117 1278 1118 1279 long long RingBuffer::SetAdjustFilesize(void) 1119 1280 { 1281 rwlock.lockForWrite(); 1282 poslock.lockForRead(); 1120 1283 readAdjust += internalreadpos; 1284 poslock.unlock(); 1285 rwlock.unlock(); 1121 1286 return readAdjust; 1122 1287 } 1123 1288 1124 1289 int RingBuffer::Peek(void *buf, int count) 1125 1290 { 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); 1166 1292 if (ret != count) 1167 1293 { 1168 1294 VERBOSE(VB_IMPORTANT, LOC_WARN + … … 1172 1298 return ret; 1173 1299 } 1174 1300 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) 1301 bool RingBuffer::WaitForReadsAllowed(void) 1184 1302 { 1185 if (commserror)1186 return 0;1303 MythTimer t; 1304 t.start(); 1187 1305 1188 bool readone = false; 1189 int readErr = 0; 1190 1191 if (readaheadpaused && stopreads) 1306 while (!readsallowed && !stopreads && 1307 !request_pause && !commserror && readaheadrunning) 1192 1308 { 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.."); 1199 1314 1200 while (!readsallowed && !stopreads) 1201 { 1202 if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000)) 1315 if (t.elapsed() > 10000) 1203 1316 { 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; 1224 1320 } 1225 1321 } 1226 1322 } 1227 1323 1324 return readsallowed; 1325 } 1326 1327 bool RingBuffer::WaitForAvail(int count) 1328 { 1228 1329 int avail = ReadBufAvail(); 1330 count = (ateof && avail < count) ? avail : count; 1229 1331 1230 if (ateof && avail < count)1231 count = avail;1232 1233 1332 MythTimer t; 1234 1333 t.start(); 1235 while (avail < count && !stopreads) 1334 while ((avail < count) && !stopreads && 1335 !request_pause && !commserror && readaheadrunning) 1236 1336 { 1237 availWaitMutex.lock();1238 1337 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) 1240 1345 { 1241 1346 int elapsed = t.elapsed(); 1242 if (/*((elapsed > 500) && (elapsed < 750)) ||*/ 1347 if (((elapsed > 250) && (elapsed < 500)) || 1348 ((elapsed > 500) && (elapsed < 750)) || 1243 1349 ((elapsed > 1000) && (elapsed < 1250)) || 1244 1350 ((elapsed > 2000) && (elapsed < 2250)) || 1245 1351 ((elapsed > 4000) && (elapsed < 4250)) || 1246 ((elapsed > 8000) && (elapsed < 8250))) 1352 ((elapsed > 8000) && (elapsed < 8250)) || 1353 ((elapsed > 9000))) 1247 1354 { 1248 1355 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)); 1251 1360 if (livetvchain) 1252 1361 { 1253 1362 VERBOSE(VB_IMPORTANT, "Checking to see if there's a " … … 1270 1379 VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to " 1271 1380 "impending livetv switch."); 1272 1381 1273 ateof = true; 1274 wanttoread = 0; 1275 stopreads = true; 1276 availWaitMutex.unlock(); 1277 return 0; 1382 return false; 1278 1383 } 1279 1384 } 1385 } 1280 1386 1387 wanttoread = 0; 1388 1389 return avail >= count; 1390 } 1391 1392 int 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 */ 1482 int 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(); 1281 1534 wanttoread = 0; 1282 availWaitMutex.unlock(); 1535 stopreads = true; 1536 rwlock.unlock(); 1537 return 0; 1538 } 1283 1539 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 } 1287 1551 1288 if (commserror) 1289 return 0; 1552 count = min(ReadBufAvail(), count); 1553 1554 if (count <= 0) 1555 { 1556 rwlock.unlock(); 1557 return count; 1290 1558 } 1291 1559 1292 if ((ateof || stopreads) && avail < count) 1293 count = avail; 1560 if (peek) 1561 rbrlock.lockForRead(); 1562 else 1563 rbrlock.lockForWrite(); 1294 1564 1565 VERBOSE(VB_FILE, LOC + QString("ReadPriv(*, %1, %2) @%3 -- copying data") 1566 .arg(count).arg(peek?"peek":"normal").arg(rbrpos)); 1567 1295 1568 if (rbrpos + count > (int) kBufferSize) 1296 1569 { 1297 1570 int firstsize = kBufferSize - rbrpos; … … 1301 1574 memcpy((char *)buf + firstsize, readAheadBuffer, secondsize); 1302 1575 } 1303 1576 else 1577 { 1304 1578 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 } 1305 1583 1306 1584 if (!peek) 1307 1585 { 1308 readAheadLock.lock();1309 1586 rbrpos = (rbrpos + count) % kBufferSize; 1310 readAheadLock.unlock();1587 generalWait.wakeAll(); 1311 1588 } 1589 rbrlock.unlock(); 1590 rwlock.unlock(); 1312 1591 1313 if (readone)1314 {1315 Pause();1316 WaitForPause();1317 }1318 1319 1592 return count; 1320 1593 } 1321 1594 … … 1329 1602 */ 1330 1603 int RingBuffer::Read(void *buf, int count) 1331 1604 { 1332 int ret = -1;1333 if ( writemode)1605 int ret = ReadPriv(buf, count, false); 1606 if (ret > 0) 1334 1607 { 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(); 1370 1609 readpos += ret; 1610 poslock.unlock(); 1371 1611 } 1372 1373 rwlock.unlock();1374 1612 return ret; 1375 1613 } 1376 1614 1377 1615 /** \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. 1379 1617 */ 1380 1618 bool RingBuffer::IsIOBound(void) const 1381 1619 { … … 1404 1642 */ 1405 1643 int RingBuffer::Write(const void *buf, uint count) 1406 1644 { 1407 int ret = -1; 1645 rwlock.lockForRead(); 1646 1408 1647 if (!writemode) 1409 1648 { 1410 1649 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file."); 1411 return ret; 1650 rwlock.unlock(); 1651 return -1; 1412 1652 } 1413 1653 1414 1654 if (!tfw && !remotefile) 1415 return ret; 1655 { 1656 rwlock.unlock(); 1657 return -1; 1658 } 1416 1659 1417 rwlock.lockForRead(); 1418 1660 int ret = -1; 1419 1661 if (tfw) 1420 1662 ret = tfw->Write(buf, count); 1421 1663 else 1422 1664 ret = remotefile->Write(buf, count); 1423 writepos += ret;1424 1665 1666 if (ret > 0) 1667 { 1668 poslock.lockForWrite(); 1669 writepos += ret; 1670 poslock.unlock(); 1671 } 1672 1425 1673 rwlock.unlock(); 1674 1426 1675 return ret; 1427 1676 } 1428 1677 … … 1431 1680 */ 1432 1681 void RingBuffer::Sync(void) 1433 1682 { 1683 rwlock.lockForRead(); 1434 1684 if (tfw) 1435 1685 tfw->Sync(); 1686 rwlock.unlock(); 1436 1687 } 1437 1688 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. 1440 1690 */ 1441 long long RingBuffer::Seek(long long pos, int whence )1691 long long RingBuffer::Seek(long long pos, int whence, bool has_lock) 1442 1692 { 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 1443 1709 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 } 1445 1716 1446 wantseek = true; 1447 rwlock.lockForWrite(); 1448 wantseek = false; 1717 poslock.lockForWrite(); 1449 1718 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))) 1453 1723 { 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; 1456 1732 } 1457 1733 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; 1459 1736 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 1461 1862 if (remotefile) 1863 { 1462 1864 ret = remotefile->Seek(pos, whence, readpos); 1865 if (ret<0) 1866 errno = EINVAL; 1867 } 1463 1868 #ifdef USING_FRONTEND 1869 else if ((dvdPriv || bdPriv) && (SEEK_END == whence)) 1870 { 1871 errno = EINVAL; 1872 ret = -1; 1873 } 1464 1874 else if (dvdPriv) 1465 1875 { 1466 dvdPriv->NormalSeek( pos);1467 ret = pos;1876 dvdPriv->NormalSeek(new_pos); 1877 ret = new_pos; 1468 1878 } 1469 1879 else if (bdPriv) 1470 1880 { 1471 bdPriv->Seek( pos);1472 ret = pos;1881 bdPriv->Seek(new_pos); 1882 ret = new_pos; 1473 1883 } 1474 1884 #endif // USING_FRONTEND 1475 1885 else 1476 1886 { 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); 1492 1888 } 1493 1889 1494 1890 if (ret >= 0) 1495 1891 { 1496 if (whence == SEEK_SET) 1497 readpos = pos; 1498 else if (whence == SEEK_CUR) 1499 readpos += pos; 1892 readpos = ret; 1893 1894 ignorereadpos = -1; 1500 1895 1501 1896 if (readaheadrunning) 1502 1897 ResetReadAhead(readpos); … … 1511 1906 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 1512 1907 } 1513 1908 1514 rwlock.unlock();1909 poslock.unlock(); 1515 1910 1911 generalWait.wakeAll(); 1912 1913 if (!has_lock) 1914 rwlock.unlock(); 1915 1516 1916 return ret; 1517 1917 } 1518 1918 1519 /** \fn RingBuffer::WriterSeek(long long, int) 1520 * \brief Calls ThreadedFileWriter::Seek(long long,int). 1919 /** \brief Calls ThreadedFileWriter::Seek(long long,int). 1521 1920 */ 1522 long long RingBuffer::WriterSeek(long long pos, int whence )1921 long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock) 1523 1922 { 1524 1923 long long ret = -1; 1525 1924 1925 if (!has_lock) 1926 rwlock.lockForRead(); 1927 1928 poslock.lockForWrite(); 1929 1526 1930 if (tfw) 1527 1931 { 1528 1932 ret = tfw->Seek(pos, whence); 1529 1933 writepos = ret; 1530 1934 } 1531 1935 1936 poslock.unlock(); 1937 1938 if (!has_lock) 1939 rwlock.unlock(); 1940 1532 1941 return ret; 1533 1942 } 1534 1943 … … 1538 1947 */ 1539 1948 void RingBuffer::WriterFlush(void) 1540 1949 { 1950 rwlock.lockForRead(); 1541 1951 if (tfw) 1542 1952 { 1543 1953 tfw->Flush(); 1544 1954 tfw->Sync(); 1545 1955 } 1956 rwlock.unlock(); 1546 1957 } 1547 1958 1548 1959 /** \fn RingBuffer::SetWriteBufferSize(int) … … 1550 1961 */ 1551 1962 void RingBuffer::SetWriteBufferSize(int newSize) 1552 1963 { 1964 rwlock.lockForRead(); 1553 1965 if (tfw) 1554 1966 tfw->SetWriteBufferSize(newSize); 1967 rwlock.unlock(); 1555 1968 } 1556 1969 1557 1970 /** \fn RingBuffer::SetWriteBufferMinWriteSize(int) … … 1559 1972 */ 1560 1973 void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize) 1561 1974 { 1975 rwlock.lockForRead(); 1562 1976 if (tfw) 1563 1977 tfw->SetWriteBufferMinWriteSize(newMinSize); 1978 rwlock.unlock(); 1564 1979 } 1565 1980 1566 1981 /** \fn RingBuffer::GetReadPosition(void) const … … 1568 1983 */ 1569 1984 long long RingBuffer::GetReadPosition(void) const 1570 1985 { 1986 rwlock.lockForRead(); 1987 poslock.lockForRead(); 1988 long long ret = readpos; 1571 1989 #ifdef USING_FRONTEND 1572 1990 if (dvdPriv) 1573 ret urndvdPriv->GetReadPosition();1991 ret = dvdPriv->GetReadPosition(); 1574 1992 else if (bdPriv) 1575 ret urnbdPriv->GetReadPosition();1993 ret = bdPriv->GetReadPosition(); 1576 1994 #endif // USING_FRONTEND 1577 1578 return readpos; 1995 poslock.unlock(); 1996 rwlock.unlock(); 1997 return ret; 1579 1998 } 1580 1999 1581 2000 /** \fn RingBuffer::GetWritePosition(void) const … … 1583 2002 */ 1584 2003 long long RingBuffer::GetWritePosition(void) const 1585 2004 { 1586 return writepos; 2005 poslock.lockForRead(); 2006 long long ret = writepos; 2007 poslock.unlock(); 2008 return ret; 1587 2009 } 1588 2010 1589 2011 /** \fn RingBuffer::GetRealFileSize(void) const … … 1592 2014 */ 1593 2015 long long RingBuffer::GetRealFileSize(void) const 1594 2016 { 2017 rwlock.lockForRead(); 2018 long long ret = -1; 1595 2019 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; 1600 2025 } 1601 2026 1602 2027 /** \fn RingBuffer::LiveMode(void) const … … 1605 2030 */ 1606 2031 bool RingBuffer::LiveMode(void) const 1607 2032 { 1608 return (livetvchain); 2033 rwlock.lockForRead(); 2034 bool ret = (livetvchain); 2035 rwlock.unlock(); 2036 return ret; 1609 2037 } 1610 2038 1611 2039 /** \fn RingBuffer::SetLiveMode(LiveTVChain*) … … 1614 2042 */ 1615 2043 void RingBuffer::SetLiveMode(LiveTVChain *chain) 1616 2044 { 2045 rwlock.lockForWrite(); 1617 2046 livetvchain = chain; 2047 rwlock.unlock(); 1618 2048 } 1619 2049 1620 2050 bool RingBuffer::InDVDMenuOrStillFrame(void) 1621 2051 { 2052 rwlock.lockForRead(); 2053 bool ret = false; 1622 2054 #ifdef USING_FRONTEND 1623 2055 if (dvdPriv) 1624 ret urn(dvdPriv->IsInMenu() || dvdPriv->InStillFrame());2056 ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame()); 1625 2057 #endif // USING_FRONTEND 1626 return false; 2058 rwlock.unlock(); 2059 return ret; 1627 2060 } 1628 2061 1629 2062 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/RingBuffer.h
1 1 // -*- Mode: c++ -*- 2 2 3 #ifndef RINGBUFFER4 #define RINGBUFFER3 #ifndef _RINGBUFFER_H_ 4 #define _RINGBUFFER_H_ 5 5 6 6 #include <QReadWriteLock> 7 7 #include <QWaitCondition> … … 38 38 39 39 // Gets 40 40 /// 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 } 45 55 /// Returns value of stopreads 46 56 /// \sa StartReads(void), StopReads(void) 47 57 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; 52 59 long long GetReadPosition(void) const; 53 60 long long GetWritePosition(void) const; 54 61 long long GetRealFileSize(void) const; 55 uint GetBitrate(void) const;56 uint GetReadBlockSize(void) const;57 62 bool IsOpen(void) const; 63 bool IsNearEnd(double fps, uint vvf) const; 58 64 59 65 // General Commands 60 66 void OpenFile(const QString &lfilename, uint retryCount = 12/*4*/); … … 66 72 bool resetInternal = false); 67 73 68 74 // Seeks 69 long long Seek(long long pos, int whence );75 long long Seek(long long pos, int whence, bool has_lock = false); 70 76 71 77 // Pause commands 72 78 void Pause(void); … … 82 88 bool LiveMode(void) const; 83 89 void SetLiveMode(LiveTVChain *chain); 84 90 /// 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 } 86 97 87 98 // ThreadedFileWriter proxies 88 99 int Write(const void *buf, uint count); 89 100 bool IsIOBound(void) const; 90 101 void WriterFlush(void); 91 102 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); 93 104 94 105 // DVDRingBuffer proxies 95 106 /// 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 } 98 119 bool InDVDMenuOrStillFrame(void); 99 120 100 121 // BDRingBuffer proxies … … 108 129 protected: 109 130 void run(void); // QThread 110 131 void CalcReadAheadThresh(void); 132 bool PauseAndWait(void); 111 133 int safe_read_bd(void *data, uint sz); 112 134 int safe_read_dvd(void *data, uint sz); 113 135 int safe_read(int fd, void *data, uint sz); 114 136 int safe_read(RemoteFile *rf, void *data, uint sz); 115 137 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); 117 142 118 143 int ReadBufFree(void) const; 119 144 int ReadBufAvail(void) const; 120 145 121 void StartupReadAheadThread(void);122 146 void ResetReadAhead(long long newinternal); 123 147 void KillReadAheadThread(void); 124 148 125 149 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 130 159 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; 133 163 134 ThreadedFileWriter *tfw; // not protected by a lock LR135 int fd2; // not protected by a lock LR136 137 bool writemode; // not protected by a lock LR138 139 long long readpos; // not protected by a lock HR140 long long writepos; // not protected by a lock HR141 142 bool stopreads; // not protected by a lock HR143 144 164 mutable QReadWriteLock rwlock; 145 165 146 RemoteFile *remotefile; // not protected by a lock LR 166 QString filename; // protected by rwlock 167 QString subtitlefilename; // protected by rwlock 147 168 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 151 171 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 164 173 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 170 175 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 172 194 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 176 197 177 QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex 178 QMutex readsAllowedWaitMutex; 198 bool oldfile; // protected by rwlock 179 199 180 int numfailures; // not protected by a lock MR 200 LiveTVChain *livetvchain; // protected by rwlock 201 bool ignoreliveeof; // protected by rwlock 181 202 182 bool commserror; // not protected by a lock MR203 long long readAdjust; // protected by rwlock 183 204 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. 186 210 187 bool oldfile; // not protected by a lock LR188 189 LiveTVChain *livetvchain; // not protected by a lock HR190 bool ignoreliveeof; // not protected by a lock HR191 192 long long readAdjust; // not protected by a lock HR193 194 211 /// 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 197 213 198 214 public: 199 215 static QMutex subExtLock; … … 206 222 static const uint kReadTestSize; 207 223 }; 208 224 209 #endif 225 #endif // _RINGBUFFER_H_ -
libs/libmythtv/mythplayer.cpp
3190 3190 if (!videoOutput) 3191 3191 return false; 3192 3192 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()); 3216 3196 } 3217 3197 3218 3198 /** \brief Returns true iff near end of recording.