Ticket #8812: 8812-v15.patch
| File 8812-v15.patch, 94.6 KB (added by , 16 years ago) |
|---|
-
libs/libmythtv/mythiowrapper.cpp
256 256 if (!m_filenames.contains(fileID)) 257 257 { 258 258 m_fileWrapperLock.unlock(); 259 return -1;259 return fstat(fileID, buf); 260 260 } 261 261 QString filename = m_filenames[fileID]; 262 262 m_fileWrapperLock.unlock(); -
libs/libmythtv/importrecorder.cpp
104 104 { 105 105 MythCommFlagPlayer *cfp = new MythCommFlagPlayer(); 106 106 RingBuffer *rb = new RingBuffer( 107 ringBuffer->GetFilename(), false, true, 6 );107 ringBuffer->GetFilename(), false, true, 6000); 108 108 109 109 PlayerContext *ctx = new PlayerContext(kImportRecorderInUseID); 110 110 ctx->SetPlayingInfo(curRecording); -
libs/libmythtv/mythplayer.h
4 4 #include <stdint.h> 5 5 6 6 #include <sys/time.h> 7 #include <limits.h> 7 8 8 9 #include <QObject> 9 10 #include <QEvent> … … 36 37 } 37 38 using namespace std; 38 39 40 #ifndef LLONG_MIN 41 #define LLONG_MIN LONG_LONG_MIN 42 #endif 43 39 44 class VideoOutput; 40 45 class RemoteEncoder; 41 46 class MythSqlDatabase; … … 373 378 int64_t ResetAudioTimecodeOffset(void) 374 379 { tc_wrap[TC_AUDIO] = 0LL; return tc_wrap[TC_AUDIO]; } 375 380 int64_t ResyncAudioTimecodeOffset(void) 376 { tc_wrap[TC_AUDIO] = INT64_MIN; return 0L; }381 { tc_wrap[TC_AUDIO] = LLONG_MIN; return 0L; } 377 382 int64_t GetAudioTimecodeOffset(void) const 378 383 { return tc_wrap[TC_AUDIO]; } 379 384 void SaveAudioTimecodeOffset(int64_t v) -
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; 49 const int RingBuffer::kDefaultOpenTimeout = 2000; // ms 48 50 49 51 #define CHUNK 32768 /* readblocksize increments */ 50 52 … … 65 67 66 68 /* 67 69 Locking relations: 68 rwlock->readAheadLock 69 ->readsAllowedWaitMutex->readAheadRunningCondLock 70 ->availWaitMutex 70 rwlock->poslock->rbrlock->rbwlock 71 71 72 72 A child should never lock any of the parents without locking 73 73 the parent lock before the child lock. 74 74 void RingBuffer::Example1() 75 75 { 76 QMutexLocker locker1(&readAheadRunningCondLock);77 QMutexLocker locker2(&readsAllowedWaitMutex); // error!76 poslock.lockForWrite(); 77 rwlock.lockForRead(); // error! 78 78 blah(); // <- does not implicitly aquire any locks 79 rwlock.unlock(); 80 poslock.unlock(); 79 81 } 80 82 void RingBuffer::Example2() 81 83 { 82 QMutexLocker locker1(&readsAllowedWaitMutex);83 QMutexLocker locker2(&readAheadRunningCondLock); // ok!84 rwlock.lockForRead(); 85 rbrlock.lockForWrite(); // ok! 84 86 blah(); // <- does not implicitly aquire any locks 87 rbrlock.unlock(); 88 rwlock.unlock(); 85 89 } 86 90 */ 87 91 … … 96 100 * 97 101 */ 98 102 99 /** \fn RingBuffer::RingBuffer(const QString&, bool, bool, uint) 100 * \brief Creates a RingBuffer instance. 103 /** \brief Creates a RingBuffer instance. 101 104 * 102 105 * You can explicitly disable the readahead thread by setting 103 106 * readahead to false, or by just not calling Start(void). … … 107 110 * \param readahead If false a call to Start(void) will not 108 111 * a pre-buffering thread, otherwise Start(void) 109 112 * will start a pre-buffering thread. 110 * \param read_retries How often to retry reading the file 111 * before giving up. 113 * \param timeout_ms if < 0, then we will not open the file. 114 * Otherwise it's how long to try opening 115 * the file after the first failure in 116 * milliseconds before giving up. 112 117 */ 113 118 RingBuffer::RingBuffer(const QString &lfilename, 114 119 bool write, bool readahead, 115 uint read_retries) 116 : filename(lfilename), subtitlefilename(QString::null), 120 int timeout_ms) 121 : readpos(0), writepos(0), 122 internalreadpos(0), ignorereadpos(-1), 123 rbrpos(0), rbwpos(0), 124 stopreads(false), 125 filename(lfilename), subtitlefilename(QString::null), 117 126 tfw(NULL), fd2(-1), 118 writemode(false), 119 readpos(0), writepos(0), 120 stopreads(false), remotefile(NULL), 127 writemode(false), remotefile(NULL), 121 128 startreadahead(readahead),readAheadBuffer(NULL), 122 readaheadrunning(false), readaheadpaused(false), 123 pausereadthread(false), 124 rbrpos(0), rbwpos(0), 125 internalreadpos(0), ateof(false), 126 readsallowed(false), wantseek(false), setswitchtonext(false), 127 streamOnly(false), 128 rawbitrate(4000), playspeed(1.0f), 129 readaheadrunning(false), reallyrunning(false), 130 request_pause(false), paused(false), 131 ateof(false), readsallowed(false), 132 setswitchtonext(false), streamOnly(false), 133 rawbitrate(8000), playspeed(1.0f), 129 134 fill_threshold(65536), fill_min(-1), 130 135 readblocksize(CHUNK), wanttoread(0), 131 136 numfailures(0), commserror(false), … … 183 188 return; 184 189 } 185 190 186 if ( read_retries != (uint)-1)187 OpenFile(filename, read_retries);191 if (timeout_ms >= 0) 192 OpenFile(filename, timeout_ms); 188 193 } 189 194 190 195 /** \fn check_permissions(const QString&) … … 263 268 return QString::null; 264 269 } 265 270 266 /** \fn RingBuffer::OpenFile(const QString&, uint) 267 * \brief Opens a file for reading. 271 /** \brief Opens a file for reading. 268 272 * 269 273 * \param lfilename Name of file to read 270 * \param retryCount How often to retry reading the file before giving up 274 * \param retry_ms How many ms to retry reading the file 275 * after the first try before giving up. 271 276 */ 272 void RingBuffer::OpenFile(const QString &lfilename, uint retry Count)277 void RingBuffer::OpenFile(const QString &lfilename, uint retry_ms) 273 278 { 274 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 )")275 .arg(lfilename).arg(retry Count));279 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 ms)") 280 .arg(lfilename).arg(retry_ms)); 276 281 277 uint openAttempts = retryCount + 1;282 rwlock.lockForWrite(); 278 283 279 284 filename = lfilename; 280 285 … … 365 370 if (is_local) 366 371 { 367 372 char buf[kReadTestSize]; 368 int timetowait = 500 * openAttempts;369 373 int lasterror = 0; 370 374 371 375 MythTimer openTimer; 372 376 openTimer.start(); 373 377 374 while (openTimer.elapsed() < timetowait) 378 uint openAttempts = 0; 379 do 375 380 { 381 openAttempts++; 376 382 lasterror = 0; 377 383 QByteArray fname = filename.toLocal8Bit(); 378 384 fd2 = open(fname.constData(), … … 381 387 if (fd2 < 0) 382 388 { 383 389 if (!check_permissions(filename)) 390 { 391 lasterror = 3; 384 392 break; 393 } 385 394 386 395 lasterror = 1; 387 usleep(10 00);396 usleep(10 * 1000); 388 397 } 389 398 else 390 399 { … … 394 403 lasterror = 2; 395 404 close(fd2); 396 405 fd2 = -1; 397 usleep(1000); 406 if (oldfile) 407 break; // if it's an old file it won't grow.. 408 usleep(10 * 1000); 398 409 } 399 410 else 400 411 { 401 lseek(fd2, 0, SEEK_SET); 412 if (0 == lseek(fd2, 0, SEEK_SET)) 413 { 402 414 #if HAVE_POSIX_FADVISE 403 posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL);415 posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL); 404 416 #endif 405 openAttempts = 0; 406 break; 417 lasterror = 0; 418 break; 419 } 420 lasterror = 4; 421 close(fd2); 422 fd2 = -1; 407 423 } 408 424 } 409 425 } 426 while ((uint)openTimer.elapsed() < retry_ms); 410 427 411 428 switch (lasterror) 412 429 { 430 case 0: 431 { 432 QFileInfo fi(filename); 433 oldfile = fi.lastModified() 434 .secsTo(QDateTime::currentDateTime()) > 60; 435 QString extension = fi.completeSuffix().toLower(); 436 if (is_subtitle_possible(extension)) 437 subtitlefilename = local_sub_filename(fi); 438 break; 439 } 413 440 case 1: 414 VERBOSE(VB_IMPORTANT, LOC +415 QString(" Could not open %1.").arg(filename));441 VERBOSE(VB_IMPORTANT, LOC_ERR + 442 QString("OpenFile(): Could not open.")); 416 443 break; 417 444 case 2: 418 VERBOSE(VB_IMPORTANT, LOC +419 QString(" Invalid file (fd %1) when opening '%2'.")420 .arg( fd2).arg(filename));445 VERBOSE(VB_IMPORTANT, LOC_ERR + 446 QString("OpenFile(): File too small (%1B).") 447 .arg(QFileInfo(filename).size())); 421 448 break; 449 case 3: 450 VERBOSE(VB_IMPORTANT, LOC_ERR + 451 "OpenFile(): Improper permissions."); 452 break; 453 case 4: 454 VERBOSE(VB_IMPORTANT, LOC_ERR + 455 "OpenFile(): Can not seek in file."); 456 break; 422 457 default: 423 458 break; 424 459 } 460 VERBOSE(VB_FILE, LOC + QString("OpenFile() made %1 attempts in %2 ms") 461 .arg(openAttempts).arg(openTimer.elapsed())); 425 462 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 463 } 438 464 #ifdef USING_FRONTEND 439 465 else if (is_dvd) 440 466 { 441 467 dvdPriv->OpenFile(filename); 442 rwlock.lockForWrite();443 468 readblocksize = DVD_BLOCK_SIZE * 62; 444 rwlock.unlock();445 469 } 446 470 else if (is_bd) 447 471 { 448 472 bdPriv->OpenFile(filename); 449 rwlock.lockForWrite();450 473 readblocksize = BD_BLOCK_SIZE * 62; 451 rwlock.unlock();452 474 } 453 475 #endif // USING_FRONTEND 454 476 else … … 481 503 } 482 504 } 483 505 484 remotefile = new RemoteFile(filename, false, true, -1, &auxFiles); 506 remotefile = new RemoteFile(filename, false, true, 507 retry_ms, &auxFiles); 485 508 if (!remotefile->isOpen()) 486 509 { 487 VERBOSE(VB_IMPORTANT, 510 VERBOSE(VB_IMPORTANT, LOC_ERR + 488 511 QString("RingBuffer::RingBuffer(): Failed to open remote " 489 512 "file (%1)").arg(filename)); 490 513 delete remotefile; … … 503 526 commserror = false; 504 527 numfailures = 0; 505 528 506 UpdateRawBitrate(4000); 529 rawbitrate = 8000; 530 CalcReadAheadThresh(); 531 532 rwlock.unlock(); 507 533 } 508 534 509 535 /** \fn RingBuffer::IsOpen(void) const … … 511 537 */ 512 538 bool RingBuffer::IsOpen(void) const 513 539 { 540 rwlock.lockForRead(); 541 bool ret; 514 542 #ifdef USING_FRONTEND 515 ret urntfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||543 ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) || 516 544 (bdPriv && bdPriv->IsOpen()); 517 545 #else // if !USING_FRONTEND 518 ret urntfw || (fd2 > -1) || remotefile;546 ret = tfw || (fd2 > -1) || remotefile; 519 547 #endif // !USING_FRONTEND 548 rwlock.unlock(); 549 return ret; 520 550 } 521 551 522 552 /** \fn RingBuffer::~RingBuffer(void) … … 557 587 } 558 588 #endif // USING_FRONTEND 559 589 590 if (readAheadBuffer) // this only runs if thread is terminated 591 { 592 delete [] readAheadBuffer; 593 readAheadBuffer = NULL; 594 } 595 560 596 rwlock.unlock(); 561 597 } 562 598 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 599 /** \fn RingBuffer::Reset(bool, bool, bool) 577 600 * \brief Resets the read-ahead thread and our position in the file 578 601 */ 579 602 void RingBuffer::Reset(bool full, bool toAdjust, bool resetInternal) 580 603 { 581 wantseek = true; 604 VERBOSE(VB_FILE, LOC + QString("Reset(%1,%2,%3)") 605 .arg(full).arg(toAdjust).arg(resetInternal)); 606 582 607 rwlock.lockForWrite(); 583 wantseek = false; 608 poslock.lockForWrite(); 609 584 610 numfailures = 0; 585 611 commserror = false; 586 612 setswitchtonext = false; … … 590 616 591 617 if (readpos != 0) 592 618 { 593 VERBOSE(VB_IMPORTANT, QString(619 VERBOSE(VB_IMPORTANT, LOC + QString( 594 620 "RingBuffer::Reset() nonzero readpos. toAdjust: %1 readpos: %2" 595 621 " readAdjust: %3").arg(toAdjust).arg(readpos).arg(readAdjust)); 596 622 } … … 604 630 if (resetInternal) 605 631 internalreadpos = readpos; 606 632 633 generalWait.wakeAll(); 634 poslock.unlock(); 607 635 rwlock.unlock(); 608 636 } 609 637 … … 625 653 unsigned errcnt = 0; 626 654 unsigned zerocnt = 0; 627 655 628 if (fd < 0)656 if (fd2 < 0) 629 657 { 630 658 VERBOSE(VB_IMPORTANT, LOC_ERR + 631 659 "Invalid file descriptor in 'safe_read()'"); … … 637 665 638 666 while (tot < sz) 639 667 { 640 ret = read(fd , (char *)data + tot, sz - tot);668 ret = read(fd2, (char *)data + tot, sz - tot); 641 669 if (ret < 0) 642 670 { 643 671 if (errno == EAGAIN) … … 691 719 */ 692 720 int RingBuffer::safe_read(RemoteFile *rf, void *data, uint sz) 693 721 { 694 int ret = 0; 695 696 ret = rf->Read(data, sz); 722 int ret = rf->Read(data, sz); 697 723 if (ret < 0) 698 724 { 699 725 VERBOSE(VB_IMPORTANT, LOC_ERR + 700 726 "RingBuffer::safe_read(RemoteFile* ...): read failed"); 701 727 728 poslock.lockForRead(); 702 729 rf->Seek(internalreadpos - readAdjust, SEEK_SET); 703 ret = 0;730 poslock.unlock(); 704 731 numfailures++; 705 } 732 } 733 else if (ret == 0) 734 { 735 VERBOSE(VB_FILE, LOC + 736 "RingBuffer::safe_read(RemoteFile* ...): at EOF"); 737 } 706 738 707 739 return ret; 708 740 } … … 714 746 */ 715 747 void RingBuffer::UpdateRawBitrate(uint raw_bitrate) 716 748 { 749 VERBOSE(VB_FILE, LOC + QString("UpdateRawBitrate(%1Kb)").arg(raw_bitrate)); 750 if (raw_bitrate < 2500) 751 { 752 VERBOSE(VB_FILE, LOC + 753 QString("UpdateRawBitrate(%1Kb) - ignoring bitrate,") 754 .arg(raw_bitrate) + 755 "\n\t\t\tappears to be abnormally low."); 756 return; 757 } 758 717 759 rwlock.lockForWrite(); 718 760 rawbitrate = raw_bitrate; 719 761 CalcReadAheadThresh(); 720 762 rwlock.unlock(); 721 763 } 722 764 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 765 /** \fn RingBuffer::UpdatePlaySpeed(float) 749 766 * \brief Set the play speed, to allow RingBuffer adjust effective bitrate. 750 767 * \param play_speed Speed to set. (1.0 for normal speed) … … 768 785 { 769 786 uint estbitrate = 0; 770 787 771 wantseek = false;772 788 readsallowed = false; 773 readblocksize = CHUNK;789 readblocksize = max(readblocksize, CHUNK); 774 790 775 791 // loop without sleeping if the buffered data is less than this 776 fill_threshold = CHUNK * 2; 777 fill_min = 1; 792 fill_threshold = kBufferSize / 8; 778 793 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; 794 const uint KB32 = 32*1024; 795 const uint KB64 = 64*1024; 796 const uint KB128 = 128*1024; 797 const uint KB256 = 256*1024; 798 const uint KB512 = 512*1024; 787 799 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; 800 estbitrate = (uint) max(abs(rawbitrate * playspeed), 801 0.5f * rawbitrate); 802 estbitrate = min(rawbitrate * 3, estbitrate); 803 int rbs = (estbitrate > 2500) ? KB64 : KB32; 804 rbs = (estbitrate > 5000) ? KB128 : rbs; 805 rbs = (estbitrate > 9000) ? KB256 : rbs; 806 rbs = (estbitrate > 18000) ? KB512 : rbs; 807 readblocksize = max(rbs,readblocksize); 795 808 796 // minumum seconds of buffering before allowing read 797 float secs_min = 0.1; 809 // minumum seconds of buffering before allowing read 810 float secs_min = 0.25; 811 // set the minimum buffering before allowing ffmpeg read 812 fill_min = (uint) ((estbitrate * secs_min) * 0.125f); 813 // make this a multiple of ffmpeg block size.. 814 fill_min = ((fill_min / KB32) + 1) * KB32; 798 815 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 -> " 816 VERBOSE(VB_FILE, LOC + 817 QString("CalcReadAheadThresh(%1 Kb)\n\t\t\t -> " 808 818 "threshhold(%2 KB) min read(%3 KB) blk size(%4 KB)") 809 819 .arg(estbitrate).arg(fill_threshold/1024) 810 820 .arg(fill_min/1024).arg(readblocksize/1024)); 811 821 } 812 822 813 /** \fn RingBuffer::ReadBufFree(void) const 814 * \brief Returns number of bytes available for reading into buffer. 815 */ 823 bool RingBuffer::IsNearEnd(double fps, uint vvf) const 824 { 825 rwlock.lockForRead(); 826 int sz = ReadBufAvail(); 827 uint rbs = readblocksize; 828 // telecom kilobytes (i.e. 1000 per k not 1024) 829 uint tmp = (uint) max(abs(rawbitrate * playspeed), 0.5f * rawbitrate); 830 uint kbits_per_sec = min(rawbitrate * 3, tmp); 831 rwlock.unlock(); 832 833 // WARNING: readahead_frames can greatly overestimate or underestimate 834 // the number of frames available in the read ahead buffer 835 // when rh_frames is less than the keyframe distance. 836 double bytes_per_frame = kbits_per_sec * (1000.0/8.0) / fps; 837 double readahead_frames = sz / bytes_per_frame; 838 839 bool near_end = ((vvf + readahead_frames) < 10.0) || (sz < rbs*1.5); 840 841 VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()" 842 <<" br("<<(kbits_per_sec/8)<<"KB)" 843 <<" sz("<<(sz / 1000)<<"KB)" 844 <<" vfl("<<vvf<<")" 845 <<" frh("<<((uint)readahead_frames)<<")" 846 <<" ne:"<<near_end); 847 848 return near_end; 849 } 850 851 /// \brief Returns number of bytes available for reading into buffer. 852 /// WARNING: Must be called with rwlock in locked state. 816 853 int RingBuffer::ReadBufFree(void) const 817 854 { 818 QMutexLocker locker(&readAheadLock); 819 return ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1; 855 rbrlock.lockForRead(); 856 rbwlock.lockForRead(); 857 int ret = ((rbwpos >= rbrpos) ? rbrpos + kBufferSize : rbrpos) - rbwpos - 1; 858 rbwlock.unlock(); 859 rbrlock.unlock(); 860 return ret; 820 861 } 821 862 822 /** \fn RingBuffer::ReadBufAvail(void) const 823 * \brief Returns number of bytes available for reading from buffer. 824 */ 863 /// \brief Returns number of bytes available for reading from buffer. 864 /// WARNING: Must be called with rwlock in locked state. 825 865 int RingBuffer::ReadBufAvail(void) const 826 866 { 827 QMutexLocker locker(&readAheadLock); 828 return (rbwpos >= rbrpos) ? 829 rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos; 867 rbrlock.lockForRead(); 868 rbwlock.lockForRead(); 869 int ret = (rbwpos >= rbrpos) ? rbwpos - rbrpos : kBufferSize - rbrpos + rbwpos; 870 rbwlock.unlock(); 871 rbrlock.unlock(); 872 return ret; 830 873 } 831 874 832 875 /** \fn RingBuffer::ResetReadAhead(long long) … … 836 879 * buffer doesn't contain any stale data, and so that it will read 837 880 * any new data from the new position in the file. 838 881 * 839 * WARNING: Must be called with rwlock in write lock state.882 * WARNING: Must be called with rwlock and poslock in write lock state. 840 883 * 841 884 * \param newinternal Position in file to start reading data from 842 885 */ 843 886 void RingBuffer::ResetReadAhead(long long newinternal) 844 887 { 845 readAheadLock.lock(); 846 readblocksize = CHUNK; 888 VERBOSE(VB_FILE, LOC + QString("ResetReadAhead(internalreadpos = %1->%2)") 889 .arg(internalreadpos).arg(newinternal)); 890 891 rbrlock.lockForWrite(); 892 rbwlock.lockForWrite(); 893 894 CalcReadAheadThresh(); 847 895 rbrpos = 0; 848 896 rbwpos = 0; 849 897 internalreadpos = newinternal; 850 898 ateof = false; 851 899 readsallowed = false; 852 900 setswitchtonext = false; 853 readAheadLock.unlock(); 901 generalWait.wakeAll(); 902 903 rbwlock.unlock(); 904 rbrlock.unlock(); 854 905 } 855 906 856 /** \fn RingBuffer::StartupReadAheadThread(void)857 * \brief Creates the read-ahead thread, and waits for it to start.907 /** 908 * \brief Starts the read-ahead thread. 858 909 * 859 * \sa Start(void). 910 * If the RingBuffer constructor was not called with a usereadahead 911 * of true of if this was reset to false because we're dealing with 912 * a DVD the read ahead thread will not be started. 913 * 914 * If this RingBuffer is in write-mode a warning will be printed and 915 * the read ahead thread will not be started. 916 * 917 * If the read ahead thread is already running a warning will be printed 918 * and the read ahead thread will not be started. 919 * 860 920 */ 861 void RingBuffer::Start upReadAheadThread(void)921 void RingBuffer::Start(void) 862 922 { 863 readaheadrunning = false;923 bool do_start = true; 864 924 865 readAheadRunningCondLock.lock(); 925 rwlock.lockForWrite(); 926 if (!startreadahead) 927 { 928 do_start = false; 929 } 930 else if (writemode) 931 { 932 VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, " 933 "this is a write only RingBuffer"); 934 do_start = false; 935 } 936 else if (readaheadrunning) 937 { 938 VERBOSE(VB_IMPORTANT, LOC_WARN + "Not starting read ahead thread, " 939 "already running"); 940 do_start = false; 941 } 942 943 if (!do_start) 944 { 945 rwlock.unlock(); 946 return; 947 } 948 949 StartReads(); 950 866 951 QThread::start(); 867 readAheadRunningCond.wait(&readAheadRunningCondLock); 868 readAheadRunningCondLock.unlock(); 952 953 while (readaheadrunning && !reallyrunning) 954 generalWait.wait(&rwlock); 955 956 rwlock.unlock(); 869 957 } 870 958 871 959 /** \fn RingBuffer::KillReadAheadThread(void) … … 873 961 */ 874 962 void RingBuffer::KillReadAheadThread(void) 875 963 { 876 if (!readaheadrunning) 877 return; 878 879 readaheadrunning = false; 880 QThread::wait(); 964 while (isRunning()) 965 { 966 rwlock.lockForWrite(); 967 bool do_wait = readaheadrunning; 968 readaheadrunning = false; 969 StopReads(); 970 generalWait.wakeAll(); 971 rwlock.unlock(); 972 QThread::wait(5000); 973 } 881 974 } 882 975 883 976 /** \fn RingBuffer::StopReads(void) … … 887 980 void RingBuffer::StopReads(void) 888 981 { 889 982 stopreads = true; 890 availWait.wakeAll();983 generalWait.wakeAll(); 891 984 } 892 985 893 986 /** \fn RingBuffer::StartReads(void) … … 897 990 void RingBuffer::StartReads(void) 898 991 { 899 992 stopreads = false; 993 generalWait.wakeAll(); 900 994 } 901 995 902 996 /** \fn RingBuffer::Pause(void) … … 905 999 */ 906 1000 void RingBuffer::Pause(void) 907 1001 { 908 pausereadthread = true;909 1002 StopReads(); 1003 1004 rwlock.lockForWrite(); 1005 request_pause = true; 1006 rwlock.unlock(); 910 1007 } 911 1008 912 1009 /** \fn RingBuffer::Unpause(void) … … 916 1013 void RingBuffer::Unpause(void) 917 1014 { 918 1015 StartReads(); 919 pausereadthread = false; 1016 1017 rwlock.lockForWrite(); 1018 request_pause = false; 1019 generalWait.wakeAll(); 1020 rwlock.unlock(); 920 1021 } 921 1022 1023 /// Returns false iff read-ahead is not running and read-ahead is not paused. 1024 bool RingBuffer::isPaused(void) const 1025 { 1026 rwlock.lockForRead(); 1027 bool ret = !readaheadrunning || paused; 1028 rwlock.unlock(); 1029 return ret; 1030 } 1031 922 1032 /** \fn RingBuffer::WaitForPause(void) 923 1033 * \brief Waits for Pause(void) to take effect. 924 1034 */ 925 1035 void RingBuffer::WaitForPause(void) 926 1036 { 927 if (!readaheadrunning)928 return;1037 MythTimer t; 1038 t.start(); 929 1039 930 if (!readaheadpaused) 1040 rwlock.lockForRead(); 1041 while (readaheadrunning && !paused && request_pause) 931 1042 { 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(); 1043 generalWait.wait(&rwlock, 1000); 1044 if (readaheadrunning && !paused && request_pause && t.elapsed() > 1000) 1045 { 1046 VERBOSE(VB_IMPORTANT, LOC_WARN + 1047 QString("Waited %1 ms for ringbuffer pause..") 1048 .arg(t.elapsed())); 1049 } 1050 } 1051 rwlock.unlock(); 1052 } 936 1053 937 while (!pauseWait.wait(&mutex, 1000)) 938 VERBOSE(VB_IMPORTANT, 939 LOC + "Waited too long for ringbuffer pause.."); 1054 bool RingBuffer::PauseAndWait(void) 1055 { 1056 const uint timeout = 500; // ms 1057 1058 if (request_pause) 1059 { 1060 if (!paused) 1061 { 1062 rwlock.unlock(); 1063 rwlock.lockForWrite(); 1064 1065 if (request_pause) 1066 { 1067 paused = true; 1068 generalWait.wakeAll(); 1069 } 1070 1071 rwlock.unlock(); 1072 rwlock.lockForRead(); 1073 } 1074 1075 if (request_pause && paused && readaheadrunning) 1076 generalWait.wait(&rwlock, timeout); 940 1077 } 1078 1079 if (!request_pause && paused) 1080 { 1081 rwlock.unlock(); 1082 rwlock.lockForWrite(); 1083 1084 if (!request_pause) 1085 { 1086 paused = false; 1087 generalWait.wakeAll(); 1088 } 1089 1090 rwlock.unlock(); 1091 rwlock.lockForRead(); 1092 } 1093 1094 return request_pause || paused; 941 1095 } 942 1096 943 1097 void RingBuffer::run(void) 944 1098 { 945 long long totfree = 0; 946 int ret = -1; 947 int used = 0; 948 int loops = 0; 949 1099 // These variables are used to adjust the read block size 950 1100 struct timeval lastread, now; 951 gettimeofday(&lastread, NULL);952 const int KB640 = 640*1024;953 1101 int readtimeavg = 300; 954 int readinterval;1102 bool ignore_for_read_timing = true; 955 1103 956 pausereadthread = false;1104 gettimeofday(&lastread, NULL); // this is just to keep gcc happy 957 1105 958 readAheadBuffer = new char[kBufferSize + KB640];959 960 1106 rwlock.lockForWrite(); 1107 poslock.lockForWrite(); 1108 request_pause = false; 1109 readAheadBuffer = new char[kBufferSize + 1024]; 961 1110 ResetReadAhead(0); 1111 readaheadrunning = true; 1112 reallyrunning = true; 1113 generalWait.wakeAll(); 1114 poslock.unlock(); 962 1115 rwlock.unlock(); 963 1116 964 totfree = ReadBufFree(); 1117 // NOTE: this must loop at some point hold only 1118 // a read lock on rwlock, so that other functions 1119 // such as reset and seek can take priority. 965 1120 966 readaheadrunning = true; 967 readAheadRunningCondLock.lock(); 968 readAheadRunningCond.wakeAll(); 969 readAheadRunningCondLock.unlock(); 1121 rwlock.lockForRead(); 1122 1123 VERBOSE(VB_FILE, LOC + QString("Initial readblocksize %1K & fill_min %2K") 1124 .arg(readblocksize/1024).arg(fill_min/1024)); 1125 970 1126 while (readaheadrunning) 971 1127 { 972 if ( pausereadthread || writemode)1128 if (PauseAndWait()) 973 1129 { 974 readaheadpaused = true; 975 pauseWait.wakeAll(); 976 usleep(5000); 977 totfree = ReadBufFree(); 1130 ignore_for_read_timing = true; 978 1131 continue; 979 1132 } 980 1133 981 if (readaheadpaused) 1134 long long totfree = ReadBufFree(); 1135 1136 // These are conditions where we don't want to go through 1137 // the loop if they are true. 1138 if (((totfree < readblocksize) && readsallowed) || 1139 (ignorereadpos >= 0) || commserror || stopreads) 982 1140 { 983 totfree = ReadBufFree(); 984 readaheadpaused = false; 1141 ignore_for_read_timing |= 1142 (ignorereadpos >= 0) || commserror || stopreads; 1143 generalWait.wait(&rwlock, (stopreads) ? 50 : 1000); 1144 continue; 985 1145 } 986 1146 987 totfree = ReadBufFree(); 988 if (totfree < GetReadBlockSize()) 1147 // These are conditions where we want to sleep to allow 1148 // other threads to do stuff. 1149 if (setswitchtonext || (ateof && readsallowed)) 989 1150 { 990 usleep(50000); 1151 ignore_for_read_timing = true; 1152 generalWait.wait(&rwlock, 1000); 991 1153 totfree = ReadBufFree(); 992 ++loops;993 // break out if we've spent lots of time here, just in case things994 // are waiting on a wait condition that never got triggered.995 if (readsallowed && loops < 10)996 continue;997 1154 } 998 loops = 0;999 1155 1000 rwlock.lockForRead(); 1001 if (totfree > readblocksize && !commserror && !ateof && !setswitchtonext) 1156 int read_return = -1; 1157 if (totfree >= readblocksize && !commserror && 1158 !ateof && !setswitchtonext) 1002 1159 { 1003 1160 // limit the read size 1004 1161 totfree = readblocksize; 1005 1162 1006 1163 // adapt blocksize 1007 1164 gettimeofday(&now, NULL); 1008 readinterval = (now.tv_sec - lastread.tv_sec ) * 1000 + 1009 (now.tv_usec - lastread.tv_usec) / 1000; 1165 if (!ignore_for_read_timing) 1166 { 1167 int readinterval = (now.tv_sec - lastread.tv_sec ) * 1000 + 1168 (now.tv_usec - lastread.tv_usec) / 1000; 1169 readtimeavg = (readtimeavg * 9 + readinterval) / 10; 1010 1170 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; 1171 if (readtimeavg < 150 && (uint)readblocksize < (kBufferSize>>2)) 1172 { 1173 int old_block_size = readblocksize; 1174 readblocksize = 3 * readblocksize / 2; 1175 readblocksize = ((readblocksize+CHUNK-1) / CHUNK) * CHUNK; 1176 VERBOSE(VB_FILE, LOC + 1177 QString("Avg read interval was %1 msec. " 1178 "%2K -> %3K block size") 1179 .arg(readtimeavg) 1180 .arg(old_block_size/1024) 1181 .arg(readblocksize/1024)); 1182 readtimeavg = 225; 1183 } 1184 else if (readtimeavg > 300 && readblocksize > CHUNK) 1185 { 1186 readblocksize -= CHUNK; 1187 VERBOSE(VB_FILE, LOC + 1188 QString("Avg read interval was %1 msec. " 1189 "%2K -> %3K block size") 1190 .arg(readtimeavg) 1191 .arg((readblocksize+CHUNK)/1024) 1192 .arg(readblocksize/1024)); 1193 readtimeavg = 225; 1194 } 1020 1195 } 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 } 1196 ignore_for_read_timing = false; 1029 1197 lastread = now; 1030 1198 1199 rbwlock.lockForRead(); 1031 1200 if (rbwpos + totfree > kBufferSize) 1201 { 1032 1202 totfree = kBufferSize - rbwpos; 1203 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1204 "Shrinking read, near end of buffer"); 1205 } 1033 1206 1034 1207 if (internalreadpos == 0) 1035 totfree = fill_min; 1208 { 1209 totfree = max(fill_min, readblocksize); 1210 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1211 "Reading enough data to start playback"); 1212 } 1036 1213 1214 VERBOSE(VB_FILE|VB_EXTRA, 1215 LOC + QString("safe_read(...@%1, %2) -- begin") 1216 .arg(rbwpos).arg(totfree)); 1037 1217 if (remotefile) 1038 1218 { 1039 1219 if (livetvchain && livetvchain->HasNext()) 1040 1220 remotefile->SetTimeout(true); 1041 1042 ret = safe_read(remotefile, readAheadBuffer + rbwpos, 1043 totfree); 1044 internalreadpos += ret; 1221 read_return = safe_read( 1222 remotefile, readAheadBuffer + rbwpos, totfree); 1045 1223 } 1046 1224 #ifdef USING_FRONTEND 1047 1225 else if (dvdPriv) 1048 1226 { 1049 re t = dvdPriv->safe_read(readAheadBuffer + rbwpos, totfree);1050 internalreadpos += ret;1227 read_return = dvdPriv->safe_read( 1228 readAheadBuffer + rbwpos, totfree); 1051 1229 } 1052 1230 else if (bdPriv) 1053 1231 { 1054 re t = bdPriv->safe_read(readAheadBuffer + rbwpos, totfree);1055 internalreadpos += ret;1232 read_return = bdPriv->safe_read( 1233 readAheadBuffer + rbwpos, totfree); 1056 1234 } 1057 1235 #endif // USING_FRONTEND 1058 1236 else 1059 1237 { 1060 ret = safe_read(fd2, readAheadBuffer + rbwpos, totfree); 1061 internalreadpos += ret; 1238 read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree); 1062 1239 } 1240 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1241 QString("safe_read(...@%1, %2) -> %3") 1242 .arg(rbwpos).arg(totfree).arg(read_return)); 1243 rbwlock.unlock(); 1244 } 1063 1245 1064 readAheadLock.lock(); 1065 if (ret > 0 ) 1066 rbwpos = (rbwpos + ret) % kBufferSize; 1067 readAheadLock.unlock(); 1246 if (read_return >= 0) 1247 { 1248 poslock.lockForWrite(); 1249 rbwlock.lockForWrite(); 1250 internalreadpos += read_return; 1251 rbwpos = (rbwpos + read_return) % kBufferSize; 1252 VERBOSE(VB_FILE|VB_EXTRA, 1253 LOC + QString("rbwpos += %1K requested %2K in read") 1254 .arg(read_return/1024,3).arg(totfree/1024,3)); 1255 rbwlock.unlock(); 1256 poslock.unlock(); 1257 } 1068 1258 1069 if (ret == 0 && !stopreads) 1259 int used = kBufferSize - ReadBufFree(); 1260 1261 if ((0 == read_return) || (numfailures > 5) || 1262 (readsallowed != (used >= fill_min || ateof || 1263 setswitchtonext || commserror))) 1264 { 1265 // If readpos changes while the lock is released 1266 // we should not handle the 0 read_return now. 1267 long long old_readpos = readpos; 1268 1269 rwlock.unlock(); 1270 rwlock.lockForWrite(); 1271 1272 commserror |= (numfailures > 5); 1273 1274 readsallowed = used >= fill_min || ateof || 1275 setswitchtonext || commserror; 1276 1277 if (0 == read_return && old_readpos == readpos) 1070 1278 { 1071 1279 if (livetvchain) 1072 1280 { … … 1078 1286 } 1079 1287 } 1080 1288 else 1289 { 1290 VERBOSE(VB_FILE|VB_EXTRA, 1291 LOC + "setting ateof (read_return == 0)"); 1081 1292 ateof = true; 1293 } 1082 1294 } 1083 }1084 1295 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; 1296 rwlock.unlock(); 1297 rwlock.lockForRead(); 1298 used = kBufferSize - ReadBufFree(); 1095 1299 } 1096 1300 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)); 1301 VERBOSE(VB_FILE|VB_EXTRA, LOC + "@ end of read ahead loop"); 1107 1302 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 || 1303 if (readsallowed || commserror || ateof || setswitchtonext || 1122 1304 (wanttoread <= used && wanttoread > 0)) 1123 1305 { 1124 availWait.wakeAll(); 1306 // To give other threads a good chance to handle these 1307 // conditions, even if they are only requesting a read lock 1308 // like us, yield (currently implemented with short usleep). 1309 generalWait.wakeAll(); 1310 rwlock.unlock(); 1311 usleep(5 * 1000); 1312 rwlock.lockForRead(); 1125 1313 } 1126 availWaitMutex.unlock(); 1127 1128 rwlock.unlock(); 1129 1130 if ((used >= fill_threshold || wantseek || ateof || setswitchtonext) && 1131 !pausereadthread) 1314 else 1132 1315 { 1133 usleep(500); 1316 // yield if we have nothing to do... 1317 if (!request_pause && 1318 (used >= fill_threshold || ateof || setswitchtonext)) 1319 { 1320 generalWait.wait(&rwlock, 1000); 1321 } 1134 1322 } 1135 1323 } 1136 1324 1325 rwlock.unlock(); 1326 1327 rwlock.lockForWrite(); 1328 rbrlock.lockForWrite(); 1329 rbwlock.lockForWrite(); 1330 1331 rbrpos = 0; 1332 rbwpos = 0; 1333 reallyrunning = false; 1334 readsallowed = false; 1137 1335 delete [] readAheadBuffer; 1336 1138 1337 readAheadBuffer = NULL; 1139 rbrpos = 0; 1140 rbwpos = 0; 1338 rbwlock.unlock(); 1339 rbrlock.unlock(); 1340 rwlock.unlock(); 1141 1341 } 1142 1342 1143 1343 long long RingBuffer::SetAdjustFilesize(void) 1144 1344 { 1345 rwlock.lockForWrite(); 1346 poslock.lockForRead(); 1145 1347 readAdjust += internalreadpos; 1146 return readAdjust; 1348 long long ra = readAdjust; 1349 poslock.unlock(); 1350 rwlock.unlock(); 1351 return ra; 1147 1352 } 1148 1353 1149 1354 int RingBuffer::Peek(void *buf, int count) 1150 1355 { 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 1356 int ret = ReadPriv(buf, count, true); 1191 1357 if (ret != count) 1192 1358 { 1193 1359 VERBOSE(VB_IMPORTANT, LOC_WARN + … … 1197 1363 return ret; 1198 1364 } 1199 1365 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) 1366 bool RingBuffer::WaitForReadsAllowed(void) 1209 1367 { 1210 if (commserror)1211 return 0;1368 MythTimer t; 1369 t.start(); 1212 1370 1213 bool readone = false; 1214 int readErr = 0; 1215 1216 if (readaheadpaused && stopreads) 1371 while (!readsallowed && !stopreads && 1372 !request_pause && !commserror && readaheadrunning) 1217 1373 { 1218 readone = true; 1219 Unpause(); 1220 } 1221 else 1222 { 1223 QMutexLocker locker(&readsAllowedWaitMutex); 1374 generalWait.wait(&rwlock, 1000); 1375 if (!readsallowed && t.elapsed() > 1000) 1376 { 1377 VERBOSE(VB_IMPORTANT, LOC_WARN + 1378 "Taking too long to be allowed to read.."); 1224 1379 1225 while (!readsallowed && !stopreads) 1226 { 1227 if (!readsAllowedWait.wait(&readsAllowedWaitMutex, 1000)) 1380 if (t.elapsed() > 10000) 1228 1381 { 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 } 1382 VERBOSE(VB_IMPORTANT, LOC_ERR + "Took more than " 1383 "10 seconds to be allowed to read, aborting."); 1384 return false; 1249 1385 } 1250 1386 } 1251 1387 } 1252 1388 1389 return readsallowed; 1390 } 1391 1392 bool RingBuffer::WaitForAvail(int count) 1393 { 1253 1394 int avail = ReadBufAvail(); 1395 count = (ateof && avail < count) ? avail : count; 1254 1396 1255 if (ateof && avail < count)1256 count = avail;1257 1258 1397 MythTimer t; 1259 1398 t.start(); 1260 while (avail < count && !stopreads) 1399 while ((avail < count) && !stopreads && 1400 !request_pause && !commserror && readaheadrunning) 1261 1401 { 1262 availWaitMutex.lock();1263 1402 wanttoread = count; 1264 if (!availWait.wait(&availWaitMutex, 250)) 1403 generalWait.wait(&rwlock, 250); 1404 avail = ReadBufAvail(); 1405 1406 if ((ateof || setswitchtonext) && avail < count) 1407 count = avail; 1408 1409 if (avail < count) 1265 1410 { 1266 1411 int elapsed = t.elapsed(); 1267 if (/*((elapsed > 500) && (elapsed < 750)) ||*/ 1412 if (((elapsed > 250) && (elapsed < 500)) || 1413 ((elapsed > 500) && (elapsed < 750)) || 1268 1414 ((elapsed > 1000) && (elapsed < 1250)) || 1269 1415 ((elapsed > 2000) && (elapsed < 2250)) || 1270 1416 ((elapsed > 4000) && (elapsed < 4250)) || 1271 ((elapsed > 8000) && (elapsed < 8250))) 1417 ((elapsed > 8000) && (elapsed < 8250)) || 1418 ((elapsed > 9000))) 1272 1419 { 1273 1420 VERBOSE(VB_IMPORTANT, LOC + "Waited " + 1274 QString("%1").arg((elapsed / 500) * 0.5f, 3, 'f', 1) + 1275 " seconds for data to become available..."); 1421 QString("%1").arg((elapsed / 250) * 0.25f, 3, 'f', 1) + 1422 " seconds for data \n\t\t\tto become available..." + 1423 QString(" %2 < %3") 1424 .arg(avail).arg(count)); 1276 1425 if (livetvchain) 1277 1426 { 1278 1427 VERBOSE(VB_IMPORTANT, "Checking to see if there's a " … … 1295 1444 VERBOSE(VB_IMPORTANT, LOC + "Timing out wait due to " 1296 1445 "impending livetv switch."); 1297 1446 1298 ateof = true; 1299 wanttoread = 0; 1300 stopreads = true; 1301 availWaitMutex.unlock(); 1302 return 0; 1447 return false; 1303 1448 } 1304 1449 } 1450 } 1305 1451 1452 wanttoread = 0; 1453 1454 return avail >= count; 1455 } 1456 1457 int RingBuffer::ReadDirect(void *buf, int count, bool peek) 1458 { 1459 long long old_pos = 0; 1460 if (peek) 1461 { 1462 poslock.lockForRead(); 1463 old_pos = (ignorereadpos >= 0) ? ignorereadpos : readpos; 1464 poslock.unlock(); 1465 } 1466 1467 int ret; 1468 if (remotefile) 1469 ret = safe_read(remotefile, buf, count); 1470 #ifdef USING_FRONTEND 1471 else if (dvdPriv) 1472 ret = dvdPriv->safe_read(buf, count); 1473 else if (bdPriv) 1474 ret = bdPriv->safe_read(buf, count); 1475 #endif // USING_FRONTEND 1476 else if (fd2 >= 0) 1477 ret = safe_read(fd2, buf, count); 1478 else 1479 { 1480 ret = -1; 1481 errno = EBADF; 1482 } 1483 1484 poslock.lockForWrite(); 1485 if (ignorereadpos >= 0 && ret > 0) 1486 { 1487 if (peek) 1488 { 1489 // seek should always succeed since we were at this position 1490 if (remotefile) 1491 remotefile->Seek(old_pos, SEEK_SET); 1492 else 1493 lseek64(fd2, old_pos, SEEK_SET); 1494 } 1495 else 1496 { 1497 ignorereadpos += ret; 1498 } 1499 poslock.unlock(); 1500 return ret; 1501 } 1502 poslock.unlock(); 1503 1504 if (peek && ret > 0) 1505 { 1506 if (!dvdPriv && !bdPriv) 1507 { 1508 long long new_pos = Seek(old_pos, SEEK_SET, true); 1509 if (new_pos != old_pos) 1510 { 1511 VERBOSE(VB_IMPORTANT, LOC_ERR + 1512 QString("Peek() Failed to return from new " 1513 "position %1 to old position %2, now " 1514 "at position %3") 1515 .arg(old_pos - ret).arg(old_pos).arg(new_pos)); 1516 } 1517 } 1518 else if (old_pos != 0) 1519 { 1520 VERBOSE(VB_IMPORTANT, LOC_ERR + 1521 "DVD and Blu-Ray do not support arbitrary " 1522 "peeks except when read-ahead is enabled." 1523 "\n\t\t\tWill seek to beginning of video."); 1524 } 1525 #ifdef USING_FRONTEND 1526 if (dvdPriv) 1527 dvdPriv->NormalSeek(old_pos); 1528 else if (bdPriv) 1529 bdPriv->Seek(old_pos); 1530 #endif // USING_FRONTEND 1531 } 1532 1533 return ret; 1534 } 1535 1536 /** \brief When possible reads from the read-ahead buffer, 1537 * otherwise reads directly from the device. 1538 * 1539 * \param buf Pointer to where data will be written 1540 * \param count Number of bytes to read 1541 * \param peek If true, don't increment read count 1542 * \return Returns number of bytes read 1543 */ 1544 int RingBuffer::ReadPriv(void *buf, int count, bool peek) 1545 { 1546 QString loc_desc = 1547 QString("ReadPriv(..%1, %2)") 1548 .arg(count).arg(peek?"peek":"normal"); 1549 VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + 1550 QString(" @%1 -- begin").arg(rbrpos)); 1551 1552 rwlock.lockForRead(); 1553 if (writemode) 1554 { 1555 VERBOSE(VB_IMPORTANT, LOC_ERR + loc_desc + 1556 ": Attempt to read from a write only file"); 1557 errno = EBADF; 1558 rwlock.unlock(); 1559 return -1; 1560 } 1561 1562 if (commserror) 1563 { 1564 VERBOSE(VB_IMPORTANT, LOC_ERR + loc_desc + 1565 ": Attempt to read after commserror set"); 1566 errno = EIO; 1567 rwlock.unlock(); 1568 return -1; 1569 } 1570 1571 if (request_pause || stopreads || !readaheadrunning || (ignorereadpos>=0)) 1572 { 1573 rwlock.unlock(); 1574 rwlock.lockForWrite(); 1575 // we need a write lock so the read-ahead thread 1576 // can't start mucking with the read position. 1577 // If the read ahead thread was started while we 1578 // didn't hold the lock, we proceed with a normal 1579 // read from the buffer, otherwise we read directly. 1580 if (request_pause || stopreads || 1581 !readaheadrunning || (ignorereadpos >= 0)) 1582 { 1583 int ret = ReadDirect(buf, count, peek); 1584 VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + 1585 QString(": ReadDirect checksum %1") 1586 .arg(qChecksum((char*)buf,count))); 1587 rwlock.unlock(); 1588 return ret; 1589 } 1590 rwlock.unlock(); 1591 rwlock.lockForRead(); 1592 } 1593 1594 if (!WaitForReadsAllowed()) 1595 { 1596 VERBOSE(VB_FILE, LOC + loc_desc + ": !WaitForReadsAllowed()"); 1597 rwlock.unlock(); 1598 rwlock.lockForWrite(); 1306 1599 wanttoread = 0; 1307 availWaitMutex.unlock(); 1600 stopreads = true; 1601 rwlock.unlock(); 1602 return 0; 1603 } 1308 1604 1309 avail = ReadBufAvail(); 1310 if ((ateof || setswitchtonext) && avail < count) 1311 count = avail; 1605 if (!WaitForAvail(count)) 1606 { 1607 VERBOSE(VB_FILE, LOC + loc_desc + ": !WaitForAvail()"); 1608 rwlock.unlock(); 1609 rwlock.lockForWrite(); 1610 ateof = true; 1611 wanttoread = 0; 1612 stopreads = true; 1613 rwlock.unlock(); 1614 return 0; 1615 } 1312 1616 1313 if (commserror) 1314 return 0; 1617 count = min(ReadBufAvail(), count); 1618 1619 if (count <= 0) 1620 { 1621 // this can happen under a few conditions but the most 1622 // notable is an exit from the read ahead thread or 1623 // the end of the file stream has been reached. 1624 VERBOSE(VB_FILE, LOC + loc_desc + ": ReadBufAvail() == 0"); 1625 rwlock.unlock(); 1626 return count; 1315 1627 } 1316 1628 1317 if ((ateof || stopreads) && avail < count) 1318 count = avail; 1629 if (peek) 1630 rbrlock.lockForRead(); 1631 else 1632 rbrlock.lockForWrite(); 1319 1633 1634 VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + " -- copying data"); 1635 1320 1636 if (rbrpos + count > (int) kBufferSize) 1321 1637 { 1322 1638 int firstsize = kBufferSize - rbrpos; … … 1326 1642 memcpy((char *)buf + firstsize, readAheadBuffer, secondsize); 1327 1643 } 1328 1644 else 1645 { 1329 1646 memcpy(buf, readAheadBuffer + rbrpos, count); 1647 } 1648 VERBOSE(VB_FILE|VB_EXTRA, LOC + loc_desc + QString(" -- checksum %1") 1649 .arg(qChecksum((char*)buf,count))); 1330 1650 1331 1651 if (!peek) 1332 1652 { 1333 readAheadLock.lock();1334 1653 rbrpos = (rbrpos + count) % kBufferSize; 1335 readAheadLock.unlock();1654 generalWait.wakeAll(); 1336 1655 } 1656 rbrlock.unlock(); 1657 rwlock.unlock(); 1337 1658 1338 if (readone)1339 {1340 Pause();1341 WaitForPause();1342 }1343 1344 1659 return count; 1345 1660 } 1346 1661 … … 1354 1669 */ 1355 1670 int RingBuffer::Read(void *buf, int count) 1356 1671 { 1357 int ret = -1;1358 if ( writemode)1672 int ret = ReadPriv(buf, count, false); 1673 if (ret > 0) 1359 1674 { 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); 1675 poslock.lockForWrite(); 1395 1676 readpos += ret; 1677 poslock.unlock(); 1396 1678 } 1397 1398 rwlock.unlock();1399 1679 return ret; 1400 1680 } 1401 1681 1402 1682 /** \fn RingBuffer::IsIOBound(void) const 1403 * \brief Returns true if a RingBuffer:: Read(void*,int) is likely to block.1683 * \brief Returns true if a RingBuffer::Write(void*,int) is likely to block. 1404 1684 */ 1405 1685 bool RingBuffer::IsIOBound(void) const 1406 1686 { … … 1429 1709 */ 1430 1710 int RingBuffer::Write(const void *buf, uint count) 1431 1711 { 1432 int ret = -1; 1712 rwlock.lockForRead(); 1713 1433 1714 if (!writemode) 1434 1715 { 1435 1716 VERBOSE(VB_IMPORTANT, LOC_ERR + "Tried to write to a read only file."); 1436 return ret; 1717 rwlock.unlock(); 1718 return -1; 1437 1719 } 1438 1720 1439 1721 if (!tfw && !remotefile) 1440 return ret; 1722 { 1723 rwlock.unlock(); 1724 return -1; 1725 } 1441 1726 1442 rwlock.lockForRead(); 1443 1727 int ret = -1; 1444 1728 if (tfw) 1445 1729 ret = tfw->Write(buf, count); 1446 1730 else 1447 1731 ret = remotefile->Write(buf, count); 1448 writepos += ret;1449 1732 1733 if (ret > 0) 1734 { 1735 poslock.lockForWrite(); 1736 writepos += ret; 1737 poslock.unlock(); 1738 } 1739 1450 1740 rwlock.unlock(); 1741 1451 1742 return ret; 1452 1743 } 1453 1744 … … 1456 1747 */ 1457 1748 void RingBuffer::Sync(void) 1458 1749 { 1750 rwlock.lockForRead(); 1459 1751 if (tfw) 1460 1752 tfw->Sync(); 1753 rwlock.unlock(); 1461 1754 } 1462 1755 1463 /** \fn RingBuffer::Seek(long long, int) 1464 * \brief Seeks to a particular position in the file. 1756 /** \brief Seeks to a particular position in the file. 1465 1757 */ 1466 long long RingBuffer::Seek(long long pos, int whence )1758 long long RingBuffer::Seek(long long pos, int whence, bool has_lock) 1467 1759 { 1760 VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)") 1761 .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET": 1762 ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END")) 1763 .arg(has_lock?"locked":"unlocked")); 1764 1765 long long ret = -1; 1766 1767 StopReads(); 1768 1769 // lockForWrite takes priority over lockForRead, so this will 1770 // take priority over the lockForRead in the read ahead thread. 1771 if (!has_lock) 1772 rwlock.lockForWrite(); 1773 1774 StartReads(); 1775 1468 1776 if (writemode) 1469 return WriterSeek(pos, whence); 1777 { 1778 ret = WriterSeek(pos, whence, true); 1779 if (!has_lock) 1780 rwlock.unlock(); 1781 return ret; 1782 } 1470 1783 1471 wantseek = true; 1472 rwlock.lockForWrite(); 1473 wantseek = false; 1784 poslock.lockForWrite(); 1474 1785 1475 // optimize nop seeks 1476 if ((whence == SEEK_SET && pos == readpos) || 1477 (whence == SEEK_CUR && pos == 0)) 1786 // Optimize no-op seeks 1787 if (readaheadrunning && 1788 ((whence == SEEK_SET && pos == readpos) || 1789 (whence == SEEK_CUR && pos == 0))) 1478 1790 { 1479 rwlock.unlock(); 1480 return readpos; 1791 ret = readpos; 1792 1793 poslock.unlock(); 1794 if (!has_lock) 1795 rwlock.unlock(); 1796 1797 return ret; 1481 1798 } 1482 1799 1483 errno = 0; // clear errno, in case of remotefile error 1800 // only valid for SEEK_SET & SEEK_CUR 1801 long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos; 1484 1802 1485 long long ret = -1; 1803 #if 1 1804 // Optimize short seeks where the data for 1805 // them is in our ringbuffer already. 1806 if (readaheadrunning && 1807 (SEEK_SET==whence || SEEK_CUR==whence)) 1808 { 1809 rbrlock.lockForWrite(); 1810 rbwlock.lockForRead(); 1811 VERBOSE(VB_FILE, LOC + 1812 QString("Seek(): rbrpos: %1 rbwpos: %2" 1813 "\n\t\t\treadpos: %3 internalreadpos: %4") 1814 .arg(rbrpos).arg(rbwpos) 1815 .arg(readpos).arg(internalreadpos)); 1816 bool used_opt = false; 1817 if ((new_pos < readpos)) 1818 { 1819 int min_safety = max(fill_min, readblocksize); 1820 int free = ((rbwpos >= rbrpos) ? 1821 rbrpos + kBufferSize : rbrpos) - rbwpos; 1822 int internal_backbuf = 1823 (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos; 1824 internal_backbuf = min(internal_backbuf, free - min_safety); 1825 long long sba = readpos - new_pos; 1826 VERBOSE(VB_FILE, LOC + 1827 QString("Seek(): internal_backbuf: %1 sba: %2") 1828 .arg(internal_backbuf).arg(sba)); 1829 if (internal_backbuf >= sba) 1830 { 1831 rbrpos = (rbrpos>=sba) ? rbrpos - sba : 1832 kBufferSize + rbrpos - sba; 1833 used_opt = true; 1834 VERBOSE(VB_FILE, LOC + 1835 QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2" 1836 "\n\t\t\treadpos: %3 internalreadpos: %4") 1837 .arg(rbrpos).arg(rbwpos) 1838 .arg(new_pos).arg(internalreadpos)); 1839 } 1840 } 1841 else if ((new_pos >= readpos) && (new_pos <= internalreadpos)) 1842 { 1843 rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize; 1844 used_opt = true; 1845 VERBOSE(VB_FILE, LOC + 1846 QString("Seek(): OPT2 rbrpos: %1 sba: %2") 1847 .arg(rbrpos).arg(readpos - new_pos)); 1848 } 1849 rbwlock.unlock(); 1850 rbrlock.unlock(); 1851 1852 if (used_opt) 1853 { 1854 if (ignorereadpos >= 0) 1855 { 1856 // seek should always succeed since we were at this position 1857 int ret; 1858 if (remotefile) 1859 ret = remotefile->Seek(internalreadpos, SEEK_SET); 1860 else 1861 ret = lseek64(fd2, internalreadpos, SEEK_SET); 1862 VERBOSE(VB_FILE, LOC + 1863 QString("Seek to %1 from ignore pos %2 returned %3") 1864 .arg(internalreadpos).arg(ignorereadpos).arg(ret)); 1865 ignorereadpos = -1; 1866 } 1867 readpos = new_pos; 1868 poslock.unlock(); 1869 generalWait.wakeAll(); 1870 ateof = false; 1871 readsallowed = false; 1872 if (!has_lock) 1873 rwlock.unlock(); 1874 return new_pos; 1875 } 1876 } 1877 #endif 1878 1879 #if 1 1880 // This optimizes the seek end-250000, read, seek 0, read portion 1881 // of the pattern ffmpeg performs at the start of playback to 1882 // determine the pts. 1883 // If the seek is a SEEK_END or is a seek where the position 1884 // changes over 100 MB we check the file size and if the 1885 // destination point is within 300000 bytes of the end of 1886 // the file we enter a special mode where the read ahead 1887 // buffer stops reading data and all reads are made directly 1888 // until another seek is performed. The point of all this is 1889 // to avoid flushing out the buffer that still contains all 1890 // the data the final seek 0, read will need just to read the 1891 // last 250000 bytes. A further optimization would be to buffer 1892 // the 250000 byte read, which is currently performed in 32KB 1893 // blocks (inefficient with RemoteFile). 1894 if ((remotefile || fd2 >= 0) && (ignorereadpos < 0)) 1895 { 1896 long long off_end = 0xDEADBEEF; 1897 if (SEEK_END == whence) 1898 { 1899 off_end = pos; 1900 if (remotefile) 1901 { 1902 new_pos = remotefile->GetFileSize() - off_end; 1903 } 1904 else 1905 { 1906 QFileInfo fi(filename); 1907 new_pos = fi.size() - off_end; 1908 } 1909 } 1910 else if (abs(new_pos-readpos) > 100000000) 1911 { 1912 if (remotefile) 1913 { 1914 off_end = remotefile->GetFileSize() - new_pos; 1915 } 1916 else 1917 { 1918 QFileInfo fi(filename); 1919 off_end = fi.size() - new_pos; 1920 } 1921 } 1922 if (off_end < 300000) 1923 { 1924 VERBOSE(VB_FILE, LOC + 1925 QString("Seek(): offset from end: %1").arg(off_end) + 1926 "\n\t\t\t -- ignoring read ahead thread until next seek."); 1927 1928 ignorereadpos = new_pos; 1929 errno = EINVAL; 1930 int ret; 1931 if (remotefile) 1932 ret = remotefile->Seek(ignorereadpos, SEEK_SET); 1933 else 1934 ret = lseek64(fd2, ignorereadpos, SEEK_SET); 1935 1936 if (ret < 0) 1937 { 1938 int tmp_eno = errno; 1939 QString cmd = QString("Seek(%1, %2) ign ") 1940 .arg(ignorereadpos) 1941 .arg((SEEK_SET == whence) ? "SEEK_SET" : 1942 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 1943 1944 ignorereadpos = -1; 1945 1946 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 1947 1948 // try to return to former position.. 1949 if (remotefile) 1950 ret = remotefile->Seek(internalreadpos, SEEK_SET); 1951 else 1952 ret = lseek64(fd2, internalreadpos, SEEK_SET); 1953 if (ret < 0) 1954 { 1955 QString cmd = QString("Seek(%1, %2) int ") 1956 .arg(internalreadpos) 1957 .arg((SEEK_SET == whence) ? "SEEK_SET" : 1958 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 1959 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 1960 } 1961 else 1962 { 1963 QString cmd = QString("Seek(%1, %2) int ") 1964 .arg(internalreadpos) 1965 .arg((SEEK_SET == whence) ? "SEEK_SET" : 1966 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 1967 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " succeeded"); 1968 } 1969 ret = -1; 1970 errno = tmp_eno; 1971 } 1972 else 1973 { 1974 ateof = false; 1975 readsallowed = false; 1976 } 1977 1978 rbwlock.unlock(); 1979 rbrlock.unlock(); 1980 poslock.unlock(); 1981 1982 generalWait.wakeAll(); 1983 1984 if (!has_lock) 1985 rwlock.unlock(); 1986 1987 return ret; 1988 } 1989 } 1990 #endif 1991 1992 // Here we perform a normal seek. When successful we 1993 // need to call ResetReadAhead(). A reset means we will 1994 // need to refill the buffer, which takes some time. 1486 1995 if (remotefile) 1996 { 1487 1997 ret = remotefile->Seek(pos, whence, readpos); 1998 if (ret<0) 1999 errno = EINVAL; 2000 } 1488 2001 #ifdef USING_FRONTEND 2002 else if ((dvdPriv || bdPriv) && (SEEK_END == whence)) 2003 { 2004 errno = EINVAL; 2005 ret = -1; 2006 } 1489 2007 else if (dvdPriv) 1490 2008 { 1491 dvdPriv->NormalSeek( pos);1492 ret = pos;2009 dvdPriv->NormalSeek(new_pos); 2010 ret = new_pos; 1493 2011 } 1494 2012 else if (bdPriv) 1495 2013 { 1496 bdPriv->Seek( pos);1497 ret = pos;2014 bdPriv->Seek(new_pos); 2015 ret = new_pos; 1498 2016 } 1499 2017 #endif // USING_FRONTEND 1500 2018 else 1501 2019 { 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 } 2020 ret = lseek64(fd2, pos, whence); 1517 2021 } 1518 2022 1519 2023 if (ret >= 0) 1520 2024 { 1521 2025 readpos = ret; 2026 2027 ignorereadpos = -1; 1522 2028 1523 2029 if (readaheadrunning) 1524 2030 ResetReadAhead(readpos); … … 1533 2039 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 1534 2040 } 1535 2041 1536 rwlock.unlock();2042 poslock.unlock(); 1537 2043 2044 generalWait.wakeAll(); 2045 2046 if (!has_lock) 2047 rwlock.unlock(); 2048 1538 2049 return ret; 1539 2050 } 1540 2051 1541 /** \fn RingBuffer::WriterSeek(long long, int) 1542 * \brief Calls ThreadedFileWriter::Seek(long long,int). 2052 /** \brief Calls ThreadedFileWriter::Seek(long long,int). 1543 2053 */ 1544 long long RingBuffer::WriterSeek(long long pos, int whence )2054 long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock) 1545 2055 { 1546 2056 long long ret = -1; 1547 2057 2058 if (!has_lock) 2059 rwlock.lockForRead(); 2060 2061 poslock.lockForWrite(); 2062 1548 2063 if (tfw) 1549 2064 { 1550 2065 ret = tfw->Seek(pos, whence); 1551 2066 writepos = ret; 1552 2067 } 1553 2068 2069 poslock.unlock(); 2070 2071 if (!has_lock) 2072 rwlock.unlock(); 2073 1554 2074 return ret; 1555 2075 } 1556 2076 … … 1560 2080 */ 1561 2081 void RingBuffer::WriterFlush(void) 1562 2082 { 2083 rwlock.lockForRead(); 1563 2084 if (tfw) 1564 2085 { 1565 2086 tfw->Flush(); 1566 2087 tfw->Sync(); 1567 2088 } 2089 rwlock.unlock(); 1568 2090 } 1569 2091 1570 2092 /** \fn RingBuffer::SetWriteBufferSize(int) … … 1572 2094 */ 1573 2095 void RingBuffer::SetWriteBufferSize(int newSize) 1574 2096 { 2097 rwlock.lockForRead(); 1575 2098 if (tfw) 1576 2099 tfw->SetWriteBufferSize(newSize); 2100 rwlock.unlock(); 1577 2101 } 1578 2102 1579 2103 /** \fn RingBuffer::SetWriteBufferMinWriteSize(int) … … 1581 2105 */ 1582 2106 void RingBuffer::SetWriteBufferMinWriteSize(int newMinSize) 1583 2107 { 2108 rwlock.lockForRead(); 1584 2109 if (tfw) 1585 2110 tfw->SetWriteBufferMinWriteSize(newMinSize); 2111 rwlock.unlock(); 1586 2112 } 1587 2113 2114 /** \brief Tell RingBuffer if this is an old file or not. 2115 * 2116 * Normally the RingBuffer determines that the file is old 2117 * if it has not been modified in the last minute. This 2118 * allows one to override that determination externally. 2119 * 2120 * If for instance you are slowly writing to the file you 2121 * could call this with the value of false. If you just 2122 * finished writing the file you could call it with the 2123 * value true. Knowing that the file is old allows MythTV 2124 * to determine that a read at the end of the file is 2125 * really an end-of-file condition more quickly. But if 2126 * the file is growing it can also cause the RingBuffer to 2127 * report an end-of-file condition prematurely. 2128 */ 2129 void RingBuffer::SetOldFile(bool is_old) 2130 { 2131 rwlock.lockForWrite(); 2132 oldfile = is_old; 2133 rwlock.unlock(); 2134 } 2135 2136 // This appears to allow direct access to the DVD/BD device 2137 // when called with false (the default value), and enable 2138 // the ring buffer when called with true. But I'm not entirely 2139 // certain. -- dtk 2010-08-26 2140 void RingBuffer::SetStreamOnly(bool stream) 2141 { 2142 rwlock.lockForWrite(); 2143 streamOnly = stream; 2144 rwlock.unlock(); 2145 } 2146 2147 /// Returns name of file used by this RingBuffer 2148 QString RingBuffer::GetFilename(void) const 2149 { 2150 rwlock.lockForRead(); 2151 QString tmp = filename; 2152 tmp.detach(); 2153 rwlock.unlock(); 2154 return tmp; 2155 } 2156 2157 QString RingBuffer::GetSubtitleFilename(void) const 2158 { 2159 rwlock.lockForRead(); 2160 QString tmp = subtitlefilename; 2161 tmp.detach(); 2162 rwlock.unlock(); 2163 return tmp; 2164 } 2165 1588 2166 /** \fn RingBuffer::GetReadPosition(void) const 1589 2167 * \brief Returns how far into the file we have read. 1590 2168 */ 1591 2169 long long RingBuffer::GetReadPosition(void) const 1592 2170 { 2171 rwlock.lockForRead(); 2172 poslock.lockForRead(); 2173 long long ret = readpos; 1593 2174 #ifdef USING_FRONTEND 1594 2175 if (dvdPriv) 1595 ret urndvdPriv->GetReadPosition();2176 ret = dvdPriv->GetReadPosition(); 1596 2177 else if (bdPriv) 1597 ret urnbdPriv->GetReadPosition();2178 ret = bdPriv->GetReadPosition(); 1598 2179 #endif // USING_FRONTEND 1599 1600 return readpos; 2180 poslock.unlock(); 2181 rwlock.unlock(); 2182 return ret; 1601 2183 } 1602 2184 1603 2185 /** \fn RingBuffer::GetWritePosition(void) const … … 1605 2187 */ 1606 2188 long long RingBuffer::GetWritePosition(void) const 1607 2189 { 1608 return writepos; 2190 poslock.lockForRead(); 2191 long long ret = writepos; 2192 poslock.unlock(); 2193 return ret; 1609 2194 } 1610 2195 1611 2196 /** \fn RingBuffer::GetRealFileSize(void) const … … 1614 2199 */ 1615 2200 long long RingBuffer::GetRealFileSize(void) const 1616 2201 { 2202 rwlock.lockForRead(); 2203 long long ret = -1; 1617 2204 if (remotefile) 1618 return remotefile->GetFileSize(); 1619 1620 QFileInfo info(filename); 1621 return info.size(); 2205 ret = remotefile->GetFileSize(); 2206 else 2207 ret = QFileInfo(filename).size(); 2208 rwlock.unlock(); 2209 return ret; 1622 2210 } 1623 2211 1624 2212 /** \fn RingBuffer::LiveMode(void) const … … 1627 2215 */ 1628 2216 bool RingBuffer::LiveMode(void) const 1629 2217 { 1630 return (livetvchain); 2218 rwlock.lockForRead(); 2219 bool ret = (livetvchain); 2220 rwlock.unlock(); 2221 return ret; 1631 2222 } 1632 2223 1633 2224 /** \fn RingBuffer::SetLiveMode(LiveTVChain*) … … 1636 2227 */ 1637 2228 void RingBuffer::SetLiveMode(LiveTVChain *chain) 1638 2229 { 2230 rwlock.lockForWrite(); 1639 2231 livetvchain = chain; 2232 rwlock.unlock(); 1640 2233 } 1641 2234 2235 /// Tells RingBuffer whether to igonre the end-of-file 2236 void RingBuffer::IgnoreLiveEOF(bool ignore) 2237 { 2238 rwlock.lockForWrite(); 2239 ignoreliveeof = ignore; 2240 rwlock.unlock(); 2241 } 2242 2243 /** \brief Returns true if this is a DVD backed RingBuffer. 2244 * 2245 * NOTE: This is not locked because ReadDirect calls 2246 * DVD safe_read which sleeps with a write lock on 2247 * rwlock in the DVDNAV_WAIT condition. 2248 * 2249 * Due to the lack of locking is only safe to call once OpenFile() 2250 * has completed. 2251 */ 2252 bool RingBuffer::IsDVD(void) const 2253 { 2254 //rwlock.lockForRead(); 2255 bool ret = dvdPriv; 2256 //rwlock.unlock(); 2257 return ret; 2258 } 2259 2260 /** \brief Returns true if this is a DVD backed RingBuffer. 2261 * 2262 * NOTE: This is not locked because ReadDirect calls 2263 * DVD safe_read which sleeps with a write lock on 2264 * rwlock in the DVDNAV_WAIT condition. 2265 * 2266 * Due to the lack of locking is only safe to call once OpenFile() 2267 * has completed. 2268 */ 1642 2269 bool RingBuffer::InDVDMenuOrStillFrame(void) 1643 2270 { 2271 //rwlock.lockForRead(); 2272 bool ret = false; 1644 2273 #ifdef USING_FRONTEND 1645 2274 if (dvdPriv) 1646 ret urn(dvdPriv->IsInMenu() || dvdPriv->InStillFrame());2275 ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame()); 1647 2276 #endif // USING_FRONTEND 1648 return false; 2277 //rwlock.unlock(); 2278 return ret; 1649 2279 } 1650 2280 2281 /// Returns true if this is a Blu-ray backed RingBuffer. 2282 bool RingBuffer::IsBD(void) const 2283 { 2284 //rwlock.lockForRead(); 2285 bool ret = bdPriv; 2286 //rwlock.unlock(); 2287 return ret; 2288 } 2289 1651 2290 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/tv_play.cpp
873 873 switchToInputId(0), 874 874 wantsToQuit(true), 875 875 stretchAdjustment(false), 876 audiosyncAdjustment(false), audiosyncBaseline( INT64_MIN),876 audiosyncAdjustment(false), audiosyncBaseline(LLONG_MIN), 877 877 editmode(false), zoomMode(false), 878 878 sigMonMode(false), 879 879 endOfRecording(false), … … 1971 1971 .arg(playbackURL).arg(ctx->tvchain->GetCardType(-1))); 1972 1972 1973 1973 ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true, 1974 opennow ? 12 : (uint)-1));1974 opennow ? 2000 : -1)); 1975 1975 ctx->buffer->SetLiveMode(ctx->tvchain); 1976 1976 } 1977 1977 … … 5644 5644 5645 5645 bool res = false; 5646 5646 5647 if ( INT64_MIN != audiosyncBaseline)5647 if (LLONG_MIN != audiosyncBaseline) 5648 5648 { 5649 5649 int64_t aud_tc = ctx->player->GetAudioTimecodeOffset(); 5650 5650 ctx->player->SaveAudioTimecodeOffset(aud_tc - audiosyncBaseline); … … 6365 6365 QString playbackURL = ctx->playingInfo->GetPlaybackURL(true); 6366 6366 bool opennow = (ctx->tvchain->GetCardType(-1) != "DUMMY"); 6367 6367 ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true, 6368 opennow ? 12 : (uint)-1));6368 opennow ? 2000 : -1)); 6369 6369 6370 6370 ctx->tvchain->SetProgram(*ctx->playingInfo); 6371 6371 ctx->buffer->SetLiveMode(ctx->tvchain); … … 8056 8056 return; 8057 8057 } 8058 8058 8059 if (!audiosyncAdjustment && INT64_MIN == audiosyncBaseline)8059 if (!audiosyncAdjustment && LLONG_MIN == audiosyncBaseline) 8060 8060 audiosyncBaseline = ctx->player->GetAudioTimecodeOffset(); 8061 8061 8062 8062 audiosyncAdjustment = allowEdit; -
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> … … 27 27 { 28 28 public: 29 29 RingBuffer(const QString &lfilename, bool write, 30 bool usereadahead = true, uint read_retries = 12/*6*/); 30 bool usereadahead = true, 31 int timeout_ms = kDefaultOpenTimeout); 31 32 ~RingBuffer(); 32 33 33 34 // Sets 34 35 void SetWriteBufferSize(int newSize); 35 36 void SetWriteBufferMinWriteSize(int newMinSize); 37 void SetOldFile(bool is_old); 38 void SetStreamOnly(bool stream); 36 39 void UpdateRawBitrate(uint rawbitrate); 37 40 void UpdatePlaySpeed(float playspeed); 38 void SetStreamOnly(bool stream) { streamOnly = stream; }39 41 40 42 // Gets 41 /// Returns name of file used by this RingBuffer 42 QString GetFilename(void) const { return filename; } 43 QString GetSubtitleFilename(void) const { return subtitlefilename; } 44 /// Returns ReadBufAvail(void) 45 int DataInReadAhead(void) const { return ReadBufAvail(); } 43 QString GetFilename(void) const; 44 QString GetSubtitleFilename(void) const; 46 45 /// Returns value of stopreads 47 46 /// \sa StartReads(void), StopReads(void) 48 47 bool GetStopReads(void) const { return stopreads; } 49 /// Returns false iff read-ahead is not 50 /// running and read-ahead is not paused. 51 bool isPaused(void) const 52 { return (!readaheadrunning) ? true : readaheadpaused; } 48 bool isPaused(void) const; 53 49 long long GetReadPosition(void) const; 54 50 long long GetWritePosition(void) const; 55 51 long long GetRealFileSize(void) const; 56 uint GetBitrate(void) const;57 uint GetReadBlockSize(void) const;58 52 bool IsOpen(void) const; 53 bool IsNearEnd(double fps, uint vvf) const; 59 54 60 55 // General Commands 61 void OpenFile(const QString &lfilename, uint retryCount = 12/*4*/); 56 void OpenFile(const QString &lfilename, 57 uint retry_ms = kDefaultOpenTimeout); 62 58 int Read(void *buf, int count); 63 59 int Peek(void *buf, int count); // only works with readahead 64 60 … … 67 63 bool resetInternal = false); 68 64 69 65 // Seeks 70 long long Seek(long long pos, int whence );66 long long Seek(long long pos, int whence, bool has_lock = false); 71 67 72 68 // Pause commands 73 69 void Pause(void); … … 82 78 // LiveTVChain support 83 79 bool LiveMode(void) const; 84 80 void SetLiveMode(LiveTVChain *chain); 85 /// Tells RingBuffer whether to igonre the end-of-file 86 void IgnoreLiveEOF(bool ignore) { ignoreliveeof = ignore; } 81 void IgnoreLiveEOF(bool ignore); 87 82 88 83 // ThreadedFileWriter proxies 89 84 int Write(const void *buf, uint count); 90 85 bool IsIOBound(void) const; 91 86 void WriterFlush(void); 92 87 void Sync(void); 93 long long WriterSeek(long long pos, int whence );88 long long WriterSeek(long long pos, int whence, bool has_lock = false); 94 89 95 90 // DVDRingBuffer proxies 96 /// Returns true if this is a DVD backed RingBuffer. 97 inline bool isDVD(void) const { return dvdPriv; } 98 DVDRingBufferPriv *DVD() { return dvdPriv; } 91 bool IsDVD(void) const; 99 92 bool InDVDMenuOrStillFrame(void); 100 93 101 94 // BDRingBuffer proxies 102 /// Returns true if this is a Blu-ray backed RingBuffer. 103 inline bool isBD(void) const { return bdPriv; } 104 BDRingBufferPriv *BD() { return bdPriv; } 95 bool IsBD(void) const; 105 96 106 97 long long SetAdjustFilesize(void); 107 void SetTimeout(bool fast) { oldfile = fast; }108 98 99 /// Calls SetOldFile(), do not use 100 void SetTimeout(bool is_old) MDEPRECATED { SetOldFile(is_old); } 101 /// Calls IsDVD(), do not use 102 bool isDVD(void) const MDEPRECATED { return IsDVD(); } 103 /// Calls IsBD(), do not use 104 bool isBD(void) const MDEPRECATED { return IsBD(); } 105 /// Illicitly manipulating privates is ill advised! 106 /// DO NOT USE 107 DVDRingBufferPriv *DVD() MDEPRECATED 108 { 109 return dvdPriv; 110 } 111 /// Illicitly manipulating privates is ill advised! 112 /// DO NOT USE 113 BDRingBufferPriv *BD() MDEPRECATED 114 { 115 return bdPriv; 116 } 117 118 static const int kDefaultOpenTimeout; 119 109 120 protected: 110 121 void run(void); // QThread 111 122 void CalcReadAheadThresh(void); 123 bool PauseAndWait(void); 112 124 int safe_read_bd(void *data, uint sz); 113 125 int safe_read_dvd(void *data, uint sz); 114 126 int safe_read(int fd, void *data, uint sz); 115 127 int safe_read(RemoteFile *rf, void *data, uint sz); 116 128 117 int ReadFromBuf(void *buf, int count, bool peek = false); 129 int ReadPriv(void *buf, int count, bool peek); 130 int ReadDirect(void *buf, int count, bool peek); 131 bool WaitForReadsAllowed(void); 132 bool WaitForAvail(int count); 118 133 119 134 int ReadBufFree(void) const; 120 135 int ReadBufAvail(void) const; 121 136 122 void StartupReadAheadThread(void);123 137 void ResetReadAhead(long long newinternal); 124 138 void KillReadAheadThread(void); 125 139 126 140 private: 127 // NR == trivial risk, not protected, but only modified in single thread 128 // LR == low risk, not protected, but only modified on Open,Close,ctor,dtor 129 // HR == high risk, likely to cause unexpected behaviour 130 // MR == medium risk, unsafe methods unlikely to be called at wrong moment 141 mutable QReadWriteLock poslock; 142 long long readpos; // protected by poslock 143 long long writepos; // protected by poslock 144 long long internalreadpos; // protected by poslock 145 long long ignorereadpos; // protected by poslock 146 mutable QReadWriteLock rbrlock; 147 int rbrpos; // protected by rbrlock 148 mutable QReadWriteLock rbwlock; 149 int rbwpos; // protected by rbwlock 131 150 132 QString filename; // not protected by a lock LR 133 QString subtitlefilename; // not protected by a lock LR 151 // note should not go under rwlock.. 152 // this is used to break out of read_safe where rwlock is held 153 volatile bool stopreads; 134 154 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 155 mutable QReadWriteLock rwlock; 146 156 147 RemoteFile *remotefile; // not protected by a lock LR 157 QString filename; // protected by rwlock 158 QString subtitlefilename; // protected by rwlock 148 159 149 // this lock does not consistently protect anything, 150 // but seems to be intented to protect rbrpos & rbwpos 151 mutable QMutex readAheadLock; 160 ThreadedFileWriter *tfw; // protected by rwlock 161 int fd2; // protected by rwlock 152 162 153 bool startreadahead; // not protected by a lock HR 154 char *readAheadBuffer; // not protected by a lock MR 155 bool readaheadrunning; // not protected by a lock HR 156 bool readaheadpaused; // not protected by a lock HR 157 bool pausereadthread; // not protected by a lock HR 158 int rbrpos; // not protected by a lock HR 159 int rbwpos; // not protected by a lock HR 160 long long internalreadpos; // not protected by a lock HR 161 bool ateof; // not protected by a lock HR 162 bool readsallowed; // not protected by a lock HR 163 volatile bool wantseek; // not protected by a lock HR 164 bool setswitchtonext; // protected by rwlock 165 bool streamOnly; 163 bool writemode; // protected by rwlock 166 164 167 uint rawbitrate; // protected by rwlock 168 float playspeed; // protected by rwlock 169 int fill_threshold;// not protected by a lock HR 170 int fill_min; // protected by rwlock 171 int readblocksize; // protected by rwlock 165 RemoteFile *remotefile; // protected by rwlock 172 166 173 QWaitCondition pauseWait; // not protected by a lock HR 167 bool startreadahead; // protected by rwlock 168 char *readAheadBuffer; // protected by rwlock 169 bool readaheadrunning; // protected by rwlock 170 bool reallyrunning; // protected by rwlock 171 bool request_pause; // protected by rwlock 172 bool paused; // protected by rwlock 173 bool ateof; // protected by rwlock 174 bool readsallowed; // protected by rwlock 175 bool setswitchtonext; // protected by rwlock 176 bool streamOnly; // protected by rwlock 177 bool ignorereadahead; // protected by rwlock 178 uint rawbitrate; // protected by rwlock 179 float playspeed; // protected by rwlock 180 int fill_threshold; // protected by rwlock 181 int fill_min; // protected by rwlock 182 int readblocksize; // protected by rwlock 183 int wanttoread; // protected by rwlock 184 int numfailures; // protected by rwlock (see note 1) 185 bool commserror; // protected by rwlock 174 186 175 int wanttoread; // not protected by a lock HR 176 QWaitCondition availWait; // protected by availWaitMutex 177 QMutex availWaitMutex; 187 // We should really subclass for these two sets of functionality.. 188 // current implementation is not thread-safe. 189 DVDRingBufferPriv *dvdPriv; // NOT protected by a lock 190 BDRingBufferPriv *bdPriv; // NOT protected by a lock 178 191 179 QWaitCondition readsAllowedWait;// protected by readsAllowedWaitMutex 180 QMutex readsAllowedWaitMutex; 192 bool oldfile; // protected by rwlock 181 193 182 int numfailures; // not protected by a lock MR 194 LiveTVChain *livetvchain; // protected by rwlock 195 bool ignoreliveeof; // protected by rwlock 183 196 184 bool commserror; // not protected by a lock MR197 long long readAdjust; // protected by rwlock 185 198 186 DVDRingBufferPriv *dvdPriv; // not protected by a lock LR 187 BDRingBufferPriv *bdPriv; // not protected by a lock LR 199 // note 1: numfailures is modified with only a read lock in the 200 // read ahead thread, but this is safe since all other places 201 // that use it are protected by a write lock. But this is a 202 // fragile state of affairs and care must be taken when modifying 203 // code or locking around this variable. 188 204 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 205 /// Condition to signal that the read ahead thread is running 197 QWaitCondition readAheadRunningCond;//protected by readAheadRunningCondLock 198 QMutex readAheadRunningCondLock; 206 QWaitCondition generalWait; // protected by rwlock 199 207 200 208 public: 201 209 static QMutex subExtLock; … … 208 216 static const uint kReadTestSize; 209 217 }; 210 218 211 #endif 219 #endif // _RINGBUFFER_H_ -
libs/libmythtv/mythplayer.cpp
892 892 893 893 void MythPlayer::OpenDummy(void) 894 894 { 895 VERBOSE(VB_IMPORTANT, LOC + "OpenDummy()"); 896 895 897 isDummy = true; 896 898 897 899 float displayAspect = … … 935 937 SetDecoder(NULL); 936 938 int testreadsize = 2048; 937 939 940 MythTimer bigTimer; bigTimer.start(); 941 int timeout = (retries + 1) * 500; 938 942 while (testreadsize <= kDecoderProbeBufferSize) 939 943 { 940 if (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize) 944 MythTimer peekTimer; peekTimer.start(); 945 while (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize) 941 946 { 942 VERBOSE(VB_IMPORTANT, LOC_ERR + 943 QString("OpenFile(): Error, couldn't read file: %1") 944 .arg(player_ctx->buffer->GetFilename())); 945 return -1; 947 if (peekTimer.elapsed() > 1000 || bigTimer.elapsed() > timeout) 948 { 949 VERBOSE(VB_IMPORTANT, LOC_ERR + 950 QString("OpenFile(): Could not read " 951 "first %1 bytes of '%2'") 952 .arg(testreadsize) 953 .arg(player_ctx->buffer->GetFilename())); 954 return -1; 955 } 956 VERBOSE(VB_IMPORTANT, LOC_WARN + "OpenFile() waiting on data"); 957 usleep(50 * 1000); 946 958 } 947 959 948 960 player_ctx->LockPlayingInfo(__FILE__, __LINE__); … … 959 971 player_ctx->GetSpecialDecode())); 960 972 } 961 973 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 962 if (GetDecoder() )974 if (GetDecoder() || (bigTimer.elapsed() > timeout)) 963 975 break; 964 976 testreadsize <<= 1; 965 977 } … … 2167 2179 return; 2168 2180 } 2169 2181 2170 uint retries = 10; // about 5 seconds of retries2171 player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL(), retries);2182 player_ctx->buffer->OpenFile( 2183 pginfo->GetPlaybackURL(), RingBuffer::kDefaultOpenTimeout); 2172 2184 2173 2185 if (!player_ctx->buffer->IsOpen()) 2174 2186 { 2175 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()); 2176 2191 eof = true; 2177 2192 SetErrored(QObject::tr("Error opening switch program buffer")); 2178 2193 delete pginfo; … … 2289 2304 2290 2305 SendMythSystemPlayEvent("PLAY_CHANGED", pginfo); 2291 2306 2292 player_ctx->buffer->OpenFile(pginfo->GetPlaybackURL()); 2307 player_ctx->buffer->OpenFile( 2308 pginfo->GetPlaybackURL(), RingBuffer::kDefaultOpenTimeout); 2309 2293 2310 if (!player_ctx->buffer->IsOpen()) 2294 2311 { 2295 VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed."); 2312 VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed " + 2313 QString("(card type: %1).") 2314 .arg(player_ctx->tvchain->GetCardType(newid))); 2315 VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString()); 2316 2296 2317 eof = true; 2297 2318 SetErrored(QObject::tr("Error opening jump program file buffer")); 2298 2319 delete pginfo; … … 2884 2905 2885 2906 void MythPlayer::WrapTimecode(int64_t &timecode, TCTypes tc_type) 2886 2907 { 2887 if ((tc_type == TC_AUDIO) && (tc_wrap[TC_AUDIO] == INT64_MIN))2908 if ((tc_type == TC_AUDIO) && (tc_wrap[TC_AUDIO] == LLONG_MIN)) 2888 2909 { 2889 2910 int64_t newaudio; 2890 2911 newaudio = tc_lastval[TC_VIDEO]; … … 3189 3210 if (!videoOutput) 3190 3211 return false; 3191 3212 3192 int sz = player_ctx->buffer->DataInReadAhead(); 3193 uint rbs = player_ctx->buffer->GetReadBlockSize(); 3194 uint kbits_per_sec = player_ctx->buffer->GetBitrate(); 3195 uint vvf = videoOutput->ValidVideoFrames(); 3196 double inv_fps = 1.0 / GetDecoder()->GetFPS(); 3197 double bytes_per_frame = kbits_per_sec * (1000.0/8.0) * inv_fps; 3198 double rh_frames = sz / bytes_per_frame; 3199 3200 // WARNING: rh_frames can greatly overestimate or underestimate 3201 // the number of frames available in the read ahead buffer 3202 // when rh_frames is less than the keyframe distance. 3203 3204 bool near_end = ((vvf + rh_frames) < 10.0) || (sz < rbs*1.5); 3205 3206 VERBOSE(VB_PLAYBACK, LOC + "IsReallyNearEnd()" 3207 <<" br("<<(kbits_per_sec/8)<<"KB)" 3208 <<" fps("<<((uint)(1.0/inv_fps))<<")" 3209 <<" sz("<<(sz / 1000)<<"KB)" 3210 <<" vfl("<<vvf<<")" 3211 <<" frh("<<((uint)rh_frames)<<")" 3212 <<" ne:"<<near_end); 3213 3214 return near_end; 3213 return player_ctx->buffer->IsNearEnd( 3214 GetDecoder()->GetFPS(), 3215 videoOutput->ValidVideoFrames()); 3215 3216 } 3216 3217 3217 3218 /** \brief Returns true iff near end of recording. -
libs/libmythtv/subtitlescreen.cpp
117 117 { 118 118 VideoOutput *videoOut = m_player->getVideoOutput(); 119 119 VideoFrame *currentFrame = videoOut ? videoOut->GetLastShownFrame() : NULL; 120 long long now = currentFrame ? currentFrame->timecode : INT64_MAX;120 long long now = currentFrame ? currentFrame->timecode : LLONG_MAX; 121 121 QMutableHashIterator<MythUIType*, long long> it(m_expireTimes); 122 122 while (it.hasNext()) 123 123 { -
libs/libmythdb/remotefile.h
17 17 RemoteFile(const QString &url = "", 18 18 bool write = false, 19 19 bool usereadahead = true, 20 int retries = -1,20 int timeout_ms = 2000/*RingBuffer::kDefaultOpenTimeout*/, 21 21 const QStringList *possibleAuxiliaryFiles = NULL); 22 22 ~RemoteFile(); 23 23 … … 59 59 60 60 QString path; 61 61 bool usereadahead; 62 int retries;62 int timeout_ms; 63 63 long long filesize; 64 64 bool timeoutisfast; 65 65 long long readposition; -
libs/libmythdb/remotefile.cpp
13 13 #include "mythtimer.h" 14 14 15 15 RemoteFile::RemoteFile(const QString &_path, bool write, bool useRA, 16 int _ retries,16 int _timeout_ms, 17 17 const QStringList *possibleAuxiliaryFiles) : 18 18 path(_path), 19 usereadahead(useRA), retries(_retries),19 usereadahead(useRA), timeout_ms(_timeout_ms), 20 20 filesize(-1), timeoutisfast(false), 21 21 readposition(0), recordernum(0), 22 22 lock(QMutex::NonRecursive), … … 27 27 if (writemode) 28 28 { 29 29 usereadahead = false; 30 retries = -1;30 timeout_ms = -1; 31 31 } 32 32 else if (possibleAuxiliaryFiles) 33 33 possibleauxfiles = *possibleAuxiliaryFiles; … … 107 107 } 108 108 else 109 109 { 110 strlist.append( QString("ANN FileTransfer %1 %2 %3 %4") 111 .arg(hostname).arg(writemode).arg(usereadahead).arg(retries) ); 110 strlist.push_back(QString("ANN FileTransfer %1 %2 %3 %4") 111 .arg(hostname).arg(writemode) 112 .arg(usereadahead).arg(timeout_ms)); 112 113 strlist << QString("%1").arg(dir); 113 114 strlist << sgroup; 114 115 -
programs/mythbackend/filetransfer.cpp
9 9 #include "programinfo.h" 10 10 11 11 FileTransfer::FileTransfer(QString &filename, MythSocket *remote, 12 bool usereadahead, int retries) :12 bool usereadahead, int timeout_ms) : 13 13 readthreadlive(true), readsLocked(false), 14 rbuffer(new RingBuffer(filename, false, usereadahead, retries)),14 rbuffer(new RingBuffer(filename, false, usereadahead, timeout_ms)), 15 15 sock(remote), ateof(false), lock(QMutex::NonRecursive), 16 16 refLock(QMutex::NonRecursive), refCount(0), writemode(false) 17 17 { -
programs/mythbackend/mainserver.cpp
1248 1248 FileTransfer *ft = NULL; 1249 1249 bool writemode = false; 1250 1250 bool usereadahead = true; 1251 int retries = -1;1251 int timeout_ms = 2000; 1252 1252 if (commands.size() > 3) 1253 1253 writemode = commands[3].toInt(); 1254 1254 … … 1256 1256 usereadahead = commands[4].toInt(); 1257 1257 1258 1258 if (commands.size() > 5) 1259 retries = commands[5].toInt();1259 timeout_ms = commands[5].toInt(); 1260 1260 1261 1261 if (writemode) 1262 1262 { … … 1312 1312 return; 1313 1313 } 1314 1314 1315 if ( retries < 0)1315 if (writemode) 1316 1316 ft = new FileTransfer(filename, socket, writemode); 1317 1317 else 1318 ft = new FileTransfer(filename, socket, usereadahead, retries);1318 ft = new FileTransfer(filename, socket, usereadahead, timeout_ms); 1319 1319 1320 1320 sockListLock.lockForWrite(); 1321 1321 fileTransferList.push_back(ft); -
programs/mythbackend/filetransfer.h
26 26 27 27 public: 28 28 FileTransfer(QString &filename, MythSocket *remote, 29 bool usereadahead, int retries);29 bool usereadahead, int timeout_ms); 30 30 FileTransfer(QString &filename, MythSocket *remote, bool write); 31 31 32 32 MythSocket *getSocket() { return sock; }
