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