26 int pipe_ret = pipe(mypipe.data());
29 LOG(VB_GENERAL, LOG_ERR,
"Failed to open pipes" +
ENO);
35 long flags = fcntl(mypipe[0], F_GETFL);
38 int ret = fcntl(mypipe[0], F_SETFL, flags|
O_NONBLOCK);
40 LOG(VB_GENERAL, LOG_ERR,
41 QString(
"Set pipe flags error") +
ENO);
45 LOG(VB_GENERAL, LOG_ERR, QString(
"Get pipe flags error") +
ENO);
48 for (
uint i = 0; i < 2; i++)
51 flags = fcntl(mypipe[i], F_GETFL);
60#define REPORT_RING_STATS 0
62#define LOC QString("DevRdB(%1): ").arg(m_videoDevice)
65 DeviceReaderCB *cb,
bool use_poll,
bool error_exit_on_poll_timeout)
68 m_usingPoll(use_poll),
69 m_pollTimeoutIsError(error_exit_on_poll_timeout)
72#warning mingw DeviceReadBuffer::Poll
75 LOG(VB_GENERAL, LOG_WARNING,
LOC +
76 "mingw DeviceReadBuffer::Poll is not implemented");
93 uint readQuanta,
uint deviceBufferSize,
94 uint deviceBufferCount)
96 QMutexLocker locker(&
m_lock);
113 "HDRingbufferSize",
static_cast<int>(50 *
m_readQuanta)) * 1024_UZ;
128 LOG(VB_GENERAL, LOG_ERR,
LOC +
129 QString(
"Failed to allocate buffer of size %1 = %2 + %3")
144 LOG(VB_RECORD, LOG_INFO,
LOC + QString(
"buffer size %1 KB").arg(
m_size/1024));
151 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- begin");
153 QMutexLocker locker(&
m_lock);
169 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- middle");
174 LOG(VB_RECORD, LOG_INFO,
LOC +
"Start() -- end");
179 QMutexLocker locker(&
m_lock);
194 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- begin");
195 QMutexLocker locker(&
m_lock);
203 LOG(VB_RECORD, LOG_INFO,
LOC +
"Stop() -- end");
208 QMutexLocker locker(&
m_lock);
215 QMutexLocker locker(&
m_lock);
226 std::string buf(1,
'\0');
231 if ((wret < 0) && (EAGAIN != errno) && (EINTR != errno))
233 LOG(VB_GENERAL, LOG_ERR,
LOC +
"WakePoll failed.");
242 for (
uint i = 0; i < 2; i++)
255 QMutexLocker locker(&
m_lock);
261 QMutexLocker locker(&
m_lock);
271 QMutexLocker locker(&
m_lock);
281 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);
337 QMutexLocker locker(&
m_lock);
352 ssize_t read_len = 0;
378 QMutexLocker locker(&
m_lock);
381 LOG(VB_RECORD, LOG_ERR,
LOC +
"fill_ringbuffer: error state");
388 for (cnt = 0, read_len = 0, total = 0;
415 if (errcnt == 0 && total < throttle)
456# pragma message( "mingw DeviceReadBuffer::Poll" )
458# warning mingw DeviceReadBuffer::Poll
460 LOG(VB_GENERAL, LOG_ERR,
LOC +
461 "mingw DeviceReadBuffer::Poll is not implemented");
469 std::array<struct pollfd,2> polls {};
472 polls[0].events = POLLIN | POLLPRI;
473 polls[0].revents = 0;
479 polls[1].events = POLLIN;
480 polls[1].revents = 0;
485 polls[0].revents = 0;
486 polls[1].revents = 0;
487 poll_cnt = (
m_wakePipe[0] >= 0) ? poll_cnt : 1;
496 int ret = poll(polls.data(), poll_cnt,
timeout.count());
498 if (polls[0].revents & POLLHUP)
500 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll eof (POLLHUP)");
503 if (polls[0].revents & POLLNVAL)
505 LOG(VB_GENERAL, LOG_ERR,
LOC +
"poll error" +
ENO);
516 if (polls[0].revents & POLLPRI)
521 if (polls[0].revents & POLLIN)
527 if ((EOVERFLOW == errno))
530 if ((EAGAIN == errno) || (EINTR == errno))
540 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Poll giving up 1");
541 QMutexLocker locker(&
m_lock);
549 if ((poll_cnt > 1) && (polls[1].revents & POLLIN))
551 std::array<char,128> dummy {};
558 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Poll giving up after %1ms")
560 QMutexLocker locker(&
m_lock);
566 std::chrono::milliseconds e = timer.
elapsed();
569 LOG(VB_GENERAL, LOG_WARNING,
LOC +
570 QString(
"Poll took an unusually long time %1 ms")
571 .arg(timer.
elapsed().count()));
579 ssize_t len,
size_t requested_len,
uint &errcnt)
581 if (len > (ssize_t)requested_len)
583 LOG(VB_GENERAL, LOG_ERR,
LOC +
584 "Driver is returning bogus values on read");
587 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
588 QMutexLocker locker(&
m_lock);
596# pragma message( "mingw DeviceReadBuffer::CheckForErrors" )
598# warning mingw DeviceReadBuffer::CheckForErrors
600 LOG(VB_GENERAL, LOG_ERR,
LOC +
601 "mingw DeviceReadBuffer::CheckForErrors is not implemented");
613 if (EOVERFLOW == errno)
615 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Driver buffers overflowed");
619 LOG(VB_GENERAL, LOG_ERR,
LOC +
624 LOG(VB_RECORD, LOG_ERR,
LOC +
"Too many errors.");
625 QMutexLocker locker(&
m_lock);
637 LOG(VB_GENERAL, LOG_ERR,
LOC +
638 QString(
"End-Of-File? fd(%1)").arg(
m_streamFd));
662 size_t cnt = std::min(count, avail);
707 while (unused < needed)
732 QMutexLocker locker(&
m_lock);
734 while ((needed > avail) &&
isRunning() &&
747 static constexpr std::chrono::seconds secs { 20s };
748 static constexpr double d1_s = 1.0 / secs.count();
751 QMutexLocker locker(&
m_lock);
752 double rsize = 100.0 /
m_size;
753 QString msg = QString(
"fill avg(%1%) ").arg(
m_avgUsed*rsize,5,
'f',2);
754 msg += QString(
"fill max(%1%) ").arg(
m_maxUsed*rsize,5,
'f',2);
766 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)