Go to the documentation of this file.
17 #define REPORT_RING_STATS 0 // NOLINT(cppcoreguidelines-macro-usage)
19 #define LOC QString("DevRdB(%1): ").arg(m_videoDevice)
22 DeviceReaderCB *cb,
bool use_poll,
bool error_exit_on_poll_timeout)
25 m_usingPoll(use_poll),
26 m_pollTimeoutIsError(error_exit_on_poll_timeout)
29 #warning mingw DeviceReadBuffer::Poll
32 LOG(VB_GENERAL, LOG_WARNING,
LOC +
33 "mingw DeviceReadBuffer::Poll is not implemented");
50 uint readQuanta,
uint deviceBufferSize,
51 uint deviceBufferCount)
53 QMutexLocker locker(&
m_lock);
70 "HDRingbufferSize",
static_cast<int>(50 *
m_readQuanta)) * 1024_UZ;
85 LOG(VB_GENERAL, LOG_ERR,
LOC +
86 QString(
"Failed to allocate buffer of size %1 = %2 + %3")
101 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"buffer size %1 KB").arg(
m_size/1024));
108 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- begin");
110 QMutexLocker locker(&
m_lock);
126 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- middle");
131 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- end");
136 QMutexLocker locker(&
m_lock);
151 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- begin");
152 QMutexLocker locker(&
m_lock);
160 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- end");
165 QMutexLocker locker(&
m_lock);
172 QMutexLocker locker(&
m_lock);
183 std::string buf(1,
'\0');
188 if ((wret < 0) && (EAGAIN != errno) && (EINTR != errno))
190 LOG(VB_GENERAL, LOG_ERR,
LOC +
"WakePoll failed.");
199 for (
uint i = 0; i < 2; i++)
212 QMutexLocker locker(&
m_lock);
218 QMutexLocker locker(&
m_lock);
228 QMutexLocker locker(&
m_lock);
238 QMutexLocker locker(&
m_lock);
244 QMutexLocker locker(&
m_lock);
250 QMutexLocker locker(&
m_lock);
256 QMutexLocker locker(&
m_lock);
262 QMutexLocker locker(&
m_lock);
268 QMutexLocker locker(&
m_lock);
274 QMutexLocker locker(&
m_lock);
280 QMutexLocker locker(&
m_lock);
284 #if REPORT_RING_STATS
294 QMutexLocker locker(&
m_lock);
298 #if REPORT_RING_STATS
309 ssize_t read_len = 0;
335 QMutexLocker locker(&
m_lock);
338 LOG(VB_RECORD, LOG_ERR,
LOC +
"fill_ringbuffer: error state");
345 for (cnt = 0, read_len = 0, total = 0;
372 if (errcnt == 0 && total < throttle)
413 # pragma message( "mingw DeviceReadBuffer::Poll" )
415 # warning mingw DeviceReadBuffer::Poll
417 LOG(VB_GENERAL, LOG_ERR,
LOC +
418 "mingw DeviceReadBuffer::Poll is not implemented");
426 std::array<struct pollfd,2> polls {};
429 polls[0].events = POLLIN | POLLPRI;
430 polls[0].revents = 0;
436 polls[1].events = POLLIN;
437 polls[1].revents = 0;
442 polls[0].revents = 0;
443 polls[1].revents = 0;
444 poll_cnt = (
m_wakePipe[0] >= 0) ? poll_cnt : 1;
453 int ret = poll(polls.data(), poll_cnt,
timeout.count());
455 if (polls[0].revents & POLLHUP)
457 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll eof (POLLHUP)");
460 if (polls[0].revents & POLLNVAL)
462 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll error" +
ENO);
473 if (polls[0].revents & POLLPRI)
478 if (polls[0].revents & POLLIN)
484 if ((EOVERFLOW == errno))
487 if ((EAGAIN == errno) || (EINTR == errno))
497 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Poll giving up 1");
498 QMutexLocker locker(&
m_lock);
506 if ((poll_cnt > 1) && (polls[1].revents & POLLIN))
508 std::array<char,128> dummy {};
515 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Poll giving up after %1ms")
517 QMutexLocker locker(&
m_lock);
523 std::chrono::milliseconds e = timer.
elapsed();
526 LOG(VB_GENERAL, LOG_WARNING,
LOC +
527 QString(
"Poll took an unusually long time %1 ms")
528 .arg(timer.
elapsed().count()));
536 ssize_t len,
size_t requested_len,
uint &errcnt)
538 if (len > (ssize_t)requested_len)
540 LOG(VB_GENERAL, LOG_ERR,
LOC +
541 "Driver is returning bogus values on read");
544 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
545 QMutexLocker locker(&
m_lock);
553 # pragma message( "mingw DeviceReadBuffer::CheckForErrors" )
555 # warning mingw DeviceReadBuffer::CheckForErrors
557 LOG(VB_GENERAL, LOG_ERR,
LOC +
558 "mingw DeviceReadBuffer::CheckForErrors is not implemented");
570 if (EOVERFLOW == errno)
572 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Driver buffers overflowed");
576 LOG(VB_GENERAL, LOG_ERR,
LOC +
581 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
582 QMutexLocker locker(&
m_lock);
594 LOG(VB_GENERAL, LOG_ERR,
LOC +
595 QString(
"End-Of-File? fd(%1)").arg(
m_streamFd));
619 size_t cnt = std::min(count, avail);
647 #if REPORT_RING_STATS
664 while (unused < needed)
689 QMutexLocker locker(&
m_lock);
691 while ((needed > avail) &&
isRunning() &&
703 #if REPORT_RING_STATS
704 static constexpr std::chrono::seconds secs { 20s };
705 static constexpr
double d1_s = 1.0 / secs.count();
708 QMutexLocker locker(&
m_lock);
709 double rsize = 100.0 /
m_size;
710 QString msg = QString(
"fill avg(%1%) ").arg(
m_avgUsed*rsize,5,
'f',2);
711 msg += QString(
"fill max(%1%) ").arg(
m_maxUsed*rsize,5,
'f',2);
723 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
#define ENO
This can be appended to the LOG args with "+".
unsigned char * m_readPtr
QWaitCondition m_pauseWait
void WakePoll(void) const
bool Setup(const QString &streamName, int streamfd, uint readQuanta=sizeof(TSPacket), uint deviceBufferSize=0, uint deviceBufferCount=1)
pipe_flag_array m_wakePipeFlags
A QElapsedTimer based timer to replace use of QTime as a timer.
bool IsPaused(void) const
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
bool WaitForPaused(unsigned long timeout)
def read(device=None, features=[])
static void usleep(std::chrono::microseconds time)
def write(text, progress=True)
uint WaitForUsed(uint needed, std::chrono::milliseconds max_wait) const
uint Read(unsigned char *buf, uint count)
Try to Read count bytes from into buffer.
void start(void)
starts measuring elapsed time.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
bool IsPauseRequested(void) const
bool WaitForUnpause(unsigned long timeout)
uint GetContiguousUnused(void) const
virtual void ReaderPaused(int fd)=0
uint WaitForUnused(uint needed) const
bool CheckForErrors(ssize_t read_len, size_t requested_len, uint &errcnt)
bool m_pollTimeoutIsError
static void setup_pipe(pipe_fd_array &, pipe_flag_array &)
DeviceReaderCB * m_readerCB
bool IsRunning(void) const
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
QWaitCondition m_unpauseWait
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void ClosePipes(void) const
virtual void PriorityEvent(int fd)=0
int GetNumSetting(const QString &key, int defaultval=0)
uint GetUnused(void) const
~DeviceReadBuffer() override
std::chrono::milliseconds m_maxPollWait
unsigned char * m_writePtr
DeviceReadBuffer(DeviceReaderCB *cb, bool use_poll=true, bool error_exit_on_poll_timeout=true)
This is a wrapper around QThread that does several additional things.
bool isRunning(void) const
bool IsErrored(void) const
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
void IncrWritePointer(uint len)
void SetRequestPause(bool request)
QWaitCondition m_dataWait
void IncrReadPointer(uint len)
void Reset(const QString &streamName, int streamfd)