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