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 BSkyB 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 BSkyB 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  TransTextEditSetting *label;
630  label=new TransTextEditSetting();
631  label->setValue(QObject::tr("Use only the transmitted guide data."));
632  label->setHelpText(
633  QObject::tr("This will usually only work with ATSC or DVB channels, "
634  "and generally provides data only for the next few days."));
635  _setting->addTargetedChild("eitonly", label);
636 }
637 
639 {
640  // Force this value on
641  m_useeit->setValue(true);
642  m_useeit->Save();
643 }
644 
646 {
647  m_useeit = new UseEIT(_parent);
648  m_useeit->setValue(false);
649  m_useeit->setVisible(false);
651 
652  auto *label = new TransTextEditSetting();
653  label->setValue(QObject::tr("Do not configure a grabber"));
654  addTargetedChild("/bin/true", label);
655 }
656 
658 {
659  m_useeit->setValue(false);
660  m_useeit->Save();
661 }
662 
664 {
665  // must be first
666  m_id = new ID();
667  addChild(m_id = new ID());
668 
669  setLabel(QObject::tr("Video Source Setup"));
670  addChild(m_name = new Name(*this));
671  addChild(new XMLTVGrabber(*this));
672  addChild(new FreqTableSelector(*this));
673  addChild(new ScanFrequency(*this));
674  addChild(new DVBNetID(*this, -1, -1));
675  addChild(new BouquetID(*this, 0, 0));
676  addChild(new RegionID(*this, 0, 0));
677 }
678 
680 {
681  return true;
682 }
683 
685 {
687 }
688 
689 bool VideoSourceEditor::cardTypesInclude(const int &sourceID,
690  const QString &thecardtype)
691 {
692  MSqlQuery query(MSqlQuery::InitCon());
693  query.prepare("SELECT count(cardtype)"
694  " FROM capturecard "
695  " WHERE capturecard.sourceid = :SOURCEID "
696  " AND capturecard.cardtype = :CARDTYPE ;");
697  query.bindValue(":SOURCEID", sourceID);
698  query.bindValue(":CARDTYPE", thecardtype);
699 
700  if (query.exec() && query.next())
701  {
702  int count = query.value(0).toInt();
703 
704  if (count > 0)
705  return true;
706  }
707 
708  return false;
709 }
710 
712 {
713  MSqlQuery result(MSqlQuery::InitCon());
714  result.prepare("SELECT name, sourceid FROM videosource;");
715 
716  if (result.exec() && result.isActive() && result.size() > 0)
717  {
718  while (result.next())
719  {
720  auto* source = new VideoSource();
721  source->setLabel(result.value(0).toString());
722  source->loadByID(result.value(1).toInt());
723  setting->addChild(source);
724  }
725  }
726 }
727 
729 {
730  MSqlQuery result(MSqlQuery::InitCon());
731  result.prepare("SELECT name, sourceid FROM videosource;");
732 
733  if (result.exec() && result.isActive() && result.size() > 0)
734  {
735  while (result.next())
736  {
737  setting->addSelection(result.value(0).toString(),
738  result.value(1).toString());
739  }
740  }
741 }
742 
743 void VideoSource::loadByID(int sourceid)
744 {
745  m_id->setValue(sourceid);
746 }
747 
749 {
750  public:
751  explicit VideoDevice(const CaptureCard &parent,
752  uint minor_min = 0,
753  uint minor_max = UINT_MAX,
754  const QString& card = QString(),
755  const QString& driver = QString()) :
756  CaptureCardComboBoxSetting(parent, true, "videodevice")
757  {
758  setLabel(QObject::tr("Video device"));
759 
760  // /dev/v4l/video*
761  QDir dev("/dev/v4l", "video*", QDir::Name, QDir::System);
762  fillSelectionsFromDir(dev, minor_min, minor_max,
763  card, driver, false);
764 
765  // /dev/video*
766  dev.setPath("/dev");
767  fillSelectionsFromDir(dev, minor_min, minor_max,
768  card, driver, false);
769 
770  // /dev/dtv/video*
771  dev.setPath("/dev/dtv");
772  fillSelectionsFromDir(dev, minor_min, minor_max,
773  card, driver, false);
774 
775  // /dev/dtv*
776  dev.setPath("/dev");
777  dev.setNameFilters(QStringList("dtv*"));
778  fillSelectionsFromDir(dev, minor_min, minor_max,
779  card, driver, false);
780  };
781 
786  void fillSelectionsFromDir(const QDir &dir, bool absPath = true)
787  {
788  // Needed to make both compiler and doxygen happy.
789  (void) absPath;
790 
791  fillSelectionsFromDir(dir, 0, 255, QString(), QString(), false);
792  }
793 
794  uint fillSelectionsFromDir(const QDir& dir,
795  uint minor_min, uint minor_max,
796  const QString& card, const QString& driver,
797  bool allow_duplicates)
798  {
799  uint cnt = 0;
800 
801  QFileInfoList il = dir.entryInfoList();
802  QRegExp *driverExp = nullptr;
803  if (!driver.isEmpty())
804  driverExp = new QRegExp(driver);
805 
806  for( QFileInfoList::iterator it = il.begin();
807  it != il.end();
808  ++it )
809  {
810  QFileInfo &fi = *it;
811 
812  struct stat st {};
813  QString filepath = fi.absoluteFilePath();
814  int err = lstat(filepath.toLocal8Bit().constData(), &st);
815 
816  if (err)
817  {
818  LOG(VB_GENERAL, LOG_ERR,
819  QString("Could not stat file: %1").arg(filepath));
820  continue;
821  }
822 
823  // is this is a character device?
824  if (!S_ISCHR(st.st_mode))
825  continue;
826 
827  // is this device is in our minor range?
828  uint minor_num = minor(st.st_rdev);
829  if (minor_min > minor_num || minor_max < minor_num)
830  continue;
831 
832  // ignore duplicates if allow_duplicates not set
833  if (!allow_duplicates && m_minorList[minor_num])
834  continue;
835 
836  // if the driver returns any info add this device to our list
837  QByteArray tmp = filepath.toLatin1();
838  int videofd = open(tmp.constData(), O_RDWR);
839  if (videofd >= 0)
840  {
841  QString card_name;
842  QString driver_name;
843  if (CardUtil::GetV4LInfo(videofd, card_name, driver_name) &&
844  (!driverExp || (driverExp->exactMatch(driver_name))) &&
845  (card.isEmpty() || (card_name == card)))
846  {
847  addSelection(filepath);
848  cnt++;
849  }
850  close(videofd);
851  }
852 
853  // add to list of minors discovered to avoid duplicates
854  m_minorList[minor_num] = 1;
855  }
856  delete driverExp;
857 
858  return cnt;
859  }
860 
861  QString Driver(void) const { return m_driverName; }
862  QString Card(void) const { return m_cardName; }
863 
864  private:
865  QMap<uint, uint> m_minorList;
866  QString m_cardName;
867  QString m_driverName;
868 };
869 
871 {
872  public:
873  explicit VBIDevice(const CaptureCard &parent) :
874  CaptureCardComboBoxSetting(parent, true /*, mustexist true */,
875  "vbidevice")
876  {
877  setLabel(QObject::tr("VBI device"));
878  setFilter(QString(), QString());
879  setHelpText(QObject::tr("Device to read VBI (captions) from."));
880  };
881 
882  uint setFilter(const QString &card, const QString &driver)
883  {
884  uint count = 0;
885  clearSelections();
886  QDir dev("/dev/v4l", "vbi*", QDir::Name, QDir::System);
887  if (!(count = fillSelectionsFromDir(dev, card, driver)))
888  {
889  dev.setPath("/dev");
890  if (!(count = fillSelectionsFromDir(dev, card, driver)) &&
891  !getValue().isEmpty())
892  {
893  addSelection(getValue(),getValue(),true);
894  }
895  }
896 
897  return count;
898  }
899 
904  void fillSelectionsFromDir(const QDir &dir, bool absPath = true)
905  {
906  // Needed to make both compiler and doxygen happy.
907  (void) absPath;
908 
909  fillSelectionsFromDir(dir, QString(), QString());
910  }
911 
912  uint fillSelectionsFromDir(const QDir &dir, const QString &card,
913  const QString &driver)
914  {
915  QStringList devices;
916  QFileInfoList il = dir.entryInfoList();
917  for( QFileInfoList::iterator it = il.begin();
918  it != il.end();
919  ++it )
920  {
921  QFileInfo &fi = *it;
922 
923  QString device = fi.absoluteFilePath();
924  QByteArray adevice = device.toLatin1();
925  int vbifd = open(adevice.constData(), O_RDWR);
926  if (vbifd < 0)
927  continue;
928 
929  QString cn;
930  QString dn;
931  if (CardUtil::GetV4LInfo(vbifd, cn, dn) &&
932  (driver.isEmpty() || (dn == driver)) &&
933  (card.isEmpty() || (cn == card)))
934  {
935  devices.push_back(device);
936  }
937 
938  close(vbifd);
939  }
940 
941  QString sel = getValue();
942  for (uint i = 0; i < (uint) devices.size(); i++)
943  addSelection(devices[i], devices[i], devices[i] == sel);
944 
945  return (uint) devices.size();
946  }
947 };
948 
950 {
951  public:
952  explicit CommandPath(const CaptureCard &parent) :
954  "videodevice"))
955  {
956  setLabel(QObject::tr(""));
957  setValue("");
958  setHelpText(QObject::tr("Specify the command to run, with any "
959  "needed arguments."));
960  };
961 };
962 
964 {
965  public:
966  explicit FileDevice(const CaptureCard &parent) :
968  new CaptureCardDBStorage(this, parent, "videodevice")
969  /* mustexist, false */)
970  {
971  setLabel(QObject::tr("File path"));
972  };
973 };
974 
976 {
977  public:
978  explicit AudioDevice(const CaptureCard &parent) :
979  CaptureCardComboBoxSetting(parent, true /* mustexist false */,
980  "audiodevice")
981  {
982  setLabel(QObject::tr("Audio device"));
983 #if USING_OSS
984  QDir dev("/dev", "dsp*", QDir::Name, QDir::System);
986  dev.setPath("/dev/sound");
988 #endif
989 #if USING_ALSA
990  addSelection("ALSA:default", "ALSA:default");
991 #endif
992  addSelection(QObject::tr("(None)"), "NULL");
993  setHelpText(QObject::tr("Device to read audio from, "
994  "if audio is separate from the video."));
995  };
996 };
997 
999 {
1000  public:
1001  SignalTimeout(const CaptureCard &parent, uint value, uint min_val) :
1002  CaptureCardSpinBoxSetting(parent, min_val, 60000, 250, "signal_timeout")
1003  {
1004  setLabel(QObject::tr("Signal timeout (ms)"));
1005  setValue(QString::number(value));
1006  setHelpText(QObject::tr(
1007  "Maximum time (in milliseconds) MythTV waits for "
1008  "a signal when scanning for channels."));
1009  };
1010 };
1011 
1013 {
1014  public:
1015  ChannelTimeout(const CaptureCard &parent, uint value, uint min_val) :
1016  CaptureCardSpinBoxSetting(parent, min_val, 65000, 250,
1017  "channel_timeout")
1018  {
1019  setLabel(QObject::tr("Tuning timeout (ms)"));
1020  setValue(value);
1021  setHelpText(QObject::tr(
1022  "Maximum time (in milliseconds) MythTV waits for "
1023  "a channel lock. For recordings, if this time is "
1024  "exceeded, the recording will be marked as failed."));
1025  };
1026 };
1027 
1029 {
1030  public:
1031  explicit AudioRateLimit(const CaptureCard &parent) :
1032  CaptureCardComboBoxSetting(parent, false, "audioratelimit")
1033  {
1034  setLabel(QObject::tr("Force audio sampling rate"));
1035  setHelpText(
1036  QObject::tr("If non-zero, override the audio sampling "
1037  "rate in the recording profile when this card is "
1038  "used. Use this if your capture card does not "
1039  "support all of the standard rates."));
1040  addSelection(QObject::tr("(None)"), "0");
1041  addSelection("32000");
1042  addSelection("44100");
1043  addSelection("48000");
1044  };
1045 };
1046 
1048 {
1049  public:
1050  explicit SkipBtAudio(const CaptureCard &parent) :
1052  "skipbtaudio"))
1053  {
1054  setLabel(QObject::tr("Do not adjust volume"));
1055  setHelpText(
1056  QObject::tr("Enable this option for budget BT878 based "
1057  "DVB-T cards such as the AverTV DVB-T which "
1058  "require the audio volume to be left alone."));
1059  };
1060 };
1061 
1063 {
1064  public:
1065  explicit DVBCardNum(const CaptureCard &parent) :
1066  CaptureCardComboBoxSetting(parent, true, "videodevice")
1067  {
1068  setLabel(QObject::tr("DVB device"));
1069  setHelpText(
1070  QObject::tr("When you change this setting, the text below "
1071  "should change to the name and type of your card. "
1072  "If the card cannot be opened, an error message "
1073  "will be displayed."));
1074  fillSelections(QString());
1075  };
1076 
1080  void fillSelections(const QString &current)
1081  {
1082  clearSelections();
1083 
1084  // Get devices from filesystem
1085  QStringList sdevs = CardUtil::ProbeVideoDevices("DVB");
1086 
1087  // Add current if needed
1088  if (!current.isEmpty() &&
1089  (find(sdevs.begin(), sdevs.end(), current) == sdevs.end()))
1090  {
1091  stable_sort(sdevs.begin(), sdevs.end());
1092  }
1093 
1094  QStringList db = CardUtil::GetVideoDevices("DVB");
1095 
1096  QMap<QString,bool> in_use;
1097  QString sel = current;
1098  for (uint i = 0; i < (uint)sdevs.size(); i++)
1099  {
1100  const QString dev = sdevs[i];
1101  in_use[sdevs[i]] = find(db.begin(), db.end(), dev) != db.end();
1102  if (sel.isEmpty() && !in_use[sdevs[i]])
1103  sel = dev;
1104  }
1105 
1106  if (sel.isEmpty() && !sdevs.empty())
1107  sel = sdevs[0];
1108 
1109  QString usestr = QString(" -- ");
1110  usestr += QObject::tr("Warning: already in use");
1111 
1112  for (uint i = 0; i < (uint)sdevs.size(); i++)
1113  {
1114  const QString dev = sdevs[i];
1115  QString desc = dev + (in_use[sdevs[i]] ? usestr : "");
1116  desc = (current == sdevs[i]) ? dev : desc;
1117  addSelection(desc, dev, dev == sel);
1118  }
1119  }
1120 
1121  void Load(void) override // StandardSetting
1122  {
1123  clearSelections();
1124  addSelection(QString());
1125 
1127 
1129  fillSelections(dev);
1130  }
1131 };
1132 
1133 // Use capturecard/inputname to store the delivery system selection of the card
1135 {
1136  public:
1137  explicit DVBCardType(const CaptureCard &parent) :
1138  CaptureCardComboBoxSetting(parent, false, "inputname")
1139  {
1140  setLabel(QObject::tr("Delivery system"));
1141  setHelpText(
1142  QObject::tr("If your card supports more than one delivery system "
1143  "then you can select here the one that you want to use."));
1144  };
1145 };
1146 
1148 {
1149  public:
1151  {
1152  setLabel(QObject::tr("Frontend ID"));
1153  setHelpText(
1154  QObject::tr("Identification string reported by the card. "
1155  "If the message \"Could not get card info...\" appears "
1156  "the card can be in use by another program."));
1157  };
1158 };
1159 
1161 {
1162  public:
1163  explicit DVBNoSeqStart(const CaptureCard &parent) :
1165  new CaptureCardDBStorage(this, parent, "dvb_wait_for_seqstart"))
1166  {
1167  setLabel(QObject::tr("Wait for SEQ start header"));
1168  setValue(true);
1169  setHelpText(
1170  QObject::tr("If enabled, drop packets from the start of a DVB "
1171  "recording until a sequence start header is seen."));
1172  };
1173 };
1174 
1176 {
1177  public:
1178  explicit DVBOnDemand(const CaptureCard &parent) :
1180  new CaptureCardDBStorage(this, parent, "dvb_on_demand"))
1181  {
1182  setLabel(QObject::tr("Open DVB card on demand"));
1183  setValue(true);
1184  setHelpText(
1185  QObject::tr("If enabled, only open the DVB card when required, "
1186  "leaving it free for other programs at other times."));
1187  };
1188 };
1189 
1191 {
1192  public:
1193  explicit DVBEITScan(const CaptureCard &parent) :
1195  new CaptureCardDBStorage(this, parent, "dvb_eitscan"))
1196  {
1197  setLabel(QObject::tr("Use DVB card for active EIT scan"));
1198  setValue(true);
1199  setHelpText(
1200  QObject::tr("If enabled, activate active scanning for "
1201  "program data (EIT). When this option is enabled "
1202  "the DVB card is constantly in-use."));
1203  };
1204 };
1205 
1207 {
1208  public:
1209  explicit DVBTuningDelay(const CaptureCard &parent) :
1210  CaptureCardSpinBoxSetting(parent, 0, 2000, 25, "dvb_tuning_delay")
1211  {
1212  setValue("0");
1213  setLabel(QObject::tr("DVB tuning delay (ms)"));
1214  setValue(true);
1215  setHelpText(
1216  QObject::tr("Some Linux DVB drivers, in particular for the "
1217  "Hauppauge Nova-T, require that we slow down "
1218  "the tuning process by specifying a delay "
1219  "(in milliseconds)."));
1220  };
1221 };
1222 
1224 {
1225  public:
1226  explicit FirewireGUID(const CaptureCard &parent) :
1227  CaptureCardComboBoxSetting(parent, false, "videodevice")
1228  {
1229  setLabel(QObject::tr("GUID"));
1230 #ifdef USING_FIREWIRE
1231  vector<AVCInfo> list = FirewireDevice::GetSTBList();
1232  for (size_t i = 0; i < list.size(); i++)
1233  {
1234  QString guid = list[i].GetGUIDString();
1235  m_guidToAvcInfo[guid] = list[i];
1236  addSelection(guid);
1237  }
1238 #endif // USING_FIREWIRE
1239  }
1240 
1241  AVCInfo GetAVCInfo(const QString &guid) const
1242  { return m_guidToAvcInfo[guid]; }
1243 
1244  private:
1245  QMap<QString,AVCInfo> m_guidToAvcInfo;
1246 };
1247 
1249  const FirewireGUID *_guid) :
1250  CaptureCardComboBoxSetting(parent, false, "firewire_model"),
1251  m_guid(_guid)
1252 {
1253  setLabel(QObject::tr("Cable box model"));
1254  addSelection(QObject::tr("Motorola Generic"), "MOTO GENERIC");
1255  addSelection(QObject::tr("SA/Cisco Generic"), "SA GENERIC");
1256  addSelection("DCH-3200");
1257  addSelection("DCX-3200");
1258  addSelection("DCT-3412");
1259  addSelection("DCT-3416");
1260  addSelection("DCT-6200");
1261  addSelection("DCT-6212");
1262  addSelection("DCT-6216");
1263  addSelection("QIP-6200");
1264  addSelection("QIP-7100");
1265  addSelection("PACE-550");
1266  addSelection("PACE-779");
1267  addSelection("SA3250HD");
1268  addSelection("SA4200HD");
1269  addSelection("SA4250HDC");
1270  addSelection("SA8300HD");
1271  QString help = QObject::tr(
1272  "Choose the model that most closely resembles your set top box. "
1273  "Depending on firmware revision SA4200HD may work better for a "
1274  "SA3250HD box.");
1275  setHelpText(help);
1276 }
1277 
1278 void FirewireModel::SetGUID(const QString &_guid)
1279 {
1280  (void) _guid;
1281 
1282 #ifdef USING_FIREWIRE
1283  AVCInfo info = m_guid->GetAVCInfo(_guid);
1284  QString model = FirewireDevice::GetModelName(info.m_vendorid, info.m_modelid);
1285  setValue(max(getValueIndex(model), 0));
1286 #endif // USING_FIREWIRE
1287 }
1288 
1289 void FirewireDesc::SetGUID(const QString &_guid)
1290 {
1291  (void) _guid;
1292 
1293  setLabel(tr("Description"));
1294 
1295 #ifdef USING_FIREWIRE
1296  QString name = m_guid->GetAVCInfo(_guid).m_product_name;
1297  name.replace("Scientific-Atlanta", "SA");
1298  name.replace(", Inc.", "");
1299  name.replace("Explorer(R)", "");
1300  name = name.simplified();
1301  setValue((name.isEmpty()) ? "" : name);
1302 #endif // USING_FIREWIRE
1303 }
1304 
1306 {
1307  public:
1308  explicit FirewireConnection(const CaptureCard &parent) :
1310  "firewire_connection"))
1311  {
1312  setLabel(QObject::tr("Connection Type"));
1313  addSelection(QObject::tr("Point to Point"),"0");
1314  addSelection(QObject::tr("Broadcast"),"1");
1315  }
1316 };
1317 
1319 {
1320  public:
1321  explicit FirewireSpeed(const CaptureCard &parent) :
1323  "firewire_speed"))
1324  {
1325  setLabel(QObject::tr("Speed"));
1326  addSelection(QObject::tr("100Mbps"),"0");
1327  addSelection(QObject::tr("200Mbps"),"1");
1328  addSelection(QObject::tr("400Mbps"),"2");
1329  addSelection(QObject::tr("800Mbps"),"3");
1330  }
1331 };
1332 
1333 #ifdef USING_FIREWIRE
1334 static void FirewireConfigurationGroup(CaptureCard& parent, CardType& cardtype)
1335 {
1336  auto *dev(new FirewireGUID(parent));
1337  auto *desc(new FirewireDesc(dev));
1338  auto *model(new FirewireModel(parent, dev));
1339  cardtype.addTargetedChild("FIREWIRE", dev);
1340  cardtype.addTargetedChild("FIREWIRE", new EmptyAudioDevice(parent));
1341  cardtype.addTargetedChild("FIREWIRE", new EmptyVBIDevice(parent));
1342  cardtype.addTargetedChild("FIREWIRE", desc);
1343  cardtype.addTargetedChild("FIREWIRE", model);
1344 
1345 #ifdef USING_LINUX_FIREWIRE
1346  cardtype.addTargetedChild("FIREWIRE", new FirewireConnection(parent));
1347  cardtype.addTargetedChild("FIREWIRE", new FirewireSpeed(parent));
1348 #endif // USING_LINUX_FIREWIRE
1349 
1350  cardtype.addTargetedChild("FIREWIRE", new SignalTimeout(parent, 2000, 1000));
1351  cardtype.addTargetedChild("FIREWIRE", new ChannelTimeout(parent, 9000, 1750));
1352 
1353  model->SetGUID(dev->getValue());
1354  desc->SetGUID(dev->getValue());
1355  QObject::connect(dev, SIGNAL(valueChanged(const QString&)),
1356  model, SLOT( SetGUID( const QString&)));
1357  QObject::connect(dev, SIGNAL(valueChanged(const QString&)),
1358  desc, SLOT( SetGUID( const QString&)));
1359 }
1360 #endif
1361 
1362 #if USING_HDHOMERUN
1363 
1364 // -----------------------
1365 // HDHomeRun Configuration
1366 // -----------------------
1367 
1369  HDHomeRunConfigurationGroup &_group) :
1371  new CaptureCardDBStorage(this, parent, "videodevice")),
1372  group(_group)
1373 {
1374  setVisible(false);
1375 };
1376 
1378 {
1381 }
1382 
1384 {
1387 }
1388 
1390 {
1391  public:
1392  explicit HDHomeRunEITScan(const CaptureCard &parent) :
1394  new CaptureCardDBStorage(this, parent, "dvb_eitscan"))
1395  {
1396  setLabel(QObject::tr("Use HD HomeRun for active EIT scan"));
1397  setValue(true);
1398  setHelpText(
1399  QObject::tr("If enabled, activate active scanning for "
1400  "program data (EIT). When this option is enabled "
1401  "the HD HomeRun is constantly in-use."));
1402  };
1403 };
1404 
1405 
1407 {
1408  public:
1409  explicit UseHDHomeRunDevice(QString &deviceid, QString &model,
1410  QString &ipaddr)
1411  {
1412  setLabel(QObject::tr("Use HDHomeRun %1 (%2 %3)")
1413  .arg(deviceid).arg(model).arg(ipaddr));
1414  setValue(false);
1415  setHelpText(
1416  QObject::tr("If enabled, use tuners from this HDHomeRun "
1417  "device."));
1418  };
1419 };
1420 
1422  (CaptureCard& a_parent, CardType &a_cardtype) :
1423  m_parent(a_parent)
1424 {
1425  setVisible(false);
1426 
1427  // Fill Device list
1428  FillDeviceList();
1429 
1430  m_deviceId = new HDHomeRunDeviceID(m_parent, *this);
1431 
1432  QMap<QString, HDHomeRunDevice>::iterator dit;
1433  for (dit = m_deviceList.begin(); dit != m_deviceList.end(); ++dit)
1434  {
1435  HDHomeRunDevice &dev = *dit;
1436  dev.checkbox = new UseHDHomeRunDevice(
1437  dev.deviceid, dev.model, dev.cardip);
1438  a_cardtype.addTargetedChild("HDHOMERUN", dev.checkbox);
1439  }
1440  a_cardtype.addTargetedChild("HDHOMERUN", new EmptyAudioDevice(m_parent));
1441  a_cardtype.addTargetedChild("HDHOMERUN", new EmptyVBIDevice(m_parent));
1442  a_cardtype.addTargetedChild("HDHOMERUN", m_deviceId);
1443 
1444  auto *buttonRecOpt = new GroupSetting();
1445  buttonRecOpt->setLabel(tr("Recording Options"));
1446  buttonRecOpt->addChild(new SignalTimeout(m_parent, 1000, 250));
1447  buttonRecOpt->addChild(new ChannelTimeout(m_parent, 3000, 1750));
1448  buttonRecOpt->addChild(new HDHomeRunEITScan(m_parent));
1449  a_cardtype.addTargetedChild("HDHOMERUN", buttonRecOpt);
1450 };
1451 
1453 {
1454  m_deviceList.clear();
1455 
1456  // Find physical devices first
1457  // ProbeVideoDevices returns "deviceid ip" pairs
1458  QStringList devs = CardUtil::ProbeVideoDevices("HDHOMERUN");
1459 
1460  QStringList::const_iterator it;
1461 
1462  for (it = devs.begin(); it != devs.end(); ++it)
1463  {
1464  QString dev = *it;
1465  QStringList devinfo = dev.split(" ");
1466  const QString& devid = devinfo.at(0);
1467  const QString& devip = devinfo.at(1);
1468  const QString& model = devinfo.at(2);
1469 
1470  HDHomeRunDevice tmpdevice;
1471  tmpdevice.model = model;
1472  tmpdevice.cardip = devip;
1473  tmpdevice.deviceid = devid;
1474  // Fully specify object. Checkboxes will be added later when
1475  // the configuration group is created.
1476  tmpdevice.checkbox = nullptr;
1477  m_deviceList[tmpdevice.deviceid] = tmpdevice;
1478  }
1479 
1480 #if 0
1481  // Debug dump of cards
1482  QMap<QString, HDHomeRunDevice>::iterator debugit;
1483  for (debugit = m_deviceList.begin(); debugit != m_deviceList.end(); ++debugit)
1484  {
1485  LOG(VB_GENERAL, LOG_DEBUG, QString("%1: %2 %3")
1486  .arg(debugit.key()).arg((*debugit).model)
1487  .arg((*debugit).cardip));
1488  }
1489 #endif
1490 }
1491 
1493 {
1494  QStringList devstrs = devices.split(",");
1495  for (int i = 0; i < devstrs.size(); ++i)
1496  {
1497  // Get the HDHomeRun device ID using libhdhomerun. We need to
1498  // do it this way because legacy configurations could use an
1499  // IP address and a tuner nubmer.
1500  QByteArray ba = devstrs[i].toUtf8();
1501  hdhomerun_device_t *device = hdhomerun_device_create_from_str(
1502  ba.data(), nullptr);
1503  if (!device)
1504  continue;
1505  QString devid = QString("%1").arg(
1506  hdhomerun_device_get_device_id(device), 8, 16).toUpper();
1507  hdhomerun_device_destroy(device);
1508 
1509  // If we know about this device, set its checkbox to on.
1510  QMap<QString, HDHomeRunDevice>::iterator dit;
1511  dit = m_deviceList.find(devid);
1512  if (dit != m_deviceList.end())
1513  (*dit).checkbox->setValue(true);
1514  }
1515 }
1516 
1518 {
1519  // Return a string listing each HDHomeRun device with its checbox
1520  // turned on.
1521  QStringList devstrs;
1522  QMap<QString, HDHomeRunDevice>::iterator dit;
1523  for (dit = m_deviceList.begin(); dit != m_deviceList.end(); ++dit)
1524  {
1525  if ((*dit).checkbox->boolValue())
1526  devstrs << (*dit).deviceid;
1527  }
1528  QString devices = devstrs.join(",");
1529  return devices;
1530 }
1531 
1532 #endif
1533 
1534 // -----------------------
1535 // VBOX Configuration
1536 // -----------------------
1537 
1539 {
1540  setLabel(QObject::tr("IP Address"));
1541  setHelpText(QObject::tr("Device IP or ID of a VBox device. eg. '192.168.1.100' or 'vbox_3718'"));
1542  VBoxIP::setEnabled(false);
1543  connect(this, SIGNAL(valueChanged(const QString&)),
1544  this, SLOT(UpdateDevices(const QString&)));
1545 };
1546 
1548 {
1550  if (e)
1551  {
1552  if (!m_oldValue.isEmpty())
1554  emit NewIP(getValue());
1555  }
1556  else
1557  {
1558  m_oldValue = getValue();
1559  }
1560 }
1561 
1562 void VBoxIP::UpdateDevices(const QString &v)
1563 {
1564  if (isEnabled())
1565  emit NewIP(v);
1566 }
1567 
1569 {
1570  setLabel(QObject::tr("Tuner"));
1571  setHelpText(QObject::tr("Number and type of the tuner to use. eg '1-DVBT/T2'."));
1573  connect(this, SIGNAL(valueChanged(const QString&)),
1574  this, SLOT(UpdateDevices(const QString&)));
1575 };
1576 
1578 {
1580  if (e) {
1581  if (!m_oldValue.isEmpty())
1583  emit NewTuner(getValue());
1584  }
1585  else
1586  {
1587  m_oldValue = getValue();
1588  }
1589 }
1590 
1591 void VBoxTunerIndex::UpdateDevices(const QString &v)
1592 {
1593  if (isEnabled())
1594  emit NewTuner(v);
1595 }
1596 
1598  MythUITextEditSetting(new CaptureCardDBStorage(this, parent, "videodevice"))
1599 {
1600  setLabel(tr("Device ID"));
1601  setHelpText(tr("Device ID of VBox device"));
1602  setEnabled(false);
1603 }
1604 
1605 void VBoxDeviceID::SetIP(const QString &ip)
1606 {
1607  m_ip = ip;
1608  setValue(QString("%1-%2").arg(m_ip).arg(m_tuner));
1609 }
1610 
1611 void VBoxDeviceID::SetTuner(const QString &tuner)
1612 {
1613  m_tuner = tuner;
1614  setValue(QString("%1-%2").arg(m_ip).arg(m_tuner));
1615 }
1616 
1617 void VBoxDeviceID::SetOverrideDeviceID(const QString &deviceid)
1618 {
1619  m_overrideDeviceId = deviceid;
1620  setValue(deviceid);
1621 }
1622 
1624 {
1625  GetStorage()->Load();
1626  if (!m_overrideDeviceId.isEmpty())
1627  {
1629  m_overrideDeviceId.clear();
1630  }
1631 }
1632 
1634  VBoxDeviceID *deviceid,
1635  StandardSetting *desc,
1636  VBoxIP *cardip,
1637  VBoxTunerIndex *cardtuner,
1638  VBoxDeviceList *devicelist,
1639  const CaptureCard &parent) :
1640  m_deviceId(deviceid),
1641  m_desc(desc),
1642  m_cardIp(cardip),
1643  m_cardTuner(cardtuner),
1644  m_deviceList(devicelist),
1645  m_parent(parent)
1646 {
1647  setLabel(QObject::tr("Available devices"));
1648  setHelpText(
1649  QObject::tr(
1650  "Device IP or ID, tuner number and tuner type of available VBox devices."));
1651 
1652  connect(this, SIGNAL(valueChanged(const QString&)),
1653  this, SLOT(UpdateDevices(const QString&)));
1654 };
1655 
1657 void VBoxDeviceIDList::fillSelections(const QString &cur)
1658 {
1659  clearSelections();
1660 
1661  vector<QString> devs;
1662  QMap<QString, bool> in_use;
1663 
1664  const QString& current = cur;
1665 
1666  VBoxDeviceList::iterator it = m_deviceList->begin();
1667  for (; it != m_deviceList->end(); ++it)
1668  {
1669  devs.push_back(it.key());
1670  in_use[it.key()] = (*it).inuse;
1671  }
1672 
1673  QString man_addr = VBoxDeviceIDList::tr("Manually Enter IP Address");
1674  QString sel = man_addr;
1675  devs.push_back(sel);
1676 
1677  vector<QString>::const_iterator it2 = devs.begin();
1678  for (; it2 != devs.end(); ++it2)
1679  sel = (current == *it2) ? *it2 : sel;
1680 
1681  QString usestr = QString(" -- ");
1682  usestr += QObject::tr("Warning: already in use");
1683 
1684  for (size_t i = 0; i < devs.size(); i++)
1685  {
1686  const QString dev = devs[i];
1687  QString desc = dev + (in_use[devs[i]] ? usestr : "");
1688  addSelection(desc, dev, dev == sel);
1689  }
1690 
1691  if (current != cur)
1692  {
1694  }
1695  else if (sel == man_addr && !current.isEmpty())
1696  {
1697  // Populate the proper values for IP address and tuner
1698  QStringList selection = current.split("-");
1699 
1700  m_cardIp->SetOldValue(selection.first());
1701  m_cardTuner->SetOldValue(selection.last());
1702 
1703  m_cardIp->setValue(selection.first());
1704  m_cardTuner->setValue(selection.last());
1705  }
1706 }
1707 
1709 {
1710  clearSelections();
1711 
1712  int cardid = m_parent.getCardID();
1713  QString device = CardUtil::GetVideoDevice(cardid);
1714  fillSelections(device);
1715 }
1716 
1717 void VBoxDeviceIDList::UpdateDevices(const QString &v)
1718 {
1719  if (v == VBoxDeviceIDList::tr("Manually Enter IP Address"))
1720  {
1721  m_cardIp->setEnabled(true);
1722  m_cardTuner->setEnabled(true);
1723  }
1724  else if (!v.isEmpty())
1725  {
1726  if (m_oldValue == VBoxDeviceIDList::tr("Manually Enter IP Address"))
1727  {
1728  m_cardIp->setEnabled(false);
1729  m_cardTuner->setEnabled(false);
1730  }
1731  m_deviceId->setValue(v);
1732 
1733  // Update _cardip and _cardtuner
1734  m_cardIp->setValue((*m_deviceList)[v].cardip);
1735  m_cardTuner->setValue(QString("%1").arg((*m_deviceList)[v].tunerno));
1736  m_desc->setValue((*m_deviceList)[v].desc);
1737  }
1738  m_oldValue = v;
1739 };
1740 
1741 // -----------------------
1742 // IPTV Configuration
1743 // -----------------------
1744 
1746 {
1747  public:
1748  explicit IPTVHost(const CaptureCard &parent) :
1749  CaptureCardTextEditSetting(parent, "videodevice")
1750  {
1751  setValue("http://mafreebox.freebox.fr/freeboxtv/playlist.m3u");
1752  setLabel(QObject::tr("M3U URL"));
1753  setHelpText(
1754  QObject::tr("URL of M3U containing RTSP/RTP/UDP channel URLs."));
1755  }
1756 };
1757 
1758 static void IPTVConfigurationGroup(CaptureCard& parent, CardType& cardType)
1759 {
1760  cardType.addTargetedChild("FREEBOX", new IPTVHost(parent));
1761  cardType.addTargetedChild("FREEBOX", new ChannelTimeout(parent, 30000, 1750));
1762  cardType.addTargetedChild("FREEBOX", new EmptyAudioDevice(parent));
1763  cardType.addTargetedChild("FREEBOX", new EmptyVBIDevice(parent));
1764 }
1765 
1767 {
1768  public:
1769  explicit ASIDevice(const CaptureCard &parent) :
1770  CaptureCardComboBoxSetting(parent, true, "videodevice")
1771  {
1772  setLabel(QObject::tr("ASI device"));
1773  fillSelections(QString());
1774  };
1775 
1779  void fillSelections(const QString &current)
1780  {
1781  clearSelections();
1782 
1783  // Get devices from filesystem
1784  QStringList sdevs = CardUtil::ProbeVideoDevices("ASI");
1785 
1786  // Add current if needed
1787  if (!current.isEmpty() &&
1788  (find(sdevs.begin(), sdevs.end(), current) == sdevs.end()))
1789  {
1790  stable_sort(sdevs.begin(), sdevs.end());
1791  }
1792 
1793  // Get devices from DB
1794  QStringList db = CardUtil::GetVideoDevices("ASI");
1795 
1796  // Figure out which physical devices are already in use
1797  // by another card defined in the DB, and select a device
1798  // for new configs (preferring non-conflicing devices).
1799  QMap<QString,bool> in_use;
1800  QString sel = current;
1801  for (uint i = 0; i < (uint)sdevs.size(); ++i)
1802  {
1803  const QString dev = sdevs[i];
1804  in_use[sdevs[i]] = find(db.begin(), db.end(), dev) != db.end();
1805  if (sel.isEmpty() && !in_use[sdevs[i]])
1806  sel = dev;
1807  }
1808 
1809  // Unfortunately all devices are conflicted, select first device.
1810  if (sel.isEmpty() && !sdevs.empty())
1811  sel = sdevs[0];
1812 
1813  QString usestr = QString(" -- ");
1814  usestr += QObject::tr("Warning: already in use");
1815 
1816  // Add the devices to the UI
1817  bool found = false;
1818  for (uint i = 0; i < (uint)sdevs.size(); ++i)
1819  {
1820  const QString dev = sdevs[i];
1821  QString desc = dev + (in_use[sdevs[i]] ? usestr : "");
1822  desc = (current == sdevs[i]) ? dev : desc;
1823  addSelection(desc, dev, dev == sel);
1824  found |= (dev == sel);
1825  }
1826 
1827  // If a configured device isn't on the list, add it with warning
1828  if (!found && !current.isEmpty())
1829  {
1830  QString desc = current + " -- " +
1831  QObject::tr("Warning: unable to open");
1832  addSelection(desc, current, true);
1833  }
1834  }
1835 
1836  void Load(void) override // StandardSetting
1837  {
1838  clearSelections();
1839  addSelection(QString());
1840  GetStorage()->Load();
1842  }
1843 };
1844 
1846  CardType &cardType):
1847  m_parent(a_parent),
1848  m_device(new ASIDevice(m_parent)),
1849  m_cardInfo(new TransTextEditSetting())
1850 {
1851  setVisible(false);
1852  m_cardInfo->setLabel(tr("Status"));
1853  m_cardInfo->setEnabled(false);
1854 
1855  cardType.addTargetedChild("ASI", m_device);
1856  cardType.addTargetedChild("ASI", new EmptyAudioDevice(m_parent));
1857  cardType.addTargetedChild("ASI", new EmptyVBIDevice(m_parent));
1858  cardType.addTargetedChild("ASI", m_cardInfo);
1859 
1860  connect(m_device, SIGNAL(valueChanged(const QString&)),
1861  this, SLOT( probeCard( const QString&)));
1862 
1864 };
1865 
1866 void ASIConfigurationGroup::probeCard(const QString &device)
1867 {
1868 #ifdef USING_ASI
1869  if (device.isEmpty())
1870  {
1871  m_cardInfo->setValue("");
1872  return;
1873  }
1874 
1875  if (m_parent.getCardID() && m_parent.GetRawCardType() != "ASI")
1876  {
1877  m_cardInfo->setValue("");
1878  return;
1879  }
1880 
1881  QString error;
1882  int device_num = CardUtil::GetASIDeviceNumber(device, &error);
1883  if (device_num < 0)
1884  {
1885  m_cardInfo->setValue(tr("Not a valid DVEO ASI card"));
1886  LOG(VB_GENERAL, LOG_WARNING,
1887  "ASIConfigurationGroup::probeCard(), Warning: " + error);
1888  return;
1889  }
1890  m_cardInfo->setValue(tr("Valid DVEO ASI card"));
1891 #else
1892  Q_UNUSED(device);
1893  m_cardInfo->setValue(QString("Not compiled with ASI support"));
1894 #endif
1895 }
1896 
1898  CardType& a_cardtype):
1899  m_parent(a_parent),
1900  m_info(new TransTextEditSetting()), m_size(new TransTextEditSetting())
1901 {
1902  setVisible(false);
1903  auto *device = new FileDevice(m_parent);
1904  device->setHelpText(tr("A local file used to simulate a recording."
1905  " Leave empty to use MythEvents to trigger an"
1906  " external program to import recording files."));
1907  a_cardtype.addTargetedChild("IMPORT", device);
1908 
1909  a_cardtype.addTargetedChild("IMPORT", new EmptyAudioDevice(m_parent));
1910  a_cardtype.addTargetedChild("IMPORT", new EmptyVBIDevice(m_parent));
1911 
1912  m_info->setLabel(tr("File info"));
1913  m_info->setEnabled(false);
1914  a_cardtype.addTargetedChild("IMPORT", m_info);
1915 
1916  m_size->setLabel(tr("File size"));
1917  m_size->setEnabled(false);
1918  a_cardtype.addTargetedChild("IMPORT", m_size);
1919 
1920  connect(device, SIGNAL(valueChanged(const QString&)),
1921  this, SLOT( probeCard( const QString&)));
1922 
1923  probeCard(device->getValue());
1924 };
1925 
1926 void ImportConfigurationGroup::probeCard(const QString &device)
1927 {
1928  QString ci;
1929  QString cs;
1930  QFileInfo fileInfo(device);
1931 
1932  // For convenience, ImportRecorder allows both formats:
1933  if (device.toLower().startsWith("file:"))
1934  fileInfo.setFile(device.mid(5));
1935 
1936  if (fileInfo.exists())
1937  {
1938  if (fileInfo.isReadable() && (fileInfo.isFile()))
1939  {
1940  ci = HTTPRequest::TestMimeType(fileInfo.absoluteFilePath());
1941  cs = tr("%1 MB").arg(fileInfo.size() / 1024 / 1024);
1942  }
1943  else
1944  ci = tr("File not readable");
1945  }
1946  else
1947  {
1948  ci = tr("File %1 does not exist").arg(device);
1949  }
1950 
1951  m_info->setValue(ci);
1952  m_size->setValue(cs);
1953 }
1954 
1955 // -----------------------
1956 // VBox Configuration
1957 // -----------------------
1958 
1960  (CaptureCard& a_parent, CardType& a_cardtype) :
1961  m_parent(a_parent)
1962 {
1963  setVisible(false);
1964 
1965  // Fill Device list
1966  FillDeviceList();
1967 
1968  m_deviceId = new VBoxDeviceID(m_parent);
1969  m_desc = new GroupSetting();
1970  m_desc->setLabel(tr("Description"));
1971  m_cardIp = new VBoxIP();
1972  m_cardTuner = new VBoxTunerIndex();
1973  m_deviceIdList = new VBoxDeviceIDList(
1974  m_deviceId, m_desc, m_cardIp, m_cardTuner, &m_deviceList, m_parent);
1975 
1976  a_cardtype.addTargetedChild("VBOX", m_deviceIdList);
1977  a_cardtype.addTargetedChild("VBOX", new EmptyAudioDevice(m_parent));
1978  a_cardtype.addTargetedChild("VBOX", new EmptyVBIDevice(m_parent));
1979  a_cardtype.addTargetedChild("VBOX", m_deviceId);
1980  a_cardtype.addTargetedChild("VBOX", m_desc);
1981  a_cardtype.addTargetedChild("VBOX", m_cardIp);
1982  a_cardtype.addTargetedChild("VBOX", m_cardTuner);
1983  a_cardtype.addTargetedChild("VBOX", new SignalTimeout(m_parent, 7000, 1000));
1984  a_cardtype.addTargetedChild("VBOX", new ChannelTimeout(m_parent, 10000, 1750));
1985 // TransButtonSetting *buttonRecOpt = new TransButtonSetting();
1986 // buttonRecOpt->setLabel(tr("Recording Options"));
1987 // addChild(buttonRecOpt);
1988 
1989 // connect(buttonRecOpt, SIGNAL(pressed()),
1990 // this, SLOT( VBoxExtraPanel()));
1991 
1992  connect(m_cardIp, SIGNAL(NewIP(const QString&)),
1993  m_deviceId, SLOT( SetIP(const QString&)));
1994  connect(m_cardTuner, SIGNAL(NewTuner(const QString&)),
1995  m_deviceId, SLOT( SetTuner(const QString&)));
1996 };
1997 
1999 {
2000  m_deviceList.clear();
2001 
2002  // Find physical devices first
2003  // ProbeVideoDevices returns "deviceid ip tunerno tunertype"
2004  QStringList devs = CardUtil::ProbeVideoDevices("VBOX");
2005 
2006  QStringList::const_iterator it;
2007 
2008  for (it = devs.begin(); it != devs.end(); ++it)
2009  {
2010  QString dev = *it;
2011  QStringList devinfo = dev.split(" ");
2012  const QString& id = devinfo.at(0);
2013  const QString& ip = devinfo.at(1);
2014  const QString& tunerNo = devinfo.at(2);
2015  const QString& tunerType = devinfo.at(3);
2016 
2017  VBoxDevice tmpdevice;
2018  tmpdevice.deviceid = id;
2019  tmpdevice.desc = CardUtil::GetVBoxdesc(id, ip, tunerNo, tunerType);
2020  tmpdevice.cardip = ip;
2021  tmpdevice.inuse = false;
2022  tmpdevice.discovered = true;
2023  tmpdevice.tunerno = tunerNo;
2024  tmpdevice.tunertype = tunerType;
2025  tmpdevice.mythdeviceid = id + "-" + tunerNo + "-" + tunerType;
2026  m_deviceList[tmpdevice.mythdeviceid] = tmpdevice;
2027  }
2028 
2029  // Now find configured devices
2030 
2031  // returns "ip.ip.ip.ip-n-type" or deviceid-n-type values
2032  QStringList db = CardUtil::GetVideoDevices("VBOX");
2033 
2034  for (it = db.begin(); it != db.end(); ++it)
2035  {
2036  QMap<QString, VBoxDevice>::iterator dit;
2037  dit = m_deviceList.find(*it);
2038 
2039  if (dit != m_deviceList.end())
2040  (*dit).inuse = true;
2041  }
2042 }
2043 
2044 // -----------------------
2045 // Ceton Configuration
2046 // -----------------------
2047 
2048 CetonSetting::CetonSetting(const char* label, const char* helptext)
2049 {
2050  setLabel(QObject::tr(label));
2051  setHelpText(tr(helptext));
2052  connect(this, SIGNAL(valueChanged( const QString&)),
2053  this, SLOT( UpdateDevices(const QString&)));
2054 }
2055 
2056 void CetonSetting::UpdateDevices(const QString &v)
2057 {
2058  if (isEnabled())
2059  emit NewValue(v);
2060 }
2061 
2062 void CetonSetting::LoadValue(const QString &value)
2063 {
2064  setValue(value);
2065 }
2066 
2068  MythUITextEditSetting(new CaptureCardDBStorage(this, parent, "videodevice")),
2069  m_parent(parent)
2070 {
2071  setLabel(tr("Device ID"));
2072  setHelpText(tr("Device ID of Ceton device"));
2073 }
2074 
2075 void CetonDeviceID::SetIP(const QString &ip)
2076 {
2077  QString regexp = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){4}$";
2078  if (QRegExp(regexp).exactMatch(ip + "."))
2079  {
2080  m_ip = ip;
2081  setValue(QString("%1-RTP.%3").arg(m_ip).arg(m_tuner));
2082  }
2083 }
2084 
2085 void CetonDeviceID::SetTuner(const QString &tuner)
2086 {
2087  if (QRegExp("^\\d$").exactMatch(tuner))
2088  {
2089  m_tuner = tuner;
2090  setValue(QString("%1-RTP.%2").arg(m_ip).arg(m_tuner));
2091  }
2092 }
2093 
2095 {
2096  GetStorage()->Load();
2097  UpdateValues();
2098 }
2099 
2101 {
2102  QRegExp newstyle("^([0-9.]+)-(\\d|RTP)\\.(\\d)$");
2103  if (newstyle.exactMatch(getValue()))
2104  {
2105  emit LoadedIP(newstyle.cap(1));
2106  emit LoadedTuner(newstyle.cap(3));
2107  }
2108 }
2109 
2110 #ifdef USING_CETON
2111 static void CetonConfigurationGroup(CaptureCard& parent, CardType& cardtype)
2112 {
2113  auto *deviceid = new CetonDeviceID(parent);
2114  auto *desc = new GroupSetting();
2115  desc->setLabel(QCoreApplication::translate("CetonConfigurationGroup",
2116  "Description"));
2117  auto *ip = new CetonSetting("IP Address",
2118  "IP Address of the Ceton device (192.168.200.1 by default)");
2119  auto *tuner = new CetonSetting("Tuner",
2120  "Number of the tuner on the Ceton device (first tuner is number 0)");
2121 
2122  cardtype.addTargetedChild("CETON", ip);
2123  cardtype.addTargetedChild("CETON", tuner);
2124  cardtype.addTargetedChild("CETON", deviceid);
2125  cardtype.addTargetedChild("CETON", desc);
2126  cardtype.addTargetedChild("CETON", new SignalTimeout(parent, 1000, 250));
2127  cardtype.addTargetedChild("CETON", new ChannelTimeout(parent, 3000, 1750));
2128 
2129  QObject::connect(ip, SIGNAL(NewValue(const QString&)),
2130  deviceid, SLOT( SetIP(const QString&)));
2131  QObject::connect(tuner, SIGNAL(NewValue(const QString&)),
2132  deviceid, SLOT( SetTuner(const QString&)));
2133 
2134  QObject::connect(deviceid, SIGNAL(LoadedIP(const QString&)),
2135  ip, SLOT( LoadValue(const QString&)));
2136  QObject::connect(deviceid, SIGNAL(LoadedTuner(const QString&)),
2137  tuner, SLOT( LoadValue(const QString&)));
2138 }
2139 #endif
2140 
2142  CardType& a_cardtype) :
2143  m_parent(a_parent),
2144  m_cardInfo(new TransTextEditSetting()), m_vbiDev(new VBIDevice(m_parent))
2145 {
2146  setVisible(false);
2147  QString drv = "(?!ivtv|hdpvr|(saa7164(.*))).*";
2148  auto *device = new VideoDevice(m_parent, 0, 15, QString(), drv);
2149 
2150  m_cardInfo->setLabel(tr("Probed info"));
2151  m_cardInfo->setEnabled(false);
2152 
2153  a_cardtype.addTargetedChild("V4L", device);
2154  a_cardtype.addTargetedChild("V4L", m_cardInfo);
2155  a_cardtype.addTargetedChild("V4L", m_vbiDev);
2156  a_cardtype.addTargetedChild("V4L", new AudioDevice(m_parent));
2157  a_cardtype.addTargetedChild("V4L", new AudioRateLimit(m_parent));
2158  a_cardtype.addTargetedChild("V4L", new SkipBtAudio(m_parent));
2159 
2160  connect(device, SIGNAL(valueChanged(const QString&)),
2161  this, SLOT( probeCard( const QString&)));
2162 
2163  probeCard(device->getValue());
2164 };
2165 
2166 void V4LConfigurationGroup::probeCard(const QString &device)
2167 {
2168  QString cn = tr("Failed to open");
2169  QString ci = cn;
2170  QString dn;
2171 
2172  QByteArray adevice = device.toLatin1();
2173  int videofd = open(adevice.constData(), O_RDWR);
2174  if (videofd >= 0)
2175  {
2176  if (!CardUtil::GetV4LInfo(videofd, cn, dn))
2177  ci = cn = tr("Failed to probe");
2178  else if (!dn.isEmpty())
2179  ci = cn + " [" + dn + "]";
2180  close(videofd);
2181  }
2182 
2183  m_cardInfo->setValue(ci);
2184  m_vbiDev->setFilter(cn, dn);
2185 }
2186 
2188  CardType &a_cardtype) :
2189  m_parent(a_parent),
2190  m_cardInfo(new TransTextEditSetting())
2191 {
2192  setVisible(false);
2193  QString drv = "ivtv|(saa7164(.*))";
2194  m_device = new VideoDevice(m_parent, 0, 15, QString(), drv);
2196  m_vbiDevice->setVisible(false);
2197 
2198  m_cardInfo->setLabel(tr("Probed info"));
2199  m_cardInfo->setEnabled(false);
2200 
2201  a_cardtype.addTargetedChild("MPEG", m_device);
2202  a_cardtype.addTargetedChild("MPEG", m_vbiDevice);
2203  a_cardtype.addTargetedChild("MPEG", m_cardInfo);
2204  a_cardtype.addTargetedChild("MPEG", new ChannelTimeout(m_parent, 12000, 2000));
2205 
2206  connect(m_device, SIGNAL(valueChanged(const QString&)),
2207  this, SLOT( probeCard( const QString&)));
2208 
2210 }
2211 
2212 void MPEGConfigurationGroup::probeCard(const QString &device)
2213 {
2214  QString cn = tr("Failed to open");
2215  QString ci = cn;
2216  QString dn;
2217 
2218  QByteArray adevice = device.toLatin1();
2219  int videofd = open(adevice.constData(), O_RDWR);
2220  if (videofd >= 0)
2221  {
2222  if (!CardUtil::GetV4LInfo(videofd, cn, dn))
2223  ci = cn = tr("Failed to probe");
2224  else if (!dn.isEmpty())
2225  ci = cn + " [" + dn + "]";
2226  close(videofd);
2227  }
2228 
2229  m_cardInfo->setValue(ci);
2230  m_vbiDevice->setVisible(dn!="ivtv");
2231  m_vbiDevice->setFilter(cn, dn);
2232 }
2233 
2235  CardType &a_cardtype) :
2236  m_parent(a_parent),
2237  m_info(new TransTextEditSetting()), m_size(new TransTextEditSetting())
2238 {
2239  setVisible(false);
2240  auto *device = new FileDevice(m_parent);
2241  device->setHelpText(tr("A local MPEG file used to simulate a recording."));
2242 
2243  a_cardtype.addTargetedChild("DEMO", device);
2244 
2245  a_cardtype.addTargetedChild("DEMO", new EmptyAudioDevice(m_parent));
2246  a_cardtype.addTargetedChild("DEMO", new EmptyVBIDevice(m_parent));
2247 
2248  m_info->setLabel(tr("File info"));
2249  m_info->setEnabled(false);
2250  a_cardtype.addTargetedChild("DEMO", m_info);
2251 
2252  m_size->setLabel(tr("File size"));
2253  m_size->setEnabled(false);
2254  a_cardtype.addTargetedChild("DEMO", m_size);
2255 
2256  connect(device, SIGNAL(valueChanged(const QString&)),
2257  this, SLOT( probeCard( const QString&)));
2258 
2259  probeCard(device->getValue());
2260 }
2261 
2262 void DemoConfigurationGroup::probeCard(const QString &device)
2263 {
2264  QString ci;
2265  QString cs;
2266  QFileInfo fileInfo(device.mid(5));
2267  if (fileInfo.exists())
2268  {
2269  if (fileInfo.isReadable() && (fileInfo.isFile()))
2270  {
2271  ci = HTTPRequest::TestMimeType(fileInfo.absoluteFilePath());
2272  cs = tr("%1 MB").arg(fileInfo.size() / 1024 / 1024);
2273  }
2274  else
2275  ci = tr("File not readable");
2276  }
2277  else
2278  {
2279  ci = tr("File does not exist");
2280  }
2281 
2282  m_info->setValue(ci);
2283  m_size->setValue(cs);
2284 }
2285 
2286 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
2287 ExternalConfigurationGroup::ExternalConfigurationGroup(CaptureCard &a_parent,
2288  CardType &a_cardtype) :
2289  m_parent(a_parent),
2290  m_info(new TransTextEditSetting())
2291 {
2292  setVisible(false);
2293  auto *device = new CommandPath(m_parent);
2294  device->setLabel(tr("Command path"));
2295  device->setHelpText(tr("A 'black box' application controlled via "
2296  "stdin, status on stderr and TransportStream "
2297  "read from stdout"));
2298  a_cardtype.addTargetedChild("EXTERNAL", device);
2299 
2300  m_info->setLabel(tr("File info"));
2301  m_info->setEnabled(false);
2302  a_cardtype.addTargetedChild("EXTERNAL", m_info);
2303 
2304  a_cardtype.addTargetedChild("EXTERNAL",
2305  new ChannelTimeout(m_parent, 20000, 1750));
2306 
2307  connect(device, SIGNAL(valueChanged(const QString&)),
2308  this, SLOT( probeApp( const QString&)));
2309 
2310  probeApp(device->getValue());
2311 }
2312 
2313 void ExternalConfigurationGroup::probeApp(const QString & path)
2314 {
2315  int idx1 = path.toLower().startsWith("file:") ? 5 : 0;
2316  int idx2 = path.indexOf(' ', idx1);
2317 
2318  QString ci;
2319  QString cs;
2320  QFileInfo fileInfo(path.mid(idx1, idx2 - idx1));
2321 
2322  if (fileInfo.exists())
2323  {
2324  ci = tr("'%1' is valid.").arg(fileInfo.absoluteFilePath());
2325  if (!fileInfo.isReadable() || !fileInfo.isFile())
2326  ci = tr("WARNING: '%1' is not readable.")
2327  .arg(fileInfo.absoluteFilePath());
2328  if (!fileInfo.isExecutable())
2329  ci = tr("WARNING: '%1' is not executable.")
2330  .arg(fileInfo.absoluteFilePath());
2331  }
2332  else
2333  {
2334  ci = tr("WARNING: '%1' does not exist.")
2335  .arg(fileInfo.absoluteFilePath());
2336  }
2337 
2338  m_info->setValue(ci);
2339 }
2340 #endif // !defined( USING_MINGW ) && !defined( _MSC_VER )
2341 
2343  CardType &a_cardtype) :
2344  m_parent(a_parent), m_cardInfo(new GroupSetting()),
2345  m_audioInput(new TunerCardAudioInput(m_parent, QString(), "HDPVR"))
2346 {
2347  setVisible(false);
2348 
2349  auto *device = new VideoDevice(m_parent, 0, 15, QString(), "hdpvr");
2350 
2351  m_cardInfo->setLabel(tr("Probed info"));
2352  m_cardInfo->setEnabled(false);
2353 
2354  a_cardtype.addTargetedChild("HDPVR", device);
2355  a_cardtype.addTargetedChild("HDPVR", new EmptyAudioDevice(m_parent));
2356  a_cardtype.addTargetedChild("HDPVR", new EmptyVBIDevice(m_parent));
2357  a_cardtype.addTargetedChild("HDPVR", m_cardInfo);
2358  a_cardtype.addTargetedChild("HDPVR", m_audioInput);
2359  a_cardtype.addTargetedChild("HDPVR", new ChannelTimeout(m_parent, 15000, 2000));
2360 
2361  connect(device, SIGNAL(valueChanged(const QString&)),
2362  this, SLOT( probeCard( const QString&)));
2363 
2364  probeCard(device->getValue());
2365 }
2366 
2367 void HDPVRConfigurationGroup::probeCard(const QString &device)
2368 {
2369  QString cn = tr("Failed to open");
2370  QString ci = cn;
2371  QString dn;
2372 
2373  int videofd = open(device.toLocal8Bit().constData(), O_RDWR);
2374  if (videofd >= 0)
2375  {
2376  if (!CardUtil::GetV4LInfo(videofd, cn, dn))
2377  ci = cn = tr("Failed to probe");
2378  else if (!dn.isEmpty())
2379  ci = cn + " [" + dn + "]";
2380  close(videofd);
2381  }
2382 
2383  m_cardInfo->setValue(ci);
2384  m_audioInput->fillSelections(device);
2385 }
2386 
2388  m_parent(parent),
2389  m_cardInfo(new TransTextEditSetting())
2390 {
2391  setLabel(QObject::tr("V4L2 encoder devices (multirec capable)"));
2392  m_device = new VideoDevice(m_parent, 0, 15);
2393 
2394  cardtype.addTargetedChild("V4L2ENC", m_device);
2395  m_cardInfo->setLabel(tr("Probed info"));
2396  cardtype.addTargetedChild("V4L2ENC", m_cardInfo);
2397 
2398  setVisible(false);
2399 
2400  connect(m_device, SIGNAL(valueChanged(const QString&)),
2401  this, SLOT( probeCard( const QString&)));
2402 
2403  const QString &device_name = m_device->getValue();
2404  if (!device_name.isEmpty())
2405  probeCard(device_name);
2406 }
2407 
2408 void V4L2encGroup::probeCard(const QString &device_name)
2409 {
2410 #ifdef USING_V4L2
2411  QString card_name = tr("Failed to open");
2412  QString card_info = card_name;
2413  V4L2util v4l2(device_name);
2414 
2415  if (!v4l2.IsOpen())
2416  {
2417  m_DriverName = tr("Failed to probe");
2418  return;
2419  }
2420  m_DriverName = v4l2.DriverName();
2421  card_name = v4l2.CardName();
2422 
2423  if (!m_DriverName.isEmpty())
2424  card_info = card_name + " [" + m_DriverName + "]";
2425 
2426  m_cardInfo->setValue(card_info);
2427 
2428  if (m_device->getSubSettings()->empty())
2429  {
2430  auto* audioinput = new TunerCardAudioInput(m_parent, QString(), "V4L2");
2431  if (audioinput->fillSelections(device_name) > 1)
2432  {
2433  audioinput->setName("AudioInput");
2434  m_device->addTargetedChild(m_DriverName, audioinput);
2435  }
2436  else
2437  delete audioinput;
2438 
2439  if (v4l2.HasSlicedVBI())
2440  {
2441  auto* vbidev = new VBIDevice(m_parent);
2442  if (vbidev->setFilter(card_name, m_DriverName) > 0)
2443  {
2444  vbidev->setName("VBIDevice");
2446  }
2447  else
2448  delete vbidev;
2449  }
2450 
2453  new ChannelTimeout(m_parent, 15000, 2000));
2454  }
2455 #else
2456  Q_UNUSED(device_name);
2457 #endif // USING_V4L2
2458 }
2459 
2461 {
2462  setLabel(QObject::tr("Capture Card Setup"));
2463 
2464  auto* cardtype = new CardType(parent);
2465  parent.addChild(cardtype);
2466 
2467 #ifdef USING_DVB
2468  cardtype->addTargetedChild("DVB",
2469  new DVBConfigurationGroup(parent, *cardtype));
2470 #endif // USING_DVB
2471 
2472 #ifdef USING_V4L2
2473 # ifdef USING_HDPVR
2474  cardtype->addTargetedChild("HDPVR",
2475  new HDPVRConfigurationGroup(parent, *cardtype));
2476 # endif // USING_HDPVR
2477 #endif // USING_V4L2
2478 
2479 #ifdef USING_HDHOMERUN
2480  cardtype->addTargetedChild("HDHOMERUN",
2481  new HDHomeRunConfigurationGroup(parent, *cardtype));
2482 #endif // USING_HDHOMERUN
2483 
2484 #ifdef USING_VBOX
2485  cardtype->addTargetedChild("VBOX",
2486  new VBoxConfigurationGroup(parent, *cardtype));
2487 #endif // USING_VBOX
2488 
2489 #ifdef USING_FIREWIRE
2490  FirewireConfigurationGroup(parent, *cardtype);
2491 #endif // USING_FIREWIRE
2492 
2493 #ifdef USING_CETON
2494  CetonConfigurationGroup(parent, *cardtype);
2495 #endif // USING_CETON
2496 
2497 #ifdef USING_IPTV
2498  IPTVConfigurationGroup(parent, *cardtype);
2499 #endif // USING_IPTV
2500 
2501 #ifdef USING_V4L2
2502  cardtype->addTargetedChild("V4L2ENC", new V4L2encGroup(parent, *cardtype));
2503  cardtype->addTargetedChild("V4L",
2504  new V4LConfigurationGroup(parent, *cardtype));
2505  cardtype->addTargetedChild("MJPEG",
2506  new V4LConfigurationGroup(parent, *cardtype));
2507  cardtype->addTargetedChild("GO7007",
2508  new V4LConfigurationGroup(parent, *cardtype));
2509 # ifdef USING_IVTV
2510  cardtype->addTargetedChild("MPEG",
2511  new MPEGConfigurationGroup(parent, *cardtype));
2512 # endif // USING_IVTV
2513 #endif // USING_V4L2
2514 
2515 #ifdef USING_ASI
2516  cardtype->addTargetedChild("ASI",
2517  new ASIConfigurationGroup(parent, *cardtype));
2518 #endif // USING_ASI
2519 
2520  // for testing without any actual tuner hardware:
2521  cardtype->addTargetedChild("IMPORT",
2522  new ImportConfigurationGroup(parent, *cardtype));
2523  cardtype->addTargetedChild("DEMO",
2524  new DemoConfigurationGroup(parent, *cardtype));
2525 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
2526  cardtype->addTargetedChild("EXTERNAL",
2527  new ExternalConfigurationGroup(parent,
2528  *cardtype));
2529 #endif
2530 }
2531 
2532 CaptureCard::CaptureCard(bool use_card_group)
2533  : m_id(new ID)
2534 {
2535  addChild(m_id);
2536  if (use_card_group)
2537  CaptureCardGroup(*this);
2538  addChild(new Hostname(*this));
2539 }
2540 
2541 QString CaptureCard::GetRawCardType(void) const
2542 {
2543  int cardid = getCardID();
2544  if (cardid <= 0)
2545  return QString();
2546  return CardUtil::GetRawInputType(cardid);
2547 }
2548 
2550 {
2551  MSqlQuery query(MSqlQuery::InitCon());
2552  QString qstr =
2553  "SELECT cardid, videodevice, cardtype "
2554  "FROM capturecard "
2555  "WHERE hostname = :HOSTNAME AND parentid = 0 "
2556  "ORDER BY cardid";
2557 
2558  query.prepare(qstr);
2559  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
2560 
2561  if (!query.exec())
2562  {
2563  MythDB::DBError("CaptureCard::fillSelections", query);
2564  return;
2565  }
2566 
2568 
2569  while (query.next())
2570  {
2571  uint cardid = query.value(0).toUInt();
2572  QString videodevice = query.value(1).toString();
2573  QString cardtype = query.value(2).toString();
2574 
2575  QString label = CardUtil::GetDeviceLabel(cardtype, videodevice);
2576  auto *card = new CaptureCard();
2577  card->loadByID(cardid);
2578  card->setLabel(label);
2579  setting->addChild(card);
2580  }
2581 }
2582 
2583 void CaptureCard::loadByID(int cardid)
2584 {
2585  m_id->setValue(cardid);
2586  Load();
2587 }
2588 
2590 {
2591  return true;
2592 }
2593 
2595 {
2597 }
2598 
2599 
2601 {
2602  uint init_cardid = getCardID();
2603  QString init_dev = CardUtil::GetVideoDevice(init_cardid);
2604 
2606 
2608 
2610 
2611  uint cardid = getCardID();
2612  QString type = CardUtil::GetRawInputType(cardid);
2613  QString dev = CardUtil::GetVideoDevice(cardid);
2614 
2615  if (dev != init_dev)
2616  {
2617  if (!init_dev.isEmpty())
2618  {
2619  uint init_groupid = CardUtil::GetDeviceInputGroup(init_cardid);
2620  CardUtil::UnlinkInputGroup(init_cardid, init_groupid);
2621  }
2622  if (!dev.isEmpty())
2623  {
2624  uint groupid =
2626  gCoreContext->GetHostName(), dev);
2627  CardUtil::LinkInputGroup(cardid, groupid);
2628  CardUtil::UnlinkInputGroup(0, groupid);
2629  }
2630  }
2631 
2632  // Handle any cloning we may need to do
2634  {
2635  vector<uint> clones = CardUtil::GetChildInputIDs(cardid);
2636  for (size_t i = 0; i < clones.size(); i++)
2637  CardUtil::CloneCard(cardid, clones[i]);
2638  }
2639 }
2640 
2642 {
2643  if (getCardID() == 0)
2644  {
2645  Save();
2646  Load();
2647  }
2648 }
2649 
2651  CaptureCardComboBoxSetting(parent, false, "cardtype")
2652 {
2653  setLabel(QObject::tr("Card type"));
2654  setHelpText(QObject::tr("Change the cardtype to the appropriate type for "
2655  "the capture card you are configuring."));
2656  fillSelections(this);
2657 }
2658 
2660 {
2661 #ifdef USING_DVB
2662  setting->addSelection(
2663  QObject::tr("DVB-T/S/C, ATSC or ISDB-T tuner card"), "DVB");
2664 #endif // USING_DVB
2665 
2666 #ifdef USING_V4L2
2667  setting->addSelection(
2668  QObject::tr("V4L2 encoder"), "V4L2ENC");
2669 #ifdef USING_HDPVR
2670  setting->addSelection(
2671  QObject::tr("HD-PVR H.264 encoder"), "HDPVR");
2672 # endif // USING_HDPVR
2673 #endif // USING_V4L2
2674 
2675 #ifdef USING_HDHOMERUN
2676  setting->addSelection(
2677  QObject::tr("HDHomeRun networked tuner"), "HDHOMERUN");
2678 #endif // USING_HDHOMERUN
2679 
2680 #ifdef USING_VBOX
2681  setting->addSelection(
2682  QObject::tr("V@Box TV Gateway networked tuner"), "VBOX");
2683 #endif // USING_VBOX
2684 
2685 #ifdef USING_FIREWIRE
2686  setting->addSelection(
2687  QObject::tr("FireWire cable box"), "FIREWIRE");
2688 #endif // USING_FIREWIRE
2689 
2690 #ifdef USING_CETON
2691  setting->addSelection(
2692  QObject::tr("Ceton Cablecard tuner"), "CETON");
2693 #endif // USING_CETON
2694 
2695 #ifdef USING_IPTV
2696  setting->addSelection(QObject::tr("IPTV recorder"), "FREEBOX");
2697 #endif // USING_IPTV
2698 
2699 #ifdef USING_V4L2
2700 # ifdef USING_IVTV
2701  setting->addSelection(
2702  QObject::tr("Analog to MPEG-2 encoder card (PVR-150/250/350, etc)"), "MPEG");
2703 # endif // USING_IVTV
2704  setting->addSelection(
2705  QObject::tr("Analog to MJPEG encoder card (Matrox G200, DC10, etc)"), "MJPEG");
2706  setting->addSelection(
2707  QObject::tr("Analog to MPEG-4 encoder (Plextor ConvertX USB, etc)"),
2708  "GO7007");
2709  setting->addSelection(
2710  QObject::tr("Analog capture card"), "V4L");
2711 #endif // USING_V4L2
2712 
2713 #ifdef USING_ASI
2714  setting->addSelection(QObject::tr("DVEO ASI recorder"), "ASI");
2715 #endif
2716 
2717  setting->addSelection(QObject::tr("Import test recorder"), "IMPORT");
2718  setting->addSelection(QObject::tr("Demo test recorder"), "DEMO");
2719 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
2720  setting->addSelection(QObject::tr("External (black box) recorder"),
2721  "EXTERNAL");
2722 #endif
2723 }
2724 
2726 {
2727  public:
2728  explicit InputName(const CardInput &parent) :
2729  MythUIComboBoxSetting(new CardInputDBStorage(this, parent, "inputname"))
2730  {
2731  setLabel(QObject::tr("Input name"));
2732  };
2733 
2734  void Load(void) override // StandardSetting
2735  {
2736  fillSelections();
2738  };
2739 
2741  clearSelections();
2742  addSelection(QObject::tr("(None)"), "None");
2743  auto *storage = dynamic_cast<CardInputDBStorage*>(GetStorage());
2744  if (storage == nullptr)
2745  return;
2746  uint cardid = storage->getInputID();
2747  QString type = CardUtil::GetRawInputType(cardid);
2748  QString device = CardUtil::GetVideoDevice(cardid);
2749  QStringList inputs;
2750  CardUtil::GetDeviceInputNames(device, type, inputs);
2751  while (!inputs.isEmpty())
2752  {
2753  addSelection(inputs.front());
2754  inputs.pop_front();
2755  }
2756  };
2757 };
2758 
2760 {
2761  public:
2763  {
2764  setLabel(QObject::tr("Delivery system"));
2765  setHelpText(QObject::tr(
2766  "This shows the delivery system (modulation), for instance DVB-T2, "
2767  "that you have selected when you configured the capture card. "
2768  "This must be the same as the modulation used by the video source. "));
2769  };
2770 };
2771 
2773 {
2774  public:
2775  explicit InputDisplayName(const CardInput &parent) :
2776  MythUITextEditSetting(new CardInputDBStorage(this, parent, "displayname")), m_parent(parent)
2777  {
2778  setLabel(QObject::tr("Display name"));
2779  setHelpText(QObject::tr(
2780  "This name is displayed on screen when Live TV begins "
2781  "and in various other places. Make sure the last two "
2782  "characters are unique for each input."));
2783  };
2784  void Load(void) override {
2786  if (getValue().isEmpty())
2787  setValue(tr("Input %1").arg(m_parent.getInputID()));
2788  }
2789  private:
2791 };
2792 
2794 {
2795  public:
2796  CardInputComboBoxSetting(const CardInput &parent, const QString &setting) :
2797  MythUIComboBoxSetting(new CardInputDBStorage(this, parent, setting))
2798  {
2799  }
2800 };
2801 
2803 {
2804  public:
2805  explicit SourceID(const CardInput &parent) :
2806  CardInputComboBoxSetting(parent, "sourceid")
2807  {
2808  setLabel(QObject::tr("Video source"));
2809  addSelection(QObject::tr("(None)"), "0");
2810  };
2811 
2812  void Load(void) override // StandardSetting
2813  {
2814  fillSelections();
2816  };
2817 
2819  clearSelections();
2820  addSelection(QObject::tr("(None)"), "0");
2822  };
2823 };
2824 
2826 {
2827  public:
2828  InputGroup(const CardInput &parent, uint group_num) :
2829  m_cardInput(parent),
2830  m_groupNum(group_num)
2831  {
2832  setLabel(QObject::tr("Input group") +
2833  QString(" %1").arg(m_groupNum + 1));
2834  setHelpText(QObject::tr(
2835  "Leave as 'Generic' unless this input is shared with "
2836  "another device. Only one of the inputs in an input "
2837  "group will be allowed to record at any given time."));
2838  }
2839 
2840  void Load(void) override; // StandardSetting
2841 
2842  void Save(void) override // StandardSetting
2843  {
2844  uint inputid = m_cardInput.getInputID();
2845  uint new_groupid = getValue().toUInt();
2846 
2847  if (m_groupId)
2849 
2850  if (new_groupid)
2851  {
2852  if (CardUtil::UnlinkInputGroup(inputid, new_groupid))
2853  CardUtil::LinkInputGroup(inputid, new_groupid);
2854  }
2855  }
2856 
2857  virtual void Save(const QString& /*destination*/) { Save(); }
2858 
2859  private:
2863 };
2864 
2866 {
2867 #if 0
2868  LOG(VB_GENERAL, LOG_DEBUG, QString("InputGroup::Load() %1 %2")
2869  .arg(m_groupNum).arg(m_cardInput.getInputID()));
2870 #endif
2871 
2872  uint inputid = m_cardInput.getInputID();
2873  QMap<uint, uint> grpcnt;
2874  vector<QString> names;
2875  vector<uint> grpid;
2876  vector<uint> selected_groupids;
2877 
2878  names.push_back(QObject::tr("Generic"));
2879  grpid.push_back(0);
2880  grpcnt[0]++;
2881 
2882  MSqlQuery query(MSqlQuery::InitCon());
2883  query.prepare(
2884  "SELECT cardinputid, inputgroupid, inputgroupname "
2885  "FROM inputgroup "
2886  "WHERE inputgroupname LIKE 'user:%' "
2887  "ORDER BY inputgroupid, cardinputid, inputgroupname");
2888 
2889  if (!query.exec())
2890  {
2891  MythDB::DBError("InputGroup::Load()", query);
2892  }
2893  else
2894  {
2895  while (query.next())
2896  {
2897  uint groupid = query.value(1).toUInt();
2898  if (inputid && (query.value(0).toUInt() == inputid))
2899  selected_groupids.push_back(groupid);
2900 
2901  grpcnt[groupid]++;
2902 
2903  if (grpcnt[groupid] == 1)
2904  {
2905  names.push_back(query.value(2).toString().mid(5, -1));
2906  grpid.push_back(groupid);
2907  }
2908  }
2909  }
2910 
2911  // makes sure we select something
2912  m_groupId = 0;
2913  if (m_groupNum < selected_groupids.size())
2914  m_groupId = selected_groupids[m_groupNum];
2915 
2916 #if 0
2917  LOG(VB_GENERAL, LOG_DEBUG, QString("Group num: %1 id: %2")
2918  .arg(m_groupNum).arg(m_groupId));
2919  {
2920  QString msg;
2921  for (uint i = 0; i < selected_groupids.size(); i++)
2922  msg += QString("%1 ").arg(selected_groupids[i]);
2923  LOG(VB_GENERAL, LOG_DEBUG, msg);
2924  }
2925 #endif
2926 
2927  // add selections to combobox
2928  clearSelections();
2929  uint index = 0;
2930  for (size_t i = 0; i < names.size(); i++)
2931  {
2932  bool sel = (m_groupId == grpid[i]);
2933  index = (sel) ? i : index;
2934 
2935 #if 0
2936  LOG(VB_GENERAL, LOG_DEBUG, QString("grpid %1, name '%2', i %3, s %4")
2937  .arg(grpid[i]).arg(names[i]) .arg(index).arg(sel ? "T" : "F"));
2938 #endif
2939 
2940  addSelection(names[i], QString::number(grpid[i]), sel);
2941  }
2942 
2943 #if 0
2944  LOG(VB_GENERAL, LOG_DEBUG, QString("Group index: %1").arg(index));
2945 #endif
2946 
2947  if (!names.empty())
2948  setValue(index);
2949 
2951 }
2952 
2954 {
2955  public:
2956  explicit QuickTune(const CardInput &parent) :
2957  CardInputComboBoxSetting(parent, "quicktune")
2958  {
2959  setLabel(QObject::tr("Use quick tuning"));
2960  addSelection(QObject::tr("Never"), "0", true);
2961  addSelection(QObject::tr("Live TV only"), "1", false);
2962  addSelection(QObject::tr("Always"), "2", false);
2963  setHelpText(QObject::tr(
2964  "If enabled, MythTV will tune using only the "
2965  "MPEG program number. The program numbers "
2966  "change more often than DVB or ATSC tuning "
2967  "parameters, so this is slightly less reliable. "
2968  "This will also inhibit EIT gathering during "
2969  "Live TV and recording."));
2970  };
2971 };
2972 
2974 {
2975  public:
2976  explicit ExternalChannelCommand(const CardInput &parent) :
2977  MythUITextEditSetting(new CardInputDBStorage(this, parent, "externalcommand"))
2978  {
2979  setLabel(QObject::tr("External channel change command"));
2980  setValue("");
2981  setHelpText(QObject::tr("If specified, this command will be run to "
2982  "change the channel for inputs which have an external "
2983  "tuner device such as a cable box. The first argument "
2984  "will be the channel number."));
2985  };
2986 };
2987 
2989 {
2990  public:
2991  explicit PresetTuner(const CardInput &parent) :
2992  MythUITextEditSetting(new CardInputDBStorage(this, parent, "tunechan"))
2993  {
2994  setLabel(QObject::tr("Preset tuner to channel"));
2995  setValue("");
2996  setHelpText(QObject::tr("Leave this blank unless you have an external "
2997  "tuner that is connected to the tuner input of your card. "
2998  "If so, you will need to specify the preset channel for "
2999  "the signal (normally 3 or 4)."));
3000  };
3001 };
3002 
3003 void StartingChannel::SetSourceID(const QString &sourceid)
3004 {
3005  clearSelections();
3006  if (sourceid.isEmpty() || !sourceid.toUInt())
3007  return;
3008 
3009  // Get the existing starting channel
3010  auto *storage = dynamic_cast<CardInputDBStorage*>(GetStorage());
3011  if (storage == nullptr)
3012  return;
3013  int inputId = storage->getInputID();
3014  QString startChan = CardUtil::GetStartingChannel(inputId);
3015 
3016  ChannelInfoList channels = ChannelUtil::GetAllChannels(sourceid.toUInt());
3017 
3018  if (channels.empty())
3019  {
3020  addSelection(tr("Please add channels to this source"),
3021  startChan.isEmpty() ? "0" : startChan);
3022  return;
3023  }
3024 
3025  // If there are channels sort them, then add theme
3026  // (selecting the old start channel if it is there).
3027  QString order = gCoreContext->GetSetting("ChannelOrdering", "channum");
3028  ChannelUtil::SortChannels(channels, order);
3029  bool has_visible = false;
3030  for (size_t i = 0; i < channels.size() && !has_visible; i++)
3031  has_visible |= channels[i].m_visible;
3032 
3033  for (size_t i = 0; i < channels.size(); i++)
3034  {
3035  const QString channum = channels[i].m_channum;
3036  bool sel = channum == startChan;
3037  if (!has_visible || channels[i].m_visible || sel)
3038  {
3039  addSelection(channum, channum, sel);
3040  }
3041  }
3042 }
3043 
3045 {
3046  public:
3047  explicit InputPriority(const CardInput &parent) :
3048  MythUISpinBoxSetting(new CardInputDBStorage(this, parent, "recpriority"),
3049  -99, 99, 1)
3050  {
3051  setLabel(QObject::tr("Input priority"));
3052  setValue(0);
3053  setHelpText(QObject::tr("If the input priority is not equal for "
3054  "all inputs, the scheduler may choose to record a show "
3055  "at a later time so that it can record on an input with "
3056  "a higher value."));
3057  };
3058 };
3059 
3061 {
3062  public:
3063  ScheduleOrder(const CardInput &parent, int _value) :
3064  MythUISpinBoxSetting(new CardInputDBStorage(this, parent, "schedorder"),
3065  0, 99, 1)
3066  {
3067  setLabel(QObject::tr("Schedule order"));
3068  setValue(_value);
3069  setHelpText(QObject::tr("If priorities and other factors are equal "
3070  "the scheduler will choose the available "
3071  "input with the lowest, non-zero value. "
3072  "Setting this value to zero will make the "
3073  "input unavailable to the scheduler."));
3074  };
3075 };
3076 
3078 {
3079  public:
3080  LiveTVOrder(const CardInput &parent, int _value) :
3081  MythUISpinBoxSetting(new CardInputDBStorage(this, parent, "livetvorder"),
3082  0, 99, 1)
3083  {
3084  setLabel(QObject::tr("Live TV order"));
3085  setValue(_value);
3086  setHelpText(QObject::tr("When entering Live TV, the available, local "
3087  "input with the lowest, non-zero value will "
3088  "be used. If no local inputs are available, "
3089  "the available, remote input with the lowest, "
3090  "non-zero value will be used. "
3091  "Setting this value to zero will make the "
3092  "input unavailable to live TV."));
3093  };
3094 };
3095 
3097 {
3098  public:
3099  explicit DishNetEIT(const CardInput &parent) :
3100  MythUICheckBoxSetting(new CardInputDBStorage(this, parent,
3101  "dishnet_eit"))
3102  {
3103  setLabel(QObject::tr("Use DishNet long-term EIT data"));
3104  setValue(false);
3105  setHelpText(
3106  QObject::tr(
3107  "If you point your satellite dish toward DishNet's birds, "
3108  "you may wish to enable this feature. For best results, "
3109  "enable general EIT collection as well."));
3110  };
3111 };
3112 
3113 CardInput::CardInput(const QString & cardtype, const QString & device,
3114  int _cardid) :
3115  m_id(new ID()),
3116  m_inputName(new InputName(*this)),
3117  m_sourceId(new SourceID(*this)),
3118  m_startChan(new StartingChannel(*this)),
3119  m_scan(new ButtonStandardSetting(tr("Scan for channels"))),
3120  m_srcFetch(new ButtonStandardSetting(tr("Fetch channels from listings source"))),
3121  m_externalInputSettings(new DiSEqCDevSettings()),
3122  m_inputGrp0(new InputGroup(*this, 0)),
3123  m_inputGrp1(new InputGroup(*this, 1))
3124 {
3125  addChild(m_id);
3126 
3128  {
3130  _cardid, true));
3131  }
3132 
3133  // Delivery system for DVB, input name for other,
3134  // same field capturecard/inputname for both
3135  if ("DVB" == cardtype)
3136  {
3137  auto *ds = new DeliverySystem();
3138  ds->setValue(CardUtil::GetDeliverySystemFromDB(_cardid));
3139  addChild(ds);
3140  }
3141  else
3142  {
3144  }
3145  addChild(new InputDisplayName(*this));
3147 
3148  if (CardUtil::IsEncoder(cardtype) || CardUtil::IsUnscanable(cardtype))
3149  {
3150  addChild(new ExternalChannelCommand(*this));
3151  if (CardUtil::HasTuner(cardtype, device))
3152  addChild(new PresetTuner(*this));
3153  }
3154  else
3155  {
3156  addChild(new QuickTune(*this));
3157  if ("DVB" == cardtype)
3158  addChild(new DishNetEIT(*this));
3159  }
3160 
3162  tr("Use channel scanner to find channels for this input."));
3163 
3165  tr("This uses the listings data source to "
3166  "provide the channels for this input.") + " " +
3167  tr("This can take a long time to run."));
3168 
3169  addChild(m_scan);
3171 
3173 
3174  auto *interact = new GroupSetting();
3175 
3176  interact->setLabel(QObject::tr("Interactions between inputs"));
3177  if (CardUtil::IsTunerSharingCapable(cardtype))
3178  {
3179  m_instanceCount = new InstanceCount(*this);
3180  interact->addChild(m_instanceCount);
3181  m_schedGroup = new SchedGroup(*this);
3182  interact->addChild(m_schedGroup);
3183  }
3184  interact->addChild(new InputPriority(*this));
3185  interact->addChild(new ScheduleOrder(*this, _cardid));
3186  interact->addChild(new LiveTVOrder(*this, _cardid));
3187 
3188  auto *ingrpbtn =
3189  new ButtonStandardSetting(QObject::tr("Create a New Input Group"));
3190  ingrpbtn->setHelpText(
3191  QObject::tr("Input groups are only needed when two or more cards "
3192  "share the same resource such as a FireWire card and "
3193  "an analog card input controlling the same set top box."));
3194  interact->addChild(ingrpbtn);
3195  interact->addChild(m_inputGrp0);
3196  interact->addChild(m_inputGrp1);
3197 
3198  addChild(interact);
3199 
3200  setObjectName("CardInput");
3201  SetSourceID("-1");
3202 
3203  connect(m_scan, SIGNAL(clicked()), SLOT(channelScanner()));
3204  connect(m_srcFetch, SIGNAL(clicked()), SLOT(sourceFetch()));
3205  connect(m_sourceId, SIGNAL(valueChanged(const QString&)),
3206  m_startChan,SLOT( SetSourceID (const QString&)));
3207  connect(m_sourceId, SIGNAL(valueChanged(const QString&)),
3208  this, SLOT( SetSourceID (const QString&)));
3209  connect(ingrpbtn, SIGNAL(clicked()),
3210  this, SLOT( CreateNewInputGroup()));
3211 }
3212 
3214 {
3216  {
3217  delete m_externalInputSettings;
3218  m_externalInputSettings = nullptr;
3219  }
3220 }
3221 
3222 void CardInput::SetSourceID(const QString &sourceid)
3223 {
3224  uint cid = m_id->getValue().toUInt();
3225  QString raw_card_type = CardUtil::GetRawInputType(cid);
3226  bool enable = (sourceid.toInt() > 0);
3227  m_scan->setEnabled(enable && !raw_card_type.isEmpty() &&
3228  !CardUtil::IsUnscanable(raw_card_type));
3229  m_srcFetch->setEnabled(enable);
3230 }
3231 
3232 QString CardInput::getSourceName(void) const
3233 {
3234  return m_sourceId->getValueLabel();
3235 }
3236 
3238 {
3239  m_inputGrp0->Save();
3240  m_inputGrp1->Save();
3241 
3242  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
3243  auto *settingdialog =
3244  new MythTextInputDialog(popupStack, tr("Enter new group name"));
3245 
3246  if (settingdialog->Create())
3247  {
3248  connect(settingdialog, SIGNAL(haveResult(QString)),
3249  SLOT(CreateNewInputGroupSlot(const QString&)));
3250  popupStack->AddScreen(settingdialog);
3251  }
3252  else
3253  delete settingdialog;
3254 }
3255 
3256 void CardInput::CreateNewInputGroupSlot(const QString& name)
3257 {
3258  if (name.isEmpty())
3259  {
3260  ShowOkPopup(tr("Sorry, this Input Group name cannot be blank."));
3261  return;
3262  }
3263 
3264  QString new_name = QString("user:") + name;
3265 
3266  MSqlQuery query(MSqlQuery::InitCon());
3267  query.prepare("SELECT inputgroupname "
3268  "FROM inputgroup "
3269  "WHERE inputgroupname = :GROUPNAME");
3270  query.bindValue(":GROUPNAME", new_name);
3271 
3272  if (!query.exec())
3273  {
3274  MythDB::DBError("CreateNewInputGroup 1", query);
3275  return;
3276  }
3277 
3278  if (query.next())
3279  {
3280  ShowOkPopup(tr("Sorry, this Input Group name is already in use."));
3281  return;
3282  }
3283 
3284  uint inputgroupid = CardUtil::CreateInputGroup(new_name);
3285 
3286  m_inputGrp0->Load();
3287  m_inputGrp1->Load();
3288 
3289  if (m_inputGrp0->getValue().toUInt() == 0U)
3290  {
3292  m_inputGrp0->getValueIndex(QString::number(inputgroupid)));
3293  }
3294  else
3295  {
3297  m_inputGrp1->getValueIndex(QString::number(inputgroupid)));
3298  }
3299 }
3300 
3302 {
3303  uint srcid = m_sourceId->getValue().toUInt();
3304  uint crdid = m_id->getValue().toUInt();
3305  QString in = m_inputName->getValue();
3306 
3307 #ifdef USING_BACKEND
3308  uint num_channels_before = SourceUtil::GetChannelCount(srcid);
3309 
3310  Save(); // save info for scanner.
3311 
3312  QString cardtype = CardUtil::GetRawInputType(crdid);
3313  if (CardUtil::IsUnscanable(cardtype))
3314  {
3315  LOG(VB_GENERAL, LOG_ERR,
3316  QString("Sorry, %1 cards do not yet support scanning.")
3317  .arg(cardtype));
3318  return;
3319  }
3320 
3322  auto *ssd = new StandardSettingDialog(mainStack, "generalsettings",
3323  new ScanWizard(srcid, crdid, in));
3324 
3325  if (ssd->Create())
3326  {
3327  connect(ssd, &StandardSettingDialog::Exiting,
3328  [=]()
3329  {
3330  if (SourceUtil::GetChannelCount(srcid))
3331  m_startChan->SetSourceID(QString::number(srcid));
3332  if (num_channels_before)
3333  {
3334  m_startChan->Load();
3335  m_startChan->Save();
3336  }
3337  });
3338  mainStack->AddScreen(ssd);
3339  }
3340  else
3341  delete ssd;
3342 
3343 #else
3344  LOG(VB_GENERAL, LOG_ERR, "You must compile the backend "
3345  "to be able to scan for channels");
3346 #endif
3347 }
3348 
3350 {
3351  uint srcid = m_sourceId->getValue().toUInt();
3352  uint crdid = m_id->getValue().toUInt();
3353 
3354  uint num_channels_before = SourceUtil::GetChannelCount(srcid);
3355 
3356  if (crdid && srcid)
3357  {
3358  Save(); // save info for fetch..
3359 
3360  QString cardtype = CardUtil::GetRawInputType(crdid);
3361 
3362  if (!CardUtil::IsCableCardPresent(crdid, cardtype) &&
3363  !CardUtil::IsUnscanable(cardtype) &&
3364  !CardUtil::IsEncoder(cardtype) &&
3365  cardtype != "HDHOMERUN" &&
3366  !num_channels_before)
3367  {
3368  LOG(VB_GENERAL, LOG_ERR, "Skipping channel fetch, you need to "
3369  "scan for channels first.");
3370  return;
3371  }
3372 
3373  SourceUtil::UpdateChannelsFromListings(srcid, cardtype);
3374  }
3375 
3376  if (SourceUtil::GetChannelCount(srcid))
3377  m_startChan->SetSourceID(QString::number(srcid));
3378  if (num_channels_before)
3379  {
3380  m_startChan->Load();
3381  m_startChan->Save();
3382  }
3383 }
3384 
3386 {
3387  QString cardinputidTag(":WHERECARDID");
3388 
3389  QString query("cardid = " + cardinputidTag);
3390 
3391  bindings.insert(cardinputidTag, m_parent.getInputID());
3392 
3393  return query;
3394 }
3395 
3397 {
3398  QString cardinputidTag(":SETCARDID");
3399  QString colTag(":SET" + GetColumnName().toUpper());
3400 
3401  QString query("cardid = " + cardinputidTag + ", " +
3402  GetColumnName() + " = " + colTag);
3403 
3404  bindings.insert(cardinputidTag, m_parent.getInputID());
3405  bindings.insert(colTag, m_user->GetDBValue());
3406 
3407  return query;
3408 }
3409 
3410 void CardInput::loadByID(int inputid)
3411 {
3412  m_id->setValue(inputid);
3413  m_externalInputSettings->Load(inputid);
3415 }
3416 
3417 void CardInput::loadByInput(int _cardid, const QString& _inputname)
3418 {
3419  MSqlQuery query(MSqlQuery::InitCon());
3420  query.prepare("SELECT cardid FROM capturecard "
3421  "WHERE cardid = :CARDID AND inputname = :INPUTNAME");
3422  query.bindValue(":CARDID", _cardid);
3423  query.bindValue(":INPUTNAME", _inputname);
3424 
3425  if (query.exec() && query.isActive() && query.next())
3426  {
3427  loadByID(query.value(0).toInt());
3428  }
3429 }
3430 
3432 {
3433  uint cardid = m_id->getValue().toUInt();
3436 
3437  uint icount = 1;
3438  if (m_instanceCount)
3439  icount = m_instanceCount->getValue().toUInt();
3440  vector<uint> cardids = CardUtil::GetChildInputIDs(cardid);
3441 
3442  // Delete old clone cards as required.
3443  for (size_t i = cardids.size() + 1;
3444  (i > icount) && !cardids.empty(); --i)
3445  {
3446  CardUtil::DeleteInput(cardids.back());
3447  cardids.pop_back();
3448  }
3449 
3450  // Clone this config to existing clone cards.
3451  for (size_t i = 0; i < cardids.size(); ++i)
3452  {
3453  CardUtil::CloneCard(cardid, cardids[i]);
3454  }
3455 
3456  // Create new clone cards as required.
3457  for (size_t i = cardids.size() + 1; i < icount; i++)
3458  {
3459  CardUtil::CloneCard(cardid, 0);
3460  }
3461 
3462  // Delete any unused input groups
3464 }
3465 
3467 {
3468  return m_parent.getInputID();
3469 }
3470 
3472 {
3473  return m_parent.getCardID();
3474 }
3475 
3477 {
3478  emit Clicked(m_value);
3479 }
3480 
3481 void CaptureCardEditor::AddSelection(const QString &label, const char *slot)
3482 {
3483  auto *button = new ButtonStandardSetting(label);
3484  connect(button, SIGNAL(clicked()), slot);
3485  addChild(button);
3486 }
3487 
3489 {
3490  ShowOkPopup(
3491  tr("Are you sure you want to delete "
3492  "ALL capture cards on %1?").arg(gCoreContext->GetHostName()),
3493  this,
3494  SLOT(DeleteAllCaptureCardsOnHost(bool)),
3495  true);
3496 }
3497 
3499 {
3500  ShowOkPopup(
3501  tr("Are you sure you want to delete "
3502  "ALL capture cards?"),
3503  this,
3504  SLOT(DeleteAllCaptureCards(bool)),
3505  true);
3506 }
3507 
3509 {
3510  auto *card = new CaptureCard();
3511  card->setLabel(tr("New capture card"));
3512  card->Load();
3513  addChild(card);
3514  emit settingsChanged(this);
3515 }
3516 
3518 {
3519  if (!doDelete)
3520  return;
3521 
3523  Load();
3524  emit settingsChanged(this);
3525 }
3526 
3528 {
3529  if (!doDelete)
3530  return;
3531 
3532  MSqlQuery cards(MSqlQuery::InitCon());
3533 
3534  cards.prepare(
3535  "SELECT cardid "
3536  "FROM capturecard "
3537  "WHERE hostname = :HOSTNAME");
3538  cards.bindValue(":HOSTNAME", gCoreContext->GetHostName());
3539 
3540  if (!cards.exec() || !cards.isActive())
3541  {
3542  ShowOkPopup(
3543  tr("Error getting list of cards for this host. "
3544  "Unable to delete capturecards for %1")
3545  .arg(gCoreContext->GetHostName()));
3546 
3547  MythDB::DBError("Selecting cardids for deletion", cards);
3548  return;
3549  }
3550 
3551  while (cards.next())
3552  CardUtil::DeleteInput(cards.value(0).toUInt());
3553 
3554  Load();
3555  emit settingsChanged(this);
3556 }
3557 
3559 {
3560  setLabel(tr("Capture cards"));
3561 }
3562 
3564 {
3565  clearSettings();
3566  AddSelection(QObject::tr("(New capture card)"), SLOT(AddNewCard()));
3567  AddSelection(QObject::tr("(Delete all capture cards on %1)")
3568  .arg(gCoreContext->GetHostName()),
3570  AddSelection(QObject::tr("(Delete all capture cards)"),
3573 }
3574 
3576 {
3577  setLabel(tr("Video sources"));
3578 }
3579 
3581 {
3582  clearSettings();
3583  AddSelection(QObject::tr("(New video source)"), SLOT(NewSource()));
3584  AddSelection(QObject::tr("(Delete all video sources)"),
3585  SLOT(ShowDeleteAllSourcesDialog()));
3588 }
3589 
3590 void VideoSourceEditor::AddSelection(const QString &label, const char* slot)
3591 {
3592  auto *button = new ButtonStandardSetting(label);
3593  connect(button, SIGNAL(clicked()), slot);
3594  addChild(button);
3595 }
3596 
3598 {
3599  ShowOkPopup(
3600  tr("Are you sure you want to delete "
3601  "ALL video sources?"),
3602  this,
3603  SLOT(DeleteAllSources(bool)),
3604  true);
3605 }
3606 
3608 {
3609  if (!doDelete)
3610  return;
3611 
3613  Load();
3614  emit settingsChanged(this);
3615 }
3616 
3618 {
3619  auto *source = new VideoSource();
3620  source->setLabel(tr("New video source"));
3621  source->Load();
3622  addChild(source);
3623  emit settingsChanged(this);
3624 }
3625 
3627 {
3628  setLabel(tr("Input connections"));
3629 }
3630 
3632 {
3633  m_cardInputs.clear();
3634  clearSettings();
3635 
3636  // We do this manually because we want custom labels. If
3637  // SelectSetting provided a facility to edit the labels, we
3638  // could use CaptureCard::fillSelections
3639 
3640  MSqlQuery query(MSqlQuery::InitCon());
3641  query.prepare(
3642  "SELECT cardid, videodevice, cardtype, inputname "
3643  "FROM capturecard "
3644  "WHERE hostname = :HOSTNAME "
3645  " AND parentid = 0 "
3646  "ORDER BY cardid");
3647  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
3648 
3649  if (!query.exec())
3650  {
3651  MythDB::DBError("CardInputEditor::load", query);
3652  return;
3653  }
3654 
3655  while (query.next())
3656  {
3657  uint cardid = query.value(0).toUInt();
3658  QString videodevice = query.value(1).toString();
3659  QString cardtype = query.value(2).toString();
3660  QString inputname = query.value(3).toString();
3661 
3662  auto *cardinput = new CardInput(cardtype, videodevice, cardid);
3663  cardinput->loadByID(cardid);
3664  QString inputlabel = QString("%1 (%2) -> %3")
3665  .arg(CardUtil::GetDeviceLabel(cardtype, videodevice))
3666  .arg(inputname).arg(cardinput->getSourceName());
3667  m_cardInputs.push_back(cardinput);
3668  cardinput->setLabel(inputlabel);
3669  addChild(cardinput);
3670  }
3671 
3673 }
3674 
3675 #ifdef USING_DVB
3676 static QString remove_chaff(const QString &name)
3677 {
3678  // Trim off some of the chaff.
3679  QString short_name = name;
3680  if (short_name.startsWith("LG Electronics"))
3681  short_name = short_name.right(short_name.length() - 15);
3682  if (short_name.startsWith("Oren"))
3683  short_name = short_name.right(short_name.length() - 5);
3684  if (short_name.startsWith("Nextwave"))
3685  short_name = short_name.right(short_name.length() - 9);
3686  if (short_name.startsWith("frontend", Qt::CaseInsensitive))
3687  short_name = short_name.left(short_name.length() - 9);
3688  if (short_name.endsWith("VSB/QAM"))
3689  short_name = short_name.left(short_name.length() - 8);
3690  if (short_name.endsWith("VSB"))
3691  short_name = short_name.left(short_name.length() - 4);
3692  if (short_name.endsWith("DVB-T"))
3693  short_name = short_name.left(short_name.length() - 6);
3694 
3695  // It would be infinitely better if DVB allowed us to query
3696  // the vendor ID. But instead we have to guess based on the
3697  // demodulator name. This means cards like the Air2PC HD5000
3698  // and DViCO Fusion HDTV cards are not identified correctly.
3699  short_name = short_name.simplified();
3700  if (short_name.startsWith("or51211", Qt::CaseInsensitive))
3701  short_name = "pcHDTV HD-2000";
3702  else if (short_name.startsWith("or51132", Qt::CaseInsensitive))
3703  short_name = "pcHDTV HD-3000";
3704  else if (short_name.startsWith("bcm3510", Qt::CaseInsensitive))
3705  short_name = "Air2PC v1";
3706  else if (short_name.startsWith("nxt2002", Qt::CaseInsensitive) ||
3707  short_name.startsWith("nxt200x", Qt::CaseInsensitive))
3708  short_name = "Air2PC v2";
3709  else if (short_name.startsWith("lgdt3302", Qt::CaseInsensitive))
3710  short_name = "DViCO HDTV3";
3711  else if (short_name.startsWith("lgdt3303", Qt::CaseInsensitive))
3712  short_name = "DViCO v2 or Air2PC v3 or pcHDTV HD-5500";
3713 
3714  return short_name;
3715 }
3716 #endif // USING_DVB
3717 
3718 void DVBConfigurationGroup::reloadDiseqcTree(const QString &videodevice)
3719 {
3720  if (m_diseqcTree)
3721  m_diseqcTree->Load(videodevice);
3722 }
3723 
3724 void DVBConfigurationGroup::probeCard(const QString &videodevice)
3725 {
3726  if (videodevice.isEmpty())
3727  {
3728  m_cardName->setValue("");
3729  m_cardType->setValue("");
3730  return;
3731  }
3732 
3733  if (m_parent.getCardID() && m_parent.GetRawCardType() != "DVB")
3734  {
3735  m_cardName->setValue("");
3736  m_cardType->setValue("");
3737  return;
3738  }
3739 
3740 #ifdef USING_DVB
3741  QString frontend_name = CardUtil::ProbeDVBFrontendName(videodevice);
3742  QString subtype = CardUtil::ProbeDVBType(videodevice);
3743 
3744  QString err_open = tr("Could not open card %1").arg(videodevice);
3745  QString err_other = tr("Could not get card info for card %1").arg(videodevice);
3746 
3747  switch (CardUtil::toInputType(subtype))
3748  {
3749  case CardUtil::ERROR_OPEN:
3750  m_cardName->setValue(err_open);
3751  m_cardType->setValue(strerror(errno));
3752  break;
3754  m_cardName->setValue(err_other);
3755  m_cardType->setValue("Unknown error");
3756  break;
3757  case CardUtil::ERROR_PROBE:
3758  m_cardName->setValue(err_other);
3759  m_cardType->setValue(strerror(errno));
3760  break;
3761  case CardUtil::QPSK:
3762  m_cardType->setValue("DVB-S");
3763  m_cardName->setValue(frontend_name);
3764  m_signalTimeout->setValue(7000);
3765  m_channelTimeout->setValue(10000);
3766  break;
3767  case CardUtil::DVBS2:
3768  m_cardType->setValue("DVB-S2");
3769  m_cardName->setValue(frontend_name);
3770  m_signalTimeout->setValue(7000);
3771  m_channelTimeout->setValue(10000);
3772  break;
3773  case CardUtil::QAM:
3774  m_cardType->setValue("DVB-C");
3775  m_cardName->setValue(frontend_name);
3776  m_signalTimeout->setValue(1000);
3777  m_channelTimeout->setValue(3000);
3778  break;
3779  case CardUtil::DVBT2:
3780  m_cardType->setValue("DVB-T2");
3781  m_cardName->setValue(frontend_name);
3782  m_signalTimeout->setValue(1000);
3783  m_channelTimeout->setValue(3000);
3784  break;
3785  case CardUtil::OFDM:
3786  {
3787  m_cardType->setValue("DVB-T");
3788  m_cardName->setValue(frontend_name);
3789  m_signalTimeout->setValue(1000);
3790  m_channelTimeout->setValue(3000);
3791  if (frontend_name.toLower().indexOf("usb") >= 0)
3792  {
3793  m_signalTimeout->setValue(40000);
3794  m_channelTimeout->setValue(42500);
3795  }
3796 
3797  // slow down tuning for buggy drivers
3798  if ((frontend_name == "DiBcom 3000P/M-C DVB-T") ||
3799  (frontend_name ==
3800  "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"))
3801  {
3802  m_tuningDelay->setValue(200);
3803  }
3804 
3805 #if 0 // frontends on hybrid DVB-T/Analog cards
3806  QString short_name = remove_chaff(frontend_name);
3807  m_buttonAnalog->setVisible(
3808  short_name.startsWith("zarlink zl10353",
3809  Qt::CaseInsensitive) ||
3810  short_name.startsWith("wintv hvr 900 m/r: 65008/a1c0",
3811  Qt::CaseInsensitive) ||
3812  short_name.startsWith("philips tda10046h",
3813  Qt::CaseInsensitive));
3814 #endif
3815  }
3816  break;
3817  case CardUtil::ATSC:
3818  {
3819  QString short_name = remove_chaff(frontend_name);
3820  m_cardType->setValue("ATSC");
3821  m_cardName->setValue(short_name);
3822  m_signalTimeout->setValue(500);
3823  m_channelTimeout->setValue(3000);
3824 
3825  // According to #1779 and #1935 the AverMedia 180 needs
3826  // a 3000 ms signal timeout, at least for QAM tuning.
3827  if (frontend_name == "Nextwave NXT200X VSB/QAM frontend")
3828  {
3829  m_signalTimeout->setValue(3000);
3830  m_channelTimeout->setValue(5500);
3831  }
3832 
3833 #if 0 // frontends on hybrid DVB-T/Analog cards
3834  if (frontend_name.toLower().indexOf("usb") < 0)
3835  {
3836  m_buttonAnalog->setVisible(
3837  short_name.startsWith("pchdtv", Qt::CaseInsensitive) ||
3838  short_name.startsWith("dvico", Qt::CaseInsensitive) ||
3839  short_name.startsWith("nextwave", Qt::CaseInsensitive));
3840  }
3841 #endif
3842  }
3843  break;
3844  default:
3845  break;
3846  }
3847 
3848  // Create selection list of all delivery systems of this card
3849  {
3851  QStringList delsyslist = CardUtil::ProbeDeliverySystems(videodevice);
3852  QStringList::iterator it = delsyslist.begin();
3853  for (; it != delsyslist.end(); it++)
3854  {
3855  LOG(VB_GENERAL, LOG_DEBUG, QString("DVBCardType: add deliverysystem:%1")
3856  .arg(*it));
3857 
3858  m_cardType->addSelection(*it, *it);
3859  }
3860 
3861  // Default value, used if not already defined in capturecard/inputname
3862  QString delsys = CardUtil::ProbeDefaultDeliverySystem(videodevice);
3863  if (!delsys.isEmpty())
3864  {
3865  m_cardType->setValue(delsys);
3866  }
3867  }
3868 #
3869 #else
3870  m_cardType->setValue(QString("Recompile with DVB-Support!"));
3871 #endif
3872 }
3873 
3875  QString dev, QString type) :
3876  CaptureCardComboBoxSetting(parent, false, "audiodevice"),
3877  m_lastDevice(std::move(dev)), m_lastCardType(std::move(type))
3878 {
3879  setLabel(QObject::tr("Audio input"));
3880  setHelpText(QObject::tr("If there is more than one audio input, "
3881  "select which one to use."));
3882  int cardid = parent.getCardID();
3883  if (cardid <= 0)
3884  return;
3885 
3888 }
3889 
3890 int TunerCardAudioInput::fillSelections(const QString &device)
3891 {
3892  clearSelections();
3893 
3894  if (device.isEmpty())
3895  return 0;
3896 
3897  m_lastDevice = device;
3898  QStringList inputs =
3900 
3901  for (uint i = 0; i < (uint)inputs.size(); i++)
3902  {
3903  addSelection(inputs[i], QString::number(i),
3904  m_lastDevice == QString::number(i));
3905  }
3906  return inputs.size();
3907 }
3908 
3910  CardType& cardType) :
3911  m_parent(a_parent),
3912  m_diseqcTree(new DiSEqCDevTree())
3913 {
3914  setVisible(false);
3915 
3916  m_cardNum = new DVBCardNum(m_parent);
3917  m_cardName = new DVBCardName();
3919 
3920  m_signalTimeout = new SignalTimeout(m_parent, 500, 250);
3921  m_channelTimeout = new ChannelTimeout(m_parent, 3000, 1750);
3922 
3923  cardType.addTargetedChild("DVB", m_cardNum);
3924 
3925  cardType.addTargetedChild("DVB", m_cardName);
3926  cardType.addTargetedChild("DVB", m_cardType);
3927 
3928  cardType.addTargetedChild("DVB", m_signalTimeout);
3929  cardType.addTargetedChild("DVB", m_channelTimeout);
3930 
3931  cardType.addTargetedChild("DVB", new EmptyAudioDevice(m_parent));
3932  cardType.addTargetedChild("DVB", new EmptyVBIDevice(m_parent));
3933 
3934  cardType.addTargetedChild("DVB", new DVBNoSeqStart(m_parent));
3935  cardType.addTargetedChild("DVB", new DVBOnDemand(m_parent));
3936  cardType.addTargetedChild("DVB", new DVBEITScan(m_parent));
3937 
3939  m_diseqcBtn->setLabel(tr("DiSEqC (Switch, LNB, and Rotor Configuration)"));
3940  m_diseqcBtn->setHelpText(tr("Input and satellite settings."));
3941  m_diseqcBtn->setVisible(false);
3942 
3944  cardType.addTargetedChild("DVB", m_tuningDelay);
3945  cardType.addTargetedChild("DVB", m_diseqcBtn);
3946  m_tuningDelay->setVisible(false);
3947 
3948  connect(m_cardNum, SIGNAL(valueChanged(const QString&)),
3949  this, SLOT( probeCard (const QString&)));
3950  connect(m_cardNum, SIGNAL(valueChanged(const QString&)),
3951  this, SLOT( reloadDiseqcTree(const QString&)));
3952 }
3953 
3955 {
3956  if (m_diseqcTree)
3957  {
3958  delete m_diseqcTree;
3959  m_diseqcTree = nullptr;
3960  }
3961 }
3962 
3964 {
3966  m_diseqcBtn->Load();
3968  if (m_cardType->getValue() == "DVB-S" ||
3969  m_cardType->getValue() == "DVB-S2" ||
3971  {
3972  m_diseqcBtn->setVisible(true);
3973  }
3974 }
3975 
3977 {
3981 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
CommandPath(const CaptureCard &parent)
void NewIP(const QString &)
QString m_ip
Definition: videosource.h:930
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:589
TransTextEditSetting * m_size
Definition: videosource.h:524
QString getValueLabel(void) const
CaptureCard & m_parent
Definition: videosource.h:433
static QStringList ProbeVideoDevices(const QString &rawtype)
Definition: cardutil.cpp:458
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:595
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:863
QString getSourceName(void) const
Definition: videosource.h:189
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:250
SourceID * m_sourceId
Definition: videosource.h:828
DVB-S device settings class.
Definition: diseqc.h:35
void NewSource(void)
VideoDevice * m_device
Definition: videosource.h:453
void fillSelections()
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
QString Card(void) const
vector< CardInput * > m_cardInputs
Definition: videosource.h:773
QString GetColumnName(void) const
Definition: mythstorage.h:43
virtual void clearSettings()
HDHomeRunConfigurationGroup(CaptureCard &parent, CardType &cardtype)
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
QString cardip
Definition: videosource.h:389
void probeCard(const QString &device)
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:1854
void Load(void) override
void probeCard(const QString &device)
MythUISpinBoxSetting * m_instanceCount
Definition: videosource.h:835
UseHDHomeRunDevice * checkbox
Definition: videosource.h:341
void Load(void) override
VBoxDeviceID * m_deviceId
Definition: videosource.h:905
void NewTuner(const QString &)
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:675
QString m_oldValue
Definition: videosource.h:912
void SetSourceID(const QString &sourceid)
CaptureCardSpinBoxSetting(const CaptureCard &parent, uint min_val, uint max_val, uint step, const QString &setting)
static void ClearVideoDeviceCache()
Definition: cardutil.cpp:452
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:511
SchedGroup(const CardInput &parent)
CaptureCard & m_parent
Definition: videosource.h:538
void DeleteAllSources(bool)
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:833
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)
static QString ProbeDVBFrontendName(const QString &device)
Returns the input type from the video device.
Definition: cardutil.cpp:696
const CaptureCard & m_parent
Definition: videosource.h:910
LiveTVOrder(const CardInput &parent, int _value)
virtual void setHelpText(const QString &str)
TransTextEditSetting * m_cardInfo
Definition: videosource.h:486
V4L2encGroup(CaptureCard &parent, CardType &cardType)
static bool IsInNeedOfExternalInputConf(uint inputid)
Definition: cardutil.cpp:2120
int size(void) const
Definition: mythdbcon.h:203
QString deviceid
Definition: videosource.h:387
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:434
InputGroup(const CardInput &parent, uint group_num)
FirewireModel(const CaptureCard &parent, const FirewireGUID *)
DVBEITScan(const CaptureCard &parent)
HDHomeRunConfigurationGroup & group
Definition: videosource.h:378
bool IsOpen(void) const
Definition: v4l2util.h:29
void CreateNewInputGroup()
QString GetWhereClause(MSqlBindings &bindings) const override
InputDisplayName(const CardInput &parent)
MythScreenStack * GetStack(const QString &stackname)
void Save(void) override
int getCardID(void) const
Definition: videosource.h:642
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
int getValueIndex(const QString &value) const
void Load(void) override
MythScreenStack * GetMainStack()
GroupSetting * m_cardInfo
Definition: videosource.h:470
IPTVHost(const CaptureCard &parent)
VBoxConfigurationGroup(CaptureCard &parent, CardType &cardtype)
QString getSourceName(void) const
CetonDeviceID(const CaptureCard &parent)
void Load(void) override
void Load(void) override
Definition: videosource.cpp:80
QStringList m_grabberArgs
Definition: videosource.h:134
virtual QString GetDBValue(void) const =0
static void SortChannels(ChannelInfoList &list, const QString &order, bool eliminate_duplicates=false)
DVBCardType * m_cardType
Definition: videosource.h:588
UseEIT * m_useeit
Definition: videosource.h:158
static guint32 * tmp
Definition: goom_core.c:35
static QString GetDeviceName(dvb_dev_type_t, const QString &device)
void Load(void) override
void DeleteAllCaptureCardsOnHost(bool)
MythUICheckBoxSetting * m_schedGroup
Definition: videosource.h:836
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
#define lstat
Definition: compat.h:194
static uint CloneCard(uint src_inputid, uint dst_inputid)
Definition: cardutil.cpp:1522
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
Definition: diseqc.cpp:426
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:2165
DVBCardNum * m_cardNum
Definition: videosource.h:586
void LoadedTuner(const QString &)
void UpdateDevices(const QString &)
DVBTuningDelay * m_tuningDelay
Definition: videosource.h:594
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:435
QString deviceid
Definition: videosource.h:338
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:244
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 sourceFetch()
CaptureCard(bool use_card_group=true)
void Load(void) override
static bool DeleteInput(uint inputid)
VideoSourceShow(uint _initial_sourceid)
void SetTuner(const QString &)
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:590
void SetIP(const QString &)
TunerCardAudioInput * m_audioInput
Definition: videosource.h:471
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
TransTextEditSetting * m_size
Definition: videosource.h:540
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:851
MPEGConfigurationGroup(CaptureCard &parent, CardType &cardtype)
UseHDHomeRunDevice(QString &deviceid, QString &model, QString &ipaddr)
void SetDeviceCheckBoxes(const QString &devices)
AudioDevice(const CaptureCard &parent)
void setEnabled(bool e) override
HDHomeRunDeviceList m_deviceList
Definition: videosource.h:364
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
TransTextEditSetting * m_cardInfo
Definition: videosource.h:455
QString GetSetting(const QString &key, const QString &defaultval="")
static QString GetDeliverySystemFromDB(uint inputid)
Definition: cardutil.h:279
VBoxDeviceList m_deviceList
Definition: videosource.h:419
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
StorageUser * m_user
Definition: mythstorage.h:46
void Save(void) override
static uint GetDeviceInputGroup(uint inputid)
Definition: cardutil.cpp:1909
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:383
bool isActive(void) const
Definition: mythdbcon.h:204
QString Driver(void) const
InputName * m_inputName
Definition: videosource.h:827
QString tunertype
Definition: videosource.h:391
VBoxIP * m_cardIp
Definition: videosource.h:907
void SetGUID(const QString &)
static void IPTVConfigurationGroup(CaptureCard &parent, CardType &cardType)
void ShowDeleteAllCaptureCardsDialog(void)
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
Definition: diseqc.cpp:164
bool discovered
Definition: videosource.h:393
void SetTuner(const QString &)
virtual void setEnabled(bool enabled)
void Load(void) override
VBoxDeviceID(const CaptureCard &parent)
uint m_initialSourceId
Definition: videosource.h:87
static void fillSelections(GroupSetting *setting)
void SetGUID(const QString &)
void fillSelectionsFromDir(const QDir &dir, bool absPath=true)
unsigned int uint
Definition: compat.h:140
static vector< uint > GetChildInputIDs(uint inputid)
Definition: cardutil.cpp:1345
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1973
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
CardInput(const QString &cardtype, const QString &device, int cardid)
void LoadValue(const QString &)
AVCInfo GetAVCInfo(const QString &guid) const
QString m_tuner
Definition: videosource.h:972
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:611
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:452
CardInputComboBoxSetting(const CardInput &parent, const QString &setting)
CaptureCard & m_parent
Definition: videosource.h:485
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
bool Load(const QString &device)
Loads the device tree from the database.
Definition: diseqc.cpp:315
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:53
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:454
void SetIP(const QString &)
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:273
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
TunerCardAudioInput(const CaptureCard &parent, QString dev=QString(), QString type=QString())
void UpdateDevices(const 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:807
QString tunerno
Definition: videosource.h:390
SkipBtAudio(const CaptureCard &parent)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString m_overrideDeviceId
Definition: videosource.h:932
static int GetASIDeviceNumber(const QString &device, QString *error=nullptr)
UseEIT(const VideoSource &parent)
CaptureCardGroup(CaptureCard &parent)
QMap< uint, uint > m_minorList
static QString GetVBoxdesc(const QString &id, const QString &ip, const QString &tunerNo, const QString &tunerType)
UseEIT * m_useeit
Definition: videosource.h:146
Name * m_name
Definition: videosource.h:225
ButtonStandardSetting * m_scan
Definition: videosource.h:830
static QString GetAudioDevice(uint inputid)
Definition: cardutil.h:275
void SetOldValue(const QString &s)
Definition: videosource.h:872
const VideoSource & m_parent
Definition: videosource.h:132
const FirewireGUID * m_guid
Definition: videosource.h:626
GroupSetting()=default
CaptureCard & m_parent
Definition: videosource.h:506
QString m_DriverName
Definition: videosource.h:489
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:170
DVBNetID(const VideoSource &parent, signed int value, signed int min_val)
void probeCard(const QString &device)
static bool DeleteAllSources(void)
Definition: sourceutil.cpp:554
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:407
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:832
void ShowDeleteAllCaptureCardsDialogOnHost(void)
VideoDevice * m_device
Definition: videosource.h:487
DVBNoSeqStart(const CaptureCard &parent)
void loadByID(int id)
void UpdateDevices(const QString &)
static void InvalidateTrees(void)
Invalidate cached trees.
Definition: diseqc.cpp:248
ChannelTimeout(const CaptureCard &parent, uint value, uint min_val)
XMLTVGrabber(const VideoSource &parent)
void deleteEntry(void) override
VBoxTunerIndex * m_cardTuner
Definition: videosource.h:908
QString m_driverName
static bool Exists(int cardid)
Check if a Diseqc device tree exists.
Definition: diseqc.cpp:397
void probeCard(const QString &device)
bool canDelete(void) override
QMap< QString, AVCInfo > m_guidToAvcInfo
void DeleteAllCaptureCards(bool)
void setValue(const QString &) override
VBIDevice(const CaptureCard &parent)
ASIConfigurationGroup(CaptureCard &parent, CardType &cardType)
void reload(void)
ButtonStandardSetting * m_srcFetch
Definition: videosource.h:831
QString m_cardName
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:271
CaptureCard & m_parent
Definition: videosource.h:522
CaptureCardTextEditSetting(const CaptureCard &parent, const QString &setting)
void Save(void) override
void fillSelectionsFromDir(const QDir &dir, bool absPath=true)
TransTextEditSetting * m_info
Definition: videosource.h:523
void UpdateDevices(const QString &)
ExternalChannelCommand(const CardInput &parent)
QString m_ip
Definition: videosource.h:970
int getSourceID(void) const
Definition: videosource.h:181
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:507
QString m_oldValue
Definition: videosource.h:861
void Save(void) override
int getInputID(void) const
QString m_tuner
Definition: videosource.h:931
static bool LinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1933
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:829
void loadByInput(int cardid, const QString &inputname)
TransTextEditSetting * m_cardInfo
Definition: videosource.h:508
bool canDelete(void) override
void Load(void) override
DeviceTree * m_diseqcBtn
Definition: videosource.h:596
FirewireSpeed(const CaptureCard &parent)
static QString ProbeDefaultDeliverySystem(const QString &device)
Definition: cardutil.cpp:657
DVBConfigurationGroup(CaptureCard &a_parent, CardType &cardType)
CaptureCard & m_parent
Definition: videosource.h:584
QString desc
Definition: videosource.h:388
void fillSelectionsFromDir(const QDir &dir, bool absPath=true)
InputGroup * m_inputGrp1
Definition: videosource.h:834
StandardSetting * m_desc
Definition: videosource.h:906
QString GetRawCardType(void) const
static QStringList ProbeDeliverySystems(const QString &device)
Definition: cardutil.cpp:577
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:702
void CreateNewInputGroupSlot(const QString &name)
TransTextEditSetting * m_info
Definition: videosource.h:539
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)
const CardInput & m_cardInput
vector< ChannelInfo > ChannelInfoList
Definition: channelinfo.h:121
VBoxDeviceList * m_deviceList
Definition: videosource.h:909
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
DVBCardName * m_cardName
Definition: videosource.h:587
void SetOverrideDeviceID(const QString &)
QString GetSetClause(MSqlBindings &bindings) const override
static bool is_grabber_external(const QString &grabber)
Definition: videosource.h:27
QMap< QString, VBoxDevice > VBoxDeviceList
Definition: videosource.h:396
CaptureCard & m_parent
Definition: videosource.h:469
static uint CreateDeviceInputGroup(uint inputid, const QString &type, const QString &host, const QString &device)
Definition: cardutil.cpp:1896
static QString GetStartingChannel(uint inputid)
Definition: cardutil.cpp:1713
QString mythdeviceid
Definition: videosource.h:386
int getInputID(void) const
Definition: videosource.h:802
allow access to stdout
Definition: mythsystem.h:39
FreqTableSelector(const VideoSource &parent)
QString m_oldValue
Definition: videosource.h:882
void valueChanged(const QString &)
void loadByID(int id)