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