Ticket #8812: 8812-v10.patch
File 8812-v10.patch, 77.7 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 streamOnly(false), 128 rawbitrate(4000), playspeed(1.0f), 127 readaheadrunning(false), reallyrunning(false), 128 request_pause(false), paused(false), 129 ateof(false), readsallowed(false), 130 setswitchtonext(false), streamOnly(false), 131 rawbitrate(8000), playspeed(1.0f), 129 132 fill_threshold(65536), fill_min(-1), 130 133 readblocksize(CHUNK), wanttoread(0), 131 134 numfailures(0), commserror(false), … … 263 266 return QString::null; 264 267 } 265 268 266 /** \fn RingBuffer::OpenFile(const QString&, uint) 267 * \brief Opens a file for reading. 269 /** \brief Opens a file for reading. 268 270 * 269 271 * \param lfilename Name of file to read 270 * \param retry Count How oftento retry reading the file before giving up272 * \param retryTime How many ms to retry reading the file before giving up 271 273 */ 272 void RingBuffer::OpenFile(const QString &lfilename, uint retry Count)274 void RingBuffer::OpenFile(const QString &lfilename, uint retry_ms) 273 275 { 274 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 )")275 .arg(lfilename).arg(retry Count));276 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 ms)") 277 .arg(lfilename).arg(retry_ms)); 276 278 277 uint openAttempts = retryCount + 1;279 rwlock.lockForWrite(); 278 280 279 281 filename = lfilename; 280 282 … … 365 367 if (is_local) 366 368 { 367 369 char buf[kReadTestSize]; 368 int timetowait = 500 * openAttempts;369 370 int lasterror = 0; 370 371 371 372 MythTimer openTimer; 372 373 openTimer.start(); 373 374 374 while (openTimer.elapsed() < timetowait) 375 uint openAttempts = 0; 376 while ((uint)openTimer.elapsed() < retry_ms) 375 377 { 378 openAttempts++; 376 379 lasterror = 0; 377 380 QByteArray fname = filename.toLocal8Bit(); 378 381 fd2 = open(fname.constData(), … … 381 384 if (fd2 < 0) 382 385 { 383 386 if (!check_permissions(filename)) 387 { 388 lasterror = 3; 384 389 break; 390 } 385 391 386 392 lasterror = 1; 387 usleep(10 00);393 usleep(10 * 1000); 388 394 } 389 395 else 390 396 { … … 394 400 lasterror = 2; 395 401 close(fd2); 396 402 fd2 = -1; 397 usleep(10 00);403 usleep(10 * 1000); 398 404 } 399 405 else 400 406 { 401 lseek(fd2, 0, SEEK_SET); 407 if (0 == lseek(fd2, 0, SEEK_SET)) 408 { 402 409 #if HAVE_POSIX_FADVISE 403 posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL);410 posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL); 404 411 #endif 405 openAttempts = 0; 406 break; 412 lasterror = 0; 413 break; 414 } 415 close(fd2); 416 fd2 = -1; 407 417 } 408 418 } 409 419 } 410 420 411 421 switch (lasterror) 412 422 { 423 case 0: 424 { 425 QFileInfo fi(filename); 426 oldfile = fi.lastModified() 427 .secsTo(QDateTime::currentDateTime()) > 60; 428 QString extension = fi.completeSuffix().toLower(); 429 if (is_subtitle_possible(extension)) 430 subtitlefilename = local_sub_filename(fi); 431 break; 432 } 413 433 case 1: 414 VERBOSE(VB_IMPORTANT, LOC +415 QString(" Could not open %1.").arg(filename));434 VERBOSE(VB_IMPORTANT, LOC_ERR + 435 QString("OpenFile(): Could not open.")); 416 436 break; 417 437 case 2: 418 VERBOSE(VB_IMPORTANT, LOC +419 QString(" Invalid file (fd %1) when opening '%2'.")420 .arg( fd2).arg(filename));438 VERBOSE(VB_IMPORTANT, LOC_ERR + 439 QString("OpenFile(): File too small (%1B).") 440 .arg(QFileInfo(filename).size())); 421 441 break; 442 case 3: 443 VERBOSE(VB_IMPORTANT, LOC_ERR + 444 "OpenFile(): Improper permissions."); 445 break; 422 446 default: 423 447 break; 424 448 } 449 VERBOSE(VB_FILE, LOC + QString("OpenFile() made %1 attempts in %2 ms") 450 .arg(openAttempts).arg(openTimer.elapsed())); 425 451 426 427 QFileInfo fileInfo(filename);428 if (fileInfo.lastModified().secsTo(QDateTime::currentDateTime()) >429 30 * 60)430 {431 oldfile = true;432 }433 434 QString extension = fileInfo.completeSuffix().toLower();435 if (is_subtitle_possible(extension))436 subtitlefilename = local_sub_filename(fileInfo);437 452 } 438 453 #ifdef USING_FRONTEND 439 454 else if (is_dvd) 440 455 { 441 456 dvdPriv->OpenFile(filename); 442 rwlock.lockForWrite();443 457 readblocksize = DVD_BLOCK_SIZE * 62; 444 rwlock.unlock();445 458 } 446 459 else if (is_bd) 447 460 { 448 461 bdPriv->OpenFile(filename); 449 rwlock.lockForWrite();450 462 readblocksize = BD_BLOCK_SIZE * 62; 451 rwlock.unlock();452 463 } 453 464 #endif // USING_FRONTEND 454 465 else … … 484 495 remotefile = new RemoteFile(filename, false, true, -1, &auxFiles); 485 496 if (!remotefile->isOpen()) 486 497 { 487 VERBOSE(VB_IMPORTANT, 498 VERBOSE(VB_IMPORTANT, LOC_ERR + 488 499 QString("RingBuffer::RingBuffer(): Failed to open remote " 489 500 "file (%1)").arg(filename)); 490 501 delete remotefile; … … 503 514 commserror = false; 504 515 numfailures = 0; 505 516 506 UpdateRawBitrate(4000); 517 rawbitrate = 8000; 518 CalcReadAheadThresh(); 519 520 rwlock.unlock(); 507 521 } 508 522 509 523 /** \fn RingBuffer::IsOpen(void) const … … 511 525 */ 512 526 bool RingBuffer::IsOpen(void) const 513 527 { 528 rwlock.lockForRead(); 529 bool ret; 514 530 #ifdef USING_FRONTEND 515 ret urntfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||531 ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) || 516 532 (bdPriv && bdPriv->IsOpen()); 517 533 #else // if !USING_FRONTEND 518 ret urntfw || (fd2 > -1) || remotefile;534 ret = tfw || (fd2 > -1) || remotefile; 519 535 #endif // !USING_FRONTEND 536 rwlock.unlock(); 537 return ret; 520 538 } 521 539 522 540 /** \fn RingBuffer::~RingBuffer(void) … … 560 578 rwlock.unlock(); 561 579 } 562 580 563 /** \fn RingBuffer::Start(void)564 * \brief Starts the read-ahead thread.565 *566 * If this RingBuffer is not in write-mode, the RingBuffer constructor567 * was called with a usereadahead of true, and the read-ahead thread568 * is not already running.569 */570 void RingBuffer::Start(void)571 {572 if (!writemode && !readaheadrunning && startreadahead)573 StartupReadAheadThread();574 }575 576 581 /** \fn RingBuffer::Reset(bool, bool, bool) 577 582 * \brief Resets the read-ahead thread and our position in the file 578 583 */ 579 584 void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal) 580 585 { 581 wantseek = true; 586 VERBOSE(VB_FILE, LOC + QString("Reset(%1,%2,%3)") 587 .arg(full).arg(toAdjust).arg(resetInternal)); 588 582 589 rwlock.lockForWrite(); 583 wantseek = false; 590 poslock.lockForWrite(); 591 584 592 numfailures = 0; 585 593 commserror = false; 586 594 setswitchtonext = false; … … 590 598 591 599 if (readpos != 0) 592 600 { 593 VERBOSE(VB_IMPORTANT, QString(601 VERBOSE(VB_IMPORTANT, LOC + QString( 594 602 "RingBuffer::Reset() nonzero readpos. toAdjust: %1 readpos: %2" 595 603 " readAdjust: %3").arg(toAdjust).arg(readpos).arg(readAdjust)); 596 604 } … … 604 612 if (resetInternal) 605 613 internalreadpos = readpos; 606 614 615 generalWait.wakeAll(); 616 poslock.unlock(); 607 617 rwlock.unlock(); 608 618 } 609 619 … … 625 635 unsigned errcnt = 0; 626 636 unsigned zerocnt = 0; 627 637 628 if (fd < 0)638 if (fd2 < 0) 629 639 { 630 640 VERBOSE(VB_IMPORTANT, LOC_ERR + 631 641 "Invalid file descriptor in 'safe_read()'"); … … 637 647 638 648 while (tot < sz) 639 649 { 640 ret = read(fd , (char *)data + tot, sz - tot);650 ret = read(fd2, (char *)data + tot, sz - tot); 641 651 if (ret < 0) 642 652 { 643 653 if (errno == EAGAIN) … … 699 709 VERBOSE(VB_IMPORTANT, LOC_ERR + 700 710 "RingBuffer::safe_read(RemoteFile* ...): read failed"); 701 711 712 poslock.lockForRead(); 702 713 rf->Seek(internalreadpos - readAdjust, SEEK_SET); 714 poslock.unlock(); 703 715 ret = 0; 704 716 numfailures++; 705 717 } … … 714 726 */ 715 727 void RingBuffer::UpdateRawBitrate(uint raw_bitrate) 716 728 { 729 VERBOSE(VB_FILE, LOC + QString("UpdateRawBitrate(%1Kb)").arg(raw_bitrate)); 730 if (raw_bitrate < 2500) 731 { 732 VERBOSE(VB_FILE, LOC + 733 QString("UpdateRawBitrate(%1Kb) - ignoring bitrate,") 734 .arg(raw_bitrate) + 735 "\n\t\t\tappears to be abnormally low."); 736 return; 737 } 738 717 739 rwlock.lockForWrite(); 718 740 rawbitrate = raw_bitrate; 719 741 CalcReadAheadThresh(); 720 742 rwlock.unlock(); 721 743 } 722 744 723 /** \fn RingBuffer::GetBitrate(void) const724 * \brief Returns effective bits per second (in thousands).725 *726 * NOTE: This is reported in telecom kilobytes, to get727 * the bits per second multiply by 1000, not 1024.728 */729 uint RingBuffer::GetBitrate(void) const730 {731 rwlock.lockForRead();732 uint tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate);733 rwlock.unlock();734 return min(rawbitrate * 3, tmp);735 }736 737 /** \fn RingBuffer::GetReadBlockSize(void) const738 * \brief Returns size of each disk read made by read ahead thread (in bytes).739 */740 uint RingBuffer::GetReadBlockSize(void) const741 {742 rwlock.lockForRead();743 uint tmp = readblocksize;744 rwlock.unlock();745 return tmp;746 }747 748 745 /** \fn RingBuffer::UpdatePlaySpeed(float) 749 746 * \brief Set the play speed, to allow RingBuffer adjust effective bitrate. 750 747 * \param play_speed Speed to set. (1.0 for normal speed) … … 768 765 { 769 766 uint estbitrate = 0; 770 767 771 wantseek = false;772 768 readsallowed = false; 773 readblocksize = CHUNK;769 readblocksize = max(readblocksize, CHUNK); 774 770 775 771 // loop without sleeping if the buffered data is less than this 776 fill_threshold = CHUNK * 2; 777 fill_min = 1; 772 fill_threshold = kBufferSize / 8; 778 773 779 #ifdef USING_FRONTEND 780 if (dvdPriv || bdPriv) 781 { 782 const uint KB32 = 32*1024; 783 const uint KB64 = 64*1024; 784 const uint KB128 = 128*1024; 785 const uint KB256 = 256*1024; 786 const uint KB512 = 512*1024; 774 const uint KB32 = 32*1024; 775 const uint KB64 = 64*1024; 776 const uint KB128 = 128*1024; 777 const uint KB256 = 256*1024; 778 const uint KB512 = 512*1024; 787 779 788 estbitrate = (uint) max(abs(rawbitrate * playspeed), 789 0.5f * rawbitrate); 790 estbitrate = min(rawbitrate * 3, estbitrate); 791 readblocksize = (estbitrate > 2500) ? KB64 : KB32; 792 readblocksize = (estbitrate > 5000) ? KB128 : readblocksize; 793 readblocksize = (estbitrate > 9000) ? KB256 : readblocksize; 794 readblocksize = (estbitrate > 18000) ? KB512 : readblocksize; 780 estbitrate = (uint) max(abs(rawbitrate * playspeed), 781 0.5f * rawbitrate); 782 estbitrate = min(rawbitrate * 3, estbitrate); 783 int rbs = (estbitrate > 2500) ? KB64 : KB32; 784 rbs = (estbitrate > 5000) ? KB128 : rbs; 785 rbs = (estbitrate > 9000) ? KB256 : rbs; 786 rbs = (estbitrate > 18000) ? KB512 : rbs; 787 readblocksize = max(rbs,readblocksize); 795 788 796 // minumum seconds of buffering before allowing read 797 float secs_min = 0.1; 789 // minumum seconds of buffering before allowing read 790 float secs_min = 0.25; 791 // set the minimum buffering before allowing ffmpeg read 792 fill_min = (uint) ((estbitrate * secs_min) * 0.125f); 793 // make this a multiple of ffmpeg block size.. 794 fill_min = ((fill_min / KB32) + 1) * KB32; 798 795 799 // set the minimum buffering before allowing ffmpeg read 800 fill_min = (uint) ((estbitrate * secs_min) * 0.125f); 801 // make this a multiple of ffmpeg block size.. 802 fill_min = ((fill_min / KB32) + 1) * KB32; 803 } 804 #endif // USING_FRONTEND 805 806 VERBOSE(VB_PLAYBACK, LOC + 807 QString("CalcReadAheadThresh(%1 KB)\n\t\t\t -> " 796 VERBOSE(VB_FILE, LOC + 797 QString("CalcReadAheadThresh(%1 Kb)\n\t\t\t -> " 808 798 "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)") 809 799 .arg(estbitrate).arg(fill_threshold/1024) 810 800 .arg(fill_min/1024).arg(readblocksize/1024)); 811 801 } 812 802 813 /** \fn RingBuffer::ReadBufFree(void) const 814 * \brief Returns number of bytes available for reading into buffer. 815 */ 803 bool RingBuffer::IsNearEnd(double fps, uint vvf) const 804 { 805 rwlock.lockForRead(); 806 int sz = ReadBufAvail(); 807 uint rbs = readblocksize; 808 // telecom kilobytes (i.e. 1000 per k not 1024) 809 uint tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate); 810 uint kbits_per_sec = min(rawbitrate * 3, tmp); 811 rwlock.unlock(); 812 813 // WARNING: readahead_frames can greatly overestimate or underestimate 814 // the number of frames available in the read ahead buffer 815 // when rh_frames is less than the keyframe distance. 816 double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps; 817 double readahead_frames = sz / bytes_per_frame; 818 819 bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5); 820 821 VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()" 822 <<" br("<<(kbits_per_sec/8)<<"KB)" 823 <<" sz("<<(sz / 1000)<<"KB)" 824 <<" vfl("<<vvf<<")" 825 <<" frh("<<((uint)readahead_frames)<<")" 826 <<" ne:"<<near_end); 827 828 return near_end; 829 } 830 831 /// \brief Returns number of bytes available for reading into buffer. 832 /// WARNING: Must be called with rwlock in locked state. 816 833 int RingBuffer::ReadBufFree(void) const 817 834 { 818 QMutexLocker locker(&readAheadLock); 819 return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1; 835 rbrlock.lockForRead(); 836 rbwlock.lockForRead(); 837 int ret = ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1; 838 rbwlock.unlock(); 839 rbrlock.unlock(); 840 return ret; 820 841 } 821 842 822 /** \fn RingBuffer::ReadBufAvail(void) const 823 * \brief Returns number of bytes available for reading from buffer. 824 */ 843 /// \brief Returns number of bytes available for reading from buffer. 844 /// WARNING: Must be called with rwlock in locked state. 825 845 int RingBuffer::ReadBufAvail(void) const 826 846 { 827 QMutexLocker locker(&readAheadLock); 828 return (rbwpos >= rbrpos) ? 829 rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos; 847 rbrlock.lockForRead(); 848 rbwlock.lockForRead(); 849 int ret = (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos; 850 rbwlock.unlock(); 851 rbrlock.unlock(); 852 return ret; 830 853 } 831 854 832 855 /** \fn RingBuffer::ResetReadAhead(long long) … … 836 859 * buffer doesn't contain any stale data, and so that it will read 837 860 * any new data from the new position in the file. 838 861 * 839 * WARNING: Must be called with rwlock in write lock state.862 * WARNING: Must be called with rwlock and poslock in write lock state. 840 863 * 841 864 * \param newinternal Position in file to start reading data from 842 865 */ 843 866 void RingBuffer::ResetReadAhead(long long newinternal) 844 867 { 845 readAheadLock.lock(); 846 readblocksize = CHUNK; 868 VERBOSE(VB_FILE, LOC + QString("ResetReadAhead(internalreadpos = %1->%2)") 869 .arg(internalreadpos).arg(newinternal)); 870 871 rbrlock.lockForWrite(); 872 rbwlock.lockForWrite(); 873 874 CalcReadAheadThresh(); 847 875 rbrpos = 0; 848 876 rbwpos = 0; 849 877 internalreadpos = newinternal; 850 878 ateof = false; 851 879 readsallowed = false; 852 880 setswitchtonext = false; 853 readAheadLock.unlock(); 881 generalWait.wakeAll(); 882 883 rbwlock.unlock(); 884 rbrlock.unlock(); 854 885 } 855 886 856 /** \fn RingBuffer::StartupReadAheadThread(void)857 * \brief Creates the read-ahead thread, and waits for it to start.887 /** 888 * \brief Starts the read-ahead thread. 858 889 * 859 * \sa Start(void). 890 * If the RingBuffer constructor was not called with a usereadahead 891 * of true of if this was reset to false because we're dealing with 892 * a DVD the read ahead thread will not be started. 893 * 894 * If this RingBuffer is in write-mode a warning will be printed and 895 * the read ahead thread will not be started. 896 * 897 * If the read ahead thread is already running a warning will be printed 898 * and the read ahead thread will not be started. 899 * 860 900 */ 861 void RingBuffer::Start upReadAheadThread(void)901 void RingBuffer::Start(void) 862 902 { 863 readaheadrunning = false;903 bool do_start = true; 864 904 865 readAheadRunningCondLock.lock(); 905 rwlock.lockForWrite(); 906 if (!startreadahead) 907 { 908 do_start = false; 909 } 910 else if (writemode) 911 { 912 VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, " 913 "this is a write only RingBuffer"); 914 do_start = false; 915 } 916 else if (readaheadrunning) 917 { 918 VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, " 919 "already running"); 920 do_start = false; 921 } 922 923 if (!do_start) 924 { 925 rwlock.unlock(); 926 return; 927 } 928 929 StartReads(); 930 866 931 QThread::start(); 867 readAheadRunningCond.wait(&readAheadRunningCondLock); 868 readAheadRunningCondLock.unlock(); 932 933 while (readaheadrunning && !reallyrunning) 934 generalWait.wait(&rwlock); 935 936 rwlock.unlock(); 869 937 } 870 938 871 939 /** \fn RingBuffer::KillReadAheadThread(void) … … 873 941 */ 874 942 void RingBuffer::KillReadAheadThread(void) 875 943 { 876 if (!readaheadrunning) 877 return; 944 rwlock.lockForWrite(); 945 bool do_wait = readaheadrunning; 946 readaheadrunning = false; 947 StopReads(); 948 generalWait.wakeAll(); 949 rwlock.unlock(); 878 950 879 readaheadrunning = false;880 QThread::wait();951 if (do_wait) 952 QThread::wait(); 881 953 } 882 954 883 955 /** \fn RingBuffer::StopReads(void) … … 887 959 void RingBuffer::StopReads(void) 888 960 { 889 961 stopreads = true; 890 availWait.wakeAll();962 generalWait.wakeAll(); 891 963 } 892 964 893 965 /** \fn RingBuffer::StartReads(void) … … 905 977 */ 906 978 void RingBuffer::Pause(void) 907 979 { 908 pausereadthread = true;909 980 StopReads(); 981 982 rwlock.lockForWrite(); 983 request_pause = true; 984 rwlock.unlock(); 910 985 } 911 986 912 987 /** \fn RingBuffer::Unpause(void) … … 916 991 void RingBuffer::Unpause(void) 917 992 { 918 993 StartReads(); 919 pausereadthread = false; 994 995 rwlock.lockForWrite(); 996 request_pause = false; 997 generalWait.wakeAll(); 998 rwlock.unlock(); 920 999 } 921 1000 1001 /// Returns false iff read-ahead is not running and read-ahead is not paused. 1002 bool RingBuffer::isPaused(void) const 1003 { 1004 rwlock.lockForRead(); 1005 bool ret = !readaheadrunning || paused; 1006 rwlock.unlock(); 1007 return ret; 1008 } 1009 922 1010 /** \fn RingBuffer::WaitForPause(void) 923 1011 * \brief Waits for Pause(void) to take effect. 924 1012 */ 925 1013 void RingBuffer::WaitForPause(void) 926 1014 { 927 if (!readaheadrunning)928 return;1015 MythTimer t; 1016 t.start(); 929 1017 930 if (!readaheadpaused) 1018 rwlock.lockForRead(); 1019 while (readaheadrunning && !paused && request_pause) 931 1020 { 932 // Qt4 requires a QMutex as a parameter... 933 // not sure if this is the best solution. Mutex Must be locked before wait. 934 QMutex mutex; 935 mutex.lock(); 1021 generalWait.wait(&rwlock, 1000); 1022 if (readaheadrunning && !paused && request_pause && t.elapsed() > 1000) 1023 { 1024 VERBOSE(VB_IMPORTANT, LOC_WARN + 1025 QString("Waited %1 ms for ringbuffer pause..") 1026 .arg(t.elapsed())); 1027 } 1028 } 1029 rwlock.unlock(); 1030 } 936 1031 937 while (!pauseWait.wait(&mutex, 1000)) 938 VERBOSE(VB_IMPORTANT, 939 LOC + "Waited too long for ringbuffer pause.."); 1032 bool RingBuffer::PauseAndWait(void) 1033 { 1034 const uint timeout = 500; // ms 1035 1036 if (request_pause) 1037 { 1038 if (!paused) 1039 { 1040 rwlock.unlock(); 1041 rwlock.lockForWrite(); 1042 1043 if (request_pause) 1044 { 1045 paused = true; 1046 generalWait.wakeAll(); 1047 } 1048 1049 rwlock.unlock(); 1050 rwlock.lockForRead(); 1051 } 1052 1053 if (request_pause && paused && readaheadrunning) 1054 generalWait.wait(&rwlock, timeout); 940 1055 } 1056 1057 if (!request_pause && paused) 1058 { 1059 rwlock.unlock(); 1060 rwlock.lockForWrite(); 1061 1062 if (!request_pause) 1063 { 1064 paused = false; 1065 generalWait.wakeAll(); 1066 } 1067 1068 rwlock.unlock(); 1069 rwlock.lockForRead(); 1070 } 1071 1072 return request_pause || paused; 941 1073 } 942 1074 943 1075 void RingBuffer::run(void) 944 1076 { 945 long long totfree = 0; 946 int ret = -1; 947 int used = 0; 948 int loops = 0; 949 1077 // These variables are used to adjust the read block size 950 1078 struct timeval lastread, now; 951 gettimeofday(&lastread, NULL);952 const int KB640 = 640*1024;953 1079 int readtimeavg = 300; 954 int readinterval;1080 bool ignore_for_read_timing = true; 955 1081 956 pausereadthread = false;1082 gettimeofday(&lastread, NULL); // this is just to keep gcc happy 957 1083 958 readAheadBuffer = new char[kBufferSize + KB640];959 960 1084 rwlock.lockForWrite(); 1085 poslock.lockForWrite(); 1086 request_pause = false; 1087 readAheadBuffer = new char[kBufferSize + 1024]; 961 1088 ResetReadAhead(0); 1089 readaheadrunning = true; 1090 reallyrunning = true; 1091 generalWait.wakeAll(); 1092 poslock.unlock(); 962 1093 rwlock.unlock(); 963 1094 964 totfree = ReadBufFree(); 1095 // NOTE: this must loop at some point hold only 1096 // a read lock on rwlock, so that other functions 1097 // such as reset and seek can take priority. 965 1098 966 readaheadrunning = true; 967 readAheadRunningCondLock.lock(); 968 readAheadRunningCond.wakeAll(); 969 readAheadRunningCondLock.unlock(); 1099 rwlock.lockForRead(); 1100 1101 VERBOSE(VB_FILE, LOC + QString("Initial readblocksize %1K & fill_min %2K") 1102 .arg(readblocksize/1024).arg(fill_min/1024)); 1103 970 1104 while (readaheadrunning) 971 1105 { 972 if ( pausereadthread || writemode)1106 if (PauseAndWait()) 973 1107 { 974 readaheadpaused = true; 975 pauseWait.wakeAll(); 976 usleep(5000); 977 totfree = ReadBufFree(); 1108 ignore_for_read_timing = true; 978 1109 continue; 979 1110 } 980 1111 981 if (readaheadpaused) 1112 long long totfree = ReadBufFree(); 1113 1114 if (totfree < readblocksize) 982 1115 { 983 totfree = ReadBufFree();984 readaheadpaused = false;1116 generalWait.wait(&rwlock, 1000); 1117 continue; 985 1118 } 986 1119 987 totfree = ReadBufFree(); 988 if (totfree < GetReadBlockSize()) 1120 if (ignorereadpos >= 0) 989 1121 { 990 usleep(50000); 991 totfree = ReadBufFree(); 992 ++loops; 993 // break out if we've spent lots of time here, just in case things 994 // are waiting on a wait condition that never got triggered. 995 if (readsallowed && loops < 10) 996 continue; 1122 generalWait.wait(&rwlock, 1000); 1123 continue; 997 1124 } 998 loops = 0;999 1125 1000 rwlock.lockForRead(); 1001 if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext) 1126 // No point in trying to read if stopreads is set but do sleep 1127 // a little so we don't get stuck in a tight busy loop here.. 1128 if (stopreads) 1002 1129 { 1130 ignore_for_read_timing = true; 1131 generalWait.wait(&rwlock, 10); 1132 continue; 1133 } 1134 1135 int read_return = -1; 1136 if (totfree >= readblocksize && !commserror && 1137 !ateof && !setswitchtonext) 1138 { 1003 1139 // limit the read size 1004 1140 totfree = readblocksize; 1005 1141 1006 1142 // adapt blocksize 1007 1143 gettimeofday(&now, NULL); 1008 readinterval = (now.tv_sec - lastread.tv_sec ) * 1000 + 1009 (now.tv_usec - lastread.tv_usec) / 1000; 1144 if (!ignore_for_read_timing) 1145 { 1146 int readinterval = (now.tv_sec - lastread.tv_sec ) * 1000 + 1147 (now.tv_usec - lastread.tv_usec) / 1000; 1148 readtimeavg = (readtimeavg * 9 + readinterval) / 10; 1010 1149 1011 readtimeavg = (readtimeavg * 9 + readinterval) / 10; 1012 1013 if (readtimeavg < 200 && readblocksize < KB640) 1014 { 1015 readblocksize += CHUNK; 1016 //VERBOSE(VB_PLAYBACK, 1017 // QString("Avg read interval was %1 msec. %2K block size") 1018 // .arg(readtimeavg).arg(readblocksize/1024)); 1019 readtimeavg = 300; 1150 if (readtimeavg < 150 && (uint)readblocksize < (kBufferSize>>2)) 1151 { 1152 int old_block_size = readblocksize; 1153 readblocksize = 3 * readblocksize / 2; 1154 readblocksize = ((readblocksize+CHUNK-1) / CHUNK) * CHUNK; 1155 VERBOSE(VB_FILE, LOC + 1156 QString("Avg read interval was %1 msec. " 1157 "%2K -> %3K block size") 1158 .arg(readtimeavg) 1159 .arg(old_block_size/1024) 1160 .arg(readblocksize/1024)); 1161 readtimeavg = 225; 1162 } 1163 else if (readtimeavg > 300 && readblocksize > CHUNK) 1164 { 1165 readblocksize -= CHUNK; 1166 VERBOSE(VB_FILE, LOC + 1167 QString("Avg read interval was %1 msec. " 1168 "%2K -> %3K block size") 1169 .arg(readtimeavg) 1170 .arg((readblocksize+CHUNK)/1024) 1171 .arg(readblocksize/1024)); 1172 readtimeavg = 225; 1173 } 1020 1174 } 1021 else if (readtimeavg > 400 && readblocksize > CHUNK) 1022 { 1023 readblocksize -= CHUNK; 1024 //VERBOSE(VB_PLAYBACK, 1025 // QString("Avg read interval was %1 msec. %2K block size") 1026 // .arg(readtimeavg).arg(readblocksize/1024)); 1027 readtimeavg = 300; 1028 } 1175 ignore_for_read_timing = false; 1029 1176 lastread = now; 1030 1177 1178 rbwlock.lockForRead(); 1031 1179 if (rbwpos + totfree > kBufferSize) 1180 { 1032 1181 totfree = kBufferSize - rbwpos; 1182 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1183 "Shrinking read, near end of buffer"); 1184 } 1033 1185 1034 1186 if (internalreadpos == 0) 1035 totfree = fill_min; 1187 { 1188 totfree = max(fill_min, readblocksize); 1189 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1190 "Reading enough data to start playback"); 1191 } 1036 1192 1193 VERBOSE(VB_FILE|VB_EXTRA, 1194 LOC + QString("safe_read(...@%1, %2) -- begin") 1195 .arg(rbwpos).arg(totfree)); 1037 1196 if (remotefile) 1038 1197 { 1039 1198 if (livetvchain && livetvchain->HasNext()) 1040 1199 remotefile->SetTimeout(true); 1041 1042 ret = safe_read(remotefile, readAheadBuffer + rbwpos, 1043 totfree); 1044 internalreadpos += ret; 1200 read_return = safe_read( 1201 remotefile, readAheadBuffer + rbwpos, totfree); 1045 1202 } 1046 1203 #ifdef USING_FRONTEND 1047 1204 else if (dvdPriv) 1048 1205 { 1049 re t = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);1050 internalreadpos += ret;1206 read_return = dvdPriv->safe_read( 1207 readAheadBuffer + rbwpos, totfree); 1051 1208 } 1052 1209 else if (bdPriv) 1053 1210 { 1054 re t = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);1055 internalreadpos += ret;1211 read_return = bdPriv->safe_read( 1212 readAheadBuffer + rbwpos, totfree); 1056 1213 } 1057 1214 #endif // USING_FRONTEND 1058 1215 else 1059 1216 { 1060 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree); 1061 internalreadpos += ret; 1217 read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree); 1062 1218 } 1219 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1220 QString("safe_read(...@%1, %2) -> %3") 1221 .arg(rbwpos).arg(totfree).arg(read_return)); 1222 rbwlock.unlock(); 1223 } 1063 1224 1064 readAheadLock.lock(); 1065 if (ret > 0 ) 1066 rbwpos = (rbwpos + ret) % kBufferSize; 1067 readAheadLock.unlock(); 1225 // If stopreads is set we toss the read data since we're probably 1226 // doing a seek or opening a new file anyway. 1227 if (stopreads) 1228 { 1229 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1230 "Saw stopreads.. dropping recently read data."); 1231 continue; 1232 } 1068 1233 1069 if (ret == 0 && !stopreads) 1234 if (read_return >= 0) 1235 { 1236 poslock.lockForWrite(); 1237 rbwlock.lockForWrite(); 1238 internalreadpos += read_return; 1239 rbwpos = (rbwpos + read_return) % kBufferSize; 1240 VERBOSE(VB_FILE|VB_EXTRA, 1241 LOC + QString("rbwpos += %1K requested %2K in read") 1242 .arg(read_return/1024,3).arg(totfree/1024,3)); 1243 rbwlock.unlock(); 1244 poslock.unlock(); 1245 } 1246 1247 int used = kBufferSize - ReadBufFree(); 1248 1249 if ((0 == read_return) || (numfailures > 5) || 1250 (readsallowed != (used >= fill_min || ateof || 1251 setswitchtonext || commserror))) 1252 { 1253 // If readpos changes while the lock is released 1254 // we should not handle the 0 read_return now. 1255 long long old_readpos = readpos; 1256 1257 rwlock.unlock(); 1258 rwlock.lockForWrite(); 1259 1260 commserror |= (numfailures > 5); 1261 1262 readsallowed = used >= fill_min || ateof || 1263 setswitchtonext || commserror; 1264 1265 if (0 == read_return && old_readpos == readpos) 1070 1266 { 1071 1267 if (livetvchain) 1072 1268 { … … 1078 1274 } 1079 1275 } 1080 1276 else 1277 { 1081 1278 ateof = true; 1279 } 1082 1280 } 1083 }1084 1281 1085 if (numfailures > 5) 1086 commserror = true; 1087 1088 totfree = ReadBufFree(); 1089 used = kBufferSize - totfree; 1090 1091 if (ateof || commserror) 1092 { 1093 readsallowed = true; 1094 totfree = 0; 1282 rwlock.unlock(); 1283 rwlock.lockForRead(); 1284 used = kBufferSize - ReadBufFree(); 1095 1285 } 1096 1286 1097 if (!readsallowed && (used >= fill_min || setswitchtonext)) 1098 { 1099 readsallowed = true; 1100 //VERBOSE(VB_PLAYBACK, QString("reads allowed (%1 %2)").arg(used) 1101 // .arg(fill_min)); 1102 } 1103 //else if (!readsallowed) 1104 // VERBOSE(VB_PLAYBACK, QString("buffering (%1 %2 %3)").arg(used) 1105 // .arg(fill_min) 1106 // .arg(ret)); 1287 VERBOSE(VB_FILE|VB_EXTRA, LOC + "@ end of read ahead loop"); 1107 1288 1108 if (readsallowed && used < fill_min && !ateof && !setswitchtonext) 1109 { 1110 readsallowed = false; 1111 //VERBOSE(VB_GENERAL, QString ("rebuffering (%1 %2)").arg(used) 1112 // .arg(fill_min)); 1113 } 1114 1115 readsAllowedWaitMutex.lock(); 1116 if (readsallowed || stopreads) 1117 readsAllowedWait.wakeAll(); 1118 readsAllowedWaitMutex.unlock(); 1119 1120 availWaitMutex.lock(); 1121 if (commserror || ateof || stopreads || setswitchtonext || 1289 if (readsallowed || commserror || ateof || setswitchtonext || 1122 1290 (wanttoread <= used && wanttoread > 0)) 1123 1291 { 1124 availWait.wakeAll(); 1292 // To give other threads a good chance to handle these 1293 // conditions, even if they are only requesting a read lock 1294 // like us, yield (currently implemented with short usleep). 1295 generalWait.wakeAll(); 1296 rwlock.unlock(); 1297 usleep(5 * 1000); 1298 rwlock.lockForRead(); 1125 1299 } 1126 availWaitMutex.unlock(); 1127 1128 rwlock.unlock(); 1129 1130 if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) && 1131 !pausereadthread) 1300 else 1132 1301 { 1133 usleep(500); 1302 // yield if we have nothing to do... 1303 if (!request_pause && 1304 (used >= fill_threshold || ateof || setswitchtonext)) 1305 { 1306 generalWait.wait(&rwlock, 100); 1307 } 1134 1308 } 1135 1309 } 1136 1310 1311 rwlock.unlock(); 1312 1313 rwlock.lockForWrite(); 1314 rbrlock.lockForWrite(); 1315 rbwlock.lockForWrite(); 1316 1317 rbrpos = 0; 1318 rbwpos = 0; 1319 reallyrunning = false; 1320 readsallowed = false; 1137 1321 delete [] readAheadBuffer; 1322 1138 1323 readAheadBuffer = NULL; 1139 rbrpos = 0; 1140 rbwpos = 0; 1324 rbwlock.unlock(); 1325 rbrlock.unlock(); 1326 rwlock.unlock(); 1141 1327 } 1142 1328 1143 1329 long long RingBuffer::SetAdjustFilesize(void) 1144 1330 { 1331 rwlock.lockForWrite(); 1332 poslock.lockForRead(); 1145 1333 readAdjust += internalreadpos; 1334 poslock.unlock(); 1335 rwlock.unlock(); 1146 1336 return readAdjust; 1147 1337 } 1148 1338 1149 1339 int RingBuffer::Peek(void *buf, int count) 1150 1340 { 1151 long long ret = -1; 1152 1153 if (!readaheadrunning) 1154 { 1155 long long old_pos = Seek(0, SEEK_CUR); 1156 1157 ret = Read(buf, count); 1158 #ifdef USING_FRONTEND 1159 if (ret > 0 && dvdPriv) 1160 { 1161 // This is technically incorrect it we should seek 1162 // back to exactly where we were, but we can't do 1163 // that with the DVDRingBuffer 1164 dvdPriv->NormalSeek(0); 1165 } 1166 else if (ret > 0 && bdPriv) 1167 { 1168 // No idea if this will work. 1169 bdPriv->Seek(0); 1170 } 1171 else 1172 #endif // USING_FRONTEND 1173 if (ret > 0) 1174 { 1175 long long new_pos = Seek(-ret, SEEK_CUR); 1176 if (new_pos != old_pos) 1177 { 1178 VERBOSE(VB_IMPORTANT, LOC_ERR + 1179 QString("Peek() Failed to return from new " 1180 "position %1 to old position %2, now " 1181 "at position %3") 1182 .arg(old_pos - ret).arg(old_pos).arg(new_pos)); 1183 } 1184 } 1185 } 1186 else 1187 { 1188 ret = ReadFromBuf(buf, count, true); 1189 } 1190 1341 int ret = ReadPriv(buf, count, true); 1191 1342 if (ret != count) 1192 1343 { 1193 1344 VERBOSE(VB_IMPORTANT, LOC_WARN + … … 1197 1348 return ret; 1198 1349 } 1199 1350 1200 /** 1201 * \brief Reads from the read-ahead buffer, this is called by 1202 * Read(void*, int) when the read-ahead thread is running. 1203 * \param buf Pointer to where data will be written 1204 * \param count Number of bytes to read 1205 * \param peek If true, don't increment read count 1206 * \return Returns number of bytes read 1207 */ 1208 int RingBuffer::ReadFromBuf(void *buf, int count, bool peek) 1351 bool RingBuffer::WaitForReadsAllowed(void) 1209 1352 { 1210 if (commserror)1211 return 0;1353 MythTimer t; 1354 t.start(); 1212 1355 1213 bool readone = false; 1214 int readErr = 0; 1215 1216 if (readaheadpaused && stopreads) 1356 while (!readsallowed && !stopreads && 1357 !request_pause && !commserror && readaheadrunning) 1217 1358 { 1218 readone = true; 1219 Unpause(); 1220 } 1221 else 1222 { 1223 QMutexLocker locker(&readsAllowedWaitMutex); 1359 generalWait.wait(&rwlock, 1000); 1360 if (!readsallowed && t.elapsed() > 1000) 1361 { 1362 VERBOSE(VB_IMPORTANT, LOC_WARN + 1363 "Taking too long to be allowed to read.."); 1224 1364 1225 while (!readsallowed && !stopreads) 1226 { 1227 if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000)) 1365 if (t.elapsed() > 10000) 1228 1366 { 1229 VERBOSE(VB_IMPORTANT, 1230 LOC + "Taking too long to be allowed to read.."); 1231 readErr++; 1232 1233 // HACK Sometimes the readhead thread gets borked on startup. 1234 if ((readErr > 4 && readErr % 2) && (rbrpos ==0)) 1235 { 1236 VERBOSE(VB_IMPORTANT, "restarting readhead thread.."); 1237 KillReadAheadThread(); 1238 StartupReadAheadThread(); 1239 } 1240 1241 if (readErr > 10) 1242 { 1243 VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than " 1244 "10 seconds to be allowed to read, aborting."); 1245 wanttoread = 0; 1246 stopreads = true; 1247 return 0; 1248 } 1367 VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than " 1368 "10 seconds to be allowed to read, aborting."); 1369 return false; 1249 1370 } 1250 1371 } 1251 1372 } 1252 1373 1374 return readsallowed; 1375 } 1376 1377 bool RingBuffer::WaitForAvail(int count) 1378 { 1253 1379 int avail = ReadBufAvail(); 1380 count = (ateof && avail < count) ? avail : count; 1254 1381 1255 if (ateof && avail < count)1256 count = avail;1257 1258 1382 MythTimer t; 1259 1383 t.start(); 1260 while (avail < count && !stopreads) 1384 while ((avail < count) && !stopreads && 1385 !request_pause && !commserror && readaheadrunning) 1261 1386 { 1262 availWaitMutex.lock();1263 1387 wanttoread = count; 1264 if (!availWait.wait(&availWaitMutex, 250)) 1388 generalWait.wait(&rwlock, 250); 1389 avail = ReadBufAvail(); 1390 1391 if ((ateof || setswitchtonext) && avail < count) 1392 count = avail; 1393 1394 if (avail < count) 1265 1395 { 1266 1396 int elapsed = t.elapsed(); 1267 if (/*((elapsed > 500) && (elapsed < 750)) ||*/ 1397 if (((elapsed > 250) && (elapsed < 500)) || 1398 ((elapsed > 500) && (elapsed < 750)) || 1268 1399 ((elapsed > 1000) && (elapsed < 1250)) || 1269 1400 ((elapsed > 2000) && (elapsed < 2250)) || 1270 1401 ((elapsed > 4000) && (elapsed < 4250)) || 1271 ((elapsed > 8000) && (elapsed < 8250))) 1402 ((elapsed > 8000) && (elapsed < 8250)) || 1403 ((elapsed > 9000))) 1272 1404 { 1273 1405 VERBOSE(VB_IMPORTANT, LOC + "Waited " + 1274 QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) + 1275 " seconds for data to become available..."); 1406 QString("%1").arg((elapsed / 250) * 0.25f, 3, 'f', 1) + 1407 " seconds for data \n\t\t\tto become available..." + 1408 QString(" %2 < %3") 1409 .arg(avail).arg(count)); 1276 1410 if (livetvchain) 1277 1411 { 1278 1412 VERBOSE(VB_IMPORTANT, "Checking to see if there's a " … … 1295 1429 VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to " 1296 1430 "impending livetv switch."); 1297 1431 1298 ateof = true; 1299 wanttoread = 0; 1300 stopreads = true; 1301 availWaitMutex.unlock(); 1302 return 0; 1432 return false; 1303 1433 } 1304 1434 } 1435 } 1305 1436 1437 wanttoread = 0; 1438 1439 return avail >= count; 1440 } 1441 1442 int RingBuffer::ReadDirect(void *buf, int count, bool peek) 1443 { 1444 long long old_pos = 0; 1445 if (peek) 1446 { 1447 poslock.lockForRead(); 1448 old_pos = (ignorereadpos >= 0) ? ignorereadpos : readpos; 1449 poslock.unlock(); 1450 } 1451 1452 int ret; 1453 if (remotefile) 1454 ret = safe_read(remotefile, buf, count); 1455 #ifdef USING_FRONTEND 1456 else if (dvdPriv) 1457 ret = dvdPriv->safe_read(buf, count); 1458 else if (bdPriv) 1459 ret = bdPriv->safe_read(buf, count); 1460 #endif // USING_FRONTEND 1461 else if (fd2 >= 0) 1462 ret = safe_read(fd2, buf, count); 1463 else 1464 { 1465 ret = -1; 1466 errno = EBADF; 1467 } 1468 1469 poslock.lockForWrite(); 1470 if (ignorereadpos >= 0 && ret > 0) 1471 { 1472 if (peek) 1473 { 1474 // seek should always succeed since we were at this position 1475 if (remotefile) 1476 remotefile->Seek(old_pos, SEEK_SET); 1477 else 1478 lseek64(fd2, old_pos, SEEK_SET); 1479 } 1480 else 1481 { 1482 ignorereadpos += ret; 1483 } 1484 poslock.unlock(); 1485 return ret; 1486 } 1487 poslock.unlock(); 1488 1489 if (peek && ret > 0) 1490 { 1491 if (!dvdPriv && !bdPriv) 1492 { 1493 long long new_pos = Seek(old_pos, SEEK_SET, true); 1494 if (new_pos != old_pos) 1495 { 1496 VERBOSE(VB_IMPORTANT, LOC_ERR + 1497 QString("Peek() Failed to return from new " 1498 "position %1 to old position %2, now " 1499 "at position %3") 1500 .arg(old_pos - ret).arg(old_pos).arg(new_pos)); 1501 } 1502 } 1503 else if (old_pos != 0) 1504 { 1505 VERBOSE(VB_IMPORTANT, LOC_ERR + 1506 "DVD and Blu-Ray do not support arbitrary " 1507 "peeks except when read-ahead is enabled." 1508 "\n\t\t\tWill seek to beginning of video."); 1509 } 1510 #ifdef USING_FRONTEND 1511 if (dvdPriv) 1512 { 1513 dvdPriv->NormalSeek(0); 1514 } 1515 else if (bdPriv) 1516 { 1517 bdPriv->Seek(0); 1518 } 1519 #endif // USING_FRONTEND 1520 } 1521 1522 return ret; 1523 } 1524 1525 /** \brief When possible reads from the read-ahead buffer, 1526 * otherwise reads directly from the device. 1527 * 1528 * \param buf Pointer to where data will be written 1529 * \param count Number of bytes to read 1530 * \param peek If true, don't increment read count 1531 * \return Returns number of bytes read 1532 */ 1533 int RingBuffer::ReadPriv(void *buf, int count, bool peek) 1534 { 1535 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1536 QString("ReadPriv(*, %1, %2) @%3 -- begin") 1537 .arg(count).arg(peek?"peek":"normal").arg(rbrpos)); 1538 1539 rwlock.lockForRead(); 1540 if (writemode) 1541 { 1542 VERBOSE(VB_IMPORTANT, LOC_ERR + 1543 "Attempt to read from a write only file"); 1544 errno = EBADF; 1545 rwlock.unlock(); 1546 return -1; 1547 } 1548 1549 if (commserror) 1550 { 1551 VERBOSE(VB_IMPORTANT, LOC_ERR + 1552 "Attempt to read after commserror set"); 1553 errno = EIO; 1554 rwlock.unlock(); 1555 return -1; 1556 } 1557 1558 if (request_pause || stopreads || !readaheadrunning || (ignorereadpos>=0)) 1559 { 1560 rwlock.unlock(); 1561 rwlock.lockForWrite(); 1562 // we need a write lock so the read-ahead thread 1563 // can't start mucking with the read position. 1564 // If the read ahead thread was started while we 1565 // didn't hold the lock, we proceed with a normal 1566 // read from the buffer, otherwise we read directly. 1567 if (request_pause || stopreads || 1568 !readaheadrunning || (ignorereadpos >= 0)) 1569 { 1570 int ret = ReadDirect(buf, count, peek); 1571 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1572 QString("ReadPriv(*, %1, %2) @%3 -- RD checksum %4") 1573 .arg(count).arg(peek?"peek":"normal").arg(rbrpos) 1574 .arg(qChecksum((char*)buf,count))); 1575 rwlock.unlock(); 1576 return ret; 1577 } 1578 rwlock.unlock(); 1579 rwlock.lockForRead(); 1580 } 1581 1582 if (!WaitForReadsAllowed()) 1583 { 1584 VERBOSE(VB_FILE, LOC + "!WaitForReadsAllowed()"); 1585 rwlock.unlock(); 1586 rwlock.lockForWrite(); 1306 1587 wanttoread = 0; 1307 availWaitMutex.unlock(); 1588 stopreads = true; 1589 rwlock.unlock(); 1590 return 0; 1591 } 1308 1592 1309 avail = ReadBufAvail(); 1310 if ((ateof || setswitchtonext) && avail < count) 1311 count = avail; 1593 if (!WaitForAvail(count)) 1594 { 1595 VERBOSE(VB_FILE, LOC + "!WaitForAvail()"); 1596 rwlock.unlock(); 1597 rwlock.lockForWrite(); 1598 ateof = true; 1599 wanttoread = 0; 1600 stopreads = true; 1601 rwlock.unlock(); 1602 return 0; 1603 } 1312 1604 1313 if (commserror) 1314 return 0; 1605 count = min(ReadBufAvail(), count); 1606 1607 if (count <= 0) 1608 { 1609 // this can happen under a few conditions but the most 1610 // notable is an exit from the read ahead thread. 1611 rwlock.unlock(); 1612 return count; 1315 1613 } 1316 1614 1317 if ((ateof || stopreads) && avail < count) 1318 count = avail; 1615 if (peek) 1616 rbrlock.lockForRead(); 1617 else 1618 rbrlock.lockForWrite(); 1319 1619 1620 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1621 QString("ReadPriv(*, %1, %2) @%3 -- copying data") 1622 .arg(count).arg(peek?"peek":"normal").arg(rbrpos)); 1623 1320 1624 if (rbrpos + count > (int) kBufferSize) 1321 1625 { 1322 1626 int firstsize = kBufferSize - rbrpos; … … 1326 1630 memcpy((char *)buf + firstsize, readAheadBuffer, secondsize); 1327 1631 } 1328 1632 else 1633 { 1329 1634 memcpy(buf, readAheadBuffer + rbrpos, count); 1635 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1636 QString("ReadPriv(*, %1, %2) @%3 -- checksum %4") 1637 .arg(count).arg(peek?"peek":"normal").arg(rbrpos) 1638 .arg(qChecksum(readAheadBuffer+rbrpos,count))); 1639 } 1330 1640 1331 1641 if (!peek) 1332 1642 { 1333 readAheadLock.lock();1334 1643 rbrpos = (rbrpos + count) % kBufferSize; 1335 readAheadLock.unlock();1644 generalWait.wakeAll(); 1336 1645 } 1646 rbrlock.unlock(); 1647 rwlock.unlock(); 1337 1648 1338 if (readone)1339 {1340 Pause();1341 WaitForPause();1342 }1343 1344 1649 return count; 1345 1650 } 1346 1651 … … 1354 1659 */ 1355 1660 int RingBuffer::Read(void *buf, int count) 1356 1661 { 1357 int ret = -1;1358 if ( writemode)1662 int ret = ReadPriv(buf, count, false); 1663 if (ret > 0) 1359 1664 { 1360 VERBOSE(VB_IMPORTANT, LOC_ERR + 1361 "Attempt to read from a write only file"); 1362 return ret; 1363 } 1364 1365 rwlock.lockForRead(); 1366 1367 if (!readaheadrunning) 1368 { 1369 if (remotefile) 1370 { 1371 ret = safe_read(remotefile, buf, count); 1372 readpos += ret; 1373 } 1374 #ifdef USING_FRONTEND 1375 else if (dvdPriv) 1376 { 1377 ret = dvdPriv->safe_read(buf, count); 1378 readpos += ret; 1379 } 1380 else if (bdPriv) 1381 { 1382 ret = bdPriv->safe_read(buf, count); 1383 readpos += ret; 1384 } 1385 #endif // USING_FRONTEND 1386 else 1387 { 1388 ret = safe_read(fd2, buf, count); 1389 readpos += ret; 1390 } 1391 } 1392 else 1393 { 1394 ret = ReadFromBuf(buf, count); 1665 poslock.lockForWrite(); 1395 1666 readpos += ret; 1667 poslock.unlock(); 1396 1668 } 1397 1398 rwlock.unlock();1399 1669 return ret; 1400 1670 } 1401 1671 1402 1672 /** \fn RingBuffer::IsIOBound(void) const 1403 * \brief Returns true if a RingBuffer:: Read(void*,int) is likely to block.1673 * \brief Returns true if a RingBuffer::Write(void*,int) is likely to block. 1404 1674 */ 1405 1675 bool RingBuffer::IsIOBound(void) const 1406 1676 { … … 1429 1699 */ 1430 1700 int RingBuffer::Write(const void *buf, uint count) 1431 1701 { 1432 int ret = -1; 1702 rwlock.lockForRead(); 1703 1433 1704 if (!writemode) 1434 1705 { 1435 1706 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file."); 1436 return ret; 1707 rwlock.unlock(); 1708 return -1; 1437 1709 } 1438 1710 1439 1711 if (!tfw && !remotefile) 1440 return ret; 1712 { 1713 rwlock.unlock(); 1714 return -1; 1715 } 1441 1716 1442 rwlock.lockForRead(); 1443 1717 int ret = -1; 1444 1718 if (tfw) 1445 1719 ret = tfw->Write(buf, count); 1446 1720 else 1447 1721 ret = remotefile->Write(buf, count); 1448 writepos += ret;1449 1722 1723 if (ret > 0) 1724 { 1725 poslock.lockForWrite(); 1726 writepos += ret; 1727 poslock.unlock(); 1728 } 1729 1450 1730 rwlock.unlock(); 1731 1451 1732 return ret; 1452 1733 } 1453 1734 … … 1456 1737 */ 1457 1738 void RingBuffer::Sync(void) 1458 1739 { 1740 rwlock.lockForRead(); 1459 1741 if (tfw) 1460 1742 tfw->Sync(); 1743 rwlock.unlock(); 1461 1744 } 1462 1745 1463 /** \fn RingBuffer::Seek(long long, int) 1464 * \brief Seeks to a particular position in the file. 1746 /** \brief Seeks to a particular position in the file. 1465 1747 */ 1466 long long RingBuffer::Seek(long long pos, int whence )1748 long long RingBuffer::Seek(long long pos, int whence, bool has_lock) 1467 1749 { 1750 VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)") 1751 .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET": 1752 ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END")) 1753 .arg(has_lock?"locked":"unlocked")); 1754 1755 long long ret = -1; 1756 1757 stopreads = true; 1758 1759 // lockForWrite takes priority over lockForRead, so this will 1760 // take priority over the lockForRead in the read ahead thread. 1761 if (!has_lock) 1762 rwlock.lockForWrite(); 1763 1764 stopreads = false; 1765 1468 1766 if (writemode) 1469 return WriterSeek(pos, whence); 1767 { 1768 ret = WriterSeek(pos, whence, true); 1769 if (!has_lock) 1770 rwlock.unlock(); 1771 return ret; 1772 } 1470 1773 1471 wantseek = true; 1472 rwlock.lockForWrite(); 1473 wantseek = false; 1774 poslock.lockForWrite(); 1474 1775 1475 // optimize nop seeks 1476 if ((whence == SEEK_SET && pos == readpos) || 1477 (whence == SEEK_CUR && pos == 0)) 1776 // Optimize no-op seeks 1777 if (readaheadrunning && 1778 ((whence == SEEK_SET && pos == readpos) || 1779 (whence == SEEK_CUR && pos == 0))) 1478 1780 { 1479 rwlock.unlock(); 1480 return readpos; 1781 ret = readpos; 1782 1783 poslock.unlock(); 1784 if (!has_lock) 1785 rwlock.unlock(); 1786 1787 return ret; 1481 1788 } 1482 1789 1483 errno = 0; // clear errno, in case of remotefile error 1790 // only valid for SEEK_SET & SEEK_CUR 1791 long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos; 1484 1792 1485 long long ret = -1; 1793 // Optimize short seeks where the data for 1794 // them is in our ringbuffer already. 1795 if (readaheadrunning && 1796 (SEEK_SET==whence || SEEK_CUR==whence)) 1797 { 1798 rbrlock.lockForWrite(); 1799 rbwlock.lockForRead(); 1800 VERBOSE(VB_FILE, LOC + 1801 QString("Seek(): rbrpos: %1 rbwpos: %2" 1802 "\n\t\t\treadpos: %3 internalreadpos: %4") 1803 .arg(rbrpos).arg(rbwpos) 1804 .arg(readpos).arg(internalreadpos)); 1805 bool used_opt = false; 1806 if ((new_pos < readpos)) 1807 { 1808 int min_safety = max(fill_min, readblocksize); 1809 int free = ((rbwpos >= rbrpos) ? 1810 rbrpos + kBufferSize : rbrpos) - rbwpos; 1811 int internal_backbuf = 1812 (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos; 1813 internal_backbuf = min(internal_backbuf, free - min_safety); 1814 long long sba = readpos - new_pos; 1815 VERBOSE(VB_FILE, LOC + 1816 QString("Seek(): internal_backbuf: %1 sba: %2") 1817 .arg(internal_backbuf).arg(sba)); 1818 if (internal_backbuf >= sba) 1819 { 1820 rbrpos = (rbrpos>=sba) ? rbrpos - sba : 1821 kBufferSize + rbrpos - sba; 1822 used_opt = true; 1823 VERBOSE(VB_FILE, LOC + 1824 QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2" 1825 "\n\t\t\treadpos: %3 internalreadpos: %4") 1826 .arg(rbrpos).arg(rbwpos) 1827 .arg(new_pos).arg(internalreadpos)); 1828 } 1829 } 1830 else if ((new_pos >= readpos) && (new_pos <= internalreadpos)) 1831 { 1832 rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize; 1833 used_opt = true; 1834 VERBOSE(VB_IMPORTANT, LOC + 1835 QString("Seek(): OPT2 rbrpos: %1 sba: %2") 1836 .arg(rbrpos).arg(readpos - new_pos)); 1837 } 1838 rbwlock.unlock(); 1839 rbrlock.unlock(); 1840 1841 if (used_opt) 1842 { 1843 if (ignorereadpos >= 0) 1844 { 1845 // seek should always succeed since we were at this position 1846 if (remotefile) 1847 remotefile->Seek(internalreadpos, SEEK_SET); 1848 else 1849 lseek64(fd2, internalreadpos, SEEK_SET); 1850 ignorereadpos = -1; 1851 } 1852 readpos = new_pos; 1853 poslock.unlock(); 1854 generalWait.wakeAll(); 1855 if (!has_lock) 1856 rwlock.unlock(); 1857 return new_pos; 1858 } 1859 } 1860 1861 // This optimizes the seek end-250000, read, seek 0, read portion 1862 // of the pattern ffmpeg performs at the start of playback to 1863 // determine the pts. 1864 // If the seek is a SEEK_END or is a seek where the position 1865 // changes over 100 MB we check the file size and if the 1866 // destination point is within 300000 bytes of the end of 1867 // the file we enter a special mode where the read ahead 1868 // buffer stops reading data and all reads are made directly 1869 // until another seek is performed. The point of all this is 1870 // to avoid flushing out the buffer that still contains all 1871 // the data the final seek 0, read will need just to read the 1872 // last 250000 bytes. A further optimization would be to buffer 1873 // the 250000 byte read, which is currently performed in 32KB 1874 // blocks (inefficient with RemoteFile). 1875 if ((remotefile || fd2 >= 0) && (ignorereadpos < 0)) 1876 { 1877 long long off_end = 0xDEADBEEF; 1878 if (SEEK_END == whence) 1879 { 1880 off_end = pos; 1881 if (remotefile) 1882 { 1883 new_pos = remotefile->GetFileSize() - off_end; 1884 } 1885 else 1886 { 1887 QFileInfo fi(filename); 1888 new_pos = fi.size() - off_end; 1889 } 1890 } 1891 else if (abs(new_pos-readpos) > 100000000) 1892 { 1893 if (remotefile) 1894 { 1895 off_end = remotefile->GetFileSize() - new_pos; 1896 } 1897 else 1898 { 1899 QFileInfo fi(filename); 1900 off_end = fi.size() - new_pos; 1901 } 1902 } 1903 if (off_end < 300000) 1904 { 1905 VERBOSE(VB_FILE, LOC + 1906 QString("Seek(): offset from end: %1").arg(off_end) + 1907 "\n\t\t\t -- ignoring read ahead thread until next seek."); 1908 1909 ignorereadpos = new_pos; 1910 errno = EINVAL; 1911 int ret; 1912 if (remotefile) 1913 ret = remotefile->Seek(ignorereadpos, SEEK_SET); 1914 else 1915 ret = lseek64(fd2, ignorereadpos, SEEK_SET); 1916 1917 if (ret < 0) 1918 { 1919 ignorereadpos = -1; 1920 QString cmd = QString("Seek(%1, %2)").arg(pos) 1921 .arg((SEEK_SET == whence) ? "SEEK_SET" : 1922 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 1923 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 1924 } 1925 1926 rbwlock.unlock(); 1927 rbrlock.unlock(); 1928 poslock.unlock(); 1929 1930 generalWait.wakeAll(); 1931 1932 if (!has_lock) 1933 rwlock.unlock(); 1934 1935 return ret; 1936 } 1937 } 1938 1939 // Here we perform a normal seek. When successful we 1940 // need to call ResetReadAhead(). A reset means we will 1941 // need to refill the buffer, which takes some time. 1486 1942 if (remotefile) 1943 { 1487 1944 ret = remotefile->Seek(pos, whence, readpos); 1945 if (ret<0) 1946 errno = EINVAL; 1947 } 1488 1948 #ifdef USING_FRONTEND 1949 else if ((dvdPriv || bdPriv) && (SEEK_END == whence)) 1950 { 1951 errno = EINVAL; 1952 ret = -1; 1953 } 1489 1954 else if (dvdPriv) 1490 1955 { 1491 dvdPriv->NormalSeek( pos);1492 ret = pos;1956 dvdPriv->NormalSeek(new_pos); 1957 ret = new_pos; 1493 1958 } 1494 1959 else if (bdPriv) 1495 1960 { 1496 bdPriv->Seek( pos);1497 ret = pos;1961 bdPriv->Seek(new_pos); 1962 ret = new_pos; 1498 1963 } 1499 1964 #endif // USING_FRONTEND 1500 1965 else 1501 1966 { 1502 if ((whence == SEEK_SET) || (whence == SEEK_END)) 1503 #ifdef USING_MINGW 1504 ret = lseek64(fd2, pos, whence); 1505 #else 1506 ret = lseek(fd2, pos, whence); 1507 #endif 1508 else 1509 { 1510 long long realseek = readpos + pos; 1511 #ifdef USING_MINGW 1512 ret = lseek64(fd2, realseek, SEEK_SET); 1513 #else 1514 ret = lseek(fd2, realseek, SEEK_SET); 1515 #endif 1516 } 1967 ret = lseek64(fd2, pos, whence); 1517 1968 } 1518 1969 1519 1970 if (ret >= 0) 1520 1971 { 1521 1972 readpos = ret; 1973 1974 ignorereadpos = -1; 1522 1975 1523 1976 if (readaheadrunning) 1524 1977 ResetReadAhead(readpos); … … 1533 1986 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 1534 1987 } 1535 1988 1536 rwlock.unlock();1989 poslock.unlock(); 1537 1990 1991 generalWait.wakeAll(); 1992 1993 if (!has_lock) 1994 rwlock.unlock(); 1995 1538 1996 return ret; 1539 1997 } 1540 1998 1541 /** \fn RingBuffer::WriterSeek(long long, int) 1542 * \brief Calls ThreadedFileWriter::Seek(long long,int). 1999 /** \brief Calls ThreadedFileWriter::Seek(long long,int). 1543 2000 */ 1544 long long RingBuffer::WriterSeek(long long pos, int whence )2001 long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock) 1545 2002 { 1546 2003 long long ret = -1; 1547 2004 2005 if (!has_lock) 2006 rwlock.lockForRead(); 2007 2008 poslock.lockForWrite(); 2009 1548 2010 if (tfw) 1549 2011 { 1550 2012 ret = tfw->Seek(pos, whence); 1551 2013 writepos = ret; 1552 2014 } 1553 2015 2016 poslock.unlock(); 2017 2018 if (!has_lock) 2019 rwlock.unlock(); 2020 1554 2021 return ret; 1555 2022 } 1556 2023 … … 1560 2027 */ 1561 2028 void RingBuffer::WriterFlush(void) 1562 2029 { 2030 rwlock.lockForRead(); 1563 2031 if (tfw) 1564 2032 { 1565 2033 tfw->Flush(); 1566 2034 tfw->Sync(); 1567 2035 } 2036 rwlock.unlock(); 1568 2037 } 1569 2038 1570 2039 /** \fn RingBuffer::SetWriteBufferSize(int) … … 1572 2041 */ 1573 2042 void RingBuffer::SetWriteBufferSize(int newSize) 1574 2043 { 2044 rwlock.lockForRead(); 1575 2045 if (tfw) 1576 2046 tfw->SetWriteBufferSize(newSize); 2047 rwlock.unlock(); 1577 2048 } 1578 2049 1579 2050 /** \fn RingBuffer::SetWriteBufferMinWriteSize(int) … … 1581 2052 */ 1582 2053 void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize) 1583 2054 { 2055 rwlock.lockForRead(); 1584 2056 if (tfw) 1585 2057 tfw->SetWriteBufferMinWriteSize(newMinSize); 2058 rwlock.unlock(); 1586 2059 } 1587 2060 1588 2061 /** \fn RingBuffer::GetReadPosition(void) const … … 1590 2063 */ 1591 2064 long long RingBuffer::GetReadPosition(void) const 1592 2065 { 2066 rwlock.lockForRead(); 2067 poslock.lockForRead(); 2068 long long ret = readpos; 1593 2069 #ifdef USING_FRONTEND 1594 2070 if (dvdPriv) 1595 ret urndvdPriv->GetReadPosition();2071 ret = dvdPriv->GetReadPosition(); 1596 2072 else if (bdPriv) 1597 ret urnbdPriv->GetReadPosition();2073 ret = bdPriv->GetReadPosition(); 1598 2074 #endif // USING_FRONTEND 1599 1600 return readpos; 2075 poslock.unlock(); 2076 rwlock.unlock(); 2077 return ret; 1601 2078 } 1602 2079 1603 2080 /** \fn RingBuffer::GetWritePosition(void) const … … 1605 2082 */ 1606 2083 long long RingBuffer::GetWritePosition(void) const 1607 2084 { 1608 return writepos; 2085 poslock.lockForRead(); 2086 long long ret = writepos; 2087 poslock.unlock(); 2088 return ret; 1609 2089 } 1610 2090 1611 2091 /** \fn RingBuffer::GetRealFileSize(void) const … … 1614 2094 */ 1615 2095 long long RingBuffer::GetRealFileSize(void) const 1616 2096 { 2097 rwlock.lockForRead(); 2098 long long ret = -1; 1617 2099 if (remotefile) 1618 return remotefile->GetFileSize(); 1619 1620 QFileInfo info(filename); 1621 return info.size(); 2100 ret = remotefile->GetFileSize(); 2101 else 2102 ret = QFileInfo(filename).size(); 2103 rwlock.unlock(); 2104 return ret; 1622 2105 } 1623 2106 1624 2107 /** \fn RingBuffer::LiveMode(void) const … … 1627 2110 */ 1628 2111 bool RingBuffer::LiveMode(void) const 1629 2112 { 1630 return (livetvchain); 2113 rwlock.lockForRead(); 2114 bool ret = (livetvchain); 2115 rwlock.unlock(); 2116 return ret; 1631 2117 } 1632 2118 1633 2119 /** \fn RingBuffer::SetLiveMode(LiveTVChain*) … … 1636 2122 */ 1637 2123 void RingBuffer::SetLiveMode(LiveTVChain *chain) 1638 2124 { 2125 rwlock.lockForWrite(); 1639 2126 livetvchain = chain; 2127 rwlock.unlock(); 1640 2128 } 1641 2129 1642 2130 bool RingBuffer::InDVDMenuOrStillFrame(void) 1643 2131 { 2132 rwlock.lockForRead(); 2133 bool ret = false; 1644 2134 #ifdef USING_FRONTEND 1645 2135 if (dvdPriv) 1646 ret urn(dvdPriv->IsInMenu() || dvdPriv->InStillFrame());2136 ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame()); 1647 2137 #endif // USING_FRONTEND 1648 return false; 2138 rwlock.unlock(); 2139 return ret; 1649 2140 } 1650 2141 1651 2142 /* 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> … … 35 35 void SetWriteBufferMinWriteSize(int newMinSize); 36 36 void UpdateRawBitrate(uint rawbitrate); 37 37 void UpdatePlaySpeed(float playspeed); 38 void SetStreamOnly(bool stream) { streamOnly = stream; } 38 void SetStreamOnly(bool stream) 39 { 40 rwlock.lockForWrite(); 41 streamOnly = stream; 42 rwlock.unlock(); 43 } 39 44 40 45 // Gets 41 46 /// Returns name of file used by this RingBuffer 42 QString GetFilename(void) const { return filename; } 43 QString GetSubtitleFilename(void) const { return subtitlefilename; } 44 /// Returns ReadBufAvail(void) 45 int DataInReadAhead(void) const { return ReadBufAvail(); } 47 QString GetFilename(void) const 48 { 49 rwlock.lockForRead(); 50 QString tmp = filename; tmp.detach(); 51 rwlock.unlock(); 52 return tmp; 53 } 54 QString GetSubtitleFilename(void) const 55 { 56 rwlock.lockForRead(); 57 QString tmp = subtitlefilename; tmp.detach(); 58 rwlock.unlock(); 59 return tmp; 60 } 46 61 /// Returns value of stopreads 47 62 /// \sa StartReads(void), StopReads(void) 48 63 bool GetStopReads(void) const { return stopreads; } 49 /// Returns false iff read-ahead is not 50 /// running and read-ahead is not paused. 51 bool isPaused(void) const 52 { return (!readaheadrunning) ? true : readaheadpaused; } 64 bool isPaused(void) const; 53 65 long long GetReadPosition(void) const; 54 66 long long GetWritePosition(void) const; 55 67 long long GetRealFileSize(void) const; 56 uint GetBitrate(void) const;57 uint GetReadBlockSize(void) const;58 68 bool IsOpen(void) const; 69 bool IsNearEnd(double fps, uint vvf) const; 59 70 60 71 // General Commands 61 void OpenFile(const QString &lfilename, uint retry Count = 12/*4*/);72 void OpenFile(const QString &lfilename, uint retry_ms = 2000); 62 73 int Read(void *buf, int count); 63 74 int Peek(void *buf, int count); // only works with readahead 64 75 … … 67 78 bool resetInternal = false); 68 79 69 80 // Seeks 70 long long Seek(long long pos, int whence );81 long long Seek(long long pos, int whence, bool has_lock = false); 71 82 72 83 // Pause commands 73 84 void Pause(void); … … 83 94 bool LiveMode(void) const; 84 95 void SetLiveMode(LiveTVChain *chain); 85 96 /// Tells RingBuffer whether to igonre the end-of-file 86 void IgnoreLiveEOF(bool ignore) { ignoreliveeof = ignore; } 97 void IgnoreLiveEOF(bool ignore) 98 { 99 rwlock.lockForWrite(); 100 ignoreliveeof = ignore; 101 rwlock.unlock(); 102 } 87 103 88 104 // ThreadedFileWriter proxies 89 105 int Write(const void *buf, uint count); 90 106 bool IsIOBound(void) const; 91 107 void WriterFlush(void); 92 108 void Sync(void); 93 long long WriterSeek(long long pos, int whence );109 long long WriterSeek(long long pos, int whence, bool has_lock = false); 94 110 95 111 // DVDRingBuffer proxies 96 112 /// Returns true if this is a DVD backed RingBuffer. 97 inline bool isDVD(void) const { return dvdPriv; } 98 DVDRingBufferPriv *DVD() { return dvdPriv; } 113 bool isDVD(void) const 114 { 115 rwlock.lockForRead(); 116 bool ret = dvdPriv; 117 rwlock.unlock(); 118 return ret; 119 } 120 /// Illicitly manipulating privates is ill advised! 121 DVDRingBufferPriv *DVD() 122 { 123 return dvdPriv; 124 } 99 125 bool InDVDMenuOrStillFrame(void); 100 126 101 127 // BDRingBuffer proxies … … 109 135 protected: 110 136 void run(void); // QThread 111 137 void CalcReadAheadThresh(void); 138 bool PauseAndWait(void); 112 139 int safe_read_bd(void *data, uint sz); 113 140 int safe_read_dvd(void *data, uint sz); 114 141 int safe_read(int fd, void *data, uint sz); 115 142 int safe_read(RemoteFile *rf, void *data, uint sz); 116 143 117 int ReadFromBuf(void *buf, int count, bool peek = false); 144 int ReadPriv(void *buf, int count, bool peek); 145 int ReadDirect(void *buf, int count, bool peek); 146 bool WaitForReadsAllowed(void); 147 bool WaitForAvail(int count); 118 148 119 149 int ReadBufFree(void) const; 120 150 int ReadBufAvail(void) const; 121 151 122 void StartupReadAheadThread(void);123 152 void ResetReadAhead(long long newinternal); 124 153 void KillReadAheadThread(void); 125 154 126 155 private: 127 // NR == trivial risk, not protected, but only modified in single thread 128 // LR == low risk, not protected, but only modified on Open,Close,ctor,dtor 129 // HR == high risk, likely to cause unexpected behaviour 130 // MR == medium risk, unsafe methods unlikely to be called at wrong moment 156 mutable QReadWriteLock poslock; 157 long long readpos; // protected by poslock 158 long long writepos; // protected by poslock 159 long long internalreadpos; // protected by poslock 160 long long ignorereadpos; // protected by poslock 161 mutable QReadWriteLock rbrlock; 162 int rbrpos; // protected by rbrlock 163 mutable QReadWriteLock rbwlock; 164 int rbwpos; // protected by rbwlock 131 165 132 QString filename; // not protected by a lock LR 133 QString subtitlefilename; // not protected by a lock LR 166 // note should not go under rwlock.. 167 // this is used to break out of read_safe where rwlock is held 168 volatile bool stopreads; 134 169 135 ThreadedFileWriter *tfw; // not protected by a lock LR136 int fd2; // not protected by a lock LR137 138 bool writemode; // not protected by a lock LR139 140 long long readpos; // not protected by a lock HR141 long long writepos; // not protected by a lock HR142 143 bool stopreads; // not protected by a lock HR144 145 170 mutable QReadWriteLock rwlock; 146 171 147 RemoteFile *remotefile; // not protected by a lock LR 172 QString filename; // protected by rwlock 173 QString subtitlefilename; // protected by rwlock 148 174 149 // this lock does not consistently protect anything, 150 // but seems to be intented to protect rbrpos & rbwpos 151 mutable QMutex readAheadLock; 175 ThreadedFileWriter *tfw; // protected by rwlock 176 int fd2; // protected by rwlock 152 177 153 bool startreadahead; // not protected by a lock HR 154 char *readAheadBuffer; // not protected by a lock MR 155 bool readaheadrunning; // not protected by a lock HR 156 bool readaheadpaused; // not protected by a lock HR 157 bool pausereadthread; // not protected by a lock HR 158 int rbrpos; // not protected by a lock HR 159 int rbwpos; // not protected by a lock HR 160 long long internalreadpos; // not protected by a lock HR 161 bool ateof; // not protected by a lock HR 162 bool readsallowed; // not protected by a lock HR 163 volatile bool wantseek; // not protected by a lock HR 164 bool setswitchtonext; // protected by rwlock 165 bool streamOnly; 178 bool writemode; // protected by rwlock 166 179 167 uint rawbitrate; // protected by rwlock 168 float playspeed; // protected by rwlock 169 int fill_threshold;// not protected by a lock HR 170 int fill_min; // protected by rwlock 171 int readblocksize; // protected by rwlock 180 RemoteFile *remotefile; // protected by rwlock 172 181 173 QWaitCondition pauseWait; // not protected by a lock HR 182 bool startreadahead; // protected by rwlock 183 char *readAheadBuffer; // protected by rwlock 184 bool readaheadrunning; // protected by rwlock 185 bool reallyrunning; // protected by rwlock 186 bool request_pause; // protected by rwlock 187 bool paused; // protected by rwlock 188 bool ateof; // protected by rwlock 189 bool readsallowed; // protected by rwlock 190 bool setswitchtonext; // protected by rwlock 191 bool streamOnly; // protected by rwlock 192 bool ignorereadahead; // protected by rwlock 193 uint rawbitrate; // protected by rwlock 194 float playspeed; // protected by rwlock 195 int fill_threshold; // protected by rwlock 196 int fill_min; // protected by rwlock 197 int readblocksize; // protected by rwlock 198 int wanttoread; // protected by rwlock 199 int numfailures; // protected by rwlock (see note 1) 200 bool commserror; // protected by rwlock 174 201 175 int wanttoread; // not protected by a lock HR 176 QWaitCondition availWait; // protected by availWaitMutex 177 QMutex availWaitMutex; 202 DVDRingBufferPriv *dvdPriv; // not protected by rwlock, when DVD() is used 203 BDRingBufferPriv *bdPriv; // protected by rwlock 178 204 179 QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex 180 QMutex readsAllowedWaitMutex; 205 bool oldfile; // protected by rwlock 181 206 182 int numfailures; // not protected by a lock MR 207 LiveTVChain *livetvchain; // protected by rwlock 208 bool ignoreliveeof; // protected by rwlock 183 209 184 bool commserror; // not protected by a lock MR210 long long readAdjust; // protected by rwlock 185 211 186 DVDRingBufferPriv *dvdPriv; // not protected by a lock LR 187 BDRingBufferPriv *bdPriv; // not protected by a lock LR 212 // note 1: numfailures is modified with only a read lock in the 213 // read ahead thread, but this is safe since all other places 214 // that use it are protected by a write lock. But this is a 215 // fragile state of affairs and care must be taken when modifying 216 // code or locking around this variable. 188 217 189 bool oldfile; // not protected by a lock LR190 191 LiveTVChain *livetvchain; // not protected by a lock HR192 bool ignoreliveeof; // not protected by a lock HR193 194 long long readAdjust; // not protected by a lock HR195 196 218 /// Condition to signal that the read ahead thread is running 197 QWaitCondition readAheadRunningCond;//protected by readAheadRunningCondLock 198 QMutex readAheadRunningCondLock; 219 QWaitCondition generalWait; // protected by rwlock 199 220 200 221 public: 201 222 static QMutex subExtLock; … … 208 229 static const uint kReadTestSize; 209 230 }; 210 231 211 #endif 232 #endif // _RINGBUFFER_H_ -
libs/libmythtv/mythplayer.cpp
893 893 894 894 void MythPlayer::OpenDummy(void) 895 895 { 896 VERBOSE(VB_IMPORTANT, LOC + "OpenDummy()"); 897 896 898 isDummy = true; 897 899 898 900 float displayAspect = … … 936 938 SetDecoder(NULL); 937 939 int testreadsize = 2048; 938 940 941 MythTimer bigTimer; bigTimer.start(); 942 int timeout = (retries + 1) * 500; 939 943 while (testreadsize <= kDecoderProbeBufferSize) 940 944 { 941 if (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize) 945 MythTimer peekTimer; peekTimer.start(); 946 while (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize) 942 947 { 943 VERBOSE(VB_IMPORTANT, LOC_ERR + 944 QString("OpenFile(): Error, couldn't read file: %1") 945 .arg(player_ctx->buffer->GetFilename())); 946 return -1; 948 if (peekTimer.elapsed() > 1000 || bigTimer.elapsed() > timeout) 949 { 950 VERBOSE(VB_IMPORTANT, LOC_ERR + 951 QString("OpenFile(): Could not read " 952 "first %1 bytes of '%2'") 953 .arg(testreadsize) 954 .arg(player_ctx->buffer->GetFilename())); 955 return -1; 956 } 957 VERBOSE(VB_IMPORTANT, LOC_WARN + "OpenFile() waiting on data"); 958 usleep(50 * 1000); 947 959 } 948 960 949 961 player_ctx->LockPlayingInfo(__FILE__, __LINE__); … … 960 972 player_ctx->GetSpecialDecode())); 961 973 } 962 974 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 963 if (GetDecoder() )975 if (GetDecoder() || (bigTimer.elapsed() > timeout)) 964 976 break; 965 977 testreadsize <<= 1; 966 978 } … … 2168 2180 return; 2169 2181 } 2170 2182 2171 uint retries = 10; // about 5 seconds of retries 2172 player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL(), retries); 2183 player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL(), 2000 /*ms*/); 2173 2184 2174 2185 if (!player_ctx->buffer->IsOpen()) 2175 2186 { 2176 VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed."); 2187 VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed " + 2188 QString("(card type: %1).") 2189 .arg(player_ctx->tvchain->GetCardType(newid))); 2190 VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString()); 2177 2191 eof = true; 2178 2192 SetErrored(QObject::tr("Error opening switch program buffer")); 2179 2193 delete pginfo; … … 2290 2304 2291 2305 SendMythSystemPlayEvent("PLAY_CHANGED", pginfo); 2292 2306 2293 player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL() );2307 player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL(), 2000 /*ms*/); 2294 2308 if (!player_ctx->buffer->IsOpen()) 2295 2309 { 2296 VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed."); 2310 VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed " + 2311 QString("(card type: %1).") 2312 .arg(player_ctx->tvchain->GetCardType(newid))); 2313 VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString()); 2314 2297 2315 eof = true; 2298 2316 SetErrored(QObject::tr("Error opening jump program file buffer")); 2299 2317 delete pginfo; … … 3190 3208 if (!videoOutput) 3191 3209 return false; 3192 3210 3193 int sz = player_ctx->buffer->DataInReadAhead(); 3194 uint rbs = player_ctx->buffer->GetReadBlockSize(); 3195 uint kbits_per_sec = player_ctx->buffer->GetBitrate(); 3196 uint vvf = videoOutput->ValidVideoFrames(); 3197 double inv_fps = 1.0 / GetDecoder()->GetFPS(); 3198 double bytes_per_frame = kbits_per_sec * (1000.0/8.0) * inv_fps; 3199 double rh_frames = sz / bytes_per_frame; 3200 3201 // WARNING: rh_frames can greatly overestimate or underestimate 3202 // the number of frames available in the read ahead buffer 3203 // when rh_frames is less than the keyframe distance. 3204 3205 bool near_end = ((vvf + rh_frames) < 10.0) || (sz < rbs*1.5); 3206 3207 VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()" 3208 <<" br("<<(kbits_per_sec/8)<<"KB)" 3209 <<" fps("<<((uint)(1.0/inv_fps))<<")" 3210 <<" sz("<<(sz / 1000)<<"KB)" 3211 <<" vfl("<<vvf<<")" 3212 <<" frh("<<((uint)rh_frames)<<")" 3213 <<" ne:"<<near_end); 3214 3215 return near_end; 3211 return player_ctx->buffer->IsNearEnd( 3212 GetDecoder()->GetFPS(), 3213 videoOutput->ValidVideoFrames()); 3216 3214 } 3217 3215 3218 3216 /** \brief Returns true iff near end of recording.