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