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