MythTV master
channelscan_sm.cpp
Go to the documentation of this file.
1/* -*- Mode: c++ -*-
2 * vim: set expandtab tabstop=4 shiftwidth=4:
3 *
4 * Original Project
5 * MythTV http://www.mythtv.org
6 *
7 * Copyright (c) 2004, 2005 John Pullan <john@pullan.org>
8 * Copyright (c) 2005 - 2007 Daniel Kristjansson
9 *
10 * Description:
11 * Collection of classes to provide channel scanning functionallity
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27 *
28 */
29
30// C includes
31#include <unistd.h>
32
33// C++ includes
34#include <algorithm>
35#include <utility>
36
37// Qt includes
38#include <QMutexLocker>
39#include <QObject>
40
41// MythTV includes - Other Libs
42#include "libmythbase/mthread.h"
43#include "libmythbase/mythdb.h"
45#include "libmythbase/mythconfig.h"
47
48// MythTV includes - General
49#include "cardutil.h"
50#include "channelscan_sm.h"
51#include "channelutil.h"
52#include "frequencies.h"
53#include "scanwizardconfig.h"
54#include "sourceutil.h"
55
56// MythTV includes - DTV
57#include "mpeg/scanstreamdata.h"
59
60// MythTV includes - ATSC
61#include "mpeg/atsctables.h"
62
63// MythTV includes - DVB
64#include "mpeg/dvbtables.h"
66
70
74const std::chrono::milliseconds ChannelScanSM::kDVBTableTimeout = 30s;
76const std::chrono::milliseconds ChannelScanSM::kATSCTableTimeout = 10s;
78const std::chrono::milliseconds ChannelScanSM::kMPEGTableTimeout = 15s;
79
80// Freesat and Sky
81static const uint kRegionUndefined = 0xFFFF; // Not regional
82
83QString ChannelScanSM::loc(const ChannelScanSM *siscan)
84{
85 if (siscan && siscan->m_channel)
86 return QString("ChannelScanSM[%1]").arg(siscan->m_channel->GetInputID());
87 return "ChannelScanSM(u)";
88}
89
90#define LOC (ChannelScanSM::loc(this) + ": ")
91
92static constexpr qint64 kDecryptionTimeout { 4250 };
93
94static const QString kATSCChannelFormat = "%1.%2";
95
97{
98 public:
99 ScannedChannelInfo() = default;
100
101 bool IsEmpty() const
102 {
103 return m_pats.empty() && m_pmts.empty() &&
104 m_programEncryptionStatus.isEmpty() &&
105 !m_mgt && m_cvcts.empty() &&
106 m_tvcts.empty() && m_nits.empty() &&
107 m_sdts.empty() && m_bats.empty();
108 }
109
110 // MPEG
113 QMap<uint,uint> m_programEncryptionStatus; // pnum->enc_status
114
115 // ATSC
116 const MasterGuideTable *m_mgt {nullptr};
119
120 // DVB
124};
125
150 const QString &cardtype, ChannelBase *channel,
151 int sourceID, std::chrono::milliseconds signal_timeout,
152 std::chrono::milliseconds channel_timeout, QString inputname,
153 bool test_decryption)
154 : // Set in constructor
155 m_scanMonitor(scan_monitor),
156 m_channel(channel),
157 m_signalMonitor(SignalMonitor::Init(cardtype, m_channel->GetInputID(),
158 channel, true)),
159 m_sourceID(sourceID),
160 m_signalTimeout(signal_timeout),
161 m_channelTimeout(channel_timeout),
162 m_inputName(std::move(inputname)),
163 m_testDecryption(test_decryption),
164 // Misc
165 m_analogSignalHandler(new AnalogSignalHandler(this))
166{
169
170 // Create a stream data for digital signal monitors
172 if (dtvSigMon)
173 {
174 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Connecting up DTVSignalMonitor");
175 auto *data = new ScanStreamData();
176
178 query.prepare(
179 "SELECT dvb_nit_id, bouquet_id, region_id, lcnoffset "
180 "FROM videosource "
181 "WHERE videosource.sourceid = :SOURCEID");
182 query.bindValue(":SOURCEID", m_sourceID);
183 if (!query.exec() || !query.isActive())
184 {
185 MythDB::DBError("ChannelScanSM", query);
186 }
187 else if (query.next())
188 {
189 int nitid = query.value(0).toInt();
190 data->SetRealNetworkID(nitid);
191 LOG(VB_CHANSCAN, LOG_INFO, LOC +
192 QString("Setting NIT-ID to %1").arg(nitid));
193
194 m_bouquetId = query.value(1).toUInt();
195 m_regionId = query.value(2).toUInt();
196 m_lcnOffset = query.value(3).toUInt();
197 m_nitId = nitid > 0 ? nitid : 0;
198 }
199
200 LOG(VB_CHANSCAN, LOG_INFO, LOC +
201 QString("Freesat/Sky bouquet_id:%1 region_id:%2")
202 .arg(m_bouquetId).arg(m_regionId));
203
204 dtvSigMon->SetStreamData(data);
209
210#if CONFIG_DVB
211 auto *dvbchannel = dynamic_cast<DVBChannel*>(m_channel);
212 if (dvbchannel && dvbchannel->GetRotor())
214#endif
215
216 data->AddMPEGListener(this);
217 data->AddATSCMainListener(this);
218 data->AddDVBMainListener(this);
219 data->AddDVBOtherListener(this);
220 }
221}
222
224{
225 StopScanner();
226 LOG(VB_CHANSCAN, LOG_INFO, LOC + "ChannelScanSM Stopped");
227
228 ScanStreamData *sd = nullptr;
230 {
232 }
233
234 if (m_signalMonitor)
235 {
237 delete m_signalMonitor;
238 m_signalMonitor = nullptr;
239 }
240
241 delete sd;
242
244 {
246 m_analogSignalHandler = nullptr;
247 }
248
250}
251
252void ChannelScanSM::SetAnalog(bool is_analog)
253{
255
256 if (is_analog)
258}
259
261{
262 QMutexLocker locker(&m_lock);
263
264 QString cur_chan = (*m_current).m_friendlyName;
265 QStringList list = cur_chan.split(" ", Qt::SkipEmptyParts);
266 QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
267
268 QString msg = QObject::tr("Updated Channel %1").arg(cur_chan);
269
271 {
272 int chanid = ChannelUtil::CreateChanID(m_sourceID, freqid);
273
274 QString callsign = QString("%1-%2")
275 .arg(ChannelUtil::GetUnknownCallsign()).arg(chanid);
276
278 0 /* mplexid */,
280 chanid,
281 callsign,
282 "" /* service name */,
283 freqid /* channum */,
284 0 /* service id */,
285 0 /* ATSC major channel */,
286 0 /* ATSC minor channel */,
287 false /* use on air guide */,
288 kChannelVisible /* visible */,
289 freqid);
290
291 msg = (ok) ?
292 QObject::tr("Added Channel %1").arg(cur_chan) :
293 QObject::tr("Failed to add channel %1").arg(cur_chan);
294 }
295 else
296 {
297 // nothing to do here, XMLTV has better info
298 }
299
301
302 // tell UI we are done with these channels
303 if (m_scanning)
304 {
306 m_waitingForTables = false;
308 m_dvbt2Tried = true;
309 }
310}
311
323bool ChannelScanSM::ScanExistingTransports(uint sourceid, bool follow_nit)
324{
325 if (m_scanning)
326 return false;
327
328 m_scanTransports.clear();
330
331 std::vector<uint> multiplexes = SourceUtil::GetMplexIDs(sourceid);
332
333 if (multiplexes.empty())
334 {
335 LOG(VB_CHANSCAN, LOG_ERR, LOC + "Unable to find any transports for " +
336 QString("sourceid %1").arg(sourceid));
337
338 return false;
339 }
340
341 LOG(VB_CHANSCAN, LOG_INFO, LOC +
342 QString("Found %1 transports for ").arg(multiplexes.size()) +
343 QString("sourceid %1").arg(sourceid));
344
345 for (uint multiplex : multiplexes)
346 AddToList(multiplex);
347
348 m_extendScanList = follow_nit;
349 m_waitingForTables = false;
351 if (!m_scanTransports.empty())
352 {
353 m_nextIt = m_scanTransports.begin();
354 m_scanning = true;
355 }
356 else
357 {
358 LOG(VB_CHANSCAN, LOG_ERR, LOC +
359 "Unable to find add any transports for " +
360 QString("sourceid %1").arg(sourceid));
361
362 return false;
363 }
364
365 return m_scanning;
366}
367
368void ChannelScanSM::LogLines(const QString& string)
369{
370 if (VERBOSE_LEVEL_CHECK(VB_CHANSCAN, LOG_DEBUG))
371 {
372 QStringList lines = string.split('\n');
373 for (const QString& line : std::as_const(lines))
374 LOG(VB_CHANSCAN, LOG_DEBUG, line);
375 }
376}
377
379{
380 QMutexLocker locker(&m_lock);
381
382 LOG(VB_CHANSCAN, LOG_INFO, LOC +
383 QString("Got a Program Association Table for %1")
384 .arg((*m_current).m_friendlyName));
385 LogLines(pat->toString());
386
387 // Add pmts to list, so we can do MPEG scan properly.
389 if (nullptr == monitor)
390 return;
391 ScanStreamData *sd = monitor->GetScanStreamData();
392 for (uint i = 0; i < pat->ProgramCount(); ++i)
393 {
394 sd->AddListeningPID(pat->ProgramPID(i));
395 }
396}
397
399{
400 QMutexLocker locker(&m_lock);
401
402 LOG(VB_CHANSCAN, LOG_INFO, LOC +
403 QString("Got a Conditional Access Table for %1")
404 .arg((*m_current).m_friendlyName));
405 LogLines(cat->toString());
406}
407
408void ChannelScanSM::HandlePMT(uint /*program_num*/, const ProgramMapTable *pmt)
409{
410 QMutexLocker locker(&m_lock);
411
412 LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got a Program Map Table for %1 program %2 (0x%3)")
413 .arg((*m_current).m_friendlyName).arg(pmt->ProgramNumber())
414 .arg(pmt->ProgramNumber(),4,16,QChar('0')));
415 LogLines(pmt->toString());
416
418 pmt->IsEncrypted(GetDTVChannel()->GetSIStandard()))
420
421 UpdateChannelInfo(true);
422}
423
425{
426 QMutexLocker locker(&m_lock);
427
428 LOG(VB_CHANSCAN, LOG_INFO, LOC +
429 QString("Got a Virtual Channel Table for %1")
430 .arg((*m_current).m_friendlyName));
431 LogLines(vct->toString());
432
433 for (uint i = 0; !m_currentTestingDecryption && i < vct->ChannelCount(); ++i)
434 {
435 if (vct->IsAccessControlled(i))
436 {
438 }
439 }
440
441 UpdateChannelInfo(true);
442}
443
445{
446 QMutexLocker locker(&m_lock);
447
448 LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Got the Master Guide for %1")
449 .arg((*m_current).m_friendlyName));
450 LogLines(mgt->toString());
451
452 UpdateChannelInfo(true);
453}
454
463{
464 QMutexLocker locker(&m_lock);
465
466 LOG(VB_CHANSCAN, LOG_INFO, LOC +
467 QString("Got a Service Description Table for %1 section %2/%3")
468 .arg((*m_current).m_friendlyName)
469 .arg(sdt->Section()).arg(sdt->LastSection()));
470 LogLines(sdt->toString());
471
472 // If this is Astra 28.2 add start listening for Freesat BAT and SDTo
473 if (!m_setOtherTables && (
476 {
478 if (nullptr != monitor)
479 {
480 ScanStreamData *stream = monitor->GetScanStreamData();
481 if (nullptr != stream)
482 {
483 stream->SetFreesatAdditionalSI(true);
484 m_setOtherTables = true;
485 // The whole BAT & SDTo group comes round in 10s
487 // Delay processing the SDT until we've seen BATs and SDTos
488 m_otherTableTime = std::chrono::milliseconds(m_timer.elapsed()) + m_otherTableTimeout;
489
490 LOG(VB_CHANSCAN, LOG_INFO, LOC +
491 QString("SDT has OriginalNetworkID %1, look for "
492 "additional Freesat SI").arg(sdt->OriginalNetworkID()));
493 }
494 }
495 }
496
497 if (!m_timer.hasExpired(m_otherTableTime.count()))
498 {
499 // Set the version for the SDT so we see it again.
501 if (nullptr != monitor)
502 {
503 monitor->GetDVBStreamData()->
504 SetVersionSDT(sdt->TSID(), -1, 0);
505 }
506 }
507
508 uint id = sdt->OriginalNetworkID() << 16 | sdt->TSID();
509 m_tsScanned.insert(id);
510
511 for (uint i = 0; !m_currentTestingDecryption && i < sdt->ServiceCount(); ++i)
512 {
513 if (sdt->IsEncrypted(i))
514 {
516 }
517 }
518
519 UpdateChannelInfo(true);
520}
521
523{
524 QMutexLocker locker(&m_lock);
525
526 LOG(VB_CHANSCAN, LOG_INFO, LOC +
527 QString("Got a Network Information Table id %1 for %2 section %3/%4")
528 .arg(nit->NetworkID()).arg((*m_current).m_friendlyName)
529 .arg(nit->Section()).arg(nit->LastSection()));
530 LogLines(nit->toString());
531
532 UpdateChannelInfo(true);
533}
534
536{
537 QMutexLocker locker(&m_lock);
538
539 LOG(VB_CHANSCAN, LOG_INFO, LOC +
540 QString("Got a Bouquet Association Table id %1 for %2 section %3/%4")
541 .arg(bat->BouquetID()).arg((*m_current).m_friendlyName)
542 .arg(bat->Section()).arg(bat->LastSection()));
543 LogLines(bat->toString());
544
545 m_otherTableTime = std::chrono::milliseconds(m_timer.elapsed()) + m_otherTableTimeout;
546
547 for (uint i = 0; i < bat->TransportStreamCount(); ++i)
548 {
549 uint tsid = bat->TSID(i);
550 uint netid = bat->OriginalNetworkID(i);
551 desc_list_t parsed =
554 // Look for default authority
555 const unsigned char *def_auth =
557 const unsigned char *serv_list =
559
560 if (def_auth && serv_list)
561 {
562 DefaultAuthorityDescriptor authority(def_auth);
563 ServiceListDescriptor services(serv_list);
564 if (!authority.IsValid() || !services.IsValid())
565 continue;
566
567 for (uint j = 0; j < services.ServiceCount(); ++j)
568 {
569 // If the default authority is given in the SDT this
570 // overrides any definition in the BAT (or in the NIT)
571 LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
572 QString("Found default authority '%1' in BAT for service nid %2 tid %3 sid %4")
573 .arg(authority.DefaultAuthority())
574 .arg(netid).arg(tsid).arg(services.ServiceID(j)));
575 uint64_t index = ((uint64_t)netid << 32) | (tsid << 16) |
576 services.ServiceID(j);
577 if (! m_defAuthorities.contains(index))
578 m_defAuthorities[index] = authority.DefaultAuthority();
579 }
580 }
581 }
582 UpdateChannelInfo(true);
583}
584
586{
587 QMutexLocker locker(&m_lock);
588#if 0
589 LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
590 QString("Got a Service Description Table (other) for Transport ID %1 section %2/%3")
591 .arg(tsid).arg(sdt->Section()).arg(sdt->LastSection()));
592 LogLines(sdt->toString());
593#endif
594 m_otherTableTime = std::chrono::milliseconds(m_timer.elapsed()) + m_otherTableTimeout;
595
596 uint netid = sdt->OriginalNetworkID();
597
598 for (uint i = 0; i < sdt->ServiceCount(); ++i)
599 {
600 uint serviceId = sdt->ServiceID(i);
601 desc_list_t parsed =
604 // Look for default authority
605 const unsigned char *def_auth =
607 if (def_auth)
608 {
609 DefaultAuthorityDescriptor authority(def_auth);
610 if (!authority.IsValid())
611 continue;
612#if 0
613 LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
614 QString("Found default authority '%1' in SDTo for service nid %2 tid %3 sid %4")
615 .arg(authority.DefaultAuthority())
616 .arg(netid).arg(tsid).arg(serviceId));
617#endif
618 m_defAuthorities[((uint64_t)netid << 32) | (tsid << 16) | serviceId] =
619 authority.DefaultAuthority();
620 }
621 }
622}
623
625{
626 QMutexLocker locker(&m_lock);
627
629
632
633 UpdateChannelInfo(true);
634}
635
637{
638 if (!m_currentInfo || m_currentInfo->m_pmts.empty())
639 {
640 LOG(VB_GENERAL, LOG_ERR, LOC + "Can't monitor decryption -- no pmts");
642 return false;
643 }
644
645 while (true)
646 {
647 uint pnum = 0;
648 QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.cbegin();
649#if 0
650 LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("%1/%2 checked")
651 .arg(currentEncryptionStatusChecked.size())
652 .arg(currentEncryptionStatus.size()));
653#endif
654 while (it != m_currentEncryptionStatus.cend())
655 {
657 {
658 pnum = it.key();
659 break;
660 }
661 ++it;
662 }
663
664 if (!pnum)
665 break;
666
668
669 if (!m_testDecryption)
670 {
672 continue;
673 }
674
675 const ProgramMapTable *pmt = nullptr;
676 for (uint i = 0; !pmt && (i < m_currentInfo->m_pmts.size()); ++i)
677 {
678 pmt = (m_currentInfo->m_pmts[i]->ProgramNumber() == pnum) ?
679 m_currentInfo->m_pmts[i] : nullptr;
680 }
681
682 if (pmt)
683 {
684 QString cur_chan;
685 QString cur_chan_tr;
686 GetCurrentTransportInfo(cur_chan, cur_chan_tr);
687
688 QString msg_tr =
689 QObject::tr("Program %1 Testing Decryption")
690 .arg(pnum);
691 QString msg =
692 QString("%1 -- Testing decryption of program %2")
693 .arg(cur_chan).arg(pnum);
694
696 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
697
698#if CONFIG_DVB
699 if (GetDVBChannel())
700 GetDVBChannel()->SetPMT(pmt);
701#endif // CONFIG_DVB
702
704 if (nullptr != monitor)
705 {
707 monitor->GetStreamData()->TestDecryption(pmt);
708 }
709
711 m_timer.start();
712 return true;
713 }
714
715 LOG(VB_GENERAL, LOG_INFO, LOC +
716 QString("Can't monitor decryption of program %1 -- no pmt")
717 .arg(pnum));
718
719 }
720
722 return false;
723}
724
726{
729
730 const DTVChannel *chan = GetDTVChannel();
731
732 if (!chan)
733 return type;
734
735 std::vector<DTVTunerType> tts = chan->GetTunerTypes();
736
737 for (auto & tt : tts)
738 {
739 if (tt == type)
740 return type;
741 }
742
743 if (!tts.empty())
744 return tts[0];
745
746 return type;
747}
748
750{
751 LOG(VB_CHANSCAN, LOG_DEBUG, LOC + QString("%1 NIT nid:%2 fr:%3 section:%4/%5 ts count:%6 ")
752 .arg(__func__).arg(nit->NetworkID()).arg(nit_frequency).arg(nit->Section()).arg(nit->LastSection())
753 .arg(nit->TransportStreamCount()));
754
755 for (uint i = 0; i < nit->TransportStreamCount(); ++i)
756 {
757 uint32_t tsid = nit->TSID(i);
758 uint32_t netid = nit->OriginalNetworkID(i);
759 uint32_t id = netid << 16 | tsid;
760
761 if (m_tsScanned.contains(id) || m_extendTransports.contains(id))
762 continue;
763
764 const desc_list_t& list =
767
768 for (const auto * const item : list)
769 {
770 uint64_t frequency = 0;
771 const MPEGDescriptor desc(item);
772 uint tag = desc.DescriptorTag();
773// QString tagString = desc.DescriptorTagString();
774
776 switch (tag)
777 {
779 {
781 if (cd.IsValid())
782 frequency = cd.FrequencyHz();
784 break;
785 }
787 {
788 switch (desc.DescriptorTagExtension())
789 {
791 {
793 continue; // T2 descriptor not yet used
794 }
795 default:
796 continue; // Next descriptor
797 }
798 }
800 {
802 if (cd.IsValid())
803 frequency = cd.FrequencykHz();
805 break;
806 }
808 {
810 continue; // S2 descriptor not yet used
811 }
813 {
814 const CableDeliverySystemDescriptor cd(desc);
815 if (cd.IsValid())
816 frequency = cd.FrequencyHz();
818 break;
819 }
820 default:
821 continue; // Next descriptor
822 }
823
824 // Have now a delivery system descriptor
825 tt = GuessDTVTunerType(tt);
826 DTVMultiplex tuning;
827 if (tuning.FillFromDeliverySystemDesc(tt, desc))
828 {
829 LOG(VB_CHANSCAN, LOG_DEBUG, QString("NIT onid:%1 add ts(%2):%3 %4")
830 .arg(netid).arg(i).arg(tsid).arg(tuning.toString()));
831 m_extendTransports[id] = tuning;
832 }
833 else
834 {
835 LOG(VB_CHANSCAN, LOG_DEBUG, QString("NIT onid:%1 cannot add ts(%2):%3 fr:%4")
836 .arg(netid).arg(i).arg(tsid).arg(frequency));
837 }
838
839 // Next TS in loop
840 break;
841 }
842 }
843}
844
845bool ChannelScanSM::UpdateChannelInfo(bool wait_until_complete)
846{
847 QMutexLocker locker(&m_mutex);
848
849 if (m_current == m_scanTransports.end())
850 return true;
851
852 if (wait_until_complete && !m_waitingForTables)
853 return true;
854
855 if (wait_until_complete && m_currentTestingDecryption)
856 return false;
857
859 if (!dtv_sm)
860 return false;
861
862 const ScanStreamData *sd = dtv_sm->GetScanStreamData();
863
864 if (!m_currentInfo)
866
867 bool transport_tune_complete = true;
868
869 // MPEG
870
871 // Grab PAT tables
872 pat_vec_t pattmp = sd->GetCachedPATs();
873 QMap<uint,bool> tsid_checked;
874 for (auto & pat : pattmp)
875 {
876 uint tsid = pat->TransportStreamID();
877 if (tsid_checked[tsid])
878 continue;
879 tsid_checked[tsid] = true;
880 if (m_currentInfo->m_pats.contains(tsid))
881 continue;
882
883 if (!wait_until_complete || sd->HasCachedAllPAT(tsid))
884 {
885 m_currentInfo->m_pats[tsid] = sd->GetCachedPATs(tsid);
886 if (!m_currentInfo->m_pmts.empty())
887 {
889 m_currentInfo->m_pmts.clear();
890 }
891 }
892 else
893 {
894 transport_tune_complete = false;
895 }
896 }
897 transport_tune_complete &= !pattmp.empty();
898 sd->ReturnCachedPATTables(pattmp);
899
900 // Grab PMT tables
901 if ((!wait_until_complete || sd->HasCachedAllPMTs()) &&
902 m_currentInfo->m_pmts.empty())
904
905 // ATSC
906 if (!m_currentInfo->m_mgt && sd->HasCachedMGT())
908
909 if ((!wait_until_complete || sd->HasCachedAllCVCTs()) &&
910 m_currentInfo->m_cvcts.empty())
911 {
913 }
914
915 if ((!wait_until_complete || sd->HasCachedAllTVCTs()) &&
916 m_currentInfo->m_tvcts.empty())
917 {
919 }
920
921 // DVB
922 if ((!wait_until_complete || sd->HasCachedAllNIT()) &&
923 (m_currentInfo->m_nits.empty() ||
924 m_timer.hasExpired(m_otherTableTime.count())))
925 {
927 }
928
929 sdt_vec_t sdttmp = sd->GetCachedSDTs();
930 tsid_checked.clear();
931 for (auto & sdt : sdttmp)
932 {
933 uint tsid = sdt->TSID();
934 if (tsid_checked[tsid])
935 continue;
936 tsid_checked[tsid] = true;
937 if (m_currentInfo->m_sdts.contains(tsid))
938 continue;
939
940 if (!wait_until_complete || sd->HasCachedAllSDT(tsid))
941 m_currentInfo->m_sdts[tsid] = sd->GetCachedSDTSections(tsid);
942 }
943 sd->ReturnCachedSDTTables(sdttmp);
944
945 if ((!wait_until_complete || sd->HasCachedAllBATs()) &&
946 (m_currentInfo->m_bats.empty() ||
947 m_timer.hasExpired(m_otherTableTime.count())))
948 {
950 }
951
952 // Check if transport tuning is complete
953 if (transport_tune_complete)
954 {
955 transport_tune_complete &= !m_currentInfo->m_pmts.empty();
956
957 if (!(sd->HasCachedMGT() || sd->HasCachedAnyNIT()))
958 {
959 transport_tune_complete = false;
960 }
961
962 if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
963 {
964 transport_tune_complete &= sd->HasCachedMGT();
965 transport_tune_complete &=
966 (!m_currentInfo->m_tvcts.empty() || !m_currentInfo->m_cvcts.empty());
967 }
968 else if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
969 {
970 transport_tune_complete &= !m_currentInfo->m_nits.empty();
971 transport_tune_complete &= !m_currentInfo->m_sdts.empty();
972 }
973 if (sd->HasCachedAnyBATs())
974 {
975 transport_tune_complete &= !m_currentInfo->m_bats.empty();
976 }
977 if (transport_tune_complete)
978 {
979 uint tsid = dtv_sm->GetTransportID();
980 LOG(VB_CHANSCAN, LOG_INFO, LOC +
981 QString("\nTable status after transport tune complete:") +
982 QString("\nsd->HasCachedAnyNIT(): %1").arg(sd->HasCachedAnyNIT()) +
983 QString("\nsd->HasCachedAnySDTs(): %1").arg(sd->HasCachedAnySDTs()) +
984 QString("\nsd->HasCachedAnyBATs(): %1").arg(sd->HasCachedAnyBATs()) +
985 QString("\nsd->HasCachedAllPMTs(): %1").arg(sd->HasCachedAllPMTs()) +
986 QString("\nsd->HasCachedAllNIT(): %1").arg(sd->HasCachedAllNIT()) +
987 QString("\nsd->HasCachedAllSDT(%1): %2").arg(tsid,5).arg(sd->HasCachedAllSDT(tsid)) +
988 QString("\nsd->HasCachedAllBATs(): %1").arg(sd->HasCachedAllBATs()) +
989 QString("\nsd->HasCachedMGT(): %1").arg(sd->HasCachedMGT()) +
990 QString("\nsd->HasCachedAnyVCTs(): %1").arg(sd->HasCachedAnyVCTs()) +
991 QString("\nsd->HasCachedAllCVCTs(): %1").arg(sd->HasCachedAllCVCTs()) +
992 QString("\nsd->HasCachedAllTVCTs(): %1").arg(sd->HasCachedAllTVCTs()) +
993 QString("\ncurrentInfo->m_pmts.empty(): %1").arg(m_currentInfo->m_pmts.empty()) +
994 QString("\ncurrentInfo->m_nits.empty(): %1").arg(m_currentInfo->m_nits.empty()) +
995 QString("\ncurrentInfo->m_sdts.empty(): %1").arg(m_currentInfo->m_sdts.empty()) +
996 QString("\ncurrentInfo->m_bats.empty(): %1").arg(m_currentInfo->m_bats.empty()) +
997 QString("\ncurrentInfo->m_cvtcs.empty(): %1").arg(m_currentInfo->m_cvcts.empty()) +
998 QString("\ncurrentInfo->m_tvtcs.empty(): %1").arg(m_currentInfo->m_tvcts.empty()));
999 }
1000 }
1001 if (!wait_until_complete)
1002 transport_tune_complete = true;
1003 if (transport_tune_complete)
1004 {
1005 LOG(VB_CHANSCAN, LOG_INFO, LOC +
1006 QString("transport_tune_complete: wait_until_complete %1").arg(wait_until_complete));
1007 }
1008
1009 if (transport_tune_complete && !m_currentEncryptionStatus.empty())
1011 {
1012 //GetDTVSignalMonitor()->GetStreamData()->StopTestingDecryption();
1013
1015 return false;
1016
1017 QMap<uint, uint>::const_iterator it = m_currentEncryptionStatus.cbegin();
1018 for (; it != m_currentEncryptionStatus.cend(); ++it)
1019 {
1021
1022 if (m_testDecryption)
1023 {
1024 QString msg_tr1 = QObject::tr("Program %1").arg(it.key());
1025 QString msg_tr2 = QObject::tr("Unknown decryption status");
1026 if (kEncEncrypted == *it)
1027 msg_tr2 = QObject::tr("Encrypted");
1028 else if (kEncDecrypted == *it)
1029 msg_tr2 = QObject::tr("Decrypted");
1030 QString msg_tr =QString("%1 %2").arg(msg_tr1, msg_tr2);
1032 }
1033
1034 QString msg = QString("Program %1").arg(it.key());
1035 if (kEncEncrypted == *it)
1036 msg = msg + " -- Encrypted";
1037 else if (kEncDecrypted == *it)
1038 msg = msg + " -- Decrypted";
1039 else if (kEncUnknown == *it)
1040 msg = msg + " -- Unknown decryption status";
1041
1042 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1043 }
1044 }
1045
1046 // Append transports from the NIT to the scan list
1047 if (transport_tune_complete && m_extendScanList &&
1048 !m_currentInfo->m_nits.empty())
1049 {
1050 // Update transport with delivery system descriptors from the NIT
1051 auto it = m_currentInfo->m_nits.begin();
1052 while (it != m_currentInfo->m_nits.end())
1053 {
1054 UpdateScanTransports((*m_current).m_tuning.m_frequency, *it);
1055 ++it;
1056 }
1057 }
1058
1059 // Start scanning next transport if we are done with this one..
1060 if (transport_tune_complete)
1061 {
1062 QString cchan;
1063 QString cchan_tr;
1064 uint cchan_cnt = GetCurrentTransportInfo(cchan, cchan_tr);
1065 m_channelsFound += cchan_cnt;
1066 QString chan_tr = QObject::tr("%1 -- Timed out").arg(cchan_tr);
1067 QString chan = QString( "%1 -- Timed out").arg(cchan);
1068 QString msg_tr = "";
1069 QString msg = "";
1070
1071 if (!m_currentInfo->IsEmpty())
1072 {
1076 item.m_networkID = dtv_sm->GetNetworkID();
1077 item.m_transportID = dtv_sm->GetTransportID();
1078
1080 {
1082 {
1084 }
1085 }
1087 {
1089 }
1091 {
1092 if (m_dvbt2Tried)
1094 else
1096 }
1097
1098 LOG(VB_CHANSCAN, LOG_INFO, LOC +
1099 QString("Adding %1 offset:%2 ss:%3")
1100 .arg(item.m_tuning.toString()).arg(m_current.offset())
1101 .arg(item.m_signalStrength));
1102
1103 LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
1104 QString("%1(%2) m_inputName: %3 ").arg(__FUNCTION__).arg(__LINE__).arg(m_inputName) +
1105 QString("tunerType:%1 %2 ").arg(m_scanDTVTunerType).arg(m_scanDTVTunerType.toString()) +
1106 QString("m_modSys:%1 %2 ").arg(item.m_tuning.m_modSys).arg(item.m_tuning.m_modSys.toString()) +
1107 QString("m_dvbt2Tried:%1").arg(m_dvbt2Tried));
1108
1110 m_currentInfo = nullptr;
1111 }
1112 else
1113 {
1114 delete m_currentInfo;
1115 m_currentInfo = nullptr;
1116 }
1117
1119 if (HasTimedOut())
1120 {
1121 msg_tr = (cchan_cnt) ?
1122 QObject::tr("%1 possible channels").arg(cchan_cnt) :
1123 QObject::tr("no channels");
1124 msg_tr = QString("%1, %2").arg(chan_tr, msg_tr);
1125 msg = (cchan_cnt) ?
1126 QString("%1 possible channels").arg(cchan_cnt) :
1127 QString("no channels");
1128 msg = QString("%1, %2").arg(chan_tr, msg);
1129 }
1130 else if ((m_current != m_scanTransports.end()) &&
1131 m_timer.hasExpired((*m_current).m_timeoutTune.count()) &&
1132 sm && !sm->HasSignalLock())
1133 {
1134 msg_tr = QObject::tr("%1, no signal").arg(chan_tr);
1135 msg = QString("%1, no signal").arg(chan);
1136 }
1137 else
1138 {
1139 msg_tr = QObject::tr("%1 -- Found %2 probable channels")
1140 .arg(cchan_tr).arg(cchan_cnt);
1141
1142 msg = QString("%1 -- Found %2 probable channels")
1143 .arg(cchan).arg(cchan_cnt);
1144 }
1145
1147 LOG(VB_CHANSCAN, LOG_INFO, LOC + msg);
1148
1151
1152 m_setOtherTables = false;
1153 m_otherTableTime = 0ms;
1154
1155 if (m_scanning)
1156 {
1159 m_waitingForTables = false;
1161 m_dvbt2Tried = true;
1162 }
1163 else
1164 {
1167 }
1168
1169 return true;
1170 }
1171
1172 return false;
1173}
1174
1175// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
1176#define PCM_INFO_INIT(SISTD) \
1177 ChannelInsertInfo &info = pnum_to_dbchan[pnum]; \
1178 info.m_dbMplexId = mplexid; info.m_sourceId = m_sourceID; \
1179 info.m_serviceId = pnum; info.m_freqId = freqidStr; \
1180 info.m_siStandard = SISTD;
1181
1183 const VirtualChannelTable *vct, uint i)
1184{
1185 if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
1186 vct->ServiceType(i) == 0x01 /* Analog TV */)
1187 {
1188 info.m_siStandard = "ntsc";
1189 info.m_format = "ntsc";
1190 }
1191
1192 info.m_callSign = vct->ShortChannelName(i);
1193
1194 info.m_serviceName = vct->GetExtendedChannelName(i);
1195 if (info.m_serviceName.isEmpty())
1196 info.m_serviceName = vct->ShortChannelName(i);
1197
1198 info.m_chanNum.clear();
1199
1200 info.m_serviceId = vct->ProgramNumber(i);
1201 info.m_atscMajorChannel = vct->MajorChannel(i);
1202 info.m_atscMinorChannel = vct->MinorChannel(i);
1203
1204 info.m_useOnAirGuide = !vct->IsHidden(i) || !vct->IsHiddenInGuide(i);
1205
1206 info.m_hidden = vct->IsHidden(i);
1207 info.m_hiddenInGuide = vct->IsHiddenInGuide(i);
1208
1209 info.m_vctTsId = vct->TransportStreamID();
1210 info.m_vctChanTsId = vct->ChannelTransportStreamID(i);
1211 info.m_isEncrypted |= vct->IsAccessControlled(i);
1212 info.m_isDataService = vct->ServiceType(i) == 0x04;
1213 info.m_isAudioService = vct->ServiceType(i) == 0x03;
1214
1215 info.m_inVct = true;
1216}
1217
1219 const ServiceDescriptionTable *sdt, uint i,
1220 const QMap<uint64_t, QString> &defAuthorities)
1221{
1222 // HACK begin -- special exception for these networks
1223 // this enables useonairguide by default for all matching channels
1224 // (dbver == "1067")
1225 bool force_guide_present = (
1226 // Telenor (NO)
1228#if 0 // #9592#comment:23 - meanwhile my provider changed his signaling
1229 // Kabelplus (AT) formerly Kabelsignal, registered to NDS, see #9592
1230 (sdt->OriginalNetworkID() == 222) ||
1231#endif
1232 // ERT (GR) from the private temporary allocation, see #9592:comment:17
1233 (sdt->OriginalNetworkID() == 65330) ||
1234 // Digitenne (NL) see #13427
1236 );
1237 // HACK end -- special exception for these networks
1238
1239 // Figure out best service name and callsign...
1241 QString callsign;
1242 QString service_name;
1243 if (desc)
1244 {
1245 callsign = desc->ServiceShortName();
1246 if (callsign.trimmed().isEmpty())
1247 {
1248 callsign = QString("%1-%2-%3")
1249 .arg(ChannelUtil::GetUnknownCallsign()).arg(sdt->TSID())
1250 .arg(sdt->ServiceID(i));
1251 }
1252
1253 service_name = desc->ServiceName();
1254 if (service_name.trimmed().isEmpty())
1255 service_name.clear();
1256
1257 info.m_serviceType = desc->ServiceType();
1258 info.m_isDataService =
1259 (desc && !desc->IsDTV() && !desc->IsDigitalAudio());
1260 info.m_isAudioService = (desc && desc->IsDigitalAudio());
1261 delete desc;
1262 }
1263 else
1264 {
1265 LOG(VB_CHANSCAN, LOG_INFO, "ChannelScanSM: " +
1266 QString("No ServiceDescriptor for onid %1 tid %2 sid %3")
1267 .arg(sdt->OriginalNetworkID()).arg(sdt->TSID()).arg(sdt->ServiceID(i)));
1268 }
1269
1270 if (info.m_callSign.isEmpty())
1271 info.m_callSign = callsign;
1272 if (info.m_serviceName.isEmpty())
1273 info.m_serviceName = service_name;
1274
1275 info.m_useOnAirGuide =
1276 sdt->HasEITPresentFollowing(i) ||
1277 sdt->HasEITSchedule(i) ||
1278 force_guide_present;
1279
1280 info.m_hidden = false;
1281 info.m_hiddenInGuide = false;
1282 info.m_serviceId = sdt->ServiceID(i);
1283 info.m_sdtTsId = sdt->TSID();
1284 info.m_origNetId = sdt->OriginalNetworkID();
1285 info.m_inSdt = true;
1286
1287 desc_list_t parsed =
1289 sdt->ServiceDescriptorsLength(i));
1290 // Look for default authority
1291 const unsigned char *def_auth =
1293 if (def_auth)
1294 {
1295 DefaultAuthorityDescriptor authority(def_auth);
1296 if (authority.IsValid())
1297 {
1298#if 0
1299 LOG(VB_CHANSCAN, LOG_DEBUG,
1300 QString("ChannelScanSM: Found default authority '%1' in SDT for service onid %2 tid %3 sid %4")
1301 .arg(authority.DefaultAuthority())
1302 .arg(info.m_origNetId).arg(info.m_sdtTsId).arg(info.m_serviceId));
1303#endif
1304 info.m_defaultAuthority = authority.DefaultAuthority();
1305 return;
1306 }
1307 }
1308
1309 // If no authority in the SDT then use the one found in the BAT or the SDTo
1310 uint64_t index = (uint64_t)info.m_origNetId << 32 |
1311 info.m_sdtTsId << 16 | info.m_serviceId;
1312 if (defAuthorities.contains(index))
1313 info.m_defaultAuthority = defAuthorities[index];
1314
1315 // Is this service relocated from somewhere else?
1317 if (srdesc)
1318 {
1319 info.m_oldOrigNetId = srdesc->OldOriginalNetworkID();
1320 info.m_oldTsId = srdesc->OldTransportID();
1321 info.m_oldServiceId = srdesc->OldServiceID();
1322
1323 LOG(VB_CHANSCAN, LOG_DEBUG, "ChannelScanSM: " +
1324 QString("Service '%1' onid:%2 tid:%3 sid:%4 ")
1325 .arg(info.m_serviceName)
1326 .arg(info.m_origNetId)
1327 .arg(info.m_sdtTsId)
1328 .arg(info.m_serviceId) +
1329 QString(" relocated from onid:%1 tid:%2 sid:%3")
1330 .arg(info.m_oldOrigNetId)
1331 .arg(info.m_oldTsId)
1332 .arg(info.m_oldServiceId));
1333
1334 delete srdesc;
1335 }
1336
1337}
1338
1340 QString &cur_chan, QString &cur_chan_tr) const
1341{
1342 if (m_current.iter() == m_scanTransports.end())
1343 {
1344 cur_chan.clear();
1345 cur_chan_tr.clear();
1346 return 0;
1347 }
1348
1349 uint max_chan_cnt = 0;
1350
1351 QMap<uint,ChannelInsertInfo> list = GetChannelList(m_current, m_currentInfo);
1352 {
1353 for (const auto & info : std::as_const(list))
1354 {
1355 max_chan_cnt +=
1356 (info.m_inPat || info.m_inPmt ||
1357 info.m_inSdt || info.m_inVct) ? 1 : 0;
1358 }
1359 }
1360
1361 QString offset_str_tr = m_current.offset() ?
1362 QObject::tr(" offset %2").arg(m_current.offset()) : "";
1363 cur_chan_tr = QString("%1%2")
1364 .arg((*m_current).m_friendlyName, offset_str_tr);
1365
1366 QString offset_str = m_current.offset() ?
1367 QString(" offset %2").arg(m_current.offset()) : "";
1368 cur_chan = QString("%1%2")
1369 .arg((*m_current).m_friendlyName, offset_str);
1370
1371 return max_chan_cnt;
1372}
1373
1374QMap<uint,ChannelInsertInfo>
1376 ScannedChannelInfo *scan_info) const
1377{
1378 QMap<uint,ChannelInsertInfo> pnum_to_dbchan;
1379
1380 uint mplexid = (*trans_info).m_mplexid;
1381 int freqid = (*trans_info).m_friendlyNum;
1382 QString freqidStr = (freqid) ? QString::number(freqid) : QString("");
1383 QString iptv_channel = (*trans_info).m_iptvChannel;
1384
1385 // channels.conf
1386 const DTVChannelInfoList &echan = (*trans_info).m_expectedChannels;
1387 for (const auto & chan : echan)
1388 {
1389 uint pnum = chan.m_serviceid;
1390 PCM_INFO_INIT("mpeg");
1391 info.m_serviceName = chan.m_name;
1392 info.m_inChannelsConf = true;
1393 }
1394
1395 // PATs
1396 for (const auto& pat_list : std::as_const(scan_info->m_pats))
1397 {
1398 for (const auto *pat : pat_list)
1399 {
1400 bool could_be_opencable = false;
1401 for (uint i = 0; i < pat->ProgramCount(); ++i)
1402 {
1403 if ((pat->ProgramNumber(i) == 0) &&
1404 (pat->ProgramPID(i) == PID::SCTE_PSIP_PID))
1405 {
1406 could_be_opencable = true;
1407 }
1408 }
1409
1410 for (uint i = 0; i < pat->ProgramCount(); ++i)
1411 {
1412 uint pnum = pat->ProgramNumber(i);
1413 if (pnum)
1414 {
1415 PCM_INFO_INIT("mpeg");
1416 info.m_patTsId = pat->TransportStreamID();
1417 info.m_couldBeOpencable = could_be_opencable;
1418 info.m_inPat = true;
1419 }
1420 }
1421 }
1422 }
1423
1424 // PMTs
1425 for (const auto *pmt : scan_info->m_pmts)
1426 {
1427 uint pnum = pmt->ProgramNumber();
1428 PCM_INFO_INIT("mpeg");
1429 for (uint i = 0; i < pmt->StreamCount(); ++i)
1430 {
1431 info.m_couldBeOpencable |=
1432 (StreamID::OpenCableVideo == pmt->StreamType(i));
1433 }
1434
1436 pmt->ProgramInfo(), pmt->ProgramInfoLength(),
1438
1439 for (auto & desc : descs)
1440 {
1441 RegistrationDescriptor reg(desc);
1442 if (!reg.IsValid())
1443 continue;
1444 if (reg.FormatIdentifierString() == "CUEI" ||
1445 reg.FormatIdentifierString() == "SCTE")
1446 info.m_couldBeOpencable = true;
1447 }
1448
1449 info.m_isEncrypted |= pmt->IsEncrypted(GetDTVChannel()->GetSIStandard());
1450 info.m_inPmt = true;
1451 }
1452
1453 // Cable VCTs
1454 for (const auto *cvct : scan_info->m_cvcts)
1455 {
1456 for (uint i = 0; i < cvct->ChannelCount(); ++i)
1457 {
1458 uint pnum = cvct->ProgramNumber(i);
1459 PCM_INFO_INIT("atsc");
1460 update_info(info, cvct, i);
1461
1462 // One-part channel number, as defined in the ATSC Standard:
1463 // Program and System Information Protocol for Terrestrial Broadcast and Cable
1464 // Doc. A65/2013 7 August 2013 page 35
1465 if ((info.m_atscMajorChannel & 0x3F0) == 0x3F0)
1466 {
1467 info.m_chanNum = QString::number(((info.m_atscMajorChannel & 0x00F) << 10) + info.m_atscMinorChannel);
1468 }
1469 else
1470 {
1471 info.m_chanNum = kATSCChannelFormat.arg(info.m_atscMajorChannel).arg(info.m_atscMinorChannel);
1472 }
1473 }
1474 }
1475
1476 // Terrestrial VCTs
1477 for (const auto *tvct : scan_info->m_tvcts)
1478 {
1479 for (uint i = 0; i < tvct->ChannelCount(); ++i)
1480 {
1481 uint pnum = tvct->ProgramNumber(i);
1482 PCM_INFO_INIT("atsc");
1483 update_info(info, tvct, i);
1484 info.m_chanNum = kATSCChannelFormat.arg(info.m_atscMajorChannel).arg(info.m_atscMinorChannel);
1485 }
1486 }
1487
1488 // SDTs
1489 QString siStandard = (scan_info->m_mgt == nullptr) ? "dvb" : "atsc";
1490 for (const auto& sdt_list : std::as_const(scan_info->m_sdts))
1491 {
1492 for (const auto *sdt_it : sdt_list)
1493 {
1494 for (uint i = 0; i < sdt_it->ServiceCount(); ++i)
1495 {
1496 uint pnum = sdt_it->ServiceID(i);
1497 PCM_INFO_INIT(siStandard);
1498 update_info(info, sdt_it, i, m_defAuthorities);
1499 }
1500 }
1501 }
1502
1503 // NIT
1504 QMap<qlonglong, uint> ukChanNums;
1505 QMap<qlonglong, uint> scnChanNums;
1506 QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1507 for (dbchan_it = pnum_to_dbchan.begin();
1508 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1509 {
1510 ChannelInsertInfo &info = *dbchan_it;
1511
1512 // NIT
1513 for (const auto *item : scan_info->m_nits)
1514 {
1515 for (uint i = 0; i < item->TransportStreamCount(); ++i)
1516 {
1517 const NetworkInformationTable *nit = item;
1518 if ((nit->TSID(i) == info.m_sdtTsId) &&
1519 (nit->OriginalNetworkID(i) == info.m_origNetId))
1520 {
1521 info.m_netId = nit->NetworkID();
1522 info.m_inNit = true;
1523 }
1524 else
1525 {
1526 continue;
1527 }
1528
1529 // Descriptors in the transport stream loop of this transport in the NIT
1530 const desc_list_t &list =
1533
1534 // Presence of T2 delivery system descriptor indicates DVB-T2 delivery system
1535 // DVB BlueBook A038 (Feb 2019) page 104, paragraph 6.4.6.3
1536 {
1537 const unsigned char *desc =
1540
1541 if (desc)
1542 {
1543 T2DeliverySystemDescriptor t2tdsd(desc);
1544 if (t2tdsd.IsValid())
1545 {
1546 (*trans_info).m_tuning.m_modSys = DTVModulationSystem::kModulationSystem_DVBT2;
1547 }
1548 }
1549 }
1550
1551 // Logical channel numbers
1552 {
1553 const unsigned char *desc =
1556
1557 if (desc)
1558 {
1559 DVBLogicalChannelDescriptor uklist(desc);
1560 if (!uklist.IsValid())
1561 continue;
1562 for (uint j = 0; j < uklist.ChannelCount(); ++j)
1563 {
1564 ukChanNums[((qlonglong)info.m_origNetId<<32) |
1565 uklist.ServiceID(j)] =
1566 uklist.ChannelNumber(j);
1567 }
1568 }
1569 }
1570
1571 // HD Simulcast logical channel numbers
1572 {
1573 const unsigned char *desc =
1576
1577 if (desc)
1578 {
1579 DVBSimulcastChannelDescriptor scnlist(desc);
1580 if (!scnlist.IsValid())
1581 continue;
1582 for (uint j = 0; j < scnlist.ChannelCount(); ++j)
1583 {
1584 scnChanNums[((qlonglong)info.m_origNetId<<32) |
1585 scnlist.ServiceID(j)] =
1586 scnlist.ChannelNumber(j);
1587 }
1588 }
1589 }
1590 }
1591 }
1592 }
1593
1594 // BAT
1595
1596 // Channel numbers for Freesat and Sky on Astra 28.2E
1597 //
1598 // Get the Logical Channel Number (LCN) information from the BAT.
1599 // The first filter is on the bouquet ID.
1600 // Then collect all LCN for the selected region and
1601 // for the common (undefined) region with id 0xFFFF.
1602 // The LCN of the selected region has priority; if
1603 // a service is not defined there then the value of the LCN
1604 // table of the common region is used.
1605 // This works because the BAT of each transport contains
1606 // the LCN of all transports and services for all bouquets.
1607 //
1608 // For reference, this website has the Freesat and Sky channel numbers
1609 // for each bouquet and region:
1610 // https://www.satellite-calculations.com/DVB/28.2E/28E_FreeSat_ChannelNumber.php
1611 // https://www.satellite-calculations.com/DVB/28.2E/28E_Sky_ChannelNumber.php
1612 //
1613
1614 // Lookup table from LCN to service ID
1615 QMap<uint,qlonglong> lcn_sid;
1616
1617 for (const auto *bat : scan_info->m_bats)
1618 {
1619 // Only the bouquet selected by user
1620 if (bat->BouquetID() != m_bouquetId)
1621 continue;
1622
1623 for (uint t = 0; t < bat->TransportStreamCount(); ++t)
1624 {
1625 uint netid = bat->OriginalNetworkID(t);
1626
1627 // No network check to allow scanning on all Sky satellites
1628#if 0
1629 if (!(netid == OriginalNetworkID::SES2 ||
1630 netid == OriginalNetworkID::BBC ||
1631 netid == OriginalNetworkID::SKYNZ ))
1632 continue;
1633#endif
1634 desc_list_t parsed =
1635 MPEGDescriptor::Parse(bat->TransportDescriptors(t),
1636 bat->TransportDescriptorsLength(t));
1637
1638 uint priv_dsid = 0;
1639 for (const auto *item : parsed)
1640 {
1642 {
1644 if (pd.IsValid())
1645 priv_dsid = pd.PrivateDataSpecifier();
1646 }
1647
1648 // Freesat logical channels
1649 if (priv_dsid == PrivateDataSpecifierID::FSAT &&
1651 {
1652 FreesatLCNDescriptor ld(item);
1653 if (ld.IsValid())
1654 {
1655 for (uint i = 0; i<ld.ServiceCount(); i++)
1656 {
1657 uint service_id = ld.ServiceID(i);
1658 for (uint j=0; j<ld.LCNCount(i); j++)
1659 {
1660 uint region_id = ld.RegionID(i,j);
1661 uint lcn = ld.LogicalChannelNumber(i,j);
1662 if (region_id == m_regionId)
1663 {
1664 lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1665 }
1666 else if (region_id == kRegionUndefined)
1667 {
1668 if (lcn_sid.value(lcn,0) == 0)
1669 lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1670 }
1671 }
1672 }
1673 }
1674 }
1675
1676 // Sky logical channels
1677 if (priv_dsid == PrivateDataSpecifierID::BSB1 &&
1679 {
1680 SkyLCNDescriptor ld(item);
1681 if (ld.IsValid())
1682 {
1683 uint region_id = ld.RegionID();
1684 for (uint i = 0; i<ld.ServiceCount(); i++)
1685 {
1686 uint service_id = ld.ServiceID(i);
1687 uint lcn = ld.LogicalChannelNumber(i);
1688 if (region_id == m_regionId)
1689 {
1690 lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1691 }
1692 else if (region_id == kRegionUndefined)
1693 {
1694 if (lcn_sid.value(lcn,0) == 0)
1695 lcn_sid[lcn] = ((qlonglong)netid<<32) | service_id;
1696 }
1697#if 0
1698 LOG(VB_CHANSCAN, LOG_INFO, LOC +
1699 QString("LCN bid:%1 tid:%2 rid:%3 sid:%4 lcn:%5")
1700 .arg(bat->BouquetID()).arg(bat->TSID(t)).arg(region_id).arg(service_id).arg(lcn));
1701#endif
1702 }
1703 }
1704 }
1705 }
1706 }
1707 }
1708
1709 // Create the reverse table from service id to LCN.
1710 // If the service has more than one logical
1711 // channel number the lowest number is used.
1712 QMap<qlonglong, uint> sid_lcn;
1713 QMap<uint, qlonglong>::const_iterator r = lcn_sid.constEnd();
1714 while (r != lcn_sid.constBegin())
1715 {
1716 --r;
1717 qlonglong sid = r.value();
1718 uint lcn = r.key();
1719 sid_lcn[sid] = lcn;
1720 }
1721
1722 // ------------------------------------------------------------------------
1723
1724 // Get DVB Logical Channel Numbers
1725 for (dbchan_it = pnum_to_dbchan.begin();
1726 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1727 {
1728 ChannelInsertInfo &info = *dbchan_it;
1729 qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
1730 QMap<qlonglong, uint>::const_iterator it;
1731
1732 // DVB HD Simulcast channel numbers
1733 //
1734 // The HD simulcast channel number table gives the correct channel number
1735 // when HD and SD versions of the same channel are simultaneously broadcast
1736 // and the receiver is capable of receiving the HD signal.
1737 // The latter is assumed correct for a MythTV system.
1738 //
1739 it = scnChanNums.constFind(key);
1740 if (it != scnChanNums.constEnd())
1741 {
1742 info.m_simulcastChannel = *it;
1743 }
1744
1745 // DVB Logical Channel Numbers (a.k.a. UK channel numbers)
1746 it = ukChanNums.constFind(key);
1747 if (it != ukChanNums.constEnd())
1748 {
1749 info.m_logicalChannel = *it;
1750 }
1751
1752 // Freesat and Sky channel numbers
1753 it = sid_lcn.constFind(key);
1754 if (it != sid_lcn.constEnd())
1755 {
1756 info.m_logicalChannel = *it;
1757 }
1758
1759 LOG(VB_CHANSCAN, LOG_INFO, LOC +
1760 QString("service %1 (0x%2) lcn:%3 scn:%4 callsign '%5'")
1761 .arg(info.m_serviceId).arg(info.m_serviceId,4,16,QChar('0'))
1762 .arg(info.m_logicalChannel).arg(info.m_simulcastChannel).arg(info.m_callSign));
1763 }
1764
1765 // Get QAM/SCTE/MPEG channel numbers
1766 for (dbchan_it = pnum_to_dbchan.begin();
1767 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1768 {
1769 ChannelInsertInfo &info = *dbchan_it;
1770
1771 if (!info.m_chanNum.isEmpty())
1772 continue;
1773
1774 if ((info.m_siStandard == "mpeg") ||
1775 (info.m_siStandard == "scte") ||
1776 (info.m_siStandard == "opencable"))
1777 {
1778 if (info.m_freqId.isEmpty())
1779 {
1780 info.m_chanNum = QString("%1-%2")
1781 .arg(info.m_sourceId)
1782 .arg(info.m_serviceId);
1783 }
1784 else
1785 {
1786 info.m_chanNum = QString("%1-%2")
1787 .arg(info.m_freqId)
1788 .arg(info.m_serviceId);
1789 }
1790 }
1791 }
1792
1793 // Get IPTV channel numbers
1794 for (dbchan_it = pnum_to_dbchan.begin();
1795 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1796 {
1797 ChannelInsertInfo &info = *dbchan_it;
1798
1799 if (!info.m_chanNum.isEmpty())
1800 continue;
1801
1802 if (!iptv_channel.isEmpty())
1803 {
1804 info.m_chanNum = iptv_channel;
1805 if (info.m_serviceId)
1806 info.m_chanNum += "-" + QString::number(info.m_serviceId);
1807 }
1808 }
1809
1810 // Check for decryption success
1811 for (dbchan_it = pnum_to_dbchan.begin();
1812 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1813 {
1814 uint pnum = dbchan_it.key();
1815 ChannelInsertInfo &info = *dbchan_it;
1816 info.m_decryptionStatus = scan_info->m_programEncryptionStatus[pnum];
1817 }
1818
1819 return pnum_to_dbchan;
1820}
1821
1823{
1825
1826 uint cardid = m_channel->GetInputID();
1827
1828 DTVTunerType tuner_type;
1829 tuner_type = GuessDTVTunerType(tuner_type);
1830
1831 for (const auto & it : std::as_const(m_channelList))
1832 {
1833 QMap<uint,ChannelInsertInfo> pnum_to_dbchan =
1834 GetChannelList(it.first, it.second);
1835
1836 ScanDTVTransport item((*it.first).m_tuning, tuner_type, cardid);
1837 item.m_iptvTuning = (*(it.first)).m_iptvTuning;
1838 item.m_signalStrength = (*(it.first)).m_signalStrength;
1839 item.m_networkID = (*(it.first)).m_networkID;
1840 item.m_transportID = (*(it.first)).m_transportID;
1841
1842 QMap<uint,ChannelInsertInfo>::iterator dbchan_it;
1843 for (dbchan_it = pnum_to_dbchan.begin();
1844 dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
1845 {
1846 item.m_channels.push_back(*dbchan_it);
1847 }
1848
1849 if (!item.m_channels.empty())
1850 {
1851 // Add a MPTS channel which can be used to record the entire transport
1852 // stream multiplex. These recordings can be used in stream analyzer software.
1853 if (addFullTS)
1854 {
1855 // Find the first channel that is present in PAT/PMT and use that as
1856 // template for the new MPTS channel.
1858 for (auto & channel : pnum_to_dbchan)
1859 {
1860 if (channel.m_inPat && channel.m_inPmt)
1861 {
1862 info = channel;
1863 break;
1864 }
1865 }
1866
1867 // If we cannot find a valid channel then use the first channel in
1868 // the list as template for the new MPTS channel.
1869 if (info.m_serviceId == 0)
1870 {
1871 dbchan_it = pnum_to_dbchan.begin();
1872 info = *dbchan_it;
1873 }
1874
1875 // Use transport stream ID as (fake) service ID to use in callsign
1876 // and as channel number.
1877 info.m_serviceId = info.m_sdtTsId ? info.m_sdtTsId : info.m_patTsId;
1878 info.m_chanNum = QString("%1").arg(info.m_serviceId);
1879 info.m_logicalChannel = info.m_serviceId;
1880
1881 if (tuner_type == DTVTunerType::kTunerTypeASI)
1882 {
1883 info.m_callSign = QString("MPTS_%1")
1884 .arg(CardUtil::GetDisplayName(cardid));
1885 }
1886 else if (info.m_siStandard == "mpeg" ||
1887 info.m_siStandard == "scte" ||
1888 info.m_siStandard == "opencable")
1889 {
1890 info.m_callSign = QString("MPTS_%1").arg(info.m_freqId);
1891 }
1892 else if (info.m_atscMajorChannel > 0)
1893 {
1894 if (info.m_atscMajorChannel < 0x3F0)
1895 {
1896 info.m_callSign = QString("MPTS_%1").arg(info.m_atscMajorChannel);
1897 }
1898 else
1899 {
1900 info.m_callSign = QString("MPTS_%1").arg(info.m_freqId);
1901 }
1902 }
1903 else if (info.m_serviceId > 0)
1904 {
1905 info.m_callSign = QString("MPTS_%1").arg(info.m_serviceId);
1906 }
1907 else if (!info.m_chanNum.isEmpty())
1908 {
1909 info.m_callSign = QString("MPTS_%1").arg(info.m_chanNum);
1910 }
1911 else
1912 {
1913 info.m_callSign = "MPTS_UNKNOWN";
1914 }
1915
1916 info.m_serviceName = info.m_callSign;
1917 info.m_atscMinorChannel = 0;
1918 info.m_format = "MPTS";
1919 info.m_useOnAirGuide = false;
1920 info.m_isEncrypted = false;
1921 item.m_channels.push_back(info);
1922 }
1923
1924 list.push_back(item);
1925 }
1926 }
1927
1928 return list;
1929}
1930
1932{
1933 return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
1934}
1935
1937{
1938#if CONFIG_DVB
1939 return dynamic_cast<DVBSignalMonitor*>(m_signalMonitor);
1940#else
1941 return nullptr;
1942#endif
1943}
1944
1946{
1947 return dynamic_cast<DTVChannel*>(m_channel);
1948}
1949
1951{
1952 return dynamic_cast<const DTVChannel*>(m_channel);
1953}
1954
1956{
1957#if CONFIG_HDHOMERUN
1958 return dynamic_cast<HDHRChannel*>(m_channel);
1959#else
1960 return nullptr;
1961#endif
1962}
1963
1965{
1966#if CONFIG_DVB
1967 return dynamic_cast<DVBChannel*>(m_channel);
1968#else
1969 return nullptr;
1970#endif
1971}
1972
1974{
1975#if CONFIG_DVB
1976 return dynamic_cast<const DVBChannel*>(m_channel);
1977#else
1978 return nullptr;
1979#endif
1980}
1981
1983{
1984#if CONFIG_V4L2
1985 return dynamic_cast<V4LChannel*>(m_channel);
1986#else
1987 return nullptr;
1988#endif
1989}
1990
1995{
1996 while (m_scannerThread)
1997 {
1998 m_threadExit = true;
1999 if (m_scannerThread->wait(1s))
2000 {
2001 delete m_scannerThread;
2002 m_scannerThread = nullptr;
2003 }
2004 }
2005 m_threadExit = false;
2006 m_scannerThread = new MThread("Scanner", this);
2008}
2009
2014{
2015 LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- begin");
2016
2017 while (!m_threadExit)
2018 {
2019 if (m_scanning)
2021
2022 usleep(10 * 1000);
2023 }
2024
2025 LOG(VB_CHANSCAN, LOG_INFO, LOC + "run -- end");
2026}
2027
2028// See if we have timed out
2030{
2032 m_timer.hasExpired(kDecryptionTimeout))
2033 {
2035 return true;
2036 }
2037
2038 if (!m_waitingForTables)
2039 return true;
2040
2041#if CONFIG_DVB
2042 // If the rotor is still moving, reset the timer and keep waiting
2044 if (sigmon)
2045 {
2046 const DiSEqCDevRotor *rotor =
2047 GetDVBChannel() ? GetDVBChannel()->GetRotor() : nullptr;
2048 if (rotor)
2049 {
2050 bool was_moving = false;
2051 bool is_moving = false;
2052 sigmon->GetRotorStatus(was_moving, is_moving);
2053 if (was_moving && !is_moving)
2054 {
2055 m_timer.restart();
2056 return false;
2057 }
2058 }
2059 }
2060#endif // CONFIG_DVB
2061
2062 // have the tables have timed out?
2063 if (m_timer.hasExpired(m_channelTimeout.count()))
2064 {
2065 // the channelTimeout alone is only valid if we have seen no tables..
2066 const ScanStreamData *sd = nullptr;
2067 if (GetDTVSignalMonitor())
2069
2070 if (!sd)
2071 return true;
2072
2073 if (sd->HasCachedAnyNIT() || sd->HasCachedAnySDTs())
2074 return m_timer.hasExpired(kDVBTableTimeout.count());
2075 if (sd->HasCachedMGT() || sd->HasCachedAnyVCTs())
2076 return m_timer.hasExpired(kATSCTableTimeout.count());
2077 if (sd->HasCachedAnyPAT() || sd->HasCachedAnyPMTs())
2078 return m_timer.hasExpired(kMPEGTableTimeout.count());
2079
2080 return true;
2081 }
2082
2083 // ok the tables haven't timed out, but have we hit the signal timeout?
2085 if (m_timer.hasExpired((*m_current).m_timeoutTune.count()) &&
2086 sm && !sm->HasSignalLock())
2087 {
2088 const ScanStreamData *sd = nullptr;
2089 if (GetDTVSignalMonitor())
2091
2092 if (!sd)
2093 return true;
2094
2095 // Just is case we temporarily lose the signal after we've seen
2096 // tables...
2097 if (!sd->HasCachedAnyPAT() && !sd->HasCachedAnyPMTs() &&
2098 !sd->HasCachedMGT() && !sd->HasCachedAnyVCTs() &&
2099 !sd->HasCachedAnyNIT() && !sd->HasCachedAnySDTs())
2100 {
2101 return true;
2102 }
2103 }
2104
2105 return false;
2106}
2107
2112{
2113 QMutexLocker locker(&m_lock);
2114
2115 bool do_post_insertion = m_waitingForTables;
2116
2117 if (!HasTimedOut())
2118 return;
2119
2120 if (0 == m_nextIt.offset() && m_nextIt == m_scanTransports.begin())
2121 {
2122 m_channelList.clear();
2123 m_channelsFound = 0;
2124 m_dvbt2Tried = true;
2125 }
2126
2128 {
2129 // If we failed to get a lock with DVB-T try DVB-T2.
2130 m_dvbt2Tried = true;
2132 return;
2133 }
2134
2135 if (0 == m_nextIt.offset() && m_nextIt != m_scanTransports.begin())
2136 {
2137 // Add channel to scanned list and potentially check decryption
2138 if (do_post_insertion && !UpdateChannelInfo(false))
2139 return;
2140
2141 // Stop signal monitor for previous transport
2142 locker.unlock();
2144 locker.relock();
2145 }
2146
2147 m_current = m_nextIt; // Increment current
2148 m_dvbt2Tried = false;
2149
2150 if (m_current != m_scanTransports.end())
2151 {
2153
2154 // Increment nextIt
2156 ++m_nextIt;
2157 }
2158 else if (!m_extendTransports.isEmpty())
2159 {
2160 --m_current;
2161 QMap<uint32_t,DTVMultiplex>::iterator it = m_extendTransports.begin();
2162 while (it != m_extendTransports.end())
2163 {
2164 if (!m_tsScanned.contains(it.key()))
2165 {
2166 QString name = QString("TransportID %1").arg(it.key() & 0xffff);
2168 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + name + ' ' + item.m_tuning.toString());
2169 m_scanTransports.push_back(item);
2170 m_tsScanned.insert(it.key());
2171 }
2172 ++it;
2173 }
2174 m_extendTransports.clear();
2176 ++m_nextIt;
2177 }
2178 else
2179 {
2181 m_scanning = false;
2183 }
2184}
2185
2187{
2188 const TransportScanItem &item = *transport;
2189
2190#if CONFIG_DVB
2192 if (monitor)
2193 {
2194 // always wait for rotor to finish
2196 monitor->SetRotorTarget(1.0F);
2197 }
2198#endif // CONFIG_DVB
2199
2200 DTVChannel *channel = GetDTVChannel();
2201 if (!channel)
2202 return false;
2203
2204 if (item.m_mplexid > 0 && transport.offset() == 0)
2205 return channel->TuneMultiplex(item.m_mplexid, m_inputName);
2206
2207 if (item.m_tuning.m_sistandard == "MPEG")
2208 {
2209 IPTVTuningData tuning = item.m_iptvTuning;
2210 if (tuning.GetProtocol() == IPTVTuningData::inValid)
2211 tuning.GuessProtocol();
2212 return channel->Tune(tuning, true);
2213 }
2214
2215 const uint64_t freq = item.freq_offset(transport.offset());
2216 DTVMultiplex tuning = item.m_tuning;
2217 tuning.m_frequency = freq;
2218
2220 {
2222 }
2224 {
2225 if (m_dvbt2Tried)
2227 else
2229 }
2230
2231 return channel->Tune(tuning);
2232}
2233
2235{
2236 QString offset_str = (transport.offset()) ?
2237 QObject::tr(" offset %2").arg(transport.offset()) : "";
2238 QString cur_chan = QString("%1%2")
2239 .arg((*m_current).m_friendlyName, offset_str);
2240 QString tune_msg_str =
2241 QObject::tr("ScanTransport Tuning to %1 mplexid(%2)")
2242 .arg(cur_chan).arg((*m_current).m_mplexid);
2243
2244 const TransportScanItem &item = *transport;
2245
2246 if (transport.offset() &&
2247 (item.freq_offset(transport.offset()) == item.freq_offset(0)))
2248 {
2249 m_waitingForTables = false;
2250 return; // nothing to do
2251 }
2252
2253 if (m_channelsFound)
2254 {
2255 QString progress = QObject::tr("Found %n", "", m_channelsFound);
2257 }
2258
2260 LOG(VB_CHANSCAN, LOG_INFO, LOC + tune_msg_str);
2261
2262 if (!Tune(transport))
2263 { // If we did not tune successfully, bail with message
2265 LOG(VB_CHANSCAN, LOG_ERR, LOC +
2266 QString("Failed to tune %1 mplexid(%2) at offset %3")
2267 .arg(item.m_friendlyName).arg(item.m_mplexid)
2268 .arg(transport.offset()));
2269 return;
2270 }
2271
2272 // If we have a DTV Signal Monitor, perform table scanner reset
2273 if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
2274 {
2278 }
2279
2280 // Start signal monitor for this channel
2281 if (m_signalMonitor)
2283
2284 m_timer.start();
2285 m_waitingForTables = (item.m_tuning.m_sistandard != "analog");
2286}
2287
2293{
2294 LOG(VB_CHANSCAN, LOG_INFO, LOC + "StopScanner");
2295
2296 while (m_scannerThread)
2297 {
2298 m_threadExit = true;
2299 if (m_scannerThread->wait(1s))
2300 {
2301 delete m_scannerThread;
2302 m_scannerThread = nullptr;
2303 }
2304 }
2305
2306 if (m_signalMonitor)
2308}
2309
2315 int SourceID,
2316 const QString &std,
2317 const QString &modulation,
2318 const QString &country,
2319 const QString &table_start,
2320 const QString &table_end)
2321{
2322 LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2323 QString("%1:%2 ").arg(__FUNCTION__).arg(__LINE__) +
2324 QString("SourceID:%1 ").arg(SourceID) +
2325 QString("std:%1 ").arg(std) +
2326 QString("modulation:%1 ").arg(modulation) +
2327 QString("country:%1 ").arg(country) +
2328 QString("table_start:%1 ").arg(table_start) +
2329 QString("table_end:%1 ").arg(table_end));
2330
2331 QString name("");
2332 if (m_scanning)
2333 return false;
2334
2335 m_scanTransports.clear();
2336 m_nextIt = m_scanTransports.end();
2337
2338 freq_table_list_t tables =
2339 get_matching_freq_tables(std, modulation, country);
2340
2341 if (tables.empty())
2342 {
2343 QString msg = QString("No freq table for (%1, %2, %3) found")
2344 .arg(std, modulation, country);
2346 }
2347 LOG(VB_CHANSCAN, LOG_INFO, LOC +
2348 QString("Looked up freq table (%1, %2, %3) w/%4 entries")
2349 .arg(std, modulation, country, QString::number(tables.size())));
2350
2351 QString start = table_start;
2352 const QString& end = table_end;
2353 // NOLINTNEXTLINE(modernize-loop-convert)
2354 for (auto it = tables.begin(); it != tables.end(); ++it)
2355 {
2356 const FrequencyTable &ft = **it;
2357 int name_num = ft.m_nameOffset;
2358 QString strNameFormat = ft.m_nameFormat;
2360 while (freq <= ft.m_frequencyEnd)
2361 {
2362 name = strNameFormat;
2363 if (strNameFormat.indexOf("%") >= 0)
2364 name = strNameFormat.arg(name_num);
2365
2366 if (start.isEmpty() || name == start)
2367 {
2368 start.clear();
2369
2370 TransportScanItem item(SourceID, std, name, name_num,
2371 freq, ft, m_signalTimeout);
2372 m_scanTransports.push_back(item);
2373
2374 LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanTransports " +
2375 item.toString());
2376 }
2377
2378 ++name_num;
2379 freq += ft.m_frequencyStep;
2380
2381 if (!end.isEmpty() && name == end)
2382 break;
2383 }
2384 if (!end.isEmpty() && name == end)
2385 break;
2386 }
2387
2388 while (!tables.empty())
2389 {
2390 delete tables.back();
2391 tables.pop_back();
2392 }
2393
2394 m_extendScanList = true;
2395 m_timer.start();
2396 m_waitingForTables = false;
2397
2398 m_nextIt = m_scanTransports.begin();
2400 m_scanning = true;
2401
2402 return true;
2403}
2404
2406 const QString &std,
2407 const QString &cardtype,
2408 const DTVChannelList &channels)
2409{
2410 m_scanTransports.clear();
2411 m_nextIt = m_scanTransports.end();
2412
2413 DTVTunerType tunertype;
2414 tunertype.Parse(cardtype);
2415
2416 auto it = channels.cbegin();
2417 for (uint i = 0; it != channels.cend(); ++it, ++i)
2418 {
2419 DTVTransport tmp = *it;
2420 tmp.m_sistandard = std;
2421 TransportScanItem item(sourceid, QString::number(i),
2422 tunertype, tmp, m_signalTimeout);
2423
2424 m_scanTransports.push_back(item);
2425
2426 LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanForChannels " + item.toString());
2427 }
2428
2429 if (m_scanTransports.empty())
2430 {
2431 LOG(VB_GENERAL, LOG_ERR, LOC + "ScanForChannels() no transports");
2432 return false;
2433 }
2434
2435 m_timer.start();
2436 m_waitingForTables = false;
2437
2438 m_nextIt = m_scanTransports.begin();
2440 m_scanning = true;
2441
2442 return true;
2443}
2444
2446 const fbox_chan_map_t &iptv_channels)
2447{
2448 m_scanTransports.clear();
2449 m_nextIt = m_scanTransports.end();
2450
2451 fbox_chan_map_t::const_iterator Ichan = iptv_channels.begin();
2452 for (uint idx = 0; Ichan != iptv_channels.end(); ++Ichan, ++idx)
2453 {
2454 TransportScanItem item(sourceid, QString::number(idx),
2455 Ichan.value().m_tuning, Ichan.key(),
2457
2458 m_scanTransports.push_back(item);
2459
2460 LOG(VB_CHANSCAN, LOG_INFO, LOC + "ScanIPTVChannels " + item.toString());
2461 }
2462
2463 if (m_scanTransports.empty())
2464 {
2465 LOG(VB_GENERAL, LOG_ERR, LOC + "ScanIPTVChannels() no transports");
2466 return false;
2467 }
2468
2469 m_timer.start();
2470 m_waitingForTables = false;
2471
2472 m_nextIt = m_scanTransports.begin();
2474 m_scanning = true;
2475
2476 return true;
2477}
2478
2479
2485 int sourceid, const QMap<QString,QString> &startChan)
2486{
2487 auto iter = startChan.find("type");
2488 if (iter == startChan.end())
2489 return false;
2490 iter = startChan.find("std");
2491 if (iter == startChan.end())
2492 return false;
2493
2494 QString si_std = ((*iter).toLower() != "atsc") ? "dvb" : "atsc";
2495 bool ok = false;
2496
2497 if (m_scanning)
2498 return false;
2499
2500 m_scanTransports.clear();
2501 m_nextIt = m_scanTransports.end();
2502
2503 DTVMultiplex tuning;
2504
2506 ok = type.Parse(startChan["type"]);
2507
2508 if (ok)
2509 {
2510 ok = tuning.ParseTuningParams(
2511 type,
2512 startChan["frequency"], startChan["inversion"],
2513 startChan["symbolrate"], startChan["fec"],
2514 startChan["polarity"],
2515 startChan["coderate_hp"], startChan["coderate_lp"],
2516 startChan["constellation"], startChan["trans_mode"],
2517 startChan["guard_interval"], startChan["hierarchy"],
2518 startChan["modulation"], startChan["bandwidth"],
2519 startChan["mod_sys"], startChan["rolloff"]);
2520 }
2521
2522 if (ok)
2523 {
2524 tuning.m_sistandard = si_std;
2525 TransportScanItem item(
2526 sourceid, QObject::tr("Frequency %1").arg(startChan["frequency"]),
2527 tuning, m_signalTimeout);
2528 m_scanTransports.push_back(item);
2529 }
2530
2531 if (!ok)
2532 return false;
2533
2534 m_extendScanList = true;
2535
2536 m_timer.start();
2537 m_waitingForTables = false;
2538
2539 m_nextIt = m_scanTransports.begin();
2541 m_scanning = true;
2542
2543 return true;
2544}
2545
2547{
2549 query.prepare(
2550 "SELECT sourceid, sistandard, transportid, frequency, modulation, mod_sys "
2551 "FROM dtv_multiplex "
2552 "WHERE mplexid = :MPLEXID");
2553 query.bindValue(":MPLEXID", mplexid);
2554 if (!query.exec())
2555 {
2556 MythDB::DBError("ChannelScanSM::AddToList()", query);
2557 return false;
2558 }
2559
2560 if (!query.next())
2561 {
2562 LOG(VB_GENERAL, LOG_ERR, LOC + "AddToList() " +
2563 QString("Failed to locate mplexid(%1) in DB").arg(mplexid));
2564 return false;
2565 }
2566
2567 uint sourceid = query.value(0).toUInt();
2568 QString sistandard = query.value(1).toString();
2569 uint tsid = query.value(2).toUInt();
2570 uint frequency = query.value(3).toUInt();
2571 QString modulation = query.value(4).toString();
2572 QString mod_sys = query.value(5).toString();
2573 DTVModulationSystem delsys;
2574 delsys.Parse(mod_sys);
2576 QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
2577 QString("Multiplex #%1").arg(mplexid);
2578
2579 if (modulation == "8vsb")
2580 {
2581 QString chan = QString("%1 Hz").arg(frequency);
2582 int findFrequency = (query.value(3).toInt() / 1000) - 1750;
2583 for (const auto & list : gChanLists[0].list)
2584 {
2585 if ((list.freq <= findFrequency + 200) &&
2586 (list.freq >= findFrequency - 200))
2587 {
2588 chan = QString("%1").arg(list.name);
2589 }
2590 }
2591 fn = QObject::tr("ATSC Channel %1").arg(chan);
2593 }
2594
2595 tt = GuessDTVTunerType(tt);
2596
2597 TransportScanItem item(sourceid, sistandard, fn, mplexid, m_signalTimeout);
2598
2599 LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
2600 QString("tunertype:%1 %2 sourceid:%3 sistandard:%4 fn:'%5' mplexid:%6")
2601 .arg(tt).arg(tt.toString()).arg(sourceid).arg(sistandard, fn).arg(mplexid));
2602
2603 if (item.m_tuning.FillFromDB(tt, mplexid))
2604 {
2605 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Adding " + fn);
2606 m_scanTransports.push_back(item);
2607 return true;
2608 }
2609
2610 LOG(VB_CHANSCAN, LOG_INFO, LOC + "Not adding incomplete transport " + fn);
2611 return false;
2612}
2613
2614bool ChannelScanSM::ScanTransport(uint mplexid, bool follow_nit)
2615{
2616 m_scanTransports.clear();
2617 m_nextIt = m_scanTransports.end();
2618
2619 AddToList(mplexid);
2620
2621 m_timer.start();
2622 m_waitingForTables = false;
2623
2624 m_extendScanList = follow_nit;
2626 if (!m_scanTransports.empty())
2627 {
2628 m_nextIt = m_scanTransports.begin();
2629 m_scanning = true;
2630 return true;
2631 }
2632
2633 return false;
2634}
2635
2636bool ChannelScanSM::ScanCurrentTransport(const QString &sistandard)
2637{
2638 m_scanTransports.clear();
2639 m_nextIt = m_scanTransports.end();
2640
2641 m_signalTimeout = 30s;
2642 QString name;
2643 TransportScanItem item(m_sourceID, sistandard, name, 0, m_signalTimeout);
2644 m_scanTransports.push_back(item);
2645
2646 m_timer.start();
2647 m_waitingForTables = false;
2648 m_extendScanList = false;
2650 m_nextIt = m_scanTransports.begin();
2651 m_scanning = true;
2652 return true;
2653}
2654
2659 const DTVChannelInfoList &channels,
2660 uint mpeg_program_num,
2661 QString &service_name,
2662 QString &callsign,
2663 QString &common_status_info)
2664{
2665 if (channels.empty())
2666 return true;
2667
2668 bool found = false;
2669 for (const auto & channel : channels)
2670 {
2671 LOG(VB_GENERAL, LOG_DEBUG, LOC +
2672 QString("comparing %1 %2 against %3 %4")
2673 .arg(channel.m_serviceid).arg(channel.m_name)
2674 .arg(mpeg_program_num).arg(common_status_info));
2675
2676 if (channel.m_serviceid == mpeg_program_num)
2677 {
2678 found = true;
2679 if (!channel.m_name.isEmpty())
2680 {
2681 service_name = channel.m_name;
2682 callsign = channel.m_name;
2683 }
2684 }
2685 }
2686
2687 if (found)
2688 {
2689 common_status_info += QString(" %1 %2")
2690 .arg(QObject::tr("as"), service_name);
2691 }
2692 else
2693 {
2695 QObject::tr("Skipping %1, not in imported channel map")
2696 .arg(common_status_info));
2697 }
2698
2699 return found;
2700}
std::vector< const TerrestrialVirtualChannelTable * > tvct_vec_t
std::vector< const CableVirtualChannelTable * > cvct_vec_t
Overall structure.
@ kChannelVisible
Definition: channelinfo.h:23
#define LOC
static void update_info(ChannelInsertInfo &info, const VirtualChannelTable *vct, uint i)
#define PCM_INFO_INIT(SISTD)
static const QString kATSCChannelFormat
static constexpr qint64 kDecryptionTimeout
static const uint kRegionUndefined
std::vector< const ProgramMapTable * > pmt_vec_t
QPair< transport_scan_items_it_t, ScannedChannelInfo * > ChannelListItem
cvct_vec_t GetCachedCVCTs(bool current=true) const
const MasterGuideTable * GetCachedMGT(bool current=true) const
bool HasCachedAllTVCTs(bool current=true) const
bool HasCachedAnyVCTs(bool current=true) const
tvct_vec_t GetCachedTVCTs(bool current=true) const
bool HasCachedMGT(bool current=true) const
bool HasCachedAllCVCTs(bool current=true) const
Tells what channels can be found on each transponder for one bouquet (a bunch of channels from one pr...
Definition: dvbtables.h:193
uint TSID(uint i) const
Definition: dvbtables.h:234
uint TransportDescriptorsLength(uint i) const
Definition: dvbtables.h:240
const unsigned char * TransportDescriptors(uint i) const
for(j=0;j<N;j++) x 6.0+p { descriptor() }
Definition: dvbtables.h:244
uint BouquetID() const
Definition: dvbtables.h:208
QString toString(void) const override
Definition: dvbtables.cpp:217
uint OriginalNetworkID(uint i) const
Definition: dvbtables.h:236
uint TransportStreamCount(void) const
Definition: dvbtables.h:229
unsigned long long FrequencyHz(void) const
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1876
static DTVTunerType ConvertToTunerType(DTVModulationSystem delsys)
Definition: cardutil.cpp:807
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:32
virtual int GetInputID(void) const
Definition: channelbase.h:67
Scanning class for cards that support a SignalMonitor class.
bool ScanTransportsStartingOn(int sourceid, const QMap< QString, QString > &startChan)
Generates a list of frequencies to scan and adds it to the scanTransport list, and then sets the scan...
QMutex m_lock
The big lock.
QElapsedTimer m_timer
DTVTunerType GuessDTVTunerType(DTVTunerType type) const
void UpdateScanPercentCompleted(void)
void run(void) override
This runs the event loop for ChannelScanSM until 'm_threadExit' is true.
void UpdateScanTransports(uint frequency, const NetworkInformationTable *nit)
QSet< uint32_t > m_tsScanned
std::chrono::milliseconds m_otherTableTimeout
void HandleMGT(const MasterGuideTable *mgt) override
QMap< uint32_t, DTVMultiplex > m_extendTransports
std::chrono::milliseconds m_otherTableTime
DTVTunerType m_scanDTVTunerType
ChannelList m_channelList
Found Channel Info.
DTVChannel * GetDTVChannel(void)
void HandleActiveScan(void)
Handles the TRANSPORT_LIST ChannelScanSM mode.
bool ScanForChannels(uint sourceid, const QString &std, const QString &cardtype, const DTVChannelList &channels)
void HandleEncryptionStatus(uint pnum, bool encrypted) override
transport_scan_items_t m_scanTransports
static const std::chrono::milliseconds kMPEGTableTimeout
No logic here, lets just wait at least 15 seconds.
bool ScanTransport(uint mplexid, bool follow_nit)
void HandleSDTo(uint tsid, const ServiceDescriptionTable *sdt) override
static const std::chrono::milliseconds kATSCTableTimeout
No logic here, lets just wait at least 10 seconds.
void SetAnalog(bool is_analog)
void HandleVCT(uint tsid, const VirtualChannelTable *vct) override
void HandleNIT(const NetworkInformationTable *nit) override
std::chrono::milliseconds m_signalTimeout
static QString loc(const ChannelScanSM *siscan)
void HandleSDT(uint tsid, const ServiceDescriptionTable *sdt) override
uint GetCurrentTransportInfo(QString &chan, QString &chan_tr) const
DVBSignalMonitor * GetDVBSignalMonitor(void)
QMap< uint64_t, QString > m_defAuthorities
DTVSignalMonitor * GetDTVSignalMonitor(void)
MThread * m_scannerThread
static const std::chrono::milliseconds kDVBTableTimeout
SDT's should be sent every 2 seconds and NIT's every 10 seconds, so lets wait at least 30 seconds,...
QMap< uint, bool > m_currentEncryptionStatusChecked
SignalMonitor * GetSignalMonitor(void)
bool UpdateChannelInfo(bool wait_until_complete)
bool ScanTransports(int SourceID, const QString &std, const QString &mod, const QString &country, const QString &table_start=QString(), const QString &table_end=QString())
Generates a list of frequencies to scan and adds it to the scanTransport list, and then sets the scan...
bool Tune(transport_scan_items_it_t transport)
AnalogSignalHandler * m_analogSignalHandler
V4LChannel * GetV4LChannel(void)
chan_info_map_t GetChannelList(transport_scan_items_it_t trans_info, ScannedChannelInfo *scan_info) const
void HandlePMT(uint program_num, const ProgramMapTable *pmt) override
void HandlePAT(const ProgramAssociationTable *pat) override
HDHRChannel * GetHDHRChannel(void)
~ChannelScanSM() override
bool m_currentTestingDecryption
ChannelScanSM(ScanMonitor *scan_monitor, const QString &cardtype, ChannelBase *channel, int sourceID, std::chrono::milliseconds signal_timeout, std::chrono::milliseconds channel_timeout, QString inputname, bool test_decryption)
static void LogLines(const QString &string)
void HandleAllGood(void)
void HandleCAT(const ConditionalAccessTable *cat) override
QMap< uint, uint > m_currentEncryptionStatus
bool ScanExistingTransports(uint sourceid, bool follow_nit)
If we are not already scanning a frequency table, this creates a new frequency table from database an...
bool HasTimedOut(void)
ScannedChannelInfo * m_currentInfo
transport_scan_items_it_t m_current
std::chrono::milliseconds m_channelTimeout
SignalMonitor * m_signalMonitor
QString m_inputName
void StopScanner(void)
Stops the ChannelScanSM event loop and the signal monitor, blocking until both exit.
bool ScanCurrentTransport(const QString &sistandard)
void HandleBAT(const BouquetAssociationTable *bat) override
void StartScanner(void)
Starts the ChannelScanSM event loop.
transport_scan_items_it_t m_nextIt
DVBChannel * GetDVBChannel(void)
ChannelBase * m_channel
ScanMonitor * m_scanMonitor
bool CheckImportedList(const DTVChannelInfoList &channels, uint mpeg_program_num, QString &service_name, QString &callsign, QString &common_status_info)
If we are scanning a dvb-utils import verify channel is in list.
bool TestNextProgramEncryption(void)
bool AddToList(uint mplexid)
bool ScanIPTVChannels(uint sourceid, const fbox_chan_map_t &iptv_channels)
volatile bool m_threadExit
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
static bool CreateChannel(uint db_mplexid, uint db_sourceid, uint new_channel_id, const QString &callsign, const QString &service_name, const QString &chan_num, uint service_id, uint atsc_major_channel, uint atsc_minor_channel, bool use_on_air_guide, ChannelVisibleType visible, const QString &freqid, const QString &icon=QString(), QString format="Default", const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0, int recpriority=0, int tmOffset=0, int commMethod=-1)
static QString GetUnknownCallsign(void)
static uint FindChannel(uint sourceid, const QString &freqid)
The CAT is used to transmit additional ConditionalAccessDescriptor instances, in addition to the ones...
Definition: mpegtables.h:839
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:34
virtual bool Tune(const DTVMultiplex &tuning)=0
This performs the actual frequency tuning and in some cases input switching.
virtual std::vector< DTVTunerType > GetTunerTypes(void) const
Returns a vector of supported tuning types.
Definition: dtvchannel.cpp:79
virtual bool TuneMultiplex(uint mplexid, const QString &inputname)
To be used by the channel scanner and possibly the EIT scanner.
Definition: dtvchannel.cpp:395
bool Parse(const QString &_value)
QString toString() const
bool FillFromDeliverySystemDesc(DTVTunerType type, const MPEGDescriptor &desc)
bool ParseTuningParams(DTVTunerType type, const QString &frequency, const QString &inversion, const QString &symbolrate, const QString &fec, const QString &polarity, const QString &hp_code_rate, const QString &lp_code_rate, const QString &ofdm_modulation, const QString &trans_mode, const QString &guard_interval, const QString &hierarchy, const QString &modulation, const QString &bandwidth, const QString &mod_sys, const QString &rolloff)
IPTVTuningData m_iptvTuning
Definition: dtvmultiplex.h:112
DTVModulationSystem m_modSys
Definition: dtvmultiplex.h:106
virtual bool FillFromDB(DTVTunerType type, uint mplexid)
uint64_t m_frequency
Definition: dtvmultiplex.h:94
QString m_sistandard
Definition: dtvmultiplex.h:111
This class is intended to detect the presence of needed tables.
void SetDVBService(uint network_id, uint transport_id, int service_id)
uint GetNetworkID(void) const
void AddFlags(uint64_t _flags) override
uint GetTransportID(void) const
void SetChannel(int major, int minor)
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
ScanStreamData * GetScanStreamData()
Returns the scan stream data if it exists.
DVBStreamData * GetDVBStreamData()
Returns the DVB stream data if it exists.
virtual void SetStreamData(MPEGStreamData *data)
Sets the MPEG stream data for DTVSignalMonitor to use, and connects the table signals to the monitor.
bool Parse(const QString &_value)
static const int kTunerTypeASI
static const int kTunerTypeDVBS2
QString toString() const
static const int kTunerTypeDVBT
static const int kTunerTypeUnknown
static const int kTunerTypeDVBC
static const int kTunerTypeDVBS1
static const int kTunerTypeDVBT2
static const int kTunerTypeATSC
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:31
const DiSEqCDevRotor * GetRotor(void) const
Returns rotor object if it exists, nullptr otherwise.
void SetPMT(const ProgramMapTable *pmt)
Tells the Conditional Access Module which streams we wish to decode.
Definition: dvbchannel.cpp:729
DVB Logical Channel Descriptor.
uint ChannelNumber(uint i) const
uint ServiceID(uint i) const
void SetRotorTarget(float target) override
Sets rotor target pos from 0.0 to 1.0.
void GetRotorStatus(bool &was_moving, bool &is_moving) override
DVB HD Simulcast Logical Channel Descriptor.
uint ChannelNumber(uint i) const
sdt_vec_t GetCachedSDTSections(uint tsid, bool current=true) const
bool HasCachedAnySDTs(bool current=true) const
sdt_vec_t GetCachedSDTs(bool current=true) const
bool HasCachedAnyBATs(bool current=true) const
bool HasCachedAllBATs(bool current=true) const
bool HasCachedAnyNIT(bool current=true) const
bat_vec_t GetCachedBATs(bool current=true) const
bool HasCachedAllSDT(uint tsid, bool current=true) const
void ReturnCachedSDTTables(sdt_vec_t &sdts) const
nit_const_ptr_t GetCachedNIT(uint section_num, bool current=true) const
bool HasCachedAllNIT(bool current=true) const
QString DefaultAuthority(void) const
@ terrestrial_delivery_system
@ s2_satellite_delivery_system
Rotor class.
Definition: diseqc.h:303
Freesat Logical Channel Number descriptor.
uint LCNCount(size_t i) const
uint ServiceCount(void) const
uint ServiceID(size_t i) const
uint LogicalChannelNumber(size_t i, size_t j) const
uint RegionID(size_t i, size_t j) const
QString m_nameFormat
uint64_t m_frequencyStep
uint64_t m_frequencyEnd
uint64_t m_frequencyStart
IPTVProtocol GetProtocol(void) const
void GuessProtocol(void)
static const unsigned char * FindExtension(const desc_list_t &parsed, uint desc_tag)
static desc_list_t Parse(const unsigned char *data, uint len)
uint DescriptorTag(void) const
bool IsValid(void) const
static desc_list_t ParseOnlyInclude(const unsigned char *data, uint len, int excluded_descid)
uint DescriptorTagExtension(void) const
static const unsigned char * Find(const desc_list_t &parsed, uint desc_tag)
pmt_vec_t GetCachedPMTs(void) const
void TestDecryption(const ProgramMapTable *pmt)
virtual void ReturnCachedPATTables(pat_vec_t &pats) const
bool HasCachedAnyPMTs(void) const
bool HasCachedAnyPAT(uint tsid) const
bool HasCachedAllPMTs(void) const
pat_vec_t GetCachedPATs(uint tsid) const
bool HasCachedAllPAT(uint tsid) const
virtual void ReturnCachedPMTTables(pmt_vec_t &pmts) const
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
void ResetDecryptionMonitoringState(void)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:49
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
This table tells the decoder on which PIDs to find other tables, and their sizes and each table's cur...
Definition: atsctables.h:83
QString toString(void) const override
Definition: atsctables.cpp:72
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
This table tells the decoder on which PIDs to find other tables.
Definition: dvbtables.h:34
uint OriginalNetworkID(uint i) const
original_network_id 16 2.0+p
Definition: dvbtables.h:84
QString toString(void) const override
Definition: dvbtables.cpp:32
uint TransportDescriptorsLength(uint i) const
trans_desc_length 12 4.4+p
Definition: dvbtables.h:88
uint NetworkID(void) const
network_id 16 3.0 0x0000
Definition: dvbtables.h:62
const unsigned char * TransportDescriptors(uint i) const
for(j=0;j<N;j++) x 6.0+p { descriptor() }
Definition: dvbtables.h:92
uint TSID(uint i) const
transport_stream_id 16 0.0+p
Definition: dvbtables.h:82
uint TransportStreamCount(void) const
Definition: dvbtables.h:78
@ SCTE_PSIP_PID
Definition: mpegtables.h:237
uint LastSection(void) const
Definition: mpegtables.h:534
uint Section(void) const
Definition: mpegtables.h:531
uint32_t PrivateDataSpecifier(void) const
The Program Association Table lists all the programs in a stream, and is always found on PID 0.
Definition: mpegtables.h:599
QString toString(void) const override
Definition: mpegtables.cpp:841
uint ProgramCount(void) const
Definition: mpegtables.h:619
uint ProgramPID(uint i) const
Definition: mpegtables.h:629
A PMT table maps a program described in the ProgramAssociationTable to various PID's which describe t...
Definition: mpegtables.h:676
bool IsEncrypted(const QString &sistandard) const
Returns true iff PMT contains CA descriptor for a vid/aud stream.
Definition: mpegtables.cpp:556
QString toString(void) const override
Definition: mpegtables.cpp:906
uint ProgramNumber(void) const
Definition: mpegtables.h:712
QString FormatIdentifierString(void) const
uint64_t FrequencykHz(void) const
ChannelInsertInfoList m_channels
Definition: dtvmultiplex.h:138
void ScanPercentComplete(int pct)
void ScanComplete(void)
Definition: scanmonitor.cpp:98
void ScanAppendTextToLog(const QString &status)
void ScanUpdateStatusTitleText(const QString &status)
void ScanUpdateStatusText(const QString &status)
void Reset(void) override
void SetFreesatAdditionalSI(bool freesat_si)
QMap< uint, uint > m_programEncryptionStatus
ScannedChannelInfo()=default
const MasterGuideTable * m_mgt
This table tells the decoder on which PIDs to find A/V data.
Definition: dvbtables.h:114
uint TSID() const
transport_stream_id 16 3.0 0x0000
Definition: dvbtables.h:141
QString toString(void) const override
Definition: dvbtables.cpp:129
const unsigned char * ServiceDescriptors(uint i) const
for (j=0;j<N;j++) x 5.0+p { descriptor() }
Definition: dvbtables.h:169
bool HasEITPresentFollowing(uint i) const
Definition: dvbtables.h:158
bool HasEITSchedule(uint i) const
Definition: dvbtables.h:156
ServiceDescriptor * GetServiceDescriptor(uint i) const
Definition: dvbtables.cpp:166
uint ServiceID(uint i) const
service_id 16 0.0+p
Definition: dvbtables.h:153
uint ServiceCount() const
Number of services.
Definition: dvbtables.h:148
uint ServiceDescriptorsLength(uint i) const
desc_loop_length 12 3.4+p
Definition: dvbtables.h:165
uint OriginalNetworkID() const
original_network_id 16 8.0
Definition: dvbtables.h:144
bool IsEncrypted(uint i) const
free_CA_mode 1 3.3+p
Definition: dvbtables.h:163
ServiceRelocatedDescriptor * GetServiceRelocatedDescriptor(uint i) const
Definition: dvbtables.cpp:181
QString ServiceShortName(void) const
uint ServiceType(void) const
bool IsDTV(void) const
QString ServiceName(void) const
bool IsDigitalAudio(void) const
uint ServiceID(uint i) const
uint ServiceCount(void) const
Signal monitoring base class.
Definition: signalmonitor.h:31
static const uint64_t kDTVSigMon_WaitForVCT
void RemoveListener(SignalMonitorListener *listener)
void AddListener(SignalMonitorListener *listener)
static const uint64_t kDTVSigMon_WaitForNIT
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
static const uint64_t kDTVSigMon_WaitForSDT
virtual void Stop()
Stop signal monitoring thread.
int GetSignalStrength(void)
Definition: signalmonitor.h:71
static const uint64_t kDTVSigMon_WaitForMGT
bool HasSignalLock(void) const
Returns true iff scriptStatus.IsGood() and signalLock.IsGood() return true.
Definition: signalmonitor.h:75
virtual void Start()
Start signal monitoring thread.
Sky Logical Channel Number descriptor.
uint RegionID(void) const
uint ServiceCount(void) const
uint LogicalChannelNumber(size_t i) const
uint ServiceID(size_t i) const
static std::vector< uint > GetMplexIDs(uint sourceid)
Definition: sourceutil.cpp:149
@ OpenCableVideo
Always MPEG-2??
Definition: mpegtables.h:120
Class used for doing a list of frequencies / transports.
uint64_t freq_offset(uint i) const
IPTVTuningData m_iptvTuning
DTVMultiplex m_tuning
QString toString() const
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:32
This table contains information about the channels transmitted on this multiplex.
Definition: atsctables.h:197
QString ShortChannelName(uint i) const
Definition: atsctables.h:233
bool IsHiddenInGuide(uint i) const
Definition: atsctables.h:295
bool IsHidden(uint i) const
Definition: atsctables.h:289
uint MajorChannel(uint i) const
Definition: atsctables.h:252
uint ChannelTransportStreamID(uint i) const
Definition: atsctables.h:269
uint TransportStreamID() const
Definition: atsctables.h:225
QString toString(void) const override
Definition: atsctables.cpp:203
uint MinorChannel(uint i) const
Definition: atsctables.h:257
bool IsAccessControlled(uint i) const
Definition: atsctables.h:284
uint ProgramNumber(uint i) const
Definition: atsctables.h:274
QString GetExtendedChannelName(uint idx) const
Definition: atsctables.cpp:509
uint ServiceType(uint i) const
Definition: atsctables.h:301
uint ModulationMode(uint i) const
Definition: atsctables.h:262
uint ChannelCount() const
Definition: atsctables.h:228
transport_scan_items_it_t nextTransport() const
std::list< TransportScanItem >::iterator iter()
std::vector< DTVChannelInfo > DTVChannelInfoList
Definition: dtvconfparser.h:58
std::vector< DTVTransport > DTVChannelList
Definition: dtvconfparser.h:68
std::vector< ScanDTVTransport > ScanDTVTransportList
Definition: dtvmultiplex.h:143
QMap< uint, sdt_vec_t > sdt_map_t
Definition: dvbstreamdata.h:20
std::vector< const ServiceDescriptionTable * > sdt_vec_t
Definition: dvbstreamdata.h:18
std::vector< const NetworkInformationTable * > nit_vec_t
Definition: dvbstreamdata.h:13
std::vector< const BouquetAssociationTable * > bat_vec_t
Definition: dvbstreamdata.h:24
static const std::array< const uint32_t, 4 > freq
Definition: element.cpp:45
unsigned int uint
Definition: freesurround.h:24
const CHANLISTS_vec gChanLists
bool teardown_frequency_tables(void)
freq_table_list_t get_matching_freq_tables(const QString &format, const QString &modulation, const QString &country)
std::vector< const FrequencyTable * > freq_table_list_t
static guint32 * tmp
Definition: goom_core.cpp:26
QMap< QString, IPTVChannelInfo > fbox_chan_map_t
std::vector< const unsigned char * > desc_list_t
QMap< uint, pat_vec_t > pat_map_t
std::vector< const ProgramAssociationTable * > pat_vec_t
@ kEncUnknown
@ kEncEncrypted
@ kEncDecrypted
bool progress
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
dictionary info
Definition: azlyrics.py:7
STL namespace.
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:95