5 #include <sys/select.h> 24 #define LOC QString("DVBSH[%1](%2): ").arg(m_inputid).arg(m_device) 38 QMap<QString,DVBStreamHandler*>::iterator it =
46 LOG(VB_RECORD, LOG_INFO,
47 QString(
"DVBSH[%1]: Creating new stream handler %2")
48 .arg(inputid).arg(devname));
54 LOG(VB_RECORD, LOG_INFO,
55 QString(
"DVBSH[%1]: Using existing stream handler for %2")
57 .arg(devname) + QString(
" (%1 in use)").arg(rcount));
73 QMap<QString,DVBStreamHandler*>::iterator it =
s_handlers.find(devname);
84 LOG(VB_RECORD, LOG_INFO, QString(
"DVBSH[%1]: Closing handler for %2")
85 .arg(inputid).arg(devname));
91 LOG(VB_GENERAL, LOG_ERR,
92 QString(
"DVBSH[%1] Error: Couldn't find handler for %2")
93 .arg(inputid).arg(devname));
103 , _allow_retune(
false)
105 , _dvbchannel(nullptr)
114 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"run(): begin");
121 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"run(): end");
139 for (
int tries = 1; ; ++tries)
141 dvr_fd = open(dvr_dev_path.constData(), O_RDONLY |
O_NONBLOCK);
145 LOG(VB_GENERAL, LOG_WARNING,
LOC +
146 QString(
"Opening DVR device %1 failed : %2")
149 if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
151 LOG(VB_GENERAL, LOG_ERR,
LOC +
152 QString(
"Failed to open DVR device %1 : %2")
157 std::this_thread::sleep_for(std::chrono::milliseconds(50));
162 auto *buffer =
new unsigned char[buffer_size];
165 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to allocate memory");
170 memset(buffer, 0, buffer_size);
178 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to allocate DRB buffer");
198 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunTS(): begin");
200 fd_set fd_select_set;
201 FD_ZERO( &fd_select_set);
202 FD_SET (dvr_fd, &fd_select_set);
212 len = drb->
Read(&(buffer[remainder]), buffer_size - remainder);
217 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Device error detected");
223 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Device EOF detected");
230 struct timeval
timeout = { 0, 50 * 1000 };
231 int ret = select(dvr_fd+1, &fd_select_set,
nullptr,
nullptr, &
timeout);
232 if (ret == -1 && errno != EINTR)
234 LOG(VB_GENERAL, LOG_ERR,
LOC +
"select() failed" +
ENO);
238 len =
read(dvr_fd, &(buffer[remainder]),
239 buffer_size - remainder);
242 if ((0 == len) || (-1 == len))
244 std::this_thread::sleep_for(std::chrono::microseconds(100));
267 remainder = sit.key()->ProcessData(buffer, len);
273 if (remainder > 0 && (len > remainder))
274 memmove(buffer, &(buffer[len - remainder]), remainder);
276 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunTS(): " +
"shutdown");
289 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunTS(): " +
"end");
302 int buffer_size = 4192;
303 unsigned char *buffer =
pes_alloc(buffer_size);
312 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunSR(): begin");
321 bool readSomething =
false;
322 PIDInfoMap::const_iterator fit =
m_pid_info.begin();
325 int len =
read((*fit)->filter_fd, buffer, buffer_size);
329 readSomething =
true;
338 sit.key()->HandleTables(fit.key() , psip);
344 std::this_thread::sleep_for(std::chrono::milliseconds(3));
346 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunSR(): " +
"shutdown");
354 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"RunSR(): " +
"end");
359 static pid_list_t::iterator
find(
362 pid_list_t::iterator begin,
363 pid_list_t::iterator end,
bool find_open)
365 pid_list_t::iterator it;
366 for (it = begin; it != end; ++it)
368 PIDInfoMap::const_iterator mit = map.find(*it);
369 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open))
373 for (it = list.begin(); it != begin; ++it)
375 PIDInfoMap::const_iterator mit = map.find(*it);
376 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open))
386 QMap<PIDPriority, pid_list_t> priority_queue;
387 QMap<PIDPriority, uint> priority_open_cnt;
389 PIDInfoMap::const_iterator cit =
m_pid_info.begin();
393 priority_queue[
priority].push_back(cit.key());
394 if ((*cit)->IsOpen())
398 QMap<PIDPriority, pid_list_t>::iterator it = priority_queue.begin();
399 for (; it != priority_queue.end(); ++it)
400 sort((*it).begin(), (*it).end());
405 while (priority_open_cnt[i] < priority_queue[i].size())
411 priority_queue[i].begin(), priority_queue[i].end(),
true);
412 if (open == priority_queue[i].end())
413 open = priority_queue[i].begin();
416 open, priority_queue[i].end(),
false);
418 if (closed == priority_queue[i].end())
424 priority_open_cnt[i]++;
434 if (!priority_open_cnt[j])
437 for (
uint k = 0; (k < priority_queue[j].size()) && !freed; k++)
447 priority_open_cnt[j]--;
458 priority_open_cnt[i]++;
474 priority_open_cnt[i]--;
481 priority_open_cnt[i]++;
496 if (allow && sigmon && dvbchan)
521 bool was_moving, is_moving;
525 if (was_moving && !is_moving)
527 LOG(VB_CHANNEL, LOG_INFO,
528 LOC +
"Retuning for rotor completion");
553 const uint pat_pid = 0x0;
557 QMap<QString,bool>::const_iterator it;
564 int dvr_fd = open(dvr_dev_path.constData(), O_RDONLY |
O_NONBLOCK);
572 bool supports_ts =
false;
589 #define LOC QString("PIDInfo(%1): ").arg(dvb_dev) 600 QByteArray demux_ba = demux_fn.toLatin1();
602 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"Opening filter for pid 0x%1")
605 int mux_fd = open(demux_ba.constData(), O_RDWR |
O_NONBLOCK);
608 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open demux device %1 " 609 "for filter on pid 0x%2")
610 .arg(demux_fn).arg(
_pid, 0, 16));
614 if (!use_section_reader)
616 struct dmx_pes_filter_params pesFilterParams {};
618 pesFilterParams.input = DMX_IN_FRONTEND;
619 pesFilterParams.output = DMX_OUT_TS_TAP;
620 pesFilterParams.flags = DMX_IMMEDIATE_START;
621 pesFilterParams.pes_type = DMX_PES_OTHER;
623 if (ioctl(mux_fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0)
625 LOG(VB_GENERAL, LOG_ERR,
LOC +
626 QString(
"Failed to set TS filter (pid 0x%1)")
635 struct dmx_sct_filter_params sctFilterParams {};
639 sctFilterParams.filter.filter[0] = 0;
640 sctFilterParams.filter.mask[0] = 0xff;
648 sctFilterParams.filter.filter[0] = 0x00;
649 sctFilterParams.filter.mask[0] = 0xbc;
657 sctFilterParams.filter.filter[0] = 0x02;
658 sctFilterParams.filter.mask[0] = 0xbb;
663 sctFilterParams.filter.filter[0] = 0x80;
664 sctFilterParams.filter.mask[0] = 0xa0;
668 sctFilterParams.filter.filter[0] = 0x00;
669 sctFilterParams.filter.mask[0] = 0x00;
673 sctFilterParams.timeout = 0;
674 sctFilterParams.flags = DMX_IMMEDIATE_START;
676 if (ioctl(mux_fd, DMX_SET_FILTER, &sctFilterParams) < 0)
678 LOG(VB_GENERAL, LOG_ERR,
LOC +
679 "Failed to set \"section\" filter " +
680 QString(
"(pid 0x%1) (filter %2)").arg(
_pid, 0, 16)
681 .arg(sctFilterParams.filter.filter[0]));
694 LOG(VB_RECORD, LOG_DEBUG,
LOC +
695 QString(
"Closing filter for pid 0x%1").arg(
_pid, 0, 16));
706 LOG(VB_GENERAL, LOG_ERR,
707 LOC + QString(
"Failed to close mux (pid 0x%1)")
720 int DVBRecorder::OpenFilterFd(
uint pid,
int pes_type,
uint stream_type)
722 if (_open_pid_filters >= _max_pid_filters)
728 uint msec_of_buffering = max(POLL_WARNING_TIMEOUT + 50, 1500);
730 uint pid_buffer_size = ((bpms*msec_of_buffering + 7) / 8);
732 pid_buffer_size = ((pid_buffer_size + 4095) / 4096) * 4096;
734 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"Adding pid 0x%1 size(%2)")
735 .arg(pid,0,16).arg(pid_buffer_size));
740 QByteArray dev = dvbdev.toLatin1();
742 int fd_tmp = open(dev.constData(), O_RDWR);
745 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Could not open demux device." +
ENO);
746 _max_pid_filters = _open_pid_filters;
752 uint sz = pid_buffer_size;
753 uint usecs = msec_of_buffering * 1000;
754 while (ioctl(fd_tmp, DMX_SET_BUFFER_SIZE, sz) < 0 && sz > 1024*8)
756 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to set demux buffer size for "+
757 QString(
"pid 0x%1 to %2").arg(pid,0,16).arg(sz) +
ENO);
760 sz = ((sz+4095)/4096)*4096;
764 LOG(VB_RECORD, LOG_DEBUG,
LOC +
"Set demux buffer size for " +
765 QString(
"pid 0x%1 to %2,\n\t\t\twhich gives us a %3 msec buffer.")
766 .arg(pid,0,16).arg(sz).arg(usecs/1000));
770 struct dmx_pes_filter_params params;
771 memset(¶ms, 0,
sizeof(params));
772 params.input = DMX_IN_FRONTEND;
773 params.output = DMX_OUT_TS_TAP;
774 params.flags = DMX_IMMEDIATE_START;
776 params.pes_type = (dmx_pes_type_t) pes_type;
777 if (ioctl(fd_tmp, DMX_SET_PES_FILTER, ¶ms) < 0)
781 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to set demux filter." +
ENO);
782 _max_pid_filters = _open_pid_filters;
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Collection of helper utilities for input DB use.
virtual void SetRotorValue(int)
void SetRetuneAllowed(bool allow, DTVSignalMonitor *sigmon, DVBChannel *dvbchan)
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
virtual bool Close(const QString &)
volatile bool _allow_retune
volatile bool m_running_desired
bool UpdateFiltersFromStreamData(void)
DVBStreamHandler(const QString &, int inputid)
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)
bool SupportsTSMonitoring(void)
Returns true if TS monitoring is supported.
Provides interface to the tuning hardware when using DVB drivers.
static QMap< QString, DVBStreamHandler * > s_handlers
static QMutex s_handlers_lock
unsigned char * pes_alloc(uint size)
static QMap< QString, bool > s_rec_supports_ts_monitoring
static QString GetDeviceName(dvb_dev_type_t, const QString &device)
void setObjectName(const QString &name)
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
bool IsErrored(void) const
def read(device=None, features=[])
virtual void GetRotorStatus(bool &was_moving, bool &is_moving)
bool Retune(void) override
uint Read(unsigned char *buf, uint count)
Try to Read count bytes from into buffer.
static void Return(DVBStreamHandler *&ref, int inputid)
static bool IsVideo(uint type)
Returns true iff video is an MPEG1/2/3, H264 or open cable video stream.
static DVBStreamHandler * Get(const QString &devname, int inputid)
void SetRunning(bool running, bool using_buffering, bool using_section_reader)
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
bool Open(const QString &dvb_dev, bool use_section_reader) override
bool SectionSyntaxIndicator(void) const
bool RemovePIDFilter(uint pid)
int filter_fd
Input filter file descriptor.
bool Close(const QString &dvb_dev) override
void RunTS(void)
Uses TS filtering devices to read a DVB device for tables & data.
static QMap< QString, uint > s_handlers_refcnt
QMap< uint, PIDInfo * > PIDInfoMap
static QMutex s_rec_supports_ts_monitoring_lock
#define ENO
This can be appended to the LOG args with "+".
bool m_using_section_reader
This class is intended to detect the presence of needed tables.
#define LOG(_MASK_, _LEVEL_, _STRING_)
static const unsigned int kSize
QThread::Priority priority(void) const
StreamDataList m_stream_data_list
bool Setup(const QString &streamName, int streamfd, uint readQuanta=sizeof(TSPacket), uint deviceBufferSize=0, uint deviceBufferCount=1)
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
void pes_free(unsigned char *ptr)
int elapsed(void)
Returns milliseconds elapsed since last start() or restart()
bool AddPIDFilter(PIDInfo *info)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
bool m_allow_section_reader
Buffers reads from device files.
void CycleFiltersByPriority(void) override
void WriteMPTS(unsigned char *buffer, uint len)
Write out a copy of the raw MPTS.
void RunSR(void)
Uses "Section" reader to read a DVB device for tables.
void start(void)
starts measuring elapsed time.
vector< uint > pid_list_t
bool RemoveAllPIDFilters(void)
DTVSignalMonitor * _sigmon
PIDPriority GetPIDPriority(uint pid) const
bool HasFlags(uint64_t _flags) const