MythTV  master
v2capture.cpp
Go to the documentation of this file.
1 // Program Name: capture.cpp
3 // Created : Sep. 21, 2011
4 //
5 // Copyright (c) 2011 Robert McNamara <rmcnamara@mythtv.org>
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 2 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //
25 
26 // Qt
27 #include <QList>
28 #include <QFile>
29 #include <QMutex>
30 
31 // MythTV
33 #include "libmythbase/compat.h"
36 #include "libmythbase/mythdate.h"
37 #include "libmythbase/mythversion.h"
38 #include "libmythtv/cardutil.h"
41 
42 // MythBackend
43 #include "v2capture.h"
44 #include "v2serviceUtil.h"
45 
46 // This will be initialised in a thread safe manner on first use
48  (CAPTURE_HANDLE, V2Capture::staticMetaObject, &V2Capture::RegisterCustomTypes))
49 
51 {
52  qRegisterMetaType<V2CaptureCardList*>("V2CaptureCardList");
53  qRegisterMetaType<V2CaptureCard*>("V2CaptureCard");
54  qRegisterMetaType<V2CardTypeList*>("V2CardTypeList");
55  qRegisterMetaType<V2CardType*>("V2CardType");
56  qRegisterMetaType<V2CaptureDeviceList*>("V2CaptureDeviceList");
57  qRegisterMetaType<V2CaptureDevice*>("V2CaptureDevice");
58  qRegisterMetaType<V2DiseqcTree*>("V2DiseqcTree");
59  qRegisterMetaType<V2DiseqcTreeList*>("V2DiseqcTreeList");
60  qRegisterMetaType<V2InputGroupList*>("V2InputGroupList");
61  qRegisterMetaType<V2InputGroup*>("V2InputGroup");
62  qRegisterMetaType<V2DiseqcConfig*>("V2DiseqcConfig");
63  qRegisterMetaType<V2DiseqcConfigList*>("V2DiseqcConfigList");
64  qRegisterMetaType<V2RecProfParam*>("V2RecProfParam");
65  qRegisterMetaType<V2RecProfile*>("V2RecProfile");
66  qRegisterMetaType<V2RecProfileGroup*>("V2RecProfileGroup");
67  qRegisterMetaType<V2RecProfileGroupList*>("V2RecProfileGroupList");
68  qRegisterMetaType<V2CardSubType*>("V2CardSubType");
69 }
70 
72  : MythHTTPService(s_service)
73 {
74 }
75 
77 //
79 
81  const QString &CardType )
82 {
84 
85  if (!query.isConnected())
86  throw( QString("Database not open while trying to list "
87  "V2Capture Cards."));
88 
89  QString str = "SELECT cardid, parentid, videodevice, audiodevice, vbidevice, "
90  "cardtype, defaultinput, audioratelimit, hostname, "
91  "dvb_swfilter, dvb_sat_type, dvb_wait_for_seqstart, "
92  "skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
93  "firewire_speed, firewire_model, firewire_connection, "
94  "signal_timeout, channel_timeout, dvb_tuning_delay, "
95  "contrast, brightness, colour, hue, diseqcid, dvb_eitscan, "
96  "inputname, sourceid, externalcommand, changer_device, "
97  "changer_model, tunechan, startchan, displayname, "
98  "dishnet_eit, recpriority, quicktune, schedorder, "
99  "livetvorder, reclimit, schedgroup "
100  "from capturecard";
101 
102  if (!sHostName.isEmpty())
103  str += " WHERE hostname = :HOSTNAME";
104  else if (!CardType.isEmpty())
105  str += " WHERE cardtype = :CARDTYPE";
106 
107  if (!sHostName.isEmpty() && !CardType.isEmpty())
108  str += " AND cardtype = :CARDTYPE";
109 
110  query.prepare(str);
111 
112  if (!sHostName.isEmpty())
113  query.bindValue(":HOSTNAME", sHostName);
114  if (!CardType.isEmpty())
115  query.bindValue(":CARDTYPE", CardType);
116 
117  if (!query.exec())
118  {
119  MythDB::DBError("MythAPI::GetCaptureCardList()", query);
120  throw( QString( "Database Error executing query." ));
121  }
122 
123  // ----------------------------------------------------------------------
124  // return the results of the query
125  // ----------------------------------------------------------------------
126 
127  auto* pList = new V2CaptureCardList();
128 
129  while (query.next())
130  {
131 
132  V2CaptureCard *pCaptureCard = pList->AddNewCaptureCard();
133 
134  pCaptureCard->setCardId ( query.value(0).toInt() );
135  pCaptureCard->setParentId ( query.value(1).toInt() );
136  pCaptureCard->setVideoDevice ( query.value(2).toString() );
137  pCaptureCard->setAudioDevice ( query.value(3).toString() );
138  pCaptureCard->setVBIDevice ( query.value(4).toString() );
139  pCaptureCard->setCardType ( query.value(5).toString() );
140  pCaptureCard->setDefaultInput ( query.value(6).toString() );
141  pCaptureCard->setAudioRateLimit ( query.value(7).toUInt() );
142  pCaptureCard->setHostName ( query.value(8).toString() );
143  pCaptureCard->setDVBSWFilter ( query.value(9).toUInt() );
144  pCaptureCard->setDVBSatType ( query.value(10).toUInt() );
145  pCaptureCard->setDVBWaitForSeqStart( query.value(11).toBool() );
146  pCaptureCard->setSkipBTAudio ( query.value(12).toBool() );
147  pCaptureCard->setDVBOnDemand ( query.value(13).toBool() );
148  pCaptureCard->setDVBDiSEqCType ( query.value(14).toUInt() );
149  pCaptureCard->setFirewireSpeed ( query.value(15).toUInt() );
150  pCaptureCard->setFirewireModel ( query.value(16).toString() );
151  pCaptureCard->setFirewireConnection( query.value(17).toUInt() );
152  pCaptureCard->setSignalTimeout ( query.value(18).toUInt() );
153  pCaptureCard->setChannelTimeout ( query.value(19).toUInt() );
154  pCaptureCard->setDVBTuningDelay ( query.value(20).toUInt() );
155  pCaptureCard->setContrast ( query.value(21).toUInt() );
156  pCaptureCard->setBrightness ( query.value(22).toUInt() );
157  pCaptureCard->setColour ( query.value(23).toUInt() );
158  pCaptureCard->setHue ( query.value(24).toUInt() );
159  pCaptureCard->setDiSEqCId ( query.value(25).toUInt() );
160  pCaptureCard->setDVBEITScan ( query.value(26).toBool() );
161  pCaptureCard->setInputName ( query.value(27).toString() );
162  pCaptureCard->setSourceId ( query.value(28).toInt() );
163  pCaptureCard->setExternalCommand ( query.value(29).toString() );
164  pCaptureCard->setChangerDevice ( query.value(30).toString() );
165  pCaptureCard->setChangerModel ( query.value(31).toString() );
166  pCaptureCard->setTuneChannel ( query.value(32).toString() );
167  pCaptureCard->setStartChannel ( query.value(33).toString() );
168  pCaptureCard->setDisplayName ( query.value(34).toString() );
169  pCaptureCard->setDishnetEit ( query.value(35).toBool() );
170  pCaptureCard->setRecPriority ( query.value(36).toInt() );
171  pCaptureCard->setQuickTune ( query.value(37).toBool() );
172  pCaptureCard->setSchedOrder ( query.value(38).toUInt() );
173  pCaptureCard->setLiveTVOrder ( query.value(39).toUInt() );
174  pCaptureCard->setRecLimit ( query.value(40).toUInt() );
175  pCaptureCard->setSchedGroup ( query.value(41).toBool() );
176  }
177 
178  return pList;
179 }
180 
182 //
184 
186 {
187  if ( nCardId < 1 )
188  throw( QString( "The Card ID is invalid."));
189 
190  MSqlQuery query(MSqlQuery::InitCon());
191 
192  if (!query.isConnected())
193  throw( QString("Database not open while trying to list "
194  "V2Capture Cards."));
195 
196  QString str = "SELECT cardid, parentid, videodevice, audiodevice, vbidevice, "
197  "cardtype, defaultinput, audioratelimit, hostname, "
198  "dvb_swfilter, dvb_sat_type, dvb_wait_for_seqstart, "
199  "skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
200  "firewire_speed, firewire_model, firewire_connection, "
201  "signal_timeout, channel_timeout, dvb_tuning_delay, "
202  "contrast, brightness, colour, hue, diseqcid, dvb_eitscan, "
203  "inputname, sourceid, externalcommand, changer_device, "
204  "changer_model, tunechan, startchan, displayname, "
205  "dishnet_eit, recpriority, quicktune, schedorder, "
206  "livetvorder, reclimit, schedgroup "
207  "from capturecard WHERE cardid = :CARDID";
208 
209  query.prepare(str);
210  query.bindValue(":CARDID", nCardId);
211 
212  if (!query.exec())
213  {
214  MythDB::DBError("MythAPI::GetCaptureCard()", query);
215  throw( QString( "Database Error executing query." ));
216  }
217 
218  auto* pCaptureCard = new V2CaptureCard();
219 
220  if (query.next())
221  {
222  pCaptureCard->setCardId ( query.value(0).toInt() );
223  pCaptureCard->setParentId ( query.value(1).toInt() );
224  pCaptureCard->setVideoDevice ( query.value(2).toString() );
225  pCaptureCard->setAudioDevice ( query.value(3).toString() );
226  pCaptureCard->setVBIDevice ( query.value(4).toString() );
227  pCaptureCard->setCardType ( query.value(5).toString() );
228  pCaptureCard->setDefaultInput ( query.value(6).toString() );
229  pCaptureCard->setAudioRateLimit ( query.value(7).toUInt() );
230  pCaptureCard->setHostName ( query.value(8).toString() );
231  pCaptureCard->setDVBSWFilter ( query.value(9).toUInt() );
232  pCaptureCard->setDVBSatType ( query.value(10).toUInt() );
233  pCaptureCard->setDVBWaitForSeqStart( query.value(11).toBool() );
234  pCaptureCard->setSkipBTAudio ( query.value(12).toBool() );
235  pCaptureCard->setDVBOnDemand ( query.value(13).toBool() );
236  pCaptureCard->setDVBDiSEqCType ( query.value(14).toUInt() );
237  pCaptureCard->setFirewireSpeed ( query.value(15).toUInt() );
238  pCaptureCard->setFirewireModel ( query.value(16).toString() );
239  pCaptureCard->setFirewireConnection( query.value(17).toUInt() );
240  pCaptureCard->setSignalTimeout ( query.value(18).toUInt() );
241  pCaptureCard->setChannelTimeout ( query.value(19).toUInt() );
242  pCaptureCard->setDVBTuningDelay ( query.value(20).toUInt() );
243  pCaptureCard->setContrast ( query.value(21).toUInt() );
244  pCaptureCard->setBrightness ( query.value(22).toUInt() );
245  pCaptureCard->setColour ( query.value(23).toUInt() );
246  pCaptureCard->setHue ( query.value(24).toUInt() );
247  pCaptureCard->setDiSEqCId ( query.value(25).toUInt() );
248  pCaptureCard->setDVBEITScan ( query.value(26).toBool() );
249  pCaptureCard->setInputName ( query.value(27).toString() );
250  pCaptureCard->setSourceId ( query.value(28).toInt() );
251  pCaptureCard->setExternalCommand ( query.value(29).toString() );
252  pCaptureCard->setChangerDevice ( query.value(30).toString() );
253  pCaptureCard->setChangerModel ( query.value(31).toString() );
254  pCaptureCard->setTuneChannel ( query.value(32).toString() );
255  pCaptureCard->setStartChannel ( query.value(33).toString() );
256  pCaptureCard->setDisplayName ( query.value(34).toString() );
257  pCaptureCard->setDishnetEit ( query.value(35).toBool() );
258  pCaptureCard->setRecPriority ( query.value(36).toInt() );
259  pCaptureCard->setQuickTune ( query.value(37).toBool() );
260  pCaptureCard->setSchedOrder ( query.value(38).toUInt() );
261  pCaptureCard->setLiveTVOrder ( query.value(39).toUInt() );
262  pCaptureCard->setRecLimit ( query.value(40).toUInt() );
263  pCaptureCard->setSchedGroup ( query.value(41).toBool() );
264  }
265 
266  return pCaptureCard;
267 }
268 
270 //
272 
274 {
275  auto* pCardType = new V2CardSubType();
276  QString subtype = CardUtil::ProbeSubTypeName(CardId);
277  CardUtil::INPUT_TYPES cardType = CardUtil::toInputType(subtype);
278 
279 #ifdef USING_SATIP
280  if (cardType == CardUtil::SATIP)
282 #endif // USING_SATIP
283 
284  bool HDHRdoesDVBC = false;
285  bool HDHRdoesDVB = false;
286 
287 #ifdef USING_HDHOMERUN
288  if (cardType == CardUtil::HDHOMERUN)
289  {
290  QString device = CardUtil::GetVideoDevice(CardId);
291  HDHRdoesDVBC = CardUtil::HDHRdoesDVBC(device);
292  HDHRdoesDVB = CardUtil::HDHRdoesDVB(device);
293  }
294 #endif // USING_HDHOMERUN
295 
296  pCardType->setCardId(CardId);
297  pCardType->setSubType (subtype);
298  // This enum is handled differently from others because it has
299  // two names for the same value in a few cases. We choose
300  // the name that starts with "DV" when this happens
301  QMetaEnum meta = QMetaEnum::fromType<CardUtil::INPUT_TYPES>();
302  QString key = meta.valueToKeys(cardType);
303  QStringList keyList = key.split("|");
304  key = keyList[0];
305  if (keyList.length() > 1 && keyList[1].startsWith("DV"))
306  key = keyList[1];
307  // pCardType->setInputType (cardType);
308  pCardType->setInputType (key);
309  pCardType->setHDHRdoesDVBC (HDHRdoesDVBC);
310  pCardType->setHDHRdoesDVB (HDHRdoesDVB);
311  return pCardType;
312 }
313 
314 
316 //
318 
320 {
321  return CardUtil::DeleteAllInputs();
322 }
323 
324 bool V2Capture::RemoveCaptureCard( int nCardId )
325 {
326  if ( nCardId < 1 )
327  throw( QString( "The Card ID is invalid."));
328 
329  bool bResult = CardUtil::DeleteInput(nCardId);
330 
331  return bResult;
332 }
333 
335 //
337 
338 int V2Capture::AddCaptureCard ( const QString &sVideoDevice,
339  const QString &sAudioDevice,
340  const QString &sVBIDevice,
341  const QString &CardType,
342  const uint nAudioRateLimit,
343  const QString &sHostName,
344  const uint nDVBSWFilter,
345  const uint nDVBSatType,
346  bool bDVBWaitForSeqStart,
347  bool bSkipBTAudio,
348  bool bDVBOnDemand,
349  const uint nDVBDiSEqCType,
350  const uint nFirewireSpeed,
351  const QString &sFirewireModel,
352  const uint nFirewireConnection,
353  const uint nSignalTimeout,
354  const uint nChannelTimeout,
355  const uint nDVBTuningDelay,
356  const uint nContrast,
357  const uint nBrightness,
358  const uint nColour,
359  const uint nHue,
360  const uint nDiSEqCId,
361  bool bDVBEITScan)
362 {
363  if ( sVideoDevice.isEmpty() || CardType.isEmpty() || sHostName.isEmpty() )
364  throw( QString( "This API requires at least a video device node, a card type, "
365  "and a hostname." ));
366 
367  int nResult = CardUtil::CreateCaptureCard(sVideoDevice, sAudioDevice,
368  sVBIDevice, CardType, nAudioRateLimit,
369  sHostName, nDVBSWFilter, nDVBSatType, bDVBWaitForSeqStart,
370  bSkipBTAudio, bDVBOnDemand, nDVBDiSEqCType, nFirewireSpeed,
371  sFirewireModel, nFirewireConnection, std::chrono::milliseconds(nSignalTimeout),
372  std::chrono::milliseconds(nChannelTimeout), nDVBTuningDelay, nContrast, nBrightness,
373  nColour, nHue, nDiSEqCId, bDVBEITScan);
374 
375  if ( nResult < 1 )
376  throw( QString( "Unable to create capture device." ));
377 
378  return nResult;
379 }
380 
381 bool V2Capture::UpdateCaptureCard ( int nCardId,
382  const QString &sSetting,
383  const QString &sValue )
384 {
385  if ( nCardId < 1 || sSetting.isEmpty() || sValue.isEmpty() )
386  throw( QString( "Card ID, Setting Name, and Value are required." ));
387 
388  return set_on_input(sSetting, nCardId, sValue);
389 }
390 
391 // Card Inputs
392 
393 bool V2Capture::RemoveCardInput( int nCardInputId )
394 {
395  if ( nCardInputId < 1 )
396  throw( QString( "The Input ID is invalid."));
397 
398  bool bResult = CardUtil::DeleteInput(nCardInputId);
399 
400  return bResult;
401 }
402 
403 int V2Capture::AddCardInput ( const uint nCardId,
404  const uint nSourceId,
405  const QString &sInputName,
406  const QString &sExternalCommand,
407  const QString &sChangerDevice,
408  const QString &sChangerModel,
409  const QString &sHostName,
410  const QString &sTuneChan,
411  const QString &sStartChan,
412  const QString &sDisplayName,
413  bool bDishnetEIT,
414  const uint nRecPriority,
415  const uint nQuicktune,
416  const uint nSchedOrder,
417  const uint nLiveTVOrder)
418 {
419  if ( nCardId < 1 || nSourceId < 1 ||
420  sInputName.isEmpty() || sInputName == "None" )
421  throw( QString( "This API requires at least a card ID, a source ID, "
422  "and an input name." ));
423 
424  if ( !CardUtil::IsUniqueDisplayName(sDisplayName, 0 ))
425  throw QString(" DisplayName is not set or is not unique.");
426 
427  int nResult = CardUtil::CreateCardInput(nCardId, nSourceId, sInputName,
428  sExternalCommand, sChangerDevice, sChangerModel,
429  sHostName, sTuneChan, sStartChan, sDisplayName,
430  bDishnetEIT, nRecPriority, nQuicktune, nSchedOrder,
431  nLiveTVOrder);
432 
433  return nResult;
434 }
435 
436 bool V2Capture::UpdateCardInput ( int nCardInputId,
437  const QString &sSetting,
438  const QString &sValue )
439 {
440  if ( nCardInputId < 1 || sSetting.isEmpty() || sValue.isEmpty() )
441  throw( QString( "Input ID, Setting Name, and Value are required." ));
442 
443  return set_on_input(sSetting, nCardInputId, sValue);
444 }
445 
447 {
448  auto* pCardTypeList = new V2CardTypeList();
449 
450 #ifdef USING_DVB
451  pCardTypeList->AddCardType(
452  QObject::tr("DVB-T/S/C, ATSC or ISDB-T tuner card"), "DVB");
453 #endif // USING_DVB
454 
455 #ifdef USING_V4L2
456  pCardTypeList->AddCardType(
457  QObject::tr("V4L2 encoder"), "V4L2ENC");
458  pCardTypeList->AddCardType(
459  QObject::tr("HD-PVR H.264 encoder"), "HDPVR");
460 #endif // USING_V4L2
461 
462 #ifdef USING_HDHOMERUN
463  pCardTypeList->AddCardType(
464  QObject::tr("HDHomeRun networked tuner"), "HDHOMERUN");
465 #endif // USING_HDHOMERUN
466 
467 #ifdef USING_SATIP
468  pCardTypeList->AddCardType(
469  QObject::tr("Sat>IP networked tuner"), "SATIP");
470 #endif // USING_SATIP
471 
472 #ifdef USING_VBOX
473  pCardTypeList->AddCardType(
474  QObject::tr("V@Box TV Gateway networked tuner"), "VBOX");
475 #endif // USING_VBOX
476 
477 #ifdef USING_FIREWIRE
478  pCardTypeList->AddCardType(
479  QObject::tr("FireWire cable box"), "FIREWIRE");
480 #endif // USING_FIREWIRE
481 
482 #ifdef USING_CETON
483  pCardTypeList->AddCardType(
484  QObject::tr("Ceton Cablecard tuner"), "CETON");
485 #endif // USING_CETON
486 
487 #ifdef USING_IPTV
488  pCardTypeList->AddCardType(QObject::tr("IPTV recorder"), "FREEBOX");
489 #endif // USING_IPTV
490 
491 #ifdef USING_V4L2
492  pCardTypeList->AddCardType(
493  QObject::tr("Analog to MPEG-2 encoder card (PVR-150/250/350, etc)"), "MPEG");
494  pCardTypeList->AddCardType(
495  QObject::tr("Analog to MJPEG encoder card (Matrox G200, DC10, etc)"), "MJPEG");
496  pCardTypeList->AddCardType(
497  QObject::tr("Analog to MPEG-4 encoder (Plextor ConvertX USB, etc)"),
498  "GO7007");
499  pCardTypeList->AddCardType(
500  QObject::tr("Analog capture card"), "V4L");
501 #endif // USING_V4L2
502 
503 #ifdef USING_ASI
504  pCardTypeList->AddCardType(QObject::tr("DVEO ASI recorder"), "ASI");
505 #endif
506 
507  pCardTypeList->AddCardType(QObject::tr("Import test recorder"), "IMPORT");
508  pCardTypeList->AddCardType(QObject::tr("Demo test recorder"), "DEMO");
509 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
510  pCardTypeList->AddCardType(QObject::tr("External (black box) recorder"),
511  "EXTERNAL");
512 #endif
513  return pCardTypeList;
514 }
515 
517 {
518  auto* pInputGroupList = new V2InputGroupList();
519 
520  MSqlQuery query(MSqlQuery::InitCon());
521 
522  if (!query.isConnected())
523  throw( QString("Database not open while trying to list "
524  "Input Groups."));
525 
526  QString q = "SELECT cardinputid,inputgroupid,inputgroupname "
527  "FROM inputgroup WHERE inputgroupname LIKE 'user:%' "
528  "ORDER BY inputgroupid, cardinputid";
529  query.prepare(q);
530 
531  if (!query.exec())
532  {
533  MythDB::DBError("GetUserInputGroupList", query);
534  return pInputGroupList;
535  }
536 
537  while (query.next())
538  {
539  pInputGroupList->AddInputGroup(query.value(0).toUInt(),
540  query.value(1).toUInt(),
541  query.value(2).toString());
542  }
543 
544  return pInputGroupList;
545 }
546 
547 int V2Capture::AddUserInputGroup(const QString & Name)
548 {
549  if (Name.isEmpty())
550  throw( QString( "Input group name cannot be empty." ) );
551 
552  QString new_name = QString("user:") + Name;
553 
554  uint inputgroupid = CardUtil::CreateInputGroup(new_name);
555 
556  if (inputgroupid == 0)
557  {
558  throw( QString( "Failed to add or retrieve %1" ).arg(new_name) );
559  }
560 
561  return inputgroupid;
562 }
563 
564 bool V2Capture::LinkInputGroup(const uint InputId,
565  const uint InputGroupId)
566 {
567  if (!CardUtil::LinkInputGroup(InputId, InputGroupId))
568  throw( QString ( "Failed to link input %1 to group %2" )
569  .arg(InputId).arg(InputGroupId));
570  return true;
571 }
572 
573 
575  const uint InputGroupId)
576 {
577  if (!CardUtil::UnlinkInputGroup(InputId, InputGroupId))
578  throw( QString ( "Failed to unlink input %1 from group %2" )
579  .arg(InputId).arg(InputGroupId));
580  return true;
581 }
582 
584  const uint Max )
585 {
586  return CardUtil::InputSetMaxRecordings(InputId, Max);
587 }
588 
589 
590 #ifdef USING_DVB
591 static QString remove_chaff(const QString &name)
592 {
593  // Trim off some of the chaff.
594  QString short_name = name;
595  if (short_name.startsWith("LG Electronics"))
596  short_name = short_name.right(short_name.length() - 15);
597  if (short_name.startsWith("Oren"))
598  short_name = short_name.right(short_name.length() - 5);
599  if (short_name.startsWith("Nextwave"))
600  short_name = short_name.right(short_name.length() - 9);
601  if (short_name.startsWith("frontend", Qt::CaseInsensitive))
602  short_name = short_name.left(short_name.length() - 9);
603  if (short_name.endsWith("VSB/QAM"))
604  short_name = short_name.left(short_name.length() - 8);
605  if (short_name.endsWith("VSB"))
606  short_name = short_name.left(short_name.length() - 4);
607  if (short_name.endsWith("DVB-T"))
608  short_name = short_name.left(short_name.length() - 6);
609 
610  // It would be infinitely better if DVB allowed us to query
611  // the vendor ID. But instead we have to guess based on the
612  // demodulator name. This means cards like the Air2PC HD5000
613  // and DViCO Fusion HDTV cards are not identified correctly.
614  short_name = short_name.simplified();
615  if (short_name.startsWith("or51211", Qt::CaseInsensitive))
616  short_name = "pcHDTV HD-2000";
617  else if (short_name.startsWith("or51132", Qt::CaseInsensitive))
618  short_name = "pcHDTV HD-3000";
619  else if (short_name.startsWith("bcm3510", Qt::CaseInsensitive))
620  short_name = "Air2PC v1";
621  else if (short_name.startsWith("nxt2002", Qt::CaseInsensitive) ||
622  short_name.startsWith("nxt200x", Qt::CaseInsensitive))
623  short_name = "Air2PC v2";
624  else if (short_name.startsWith("lgdt3302", Qt::CaseInsensitive))
625  short_name = "DViCO HDTV3";
626  else if (short_name.startsWith("lgdt3303", Qt::CaseInsensitive))
627  short_name = "DViCO v2 or Air2PC v3 or pcHDTV HD-5500";
628 
629  return short_name;
630 }
631 #endif // USING_DVB
632 
633 
634 
636 {
637 
638  if (CardType == "V4L2ENC") {
639  QRegularExpression drv { "^(?!ivtv|hdpvr|(saa7164(.*))).*$" };
640  return getV4l2List(drv, CardType);
641  }
642  if (CardType == "HDPVR") {
643  QRegularExpression drv { "^hdpvr$" };
644  return getV4l2List(drv, CardType);
645  }
646  if (CardType == "FIREWIRE") {
647  return getFirewireList(CardType);
648  }
649 
650  // Get devices from system
651  QStringList sdevs = CardUtil::ProbeVideoDevices(CardType);
652 
653  auto* pList = new V2CaptureDeviceList();
654  for (const auto & it : std::as_const(sdevs))
655  {
656  auto* pDev = pList->AddCaptureDevice();
657  pDev->setCardType (CardType);
658  pDev->setVideoDevice (it);
659 #ifdef USING_DVB
660  // From DVBConfigurationGroup::probeCard in Videosource.cpp
661  if (CardType == "DVB")
662  {
663  QString frontendName = CardUtil::ProbeDVBFrontendName(it);
664  pDev->setInputNames( CardUtil::ProbeDeliverySystems (it));
665  pDev->setDefaultInputName( CardUtil::ProbeDefaultDeliverySystem (it));
666  QString subType = CardUtil::ProbeDVBType(it);
667  int signalTimeout = 0;
668  int channelTimeout = 0;
669  int tuningDelay = 0;
670  QString err_open = tr("Could not open card %1").arg(it);
671  QString err_other = tr("Could not get card info for card %1").arg(it);
672 
673  switch (CardUtil::toInputType(subType))
674  {
676  frontendName = err_open;
677  subType = strerror(errno);
678  break;
680  frontendName = err_other;
681  subType = "Unknown error";
682  break;
684  frontendName = err_other;
685  subType = strerror(errno);
686  break;
687  case CardUtil::QPSK:
688  subType = "DVB-S";
689  signalTimeout = 7000;
690  channelTimeout = 10000;
691  break;
692  case CardUtil::DVBS2:
693  subType = "DVB-S2";
694  signalTimeout = 7000;
695  channelTimeout = 10000;
696  break;
697  case CardUtil::QAM:
698  subType = "DVB-C";
699  signalTimeout = 3000;
700  channelTimeout = 6000;
701  break;
702  case CardUtil::DVBT2:
703  subType = "DVB-T2";
704  signalTimeout = 3000;
705  channelTimeout = 6000;
706  break;
707  case CardUtil::OFDM:
708  {
709  subType = "DVB-T";
710  signalTimeout = 3000;
711  channelTimeout = 6000;
712  if (frontendName.toLower().indexOf("usb") >= 0)
713  {
714  signalTimeout = 40000;
715  channelTimeout = 42500;
716  }
717 
718  // slow down tuning for buggy drivers
719  if ((frontendName == "DiBcom 3000P/M-C DVB-T") ||
720  (frontendName ==
721  "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"))
722  {
723  tuningDelay = 200;
724  }
725  break;
726  }
727  case CardUtil::ATSC:
728  {
729  QString short_name = remove_chaff(frontendName);
730  subType = "ATSC";
731  frontendName = short_name;
732  signalTimeout = 2000;
733  channelTimeout = 4000;
734 
735  // According to #1779 and #1935 the AverMedia 180 needs
736  // a 3000 ms signal timeout, at least for QAM tuning.
737  if (frontendName == "Nextwave NXT200X VSB/QAM frontend")
738  {
739  signalTimeout = 3000;
740  channelTimeout = 5500;
741  }
742  break;
743  }
744  default:
745  break;
746  }
747 
748  pDev->setFrontendName ( frontendName );
749  pDev->setSubType ( subType );
750  pDev->setSignalTimeout ( signalTimeout );
751  pDev->setChannelTimeout ( channelTimeout );
752  pDev->setTuningDelay ( tuningDelay );
753  } // endif (CardType == "DVB")
754 #endif // USING_DVB
755  if (CardType == "HDHOMERUN")
756  {
757  pDev->setSignalTimeout ( 3000 );
758  pDev->setChannelTimeout ( 6000 );
759  }
760 #ifdef USING_SATIP
761  if (CardType == "SATIP")
762  {
763  pDev->setSignalTimeout ( 7000 );
764  pDev->setChannelTimeout ( 10000 );
765  // Split video device into its parts and populate the output
766  // "deviceid friendlyname ip tunernum tunertype"
767  auto word = it.split(' ');
768  // VideoDevice is set as deviceid:tunertype:tunernum
769  if (word.size() == 5) {
770  pDev->setVideoDevice(QString("%1:%2:%3").arg(word[0], word[4], word[3]));
771  pDev->setVideoDevicePrompt(QString("%1, %2, Tuner #%3").arg(word[0], word[4], word[3]));
772  pDev->setDescription(word[1]);
773  pDev->setIPAddress(word[2]);
774  pDev->setTunerType(word[4]);
775  pDev->setTunerNumber(word[3].toUInt());
776  }
777  }
778 #endif // USING_SATIP
779 #ifdef USING_VBOX
780  if (CardType == "VBOX")
781  {
782  pDev->setSignalTimeout ( 7000 );
783  pDev->setChannelTimeout ( 10000 );
784  // Split video device into its parts and populate the output
785  // "deviceid ip tunernum tunertype"
786  auto word = it.split(" ");
787  if (word.size() == 4) {
788  QString device = QString("%1-%2-%3").arg(word[0], word[2], word[3]);
789  pDev->setVideoDevice(device);
790  pDev->setVideoDevicePrompt(device);
791  QString desc = CardUtil::GetVBoxdesc(word[0], word[1], word[2], word[3]);
792  pDev->setDescription(desc);
793  pDev->setIPAddress(word[1]);
794  pDev->setTunerType(word[3]);
795  pDev->setTunerNumber(word[2].toUInt());
796  }
797  }
798 #endif // USING_VBOX
799  } // endfor (const auto & it : std::as_const(sdevs))
800  return pList;
801 }
802 
803 
804 
806 {
807  MSqlQuery query(MSqlQuery::InitCon());
808 
809  if (!query.isConnected())
810  throw( QString("Database not open while trying to list "
811  "DiseqcTrees."));
812 
813  QString str = "SELECT diseqcid, "
814  "parentid, "
815  "ordinal, "
816  "type, "
817  "subtype, "
818  "description, "
819  "switch_ports, "
820  "rotor_hi_speed, "
821  "rotor_lo_speed, "
822  "rotor_positions, "
823  "lnb_lof_switch, "
824  "lnb_lof_hi, "
825  "lnb_lof_lo, "
826  "cmd_repeat, "
827  "lnb_pol_inv, "
828  "address, "
829  "scr_userband, "
830  "scr_frequency, "
831  "scr_pin "
832  "FROM diseqc_tree ORDER BY diseqcid";
833 
834  query.prepare(str);
835 
836  if (!query.exec())
837  {
838  MythDB::DBError("MythAPI::GetDiseqcTreeList()", query);
839  throw( QString( "Database Error executing query." ));
840  }
841 
842  // ----------------------------------------------------------------------
843  // return the results of the query
844  // ----------------------------------------------------------------------
845 
846  auto* pList = new V2DiseqcTreeList();
847 
848  while (query.next())
849  {
850  auto *pRec = pList->AddDiseqcTree();
851  pRec->setDiSEqCId ( query.value( 0 ).toUInt() );
852  pRec->setParentId ( query.value( 1 ).toUInt() );
853  pRec->setOrdinal ( query.value( 2 ).toUInt() );
854  pRec->setType ( query.value( 3 ).toString() );
855  pRec->setSubType ( query.value( 4 ).toString() );
856  pRec->setDescription ( query.value( 5 ).toString() );
857  pRec->setSwitchPorts ( query.value( 6 ).toUInt() );
858  pRec->setRotorHiSpeed ( query.value( 7 ).toFloat() );
859  pRec->setRotorLoSpeed ( query.value( 8 ).toFloat() );
860  pRec->setRotorPositions ( query.value( 9 ).toString() );
861  pRec->setLnbLofSwitch ( query.value( 10 ).toInt() );
862  pRec->setLnbLofHi ( query.value( 11 ).toInt() );
863  pRec->setLnbLofLo ( query.value( 12 ).toInt() );
864  pRec->setCmdRepeat ( query.value( 13 ).toInt() );
865  pRec->setLnbPolInv ( query.value( 14 ).toBool() );
866  pRec->setAddress ( query.value( 15 ).toInt() );
867  pRec->setScrUserband ( query.value( 16 ).toUInt() );
868  pRec->setScrFrequency ( query.value( 17 ).toUInt() );
869  pRec->setScrPin ( query.value( 18 ).toInt() );
870  }
871 
872  return pList;
873 }
874 
876  uint Ordinal,
877  const QString& Type,
878  const QString& SubType,
879  const QString& Description,
880  uint SwitchPorts,
881  float RotorHiSpeed,
882  float RotorLoSpeed,
883  const QString& RotorPositions,
884  int LnbLofSwitch,
885  int LnbLofHi,
886  int LnbLofLo,
887  int CmdRepeat,
888  bool LnbPolInv,
889  int Address,
890  uint ScrUserband,
891  uint ScrFrequency,
892  int ScrPin)
893 {
894  MSqlQuery query(MSqlQuery::InitCon());
895 
896  query.prepare(
897  "INSERT INTO diseqc_tree "
898  "(parentid, "
899  "ordinal, "
900  "type, "
901  "subtype, "
902  "description, "
903  "switch_ports, "
904  "rotor_hi_speed, "
905  "rotor_lo_speed, "
906  "rotor_positions, "
907  "lnb_lof_switch, "
908  "lnb_lof_hi, "
909  "lnb_lof_lo, "
910  "cmd_repeat, "
911  "lnb_pol_inv, "
912  "address, "
913  "scr_userband, "
914  "scr_frequency, "
915  "scr_pin) "
916  "VALUES "
917  "(:PARENTID, "
918  ":ORDINAL, "
919  ":TYPE, "
920  ":SUBTYPE, "
921  ":DESCRIPTION, "
922  ":SWITCH_PORTS, "
923  ":ROTOR_HI_SPEED, "
924  ":ROTOR_LO_SPEED, "
925  ":ROTOR_POSITIONS, "
926  ":LNB_LOF_SWITCH, "
927  ":LNB_LOF_HI, "
928  ":LNB_LOF_LO, "
929  ":CMD_REPEAT, "
930  ":LNB_POL_INV, "
931  ":ADDRESS, "
932  ":SCR_USERBAND, "
933  ":SCR_FREQUENCY, "
934  ":SCR_PIN ) " );
935 
936  if (ParentId == 0) // Value 0 is set to null
937  {
938 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
939  query.bindValue(":PARENTID", QVariant(QVariant::UInt));
940 #else
941  query.bindValue(":PARENTID", QVariant(QMetaType(QMetaType::UInt)));
942 #endif
943  }
944  else
945  query.bindValue(":PARENTID", ParentId);
946  query.bindValue(":ORDINAL", Ordinal);
947  query.bindValue(":TYPE", Type);
948  query.bindValue(":SUBTYPE", SubType);
949  query.bindValue(":DESCRIPTION", Description);
950  query.bindValue(":SWITCH_PORTS", SwitchPorts);
951  query.bindValue(":ROTOR_HI_SPEED", RotorHiSpeed);
952  query.bindValue(":ROTOR_LO_SPEED", RotorLoSpeed);
953  query.bindValue(":ROTOR_POSITIONS", RotorPositions);
954  query.bindValue(":LNB_LOF_SWITCH", LnbLofSwitch);
955  query.bindValue(":LNB_LOF_HI", LnbLofHi);
956  query.bindValue(":LNB_LOF_LO", LnbLofLo);
957  query.bindValue(":CMD_REPEAT", CmdRepeat);
958  query.bindValue(":LNB_POL_INV", LnbPolInv);
959  query.bindValue(":ADDRESS", Address);
960  query.bindValue(":SCR_USERBAND", ScrUserband);
961  query.bindValue(":SCR_FREQUENCY", ScrFrequency);
962  query.bindValue(":SCR_PIN", ScrPin);
963 
964  if (!query.exec())
965  {
966  MythDB::DBError("MythAPI::AddDiseqcTree()", query);
967  throw( QString( "Database Error executing query." ));
968  }
969  uint DiSEqCId = query.lastInsertId().toInt();
970  return DiSEqCId;
971 }
972 
974  uint ParentId,
975  uint Ordinal,
976  const QString& Type,
977  const QString& SubType,
978  const QString& Description,
979  uint SwitchPorts,
980  float RotorHiSpeed,
981  float RotorLoSpeed,
982  const QString& RotorPositions,
983  int LnbLofSwitch,
984  int LnbLofHi,
985  int LnbLofLo,
986  int CmdRepeat,
987  bool LnbPolInv,
988  int Address,
989  uint ScrUserband,
990  uint ScrFrequency,
991  int ScrPin)
992 {
993  MSqlQuery query(MSqlQuery::InitCon());
994 
995  query.prepare(
996  "UPDATE diseqc_tree SET "
997  "parentid = :PARENTID, "
998  "ordinal = :ORDINAL, "
999  "type = :TYPE, "
1000  "subtype = :SUBTYPE, "
1001  "description = :DESCRIPTION, "
1002  "switch_ports = :SWITCH_PORTS, "
1003  "rotor_hi_speed = :ROTOR_HI_SPEED, "
1004  "rotor_lo_speed = :ROTOR_LO_SPEED, "
1005  "rotor_positions = :ROTOR_POSITIONS, "
1006  "lnb_lof_switch = :LNB_LOF_SWITCH, "
1007  "lnb_lof_hi = :LNB_LOF_HI, "
1008  "lnb_lof_lo = :LNB_LOF_LO, "
1009  "cmd_repeat = :CMD_REPEAT, "
1010  "lnb_pol_inv = :LNB_POL_INV, "
1011  "address = :ADDRESS, "
1012  "scr_userband = :SCR_USERBAND, "
1013  "scr_frequency = :SCR_FREQUENCY, "
1014  "scr_pin = :SCR_PIN "
1015  "WHERE diseqcid = :DISEQCID " );
1016 
1017  query.bindValue(":DISEQCID", DiSEqCId);
1018  if (ParentId == 0) // Value 0 is set to null
1019  {
1020 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1021  query.bindValue(":PARENTID", QVariant(QVariant::UInt));
1022 #else
1023  query.bindValue(":PARENTID", QVariant(QMetaType(QMetaType::UInt)));
1024 #endif
1025  }
1026  else
1027  query.bindValue(":PARENTID", ParentId);
1028  query.bindValue(":ORDINAL", Ordinal);
1029  query.bindValue(":TYPE", Type);
1030  query.bindValue(":SUBTYPE", SubType);
1031  query.bindValue(":DESCRIPTION", Description);
1032  query.bindValue(":SWITCH_PORTS", SwitchPorts);
1033  query.bindValue(":ROTOR_HI_SPEED", RotorHiSpeed);
1034  query.bindValue(":ROTOR_LO_SPEED", RotorLoSpeed);
1035  query.bindValue(":ROTOR_POSITIONS", RotorPositions);
1036  query.bindValue(":LNB_LOF_SWITCH", LnbLofSwitch);
1037  query.bindValue(":LNB_LOF_HI", LnbLofHi);
1038  query.bindValue(":LNB_LOF_LO", LnbLofLo);
1039  query.bindValue(":CMD_REPEAT", CmdRepeat);
1040  query.bindValue(":LNB_POL_INV", LnbPolInv);
1041  query.bindValue(":ADDRESS", Address);
1042  query.bindValue(":SCR_USERBAND", ScrUserband);
1043  query.bindValue(":SCR_FREQUENCY", ScrFrequency);
1044  query.bindValue(":SCR_PIN", ScrPin);
1045 
1046  if (!query.exec())
1047  {
1048  MythDB::DBError("MythAPI::UpdateDiseqcTree()", query);
1049  throw( QString( "Database Error executing query." ));
1050  }
1051  return true;
1052 }
1053 
1055 {
1056  // Find and remove children
1057  MSqlQuery query(MSqlQuery::InitCon());
1058  query.prepare("SELECT diseqcid FROM diseqc_tree WHERE parentid = :PARENTID ");
1059  query.bindValue(":PARENTID", DiSEqCId);
1060 
1061  if (!query.exec())
1062  {
1063  MythDB::DBError("MythAPI::RemoveDiseqcTree()", query);
1064  throw( QString( "Database Error executing query." ));
1065  }
1066 
1067  bool childOK = true;
1068  while (query.next())
1069  {
1070  uint child = query.value( 0 ).toUInt();
1071  childOK = RemoveDiseqcTree(child) && childOK;
1072  }
1073  // remove this row
1074  MSqlQuery query2(MSqlQuery::InitCon());
1075  query2.prepare("DELETE FROM diseqc_tree WHERE diseqcid = :DISEQCID ");
1076  query2.bindValue(":DISEQCID", DiSEqCId);
1077  if (!query2.exec())
1078  {
1079  MythDB::DBError("MythAPI::RemoveDiseqcTree()", query2);
1080  throw( QString( "Database Error executing query." ));
1081  }
1082  int numrows = query2.numRowsAffected();
1083  return numrows > 0 && childOK;
1084 }
1085 
1086 
1088 {
1089 
1090  MSqlQuery query(MSqlQuery::InitCon());
1091 
1092  if (!query.isConnected())
1093  throw( QString("Database not open while trying to list "
1094  "DiseqcConfigs."));
1095 
1096  QString str = "SELECT cardinputid, "
1097  "diseqcid, "
1098  "value "
1099  "FROM diseqc_config ORDER BY cardinputid, diseqcid";
1100 
1101  query.prepare(str);
1102 
1103  if (!query.exec())
1104  {
1105  MythDB::DBError("MythAPI::GetDiseqcConfigList()", query);
1106  throw( QString( "Database Error executing query." ));
1107  }
1108 
1109  // ----------------------------------------------------------------------
1110  // return the results of the query
1111  // ----------------------------------------------------------------------
1112 
1113  auto* pList = new V2DiseqcConfigList();
1114 
1115  while (query.next())
1116  {
1117  auto *pRec = pList->AddDiseqcConfig();
1118  pRec->setCardId ( query.value( 0 ).toUInt() );
1119  pRec->setDiSEqCId ( query.value( 1 ).toUInt() );
1120  pRec->setValue ( query.value( 2 ).toString() );
1121  }
1122  return pList;
1123 }
1124 
1126  uint DiSEqCId,
1127  const QString& Value)
1128 {
1129  MSqlQuery query(MSqlQuery::InitCon());
1130 
1131  query.prepare(
1132  "INSERT INTO diseqc_config "
1133  "(cardinputid, "
1134  "diseqcid, "
1135  "value) "
1136  "VALUES "
1137  "(:CARDID, "
1138  ":DISEQCID, "
1139  ":VALUE) ");
1140 
1141  query.bindValue(":CARDID", CardId);
1142  query.bindValue(":DISEQCID", DiSEqCId);
1143  query.bindValue(":VALUE", Value);
1144 
1145  if (!query.exec())
1146  {
1147  MythDB::DBError("MythAPI::AddDiseqcConfig()", query);
1148  throw( QString( "Database Error executing query." ));
1149  }
1150  return true;
1151 }
1152 
1153 
1155 {
1156  MSqlQuery query(MSqlQuery::InitCon());
1157  query.prepare("DELETE FROM diseqc_config WHERE cardinputid = :CARDID ");
1158  query.bindValue(":CARDID", CardId);
1159  if (!query.exec())
1160  {
1161  MythDB::DBError("MythAPI::RemoveDiseqcConfig()", query);
1162  throw( QString( "Database Error executing query." ));
1163  }
1164  int numrows = query.numRowsAffected();
1165  return numrows > 0;
1166 }
1167 
1168 
1169 V2RecProfileGroupList* V2Capture::GetRecProfileGroupList ( uint GroupId, uint ProfileId, bool OnlyInUse ) {
1170 
1171  MSqlQuery query(MSqlQuery::InitCon());
1172 
1173  QString str =
1174  "SELECT profilegroups.id, profilegroups.name, cardtype, recordingprofiles.id, recordingprofiles.name, "
1175  "videocodec, audiocodec, "
1176  "codecparams.name, codecparams.value "
1177  "FROM profilegroups "
1178  "INNER JOIN recordingprofiles on profilegroups.id = recordingprofiles.profilegroup "
1179  "LEFT OUTER JOIN codecparams on codecparams.profile = recordingprofiles.id ";
1180  QString where = "WHERE ";
1181  if (OnlyInUse)
1182  {
1183  str.append(where).append("CARDTYPE = 'TRANSCODE' OR (cardtype in (SELECT cardtype FROM capturecard)) ");
1184  where = "AND ";
1185  }
1186  if (GroupId > 0)
1187  {
1188  str.append(where).append("profilegroups.id = :GROUPID ");
1189  where = "AND ";
1190  }
1191  if (ProfileId > 0)
1192  {
1193  str.append(where).append("recordingprofiles.id = :PROFILEID ");
1194  where = "AND ";
1195  }
1196  str.append(
1197  // Force TRANSCODE entry to be at the end
1198  "ORDER BY IF(cardtype = 'TRANSCODE', 9999, profilegroups.id), recordingprofiles.id, codecparams.name ");
1199 
1200  query.prepare(str);
1201 
1202  if (GroupId > 0)
1203  query.bindValue(":GROUPID", GroupId);
1204  if (ProfileId > 0)
1205  query.bindValue(":PROFILEID", ProfileId);
1206 
1207  if (!query.exec())
1208  {
1209  MythDB::DBError("MythAPI::GetRecProfileGroupList()", query);
1210  throw( QString( "Database Error executing query." ));
1211  }
1212 
1213  // ----------------------------------------------------------------------
1214  // return the results of the query
1215  // ----------------------------------------------------------------------
1216 
1217  auto* pList = new V2RecProfileGroupList();
1218 
1219  int prevGroupId = -1;
1220  int prevProfileId = -1;
1221 
1222  V2RecProfileGroup * pGroup = nullptr;
1223  V2RecProfile *pProfile = nullptr;
1224 
1225  while (query.next())
1226  {
1227  int groupId = query.value(0).toInt();
1228  if (groupId != prevGroupId)
1229  {
1230  pGroup = pList->AddProfileGroup();
1231  pGroup->setId ( groupId );
1232  pGroup->setName ( query.value(1).toString() );
1233  pGroup->setCardType ( query.value(2).toString() );
1234  prevGroupId = groupId;
1235  }
1236  int profileId = query.value(3).toInt();
1237  // the pGroup != nullptr check is to satisfy clang-tidy.
1238  // pGroup should never be null unless the groupId on
1239  // the database is -1, which should not happen.
1240  if (profileId != prevProfileId && pGroup != nullptr)
1241  {
1242  pProfile = pGroup->AddProfile();
1243  pProfile->setId ( profileId );
1244  pProfile->setName ( query.value(4).toString() );
1245  pProfile->setVideoCodec ( query.value(5).toString() );
1246  pProfile->setAudioCodec ( query.value(6).toString() );
1247  prevProfileId = profileId;
1248  }
1249  // the pProfile != nullptr check is to satisfy clang-tidy.
1250  // pProfile should never be null unless the profileId on
1251  // the database is -1, which should not happen.
1252  if (!query.isNull(7) && pProfile != nullptr)
1253  {
1254  auto *pParam = pProfile->AddParam();
1255  pParam->setName ( query.value(7).toString() );
1256  pParam->setValue ( query.value(8).toString() );
1257  }
1258  }
1259 
1260  return pList;
1261 }
1262 
1263 int V2Capture::AddRecProfile ( uint GroupId, const QString& ProfileName,
1264  const QString& VideoCodec, const QString& AudioCodec )
1265 {
1266  if (GroupId == 0 || ProfileName.isEmpty())
1267  {
1268  LOG(VB_GENERAL, LOG_ERR,
1269  QString( "AddRecProfile: GroupId and ProfileName are required." ));
1270  return 0;
1271  }
1272 
1273  MSqlQuery query(MSqlQuery::InitCon());
1274 
1275  // Check if it already exists
1276  query.prepare(
1277  "SELECT id "
1278  "FROM recordingprofiles "
1279  "WHERE name = :NAME AND profilegroup = :PROFILEGROUP;");
1280  query.bindValue(":NAME", ProfileName);
1281  query.bindValue(":PROFILEGROUP", GroupId);
1282  if (!query.exec())
1283  {
1284  MythDB::DBError("V2Capture::AddRecProfile", query);
1285  throw( QString( "Database Error executing SELECT." ));
1286  }
1287  if (query.next())
1288  {
1289  int id = query.value(0).toInt();
1290  LOG(VB_GENERAL, LOG_ERR,
1291  QString( "Profile %1 already exists in group id %2 with id %3").arg(ProfileName).arg(GroupId).arg(id));
1292  return 0;
1293  }
1294 
1295  query.prepare(
1296  "INSERT INTO recordingprofiles "
1297  "(name, videocodec, audiocodec, profilegroup) "
1298  "VALUES "
1299  "(:NAME, :VIDEOCODEC, :AUDIOCODEC, :PROFILEGROUP);");
1300  query.bindValue(":NAME", ProfileName);
1301  query.bindValue(":VIDEOCODEC", VideoCodec);
1302  query.bindValue(":AUDIOCODEC", AudioCodec);
1303  query.bindValue(":PROFILEGROUP", GroupId);
1304  if (!query.exec())
1305  {
1306  MythDB::DBError("V2Capture::AddRecProfile", query);
1307  throw( QString( "Database Error executing INSERT." ));
1308  }
1309  int id = query.lastInsertId().toInt();
1310  RecordingProfile profile(ProfileName);
1311  profile.loadByID(id);
1312  profile.setCodecTypes();
1313  profile.Save();
1314  return id;
1315 }
1316 
1318  const QString& VideoCodec,
1319  const QString& AudioCodec )
1320 {
1321  MSqlQuery query(MSqlQuery::InitCon());
1322  query.prepare(
1323  "SELECT id from recordingprofiles "
1324  "WHERE id = :ID; ");
1325  query.bindValue(":ID", ProfileId);
1326  if (!query.exec())
1327  {
1328  MythDB::DBError("V2Capture::UpdateRecProfileParam", query);
1329  throw( QString( "Database Error executing SELECT." ));
1330  }
1331  uint id = -1;
1332  if (query.next())
1333  {
1334  id = query.value(0).toUInt();
1335  }
1336  if (id != ProfileId)
1337  {
1338  LOG(VB_GENERAL, LOG_ERR,
1339  QString("UpdateRecProfile: Profile id %1 does not exist").arg(ProfileId));
1340  return false;
1341  }
1342  query.prepare(
1343  "UPDATE recordingprofiles "
1344  "SET videocodec = :VIDEOCODEC, "
1345  "audiocodec = :AUDIOCODEC "
1346  "WHERE id = :ID; ");
1347  query.bindValue(":VIDEOCODEC", VideoCodec);
1348  query.bindValue(":AUDIOCODEC", AudioCodec);
1349  query.bindValue(":ID", ProfileId);
1350  if (!query.exec())
1351  {
1352  MythDB::DBError("V2Capture::UpdateRecProfileParam", query);
1353  throw( QString( "Database Error executing UPDATE." ));
1354  }
1356  profile.loadByID(ProfileId);
1357  profile.setCodecTypes();
1358  profile.Save();
1359  return true;
1360 }
1361 
1363 {
1364  // Delete profile parameters
1365  MSqlQuery query(MSqlQuery::InitCon());
1366  query.prepare(
1367  "DELETE from codecparams "
1368  "WHERE profile = :ID; ");
1369  query.bindValue(":ID", ProfileId);
1370  if (!query.exec())
1371  {
1372  MythDB::DBError("V2Capture::UpdateRecProfileParam", query);
1373  throw( QString( "Database Error executing DELETE." ));
1374  }
1375  int rows = query.numRowsAffected();
1376  query.prepare(
1377  "DELETE from recordingprofiles "
1378  "WHERE id = :ID; ");
1379  query.bindValue(":ID", ProfileId);
1380  if (!query.exec())
1381  {
1382  MythDB::DBError("V2Capture::UpdateRecProfileParam", query);
1383  throw( QString( "Database Error executing DELETE." ));
1384  }
1385  return (rows > 0);
1386 }
1387 
1388 
1389 
1390 bool V2Capture::UpdateRecProfileParam ( uint ProfileId, const QString &Name, const QString &Value )
1391 {
1392  MSqlQuery query(MSqlQuery::InitCon());
1393  query.prepare(
1394  "REPLACE INTO codecparams "
1395  "(profile, name, value) "
1396  "VALUES "
1397  "(:PROFILE, :NAME, :VALUE);");
1398  query.bindValue(":PROFILE", ProfileId);
1399  query.bindValue(":NAME", Name);
1400  query.bindValue(":VALUE", Value);
1401  if (!query.exec())
1402  {
1403  MythDB::DBError("V2Capture::UpdateRecProfileParam", query);
1404  throw( QString( "Database Error executing REPLACE." ));
1405  }
1406  return true;
1407 }
CardUtil::HDHRdoesDVBC
static bool HDHRdoesDVBC(const QString &device)
If the device is valid, check if the model does DVB-C.
Definition: cardutil.cpp:3093
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
CardUtil::GetVBoxdesc
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:3172
V2CardTypeList
Definition: v2captureCardList.h:58
CardUtil::CreateCardInput
static int CreateCardInput(uint inputid, uint sourceid, const QString &inputname, const QString &externalcommand, const QString &changer_device, const QString &changer_model, const QString &hostname, const QString &tunechan, const QString &startchan, const QString &displayname, bool dishnet_eit, uint recpriority, uint quicktune, uint schedorder, uint livetvorder)
Definition: cardutil.cpp:1963
MSqlQuery::isNull
bool isNull(int field) const
Definition: mythdbcon.h:219
V2Capture::UpdateCardInput
static bool UpdateCardInput(int CardInputId, const QString &Setting, const QString &Value)
Definition: v2capture.cpp:436
V2Capture::UpdateRecProfileParam
static bool UpdateRecProfileParam(uint ProfileId, const QString &Name, const QString &Value)
Definition: v2capture.cpp:1390
V2Capture::LinkInputGroup
static bool LinkInputGroup(uint InputId, uint InputGroupId)
Definition: v2capture.cpp:564
remove_chaff
static QString remove_chaff(const QString &name)
Definition: v2capture.cpp:591
CardUtil::SATIP
@ SATIP
Definition: cardutil.h:73
CardUtil::toInputType
static enum INPUT_TYPES toInputType(const QString &name)
Definition: cardutil.h:78
CardUtil::ERROR_UNKNOWN
@ ERROR_UNKNOWN
Definition: cardutil.h:52
CardUtil::DVBT2
@ DVBT2
Definition: cardutil.h:71
CardUtil::DeleteAllInputs
static bool DeleteAllInputs(void)
Definition: cardutil.cpp:2879
MSqlQuery::lastInsertId
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:936
V2DiseqcConfigList
Definition: v2captureCardList.h:213
V2Capture::GetRecProfileGroupList
static V2RecProfileGroupList * GetRecProfileGroupList(uint GroupId, uint ProfileId, bool OnlyInUse)
Definition: v2capture.cpp:1169
V2Capture::AddCardInput
static int AddCardInput(uint CardId, uint SourceId, const QString &InputName, const QString &ExternalCommand, const QString &ChangerDevice, const QString &ChangerModel, const QString &HostName, const QString &TuneChan, const QString &StartChan, const QString &DisplayName, bool DishnetEIT, uint RecPriority, uint Quicktune, uint SchedOrder, uint LiveTVOrder)
Definition: v2capture.cpp:403
V2Capture::RemoveAllCaptureCards
static bool RemoveAllCaptureCards(void)
Definition: v2capture.cpp:319
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
V2Capture::GetDiseqcTreeList
static V2DiseqcTreeList * GetDiseqcTreeList(void)
Definition: v2capture.cpp:805
mythhttpmetaservice.h
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
V2Capture::GetCaptureCardList
static V2CaptureCardList * GetCaptureCardList(const QString &HostName, const QString &CardType)
Definition: v2capture.cpp:80
set_on_input
bool set_on_input(const QString &to_set, uint inputid, const QString &value)
Definition: cardutil.cpp:1273
V2CaptureCardList
Definition: v2captureCardList.h:21
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
V2Capture::UpdateCaptureCard
static bool UpdateCaptureCard(int CardId, const QString &Setting, const QString &Value)
Definition: v2capture.cpp:381
getV4l2List
V2CaptureDeviceList * getV4l2List(const QRegularExpression &driver, const QString &cardType)
Definition: v2serviceUtil.cpp:906
V2CaptureDeviceList
Definition: v2captureCardList.h:97
V2Capture::UpdateRecProfile
static bool UpdateRecProfile(uint ProfileId, const QString &VideoCodec, const QString &AudioCodec)
Definition: v2capture.cpp:1317
CardUtil::IsUniqueDisplayName
static bool IsUniqueDisplayName(const QString &name, uint exclude_inputid)
Definition: cardutil.cpp:1896
CardUtil::ProbeSubTypeName
static QString ProbeSubTypeName(uint inputid)
Definition: cardutil.cpp:981
CardUtil::ProbeDefaultDeliverySystem
static QString ProbeDefaultDeliverySystem(const QString &device)
Definition: cardutil.cpp:707
CardUtil::ProbeDVBType
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:723
V2Capture::SetInputMaxRecordings
static bool SetInputMaxRecordings(uint InputId, uint Max)
Definition: v2capture.cpp:583
satiputils.h
CardUtil::ProbeVideoDevices
static QStringList ProbeVideoDevices(const QString &rawtype)
Definition: cardutil.cpp:447
V2InputGroupList
Definition: v2captureCardList.h:134
CardUtil::ProbeDVBFrontendName
static QString ProbeDVBFrontendName(const QString &device)
Returns the input type from the video device.
Definition: cardutil.cpp:744
CardUtil::DVBS2
@ DVBS2
Definition: cardutil.h:64
mythdate.h
CardUtil::UnlinkInputGroup
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:2153
CardUtil::QPSK
@ QPSK
Definition: cardutil.h:54
getFirewireList
V2CaptureDeviceList * getFirewireList(const QString &cardType)
Definition: v2serviceUtil.cpp:1008
v2serviceUtil.h
hardwareprofile.scan.profile
profile
Definition: scan.py:97
V2Capture::AddDiseqcConfig
static bool AddDiseqcConfig(uint CardId, uint DiSEqCId, const QString &Value)
Definition: v2capture.cpp:1125
V2RecProfileGroupList
Definition: v2recordingProfile.h:113
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
compat.h
V2RecProfile
Definition: v2recordingProfile.h:42
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
CardUtil::QAM
@ QAM
Definition: cardutil.h:55
CardUtil::HDHOMERUN
@ HDHOMERUN
Definition: cardutil.h:61
SatIP::toDVBInputType
static CardUtil::INPUT_TYPES toDVBInputType(const QString &deviceid)
Definition: satiputils.cpp:169
V2CaptureCard
Definition: v2captureCard.h:21
v2capture.h
V2Capture::GetUserInputGroupList
static V2InputGroupList * GetUserInputGroupList(void)
Definition: v2capture.cpp:516
CAPTURE_HANDLE
#define CAPTURE_HANDLE
Definition: v2capture.h:34
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:137
V2Capture::AddDiseqcTree
static int AddDiseqcTree(uint ParentId, uint Ordinal, const QString &Type, const QString &SubType, const QString &Description, uint SwitchPorts, float RotorHiSpeed, float RotorLoSpeed, const QString &RotorPositions, int LnbLofSwitch, int LnbLofHi, int LnbLofLo, int CmdRepeat, bool LnbPolInv, int Address, uint ScrUserband, uint ScrFrequency, int ScrPin)
Definition: v2capture.cpp:875
uint
unsigned int uint
Definition: compat.h:81
CardUtil::ProbeDeliverySystems
static QStringList ProbeDeliverySystems(const QString &device)
MythHTTPService
Definition: mythhttpservice.h:19
CardUtil::InputSetMaxRecordings
static bool InputSetMaxRecordings(uint parentid, uint max_recordings)
Definition: cardutil.cpp:1559
V2Capture::V2Capture
V2Capture()
Definition: v2capture.cpp:71
V2Capture::RemoveDiseqcTree
static bool RemoveDiseqcTree(uint DiSEqCId)
Definition: v2capture.cpp:1054
CardType
Definition: videosource.h:326
standardsettings.h
Q_GLOBAL_STATIC_WITH_ARGS
Q_GLOBAL_STATIC_WITH_ARGS(MythHTTPMetaService, s_service,(CAPTURE_HANDLE, V2Capture::staticMetaObject, &V2Capture::RegisterCustomTypes)) void V2Capture
Definition: v2capture.cpp:47
MythHTTPService::Name
QString & Name()
Definition: mythhttpservice.cpp:240
V2Capture::RegisterCustomTypes
static void RegisterCustomTypes()
V2Capture::RemoveDiseqcConfig
static bool RemoveDiseqcConfig(uint CardId)
Definition: v2capture.cpp:1154
V2Capture::DeleteRecProfile
static bool DeleteRecProfile(uint ProfileId)
Definition: v2capture.cpp:1362
V2Capture::GetDiseqcConfigList
static V2DiseqcConfigList * GetDiseqcConfigList(void)
Definition: v2capture.cpp:1087
mythcorecontext.h
cardutil.h
CardUtil::CreateCaptureCard
static int CreateCaptureCard(const QString &videodevice, const QString &audiodevice, const QString &vbidevice, const QString &inputtype, uint audioratelimit, const QString &hostname, uint dvb_swfilter, uint dvb_sat_type, bool dvb_wait_for_seqstart, bool skipbtaudio, bool dvb_on_demand, uint dvb_diseqc_type, uint firewire_speed, const QString &firewire_model, uint firewire_connection, std::chrono::milliseconds signal_timeout, std::chrono::milliseconds channel_timeout, uint dvb_tuning_delay, uint contrast, uint brightness, uint colour, uint hue, uint diseqcid, bool dvb_eitscan)
Definition: cardutil.cpp:2670
Name
Definition: channelsettings.cpp:71
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
CardUtil::HDHRdoesDVB
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
Definition: cardutil.cpp:3067
V2RecProfileGroup
Definition: v2recordingProfile.h:79
V2DiseqcTreeList
Definition: v2captureCardList.h:177
V2Capture::UnlinkInputGroup
static bool UnlinkInputGroup(uint InputId, uint InputGroupId)
Definition: v2capture.cpp:574
V2RecProfileGroup::AddProfile
V2RecProfile * AddProfile()
Definition: v2recordingProfile.h:97
V2Capture::GetCardTypeList
static V2CardTypeList * GetCardTypeList(void)
Definition: v2capture.cpp:446
V2CardSubType
Definition: v2captureCard.h:307
V2Capture::RemoveCaptureCard
static bool RemoveCaptureCard(int CardId)
Definition: v2capture.cpp:324
V2Capture::UpdateDiseqcTree
static bool UpdateDiseqcTree(uint DiSEqCId, uint ParentId, uint Ordinal, const QString &Type, const QString &SubType, const QString &Description, uint SwitchPorts, float RotorHiSpeed, float RotorLoSpeed, const QString &RotorPositions, int LnbLofSwitch, int LnbLofHi, int LnbLofLo, int CmdRepeat, bool LnbPolInv, int Address, uint ScrUserband, uint ScrFrequency, int ScrPin)
Definition: v2capture.cpp:973
CardUtil::OFDM
@ OFDM
Definition: cardutil.h:56
V2Capture::AddCaptureCard
static int AddCaptureCard(const QString &VideoDevice, const QString &AudioDevice, const QString &VBIDevice, const QString &CardType, uint AudioRateLimit, const QString &HostName, uint DVBSWFilter, uint DVBSatType, bool DVBWaitForSeqStart, bool SkipBTAudio, bool DVBOnDemand, uint DVBDiSEqCType, uint FirewireSpeed, const QString &FirewireModel, uint FirewireConnection, uint SignalTimeout, uint ChannelTimeout, uint DVBTuningDelay, uint Contrast, uint Brightness, uint Colour, uint Hue, uint DiSEqCId, bool DVBEITScan)
Definition: v2capture.cpp:338
MSqlQuery::numRowsAffected
int numRowsAffected() const
Definition: mythdbcon.h:217
recordingprofile.h
V2Capture::AddUserInputGroup
static int AddUserInputGroup(const QString &Name)
Definition: v2capture.cpp:547
V2Capture::GetCardSubType
static V2CardSubType * GetCardSubType(int CardId)
Definition: v2capture.cpp:273
RecordingProfile
Definition: recordingprofile.h:41
V2RecProfile::AddParam
V2RecProfParam * AddParam()
Definition: v2recordingProfile.h:56
V2Capture::GetCaptureDeviceList
static V2CaptureDeviceList * GetCaptureDeviceList(const QString &CardType)
Definition: v2capture.cpp:635
CardUtil::ATSC
@ ATSC
Definition: cardutil.h:57
V2Capture::GetCaptureCard
static V2CaptureCard * GetCaptureCard(int CardId)
Definition: v2capture.cpp:185
CardUtil::CreateInputGroup
static uint CreateInputGroup(const QString &name)
Definition: cardutil.cpp:2023
CardUtil::LinkInputGroup
static bool LinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:2102
MythHTTPMetaService
Definition: mythhttpmetaservice.h:10
CardUtil::ERROR_OPEN
@ ERROR_OPEN
Definition: cardutil.h:51
V2Capture::AddRecProfile
static int AddRecProfile(uint GroupId, const QString &ProfileName, const QString &VideoCodec, const QString &AudioCodec)
Definition: v2capture.cpp:1263
CardUtil::GetVideoDevice
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:294
CardUtil::INPUT_TYPES
INPUT_TYPES
all the different inputs
Definition: cardutil.h:49
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838
CardUtil::ERROR_PROBE
@ ERROR_PROBE
Definition: cardutil.h:53
CardUtil::DeleteInput
static bool DeleteInput(uint inputid)
Definition: cardutil.cpp:2809
V2Capture::RemoveCardInput
static bool RemoveCardInput(int CardInputId)
Definition: v2capture.cpp:393