MythTV  master
videosource.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 // Standard UNIX C headers
4 #include <unistd.h>
5 #include <fcntl.h>
6 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(_WIN32)
7 #include <sys/types.h>
8 #else
9 #include <sys/sysmacros.h>
10 #endif
11 #include <sys/stat.h>
12 
13 // C++ headers
14 #include <algorithm>
15 using namespace std;
16 
17 // Qt headers
18 #include <QCoreApplication>
19 #include <QCursor>
20 #include <QDateTime>
21 #include <QDir>
22 #include <QFile>
23 #include <QLayout>
24 #include <QMap>
25 #include <QStringList>
26 #include <QTextStream>
27 #include <utility>
28 
29 // MythTV headers
30 #include "mythconfig.h"
31 #include "mythcorecontext.h"
32 #include "videosource.h"
33 #include "scanwizard.h"
34 #include "cardutil.h"
35 #include "sourceutil.h"
36 #include "channelinfo.h"
37 #include "channelutil.h"
38 #include "frequencies.h"
39 #include "diseqcsettings.h"
40 #include "firewiredevice.h"
41 #include "compat.h"
42 #include "mythdb.h"
43 #include "mythdirs.h"
44 #include "mythlogging.h"
45 #include "libmythupnp/httprequest.h" // for TestMimeType()
46 #include "mythsystemlegacy.h"
47 #include "exitcodes.h"
48 #include "v4l2util.h"
49 #include "mythnotification.h"
50 #include "mythterminal.h"
51 
52 #ifdef USING_DVB
53 #include "dvbtypes.h"
54 #endif
55 
56 #ifdef USING_VBOX
57 #include "vboxutils.h"
58 #endif
59 
60 #ifdef USING_HDHOMERUN
61 #include HDHOMERUN_HEADERFILE
62 #endif
63 
65  QString _card_types,
66  bool _must_have_mplexid) :
67  m_initialSourceId(_initial_sourceid),
68  m_cardTypes(std::move(_card_types)),
69  m_mustHaveMplexId(_must_have_mplexid)
70 {
71  setLabel(tr("Video Source"));
73  QObject::tr(
74  "Select a video source that is connected to one "
75  "or more capture cards. Default is the video source "
76  "selected in the Channel Editor page."
77  ));
78 }
79 
81 {
83 
84  QString querystr =
85  "SELECT DISTINCT videosource.name, videosource.sourceid "
86  "FROM capturecard, videosource";
87 
88  querystr += (m_mustHaveMplexId) ? ", channel " : " ";
89 
90  querystr +=
91  "WHERE capturecard.sourceid = videosource.sourceid AND "
92  " capturecard.hostname = :HOSTNAME ";
93 
94  if (!m_cardTypes.isEmpty())
95  {
96  querystr += QString(" AND capturecard.cardtype in %1 ")
97  .arg(m_cardTypes);
98  }
99 
100  if (m_mustHaveMplexId)
101  {
102  querystr +=
103  " AND channel.sourceid = videosource.sourceid "
104  " AND channel.mplexid != 32767 "
105  " AND channel.mplexid != 0 ";
106  }
107 
108  query.prepare(querystr);
109  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
110 
111  if (!query.exec() || !query.isActive() || query.size() <= 0)
112  return;
113 
114  uint sel = 0;
115  uint cnt = 0;
116  for (; query.next(); cnt++)
117  {
118  addSelection(query.value(0).toString(),
119  query.value(1).toString());
120 
121  sel = (query.value(1).toUInt() == m_initialSourceId) ? cnt : sel;
122  }
123 
124  if (m_initialSourceId)
125  {
126  if (cnt)
127  setValue(sel);
128  }
129 
131 }
132 
134  m_initialSourceId(_initial_sourceid)
135 {
136  setLabel(tr("Video Source"));
137  setHelpText(
138  QObject::tr(
139  "The video source that is "
140  "selected in the Channel Editor page."
141  ));
142 }
143 
145 {
146  MSqlQuery query(MSqlQuery::InitCon());
147 
148  QString querystr =
149  "SELECT DISTINCT videosource.name, videosource.sourceid "
150  "FROM capturecard, videosource "
151  "WHERE capturecard.sourceid = videosource.sourceid AND "
152  " capturecard.hostname = :HOSTNAME AND "
153  " videosource.sourceid = :SOURCEID ";
154 
155  query.prepare(querystr);
156  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
157  query.bindValue(":SOURCEID", m_initialSourceId);
158 
159  if (!query.exec() || !query.isActive())
160  {
161  MythDB::DBError("VideoSourceShow::Load", query);
162  return;
163  }
164 
165  if (query.next())
166  {
167  setValue(query.value(0).toString());
168  }
169 }
170 
172 {
173  public:
174  explicit InstanceCount(const CardInput &parent) :
175  MythUISpinBoxSetting(new CardInputDBStorage(this, parent, "reclimit"),
176  1, 10, 1)
177  {
178  setLabel(QObject::tr("Max recordings"));
179  setValue(1);
180  setHelpText(
181  QObject::tr(
182  "Maximum number of simultaneous recordings MythTV will "
183  "attempt using this device. If set to a value other than "
184  "1, MythTV can sometimes record multiple programs on "
185  "the same multiplex or overlapping copies of the same "
186  "program on a single channel."
187  ));
188  };
189 };
190 
192 {
193  public:
194  explicit SchedGroup(const CardInput &parent) :
195  MythUICheckBoxSetting(new CardInputDBStorage(this, parent, "schedgroup"))
196  {
197  setLabel(QObject::tr("Schedule as group"));
198  setValue(true);
199  setHelpText(
200  QObject::tr(
201  "Schedule all virtual inputs on this device as a group. "
202  "This is more efficient than scheduling each input "
203  "individually. Additional, virtual inputs will be "
204  "automatically added as needed to fulfill the recording "
205  "load."
206  ));
207  };
208 };
209 
211 {
212  QString sourceidTag(":WHERESOURCEID");
213 
214  QString query("sourceid = " + sourceidTag);
215 
216  bindings.insert(sourceidTag, m_parent.getSourceID());
217 
218  return query;
219 }
220 
222 {
223  QString sourceidTag(":SETSOURCEID");
224  QString colTag(":SET" + GetColumnName().toUpper());
225 
226  QString query("sourceid = " + sourceidTag + ", " +
227  GetColumnName() + " = " + colTag);
228 
229  bindings.insert(sourceidTag, m_parent.getSourceID());
230  bindings.insert(colTag, m_user->GetDBValue());
231 
232  return query;
233 }
234 
236 {
237  QString cardidTag(":WHERECARDID");
238 
239  QString query("cardid = " + cardidTag);
240 
241  bindings.insert(cardidTag, m_parent.getCardID());
242 
243  return query;
244 }
245 
247 {
248  QString cardidTag(":SETCARDID");
249  QString colTag(":SET" + GetColumnName().toUpper());
250 
251  QString query("cardid = " + cardidTag + ", " +
252  GetColumnName() + " = " + colTag);
253 
254  bindings.insert(cardidTag, m_parent.getCardID());
255  bindings.insert(colTag, m_user->GetDBValue());
256 
257  return query;
258 }
259 
261 {
262  public:
263  explicit XMLTVGrabber(const VideoSource &parent) :
265  "xmltvgrabber")),
266  m_parent(parent)
267  {
268  setLabel(QObject::tr("Listings grabber"));
269  };
270 
271  void Load(void) override // StandardSetting
272  {
273  addTargetedChild("eitonly", new EITOnly_config(m_parent, this));
274  addTargetedChild("/bin/true", new NoGrabber_config(m_parent));
275 
276  addSelection(
277  QObject::tr("Transmitted guide only (EIT)"), "eitonly");
278 
279  addSelection(QObject::tr("No grabber"), "/bin/true");
280 
281  QString gname;
282  QString d1;
283  QString d2;
284  QString d3;
286 
287 #ifdef _MSC_VER
288 #pragma message( "tv_find_grabbers is not supported yet on windows." )
289  //-=>TODO:Screen doesn't show up if the call to MythSysemLegacy is executed
290 #else
291 
292  QString loc = "XMLTVGrabber::Load: ";
293  QString loc_err = "XMLTVGrabber::Load, Error: ";
294 
295  QStringList name_list;
296  QStringList prog_list;
297 
298  QStringList args;
299  args += "baseline";
300 
301  MythSystemLegacy find_grabber_proc("tv_find_grabbers", args,
303  find_grabber_proc.Run(25);
304  LOG(VB_GENERAL, LOG_INFO,
305  loc + "Running 'tv_find_grabbers " + args.join(" ") + "'.");
306  uint status = find_grabber_proc.Wait();
307 
308  if (status == GENERIC_EXIT_OK)
309  {
310  QTextStream ostream(find_grabber_proc.ReadAll());
311  while (!ostream.atEnd())
312  {
313  QString grabber_list(ostream.readLine());
314  QStringList grabber_split =
315  grabber_list.split("|", QString::SkipEmptyParts);
316  QString grabber_name = grabber_split[1] + " (xmltv)";
317  QFileInfo grabber_file(grabber_split[0]);
318 
319  name_list.push_back(grabber_name);
320  prog_list.push_back(grabber_file.fileName());
321  LOG(VB_GENERAL, LOG_DEBUG, "Found " + grabber_split[0]);
322  }
323  LOG(VB_GENERAL, LOG_INFO, loc + "Finished running tv_find_grabbers");
324  }
325  else
326  LOG(VB_GENERAL, LOG_ERR, loc + "Failed to run tv_find_grabbers");
327 
328  LoadXMLTVGrabbers(name_list, prog_list);
329 
331 #endif
332  }
333 
334  void Save(void) override // StandardSetting
335  {
337 
338  MSqlQuery query(MSqlQuery::InitCon());
339  query.prepare(
340  "UPDATE videosource "
341  "SET userid=NULL, password=NULL "
342  "WHERE xmltvgrabber NOT IN ( 'technovera' )");
343  if (!query.exec())
344  MythDB::DBError("XMLTVGrabber::Save", query);
345  }
346 
347  void LoadXMLTVGrabbers(QStringList name_list, QStringList prog_list)
348  {
349  if (name_list.size() != prog_list.size())
350  return;
351 
352  QString selValue = getValue();
353  int selIndex = getValueIndex(selValue);
354  setValue(0);
355 
356  for (uint i = 0; i < (uint) name_list.size(); i++)
357  {
358  addTargetedChild(prog_list[i],
359  new XMLTV_generic_config(m_parent, prog_list[i],
360  this));
361  addSelection(name_list[i], prog_list[i]);
362  }
363 
364  if (!selValue.isEmpty())
365  selIndex = getValueIndex(selValue);
366  if (selIndex >= 0)
367  setValue(selIndex);
368  }
369 private:
371 };
372 
374 {
375  public:
377  uint min_val, uint max_val, uint step,
378  const QString &setting) :
379  MythUISpinBoxSetting(new CaptureCardDBStorage(this, parent, setting),
380  min_val, max_val, step)
381  {
382  }
383 };
384 
386 {
387  public:
389  const QString &setting) :
390  MythUITextEditSetting(new CaptureCardDBStorage(this, parent, setting))
391  {
392  }
393 };
394 
396 {
397  public:
398  explicit ScanFrequency(const VideoSource &parent) :
399  MythUITextEditSetting(new VideoSourceDBStorage(this, parent, "scanfrequency"))
400  {
401  setLabel(QObject::tr("Scan Frequency"));
402  setHelpText(QObject::tr("The frequency to start scanning this video source. "
403  "This is then default for 'Full Scan (Tuned)' channel scanning. "
404  "Frequency value in Hz for DVB-T/T2/C, in kHz for DVB-S/S2. "
405  "Leave at 0 if not known. "));
406  };
407 };
408 
410 {
411  public:
412  DVBNetID(const VideoSource &parent, signed int value, signed int min_val) :
413  MythUISpinBoxSetting(new VideoSourceDBStorage(this, parent, "dvb_nit_id"),
414  min_val, 0xffff, 1)
415  {
416  setLabel(QObject::tr("Network ID"));
417  //: Network_ID is the name of an identifier in the DVB's Service
418  //: Information standard specification.
419  setHelpText(QObject::tr("If your provider has asked you to configure a "
420  "specific network identifier (Network_ID), "
421  "enter it here. Leave it at -1 otherwise."));
422  setValue(value);
423  };
424 };
425 
427 {
428  public:
429  BouquetID(const VideoSource &parent, signed int value, signed int min_val) :
430  MythUISpinBoxSetting(new VideoSourceDBStorage(this, parent, "bouquet_id"),
431  min_val, 0xffff, 1)
432  {
433  setLabel(QObject::tr("Bouquet ID"));
434  setHelpText(QObject::tr("Bouquet ID for Freesat or Sky on satellite Astra-2 28.2E. "
435  "Leave this at 0 if you do not receive this satellite. "
436  "This is needed to get the Freesat and Sky channel numbers. "
437  "Value 272 selects Freesat bouquet 'England HD'. "
438  "See the MythTV Wiki https://www.mythtv.org/wiki/DVB_UK."));
439  setValue(value);
440  };
441 };
442 
444 {
445  public:
446  RegionID(const VideoSource &parent, signed int value, signed int min_val) :
447  MythUISpinBoxSetting(new VideoSourceDBStorage(this, parent, "region_id"),
448  min_val, 100, 1)
449  {
450  setLabel(QObject::tr("Region ID"));
451  setHelpText(QObject::tr("Region ID for Freesat or Sky on satellite Astra-2 28.2E. "
452  "Leave this at 0 you do not receive this satellite. "
453  "This is needed to get the Freesat and Sky channel numbers. "
454  "Value 1 selects region London. "
455  "See the MythTV Wiki https://www.mythtv.org/wiki/DVB_UK."));
456  setValue(value);
457  };
458 };
459 
461  MythUIComboBoxSetting(new VideoSourceDBStorage(this, parent, "freqtable"))
462 {
463  setLabel(QObject::tr("Channel frequency table"));
464  addSelection("default");
465 
466  for (uint i = 0; chanlists[i].name; i++)
467  addSelection(chanlists[i].name);
468 
469  setHelpText(QObject::tr("Use default unless this source uses a "
470  "different frequency table than the system wide table "
471  "defined in the General settings."));
472 }
473 
475  m_sourceId(_sourceid)
476 {
477  setLabel(QObject::tr("Channel frequency table"));
478 
479  for (uint i = 0; chanlists[i].name; i++)
480  addSelection(chanlists[i].name);
481 }
482 
484 {
485  int idx1 = getValueIndex(gCoreContext->GetSetting("FreqTable"));
486  if (idx1 >= 0)
487  setValue(idx1);
488 
489  if (!m_sourceId)
490  return;
491 
492  MSqlQuery query(MSqlQuery::InitCon());
493  query.prepare(
494  "SELECT freqtable "
495  "FROM videosource "
496  "WHERE sourceid = :SOURCEID");
497  query.bindValue(":SOURCEID", m_sourceId);
498 
499  if (!query.exec() || !query.isActive())
500  {
501  MythDB::DBError("TransFreqTableSelector::load", query);
502  return;
503  }
504 
505  m_loadedFreqTable.clear();
506 
507  if (query.next())
508  {
509  m_loadedFreqTable = query.value(0).toString();
510  if (!m_loadedFreqTable.isEmpty() &&
511  (m_loadedFreqTable.toLower() != "default"))
512  {
513  int idx2 = getValueIndex(m_loadedFreqTable);
514  if (idx2 >= 0)
515  setValue(idx2);
516  }
517  }
518 }
519 
521 {
522  LOG(VB_GENERAL, LOG_INFO, "TransFreqTableSelector::Save(void)");
523 
524  if ((m_loadedFreqTable == getValue()) ||
525  ((m_loadedFreqTable.toLower() == "default") &&
526  (getValue() == gCoreContext->GetSetting("FreqTable"))))
527  {
528  return;
529  }
530 
531  MSqlQuery query(MSqlQuery::InitCon());
532  query.prepare(
533  "UPDATE videosource "
534  "SET freqtable = :FREQTABLE "
535  "WHERE sourceid = :SOURCEID");
536 
537  query.bindValue(":FREQTABLE", getValue());
538  query.bindValue(":SOURCEID", m_sourceId);
539 
540  if (!query.exec() || !query.isActive())
541  {
542  MythDB::DBError("TransFreqTableSelector::load", query);
543  return;
544  }
545 }
546 
548 {
549  m_sourceId = _sourceid;
550  Load();
551 }
552 
554 {
555  public:
556  explicit UseEIT(const VideoSource &parent) :
557  MythUICheckBoxSetting(new VideoSourceDBStorage(this, parent, "useeit"))
558  {
559  setLabel(QObject::tr("Perform EIT scan"));
560  setHelpText(QObject::tr(
561  "If enabled, program guide data for channels on this "
562  "source will be updated with data provided by the "
563  "channels themselves 'Over-the-Air'."));
564  }
565 };
566 
568  const QString& _grabber,
569  StandardSetting *_setting) :
570  m_parent(_parent), m_grabber(_grabber)
571 {
572  setVisible(false);
573 
574  QString filename = QString("%1/%2.xmltv")
575  .arg(GetConfDir()).arg(m_parent.getSourceName());
576 
577  m_grabberArgs.push_back("--config-file");
578  m_grabberArgs.push_back(filename);
579  m_grabberArgs.push_back("--configure");
580 
581  _setting->addTargetedChild(_grabber, new UseEIT(m_parent));
582 
583  auto *config = new ButtonStandardSetting(tr("Configure"));
584  config->setHelpText(tr("Run XMLTV configure command."));
585 
586  _setting->addTargetedChild(_grabber, config);
587 
588  connect(config, SIGNAL(clicked()), SLOT(RunConfig()));
589 }
590 
592 {
594 #if 0
595  QString err_msg = QObject::tr(
596  "You MUST run 'mythfilldatabase --manual' the first time,\n"
597  "instead of just 'mythfilldatabase'.\nYour grabber does not provide "
598  "channel numbers, so you have to set them manually.");
599 
601  {
602  LOG(VB_GENERAL, LOG_ERR, err_msg);
603  ShowOkPopup(err_msg);
604  }
605 #endif
606 }
607 
609 {
611  MythScreenType *ssd =
612  new MythTerminal(mainStack, m_grabber, m_grabberArgs);
613 
614  if (ssd->Create())
615  mainStack->AddScreen(ssd);
616  else
617  delete ssd;
618 }
619 
621 {
622  setVisible(false);
623 
624  m_useEit = new UseEIT(_parent);
625  m_useEit->setValue(true);
626  m_useEit->setVisible(false);
628 
629  auto *label=new TransTextEditSetting();
630  label->setValue(QObject::tr("Use only the transmitted guide data."));
631  label->setHelpText(
632  QObject::tr("This will usually only work with ATSC or DVB channels, "
633  "and generally provides data only for the next few days."));
634  _setting->addTargetedChild("eitonly", label);
635 }
636 
638 {
639  // Force this value on
640  m_useEit->setValue(true);
641  m_useEit->Save();
642 }
643 
645 {
646  m_useEit = new UseEIT(_parent);
647  m_useEit->setValue(false);
648  m_useEit->setVisible(false);
650 
651  auto *label = new TransTextEditSetting();
652  label->setValue(QObject::tr("Do not configure a grabber"));
653  addTargetedChild("/bin/true", label);
654 }
655 
657 {
658  m_useEit->setValue(false);
659  m_useEit->Save();
660 }
661 
663 {
664  // must be first
665  m_id = new ID();
666  addChild(m_id = new ID());
667 
668  setLabel(QObject::tr("Video Source Setup"));
669  addChild(m_name = new Name(*this));
670  addChild(new XMLTVGrabber(*this));
671  addChild(new FreqTableSelector(*this));
672  addChild(new ScanFrequency(*this));
673  addChild(new DVBNetID(*this, -1, -1));
674  addChild(new BouquetID(*this, 0, 0));
675  addChild(new RegionID(*this, 0, 0));
676 }
677 
679 {
680  return true;
681 }
682 
684 {
686 }
687 
688 bool VideoSourceEditor::cardTypesInclude(const int &sourceID,
689  const QString &thecardtype)
690 {
691  MSqlQuery query(MSqlQuery::InitCon());
692  query.prepare("SELECT count(cardtype)"
693  " FROM capturecard "
694  " WHERE capturecard.sourceid = :SOURCEID "
695  " AND capturecard.cardtype = :CARDTYPE ;");
696  query.bindValue(":SOURCEID", sourceID);
697  query.bindValue(":CARDTYPE", thecardtype);
698 
699  if (query.exec() && query.next())
700  {
701  int count = query.value(0).toInt();
702 
703  if (count > 0)
704  return true;
705  }
706 
707  return false;
708 }
709 
711 {
712  MSqlQuery result(MSqlQuery::InitCon());
713  result.prepare("SELECT name, sourceid FROM videosource;");
714 
715  if (result.exec() && result.isActive() && result.size() > 0)
716  {
717  while (result.next())
718  {
719  auto* source = new VideoSource();
720  source->setLabel(result.value(0).toString());
721  source->loadByID(result.value(1).toInt());
722  setting->addChild(source);
723  }
724  }
725 }
726 
728 {
729  MSqlQuery result(MSqlQuery::InitCon());
730  result.prepare("SELECT name, sourceid FROM videosource;");
731 
732  if (result.exec() && result.isActive() && result.size() > 0)
733  {
734  while (result.next())
735  {
736  setting->addSelection(result.value(0).toString(),
737  result.value(1).toString());
738  }
739  }
740 }
741 
742 void VideoSource::loadByID(int sourceid)
743 {
744  m_id->setValue(sourceid);
745 }
746 
748 {
749  public:
750  explicit VideoDevice(const CaptureCard &parent,
751  uint minor_min = 0,
752  uint minor_max = UINT_MAX,
753  const QString& card = QString(),
754  const QString& driver = QString()) :
755  CaptureCardComboBoxSetting(parent, true, "videodevice")
756  {
757  setLabel(QObject::tr("Video device"));
758 
759  // /dev/v4l/video*
760  QDir dev("/dev/v4l", "video*", QDir::Name, QDir::System);
761  fillSelectionsFromDir(dev, minor_min, minor_max,
762  card, driver, false);
763 
764  // /dev/video*
765  dev.setPath("/dev");
766  fillSelectionsFromDir(dev, minor_min, minor_max,
767  card, driver, false);
768 
769  // /dev/dtv/video*
770  dev.setPath("/dev/dtv");
771  fillSelectionsFromDir(dev, minor_min, minor_max,
772  card, driver, false);
773 
774  // /dev/dtv*
775  dev.setPath("/dev");
776  dev.setNameFilters(QStringList("dtv*"));
777  fillSelectionsFromDir(dev, minor_min, minor_max,
778  card, driver, false);
779  };
780 
785  void fillSelectionsFromDir(const QDir &dir, bool absPath = true)
786  {
787  // Needed to make both compiler and doxygen happy.
788  (void) absPath;
789 
790  fillSelectionsFromDir(dir, 0, 255, QString(), QString(), false);
791  }
792 
793  uint fillSelectionsFromDir(const QDir& dir,
794  uint minor_min, uint minor_max,
795  const QString& card, const QString& driver,
796  bool allow_duplicates)
797  {
798  uint cnt = 0;
799  QRegExp *driverExp = nullptr;
800  if (!driver.isEmpty())
801  driverExp = new QRegExp(driver);
802 
803  foreach (auto & fi, dir.entryInfoList())
804  {
805  struct stat st {};
806  QString filepath = fi.absoluteFilePath();
807  int err = lstat(filepath.toLocal8Bit().constData(), &st);
808 
809  if (err)
810  {
811  LOG(VB_GENERAL, LOG_ERR,
812  QString("Could not stat file: %1").arg(filepath));
813  continue;
814  }
815 
816  // is this is a character device?
817  if (!S_ISCHR(st.st_mode))
818  continue;
819 
820  // is this device is in our minor range?
821  uint minor_num = minor(st.st_rdev);
822  if (minor_min > minor_num || minor_max < minor_num)
823  continue;
824 
825  // ignore duplicates if allow_duplicates not set
826  if (!allow_duplicates && m_minorList[minor_num])
827  continue;
828 
829  // if the driver returns any info add this device to our list
830  QByteArray tmp = filepath.toLatin1();
831  int videofd = open(tmp.constData(), O_RDWR);
832  if (videofd >= 0)
833  {
834  QString card_name;
835  QString driver_name;
836  if (CardUtil::GetV4LInfo(videofd, card_name, driver_name) &&
837  (!driverExp || (driverExp->exactMatch(driver_name))) &&
838  (card.isEmpty() || (card_name == card)))
839  {
840  addSelection(filepath);
841  cnt++;
842  }
843  close(videofd);
844  }
845 
846  // add to list of minors discovered to avoid duplicates
847  m_minorList[minor_num] = 1;
848  }
849  delete driverExp;
850 
851  return cnt;
852  }
853 
854  QString Driver(void) const { return m_driverName; }
855  QString Card(void) const { return m_cardName; }
856 
857  private:
858  QMap<uint, uint> m_minorList;
859  QString m_cardName;
860  QString m_driverName;
861 };
862 
864 {
865  public:
866  explicit VBIDevice(const CaptureCard &parent) :
867  CaptureCardComboBoxSetting(parent, true /*, mustexist true */,
868  "vbidevice")
869  {
870  setLabel(QObject::tr("VBI device"));
871  setFilter(QString(), QString());
872  setHelpText(QObject::tr("Device to read VBI (captions) from."));
873  };
874 
875  uint setFilter(const QString &card, const QString &driver)
876  {
877  uint count = 0;
878  clearSelections();
879  QDir dev("/dev/v4l", "vbi*", QDir::Name, QDir::System);
880  if (!(count = fillSelectionsFromDir(dev, card, driver)))
881  {
882  dev.setPath("/dev");
883  if (!(count = fillSelectionsFromDir(dev, card, driver)) &&
884  !getValue().isEmpty())
885  {
886  addSelection(getValue(),getValue(),true);
887  }
888  }
889 
890  return count;
891  }
892 
897  void fillSelectionsFromDir(const QDir &dir, bool absPath = true)
898  {
899  // Needed to make both compiler and doxygen happy.
900  (void) absPath;
901 
902  fillSelectionsFromDir(dir, QString(), QString());
903  }
904 
905  uint fillSelectionsFromDir(const QDir &dir, const QString &card,
906  const QString &driver)
907  {
908  QStringList devices;
909  foreach (auto & fi, dir.entryInfoList())
910  {
911  QString device = fi.absoluteFilePath();
912  QByteArray adevice = device.toLatin1();
913  int vbifd = open(adevice.constData(), O_RDWR);
914  if (vbifd < 0)
915  continue;
916 
917  QString cn;
918  QString dn;
919  if (CardUtil::GetV4LInfo(vbifd, cn, dn) &&
920  (driver.isEmpty() || (dn == driver)) &&
921  (card.isEmpty() || (cn == card)))
922  {
923  devices.push_back(device);
924  }
925 
926  close(vbifd);
927  }
928 
929  QString sel = getValue();
930  for (uint i = 0; i < (uint) devices.size(); i++)
931  addSelection(devices[i], devices[i], devices[i] == sel);
932 
933  return (uint) devices.size();
934  }
935 };
936 
938 {
939  public:
940  explicit CommandPath(const CaptureCard &parent) :
942  "videodevice"))
943  {
944  setLabel(QObject::tr(""));
945  setValue("");
946  setHelpText(QObject::tr("Specify the command to run, with any "
947  "needed arguments."));
948  };
949 };
950 
952 {
953  public:
954  explicit FileDevice(const CaptureCard &parent) :
956  new CaptureCardDBStorage(this, parent, "videodevice")
957  /* mustexist, false */)
958  {
959  setLabel(QObject::tr("File path"));
960  };
961 };
962 
964 {
965  public:
966  explicit AudioDevice(const CaptureCard &parent) :
967  CaptureCardComboBoxSetting(parent, true /* mustexist false */,
968  "audiodevice")
969  {
970  setLabel(QObject::tr("Audio device"));
971 #if USING_OSS
972  QDir dev("/dev", "dsp*", QDir::Name, QDir::System);
974  dev.setPath("/dev/sound");
976 #endif
977 #if USING_ALSA
978  addSelection("ALSA:default", "ALSA:default");
979 #endif
980  addSelection(QObject::tr("(None)"), "NULL");
981  setHelpText(QObject::tr("Device to read audio from, "
982  "if audio is separate from the video."));
983  };
984 };
985 
987 {
988  public:
989  SignalTimeout(const CaptureCard &parent, uint value, uint min_val) :
990  CaptureCardSpinBoxSetting(parent, min_val, 60000, 250, "signal_timeout")
991  {
992  setLabel(QObject::tr("Signal timeout (ms)"));
993  setValue(QString::number(value));
994  setHelpText(QObject::tr(
995  "Maximum time (in milliseconds) MythTV waits for "
996  "a signal when scanning for channels."));
997  };
998 };
999 
1001 {
1002  public:
1003  ChannelTimeout(const CaptureCard &parent, uint value, uint min_val) :
1004  CaptureCardSpinBoxSetting(parent, min_val, 65000, 250,
1005  "channel_timeout")
1006  {
1007  setLabel(QObject::tr("Tuning timeout (ms)"));
1008  setValue(value);
1009  setHelpText(QObject::tr(
1010  "Maximum time (in milliseconds) MythTV waits for "
1011  "a channel lock. For recordings, if this time is "
1012  "exceeded, the recording will be marked as failed."));
1013  };
1014 };
1015 
1017 {
1018  public:
1019  explicit AudioRateLimit(const CaptureCard &parent) :
1020  CaptureCardComboBoxSetting(parent, false, "audioratelimit")
1021  {
1022  setLabel(QObject::tr("Force audio sampling rate"));
1023  setHelpText(
1024  QObject::tr("If non-zero, override the audio sampling "
1025  "rate in the recording profile when this card is "
1026  "used. Use this if your capture card does not "
1027  "support all of the standard rates."));
1028  addSelection(QObject::tr("(None)"), "0");
1029  addSelection("32000");
1030  addSelection("44100");
1031  addSelection("48000");
1032  };
1033 };
1034 
1036 {
1037  public:
1038  explicit SkipBtAudio(const CaptureCard &parent) :
1040  "skipbtaudio"))
1041  {
1042  setLabel(QObject::tr("Do not adjust volume"));
1043  setHelpText(
1044  QObject::tr("Enable this option for budget BT878 based "
1045  "DVB-T cards such as the AverTV DVB-T which "
1046  "require the audio volume to be left alone."));
1047  };
1048 };
1049 
1051 {
1052  public:
1053  explicit DVBCardNum(const CaptureCard &parent) :
1054  CaptureCardComboBoxSetting(parent, true, "videodevice")
1055  {
1056  setLabel(QObject::tr("DVB device"));
1057  setHelpText(
1058  QObject::tr("When you change this setting, the text below "
1059  "should change to the name and type of your card. "
1060  "If the card cannot be opened, an error message "
1061  "will be displayed."));
1062  fillSelections(QString());
1063  };
1064 
1068  void fillSelections(const QString &current)
1069  {
1070  clearSelections();
1071 
1072  // Get devices from filesystem
1073  QStringList sdevs = CardUtil::ProbeVideoDevices("DVB");
1074 
1075  // Add current if needed
1076  if (!current.isEmpty() &&
1077  (find(sdevs.begin(), sdevs.end(), current) == sdevs.end()))
1078  {
1079  stable_sort(sdevs.begin(), sdevs.end());
1080  }
1081 
1082  QStringList db = CardUtil::GetVideoDevices("DVB");
1083 
1084  QMap<QString,bool> in_use;
1085  QString sel = current;
1086  for (uint i = 0; i < (uint)sdevs.size(); i++)
1087  {
1088  const QString dev = sdevs[i];
1089  in_use[sdevs[i]] = find(db.begin(), db.end(), dev) != db.end();
1090  if (sel.isEmpty() && !in_use[sdevs[i]])
1091  sel = dev;
1092  }
1093 
1094  if (sel.isEmpty() && !sdevs.empty())
1095  sel = sdevs[0];
1096 
1097  QString usestr = QString(" -- ");
1098  usestr += QObject::tr("Warning: already in use");
1099 
1100  for (uint i = 0; i < (uint)sdevs.size(); i++)
1101  {
1102  const QString dev = sdevs[i];
1103  QString desc = dev + (in_use[sdevs[i]] ? usestr : "");
1104  desc = (current == sdevs[i]) ? dev : desc;
1105  addSelection(desc, dev, dev == sel);
1106  }
1107  }
1108 
1109  void Load(void) override // StandardSetting
1110  {
1111  clearSelections();
1112  addSelection(QString());
1113 
1115 
1117  fillSelections(dev);
1118  }
1119 };
1120 
1121 // Use capturecard/inputname to store the delivery system selection of the card
1123 {
1124  public:
1125  explicit DVBCardType(const CaptureCard &parent) :
1126  CaptureCardComboBoxSetting(parent, false, "inputname")
1127  {
1128  setLabel(QObject::tr("Delivery system"));
1129  setHelpText(
1130  QObject::tr("If your card supports more than one delivery system "
1131  "then you can select here the one that you want to use."));
1132  };
1133 };
1134 
1136 {
1137  public:
1139  {
1140  setLabel(QObject::tr("Frontend ID"));
1141  setHelpText(
1142  QObject::tr("Identification string reported by the card. "
1143  "If the message \"Could not get card info...\" appears "
1144  "the card can be in use by another program."));
1145  };
1146 };
1147 
1149 {
1150  public:
1151  explicit DVBNoSeqStart(const CaptureCard &parent) :
1153  new CaptureCardDBStorage(this, parent, "dvb_wait_for_seqstart"))
1154  {
1155  setLabel(QObject::tr("Wait for SEQ start header"));
1156  setValue(true);
1157  setHelpText(
1158  QObject::tr("If enabled, drop packets from the start of a DVB "
1159  "recording until a sequence start header is seen."));
1160  };
1161 };
1162 
1164 {
1165  public:
1166  explicit DVBOnDemand(const CaptureCard &parent) :
1168  new CaptureCardDBStorage(this, parent, "dvb_on_demand"))
1169  {
1170  setLabel(QObject::tr("Open DVB card on demand"));
1171  setValue(true);
1172  setHelpText(
1173  QObject::tr("If enabled, only open the DVB card when required, "
1174  "leaving it free for other programs at other times."));
1175  };
1176 };
1177 
1179 {
1180  public:
1181  explicit DVBEITScan(const CaptureCard &parent) :
1183  new CaptureCardDBStorage(this, parent, "dvb_eitscan"))
1184  {
1185  setLabel(QObject::tr("Use DVB card for active EIT scan"));
1186  setValue(true);
1187  setHelpText(
1188  QObject::tr("If enabled, activate active scanning for "
1189  "program data (EIT). When this option is enabled "
1190  "the DVB card is constantly in-use."));
1191  };
1192 };
1193 
1195 {
1196  public:
1197  explicit DVBTuningDelay(const CaptureCard &parent) :
1198  CaptureCardSpinBoxSetting(parent, 0, 2000, 25, "dvb_tuning_delay")
1199  {
1200  setValue("0");
1201  setLabel(QObject::tr("DVB tuning delay (ms)"));
1202  setValue(true);
1203  setHelpText(
1204  QObject::tr("Some Linux DVB drivers, in particular for the "
1205  "Hauppauge Nova-T, require that we slow down "
1206  "the tuning process by specifying a delay "
1207  "(in milliseconds)."));
1208  };
1209 };
1210 
1212 {
1213  public:
1214  explicit FirewireGUID(const CaptureCard &parent) :
1215  CaptureCardComboBoxSetting(parent, false, "videodevice")
1216  {
1217  setLabel(QObject::tr("GUID"));
1218 #ifdef USING_FIREWIRE
1219  vector<AVCInfo> list = FirewireDevice::GetSTBList();
1220  for (auto & i : list)
1221  {
1222  QString guid = i.GetGUIDString();
1223  m_guidToAvcInfo[guid] = i;
1224  addSelection(guid);
1225  }
1226 #endif // USING_FIREWIRE
1227  }
1228 
1229  AVCInfo GetAVCInfo(const QString &guid) const
1230  { return m_guidToAvcInfo[guid]; }
1231 
1232  private:
1233  QMap<QString,AVCInfo> m_guidToAvcInfo;
1234 };
1235 
1237  const FirewireGUID *_guid) :
1238  CaptureCardComboBoxSetting(parent, false, "firewire_model"),
1239  m_guid(_guid)
1240 {
1241  setLabel(QObject::tr("Cable box model"));
1242  addSelection(QObject::tr("Motorola Generic"), "MOTO GENERIC");
1243  addSelection(QObject::tr("SA/Cisco Generic"), "SA GENERIC");
1244  addSelection("DCH-3200");
1245  addSelection("DCX-3200");
1246  addSelection("DCT-3412");
1247  addSelection("DCT-3416");
1248  addSelection("DCT-6200");
1249  addSelection("DCT-6212");
1250  addSelection("DCT-6216");
1251  addSelection("QIP-6200");
1252  addSelection("QIP-7100");
1253  addSelection("PACE-550");
1254  addSelection("PACE-779");
1255  addSelection("SA3250HD");
1256  addSelection("SA4200HD");
1257  addSelection("SA4250HDC");
1258  addSelection("SA8300HD");
1259  QString help = QObject::tr(
1260  "Choose the model that most closely resembles your set top box. "
1261  "Depending on firmware revision SA4200HD may work better for a "
1262  "SA3250HD box.");
1263  setHelpText(help);
1264 }
1265 
1266 void FirewireModel::SetGUID(const QString &_guid)
1267 {
1268  (void) _guid;
1269 
1270 #ifdef USING_FIREWIRE
1271  AVCInfo info = m_guid->GetAVCInfo(_guid);
1272  QString model = FirewireDevice::GetModelName(info.m_vendorid, info.m_modelid);
1273  setValue(max(getValueIndex(model), 0));
1274 #endif // USING_FIREWIRE
1275 }
1276 
1277 void FirewireDesc::SetGUID(const QString &_guid)
1278 {
1279  (void) _guid;
1280 
1281  setLabel(tr("Description"));
1282 
1283 #ifdef USING_FIREWIRE
1284  QString name = m_guid->GetAVCInfo(_guid).m_product_name;
1285  name.replace("Scientific-Atlanta", "SA");
1286  name.replace(", Inc.", "");
1287  name.replace("Explorer(R)", "");
1288  name = name.simplified();
1289  setValue((name.isEmpty()) ? "" : name);
1290 #endif // USING_FIREWIRE
1291 }
1292 
1294 {
1295  public:
1296  explicit FirewireConnection(const CaptureCard &parent) :
1298  "firewire_connection"))
1299  {
1300  setLabel(QObject::tr("Connection Type"));
1301  addSelection(QObject::tr("Point to Point"),"0");
1302  addSelection(QObject::tr("Broadcast"),"1");
1303  }
1304 };
1305 
1307 {
1308  public:
1309  explicit FirewireSpeed(const CaptureCard &parent) :
1311  "firewire_speed"))
1312  {
1313  setLabel(QObject::tr("Speed"));
1314  addSelection(QObject::tr("100Mbps"),"0");
1315  addSelection(QObject::tr("200Mbps"),"1");
1316  addSelection(QObject::tr("400Mbps"),"2");
1317  addSelection(QObject::tr("800Mbps"),"3");
1318  }
1319 };
1320 
1321 #ifdef USING_FIREWIRE
1322 static void FirewireConfigurationGroup(CaptureCard& parent, CardType& cardtype)
1323 {
1324  auto *dev(new FirewireGUID(parent));
1325  auto *desc(new FirewireDesc(dev));
1326  auto *model(new FirewireModel(parent, dev));
1327  cardtype.addTargetedChild("FIREWIRE", dev);
1328  cardtype.addTargetedChild("FIREWIRE", new EmptyAudioDevice(parent));
1329  cardtype.addTargetedChild("FIREWIRE", new EmptyVBIDevice(parent));
1330  cardtype.addTargetedChild("FIREWIRE", desc);
1331  cardtype.addTargetedChild("FIREWIRE", model);
1332 
1333 #ifdef USING_LINUX_FIREWIRE
1334  cardtype.addTargetedChild("FIREWIRE", new FirewireConnection(parent));
1335  cardtype.addTargetedChild("FIREWIRE", new FirewireSpeed(parent));
1336 #endif // USING_LINUX_FIREWIRE
1337 
1338  cardtype.addTargetedChild("FIREWIRE", new SignalTimeout(parent, 2000, 1000));
1339  cardtype.addTargetedChild("FIREWIRE", new ChannelTimeout(parent, 9000, 1750));
1340 
1341  model->SetGUID(dev->getValue());
1342  desc->SetGUID(dev->getValue());
1343  QObject::connect(dev, SIGNAL(valueChanged(const QString&)),
1344  model, SLOT( SetGUID( const QString&)));
1345  QObject::connect(dev, SIGNAL(valueChanged(const QString&)),
1346  desc, SLOT( SetGUID( const QString&)));
1347 }
1348 #endif
1349 
1350 #if USING_HDHOMERUN
1351 
1352 // -----------------------
1353 // HDHomeRun Configuration
1354 // -----------------------
1355 
1357  HDHomeRunConfigurationGroup &_group) :
1359  new CaptureCardDBStorage(this, parent, "videodevice")),
1360  m_group(_group)
1361 {
1362  setVisible(false);
1363 };
1364 
1366 {
1369 }
1370 
1372 {
1375 }
1376 
1378 {
1379  public:
1380  explicit HDHomeRunEITScan(const CaptureCard &parent) :
1382  new CaptureCardDBStorage(this, parent, "dvb_eitscan"))
1383  {
1384  setLabel(QObject::tr("Use HD HomeRun for active EIT scan"));
1385  setValue(true);
1386  setHelpText(
1387  QObject::tr("If enabled, activate active scanning for "
1388  "program data (EIT). When this option is enabled "
1389  "the HD HomeRun is constantly in-use."));
1390  };
1391 };
1392 
1393 
1395 {
1396  public:
1397  explicit UseHDHomeRunDevice(QString &deviceid, QString &model,
1398  QString &ipaddr)
1399  {
1400  setLabel(QObject::tr("Use HDHomeRun %1 (%2 %3)")
1401  .arg(deviceid).arg(model).arg(ipaddr));
1402  setValue(false);
1403  setHelpText(
1404  QObject::tr("If enabled, use tuners from this HDHomeRun "
1405  "device."));
1406  };
1407 };
1408 
1410  (CaptureCard& a_parent, CardType &a_cardtype) :
1411  m_parent(a_parent)
1412 {
1413  setVisible(false);
1414 
1415  // Fill Device list
1416  FillDeviceList();
1417 
1418  m_deviceId = new HDHomeRunDeviceID(m_parent, *this);
1419 
1420  QMap<QString, HDHomeRunDevice>::iterator dit;
1421  for (dit = m_deviceList.begin(); dit != m_deviceList.end(); ++dit)
1422  {
1423  HDHomeRunDevice &dev = *dit;
1424  dev.m_checkbox = new UseHDHomeRunDevice(
1425  dev.m_deviceId, dev.m_model, dev.m_cardIp);
1426  a_cardtype.addTargetedChild("HDHOMERUN", dev.m_checkbox);
1427  }
1428  a_cardtype.addTargetedChild("HDHOMERUN", new EmptyAudioDevice(m_parent));
1429  a_cardtype.addTargetedChild("HDHOMERUN", new EmptyVBIDevice(m_parent));
1430  a_cardtype.addTargetedChild("HDHOMERUN", m_deviceId);
1431 
1432  auto *buttonRecOpt = new GroupSetting();
1433  buttonRecOpt->setLabel(tr("Recording Options"));
1434  buttonRecOpt->addChild(new SignalTimeout(m_parent, 3000, 250));
1435  buttonRecOpt->addChild(new ChannelTimeout(m_parent, 6000, 1750));
1436  buttonRecOpt->addChild(new HDHomeRunEITScan(m_parent));
1437  a_cardtype.addTargetedChild("HDHOMERUN", buttonRecOpt);
1438 };
1439 
1441 {
1442  m_deviceList.clear();
1443 
1444  // Find physical devices first
1445  // ProbeVideoDevices returns "deviceid ip" pairs
1446  QStringList devs = CardUtil::ProbeVideoDevices("HDHOMERUN");
1447 
1448  QStringList::const_iterator it;
1449 
1450  for (it = devs.begin(); it != devs.end(); ++it)
1451  {
1452  QString dev = *it;
1453  QStringList devinfo = dev.split(" ");
1454  const QString& devid = devinfo.at(0);
1455  const QString& devip = devinfo.at(1);
1456  const QString& model = devinfo.at(2);
1457 
1458  HDHomeRunDevice tmpdevice;
1459  tmpdevice.m_model = model;
1460  tmpdevice.m_cardIp = devip;
1461  tmpdevice.m_deviceId = devid;
1462  // Fully specify object. Checkboxes will be added later when
1463  // the configuration group is created.
1464  tmpdevice.m_checkbox = nullptr;
1465  m_deviceList[tmpdevice.m_deviceId] = tmpdevice;
1466  }
1467 
1468 #if 0
1469  // Debug dump of cards
1470  QMap<QString, HDHomeRunDevice>::iterator debugit;
1471  for (debugit = m_deviceList.begin(); debugit != m_deviceList.end(); ++debugit)
1472  {
1473  LOG(VB_GENERAL, LOG_DEBUG, QString("%1: %2 %3")
1474  .arg(debugit.key()).arg((*debugit).model)
1475  .arg((*debugit).cardip));
1476  }
1477 #endif
1478 }
1479 
1481 {
1482  QStringList devstrs = devices.split(",");
1483  for (int i = 0; i < devstrs.size(); ++i)
1484  {
1485  // Get the HDHomeRun device ID using libhdhomerun. We need to
1486  // do it this way because legacy configurations could use an
1487  // IP address and a tuner nubmer.
1488  QByteArray ba = devstrs[i].toUtf8();
1489  hdhomerun_device_t *device = hdhomerun_device_create_from_str(
1490  ba.data(), nullptr);
1491  if (!device)
1492  continue;
1493  QString devid = QString("%1").arg(
1494  hdhomerun_device_get_device_id(device), 8, 16).toUpper();
1495  hdhomerun_device_destroy(device);
1496 
1497  // If we know about this device, set its checkbox to on.
1498  QMap<QString, HDHomeRunDevice>::iterator dit;
1499  dit = m_deviceList.find(devid);
1500  if (dit != m_deviceList.end())
1501  (*dit).m_checkbox->setValue(true);
1502  }
1503 }
1504 
1506 {
1507  // Return a string listing each HDHomeRun device with its checbox
1508  // turned on.
1509  QStringList devstrs;
1510  QMap<QString, HDHomeRunDevice>::iterator dit;
1511  for (dit = m_deviceList.begin(); dit != m_deviceList.end(); ++dit)
1512  {
1513  if ((*dit).m_checkbox->boolValue())
1514  devstrs << (*dit).m_deviceId;
1515  }
1516  QString devices = devstrs.join(",");
1517  return devices;
1518 }
1519 
1520 #endif
1521 
1522 // -----------------------
1523 // VBOX Configuration
1524 // -----------------------
1525 
1527 {
1528  setLabel(QObject::tr("IP Address"));
1529  setHelpText(QObject::tr("Device IP or ID of a VBox device. eg. '192.168.1.100' or 'vbox_3718'"));
1530  VBoxIP::setEnabled(false);
1531  connect(this, SIGNAL(valueChanged(const QString&)),
1532  this, SLOT(UpdateDevices(const QString&)));
1533 };
1534 
1536 {
1538  if (e)
1539  {
1540  if (!m_oldValue.isEmpty())
1542  emit NewIP(getValue());
1543  }
1544  else
1545  {
1546  m_oldValue = getValue();
1547  }
1548 }
1549 
1550 void VBoxIP::UpdateDevices(const QString &v)
1551 {
1552  if (isEnabled())
1553  emit NewIP(v);
1554 }
1555 
1557 {
1558  setLabel(QObject::tr("Tuner"));
1559  setHelpText(QObject::tr("Number and type of the tuner to use. eg '1-DVBT/T2'."));
1561  connect(this, SIGNAL(valueChanged(const QString&)),
1562  this, SLOT(UpdateDevices(const QString&)));
1563 };
1564 
1566 {
1568  if (e) {
1569  if (!m_oldValue.isEmpty())
1571  emit NewTuner(getValue());
1572  }
1573  else
1574  {
1575  m_oldValue = getValue();
1576  }
1577 }
1578 
1579 void VBoxTunerIndex::UpdateDevices(const QString &v)
1580 {
1581  if (isEnabled())
1582  emit NewTuner(v);
1583 }
1584 
1586  MythUITextEditSetting(new CaptureCardDBStorage(this, parent, "videodevice"))
1587 {
1588  setLabel(tr("Device ID"));
1589  setHelpText(tr("Device ID of VBox device"));
1590  setEnabled(false);
1591 }
1592 
1593 void VBoxDeviceID::SetIP(const QString &ip)
1594 {
1595  m_ip = ip;
1596  setValue(QString("%1-%2").arg(m_ip).arg(m_tuner));
1597 }
1598 
1599 void VBoxDeviceID::SetTuner(const QString &tuner)
1600 {
1601  m_tuner = tuner;
1602  setValue(QString("%1-%2").arg(m_ip).arg(m_tuner));
1603 }
1604 
1605 void VBoxDeviceID::SetOverrideDeviceID(const QString &deviceid)
1606 {
1607  m_overrideDeviceId = deviceid;
1608  setValue(deviceid);
1609 }
1610 
1612 {
1613  GetStorage()->Load();
1614  if (!m_overrideDeviceId.isEmpty())
1615  {
1617  m_overrideDeviceId.clear();
1618  }
1619 }
1620 
1622  VBoxDeviceID *deviceid,
1623  StandardSetting *desc,
1624  VBoxIP *cardip,
1625  VBoxTunerIndex *cardtuner,
1626  VBoxDeviceList *devicelist,
1627  const CaptureCard &parent) :
1628  m_deviceId(deviceid),
1629  m_desc(desc),
1630  m_cardIp(cardip),
1631  m_cardTuner(cardtuner),
1632  m_deviceList(devicelist),
1633  m_parent(parent)
1634 {
1635  setLabel(QObject::tr("Available devices"));
1636  setHelpText(
1637  QObject::tr(
1638  "Device IP or ID, tuner number and tuner type of available VBox devices."));
1639 
1640  connect(this, SIGNAL(valueChanged(const QString&)),
1641  this, SLOT(UpdateDevices(const QString&)));
1642 };
1643 
1645 void VBoxDeviceIDList::fillSelections(const QString &cur)
1646 {
1647  clearSelections();
1648 
1649  vector<QString> devs;
1650  QMap<QString, bool> in_use;
1651 
1652  const QString& current = cur;
1653 
1654  for (auto it = m_deviceList->begin(); it != m_deviceList->end(); ++it)
1655  {
1656  devs.push_back(it.key());
1657  in_use[it.key()] = (*it).m_inUse;
1658  }
1659 
1660  QString man_addr = VBoxDeviceIDList::tr("Manually Enter IP Address");
1661  QString sel = man_addr;
1662  devs.push_back(sel);
1663 
1664  for (const auto & dev : devs)
1665  sel = (current == dev) ? dev : sel;
1666 
1667  QString usestr = QString(" -- ");
1668  usestr += QObject::tr("Warning: already in use");
1669 
1670  for (const auto & dev : devs)
1671  {
1672  QString desc = dev + (in_use[dev] ? usestr : "");
1673  addSelection(desc, dev, dev == sel);
1674  }
1675 
1676  if (current != cur)
1677  {
1679  }
1680  else if (sel == man_addr && !current.isEmpty())
1681  {
1682  // Populate the proper values for IP address and tuner
1683  QStringList selection = current.split("-");
1684 
1685  m_cardIp->SetOldValue(selection.first());
1686  m_cardTuner->SetOldValue(selection.last());
1687 
1688  m_cardIp->setValue(selection.first());
1689  m_cardTuner->setValue(selection.last());
1690  }
1691 }
1692 
1694 {
1695  clearSelections();
1696 
1697  int cardid = m_parent.getCardID();
1698  QString device = CardUtil::GetVideoDevice(cardid);
1699  fillSelections(device);
1700 }
1701 
1702 void VBoxDeviceIDList::UpdateDevices(const QString &v)
1703 {
1704  if (v == VBoxDeviceIDList::tr("Manually Enter IP Address"))
1705  {
1706  m_cardIp->setEnabled(true);
1707  m_cardTuner->setEnabled(true);
1708  }
1709  else if (!v.isEmpty())
1710  {
1711  if (m_oldValue == VBoxDeviceIDList::tr("Manually Enter IP Address"))
1712  {
1713  m_cardIp->setEnabled(false);
1714  m_cardTuner->setEnabled(false);
1715  }
1716  m_deviceId->setValue(v);
1717 
1718  // Update _cardip and _cardtuner
1720  m_cardTuner->setValue(QString("%1").arg((*m_deviceList)[v].m_tunerNo));
1722  }
1723  m_oldValue = v;
1724 };
1725 
1726 // -----------------------
1727 // IPTV Configuration
1728 // -----------------------
1729 
1731 {
1732  public:
1733  explicit IPTVHost(const CaptureCard &parent) :
1734  CaptureCardTextEditSetting(parent, "videodevice")
1735  {
1736  setValue("http://mafreebox.freebox.fr/freeboxtv/playlist.m3u");
1737  setLabel(QObject::tr("M3U URL"));
1738  setHelpText(
1739  QObject::tr("URL of M3U containing RTSP/RTP/UDP channel URLs."));
1740  }
1741 };
1742 
1743 static void IPTVConfigurationGroup(CaptureCard& parent, CardType& cardType)
1744 {
1745  cardType.addTargetedChild("FREEBOX", new IPTVHost(parent));
1746  cardType.addTargetedChild("FREEBOX", new ChannelTimeout(parent, 30000, 1750));
1747  cardType.addTargetedChild("FREEBOX", new EmptyAudioDevice(parent));
1748  cardType.addTargetedChild("FREEBOX", new EmptyVBIDevice(parent));
1749 }
1750 
1752 {
1753  public:
1754  explicit ASIDevice(const CaptureCard &parent) :
1755  CaptureCardComboBoxSetting(parent, true, "videodevice")
1756  {
1757  setLabel(QObject::tr("ASI device"));
1758  fillSelections(QString());
1759  };
1760 
1764  void fillSelections(const QString &current)
1765  {
1766  clearSelections();
1767 
1768  // Get devices from filesystem
1769  QStringList sdevs = CardUtil::ProbeVideoDevices("ASI");
1770 
1771  // Add current if needed
1772  if (!current.isEmpty() &&
1773  (find(sdevs.begin(), sdevs.end(), current) == sdevs.end()))
1774  {
1775  stable_sort(sdevs.begin(), sdevs.end());
1776  }
1777 
1778  // Get devices from DB
1779  QStringList db = CardUtil::GetVideoDevices("ASI");
1780 
1781  // Figure out which physical devices are already in use
1782  // by another card defined in the DB, and select a device
1783  // for new configs (preferring non-conflicing devices).
1784  QMap<QString,bool> in_use;
1785  QString sel = current;
1786  for (uint i = 0; i < (uint)sdevs.size(); ++i)
1787  {
1788  const QString dev = sdevs[i];
1789  in_use[sdevs[i]] = find(db.begin(), db.end(), dev) != db.end();
1790  if (sel.isEmpty() && !in_use[sdevs[i]])
1791  sel = dev;
1792  }
1793 
1794  // Unfortunately all devices are conflicted, select first device.
1795  if (sel.isEmpty() && !sdevs.empty())
1796  sel = sdevs[0];
1797 
1798  QString usestr = QString(" -- ");
1799  usestr += QObject::tr("Warning: already in use");
1800 
1801  // Add the devices to the UI
1802  bool found = false;
1803  for (uint i = 0; i < (uint)sdevs.size(); ++i)
1804  {
1805  const QString dev = sdevs[i];
1806  QString desc = dev + (in_use[sdevs[i]] ? usestr : "");
1807  desc = (current == sdevs[i]) ? dev : desc;
1808  addSelection(desc, dev, dev == sel);
1809  found |= (dev == sel);
1810  }
1811 
1812  // If a configured device isn't on the list, add it with warning
1813  if (!found && !current.isEmpty())
1814  {
1815  QString desc = current + " -- " +
1816  QObject::tr("Warning: unable to open");
1817  addSelection(desc, current, true);
1818  }
1819  }
1820 
1821  void Load(void) override // StandardSetting
1822  {
1823  clearSelections();
1824  addSelection(QString());
1825  GetStorage()->Load();
1827  }
1828 };
1829 
1831  CardType &cardType):
1832  m_parent(a_parent),
1833  m_device(new ASIDevice(m_parent)),
1834  m_cardInfo(new TransTextEditSetting())
1835 {
1836  setVisible(false);
1837  m_cardInfo->setLabel(tr("Status"));
1838  m_cardInfo->setEnabled(false);
1839 
1840  cardType.addTargetedChild("ASI", m_device);
1841  cardType.addTargetedChild("ASI", new EmptyAudioDevice(m_parent));
1842  cardType.addTargetedChild("ASI", new EmptyVBIDevice(m_parent));
1843  cardType.addTargetedChild("ASI", m_cardInfo);
1844 
1845  connect(m_device, SIGNAL(valueChanged(const QString&)),
1846  this, SLOT( probeCard( const QString&)));
1847 
1849 };
1850 
1851 void ASIConfigurationGroup::probeCard(const QString &device)
1852 {
1853 #ifdef USING_ASI
1854  if (device.isEmpty())
1855  {
1856  m_cardInfo->setValue("");
1857  return;
1858  }
1859 
1860  if (m_parent.getCardID() && m_parent.GetRawCardType() != "ASI")
1861  {
1862  m_cardInfo->setValue("");
1863  return;
1864  }
1865 
1866  QString error;
1867  int device_num = CardUtil::GetASIDeviceNumber(device, &error);
1868  if (device_num < 0)
1869  {
1870  m_cardInfo->setValue(tr("Not a valid DVEO ASI card"));
1871  LOG(VB_GENERAL, LOG_WARNING,
1872  "ASIConfigurationGroup::probeCard(), Warning: " + error);
1873  return;
1874  }
1875  m_cardInfo->setValue(tr("Valid DVEO ASI card"));
1876 #else
1877  Q_UNUSED(device);
1878  m_cardInfo->setValue(QString("Not compiled with ASI support"));
1879 #endif
1880 }
1881 
1883  CardType& a_cardtype):
1884  m_parent(a_parent),
1885  m_info(new GroupSetting()), m_size(new GroupSetting())
1886 {
1887  setVisible(false);
1888  auto *device = new FileDevice(m_parent);
1889  device->setHelpText(tr("A local file used to simulate a recording."
1890  " Leave empty to use MythEvents to trigger an"
1891  " external program to import recording files."));
1892  a_cardtype.addTargetedChild("IMPORT", device);
1893 
1894  a_cardtype.addTargetedChild("IMPORT", new EmptyAudioDevice(m_parent));
1895  a_cardtype.addTargetedChild("IMPORT", new EmptyVBIDevice(m_parent));
1896 
1897  m_info->setLabel(tr("File info"));
1898  a_cardtype.addTargetedChild("IMPORT", m_info);
1899 
1900  m_size->setLabel(tr("File size"));
1901  a_cardtype.addTargetedChild("IMPORT", m_size);
1902 
1903  connect(device, SIGNAL(valueChanged(const QString&)),
1904  this, SLOT( probeCard( const QString&)));
1905 
1906  probeCard(device->getValue());
1907 };
1908 
1909 void ImportConfigurationGroup::probeCard(const QString &device)
1910 {
1911  QString ci;
1912  QString cs;
1913  QFileInfo fileInfo(device);
1914 
1915  // For convenience, ImportRecorder allows both formats:
1916  if (device.toLower().startsWith("file:"))
1917  fileInfo.setFile(device.mid(5));
1918 
1919  if (fileInfo.exists())
1920  {
1921  if (fileInfo.isReadable() && (fileInfo.isFile()))
1922  {
1923  ci = HTTPRequest::TestMimeType(fileInfo.absoluteFilePath());
1924  cs = tr("%1 MB").arg(fileInfo.size() / 1024 / 1024);
1925  }
1926  else
1927  ci = tr("File not readable");
1928  }
1929  else
1930  {
1931  ci = tr("File %1 does not exist").arg(device);
1932  }
1933 
1934  m_info->setValue(ci);
1935  m_size->setValue(cs);
1936 }
1937 
1938 // -----------------------
1939 // VBox Configuration
1940 // -----------------------
1941 
1943  (CaptureCard& a_parent, CardType& a_cardtype) :
1944  m_parent(a_parent)
1945 {
1946  setVisible(false);
1947 
1948  // Fill Device list
1949  FillDeviceList();
1950 
1951  m_deviceId = new VBoxDeviceID(m_parent);
1952  m_desc = new GroupSetting();
1953  m_desc->setLabel(tr("Description"));
1954  m_cardIp = new VBoxIP();
1955  m_cardTuner = new VBoxTunerIndex();
1956  m_deviceIdList = new VBoxDeviceIDList(
1957  m_deviceId, m_desc, m_cardIp, m_cardTuner, &m_deviceList, m_parent);
1958 
1959  a_cardtype.addTargetedChild("VBOX", m_deviceIdList);
1960  a_cardtype.addTargetedChild("VBOX", new EmptyAudioDevice(m_parent));
1961  a_cardtype.addTargetedChild("VBOX", new EmptyVBIDevice(m_parent));
1962  a_cardtype.addTargetedChild("VBOX", m_deviceId);
1963  a_cardtype.addTargetedChild("VBOX", m_desc);
1964  a_cardtype.addTargetedChild("VBOX", m_cardIp);
1965  a_cardtype.addTargetedChild("VBOX", m_cardTuner);
1966  a_cardtype.addTargetedChild("VBOX", new SignalTimeout(m_parent, 7000, 1000));
1967  a_cardtype.addTargetedChild("VBOX", new ChannelTimeout(m_parent, 10000, 1750));
1968 // TransButtonSetting *buttonRecOpt = new TransButtonSetting();
1969 // buttonRecOpt->setLabel(tr("Recording Options"));
1970 // addChild(buttonRecOpt);
1971 
1972 // connect(buttonRecOpt, SIGNAL(pressed()),
1973 // this, SLOT( VBoxExtraPanel()));
1974 
1975  connect(m_cardIp, SIGNAL(NewIP(const QString&)),
1976  m_deviceId, SLOT( SetIP(const QString&)));
1977  connect(m_cardTuner, SIGNAL(NewTuner(const QString&)),
1978  m_deviceId, SLOT( SetTuner(const QString&)));
1979 };
1980 
1982 {
1983  m_deviceList.clear();
1984 
1985  // Find physical devices first
1986  // ProbeVideoDevices returns "deviceid ip tunerno tunertype"
1987  QStringList devs = CardUtil::ProbeVideoDevices("VBOX");
1988 
1989  QStringList::const_iterator it;
1990 
1991  for (it = devs.begin(); it != devs.end(); ++it)
1992  {
1993  QString dev = *it;
1994  QStringList devinfo = dev.split(" ");
1995  const QString& id = devinfo.at(0);
1996  const QString& ip = devinfo.at(1);
1997  const QString& tunerNo = devinfo.at(2);
1998  const QString& tunerType = devinfo.at(3);
1999 
2000  VBoxDevice tmpdevice;
2001  tmpdevice.m_deviceId = id;
2002  tmpdevice.m_desc = CardUtil::GetVBoxdesc(id, ip, tunerNo, tunerType);
2003  tmpdevice.m_cardIp = ip;
2004  tmpdevice.m_inUse = false;
2005  tmpdevice.m_discovered = true;
2006  tmpdevice.m_tunerNo = tunerNo;
2007  tmpdevice.m_tunerType = tunerType;
2008  tmpdevice.m_mythDeviceId = id + "-" + tunerNo + "-" + tunerType;
2009  m_deviceList[tmpdevice.m_mythDeviceId] = tmpdevice;
2010  }
2011 
2012  // Now find configured devices
2013 
2014  // returns "ip.ip.ip.ip-n-type" or deviceid-n-type values
2015  QStringList db = CardUtil::GetVideoDevices("VBOX");
2016 
2017  for (it = db.begin(); it != db.end(); ++it)
2018  {
2019  QMap<QString, VBoxDevice>::iterator dit;
2020  dit = m_deviceList.find(*it);
2021 
2022  if (dit != m_deviceList.end())
2023  (*dit).m_inUse = true;
2024  }
2025 }
2026 
2027 // -----------------------
2028 // Ceton Configuration
2029 // -----------------------
2030 
2031 CetonSetting::CetonSetting(const char* label, const char* helptext)
2032 {
2033  setLabel(QObject::tr(label));
2034  setHelpText(tr(helptext));
2035  connect(this, SIGNAL(valueChanged( const QString&)),
2036  this, SLOT( UpdateDevices(const QString&)));
2037 }
2038 
2039 void CetonSetting::UpdateDevices(const QString &v)
2040 {
2041  if (isEnabled())
2042  emit NewValue(v);
2043 }
2044 
2045 void CetonSetting::LoadValue(const QString &value)
2046 {
2047  setValue(value);
2048 }
2049 
2051  MythUITextEditSetting(new CaptureCardDBStorage(this, parent, "videodevice")),
2052  m_parent(parent)
2053 {
2054  setLabel(tr("Device ID"));
2055  setHelpText(tr("Device ID of Ceton device"));
2056 }
2057 
2058 void CetonDeviceID::SetIP(const QString &ip)
2059 {
2060  QString regexp = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){4}$";
2061  if (QRegExp(regexp).exactMatch(ip + "."))
2062  {
2063  m_ip = ip;
2064  setValue(QString("%1-RTP.%3").arg(m_ip).arg(m_tuner));
2065  }
2066 }
2067 
2068 void CetonDeviceID::SetTuner(const QString &tuner)
2069 {
2070  if (QRegExp("^\\d$").exactMatch(tuner))
2071  {
2072  m_tuner = tuner;
2073  setValue(QString("%1-RTP.%2").arg(m_ip).arg(m_tuner));
2074  }
2075 }
2076 
2078 {
2079  GetStorage()->Load();
2080  UpdateValues();
2081 }
2082 
2084 {
2085  QRegExp newstyle("^([0-9.]+)-(\\d|RTP)\\.(\\d)$");
2086  if (newstyle.exactMatch(getValue()))
2087  {
2088  emit LoadedIP(newstyle.cap(1));
2089  emit LoadedTuner(newstyle.cap(3));
2090  }
2091 }
2092 
2093 #ifdef USING_CETON
2094 static void CetonConfigurationGroup(CaptureCard& parent, CardType& cardtype)
2095 {
2096  auto *deviceid = new CetonDeviceID(parent);
2097  auto *desc = new GroupSetting();
2098  desc->setLabel(QCoreApplication::translate("CetonConfigurationGroup",
2099  "Description"));
2100  auto *ip = new CetonSetting("IP Address",
2101  "IP Address of the Ceton device (192.168.200.1 by default)");
2102  auto *tuner = new CetonSetting("Tuner",
2103  "Number of the tuner on the Ceton device (first tuner is number 0)");
2104 
2105  cardtype.addTargetedChild("CETON", ip);
2106  cardtype.addTargetedChild("CETON", tuner);
2107  cardtype.addTargetedChild("CETON", deviceid);
2108  cardtype.addTargetedChild("CETON", desc);
2109  cardtype.addTargetedChild("CETON", new SignalTimeout(parent, 1000, 250));
2110  cardtype.addTargetedChild("CETON", new ChannelTimeout(parent, 3000, 1750));
2111 
2112  QObject::connect(ip, SIGNAL(NewValue(const QString&)),
2113  deviceid, SLOT( SetIP(const QString&)));
2114  QObject::connect(tuner, SIGNAL(NewValue(const QString&)),
2115  deviceid, SLOT( SetTuner(const QString&)));
2116 
2117  QObject::connect(deviceid, SIGNAL(LoadedIP(const QString&)),
2118  ip, SLOT( LoadValue(const QString&)));
2119  QObject::connect(deviceid, SIGNAL(LoadedTuner(const QString&)),
2120  tuner, SLOT( LoadValue(const QString&)));
2121 }
2122 #endif
2123 
2125  CardType& a_cardtype) :
2126  m_parent(a_parent),
2127  m_cardInfo(new TransTextEditSetting()), m_vbiDev(new VBIDevice(m_parent))
2128 {
2129  setVisible(false);
2130  QString drv = "(?!ivtv|hdpvr|(saa7164(.*))).*";
2131  auto *device = new VideoDevice(m_parent, 0, 15, QString(), drv);
2132 
2133  m_cardInfo->setLabel(tr("Probed info"));
2134  m_cardInfo->setEnabled(false);
2135 
2136  a_cardtype.addTargetedChild("V4L", device);
2137  a_cardtype.addTargetedChild("V4L", m_cardInfo);
2138  a_cardtype.addTargetedChild("V4L", m_vbiDev);
2139  a_cardtype.addTargetedChild("V4L", new AudioDevice(m_parent));
2140  a_cardtype.addTargetedChild("V4L", new AudioRateLimit(m_parent));
2141  a_cardtype.addTargetedChild("V4L", new SkipBtAudio(m_parent));
2142 
2143  connect(device, SIGNAL(valueChanged(const QString&)),
2144  this, SLOT( probeCard( const QString&)));
2145 
2146  probeCard(device->getValue());
2147 };
2148 
2149 void V4LConfigurationGroup::probeCard(const QString &device)
2150 {
2151  QString cn = tr("Failed to open");
2152  QString ci = cn;
2153  QString dn;
2154 
2155  QByteArray adevice = device.toLatin1();
2156  int videofd = open(adevice.constData(), O_RDWR);
2157  if (videofd >= 0)
2158  {
2159  if (!CardUtil::GetV4LInfo(videofd, cn, dn))
2160  ci = cn = tr("Failed to probe");
2161  else if (!dn.isEmpty())
2162  ci = cn + " [" + dn + "]";
2163  close(videofd);
2164  }
2165 
2166  m_cardInfo->setValue(ci);
2167  m_vbiDev->setFilter(cn, dn);
2168 }
2169 
2171  CardType &a_cardtype) :
2172  m_parent(a_parent),
2173  m_cardInfo(new TransTextEditSetting())
2174 {
2175  setVisible(false);
2176  QString drv = "ivtv|(saa7164(.*))";
2177  m_device = new VideoDevice(m_parent, 0, 15, QString(), drv);
2179  m_vbiDevice->setVisible(false);
2180 
2181  m_cardInfo->setLabel(tr("Probed info"));
2182  m_cardInfo->setEnabled(false);
2183 
2184  a_cardtype.addTargetedChild("MPEG", m_device);
2185  a_cardtype.addTargetedChild("MPEG", m_vbiDevice);
2186  a_cardtype.addTargetedChild("MPEG", m_cardInfo);
2187  a_cardtype.addTargetedChild("MPEG", new ChannelTimeout(m_parent, 12000, 2000));
2188 
2189  connect(m_device, SIGNAL(valueChanged(const QString&)),
2190  this, SLOT( probeCard( const QString&)));
2191 
2193 }
2194 
2195 void MPEGConfigurationGroup::probeCard(const QString &device)
2196 {
2197  QString cn = tr("Failed to open");
2198  QString ci = cn;
2199  QString dn;
2200 
2201  QByteArray adevice = device.toLatin1();
2202  int videofd = open(adevice.constData(), O_RDWR);
2203  if (videofd >= 0)
2204  {
2205  if (!CardUtil::GetV4LInfo(videofd, cn, dn))
2206  ci = cn = tr("Failed to probe");
2207  else if (!dn.isEmpty())
2208  ci = cn + " [" + dn + "]";
2209  close(videofd);
2210  }
2211 
2212  m_cardInfo->setValue(ci);
2213  m_vbiDevice->setVisible(dn!="ivtv");
2214  m_vbiDevice->setFilter(cn, dn);
2215 }
2216 
2218  CardType &a_cardtype) :
2219  m_parent(a_parent),
2220  m_info(new GroupSetting()), m_size(new GroupSetting())
2221 {
2222  setVisible(false);
2223  auto *device = new FileDevice(m_parent);
2224  device->setHelpText(tr("A local MPEG file used to simulate a recording."));
2225 
2226  a_cardtype.addTargetedChild("DEMO", device);
2227 
2228  a_cardtype.addTargetedChild("DEMO", new EmptyAudioDevice(m_parent));
2229  a_cardtype.addTargetedChild("DEMO", new EmptyVBIDevice(m_parent));
2230 
2231  m_info->setLabel(tr("File info"));
2232  a_cardtype.addTargetedChild("DEMO", m_info);
2233 
2234  m_size->setLabel(tr("File size"));
2235  a_cardtype.addTargetedChild("DEMO", m_size);
2236 
2237  connect(device, SIGNAL(valueChanged(const QString&)),
2238  this, SLOT( probeCard( const QString&)));
2239 
2240  probeCard(device->getValue());
2241 }
2242 
2243 void DemoConfigurationGroup::probeCard(const QString &device)
2244 {
2245  QString ci;
2246  QString cs;
2247  QFileInfo fileInfo(device);
2248  if (fileInfo.exists())
2249  {
2250  if (fileInfo.isReadable() && (fileInfo.isFile()))
2251  {
2252  ci = HTTPRequest::TestMimeType(fileInfo.absoluteFilePath());
2253  cs = tr("%1 MB").arg(fileInfo.size() / 1024 / 1024);
2254  }
2255  else
2256  ci = tr("File not readable");
2257  }
2258  else
2259  {
2260  ci = tr("File does not exist");
2261  }
2262 
2263  m_info->setValue(ci);
2264  m_size->setValue(cs);
2265 }
2266 
2267 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
2268 ExternalConfigurationGroup::ExternalConfigurationGroup(CaptureCard &a_parent,
2269  CardType &a_cardtype) :
2270  m_parent(a_parent),
2271  m_info(new GroupSetting())
2272 {
2273  setVisible(false);
2274  auto *device = new CommandPath(m_parent);
2275  device->setLabel(tr("Command path"));
2276  device->setHelpText(tr("A 'black box' application controlled via stdin, status on "
2277  "stderr and TransportStream read from stdout.\n"
2278  "Use absolute path or path relative to the current directory."));
2279  a_cardtype.addTargetedChild("EXTERNAL", device);
2280 
2281  m_info->setLabel(tr("File info"));
2282  a_cardtype.addTargetedChild("EXTERNAL", m_info);
2283 
2284  a_cardtype.addTargetedChild("EXTERNAL",
2285  new ChannelTimeout(m_parent, 20000, 1750));
2286 
2287  connect(device, SIGNAL(valueChanged(const QString&)),
2288  this, SLOT( probeApp( const QString&)));
2289 
2290  probeApp(device->getValue());
2291 }
2292 
2293 void ExternalConfigurationGroup::probeApp(const QString & path)
2294 {
2295  int idx1 = path.toLower().startsWith("file:") ? 5 : 0;
2296  int idx2 = path.indexOf(' ', idx1);
2297 
2298  QString ci;
2299  QString cs;
2300  QFileInfo fileInfo(path.mid(idx1, idx2 - idx1));
2301 
2302  if (fileInfo.exists())
2303  {
2304  ci = tr("File '%1' is valid.").arg(fileInfo.absoluteFilePath());
2305  if (!fileInfo.isReadable() || !fileInfo.isFile())
2306  ci = tr("WARNING: File '%1' is not readable.")
2307  .arg(fileInfo.absoluteFilePath());
2308  if (!fileInfo.isExecutable())
2309  ci = tr("WARNING: File '%1' is not executable.")
2310  .arg(fileInfo.absoluteFilePath());
2311  }
2312  else
2313  {
2314  ci = tr("WARNING: File '%1' does not exist.")
2315  .arg(fileInfo.absoluteFilePath());
2316  }
2317 
2318  m_info->setValue(ci);
2319  m_info->setHelpText(ci);
2320 }
2321 #endif // !defined( USING_MINGW ) && !defined( _MSC_VER )
2322 
2324  CardType &a_cardtype) :
2325  m_parent(a_parent), m_cardInfo(new GroupSetting()),
2326  m_audioInput(new TunerCardAudioInput(m_parent, QString(), "HDPVR"))
2327 {
2328  setVisible(false);
2329 
2330  auto *device = new VideoDevice(m_parent, 0, 15, QString(), "hdpvr");
2331 
2332  m_cardInfo->setLabel(tr("Probed info"));
2333  m_cardInfo->setEnabled(false);
2334 
2335  a_cardtype.addTargetedChild("HDPVR", device);
2336  a_cardtype.addTargetedChild("HDPVR", new EmptyAudioDevice(m_parent));
2337  a_cardtype.addTargetedChild("HDPVR", new EmptyVBIDevice(m_parent));
2338  a_cardtype.addTargetedChild("HDPVR", m_cardInfo);
2339  a_cardtype.addTargetedChild("HDPVR", m_audioInput);
2340  a_cardtype.addTargetedChild("HDPVR", new ChannelTimeout(m_parent, 15000, 2000));
2341 
2342  connect(device, SIGNAL(valueChanged(const QString&)),
2343  this, SLOT( probeCard( const QString&)));
2344 
2345  probeCard(device->getValue());
2346 }
2347 
2348 void HDPVRConfigurationGroup::probeCard(const QString &device)
2349 {
2350  QString cn = tr("Failed to open");
2351  QString ci = cn;
2352  QString dn;
2353 
2354  int videofd = open(device.toLocal8Bit().constData(), O_RDWR);
2355  if (videofd >= 0)
2356  {
2357  if (!CardUtil::GetV4LInfo(videofd, cn, dn))
2358  ci = cn = tr("Failed to probe");
2359  else if (!dn.isEmpty())
2360  ci = cn + " [" + dn + "]";
2361  close(videofd);
2362  }
2363 
2364  m_cardInfo->setValue(ci);
2365  m_audioInput->fillSelections(device);
2366 }
2367 
2369  m_parent(parent),
2370  m_cardInfo(new TransTextEditSetting())
2371 {
2372  setLabel(QObject::tr("V4L2 encoder devices (multirec capable)"));
2373  m_device = new VideoDevice(m_parent, 0, 15);
2374 
2375  cardtype.addTargetedChild("V4L2ENC", m_device);
2376  m_cardInfo->setLabel(tr("Probed info"));
2377  cardtype.addTargetedChild("V4L2ENC", m_cardInfo);
2378 
2379  setVisible(false);
2380 
2381  connect(m_device, SIGNAL(valueChanged(const QString&)),
2382  this, SLOT( probeCard( const QString&)));
2383 
2384  const QString &device_name = m_device->getValue();
2385  if (!device_name.isEmpty())
2386  probeCard(device_name);
2387 }
2388 
2389 void V4L2encGroup::probeCard(const QString &device_name)
2390 {
2391 #ifdef USING_V4L2
2392  QString card_name = tr("Failed to open");
2393  QString card_info = card_name;
2394  V4L2util v4l2(device_name);
2395 
2396  if (!v4l2.IsOpen())
2397  {
2398  m_driverName = tr("Failed to probe");
2399  return;
2400  }
2401  m_driverName = v4l2.DriverName();
2402  card_name = v4l2.CardName();
2403 
2404  if (!m_driverName.isEmpty())
2405  card_info = card_name + " [" + m_driverName + "]";
2406 
2407  m_cardInfo->setValue(card_info);
2408 
2409  if (m_device->getSubSettings()->empty())
2410  {
2411  auto* audioinput = new TunerCardAudioInput(m_parent, QString(), "V4L2");
2412  if (audioinput->fillSelections(device_name) > 1)
2413  {
2414  audioinput->setName("AudioInput");
2415  m_device->addTargetedChild(m_driverName, audioinput);
2416  }
2417  else
2418  delete audioinput;
2419 
2420  if (v4l2.HasSlicedVBI())
2421  {
2422  auto* vbidev = new VBIDevice(m_parent);
2423  if (vbidev->setFilter(card_name, m_driverName) > 0)
2424  {
2425  vbidev->setName("VBIDevice");
2427  }
2428  else
2429  delete vbidev;
2430  }
2431 
2434  new ChannelTimeout(m_parent, 15000, 2000));
2435  }
2436 #else
2437  Q_UNUSED(device_name);
2438 #endif // USING_V4L2
2439 }
2440 
2442 {
2443  setLabel(QObject::tr("Capture Card Setup"));
2444 
2445  auto* cardtype = new CardType(parent);
2446  parent.addChild(cardtype);
2447 
2448 #ifdef USING_DVB
2449  cardtype->addTargetedChild("DVB",
2450  new DVBConfigurationGroup(parent, *cardtype));
2451 #endif // USING_DVB
2452 
2453 #ifdef USING_V4L2
2454 # ifdef USING_HDPVR
2455  cardtype->addTargetedChild("HDPVR",
2456  new HDPVRConfigurationGroup(parent, *cardtype));
2457 # endif // USING_HDPVR
2458 #endif // USING_V4L2
2459 
2460 #ifdef USING_HDHOMERUN
2461  cardtype->addTargetedChild("HDHOMERUN",
2462  new HDHomeRunConfigurationGroup(parent, *cardtype));
2463 #endif // USING_HDHOMERUN
2464 
2465 #ifdef USING_VBOX
2466  cardtype->addTargetedChild("VBOX",
2467  new VBoxConfigurationGroup(parent, *cardtype));
2468 #endif // USING_VBOX
2469 
2470 #ifdef USING_FIREWIRE
2471  FirewireConfigurationGroup(parent, *cardtype);
2472 #endif // USING_FIREWIRE
2473 
2474 #ifdef USING_CETON
2475  CetonConfigurationGroup(parent, *cardtype);
2476 #endif // USING_CETON
2477 
2478 #ifdef USING_IPTV
2479  IPTVConfigurationGroup(parent, *cardtype);
2480 #endif // USING_IPTV
2481 
2482 #ifdef USING_V4L2
2483  cardtype->addTargetedChild("V4L2ENC", new V4L2encGroup(parent, *cardtype));
2484  cardtype->addTargetedChild("V4L",
2485  new V4LConfigurationGroup(parent, *cardtype));
2486  cardtype->addTargetedChild("MJPEG",
2487  new V4LConfigurationGroup(parent, *cardtype));
2488  cardtype->addTargetedChild("GO7007",
2489  new V4LConfigurationGroup(parent, *cardtype));
2490 # ifdef USING_IVTV
2491  cardtype->addTargetedChild("MPEG",
2492  new MPEGConfigurationGroup(parent, *cardtype));
2493 # endif // USING_IVTV
2494 #endif // USING_V4L2
2495 
2496 #ifdef USING_ASI
2497  cardtype->addTargetedChild("ASI",
2498  new ASIConfigurationGroup(parent, *cardtype));
2499 #endif // USING_ASI
2500 
2501  // for testing without any actual tuner hardware:
2502  cardtype->addTargetedChild("IMPORT",
2503  new ImportConfigurationGroup(parent, *cardtype));
2504  cardtype->addTargetedChild("DEMO",
2505  new DemoConfigurationGroup(parent, *cardtype));
2506 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
2507  cardtype->addTargetedChild("EXTERNAL",
2508  new ExternalConfigurationGroup(parent,
2509  *cardtype));
2510 #endif
2511 }
2512 
2513 CaptureCard::CaptureCard(bool use_card_group)
2514  : m_id(new ID)
2515 {
2516  addChild(m_id);
2517  if (use_card_group)
2518  CaptureCardGroup(*this);
2519  addChild(new Hostname(*this));
2520 }
2521 
2522 QString CaptureCard::GetRawCardType(void) const
2523 {
2524  int cardid = getCardID();
2525  if (cardid <= 0)
2526  return QString();
2527  return CardUtil::GetRawInputType(cardid);
2528 }
2529 
2531 {
2532  MSqlQuery query(MSqlQuery::InitCon());
2533  QString qstr =
2534  "SELECT cardid, videodevice, cardtype "
2535  "FROM capturecard "
2536  "WHERE hostname = :HOSTNAME AND parentid = 0 "
2537  "ORDER BY cardid";
2538 
2539  query.prepare(qstr);
2540  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
2541 
2542  if (!query.exec())
2543  {
2544  MythDB::DBError("CaptureCard::fillSelections", query);
2545  return;
2546  }
2547 
2549 
2550  while (query.next())
2551  {
2552  uint cardid = query.value(0).toUInt();
2553  QString videodevice = query.value(1).toString();
2554  QString cardtype = query.value(2).toString();
2555 
2556  QString label = CardUtil::GetDeviceLabel(cardtype, videodevice);
2557  auto *card = new CaptureCard();
2558  card->loadByID(cardid);
2559  card->setLabel(label);
2560  setting->addChild(card);
2561  }
2562 }
2563 
2564 void CaptureCard::loadByID(int cardid)
2565 {
2566  m_id->setValue(cardid);
2567  Load();
2568 }
2569 
2571 {
2572  return true;
2573 }
2574 
2576 {
2578 }
2579 
2580 
2582 {
2583  uint init_cardid = getCardID();
2584  QString init_dev = CardUtil::GetVideoDevice(init_cardid);
2585 
2587 
2589 
2591 
2592  uint cardid = getCardID();
2593  QString type = CardUtil::GetRawInputType(cardid);
2594  QString dev = CardUtil::GetVideoDevice(cardid);
2595 
2596  if (dev != init_dev)
2597  {
2598  if (!init_dev.isEmpty())
2599  {
2600  uint init_groupid = CardUtil::GetDeviceInputGroup(init_cardid);
2601  CardUtil::UnlinkInputGroup(init_cardid, init_groupid);
2602  }
2603  if (!dev.isEmpty())
2604  {
2605  uint groupid =
2607  gCoreContext->GetHostName(), dev);
2608  CardUtil::LinkInputGroup(cardid, groupid);
2609  CardUtil::UnlinkInputGroup(0, groupid);
2610  }
2611  }
2612 
2613  // Handle any cloning we may need to do
2615  {
2616  vector<uint> clones = CardUtil::GetChildInputIDs(cardid);
2617  for (uint clone : clones)
2618  CardUtil::CloneCard(cardid, clone);
2619  }
2620 }
2621 
2623 {
2624  if (getCardID() == 0)
2625  {
2626  Save();
2627  Load();
2628  }
2629 }
2630 
2632  CaptureCardComboBoxSetting(parent, false, "cardtype")
2633 {
2634  setLabel(QObject::tr("Card type"));
2635  setHelpText(QObject::tr("Change the cardtype to the appropriate type for "
2636  "the capture card you are configuring."));
2637  fillSelections(this);
2638 }
2639 
2641 {
2642 #ifdef USING_DVB
2643  setting->addSelection(
2644  QObject::tr("DVB-T/S/C, ATSC or ISDB-T tuner card"), "DVB");
2645 #endif // USING_DVB
2646 
2647 #ifdef USING_V4L2
2648  setting->addSelection(
2649  QObject::tr("V4L2 encoder"), "V4L2ENC");
2650 #ifdef USING_HDPVR
2651  setting->addSelection(
2652  QObject::tr("HD-PVR H.264 encoder"), "HDPVR");
2653 # endif // USING_HDPVR
2654 #endif // USING_V4L2
2655 
2656 #ifdef USING_HDHOMERUN
2657  setting->addSelection(
2658  QObject::tr("HDHomeRun networked tuner"), "HDHOMERUN");
2659 #endif // USING_HDHOMERUN
2660 
2661 #ifdef USING_VBOX
2662  setting->addSelection(
2663  QObject::tr("V@Box TV Gateway networked tuner"), "VBOX");
2664 #endif // USING_VBOX
2665 
2666 #ifdef USING_FIREWIRE
2667  setting->addSelection(
2668  QObject::tr("FireWire cable box"), "FIREWIRE");
2669 #endif // USING_FIREWIRE
2670 
2671 #ifdef USING_CETON
2672  setting->addSelection(
2673  QObject::tr("Ceton Cablecard tuner"), "CETON");
2674 #endif // USING_CETON
2675 
2676 #ifdef USING_IPTV
2677  setting->addSelection(QObject::tr("IPTV recorder"), "FREEBOX");
2678 #endif // USING_IPTV
2679 
2680 #ifdef USING_V4L2
2681 # ifdef USING_IVTV
2682  setting->addSelection(
2683  QObject::tr("Analog to MPEG-2 encoder card (PVR-150/250/350, etc)"), "MPEG");
2684 # endif // USING_IVTV
2685  setting->addSelection(
2686  QObject::tr("Analog to MJPEG encoder card (Matrox G200, DC10, etc)"), "MJPEG");
2687  setting->addSelection(
2688  QObject::tr("Analog to MPEG-4 encoder (Plextor ConvertX USB, etc)"),
2689  "GO7007");
2690  setting->addSelection(
2691  QObject::tr("Analog capture card"), "V4L");
2692 #endif // USING_V4L2
2693 
2694 #ifdef USING_ASI
2695  setting->addSelection(QObject::tr("DVEO ASI recorder"), "ASI");
2696 #endif
2697 
2698  setting->addSelection(QObject::tr("Import test recorder"), "IMPORT");
2699  setting->addSelection(QObject::tr("Demo test recorder"), "DEMO");
2700 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
2701  setting->addSelection(QObject::tr("External (black box) recorder"),
2702  "EXTERNAL");
2703 #endif
2704 }
2705 
2707 {
2708  public:
2709  explicit InputName(const CardInput &parent) :
2710  MythUIComboBoxSetting(new CardInputDBStorage(this, parent, "inputname"))
2711  {
2712  setLabel(QObject::tr("Input name"));
2713  };
2714 
2715  void Load(void) override // StandardSetting
2716  {
2717  fillSelections();
2719  };
2720 
2722  clearSelections();
2723  addSelection(QObject::tr("(None)"), "None");
2724  auto *storage = dynamic_cast<CardInputDBStorage*>(GetStorage());
2725  if (storage == nullptr)
2726  return;
2727  uint cardid = storage->getInputID();
2728  QString type = CardUtil::GetRawInputType(cardid);
2729  QString device = CardUtil::GetVideoDevice(cardid);
2730  QStringList inputs;
2731  CardUtil::GetDeviceInputNames(device, type, inputs);
2732  while (!inputs.isEmpty())
2733  {
2734  addSelection(inputs.front());
2735  inputs.pop_front();
2736  }
2737  };
2738 };
2739 
2741 {
2742  public:
2744  {
2745  setLabel(QObject::tr("Delivery system"));
2746  setHelpText(QObject::tr(
2747  "This shows the delivery system (modulation), for instance DVB-T2, "
2748  "that you have selected when you configured the capture card. "
2749  "This must be the same as the modulation used by the video source. "));
2750  };
2751 };
2752 
2754 {
2755  public:
2756  explicit InputDisplayName(const CardInput &parent) :
2757  MythUITextEditSetting(new CardInputDBStorage(this, parent, "displayname")), m_parent(parent)
2758  {
2759  setLabel(QObject::tr("Display name"));
2760  setHelpText(QObject::tr(
2761  "This name is displayed on screen when Live TV begins "
2762  "and in various other places. Make sure the last two "
2763  "characters are unique for each input."));
2764  };
2765  void Load(void) override {
2767  if (getValue().isEmpty())
2768  setValue(tr("Input %1").arg(m_parent.getInputID()));
2769  }
2770  private:
2772 };
2773 
2775 {
2776  public:
2777  CardInputComboBoxSetting(const CardInput &parent, const QString &setting) :
2778  MythUIComboBoxSetting(new CardInputDBStorage(this, parent, setting))
2779  {
2780  }
2781 };
2782 
2784 {
2785  public:
2786  explicit SourceID(const CardInput &parent) :
2787  CardInputComboBoxSetting(parent, "sourceid")
2788  {
2789  setLabel(QObject::tr("Video source"));
2790  addSelection(QObject::tr("(None)"), "0");
2791  };
2792 
2793  void Load(void) override // StandardSetting
2794  {
2795  fillSelections();
2797  };
2798 
2800  clearSelections();
2801  addSelection(QObject::tr("(None)"), "0");
2803  };
2804 };
2805 
2807 {
2808  public:
2809  InputGroup(const CardInput &parent, uint group_num) :
2810  m_cardInput(parent),
2811  m_groupNum(group_num)
2812  {
2813  setLabel(QObject::tr("Input group") +
2814  QString(" %1").arg(m_groupNum + 1));
2815  setHelpText(QObject::tr(
2816  "Leave as 'Generic' unless this input is shared with "
2817  "another device. Only one of the inputs in an input "
2818  "group will be allowed to record at any given time."));
2819  }
2820 
2821  void Load(void) override; // StandardSetting
2822 
2823  void Save(void) override // StandardSetting
2824  {
2825  uint inputid = m_cardInput.getInputID();
2826  uint new_groupid = getValue().toUInt();
2827 
2828  if (m_groupId)
2830 
2831  if (new_groupid)
2832  {
2833  if (CardUtil::UnlinkInputGroup(inputid, new_groupid))
2834  CardUtil::LinkInputGroup(inputid, new_groupid);
2835  }
2836  }
2837 
2838  virtual void Save(const QString& /*destination*/) { Save(); }
2839 
2840  private:
2844 };
2845 
2847 {
2848 #if 0
2849  LOG(VB_GENERAL, LOG_DEBUG, QString("InputGroup::Load() %1 %2")
2850  .arg(m_groupNum).arg(m_cardInput.getInputID()));
2851 #endif
2852 
2853  uint inputid = m_cardInput.getInputID();
2854  QMap<uint, uint> grpcnt;
2855  vector<QString> names;
2856  vector<uint> grpid;
2857  vector<uint> selected_groupids;
2858 
2859  names.push_back(QObject::tr("Generic"));
2860  grpid.push_back(0);
2861  grpcnt[0]++;
2862 
2863  MSqlQuery query(MSqlQuery::InitCon());
2864  query.prepare(
2865  "SELECT cardinputid, inputgroupid, inputgroupname "
2866  "FROM inputgroup "
2867  "WHERE inputgroupname LIKE 'user:%' "
2868  "ORDER BY inputgroupid, cardinputid, inputgroupname");
2869 
2870  if (!query.exec())
2871  {
2872  MythDB::DBError("InputGroup::Load()", query);
2873  }
2874  else
2875  {
2876  while (query.next())
2877  {
2878  uint groupid = query.value(1).toUInt();
2879  if (inputid && (query.value(0).toUInt() == inputid))
2880  selected_groupids.push_back(groupid);
2881 
2882  grpcnt[groupid]++;
2883 
2884  if (grpcnt[groupid] == 1)
2885  {
2886  names.push_back(query.value(2).toString().mid(5, -1));
2887  grpid.push_back(groupid);
2888  }
2889  }
2890  }
2891 
2892  // makes sure we select something
2893  m_groupId = 0;
2894  if (m_groupNum < selected_groupids.size())
2895  m_groupId = selected_groupids[m_groupNum];
2896 
2897 #if 0
2898  LOG(VB_GENERAL, LOG_DEBUG, QString("Group num: %1 id: %2")
2899  .arg(m_groupNum).arg(m_groupId));
2900  {
2901  QString msg;
2902  for (uint i = 0; i < selected_groupids.size(); i++)
2903  msg += QString("%1 ").arg(selected_groupids[i]);
2904  LOG(VB_GENERAL, LOG_DEBUG, msg);
2905  }
2906 #endif
2907 
2908  // add selections to combobox
2909  clearSelections();
2910  uint index = 0;
2911  for (size_t i = 0; i < names.size(); i++)
2912  {
2913  bool sel = (m_groupId == grpid[i]);
2914  index = (sel) ? i : index;
2915 
2916 #if 0
2917  LOG(VB_GENERAL, LOG_DEBUG, QString("grpid %1, name '%2', i %3, s %4")
2918  .arg(grpid[i]).arg(names[i]) .arg(index).arg(sel ? "T" : "F"));
2919 #endif
2920 
2921  addSelection(names[i], QString::number(grpid[i]), sel);
2922  }
2923 
2924 #if 0
2925  LOG(VB_GENERAL, LOG_DEBUG, QString("Group index: %1").arg(index));
2926 #endif
2927 
2928  if (!names.empty())
2929  setValue(index);
2930 
2932 }
2933 
2935 {
2936  public:
2937  explicit QuickTune(const CardInput &parent) :
2938  CardInputComboBoxSetting(parent, "quicktune")
2939  {
2940  setLabel(QObject::tr("Use quick tuning"));
2941  addSelection(QObject::tr("Never"), "0", true);
2942  addSelection(QObject::tr("Live TV only"), "1", false);
2943  addSelection(QObject::tr("Always"), "2", false);
2944  setHelpText(QObject::tr(
2945  "If enabled, MythTV will tune using only the "
2946  "MPEG program number. The program numbers "
2947  "change more often than DVB or ATSC tuning "
2948  "parameters, so this is slightly less reliable. "
2949  "This will also inhibit EIT gathering during "
2950  "Live TV and recording."));
2951  };
2952 };
2953 
2955 {
2956  public:
2957  explicit ExternalChannelCommand(const CardInput &parent) :
2958  MythUITextEditSetting(new CardInputDBStorage(this, parent, "externalcommand"))
2959  {
2960  setLabel(QObject::tr("External channel change command"));
2961  setValue("");
2962  setHelpText(QObject::tr("If specified, this command will be run to "
2963  "change the channel for inputs which have an external "
2964  "tuner device such as a cable box. The first argument "
2965  "will be the channel number."));
2966  };
2967 };
2968 
2970 {
2971  public:
2972  explicit PresetTuner(const CardInput &parent) :
2973  MythUITextEditSetting(new CardInputDBStorage(this, parent, "tunechan"))
2974  {
2975  setLabel(QObject::tr("Preset tuner to channel"));
2976  setValue("");
2977  setHelpText(QObject::tr("Leave this blank unless you have an external "
2978  "tuner that is connected to the tuner input of your card. "
2979  "If so, you will need to specify the preset channel for "
2980  "the signal (normally 3 or 4)."));
2981  };
2982 };
2983 
2984 void StartingChannel::SetSourceID(const QString &sourceid)
2985 {
2986  clearSelections();
2987  if (sourceid.isEmpty() || !sourceid.toUInt())
2988  return;
2989 
2990  // Get the existing starting channel
2991  auto *storage = dynamic_cast<CardInputDBStorage*>(GetStorage());
2992  if (storage == nullptr)
2993  return;
2994  int inputId = storage->getInputID();
2995  QString startChan = CardUtil::GetStartingChannel(inputId);
2996 
2997  ChannelInfoList channels = ChannelUtil::GetAllChannels(sourceid.toUInt());
2998 
2999  if (channels.empty())
3000  {
3001  addSelection(tr("Please add channels to this source"),
3002  startChan.isEmpty() ? "0" : startChan);
3003  return;
3004  }
3005 
3006  // If there are channels sort them, then add theme
3007  // (selecting the old start channel if it is there).
3008  QString order = gCoreContext->GetSetting("ChannelOrdering", "channum");
3009  ChannelUtil::SortChannels(channels, order);
3010  bool has_visible = false;
3011  for (size_t i = 0; i < channels.size() && !has_visible; i++)
3012  has_visible |= channels[i].m_visible;
3013 
3014  for (auto & channel : channels)
3015  {
3016  const QString channum = channel.m_chanNum;
3017  bool sel = channum == startChan;
3018  if (!has_visible || channel.m_visible || sel)
3019  {
3020  addSelection(channum, channum, sel);
3021  }
3022  }
3023 }
3024 
3026 {
3027  public:
3028  explicit InputPriority(const CardInput &parent) :
3029  MythUISpinBoxSetting(new CardInputDBStorage(this, parent, "recpriority"),
3030  -99, 99, 1)
3031  {
3032  setLabel(QObject::tr("Input priority"));
3033  setValue(0);
3034  setHelpText(QObject::tr("If the input priority is not equal for "
3035  "all inputs, the scheduler may choose to record a show "
3036  "at a later time so that it can record on an input with "
3037  "a higher value."));
3038  };
3039 };
3040 
3042 {
3043  public:
3044  ScheduleOrder(const CardInput &parent, int _value) :
3045  MythUISpinBoxSetting(new CardInputDBStorage(this, parent, "schedorder"),
3046  0, 99, 1)
3047  {
3048  setLabel(QObject::tr("Schedule order"));
3049  setValue(_value);
3050  setHelpText(QObject::tr("If priorities and other factors are equal "
3051  "the scheduler will choose the available "
3052  "input with the lowest, non-zero value. "
3053  "Setting this value to zero will make the "
3054  "input unavailable to the scheduler."));
3055  };
3056 };
3057 
3059 {
3060  public:
3061  LiveTVOrder(const CardInput &parent, int _value) :
3062  MythUISpinBoxSetting(new CardInputDBStorage(this, parent, "livetvorder"),
3063  0, 99, 1)
3064  {
3065  setLabel(QObject::tr("Live TV order"));
3066  setValue(_value);
3067  setHelpText(QObject::tr("When entering Live TV, the available, local "
3068  "input with the lowest, non-zero value will "
3069  "be used. If no local inputs are available, "
3070  "the available, remote input with the lowest, "
3071  "non-zero value will be used. "
3072  "Setting this value to zero will make the "
3073  "input unavailable to live TV."));
3074  };
3075 };
3076 
3078 {
3079  public:
3080  explicit DishNetEIT(const CardInput &parent) :
3081  MythUICheckBoxSetting(new CardInputDBStorage(this, parent,
3082  "dishnet_eit"))
3083  {
3084  setLabel(QObject::tr("Use DishNet long-term EIT data"));
3085  setValue(false);
3086  setHelpText(
3087  QObject::tr(
3088  "If you point your satellite dish toward DishNet's birds, "
3089  "you may wish to enable this feature. For best results, "
3090  "enable general EIT collection as well."));
3091  };
3092 };
3093 
3094 CardInput::CardInput(const QString & cardtype, const QString & device,
3095  int _cardid) :
3096  m_id(new ID()),
3097  m_inputName(new InputName(*this)),
3098  m_sourceId(new SourceID(*this)),
3099  m_startChan(new StartingChannel(*this)),
3100  m_scan(new ButtonStandardSetting(tr("Scan for channels"))),
3101  m_srcFetch(new ButtonStandardSetting(tr("Fetch channels from listings source"))),
3102  m_externalInputSettings(new DiSEqCDevSettings()),
3103  m_inputGrp0(new InputGroup(*this, 0)),
3104  m_inputGrp1(new InputGroup(*this, 1))
3105 {
3106  addChild(m_id);
3107 
3109  {
3111  _cardid, true));
3112  }
3113 
3114  // Delivery system for DVB, input name for other,
3115  // same field capturecard/inputname for both
3116  if ("DVB" == cardtype)
3117  {
3118  auto *ds = new DeliverySystem();
3119  ds->setValue(CardUtil::GetDeliverySystemFromDB(_cardid));
3120  addChild(ds);
3121  }
3122  else
3123  {
3125  }
3126  addChild(new InputDisplayName(*this));
3128 
3129  if (CardUtil::IsEncoder(cardtype) || CardUtil::IsUnscanable(cardtype))
3130  {
3131  addChild(new ExternalChannelCommand(*this));
3132  if (CardUtil::HasTuner(cardtype, device))
3133  addChild(new PresetTuner(*this));
3134  }
3135  else
3136  {
3137  addChild(new QuickTune(*this));
3138  if ("DVB" == cardtype)
3139  addChild(new DishNetEIT(*this));
3140  }
3141 
3143  tr("Use channel scanner to find channels for this input."));
3144 
3146  tr("This uses the listings data source to "
3147  "provide the channels for this input.") + " " +
3148  tr("This can take a long time to run."));
3149 
3150  addChild(m_scan);
3152 
3154 
3155  auto *interact = new GroupSetting();
3156 
3157  interact->setLabel(QObject::tr("Interactions between inputs"));
3158  if (CardUtil::IsTunerSharingCapable(cardtype))
3159  {
3160  m_instanceCount = new InstanceCount(*this);
3161  interact->addChild(m_instanceCount);
3162  m_schedGroup = new SchedGroup(*this);
3163  interact->addChild(m_schedGroup);
3164  }
3165  interact->addChild(new InputPriority(*this));
3166  interact->addChild(new ScheduleOrder(*this, _cardid));
3167  interact->addChild(new LiveTVOrder(*this, _cardid));
3168 
3169  auto *ingrpbtn =
3170  new ButtonStandardSetting(QObject::tr("Create a New Input Group"));
3171  ingrpbtn->setHelpText(
3172  QObject::tr("Input groups are only needed when two or more cards "
3173  "share the same resource such as a FireWire card and "
3174  "an analog card input controlling the same set top box."));
3175  interact->addChild(ingrpbtn);
3176  interact->addChild(m_inputGrp0);
3177  interact->addChild(m_inputGrp1);
3178 
3179  addChild(interact);
3180 
3181  setObjectName("CardInput");
3182  SetSourceID("-1");
3183 
3184  connect(m_scan, SIGNAL(clicked()), SLOT(channelScanner()));
3185  connect(m_srcFetch, SIGNAL(clicked()), SLOT(sourceFetch()));
3186  connect(m_sourceId, SIGNAL(valueChanged(const QString&)),
3187  m_startChan,SLOT( SetSourceID (const QString&)));
3188  connect(m_sourceId, SIGNAL(valueChanged(const QString&)),
3189  this, SLOT( SetSourceID (const QString&)));
3190  connect(ingrpbtn, SIGNAL(clicked()),
3191  this, SLOT( CreateNewInputGroup()));
3192 }
3193 
3195 {
3197  {
3198  delete m_externalInputSettings;
3199  m_externalInputSettings = nullptr;
3200  }
3201 }
3202 
3203 void CardInput::SetSourceID(const QString &sourceid)
3204 {
3205  uint cid = m_id->getValue().toUInt();
3206  QString raw_card_type = CardUtil::GetRawInputType(cid);
3207  bool enable = (sourceid.toInt() > 0);
3208  m_scan->setEnabled(enable && !raw_card_type.isEmpty() &&
3209  !CardUtil::IsUnscanable(raw_card_type));
3210  m_srcFetch->setEnabled(enable);
3211 }
3212 
3213 QString CardInput::getSourceName(void) const
3214 {
3215  return m_sourceId->getValueLabel();
3216 }
3217 
3219 {
3220  m_inputGrp0->Save();
3221  m_inputGrp1->Save();
3222 
3223  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
3224  auto *settingdialog =
3225  new MythTextInputDialog(popupStack, tr("Enter new group name"));
3226 
3227  if (settingdialog->Create())
3228  {
3229  connect(settingdialog, SIGNAL(haveResult(QString)),
3230  SLOT(CreateNewInputGroupSlot(const QString&)));
3231  popupStack->AddScreen(settingdialog);
3232  }
3233  else
3234  delete settingdialog;
3235 }
3236 
3237 void CardInput::CreateNewInputGroupSlot(const QString& name)
3238 {
3239  if (name.isEmpty())
3240  {
3241  ShowOkPopup(tr("Sorry, this Input Group name cannot be blank."));
3242  return;
3243  }
3244 
3245  QString new_name = QString("user:") + name;
3246 
3247  MSqlQuery query(MSqlQuery::InitCon());
3248  query.prepare("SELECT inputgroupname "
3249  "FROM inputgroup "
3250  "WHERE inputgroupname = :GROUPNAME");
3251  query.bindValue(":GROUPNAME", new_name);
3252 
3253  if (!query.exec())
3254  {
3255  MythDB::DBError("CreateNewInputGroup 1", query);
3256  return;
3257  }
3258 
3259  if (query.next())
3260  {
3261  ShowOkPopup(tr("Sorry, this Input Group name is already in use."));
3262  return;
3263  }
3264 
3265  uint inputgroupid = CardUtil::CreateInputGroup(new_name);
3266 
3267  m_inputGrp0->Load();
3268  m_inputGrp1->Load();
3269 
3270  if (m_inputGrp0->getValue().toUInt() == 0U)
3271  {
3273  m_inputGrp0->getValueIndex(QString::number(inputgroupid)));
3274  }
3275  else
3276  {
3278  m_inputGrp1->getValueIndex(QString::number(inputgroupid)));
3279  }
3280 }
3281 
3283 {
3284  uint srcid = m_sourceId->getValue().toUInt();
3285  uint crdid = m_id->getValue().toUInt();
3286  QString in = m_inputName->getValue();
3287 
3288 #ifdef USING_BACKEND
3289  uint num_channels_before = SourceUtil::GetChannelCount(srcid);
3290 
3291  Save(); // save info for scanner.
3292 
3293  QString cardtype = CardUtil::GetRawInputType(crdid);
3294  if (CardUtil::IsUnscanable(cardtype))
3295  {
3296  LOG(VB_GENERAL, LOG_ERR,
3297  QString("Sorry, %1 cards do not yet support scanning.")
3298  .arg(cardtype));
3299  return;
3300  }
3301 
3303  auto *ssd = new StandardSettingDialog(mainStack, "generalsettings",
3304  new ScanWizard(srcid, crdid, in));
3305 
3306  if (ssd->Create())
3307  {
3308  connect(ssd, &StandardSettingDialog::Exiting,
3309  [=]()
3310  {
3311  if (SourceUtil::GetChannelCount(srcid))
3312  m_startChan->SetSourceID(QString::number(srcid));
3313  if (num_channels_before)
3314  {
3315  m_startChan->Load();
3316  m_startChan->Save();
3317  }
3318  });
3319  mainStack->AddScreen(ssd);
3320  }
3321  else
3322  delete ssd;
3323 
3324 #else
3325  LOG(VB_GENERAL, LOG_ERR, "You must compile the backend "
3326  "to be able to scan for channels");
3327 #endif
3328 }
3329 
3331 {
3332  uint srcid = m_sourceId->getValue().toUInt();
3333  uint crdid = m_id->getValue().toUInt();
3334 
3335  uint num_channels_before = SourceUtil::GetChannelCount(srcid);
3336 
3337  if (crdid && srcid)
3338  {
3339  Save(); // save info for fetch..
3340 
3341  QString cardtype = CardUtil::GetRawInputType(crdid);
3342 
3343  if (!CardUtil::IsCableCardPresent(crdid, cardtype) &&
3344  !CardUtil::IsUnscanable(cardtype) &&
3345  !CardUtil::IsEncoder(cardtype) &&
3346  cardtype != "HDHOMERUN" &&
3347  !num_channels_before)
3348  {
3349  LOG(VB_GENERAL, LOG_ERR, "Skipping channel fetch, you need to "
3350  "scan for channels first.");
3351  return;
3352  }
3353 
3354  SourceUtil::UpdateChannelsFromListings(srcid, cardtype);
3355  }
3356 
3357  if (SourceUtil::GetChannelCount(srcid))
3358  m_startChan->SetSourceID(QString::number(srcid));
3359  if (num_channels_before)
3360  {
3361  m_startChan->Load();
3362  m_startChan->Save();
3363  }
3364 }
3365 
3367 {
3368  QString cardinputidTag(":WHERECARDID");
3369 
3370  QString query("cardid = " + cardinputidTag);
3371 
3372  bindings.insert(cardinputidTag, m_parent.getInputID());
3373 
3374  return query;
3375 }
3376 
3378 {
3379  QString cardinputidTag(":SETCARDID");
3380  QString colTag(":SET" + GetColumnName().toUpper());
3381 
3382  QString query("cardid = " + cardinputidTag + ", " +
3383  GetColumnName() + " = " + colTag);
3384 
3385  bindings.insert(cardinputidTag, m_parent.getInputID());
3386  bindings.insert(colTag, m_user->GetDBValue());
3387 
3388  return query;
3389 }
3390 
3391 void CardInput::loadByID(int inputid)
3392 {
3393  m_id->setValue(inputid);
3394  m_externalInputSettings->Load(inputid);
3396 }
3397 
3398 void CardInput::loadByInput(int _cardid, const QString& _inputname)
3399 {
3400  MSqlQuery query(MSqlQuery::InitCon());
3401  query.prepare("SELECT cardid FROM capturecard "
3402  "WHERE cardid = :CARDID AND inputname = :INPUTNAME");
3403  query.bindValue(":CARDID", _cardid);
3404  query.bindValue(":INPUTNAME", _inputname);
3405 
3406  if (query.exec() && query.isActive() && query.next())
3407  {
3408  loadByID(query.value(0).toInt());
3409  }
3410 }
3411 
3413 {
3414  uint cardid = m_id->getValue().toUInt();
3417 
3418  uint icount = 1;
3419  if (m_instanceCount)
3420  icount = m_instanceCount->getValue().toUInt();
3421  vector<uint> cardids = CardUtil::GetChildInputIDs(cardid);
3422 
3423  // Delete old clone cards as required.
3424  for (size_t i = cardids.size() + 1;
3425  (i > icount) && !cardids.empty(); --i)
3426  {
3427  CardUtil::DeleteInput(cardids.back());
3428  cardids.pop_back();
3429  }
3430 
3431  // Clone this config to existing clone cards.
3432  for (uint id : cardids)
3433  CardUtil::CloneCard(cardid, id);
3434 
3435  // Create new clone cards as required.
3436  for (size_t i = cardids.size() + 1; i < icount; i++)
3437  {
3438  CardUtil::CloneCard(cardid, 0);
3439  }
3440 
3441  // Delete any unused input groups
3443 }
3444 
3446 {
3447  return m_parent.getInputID();
3448 }
3449 
3451 {
3452  return m_parent.getCardID();
3453 }
3454 
3456 {
3457  emit Clicked(m_value);
3458 }
3459 
3460 void CaptureCardEditor::AddSelection(const QString &label, const char *slot)
3461 {
3462  auto *button = new ButtonStandardSetting(label);
3463  connect(button, SIGNAL(clicked()), slot);
3464  addChild(button);
3465 }
3466 
3468 {
3469  ShowOkPopup(
3470  tr("Are you sure you want to delete "
3471  "ALL capture cards on %1?").arg(gCoreContext->GetHostName()),
3472  this,
3473  SLOT(DeleteAllCaptureCardsOnHost(bool)),
3474  true);
3475 }
3476 
3478 {
3479  ShowOkPopup(
3480  tr("Are you sure you want to delete "
3481  "ALL capture cards?"),
3482  this,
3483  SLOT(DeleteAllCaptureCards(bool)),
3484  true);
3485 }
3486 
3488 {
3489  auto *card = new CaptureCard();
3490  card->setLabel(tr("New capture card"));
3491  card->Load();
3492  addChild(card);
3493  emit settingsChanged(this);
3494 }
3495 
3497 {
3498  if (!doDelete)
3499  return;
3500 
3502  Load();
3503  emit settingsChanged(this);
3504 }
3505 
3507 {
3508  if (!doDelete)
3509  return;
3510 
3511  MSqlQuery cards(MSqlQuery::InitCon());
3512 
3513  cards.prepare(
3514  "SELECT cardid "
3515  "FROM capturecard "
3516  "WHERE hostname = :HOSTNAME");
3517  cards.bindValue(":HOSTNAME", gCoreContext->GetHostName());
3518 
3519  if (!cards.exec() || !cards.isActive())
3520  {
3521  ShowOkPopup(
3522  tr("Error getting list of cards for this host. "
3523  "Unable to delete capturecards for %1")
3524  .arg(gCoreContext->GetHostName()));
3525 
3526  MythDB::DBError("Selecting cardids for deletion", cards);
3527  return;
3528  }
3529 
3530  while (cards.next())
3531  CardUtil::DeleteInput(cards.value(0).toUInt());
3532 
3533  Load();
3534  emit settingsChanged(this);
3535 }
3536 
3538 {
3539  setLabel(tr("Capture cards"));
3540 }
3541 
3543 {
3544  clearSettings();
3545  AddSelection(QObject::tr("(New capture card)"), SLOT(AddNewCard()));
3546  AddSelection(QObject::tr("(Delete all capture cards on %1)")
3547  .arg(gCoreContext->GetHostName()),
3549  AddSelection(QObject::tr("(Delete all capture cards)"),
3552 }
3553 
3555 {
3556  setLabel(tr("Video sources"));
3557 }
3558 
3560 {
3561  clearSettings();
3562  AddSelection(QObject::tr("(New video source)"), SLOT(NewSource()));
3563  AddSelection(QObject::tr("(Delete all video sources)"),
3564  SLOT(ShowDeleteAllSourcesDialog()));
3567 }
3568 
3569 void VideoSourceEditor::AddSelection(const QString &label, const char* slot)
3570 {
3571  auto *button = new ButtonStandardSetting(label);
3572  connect(button, SIGNAL(clicked()), slot);
3573  addChild(button);
3574 }
3575 
3577 {
3578  ShowOkPopup(
3579  tr("Are you sure you want to delete "
3580  "ALL video sources?"),
3581  this,
3582  SLOT(DeleteAllSources(bool)),
3583  true);
3584 }
3585 
3587 {
3588  if (!doDelete)
3589  return;
3590 
3592  Load();
3593  emit settingsChanged(this);
3594 }
3595 
3597 {
3598  auto *source = new VideoSource();
3599  source->setLabel(tr("New video source"));
3600  source->Load();
3601  addChild(source);
3602  emit settingsChanged(this);
3603 }
3604 
3606 {
3607  setLabel(tr("Input connections"));
3608 }
3609 
3611 {
3612  m_cardInputs.clear();
3613  clearSettings();
3614 
3615  // We do this manually because we want custom labels. If
3616  // SelectSetting provided a facility to edit the labels, we
3617  // could use CaptureCard::fillSelections
3618 
3619  MSqlQuery query(MSqlQuery::InitCon());
3620  query.prepare(
3621  "SELECT cardid, videodevice, cardtype, inputname "
3622  "FROM capturecard "
3623  "WHERE hostname = :HOSTNAME "
3624  " AND parentid = 0 "
3625  "ORDER BY cardid");
3626  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
3627 
3628  if (!query.exec())
3629  {
3630  MythDB::DBError("CardInputEditor::load", query);
3631  return;
3632  }
3633 
3634  while (query.next())
3635  {
3636  uint cardid = query.value(0).toUInt();
3637  QString videodevice = query.value(1).toString();
3638  QString cardtype = query.value(2).toString();
3639  QString inputname = query.value(3).toString();
3640 
3641  auto *cardinput = new CardInput(cardtype, videodevice, cardid);
3642  cardinput->loadByID(cardid);
3643  QString inputlabel = QString("%1 (%2) -> %3")
3644  .arg(CardUtil::GetDeviceLabel(cardtype, videodevice))
3645  .arg(inputname).arg(cardinput->getSourceName());
3646  m_cardInputs.push_back(cardinput);
3647  cardinput->setLabel(inputlabel);
3648  addChild(cardinput);
3649  }
3650 
3652 }
3653 
3654 #ifdef USING_DVB
3655 static QString remove_chaff(const QString &name)
3656 {
3657  // Trim off some of the chaff.
3658  QString short_name = name;
3659  if (short_name.startsWith("LG Electronics"))
3660  short_name = short_name.right(short_name.length() - 15);
3661  if (short_name.startsWith("Oren"))
3662  short_name = short_name.right(short_name.length() - 5);
3663  if (short_name.startsWith("Nextwave"))
3664  short_name = short_name.right(short_name.length() - 9);
3665  if (short_name.startsWith("frontend", Qt::CaseInsensitive))
3666  short_name = short_name.left(short_name.length() - 9);
3667  if (short_name.endsWith("VSB/QAM"))
3668  short_name = short_name.left(short_name.length() - 8);
3669  if (short_name.endsWith("VSB"))
3670  short_name = short_name.left(short_name.length() - 4);
3671  if (short_name.endsWith("DVB-T"))
3672  short_name = short_name.left(short_name.length() - 6);
3673 
3674  // It would be infinitely better if DVB allowed us to query
3675  // the vendor ID. But instead we have to guess based on the
3676  // demodulator name. This means cards like the Air2PC HD5000
3677  // and DViCO Fusion HDTV cards are not identified correctly.
3678  short_name = short_name.simplified();
3679  if (short_name.startsWith("or51211", Qt::CaseInsensitive))
3680  short_name = "pcHDTV HD-2000";
3681  else if (short_name.startsWith("or51132", Qt::CaseInsensitive))
3682  short_name = "pcHDTV HD-3000";
3683  else if (short_name.startsWith("bcm3510", Qt::CaseInsensitive))
3684  short_name = "Air2PC v1";
3685  else if (short_name.startsWith("nxt2002", Qt::CaseInsensitive) ||
3686  short_name.startsWith("nxt200x", Qt::CaseInsensitive))
3687  short_name = "Air2PC v2";
3688  else if (short_name.startsWith("lgdt3302", Qt::CaseInsensitive))
3689  short_name = "DViCO HDTV3";
3690  else if (short_name.startsWith("lgdt3303", Qt::CaseInsensitive))
3691  short_name = "DViCO v2 or Air2PC v3 or pcHDTV HD-5500";
3692 
3693  return short_name;
3694 }
3695 #endif // USING_DVB
3696 
3697 void DVBConfigurationGroup::reloadDiseqcTree(const QString &videodevice)
3698 {
3699  if (m_diseqcTree)
3700  m_diseqcTree->Load(videodevice);
3701 
3702  if (m_cardType->getValue() == "DVB-S" ||
3703  m_cardType->getValue() == "DVB-S2" )
3704  {
3705  m_diseqcBtn->setVisible(true);
3706  }
3707  else
3708  {
3709  m_diseqcBtn->setVisible(false);
3710  }
3711  emit getParent()->settingsChanged(this);
3712 }
3713 
3714 void DVBConfigurationGroup::probeCard(const QString &videodevice)
3715 {
3716  if (videodevice.isEmpty())
3717  {
3718  m_cardName->setValue("");
3719  m_cardType->setValue("");
3720  return;
3721  }
3722 
3723  if (m_parent.getCardID() && m_parent.GetRawCardType() != "DVB")
3724  {
3725  m_cardName->setValue("");
3726  m_cardType->setValue("");
3727  return;
3728  }
3729 
3730 #ifdef USING_DVB
3731  QString frontend_name = CardUtil::ProbeDVBFrontendName(videodevice);
3732  QString subtype = CardUtil::ProbeDVBType(videodevice);
3733 
3734  QString err_open = tr("Could not open card %1").arg(videodevice);
3735  QString err_other = tr("Could not get card info for card %1").arg(videodevice);
3736 
3737  switch (CardUtil::toInputType(subtype))
3738  {
3739  case CardUtil::ERROR_OPEN:
3740  m_cardName->setValue(err_open);
3741  m_cardType->setValue(strerror(errno));
3742  break;
3744  m_cardName->setValue(err_other);
3745  m_cardType->setValue("Unknown error");
3746  break;
3747  case CardUtil::ERROR_PROBE:
3748  m_cardName->setValue(err_other);
3749  m_cardType->setValue(strerror(errno));
3750  break;
3751  case CardUtil::QPSK:
3752  m_cardType->setValue("DVB-S");
3753  m_cardName->setValue(frontend_name);
3754  m_signalTimeout->setValue(7000);
3755  m_channelTimeout->setValue(10000);
3756  break;
3757  case CardUtil::DVBS2:
3758  m_cardType->setValue("DVB-S2");
3759  m_cardName->setValue(frontend_name);
3760  m_signalTimeout->setValue(7000);
3761  m_channelTimeout->setValue(10000);
3762  break;
3763  case CardUtil::QAM:
3764  m_cardType->setValue("DVB-C");
3765  m_cardName->setValue(frontend_name);
3766  m_signalTimeout->setValue(3000);
3767  m_channelTimeout->setValue(6000);
3768  break;
3769  case CardUtil::DVBT2:
3770  m_cardType->setValue("DVB-T2");
3771  m_cardName->setValue(frontend_name);
3772  m_signalTimeout->setValue(3000);
3773  m_channelTimeout->setValue(6000);
3774  break;
3775  case CardUtil::OFDM:
3776  {
3777  m_cardType->setValue("DVB-T");
3778  m_cardName->setValue(frontend_name);
3779  m_signalTimeout->setValue(3000);
3780  m_channelTimeout->setValue(6000);
3781  if (frontend_name.toLower().indexOf("usb") >= 0)
3782  {
3783  m_signalTimeout->setValue(40000);
3784  m_channelTimeout->setValue(42500);
3785  }
3786 
3787  // slow down tuning for buggy drivers
3788  if ((frontend_name == "DiBcom 3000P/M-C DVB-T") ||
3789  (frontend_name ==
3790  "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"))
3791  {
3792  m_tuningDelay->setValue(200);
3793  }
3794 
3795 #if 0 // frontends on hybrid DVB-T/Analog cards
3796  QString short_name = remove_chaff(frontend_name);
3797  m_buttonAnalog->setVisible(
3798  short_name.startsWith("zarlink zl10353",
3799  Qt::CaseInsensitive) ||
3800  short_name.startsWith("wintv hvr 900 m/r: 65008/a1c0",
3801  Qt::CaseInsensitive) ||
3802  short_name.startsWith("philips tda10046h",
3803  Qt::CaseInsensitive));
3804 #endif
3805  }
3806  break;
3807  case CardUtil::ATSC:
3808  {
3809  QString short_name = remove_chaff(frontend_name);
3810  m_cardType->setValue("ATSC");
3811  m_cardName->setValue(short_name);
3812  m_signalTimeout->setValue(2000);
3813  m_channelTimeout->setValue(4000);
3814 
3815  // According to #1779 and #1935 the AverMedia 180 needs
3816  // a 3000 ms signal timeout, at least for QAM tuning.
3817  if (frontend_name == "Nextwave NXT200X VSB/QAM frontend")
3818  {
3819  m_signalTimeout->setValue(3000);
3820  m_channelTimeout->setValue(5500);
3821  }
3822 
3823 #if 0 // frontends on hybrid DVB-T/Analog cards
3824  if (frontend_name.toLower().indexOf("usb") < 0)
3825  {
3826  m_buttonAnalog->setVisible(
3827  short_name.startsWith("pchdtv", Qt::CaseInsensitive) ||
3828  short_name.startsWith("dvico", Qt::CaseInsensitive) ||
3829  short_name.startsWith("nextwave", Qt::CaseInsensitive));
3830  }
3831 #endif
3832  }
3833  break;
3834  default:
3835  break;
3836  }
3837 
3838  // Create selection list of all delivery systems of this card
3839  {
3841  QStringList delsyslist = CardUtil::ProbeDeliverySystems(videodevice);
3842  foreach (auto & item, delsyslist)
3843  {
3844  LOG(VB_GENERAL, LOG_DEBUG, QString("DVBCardType: add deliverysystem:%1")
3845  .arg(item));
3846 
3847  m_cardType->addSelection(item, item);
3848  }
3849 
3850  // Default value, used if not already defined in capturecard/inputname
3851  QString delsys = CardUtil::ProbeDefaultDeliverySystem(videodevice);
3852  if (!delsys.isEmpty())
3853  {
3854  m_cardType->setValue(delsys);
3855  }
3856  }
3857 #
3858 #else
3859  m_cardType->setValue(QString("Recompile with DVB-Support!"));
3860 #endif
3861 }
3862 
3864  QString dev, QString type) :
3865  CaptureCardComboBoxSetting(parent, false, "audiodevice"),
3866  m_lastDevice(std::move(dev)), m_lastCardType(std::move(type))
3867 {
3868  setLabel(QObject::tr("Audio input"));
3869  setHelpText(QObject::tr("If there is more than one audio input, "
3870  "select which one to use."));
3871  int cardid = parent.getCardID();
3872  if (cardid <= 0)
3873  return;
3874 
3877 }
3878 
3879 int TunerCardAudioInput::fillSelections(const QString &device)
3880 {
3881  clearSelections();
3882 
3883  if (device.isEmpty())
3884  return 0;
3885 
3886  m_lastDevice = device;
3887  QStringList inputs =
3889 
3890  for (uint i = 0; i < (uint)inputs.size(); i++)
3891  {
3892  addSelection(inputs[i], QString::number(i),
3893  m_lastDevice == QString::number(i));
3894  }
3895  return inputs.size();
3896 }
3897 
3899  CardType& cardType) :
3900  m_parent(a_parent),
3901  m_diseqcTree(new DiSEqCDevTree())
3902 {
3903  setVisible(false);
3904 
3905  m_cardNum = new DVBCardNum(m_parent);
3906  m_cardName = new DVBCardName();
3908 
3909  m_signalTimeout = new SignalTimeout(m_parent, 500, 250);
3910  m_channelTimeout = new ChannelTimeout(m_parent, 3000, 1750);
3911 
3912  cardType.addTargetedChild("DVB", m_cardNum);
3913 
3914  cardType.addTargetedChild("DVB", m_cardName);
3915  cardType.addTargetedChild("DVB", m_cardType);
3916 
3917  cardType.addTargetedChild("DVB", m_signalTimeout);
3918  cardType.addTargetedChild("DVB", m_channelTimeout);
3919 
3920  cardType.addTargetedChild("DVB", new EmptyAudioDevice(m_parent));
3921  cardType.addTargetedChild("DVB", new EmptyVBIDevice(m_parent));
3922 
3923  cardType.addTargetedChild("DVB", new DVBNoSeqStart(m_parent));
3924  cardType.addTargetedChild("DVB", new DVBOnDemand(m_parent));
3925  cardType.addTargetedChild("DVB", new DVBEITScan(m_parent));
3926 
3928  m_diseqcBtn->setLabel(tr("DiSEqC (Switch, LNB and Rotor Configuration)"));
3929  m_diseqcBtn->setHelpText(tr("Input and satellite settings."));
3930 
3932  cardType.addTargetedChild("DVB", m_tuningDelay);
3933  cardType.addTargetedChild("DVB", m_diseqcBtn);
3934  m_tuningDelay->setVisible(false);
3935 
3936  connect(m_cardNum, SIGNAL(valueChanged(const QString&)),
3937  this, SLOT( probeCard (const QString&)));
3938  connect(m_cardNum, SIGNAL(valueChanged(const QString&)),
3939  this, SLOT( reloadDiseqcTree(const QString&)));
3940 }
3941 
3943 {
3944  if (m_diseqcTree)
3945  {
3946  delete m_diseqcTree;
3947  m_diseqcTree = nullptr;
3948  }
3949 }
3950 
3952 {
3954  m_diseqcBtn->Load();
3956  if (m_cardType->getValue() == "DVB-S" ||
3957  m_cardType->getValue() == "DVB-S2" ||
3959  {
3960  m_diseqcBtn->setVisible(true);
3961  }
3962 }
3963 
3965 {
3969 }
static QString GetDeviceName(dvb_dev_type_t type, const QString &device)
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
CommandPath(const CaptureCard &parent)
void NewIP(const QString &)
QString m_ip
Definition: videosource.h:932
void Load(void) override
QuickTune(const CardInput &parent)
void Run(time_t timeout=0)
Runs a command inside the /bin/sh shell. Returns immediately.
static bool IsTunerSharingCapable(const QString &rawtype)
Definition: cardutil.h:162
static QString remove_chaff(const QString &name)
void SetSourceID(uint _sourceid)
static QString GetModelName(uint vendor_id, uint model_id)
SignalTimeout * m_signalTimeout
Definition: videosource.h:591
void DeleteAllSources(bool doDelete)
QString getValueLabel(void) const
CaptureCard & m_parent
Definition: videosource.h:435
static QStringList ProbeVideoDevices(const QString &rawtype)
Definition: cardutil.cpp:460
BouquetID(const VideoSource &parent, signed int value, signed int min_val)
XMLTV_generic_config(const VideoSource &_parent, const QString &_grabber, StandardSetting *_setting)
DiSEqCDevTree * m_diseqcTree
Definition: videosource.h:597
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
void DeleteAllCaptureCardsOnHost(bool doDelete)
QString getSourceName(void) const
Definition: videosource.h:191
static ChannelInfoList GetAllChannels(uint sourceid)
Returns channels that are not connected to an input and channels that are not marked as visible.
Definition: channelutil.h:252
void UpdateDevices(const QString &v)
SourceID * m_sourceId
Definition: videosource.h:830
DVB-S device settings class.
Definition: diseqc.h:35
void NewSource(void)
VideoDevice * m_device
Definition: videosource.h:455
void fillSelections()
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
QString Card(void) const
vector< CardInput * > m_cardInputs
Definition: videosource.h:775
QString GetColumnName(void) const
Definition: mythstorage.h:47
virtual void clearSettings()
HDHomeRunConfigurationGroup(CaptureCard &parent, CardType &cardtype)
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
void probeCard(const QString &device)
UseEIT * m_useEit
Definition: videosource.h:148
MythConfirmationDialog * ShowOkPopup(const QString &message, QObject *parent, const char *slot, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
CardType(const CaptureCard &parent)
static uint CreateInputGroup(const QString &name)
Definition: cardutil.cpp:1846
void Load(void) override
void probeCard(const QString &device)
MythUISpinBoxSetting * m_instanceCount
Definition: videosource.h:837
void Load(void) override
VBoxDeviceID * m_deviceId
Definition: videosource.h:907
void NewTuner(const QString &)
QString m_deviceId
Definition: videosource.h:340
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:668
QString m_oldValue
Definition: videosource.h:914
void SetSourceID(const QString &sourceid)
CaptureCardSpinBoxSetting(const CaptureCard &parent, uint min_val, uint max_val, uint step, const QString &setting)
~CardInput() override
static void ClearVideoDeviceCache()
Definition: cardutil.cpp:454
ASIDevice(const CaptureCard &parent)
AudioRateLimit(const CaptureCard &parent)
NoGrabber_config(const VideoSource &_parent)
static uint GetChannelCount(uint sourceid)
Definition: sourceutil.cpp:111
void Load(void) override
SignalTimeout(const CaptureCard &parent, uint value, uint min_val)
static void error(const char *str,...)
Definition: vbi.c:42
Storage * GetStorage(void) const
static bool DeleteSource(uint sourceid)
Definition: sourceutil.cpp:507
SchedGroup(const CardInput &parent)
CaptureCard & m_parent
Definition: videosource.h:540
StandardSetting * getParent() const
virtual void Save(const QString &)
void Save(void) override
static void FirewireConfigurationGroup(CaptureCard &parent, CardType &cardtype)
static enum INPUT_TYPES toInputType(const QString &name)
Definition: cardutil.h:72
void settingsChanged(StandardSetting *selectedSetting=nullptr)
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
ScheduleOrder(const CardInput &parent, int _value)
InputGroup * m_inputGrp0
Definition: videosource.h:835
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)
virtual void Load(void)
virtual bool Create(void)
DVBCardType(const CaptureCard &parent)
void addSelection(const QString &label, QString value=QString(), bool select=false)
QString m_desc
Definition: videosource.h:390
static QString ProbeDVBFrontendName(const QString &device)
Returns the input type from the video device.
Definition: cardutil.cpp:689
const CaptureCard & m_parent
Definition: videosource.h:912
LiveTVOrder(const CardInput &parent, int _value)
virtual void setHelpText(const QString &str)
TransTextEditSetting * m_cardInfo
Definition: videosource.h:488
void SetTuner(const QString &tuner)
V4L2encGroup(CaptureCard &parent, CardType &cardType)
static bool IsInNeedOfExternalInputConf(uint inputid)
Definition: cardutil.cpp:2112
int size(void) const
Definition: mythdbcon.h:203
static bool IsUnscanable(const QString &rawtype)
Definition: cardutil.h:144
static bool cardTypesInclude(const int &SourceID, const QString &thecardtype)
TransTextEditSetting * m_cardInfo
Definition: videosource.h:436
InputGroup(const CardInput &parent, uint group_num)
DVBEITScan(const CaptureCard &parent)
bool IsOpen(void) const
Definition: v4l2util.h:29
void CreateNewInputGroup()
QString GetWhereClause(MSqlBindings &bindings) const override
InputDisplayName(const CardInput &parent)
UseEIT * m_useEit
Definition: videosource.h:160
MythScreenStack * GetStack(const QString &stackname)
void Save(void) override
int getCardID(void) const
Definition: videosource.h:644
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QString m_product_name
Definition: avcinfo.h:45
void AddSelection(const QString &label, const char *slot)
void Load(void) override
void DeleteAllCaptureCards(bool doDelete)
int getValueIndex(const QString &value) const
void Load(void) override
MythScreenStack * GetMainStack()
GroupSetting * m_cardInfo
Definition: videosource.h:472
IPTVHost(const CaptureCard &parent)
VBoxConfigurationGroup(CaptureCard &parent, CardType &cardtype)
QString getSourceName(void) const
CetonDeviceID(const CaptureCard &parent)
QString m_tunerNo
Definition: videosource.h:392
void Load(void) override
void Load(void) override
Definition: videosource.cpp:80
QStringList m_grabberArgs
Definition: videosource.h:136
virtual QString GetDBValue(void) const =0
QString m_cardIp
Definition: videosource.h:342
static void SortChannels(ChannelInfoList &list, const QString &order, bool eliminate_duplicates=false)
DVBCardType * m_cardType
Definition: videosource.h:590
static guint32 * tmp
Definition: goom_core.c:35
void Load(void) override
MythUICheckBoxSetting * m_schedGroup
Definition: videosource.h:838
static bool HasTuner(const QString &rawtype, const QString &device)
Definition: cardutil.cpp:228
void Clicked(const QString &choice)
DVBTuningDelay(const CaptureCard &parent)
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
Definition: diseqc.cpp:130
void LoadValue(const QString &value)
#define lstat
Definition: compat.h:194
static uint CloneCard(uint src_inputid, uint dst_inputid)
Definition: cardutil.cpp:1514
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
Definition: diseqc.cpp:424
void probeCard(const QString &device)
void fillSelections(const QString &current)
Adds all available cards to list If current is >= 0 it will be considered available even if no device...
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2157
DVBCardNum * m_cardNum
Definition: videosource.h:588
void LoadedTuner(const QString &)
DVBTuningDelay * m_tuningDelay
Definition: videosource.h:596
void Load(void) override
RegionID(const VideoSource &parent, signed int value, signed int min_val)
void NewValue(const QString &)
const char * name
Definition: frequencies.h:102
virtual QString getValue(void) const
static bool IsEncoder(const QString &rawtype)
Definition: cardutil.h:121
VBIDevice * m_vbiDev
Definition: videosource.h:437
void fillSelections(const QString &current)
Adds all available cards to list If current is >= 0 it will be considered available even if no device...
uint fillSelectionsFromDir(const QDir &dir, uint minor_min, uint minor_max, const QString &card, const QString &driver, bool allow_duplicates)
QString GetConfDir(void)
Definition: mythdirs.cpp:224
const CaptureCard & m_parent
Definition: videosource.h:246
void AddSelection(const QString &label, const char *slot)
QVariant value(int i) const
Definition: mythdbcon.h:198
void loadByID(int id)
void probeCard(const QString &device)
void UpdateDevices(const QString &v)
void sourceFetch()
CaptureCard(bool use_card_group=true)
void Load(void) override
static bool DeleteInput(uint inputid)
void SetIP(const QString &ip)
VideoSourceShow(uint _initial_sourceid)
void ShowDeleteAllSourcesDialog(void)
static vector< AVCInfo > GetSTBList(void)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
Definition: mythdbcon.h:98
SourceID(const CardInput &parent)
struct CHANLISTS chanlists[]
ScanFrequency(const VideoSource &parent)
QString GetWhereClause(MSqlBindings &bindings) const override
uint m_vendorid
Definition: avcinfo.h:42
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
static QString TestMimeType(const QString &sFileName)
void Save(void) override
void fillSelections()
ChannelTimeout * m_channelTimeout
Definition: videosource.h:592
TunerCardAudioInput * m_audioInput
Definition: videosource.h:473
void Load(void) override
void probeCard(const QString &device)
#define close
Definition: compat.h:16
void setValue(int value) override
FileDevice(const CaptureCard &parent)
int getCardID(void) const
void fillSelections(const QString &current)
Adds all available device-tuner combinations to list.
void LoadedIP(const QString &)
InputName(const CardInput &parent)
static bool DeleteAllInputs(void)
VideoDevice(const CaptureCard &parent, uint minor_min=0, uint minor_max=UINT_MAX, const QString &card=QString(), const QString &driver=QString())
virtual void setLabel(QString str)
void SetOldValue(const QString &s)
Definition: videosource.h:853
MPEGConfigurationGroup(CaptureCard &parent, CardType &cardtype)
UseHDHomeRunDevice(QString &deviceid, QString &model, QString &ipaddr)
void SetDeviceCheckBoxes(const QString &devices)
void SetTuner(const QString &tuner)
AudioDevice(const CaptureCard &parent)
void UpdateDevices(const QString &v)
void setEnabled(bool e) override
HDHomeRunDeviceList m_deviceList
Definition: videosource.h:366
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
TransTextEditSetting * m_cardInfo
Definition: videosource.h:457
QString GetSetting(const QString &key, const QString &defaultval="")
static QString GetDeliverySystemFromDB(uint inputid)
Definition: cardutil.h:279
VBoxDeviceList m_deviceList
Definition: videosource.h:421
DemoConfigurationGroup(CaptureCard &parent, CardType &cardtype)
QByteArray & ReadAll()
void LoadXMLTVGrabbers(QStringList name_list, QStringList prog_list)
static bool IsCableCardPresent(uint inputid, const QString &inputType)
Definition: cardutil.cpp:117
~DVBConfigurationGroup() override
StorageUser * m_user
Definition: mythstorage.h:50
void valueChanged(const QString &newValue)
void Save(void) override
static uint GetDeviceInputGroup(uint inputid)
Definition: cardutil.cpp:1901
TransFreqTableSelector(uint _sourceid)
InstanceCount(const CardInput &parent)
#define minor(X)
Definition: compat.h:138
V4LConfigurationGroup(CaptureCard &parent, CardType &cardtype)
DishNetEIT(const CardInput &parent)
static bool UpdateChannelsFromListings(uint sourceid, const QString &inputtype=QString(), bool wait=false)
Definition: sourceutil.cpp:379
bool isActive(void) const
Definition: mythdbcon.h:204
QString Driver(void) const
InputName * m_inputName
Definition: videosource.h:829
void UpdateDevices(const QString &v)
VBoxIP * m_cardIp
Definition: videosource.h:909
static void IPTVConfigurationGroup(CaptureCard &parent, CardType &cardType)
void ShowDeleteAllCaptureCardsDialog(void)
QString m_deviceId
Definition: videosource.h:389
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
Definition: diseqc.cpp:164
virtual void setEnabled(bool enabled)
void Load(void) override
VBoxDeviceID(const CaptureCard &parent)
uint m_initialSourceId
Definition: videosource.h:89
static void fillSelections(GroupSetting *setting)
void fillSelectionsFromDir(const QDir &dir, bool absPath=true)
unsigned int uint
Definition: compat.h:140
static vector< uint > GetChildInputIDs(uint inputid)
Definition: cardutil.cpp:1337
void SetOverrideDeviceID(const QString &deviceid)
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1965
CardInput(const QString &cardtype, const QString &device, int cardid)
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
AVCInfo GetAVCInfo(const QString &guid) const
QString m_driverName
Definition: videosource.h:491
QString m_tuner
Definition: videosource.h:974
void edit(MythScreenType *screen) override
HDHomeRunDeviceID(const CaptureCard &parent, HDHomeRunConfigurationGroup &_group)
static void fillSelections(GroupSetting *setting)
virtual void Load(void)=0
const FirewireGUID * m_guid
Definition: videosource.h:613
bool isEnabled() const
FirewireConnection(const CaptureCard &parent)
void probeCard(const QString &videodevice)
void Load(void) override
virtual QList< StandardSetting * > * getSubSettings()
CaptureCard & m_parent
Definition: videosource.h:454
CardInputComboBoxSetting(const CardInput &parent, const QString &setting)
CaptureCard & m_parent
Definition: videosource.h:487
static void GetDeviceInputNames(const QString &device, const QString &inputtype, QStringList &inputs)
void Save(void) override
void deleteEntry(void) override
CetonSetting(const char *label, const char *helptext)
virtual void addChild(StandardSetting *child)
void Save(void) override
void SetGUID(const QString &_guid)
bool Load(const QString &device)
Loads the device tree from the database.
Definition: diseqc.cpp:313
DVBOnDemand(const CaptureCard &parent)
InputPriority(const CardInput &parent)
MythMainWindow * GetMythMainWindow(void)
void Load(void) override
HDHomeRunEITScan(const CaptureCard &parent)
static void CetonConfigurationGroup(CaptureCard &parent, CardType &cardtype)
const VideoSource & m_parent
Definition: videosource.h:55
void SetIP(const QString &ip)
uint Wait(time_t timeout=0)
void Load(void) override
void Load(void) override
virtual void Save(void)
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
VBIDevice * m_vbiDevice
Definition: videosource.h:456
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:273
void setValue(const QString &newValue) override
VideoSourceSelector(uint _initial_sourceid, QString _card_types, bool _must_have_mplexid)
Definition: videosource.cpp:64
run process through shell
Definition: mythsystem.h:41
void setEnabled(bool e) override
QString m_tunerType
Definition: videosource.h:393
TunerCardAudioInput(const CaptureCard &parent, QString dev=QString(), QString type=QString())
Dialog prompting the user to enter a text string.
void setVisible(bool visible)
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
SkipBtAudio(const CaptureCard &parent)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString m_overrideDeviceId
Definition: videosource.h:934
static int GetASIDeviceNumber(const QString &device, QString *error=nullptr)
UseEIT(const VideoSource &parent)
CaptureCardGroup(CaptureCard &parent)
QMap< uint, uint > m_minorList
GroupSetting * m_size
Definition: videosource.h:542
static QString GetVBoxdesc(const QString &id, const QString &ip, const QString &tunerNo, const QString &tunerType)
Name * m_name
Definition: videosource.h:227
ButtonStandardSetting * m_scan
Definition: videosource.h:832
static QString GetAudioDevice(uint inputid)
Definition: cardutil.h:275
void SetOldValue(const QString &s)
Definition: videosource.h:874
HDHomeRunConfigurationGroup & m_group
Definition: videosource.h:380
const VideoSource & m_parent
Definition: videosource.h:134
const FirewireGUID * m_guid
Definition: videosource.h:628
GroupSetting()=default
CaptureCard & m_parent
Definition: videosource.h:508
uint m_modelid
Definition: avcinfo.h:43
EITOnly_config(const VideoSource &_parent, StandardSetting *_setting)
void Load(void) override
void setValue(int value) override
Definition: videosource.h:172
DVBNetID(const VideoSource &parent, signed int value, signed int min_val)
void probeCard(const QString &device)
static bool DeleteAllSources(void)
Definition: sourceutil.cpp:550
QString m_cardIp
Definition: videosource.h:391
void channelScanner()
static QStringList ProbeAudioInputs(const QString &device, const QString &inputtype=QString())
const CardInput & m_parent
QString GetSetClause(MSqlBindings &bindings) const override
static QStringList GetVideoDevices(const QString &rawtype, QString hostname=QString())
Returns the videodevices of the matching inputs, duplicates removed.
Definition: cardutil.cpp:409
uint setFilter(const QString &card, const QString &driver)
QString GetSetClause(MSqlBindings &bindings) const override
int fillSelections(const QString &device)
DiSEqCDevSettings * m_externalInputSettings
Definition: videosource.h:834
void ShowDeleteAllCaptureCardsDialogOnHost(void)
VideoDevice * m_device
Definition: videosource.h:489
DVBNoSeqStart(const CaptureCard &parent)
void loadByID(int id)
static void InvalidateTrees(void)
Invalidate cached trees.
Definition: diseqc.cpp:247
ChannelTimeout(const CaptureCard &parent, uint value, uint min_val)
XMLTVGrabber(const VideoSource &parent)
void deleteEntry(void) override
bool m_inUse
Definition: videosource.h:394
GroupSetting * m_size
Definition: videosource.h:526
VBoxTunerIndex * m_cardTuner
Definition: videosource.h:910
QString m_driverName
static bool Exists(int cardid)
Check if a Diseqc device tree exists.
Definition: diseqc.cpp:395
void probeCard(const QString &device)
bool canDelete(void) override
QMap< QString, AVCInfo > m_guidToAvcInfo
VBIDevice(const CaptureCard &parent)
ASIConfigurationGroup(CaptureCard &parent, CardType &cardType)
void reload(void)
ButtonStandardSetting * m_srcFetch
Definition: videosource.h:833
QString m_cardName
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:271
CaptureCard & m_parent
Definition: videosource.h:524
CaptureCardTextEditSetting(const CaptureCard &parent, const QString &setting)
void Save(void) override
void fillSelectionsFromDir(const QDir &dir, bool absPath=true)
GroupSetting * m_info
Definition: videosource.h:525
ExternalChannelCommand(const CardInput &parent)
QString m_ip
Definition: videosource.h:972
int getSourceID(void) const
Definition: videosource.h:183
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static bool GetListingsLoginData(uint sourceid, QString &grabber, QString &userid, QString &passwd, QString &lineupid)
Definition: sourceutil.cpp:147
HDPVRConfigurationGroup(CaptureCard &parent, CardType &cardtype)
ASIDevice * m_device
Definition: videosource.h:509
QString m_oldValue
Definition: videosource.h:863
void Save(void) override
int getInputID(void) const
QString m_tuner
Definition: videosource.h:933
static bool LinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1925
FirewireGUID(const CaptureCard &parent)
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
Screen in which all other widgets are contained and rendered.
void reloadDiseqcTree(const QString &device)
StartingChannel * m_startChan
Definition: videosource.h:831
bool m_discovered
Definition: videosource.h:395
void loadByInput(int cardid, const QString &inputname)
TransTextEditSetting * m_cardInfo
Definition: videosource.h:510
bool canDelete(void) override
void Load(void) override
DeviceTree * m_diseqcBtn
Definition: videosource.h:598
FirewireSpeed(const CaptureCard &parent)
void SetGUID(const QString &_guid)
static QString ProbeDefaultDeliverySystem(const QString &device)
Definition: cardutil.cpp:650
DVBConfigurationGroup(CaptureCard &a_parent, CardType &cardType)
CaptureCard & m_parent
Definition: videosource.h:586
void fillSelectionsFromDir(const QDir &dir, bool absPath=true)
InputGroup * m_inputGrp1
Definition: videosource.h:836
StandardSetting * m_desc
Definition: videosource.h:908
QString GetRawCardType(void) const
static QStringList ProbeDeliverySystems(const QString &device)
Definition: cardutil.cpp:571
QString GetHostName(void)
void Save(void) override
void Save(void) override
const VideoSource & m_parent
DVBCardNum(const CaptureCard &parent)
const CardInput & m_parent
Definition: videosource.h:704
void CreateNewInputGroupSlot(const QString &name)
bool HasSlicedVBI(void) const
VBoxDeviceIDList(VBoxDeviceID *deviceid, StandardSetting *desc, VBoxIP *cardip, VBoxTunerIndex *cardtuner, VBoxDeviceList *devicelist, const CaptureCard &parent)
void addTargetedChild(const QString &value, StandardSetting *setting)
DVB-S device tree class.
Definition: diseqc.h:73
uint fillSelectionsFromDir(const QDir &dir, const QString &card, const QString &driver)
QString DriverName(void) const
Definition: v4l2util.h:48
static void fillSelections(MythUIComboBoxSetting *setting)
virtual void setValue(const QString &newValue)
UseHDHomeRunDevice * m_checkbox
Definition: videosource.h:343
const CardInput & m_cardInput
vector< ChannelInfo > ChannelInfoList
Definition: channelinfo.h:133
VBoxDeviceList * m_deviceList
Definition: videosource.h:911
QString CardName(void) const
Definition: v4l2util.h:49
ImportConfigurationGroup(CaptureCard &parent, CardType &cardtype)
void AddNewCard(void)
void SetSourceID(const QString &sourceid)
PresetTuner(const CardInput &parent)
QString GetWhereClause(MSqlBindings &bindings) const override
GroupSetting * m_info
Definition: videosource.h:541
DVBCardName * m_cardName
Definition: videosource.h:589
QString GetSetClause(MSqlBindings &bindings) const override
static bool is_grabber_external(const QString &grabber)
Definition: videosource.h:29
QMap< QString, VBoxDevice > VBoxDeviceList
Definition: videosource.h:398
CaptureCard & m_parent
Definition: videosource.h:471
QString m_mythDeviceId
Definition: videosource.h:388
static uint CreateDeviceInputGroup(uint inputid, const QString &type, const QString &host, const QString &device)
Definition: cardutil.cpp:1888
static QString GetStartingChannel(uint inputid)
Definition: cardutil.cpp:1705
int getInputID(void) const
Definition: videosource.h:804
allow access to stdout
Definition: mythsystem.h:39
FreqTableSelector(const VideoSource &parent)
QString m_oldValue
Definition: videosource.h:884
FirewireModel(const CaptureCard &parent, const FirewireGUID *_guid)
void loadByID(int id)