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