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