7#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
8#include <QtSystemDetection>
30 int pipe_ret = pipe(mypipe.data());
33 LOG(VB_GENERAL, LOG_ERR,
"Failed to open pipes" +
ENO);
39 long flags = fcntl(mypipe[0], F_GETFL);
42 int ret = fcntl(mypipe[0], F_SETFL, flags|
O_NONBLOCK);
44 LOG(VB_GENERAL, LOG_ERR,
45 QString(
"Set pipe flags error") +
ENO);
49 LOG(VB_GENERAL, LOG_ERR, QString(
"Get pipe flags error") +
ENO);
52 for (
uint i = 0; i < 2; i++)
55 flags = fcntl(mypipe[i], F_GETFL);
64#define REPORT_RING_STATS 0
66#define LOC QString("DevRdB(%1): ").arg(m_videoDevice)
69 DeviceReaderCB *cb,
bool use_poll,
bool error_exit_on_poll_timeout)
72 m_usingPoll(use_poll),
73 m_pollTimeoutIsError(error_exit_on_poll_timeout)
76# if !defined(_MSC_VER) || __cplusplus >= 202302L
77# warning mingw DeviceReadBuffer::Poll is not implemented
81 LOG(VB_GENERAL, LOG_WARNING,
LOC +
82 "mingw DeviceReadBuffer::Poll is not implemented");
99 uint readQuanta,
uint deviceBufferSize,
100 uint deviceBufferCount)
102 QMutexLocker locker(&
m_lock);
119 "HDRingbufferSize",
static_cast<int>(50 *
m_readQuanta)) * 1024_UZ;
134 LOG(VB_GENERAL, LOG_ERR,
LOC +
135 QString(
"Failed to allocate buffer of size %1 = %2 + %3")
150 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"buffer size %1 KB").arg(
m_size/1024));
157 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- begin");
159 QMutexLocker locker(&
m_lock);
175 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- middle");
180 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- end");
185 QMutexLocker locker(&
m_lock);
200 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- begin");
201 QMutexLocker locker(&
m_lock);
209 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- end");
214 QMutexLocker locker(&
m_lock);
221 QMutexLocker locker(&
m_lock);
232 std::string buf(1,
'\0');
237 if ((wret < 0) && (EAGAIN != errno) && (EINTR != errno))
239 LOG(VB_GENERAL, LOG_ERR,
LOC +
"WakePoll failed.");
248 for (
uint i = 0; i < 2; i++)
261 QMutexLocker locker(&
m_lock);
267 QMutexLocker locker(&
m_lock);
277 QMutexLocker locker(&
m_lock);
287 QMutexLocker locker(&
m_lock);
293 QMutexLocker locker(&
m_lock);
299 QMutexLocker locker(&
m_lock);
305 QMutexLocker locker(&
m_lock);
311 QMutexLocker locker(&
m_lock);
317 QMutexLocker locker(&
m_lock);
323 QMutexLocker locker(&
m_lock);
329 QMutexLocker locker(&
m_lock);
343 QMutexLocker locker(&
m_lock);
358 ssize_t read_len = 0;
384 QMutexLocker locker(&
m_lock);
387 LOG(VB_RECORD, LOG_ERR,
LOC +
"fill_ringbuffer: error state");
394 for (cnt = 0, read_len = 0, total = 0;
421 if (errcnt == 0 && total < throttle)
462# pragma message( "mingw DeviceReadBuffer::Poll" )
464# warning mingw DeviceReadBuffer::Poll
466 LOG(VB_GENERAL, LOG_ERR,
LOC +
467 "mingw DeviceReadBuffer::Poll is not implemented");
475 std::array<struct pollfd,2> polls {};
478 polls[0].events = POLLIN | POLLPRI;
479 polls[0].revents = 0;
485 polls[1].events = POLLIN;
486 polls[1].revents = 0;
491 polls[0].revents = 0;
492 polls[1].revents = 0;
493 poll_cnt = (
m_wakePipe[0] >= 0) ? poll_cnt : 1;
502 int ret = poll(polls.data(), poll_cnt,
timeout.count());
504 if (polls[0].revents & POLLHUP)
506 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll eof (POLLHUP)");
509 if (polls[0].revents & POLLNVAL)
511 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll error" +
ENO);
522 if (polls[0].revents & POLLPRI)
527 if (polls[0].revents & POLLIN)
533 if ((EOVERFLOW == errno))
536 if ((EAGAIN == errno) || (EINTR == errno))
546 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Poll giving up 1");
547 QMutexLocker locker(&
m_lock);
555 if ((poll_cnt > 1) && (polls[1].revents & POLLIN))
557 std::array<char,128> dummy {};
564 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Poll giving up after %1ms")
566 QMutexLocker locker(&
m_lock);
572 std::chrono::milliseconds e = timer.
elapsed();
575 LOG(VB_GENERAL, LOG_WARNING,
LOC +
576 QString(
"Poll took an unusually long time %1 ms")
577 .arg(timer.
elapsed().count()));
585 ssize_t len,
size_t requested_len,
uint &errcnt)
587 if (len > (ssize_t)requested_len)
589 LOG(VB_GENERAL, LOG_ERR,
LOC +
590 "Driver is returning bogus values on read");
593 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
594 QMutexLocker locker(&
m_lock);
602# pragma message( "mingw DeviceReadBuffer::CheckForErrors" )
604# warning mingw DeviceReadBuffer::CheckForErrors
606 LOG(VB_GENERAL, LOG_ERR,
LOC +
607 "mingw DeviceReadBuffer::CheckForErrors is not implemented");
619 if (EOVERFLOW == errno)
621 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Driver buffers overflowed");
625 LOG(VB_GENERAL, LOG_ERR,
LOC +
630 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
631 QMutexLocker locker(&
m_lock);
643 LOG(VB_GENERAL, LOG_ERR,
LOC +
644 QString(
"End-Of-File? fd(%1)").arg(
m_streamFd));
668 size_t cnt = std::min(count, avail);
713 while (unused < needed)
738 QMutexLocker locker(&
m_lock);
740 while ((needed > avail) &&
isRunning() &&
753 static constexpr std::chrono::seconds secs { 20s };
754 static constexpr double d1_s = 1.0 / secs.count();
757 QMutexLocker locker(&
m_lock);
758 double rsize = 100.0 /
m_size;
759 QString msg = QString(
"fill avg(%1%) ").arg(
m_avgUsed*rsize,5,
'f',2);
760 msg += QString(
"fill max(%1%) ").arg(
m_maxUsed*rsize,5,
'f',2);
772 LOG(VB_GENERAL, LOG_INFO,
LOC + msg);
void ClosePipes(void) const
bool IsRunning(void) const
bool WaitForUnpause(unsigned long timeout)
std::array< long, 2 > pipe_flag_array
unsigned char * m_writePtr
DeviceReadBuffer(DeviceReaderCB *cb, bool use_poll=true, bool error_exit_on_poll_timeout=true)
bool m_pollTimeoutIsError
bool IsPauseRequested(void) const
unsigned char * m_readPtr
QWaitCondition m_pauseWait
bool Setup(const QString &streamName, int streamfd, uint readQuanta=sizeof(TSPacket), uint deviceBufferSize=0, uint deviceBufferCount=1)
void SetRequestPause(bool request)
uint WaitForUnused(uint needed) const
std::chrono::milliseconds m_maxPollWait
uint Read(unsigned char *buf, uint count)
Try to Read count bytes from into buffer.
std::array< int, 2 > pipe_fd_array
~DeviceReadBuffer() override
static void setup_pipe(pipe_fd_array &mypipe, pipe_flag_array &myflags)
bool IsPaused(void) const
void IncrWritePointer(uint len)
pipe_flag_array m_wakePipeFlags
QWaitCondition m_dataWait
QWaitCondition m_unpauseWait
bool IsErrored(void) const
void WakePoll(void) const
DeviceReaderCB * m_readerCB
void Reset(const QString &streamName, int streamfd)
bool CheckForErrors(ssize_t read_len, size_t requested_len, uint &errcnt)
uint GetUnused(void) const
uint GetContiguousUnused(void) const
uint WaitForUsed(uint needed, std::chrono::milliseconds max_wait) const
bool WaitForPaused(unsigned long timeout)
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
void IncrReadPointer(uint len)
virtual void PriorityEvent(int fd)=0
virtual void ReaderPaused(int fd)=0
This is a wrapper around QThread that does several additional things.
bool isRunning(void) const
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
static void usleep(std::chrono::microseconds time)
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
int GetNumSetting(const QString &key, int defaultval=0)
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(void)
starts measuring elapsed time.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
def read(device=None, features=[])
def write(text, progress=True)