MythTV master
dvbstreamhandler.cpp
Go to the documentation of this file.
1// -*- Mode: c++ -*-
2
3// POSIX headers
4#include <chrono> // for milliseconds
5#include <fcntl.h>
6#include <sys/ioctl.h>
7#include <sys/select.h>
8#include <thread> // for sleep_for
9
10// Qt headers
11#include <QString>
12
13// MythTV headers
15
16#include "cardutil.h"
17#include "diseqc.h" // for rotor retune
18#include "dtvsignalmonitor.h"
19#include "dvbchannel.h"
20#include "dvbstreamhandler.h"
21#include "dvbtypes.h" // for pid filtering
22#include "mpeg/mpegstreamdata.h"
24
25#define LOC QString("DVBSH[%1](%2): ").arg(m_inputId).arg(m_device)
26
29
30QMap<QString,DVBStreamHandler*> DVBStreamHandler::s_handlers;
31QMap<QString,uint> DVBStreamHandler::s_handlersRefCnt;
33
34#ifndef __suseconds_t
35#ifdef Q_OS_MACOS
36using __suseconds_t = __darwin_suseconds_t;
37#else
38using __suseconds_t = long int;
39#endif
40#endif
41static constexpr __suseconds_t k50Milliseconds {static_cast<__suseconds_t>(50 * 1000)};
42
43
45 int inputid)
46{
47 QMutexLocker locker(&s_handlersLock);
48
49 QMap<QString,DVBStreamHandler*>::iterator it =
50 s_handlers.find(devname);
51
52 if (it == s_handlers.end())
53 {
54 s_handlers[devname] = new DVBStreamHandler(devname, inputid);
55 s_handlersRefCnt[devname] = 1;
56
57 LOG(VB_RECORD, LOG_INFO,
58 QString("DVBSH[%1]: Creating new stream handler %2")
59 .arg(inputid).arg(devname));
60 }
61 else
62 {
63 s_handlersRefCnt[devname]++;
64 uint rcount = s_handlersRefCnt[devname];
65 LOG(VB_RECORD, LOG_INFO,
66 QString("DVBSH[%1]: Using existing stream handler for %2")
67 .arg(inputid)
68 .arg(devname) + QString(" (%1 in use)").arg(rcount));
69 }
70
71 return s_handlers[devname];
72}
73
75{
76 QMutexLocker locker(&s_handlersLock);
77
78 QString devname = ref->m_device;
79
80 QMap<QString,uint>::iterator rit = s_handlersRefCnt.find(devname);
81 if (rit == s_handlersRefCnt.end())
82 return;
83
84 QMap<QString,DVBStreamHandler*>::iterator it = s_handlers.find(devname);
85
86 if (*rit > 1)
87 {
88 ref = nullptr;
89 (*rit)--;
90 return;
91 }
92
93 if ((it != s_handlers.end()) && (*it == ref))
94 {
95 LOG(VB_RECORD, LOG_INFO, QString("DVBSH[%1]: Closing handler for %2")
96 .arg(inputid).arg(devname));
97 delete *it;
98 s_handlers.erase(it);
99 }
100 else
101 {
102 LOG(VB_GENERAL, LOG_ERR,
103 QString("DVBSH[%1] Error: Couldn't find handler for %2")
104 .arg(inputid).arg(devname));
105 }
106
107 s_handlersRefCnt.erase(rit);
108 ref = nullptr;
109}
110
111DVBStreamHandler::DVBStreamHandler(const QString &dvb_device, int inputid)
112 : StreamHandler(dvb_device, inputid)
113 , m_dvrDevPath(CardUtil::GetDeviceName(DVB_DEV_DVR, m_device))
114{
115 setObjectName("DVBRead");
116}
117
119{
120 RunProlog();
121 LOG(VB_RECORD, LOG_DEBUG, LOC + "run(): begin");
122
124 RunSR();
125 else
126 RunTS();
127
128 LOG(VB_RECORD, LOG_DEBUG, LOC + "run(): end");
129 RunEpilog();
130}
131
143{
144 QByteArray dvr_dev_path = m_dvrDevPath.toLatin1();
145 int dvr_fd = 0;
146 for (int tries = 1; ; ++tries)
147 {
148 dvr_fd = open(dvr_dev_path.constData(), O_RDONLY | O_NONBLOCK);
149 if (dvr_fd >= 0)
150 break;
151
152 LOG(VB_GENERAL, LOG_WARNING, LOC +
153 QString("Opening DVR device %1 failed : %2")
154 .arg(m_dvrDevPath, strerror(errno)));
155
156 if (tries >= 20 || (errno != EBUSY && errno != EAGAIN))
157 {
158 LOG(VB_GENERAL, LOG_ERR, LOC +
159 QString("Failed to open DVR device %1 : %2")
160 .arg(m_dvrDevPath, strerror(errno)));
161 m_bError = true;
162 return;
163 }
164 std::this_thread::sleep_for(50ms);
165 }
166
167 int remainder = 0;
168 int buffer_size = TSPacket::kSize * 15000;
169 auto *buffer = new unsigned char[buffer_size];
170 if (!buffer)
171 {
172 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate memory");
173 close(dvr_fd);
174 m_bError = true;
175 return;
176 }
177 memset(buffer, 0, buffer_size);
178
179 DeviceReadBuffer *drb = nullptr;
181 {
182 drb = new DeviceReadBuffer(this, true, false);
183 if (!drb->Setup(m_device, dvr_fd))
184 {
185 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to allocate DRB buffer");
186 delete drb;
187 delete[] buffer;
188 close(dvr_fd);
189 m_bError = true;
190 return;
191 }
192
193 drb->Start();
194 }
195
196 {
197 // SetRunning() + set m_drb
198 QMutexLocker locker(&m_startStopLock);
199 m_running = true;
201 m_usingSectionReader = false;
202 m_drb = drb;
203 }
204
205 LOG(VB_RECORD, LOG_DEBUG, LOC + "RunTS(): begin");
206
207 fd_set fd_select_set;
208 FD_ZERO( &fd_select_set); // NOLINT(readability-isolate-declaration)
209 FD_SET (dvr_fd, &fd_select_set);
210 while (m_runningDesired && !m_bError)
211 {
214
215 ssize_t len = 0;
216
217 if (drb)
218 {
219 len = drb->Read(&(buffer[remainder]), buffer_size - remainder);
220
221 // Check for DRB errors
222 if (drb->IsErrored())
223 {
224 LOG(VB_GENERAL, LOG_ERR, LOC + "Device error detected");
225 m_bError = true;
226 }
227
228 if (drb->IsEOF() && m_runningDesired)
229 {
230 LOG(VB_GENERAL, LOG_ERR, LOC + "Device EOF detected");
231 m_bError = true;
232 }
233 }
234 else
235 {
236 // timeout gets reset by select, so we need to create new one
237 struct timeval timeout = { 0, k50Milliseconds };
238 int ret = select(dvr_fd+1, &fd_select_set, nullptr, nullptr, &timeout);
239 if (ret == -1 && errno != EINTR)
240 {
241 LOG(VB_GENERAL, LOG_ERR, LOC + "select() failed" + ENO);
242 }
243 else
244 {
245 len = read(dvr_fd, &(buffer[remainder]),
246 buffer_size - remainder);
247 }
248
249 if ((0 == len) || (-1 == len))
250 {
251 std::this_thread::sleep_for(100us);
252 continue;
253 }
254 }
255
256 len += remainder;
257
258 if (len < 10) // 10 bytes = 4 bytes TS header + 6 bytes PES header
259 {
260 remainder = len;
261 continue;
262 }
263
264 m_listenerLock.lock();
265
266 if (m_streamDataList.empty())
267 {
268 m_listenerLock.unlock();
269 continue;
270 }
271
272 for (auto sit = m_streamDataList.cbegin(); sit != m_streamDataList.cend(); ++sit)
273 remainder = sit.key()->ProcessData(buffer, len);
274
275 WriteMPTS(buffer, len - remainder);
276
277 m_listenerLock.unlock();
278
279 if (remainder > 0 && (len > remainder)) // leftover bytes
280 memmove(buffer, &(buffer[len - remainder]), remainder);
281 }
282 LOG(VB_RECORD, LOG_DEBUG, LOC + "RunTS(): " + "shutdown");
283
285
286 {
287 QMutexLocker locker(&m_startStopLock);
288 m_drb = nullptr;
289 }
290
291 delete drb;
292 close(dvr_fd);
293 delete[] buffer;
294
295 LOG(VB_RECORD, LOG_DEBUG, LOC + "RunTS(): " + "end");
296
297 SetRunning(false, m_needsBuffering, false);
298}
299
307{
308 int buffer_size = 4192; // maximum size of Section we handle
309 unsigned char *buffer = pes_alloc(buffer_size);
310 if (!buffer)
311 {
312 m_bError = true;
313 return;
314 }
315
316 SetRunning(true, m_needsBuffering, true);
317
318 LOG(VB_RECORD, LOG_DEBUG, LOC + "RunSR(): begin");
319
320 while (m_runningDesired && !m_bError)
321 {
324
325 QMutexLocker read_locker(&m_pidLock);
326
327 bool readSomething = false;
328 for (auto fit = m_pidInfo.cbegin(); fit != m_pidInfo.cend(); ++fit)
329 {
330 int len = read((*fit)->m_filterFd, buffer, buffer_size);
331 if (len <= 0)
332 continue;
333
334 readSomething = true;
335
336 const PSIPTable psip(buffer);
337
338 if (psip.SectionSyntaxIndicator())
339 {
340 m_listenerLock.lock();
341 for (auto sit = m_streamDataList.cbegin(); sit != m_streamDataList.cend(); ++sit)
342 sit.key()->HandleTables(fit.key() /* pid */, psip);
343 m_listenerLock.unlock();
344 }
345 }
346
347 if (!readSomething)
348 std::this_thread::sleep_for(3ms);
349 }
350 LOG(VB_RECORD, LOG_DEBUG, LOC + "RunSR(): " + "shutdown");
351
353
354 pes_free(buffer);
355
356 SetRunning(false, m_needsBuffering, true);
357
358 LOG(VB_RECORD, LOG_DEBUG, LOC + "RunSR(): " + "end");
359}
360
361using pid_list_t = std::vector<uint>;
362
363static pid_list_t::iterator find(
364 const PIDInfoMap &map,
365 pid_list_t &list,
366 pid_list_t::iterator begin,
367 pid_list_t::iterator end, bool find_open)
368{
369 pid_list_t::iterator it;
370 for (it = begin; it != end; ++it)
371 {
372 PIDInfoMap::const_iterator mit = map.find(*it);
373 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open))
374 return it;
375 }
376
377 for (it = list.begin(); it != begin; ++it)
378 {
379 PIDInfoMap::const_iterator mit = map.find(*it);
380 if ((mit != map.end()) && ((*mit)->IsOpen() == find_open))
381 return it;
382 }
383
384 return list.end();
385}
386
388{
389 QMutexLocker writing_locker(&m_pidLock);
390 QMap<PIDPriority, pid_list_t> priority_queue;
391 QMap<PIDPriority, uint> priority_open_cnt;
392
393 for (auto cit = m_pidInfo.cbegin(); cit != m_pidInfo.cend(); ++cit)
394 {
395 PIDPriority priority = GetPIDPriority((*cit)->m_pid);
396 priority_queue[priority].push_back(cit.key());
397 if ((*cit)->IsOpen())
398 priority_open_cnt[priority]++;
399 }
400
401 for (auto & it : priority_queue)
402 std::sort(it.begin(), it.end());
403
405 i = (PIDPriority)((int)i-1))
406 {
407 while (priority_open_cnt[i] < priority_queue[i].size())
408 {
409 // if we can open a filter, just do it
410
411 // find first closed filter after first open an filter "k"
412 auto open = find(m_pidInfo, priority_queue[i],
413 priority_queue[i].begin(), priority_queue[i].end(), true);
414 if (open == priority_queue[i].end())
415 open = priority_queue[i].begin();
416
417 auto closed = find(m_pidInfo, priority_queue[i],
418 open, priority_queue[i].end(), false);
419
420 if (closed == priority_queue[i].end())
421 break; // something is broken
422
423 if (m_pidInfo[*closed]->Open(m_device, m_usingSectionReader))
424 {
426 priority_open_cnt[i]++;
427 continue;
428 }
429
430 // if we can't open a filter, try to close a lower priority one
431 bool freed = false;
432 for (auto j = (PIDPriority)((int)i - 1);
433 (j > kPIDPriorityNone) && !freed;
434 j = (PIDPriority)((int)j-1))
435 {
436 if (!priority_open_cnt[j])
437 continue;
438
439 for (uint k = 0; (k < priority_queue[j].size()) && !freed; k++)
440 {
441 PIDInfo *info = m_pidInfo[priority_queue[j][k]];
442 if (!info->IsOpen())
443 continue;
444
445 if (info->Close(m_device))
446 freed = true;
447
449 priority_open_cnt[j]--;
450 }
451 }
452
453 if (freed)
454 {
455 // if we can open a filter, just do it
456 if (m_pidInfo[*closed]->Open(
458 {
460 priority_open_cnt[i]++;
461 continue;
462 }
463 }
464
465 // we have to cycle within our priority level
466
467 if (m_cycleTimer.elapsed() < 1s)
468 break; // we don't want to cycle too often
469
470 if (!m_pidInfo[*open]->IsOpen())
471 break; // nothing to close..
472
473 // close "open"
474 bool ok = m_pidInfo[*open]->Close(m_device);
476 priority_open_cnt[i]--;
477
478 // open "closed"
479 if (ok && m_pidInfo[*closed]->
481 {
483 priority_open_cnt[i]++;
484 }
485
486 break; // we only want to cycle once per priority per run
487 }
488 }
489
491}
492
494 bool allow,
495 DTVSignalMonitor *sigmon,
496 DVBChannel *dvbchan)
497{
498 if (allow && sigmon && dvbchan)
499 {
500 m_allowRetune = true;
501 m_sigMon = sigmon;
502 m_dvbChannel = dvbchan;
503 }
504 else
505 {
506 m_allowRetune = false;
507 m_sigMon = nullptr;
508 m_dvbChannel = nullptr;
509 }
510}
511
513{
514 if (!m_allowRetune)
515 return;
516
517 // Rotor position
519 {
520 const DiSEqCDevRotor *rotor = m_dvbChannel->GetRotor();
521 if (rotor)
522 {
523 bool was_moving = false;
524 bool is_moving = false;
525 m_sigMon->GetRotorStatus(was_moving, is_moving);
526
527 // Retune if move completes normally
528 if (was_moving && !is_moving)
529 {
530 LOG(VB_CHANNEL, LOG_INFO,
531 LOC + "Retuning for rotor completion");
533
534 // (optionally) No need to wait for SDT anymore...
535 // RemoveFlags(kDTVSigMon_WaitForSDT);
536 }
537 }
538 else
539 {
540 // If no rotor is present, pretend the movement is completed
542 }
543 }
544}
545
555{
556 const uint pat_pid = 0x0;
557
558 {
559 QMutexLocker locker(&s_rec_supportsTsMonitoringLock);
560 QMap<QString,bool>::const_iterator it;
561 it = s_recSupportsTsMonitoring.constFind(m_device);
562 if (it != s_recSupportsTsMonitoring.constEnd())
563 return *it;
564 }
565
566 QByteArray dvr_dev_path = m_dvrDevPath.toLatin1();
567 int dvr_fd = open(dvr_dev_path.constData(), O_RDONLY | O_NONBLOCK);
568 if (dvr_fd < 0)
569 {
570 QMutexLocker locker(&s_rec_supportsTsMonitoringLock);
572 return false;
573 }
574
575 bool supports_ts = false;
576 if (AddPIDFilter(new DVBPIDInfo(pat_pid)))
577 {
578 supports_ts = true;
579 RemovePIDFilter(pat_pid);
580 }
581
582 close(dvr_fd);
583
584 QMutexLocker locker(&s_rec_supportsTsMonitoringLock);
585 s_recSupportsTsMonitoring[m_device] = supports_ts;
586
587 return supports_ts;
588}
589
590#undef LOC
591
592#define LOC QString("PIDInfo(%1): ").arg(dvb_dev)
593
594bool DVBPIDInfo::Open(const QString &dvb_dev, bool use_section_reader)
595{
596 if (m_filterFd >= 0)
597 {
599 m_filterFd = -1;
600 }
601
602 QString demux_fn = CardUtil::GetDeviceName(DVB_DEV_DEMUX, dvb_dev);
603 QByteArray demux_ba = demux_fn.toLatin1();
604
605 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Opening filter for pid 0x%1")
606 .arg(m_pid, 0, 16));
607
608 int mux_fd = open(demux_ba.constData(), O_RDWR | O_NONBLOCK);
609 if (mux_fd == -1)
610 {
611 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to open demux device %1 "
612 "for filter on pid 0x%2")
613 .arg(demux_fn).arg(m_pid, 0, 16));
614 return false;
615 }
616
617 if (!use_section_reader)
618 {
619 struct dmx_pes_filter_params pesFilterParams {};
620 pesFilterParams.pid = (uint16_t) m_pid;
621 pesFilterParams.input = DMX_IN_FRONTEND;
622 pesFilterParams.output = DMX_OUT_TS_TAP;
623 pesFilterParams.flags = DMX_IMMEDIATE_START;
624 pesFilterParams.pes_type = DMX_PES_OTHER;
625
626 if (ioctl(mux_fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0)
627 {
628 LOG(VB_GENERAL, LOG_ERR, LOC +
629 QString("Failed to set TS filter (pid 0x%1)")
630 .arg(m_pid, 0, 16));
631
632 close(mux_fd);
633 return false;
634 }
635 }
636 else
637 {
638 struct dmx_sct_filter_params sctFilterParams {};
639 switch ( m_pid )
640 {
641 case 0x0: // PAT
642 sctFilterParams.filter.filter[0] = 0;
643 sctFilterParams.filter.mask[0] = 0xff;
644 break;
645 case 0x0010: // assume this is for an NIT, NITo, PMT
646 // This filter will give us table ids 0x00-0x03, 0x40-0x43
647 // we expect to see table ids 0x02, 0x40 and 0x41 on this PID
648 // NOTE: In theory, this will break with ATSC when PID 0x10
649 // is used for ATSC/MPEG tables. This is frowned upon,
650 // but PMTs have been seen on in the wild.
651 sctFilterParams.filter.filter[0] = 0x00;
652 sctFilterParams.filter.mask[0] = 0xbc;
653 break;
654 case 0x0011: // assume this is for an SDT, SDTo, PMT
655 // This filter will give us table ids 0x02, 0x06, 0x42 and 0x46
656 // All but 0x06 are ones we want to see.
657 // NOTE: In theory this will break with ATSC when pid 0x11
658 // is used for random ATSC tables. In practice only
659 // video data has been seen on 0x11.
660 sctFilterParams.filter.filter[0] = 0x02;
661 sctFilterParams.filter.mask[0] = 0xbb;
662 break;
663 case 0x1ffb: // assume this is for various ATSC tables
664 // MGT 0xC7, Terrestrial VCT 0xC8, Cable VCT 0xC9, RRT 0xCA,
665 // STT 0xCD, DCCT 0xD3, DCCSCT 0xD4, Caption 0x86
666 sctFilterParams.filter.filter[0] = 0x80;
667 sctFilterParams.filter.mask[0] = 0xa0;
668 break;
669 default:
670 // otherwise assume it could be any table
671 sctFilterParams.filter.filter[0] = 0x00;
672 sctFilterParams.filter.mask[0] = 0x00;
673 break;
674 }
675 sctFilterParams.pid = (uint16_t) m_pid;
676 sctFilterParams.timeout = 0;
677 sctFilterParams.flags = DMX_IMMEDIATE_START;
678
679 if (ioctl(mux_fd, DMX_SET_FILTER, &sctFilterParams) < 0)
680 {
681 LOG(VB_GENERAL, LOG_ERR, LOC +
682 "Failed to set \"section\" filter " +
683 QString("(pid 0x%1) (filter %2)").arg(m_pid, 0, 16)
684 .arg(sctFilterParams.filter.filter[0]));
685 close(mux_fd);
686 return false;
687 }
688 }
689
690 m_filterFd = mux_fd;
691
692 return true;
693}
694
695bool DVBPIDInfo::Close(const QString &dvb_dev)
696{
697 LOG(VB_RECORD, LOG_DEBUG, LOC +
698 QString("Closing filter for pid 0x%1").arg(m_pid, 0, 16));
699
700 if (!IsOpen())
701 return false;
702
703 int tmp = m_filterFd;
704 m_filterFd = -1;
705
706 int err = close(tmp);
707 if (err < 0)
708 {
709 LOG(VB_GENERAL, LOG_ERR,
710 LOC + QString("Failed to close mux (pid 0x%1)")
711 .arg(m_pid, 0, 16) + ENO);
712
713 return false;
714 }
715
716 return true;
717}
718
719#if 0
720
721// We don't yet do kernel buffer allocation in dvbstreamhandler..
722
723int DVBRecorder::OpenFilterFd(uint pid, int pes_type, uint stream_type)
724{
725 if (_open_pid_filters >= _max_pid_filters)
726 return -1;
727
728 // bits per millisecond
729 uint bpms = (StreamID::IsVideo(stream_type)) ? 19200 : 500;
730 // msec of buffering we want
731 std::chrono::milliseconds msec_of_buffering = std::max(POLL_WARNING_TIMEOUT + 50ms, 1500ms);
732 // actual size of buffer we need
733 uint pid_buffer_size = ((bpms*msec_of_buffering.count() + 7) / 8);
734 // rounded up to the nearest page
735 pid_buffer_size = ((pid_buffer_size + 4095) / 4096) * 4096;
736
737 LOG(VB_RECORD, LOG_DEBUG, LOC + QString("Adding pid 0x%1 size(%2)")
738 .arg(pid,0,16).arg(pid_buffer_size));
739
740 // Open the demux device
741 QString dvbdev = CardUtil::GetDeviceName(
742 DVB_DEV_DEMUX, _card_number_option);
743 QByteArray dev = dvbdev.toLatin1();
744
745 int fd_tmp = open(dev.constData(), O_RDWR);
746 if (fd_tmp < 0)
747 {
748 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not open demux device." + ENO);
749 _max_pid_filters = _open_pid_filters;
750 return -1;
751 }
752
753 // Try to make the demux buffer large enough to
754 // allow for longish disk writes.
755 uint sz = pid_buffer_size;
756 std::chrono::microseconds usecs = msec_of_buffering;
757 while (ioctl(fd_tmp, DMX_SET_BUFFER_SIZE, sz) < 0 && sz > 1024*8)
758 {
759 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set demux buffer size for "+
760 QString("pid 0x%1 to %2").arg(pid,0,16).arg(sz) + ENO);
761
762 sz /= 2;
763 sz = ((sz+4095)/4096)*4096;
764 usecs /= 2;
765 }
766#if 0
767 LOG(VB_RECORD, LOG_DEBUG, LOC + "Set demux buffer size for " +
768 QString("pid 0x%1 to %2,\n\t\t\twhich gives us a %3 msec buffer.")
769 .arg(pid,0,16).arg(sz)
770 .arg(duration_cast<std::chrono::milliseconds>(usecs).count()));
771#endif
772
773 // Set the filter type
774 struct dmx_pes_filter_params params;
775 memset(&params, 0, sizeof(params));
776 params.input = DMX_IN_FRONTEND;
777 params.output = DMX_OUT_TS_TAP;
778 params.flags = DMX_IMMEDIATE_START;
779 params.pid = pid;
780 params.pes_type = (dmx_pes_type_t) pes_type;
781 if (ioctl(fd_tmp, DMX_SET_PES_FILTER, &params) < 0)
782 {
783 close(fd_tmp);
784
785 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to set demux filter." + ENO);
786 _max_pid_filters = _open_pid_filters;
787 return -1;
788 }
789
790 _open_pid_filters++;
791 return fd_tmp;
792}
793#endif
@ DVB_DEV_DEMUX
Definition: cardutil.h:32
@ DVB_DEV_DVR
Definition: cardutil.h:31
Collection of helper utilities for input DB use.
Definition: cardutil.h:42
static QString GetDeviceName(dvb_dev_type_t type, const QString &device)
Definition: cardutil.cpp:2967
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.
Definition: dvbchannel.h:31
bool Retune(void) override
Definition: dvbchannel.cpp:983
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.
DeviceReadBuffer * m_drb
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
bool IsEOF(void) const
Rotor class.
Definition: diseqc.h:303
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
QThread::Priority priority(void) const
Definition: mthread.cpp:253
void setObjectName(const QString &name)
Definition: mthread.cpp:238
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
int m_filterFd
Input filter file descriptor.
Definition: streamhandler.h:43
uint m_pid
Definition: streamhandler.h:42
bool IsOpen(void) const
Definition: streamhandler.h:40
A PSIP table is a variant of a PES packet containing an MPEG, ATSC or DVB table.
Definition: mpegtables.h:410
bool SectionSyntaxIndicator(void) const
Definition: mpegtables.h:499
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)
MythTimer m_cycleTimer
void WriteMPTS(const unsigned char *buffer, uint len)
Write out a copy of the raw MPTS.
QString m_device
PIDInfoMap m_pidInfo
volatile bool m_runningDesired
volatile bool m_bError
bool RemoveAllPIDFilters(void)
void SetRunning(bool running, bool using_buffering, bool using_section_reader)
QMutex m_startStopLock
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.
Definition: mpegtables.h:168
static constexpr unsigned int kSize
Definition: tspacket.h:261
#define O_NONBLOCK
Definition: compat.h:258
unsigned int uint
Definition: compat.h:68
#define close
Definition: compat.h:30
#define LOC
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
static guint32 * tmp
Definition: goom_core.cpp:26
unsigned short uint16_t
Definition: iso6937tables.h:3
PIDPriority
@ kPIDPriorityNone
@ kPIDPriorityHigh
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:74
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
dictionary info
Definition: azlyrics.py:7
def read(device=None, features=[])
Definition: disc.py:35
void pes_free(unsigned char *ptr)
Definition: pespacket.cpp:380
unsigned char * pes_alloc(uint size)
Definition: pespacket.cpp:368
QMap< uint, PIDInfo * > PIDInfoMap
Definition: streamhandler.h:50