9#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
10#include <QtSystemDetection>
18#ifndef __cpp_size_t_suffix
34 int pipe_ret = pipe(mypipe.data());
37 LOG(VB_GENERAL, LOG_ERR,
"Failed to open pipes" +
ENO);
43 long flags = fcntl(mypipe[0], F_GETFL);
46 int ret = fcntl(mypipe[0], F_SETFL, flags|
O_NONBLOCK);
48 LOG(VB_GENERAL, LOG_ERR,
49 QString(
"Set pipe flags error") +
ENO);
53 LOG(VB_GENERAL, LOG_ERR, QString(
"Get pipe flags error") +
ENO);
56 for (
uint i = 0; i < 2; i++)
59 flags = fcntl(mypipe[i], F_GETFL);
68#define REPORT_RING_STATS 0
70#define LOC QString("DevRdB(%1): ").arg(m_videoDevice)
73 DeviceReaderCB *cb,
bool use_poll,
bool error_exit_on_poll_timeout)
76 m_usingPoll(use_poll),
77 m_pollTimeoutIsError(error_exit_on_poll_timeout)
80# warning mingw DeviceReadBuffer::Poll is not implemented
83 LOG(VB_GENERAL, LOG_WARNING,
LOC +
84 "mingw DeviceReadBuffer::Poll is not implemented");
101 uint readQuanta,
uint deviceBufferSize,
102 uint deviceBufferCount)
104 QMutexLocker locker(&
m_lock);
120#ifdef __cpp_size_t_suffix
122 "HDRingbufferSize",
static_cast<int>(50 *
m_readQuanta)) * 1024UZ;
125 "HDRingbufferSize",
static_cast<int>(50 *
m_readQuanta)) * 1024_UZ;
141 LOG(VB_GENERAL, LOG_ERR,
LOC +
142 QString(
"Failed to allocate buffer of size %1 = %2 + %3")
157 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"buffer size %1 KB").arg(
m_size/1024));
164 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- begin");
166 QMutexLocker locker(&
m_lock);
182 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- middle");
187 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- end");
192 QMutexLocker locker(&
m_lock);
207 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- begin");
208 QMutexLocker locker(&
m_lock);
216 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- end");
221 QMutexLocker locker(&
m_lock);
228 QMutexLocker locker(&
m_lock);
239 std::string buf(1,
'\0');
244 if ((wret < 0) && (EAGAIN != errno) && (EINTR != errno))
246 LOG(VB_GENERAL, LOG_ERR,
LOC +
"WakePoll failed.");
255 for (
uint i = 0; i < 2; i++)
268 QMutexLocker locker(&
m_lock);
274 QMutexLocker locker(&
m_lock);
284 QMutexLocker locker(&
m_lock);
294 QMutexLocker locker(&
m_lock);
300 QMutexLocker locker(&
m_lock);
306 QMutexLocker locker(&
m_lock);
312 QMutexLocker locker(&
m_lock);
318 QMutexLocker locker(&
m_lock);
324 QMutexLocker locker(&
m_lock);
330 QMutexLocker locker(&
m_lock);
336 QMutexLocker locker(&
m_lock);
350 QMutexLocker locker(&
m_lock);
365 ssize_t read_len = 0;
383 std::this_thread::sleep_for(5ms);
391 QMutexLocker locker(&
m_lock);
394 LOG(VB_RECORD, LOG_ERR,
LOC +
"fill_ringbuffer: error state");
401 for (cnt = 0, read_len = 0, total = 0;
428 if (errcnt == 0 && total < throttle)
429 std::this_thread::sleep_for(1ms);
454 std::this_thread::sleep_for(5ms);
468# warning mingw DeviceReadBuffer::Poll
469 LOG(VB_GENERAL, LOG_ERR,
LOC +
470 "mingw DeviceReadBuffer::Poll is not implemented");
478 std::array<struct pollfd,2> polls {};
481 polls[0].events = POLLIN | POLLPRI;
482 polls[0].revents = 0;
488 polls[1].events = POLLIN;
489 polls[1].revents = 0;
494 polls[0].revents = 0;
495 polls[1].revents = 0;
496 poll_cnt = (
m_wakePipe[0] >= 0) ? poll_cnt : 1;
505 int ret = poll(polls.data(), poll_cnt,
timeout.count());
507 if (polls[0].revents & POLLHUP)
509 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll eof (POLLHUP)");
512 if (polls[0].revents & POLLNVAL)
514 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll error" +
ENO);
525 if (polls[0].revents & POLLPRI)
530 if (polls[0].revents & POLLIN)
536 if ((EOVERFLOW == errno))
539 if ((EAGAIN == errno) || (EINTR == errno))
542 std::this_thread::sleep_for(2500us);
549 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Poll giving up 1");
550 QMutexLocker locker(&
m_lock);
558 if ((poll_cnt > 1) && (polls[1].revents & POLLIN))
560 std::array<char,128> dummy {};
567 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Poll giving up after %1ms")
569 QMutexLocker locker(&
m_lock);
575 std::chrono::milliseconds e = timer.
elapsed();
578 LOG(VB_GENERAL, LOG_WARNING,
LOC +
579 QString(
"Poll took an unusually long time %1 ms")
580 .arg(timer.
elapsed().count()));
588 ssize_t len,
size_t requested_len,
uint &errcnt)
590 if (len > (ssize_t)requested_len)
592 LOG(VB_GENERAL, LOG_ERR,
LOC +
593 "Driver is returning bogus values on read");
596 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
597 QMutexLocker locker(&
m_lock);
604# warning mingw DeviceReadBuffer::CheckForErrors
605 LOG(VB_GENERAL, LOG_ERR,
LOC +
606 "mingw DeviceReadBuffer::CheckForErrors is not implemented");
615 std::this_thread::sleep_for(2500us);
618 if (EOVERFLOW == errno)
620 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Driver buffers overflowed");
624 LOG(VB_GENERAL, LOG_ERR,
LOC +
629 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
630 QMutexLocker locker(&
m_lock);
635 std::this_thread::sleep_for(500ms);
642 LOG(VB_GENERAL, LOG_ERR,
LOC +
643 QString(
"End-Of-File? fd(%1)").arg(
m_streamFd));
651 std::this_thread::sleep_for(500ms);
667 size_t cnt = std::min(count, avail);
712 while (unused < needed)
717 std::this_thread::sleep_for(5ms);
737 QMutexLocker locker(&
m_lock);
739 while ((needed > avail) &&
isRunning() &&
752 static constexpr std::chrono::seconds secs { 20s };
753 static constexpr double d1_s = 1.0 / secs.count();
756 QMutexLocker locker(&
m_lock);
757 double rsize = 100.0 /
m_size;
758 QString msg = QString(
"fill avg(%1%) ").arg(
m_avgUsed*rsize,5,
'f',2);
759 msg += QString(
"fill max(%1%) ").arg(
m_maxUsed*rsize,5,
'f',2);
771 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().
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)