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