MythTV  master
channelutil.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 #include <algorithm>
4 #include <cstdint>
5 #include <set>
6 #include <utility>
7 
8 #include <QFile>
9 #include <QHash>
10 #include <QImage>
11 #include <QReadWriteLock>
12 #include <QRegularExpression>
13 
14 #include "libmythbase/mythdb.h"
16 #include "libmythbase/stringutil.h"
17 
18 #include "channelutil.h"
19 #include "mpeg/dvbtables.h"
21 #include "sourceutil.h"
22 
23 #define LOC QString("ChanUtil: ")
24 
25 const QString ChannelUtil::kATSCSeparators = "(_|-|#|\\.)";
26 
27 static uint get_dtv_multiplex(uint db_source_id, const QString& sistandard,
28  uint64_t frequency,
29  // DVB specific
30  uint transport_id,
31  // tsid exists with other sistandards,
32  // but we only trust it in dvb-land.
33  uint network_id,
34  // must check polarity for dvb-s
35  signed char polarity)
36 {
37  QString qstr =
38  "SELECT mplexid "
39  "FROM dtv_multiplex "
40  "WHERE sourceid = :SOURCEID "
41  " AND sistandard = :SISTANDARD ";
42 
43  if (sistandard.toLower() != "dvb")
44  qstr += "AND frequency = :FREQUENCY ";
45  else
46  {
47  qstr += "AND transportid = :TRANSPORTID ";
48  qstr += "AND networkid = :NETWORKID ";
49  qstr += "AND polarity = :POLARITY ";
50  }
51 
52 
54  query.prepare(qstr);
55 
56  query.bindValue(":SOURCEID", db_source_id);
57  query.bindValue(":SISTANDARD", sistandard);
58 
59  if (sistandard.toLower() != "dvb")
60  query.bindValue(":FREQUENCY", QString::number(frequency));
61  else
62  {
63  query.bindValue(":TRANSPORTID", transport_id);
64  query.bindValue(":NETWORKID", network_id);
65  query.bindValue(":POLARITY", QChar(polarity));
66  }
67 
68  if (!query.exec() || !query.isActive())
69  {
70  MythDB::DBError("get_dtv_multiplex", query);
71  return 0;
72  }
73 
74  if (query.next())
75  return query.value(0).toUInt();
76 
77  return 0;
78 }
79 
81  int db_source_id, const QString& sistandard,
82  uint64_t frequency, const QString& modulation,
83  // DVB specific
84  int transport_id, int network_id,
85  int symbol_rate, signed char bandwidth,
86  signed char polarity, signed char inversion,
87  signed char trans_mode,
88  const QString& inner_FEC, const QString& constellation,
89  signed char hierarchy, const QString& hp_code_rate,
90  const QString& lp_code_rate, const QString& guard_interval,
91  const QString& mod_sys, const QString& rolloff)
92 {
94 
95  // If transport is already present, skip insert
96  uint mplex = get_dtv_multiplex(
97  db_source_id, sistandard, frequency,
98  // DVB specific
99  transport_id, network_id, polarity);
100 
101  LOG(VB_CHANSCAN, LOG_INFO, "insert_dtv_multiplex(" +
102  QString("dbid:%1 std:'%2' ").arg(db_source_id).arg(sistandard) +
103  QString("freq:%1 mod:%2 ").arg(frequency).arg(modulation) +
104  QString("tid:%1 nid:%2 ").arg(transport_id).arg(network_id) +
105  QString("pol:%1 msys:%2 ...)").arg(QChar(polarity)).arg(mod_sys) +
106  QString("mplexid:%1").arg(mplex));
107 
108  bool isDVB = (sistandard.toLower() == "dvb");
109 
110  QString updateStr =
111  "UPDATE dtv_multiplex "
112  "SET frequency = :FREQUENCY1, ";
113 
114  updateStr += (!modulation.isNull()) ?
115  "modulation = :MODULATION, " : "";
116  updateStr += (symbol_rate >= 0) ?
117  "symbolrate = :SYMBOLRATE, " : "";
118  updateStr += (bandwidth >= 0) ?
119  "bandwidth = :BANDWIDTH, " : "";
120  updateStr += (polarity >= 0) ?
121  "polarity = :POLARITY, " : "";
122  updateStr += (inversion >= 0) ?
123  "inversion = :INVERSION, " : "";
124  updateStr += (trans_mode >= 0) ?
125  "transmission_mode= :TRANS_MODE, " : "";
126  updateStr += (!inner_FEC.isNull()) ?
127  "fec = :INNER_FEC, " : "";
128  updateStr += (!constellation.isNull()) ?
129  "constellation = :CONSTELLATION, " : "";
130  updateStr += (hierarchy >= 0) ?
131  "hierarchy = :HIERARCHY, " : "";
132  updateStr += (!hp_code_rate.isNull()) ?
133  "hp_code_rate = :HP_CODE_RATE, " : "";
134  updateStr += (!lp_code_rate.isNull()) ?
135  "lp_code_rate = :LP_CODE_RATE, " : "";
136  updateStr += (!guard_interval.isNull()) ?
137  "guard_interval = :GUARD_INTERVAL, " : "";
138  updateStr += (!mod_sys.isNull()) ?
139  "mod_sys = :MOD_SYS, " : "";
140  updateStr += (symbol_rate >= 0) ?
141  "rolloff = :ROLLOFF, " : "";
142  updateStr += (transport_id && !isDVB) ?
143  "transportid = :TRANSPORTID, " : "";
144 
145  updateStr = updateStr.left(updateStr.length()-2) + " ";
146 
147  updateStr +=
148  "WHERE sourceid = :SOURCEID AND "
149  " sistandard = :SISTANDARD AND ";
150 
151  updateStr += (isDVB) ?
152  " polarity = :WHEREPOLARITY AND "
153  " transportid = :TRANSPORTID AND networkid = :NETWORKID " :
154  " frequency = :FREQUENCY2 ";
155 
156  QString insertStr =
157  "INSERT INTO dtv_multiplex "
158  " (sourceid, sistandard, frequency, ";
159 
160  insertStr += (!modulation.isNull()) ? "modulation, " : "";
161  insertStr += (transport_id || isDVB) ? "transportid, " : "";
162  insertStr += (isDVB) ? "networkid, " : "";
163  insertStr += (symbol_rate >= 0) ? "symbolrate, " : "";
164  insertStr += (bandwidth >= 0) ? "bandwidth, " : "";
165  insertStr += (polarity >= 0) ? "polarity, " : "";
166  insertStr += (inversion >= 0) ? "inversion, " : "";
167  insertStr += (trans_mode >= 0) ? "transmission_mode, " : "";
168  insertStr += (!inner_FEC.isNull()) ? "fec, " : "";
169  insertStr += (!constellation.isNull()) ? "constellation, " : "";
170  insertStr += (hierarchy >= 0) ? "hierarchy, " : "";
171  insertStr += (!hp_code_rate.isNull()) ? "hp_code_rate, " : "";
172  insertStr += (!lp_code_rate.isNull()) ? "lp_code_rate, " : "";
173  insertStr += (!guard_interval.isNull()) ? "guard_interval, " : "";
174  insertStr += (!mod_sys.isNull()) ? "mod_sys, " : "";
175  insertStr += (!rolloff.isNull()) ? "rolloff, " : "";
176  insertStr = insertStr.left(insertStr.length()-2) + ") ";
177 
178  insertStr +=
179  "VALUES "
180  " (:SOURCEID, :SISTANDARD, :FREQUENCY1, ";
181  insertStr += (!modulation.isNull()) ? ":MODULATION, " : "";
182  insertStr += (transport_id || isDVB) ? ":TRANSPORTID, " : "";
183  insertStr += (isDVB) ? ":NETWORKID, " : "";
184  insertStr += (symbol_rate >= 0) ? ":SYMBOLRATE, " : "";
185  insertStr += (bandwidth >= 0) ? ":BANDWIDTH, " : "";
186  insertStr += (polarity >= 0) ? ":POLARITY, " : "";
187  insertStr += (inversion >= 0) ? ":INVERSION, " : "";
188  insertStr += (trans_mode >= 0) ? ":TRANS_MODE, " : "";
189  insertStr += (!inner_FEC.isNull()) ? ":INNER_FEC, " : "";
190  insertStr += (!constellation.isNull()) ? ":CONSTELLATION, " : "";
191  insertStr += (hierarchy >= 0) ? ":HIERARCHY, " : "";
192  insertStr += (!hp_code_rate.isNull()) ? ":HP_CODE_RATE, " : "";
193  insertStr += (!lp_code_rate.isNull()) ? ":LP_CODE_RATE, " : "";
194  insertStr += (!guard_interval.isNull()) ? ":GUARD_INTERVAL, " : "";
195  insertStr += (!mod_sys.isNull()) ? ":MOD_SYS, " : "";
196  insertStr += (!rolloff.isNull()) ? ":ROLLOFF, " : "";
197  insertStr = insertStr.left(insertStr.length()-2) + ");";
198 
199  query.prepare((mplex) ? updateStr : insertStr);
200 
201  query.bindValue(":SOURCEID", db_source_id);
202  query.bindValue(":SISTANDARD", sistandard);
203  query.bindValue(":FREQUENCY1", QString::number(frequency));
204 
205  if (mplex)
206  {
207  if (isDVB)
208  {
209  query.bindValue(":TRANSPORTID", transport_id);
210  query.bindValue(":NETWORKID", network_id);
211  query.bindValue(":WHEREPOLARITY", QChar(polarity));
212  }
213  else
214  {
215  query.bindValue(":FREQUENCY2", QString::number(frequency));
216  if (transport_id)
217  query.bindValue(":TRANSPORTID", transport_id);
218  }
219  }
220  else
221  {
222  if (transport_id || isDVB)
223  query.bindValue(":TRANSPORTID", transport_id);
224  if (isDVB)
225  query.bindValue(":NETWORKID", network_id);
226  }
227 
228  if (!modulation.isNull())
229  query.bindValue(":MODULATION", modulation);
230 
231  if (symbol_rate >= 0)
232  query.bindValue(":SYMBOLRATE", symbol_rate);
233  if (bandwidth >= 0)
234  query.bindValue(":BANDWIDTH", QString("%1").arg((char)bandwidth));
235  if (polarity >= 0)
236  query.bindValue(":POLARITY", QString("%1").arg((char)polarity));
237  if (inversion >= 0)
238  query.bindValue(":INVERSION", QString("%1").arg((char)inversion));
239  if (trans_mode >= 0)
240  query.bindValue(":TRANS_MODE", QString("%1").arg((char)trans_mode));
241 
242  if (!inner_FEC.isNull())
243  query.bindValue(":INNER_FEC", inner_FEC);
244  if (!constellation.isNull())
245  query.bindValue(":CONSTELLATION", constellation);
246  if (hierarchy >= 0)
247  query.bindValue(":HIERARCHY", QString("%1").arg((char)hierarchy));
248  if (!hp_code_rate.isNull())
249  query.bindValue(":HP_CODE_RATE", hp_code_rate);
250  if (!lp_code_rate.isNull())
251  query.bindValue(":LP_CODE_RATE", lp_code_rate);
252  if (!guard_interval.isNull())
253  query.bindValue(":GUARD_INTERVAL",guard_interval);
254  if (!mod_sys.isNull())
255  query.bindValue(":MOD_SYS", mod_sys);
256  if (!rolloff.isNull())
257  query.bindValue(":ROLLOFF", rolloff);
258 
259  if (!query.exec() || !query.isActive())
260  {
261  MythDB::DBError("Adding transport to Database.", query);
262  return 0;
263  }
264 
265  if (mplex)
266  return mplex;
267 
268  mplex = get_dtv_multiplex(
269  db_source_id, sistandard, frequency,
270  // DVB specific
271  transport_id, network_id, polarity);
272 
273  LOG(VB_CHANSCAN, LOG_INFO, QString("insert_dtv_multiplex -- ") +
274  QString("inserted mplexid %1").arg(mplex));
275 
276  return mplex;
277 }
278 
279 static void handle_transport_desc(std::vector<uint> &muxes,
280  const MPEGDescriptor &desc,
281  uint sourceid, uint tsid, uint netid)
282 {
283  uint tag = desc.DescriptorTag();
284 
286  {
288  uint64_t freq = cd.FrequencyHz();
289 
290  // Use the frequency we already have for this mplex
291  // as it may be one of the other_frequencies for this mplex
292  int mux = ChannelUtil::GetMplexID(sourceid, tsid, netid);
293  if (mux > 0)
294  {
295  QString dummy_mod;
296  QString dummy_sistd;
297  uint dummy_tsid = 0;
298  uint dummy_netid = 0;
299  ChannelUtil::GetTuningParams(mux, dummy_mod, freq,
300  dummy_tsid, dummy_netid, dummy_sistd);
301  }
302 
304  (int)sourceid, "dvb",
305  freq, QString(),
306  // DVB specific
307  (int)tsid, (int)netid,
308  -1, cd.BandwidthString().at(0).toLatin1(),
309  -1, 'a',
310  cd.TransmissionModeString().at(0).toLatin1(),
311  QString(), cd.ConstellationString(),
312  cd.HierarchyString().at(0).toLatin1(), cd.CodeRateHPString(),
314  QString(), QString());
315 
316  if (mux)
317  muxes.push_back(mux);
318 
319  /* unused
320  HighPriority()
321  IsTimeSlicingIndicatorUsed()
322  IsMPE_FECUsed()
323  NativeInterleaver()
324  Alpha()
325  */
326  }
328  {
329  const SatelliteDeliverySystemDescriptor cd(desc);
330 
332  sourceid, "dvb",
333  cd.FrequencykHz(), cd.ModulationString(),
334  // DVB specific
335  tsid, netid,
336  cd.SymbolRateHz(), -1,
337  cd.PolarizationString().at(0).toLatin1(), 'a',
338  -1,
339  cd.FECInnerString(), QString(),
340  -1, QString(),
341  QString(), QString(),
343 
344  if (mux)
345  muxes.push_back(mux);
346 
347  /* unused
348  OrbitalPositionString() == OrbitalLocation
349  */
350  }
351  else if (tag == DescriptorID::cable_delivery_system)
352  {
353  const CableDeliverySystemDescriptor cd(desc);
354 
356  sourceid, "dvb",
357  cd.FrequencyHz(), cd.ModulationString(),
358  // DVB specific
359  tsid, netid,
360  cd.SymbolRateHz(), -1,
361  -1, 'a',
362  -1,
363  cd.FECInnerString(), QString(),
364  -1, QString(),
365  QString(), QString(),
366  QString(), QString());
367 
368  if (mux)
369  muxes.push_back(mux);
370  }
371 }
372 
373 uint ChannelUtil::CreateMultiplex(int sourceid, const QString& sistandard,
374  uint64_t frequency, const QString& modulation,
375  int transport_id, int network_id)
376 {
377  return CreateMultiplex(
378  sourceid, sistandard,
379  frequency, modulation,
380  transport_id, network_id,
381  -1, -1,
382  -1, -1,
383  -1,
384  QString(), QString(),
385  -1, QString(),
386  QString(), QString(),
387  QString(), QString());
388 }
389 
391  int sourceid, const QString& sistandard,
392  uint64_t freq, const QString& modulation,
393  // DVB specific
394  int transport_id, int network_id,
395  int symbol_rate, signed char bandwidth,
396  signed char polarity, signed char inversion,
397  signed char trans_mode,
398  const QString& inner_FEC, const QString& constellation,
399  signed char hierarchy, const QString& hp_code_rate,
400  const QString& lp_code_rate, const QString& guard_interval,
401  const QString& mod_sys, const QString& rolloff)
402 {
403  return insert_dtv_multiplex(
404  sourceid, sistandard,
405  freq, modulation,
406  // DVB specific
407  transport_id, network_id,
408  symbol_rate, bandwidth,
409  polarity, inversion,
410  trans_mode,
411  inner_FEC, constellation,
412  hierarchy, hp_code_rate,
413  lp_code_rate, guard_interval,
414  mod_sys, rolloff);
415 }
416 
418  int transport_id, int network_id)
419 {
420  return insert_dtv_multiplex(
421  sourceid, mux.m_sistandard,
422  mux.m_frequency, mux.m_modulation.toString(),
423  // DVB specific
424  transport_id, network_id,
425  mux.m_symbolRate, mux.m_bandwidth.toChar().toLatin1(),
426  mux.m_polarity.toChar().toLatin1(), mux.m_inversion.toChar().toLatin1(),
427  mux.m_transMode.toChar().toLatin1(),
428  mux.m_fec.toString(), mux.m_modulation.toString(),
429  mux.m_hierarchy.toChar().toLatin1(), mux.m_hpCodeRate.toString(),
431  mux.m_modSys.toString(), mux.m_rolloff.toString());
432 }
433 
434 
439  int sourceid, const NetworkInformationTable *nit)
440 {
441  std::vector<uint> muxes;
442 
443  if (sourceid <= 0)
444  return muxes;
445 
446  for (uint i = 0; i < nit->TransportStreamCount(); ++i)
447  {
448  const desc_list_t& list =
451 
452  uint tsid = nit->TSID(i);
453  uint netid = nit->OriginalNetworkID(i);
454  for (const auto *j : list)
455  {
456  const MPEGDescriptor desc(j);
457  handle_transport_desc(muxes, desc, sourceid, tsid, netid);
458  }
459  }
460  return muxes;
461 }
462 
463 uint ChannelUtil::GetMplexID(uint sourceid, const QString &channum)
464 {
465  MSqlQuery query(MSqlQuery::InitCon());
466  /* See if mplexid is already in the database */
467  query.prepare(
468  "SELECT mplexid "
469  "FROM channel "
470  "WHERE deleted IS NULL AND "
471  " sourceid = :SOURCEID AND "
472  " channum = :CHANNUM");
473 
474  query.bindValue(":SOURCEID", sourceid);
475  query.bindValue(":CHANNUM", channum);
476 
477  if (!query.exec() || !query.isActive())
478  MythDB::DBError("GetMplexID 0", query);
479  else if (query.next())
480  return query.value(0).toInt();
481 
482  return 0;
483 }
484 
485 int ChannelUtil::GetMplexID(uint sourceid, uint64_t frequency)
486 {
487  MSqlQuery query(MSqlQuery::InitCon());
488  /* See if mplexid is already in the database */
489  query.prepare(
490  "SELECT mplexid "
491  "FROM dtv_multiplex "
492  "WHERE sourceid = :SOURCEID AND "
493  " frequency = :FREQUENCY");
494 
495  query.bindValue(":SOURCEID", sourceid);
496  query.bindValue(":FREQUENCY", QString::number(frequency));
497 
498  if (!query.exec() || !query.isActive())
499  {
500  MythDB::DBError("GetMplexID 1", query);
501  return -1;
502  }
503 
504  if (query.next())
505  return query.value(0).toInt();
506 
507  return -1;
508 }
509 
510 int ChannelUtil::GetMplexID(uint sourceid, uint64_t frequency,
511  uint transport_id, uint network_id)
512 {
513  MSqlQuery query(MSqlQuery::InitCon());
514  // See if transport already in database
515  query.prepare(
516  "SELECT mplexid "
517  "FROM dtv_multiplex "
518  "WHERE networkid = :NETWORKID AND "
519  " transportid = :TRANSPORTID AND "
520  " frequency = :FREQUENCY AND "
521  " sourceid = :SOURCEID");
522 
523  query.bindValue(":SOURCEID", sourceid);
524  query.bindValue(":NETWORKID", network_id);
525  query.bindValue(":TRANSPORTID", transport_id);
526  query.bindValue(":FREQUENCY", QString::number(frequency));
527 
528  if (!query.exec() || !query.isActive())
529  {
530  MythDB::DBError("GetMplexID 2", query);
531  return -1;
532  }
533 
534  if (query.next())
535  return query.value(0).toInt();
536 
537  return -1;
538 }
539 
541  uint transport_id, uint network_id)
542 {
543  MSqlQuery query(MSqlQuery::InitCon());
544  // See if transport already in database
545  query.prepare(
546  "SELECT mplexid "
547  "FROM dtv_multiplex "
548  "WHERE networkid = :NETWORKID AND "
549  " transportid = :TRANSPORTID AND "
550  " sourceid = :SOURCEID");
551 
552  query.bindValue(":SOURCEID", sourceid);
553  query.bindValue(":NETWORKID", network_id);
554  query.bindValue(":TRANSPORTID", transport_id);
555 
556  if (!query.exec() || !query.isActive())
557  {
558  MythDB::DBError("GetMplexID 3", query);
559  return -1;
560  }
561 
562  if (query.next())
563  return query.value(0).toInt();
564 
565  return -1;
566 }
567 
569 {
570  MSqlQuery query(MSqlQuery::InitCon());
571  /* See if mplexid is already in the database */
572  query.prepare(
573  "SELECT mplexid "
574  "FROM channel "
575  "WHERE chanid = :CHANID");
576 
577  query.bindValue(":CHANID", chanid);
578 
579  if (!query.exec())
580  MythDB::DBError("GetMplexID 4", query);
581  else if (query.next())
582  return query.value(0).toInt();
583 
584  return 0;
585 }
586 
609 // current_mplexid always exists in scanner, see ScanTransport()
610 //
611 int ChannelUtil::GetBetterMplexID(int current_mplexid,
612  int transport_id,
613  int network_id)
614 {
615  LOG(VB_CHANSCAN, LOG_INFO,
616  QString("GetBetterMplexID(mplexId %1, tId %2, netId %3)")
617  .arg(current_mplexid).arg(transport_id).arg(network_id));
618 
619  int q_networkid = 0;
620  int q_transportid = 0;
621  MSqlQuery query(MSqlQuery::InitCon());
622 
623  query.prepare("SELECT networkid, transportid "
624  "FROM dtv_multiplex "
625  "WHERE mplexid = :MPLEX_ID");
626 
627  query.bindValue(":MPLEX_ID", current_mplexid);
628 
629  if (!query.exec())
630  MythDB::DBError("Getting mplexid global search", query);
631  else if (query.next())
632  {
633  q_networkid = query.value(0).toInt();
634  q_transportid = query.value(1).toInt();
635  }
636 
637  // Got a match, return it.
638  if ((q_networkid == network_id) && (q_transportid == transport_id))
639  {
640  LOG(VB_CHANSCAN, LOG_INFO,
641  QString("GetBetterMplexID(): Returning perfect match %1")
642  .arg(current_mplexid));
643  return current_mplexid;
644  }
645 
646  // Not in DB at all, insert it
647  if (!q_networkid && !q_transportid)
648  {
649  int qsize = query.size();
650  query.prepare("UPDATE dtv_multiplex "
651  "SET networkid = :NETWORK_ID, "
652  " transportid = :TRANSPORT_ID "
653  "WHERE mplexid = :MPLEX_ID");
654 
655  query.bindValue(":NETWORK_ID", network_id);
656  query.bindValue(":TRANSPORT_ID", transport_id);
657  query.bindValue(":MPLEX_ID", current_mplexid);
658 
659  if (!query.exec())
660  MythDB::DBError("Getting mplexid global search", query);
661 
662  LOG(VB_CHANSCAN, LOG_INFO,
663  QString("GetBetterMplexID(): net id and transport id "
664  "are null, qsize(%1), Returning %2")
665  .arg(qsize).arg(current_mplexid));
666  return current_mplexid;
667  }
668 
669  // We have a partial match, so we try to do better...
670  std::array<QString,2> theQueries
671  {
672  QString("SELECT a.mplexid "
673  "FROM dtv_multiplex a, dtv_multiplex b "
674  "WHERE a.networkid = :NETWORK_ID AND "
675  " a.transportid = :TRANSPORT_ID AND "
676  " a.sourceid = b.sourceid AND "
677  " b.mplexid = :MPLEX_ID"),
678 
679  QString("SELECT mplexid "
680  "FROM dtv_multiplex "
681  "WHERE networkid = :NETWORK_ID AND "
682  " transportid = :TRANSPORT_ID"),
683  };
684 
685  for (uint i=0; i<2; i++)
686  {
687  query.prepare(theQueries[i]);
688 
689  query.bindValue(":NETWORK_ID", network_id);
690  query.bindValue(":TRANSPORT_ID", transport_id);
691  if (i == 0)
692  query.bindValue(":MPLEX_ID", current_mplexid);
693 
694  if (!query.exec() || !query.isActive())
695  MythDB::DBError("Finding matching mplexid", query);
696 
697  if (query.size() == 1 && query.next())
698  {
699  LOG(VB_CHANSCAN, LOG_INFO,
700  QString("GetBetterMplexID(): query#%1 qsize(%2) "
701  "Returning %3")
702  .arg(i).arg(query.size()).arg(current_mplexid));
703  return query.value(0).toInt();
704  }
705 
706  if (query.next())
707  {
708  int ret = (i==0) ? current_mplexid : query.value(0).toInt();
709  LOG(VB_CHANSCAN, LOG_INFO,
710  QString("GetBetterMplexID(): query#%1 qsize(%2) "
711  "Returning %3")
712  .arg(i).arg(query.size()).arg(ret));
713  return ret;
714  }
715  }
716 
717  // If you still didn't find this combo return -1 (failure)
718  LOG(VB_CHANSCAN, LOG_INFO, "GetBetterMplexID(): Returning -1");
719  return -1;
720 }
721 
723  QString &modulation,
724  uint64_t &frequency,
725  uint &dvb_transportid,
726  uint &dvb_networkid,
727  QString &si_std)
728 {
729  if (!mplexid || (mplexid == 32767)) /* 32767 deals with old lineups */
730  return false;
731 
732  MSqlQuery query(MSqlQuery::InitCon());
733  query.prepare(
734  "SELECT transportid, networkid, frequency, modulation, sistandard "
735  "FROM dtv_multiplex "
736  "WHERE mplexid = :MPLEXID");
737  query.bindValue(":MPLEXID", mplexid);
738 
739  if (!query.exec())
740  {
741  MythDB::DBError("GetTuningParams failed ", query);
742  return false;
743  }
744 
745  if (!query.next())
746  return false;
747 
748  dvb_transportid = query.value(0).toUInt();
749  dvb_networkid = query.value(1).toUInt();
750  frequency = query.value(2).toULongLong();
751  modulation = query.value(3).toString();
752  si_std = query.value(4).toString();
753 
754  return true;
755 }
756 
757 QString ChannelUtil::GetChannelStringField(int chan_id, const QString &field)
758 {
759  if (chan_id < 0)
760  return {};
761 
762  MSqlQuery query(MSqlQuery::InitCon());
763  query.prepare(QString("SELECT %1 FROM channel "
764  "WHERE chanid = :CHANID").arg(field));
765  query.bindValue(":CHANID", chan_id);
766  if (!query.exec())
767  {
768  MythDB::DBError("Selecting channel/dtv_multiplex 1", query);
769  return {};
770  }
771 
772  if (!query.next())
773  return {};
774 
775  return query.value(0).toString();
776 }
777 
778 QString ChannelUtil::GetChanNum(int chan_id)
779 {
780  return GetChannelStringField(chan_id, QString("channum"));
781 }
782 
783 std::chrono::minutes ChannelUtil::GetTimeOffset(int chan_id)
784 {
785  return std::chrono::minutes(GetChannelStringField(chan_id, QString("tmoffset")).toInt());
786 }
787 
788 int ChannelUtil::GetSourceID(int db_mplexid)
789 {
790  MSqlQuery query(MSqlQuery::InitCon());
791 
792  query.prepare("SELECT sourceid "
793  "FROM dtv_multiplex "
794  "WHERE mplexid = :MPLEXID");
795  query.bindValue(":MPLEXID", db_mplexid);
796  if (!query.exec())
797  {
798  MythDB::DBError("Selecting channel/dtv_multiplex", query);
799  return -1;
800  }
801 
802  if (query.next())
803  return query.value(0).toInt();
804 
805  return -1;
806 }
807 
809 {
810  MSqlQuery query(MSqlQuery::InitCon());
811 
812  query.prepare(
813  "SELECT sourceid "
814  "FROM channel "
815  "WHERE chanid = :CHANID");
816  query.bindValue(":CHANID", chanid);
817 
818  if (!query.exec())
819  MythDB::DBError("Selecting channel/dtv_multiplex", query);
820  else if (query.next())
821  return query.value(0).toUInt();
822 
823  return 0;
824 }
825 
826 QStringList ChannelUtil::GetInputTypes(uint chanid)
827 {
828  MSqlQuery query(MSqlQuery::InitCon());
829  query.prepare("SELECT cardtype "
830  "FROM capturecard, channel "
831  "WHERE channel.chanid = :CHANID AND "
832  " channel.sourceid = capturecard.sourceid "
833  "GROUP BY cardtype");
834  query.bindValue(":CHANID", chanid);
835 
836  QStringList list;
837  if (!query.exec())
838  {
839  MythDB::DBError("ChannelUtil::GetInputTypes", query);
840  return list;
841  }
842  while (query.next())
843  list.push_back(query.value(0).toString());
844  return list;
845 }
846 
847 static bool lt_pidcache(
848  const pid_cache_item_t a, const pid_cache_item_t b)
849 {
850  return a.GetPID() < b.GetPID();
851 }
852 
860  pid_cache_t &pid_cache)
861 {
862  MSqlQuery query(MSqlQuery::InitCon());
863  query.prepare("SELECT pid, tableid FROM pidcache "
864  "WHERE chanid = :CHANID");
865 
866  query.bindValue(":CHANID", chanid);
867 
868  if (!query.exec())
869  {
870  MythDB::DBError("GetCachedPids: fetching pids", query);
871  return false;
872  }
873 
874  while (query.next())
875  {
876  int pid = query.value(0).toInt();
877  int tid = query.value(1).toInt();
878  if ((pid >= 0) && (tid >= 0))
879  pid_cache.emplace_back(pid, tid);
880  }
881  stable_sort(pid_cache.begin(), pid_cache.end(), lt_pidcache);
882 
883  return true;
884 }
885 
893  const pid_cache_t &_pid_cache,
894  bool delete_all)
895 {
896  MSqlQuery query(MSqlQuery::InitCon());
897 
899  if (delete_all)
900  query.prepare("DELETE FROM pidcache WHERE chanid = :CHANID");
901  else
902  {
903  query.prepare(
904  "DELETE FROM pidcache "
905  "WHERE chanid = :CHANID AND tableid < 65536");
906  }
907 
908  query.bindValue(":CHANID", chanid);
909 
910  if (!query.exec())
911  {
912  MythDB::DBError("GetCachedPids -- delete", query);
913  return false;
914  }
915 
916  pid_cache_t old_cache;
917  GetCachedPids(chanid, old_cache);
918  pid_cache_t pid_cache = _pid_cache;
919  stable_sort(pid_cache.begin(), pid_cache.end(), lt_pidcache);
920 
922  query.prepare(
923  "INSERT INTO pidcache "
924  "SET chanid = :CHANID, pid = :PID, tableid = :TABLEID");
925  query.bindValue(":CHANID", chanid);
926 
927  bool ok = true;
928  auto ito = old_cache.begin();
929  for (const auto& itn : pid_cache)
930  {
931  // if old pid smaller than current new pid, skip this old pid
932  for (; ito != old_cache.end() && ito->GetPID() < itn.GetPID(); ++ito);
933 
934  // if already in DB, skip DB insert
935  if (ito != old_cache.end() && ito->GetPID() == itn.GetPID())
936  continue;
937 
938  query.bindValue(":PID", itn.GetPID());
939  query.bindValue(":TABLEID", itn.GetComposite());
940 
941  if (!query.exec())
942  {
943  MythDB::DBError("GetCachedPids -- insert", query);
944  ok = false;
945  }
946  }
947 
948  return ok;
949 }
950 
951 QString ChannelUtil::GetChannelValueStr(const QString &channel_field,
952  uint sourceid,
953  const QString &channum)
954 {
955  QString retval;
956 
957  MSqlQuery query(MSqlQuery::InitCon());
958 
959  query.prepare(
960  QString(
961  "SELECT channel.%1 "
962  "FROM channel "
963  "WHERE deleted IS NULL AND "
964  " channum = :CHANNUM AND "
965  " sourceid = :SOURCEID")
966  .arg(channel_field));
967 
968  query.bindValue(":SOURCEID", sourceid);
969  query.bindValue(":CHANNUM", channum);
970 
971  if (!query.exec() || !query.isActive())
972  MythDB::DBError("getchannelvalue", query);
973  else if (query.next())
974  retval = query.value(0).toString();
975 
976  return retval;
977 }
978 
979 int ChannelUtil::GetChannelValueInt(const QString &channel_field,
980  uint sourceid,
981  const QString &channum)
982 {
983  QString val = GetChannelValueStr(channel_field, sourceid, channum);
984 
985  int retval = 0;
986  if (!val.isEmpty())
987  retval = val.toInt();
988 
989  return (retval) ? retval : -1;
990 }
991 
992 QString ChannelUtil::GetChannelNumber(uint sourceid, const QString &channel_name)
993 {
994  if (channel_name.isEmpty())
995  return {};
996 
997  MSqlQuery query(MSqlQuery::InitCon());
998  query.prepare("SELECT channum FROM channel WHERE sourceid = :SOURCEID "
999  "AND name = :NAME "
1000  "AND deleted IS NULL;" );
1001  query.bindValue(":SOURCEID", sourceid);
1002  query.bindValue(":NAME", channel_name.left(64)); // Field channel.name is 64 characters
1003  if (!query.exec())
1004  {
1005  MythDB::DBError("GetChannelNumber", query);
1006  return {};
1007  }
1008 
1009  if (!query.next())
1010  return {};
1011 
1012  return query.value(0).toString();
1013 }
1014 
1016  const QString &new_channum,
1017  const QString &old_channum)
1018 {
1019  if (new_channum.isEmpty() || old_channum.isEmpty())
1020  return false;
1021 
1022  if (new_channum == old_channum)
1023  return true;
1024 
1025  uint old_mplexid = GetMplexID(srcid, old_channum);
1026  if (!old_mplexid)
1027  return false;
1028 
1029  uint new_mplexid = GetMplexID(srcid, new_channum);
1030  if (!new_mplexid)
1031  return false;
1032 
1033  LOG(VB_CHANNEL, LOG_INFO, QString("IsOnSameMultiplex? %1==%2 -> %3")
1034  .arg(old_mplexid).arg(new_mplexid)
1035  .arg(old_mplexid == new_mplexid));
1036 
1037  return old_mplexid == new_mplexid;
1038 }
1039 
1045 static QStringList get_valid_recorder_list(uint chanid)
1046 {
1047  QStringList reclist;
1048 
1049  // Query the database to determine which source is being used currently.
1050  // set the EPG so that it only displays the channels of the current source
1051  MSqlQuery query(MSqlQuery::InitCon());
1052  // We want to get the current source id for this recorder
1053  query.prepare(
1054  "SELECT capturecard.cardid "
1055  "FROM channel "
1056  "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1057  "WHERE channel.chanid = :CHANID AND "
1058  " capturecard.livetvorder > 0 "
1059  "ORDER BY capturecard.livetvorder, capturecard.cardid");
1060  query.bindValue(":CHANID", chanid);
1061 
1062  if (!query.exec() || !query.isActive())
1063  {
1064  MythDB::DBError("get_valid_recorder_list ChanID", query);
1065  return reclist;
1066  }
1067 
1068  while (query.next())
1069  reclist << query.value(0).toString();
1070 
1071  return reclist;
1072 }
1073 
1079 static QStringList get_valid_recorder_list(const QString &channum)
1080 {
1081  QStringList reclist;
1082 
1083  // Query the database to determine which source is being used currently.
1084  // set the EPG so that it only displays the channels of the current source
1085  MSqlQuery query(MSqlQuery::InitCon());
1086  // We want to get the current source id for this recorder
1087  query.prepare(
1088  "SELECT capturecard.cardid "
1089  "FROM channel "
1090  "LEFT JOIN capturecard ON channel.sourceid = capturecard.sourceid "
1091  "WHERE channel.deleted IS NULL AND "
1092  " channel.channum = :CHANNUM AND "
1093  " capturecard.livetvorder > 0 "
1094  "ORDER BY capturecard.livetvorder, capturecard.cardid");
1095  query.bindValue(":CHANNUM", channum);
1096 
1097  if (!query.exec() || !query.isActive())
1098  {
1099  MythDB::DBError("get_valid_recorder_list ChanNum", query);
1100  return reclist;
1101  }
1102 
1103  while (query.next())
1104  reclist << query.value(0).toString();
1105 
1106  return reclist;
1107 }
1108 
1117  uint chanid, const QString &channum)
1118 {
1119  if (chanid)
1120  return get_valid_recorder_list(chanid);
1121  if (!channum.isEmpty())
1122  return get_valid_recorder_list(channum);
1123  return {};
1124 }
1125 
1126 
1127 std::vector<uint> ChannelUtil::GetConflicting(const QString &channum, uint sourceid)
1128 {
1129  MSqlQuery query(MSqlQuery::InitCon());
1130  std::vector<uint> conflicting;
1131 
1132  if (sourceid)
1133  {
1134  query.prepare(
1135  "SELECT chanid from channel "
1136  "WHERE deleted IS NULL AND "
1137  " sourceid = :SOURCEID AND "
1138  " channum = :CHANNUM");
1139  query.bindValue(":SOURCEID", sourceid);
1140  }
1141  else
1142  {
1143  query.prepare(
1144  "SELECT chanid from channel "
1145  "WHERE deleted IS NULL AND "
1146  " channum = :CHANNUM");
1147  }
1148 
1149  query.bindValue(":CHANNUM", channum);
1150  if (!query.exec())
1151  {
1152  MythDB::DBError("IsConflicting", query);
1153  conflicting.push_back(0);
1154  return conflicting;
1155  }
1156 
1157  while (query.next())
1158  conflicting.push_back(query.value(0).toUInt());
1159 
1160  return conflicting;
1161 }
1162 
1163 bool ChannelUtil::SetChannelValue(const QString &field_name,
1164  const QString& value,
1165  uint sourceid,
1166  const QString &channum)
1167 {
1168  MSqlQuery query(MSqlQuery::InitCon());
1169 
1170  query.prepare(
1171  QString("UPDATE channel SET channel.%1=:VALUE "
1172  "WHERE channel.channum = :CHANNUM AND "
1173  " channel.sourceid = :SOURCEID").arg(field_name));
1174 
1175  query.bindValue(":VALUE", value);
1176  query.bindValue(":CHANNUM", channum);
1177  query.bindValue(":SOURCEID", sourceid);
1178 
1179  return query.exec();
1180 }
1181 
1182 bool ChannelUtil::SetChannelValue(const QString &field_name,
1183  const QString& value,
1184  int chanid)
1185 {
1186  MSqlQuery query(MSqlQuery::InitCon());
1187 
1188  query.prepare(
1189  QString("UPDATE channel SET channel.%1=:VALUE "
1190  "WHERE channel.chanid = :CHANID").arg(field_name));
1191 
1192  query.bindValue(":VALUE", value);
1193  query.bindValue(":CHANID", chanid);
1194 
1195  return query.exec();
1196 }
1197 
1201 
1204 {
1205  s_channelDefaultAuthorityMapLock.lockForRead();
1206 
1208  {
1210  s_channelDefaultAuthorityMapLock.lockForWrite();
1211  // cppcheck-suppress knownConditionTrueFalse
1213  {
1214  MSqlQuery query(MSqlQuery::InitCon());
1215  query.prepare(
1216  "SELECT chanid, m.default_authority "
1217  "FROM channel c "
1218  "LEFT JOIN dtv_multiplex m "
1219  "ON (c.mplexid = m.mplexid) "
1220  "WHERE deleted IS NULL");
1221  if (query.exec())
1222  {
1223  while (query.next())
1224  {
1225  if (!query.value(1).toString().isEmpty())
1226  {
1227  s_channelDefaultAuthorityMap[query.value(0).toUInt()] =
1228  query.value(1).toString();
1229  }
1230  }
1232  }
1233  else
1234  {
1235  MythDB::DBError("GetDefaultAuthority 1", query);
1236  }
1237 
1238  query.prepare(
1239  "SELECT chanid, default_authority "
1240  "FROM channel "
1241  "WHERE deleted IS NULL");
1242  if (query.exec())
1243  {
1244  while (query.next())
1245  {
1246  if (!query.value(1).toString().isEmpty())
1247  {
1248  s_channelDefaultAuthorityMap[query.value(0).toUInt()] =
1249  query.value(1).toString();
1250  }
1251  }
1253  }
1254  else
1255  {
1256  MythDB::DBError("GetDefaultAuthority 2", query);
1257  }
1258 
1259  }
1260  }
1261 
1262  QMap<uint,QString>::iterator it = s_channelDefaultAuthorityMap.find(chanid);
1263  QString ret;
1264  if (it != s_channelDefaultAuthorityMap.end())
1265  ret = *it;
1267 
1268  return ret;
1269 }
1270 
1272 {
1273  static QReadWriteLock s_channelIconMapLock;
1274  static QHash<uint,QString> s_channelIconMap;
1275  static bool s_runInit = true;
1276 
1277  s_channelIconMapLock.lockForRead();
1278 
1279  QString ret(s_channelIconMap.value(chanid, "_cold_"));
1280 
1281  s_channelIconMapLock.unlock();
1282 
1283  if (ret != "_cold_")
1284  return ret;
1285 
1286  s_channelIconMapLock.lockForWrite();
1287 
1288  MSqlQuery query(MSqlQuery::InitCon());
1289  QString iconquery = "SELECT chanid, icon FROM channel";
1290 
1291  if (s_runInit)
1292  iconquery += " WHERE visible > 0";
1293  else
1294  iconquery += " WHERE chanid = :CHANID";
1295 
1296  query.prepare(iconquery);
1297 
1298  if (!s_runInit)
1299  query.bindValue(":CHANID", chanid);
1300 
1301  if (query.exec())
1302  {
1303  if (s_runInit)
1304  {
1305  s_channelIconMap.reserve(query.size());
1306  while (query.next())
1307  {
1308  s_channelIconMap[query.value(0).toUInt()] =
1309  query.value(1).toString();
1310  }
1311  s_runInit = false;
1312  }
1313  else
1314  {
1315  s_channelIconMap[chanid] = (query.next()) ?
1316  query.value(1).toString() : "";
1317  }
1318  }
1319  else
1320  {
1321  MythDB::DBError("GetIcon", query);
1322  }
1323 
1324  ret = s_channelIconMap.value(chanid, "");
1325 
1326  s_channelIconMapLock.unlock();
1327 
1328  return ret;
1329 }
1330 
1332 {
1333  return tr("UNKNOWN", "Synthesized callsign");
1334 }
1335 
1336 int ChannelUtil::GetChanID(int mplexid, int service_transport_id,
1337  int major_channel, int minor_channel,
1338  int program_number)
1339 {
1340  MSqlQuery query(MSqlQuery::InitCon());
1341 
1342  // find source id, so we can find manually inserted ATSC channels
1343  query.prepare("SELECT sourceid "
1344  "FROM dtv_multiplex "
1345  "WHERE mplexid = :MPLEXID");
1346  query.bindValue(":MPLEXID", mplexid);
1347  if (!query.exec())
1348  {
1349  MythDB::DBError("Selecting channel/dtv_multiplex 2", query);
1350  return -1;
1351  }
1352  if (!query.next())
1353  return -1;
1354 
1355  int source_id = query.value(0).toInt();
1356 
1357  // find a proper ATSC channel
1358  query.prepare("SELECT chanid FROM channel,dtv_multiplex "
1359  "WHERE channel.deleted IS NULL AND "
1360  " channel.sourceid = :SOURCEID AND "
1361  " atsc_major_chan = :MAJORCHAN AND "
1362  " atsc_minor_chan = :MINORCHAN AND "
1363  " dtv_multiplex.transportid = :TRANSPORTID AND "
1364  " dtv_multiplex.mplexid = :MPLEXID AND "
1365  " dtv_multiplex.sourceid = channel.sourceid AND "
1366  " dtv_multiplex.mplexid = channel.mplexid");
1367 
1368  query.bindValue(":SOURCEID", source_id);
1369  query.bindValue(":MAJORCHAN", major_channel);
1370  query.bindValue(":MINORCHAN", minor_channel);
1371  query.bindValue(":TRANSPORTID", service_transport_id);
1372  query.bindValue(":MPLEXID", mplexid);
1373 
1374  if (query.exec() && query.next())
1375  return query.value(0).toInt();
1376 
1377  // Find manually inserted/edited channels in order of scariness.
1378  // find renamed channel, where atsc is valid
1379  query.prepare("SELECT chanid FROM channel "
1380  "WHERE deleted IS NULL AND "
1381  "sourceid = :SOURCEID AND "
1382  "atsc_major_chan = :MAJORCHAN AND "
1383  "atsc_minor_chan = :MINORCHAN");
1384 
1385  query.bindValue(":SOURCEID", source_id);
1386  query.bindValue(":MAJORCHAN", major_channel);
1387  query.bindValue(":MINORCHAN", minor_channel);
1388 
1389  if (query.exec() && query.next())
1390  return query.value(0).toInt();
1391 
1392  // find based on mpeg program number and mplexid alone
1393  query.prepare("SELECT chanid FROM channel "
1394  "WHERE deleted IS NULL AND "
1395  "sourceid = :SOURCEID AND "
1396  "serviceID = :SERVICEID AND "
1397  "mplexid = :MPLEXID");
1398 
1399  query.bindValue(":SOURCEID", source_id);
1400  query.bindValue(":SERVICEID", program_number);
1401  query.bindValue(":MPLEXID", mplexid);
1402 
1403  if (query.exec() && query.next())
1404  return query.value(0).toInt();
1405 
1406  return -1;
1407 }
1408 
1409 uint ChannelUtil::FindChannel(uint sourceid, const QString &freqid)
1410 {
1411  MSqlQuery query(MSqlQuery::InitCon());
1412  query.prepare("SELECT chanid "
1413  "FROM channel "
1414  "WHERE deleted IS NULL AND "
1415  " sourceid = :SOURCEID AND "
1416  " freqid = :FREQID");
1417 
1418  query.bindValue(":SOURCEID", sourceid);
1419  query.bindValue(":FREQID", freqid);
1420 
1421  if (!query.exec() || !query.isActive())
1422  MythDB::DBError("FindChannel", query);
1423  else if (query.next())
1424  return query.value(0).toUInt();
1425 
1426  return 0;
1427 }
1428 
1429 
1430 static uint get_max_chanid(uint sourceid)
1431 {
1432  QString qstr = "SELECT MAX(chanid) FROM channel ";
1433  qstr += (sourceid) ? "WHERE sourceid = :SOURCEID" : "";
1434 
1436  query.prepare(qstr);
1437 
1438  if (sourceid)
1439  query.bindValue(":SOURCEID", sourceid);
1440 
1441  if (!query.exec() || !query.isActive())
1442  MythDB::DBError("Getting chanid for new channel (2)", query);
1443  else if (!query.next())
1444  LOG(VB_GENERAL, LOG_ERR, "Error getting chanid for new channel.");
1445  else
1446  return query.value(0).toUInt();
1447 
1448  return 0;
1449 }
1450 
1451 static bool chanid_available(uint chanid)
1452 {
1454  query.prepare(
1455  "SELECT chanid "
1456  "FROM channel "
1457  "WHERE chanid = :CHANID");
1458  query.bindValue(":CHANID", chanid);
1459 
1460  if (!query.exec() || !query.isActive())
1461  MythDB::DBError("is_chan_id_available", query);
1462  else if (query.size() == 0)
1463  return true;
1464 
1465  return false;
1466 }
1467 
1472 int ChannelUtil::CreateChanID(uint sourceid, const QString &chan_num)
1473 {
1474  // first try to base it on the channel number for human readability
1475  static const QRegularExpression kNonDigitRE { R"(\D)" };
1476  uint chanid = 0;
1477  int chansep = chan_num.indexOf(kNonDigitRE);
1478  if (chansep > 0)
1479  {
1480  chanid =
1481  sourceid * 10000 +
1482  chan_num.left(chansep).toInt() * 100 +
1483  chan_num.right(chan_num.length() - chansep - 1).toInt();
1484  }
1485  else
1486  {
1487  chanid = sourceid * 10000 + chan_num.toInt();
1488  }
1489 
1490  if ((chanid > sourceid * 10000) && (chanid_available(chanid)))
1491  return chanid;
1492 
1493  // try to at least base it on the sourceid for human readability
1494  chanid = std::max(get_max_chanid(sourceid) + 1, sourceid * 10000);
1495 
1496  if (chanid_available(chanid))
1497  return chanid;
1498 
1499  // just get a chanid we know should work
1500  chanid = get_max_chanid(0) + 1;
1501 
1502  if (chanid_available(chanid))
1503  return chanid;
1504 
1505  // failure
1506  return -1;
1507 }
1508 
1510  uint db_sourceid,
1511  uint new_channel_id,
1512  const QString &callsign,
1513  const QString &service_name,
1514  const QString &chan_num,
1515  uint service_id,
1516  uint atsc_major_channel,
1517  uint atsc_minor_channel,
1518  bool use_on_air_guide,
1519  ChannelVisibleType visible,
1520  const QString &freqid,
1521  const QString& icon,
1522  QString format,
1523  const QString& xmltvid,
1524  const QString& default_authority,
1525  uint service_type,
1526  int recpriority,
1527  int tmOffset,
1528  int commMethod )
1529 {
1530  MSqlQuery query(MSqlQuery::InitCon());
1531 
1532  QString chanNum = (chan_num == "-1") ?
1533  QString::number(service_id) : chan_num;
1534 
1535  QString qstr =
1536  "INSERT INTO channel "
1537  " (chanid, channum, sourceid, "
1538  " callsign, name, serviceid, ";
1539  qstr += (db_mplexid > 0) ? "mplexid, " : "";
1540  qstr += (!freqid.isEmpty()) ? "freqid, " : "";
1541  qstr +=
1542  " atsc_major_chan, atsc_minor_chan, "
1543  " useonairguide, visible, tvformat, "
1544  " icon, xmltvid, default_authority, "
1545  " service_type, recpriority, tmoffset, "
1546  " commmethod ) "
1547  "VALUES "
1548  " (:CHANID, :CHANNUM, :SOURCEID, "
1549  " :CALLSIGN, :NAME, :SERVICEID, ";
1550  qstr += (db_mplexid > 0) ? ":MPLEXID, " : "";
1551  qstr += (!freqid.isEmpty()) ? ":FREQID, " : "";
1552  qstr +=
1553  " :MAJORCHAN, :MINORCHAN, "
1554  " :USEOAG, :VISIBLE, :TVFORMAT, "
1555  " :ICON, :XMLTVID, :AUTHORITY, "
1556  " :SERVICETYPE, :RECPRIORITY, :TMOFFSET, "
1557  " :COMMMETHOD ) ";
1558 
1559  query.prepare(qstr);
1560 
1561  query.bindValue (":CHANID", new_channel_id);
1562  query.bindValueNoNull(":CHANNUM", chanNum);
1563  query.bindValue (":SOURCEID", db_sourceid);
1564  query.bindValueNoNull(":CALLSIGN", callsign);
1565  query.bindValueNoNull(":NAME", service_name);
1566 
1567  if (db_mplexid > 0)
1568  query.bindValue(":MPLEXID", db_mplexid);
1569 
1570  query.bindValue(":SERVICEID", service_id);
1571  query.bindValue(":MAJORCHAN", atsc_major_channel);
1572  query.bindValue(":MINORCHAN", atsc_minor_channel);
1573  query.bindValue(":USEOAG", use_on_air_guide);
1574  query.bindValue(":VISIBLE", visible);
1575 
1576  if (!freqid.isEmpty())
1577  query.bindValue(":FREQID", freqid);
1578 
1579  QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : std::move(format);
1580  query.bindValueNoNull(":TVFORMAT", tvformat);
1581  query.bindValueNoNull(":ICON", icon);
1582  query.bindValueNoNull(":XMLTVID", xmltvid);
1583  query.bindValueNoNull(":AUTHORITY", default_authority);
1584  query.bindValue (":SERVICETYPE", service_type);
1585  query.bindValue (":RECPRIORITY", recpriority);
1586  query.bindValue (":TMOFFSET", tmOffset);
1587  query.bindValue (":COMMMETHOD", commMethod);
1588 
1589  if (!query.exec() || !query.isActive())
1590  {
1591  MythDB::DBError("Adding Service", query);
1592  return false;
1593  }
1594  return true;
1595 }
1596 
1598  uint source_id,
1599  uint channel_id,
1600  const QString &callsign,
1601  const QString &service_name,
1602  const QString &chan_num,
1603  uint service_id,
1604  uint atsc_major_channel,
1605  uint atsc_minor_channel,
1606  bool use_on_air_guide,
1607  ChannelVisibleType visible,
1608  const QString& freqid,
1609  const QString& icon,
1610  QString format,
1611  const QString& xmltvid,
1612  const QString& default_authority,
1613  uint service_type,
1614  int recpriority,
1615  int tmOffset,
1616  int commMethod )
1617 {
1618  if (!channel_id)
1619  return false;
1620 
1621  QString tvformat = (atsc_minor_channel > 0) ? "ATSC" : std::move(format);
1622  bool set_channum = !chan_num.isEmpty() && chan_num != "-1";
1623  QString qstr = QString(
1624  "UPDATE channel "
1625  "SET %1 %2 %3 %4 %5 %6 %7 %8 %9 "
1626  " mplexid = :MPLEXID, serviceid = :SERVICEID, "
1627  " atsc_major_chan = :MAJORCHAN, atsc_minor_chan = :MINORCHAN, "
1628  " callsign = :CALLSIGN, name = :NAME, "
1629  " sourceid = :SOURCEID, useonairguide = :USEOAG, "
1630  " visible = :VISIBLE, service_type = :SERVICETYPE "
1631  "WHERE chanid=:CHANID")
1632  .arg((!set_channum) ? "" : "channum = :CHANNUM, ",
1633  (freqid.isEmpty()) ? "" : "freqid = :FREQID, ",
1634  (icon.isEmpty()) ? "" : "icon = :ICON, ",
1635  (tvformat.isEmpty()) ? "" : "tvformat = :TVFORMAT, ",
1636  (xmltvid.isEmpty()) ? "" : "xmltvid = :XMLTVID, ",
1637  (default_authority.isEmpty()) ?
1638  "" : "default_authority = :AUTHORITY,",
1639  (recpriority == INT_MIN) ? "" : "recpriority = :RECPRIORITY, ",
1640  (tmOffset == INT_MIN) ? "" : "tmOffset = :TMOFFSET, ",
1641  (commMethod == INT_MIN) ? "" : "commmethod = :COMMMETHOD, ");
1642 
1643  MSqlQuery query(MSqlQuery::InitCon());
1644  query.prepare(qstr);
1645 
1646  query.bindValue(":CHANID", channel_id);
1647 
1648  if (set_channum)
1649  query.bindValue(":CHANNUM", chan_num);
1650 
1651  query.bindValue (":SOURCEID", source_id);
1652  query.bindValueNoNull(":CALLSIGN", callsign);
1653  query.bindValueNoNull(":NAME", service_name);
1654 
1655  query.bindValue(":MPLEXID", db_mplexid);
1656  query.bindValue(":SERVICEID", service_id);
1657  query.bindValue(":MAJORCHAN", atsc_major_channel);
1658  query.bindValue(":MINORCHAN", atsc_minor_channel);
1659  query.bindValue(":USEOAG", use_on_air_guide);
1660  query.bindValue(":VISIBLE", visible);
1661  query.bindValue(":SERVICETYPE", service_type);
1662 
1663  if (!freqid.isNull())
1664  query.bindValue(":FREQID", freqid);
1665  if (!tvformat.isNull())
1666  query.bindValue(":TVFORMAT", tvformat);
1667  if (!icon.isNull())
1668  query.bindValue(":ICON", icon);
1669  if (!xmltvid.isNull())
1670  query.bindValue(":XMLTVID", xmltvid);
1671  if (!default_authority.isNull())
1672  query.bindValue(":AUTHORITY", default_authority);
1673  if (recpriority != INT_MIN)
1674  query.bindValue(":RECPRIORITY", recpriority);
1675  if (tmOffset != INT_MIN)
1676  query.bindValue(":TMOFFSET", tmOffset);
1677  if (commMethod != INT_MIN)
1678  query.bindValue(":COMMMETHOD", commMethod);
1679 
1680  if (!query.exec())
1681  {
1682  MythDB::DBError("Updating Service", query);
1683  return false;
1684  }
1685  return true;
1686 }
1687 
1689 {
1690  MSqlQuery query(MSqlQuery::InitCon());
1691  query.prepare(
1692  "SELECT channum "
1693  "FROM channel "
1694  "WHERE chanid = :ID");
1695  query.bindValue(":ID", chan.m_channelId);
1696 
1697  if (!query.exec())
1698  {
1699  MythDB::DBError("UpdateChannelNumberFromDB", query);
1700  return;
1701  }
1702 
1703  if (query.next())
1704  {
1705  QString channum = query.value(0).toString();
1706 
1707  if (!channum.isEmpty())
1708  {
1709  chan.m_chanNum = channum;
1710  }
1711  }
1712 }
1713 
1715 {
1716  MSqlQuery query(MSqlQuery::InitCon());
1717  query.prepare(
1718  "SELECT xmltvid, useonairguide, visible "
1719  "FROM channel "
1720  "WHERE chanid = :ID");
1721  query.bindValue(":ID", chan.m_channelId);
1722 
1723  if (!query.exec())
1724  {
1725  MythDB::DBError("UpdateInsertInfoFromDB", query);
1726  return;
1727  }
1728 
1729  if (query.next())
1730  {
1731  QString xmltvid = query.value(0).toString();
1732  bool useeit = query.value(1).toBool();
1733  ChannelVisibleType visible =
1734  static_cast<ChannelVisibleType>(query.value(2).toInt());
1735 
1736  if (!xmltvid.isEmpty())
1737  {
1738  if (useeit)
1739  {
1740  LOG(VB_GENERAL, LOG_ERR,
1741  "Using EIT and xmltv for the same channel "
1742  "is an unsupported configuration.");
1743  }
1744  chan.m_xmltvId = xmltvid;
1745  }
1746  chan.m_useOnAirGuide = useeit;
1747  chan.m_hidden = (visible == kChannelNotVisible ||
1748  visible == kChannelNeverVisible);
1749  chan.m_visible = visible;
1750  }
1751 }
1752 
1754  uint channel_id, const IPTVTuningData &tuning)
1755 {
1756  MSqlQuery query(MSqlQuery::InitCon());
1757 
1758  query.prepare(
1759  "DELETE FROM iptv_channel "
1760  "WHERE chanid=:CHANID");
1761  query.bindValue(":CHANID", channel_id);
1762 
1763  if (!query.exec())
1764  {
1765  MythDB::DBError("UpdateIPTVTuningData -- delete", query);
1766  return false;
1767  }
1768 
1769  query.prepare(
1770  "INSERT INTO iptv_channel (chanid, url, type, bitrate) "
1771  "VALUES (:CHANID, :URL, :TYPE, :BITRATE)");
1772  query.bindValue(":CHANID", channel_id);
1773 
1774  query.bindValue(":URL", tuning.GetDataURL().toString());
1775  query.bindValue(":TYPE", tuning.GetFECTypeString(0));
1776  query.bindValue(":BITRATE", tuning.GetBitrate(0));
1777 
1778  if (!query.exec())
1779  {
1780  MythDB::DBError("UpdateIPTVTuningData -- data", query);
1781  return false;
1782  }
1783 
1784  if (tuning.GetFECURL0().port() >= 0)
1785  {
1786  query.bindValue(":URL", tuning.GetFECURL0().toString());
1787  query.bindValue(":TYPE", tuning.GetFECTypeString(1));
1788  query.bindValue(":BITRATE", tuning.GetBitrate(1));
1789  if (!query.exec())
1790  {
1791  MythDB::DBError("UpdateIPTVTuningData -- fec 0", query);
1792  return false;
1793  }
1794  }
1795 
1796  if (tuning.GetFECURL1().port() >= 0)
1797  {
1798  query.bindValue(":URL", tuning.GetFECURL1().toString());
1799  query.bindValue(":TYPE", tuning.GetFECTypeString(2));
1800  query.bindValue(":BITRATE", tuning.GetBitrate(2));
1801  if (!query.exec())
1802  {
1803  MythDB::DBError("UpdateIPTVTuningData -- fec 1", query);
1804  return false;
1805  }
1806  }
1807 
1808  return true;
1809 }
1810 
1812 {
1813  MSqlQuery query(MSqlQuery::InitCon());
1814  query.prepare(
1815  "UPDATE channel "
1816  "SET deleted = NOW() "
1817  "WHERE chanid = :ID");
1818  query.bindValue(":ID", channel_id);
1819 
1820  if (!query.exec())
1821  {
1822  MythDB::DBError("Delete Channel", query);
1823  return false;
1824  }
1825 
1826  return true;
1827 }
1828 
1830 {
1831  MSqlQuery query(MSqlQuery::InitCon());
1832  query.prepare(
1833  "UPDATE channel "
1834  "SET visible = :VISIBLE "
1835  "WHERE chanid = :ID");
1836  query.bindValue(":ID", channel_id);
1837  query.bindValue(":VISIBLE", visible);
1838 
1839  if (!query.exec())
1840  {
1841  MythDB::DBError("ChannelUtil::SetVisible", query);
1842  return false;
1843  }
1844 
1845  return true;
1846 }
1847 
1849 {
1850  MSqlQuery query(MSqlQuery::InitCon());
1851 
1852  query.prepare("UPDATE dtv_multiplex "
1853  "SET serviceversion = :VERSION "
1854  "WHERE mplexid = :MPLEXID");
1855 
1856  query.bindValue(":VERSION", version);
1857  query.bindValue(":MPLEXID", mplexid);
1858 
1859  if (!query.exec())
1860  {
1861  MythDB::DBError("Selecting channel/dtv_multiplex", query);
1862  return false;
1863  }
1864  return true;
1865 }
1866 
1868 {
1869  MSqlQuery query(MSqlQuery::InitCon());
1870 
1871  query.prepare("SELECT serviceversion "
1872  "FROM dtv_multiplex "
1873  "WHERE mplexid = :MPLEXID");
1874 
1875  query.bindValue(":MPLEXID", mplexid);
1876 
1877  if (!query.exec())
1878  {
1879  MythDB::DBError("Selecting channel/dtv_multiplex", query);
1880  return 0;
1881  }
1882 
1883  if (query.next())
1884  return query.value(0).toInt();
1885 
1886  return -1;
1887 }
1888 
1889 bool ChannelUtil::GetATSCChannel(uint sourceid, const QString &channum,
1890  uint &major, uint &minor)
1891 {
1892  major = minor = 0;
1893 
1894  MSqlQuery query(MSqlQuery::InitCon());
1895  query.prepare(
1896  "SELECT atsc_major_chan, atsc_minor_chan "
1897  "FROM channel "
1898  "WHERE deleted IS NULL AND "
1899  " channum = :CHANNUM AND "
1900  " sourceid = :SOURCEID");
1901 
1902  query.bindValue(":SOURCEID", sourceid);
1903  query.bindValue(":CHANNUM", channum);
1904 
1905  if (!query.exec() || !query.isActive())
1906  MythDB::DBError("getatscchannel", query);
1907  else if (query.next())
1908  {
1909  major = query.value(0).toUInt();
1910  minor = query.value(1).toUInt();
1911  return true;
1912  }
1913 
1914  return false;
1915 }
1916 
1918  uint sourceid,
1919  uint &chanid, const QString &channum,
1920  QString &tvformat, QString &modulation,
1921  QString &freqtable, QString &freqid,
1922  int &finetune, uint64_t &frequency,
1923  QString &dtv_si_std, int &mpeg_prog_num,
1924  uint &atsc_major, uint &atsc_minor,
1925  uint &dvb_transportid, uint &dvb_networkid,
1926  uint &mplexid,
1927  bool &commfree)
1928 {
1929  chanid = 0;
1930  tvformat.clear();
1931  modulation.clear();
1932  freqtable.clear();;
1933  freqid.clear();
1934  dtv_si_std.clear();
1935  finetune = 0;
1936  frequency = 0;
1937  mpeg_prog_num = -1;
1938  atsc_major = atsc_minor = mplexid = 0;
1939  dvb_networkid = dvb_transportid = 0;
1940  commfree = false;
1941 
1942  int found = 0;
1943  MSqlQuery query(MSqlQuery::InitCon());
1944  query.prepare(
1945  "SELECT finetune, freqid, tvformat, freqtable, "
1946  " commmethod, mplexid, "
1947  " atsc_major_chan, atsc_minor_chan, serviceid, "
1948  " chanid, visible "
1949  "FROM channel, videosource "
1950  "WHERE channel.deleted IS NULL AND "
1951  " videosource.sourceid = channel.sourceid AND "
1952  " channum = :CHANNUM AND "
1953  " channel.sourceid = :SOURCEID "
1954  "ORDER BY channel.visible > 0 DESC, channel.chanid ");
1955  query.bindValue(":CHANNUM", channum);
1956  query.bindValue(":SOURCEID", sourceid);
1957 
1958  if (!query.exec() || !query.isActive())
1959  {
1960  MythDB::DBError("GetChannelData", query);
1961  return false;
1962  }
1963 
1964  if (query.next())
1965  {
1966  finetune = query.value(0).toInt();
1967  freqid = query.value(1).toString();
1968  tvformat = query.value(2).toString();
1969  freqtable = query.value(3).toString();
1970  commfree = (query.value(4).toInt() == -2);
1971  mplexid = query.value(5).toUInt();
1972  atsc_major = query.value(6).toUInt();
1973  atsc_minor = query.value(7).toUInt();
1974  mpeg_prog_num = (query.value(8).isNull()) ? -1
1975  : query.value(8).toInt();
1976  chanid = query.value(9).toUInt();
1977 
1978  if (query.value(10).toInt() > kChannelNotVisible)
1979  found++;
1980  }
1981 
1982  while (query.next())
1983  if (query.value(10).toInt() > kChannelNotVisible)
1984  found++;
1985 
1986  if (found == 0 && chanid)
1987  {
1988  LOG(VB_GENERAL, LOG_WARNING,
1989  QString("No visible channels for %1, using invisble chanid %2")
1990  .arg(channum).arg(chanid));
1991  }
1992 
1993  if (found > 1)
1994  {
1995  LOG(VB_GENERAL, LOG_WARNING,
1996  QString("Found multiple visible channels for %1, using chanid %2")
1997  .arg(channum).arg(chanid));
1998  }
1999 
2000  if (!chanid)
2001  {
2002  LOG(VB_GENERAL, LOG_ERR,
2003  QString("Could not find channel '%1' in DB for source %2 '%3'.")
2004  .arg(channum).arg(sourceid).arg(SourceUtil::GetSourceName(sourceid)));
2005  return false;
2006  }
2007 
2008  if (!mplexid || (mplexid == 32767)) /* 32767 deals with old lineups */
2009  return true;
2010 
2011  return GetTuningParams(mplexid, modulation, frequency,
2012  dvb_transportid, dvb_networkid, dtv_si_std);
2013 }
2014 
2016 {
2017  MSqlQuery query(MSqlQuery::InitCon());
2018  query.prepare(
2019  "SELECT type+0, url, bitrate "
2020  "FROM iptv_channel "
2021  "WHERE chanid = :CHANID "
2022  "ORDER BY type+0");
2023  query.bindValue(":CHANID", chanid);
2024 
2025  if (!query.exec())
2026  {
2027  MythDB::DBError("GetChannelData -- iptv", query);
2028  return {};
2029  }
2030 
2031  QString data_url;
2032  QString fec_url0;
2033  QString fec_url1;
2035  std::array<uint,3> bitrate { 0, 0, 0, };
2036  while (query.next())
2037  {
2039  query.value(0).toUInt();
2040  switch (type)
2041  {
2042  case IPTVTuningData::kData:
2043  data_url = query.value(1).toString();
2044  bitrate[0] = query.value(2).toUInt();
2045  break;
2049  fec_url0 = query.value(1).toString();
2050  bitrate[1] = query.value(2).toUInt();
2051  break;
2055  fec_url1 = query.value(1).toString();
2056  bitrate[2] = query.value(2).toUInt();
2057  break;
2058  }
2059  switch (type)
2060  {
2061  case IPTVTuningData::kData:
2062  break;
2064  fec_type = IPTVTuningData::kRFC2733;
2065  break;
2067  fec_type = IPTVTuningData::kRFC5109;
2068  break;
2070  fec_type = IPTVTuningData::kSMPTE2022;
2071  break;
2075  break; // will be handled by type of first FEC stream
2076  }
2077  }
2078 
2079  IPTVTuningData tuning(data_url, bitrate[0], fec_type,
2080  fec_url0, bitrate[1], fec_url1, bitrate[2]);
2081  LOG(VB_GENERAL, LOG_INFO, QString("Loaded %1 for %2")
2082  .arg(tuning.GetDeviceName()).arg(chanid));
2083  return tuning;
2084 }
2085 
2086 // TODO This should be modified to load a complete channelinfo object including
2087 // all fields from the database
2092  uint sourceid, bool visible_only, bool include_disconnected,
2093  const QString &group_by, uint channel_groupid)
2094 {
2095  ChannelInfoList list;
2096 
2097  MSqlQuery query(MSqlQuery::InitCon());
2098 
2099  QString qstr = QString(
2100  "SELECT videosource.sourceid, GROUP_CONCAT(capturecard.cardid) "
2101  "FROM videosource "
2102  "%1 JOIN capturecard ON capturecard.sourceid = videosource.sourceid "
2103  "GROUP BY videosource.sourceid")
2104  .arg((include_disconnected) ? "LEFT" : "");
2105 
2106  query.prepare(qstr);
2107  if (!query.exec())
2108  {
2109  MythDB::DBError("ChannelUtil::GetChannels()", query);
2110  return list;
2111  }
2112 
2113  QMap<uint, QList<uint>> inputIdLists;
2114  while (query.next())
2115  {
2116  uint qSourceId = query.value(0).toUInt();
2117  QList<uint> &inputIdList = inputIdLists[qSourceId];
2118  QStringList inputIds = query.value(1).toString().split(",");
2119  while (!inputIds.isEmpty())
2120  inputIdList.append(inputIds.takeFirst().toUInt());
2121  }
2122 
2123  qstr = QString(
2124  "SELECT channum, callsign, channel.chanid, "
2125  " atsc_major_chan, atsc_minor_chan, "
2126  " name, icon, mplexid, visible, "
2127  " channel.sourceid, "
2128  " GROUP_CONCAT(DISTINCT channelgroup.grpid), "
2129  " xmltvid "
2130  "FROM channel "
2131  "LEFT JOIN channelgroup ON channel.chanid = channelgroup.chanid ");
2132 
2133  qstr += "WHERE deleted IS NULL ";
2134 
2135  if (sourceid)
2136  qstr += QString("AND channel.sourceid='%1' ").arg(sourceid);
2137 
2138  // Select only channels from the specified channel group
2139  if (channel_groupid > 0)
2140  qstr += QString("AND channelgroup.grpid = '%1' ").arg(channel_groupid);
2141 
2142  if (visible_only)
2143  qstr += QString("AND visible > 0 ");
2144 
2145  qstr += " GROUP BY chanid";
2146 
2147  if (!group_by.isEmpty())
2148  qstr += QString(", %1").arg(group_by);
2149 
2150  query.prepare(qstr);
2151  if (!query.exec())
2152  {
2153  MythDB::DBError("ChannelUtil::GetChannels()", query);
2154  return list;
2155  }
2156 
2157  while (query.next())
2158  {
2159  if (query.value(0).toString().isEmpty() || !query.value(2).toBool())
2160  continue; // skip if channum blank, or chanid empty
2161 
2162  uint qSourceID = query.value(9).toUInt();
2163  ChannelInfo chan(
2164  query.value(0).toString(), /* channum */
2165  query.value(1).toString(), /* callsign */
2166  query.value(2).toUInt(), /* chanid */
2167  query.value(3).toUInt(), /* ATSC major */
2168  query.value(4).toUInt(), /* ATSC minor */
2169  query.value(7).toUInt(), /* mplexid */
2170  static_cast<ChannelVisibleType>(query.value(8).toInt()),
2171  /* visible */
2172  query.value(5).toString(), /* name */
2173  query.value(6).toString(), /* icon */
2174  qSourceID); /* sourceid */
2175 
2176  chan.m_xmltvId = query.value(11).toString(); /* xmltvid */
2177 
2178  for (auto inputId : std::as_const(inputIdLists[qSourceID]))
2179  chan.AddInputId(inputId);
2180 
2181  QStringList groupIDs = query.value(10).toString().split(",");
2182  while (!groupIDs.isEmpty())
2183  chan.AddGroupId(groupIDs.takeFirst().toUInt());
2184 
2185  list.push_back(chan);
2186 
2187  }
2188 
2189  return list;
2190 }
2191 
2192 std::vector<uint> ChannelUtil::GetChanIDs(int sourceid, bool onlyVisible)
2193 {
2194  MSqlQuery query(MSqlQuery::InitCon());
2195 
2196  QString select = "SELECT chanid FROM channel WHERE deleted IS NULL ";
2197  // Yes, this a little ugly
2198  if (onlyVisible || sourceid > 0)
2199  {
2200  if (onlyVisible)
2201  select += "AND visible > 0 ";
2202  if (sourceid > 0)
2203  select += "AND sourceid=" + QString::number(sourceid);
2204  }
2205 
2206  std::vector<uint> list;
2207  query.prepare(select);
2208  if (!query.exec())
2209  {
2210  MythDB::DBError("SourceUtil::GetChanIDs()", query);
2211  return list;
2212  }
2213 
2214  while (query.next())
2215  list.push_back(query.value(0).toUInt());
2216 
2217  return list;
2218 }
2219 
2220 inline bool lt_callsign(const ChannelInfo &a, const ChannelInfo &b)
2221 {
2223 }
2224 
2225 inline bool lt_smart(const ChannelInfo &a, const ChannelInfo &b)
2226 {
2227  static QMutex s_sepExprLock;
2228  static const QRegularExpression kSepExpr(ChannelUtil::kATSCSeparators);
2229 
2230  bool isIntA = false;
2231  bool isIntB = false;
2232  int a_int = a.m_chanNum.toUInt(&isIntA);
2233  int b_int = b.m_chanNum.toUInt(&isIntB);
2234  int a_major = a.m_atscMajorChan;
2235  int b_major = b.m_atscMajorChan;
2236  int a_minor = a.m_atscMinorChan;
2237  int b_minor = b.m_atscMinorChan;
2238 
2239  // Extract minor and major numbers from channum..
2240  int idxA = 0;
2241  int idxB = 0;
2242  {
2243  QMutexLocker locker(&s_sepExprLock);
2244  idxA = a.m_chanNum.indexOf(kSepExpr);
2245  idxB = b.m_chanNum.indexOf(kSepExpr);
2246  }
2247  if (idxA >= 0)
2248  {
2249  bool tmp1 = false;
2250  bool tmp2 = false;
2251  int major = a.m_chanNum.left(idxA).toUInt(&tmp1);
2252  int minor = a.m_chanNum.mid(idxA+1).toUInt(&tmp2);
2253  if (tmp1 && tmp2)
2254  (a_major = major), (a_minor = minor), (isIntA = false);
2255  }
2256 
2257  if (idxB >= 0)
2258  {
2259  bool tmp1 = false;
2260  bool tmp2 = false;
2261  int major = b.m_chanNum.left(idxB).toUInt(&tmp1);
2262  int minor = b.m_chanNum.mid(idxB+1).toUInt(&tmp2);
2263  if (tmp1 && tmp2)
2264  (b_major = major), (b_minor = minor), (isIntB = false);
2265  }
2266 
2267  // If ATSC channel has been renumbered, sort by new channel number
2268  if ((a_minor > 0) && isIntA)
2269  {
2270  int atsc_int = (QString("%1%2").arg(a_major).arg(a_minor)).toInt();
2271  a_minor = (atsc_int == a_int) ? a_minor : 0;
2272  }
2273 
2274  if ((b_minor > 0) && isIntB)
2275  {
2276  int atsc_int = (QString("%1%2").arg(b_major).arg(b_minor)).toInt();
2277  b_minor = (atsc_int == b_int) ? b_minor : 0;
2278  }
2279 
2280  // one of the channels is an ATSC channel, and the other
2281  // is either ATSC or is numeric.
2282  if ((a_minor || b_minor) &&
2283  (a_minor || isIntA) && (b_minor || isIntB))
2284  {
2285  int a_maj = (!a_minor && isIntA) ? a_int : a_major;
2286  int b_maj = (!b_minor && isIntB) ? b_int : b_major;
2287  int cmp = a_maj - b_maj;
2288  if (cmp != 0)
2289  return cmp < 0;
2290 
2291  cmp = a_minor - b_minor;
2292  if (cmp != 0)
2293  return cmp < 0;
2294  }
2295 
2296  if (isIntA && isIntB)
2297  {
2298  // both channels have a numeric channum
2299  int cmp = a_int - b_int;
2300  if (cmp)
2301  return cmp < 0;
2302  }
2303  else if (isIntA ^ isIntB)
2304  {
2305  // if only one is channel numeric always consider it less than
2306  return isIntA;
2307  }
2308  else
2309  {
2310  // neither of channels have a numeric channum
2312  if (cmp)
2313  return cmp < 0;
2314  }
2315 
2316  return lt_callsign(a,b);
2317 }
2318 
2320 {
2321  MSqlQuery query(MSqlQuery::InitCon());
2322  QString select;
2323 
2324 
2325  select = "SELECT chanid FROM channel WHERE deleted IS NULL ";
2326  if (sourceid >= 0)
2327  select += "AND sourceid=" + QString::number(sourceid);
2328  select += ';';
2329 
2330  query.prepare(select);
2331 
2332  if (!query.exec() || !query.isActive())
2333  return 0;
2334 
2335  return query.size();
2336 }
2337 
2338 void ChannelUtil::SortChannels(ChannelInfoList &list, const QString &order,
2339  bool eliminate_duplicates)
2340 {
2341  bool cs = order.toLower() == "callsign";
2342  if (cs)
2343  stable_sort(list.begin(), list.end(), lt_callsign);
2344  else /* if (sortorder == "channum") */
2345  stable_sort(list.begin(), list.end(), lt_smart);
2346 
2347  if (eliminate_duplicates && !list.empty())
2348  {
2350  tmp.push_back(list[0]);
2351  for (size_t i = 1; i < list.size(); i++)
2352  {
2353  if ((cs && lt_callsign(tmp.back(), list[i])) ||
2354  (!cs && lt_smart(tmp.back(), list[i])))
2355  {
2356  tmp.push_back(list[i]);
2357  }
2358  }
2359 
2360  list = tmp;
2361  }
2362 }
2363 
2364 // Return the array index of the best matching channel. An exact
2365 // match is the best match. Otherwise, find the closest numerical
2366 // value greater than channum. E.g., if the channel list is {2_1,
2367 // 2_2, 4_1, 4_2, 300} then input 3 returns 2_2, input 4 returns 2_2,
2368 // and input 5 returns 4_2.
2369 //
2370 // The list does not need to be sorted.
2372  const QString &channum)
2373 {
2374  ChannelInfo target;
2375  target.m_chanNum = channum;
2376  int b = -1; // index of best seen so far
2377  for (int i = 0; i < (int)list.size(); ++i)
2378  {
2379  // Index i is a better result if any of the following hold:
2380  // i is the first element seen
2381  // i < target < best (i.e., i is the first one less than the target)
2382  // best < i < target
2383  // target < i < best
2384  if ((b < 0) ||
2385  (lt_smart(list[i], target) && lt_smart(target, list[b])) ||
2386  (lt_smart(list[b], list[i]) && lt_smart(list[i], target)) ||
2387  (lt_smart(target, list[i]) && lt_smart(list[i], list[b])))
2388  {
2389  b = i;
2390  }
2391  }
2392  return b;
2393 }
2394 
2396  const ChannelInfoList &sorted,
2397  uint old_chanid,
2398  uint mplexid_restriction,
2399  uint chanid_restriction,
2400  ChannelChangeDirection direction,
2401  bool skip_non_visible,
2402  bool skip_same_channum_and_callsign,
2403  bool skip_other_sources)
2404 {
2405  auto it = find(sorted.cbegin(), sorted.cend(), old_chanid);
2406 
2407  if (it == sorted.end())
2408  it = sorted.begin(); // not in list, pretend we are on first channel
2409 
2410  if (it == sorted.end())
2411  return 0; // no channels..
2412 
2413  auto start = it;
2414 
2415  if (CHANNEL_DIRECTION_DOWN == direction)
2416  {
2417  do
2418  {
2419  if (it == sorted.begin())
2420  {
2421  it = find(sorted.begin(), sorted.end(),
2422  sorted.rbegin()->m_chanId);
2423  if (it == sorted.end())
2424  {
2425  --it;
2426  }
2427  }
2428  else
2429  {
2430  --it;
2431  }
2432  }
2433  while ((it != start) &&
2434  ((skip_non_visible && it->m_visible < kChannelVisible) ||
2435  (skip_other_sources &&
2436  it->m_sourceId != start->m_sourceId) ||
2437  (skip_same_channum_and_callsign &&
2438  it->m_chanNum == start->m_chanNum &&
2439  it->m_callSign == start->m_callSign) ||
2440  ((mplexid_restriction != 0U) &&
2441  (mplexid_restriction != it->m_mplexId)) ||
2442  ((chanid_restriction != 0U) &&
2443  (chanid_restriction != it->m_chanId))));
2444  }
2445  else if ((CHANNEL_DIRECTION_UP == direction) ||
2446  (CHANNEL_DIRECTION_FAVORITE == direction))
2447  {
2448  do
2449  {
2450  ++it;
2451  if (it == sorted.end())
2452  it = sorted.begin();
2453  }
2454  while ((it != start) &&
2455  ((skip_non_visible && it->m_visible < kChannelVisible) ||
2456  (skip_other_sources &&
2457  it->m_sourceId != start->m_sourceId) ||
2458  (skip_same_channum_and_callsign &&
2459  it->m_chanNum == start->m_chanNum &&
2460  it->m_callSign == start->m_callSign) ||
2461  ((mplexid_restriction != 0U) &&
2462  (mplexid_restriction != it->m_mplexId)) ||
2463  ((chanid_restriction != 0U) &&
2464  (chanid_restriction != it->m_chanId))));
2465  }
2466 
2467  return it->m_chanId;
2468 }
2469 
2471  uint &totalAvailable,
2472  bool ignoreHidden,
2473  ChannelUtil::OrderBy orderBy,
2474  ChannelUtil::GroupBy groupBy,
2475  uint sourceID,
2476  uint channelGroupID,
2477  bool liveTVOnly,
2478  const QString& callsign,
2479  const QString& channum,
2480  bool ignoreUntunable)
2481 {
2482  ChannelInfoList channelList;
2483 
2484  MSqlQuery query(MSqlQuery::InitCon());
2485 
2486  QString sql = QString(
2487  "SELECT parentid, GROUP_CONCAT(cardid ORDER BY cardid) "
2488  "FROM capturecard "
2489  "WHERE parentid <> 0 "
2490  "GROUP BY parentid ");
2491 
2492  query.prepare(sql);
2493  if (!query.exec())
2494  {
2495  MythDB::DBError("ChannelUtil::GetChannels()", query);
2496  return channelList;
2497  }
2498 
2499  QMap<uint, QList<uint>> childIdLists;
2500  while (query.next())
2501  {
2502  auto parentId = query.value(0).toUInt();
2503  auto &childIdList = childIdLists[parentId];
2504  auto childIds = query.value(1).toString().split(",");
2505  while (!childIds.isEmpty())
2506  childIdList.append(childIds.takeFirst().toUInt());
2507  }
2508 
2509  sql = "SELECT %1 channum, freqid, channel.sourceid, "
2510  "callsign, name, icon, finetune, videofilters, xmltvid, "
2511  "channel.recpriority, channel.contrast, channel.brightness, "
2512  "channel.colour, channel.hue, tvformat, "
2513  "visible, outputfilters, useonairguide, mplexid, "
2514  "serviceid, atsc_major_chan, atsc_minor_chan, last_record, "
2515  "default_authority, commmethod, tmoffset, iptvid, "
2516  "channel.chanid, "
2517  "GROUP_CONCAT(DISTINCT `groups`.`groupids`), " // Creates a CSV list of channel groupids for this channel
2518  "GROUP_CONCAT(DISTINCT capturecard.cardid "
2519  " ORDER BY livetvorder), " // Creates a CSV list of inputids for this channel
2520  "MIN(livetvorder) livetvorder "
2521  "FROM channel ";
2522  if (!channelGroupID)
2523  sql += "LEFT ";
2524  sql += "JOIN ( "
2525  " SELECT chanid ,"
2526  " GROUP_CONCAT(grpid ORDER BY grpid) groupids "
2527  " FROM channelgroup ";
2528  if (channelGroupID)
2529  sql += " WHERE grpid = :CHANGROUPID ";
2530  sql += " GROUP BY chanid "
2531  ") `groups` "
2532  " ON channel.chanid = `groups`.`chanid` ";
2533  if (!ignoreUntunable && !liveTVOnly)
2534  sql += "LEFT ";
2535  sql += "JOIN capturecard "
2536  " ON capturecard.sourceid = channel.sourceid "
2537  " AND capturecard.parentid = 0 ";
2538  if (liveTVOnly)
2539  sql += " AND capturecard.livetvorder > 0 ";
2540 
2541  sql += "WHERE channel.deleted IS NULL ";
2542  if (ignoreHidden)
2543  sql += "AND channel.visible > 0 ";
2544 
2545  if (sourceID > 0)
2546  sql += "AND channel.sourceid = :SOURCEID ";
2547 
2548  if (groupBy == kChanGroupByCallsign)
2549  sql += "GROUP BY channel.callsign ";
2550  else if (groupBy == kChanGroupByCallsignAndChannum)
2551  sql += "GROUP BY channel.callsign, channel.channum ";
2552  else
2553  sql += "GROUP BY channel.chanid "; // We must always group for this query
2554 
2555  if (orderBy == kChanOrderByName)
2556  sql += "ORDER BY channel.name ";
2557  else if (orderBy == kChanOrderByChanNum)
2558  {
2559  // Natural sorting including subchannels e.g. 2_4, 1.3
2560  sql += "ORDER BY LPAD(CAST(channel.channum AS UNSIGNED), 10, 0), "
2561  " LPAD(channel.channum, 10, 0) ";
2562  }
2563  else // kChanOrderByLiveTV
2564  {
2565  sql += "ORDER BY callsign = :CALLSIGN1 AND channum = :CHANNUM DESC, "
2566  " callsign = :CALLSIGN2 DESC, "
2567  " livetvorder, "
2568  " channel.recpriority DESC, "
2569  " chanid ";
2570  }
2571 
2572  if (count > 0)
2573  sql += "LIMIT :LIMIT ";
2574 
2575  if (startIndex > 0)
2576  sql += "OFFSET :STARTINDEX ";
2577 
2578 
2579  if (startIndex > 0 || count > 0)
2580  sql = sql.arg("SQL_CALC_FOUND_ROWS");
2581  else
2582  sql = sql.arg(""); // remove place holder
2583 
2584  query.prepare(sql);
2585 
2586  if (channelGroupID > 0)
2587  query.bindValue(":CHANGROUPID", channelGroupID);
2588 
2589  if (sourceID > 0)
2590  query.bindValue(":SOURCEID", sourceID);
2591 
2592  if (count > 0)
2593  query.bindValue(":LIMIT", count);
2594 
2595  if (startIndex > 0)
2596  query.bindValue(":STARTINDEX", startIndex);
2597 
2598  if (orderBy == kChanOrderByLiveTV)
2599  {
2600  query.bindValue(":CALLSIGN1", callsign);
2601  query.bindValue(":CHANNUM", channum);
2602  query.bindValue(":CALLSIGN2", callsign);
2603  }
2604 
2605  if (!query.exec())
2606  {
2607  MythDB::DBError("ChannelInfo::Load()", query);
2608  return channelList;
2609  }
2610 
2611  QList<uint> groupIdList;
2612  while (query.next())
2613  {
2614  ChannelInfo channelInfo;
2615  channelInfo.m_chanNum = query.value(0).toString();
2616  channelInfo.m_freqId = query.value(1).toString();
2617  channelInfo.m_sourceId = query.value(2).toUInt();
2618  channelInfo.m_callSign = query.value(3).toString();
2619  channelInfo.m_name = query.value(4).toString();
2620  channelInfo.m_icon = query.value(5).toString();
2621  channelInfo.m_fineTune = query.value(6).toInt();
2622  channelInfo.m_videoFilters = query.value(7).toString();
2623  channelInfo.m_xmltvId = query.value(8).toString();
2624  channelInfo.m_recPriority = query.value(9).toInt();
2625  channelInfo.m_contrast = query.value(10).toUInt();
2626  channelInfo.m_brightness = query.value(11).toUInt();
2627  channelInfo.m_colour = query.value(12).toUInt();
2628  channelInfo.m_hue = query.value(13).toUInt();
2629  channelInfo.m_tvFormat = query.value(14).toString();
2630  channelInfo.m_visible =
2631  static_cast<ChannelVisibleType>(query.value(15).toInt());
2632  channelInfo.m_outputFilters = query.value(16).toString();
2633  channelInfo.m_useOnAirGuide = query.value(17).toBool();
2634  channelInfo.m_mplexId = query.value(18).toUInt();
2635  channelInfo.m_serviceId = query.value(19).toUInt();
2636  channelInfo.m_atscMajorChan = query.value(20).toUInt();
2637  channelInfo.m_atscMinorChan = query.value(21).toUInt();
2638  channelInfo.m_lastRecord = query.value(22).toDateTime();
2639  channelInfo.m_defaultAuthority = query.value(23).toString();
2640  channelInfo.m_commMethod = query.value(24).toUInt();
2641  channelInfo.m_tmOffset = query.value(25).toUInt();
2642  channelInfo.m_iptvId = query.value(26).toUInt();
2643  channelInfo.m_chanId = query.value(27).toUInt();
2644 
2645  QStringList groupIDs = query.value(28).toString().split(",");
2646  groupIdList.clear();
2647  while (!groupIDs.isEmpty())
2648  groupIdList.push_back(groupIDs.takeFirst().toUInt());
2649  std::sort(groupIdList.begin(), groupIdList.end());
2650  for (auto groupId : groupIdList)
2651  channelInfo.AddGroupId(groupId);
2652 
2653  QStringList parentIDs = query.value(29).toString().split(",");
2654  while (!parentIDs.isEmpty())
2655  {
2656  auto parentId = parentIDs.takeFirst().toUInt();
2657  channelInfo.AddInputId(parentId);
2658  auto childIdList = childIdLists[parentId];
2659  for (auto childId : childIdList)
2660  channelInfo.AddInputId(childId);
2661  }
2662 
2663  channelList.push_back(channelInfo);
2664  }
2665 
2666  if ((startIndex > 0 || count > 0) &&
2667  query.exec("SELECT FOUND_ROWS()") && query.next())
2668  totalAvailable = query.value(0).toUInt();
2669  else
2670  totalAvailable = query.size();
2671 
2672  return channelList;
2673 }
2674 
2675 /* vim: set expandtab tabstop=4 shiftwidth=4: */
ChannelInfo
Definition: channelinfo.h:31
DTVModulation::toString
QString toString() const
Definition: dtvconfparserhelpers.h:412
NetworkInformationTable::TransportDescriptorsLength
uint TransportDescriptorsLength(uint i) const
trans_desc_length 12 4.4+p
Definition: dvbtables.h:83
DTVMultiplex::m_frequency
uint64_t m_frequency
Definition: dtvmultiplex.h:94
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
DTVMultiplex
Definition: dtvmultiplex.h:24
ChannelUtil::kChanGroupByCallsign
@ kChanGroupByCallsign
Definition: channelutil.h:215
MSqlQuery::bindValueNoNull
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:902
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:214
kChannelNeverVisible
@ kChannelNeverVisible
Definition: channelinfo.h:25
TerrestrialDeliverySystemDescriptor::HierarchyString
QString HierarchyString(void) const
Definition: dvbdescriptors.h:1012
insert_dtv_multiplex
static uint insert_dtv_multiplex(int db_source_id, const QString &sistandard, uint64_t frequency, const QString &modulation, int transport_id, int network_id, int symbol_rate, signed char bandwidth, signed char polarity, signed char inversion, signed char trans_mode, const QString &inner_FEC, const QString &constellation, signed char hierarchy, const QString &hp_code_rate, const QString &lp_code_rate, const QString &guard_interval, const QString &mod_sys, const QString &rolloff)
Definition: channelutil.cpp:80
ChannelInsertInfo::m_useOnAirGuide
bool m_useOnAirGuide
Definition: channelinfo.h:226
DescriptorID::satellite_delivery_system
@ satellite_delivery_system
Definition: mpegdescriptors.h:75
MPEGDescriptor::DescriptorTag
uint DescriptorTag(void) const
Definition: mpegdescriptors.h:345
TerrestrialDeliverySystemDescriptor::GuardIntervalString
QString GuardIntervalString(void) const
Definition: dvbdescriptors.h:1058
ChannelInfo::m_outputFilters
QString m_outputFilters
Definition: channelinfo.h:107
DTVTransmitMode::toChar
QChar toChar() const
Definition: dtvconfparserhelpers.h:476
NetworkInformationTable::TSID
uint TSID(uint i) const
transport_stream_id 16 0.0+p
Definition: dvbtables.h:77
ChannelInsertInfo::m_chanNum
QString m_chanNum
Definition: channelinfo.h:221
DTVMultiplex::m_rolloff
DTVRollOff m_rolloff
Definition: dtvmultiplex.h:107
DTVInversion::toChar
QChar toChar() const
Definition: dtvconfparserhelpers.h:206
DTVPolarity::toChar
QChar toChar() const
Definition: dtvconfparserhelpers.h:633
mythdb.h
IPTVTuningData::FECType
FECType
Definition: iptvtuningdata.h:23
SourceUtil::GetSourceName
static QString GetSourceName(uint sourceid)
Definition: sourceutil.cpp:47
ChannelInfo::m_chanId
uint m_chanId
Definition: channelinfo.h:85
ChannelUtil::LoadChannels
static ChannelInfoList LoadChannels(uint startIndex, uint count, uint &totalAvailable, bool ignoreHidden=true, OrderBy orderBy=kChanOrderByChanNum, GroupBy groupBy=kChanGroupByChanid, uint sourceID=0, uint channelGroupID=0, bool liveTVOnly=false, const QString &callsign="", const QString &channum="", bool ignoreUntunable=true)
Load channels from database into a list of ChannelInfo objects.
Definition: channelutil.cpp:2470
ChannelUtil::DeleteChannel
static bool DeleteChannel(uint channel_id)
Definition: channelutil.cpp:1811
ChannelChangeDirection
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
Definition: tv.h:31
ChannelInfo::m_freqId
QString m_freqId
Definition: channelinfo.h:87
pid_cache_item_t
Definition: channelutil.h:24
NetworkInformationTable::TransportDescriptors
const unsigned char * TransportDescriptors(uint i) const
for(j=0;j<N;j++) x 6.0+p { descriptor() }
Definition: dvbtables.h:87
IPTVTuningData::kSMPTE2022_1
@ kSMPTE2022_1
Definition: iptvtuningdata.h:38
ChannelUtil::GetChannelNumber
static QString GetChannelNumber(uint sourceid, const QString &channel_name)
Definition: channelutil.cpp:992
freq
static const std::array< const uint32_t, 4 > freq
Definition: element.cpp:45
ChannelUtil::GetBetterMplexID
static int GetBetterMplexID(int current_mplexid, int transport_id, int network_id)
Returns best match multiplex ID, creating one if needed.
Definition: channelutil.cpp:611
ChannelInfo::m_fineTune
int m_fineTune
Definition: channelinfo.h:95
ChannelInfo::m_iptvId
uint m_iptvId
Definition: channelinfo.h:121
ChannelUtil::SetChannelValue
static bool SetChannelValue(const QString &field_name, const QString &value, uint sourceid, const QString &channum)
Definition: channelutil.cpp:1163
ChannelUtil::GetATSCChannel
static bool GetATSCChannel(uint sourceid, const QString &channum, uint &major, uint &minor)
Definition: channelutil.cpp:1889
ChannelInfo::AddInputId
void AddInputId(uint linputid)
Definition: channelinfo.h:71
ChannelUtil::OrderBy
OrderBy
Definition: channelutil.h:206
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
ChannelUtil::kChanOrderByLiveTV
@ kChanOrderByLiveTV
Definition: channelutil.h:210
DTVMultiplex::m_hierarchy
DTVHierarchy m_hierarchy
Definition: dtvmultiplex.h:103
CableDeliverySystemDescriptor
Definition: dvbdescriptors.h:751
ChannelInfo::m_atscMajorChan
uint m_atscMajorChan
Definition: channelinfo.h:113
IPTVTuningData::GetDataURL
QUrl GetDataURL(void) const
Definition: iptvtuningdata.h:138
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
IPTVTuningData::GetFECURL0
QUrl GetFECURL0(void) const
Definition: iptvtuningdata.h:139
ChannelInfo::m_name
QString m_name
Definition: channelinfo.h:92
ChannelUtil::GetCachedPids
static bool GetCachedPids(uint chanid, pid_cache_t &pid_cache)
Returns cached MPEG PIDs when given a Channel ID.
Definition: channelutil.cpp:859
ChannelUtil::SetVisible
static bool SetVisible(uint channel_id, ChannelVisibleType visible)
Definition: channelutil.cpp:1829
ChannelInsertInfo::m_hidden
bool m_hidden
Definition: channelinfo.h:227
CHANNEL_DIRECTION_FAVORITE
@ CHANNEL_DIRECTION_FAVORITE
Definition: tv.h:35
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
DescriptorID::terrestrial_delivery_system
@ terrestrial_delivery_system
Definition: mpegdescriptors.h:99
ChannelUtil::GetMplexID
static uint GetMplexID(uint sourceid, const QString &channum)
Definition: channelutil.cpp:463
DTVMultiplex::m_bandwidth
DTVBandwidth m_bandwidth
Definition: dtvmultiplex.h:97
CableDeliverySystemDescriptor::FrequencyHz
unsigned long long FrequencyHz(void) const
Definition: dvbdescriptors.h:766
ChannelUtil::GetIPTVTuningData
static IPTVTuningData GetIPTVTuningData(uint chanid)
Definition: channelutil.cpp:2015
DTVCodeRate::toString
QString toString() const
Definition: dtvconfparserhelpers.h:341
ChannelUtil::GetChannelStringField
static QString GetChannelStringField(int chan_id, const QString &field)
Definition: channelutil.cpp:757
ChannelUtil::GetNextChannel
static uint GetNextChannel(const ChannelInfoList &sorted, uint old_chanid, uint mplexid_restriction, uint chanid_restriction, ChannelChangeDirection direction, bool skip_non_visible=true, bool skip_same_channum_and_callsign=false, bool skip_other_sources=false)
Definition: channelutil.cpp:2395
CableDeliverySystemDescriptor::FECInnerString
QString FECInnerString(void) const
Definition: dvbdescriptors.h:828
ChannelUtil::GetUnknownCallsign
static QString GetUnknownCallsign(void)
Definition: channelutil.cpp:1331
ChannelVisibleType
ChannelVisibleType
Definition: channelinfo.h:20
IPTVTuningData::IPTVType
IPTVType
Definition: iptvtuningdata.h:31
ChannelInfo::m_icon
QString m_icon
Definition: channelinfo.h:93
TerrestrialDeliverySystemDescriptor
Definition: dvbdescriptors.h:942
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
ChannelInsertInfo
Definition: channelinfo.h:133
ChannelUtil::GetInputTypes
static QStringList GetInputTypes(uint chanid)
Definition: channelutil.cpp:826
ChannelUtil::SortChannels
static void SortChannels(ChannelInfoList &list, const QString &order, bool eliminate_duplicates=false)
Definition: channelutil.cpp:2338
get_max_chanid
static uint get_max_chanid(uint sourceid)
Definition: channelutil.cpp:1430
ChannelUtil::GetSourceID
static int GetSourceID(int mplexid)
Definition: channelutil.cpp:788
ChannelInfo::m_commMethod
int m_commMethod
Definition: channelinfo.h:119
DTVMultiplex::m_inversion
DTVInversion m_inversion
Definition: dtvmultiplex.h:96
ChannelUtil::s_channelDefaultAuthorityMap
static QMap< uint, QString > s_channelDefaultAuthorityMap
Definition: channelutil.h:357
ChannelInfo::m_useOnAirGuide
bool m_useOnAirGuide
Definition: channelinfo.h:108
sourceutil.h
kChannelVisible
@ kChannelVisible
Definition: channelinfo.h:23
chanid_available
static bool chanid_available(uint chanid)
Definition: channelutil.cpp:1451
ChannelUtil::GroupBy
GroupBy
Definition: channelutil.h:213
CHANNEL_DIRECTION_DOWN
@ CHANNEL_DIRECTION_DOWN
Definition: tv.h:34
minor
#define minor(X)
Definition: compat.h:78
IPTVTuningData::kData
@ kData
Definition: iptvtuningdata.h:33
ChannelUtil::GetChanID
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
Definition: channelutil.cpp:1336
TerrestrialDeliverySystemDescriptor::BandwidthString
QString BandwidthString(void) const
Definition: dvbdescriptors.h:970
mythlogging.h
DTVRollOff::toString
QString toString() const
Definition: dtvconfparserhelpers.h:768
MPEGDescriptor::Parse
static desc_list_t Parse(const unsigned char *data, uint len)
Definition: mpegdescriptors.cpp:16
ChannelUtil::FindChannel
static uint FindChannel(uint sourceid, const QString &freqid)
Definition: channelutil.cpp:1409
ChannelUtil::GetChannelsInternal
static ChannelInfoList GetChannelsInternal(uint sourceid, bool visible_only, bool include_disconnected, const QString &group_by, uint channel_groupid)
Definition: channelutil.cpp:2091
DTVMultiplex::m_guardInterval
DTVGuardInterval m_guardInterval
Definition: dtvmultiplex.h:102
ChannelInfo::m_atscMinorChan
uint m_atscMinorChan
Definition: channelinfo.h:114
MPEGDescriptor
Definition: mpegdescriptors.h:302
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
ChannelUtil::UpdateChannel
static bool UpdateChannel(uint db_mplexid, uint source_id, uint 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=QString(), const QString &icon=QString(), QString format=QString(), const QString &xmltvid=QString(), const QString &default_authority=QString(), uint service_type=0, int recpriority=INT_MIN, int tmOffset=INT_MIN, int commMethod=INT_MIN)
Definition: channelutil.cpp:1597
SatelliteDeliverySystemDescriptor::RollOffString
QString RollOffString(void) const
Definition: dvbdescriptors.h:887
IPTVTuningData::kRFC2733_2
@ kRFC2733_2
Definition: iptvtuningdata.h:35
pid_cache_t
std::vector< pid_cache_item_t > pid_cache_t
Definition: channelutil.h:43
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
IPTVTuningData::GetDeviceName
QString GetDeviceName(void) const
Definition: iptvtuningdata.h:112
lt_smart
bool lt_smart(const ChannelInfo &a, const ChannelInfo &b)
Definition: channelutil.cpp:2225
IPTVTuningData::GetFECURL1
QUrl GetFECURL1(void) const
Definition: iptvtuningdata.h:140
StringUtil::naturalCompare
MBASE_PUBLIC int naturalCompare(const QString &_a, const QString &_b, Qt::CaseSensitivity caseSensitivity=Qt::CaseSensitive)
This method chops the input a and b into pieces of digits and non-digits (a1.05 becomes a | 1 | .
Definition: stringutil.cpp:160
desc_list_t
std::vector< const unsigned char * > desc_list_t
Definition: mpegdescriptors.h:18
ChannelUtil::kChanGroupByCallsignAndChannum
@ kChanGroupByCallsignAndChannum
Definition: channelutil.h:216
ChannelInfo::m_chanNum
QString m_chanNum
Definition: channelinfo.h:86
TerrestrialDeliverySystemDescriptor::ConstellationString
QString ConstellationString(void) const
Definition: dvbdescriptors.h:991
stringutil.h
ChannelInsertInfo::m_channelId
uint m_channelId
Definition: channelinfo.h:218
DTVMultiplex::m_hpCodeRate
DTVCodeRate m_hpCodeRate
Definition: dtvmultiplex.h:98
ChannelUtil::s_channelDefaultAuthorityMapLock
static QReadWriteLock s_channelDefaultAuthorityMapLock
Definition: channelutil.h:356
lt_pidcache
static bool lt_pidcache(const pid_cache_item_t a, const pid_cache_item_t b)
Definition: channelutil.cpp:847
SatelliteDeliverySystemDescriptor::FECInnerString
QString FECInnerString(void) const
Definition: dvbdescriptors.h:936
IPTVTuningData
Definition: iptvtuningdata.h:20
ChannelUtil::GetChannelValueStr
static QString GetChannelValueStr(const QString &channel_field, uint sourceid, const QString &channum)
Definition: channelutil.cpp:951
DTVHierarchy::toChar
QChar toChar() const
Definition: dtvconfparserhelpers.h:594
dvbtables.h
ChannelUtil::CreateChanID
static int CreateChanID(uint sourceid, const QString &chan_num)
Creates a unique channel ID for database use.
Definition: channelutil.cpp:1472
DTVMultiplex::m_modSys
DTVModulationSystem m_modSys
Definition: dtvmultiplex.h:106
ChannelInfo::m_tmOffset
int m_tmOffset
Definition: channelinfo.h:120
DTVMultiplex::m_fec
DTVCodeRate m_fec
Definition: dtvmultiplex.h:105
ChannelInfo::m_hue
uint m_hue
Definition: channelinfo.h:103
ChannelUtil::kChanOrderByName
@ kChanOrderByName
Definition: channelutil.h:209
ChannelInfo::m_contrast
uint m_contrast
Definition: channelinfo.h:100
ChannelUtil::s_channelDefaultAuthority_runInit
static bool s_channelDefaultAuthority_runInit
Definition: channelutil.h:358
NetworkInformationTable::OriginalNetworkID
uint OriginalNetworkID(uint i) const
original_network_id 16 2.0+p
Definition: dvbtables.h:79
ChannelInfo::AddGroupId
void AddGroupId(uint lgroupid)
Definition: channelinfo.h:59
handle_transport_desc
static void handle_transport_desc(std::vector< uint > &muxes, const MPEGDescriptor &desc, uint sourceid, uint tsid, uint netid)
Definition: channelutil.cpp:279
IPTVTuningData::kSMPTE2022_2
@ kSMPTE2022_2
Definition: iptvtuningdata.h:39
DescriptorID::cable_delivery_system
@ cable_delivery_system
Definition: mpegdescriptors.h:76
ChannelUtil::GetChannelValueInt
static int GetChannelValueInt(const QString &channel_field, uint sourceid, const QString &channum)
Definition: channelutil.cpp:979
MSqlQuery::ChannelCon
static MSqlQueryInfo ChannelCon()
Returns dedicated connection. (Required for using temporary SQL tables.)
Definition: mythdbcon.cpp:599
ChannelUtil::UpdateInsertInfoFromDB
static void UpdateInsertInfoFromDB(ChannelInsertInfo &chan)
Definition: channelutil.cpp:1714
ChannelUtil::CreateChannel
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)
Definition: channelutil.cpp:1509
lt_callsign
bool lt_callsign(const ChannelInfo &a, const ChannelInfo &b)
Definition: channelutil.cpp:2220
channelutil.h
DTVMultiplex::m_symbolRate
uint64_t m_symbolRate
Definition: dtvmultiplex.h:95
DTVModulationSystem::toString
QString toString() const
Definition: dtvconfparserhelpers.h:719
ChannelUtil::GetTimeOffset
static std::chrono::minutes GetTimeOffset(int chan_id)
Returns the listings time offset in minutes for given channel.
Definition: channelutil.cpp:783
IPTVTuningData::kRFC2733
@ kRFC2733
Definition: iptvtuningdata.h:26
ChannelUtil::GetChannelData
static bool GetChannelData(uint sourceid, uint &chanid, const QString &channum, QString &tvformat, QString &modulation, QString &freqtable, QString &freqid, int &finetune, uint64_t &frequency, QString &dtv_si_std, int &mpeg_prog_num, uint &atsc_major, uint &atsc_minor, uint &dvb_transportid, uint &dvb_networkid, uint &mplexid, bool &commfree)
Definition: channelutil.cpp:1917
ChannelUtil::CreateMultiplexes
static std::vector< uint > CreateMultiplexes(int sourceid, const NetworkInformationTable *nit)
Definition: channelutil.cpp:438
TerrestrialDeliverySystemDescriptor::CodeRateLPString
QString CodeRateLPString(void) const
Definition: dvbdescriptors.h:1042
IPTVTuningData::kRFC5109
@ kRFC5109
Definition: iptvtuningdata.h:27
ChannelUtil::SetServiceVersion
static bool SetServiceVersion(int mplexid, int version)
Definition: channelutil.cpp:1848
ChannelInfo::m_serviceId
uint m_serviceId
Definition: channelinfo.h:111
ChannelUtil::GetIcon
static QString GetIcon(uint chanid)
Definition: channelutil.cpp:1271
pid_cache_item_t::GetPID
uint GetPID(void) const
Definition: channelutil.h:30
get_valid_recorder_list
static QStringList get_valid_recorder_list(uint chanid)
Returns list of the recorders that have chanid in their sources.
Definition: channelutil.cpp:1045
SatelliteDeliverySystemDescriptor::ModulationSystemString
QString ModulationSystemString(void) const
Definition: dvbdescriptors.h:894
ChannelUtil::CreateMultiplex
static uint CreateMultiplex(int sourceid, const QString &sistandard, uint64_t frequency, const QString &modulation, int transport_id=-1, int network_id=-1)
Definition: channelutil.cpp:373
CableDeliverySystemDescriptor::ModulationString
QString ModulationString(void) const
Definition: dvbdescriptors.h:798
SatelliteDeliverySystemDescriptor::SymbolRateHz
uint SymbolRateHz(void) const
Definition: dvbdescriptors.h:919
DTVBandwidth::toChar
QChar toChar() const
Definition: dtvconfparserhelpers.h:269
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
ChannelUtil::GetSourceIDForChannel
static uint GetSourceIDForChannel(uint chanid)
Definition: channelutil.cpp:808
ChannelUtil::GetServiceVersion
static int GetServiceVersion(int mplexid)
Definition: channelutil.cpp:1867
ChannelUtil::UpdateChannelNumberFromDB
static void UpdateChannelNumberFromDB(ChannelInsertInfo &chan)
Definition: channelutil.cpp:1688
CHANNEL_DIRECTION_UP
@ CHANNEL_DIRECTION_UP
Definition: tv.h:33
TerrestrialDeliverySystemDescriptor::FrequencyHz
uint64_t FrequencyHz(void) const
Definition: dvbdescriptors.h:958
IPTVTuningData::kRFC2733_1
@ kRFC2733_1
Definition: iptvtuningdata.h:34
ChannelInfo::m_sourceId
uint m_sourceId
Definition: channelinfo.h:89
IPTVTuningData::GetFECTypeString
QString GetFECTypeString(uint i) const
Definition: iptvtuningdata.h:155
DTVMultiplex::m_sistandard
QString m_sistandard
Definition: dtvmultiplex.h:111
TerrestrialDeliverySystemDescriptor::TransmissionModeString
QString TransmissionModeString(void) const
Definition: dvbdescriptors.h:1071
ChannelInfo::m_tvFormat
QString m_tvFormat
Definition: channelinfo.h:105
IPTVTuningData::kRFC5109_2
@ kRFC5109_2
Definition: iptvtuningdata.h:37
SatelliteDeliverySystemDescriptor::PolarizationString
QString PolarizationString() const
Definition: dvbdescriptors.h:869
ChannelInfo::m_recPriority
int m_recPriority
Definition: channelinfo.h:98
ChannelUtil::kChanOrderByChanNum
@ kChanOrderByChanNum
Definition: channelutil.h:208
SatelliteDeliverySystemDescriptor
Definition: dvbdescriptors.h:833
ChannelUtil::GetConflicting
static std::vector< uint > GetConflicting(const QString &channum, uint sourceid=0)
Definition: channelutil.cpp:1127
TerrestrialDeliverySystemDescriptor::CodeRateHPString
QString CodeRateHPString(void) const
Definition: dvbdescriptors.h:1033
ChannelInfo::m_xmltvId
QString m_xmltvId
Definition: channelinfo.h:97
CableDeliverySystemDescriptor::SymbolRateHz
uint SymbolRateHz(void) const
Definition: dvbdescriptors.h:811
DTVMultiplex::m_modulation
DTVModulation m_modulation
Definition: dtvmultiplex.h:100
ChannelInfo::m_videoFilters
QString m_videoFilters
Definition: channelinfo.h:96
DTVMultiplex::m_polarity
DTVPolarity m_polarity
Definition: dtvmultiplex.h:104
ChannelUtil::GetValidRecorderList
static QStringList GetValidRecorderList(uint chanid, const QString &channum)
Returns list of the recorders that have chanid or channum in their sources.
Definition: channelutil.cpp:1116
ChannelUtil::SaveCachedPids
static bool SaveCachedPids(uint chanid, const pid_cache_t &_pid_cache, bool delete_all=false)
Saves PIDs for PSIP tables to database.
Definition: channelutil.cpp:892
IPTVTuningData::kRFC5109_1
@ kRFC5109_1
Definition: iptvtuningdata.h:36
ChannelUtil::GetChannelCount
static uint GetChannelCount(int sourceid=-1)
Definition: channelutil.cpp:2319
ChannelUtil::GetChanNum
static QString GetChanNum(int chan_id)
Returns the channel-number string of the given channel.
Definition: channelutil.cpp:778
ChannelInsertInfo::m_xmltvId
QString m_xmltvId
Definition: channelinfo.h:233
ChannelUtil::GetNearestChannel
static int GetNearestChannel(const ChannelInfoList &list, const QString &channum)
Definition: channelutil.cpp:2371
NetworkInformationTable::TransportStreamCount
uint TransportStreamCount(void) const
Definition: dvbtables.h:73
ChannelInfo::m_lastRecord
QDateTime m_lastRecord
Definition: channelinfo.h:116
ChannelUtil::GetChanIDs
static std::vector< uint > GetChanIDs(int sourceid=-1, bool onlyVisible=false)
Definition: channelutil.cpp:2192
DTVGuardInterval::toString
QString toString() const
Definition: dtvconfparserhelpers.h:540
ChannelInfo::m_mplexId
uint m_mplexId
Definition: channelinfo.h:110
ChannelUtil::GetDefaultAuthority
static QString GetDefaultAuthority(uint chanid)
Returns the DVB default authority for the chanid given.
Definition: channelutil.cpp:1203
ChannelInfo::m_brightness
uint m_brightness
Definition: channelinfo.h:101
ChannelInfo::m_colour
uint m_colour
Definition: channelinfo.h:102
ChannelUtil::GetTuningParams
static bool GetTuningParams(uint mplexid, QString &modulation, uint64_t &frequency, uint &dvb_transportid, uint &dvb_networkid, QString &si_std)
Definition: channelutil.cpp:722
SatelliteDeliverySystemDescriptor::FrequencykHz
uint64_t FrequencykHz(void) const
Definition: dvbdescriptors.h:849
ChannelInfo::m_visible
ChannelVisibleType m_visible
Definition: channelinfo.h:106
IPTVTuningData::GetBitrate
uint GetBitrate(uint i) const
Definition: iptvtuningdata.h:151
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:77
ChannelUtil::IsOnSameMultiplex
static bool IsOnSameMultiplex(uint srcid, const QString &new_channum, const QString &old_channum)
Definition: channelutil.cpp:1015
DTVMultiplex::m_transMode
DTVTransmitMode m_transMode
Definition: dtvmultiplex.h:101
ChannelInfo::m_defaultAuthority
QString m_defaultAuthority
Definition: channelinfo.h:118
ChannelInfo::m_callSign
QString m_callSign
Definition: channelinfo.h:91
IPTVTuningData::kSMPTE2022
@ kSMPTE2022
Definition: iptvtuningdata.h:28
ChannelUtil::kATSCSeparators
static const QString kATSCSeparators
Definition: channelutil.h:345
SatelliteDeliverySystemDescriptor::ModulationString
QString ModulationString(void) const
Definition: dvbdescriptors.h:908
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:363
kChannelNotVisible
@ kChannelNotVisible
Definition: channelinfo.h:24
ChannelInsertInfo::m_visible
ChannelVisibleType m_visible
Definition: channelinfo.h:229
uint
unsigned int uint
Definition: freesurround.h:24
ChannelUtil::UpdateIPTVTuningData
static bool UpdateIPTVTuningData(uint channel_id, const IPTVTuningData &tuning)
Definition: channelutil.cpp:1753
get_dtv_multiplex
static uint get_dtv_multiplex(uint db_source_id, const QString &sistandard, uint64_t frequency, uint transport_id, uint network_id, signed char polarity)
Definition: channelutil.cpp:27
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
DTVMultiplex::m_lpCodeRate
DTVCodeRate m_lpCodeRate
Definition: dtvmultiplex.h:99
NetworkInformationTable
This table tells the decoder on which PIDs to find other tables.
Definition: dvbtables.h:28
HLSReader.h
IPTVTuningData::kNone
@ kNone
Definition: iptvtuningdata.h:25
ChannelInfoList
std::vector< ChannelInfo > ChannelInfoList
Definition: channelinfo.h:131