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