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