26#define LOC QString("DVBSH[%1](%2): ").arg(m_inputId).arg(m_device)
50 QMap<QString,DVBStreamHandler*>::iterator it =
58 LOG(VB_RECORD, LOG_INFO,
59 QString(
"DVBSH[%1]: Creating new stream handler %2")
60 .arg(inputid).arg(devname));
66 LOG(VB_RECORD, LOG_INFO,
67 QString(
"DVBSH[%1]: Using existing stream handler for %2")
69 .arg(devname) + QString(
" (%1 in use)").arg(rcount));
85 QMap<QString,DVBStreamHandler*>::iterator it =
s_handlers.find(devname);
96 LOG(VB_RECORD, LOG_INFO, QString(
"DVBSH[%1]: Closing handler for %2")
97 .arg(inputid).arg(devname));
103 LOG(VB_GENERAL, LOG_ERR,
104 QString(
"DVBSH[%1] Error: Couldn't find handler for %2")
105 .arg(inputid).arg(devname));
122 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"run(): begin");
129 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"run(): end");
147 for (
int tries = 1; ; ++tries)
149 dvr_fd = open(dvr_dev_path.constData(), O_RDONLY |
O_NONBLOCK);
153 LOG(VB_GENERAL, LOG_WARNING,
LOC +
154 QString(
"Opening DVR device %1 failed : %2")
157 if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
159 LOG(VB_GENERAL, LOG_ERR,
LOC +
160 QString(
"Failed to open DVR device %1 : %2")
165 std::this_thread::sleep_for(50ms);
170 auto *buffer =
new unsigned char[buffer_size];
173 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to allocate memory");
178 memset(buffer, 0, buffer_size);
186 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to allocate DRB buffer");
206 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunTS(): begin");
208 fd_set fd_select_set;
209 FD_ZERO( &fd_select_set);
210 FD_SET (dvr_fd, &fd_select_set);
220 len = drb->
Read(&(buffer[remainder]), buffer_size - remainder);
225 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Device error detected");
231 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Device EOF detected");
239 int ret = select(dvr_fd+1, &fd_select_set,
nullptr,
nullptr, &
timeout);
240 if (ret == -1 && errno != EINTR)
242 LOG(VB_GENERAL, LOG_ERR,
LOC +
"select() failed" +
ENO);
246 len =
read(dvr_fd, &(buffer[remainder]),
247 buffer_size - remainder);
250 if ((0 == len) || (-1 == len))
252 std::this_thread::sleep_for(100us);
274 remainder = sit.key()->ProcessData(buffer, len);
280 if (remainder > 0 && (len > remainder))
281 memmove(buffer, &(buffer[len - remainder]), remainder);
283 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunTS(): " +
"shutdown");
296 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunTS(): " +
"end");
309 int buffer_size = 4192;
310 unsigned char *buffer =
pes_alloc(buffer_size);
319 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunSR(): begin");
328 bool readSomething =
false;
331 int len =
read((*fit)->m_filterFd, buffer, buffer_size);
335 readSomething =
true;
343 sit.key()->HandleTables(fit.key() , psip);
349 std::this_thread::sleep_for(3ms);
351 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunSR(): " +
"shutdown");
359 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunSR(): " +
"end");
364static pid_list_t::iterator
find(
367 pid_list_t::iterator begin,
368 pid_list_t::iterator end,
bool find_open)
370 pid_list_t::iterator it;
371 for (it = begin; it != end; ++it)
373 PIDInfoMap::const_iterator mit = map.find(*it);
374 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open))
378 for (it = list.begin(); it != begin; ++it)
380 PIDInfoMap::const_iterator mit = map.find(*it);
381 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open))
391 QMap<PIDPriority, pid_list_t> priority_queue;
392 QMap<PIDPriority, uint> priority_open_cnt;
397 priority_queue[
priority].push_back(cit.key());
398 if ((*cit)->IsOpen())
402 for (
auto & it : priority_queue)
403 std::ranges::sort(it);
408 while (priority_open_cnt[i] < priority_queue[i].size())
414 priority_queue[i].begin(), priority_queue[i].end(),
true);
415 if (open == priority_queue[i].end())
416 open = priority_queue[i].begin();
419 open, priority_queue[i].end(),
false);
421 if (closed == priority_queue[i].end())
427 priority_open_cnt[i]++;
437 if (!priority_open_cnt[j])
440 for (
uint k = 0; (k < priority_queue[j].size()) && !freed; k++)
450 priority_open_cnt[j]--;
461 priority_open_cnt[i]++;
477 priority_open_cnt[i]--;
484 priority_open_cnt[i]++;
499 if (allow && sigmon && dvbchan)
524 bool was_moving =
false;
525 bool is_moving =
false;
529 if (was_moving && !is_moving)
531 LOG(VB_CHANNEL, LOG_INFO,
532 LOC +
"Retuning for rotor completion");
557 const uint pat_pid = 0x0;
561 QMap<QString,bool>::const_iterator it;
568 int dvr_fd = open(dvr_dev_path.constData(), O_RDONLY |
O_NONBLOCK);
576 bool supports_ts =
false;
593#define LOC QString("PIDInfo(%1): ").arg(dvb_dev)
604 QByteArray demux_ba = demux_fn.toLatin1();
606 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"Opening filter for pid 0x%1")
609 int mux_fd = open(demux_ba.constData(), O_RDWR |
O_NONBLOCK);
612 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open demux device %1 "
613 "for filter on pid 0x%2")
614 .arg(demux_fn).arg(
m_pid, 0, 16));
618 if (!use_section_reader)
620 struct dmx_pes_filter_params pesFilterParams {};
622 pesFilterParams.input = DMX_IN_FRONTEND;
623 pesFilterParams.output = DMX_OUT_TS_TAP;
624 pesFilterParams.flags = DMX_IMMEDIATE_START;
625 pesFilterParams.pes_type = DMX_PES_OTHER;
627 if (ioctl(mux_fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0)
629 LOG(VB_GENERAL, LOG_ERR,
LOC +
630 QString(
"Failed to set TS filter (pid 0x%1)")
639 struct dmx_sct_filter_params sctFilterParams {};
643 sctFilterParams.filter.filter[0] = 0;
644 sctFilterParams.filter.mask[0] = 0xff;
652 sctFilterParams.filter.filter[0] = 0x00;
653 sctFilterParams.filter.mask[0] = 0xbc;
661 sctFilterParams.filter.filter[0] = 0x02;
662 sctFilterParams.filter.mask[0] = 0xbb;
667 sctFilterParams.filter.filter[0] = 0x80;
668 sctFilterParams.filter.mask[0] = 0xa0;
672 sctFilterParams.filter.filter[0] = 0x00;
673 sctFilterParams.filter.mask[0] = 0x00;
677 sctFilterParams.timeout = 0;
678 sctFilterParams.flags = DMX_IMMEDIATE_START;
680 if (ioctl(mux_fd, DMX_SET_FILTER, &sctFilterParams) < 0)
682 LOG(VB_GENERAL, LOG_ERR,
LOC +
683 "Failed to set \"section\" filter " +
684 QString(
"(pid 0x%1) (filter %2)").arg(
m_pid, 0, 16)
685 .arg(sctFilterParams.filter.filter[0]));
698 LOG(VB_RECORD, LOG_DEBUG,
LOC +
699 QString(
"Closing filter for pid 0x%1").arg(
m_pid, 0, 16));
707 int err =
close(tmp);
710 LOG(VB_GENERAL, LOG_ERR,
711 LOC + QString(
"Failed to close mux (pid 0x%1)")
724int DVBRecorder::OpenFilterFd(
uint pid,
int pes_type,
uint stream_type)
726 if (_open_pid_filters >= _max_pid_filters)
732 std::chrono::milliseconds msec_of_buffering = std::max(POLL_WARNING_TIMEOUT + 50ms, 1500ms);
734 uint pid_buffer_size = ((bpms*msec_of_buffering.count() + 7) / 8);
736 pid_buffer_size = ((pid_buffer_size + 4095) / 4096) * 4096;
738 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"Adding pid 0x%1 size(%2)")
739 .arg(pid,0,16).arg(pid_buffer_size));
744 QByteArray dev = dvbdev.toLatin1();
746 int fd_tmp = open(dev.constData(), O_RDWR);
749 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Could not open demux device." +
ENO);
750 _max_pid_filters = _open_pid_filters;
756 uint sz = pid_buffer_size;
757 std::chrono::microseconds usecs = msec_of_buffering;
758 while (ioctl(fd_tmp, DMX_SET_BUFFER_SIZE, sz) < 0 && sz > 1024*8)
760 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to set demux buffer size for "+
761 QString(
"pid 0x%1 to %2").arg(pid,0,16).arg(sz) +
ENO);
764 sz = ((sz+4095)/4096)*4096;
768 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Set demux buffer size for " +
769 QString(
"pid 0x%1 to %2,\n\t\t\twhich gives us a %3 msec buffer.")
770 .arg(pid,0,16).arg(sz)
771 .arg(duration_cast<std::chrono::milliseconds>(usecs).count()));
775 struct dmx_pes_filter_params params;
776 memset(¶ms, 0,
sizeof(params));
777 params.input = DMX_IN_FRONTEND;
778 params.output = DMX_OUT_TS_TAP;
779 params.flags = DMX_IMMEDIATE_START;
781 params.pes_type = (dmx_pes_type_t) pes_type;
782 if (ioctl(fd_tmp, DMX_SET_PES_FILTER, ¶ms) < 0)
786 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to set demux filter." +
ENO);
787 _max_pid_filters = _open_pid_filters;
Collection of helper utilities for input DB use.
static QString GetDeviceName(dvb_dev_type_t type, const QString &device)
This class is intended to detect the presence of needed tables.
virtual void SetRotorValue(int)
virtual void GetRotorStatus(bool &was_moving, bool &is_moving)
Provides interface to the tuning hardware when using DVB drivers.
bool Retune(void) override
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
bool Close(const QString &dvb_dev) override
bool Open(const QString &dvb_dev, bool use_section_reader) override
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
static QMap< QString, DVBStreamHandler * > s_handlers
void CycleFiltersByPriority(void) override
volatile bool m_allowRetune
DVBChannel * m_dvbChannel
DVBStreamHandler(const QString &dvb_device, int inputid)
void RunTS(void)
Uses TS filtering devices to read a DVB device for tables & data.
void SetRetuneAllowed(bool allow, DTVSignalMonitor *sigmon, DVBChannel *dvbchan)
static QMutex s_rec_supportsTsMonitoringLock
void RunSR(void)
Uses "Section" reader to read a DVB device for tables.
static QMap< QString, bool > s_recSupportsTsMonitoring
static QMutex s_handlersLock
DTVSignalMonitor * m_sigMon
static void Return(DVBStreamHandler *&ref, int inputid)
static DVBStreamHandler * Get(const QString &devname, int inputid)
bool SupportsTSMonitoring(void)
Returns true if TS monitoring is supported.
static QMap< QString, uint > s_handlersRefCnt
Buffers reads from device files.
bool Setup(const QString &streamName, int streamfd, uint readQuanta=sizeof(TSPacket), uint deviceBufferSize=0, uint deviceBufferCount=1)
uint Read(unsigned char *buf, uint count)
Try to Read count bytes from into buffer.
bool IsErrored(void) const
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
QThread::Priority priority(void) const
void setObjectName(const QString &name)
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(void)
starts measuring elapsed time.
int m_filterFd
Input filter file descriptor.
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
bool SectionSyntaxIndicator(void) const
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
bool HasFlags(uint64_t _flags) const
QRecursiveMutex m_pidLock
bool AddPIDFilter(PIDInfo *info)
StreamDataList m_streamDataList
bool RemovePIDFilter(uint pid)
void WriteMPTS(const unsigned char *buffer, uint len)
Write out a copy of the raw MPTS.
volatile bool m_runningDesired
bool RemoveAllPIDFilters(void)
void SetRunning(bool running, bool using_buffering, bool using_section_reader)
bool m_usingSectionReader
bool UpdateFiltersFromStreamData(void)
PIDPriority GetPIDPriority(uint pid) const
bool m_allowSectionReader
QRecursiveMutex m_listenerLock
static bool IsVideo(uint type)
Returns true iff video is an MPEG1/2/3, H264 or open cable video stream.
static constexpr unsigned int kSize
static constexpr __suseconds_t k50Milliseconds
std::vector< uint > pid_list_t
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
__darwin_suseconds_t __suseconds_t
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
def read(device=None, features=[])
void pes_free(unsigned char *ptr)
unsigned char * pes_alloc(uint size)
QMap< uint, PIDInfo * > PIDInfoMap