MythTV  master
mythmediabuffer.cpp
Go to the documentation of this file.
1 // Std
2 #include <algorithm>
3 #include <cmath>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <cerrno>
7 #include <chrono>
8 #include <thread>
9 #include <sys/types.h>
10 #include <sys/time.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 
14 // Qt
15 #include <QFile>
16 #include <QDateTime>
17 #include <QReadLocker>
18 
19 // MythTV
20 #include "libmyth/mythcontext.h"
21 #include "libmythbase/compat.h"
22 #include "libmythbase/mythcdrom.h"
23 #include "libmythbase/mythconfig.h"
24 #include "libmythbase/mythdate.h"
27 #include "libmythbase/mythtimer.h"
28 #include "libmythbase/remotefile.h"
30 
31 #include "Bluray/mythbdbuffer.h"
32 #include "DVD/mythdvdbuffer.h"
33 #include "DVD/mythdvdstream.h"
35 #include "io/mythfilebuffer.h"
36 #include "io/mythmediabuffer.h"
37 #include "io/mythstreamingbuffer.h"
38 #include "livetvchain.h"
39 
40 // FFmpeg
41 extern "C" {
42 #include "libavformat/avformat.h"
43 }
44 
45 #define LOC QString("RingBuf(%1): ").arg(m_filename)
46 
47 
48 /*
49  Locking relations:
50  rwlock->poslock->rbrlock->rbwlock
51 
52  A child should never lock any of the parents without locking
53  the parent lock before the child lock.
54  void MythMediaBuffer::Example1()
55  {
56  poslock.lockForWrite();
57  rwlock.lockForRead(); // error!
58  blah(); // <- does not implicitly acquire any locks
59  rwlock.unlock();
60  poslock.unlock();
61  }
62  void MythMediaBuffer::Example2()
63  {
64  rwlock.lockForRead();
65  rbrlock.lockForWrite(); // ok!
66  blah(); // <- does not implicitly acquire any locks
67  rbrlock.unlock();
68  rwlock.unlock();
69  }
70 */
71 
99 MythMediaBuffer *MythMediaBuffer::Create(const QString &Filename, bool Write,
100  bool UseReadAhead, std::chrono::milliseconds Timeout, bool StreamOnly)
101 {
102  QString filename = Filename;
103  QString lower = filename.toLower();
104 
105  if (Write)
106  return new MythFileBuffer(filename, Write, UseReadAhead, Timeout);
107 
108  bool dvddir = false;
109  bool bddir = false;
110  bool httpurl = lower.startsWith("http://") || lower.startsWith("https://");
111  bool iptvurl = lower.startsWith("rtp://") || lower.startsWith("tcp://") ||
112  lower.startsWith("udp://");
113  bool mythurl = lower.startsWith("myth://");
114  bool bdurl = lower.startsWith("bd:");
115  bool dvdurl = lower.startsWith("dvd:");
116  bool imgext = lower.endsWith(".img") || lower.endsWith(".iso");
117 
118  if (imgext)
119  {
121  {
122  case MythCDROM::kBluray:
123  bdurl = true;
124  break;
125  case MythCDROM::kDVD:
126  dvdurl = true;
127  break;
128  default: break;
129  }
130  }
131 
132  if (httpurl || iptvurl)
133  {
135  return new HLSRingBuffer(filename);
136  return new MythStreamingBuffer(filename);
137  }
138  if (!StreamOnly && mythurl)
139  {
140  struct stat fileInfo {};
141  if ((RemoteFile::Exists(filename, &fileInfo)) &&
142  (S_ISDIR(fileInfo.st_mode)))
143  {
144  if (RemoteFile::Exists(filename + "/VIDEO_TS"))
145  dvddir = true;
146  else if (RemoteFile::Exists(filename + "/BDMV"))
147  bddir = true;
148  }
149  }
150  else if (!StreamOnly && !mythurl)
151  {
152  if (QFile::exists(filename + "/VIDEO_TS"))
153  dvddir = true;
154  else if (QFile::exists(filename + "/BDMV"))
155  bddir = true;
156  }
157 
158  if (!StreamOnly && (dvdurl || dvddir))
159  {
160  if (filename.startsWith("dvd:")) // URI "dvd:" + path
161  filename.remove(0,4); // e.g. "dvd:/dev/dvd"
162 
163  if (!(mythurl || QFile::exists(filename)))
164  filename = "/dev/dvd";
165  LOG(VB_PLAYBACK, LOG_INFO, "Trying DVD at " + filename);
166  return new MythDVDBuffer(filename);
167  }
168 
169  if (!StreamOnly && (bdurl || bddir))
170  {
171  if (filename.startsWith("bd:")) // URI "bd:" + path
172  filename.remove(0,3); // e.g. "bd:/videos/ET"
173 
174  if (!(mythurl || QFile::exists(filename)))
175  filename = "/dev/dvd";
176  LOG(VB_PLAYBACK, LOG_INFO, "Trying BD at " + filename);
177  return new MythBDBuffer(filename);
178  }
179 
180  if (!mythurl && imgext && filename.startsWith("dvd:"))
181  {
182  LOG(VB_PLAYBACK, LOG_INFO, "DVD image at " + filename);
183  return new MythDVDStream(filename);
184  }
185 
186  if (!mythurl && lower.endsWith(".vob") && filename.contains("/VIDEO_TS/"))
187  {
188  LOG(VB_PLAYBACK, LOG_INFO, "DVD VOB at " + filename);
189  auto *dvdstream = new MythDVDStream(filename);
190  if (dvdstream && dvdstream->IsOpen())
191  return dvdstream;
192  delete dvdstream;
193  }
194 
195  return new MythFileBuffer(filename, Write, UseReadAhead, Timeout);
196 }
197 
199  : MThread("RingBuffer"),
200  m_type(Type)
201 {
202 }
203 
205 {
206  return m_type;
207 }
208 
209 #undef NDEBUG
210 #include <cassert>
211 
220 {
221  assert(!isRunning());
222  wait();
223 
224  delete [] m_readAheadBuffer;
225  m_readAheadBuffer = nullptr;
226 
227  if (m_tfw)
228  {
229  m_tfw->Flush();
230  delete m_tfw;
231  m_tfw = nullptr;
232  }
233 }
234 
238 void MythMediaBuffer::Reset(bool Full, bool ToAdjust, bool ResetInternal)
239 {
240  LOG(VB_FILE, LOG_INFO, LOC + QString("Reset(%1,%2,%3)")
241  .arg(Full).arg(ToAdjust).arg(ResetInternal));
242 
243  m_rwLock.lockForWrite();
244  m_posLock.lockForWrite();
245 
246  m_numFailures = 0;
247  m_commsError = false;
248  m_setSwitchToNext = false;
249 
250  m_writePos = 0;
251  m_readPos = (ToAdjust) ? (m_readPos - m_readAdjust) : 0;
252 
253  if (m_readPos != 0)
254  {
255  LOG(VB_GENERAL, LOG_ERR, LOC +
256  QString("MythMediaBuffer::Reset() nonzero readpos. toAdjust: %1 "
257  "readpos: %2 readAdjust: %3")
258  .arg(ToAdjust).arg(m_readPos).arg(m_readAdjust));
259  }
260 
261  m_readAdjust = 0;
262  m_readPos = (m_readPos < 0) ? 0 : m_readPos;
263 
264  if (Full)
266 
267  if (ResetInternal)
269 
270  m_generalWait.wakeAll();
271  m_posLock.unlock();
272  m_rwLock.unlock();
273 }
274 
280 {
281  LOG(VB_FILE, LOG_INFO, LOC + QString("UpdateRawBitrate(%1Kb)").arg(RawBitrate));
282 
283  // an audio only stream could be as low as 64Kb (DVB radio) and
284  // an MHEG only stream is likely to be reported as 0Kb
285  if (RawBitrate < 64)
286  {
287  LOG(VB_FILE, LOG_INFO, LOC + QString("Bitrate too low - setting to 64Kb"));
288  RawBitrate = 64;
289  }
290  else if (RawBitrate > 100000)
291  {
292  LOG(VB_FILE, LOG_INFO, LOC + QString("Bitrate too high - setting to 100Mb"));
293  RawBitrate = 100000;
294  }
295 
296  m_rwLock.lockForWrite();
297  m_rawBitrate = RawBitrate;
299  m_bitrateInitialized = true;
300  m_rwLock.unlock();
301 }
302 
307 void MythMediaBuffer::UpdatePlaySpeed(float PlaySpeed)
308 {
309  m_rwLock.lockForWrite();
310  m_playSpeed = PlaySpeed;
312  m_rwLock.unlock();
313 }
314 
316 {
317  m_bitrateMonitorEnabled = Enable;
318 }
319 
321 {
322  m_waitForWrite = true;
323 }
324 
330 void MythMediaBuffer::SetBufferSizeFactors(bool EstBitrate, bool Matroska)
331 {
332  m_rwLock.lockForWrite();
333  m_unknownBitrate = EstBitrate;
334  m_fileIsMatroska = Matroska;
335  m_rwLock.unlock();
337 }
338 
339 static inline uint estbitrate_to_rbs(uint estbitrate)
340 {
341  if (estbitrate > 18000)
342  return 512*1024;
343  if (estbitrate > 9000)
344  return 256*1024;
345  if (estbitrate > 5000)
346  return 128*1024;
347  if (estbitrate > 2500)
348  return 64*1024;
349  if (estbitrate > 1250)
350  return 32*1024;
351  if (estbitrate >= 500)
352  return 16*1024;
353  if (estbitrate > 250)
354  return 8*1024;
355  if (estbitrate > 125)
356  return 4*1024;
357  return 2*1024;
358 }
359 
368 {
369  uint estbitrate = 0;
370 
371  m_readsAllowed = false;
372  m_readsDesired = false;
373 
374  // loop without sleeping if the buffered data is less than this
375  m_fillThreshold = 7 * m_bufferSize / 8;
376 
377  estbitrate = static_cast<uint>(std::max(abs(m_rawBitrate * m_playSpeed), 0.5F * m_rawBitrate));
378  estbitrate = std::min(m_rawBitrate * 3, estbitrate);
379  int const rbs = estbitrate_to_rbs(estbitrate);
380 
381  if (rbs < DEFAULT_CHUNK_SIZE)
382  m_readBlockSize = rbs;
383  else
384  m_readBlockSize = m_bitrateInitialized ? std::max(rbs, m_readBlockSize) : rbs;
385 
386  // minimum seconds of buffering before allowing read
387  float secs_min = 0.3F;
388  // set the minimum buffering before allowing ffmpeg read
389  m_fillMin = static_cast<int>((estbitrate * 1000 * secs_min) * 0.125F);
390  // make this a multiple of ffmpeg block size..
392  {
393  if (m_lowBuffers)
394  LOG(VB_GENERAL, LOG_INFO, LOC + "Buffering optimisations disabled.");
395  m_lowBuffers = false;
397  m_fillMin = std::min(m_fillMin, static_cast<int>(m_bufferSize / 2));
398  }
399  else
400  {
401  m_lowBuffers = true;
402  LOG(VB_GENERAL, LOG_WARNING, "Enabling buffering optimisations for low bitrate stream.");
403  }
404 
405  LOG(VB_FILE, LOG_INFO, LOC +
406  QString("CalcReadAheadThresh(%1 Kb)\n\t\t\t -> "
407  "threshold(%2 KB) min read(%3 KB) blk size(%4 KB)")
408  .arg(estbitrate).arg(m_fillThreshold/1024)
409  .arg(m_fillMin/1024).arg(m_readBlockSize/1024));
410 }
411 
412 bool MythMediaBuffer::IsNearEnd(double /*Framerate*/, uint Frames) const
413 {
414  QReadLocker lock(&m_rwLock);
415 
416  // file is still being read, so can't be finished
417  if (!m_ateof && !m_setSwitchToNext)
418  return false;
419 
420  m_posLock.lockForRead();
421  long long readpos = m_readPos;
422  long long size = m_internalReadPos - m_readPos;
423  m_posLock.unlock();
424 
425  // telecom kilobytes (i.e. 1000 per k not 1024)
426  uint tmp = static_cast<uint>(std::max(abs(m_rawBitrate * m_playSpeed), 0.5F * m_rawBitrate));
427  uint kbitspersec = std::min(m_rawBitrate * 3, tmp);
428  if (kbitspersec == 0)
429  return false;
430 
431  double readahead_time = size / (kbitspersec * (1000.0 / 8.0));
432 
433  bool near_end = readahead_time <= 1.5;
434  LOG(VB_PLAYBACK, LOG_INFO, LOC + "IsReallyNearEnd()" +
435  QString(" br(%1KB)").arg(kbitspersec/8) +
436  QString(" sz(%1KB)").arg(size / 1000LL) +
437  QString(" vfl(%1)").arg(Frames) +
438  QString(" time(%1)").arg(readahead_time) +
439  QString(" rawbitrate(%1)").arg(m_rawBitrate) +
440  QString(" avail(%1)").arg(size) +
441  QString(" internal_size(%1)").arg(m_internalReadPos) +
442  QString(" readposition(%1)").arg(readpos) +
443  QString(" stopreads(%1)").arg(m_stopReads) +
444  QString(" paused(%1)").arg(m_paused) +
445  QString(" ne:%1").arg(near_end));
446  return near_end;
447 }
448 
452 {
453  m_rbrLock.lockForRead();
454  m_rbwLock.lockForRead();
455  int ret = ((m_rbwPos >= m_rbrPos) ? m_rbrPos + static_cast<int>(m_bufferSize) : m_rbrPos) - m_rbwPos - 1;
456  m_rbwLock.unlock();
457  m_rbrLock.unlock();
458  return ret;
459 }
460 
463 {
464  QReadLocker lock(&m_rwLock);
465  return ReadBufAvail();
466 }
467 
468 long long MythMediaBuffer::GetRealFileSize(void) const
469 {
470  {
471  QReadLocker lock(&m_rwLock);
472  if (m_readInternalMode)
473  return ReadBufAvail();
474  }
475 
476  return GetRealFileSizeInternal();
477 }
478 
479 long long MythMediaBuffer::Seek(long long Position, int Whence, bool HasLock)
480 {
481  LOG(VB_FILE, LOG_INFO, LOC + QString("Seek: Position:%1 Type: %2 Locked: %3)")
482  .arg(Position)
483  .arg((SEEK_SET == Whence) ? "SEEK_SET" : ((SEEK_CUR == Whence) ? "SEEK_CUR" : "SEEK_END"),
484  HasLock?"locked":"unlocked"));
485 
486  if (!HasLock)
487  m_rwLock.lockForWrite();
488 
489  long long ret = 0;
490 
491  if (m_readInternalMode)
492  {
493  m_posLock.lockForWrite();
494  // only valid for SEEK_SET & SEEK_CUR
495  switch (Whence)
496  {
497  case SEEK_SET:
498  m_readPos = Position;
499  break;
500  case SEEK_CUR:
501  m_readPos += Position;
502  break;
503  case SEEK_END:
504  m_readPos = ReadBufAvail() - Position;
505  break;
506  }
507  m_readOffset = static_cast<int>(m_readPos);
508  m_posLock.unlock();
509  ret = m_readPos;
510  }
511  else
512  {
513  ret = SeekInternal(Position, Whence);
514  }
515 
516  m_generalWait.wakeAll();
517 
518  if (!HasLock)
519  m_rwLock.unlock();
520  return ret;
521 }
522 
524 {
525  QWriteLocker lock(&m_rwLock);
526  bool old = m_readInternalMode;
527 
528  if (Mode == old)
529  return old;
530 
532 
533  if (!Mode)
534  {
535  // adjust real read position in ringbuffer
536  m_rbrLock.lockForWrite();
537  m_rbrPos = (m_rbrPos + m_readOffset) % static_cast<int>(m_bufferSize);
538  m_generalWait.wakeAll();
539  m_rbrLock.unlock();
540  // reset the read offset as we are exiting the internal read mode
541  m_readOffset = 0;
542  }
543 
544  LOG(VB_FILE, LOG_DEBUG, LOC + QString("SetReadInternalMode: %1").arg(Mode ? "on" : "off"));
545  return old;
546 }
547 
549 {
550  return m_readInternalMode;
551 }
552 
556 {
557  m_rbrLock.lockForRead();
558  m_rbwLock.lockForRead();
559  int ret = (m_rbwPos >= m_rbrPos) ? m_rbwPos - m_rbrPos : static_cast<int>(m_bufferSize) - m_rbrPos + m_rbwPos;
560  m_rbwLock.unlock();
561  m_rbrLock.unlock();
562  return ret;
563 }
564 
575 void MythMediaBuffer::ResetReadAhead(long long NewInternal)
576 {
577  LOG(VB_FILE, LOG_INFO, LOC + QString("ResetReadAhead(internalreadpos = %1->%2)")
578  .arg(m_internalReadPos).arg(NewInternal));
579 
580  m_readInternalMode = false;
581  m_readOffset = 0;
582 
583  m_rbrLock.lockForWrite();
584  m_rbwLock.lockForWrite();
585 
587 
588  m_rbrPos = 0;
589  m_rbwPos = 0;
590  m_internalReadPos = NewInternal;
591  m_ateof = false;
592  m_readsAllowed = false;
593  m_readsDesired = false;
594  m_recentSeek = true;
595  m_setSwitchToNext = false;
596 
597  m_generalWait.wakeAll();
598 
599  m_rbwLock.unlock();
600  m_rbrLock.unlock();
601 }
602 
618 {
619  bool dostart = true;
620 
621  m_rwLock.lockForWrite();
622  if (!m_startReadAhead)
623  {
624  dostart = false;
625  }
626  else if (m_writeMode)
627  {
628  LOG(VB_GENERAL, LOG_WARNING, LOC + "Not starting read ahead thread - write only RingBuffer");
629  dostart = false;
630  }
631  else if (m_readAheadRunning)
632  {
633  LOG(VB_GENERAL, LOG_WARNING, LOC + "Not starting read ahead thread - already running");
634  dostart = false;
635  }
636 
637  if (!dostart)
638  {
639  m_rwLock.unlock();
640  return;
641  }
642 
643  StartReads();
644  MThread::start();
646  m_generalWait.wait(&m_rwLock);
647  m_rwLock.unlock();
648 }
649 
654 {
655  while (isRunning())
656  {
657  m_rwLock.lockForWrite();
658  m_readAheadRunning = false;
659  StopReads();
660  m_generalWait.wakeAll();
661  m_rwLock.unlock();
662  MThread::wait(5s);
663  }
664 }
665 
670 {
671  LOG(VB_FILE, LOG_INFO, LOC + "StopReads()");
672  m_stopReads = true;
673  m_generalWait.wakeAll();
674 }
675 
680 {
681  LOG(VB_FILE, LOG_INFO, LOC + "StartReads()");
682  m_stopReads = false;
683  m_generalWait.wakeAll();
684 }
685 
691 {
692  LOG(VB_FILE, LOG_INFO, LOC + "Pausing read ahead thread");
693  StopReads();
694 
695  m_rwLock.lockForWrite();
696  m_requestPause = true;
697  m_rwLock.unlock();
698 }
699 
705 {
706  LOG(VB_FILE, LOG_INFO, LOC + "Unpausing readahead thread");
707  StartReads();
708 
709  m_rwLock.lockForWrite();
710  m_requestPause = false;
711  m_generalWait.wakeAll();
712  m_rwLock.unlock();
713 }
714 
719 {
720  MythTimer t;
721  t.start();
722 
723  m_rwLock.lockForRead();
725  {
726  m_generalWait.wait(&m_rwLock, 1000);
727  if (m_readAheadRunning && !m_paused && m_requestPause && t.elapsed() > 1s)
728  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Waited %1 ms for ringbuffer pause")
729  .arg(t.elapsed().count()));
730  }
731  m_rwLock.unlock();
732 }
733 
735 {
736  const uint timeout = 500; // ms
737 
738  if (m_requestPause)
739  {
740  if (!m_paused)
741  {
742  m_rwLock.unlock();
743  m_rwLock.lockForWrite();
744 
745  if (m_requestPause)
746  {
747  m_paused = true;
748  m_generalWait.wakeAll();
749  }
750 
751  m_rwLock.unlock();
752  m_rwLock.lockForRead();
753  }
754 
757  }
758 
759  if (!m_requestPause && m_paused)
760  {
761  m_rwLock.unlock();
762  m_rwLock.lockForWrite();
763 
764  if (!m_requestPause)
765  {
766  m_paused = false;
767  m_generalWait.wakeAll();
768  }
769 
770  m_rwLock.unlock();
771  m_rwLock.lockForRead();
772  }
773 
774  return m_requestPause || m_paused;
775 }
776 
778 {
779  m_rwLock.lockForWrite();
780  m_posLock.lockForWrite();
781 
782  uint oldsize = m_bufferSize;
783  uint newsize = BUFFER_SIZE_MINIMUM;
784  if (m_remotefile)
785  {
786  newsize *= BUFFER_FACTOR_NETWORK;
787  if (m_fileIsMatroska)
788  newsize *= BUFFER_FACTOR_MATROSKA;
789  if (m_unknownBitrate)
790  newsize *= BUFFER_FACTOR_BITRATE;
791  }
792 
793  // N.B. Don't try and make it smaller - bad things happen...
794  if (m_readAheadBuffer && (oldsize >= newsize))
795  {
796  m_posLock.unlock();
797  m_rwLock.unlock();
798  return;
799  }
800 
801  m_bufferSize = newsize;
802  if (m_readAheadBuffer)
803  {
804  char* newbuffer = new char[m_bufferSize + 1024];
805  memcpy(newbuffer, m_readAheadBuffer + m_rbwPos, oldsize - static_cast<uint>(m_rbwPos));
806  memcpy(newbuffer + (oldsize - static_cast<uint>(m_rbwPos)), m_readAheadBuffer, static_cast<uint>(m_rbwPos));
807  delete [] m_readAheadBuffer;
808  m_readAheadBuffer = newbuffer;
810  (m_rbrPos + static_cast<int>(oldsize) - m_rbwPos);
811  m_rbwPos = static_cast<int>(oldsize);
812  }
813  else
814  {
815  m_readAheadBuffer = new char[m_bufferSize + 1024];
816  }
818  m_posLock.unlock();
819  m_rwLock.unlock();
820 
821  LOG(VB_FILE, LOG_INFO, LOC + QString("Created readAheadBuffer: %1Mb")
822  .arg(newsize >> 20));
823 }
824 
826 {
827  RunProlog();
828 
829  // These variables are used to adjust the read block size
830  std::chrono::milliseconds readTimeAvg = 300ms;
831  bool ignoreForReadTiming = true;
832  int eofreads = 0;
833 
834  auto lastread = nowAsDuration<std::chrono::milliseconds>();
835 
837  m_rwLock.lockForWrite();
838  m_posLock.lockForWrite();
839  m_requestPause = false;
840  ResetReadAhead(0);
841  m_readAheadRunning = true;
842  m_reallyRunning = true;
843  m_generalWait.wakeAll();
844  m_posLock.unlock();
845  m_rwLock.unlock();
846 
847  // NOTE: this must loop at some point hold only
848  // a read lock on rwlock, so that other functions
849  // such as reset and seek can take priority.
850 
851  m_rwLock.lockForRead();
852 
853  LOG(VB_FILE, LOG_INFO, LOC + QString("Initial readblocksize %1K fillMin %2K")
854  .arg(m_readBlockSize/1024).arg(m_fillMin/1024));
855 
856  while (m_readAheadRunning)
857  {
858  m_rwLock.unlock();
859  bool isopened = IsOpen();
860  m_rwLock.lockForRead();
861 
862  if (!isopened)
863  {
864  LOG(VB_FILE, LOG_WARNING, LOC + QString("File not opened, terminating readahead thread"));
865  m_posLock.lockForWrite();
866  m_readAheadRunning = false;
867  m_generalWait.wakeAll();
868  m_posLock.unlock();
869  break;
870  }
871  if (PauseAndWait())
872  {
873  ignoreForReadTiming = true;
874  LOG(VB_FILE, LOG_DEBUG, LOC + "run: PauseAndWait Not reading continuing");
875  continue;
876  }
877 
878  long long totfree = ReadBufFree();
879 
880  const uint KB32 = 32*1024;
881  const int KB512 = 512*1024;
882  // These are conditions where we don't want to go through
883  // the loop if they are true.
884  if (((totfree < KB32) && m_readsAllowed) ||
886  {
887  ignoreForReadTiming |= (m_ignoreReadPos >= 0) || m_commsError || m_stopReads;
888  m_generalWait.wait(&m_rwLock, (m_stopReads) ? 50 : 1000);
889  LOG(VB_FILE, LOG_DEBUG, LOC +
890  QString("run: Not reading continuing: totfree(%1) "
891  "readsallowed(%2) ignorereadpos(%3) commserror(%4) "
892  "stopreads(%5)")
893  .arg(totfree).arg(m_readsAllowed).arg(m_ignoreReadPos)
894  .arg(m_commsError).arg(m_stopReads));
895  continue;
896  }
897 
898  // These are conditions where we want to sleep to allow
899  // other threads to do stuff.
901  {
902  ignoreForReadTiming = true;
903  m_generalWait.wait(&m_rwLock, 1000);
904  totfree = ReadBufFree();
905  }
906 
907  int readResult = -1;
908  if (totfree >= KB32 && !m_commsError && !m_ateof && !m_setSwitchToNext)
909  {
910  // limit the read size
911  if (m_readBlockSize > totfree)
912  totfree = (totfree / KB32) * KB32; // must be multiple of 32KB
913  else
914  totfree = m_readBlockSize;
915 
916  // adapt blocksize
917  auto now = nowAsDuration<std::chrono::milliseconds>();
918  if (!ignoreForReadTiming)
919  {
920  readTimeAvg = (readTimeAvg * 9 + (now - lastread)) / 10;
921 
922  if (readTimeAvg < 150ms &&
923  static_cast<uint>(m_readBlockSize) < (BUFFER_SIZE_MINIMUM >>2) &&
924  m_readBlockSize >= DEFAULT_CHUNK_SIZE /* low_buffers */ &&
925  m_readBlockSize <= KB512)
926  {
927  int old_block_size = m_readBlockSize;
930  m_readBlockSize = std::min(m_readBlockSize, KB512);
931  LOG(VB_FILE, LOG_INFO, LOC + QString("Avg read interval was %1 msec. "
932  "%2K -> %3K block size")
933  .arg(readTimeAvg.count()).arg(old_block_size/1024).arg(m_readBlockSize/1024));
934  readTimeAvg = 225ms;
935  }
936  else if (readTimeAvg > 300ms && m_readBlockSize > DEFAULT_CHUNK_SIZE)
937  {
939  LOG(VB_FILE, LOG_INFO, LOC +
940  QString("Avg read interval was %1 msec. %2K -> %3K block size")
941  .arg(readTimeAvg.count())
943  .arg(m_readBlockSize/1024));
944  readTimeAvg = 225ms;
945  }
946  }
947  lastread = now;
948 
949  m_rbwLock.lockForRead();
950  if (m_rbwPos + totfree > m_bufferSize)
951  {
952  totfree = m_bufferSize - static_cast<uint>(m_rbwPos);
953  LOG(VB_FILE, LOG_DEBUG, LOC + "Shrinking read, near end of buffer");
954  }
955 
956  if (m_internalReadPos == 0)
957  {
958  totfree = std::max(m_fillMin, m_readBlockSize);
959  LOG(VB_FILE, LOG_DEBUG, LOC + "Reading enough data to start playback");
960  }
961 
962  LOG(VB_FILE, LOG_DEBUG, LOC + QString("safe_read(...@%1, %2) -- begin")
963  .arg(m_rbwPos).arg(totfree));
964 
965  MythTimer sr_timer;
966  sr_timer.start();
967 
968  int rbwposcopy = m_rbwPos;
969 
970  // MythFileBuffer::SafeRead(RemoteFile*...) acquires poslock;
971  // so we need to unlock this here to preserve locking order.
972  m_rbwLock.unlock();
973 
974  readResult = SafeRead(m_readAheadBuffer + rbwposcopy, static_cast<uint>(totfree));
975 
976  int sr_elapsed = sr_timer.elapsed().count();
977  uint64_t bps = !sr_elapsed ? 1000000001 :
978  static_cast<uint64_t>((readResult * 8000.0) / static_cast<double>(sr_elapsed));
979  LOG(VB_FILE, LOG_DEBUG, LOC +
980  QString("safe_read(...@%1, %2) -> %3, took %4 ms %5 avg %6 ms")
981  .arg(rbwposcopy).arg(totfree).arg(readResult).arg(sr_elapsed)
982  .arg(QString("(%1Mbps)").arg(static_cast<double>(bps) / 1000000.0))
983  .arg(readTimeAvg.count()));
984  UpdateStorageRate(bps);
985 
986  if (readResult >= 0)
987  {
988  m_posLock.lockForWrite();
989  m_rbwLock.lockForWrite();
990 
991  if (rbwposcopy == m_rbwPos)
992  {
993  m_internalReadPos += readResult;
994  m_rbwPos = (m_rbwPos + readResult) % static_cast<int>(m_bufferSize);
995  LOG(VB_FILE, LOG_DEBUG, LOC + QString("rbwpos += %1K requested %2K in read")
996  .arg(readResult/1024,3).arg(totfree/1024,3));
997  }
998  m_numFailures = 0;
999 
1000  m_rbwLock.unlock();
1001  m_posLock.unlock();
1002 
1003  LOG(VB_FILE, LOG_DEBUG, LOC + QString("total read so far: %1 bytes")
1004  .arg(m_internalReadPos));
1005  }
1006  }
1007  else
1008  {
1009  LOG(VB_FILE, LOG_DEBUG, LOC +
1010  QString("We are not reading anything (totfree: %1 commserror:%2 ateof:%3 setswitchtonext:%4")
1011  .arg(totfree).arg(m_commsError).arg(m_ateof).arg(m_setSwitchToNext));
1012  }
1013 
1014  int used = static_cast<int>(m_bufferSize) - ReadBufFree();
1015  bool readsWereAllowed = m_readsAllowed;
1016 
1017  ignoreForReadTiming = (totfree < m_readBlockSize) || (readResult < totfree);
1018 
1019  if ((0 == readResult) || (m_numFailures > 5) ||
1020  (m_readsAllowed != (used >= 1 || m_ateof || m_setSwitchToNext || m_commsError)) ||
1022  {
1023  // If readpos changes while the lock is released
1024  // we should not handle the 0 read_return now.
1025  long long oldreadposition = m_readPos;
1026 
1027  m_rwLock.unlock();
1028  m_rwLock.lockForWrite();
1029 
1030  m_commsError |= (m_numFailures > 5);
1031 
1034 
1035  if ((0 == readResult) && (oldreadposition == m_readPos))
1036  {
1037  eofreads++;
1038  if (eofreads >= 3 && m_readBlockSize >= KB512)
1039  {
1040  // not reading anything
1043  }
1044 
1045  if (m_liveTVChain)
1046  {
1048  {
1049  // we receive new livetv chain element event
1050  // before we receive file closed for writing event
1051  // so don't need to test if file is closed for writing
1052  m_liveTVChain->SwitchToNext(true);
1053  m_setSwitchToNext = true;
1054  }
1056  {
1057  LOG(VB_FILE, LOG_DEBUG, LOC +
1058  QString("EOF encountered, but %1 still being written to")
1059  .arg(m_filename));
1060  // We reached EOF, but file still open for writing and
1061  // no next program in livetvchain
1062  // wait a little bit (60ms same wait as typical safe_read)
1063  m_generalWait.wait(&m_rwLock, 60);
1064  }
1065  }
1067  {
1068  LOG(VB_FILE, LOG_DEBUG, LOC +
1069  QString("EOF encountered, but %1 still being written to")
1070  .arg(m_filename));
1071  // We reached EOF, but file still open for writing,
1072  // typically active in-progress recording
1073  // wait a little bit (60ms same wait as typical safe_read)
1074  m_generalWait.wait(&m_rwLock, 60);
1075  m_beingWritten = true;
1076  }
1077  else
1078  {
1080  {
1081  LOG(VB_FILE, LOG_DEBUG, LOC + "Waiting for file to grow large enough to process.");
1082  m_generalWait.wait(&m_rwLock, 300);
1083  }
1084  else
1085  {
1086  LOG(VB_FILE, LOG_DEBUG, LOC + "setting ateof (readResult == 0)");
1087  m_ateof = true;
1088  }
1089  }
1090  }
1091 
1092  m_rwLock.unlock();
1093  m_rwLock.lockForRead();
1094  used = static_cast<int>(m_bufferSize) - ReadBufFree();
1095  }
1096  else
1097  {
1098  eofreads = 0;
1099  }
1100 
1101  LOG(VB_FILE, LOG_DEBUG, LOC + "@ end of read ahead loop");
1102 
1104  (m_wantToRead <= used && m_wantToRead > 0))
1105  {
1106  // To give other threads a good chance to handle these
1107  // conditions, even if they are only requesting a read lock
1108  // like us, yield (currently implemented with short usleep).
1109  m_generalWait.wakeAll();
1110  m_rwLock.unlock();
1111  std::this_thread::sleep_for(5ms);
1112  m_rwLock.lockForRead();
1113  }
1114  else
1115  {
1116  // yield if we have nothing to do...
1117  if (!m_requestPause && readsWereAllowed &&
1118  (used >= m_fillThreshold || m_ateof || m_setSwitchToNext))
1119  {
1120  m_generalWait.wait(&m_rwLock, 50);
1121  }
1122  else if (m_readsAllowed)
1123  {
1124  // if reads are allowed release the lock and yield so the
1125  // reader gets a chance to read before the buffer is full.
1126  m_generalWait.wakeAll();
1127  m_rwLock.unlock();
1128  std::this_thread::sleep_for(5ms);
1129  m_rwLock.lockForRead();
1130  }
1131  }
1132  }
1133 
1134  m_rwLock.unlock();
1135 
1136  m_rwLock.lockForWrite();
1137  m_rbrLock.lockForWrite();
1138  m_rbwLock.lockForWrite();
1139 
1140  delete [] m_readAheadBuffer;
1141 
1142  m_readAheadBuffer = nullptr;
1143  m_rbrPos = 0;
1144  m_rbwPos = 0;
1145  m_reallyRunning = false;
1146  m_readsAllowed = false;
1147  m_readsDesired = false;
1148 
1149  m_rbwLock.unlock();
1150  m_rbrLock.unlock();
1151  m_rwLock.unlock();
1152 
1153  LOG(VB_FILE, LOG_INFO, LOC + QString("Exiting readahead thread"));
1154 
1155  RunEpilog();
1156 }
1157 
1159 {
1160  m_rwLock.lockForWrite();
1161  m_posLock.lockForRead();
1163  long long readadjust = m_readAdjust;
1164  m_posLock.unlock();
1165  m_rwLock.unlock();
1166  return readadjust;
1167 }
1168 
1170 int MythMediaBuffer::Peek(void *Buffer, int Count)
1171 {
1172  int result = ReadPriv(Buffer, Count, true);
1173  if (result != Count)
1174  {
1175  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Peek requested %1 bytes but only have %2")
1176  .arg(Count).arg(result));
1177  }
1178  return result;
1179 }
1180 
1181 int MythMediaBuffer::Peek(std::vector<char>& Buffer)
1182 {
1183  return Peek(Buffer.data(), Buffer.size());
1184 };
1185 
1187 {
1188  // Wait up to 30000 ms for reads allowed (or readsdesired if post seek/open)
1190  m_recentSeek = false;
1191  std::chrono::milliseconds timeoutms = 30s;
1192  int count = 0;
1193  MythTimer timer;
1194  timer.start();
1195 
1196  while ((timer.elapsed() < timeoutms) && !check && !m_stopReads &&
1198  {
1199  std::chrono::milliseconds delta = clamp(timeoutms - timer.elapsed(), 10ms, 100ms);
1200  m_generalWait.wait(&m_rwLock, delta.count());
1201  if (!check && timer.elapsed() > 1s && (count % 100) == 0)
1202  LOG(VB_GENERAL, LOG_WARNING, LOC + "Taking too long to be allowed to read..");
1203  count++;
1204  }
1205 
1206  if (timer.elapsed() >= timeoutms)
1207  {
1208  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Took more than %1 seconds to be allowed to read, aborting.")
1209  .arg(duration_cast<std::chrono::seconds>(timeoutms).count()));
1210  return false;
1211  }
1212  return check;
1213 }
1214 
1215 int MythMediaBuffer::WaitForAvail(int Count, std::chrono::milliseconds Timeout)
1216 {
1217  int available = ReadBufAvail();
1218  if (available >= Count)
1219  return available;
1220 
1221  Count = (m_ateof && available < Count) ? available : Count;
1222 
1223  if (m_liveTVChain && m_setSwitchToNext && (available < Count))
1224  return available;
1225 
1226  // Make sure that if the read ahead thread is sleeping and
1227  // it should be reading that we start reading right away.
1228  if ((available < Count) && !m_stopReads && !m_requestPause && !m_commsError && m_readAheadRunning)
1229  m_generalWait.wakeAll();
1230 
1231  MythTimer timer;
1232  timer.start();
1233  while ((available < Count) && !m_stopReads && !m_requestPause && !m_commsError && m_readAheadRunning)
1234  {
1235  m_wantToRead = Count;
1236  std::chrono::milliseconds delta = clamp(Timeout - timer.elapsed(), 10ms, 250ms);
1237  m_generalWait.wait(&m_rwLock, delta.count());
1238  available = ReadBufAvail();
1239  if (m_ateof)
1240  break;
1241  if (m_lowBuffers && available >= m_fillMin)
1242  break;
1243  if (timer.elapsed() > Timeout)
1244  break;
1245  }
1246 
1247  m_wantToRead = 0;
1248  return available;
1249 }
1250 
1251 int MythMediaBuffer::ReadDirect(void *Buffer, int Count, bool Peek)
1252 {
1253  long long oldposition = 0;
1254  if (Peek)
1255  {
1256  m_posLock.lockForRead();
1257  oldposition = (m_ignoreReadPos >= 0) ? m_ignoreReadPos : m_readPos;
1258  m_posLock.unlock();
1259  }
1260 
1261  MythTimer timer;
1262  timer.start();
1263  int result = SafeRead(Buffer, static_cast<uint>(Count));
1264  int elapsed = timer.elapsed().count();
1265  uint64_t bps = !elapsed ? 1000000001 : static_cast<uint64_t>((result * 8000.0) / static_cast<double>(elapsed));
1266  UpdateStorageRate(bps);
1267 
1268  m_posLock.lockForWrite();
1269  if (m_ignoreReadPos >= 0 && result > 0)
1270  {
1271  if (Peek)
1272  {
1273  // seek should always succeed since we were at this position
1274  long long cur_pos = -1;
1275  if (m_remotefile)
1276  cur_pos = m_remotefile->Seek(oldposition, SEEK_SET);
1277  else if (m_fd2 >= 0)
1278  cur_pos = lseek64(m_fd2, oldposition, SEEK_SET);
1279  if (cur_pos < 0)
1280  {
1281  LOG(VB_FILE, LOG_ERR, LOC + "Seek failed repositioning to previous position");
1282  }
1283  }
1284  else
1285  {
1286  m_ignoreReadPos += result;
1287  }
1288  m_posLock.unlock();
1289  return result;
1290  }
1291  m_posLock.unlock();
1292 
1293  if (Peek && (result > 0))
1294  {
1295  if ((IsDVD() || IsBD()) && oldposition != 0)
1296  {
1297  LOG(VB_GENERAL, LOG_ERR, LOC +
1298  "DVD and Blu-Ray do not support arbitrary "
1299  "peeks except when read-ahead is enabled."
1300  "\n\t\t\tWill seek to beginning of video.");
1301  oldposition = 0;
1302  }
1303 
1304  long long newposition = Seek(oldposition, SEEK_SET, true);
1305 
1306  if (newposition != oldposition)
1307  {
1308  LOG(VB_GENERAL, LOG_ERR, LOC +
1309  QString("Peek() Failed to return from new position %1 to old position %2, now "
1310  "at position %3")
1311  .arg(oldposition - result).arg(oldposition).arg(newposition));
1312  }
1313  }
1314 
1315  return result;
1316 }
1317 
1326 int MythMediaBuffer::ReadPriv(void *Buffer, int Count, bool Peek)
1327 {
1328  QString desc = QString("ReadPriv(..%1, %2)").arg(Count).arg(Peek ? "peek" : "normal");
1329  LOG(VB_FILE, LOG_DEBUG, LOC + desc + QString(" @%1 -- begin").arg(m_rbrPos));
1330 
1331  m_rwLock.lockForRead();
1332  if (m_writeMode)
1333  {
1334  LOG(VB_GENERAL, LOG_ERR, LOC + desc + ": Attempt to read from a write only file");
1335  errno = EBADF;
1336  m_rwLock.unlock();
1337  return -1;
1338  }
1339 
1341  {
1342  m_rwLock.unlock();
1343  m_rwLock.lockForWrite();
1344  // we need a write lock so the read-ahead thread
1345  // can't start mucking with the read position.
1346  // If the read ahead thread was started while we
1347  // didn't hold the lock, we proceed with a normal
1348  // read from the buffer, otherwise we read directly.
1350  {
1351  int result = ReadDirect(Buffer, Count, Peek);
1352 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1353  quint16 checksum = qChecksum(reinterpret_cast<char*>(Buffer), static_cast<uint>(Count));
1354 #else
1355  QByteArrayView BufferView(reinterpret_cast<char*>(Buffer), Count);
1356  quint16 checksum = qChecksum(BufferView);
1357 #endif
1358  LOG(VB_FILE, LOG_DEBUG, LOC + desc + QString(": ReadDirect checksum %1")
1359  .arg(checksum));
1360  m_rwLock.unlock();
1361  return result;
1362  }
1363  m_rwLock.unlock();
1364  m_rwLock.lockForRead();
1365  }
1366 
1367  if (!WaitForReadsAllowed())
1368  {
1369  LOG(VB_FILE, LOG_NOTICE, LOC + desc + ": !WaitForReadsAllowed()");
1370  m_rwLock.unlock();
1371  m_stopReads = true; // this needs to be outside the lock
1372  m_rwLock.lockForWrite();
1373  m_wantToRead = 0;
1374  m_rwLock.unlock();
1375  return 0;
1376  }
1377 
1378  int available = ReadBufAvail();
1380 
1381  // Wait up to 10000 ms for any data
1382  std::chrono::milliseconds timeout_ms = 10s;
1383  while (!m_readInternalMode && !m_ateof && (timer.elapsed() < timeout_ms) && m_readAheadRunning &&
1385  {
1386  available = WaitForAvail(Count, std::min(timeout_ms - timer.elapsed(), 100ms));
1387  if (m_liveTVChain && m_setSwitchToNext && available < Count)
1388  {
1389  LOG(VB_GENERAL, LOG_INFO, LOC + "Checking to see if there's a new livetv program to switch to..");
1391  break;
1392  }
1393  if (available > 0)
1394  break;
1395  }
1396  if (timer.elapsed() > 6s)
1397  {
1398  LOG(VB_GENERAL, LOG_WARNING, LOC + desc + QString(" -- waited %1 ms for avail(%2) > count(%3)")
1399  .arg(timer.elapsed().count()).arg(available).arg(Count));
1400  }
1401 
1402  if (m_readInternalMode)
1403  {
1404  LOG(VB_FILE, LOG_DEBUG, LOC + QString("ReadPriv: %1 bytes available, %2 left")
1405  .arg(available).arg(available-m_readOffset));
1406  }
1407  Count = std::min(available - m_readOffset, Count);
1408 
1409  if ((Count <= 0) && (m_ateof || m_readInternalMode))
1410  {
1411  // If we're at the end of file return 0 bytes
1412  m_rwLock.unlock();
1413  return Count;
1414  }
1415 
1416  if (Count <= 0)
1417  {
1418  // If we're not at the end of file but have no data
1419  // at this point time out and shutdown read ahead.
1420  LOG(VB_GENERAL, LOG_ERR, LOC + desc + QString(" -- timed out waiting for data (%1 ms)")
1421  .arg(timer.elapsed().count()));
1422 
1423  m_rwLock.unlock();
1424  m_stopReads = true; // this needs to be outside the lock
1425  m_rwLock.lockForWrite();
1426  m_ateof = true;
1427  m_wantToRead = 0;
1428  m_generalWait.wakeAll();
1429  m_rwLock.unlock();
1430  return Count;
1431  }
1432 
1433  if (Peek || m_readInternalMode)
1434  m_rbrLock.lockForRead();
1435  else
1436  m_rbrLock.lockForWrite();
1437 
1438  LOG(VB_FILE, LOG_DEBUG, LOC + desc + ": Copying data");
1439 
1440  int readposition = 0;
1441  if (m_rbrPos + m_readOffset > static_cast<int>(m_bufferSize))
1442  readposition = (m_rbrPos + m_readOffset) - static_cast<int>(m_bufferSize);
1443  else
1444  readposition = m_rbrPos + m_readOffset;
1445 
1446  if (readposition + Count > static_cast<int>(m_bufferSize))
1447  {
1448  int firstsize = static_cast<int>(m_bufferSize) - readposition;
1449  int secondsize = Count - firstsize;
1450 
1451  memcpy(Buffer, m_readAheadBuffer + readposition, static_cast<size_t>(firstsize));
1452  memcpy(reinterpret_cast<char*>(Buffer) + firstsize, m_readAheadBuffer, static_cast<size_t>(secondsize));
1453  }
1454  else
1455  {
1456  memcpy(Buffer, m_readAheadBuffer + readposition, static_cast<uint>(Count));
1457  }
1458 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1459  quint16 checksum = qChecksum(reinterpret_cast<char*>(Buffer), static_cast<uint>(Count));
1460 #else
1461  QByteArrayView BufferView(reinterpret_cast<char*>(Buffer), Count);
1462  quint16 checksum = qChecksum(BufferView);
1463 #endif
1464  LOG(VB_FILE, LOG_DEBUG, LOC + desc + QString(": Checksum %1").arg(checksum));
1465 
1466  if (!Peek)
1467  {
1468  if (m_readInternalMode)
1469  {
1470  m_readOffset += Count;
1471  }
1472  else
1473  {
1474  m_rbrPos = (m_rbrPos + Count) % static_cast<int>(m_bufferSize);
1475  m_generalWait.wakeAll();
1476  }
1477  }
1478  m_rbrLock.unlock();
1479  m_rwLock.unlock();
1480 
1481  return Count;
1482 }
1483 
1492 int MythMediaBuffer::Read(void *Buffer, int Count)
1493 {
1494  int ret = ReadPriv(Buffer, Count, false);
1495  if (ret > 0)
1496  {
1497  m_posLock.lockForWrite();
1498  m_readPos += ret;
1499  m_posLock.unlock();
1500  UpdateDecoderRate(static_cast<uint64_t>(ret));
1501  }
1502 
1503  return ret;
1504 }
1505 
1506 QString MythMediaBuffer::BitrateToString(uint64_t Rate, bool Hz)
1507 {
1508  if (Rate < 1)
1509  return "-";
1510 
1511  if (Rate > 1000000000)
1512  return QObject::tr(">1Gbps");
1513 
1514  QString msg;
1515  auto bitrate = static_cast<double>(NAN);
1516  auto rate = static_cast<double>(Rate);
1517  int range = 0;
1518 
1519  if (Rate >= 1000000)
1520  {
1521  msg = Hz ? QObject::tr("%1MHz") : QObject::tr("%1Mbps");
1522  bitrate = rate / 1000000.0;
1523  range = Hz ? 3 : 1;
1524  }
1525  else if (Rate >= 1000)
1526  {
1527  msg = Hz ? QObject::tr("%1kHz") : QObject::tr("%1kbps");
1528  bitrate = rate / 1000.0;
1529  range = Hz ? 1 : 0;
1530  }
1531  else
1532  {
1533  msg = Hz ? QObject::tr("%1Hz") : QObject::tr("%1bps");
1534  bitrate = rate;
1535  }
1536  return msg.arg(bitrate, 0, 'f', range);
1537 }
1538 
1540 {
1542 }
1543 
1545 {
1547 }
1548 
1550 {
1552  return "N/A";
1553 
1554  int avail = (m_rbwPos >= m_rbrPos) ? m_rbwPos - m_rbrPos
1555  : static_cast<int>(m_bufferSize) - m_rbrPos + m_rbwPos;
1556  return QString("%1%").arg(lroundf((static_cast<float>(avail) / static_cast<float>(m_bufferSize) * 100.0F)));
1557 }
1558 
1560 {
1561  return m_bufferSize;
1562 }
1563 
1564 uint64_t MythMediaBuffer::UpdateDecoderRate(uint64_t Latest)
1565 {
1567  return 0;
1568 
1569  auto current = std::chrono::milliseconds(QDateTime::currentMSecsSinceEpoch());
1570  std::chrono::milliseconds expire = current - 1s;
1571 
1572  m_decoderReadLock.lock();
1573  if (Latest)
1574  m_decoderReads.insert(current, Latest);
1575  uint64_t total = 0;
1576  QMutableMapIterator<std::chrono::milliseconds,uint64_t> it(m_decoderReads);
1577  while (it.hasNext())
1578  {
1579  it.next();
1580  if (it.key() < expire || it.key() > current)
1581  it.remove();
1582  else
1583  total += it.value();
1584  }
1585 
1586  int size = m_decoderReads.size();
1587  m_decoderReadLock.unlock();
1588 
1589  auto average = static_cast<uint64_t>(static_cast<double>(total) * 8.0);
1590  LOG(VB_FILE, LOG_INFO, LOC + QString("Decoder read speed: %1 %2")
1591  .arg(average).arg(size));
1592  return average;
1593 }
1594 
1595 uint64_t MythMediaBuffer::UpdateStorageRate(uint64_t Latest)
1596 {
1598  return 0;
1599 
1600  auto current = std::chrono::milliseconds(QDateTime::currentMSecsSinceEpoch());
1601  auto expire = current - 1s;
1602 
1603  m_storageReadLock.lock();
1604  if (Latest)
1605  m_storageReads.insert(current, Latest);
1606  uint64_t total = 0;
1607  QMutableMapIterator<std::chrono::milliseconds,uint64_t> it(m_storageReads);
1608  while (it.hasNext())
1609  {
1610  it.next();
1611  if (it.key() < expire || it.key() > current)
1612  it.remove();
1613  else
1614  total += it.value();
1615  }
1616 
1617  int size = m_storageReads.size();
1618  m_storageReadLock.unlock();
1619 
1620  uint64_t average = size ? static_cast<uint64_t>(static_cast<double>(total) / size) : 0;
1621  LOG(VB_FILE, LOG_INFO, LOC + QString("Average storage read speed: %1 (Reads %2")
1622  .arg(average).arg(m_storageReads.size()));
1623  return average;
1624 }
1625 
1630 int MythMediaBuffer::Write(const void *Buffer, uint Count)
1631 {
1632  m_rwLock.lockForRead();
1633  int result = -1;
1634 
1635  if (!m_writeMode)
1636  {
1637  LOG(VB_GENERAL, LOG_ERR, LOC + "Tried to write to a read only file.");
1638  m_rwLock.unlock();
1639  return result;
1640  }
1641 
1642  if (!m_tfw && !m_remotefile)
1643  {
1644  m_rwLock.unlock();
1645  return result;
1646  }
1647 
1648  if (m_tfw)
1649  result = m_tfw->Write(Buffer, Count);
1650  else
1651  result = m_remotefile->Write(Buffer, static_cast<int>(Count));
1652 
1653  if (result > 0)
1654  {
1655  m_posLock.lockForWrite();
1656  m_writePos += result;
1657  m_posLock.unlock();
1658  }
1659 
1660  m_rwLock.unlock();
1661  return result;
1662 }
1663 
1668 {
1669  m_rwLock.lockForRead();
1670  if (m_tfw)
1671  m_tfw->Sync();
1672  m_rwLock.unlock();
1673 }
1674 
1677 long long MythMediaBuffer::WriterSeek(long long Position, int Whence, bool HasLock)
1678 {
1679  long long result = -1;
1680 
1681  if (!HasLock)
1682  m_rwLock.lockForRead();
1683 
1684  m_posLock.lockForWrite();
1685 
1686  if (m_tfw)
1687  {
1688  result = m_tfw->Seek(Position, Whence);
1689  m_writePos = result;
1690  }
1691 
1692  m_posLock.unlock();
1693 
1694  if (!HasLock)
1695  m_rwLock.unlock();
1696 
1697  return result;
1698 }
1699 
1704 {
1705  m_rwLock.lockForRead();
1706  if (m_tfw)
1707  m_tfw->Flush();
1708  m_rwLock.unlock();
1709 }
1710 
1715 {
1716  QReadLocker lock(&m_rwLock);
1717  if (m_tfw)
1718  return m_tfw->SetBlocking(Lock);
1719  return false;
1720 }
1721 
1738 {
1739  LOG(VB_FILE, LOG_INFO, LOC + QString("SetOldFile: %1)").arg(Old));
1740  m_rwLock.lockForWrite();
1741  m_oldfile = Old;
1742  m_rwLock.unlock();
1743 }
1744 
1745 QString MythMediaBuffer::GetFilename(void) const
1746 {
1747  m_rwLock.lockForRead();
1748  QString tmp = m_filename;
1749  m_rwLock.unlock();
1750  return tmp;
1751 }
1752 
1754 {
1755  return m_safeFilename;
1756 }
1757 
1759 {
1760  m_rwLock.lockForRead();
1761  QString tmp = m_subtitleFilename;
1762  m_rwLock.unlock();
1763  return tmp;
1764 }
1765 
1767 {
1768  m_rwLock.lockForRead();
1769  QString tmp = m_lastError;
1770  m_rwLock.unlock();
1771  return tmp;
1772 }
1773 
1775 {
1776  return m_commsError;
1777 }
1778 
1780 {
1781  m_commsError = false;
1782 }
1783 
1785 {
1786  return m_stopReads;
1787 }
1788 
1793 {
1794  m_posLock.lockForRead();
1795  long long ret = m_writePos;
1796  m_posLock.unlock();
1797  return ret;
1798 }
1799 
1805 {
1806  m_rwLock.lockForRead();
1807  bool ret = (m_liveTVChain);
1808  m_rwLock.unlock();
1809  return ret;
1810 }
1811 
1817 {
1818  m_rwLock.lockForWrite();
1819  m_liveTVChain = Chain;
1820  m_rwLock.unlock();
1821 }
1822 
1825 {
1826  m_rwLock.lockForWrite();
1827  m_ignoreLiveEOF = Ignore;
1828  m_rwLock.unlock();
1829 }
1830 
1831 bool MythMediaBuffer::IsDisc(void) const
1832 {
1833  return IsDVD() || IsBD();
1834 }
1835 
1836 bool MythMediaBuffer::IsDVD(void) const
1837 {
1838  return m_type == kMythBufferDVD;
1839 }
1840 
1841 bool MythMediaBuffer::IsBD(void) const
1842 {
1843  return m_type == kMythBufferBD;
1844 }
1845 
1847 {
1848  return dynamic_cast<const MythDVDBuffer*>(this);
1849 }
1850 
1852 {
1853  return dynamic_cast<const MythBDBuffer*>(this);
1854 }
1855 
1857 {
1858  return dynamic_cast<MythDVDBuffer*>(this);
1859 }
1860 
1862 {
1863  return dynamic_cast<MythBDBuffer*>(this);
1864 }
1865 
1867 {
1868  static QRecursiveMutex s_avnetworkLock;
1869  static bool s_avnetworkInitialised = false;
1870  QMutexLocker lock(&s_avnetworkLock);
1871  if (!s_avnetworkInitialised)
1872  {
1873  avformat_network_init();
1874  s_avnetworkInitialised = true;
1875  }
1876 }
mythdvdstream.h
MythMediaBuffer::BD
const MythBDBuffer * BD(void) const
Definition: mythmediabuffer.cpp:1851
kMythBufferDVD
@ kMythBufferDVD
Definition: mythmediabuffer.h:52
MythTimer::elapsed
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
MythMediaBuffer::SafeRead
virtual int SafeRead(void *Buffer, uint Size)=0
ThreadedFileWriter::Seek
long long Seek(long long pos, int whence)
Seek to a position within stream; May be unsafe.
Definition: threadedfilewriter.cpp:297
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
MythMediaBuffer::m_tfw
ThreadedFileWriter * m_tfw
Definition: mythmediabuffer.h:196
MythMediaBuffer::SetBufferSizeFactors
void SetBufferSizeFactors(bool EstBitrate, bool Matroska)
Tells RingBuffer that the raw bitrate may be inaccurate and the underlying container is matroska,...
Definition: mythmediabuffer.cpp:330
MythMediaBuffer::PauseAndWait
bool PauseAndWait(void)
Definition: mythmediabuffer.cpp:734
ThreadedFileWriter::Sync
void Sync(void) const
Flush data written to the file descriptor to disk.
Definition: threadedfilewriter.cpp:355
MythMediaBuffer::m_rbrPos
int m_rbrPos
Definition: mythmediabuffer.h:180
MythMediaBuffer::m_readAdjust
long long m_readAdjust
Definition: mythmediabuffer.h:228
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
LiveTVChain::HasNext
bool HasNext(void) const
Definition: livetvchain.cpp:406
MythMediaBuffer::m_startReadAhead
bool m_startReadAhead
Definition: mythmediabuffer.h:204
HLSRingBuffer::TestForHTTPLiveStreaming
static bool TestForHTTPLiveStreaming(const QString &filename)
Definition: httplivestreambuffer.cpp:1713
MythMediaBuffer::Seek
long long Seek(long long Position, int Whence, bool HasLock=false)
Definition: mythmediabuffer.cpp:479
RemoteFile::Exists
static bool Exists(const QString &url, struct stat *fileinfo)
Definition: remotefile.cpp:460
MythMediaBuffer::StopReads
void StopReads(void)
Definition: mythmediabuffer.cpp:669
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
MythMediaBuffer::UpdatePlaySpeed
void UpdatePlaySpeed(float PlaySpeed)
Set the play speed, to allow RingBuffer adjust effective bitrate.
Definition: mythmediabuffer.cpp:307
MythMediaBuffer::m_commsError
bool m_commsError
Definition: mythmediabuffer.h:224
MythMediaBuffer::m_oldfile
bool m_oldfile
Definition: mythmediabuffer.h:225
MythMediaBuffer::EnableBitrateMonitor
void EnableBitrateMonitor(bool Enable)
Definition: mythmediabuffer.cpp:315
mythcdrom.h
MythMediaBuffer::WriterSetBlocking
bool WriterSetBlocking(bool Lock=true)
Calls ThreadedFileWriter::SetBlocking(bool)
Definition: mythmediabuffer.cpp:1714
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1792
MythMediaBuffer::m_fd2
int m_fd2
Definition: mythmediabuffer.h:197
MythMediaBuffer::m_safeFilename
QString m_safeFilename
Definition: mythmediabuffer.h:190
MythMediaBuffer::GetDecoderRate
QString GetDecoderRate(void)
Definition: mythmediabuffer.cpp:1539
MythMediaBuffer::CalcReadAheadThresh
void CalcReadAheadThresh(void)
Calculates m_fillMin, m_fillThreshold, and m_readBlockSize from the estimated effective bitrate of th...
Definition: mythmediabuffer.cpp:367
mythdvdbuffer.h
xbmcvfs.exists
bool exists(str path)
Definition: xbmcvfs.py:51
MythMediaBuffer::m_type
MythBufferType m_type
Definition: mythmediabuffer.h:171
MythMediaBuffer::ReadDirect
int ReadDirect(void *Buffer, int Count, bool Peek)
Definition: mythmediabuffer.cpp:1251
MythMediaBuffer::Write
int Write(const void *Buffer, uint Count)
Writes buffer to ThreadedFileWriter::Write(const void*,uint)
Definition: mythmediabuffer.cpp:1630
MythMediaBuffer::m_readOffset
int m_readOffset
Definition: mythmediabuffer.h:229
ThreadedFileWriter::Flush
void Flush(void)
Allow DiskLoop() to flush buffer completely ignoring low watermark.
Definition: threadedfilewriter.cpp:318
MythMediaBuffer
Definition: mythmediabuffer.h:59
MythMediaBuffer::IsDVD
bool IsDVD(void) const
Definition: mythmediabuffer.cpp:1836
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
MythMediaBuffer::Unpause
void Unpause(void)
Unpauses the read-ahead thread. Calls StartReads(void).
Definition: mythmediabuffer.cpp:704
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
MythMediaBuffer::GetSafeFilename
QString GetSafeFilename(void)
Definition: mythmediabuffer.cpp:1753
MythMediaBuffer::GetReadBufAvail
int GetReadBufAvail(void) const
Returns number of bytes available for reading from buffer.
Definition: mythmediabuffer.cpp:462
MythMediaBuffer::m_lastError
QString m_lastError
Definition: mythmediabuffer.h:195
MythMediaBuffer::m_generalWait
QWaitCondition m_generalWait
Condition to signal that the read ahead thread is running.
Definition: mythmediabuffer.h:246
RemoteFile::Write
int Write(const void *data, int size)
Definition: remotefile.cpp:835
MythMediaBuffer::ReadBufFree
int ReadBufFree(void) const
Returns number of bytes available for reading into buffer.
Definition: mythmediabuffer.cpp:451
MythMediaBuffer::IsBD
bool IsBD(void) const
Definition: mythmediabuffer.cpp:1841
MythMediaBuffer::SetAdjustFilesize
long long SetAdjustFilesize(void)
Definition: mythmediabuffer.cpp:1158
MythMediaBuffer::WaitForReadsAllowed
bool WaitForReadsAllowed(void)
Definition: mythmediabuffer.cpp:1186
MythMediaBuffer::UpdateRawBitrate
void UpdateRawBitrate(uint RawBitrate)
Set the raw bit rate, to allow RingBuffer adjust effective bitrate.
Definition: mythmediabuffer.cpp:279
LOC
#define LOC
Definition: mythmediabuffer.cpp:45
MythMediaBuffer::BitrateToString
static QString BitrateToString(uint64_t Rate, bool Hz=false)
Definition: mythmediabuffer.cpp:1506
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
MythMediaBuffer::m_paused
bool m_paused
Definition: mythmediabuffer.h:209
MythMediaBuffer::m_decoderReadLock
QMutex m_decoderReadLock
Definition: mythmediabuffer.h:234
MythMediaBuffer::m_readsAllowed
bool m_readsAllowed
Definition: mythmediabuffer.h:213
MythMediaBuffer::GetStopReads
bool GetStopReads(void) const
Definition: mythmediabuffer.cpp:1784
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
MythMediaBuffer::GetBufferSize
uint GetBufferSize(void) const
Definition: mythmediabuffer.cpp:1559
BUFFER_FACTOR_NETWORK
static constexpr uint8_t BUFFER_FACTOR_NETWORK
Definition: mythmediabuffer.h:27
MythMediaBuffer::WaitForAvail
int WaitForAvail(int Count, std::chrono::milliseconds Timeout)
Definition: mythmediabuffer.cpp:1215
MythMediaBuffer::m_rawBitrate
uint m_rawBitrate
Definition: mythmediabuffer.h:217
MythMediaBuffer::ReadPriv
int ReadPriv(void *Buffer, int Count, bool Peek)
When possible reads from the read-ahead buffer, otherwise reads directly from the device.
Definition: mythmediabuffer.cpp:1326
MythMediaBuffer::m_liveTVChain
LiveTVChain * m_liveTVChain
Definition: mythmediabuffer.h:226
MythCoreContext::IsRegisteredFileForWrite
bool IsRegisteredFileForWrite(const QString &file)
Definition: mythcorecontext.cpp:2165
MythMediaBuffer::GetFilename
QString GetFilename(void) const
Definition: mythmediabuffer.cpp:1745
MythMediaBuffer::GetRealFileSize
long long GetRealFileSize(void) const
Definition: mythmediabuffer.cpp:468
MythMediaBuffer::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: mythmediabuffer.cpp:825
threadedfilewriter.h
mythdate.h
MythMediaBuffer::SetOldFile
void SetOldFile(bool Old)
Tell RingBuffer if this is an old file or not.
Definition: mythmediabuffer.cpp:1737
MythMediaBuffer::m_readPos
long long m_readPos
Definition: mythmediabuffer.h:174
MythMediaBuffer::m_beingWritten
bool m_beingWritten
Definition: mythmediabuffer.h:212
MythDVDStream
Definition: mythdvdstream.h:19
mythlogging.h
MythMediaBuffer::SeekInternal
virtual long long SeekInternal(long long Position, int Whence)=0
RemoteFile::Seek
long long Seek(long long pos, int whence, long long curpos=-1)
Definition: remotefile.cpp:758
MythMediaBuffer::WaitForPause
void WaitForPause(void)
Waits for Pause(void) to take effect.
Definition: mythmediabuffer.cpp:718
remotefile.h
MythMediaBuffer::WriterSeek
long long WriterSeek(long long Position, int Whence, bool HasLock=false)
Calls ThreadedFileWriter::Seek(long long,int).
Definition: mythmediabuffer.cpp:1677
MythCDROM::kBluray
@ kBluray
Definition: mythcdrom.h:29
MythMediaBuffer::m_requestPause
bool m_requestPause
Definition: mythmediabuffer.h:208
hardwareprofile.i18n.t
t
Definition: i18n.py:36
MythMediaBuffer::m_readInternalMode
bool m_readInternalMode
Definition: mythmediabuffer.h:230
compat.h
MythMediaBuffer::~MythMediaBuffer
~MythMediaBuffer() override=0
Deletes.
Definition: mythmediabuffer.cpp:219
MythMediaBuffer::GetSubtitleFilename
QString GetSubtitleFilename(void) const
Definition: mythmediabuffer.cpp:1758
MythMediaBuffer::m_remotefile
RemoteFile * m_remotefile
Definition: mythmediabuffer.h:199
MythMediaBuffer::UpdateStorageRate
uint64_t UpdateStorageRate(uint64_t Latest=0)
Definition: mythmediabuffer.cpp:1595
MythMediaBuffer::ResetCommsError
void ResetCommsError(void)
Definition: mythmediabuffer.cpp:1779
MythMediaBuffer::m_decoderReads
QMap< std::chrono::milliseconds, uint64_t > m_decoderReads
Definition: mythmediabuffer.h:235
HLSRingBuffer
Definition: httplivestreambuffer.h:43
MythMediaBuffer::m_writePos
long long m_writePos
Definition: mythmediabuffer.h:175
MythMediaBuffer::m_readBlockSize
int m_readBlockSize
Definition: mythmediabuffer.h:221
MythMediaBuffer::m_rbwLock
QReadWriteLock m_rbwLock
Definition: mythmediabuffer.h:182
MythMediaBuffer::GetCommsError
bool GetCommsError(void) const
Definition: mythmediabuffer.cpp:1774
MythMediaBuffer::m_waitForWrite
bool m_waitForWrite
Definition: mythmediabuffer.h:211
MythBDBuffer
Definition: mythbdbuffer.h:19
MythMediaBuffer::m_setSwitchToNext
bool m_setSwitchToNext
Definition: mythmediabuffer.h:216
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
MythMediaBuffer::m_readAheadBuffer
char * m_readAheadBuffer
Definition: mythmediabuffer.h:205
BUFFER_FACTOR_BITRATE
static constexpr uint8_t BUFFER_FACTOR_BITRATE
Definition: mythmediabuffer.h:28
LiveTVChain::ReloadAll
void ReloadAll(const QStringList &data=QStringList())
Definition: livetvchain.cpp:212
MythMediaBuffer::m_numFailures
int m_numFailures
Definition: mythmediabuffer.h:223
MythMediaBuffer::m_bufferSize
uint m_bufferSize
Definition: mythmediabuffer.h:200
MythMediaBuffer::LiveMode
bool LiveMode(void) const
Returns true if this RingBuffer has been assigned a LiveTVChain.
Definition: mythmediabuffer.cpp:1804
MythMediaBuffer::m_lowBuffers
bool m_lowBuffers
Definition: mythmediabuffer.h:201
MythMediaBuffer::m_fillThreshold
int m_fillThreshold
Definition: mythmediabuffer.h:219
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
clamp
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:204
MythMediaBuffer::m_filename
QString m_filename
Definition: mythmediabuffer.h:193
BUFFER_FACTOR_MATROSKA
static constexpr uint8_t BUFFER_FACTOR_MATROSKA
Definition: mythmediabuffer.h:29
MythMediaBuffer::CreateReadAheadBuffer
void CreateReadAheadBuffer(void)
Definition: mythmediabuffer.cpp:777
MythBufferType
MythBufferType
Definition: mythmediabuffer.h:48
mythmediabuffer.h
MythFileBuffer
Definition: mythfilebuffer.h:7
MythMediaBuffer::IgnoreLiveEOF
void IgnoreLiveEOF(bool Ignore)
Tells RingBuffer whether to ignore the end-of-file.
Definition: mythmediabuffer.cpp:1824
ThreadedFileWriter::Write
int Write(const void *data, uint count)
Writes data to the end of the write buffer.
Definition: threadedfilewriter.cpp:190
estbitrate_to_rbs
static uint estbitrate_to_rbs(uint estbitrate)
Definition: mythmediabuffer.cpp:339
MythMediaBuffer::Read
int Read(void *Buffer, int Count)
This is the public method for reading from a file, it calls the appropriate read method if the file i...
Definition: mythmediabuffer.cpp:1492
MythCDROM::inspectImage
static ImageType inspectImage(const QString &path)
Definition: mythcdrom.cpp:188
MythMediaBuffer::IsReadInternalMode
bool IsReadInternalMode(void) const
Definition: mythmediabuffer.cpp:548
MythMediaBuffer::m_rbrLock
QReadWriteLock m_rbrLock
Definition: mythmediabuffer.h:179
MythMediaBuffer::m_readsDesired
bool m_readsDesired
Definition: mythmediabuffer.h:214
MythMediaBuffer::WriterFlush
void WriterFlush(void)
Calls ThreadedFileWriter::Flush(void)
Definition: mythmediabuffer.cpp:1703
mythbdbuffer.h
MythMediaBuffer::KillReadAheadThread
void KillReadAheadThread(void)
Stops the read-ahead thread, and waits for it to stop.
Definition: mythmediabuffer.cpp:653
MythMediaBuffer::AVFormatInitNetwork
static void AVFormatInitNetwork(void)
Definition: mythmediabuffer.cpp:1866
livetvchain.h
MythMediaBuffer::m_playSpeed
float m_playSpeed
Definition: mythmediabuffer.h:218
Buffer
Definition: MythExternControl.h:36
MythMediaBuffer::m_recentSeek
volatile bool m_recentSeek
Definition: mythmediabuffer.h:215
MythMediaBuffer::m_ignoreLiveEOF
bool m_ignoreLiveEOF
Definition: mythmediabuffer.h:227
MythMediaBuffer::m_storageReadLock
QMutex m_storageReadLock
Definition: mythmediabuffer.h:236
assert
#define assert(x)
Definition: audiooutputalsa.cpp:16
mythmiscutil.h
MythMediaBuffer::m_unknownBitrate
bool m_unknownBitrate
Definition: mythmediabuffer.h:203
MythMediaBuffer::ResetReadAhead
void ResetReadAhead(long long NewInternal)
Restart the read-ahead thread at the 'newinternal' position.
Definition: mythmediabuffer.cpp:575
MythMediaBuffer::MythMediaBuffer
MythMediaBuffer(MythBufferType Type)
Definition: mythmediabuffer.cpp:198
MythMediaBuffer::SetReadInternalMode
bool SetReadInternalMode(bool Mode)
Definition: mythmediabuffer.cpp:523
LiveTVChain::SwitchToNext
void SwitchToNext(bool up)
Sets the recording to switch to.
Definition: livetvchain.cpp:594
httplivestreambuffer.h
MythMediaBuffer::m_fileIsMatroska
bool m_fileIsMatroska
Definition: mythmediabuffer.h:202
MythStreamingBuffer
Definition: mythstreamingbuffer.h:13
MythCDROM::kDVD
@ kDVD
Definition: mythcdrom.h:30
MythMediaBuffer::m_wantToRead
int m_wantToRead
Definition: mythmediabuffer.h:222
BUFFER_SIZE_MINIMUM
static constexpr uint32_t BUFFER_SIZE_MINIMUM
Definition: mythmediabuffer.h:26
MythTimer::kStartRunning
@ kStartRunning
Definition: mythtimer.h:17
MythMediaBuffer::GetRealFileSizeInternal
virtual long long GetRealFileSizeInternal(void) const
Definition: mythmediabuffer.h:166
MythMediaBuffer::IsDisc
bool IsDisc(void) const
Definition: mythmediabuffer.cpp:1831
MythMediaBuffer::Start
void Start(void)
Starts the read-ahead thread.
Definition: mythmediabuffer.cpp:617
mythcontext.h
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
MythMediaBuffer::GetAvailableBuffer
QString GetAvailableBuffer(void)
Definition: mythmediabuffer.cpp:1549
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:263
MythMediaBuffer::ReadBufAvail
int ReadBufAvail(void) const
Returns number of bytes available for reading from buffer.
Definition: mythmediabuffer.cpp:555
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:99
MythMediaBuffer::m_bitrateInitialized
bool m_bitrateInitialized
Definition: mythmediabuffer.h:249
MythMediaBuffer::GetLastError
QString GetLastError(void) const
Definition: mythmediabuffer.cpp:1766
kMythBufferBD
@ kMythBufferBD
Definition: mythmediabuffer.h:53
MythMediaBuffer::m_reallyRunning
bool m_reallyRunning
Definition: mythmediabuffer.h:207
MythMediaBuffer::SetLiveMode
void SetLiveMode(LiveTVChain *Chain)
Assigns a LiveTVChain to this RingBuffer.
Definition: mythmediabuffer.cpp:1816
mythtimer.h
MythMediaBuffer::m_subtitleFilename
QString m_subtitleFilename
Definition: mythmediabuffer.h:194
mythfilebuffer.h
MythMediaBuffer::m_writeMode
bool m_writeMode
Definition: mythmediabuffer.h:198
MythMediaBuffer::DVD
const MythDVDBuffer * DVD(void) const
Definition: mythmediabuffer.cpp:1846
MythMediaBuffer::m_posLock
QReadWriteLock m_posLock
Definition: mythmediabuffer.h:173
mythstreamingbuffer.h
MythMediaBuffer::m_bitrateMonitorEnabled
bool m_bitrateMonitorEnabled
Definition: mythmediabuffer.h:233
MythMediaBuffer::Peek
int Peek(void *Buffer, int Count)
Definition: mythmediabuffer.cpp:1170
MythMediaBuffer::m_stopReads
volatile bool m_stopReads
Definition: mythmediabuffer.h:187
ThreadedFileWriter::SetBlocking
bool SetBlocking(bool block=true)
Set write blocking mode While in blocking mode, ThreadedFileWriter::Write will wait for buffers to be...
Definition: threadedfilewriter.cpp:613
DEFAULT_CHUNK_SIZE
static constexpr int32_t DEFAULT_CHUNK_SIZE
Definition: mythmediabuffer.h:31
MythMediaBuffer::IsNearEnd
bool IsNearEnd(double Framerate, uint Frames) const
Definition: mythmediabuffer.cpp:412
MythMediaBuffer::m_rwLock
QReadWriteLock m_rwLock
Definition: mythmediabuffer.h:192
MythMediaBuffer::StartReads
void StartReads(void)
Definition: mythmediabuffer.cpp:679
MythDVDBuffer
Definition: mythdvdbuffer.h:37
build_compdb.filename
filename
Definition: build_compdb.py:21
MythMediaBuffer::m_storageReads
QMap< std::chrono::milliseconds, uint64_t > m_storageReads
Definition: mythmediabuffer.h:237
MythMediaBuffer::m_ateof
bool m_ateof
Definition: mythmediabuffer.h:210
MythMediaBuffer::GetStorageRate
QString GetStorageRate(void)
Definition: mythmediabuffer.cpp:1544
MythMediaBuffer::UpdateDecoderRate
uint64_t UpdateDecoderRate(uint64_t Latest=0)
Definition: mythmediabuffer.cpp:1564
MythMediaBuffer::m_internalReadPos
long long m_internalReadPos
Definition: mythmediabuffer.h:176
MythMediaBuffer::Pause
void Pause(void)
Pauses the read-ahead thread. Calls StopReads(void).
Definition: mythmediabuffer.cpp:690
MythMediaBuffer::Sync
void Sync(void)
Calls ThreadedFileWriter::Sync(void)
Definition: mythmediabuffer.cpp:1667
MythMediaBuffer::m_rbwPos
int m_rbwPos
Definition: mythmediabuffer.h:183
Mode
Mode
Definition: synaesthesia.h:23
MythMediaBuffer::m_ignoreReadPos
long long m_ignoreReadPos
Definition: mythmediabuffer.h:177
MythMediaBuffer::m_readAheadRunning
bool m_readAheadRunning
Definition: mythmediabuffer.h:206
MythMediaBuffer::Reset
void Reset(bool Full=false, bool ToAdjust=false, bool ResetInternal=false)
Resets the read-ahead thread and our position in the file.
Definition: mythmediabuffer.cpp:238
MythMediaBuffer::IsOpen
virtual bool IsOpen(void) const =0
MythMediaBuffer::GetType
MythBufferType GetType() const
Definition: mythmediabuffer.cpp:204
MythMediaBuffer::m_fillMin
int m_fillMin
Definition: mythmediabuffer.h:220
LiveTVChain
Keeps track of recordings in a current LiveTV instance.
Definition: livetvchain.h:32
MythMediaBuffer::SetWaitForWrite
void SetWaitForWrite(void)
Definition: mythmediabuffer.cpp:320