Ticket #6537: svn20533s2api-part1

File svn20533s2api-part1, 135.3 KB (added by happybaby, 15 years ago)
Line 
1Index: libs/libmythtv/firewirechannel.cpp
2===================================================================
3--- libs/libmythtv/firewirechannel.cpp  (révision 20533)
4+++ libs/libmythtv/firewirechannel.cpp  (copie de travail)
5@@ -60,6 +60,7 @@
6 
7     // Fetch tuning data from the database.
8     QString tvformat, modulation, freqtable, freqid, dtv_si_std;
9+    QString msystem, rolloff;
10     int finetune;
11     uint64_t frequency;
12     int mpeg_prog_num;
13@@ -70,6 +71,7 @@
14         tvformat, modulation, freqtable, freqid,
15         finetune, frequency,
16         dtv_si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
17+        msystem, rolloff,
18         mplexid, commfree))
19     {
20         VERBOSE(VB_IMPORTANT, loc + " " + QString(
21Index: libs/libmythtv/dtvconfparserhelpers.h
22===================================================================
23--- libs/libmythtv/dtvconfparserhelpers.h       (révision 20533)
24+++ libs/libmythtv/dtvconfparserhelpers.h       (copie de travail)
25@@ -74,14 +74,11 @@
26   public:
27     enum
28     {
29-        kTunerTypeQPSK    = 0,
30-        kTunerTypeQAM     = 1,
31-        kTunerTypeOFDM    = 2,
32+        kTunerTypeQPSK    = 0,         // DVB-S
33+        kTunerTypeQAM     = 1,         // DVB-C
34+        kTunerTypeOFDM    = 2,         // DVB-T
35         kTunerTypeATSC    = 3,
36-        kTunerTypeDVB_S   = (1 << 2), // same as QPSK but for new API
37-        kTunerTypeDVB_C   = (1 << 3), // same as QAM  but for new API
38-        kTunerTypeDVB_T   = (1 << 4), // same as OFDM but for new API
39-        kTunerTypeDVB_S2  = (1 << 5),
40+        kTunerTypeDVB_S2  = (1 << 30), // In S2API DVB-S2 is only a capability
41         kTunerTypeUnknown = (1 << 31),
42     };
43 
44@@ -95,8 +92,6 @@
45     {
46         return ((kTunerTypeQPSK   == value) ||
47                 (kTunerTypeQAM    == value) ||
48-                (kTunerTypeDVB_S  == value) ||
49-                (kTunerTypeDVB_C  == value) ||
50                 (kTunerTypeDVB_S2 == value));
51     }
52 
53@@ -201,7 +196,7 @@
54     static const DTVParamHelperStruct confTable[];
55     static const DTVParamHelperStruct vdrTable[];
56     static const DTVParamHelperStruct parseTable[];
57-    static const uint kDBStrCnt = 10;
58+    static const uint kDBStrCnt = 12;
59     static const char *dbStr[kDBStrCnt];
60 
61   public:
62@@ -217,6 +212,8 @@
63         kFEC_7_8,
64         kFEC_8_9,
65         kFECAuto,
66+        kFEC_3_5,
67+        kFEC_9_10,
68     };
69 
70     DTVCodeRate(int _default = kFECAuto) : DTVParamHelper(_default) { }
71@@ -260,14 +257,15 @@
72         kModulationQAMAuto = 6,
73         kModulation8VSB    = 7,
74         kModulation16VSB   = 8,
75-        kModulation2VSB    = 9,
76-        kModulation4VSB    = 10,
77-        kModulationBPSK    = 11,
78-        kModulation16APSK  = 12,
79-        kModulation32APSK  = 13,
80-        kModulation8PSK    = 14,
81-        kModulation16PSK   = 15,
82+        kModulation8PSK    = 9,
83+        kModulation16APSK  = 10,
84+        kModulation32APSK  = 11,
85+        kModulationDQPSK   = 12,
86+        kModulation2VSB    = 13,
87+        kModulation4VSB    = 14,
88+        kModulationBPSK    = 15,
89         kModulationAnalog  = 16, /* for analog channel scanner */
90+        kModulation16PSK   = 17,
91     };
92 
93     DTVModulation(int _default = kModulationQAMAuto)
94@@ -449,4 +447,99 @@
95         { return DTVParamHelper::toString(dbStr, _value, kDBStrCnt); }
96 };
97 
98+class DTVModulationSystem : public DTVParamHelper
99+{
100+  protected:
101+    static const DTVParamHelperStruct confTable[];
102+    static const DTVParamHelperStruct vdrTable[];
103+    static const DTVParamHelperStruct parseTable[];
104+    static const uint kDBStrCnt = 2;
105+    static const char *dbStr[kDBStrCnt];
106+
107+  public:
108+    enum
109+    {
110+        kModulationSystemDVBS,
111+        kModulationSystemDVBS2,
112+    };
113+
114+    DTVModulationSystem(int _default = kModulationSystemDVBS)
115+        : DTVParamHelper(_default) { }
116+
117+    bool ParseConf(const QString &_value)
118+       { return ParseParam(_value, value, confTable); }
119+    bool ParseVDR(const QString &_value)
120+       { return ParseParam(_value, value, vdrTable); }
121+    bool Parse(const QString &_value)
122+       { return ParseParam(_value, value, parseTable); }
123+
124+    QString toString() const { return toString(value); }
125+
126+    static QString toString(int _value)
127+        { return DTVParamHelper::toString(dbStr, _value, kDBStrCnt); }
128+};
129+
130+class DTVRollOff : public DTVParamHelper
131+{
132+  protected:
133+    static const DTVParamHelperStruct confTable[];
134+    static const DTVParamHelperStruct vdrTable[];
135+    static const DTVParamHelperStruct parseTable[];
136+    static const uint kDBStrCnt = 4;
137+    static const char *dbStr[kDBStrCnt];
138+
139+  public:
140+    enum
141+    {
142+        kRollOff35,
143+        kRollOff20,
144+        kRollOff25,
145+        kRollOffAuto,
146+    };
147+
148+    DTVRollOff(int _default = kRollOff35)
149+        : DTVParamHelper(_default) { }
150+
151+    bool ParseConf(const QString &_value)
152+       { return ParseParam(_value, value, confTable); }
153+    bool ParseVDR(const QString &_value)
154+       { return ParseParam(_value, value, vdrTable); }
155+    bool Parse(const QString &_value)
156+       { return ParseParam(_value, value, parseTable); }
157+
158+    QString toString() const { return toString(value); }
159+
160+    static QString toString(int _value)
161+        { return DTVParamHelper::toString(dbStr, _value, kDBStrCnt); }
162+};
163+
164+class DTVPilot : public DTVParamHelper
165+{
166+  protected:
167+    static const DTVParamHelperStruct confTable[];
168+    static const DTVParamHelperStruct vdrTable[];
169+    static const DTVParamHelperStruct parseTable[];
170+    static const uint kDBStrCnt = 3;
171+    static const char *dbStr[kDBStrCnt];
172+
173+  public:
174+    enum
175+    {
176+        kPilotOn,
177+        kPilotOff,
178+        kPilotAuto,
179+    };
180+
181+    DTVPilot(int _default = kPilotAuto)
182+        : DTVParamHelper(_default) { }
183+
184+    bool ParseConf(const QString &_value)
185+       { return ParseParam(_value, value, confTable); }
186+
187+    QString toString() const { return toString(value); }
188+
189+    static QString toString(int _value)
190+        { return DTVParamHelper::toString(dbStr, _value, kDBStrCnt); }
191+};
192+
193 #endif // _DTVCONFPARSERHELPERS_H_
194Index: libs/libmythtv/channelscan/channelimporter.cpp
195===================================================================
196--- libs/libmythtv/channelscan/channelimporter.cpp      (révision 20533)
197+++ libs/libmythtv/channelscan/channelimporter.cpp      (copie de travail)
198@@ -503,7 +503,6 @@
199 
200     bool is_dvbs =
201         (DTVTunerType::kTunerTypeQPSK   == tuner_type) ||
202-        (DTVTunerType::kTunerTypeDVB_S  == tuner_type) ||
203         (DTVTunerType::kTunerTypeDVB_S2 == tuner_type);
204 
205     uint freq_mult = (is_dvbs) ? 1 : 1000;
206Index: libs/libmythtv/channelscan/scaninfo.cpp
207===================================================================
208--- libs/libmythtv/channelscan/scaninfo.cpp     (révision 20533)
209+++ libs/libmythtv/channelscan/scaninfo.cpp     (copie de travail)
210@@ -81,7 +81,8 @@
211         "       hp_code_rate,      lp_code_rate,   modulation, "
212         "       transmission_mode, guard_interval, hierarchy, "
213         "       modulation,        bandwidth,      sistandard, "
214-        "       tuner_type,        transportid "
215+        "       tuner_type,        transportid, "
216+        "       msystem,           rolloff "
217         "FROM channelscan_dtv_multiplex "
218         "WHERE scanid = :SCANID");
219     query.bindValue(":SCANID", scanid);
220@@ -102,7 +103,8 @@
221             query.value(6).toString(),  query.value(7).toString(),
222             query.value(8).toString(),  query.value(9).toString(),
223             query.value(10).toString(), query.value(11).toString(),
224-            query.value(12).toString());
225+            query.value(12).toString(), query.value(16).toString(),
226+            query.value(17).toString());
227 
228         query2.prepare(
229             "SELECT "
230Index: libs/libmythtv/channelscan/channelscan_sm.cpp
231===================================================================
232--- libs/libmythtv/channelscan/channelscan_sm.cpp       (révision 20533)
233+++ libs/libmythtv/channelscan/channelscan_sm.cpp       (copie de travail)
234@@ -1518,7 +1518,8 @@
235             startChan["coderate_hp"],    startChan["coderate_lp"],
236             startChan["constellation"],  startChan["trans_mode"],
237             startChan["guard_interval"], startChan["hierarchy"],
238-            startChan["modulation"],     startChan["bandwidth"]);
239+            startChan["modulation"],     startChan["bandwidth"],
240+            startChan["msystem"],        startChan["rolloff"]);
241     }
242 
243     if (ok)
244Index: libs/libmythtv/channelscan/modulationsetting.h
245===================================================================
246--- libs/libmythtv/channelscan/modulationsetting.h      (révision 20533)
247+++ libs/libmythtv/channelscan/modulationsetting.h      (copie de travail)
248@@ -58,9 +58,7 @@
249     {
250         addSelection(QObject::tr("Auto"),"auto",true);
251         addSelection("QPSK","qpsk");
252-#ifdef FE_GET_EXTENDED_INFO
253         addSelection("8PSK","8psk");
254-#endif
255         addSelection("QAM 16","qam_16");
256         addSelection("QAM 32","qam_32");
257         addSelection("QAM 64","qam_64");
258Index: libs/libmythtv/channelscan/channelscanmiscsettings.h
259===================================================================
260--- libs/libmythtv/channelscan/channelscanmiscsettings.h        (révision 20533)
261+++ libs/libmythtv/channelscan/channelscanmiscsettings.h        (copie de travail)
262@@ -146,11 +146,13 @@
263         addSelection("1/2");
264         addSelection("2/3");
265         addSelection("3/4");
266+        addSelection("3/5");
267         addSelection("4/5");
268         addSelection("5/6");
269         addSelection("6/7");
270         addSelection("7/8");
271         addSelection("8/9");
272+        addSelection("9/10");
273     }
274 };
275 
276@@ -165,6 +167,38 @@
277     }
278 };
279 
280+class ScanModulationSystem: public ComboBoxSetting, public TransientStorage
281+{
282+  public:
283+    ScanModulationSystem() : ScanModulationSystemSetting(this)
284+    {
285+        setLabel(QObject::tr("Modul. System"));
286+        setHelpText(QObject::tr("Modulation System (Default: DVB-S)"));
287+        addSelection("DVB-S","dvbs",true);
288+        addSelection("DVB-S2","dvbs2");
289+    };
290+};
291+
292+
293+class ScanRollOff: public ComboBoxSetting
294+{
295+  public:
296+    ScanRollOff(Storage *_storage) : ComboBoxSetting(_storage)
297+    {
298+        setLabel(QObject::tr("Roll-off"));
299+        setHelpText(QObject::tr(
300+                        "Roll-off (Default: Auto):\n"
301+                        "The  DVB-S2  standard  in  addition \n"
302+                        " to  the  single  DVB-S    35%  roll-off\n"
303+                        " factor,  provides  two  additional roll-off\n"
304+                        " factors to further increase transponder efficiency"));
305+        addSelection(QObject::tr("Auto"),"auto");
306+        addSelection("0.35","0.35",true);
307+        addSelection("0.20");
308+        addSelection("0.25");
309+    }
310+};
311+
312 class ScanCodeRateLP: public ScanFecSetting, public TransientStorage
313 {
314   public:
315Index: libs/libmythtv/channelscan/channelscanner.cpp
316===================================================================
317--- libs/libmythtv/channelscan/channelscanner.cpp       (révision 20533)
318+++ libs/libmythtv/channelscan/channelscanner.cpp       (copie de travail)
319@@ -146,6 +146,7 @@
320     }
321     else if ((ScanTypeSetting::NITAddScan_DVBT == scantype) ||
322              (ScanTypeSetting::NITAddScan_DVBS == scantype) ||
323+             (ScanTypeSetting::NITAddScan_DVBS2 == scantype) ||
324              (ScanTypeSetting::NITAddScan_DVBC == scantype))
325     {
326         VERBOSE(VB_CHANSCAN, LOC + "ScanTransports()");
327@@ -221,6 +222,7 @@
328     DTVConfParser::cardtype_t type = DTVConfParser::UNKNOWN;
329     type = (CardUtil::DVBT == cardtype) ? DTVConfParser::OFDM : type;
330     type = (CardUtil::QPSK == cardtype) ? DTVConfParser::QPSK : type;
331+    type = (CardUtil::DVBS2 == cardtype) ? DTVConfParser::DVBS2 : type;
332     type = (CardUtil::DVBC == cardtype) ? DTVConfParser::QAM  : type;
333     type = ((CardUtil::ATSC == cardtype) ||
334             (CardUtil::HDHOMERUN == cardtype)) ? DTVConfParser::ATSC : type;
335@@ -304,6 +306,7 @@
336         QString sub_type = CardUtil::ProbeDVBType(device).toUpper();
337         bool need_nit = (("QAM"  == sub_type) ||
338                          ("QPSK" == sub_type) ||
339+                         ("DVB_S2" == sub_type) ||
340                          ("OFDM" == sub_type));
341 
342         // Ugh, Some DVB drivers don't fully support signal monitoring...
343Index: libs/libmythtv/channelscan/panedvbs2.h
344===================================================================
345--- libs/libmythtv/channelscan/panedvbs2.h      (révision 20533)
346+++ libs/libmythtv/channelscan/panedvbs2.h      (copie de travail)
347@@ -22,9 +22,11 @@
348         left->addChild( pfrequency  = new ScanFrequency());
349         left->addChild( ppolarity   = new ScanPolarity());
350         left->addChild( psymbolrate = new ScanSymbolRate());
351-        right->addChild(pfec        = new ScanFec());
352+        left->addChild( pfec        = new ScanFec());
353+        right->addChild(pmsystem    = new ScanModulationSystem());
354         right->addChild(pmodulation = new ScanModulation());
355         right->addChild(pinversion  = new ScanInversion());
356+        right->addChild(prolloff    = new ScanRollOff());
357         addChild(left);
358         addChild(right);     
359     }
360@@ -35,6 +37,8 @@
361     QString fec(void)        const { return pfec->getValue();        }
362     QString polarity(void)   const { return ppolarity->getValue();   }
363     QString modulation(void) const { return pmodulation->getValue(); }
364+    QString rolloff(void)    const { return prolloff->getValue();    }
365+    QString msystem(void)    const { return pmsystem->getValue();    }
366 
367   protected:
368     ScanFrequency  *pfrequency;
369@@ -43,6 +47,8 @@
370     ScanFec        *pfec;
371     ScanPolarity   *ppolarity;
372     ScanModulation *pmodulation;
373+    ScanRollOff    *prolloff;
374+    ScanModulationSystem    *pmsystem;
375 };
376 
377 #endif // _PANE_DVBS2_H_
378Index: libs/libmythtv/channelscan/scanwizardconfig.cpp
379===================================================================
380--- libs/libmythtv/channelscan/scanwizardconfig.cpp     (révision 20533)
381+++ libs/libmythtv/channelscan/scanwizardconfig.cpp     (copie de travail)
382@@ -140,6 +140,12 @@
383             addSelection(tr("Import existing scan"),
384                          QString::number(ExistingScanImport));
385             break;
386+        case CardUtil::DVBS2:
387+            addSelection(tr("Full Scan (Tuned)"),
388+                    QString::number(NITAddScan_DVBS2));
389+            addSelection(tr("Import channels.conf"),
390+                    QString::number(DVBUtilsImport));
391+            break;       
392         case CardUtil::QAM:
393             addSelection(tr("Full Scan (Tuned)"),
394                          QString::number(NITAddScan_DVBC));
395@@ -376,6 +382,19 @@
396         startChan["modulation"] = "qpsk";
397         startChan["polarity"]   = pane->polarity();
398     }
399+    else if (ScanTypeSetting::NITAddScan_DVBS2 == st)
400+    {
401+        const PaneDVBS2 *pane = paneDVBS2;
402+
403+        startChan["std"]        = "dvb";
404+        startChan["frequency"]  = pane->frequency();
405+        startChan["inversion"]  = pane->inversion();
406+        startChan["symbolrate"] = pane->symbolrate();
407+        startChan["fec"]        = pane->fec();
408+        startChan["modulation"] = pane->modulation();;
409+        startChan["polarity"]   = pane->polarity();
410+        startChan["rolloff"]    = pane->rolloff();
411+    }
412     else if (ScanTypeSetting::NITAddScan_DVBC == st)
413     {
414         const PaneDVBC *pane = paneDVBC;
415Index: libs/libmythtv/dtvconfparserhelpers.cpp
416===================================================================
417--- libs/libmythtv/dtvconfparserhelpers.cpp     (révision 20533)
418+++ libs/libmythtv/dtvconfparserhelpers.cpp     (copie de travail)
419@@ -47,9 +47,6 @@
420     dtv_tt_canonical_str[kTunerTypeQAM]     = "QAM";
421     dtv_tt_canonical_str[kTunerTypeOFDM]    = "OFDM";
422     dtv_tt_canonical_str[kTunerTypeATSC]    = "ATSC";
423-    dtv_tt_canonical_str[kTunerTypeDVB_S]   = "DVB_S";
424-    dtv_tt_canonical_str[kTunerTypeDVB_C]   = "DVB_C";
425-    dtv_tt_canonical_str[kTunerTypeDVB_T]   = "DVB_T";
426     dtv_tt_canonical_str[kTunerTypeDVB_S2]  = "DVB_S2";
427     dtv_tt_canonical_str[kTunerTypeUnknown] = "UNKNOWN";
428 }
429@@ -69,9 +66,6 @@
430     { "QAM",     kTunerTypeQAM     },
431     { "OFDM",    kTunerTypeOFDM    },
432     { "ATSC",    kTunerTypeATSC    },
433-    { "DVB_S",   kTunerTypeDVB_S   },
434-    { "DVB_C",   kTunerTypeDVB_C   },
435-    { "DVB_T",   kTunerTypeDVB_T   },
436     { "DVB_S2",  kTunerTypeDVB_S2  },
437     { "UNKNOWN", kTunerTypeUnknown },
438     { NULL,      kTunerTypeUnknown },
439@@ -154,7 +148,9 @@
440     { "FEC_6_7",  kFEC_6_7  },
441     { "FEC_7_8",  kFEC_7_8  },
442     { "FEC_8_9",  kFEC_8_9  },
443-    { "FEC_NONE", kFECNone },
444+    { "FEC_3_5",  kFEC_3_5  },
445+    { "FEC_9_10", kFEC_9_10 },
446+    { "FEC_NONE", kFECNone  },
447     { NULL,       kFECAuto },
448 };
449 
450@@ -164,11 +160,13 @@
451     { "12",  kFEC_1_2 },
452     { "23",  kFEC_2_3 },
453     { "34",  kFEC_3_4 },
454+    { "35",  kFEC_3_5 },
455     { "45",  kFEC_4_5 },
456     { "56",  kFEC_5_6 },
457     { "67",  kFEC_6_7 },
458     { "78",  kFEC_7_8 },
459     { "89",  kFEC_8_9 },
460+    { "910", kFEC_9_10},
461     { "0",   kFECNone },
462     { NULL,  kFECAuto }
463 };
464@@ -184,6 +182,8 @@
465     { "6/7",  kFEC_6_7 },
466     { "7/8",  kFEC_7_8 },
467     { "8/9",  kFEC_8_9 },
468+    { "3/5",  kFEC_3_5 },
469+    { "9/10", kFEC_9_10},
470     { "none", kFECNone },
471     { NULL,   kFECAuto }
472 };
473@@ -199,7 +199,9 @@
474      "6/7",  ///< kFEC_6_7
475      "7/8",  ///< kFEC_7_8
476      "8/9",  ///< kFEC_8_9
477-     "auto"  ///< kFECAuto
478+     "3/5",  ///< kFEC_3_5
479+     "9/10", ///< kFEC_9_10
480+     "auto", ///< kFECAuto
481 };
482 
483 const DTVParamHelperStruct DTVModulation::confTable[] =
484@@ -220,6 +222,7 @@
485    { "32APSK",   kModulation32APSK  },
486    { "8PSK",     kModulation8PSK    },
487    { "16PSK",    kModulation16PSK   },
488+   { "DQPSK",    kModulationDQPSK   },
489    { "analog",   kModulationAnalog  },
490    { NULL,       kModulationQAMAuto },
491 };
492@@ -232,6 +235,12 @@
493    { "64",  kModulationQAM64   },
494    { "128", kModulationQAM128  },
495    { "256", kModulationQAM256  },
496+   { "2",   kModulationQPSK    },
497+   { "10",  kModulation8VSB    },
498+   { "11",  kModulation16VSB   },
499+   { "6",   kModulation16APSK  },
500+   { "7",   kModulation32APSK  },
501+   { "5",   kModulation8PSK    },
502    { "0",   kModulationQPSK    },
503    { NULL,  kModulationQAMAuto },
504 };
505@@ -254,6 +263,7 @@
506    { "32apsk",   kModulation32APSK  },
507    { "8psk",     kModulation8PSK    },
508    { "16psk",    kModulation16PSK   },
509+   { "dqpsk",    kModulationDQPSK   },
510    // alternates
511    { "a",        kModulationQAMAuto },
512    { "qam_auto", kModulationQAMAuto },
513@@ -272,6 +282,7 @@
514    { "32-apsk",  kModulation32APSK  },
515    { "8-psk",    kModulation8PSK    },
516    { "16-psk",   kModulation16PSK   },
517+   { "dq-psk",   kModulationDQPSK   },
518    { NULL,       kModulationQAMAuto },
519 };
520 
521@@ -293,6 +304,7 @@
522     "32apsk",  ///< kModulation32APSK
523     "8psk",    ///< kModulation8PSK
524     "16psk",   ///< kModulation16PSK
525+    "dqpsk",   ///< kModulationDQPSK
526 };
527 
528 const DTVParamHelperStruct DTVTransmitMode::confTable[] =
529@@ -420,3 +432,65 @@
530    "r", ///< kPolarityRight
531    "l"  ///< kPolarityLeft
532 };
533+
534+const DTVParamHelperStruct DTVModulationSystem::confTable[] =
535+{
536+   { "SYS_DVBS",  kModulationSystemDVBS  },
537+   { "SYS_DVBS2", kModulationSystemDVBS2 },
538+   { NULL,        kModulationSystemDVBS  },
539+};
540+
541+const DTVParamHelperStruct DTVModulationSystem::vdrTable[] =
542+{
543+   { "0",  kModulationSystemDVBS  },
544+   { "1",  kModulationSystemDVBS2 },
545+   { NULL, kModulationSystemDVBS  },
546+};
547+
548+const DTVParamHelperStruct DTVModulationSystem::parseTable[] =
549+{
550+   { "dvbs2", kModulationSystemDVBS2 },
551+   { "dvbs",  kModulationSystemDVBS  },
552+   { NULL,    kModulationSystemDVBS  },
553+};
554+
555+const char *DTVModulationSystem::dbStr[DTVModulationSystem::kDBStrCnt] =
556+{
557+    "dvbs",  ///< kModulationSystemDVBS
558+    "dvbs2", ///< kModulationSystemDVBS2
559+};
560+
561+const DTVParamHelperStruct DTVRollOff::confTable[] =
562+{
563+   { "ROLLOFF_35",   kRollOff35   },
564+   { "ROLLOFF_20",   kRollOff20   },
565+   { "ROLLOFF_25",   kRollOff25   },
566+   { "ROLLOFF_AUTO", kRollOffAuto },
567+   { NULL,           kRollOffAuto },
568+};
569+
570+const DTVParamHelperStruct DTVRollOff::vdrTable[] =
571+{
572+   { "35",   kRollOff35   },
573+   { "20",   kRollOff20   },
574+   { "25",   kRollOff25   },
575+   { "0",    kRollOffAuto },
576+   { NULL,   kRollOff35   },
577+};
578+
579+const DTVParamHelperStruct DTVRollOff::parseTable[] =
580+{
581+   { "0.35",   kRollOff35   },
582+   { "0.20",   kRollOff20   },
583+   { "0.25",   kRollOff25   },
584+   { "auto",   kRollOffAuto },
585+   { NULL,     kRollOff35   },
586+};
587+
588+const char *DTVRollOff::dbStr[DTVRollOff::kDBStrCnt] =
589+{
590+   "0.35",   ///< kRollOff35
591+   "0.20",   ///< kRollOff20
592+   "0.25",   ///< kRollOff25
593+   "auto",   ///< kRollOffAuto
594+};
595Index: libs/libmythtv/dtvconfparser.cpp
596===================================================================
597--- libs/libmythtv/dtvconfparser.cpp    (révision 20533)
598+++ libs/libmythtv/dtvconfparser.cpp    (copie de travail)
599@@ -112,7 +112,7 @@
600         {
601             if ((type == OFDM) && (str == "T"))
602                 ok &= ParseVDR(list, channelNo);
603-            else if ((type == QPSK) && (str == "S"))
604+            else if (((type == QPSK) || (type == DVBS2)) && (str == "S"))
605                 ok &= ParseVDR(list, channelNo);
606             else if ((type == QAM) && (str == "C"))
607                 ok &= ParseVDR(list, channelNo);
608@@ -121,7 +121,7 @@
609             ok &= ParseConfOFDM(list);
610         else if (type == ATSC)
611             ok &= ParseConfATSC(list);
612-        else if (type == QPSK)
613+        else if ((type == QPSK) || (type == DVBS2))
614             ok &= ParseConfQPSK(list);
615         else if (type == QAM)
616             ok &= ParseConfQAM(list);
617@@ -213,6 +213,7 @@
618     PARSE_SKIP(unknown);
619     PARSE_SKIP(unknown);
620     PARSE_UINT(chan.serviceid);
621+    mux.modulation = DTVModulation::kModulationQPSK;
622 
623     AddChannel(mux, chan);
624 
625@@ -274,6 +275,10 @@
626             case 'R':
627             case 'L':
628                 mux.polarity.ParseVDR(ori);
629+            case 'S':
630+                mux.msystem.ParseVDR(params);
631+            case 'O':
632+                mux.rolloff.ParseVDR(params);
633                 break;
634             default:
635                 return false;
636Index: libs/libmythtv/dtvmultiplex.h
637===================================================================
638--- libs/libmythtv/dtvmultiplex.h       (révision 20533)
639+++ libs/libmythtv/dtvmultiplex.h       (copie de travail)
640@@ -49,31 +49,40 @@
641         const QString &symbol_rate,  const QString &fec_inner,
642         const QString &modulation,   const QString &polarity);
643 
644+    bool ParseDVB_S2(
645+        const QString &frequency,    const QString &inversion,
646+        const QString &symbol_rate,  const QString &fec_inner,
647+        const QString &modulation,   const QString &polarity,
648+        const QString &msystem,      const QString &rolloff);
649+
650     bool ParseTuningParams(
651         DTVTunerType type,
652         QString frequency,    QString inversion,      QString symbolrate,
653         QString fec,          QString polarity,
654         QString hp_code_rate, QString lp_code_rate,   QString constellation,
655         QString trans_mode,   QString guard_interval, QString hierarchy,
656-        QString modulation,   QString bandwidth);
657+        QString modulation,   QString bandwidth,
658+        QString msystem,      QString rolloff);
659 
660     QString toString() const;
661 
662   public:
663     // Basic tuning
664-    uint64_t         frequency;
665-    uint64_t         symbolrate;
666-    DTVInversion     inversion;
667-    DTVBandwidth     bandwidth;
668-    DTVCodeRate      hp_code_rate;  ///< High Priority FEC rate
669-    DTVCodeRate      lp_code_rate;  ///< Low Priority FEC rate
670-    //DTVModulation    constellation; ///< Modulation for OFDM, TODO Remove
671-    DTVModulation    modulation;
672-    DTVTransmitMode  trans_mode;
673-    DTVGuardInterval guard_interval;
674-    DTVHierarchy     hierarchy;
675-    DTVPolarity      polarity;
676-    DTVCodeRate      fec; ///< Inner Forward Error Correction rate
677+    uint64_t            frequency;
678+    uint64_t            symbolrate;
679+    DTVInversion        inversion;
680+    DTVBandwidth        bandwidth;
681+    DTVCodeRate         hp_code_rate;  ///< High Priority FEC rate
682+    DTVCodeRate         lp_code_rate;  ///< Low Priority FEC rate
683+    //DTVModulation     constellation; ///< Modulation for OFDM, TODO Remove
684+    DTVModulation       modulation;
685+    DTVTransmitMode     trans_mode;
686+    DTVGuardInterval    guard_interval;
687+    DTVHierarchy        hierarchy;
688+    DTVPolarity         polarity;
689+    DTVCodeRate         fec; ///< Inner Forward Error Correction rate
690+    DTVModulationSystem msystem;
691+    DTVRollOff          rolloff;
692 
693     // Optional additional info
694     uint             mplex;
695@@ -99,8 +108,10 @@
696         QString fec,          QString polarity,
697         QString hp_code_rate, QString lp_code_rate,   QString constellation,
698         QString trans_mode,   QString guard_interval, QString hierarchy,
699-        QString modulation,   QString bandwidth);
700+        QString modulation,   QString bandwidth,
701+       QString msystem,      QString rolloff);
702 
703+
704   public:
705     DTVTunerType          tuner_type;
706     uint                  cardid;
707Index: libs/libmythtv/channelutil.h
708===================================================================
709--- libs/libmythtv/channelutil.h        (révision 20533)
710+++ libs/libmythtv/channelutil.h        (copie de travail)
711@@ -67,7 +67,8 @@
712         signed char trans_mode,
713         QString     inner_FEC,    QString     constellation,
714         signed char hierarchy,    QString     hp_code_rate,
715-        QString     lp_code_rate, QString     guard_interval);
716+        QString     lp_code_rate, QString     guard_interval,
717+        QString     msystem,      QString     rolloff);
718 
719     static uint    CreateMultiplex(uint sourceid, const DTVMultiplex&,
720                                    int transport_id, int network_id);
721@@ -85,11 +86,13 @@
722     static int     GetBetterMplexID(int current_mplexid,
723                                     int transport_id, int network_id);
724 
725-    static bool    GetTuningParams(uint mplexid,
726+    static bool    GetTuningParams(uint      mplexid,
727                                    QString  &modulation,
728                                    uint64_t &frequency,
729                                    uint     &dvb_transportid,
730                                    uint     &dvb_networkid,
731+                                   QString  &dvb_msystem,
732+                                   QString  &dvb_rolloff,
733                                    QString  &si_std);
734 
735     static bool    GetATSCChannel(uint sourceid, const QString &channum,
736@@ -156,9 +159,10 @@
737         QString &tvformat,        QString       &modulation,
738         QString &freqtable,       QString       &freqid,
739         int     &finetune,        uint64_t      &frequency,
740-        QString &dtv_si_std,      int     &mpeg_prog_num,
741+        QString &dtv_si_std,      int           &mpeg_prog_num,
742         uint    &atsc_major,      uint          &atsc_minor,
743         uint    &dvb_transportid, uint          &dvb_networkid,
744+        QString &dvb_msystem,     QString       &dvb_rolloff,
745         uint    &mplexid,         bool          &commfree);
746     static bool    GetChannelSettings(int chanid, bool &useonairguide,
747                                     bool &hidden);
748Index: libs/libmythtv/cardutil.h
749===================================================================
750--- libs/libmythtv/cardutil.h   (révision 20533)
751+++ libs/libmythtv/cardutil.h   (copie de travail)
752@@ -55,6 +55,7 @@
753         HDHOMERUN = 10,
754         FREEBOX   = 11,
755         HDPVR     = 12,
756+        DVBS2     = 13,
757     };
758 
759     static enum CARD_TYPES toCardType(const QString &name)
760@@ -85,6 +86,8 @@
761             return FREEBOX;
762         if ("HDPVR" == name)
763             return HDPVR;
764+        if ("DVB_S2" == name)
765+            return DVBS2;
766         return ERROR_UNKNOWN;
767     }
768 
769Index: libs/libmythtv/libmythtv.pro
770===================================================================
771--- libs/libmythtv/libmythtv.pro        (révision 20533)
772+++ libs/libmythtv/libmythtv.pro        (copie de travail)
773@@ -25,7 +25,7 @@
774 DEPENDPATH  += ../libmyth ../libavcodec ../libavformat ../libavutil ../libswscale
775 DEPENDPATH  += ../libmythmpeg2 ../libmythdb ../libmythhdhomerun
776 DEPENDPATH  += ../libmythdvdnav/
777-DEPENDPATH  += ./dvbdev ./mpeg ./iptv ./channelscan
778+DEPENDPATH  += ./dvbdev ./mpeg ./iptv
779 DEPENDPATH  += ../libmythlivemedia/BasicUsageEnvironment/include
780 DEPENDPATH  += ../libmythlivemedia/BasicUsageEnvironment
781 DEPENDPATH  += ../libmythlivemedia/groupsock/include
782@@ -249,9 +249,6 @@
783 SOURCES += dtvmultiplex.cpp
784 SOURCES += dtvconfparser.cpp        dtvconfparserhelpers.cpp
785 
786-HEADERS += channelscan/scaninfo.h   channelscan/channelimporter.h
787-SOURCES += channelscan/scaninfo.cpp channelscan/channelimporter.cpp
788-
789 using_frontend {
790     # Recording profile stuff
791     HEADERS += profilegroup.h
792@@ -402,44 +399,13 @@
793     SOURCES += inputinfo.cpp               inputgroupmap.cpp
794 
795     # Channel scanner stuff
796-    HEADERS += scanwizard.h
797-    SOURCES += scanwizard.cpp
798+    HEADERS += scanwizard.h                scanwizardhelpers.h
799+    HEADERS += siscan.h
800+    HEADERS += scanwizardscanner.h
801+    SOURCES += scanwizard.cpp              scanwizardhelpers.cpp
802+    SOURCES += siscan.cpp
803+    SOURCES += scanwizardscanner.cpp
804 
805-    HEADERS += channelscan/channelscan_sm.h
806-    HEADERS += channelscan/channelscanner.h
807-    HEADERS += channelscan/channelscanner_gui.h
808-    HEADERS += channelscan/channelscanner_cli.h
809-    HEADERS += channelscan/frequencytablesetting.h
810-    HEADERS += channelscan/inputselectorsetting.h
811-    HEADERS += channelscan/loglist.h
812-    HEADERS += channelscan/channelscanmiscsettings.h
813-    HEADERS += channelscan/modulationsetting.h
814-    HEADERS += channelscan/multiplexsetting.h
815-    HEADERS += channelscan/paneanalog.h
816-    HEADERS += channelscan/paneatsc.h
817-    HEADERS += channelscan/panedvbc.h
818-    HEADERS += channelscan/panedvbs.h
819-    HEADERS += channelscan/panedvbs2.h
820-    HEADERS += channelscan/panedvbt.h
821-    HEADERS += channelscan/panedvbutilsimport.h
822-    HEADERS += channelscan/panesingle.h
823-    HEADERS += channelscan/scanmonitor.h
824-    HEADERS += channelscan/scanprogresspopup.h
825-    HEADERS += channelscan/scanwizardconfig.h
826-
827-    SOURCES += channelscan/channelscan_sm.cpp
828-    SOURCES += channelscan/channelscanner.cpp
829-    SOURCES += channelscan/channelscanner_gui.cpp
830-    SOURCES += channelscan/channelscanner_cli.cpp
831-    SOURCES += channelscan/frequencytablesetting.cpp
832-    SOURCES += channelscan/inputselectorsetting.cpp
833-    SOURCES += channelscan/loglist.cpp
834-    SOURCES += channelscan/multiplexsetting.cpp
835-    SOURCES += channelscan/paneanalog.cpp
836-    SOURCES += channelscan/scanmonitor.cpp
837-    SOURCES += channelscan/scanprogresspopup.cpp
838-    SOURCES += channelscan/scanwizardconfig.cpp
839-
840     # EIT stuff
841     HEADERS += eithelper.h                 eitscanner.h
842     HEADERS += eitfixup.h                  eitcache.h
843Index: libs/libmythtv/scanwizardhelpers.h
844===================================================================
845--- libs/libmythtv/scanwizardhelpers.h  (révision 0)
846+++ libs/libmythtv/scanwizardhelpers.h  (révision 0)
847@@ -0,0 +1,992 @@
848+/* -*- Mode: c++ -*-
849+ * $Id$
850+ * vim: set expandtab tabstop=4 shiftwidth=4:
851+ *
852+ * Original Project
853+ *      MythTV      http://www.mythtv.org
854+ *
855+ * Author(s):
856+ *      John Pullan  (john@pullan.org)
857+ *
858+ * Description:
859+ *     Collection of classes to provide dvb channel scanning
860+ *     functionality
861+ *
862+ *
863+ * This program is free software; you can redistribute it and/or
864+ * modify it under the terms of the GNU General Public License
865+ * as published by the Free Software Foundation; either version 2
866+ * of the License, or (at your option) any later version.
867+ *
868+ * This program is distributed in the hope that it will be useful,
869+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
870+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
871+ * GNU General Public License for more details.
872+ *
873+ * You should have received a copy of the GNU General Public License
874+ * along with this program; if not, write to the Free Software
875+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
876+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
877+ *
878+ */
879+
880+#ifndef SCANWIZARDHELPERS_H
881+#define SCANWIZARDHELPERS_H
882+
883+#include "compat.h"
884+#include "settings.h"
885+
886+#include <qwaitcondition.h>
887+#include <qevent.h>
888+
889+class TransFreqTableSelector;
890+class TransLabelSetting;
891+class ScanWizardScanner;
892+class ScanWizard;
893+class OptionalTypeSetting;
894+class VideoSourceSelector;
895+class OFDMPane;
896+class QPSKPane;
897+class DVBS2Pane;
898+class ATSCPane;
899+class QAMPane;
900+class AnalogPane;
901+class STPane;
902+class DVBUtilsImportPane;
903+
904+class ScanSignalMeter: public ProgressSetting, public TransientStorage
905+{
906+  public:
907+    ScanSignalMeter(int steps): ProgressSetting(this, steps) {};
908+};
909+
910+class ScanProgressPopup : public ConfigurationPopupDialog
911+{
912+    Q_OBJECT
913+
914+    friend class QObject; // quiet OSX gcc warning
915+
916+  public:
917+    ScanProgressPopup(bool lock, bool strength, bool snr);
918+    virtual void deleteLater(void);
919+
920+    void CreateDialog(void);
921+    virtual DialogCode exec(void);
922+    void DeleteDialog(void);
923+
924+    void SetStatusSignalToNoise(int value);
925+    void SetStatusSignalStrength(int value);
926+    void SetStatusLock(int value);
927+    void SetScanProgress(double value);
928+
929+    void SetStatusText(const QString &value);
930+    void SetStatusTitleText(const QString &value);
931+
932+  private slots:
933+    void Done(void);
934+
935+  private:
936+    ~ScanProgressPopup();
937+
938+    bool               done;
939+    QWaitCondition     wait;
940+
941+    ScanSignalMeter   *ss;
942+    ScanSignalMeter   *sn;
943+    ScanSignalMeter   *progressBar;
944+
945+    TransLabelSetting *sl;
946+    TransLabelSetting *sta;
947+};
948+
949+class ScannerEvent : public QEvent
950+{
951+    friend class QObject; // quiet OSX gcc warning
952+
953+  public:
954+    enum TYPE
955+    {
956+        ScanComplete,
957+        ScanShutdown,
958+        AppendTextToLog,
959+        SetStatusText,
960+        SetStatusTitleText,
961+        SetPercentComplete,
962+        SetStatusRotorPosition,
963+        SetStatusSignalToNoise,
964+        SetStatusSignalStrength,
965+        SetStatusSignalLock,
966+    };
967+
968+    ScannerEvent(TYPE t) :
969+        QEvent((QEvent::Type)(t + QEvent::User)),
970+        str(""), intvalue(0), spp_ptr(NULL) { ; }
971+
972+    QString strValue()              const { return str; }
973+    void    strValue(const QString& _str) { str = _str; }
974+
975+    int     intValue()        const { return intvalue; }
976+    void    intValue(int _intvalue) { intvalue = _intvalue; }
977+
978+    ScanProgressPopup *ScanProgressPopupValue() const { return spp_ptr; }
979+    void    ScanProgressPopupValue(ScanProgressPopup *_spp_ptr)
980+        { spp_ptr = _spp_ptr; }
981+
982+    TYPE    eventType()       const { return (TYPE)(type()-QEvent::User); }
983+
984+  private:
985+    ~ScannerEvent() { }
986+
987+  private:
988+    QString str;
989+    int     intvalue;
990+    ScanProgressPopup *spp_ptr;
991+};
992+
993+void post_event(QObject *dest, ScannerEvent::TYPE type, int val);
994+void post_event(QObject *dest, ScannerEvent::TYPE type, const QString &val);
995+void post_event(QObject *dest, ScannerEvent::TYPE type, int val,
996+                ScanProgressPopup *spp);
997+
998+// ///////////////////////////////
999+// Settings Below Here
1000+// ///////////////////////////////
1001+
1002+class MultiplexSetting : public ComboBoxSetting, public TransientStorage
1003+{
1004+    Q_OBJECT
1005+
1006+  public:
1007+    MultiplexSetting() : ComboBoxSetting(this), sourceid(0)
1008+        { setLabel(tr("Transport")); }
1009+
1010+    virtual void Load(void);
1011+
1012+    void SetSourceID(uint _sourceid);
1013+
1014+  protected:
1015+    uint sourceid;
1016+};
1017+
1018+class IgnoreSignalTimeout : public CheckBoxSetting, public TransientStorage
1019+{
1020+  public:
1021+    IgnoreSignalTimeout() : CheckBoxSetting(this)
1022+    {
1023+        setLabel(QObject::tr("Ignore Signal Timeout"));
1024+        setHelpText(
1025+            QObject::tr("This option allows you to slow down the scan for "
1026+                        "broken drivers, such as the DVB drivers for the "
1027+                        "Leadtek LR6650 DVB card."));
1028+    }
1029+};
1030+
1031+class InputSelector : public ComboBoxSetting, public TransientStorage
1032+{
1033+    Q_OBJECT
1034+
1035+  public:
1036+    InputSelector(uint _default_cardid, const QString &_default_inputname);
1037+
1038+    virtual void Load(void);
1039+
1040+    uint GetCardID(void) const;
1041+
1042+    QString GetInputName(void) const;
1043+
1044+    static bool Parse(const QString &cardid_inputname,
1045+                      uint          &cardid,
1046+                      QString       &inputname);
1047+
1048+  public slots:
1049+    void SetSourceID(const QString &_sourceid);
1050+
1051+  private:
1052+    uint    sourceid;
1053+    uint    default_cardid;
1054+    QString default_inputname;
1055+};
1056+
1057+class ScanCountry : public ComboBoxSetting, public TransientStorage
1058+{
1059+    Q_OBJECT
1060+
1061+  public:
1062+    enum Country
1063+    {
1064+        AU,
1065+        FI,
1066+        SE,
1067+        UK,
1068+        DE,
1069+        ES,
1070+        NZ,
1071+        FR,
1072+    };
1073+
1074+    ScanCountry();
1075+};
1076+
1077+class ScanTypeSetting : public ComboBoxSetting, public TransientStorage
1078+{
1079+    Q_OBJECT
1080+  public:
1081+    enum Type
1082+    {
1083+        Error_Open = 0,
1084+        Error_Probe,
1085+        // Scans that check each frequency in a predefined list
1086+        FullScan_Analog,
1087+        FullScan_ATSC,
1088+        FullScan_OFDM,
1089+        // Scans starting on one frequency that adds each transport
1090+        // seen in the Network Information Tables to the scan.
1091+        NITAddScan_OFDM,
1092+        NITAddScan_QPSK,
1093+        NITAddScan_DVBS2,
1094+        NITAddScan_QAM,
1095+        // Scan of all transports already in the database
1096+        FullTransportScan,
1097+        // Scan of one transport already in the database
1098+        TransportScan,
1099+        // IPTV import of channels from M3U URL
1100+        IPTVImport,
1101+        // Imports lists from dvb-utils scanners
1102+        DVBUtilsImport,
1103+    };
1104+
1105+    ScanTypeSetting() : ComboBoxSetting(this), hw_cardid(0)
1106+        { setLabel(QObject::tr("Scan Type")); }
1107+
1108+  protected slots:
1109+    void SetInput(const QString &cardids_inputname);
1110+
1111+  protected:
1112+    uint    hw_cardid;
1113+};
1114+
1115+class ScanOptionalConfig : public TriggeredConfigurationGroup
1116+{
1117+    Q_OBJECT
1118+
1119+  public:
1120+    ScanOptionalConfig(ScanTypeSetting *_scan_type);
1121+
1122+    QString GetATSCFormat(const QString&)    const;
1123+    QString GetFrequencyStandard(void)       const;
1124+    QString GetModulation(void)              const;
1125+    QString GetRollOff(void)                 const;
1126+    QString GetFrequencyTable(void)          const;
1127+    bool    DoIgnoreSignalTimeout(void)      const;
1128+    QString GetFilename(void)                const;
1129+    uint    GetMultiplex(void)               const;
1130+    bool    DoDeleteChannels(void)           const;
1131+    bool    DoRenameChannels(void)           const;
1132+    QMap<QString,QString> GetStartChan(void) const;
1133+
1134+    void SetDefaultATSCFormat(const QString &atscFormat);
1135+
1136+  public slots:
1137+    void SetSourceID(const QString&);
1138+    void triggerChanged(const QString&);
1139+
1140+  private:
1141+    ScanTypeSetting     *scanType;
1142+    ScanCountry         *country;
1143+    IgnoreSignalTimeout *ignoreSignalTimeoutAll;
1144+    OFDMPane            *paneOFDM;
1145+    QPSKPane            *paneQPSK;
1146+    DVBS2Pane           *paneDVBS2;
1147+    ATSCPane            *paneATSC;
1148+    QAMPane             *paneQAM;
1149+    AnalogPane          *paneAnalog;
1150+    STPane              *paneSingle;
1151+    DVBUtilsImportPane  *paneDVBUtilsImport;
1152+};
1153+
1154+class ScanWizardConfig: public VerticalConfigurationGroup
1155+{
1156+    Q_OBJECT
1157+
1158+  public:
1159+    ScanWizardConfig(ScanWizard *_parent,
1160+                     uint        default_sourceid,
1161+                     uint        default_cardid,
1162+                     QString     default_inputname);
1163+
1164+    uint    GetSourceID(void)     const;
1165+    QString GetATSCFormat(void)   const;
1166+    QString GetModulation(void)   const { return scanConfig->GetModulation(); }
1167+    int     GetScanType(void)     const { return scanType->getValue().toInt();}
1168+    uint    GetCardID(void)       const { return input->GetCardID();          }
1169+    QString GetInputName(void)    const { return input->GetInputName();       }
1170+    QString GetFilename(void)     const { return scanConfig->GetFilename();   }
1171+    uint    GetMultiplex(void)    const { return scanConfig->GetMultiplex();  }
1172+    bool DoDeleteChannels(void) const { return scanConfig->DoDeleteChannels();}
1173+    bool DoRenameChannels(void) const { return scanConfig->DoRenameChannels();}
1174+    QString GetFrequencyStandard(void) const
1175+        { return scanConfig->GetFrequencyStandard(); }
1176+    QString GetFrequencyTable(void) const
1177+        { return scanConfig->GetFrequencyTable(); }
1178+    QMap<QString,QString> GetStartChan(void) const
1179+        { return scanConfig->GetStartChan(); }
1180+    bool    DoIgnoreSignalTimeout(void) const
1181+        { return scanConfig->DoIgnoreSignalTimeout(); }
1182+
1183+    void SetDefaultATSCFormat(const QString &atscFormat)
1184+        { scanConfig->SetDefaultATSCFormat(atscFormat); }
1185+
1186+  protected:
1187+    VideoSourceSelector *videoSource;
1188+    InputSelector       *input;
1189+    ScanTypeSetting     *scanType;
1190+    ScanOptionalConfig  *scanConfig;
1191+};
1192+
1193+class LogList: public ListBoxSetting, public TransientStorage
1194+{
1195+  public:
1196+    LogList();
1197+
1198+    void updateText(const QString& status);
1199+  protected:
1200+    int n;
1201+};
1202+
1203+class ScanFrequencyTable: public ComboBoxSetting, public TransientStorage
1204+{
1205+  public:
1206+    ScanFrequencyTable() : ComboBoxSetting(this)
1207+    {
1208+        addSelection(QObject::tr("Broadcast"),        "us",          true);
1209+        addSelection(QObject::tr("Cable")     + " " +
1210+                     QObject::tr("High"),             "uscablehigh", false);
1211+        addSelection(QObject::tr("Cable HRC") + " " +
1212+                     QObject::tr("High"),             "ushrchigh",   false);
1213+        addSelection(QObject::tr("Cable IRC") + " " +
1214+                     QObject::tr("High"),             "usirchigh",   false);
1215+        addSelection(QObject::tr("Cable"),            "uscable",     false);
1216+        addSelection(QObject::tr("Cable HRC"),        "ushrc",       false);
1217+        addSelection(QObject::tr("Cable IRC"),        "usirc",       false);
1218+
1219+        setLabel(QObject::tr("Frequency Table"));
1220+        setHelpText(QObject::tr("Frequency table to use.") + " " +
1221+                    QObject::tr(
1222+                        "The option of scanning only \"High\" "
1223+                        "frequency channels is useful because most "
1224+                        "digital channels are on the higher frequencies."));
1225+    }
1226+};
1227+
1228+class ScanATSCModulation: public ComboBoxSetting, public TransientStorage
1229+{
1230+  public:
1231+    ScanATSCModulation() : ComboBoxSetting(this)
1232+    {
1233+        addSelection(QObject::tr("Terrestrial")+" (8-VSB)","vsb8",  true);
1234+        addSelection(QObject::tr("Cable") + " (QAM-256)", "qam256", false);
1235+        addSelection(QObject::tr("Cable") + " (QAM-128)", "qam128", false);
1236+        addSelection(QObject::tr("Cable") + " (QAM-64)",  "qam64",  false);
1237+
1238+        setLabel(QObject::tr("Modulation"));
1239+        setHelpText(
1240+            QObject::tr("Modulation, 8-VSB, QAM-256, etc.") + " " +
1241+            QObject::tr("Most cable systems in the United States use "
1242+                        "QAM-256 or QAM-64, but some mixed systems "
1243+                        "may use 8-VSB for over-the-air channels."));
1244+    }
1245+};
1246+
1247+class ScanATSCChannelFormat: public ComboBoxSetting, public TransientStorage
1248+{
1249+  public:
1250+    ScanATSCChannelFormat() : ComboBoxSetting(this)
1251+    {
1252+        addSelection(QObject::tr("(5_1) Underscore"), "%1_%2", true);
1253+        addSelection(QObject::tr("(5-1) Minus"),      "%1-%2", false);
1254+        addSelection(QObject::tr("(5.1) Period"),     "%1.%2", false);
1255+        addSelection(QObject::tr("(501) Zero"),       "%10%2", false);
1256+        addSelection(QObject::tr("(51) None"),        "%1%2",  false);
1257+        setLabel(QObject::tr("ATSC Channel Separator"));
1258+        setHelpText(QObject::tr("What to use to separate ATSC major "
1259+                                "and minor channels."));
1260+    }
1261+};
1262+
1263+class ScanOldChannelTreatment: public ComboBoxSetting, public TransientStorage
1264+{
1265+  public:
1266+    ScanOldChannelTreatment(bool rename = true) : ComboBoxSetting(this)
1267+    {
1268+        addSelection(QObject::tr("Minimal Updates"),    "minimal");
1269+        if (rename)
1270+            addSelection(QObject::tr("Rename to Match"),    "rename");
1271+        addSelection(QObject::tr("Delete"),             "delete");
1272+        setLabel(QObject::tr("Existing Channel Treatment"));
1273+        setHelpText(QObject::tr("How to treat existing channels."));
1274+    }
1275+};
1276+
1277+class ScanFrequency: public LineEditSetting, public TransientStorage
1278+{
1279+  public:
1280+    ScanFrequency(bool in_kHz = false) : LineEditSetting(this)
1281+    {
1282+        QString units = (in_kHz) ? "kHz" : "Hz";
1283+        setLabel(QObject::tr("Frequency (%1)").arg(units));
1284+        setHelpText(
1285+            QObject::tr(
1286+                "Frequency (Option has no default).\n"
1287+                "The frequency for this channel in %1.").arg(units));
1288+    };
1289+};
1290+
1291+class ScanSymbolRate: public ComboBoxSetting, public TransientStorage
1292+{
1293+  public:
1294+    ScanSymbolRate() : ComboBoxSetting(this, true)
1295+    {
1296+        setLabel(QObject::tr("Symbol Rate"));
1297+        setHelpText(
1298+             QObject::tr(
1299+                "Symbol Rate (symbols/second).\n"
1300+                "Most dvb-s transponders transmit at 27.5 "
1301+                "million symbols per second."));
1302+        addSelection("3333000");
1303+        addSelection("22000000");
1304+        addSelection("27500000", "27500000", true);
1305+        addSelection("28000000");
1306+        addSelection("28500000");
1307+        addSelection("29900000");
1308+    };
1309+};
1310+
1311+class ScanPolarity: public ComboBoxSetting, public TransientStorage
1312+{
1313+  public:
1314+    ScanPolarity() : ComboBoxSetting(this)
1315+    {
1316+        setLabel(QObject::tr("Polarity"));
1317+        setHelpText(QObject::tr("Polarity (Option has no default)"));
1318+        addSelection(QObject::tr("Horizontal"), "h",true);
1319+        addSelection(QObject::tr("Vertical"), "v");
1320+        addSelection(QObject::tr("Right Circular"), "r");
1321+        addSelection(QObject::tr("Left Circular"), "l");
1322+    };
1323+};
1324+
1325+class ScanInversion: public ComboBoxSetting, public TransientStorage
1326+{
1327+  public:
1328+    ScanInversion() : ComboBoxSetting(this)
1329+    {
1330+        setLabel(QObject::tr("Inversion"));
1331+        setHelpText(QObject::tr(
1332+                        "Inversion (Default: Auto):\n"
1333+                        "Most cards can autodetect this now, so "
1334+                        "leave it at Auto unless it won't work."));
1335+        addSelection(QObject::tr("Auto"), "a",true);
1336+        addSelection(QObject::tr("On"), "1");
1337+        addSelection(QObject::tr("Off"), "0");
1338+    };
1339+};
1340+
1341+class ScanBandwidth: public ComboBoxSetting, public TransientStorage
1342+{
1343+  public:
1344+    ScanBandwidth() : ComboBoxSetting(this)
1345+    {
1346+        setLabel(QObject::tr("Bandwidth"));
1347+        setHelpText(QObject::tr("Bandwidth (Default: Auto)\n"));
1348+        addSelection(QObject::tr("Auto"),"a",true);
1349+        addSelection(QObject::tr("6 MHz"),"6");
1350+        addSelection(QObject::tr("7 MHz"),"7");
1351+        addSelection(QObject::tr("8 MHz"),"8");
1352+    };
1353+};
1354+
1355+class ScanModulationSetting: public ComboBoxSetting
1356+{
1357+  public:
1358+    ScanModulationSetting(Storage *_storage) : ComboBoxSetting(_storage)
1359+    {
1360+        addSelection(QObject::tr("Auto"),"auto",true);
1361+        addSelection("QPSK","qpsk");
1362+        addSelection("8PSK","8psk");
1363+        addSelection("QAM 16","qam_16");
1364+        addSelection("QAM 32","qam_32");
1365+        addSelection("QAM 64","qam_64");
1366+        addSelection("QAM 128","qam_128");
1367+        addSelection("QAM 256","qam_256");
1368+    };
1369+};
1370+
1371+class ScanModulation: public ScanModulationSetting, public TransientStorage
1372+{
1373+  public:
1374+    ScanModulation() : ScanModulationSetting(this)
1375+    {
1376+        setLabel(QObject::tr("Modulation"));
1377+        setHelpText(QObject::tr("Modulation (Default: Auto)"));
1378+    };
1379+};
1380+
1381+class ScanModulationSystemSetting: public ComboBoxSetting
1382+{
1383+  public:
1384+    ScanModulationSystemSetting(Storage *_storage) : ComboBoxSetting(_storage)
1385+    {
1386+        addSelection("DVB-S","dvbs",true);
1387+        addSelection("DVB-S2","dvbs2");
1388+    };
1389+};
1390+
1391+class ScanModulationSystem: public ScanModulationSystemSetting, public TransientStorage
1392+{
1393+  public:
1394+    ScanModulationSystem() : ScanModulationSystemSetting(this)
1395+    {
1396+        setLabel(QObject::tr("Modul. System"));
1397+        setHelpText(QObject::tr("Modulation System (Default: DVB-S)"));
1398+    };
1399+};
1400+
1401+class ScanRollOffSetting: public ComboBoxSetting
1402+{
1403+  public:
1404+    ScanRollOffSetting(Storage *_storage) : ComboBoxSetting(_storage)
1405+    {
1406+        addSelection(QObject::tr("Auto"),"auto");
1407+        addSelection("0.35","0.35",true);
1408+        addSelection("0.20","0.20");
1409+        addSelection("0.25","0.25");
1410+    };
1411+};
1412+
1413+class ScanRollOff: public ScanRollOffSetting, public TransientStorage
1414+{
1415+  public:
1416+    ScanRollOff() : ScanRollOffSetting(this)
1417+    {
1418+        setLabel(QObject::tr("RollOff"));
1419+        setHelpText(QObject::tr("RollOff (Default: 0.35)"));
1420+    };
1421+};
1422+
1423+class ScanConstellation: public ScanModulationSetting,
1424+                         public TransientStorage
1425+{
1426+  public:
1427+    ScanConstellation() : ScanModulationSetting(this)
1428+    {
1429+        setLabel(QObject::tr("Constellation"));
1430+        setHelpText(QObject::tr("Constellation (Default: Auto)"));
1431+    };
1432+};
1433+
1434+class ScanFecSetting: public ComboBoxSetting
1435+{
1436+  public:
1437+    ScanFecSetting(Storage *_storage) : ComboBoxSetting(_storage)
1438+    {
1439+        addSelection(QObject::tr("Auto"),"auto",true);
1440+        addSelection(QObject::tr("None"),"none");
1441+        addSelection("1/2");
1442+        addSelection("2/3");
1443+        addSelection("3/4");
1444+        addSelection("3/5");
1445+        addSelection("4/5");
1446+        addSelection("5/6");
1447+        addSelection("6/7");
1448+        addSelection("7/8");
1449+        addSelection("8/9");
1450+        addSelection("9/10");
1451+    }
1452+};
1453+
1454+class ScanFec: public ScanFecSetting, public TransientStorage
1455+{
1456+  public:
1457+    ScanFec() : ScanFecSetting(this)
1458+    {
1459+        setLabel(QObject::tr("FEC"));
1460+        setHelpText(QObject::tr(
1461+                        "Forward Error Correction (Default: Auto)"));
1462+    }
1463+};
1464+
1465+class ScanCodeRateLP: public ScanFecSetting, public TransientStorage
1466+{
1467+  public:
1468+    ScanCodeRateLP() : ScanFecSetting(this)
1469+    {
1470+        setLabel(QObject::tr("LP Coderate"));
1471+        setHelpText(QObject::tr("Low Priority Code Rate (Default: Auto)"));
1472+    }
1473+};
1474+
1475+class ScanCodeRateHP: public ScanFecSetting, public TransientStorage
1476+{
1477+  public:
1478+    ScanCodeRateHP() : ScanFecSetting(this)
1479+    {
1480+        setLabel(QObject::tr("HP Coderate"));
1481+        setHelpText(QObject::tr("High Priority Code Rate (Default: Auto)"));
1482+    };
1483+};
1484+
1485+class ScanGuardInterval: public ComboBoxSetting, public TransientStorage
1486+{
1487+  public:
1488+    ScanGuardInterval() : ComboBoxSetting(this)
1489+    {
1490+        setLabel(QObject::tr("Guard Interval"));
1491+        setHelpText(QObject::tr("Guard Interval (Default: Auto)"));
1492+        addSelection(QObject::tr("Auto"),"auto");
1493+        addSelection("1/4");
1494+        addSelection("1/8");
1495+        addSelection("1/16");
1496+        addSelection("1/32");
1497+    };
1498+};
1499+
1500+class ScanTransmissionMode: public ComboBoxSetting, public TransientStorage
1501+{
1502+  public:
1503+    ScanTransmissionMode() : ComboBoxSetting(this)
1504+    {
1505+        setLabel(QObject::tr("Trans. Mode"));
1506+        setHelpText(QObject::tr("Transmission Mode (Default: Auto)"));
1507+        addSelection(QObject::tr("Auto"),"a");
1508+        addSelection("2K","2");
1509+        addSelection("8K","8");
1510+    };
1511+};
1512+
1513+class ScanHierarchy: public ComboBoxSetting, public TransientStorage
1514+{
1515+    public:
1516+    ScanHierarchy() : ComboBoxSetting(this)
1517+    {
1518+        setLabel(QObject::tr("Hierarchy"));
1519+        setHelpText(QObject::tr("Hierarchy (Default: Auto)"));
1520+        addSelection(QObject::tr("Auto"),"a");
1521+        addSelection(QObject::tr("None"), "n");
1522+        addSelection("1");
1523+        addSelection("2");
1524+        addSelection("4");
1525+    };
1526+};
1527+
1528+class OFDMPane : public HorizontalConfigurationGroup
1529+{
1530+  public:
1531+    OFDMPane() : HorizontalConfigurationGroup(false, false, true, true)
1532+    {
1533+        setUseFrame(false);
1534+        VerticalConfigurationGroup *left =
1535+            new VerticalConfigurationGroup(false,true,true,false);
1536+        VerticalConfigurationGroup *right =
1537+            new VerticalConfigurationGroup(false,true,true,false);
1538+        left->addChild(pfrequency       = new ScanFrequency());
1539+        left->addChild(pbandwidth       = new ScanBandwidth());
1540+        left->addChild(pinversion       = new ScanInversion());
1541+        left->addChild(pconstellation   = new ScanConstellation());
1542+        right->addChild(pcoderate_lp    = new ScanCodeRateLP());
1543+        right->addChild(pcoderate_hp    = new ScanCodeRateHP());
1544+        right->addChild(ptrans_mode     = new ScanTransmissionMode());
1545+        right->addChild(pguard_interval = new ScanGuardInterval());
1546+        right->addChild(phierarchy      = new ScanHierarchy());
1547+        addChild(left);
1548+        addChild(right);
1549+    }
1550+
1551+    QString frequency(void)      const { return pfrequency->getValue();     }
1552+    QString bandwidth(void)      const { return pbandwidth->getValue();     }
1553+    QString inversion(void)      const { return pinversion->getValue();     }
1554+    QString constellation(void)  const { return pconstellation->getValue(); }
1555+    QString coderate_lp(void)    const { return pcoderate_lp->getValue();   }
1556+    QString coderate_hp(void)    const { return pcoderate_hp->getValue();   }
1557+    QString trans_mode(void)     const { return ptrans_mode->getValue();    }
1558+    QString guard_interval(void) const { return pguard_interval->getValue(); }
1559+    QString hierarchy(void)      const { return phierarchy->getValue();     }
1560+
1561+  protected:
1562+    ScanFrequency        *pfrequency;
1563+    ScanInversion        *pinversion;
1564+    ScanBandwidth        *pbandwidth;
1565+    ScanConstellation    *pconstellation;
1566+    ScanCodeRateLP       *pcoderate_lp;
1567+    ScanCodeRateHP       *pcoderate_hp;
1568+    ScanTransmissionMode *ptrans_mode;
1569+    ScanGuardInterval    *pguard_interval;
1570+    ScanHierarchy        *phierarchy;
1571+};
1572+
1573+class DVBS2Pane : public HorizontalConfigurationGroup
1574+{
1575+  public:
1576+    DVBS2Pane() : HorizontalConfigurationGroup(false,false,true,false)
1577+    {
1578+        setUseFrame(false);
1579+        VerticalConfigurationGroup *left =
1580+            new VerticalConfigurationGroup(false,true);
1581+        VerticalConfigurationGroup *right =
1582+            new VerticalConfigurationGroup(false,true);
1583+        left->addChild( pfrequency  = new ScanFrequency());
1584+        left->addChild( ppolarity   = new ScanPolarity());
1585+        left->addChild( psymbolrate = new ScanSymbolRate());
1586+        left->addChild( pfec        = new ScanFec());
1587+        right->addChild(pmsystem    = new ScanModulationSystem());
1588+        right->addChild(pmodulation = new ScanModulation());
1589+        right->addChild(pinversion  = new ScanInversion());
1590+        right->addChild(prolloff    = new ScanRollOff());
1591+        addChild(left);
1592+        addChild(right);
1593+    }
1594+
1595+    QString frequency(void)  const { return pfrequency->getValue();  }
1596+    QString symbolrate(void) const { return psymbolrate->getValue(); }
1597+    QString inversion(void)  const { return pinversion->getValue();  }
1598+    QString fec(void)        const { return pfec->getValue();        }
1599+    QString polarity(void)   const { return ppolarity->getValue();   }
1600+    QString msystem(void)    const { return pmsystem->getValue();    }
1601+    QString modulation(void) const { return pmodulation->getValue(); }
1602+    QString rolloff(void)    const { return prolloff->getValue();    }
1603+
1604+  protected:
1605+    ScanFrequency        *pfrequency;
1606+    ScanSymbolRate       *psymbolrate;
1607+    ScanInversion        *pinversion;
1608+    ScanFec              *pfec;
1609+    ScanPolarity         *ppolarity;
1610+    ScanModulation       *pmodulation;
1611+    ScanModulationSystem *pmsystem;
1612+    ScanRollOff          *prolloff;
1613+};
1614+
1615+class QPSKPane : public HorizontalConfigurationGroup
1616+{
1617+  public:
1618+    QPSKPane() : HorizontalConfigurationGroup(false, false, true, false)
1619+    {
1620+        setUseFrame(false);
1621+        VerticalConfigurationGroup *left =
1622+            new VerticalConfigurationGroup(false,true);
1623+        VerticalConfigurationGroup *right =
1624+            new VerticalConfigurationGroup(false,true);
1625+        left->addChild(pfrequency  = new ScanFrequency(true));
1626+        left->addChild(ppolarity   = new ScanPolarity());
1627+        left->addChild(psymbolrate = new ScanSymbolRate());
1628+        right->addChild(pfec       = new ScanFec());
1629+        right->addChild(pinversion = new ScanInversion());
1630+        addChild(left);
1631+        addChild(right);
1632+    }
1633+
1634+    QString frequency(void)  const { return pfrequency->getValue();  }
1635+    QString symbolrate(void) const { return psymbolrate->getValue(); }
1636+    QString inversion(void)  const { return pinversion->getValue();  }
1637+    QString fec(void)        const { return pfec->getValue();        }
1638+    QString polarity(void)   const { return ppolarity->getValue();   }
1639+
1640+  protected:
1641+    ScanFrequency  *pfrequency;
1642+    ScanSymbolRate *psymbolrate;
1643+    ScanInversion  *pinversion;
1644+    ScanFec        *pfec;
1645+    ScanPolarity   *ppolarity;
1646+};
1647+
1648+class QAMPane : public HorizontalConfigurationGroup
1649+{
1650+  public:
1651+    QAMPane() : HorizontalConfigurationGroup(false, false, true, false)
1652+    {
1653+        setUseFrame(false);
1654+        VerticalConfigurationGroup *left =
1655+            new VerticalConfigurationGroup(false,true);
1656+        VerticalConfigurationGroup *right =
1657+            new VerticalConfigurationGroup(false,true);
1658+        left->addChild(pfrequency   = new ScanFrequency());
1659+        left->addChild(psymbolrate  = new ScanSymbolRate());
1660+        left->addChild(pinversion   = new ScanInversion());
1661+        right->addChild(pmodulation = new ScanModulation());
1662+        right->addChild(pfec        = new ScanFec());
1663+        addChild(left);
1664+        addChild(right);
1665+    }
1666+
1667+    QString frequency(void)  const { return pfrequency->getValue();  }
1668+    QString symbolrate(void) const { return psymbolrate->getValue(); }
1669+    QString inversion(void)  const { return pinversion->getValue();  }
1670+    QString fec(void)        const { return pfec->getValue();        }
1671+    QString modulation(void) const { return pmodulation->getValue(); }
1672+
1673+  protected:
1674+    ScanFrequency  *pfrequency;
1675+    ScanSymbolRate *psymbolrate;
1676+    ScanInversion  *pinversion;
1677+    ScanModulation *pmodulation;
1678+    ScanFec        *pfec;
1679+};
1680+
1681+class ATSCPane : public VerticalConfigurationGroup
1682+{
1683+  public:
1684+    ATSCPane() : VerticalConfigurationGroup(false, false, true, false)
1685+    {
1686+        addChild(atsc_table            = new ScanFrequencyTable());
1687+        addChild(atsc_modulation       = new ScanATSCModulation());
1688+        addChild(atsc_format           = new ScanATSCChannelFormat());
1689+        addChild(old_channel_treatment = new ScanOldChannelTreatment());
1690+    }
1691+
1692+    QString atscFreqTable(void)  const { return atsc_table->getValue();      }
1693+    QString atscModulation(void) const { return atsc_modulation->getValue(); }
1694+    QString GetATSCFormat(void)  const { return atsc_format->getValue();     }
1695+    bool DoDeleteChannels(void) const
1696+        { return old_channel_treatment->getValue() == "delete"; }
1697+    bool DoRenameChannels(void) const
1698+        { return old_channel_treatment->getValue() == "rename"; }
1699+
1700+    void SetDefaultATSCFormat(const QString &d)
1701+    {
1702+        int val = atsc_format->getValueIndex(d);
1703+        atsc_format->setValue(val);
1704+    }
1705+
1706+  protected:
1707+    ScanFrequencyTable      *atsc_table;
1708+    ScanATSCModulation      *atsc_modulation;
1709+    ScanATSCChannelFormat   *atsc_format;
1710+    ScanOldChannelTreatment *old_channel_treatment;
1711+};
1712+
1713+class AnalogPane : public VerticalConfigurationGroup
1714+{
1715+  public:
1716+    AnalogPane();
1717+
1718+    void SetSourceID(uint sourceid);
1719+
1720+    QString GetFrequencyTable(void) const;
1721+
1722+    bool DoDeleteChannels(void) const
1723+        { return old_channel_treatment->getValue() == "delete"; }
1724+    bool DoRenameChannels(void) const
1725+        { return old_channel_treatment->getValue() == "rename"; }
1726+
1727+  protected:
1728+    TransFreqTableSelector  *freq_table;
1729+    ScanOldChannelTreatment *old_channel_treatment;
1730+};
1731+
1732+class STPane : public VerticalConfigurationGroup
1733+{
1734+  public:
1735+    STPane() :
1736+        VerticalConfigurationGroup(false, false, true, false),
1737+        transport_setting(new MultiplexSetting()),
1738+        atsc_format(new ScanATSCChannelFormat()),
1739+        old_channel_treatment(new ScanOldChannelTreatment()),
1740+        ignore_signal_timeout(new IgnoreSignalTimeout())
1741+    {
1742+        addChild(transport_setting);
1743+        addChild(atsc_format);
1744+        addChild(old_channel_treatment);
1745+        addChild(ignore_signal_timeout);
1746+    }
1747+
1748+    QString GetATSCFormat(void) const { return atsc_format->getValue(); }
1749+    bool DoDeleteChannels(void) const
1750+        { return old_channel_treatment->getValue() == "delete"; }
1751+    bool DoRenameChannels(void) const
1752+        { return old_channel_treatment->getValue() == "rename"; }
1753+    int  GetMultiplex(void) const
1754+        { return transport_setting->getValue().toInt(); }
1755+    bool ignoreSignalTimeout(void) const
1756+        { return ignore_signal_timeout->getValue().toInt(); }
1757+
1758+    void SetDefaultATSCFormat(const QString &d)
1759+    {
1760+        int val = atsc_format->getValueIndex(d);
1761+        atsc_format->setValue(val);
1762+    }
1763+
1764+    void SetSourceID(uint sourceid)
1765+        { transport_setting->SetSourceID(sourceid); }
1766+
1767+  protected:
1768+    MultiplexSetting        *transport_setting;
1769+    ScanATSCChannelFormat   *atsc_format;
1770+    ScanOldChannelTreatment *old_channel_treatment;
1771+    IgnoreSignalTimeout     *ignore_signal_timeout;
1772+};
1773+
1774+class DVBUtilsImportPane : public VerticalConfigurationGroup
1775+{
1776+    Q_OBJECT
1777+
1778+  public:
1779+    DVBUtilsImportPane() :
1780+        VerticalConfigurationGroup(false,false,true,false),
1781+        filename(new TransLineEditSetting()),
1782+        atsc_format(new ScanATSCChannelFormat()),
1783+        old_channel_treatment(new ScanOldChannelTreatment()),
1784+        ignore_signal_timeout(new IgnoreSignalTimeout())
1785+    {
1786+        filename->setLabel(tr("File location"));
1787+        filename->setHelpText(tr("Location of the channels.conf file."));
1788+        addChild(filename);
1789+
1790+        addChild(atsc_format);
1791+        addChild(old_channel_treatment);
1792+        addChild(ignore_signal_timeout);
1793+    }
1794+
1795+    QString GetFilename(void)   const { return filename->getValue();    }
1796+    QString GetATSCFormat(void) const { return atsc_format->getValue(); }
1797+
1798+    bool DoDeleteChannels(void) const
1799+        { return old_channel_treatment->getValue() == "delete"; }
1800+    bool DoRenameChannels(void) const
1801+        { return old_channel_treatment->getValue() == "rename"; }
1802+    bool DoIgnoreSignalTimeout(void) const
1803+        { return ignore_signal_timeout->getValue().toInt(); }
1804+
1805+    void SetDefaultATSCFormat(const QString &d)
1806+    {
1807+        int val = atsc_format->getValueIndex(d);
1808+        atsc_format->setValue(val);
1809+    }
1810+
1811+  private:
1812+    TransLineEditSetting    *filename;
1813+    ScanATSCChannelFormat   *atsc_format;
1814+    ScanOldChannelTreatment *old_channel_treatment;
1815+    IgnoreSignalTimeout     *ignore_signal_timeout;
1816+};
1817+
1818+class ErrorPane : public HorizontalConfigurationGroup
1819+{
1820+  public:
1821+    ErrorPane(const QString &error) :
1822+        HorizontalConfigurationGroup(false, false, true, false)
1823+    {
1824+        TransLabelSetting* label = new TransLabelSetting();
1825+        label->setValue(error);
1826+        addChild(label);
1827+    }
1828+};
1829+
1830+class BlankSetting: public TransLabelSetting
1831+{
1832+  public:
1833+    BlankSetting() : TransLabelSetting()
1834+    {
1835+        setLabel("");
1836+    }
1837+};
1838+
1839+#endif // SCANWIZARDHELPERS_H
1840Index: libs/libmythtv/scanwizardscanner.cpp
1841===================================================================
1842--- libs/libmythtv/scanwizardscanner.cpp        (révision 0)
1843+++ libs/libmythtv/scanwizardscanner.cpp        (révision 0)
1844@@ -0,0 +1,654 @@
1845+/* -*- Mode: c++ -*-
1846+ * vim: set expandtab tabstop=4 shiftwidth=4:
1847+ *
1848+ * Original Project
1849+ *      MythTV      http://www.mythtv.org
1850+ *
1851+ * Copyright (c) 2004, 2005 John Pullan <john@pullan.org>
1852+ * Copyright (c) 2005 - 2007 Daniel Kristjansson
1853+ *
1854+ * Description:
1855+ *     Collection of classes to provide channel scanning functionallity
1856+ *
1857+ * This program is free software; you can redistribute it and/or
1858+ * modify it under the terms of the GNU General Public License
1859+ * as published by the Free Software Foundation; either version 2
1860+ * of the License, or (at your option) any later version.
1861+ *
1862+ * This program is distributed in the hope that it will be useful,
1863+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1864+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1865+ * GNU General Public License for more details.
1866+ *
1867+ * You should have received a copy of the GNU General Public License
1868+ * along with this program; if not, write to the Free Software
1869+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1870+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
1871+ *
1872+ */
1873+
1874+// System headers
1875+#include <unistd.h>
1876+
1877+// Qt headers
1878+#include <QApplication>
1879+#include <QEvent>
1880+
1881+// MythTV headers
1882+#include "mythcontext.h"
1883+#include "mythverbose.h"
1884+#include "scanwizard.h"
1885+#include "scanwizardhelpers.h"
1886+#include "scanwizardscanner.h"
1887+#include "channelbase.h"
1888+#include "dtvsignalmonitor.h"
1889+#include "siscan.h"
1890+#include "dtvconfparser.h"
1891+
1892+#ifdef USING_V4L
1893+#include "v4lchannel.h"
1894+#include "analogsignalmonitor.h"
1895+#endif
1896+
1897+#ifdef USING_DVB
1898+#include "dvbchannel.h"
1899+#include "dvbsignalmonitor.h"
1900+#endif
1901+
1902+#ifdef USING_HDHOMERUN
1903+#include "hdhrchannel.h"
1904+#include "hdhrsignalmonitor.h"
1905+#endif
1906+
1907+#ifdef USING_IPTV
1908+#include "iptvchannelfetcher.h"
1909+#endif
1910+
1911+#define LOC QString("SWizScan: ")
1912+#define LOC_ERR QString("SWizScan, Error: ")
1913+
1914+/// Percentage to set to after the transports have been scanned
1915+#define TRANSPORT_PCT 6
1916+/// Percentage to set to after the first tune
1917+#define TUNED_PCT     3
1918+
1919+QString ScanWizardScanner::kTitle = QString::null;
1920+
1921+// kTitel must be initialized after the Qt translation system is initialized...
1922+static void init_statics(void)
1923+{
1924+    static QMutex lock;
1925+    static bool do_init = true;
1926+    QMutexLocker locker(&lock);
1927+    if (do_init)
1928+    {
1929+        ScanWizardScanner::kTitle = ScanWizardScanner::tr("Scanning");
1930+        do_init = false;
1931+    }
1932+}
1933+
1934+ScanWizardScanner::ScanWizardScanner(void)
1935+    : VerticalConfigurationGroup(false, true, false, false),
1936+      log(new LogList()), channel(NULL), popupProgress(NULL),
1937+      scanner(NULL), freeboxScanner(NULL), nVideoSource(0)
1938+{
1939+    init_statics();
1940+
1941+    setLabel(kTitle);
1942+    addChild(log);
1943+}
1944+
1945+ScanWizardScanner::~ScanWizardScanner()
1946+{
1947+    Teardown();
1948+
1949+    QMutexLocker locker(&popupLock);
1950+    StopPopup();
1951+}
1952+
1953+void ScanWizardScanner::Teardown()
1954+{
1955+    // Join the thread and close the channel
1956+    if (scanner)
1957+    {
1958+        scanner->deleteLater();
1959+        scanner = NULL;
1960+    }
1961+
1962+    if (channel)
1963+    {
1964+        delete channel;
1965+        channel = NULL;
1966+    }
1967+
1968+#ifdef USING_IPTV
1969+    if (freeboxScanner)
1970+    {
1971+        freeboxScanner->Stop();
1972+        freeboxScanner->deleteLater();
1973+        freeboxScanner = NULL;
1974+    }
1975+#endif
1976+}
1977+
1978+void ScanWizardScanner::customEvent(QEvent *e)
1979+{
1980+    ScannerEvent *scanEvent = (ScannerEvent*) e;
1981+
1982+    switch (scanEvent->eventType())
1983+    {
1984+        case ScannerEvent::ScanComplete:
1985+        {
1986+            QMutexLocker locker(&popupLock);
1987+            if (popupProgress)
1988+            {
1989+                popupProgress->SetScanProgress(1.0);
1990+                popupProgress->accept();
1991+            }
1992+        }
1993+        break;
1994+
1995+        case ScannerEvent::ScanShutdown:
1996+        {
1997+            if (scanEvent->ScanProgressPopupValue())
1998+            {
1999+                ScanProgressPopup *spp = scanEvent->ScanProgressPopupValue();
2000+                spp->DeleteDialog();
2001+                spp->deleteLater();
2002+            }
2003+
2004+            Teardown();
2005+        }
2006+        break;
2007+
2008+        case ScannerEvent::AppendTextToLog:
2009+        {
2010+            log->updateText(scanEvent->strValue());
2011+        }
2012+        break;
2013+
2014+        default:
2015+            break;
2016+    }
2017+
2018+    QMutexLocker locker(&popupLock);
2019+    if (!popupProgress)
2020+        return;
2021+
2022+    switch (scanEvent->eventType())
2023+    {
2024+        case ScannerEvent::SetStatusText:
2025+            popupProgress->SetStatusText(scanEvent->strValue());
2026+            break;
2027+        case ScannerEvent::SetStatusTitleText:
2028+            popupProgress->SetStatusTitleText(scanEvent->strValue());
2029+            break;
2030+        case ScannerEvent::SetPercentComplete:
2031+            popupProgress->SetScanProgress(scanEvent->intValue() * 0.01);
2032+            break;
2033+        case ScannerEvent::SetStatusSignalLock:
2034+            popupProgress->SetStatusLock(scanEvent->intValue());
2035+            break;
2036+        case ScannerEvent::SetStatusSignalToNoise:
2037+            popupProgress->SetStatusSignalToNoise(scanEvent->intValue());
2038+            break;
2039+        case ScannerEvent::SetStatusSignalStrength:
2040+            popupProgress->SetStatusSignalStrength(scanEvent->intValue());
2041+            break;
2042+        default:
2043+            break;
2044+    }
2045+}
2046+
2047+void ScanWizardScanner::scanComplete()
2048+{
2049+    ScannerEvent::TYPE se = ScannerEvent::ScanComplete;
2050+    QApplication::postEvent(this, new ScannerEvent(se));
2051+}
2052+
2053+void ScanWizardScanner::transportScanComplete()
2054+{
2055+    scanner->ScanServicesSourceID(nVideoSource);
2056+    ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);
2057+    e->intValue(TRANSPORT_PCT);
2058+    QApplication::postEvent(this, e);
2059+}
2060+
2061+void ScanWizardScanner::serviceScanPctComplete(int pct)
2062+{
2063+    ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);
2064+    int tmp = TRANSPORT_PCT + ((100 - TRANSPORT_PCT) * pct)/100;
2065+    e->intValue(tmp);
2066+    QApplication::postEvent(this, e);
2067+}
2068+
2069+void ScanWizardScanner::updateText(const QString &str)
2070+{
2071+    if (str.isEmpty())
2072+        return;
2073+    ScannerEvent* e = new ScannerEvent(ScannerEvent::AppendTextToLog);
2074+    e->strValue(str);
2075+    QApplication::postEvent(this, e);
2076+}
2077+
2078+void ScanWizardScanner::updateStatusText(const QString &str)
2079+{
2080+    QString msg = tr("Scanning");
2081+    if (!str.isEmpty())
2082+        msg = QString("%1 %2").arg(msg).arg(str);
2083+
2084+    ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusText);
2085+    e->strValue(msg);
2086+    QApplication::postEvent(this, e);
2087+}
2088+
2089+void ScanWizardScanner::StatusSignalLock(const SignalMonitorValue &val)
2090+{
2091+    dvbLock(val.GetValue());
2092+}
2093+
2094+void ScanWizardScanner::StatusSignalToNoise(const SignalMonitorValue &val)
2095+{
2096+    dvbSNR(val.GetNormalizedValue(0, 65535));
2097+}
2098+
2099+void ScanWizardScanner::StatusSignalStrength(const SignalMonitorValue &val)
2100+{
2101+    dvbSignalStrength(val.GetNormalizedValue(0, 65535));
2102+}
2103+
2104+void ScanWizardScanner::dvbLock(int locked)
2105+{
2106+    ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalLock);
2107+    e->intValue(locked);
2108+    QApplication::postEvent(this, e);
2109+}
2110+
2111+void ScanWizardScanner::dvbSNR(int i)
2112+{
2113+    ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalToNoise);
2114+    e->intValue(i);
2115+    QApplication::postEvent(this, e);
2116+}
2117+
2118+void ScanWizardScanner::dvbSignalStrength(int i)
2119+{
2120+    ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalStrength);
2121+    e->intValue(i);
2122+    QApplication::postEvent(this, e);
2123+}
2124+
2125+// full scan of existing transports broken
2126+// existing transport scan broken
2127+void ScanWizardScanner::Scan(
2128+    int            scantype,
2129+    uint           cardid,
2130+    const QString &inputname,
2131+    uint           sourceid,
2132+    bool           do_delete_channels,
2133+    bool           do_rename_channels,
2134+    bool           do_ignore_signal_timeout,
2135+    // stuff needed for particular scans
2136+    uint           mplexid /* TransportScan */,
2137+    const QMap<QString,QString> &startChan /* NITAddScan */,
2138+    const QString &freq_std /* FullScan */,
2139+    const QString &mod /* FullScan */,
2140+    const QString &tbl /* FullScan */,
2141+    const QString &atsc_format /* any ATSC scan */)
2142+{
2143+    nVideoSource = sourceid;
2144+    PreScanCommon(scantype, cardid, inputname,
2145+                  sourceid, do_ignore_signal_timeout);
2146+
2147+    VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete()");
2148+
2149+    if (!scanner)
2150+    {
2151+        VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete(): "
2152+                "scanner does not exist...");
2153+        return;
2154+    }
2155+
2156+    scanner->StartScanner();
2157+    updateStatusText("");
2158+
2159+    bool ok = false;
2160+
2161+    if (do_delete_channels && (ScanTypeSetting::TransportScan == scantype))
2162+    {
2163+        MSqlQuery query(MSqlQuery::InitCon());
2164+        query.prepare("DELETE FROM channel "
2165+                      "WHERE sourceid = :SOURCEID AND "
2166+                      "      mplexid  = :MPLEXID");
2167+        query.bindValue(":SOURCEID", sourceid);
2168+        query.bindValue(":MPLEXID",  mplexid);
2169+        query.exec();
2170+    }
2171+    else if (do_delete_channels)
2172+    {
2173+        MSqlQuery query(MSqlQuery::InitCon());
2174+        query.prepare("DELETE FROM channel "
2175+                      "WHERE sourceid = :SOURCEID");
2176+        query.bindValue(":SOURCEID", sourceid);
2177+        query.exec();
2178+
2179+        if (ScanTypeSetting::TransportScan != scantype)
2180+        {
2181+            query.prepare("DELETE FROM dtv_multiplex "
2182+                          "WHERE sourceid = :SOURCEID");
2183+            query.bindValue(":SOURCEID", sourceid);
2184+            query.exec();
2185+        }
2186+    }
2187+
2188+    scanner->SetChannelFormat(atsc_format);
2189+    scanner->SetRenameChannels(do_rename_channels);
2190+
2191+    if ((ScanTypeSetting::FullScan_ATSC   == scantype) ||
2192+        (ScanTypeSetting::FullScan_OFDM   == scantype) ||
2193+        (ScanTypeSetting::FullScan_Analog == scantype))
2194+    {
2195+        VERBOSE(VB_SIPARSER, LOC +
2196+                "ScanTransports("<<freq_std<<", "<<mod<<", "<<tbl<<")");
2197+
2198+        // HACK HACK HACK -- begin
2199+        // if using QAM we may need additional time... (at least with HD-3000)
2200+        if ((mod.left(3).toLower() == "qam") &&
2201+            (scanner->GetSignalTimeout() < 1000))
2202+        {
2203+            scanner->SetSignalTimeout(1000);
2204+        }
2205+        // HACK HACK HACK -- end
2206+
2207+        scanner->SetAnalog(ScanTypeSetting::FullScan_Analog == scantype);
2208+
2209+        ok = scanner->ScanTransports(sourceid, freq_std, mod, tbl);
2210+    }
2211+    else if ((ScanTypeSetting::NITAddScan_OFDM  == scantype) ||
2212+             (ScanTypeSetting::NITAddScan_QPSK  == scantype) ||
2213+             (ScanTypeSetting::NITAddScan_DVBS2 == scantype) ||
2214+             (ScanTypeSetting::NITAddScan_QAM   == scantype))
2215+    {
2216+        VERBOSE(VB_SIPARSER, LOC + "ScanTransports()");
2217+
2218+        ok = scanner->ScanTransportsStartingOn(sourceid, startChan);
2219+    }
2220+    else if (ScanTypeSetting::FullTransportScan == scantype)
2221+    {
2222+        VERBOSE(VB_SIPARSER, LOC + "ScanServicesSourceID("<<sourceid<<")");
2223+
2224+        ok = scanner->ScanServicesSourceID(sourceid);
2225+        if (ok)
2226+        {
2227+            serviceScanPctComplete(0);
2228+        }
2229+        else
2230+        {
2231+            MythPopupBox::showOkPopup(gContext->GetMainWindow(),
2232+                                      tr("ScanWizard"),
2233+                                      tr("Error tuning to transport"));
2234+            Teardown();
2235+        }
2236+    }
2237+    else if ((ScanTypeSetting::DVBUtilsImport == scantype) && channels.size())
2238+    {
2239+        ok = true;
2240+
2241+        VERBOSE(VB_SIPARSER, LOC + "ScanForChannels("<<sourceid<<")");
2242+
2243+        QString card_type = CardUtil::GetRawCardType(cardid);
2244+        QString sub_type  = card_type;
2245+        if (card_type == "DVB")
2246+        {
2247+            QString device = CardUtil::GetVideoDevice(cardid);
2248+
2249+            ok = !device.isEmpty();
2250+            if (ok)
2251+                sub_type = CardUtil::ProbeDVBType(device).toUpper();
2252+        }
2253+
2254+        if (ok)
2255+        {
2256+            ok = scanner->ScanForChannels(sourceid, freq_std,
2257+                                          sub_type, channels);
2258+        }
2259+        if (ok)
2260+        {
2261+            serviceScanPctComplete(0);
2262+        }
2263+        else
2264+        {
2265+            MythPopupBox::showOkPopup(gContext->GetMainWindow(),
2266+                                      tr("ScanWizard"),
2267+                                      tr("Error tuning to transport"));
2268+            Teardown();
2269+        }
2270+    }
2271+    else if (ScanTypeSetting::TransportScan == scantype)
2272+    {
2273+        VERBOSE(VB_SIPARSER, LOC + "ScanTransport("<<mplexid<<")");
2274+
2275+        ok = scanner->ScanTransport(mplexid);
2276+    }
2277+
2278+    if (!ok)
2279+    {
2280+        VERBOSE(VB_IMPORTANT, "Failed to handle tune complete.");
2281+    }
2282+}
2283+
2284+void ScanWizardScanner::ImportDVBUtils(uint sourceid, int cardtype,
2285+                                       const QString &file)
2286+{
2287+    channels.clear();
2288+
2289+    DTVConfParser::cardtype_t type = DTVConfParser::UNKNOWN;
2290+    type = (CardUtil::OFDM  == cardtype) ? DTVConfParser::OFDM : type;
2291+    type = (CardUtil::QPSK  == cardtype) ? DTVConfParser::QPSK : type;
2292+    type = (CardUtil::DVBS2 == cardtype) ? DTVConfParser::DVBS2 : type;
2293+    type = (CardUtil::QAM   == cardtype) ? DTVConfParser::QAM  : type;
2294+    type = ((CardUtil::ATSC == cardtype)||(CardUtil::HDHOMERUN == cardtype)) ?
2295+        DTVConfParser::ATSC : type;
2296+
2297+    if (type == DTVConfParser::UNKNOWN)
2298+        return;
2299+
2300+    DTVConfParser parser(type, sourceid, file);
2301+
2302+    DTVConfParser::return_t ret = parser.Parse();
2303+    if (DTVConfParser::OK != ret)
2304+    {
2305+        QString msg = (DTVConfParser::ERROR_PARSE == ret) ?
2306+            tr("Failed to parse '%1'") : tr("Failed to open '%1'");
2307+
2308+        MythPopupBox::showOkPopup(gContext->GetMainWindow(),
2309+                                  tr("ScanWizard"), msg.arg(file));
2310+    }
2311+    else
2312+    {
2313+        channels = parser.GetChannels();
2314+    }
2315+}
2316+
2317+void ScanWizardScanner::PreScanCommon(int scantype,
2318+                                      uint cardid,
2319+                                      const QString &inputname,
2320+                                      uint sourceid,
2321+                                      bool do_ignore_signal_timeout)
2322+{
2323+    uint signal_timeout  = 1000;
2324+    uint channel_timeout = 40000;
2325+    CardUtil::GetTimeouts(cardid, signal_timeout, channel_timeout);
2326+
2327+    QString device = CardUtil::GetVideoDevice(cardid);
2328+    if (device.isEmpty())
2329+    {
2330+        VERBOSE(VB_IMPORTANT, "No Device");
2331+        return;
2332+    }
2333+
2334+    QString card_type = CardUtil::GetRawCardType(cardid);
2335+
2336+    if ("DVB" == card_type)
2337+    {
2338+        QString sub_type = CardUtil::ProbeDVBType(device).toUpper();
2339+        bool need_nit = (("QAM"    == sub_type) ||
2340+                         ("QPSK"   == sub_type) ||
2341+                         ("DVB_S2" == sub_type) ||
2342+                         ("OFDM"   == sub_type));
2343+
2344+        // Ugh, Some DVB drivers don't fully support signal monitoring...
2345+        if ((ScanTypeSetting::TransportScan     == scantype) ||
2346+            (ScanTypeSetting::FullTransportScan == scantype))
2347+        {
2348+            signal_timeout = (do_ignore_signal_timeout) ?
2349+                channel_timeout * 10 : signal_timeout;
2350+        }
2351+
2352+        // Since we the NIT is only sent every 10 seconds, we add an
2353+        // extra 20 + 2 seconds to the scan time for DVB countries.
2354+        channel_timeout += (need_nit) ? 22 * 1000 : 0;
2355+    }
2356+
2357+#ifdef USING_DVB
2358+    if ("DVB" == card_type)
2359+        channel = new DVBChannel(device);
2360+#endif
2361+
2362+#ifdef USING_V4L
2363+    if (("V4L" == card_type) || ("MPEG" == card_type) ||
2364+        ("HDPVR" == card_type))
2365+    {
2366+        channel = new V4LChannel(NULL, device);
2367+    }
2368+#endif
2369+
2370+#ifdef USING_HDHOMERUN
2371+    if ("HDHOMERUN" == card_type)
2372+    {
2373+        uint tuner = CardUtil::GetHDHRTuner(cardid);
2374+        channel = new HDHRChannel(NULL, device, tuner);
2375+    }
2376+#endif // USING_HDHOMERUN
2377+
2378+    if (!channel)
2379+    {
2380+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel not created");
2381+        return;
2382+    }
2383+
2384+    // explicitly set the cardid
2385+    channel->SetCardID(cardid);
2386+
2387+    // If the backend is running this may fail...
2388+    if (!channel->Open())
2389+    {
2390+        VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel could not be opened");
2391+        return;
2392+    }
2393+
2394+    scanner = new SIScan(card_type, channel, sourceid, signal_timeout,
2395+                         channel_timeout, inputname);
2396+
2397+    scanner->SetForceUpdate(true);
2398+
2399+    bool ftao = CardUtil::IgnoreEncrypted(cardid, inputname);
2400+    scanner->SetFTAOnly(ftao);
2401+
2402+    bool tvo = CardUtil::TVOnly(cardid, inputname);
2403+    scanner->SetTVOnly(tvo);
2404+
2405+    connect(scanner, SIGNAL(ServiceScanComplete(void)),
2406+            this,    SLOT(  scanComplete(void)));
2407+    connect(scanner, SIGNAL(TransportScanComplete(void)),
2408+            this,    SLOT(  transportScanComplete(void)));
2409+    connect(scanner, SIGNAL(ServiceScanUpdateStatusText(const QString&)),
2410+            this,    SLOT(  updateStatusText(const QString&)));
2411+    connect(scanner, SIGNAL(ServiceScanUpdateText(const QString&)),
2412+            this,    SLOT(  updateText(const QString&)));
2413+    connect(scanner, SIGNAL(TransportScanUpdateText(const QString&)),
2414+            this,    SLOT(  updateText(const QString&)));
2415+    connect(scanner, SIGNAL(PctServiceScanComplete(int)),
2416+            this,    SLOT(  serviceScanPctComplete(int)));
2417+
2418+    // Signal Meters are connected here
2419+    SignalMonitor *monitor = scanner->GetSignalMonitor();
2420+    if (monitor)
2421+        monitor->AddListener(this);
2422+   
2423+    DVBSignalMonitor *dvbm = NULL;
2424+#ifdef USING_DVB
2425+    dvbm = scanner->GetDVBSignalMonitor();
2426+#endif // USING_DVB
2427+
2428+    MonitorProgress(monitor, monitor, dvbm);
2429+}
2430+
2431+void ScanWizardScanner::ImportM3U(uint cardid, const QString &inputname,
2432+                                  uint sourceid)
2433+{
2434+    (void) cardid;
2435+    (void) inputname;
2436+    (void) sourceid;
2437+
2438+#ifdef USING_IPTV
2439+    //Create an analog scan object
2440+    freeboxScanner = new IPTVChannelFetcher(cardid, inputname, sourceid);
2441+
2442+    connect(freeboxScanner, SIGNAL(ServiceScanComplete(void)),
2443+            this,           SLOT(  scanComplete(void)));
2444+    connect(freeboxScanner, SIGNAL(ServiceScanUpdateText(const QString&)),
2445+            this,           SLOT(  updateText(const QString&)));
2446+    connect(freeboxScanner, SIGNAL(ServiceScanPercentComplete(int)),
2447+            this,           SLOT(  serviceScanPctComplete(int)));
2448+
2449+    MonitorProgress(false, false, false);
2450+
2451+    if (!freeboxScanner->Scan())
2452+    {
2453+        MythPopupBox::showOkPopup(gContext->GetMainWindow(),
2454+                                  tr("ScanWizard"),
2455+                                  tr("Error starting scan"));
2456+    }
2457+#endif // USING_IPTV
2458+}
2459+
2460+void *spawn_popup(void *tmp)
2461+{
2462+    ((ScanWizardScanner*)(tmp))->RunPopup();
2463+    return NULL;
2464+}
2465+
2466+void ScanWizardScanner::RunPopup(void)
2467+{
2468+    DialogCode ret = popupProgress->exec();
2469+
2470+    post_event(this, ScannerEvent::ScanShutdown, ret, popupProgress);
2471+    popupProgress = NULL;
2472+}
2473+
2474+void ScanWizardScanner::StopPopup(void)
2475+{
2476+    if (popupProgress)
2477+    {
2478+        popupProgress->reject();
2479+        popupLock.unlock();
2480+        pthread_join(popup_thread, NULL);
2481+        popupLock.lock();
2482+    }
2483+}
2484+
2485+void ScanWizardScanner::MonitorProgress(bool lock, bool strength, bool snr)
2486+{
2487+    QMutexLocker locker(&popupLock);
2488+    StopPopup();
2489+    popupProgress = new ScanProgressPopup(lock, strength, snr);
2490+    popupProgress->CreateDialog();
2491+    if (pthread_create(&popup_thread, NULL, spawn_popup, this) != 0)
2492+    {
2493+        VERBOSE(VB_IMPORTANT, "Failed to start MonitorProgress thread");
2494+        popupProgress->DeleteDialog();
2495+        popupProgress->deleteLater();
2496+        popupProgress = NULL;
2497+    }
2498+}
2499Index: libs/libmythtv/hdhrchannel.cpp
2500===================================================================
2501--- libs/libmythtv/hdhrchannel.cpp      (révision 20533)
2502+++ libs/libmythtv/hdhrchannel.cpp      (copie de travail)
2503@@ -292,6 +292,7 @@
2504 
2505     // Fetch tuning data from the database.
2506     QString tvformat, modulation, freqtable, freqid, si_std;
2507+    QString msystem, rolloff;
2508     int finetune;
2509     uint64_t frequency;
2510     int mpeg_prog_num;
2511@@ -302,6 +303,7 @@
2512         tvformat, modulation, freqtable, freqid,
2513         finetune, frequency,
2514         si_std, mpeg_prog_num, atsc_major, atsc_minor, tsid, netid,
2515+        msystem, rolloff,
2516         mplexid, commfree))
2517     {
2518         return false;
2519@@ -370,10 +372,13 @@
2520     uint64_t frequency;
2521     uint     transportid;
2522     uint     dvb_networkid;
2523-
2524+    QString  dvb_msystem;
2525+    QString  dvb_rolloff;
2526+   
2527     if (!ChannelUtil::GetTuningParams(
2528             mplexid, modulation, frequency,
2529-            transportid, dvb_networkid, si_std))
2530+            transportid, dvb_networkid,
2531+            dvb_msystem, dvb_rolloff, si_std))
2532     {
2533         VERBOSE(VB_IMPORTANT, LOC_ERR + "TuneMultiplex(): " +
2534                 QString("Could not find tuning parameters for multiplex %1.")
2535Index: libs/libmythtv/siscan.cpp
2536===================================================================
2537--- libs/libmythtv/siscan.cpp   (révision 0)
2538+++ libs/libmythtv/siscan.cpp   (révision 0)
2539@@ -0,0 +1,1662 @@
2540+// -*- Mode: c++ -*-
2541+
2542+// C includes
2543+#include <cstdio>
2544+#include <pthread.h>
2545+#include <unistd.h>
2546+
2547+// Qt includes
2548+#include <qmutex.h>
2549+
2550+// MythTV includes - General
2551+#include "siscan.h"
2552+#include "scheduledrecording.h"
2553+#include "frequencies.h"
2554+#include "mythdb.h"
2555+#include "channelutil.h"
2556+#include "cardutil.h"
2557+
2558+// MythTV includes - DTV
2559+#include "dtvsignalmonitor.h"
2560+#include "scanstreamdata.h"
2561+
2562+// MythTV includes - ATSC
2563+#include "atsctables.h"
2564+
2565+// MythTV includes - DVB
2566+#include "dvbsignalmonitor.h"
2567+#include "dvbtables.h"
2568+
2569+#include "dvbchannel.h"
2570+#include "hdhrchannel.h"
2571+#include "v4lchannel.h"
2572+#include "compat.h"
2573+
2574+QString SIScan::loc(const SIScan *siscan)
2575+{
2576+    if (siscan && siscan->channel)
2577+        return QString("SIScan(%1)").arg(siscan->channel->GetDevice());
2578+    return "SIScan(u)";
2579+}
2580+
2581+#define LOC     (SIScan::loc(this) + ": ")
2582+#define LOC_ERR (SIScan::loc(this) + ", Error: ")
2583+
2584+/** \class SIScan
2585+ *  \brief Scanning class for cards that support a SignalMonitor class.
2586+ *
2587+ *   Currently both SIParser and ScanStreamData are being used in
2588+ *   this class. The SIParser is being phased out, so that is not
2589+ *   described here.
2590+ *
2591+ *   With ScanStreamData, we call ScanTransport() on each transport
2592+ *   and frequency offset in the list of transports. This list is
2593+ *   created from a FrequencyTable object.
2594+ *
2595+ *   Each ScanTransport() call resets the ScanStreamData and the
2596+ *   SignalMonitor, then tunes to a new frequency and notes the tuning
2597+ *   time in the "timer" QTime object.
2598+ *
2599+ *   HandleActiveScan is called every time through the event loop
2600+ *   and is what calls ScanTransport(), as well as checking when
2601+ *   the current time is "timeoutTune" or "channelTimeout" milliseconds
2602+ *   ahead of "timer". When the "timeoutTune" is exceeded we check
2603+ *   to see if we have a signal lock on the channel, if we don't we
2604+ *   check the next transport. When the larger "channelTimeout" is
2605+ *   exceeded we do nothing unless "waitingForTables" is still true,
2606+ *   if so we check if we at least got a PAT and if so we insert
2607+ *    a channel based on that by calling HandleMPEGDBInsertion().
2608+ *
2609+ *   Meanwhile the ScanStreamData() emits several signals. For
2610+ *   the UI it emits signal quality signals. For SIScan it emits
2611+ *   UpdateMGT, UpdateVCT, UpdateNIT, and UpdateSDT signals. We
2612+ *   connect these to the HandleMGT, HandleVCT, etc. These in
2613+ *   turn just call HandleATSCDBInsertion() or
2614+ *   HandleDVBDBInsertion() depending on the type of table.
2615+ *
2616+ *   HandleATSCDBInsertion() first checks if we have all the VCTs
2617+ *   described in the MGT. If we do we call UpdateVCTinDB() for each
2618+ *   TVCT and CVCT in the stream. UpdateVCTinDB() inserts the actual
2619+ *   channels. Then we set "waitingForTables" to false, set the
2620+ *   scanOffsetIt to 99 and updates the UI to reflect the added channel.
2621+ *   HandleDVBDBInsertion() and HandleMPEGDBInsertion() are similar.
2622+ */
2623+
2624+SIScan::SIScan(const QString &_cardtype, ChannelBase *_channel, int _sourceID,
2625+               uint signal_timeout, uint channel_timeout,
2626+               const QString &_inputname)
2627+    : // Set in constructor
2628+      channel(_channel),
2629+      signalMonitor(SignalMonitor::Init(_cardtype, -1, _channel)),
2630+      sourceID(_sourceID),
2631+      scanMode(IDLE),
2632+      signalTimeout(signal_timeout),
2633+      channelTimeout(channel_timeout),
2634+      inputname(_inputname),
2635+      // Settable
2636+      isAnalog(false),
2637+      ignoreAudioOnlyServices(false),
2638+      ignoreDataServices(false),
2639+      ignoreEncryptedServices(false),
2640+      forceUpdate(false),
2641+      renameChannels(false),
2642+      channelFormat("%1_%2"),
2643+      // State
2644+      threadExit(false),
2645+      waitingForTables(false),
2646+      // Transports List
2647+      transportsScanned(0),
2648+      // Misc
2649+      scanner_thread_running(false)
2650+{
2651+    inputname.detach();
2652+
2653+    // Initialize statics
2654+    current = transport_scan_items_it_t( scanTransports.end());
2655+
2656+    signalMonitor->AddListener(this);
2657+
2658+    // Create a stream data for digital signal monitors
2659+    DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
2660+    if (dtvSigMon)
2661+    {
2662+        VERBOSE(VB_SIPARSER, LOC + "Connecting up DTVSignalMonitor");
2663+        ScanStreamData *data = new ScanStreamData();
2664+
2665+        dtvSigMon->SetStreamData(data);
2666+        dtvSigMon->AddFlags(SignalMonitor::kDTVSigMon_WaitForMGT |
2667+                            SignalMonitor::kDTVSigMon_WaitForVCT |
2668+                            SignalMonitor::kDTVSigMon_WaitForNIT |
2669+                            SignalMonitor::kDTVSigMon_WaitForSDT);
2670+
2671+        data->AddMPEGListener(this);
2672+        data->AddATSCMainListener(this);
2673+        data->AddDVBMainListener(this);
2674+    }
2675+}
2676+
2677+SIScan::~SIScan(void)
2678+{
2679+    // Use deleteLater() instead
2680+    StopScanner();
2681+    VERBOSE(VB_SIPARSER, LOC + "SIScanner dtor");
2682+}
2683+
2684+void SIScan::deleteLater(void)
2685+{
2686+    disconnect();
2687+    StopScanner();
2688+    VERBOSE(VB_SIPARSER, LOC + "SIScanner Stopped");
2689+    channel = 0; // Deleted by caller
2690+    teardown_frequency_tables();
2691+    QObject::deleteLater();
2692+}
2693+
2694+void SIScan::AllGood(void)
2695+{
2696+    if (!isAnalog)
2697+        return;
2698+
2699+    QString cur_chan = (*current).FriendlyName;
2700+    QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);
2701+    QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
2702+
2703+    bool ok = false;
2704+
2705+    QString msg = tr("Updated Channel %1").arg(cur_chan);
2706+
2707+    if (!ChannelUtil::FindChannel(sourceID, freqid))
2708+    {
2709+        int chanid = ChannelUtil::CreateChanID(sourceID, freqid);
2710+
2711+        QString callsign = QString("%1%2")
2712+            .arg(ChannelUtil::GetUnknownCallsign()).arg(freqid);
2713+
2714+        ok = ChannelUtil::CreateChannel(
2715+            0      /* mplexid */,
2716+            sourceID,
2717+            chanid,
2718+            callsign,
2719+            ""     /* service name       */,
2720+            freqid /* channum            */,
2721+            0      /* service id         */,
2722+            0      /* ATSC major channel */,
2723+            0      /* ATSC minor channel */,
2724+            false  /* use on air guide   */,
2725+            false  /* hidden             */,
2726+            false  /* hidden in guide    */,
2727+            freqid);
2728+
2729+        msg = (ok) ?
2730+            tr("Added Channel %1").arg(cur_chan) :
2731+            tr("Failed to add channel %1").arg(cur_chan);
2732+    }
2733+    else
2734+    {
2735+        // nothing to do here, XMLTV & DataDirect have better info
2736+    }
2737+
2738+    emit ServiceScanUpdateText(msg);
2739+
2740+    // tell UI we are done with these channels
2741+    if (scanMode == TRANSPORT_LIST)
2742+    {
2743+        UpdateScanPercentCompleted();
2744+        waitingForTables = false;
2745+        nextIt = current.nextTransport();
2746+    }
2747+}
2748+
2749+/** \fn SIScan::ScanServicesSourceID(int)
2750+ *  \brief If we are not already scanning a frequency table, this creates
2751+ *         a new frequency table from database and begins scanning it.
2752+ *
2753+ *   This is used by DVB to scan for channels we are told about from other
2754+ *   channels.
2755+ *
2756+ *   Note: Something similar could be used with ATSC when EIT for other
2757+ *   channels is available on another ATSC channel, as encouraged by the
2758+ *   ATSC specification.
2759+ */
2760+bool SIScan::ScanServicesSourceID(int SourceID)
2761+{
2762+    if (scanMode == TRANSPORT_LIST)
2763+        return false;
2764+
2765+    nextIt = transport_scan_items_it_t( scanTransports.end() );
2766+
2767+    MSqlQuery query(MSqlQuery::InitCon());
2768+    // Run DB query to get transports on sourceid SourceID
2769+    // connected to this card
2770+    QString theQuery = QString(
2771+        "SELECT sourceid, mplexid, sistandard, transportid "
2772+        "FROM dtv_multiplex WHERE sourceid = %1").arg(SourceID);
2773+    query.prepare(theQuery);
2774+
2775+    if (!query.exec() || !query.isActive())
2776+    {
2777+        MythDB::DBError("Get Transports for SourceID", query);
2778+        return false;
2779+    }
2780+
2781+    if (query.size() <= 0)
2782+    {
2783+        VERBOSE(VB_SIPARSER, LOC + "Unable to find any transports for " +
2784+                QString("sourceid %1").arg(sourceID));
2785+
2786+        return false;
2787+    }
2788+
2789+    while (query.next())
2790+    {
2791+        int sourceid = query.value(0).toInt();
2792+        int mplexid  = query.value(1).toInt();
2793+        QString std  = query.value(2).toString();
2794+        int tsid     = query.value(3).toInt();
2795+
2796+        QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
2797+            QString("Multiplex #%1").arg(mplexid);
2798+
2799+        VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);
2800+
2801+        TransportScanItem item(sourceid, std, fn, mplexid, signalTimeout);
2802+        scanTransports += item;
2803+    }
2804+
2805+    waitingForTables  = false;
2806+    transportsScanned = 0;
2807+    if (scanTransports.size())
2808+    {
2809+        nextIt        = transport_scan_items_it_t(scanTransports.begin());
2810+        scanMode      = TRANSPORT_LIST;
2811+        return true;
2812+    }
2813+
2814+    return false;
2815+}
2816+
2817+void SIScan::HandlePAT(const ProgramAssociationTable *pat)
2818+{
2819+    VERBOSE(VB_SIPARSER, LOC +
2820+            QString("Got a Program Association Table for %1")
2821+            .arg((*current).FriendlyName));
2822+
2823+    // Add pmts to list, so we can do MPEG scan properly.
2824+    ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();
2825+    for (uint i = 0; i < pat->ProgramCount(); i++)
2826+    {
2827+        if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.
2828+            sd->AddListeningPID(pat->ProgramPID(i));
2829+    }
2830+}
2831+
2832+void SIScan::HandleVCT(uint, const VirtualChannelTable*)
2833+{
2834+    VERBOSE(VB_SIPARSER, LOC + QString("Got a Virtual Channel Table for %1")
2835+            .arg((*current).FriendlyName));
2836+
2837+    HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
2838+}
2839+
2840+void SIScan::HandleMGT(const MasterGuideTable*)
2841+{
2842+    VERBOSE(VB_SIPARSER, LOC + QString("Got the Master Guide for %1")
2843+            .arg((*current).FriendlyName));
2844+
2845+    HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
2846+}
2847+
2848+void SIScan::HandleSDT(uint, const ServiceDescriptionTable* sdt)
2849+{
2850+    VERBOSE(VB_SIPARSER, LOC +
2851+            QString("Got a Service Description Table for %1")
2852+            .arg((*current).FriendlyName));
2853+    VERBOSE(VB_SIPARSER, LOC + sdt->toString());
2854+
2855+    HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
2856+}
2857+
2858+void SIScan::HandleNIT(const NetworkInformationTable *nit)
2859+{
2860+    VERBOSE(VB_SIPARSER, LOC +
2861+            QString("Got a Network Information Table for %1")
2862+            .arg((*current).FriendlyName));
2863+    VERBOSE(VB_SIPARSER, LOC + nit->toString());
2864+
2865+    if (nit->TransportStreamCount())
2866+    {
2867+        emit TransportScanUpdateText(
2868+            tr("Network %1 Processing").arg(nit->NetworkName()));
2869+
2870+        vector<uint> mp;
2871+        mp = ChannelUtil::CreateMultiplexes(sourceID, nit);
2872+        VERBOSE(VB_SIPARSER, QString("Created %1 multiplexes from NIT")
2873+                .arg(mp.size()));
2874+
2875+        // Get channel numbers from UK Frequency List Descriptors
2876+        for (uint i = 0; i < nit->TransportStreamCount(); i++)
2877+        {
2878+            const desc_list_t& list =
2879+                MPEGDescriptor::Parse(nit->TransportDescriptors(i),
2880+                                      nit->TransportDescriptorsLength(i));
2881+
2882+            const unsigned char* desc =
2883+                MPEGDescriptor::Find(list, DescriptorID::dvb_uk_channel_list);
2884+
2885+            if (desc)
2886+            {
2887+                UKChannelListDescriptor uklist(desc);
2888+                for (uint j = 0; j < uklist.ChannelCount(); j++)
2889+                    dvbChanNums[uklist.ServiceID(j)] = uklist.ChannelNumber(j);
2890+            }
2891+        }
2892+    }
2893+
2894+    const ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();
2895+    const DVBStreamData &dsd = *sd;
2896+    if (dsd.HasAllNITSections())
2897+    {
2898+        emit TransportScanUpdateText(tr("Finished processing Transport List"));
2899+        emit TransportScanComplete();
2900+    }
2901+
2902+    HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
2903+}
2904+
2905+void SIScan::HandleMPEGDBInsertion(const ScanStreamData *sd, bool)
2906+{
2907+    // Try to determine if this might be "OpenCable" transport.
2908+    QString sistandard = sd->GetSIStandard((*current).tuning.sistandard);
2909+
2910+    if (!(*current).mplexid)
2911+        (*current).mplexid = InsertMultiplex(current);
2912+
2913+    if (!(*current).mplexid)
2914+        return;
2915+
2916+    int     mplexid = (*current).mplexid;
2917+    int     freqid  = (*current).friendlyNum;
2918+    QString fn      = (*current).FriendlyName;
2919+
2920+    pat_vec_t pats = sd->GetCachedPATs();
2921+    pmt_map_t pmt_map = sd->GetCachedPMTMap();
2922+    for (uint i = 0; i < pats.size(); i++)
2923+    {
2924+        UpdatePATinDB(mplexid, fn, freqid, pats[i], pmt_map,
2925+                      (*current).expectedChannels, sistandard, true);
2926+    }
2927+    sd->ReturnCachedPMTTables(pmt_map);
2928+    sd->ReturnCachedPATTables(pats);
2929+
2930+    // tell UI we are done with these channels
2931+    if (scanMode == TRANSPORT_LIST)
2932+    {
2933+        UpdateScanPercentCompleted();
2934+        waitingForTables = false;
2935+        nextIt = current.nextTransport();
2936+    }
2937+}
2938+
2939+void SIScan::HandleATSCDBInsertion(const ScanStreamData *sd,
2940+                                   bool wait_until_complete)
2941+{
2942+    if (wait_until_complete && !sd->HasCachedAllVCTs())
2943+        return;
2944+
2945+    if (!(*current).mplexid)
2946+        (*current).mplexid = InsertMultiplex(current);
2947+
2948+    if (!(*current).mplexid)
2949+        return;
2950+
2951+    int     mplexid = (*current).mplexid;
2952+    int     freqid  = (*current).friendlyNum;
2953+    QString fn      = (*current).FriendlyName;
2954+
2955+    // Insert Terrestrial VCTs
2956+    tvct_vec_t tvcts = sd->GetCachedTVCTs();
2957+    for (uint i = 0; i < tvcts.size(); i++)
2958+    {
2959+        UpdateVCTinDB(mplexid, fn, freqid, tvcts[i],
2960+                      (*current).expectedChannels, true);
2961+    }
2962+    sd->ReturnCachedTVCTTables(tvcts);
2963+
2964+    // Insert Cable VCTs
2965+    cvct_vec_t cvcts = sd->GetCachedCVCTs();
2966+    for (uint i = 0; i < cvcts.size(); i++)
2967+    {
2968+        UpdateVCTinDB(mplexid, fn, freqid, cvcts[i],
2969+                      (*current).expectedChannels, true);
2970+    }
2971+    sd->ReturnCachedCVCTTables(cvcts);
2972+
2973+    // tell UI we are done with these channels
2974+    if (scanMode == TRANSPORT_LIST)
2975+    {
2976+        UpdateScanPercentCompleted();
2977+        waitingForTables = false;
2978+        nextIt = current.nextTransport();
2979+    }
2980+}
2981+
2982+void SIScan::HandleDVBDBInsertion(const ScanStreamData *sd,
2983+                                  bool wait_until_complete)
2984+{
2985+    const DVBStreamData &dsd = (const DVBStreamData &)(*sd);
2986+    if (wait_until_complete && !(dsd.HasCachedSDT() && dsd.HasCachedAllNIT()))
2987+        return;
2988+
2989+    emit ServiceScanUpdateText(tr("Updating Services"));
2990+
2991+    if (!(*current).mplexid)
2992+        (*current).mplexid = InsertMultiplex(current);
2993+
2994+    vector<const ServiceDescriptionTable*> sdts = sd->GetCachedSDTs();
2995+    for (uint i = 0; i < sdts.size(); i++)
2996+    {
2997+        UpdateSDTinDB((*current).mplexid, sdts[i],
2998+                      (*current).expectedChannels, forceUpdate);
2999+    }
3000+    sd->ReturnCachedSDTTables(sdts);
3001+
3002+    emit ServiceScanUpdateText(tr("Finished processing Services"));
3003+
3004+    if (scanMode == TRANSPORT_LIST)
3005+    {
3006+        UpdateScanPercentCompleted();
3007+        waitingForTables = false;
3008+        nextIt = current.nextTransport();
3009+    }
3010+    else
3011+    {
3012+        emit PctServiceScanComplete(100);
3013+        emit ServiceScanComplete();
3014+    }
3015+}
3016+
3017+/** \fn SIScan::HandlePostInsertion(void)
3018+ *  \brief Insert channels based on any partial tables we do have.
3019+ *  \return true if we saw any tables
3020+ */
3021+bool SIScan::HandlePostInsertion(void)
3022+{
3023+    DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
3024+    if (!dtvSigMon)
3025+        return false;
3026+
3027+    const ScanStreamData *sd = dtvSigMon->GetScanStreamData();
3028+
3029+    VERBOSE(VB_SIPARSER, LOC + "HandlePostInsertion() " +
3030+            QString("pat(%1)").arg(sd->HasCachedAnyPAT()));
3031+
3032+    const MasterGuideTable *mgt = sd->GetCachedMGT();
3033+    if (mgt)
3034+    {
3035+        VERBOSE(VB_IMPORTANT, mgt->toString());
3036+        HandleATSCDBInsertion(sd, false);
3037+        sd->ReturnCachedTable(mgt);
3038+        return true;
3039+    }
3040+
3041+    const NetworkInformationTable *nit = sd->GetCachedNIT(0, true);
3042+    sdt_vec_t sdts = sd->GetCachedSDTs();
3043+    if (nit || sdts.size())
3044+    {
3045+        if (nit)
3046+            VERBOSE(VB_IMPORTANT, nit->toString());
3047+        HandleDVBDBInsertion(sd, false);
3048+        sd->ReturnCachedSDTTables(sdts);
3049+        sd->ReturnCachedTable(nit);
3050+        return true;
3051+    }
3052+
3053+    if (sd->HasCachedAnyPAT())
3054+    {
3055+        VERBOSE(VB_IMPORTANT, LOC + "Post insertion found PAT..");
3056+        HandleMPEGDBInsertion(sd, false);
3057+        return true;
3058+    }
3059+    return false;
3060+}
3061+
3062+DTVSignalMonitor* SIScan::GetDTVSignalMonitor(void)
3063+{
3064+    return dynamic_cast<DTVSignalMonitor*>(signalMonitor);
3065+}
3066+
3067+DVBSignalMonitor* SIScan::GetDVBSignalMonitor(void)
3068+{
3069+#ifdef USING_DVB
3070+    return dynamic_cast<DVBSignalMonitor*>(signalMonitor);
3071+#else
3072+    return NULL;
3073+#endif
3074+}
3075+
3076+DTVChannel *SIScan::GetDTVChannel(void)
3077+{
3078+    return dynamic_cast<DTVChannel*>(channel);
3079+}
3080+
3081+DVBChannel *SIScan::GetDVBChannel(void)
3082+{
3083+#ifdef USING_DVB
3084+    return dynamic_cast<DVBChannel*>(channel);
3085+#else
3086+    return NULL;
3087+#endif
3088+}
3089+
3090+V4LChannel *SIScan::GetV4LChannel(void)
3091+{
3092+#ifdef USING_V4L
3093+    return dynamic_cast<V4LChannel*>(channel);
3094+#else
3095+    return NULL;
3096+#endif
3097+}
3098+
3099+/** \fn SIScan::SpawnScanner(void*)
3100+ *  \brief Thunk that allows scanner_thread pthread to
3101+ *         call SIScan::RunScanner().
3102+ */
3103+void *SIScan::SpawnScanner(void *param)
3104+{
3105+    SIScan *scanner = (SIScan *)param;
3106+    scanner->RunScanner();
3107+    return NULL;
3108+}
3109+
3110+/** \fn SIScan::StartScanner(void)
3111+ *  \brief Starts the SIScan event loop.
3112+ */
3113+void SIScan::StartScanner(void)
3114+{
3115+    pthread_create(&scanner_thread, NULL, SpawnScanner, this);
3116+}
3117+
3118+/** \fn SIScan::RunScanner(void)
3119+ *  \brief This runs the event loop for SIScan until 'threadExit' is true.
3120+ */
3121+void SIScan::RunScanner(void)
3122+{
3123+    VERBOSE(VB_SIPARSER, LOC + "Starting SIScanner");
3124+
3125+    scanner_thread_running = true;
3126+    threadExit = false;
3127+
3128+    while (!threadExit)
3129+    {
3130+        if (scanMode == TRANSPORT_LIST)
3131+            HandleActiveScan();
3132+
3133+        usleep(250);
3134+    }
3135+    scanner_thread_running = false;
3136+}
3137+
3138+// See if we have timed out
3139+bool SIScan::HasTimedOut(void)
3140+{
3141+    if (!waitingForTables)
3142+        return true;
3143+
3144+    // have the tables have timed out?
3145+    if (timer.elapsed() > (int)channelTimeout)
3146+    {
3147+        QString offset_str = current.offset() ?
3148+            QObject::tr(" offset %2").arg(current.offset()) : "";
3149+        QString cur_chan = QString("%1%2")
3150+            .arg((*current).FriendlyName).arg(offset_str);
3151+        QString time_out_table_str =
3152+            QObject::tr("Timeout Scanning %1 -- no tables").arg(cur_chan);
3153+
3154+        emit ServiceScanUpdateText(time_out_table_str);
3155+        VERBOSE(VB_SIPARSER, LOC + time_out_table_str);
3156+
3157+        return true;
3158+    }
3159+
3160+    // ok the tables haven't timed out, but have we hit the signal timeout?
3161+    if (timer.elapsed() > (int)(*current).timeoutTune)
3162+    {
3163+        // If we don't have a signal in timeoutTune msec, continue..
3164+        SignalMonitor *sm = GetSignalMonitor();
3165+        if (NULL == sm || sm->HasSignalLock())
3166+            return false;
3167+
3168+        QString offset_str = current.offset() ?
3169+            QObject::tr(" offset %2").arg(current.offset()) : "";
3170+        QString cur_chan = QString("%1%2")
3171+            .arg((*current).FriendlyName).arg(offset_str);
3172+        QString time_out_sig_str =
3173+            QObject::tr("Timeout Scanning %1 -- no signal").arg(cur_chan);
3174+
3175+        emit ServiceScanUpdateText(time_out_sig_str);
3176+        VERBOSE(VB_SIPARSER, LOC + time_out_sig_str);
3177+
3178+        return true;
3179+    }
3180+    return false;
3181+}
3182+
3183+/** \fn SIScan::HandleActiveScan(void)
3184+ *  \brief Handles the TRANSPORT_LIST SIScan mode.
3185+ */
3186+void SIScan::HandleActiveScan(void)
3187+{
3188+    bool do_post_insertion = waitingForTables;
3189+
3190+    if (!HasTimedOut())
3191+        return;
3192+
3193+    if (0 == nextIt.offset() && nextIt != transport_scan_items_it_t(scanTransports.begin()))
3194+    {
3195+        // Stop signal monitor for previous transport
3196+        signalMonitor->Stop();
3197+
3198+        if (do_post_insertion)
3199+            HandlePostInsertion();
3200+
3201+        transportsScanned++;
3202+        UpdateScanPercentCompleted();
3203+    }
3204+
3205+    current = nextIt; // Increment current
3206+
3207+    if (current != transport_scan_items_it_t(scanTransports.end()))
3208+    {
3209+        ScanTransport(current);
3210+
3211+        // Increment nextIt
3212+        nextIt = current;
3213+        ++nextIt;
3214+    }
3215+    else
3216+    {
3217+        emit ServiceScanComplete();
3218+        scanMode = IDLE;
3219+        scanTransports.clear();
3220+        current = nextIt = transport_scan_items_it_t(scanTransports.end());
3221+    }
3222+}
3223+
3224+bool SIScan::Tune(const transport_scan_items_it_t transport)
3225+{
3226+    const TransportScanItem &item = *transport;
3227+    const uint64_t freq = item.freq_offset(transport.offset());
3228+
3229+#ifdef USING_DVB
3230+    if (GetDVBSignalMonitor() && GetDVBChannel())
3231+    {
3232+        if (GetDVBChannel()->GetRotor())
3233+        {
3234+            GetDVBSignalMonitor()->AddFlags(SignalMonitor::kDVBSigMon_WaitForPos);
3235+            GetDVBSignalMonitor()->SetRotorTarget(1.0f);
3236+        }
3237+    }
3238+#endif // USING_DVB
3239+
3240+    if (!GetDTVChannel())
3241+        return false;
3242+
3243+    if (item.mplexid > 0)
3244+        return GetDTVChannel()->TuneMultiplex(item.mplexid, inputname);
3245+
3246+    DTVMultiplex tuning = item.tuning;
3247+    tuning.frequency = freq;
3248+    return GetDTVChannel()->Tune(tuning, inputname);
3249+}
3250+
3251+void SIScan::ScanTransport(const transport_scan_items_it_t transport)
3252+{
3253+    QString offset_str = (transport.offset()) ?
3254+        QObject::tr(" offset %2").arg(transport.offset()) : "";
3255+    QString cur_chan = QString("%1%2")
3256+        .arg((*current).FriendlyName).arg(offset_str);
3257+    QString tune_msg_str =
3258+        QObject::tr("Tuning to %1 mplexid(%2)")
3259+        .arg(cur_chan).arg((*current).mplexid);
3260+
3261+    const TransportScanItem &item = *transport;
3262+
3263+    if (transport.offset() &&
3264+        (item.freq_offset(transport.offset()) == item.freq_offset(0)))
3265+    {
3266+        waitingForTables = false;
3267+        return; // nothing to do
3268+    }
3269+
3270+    emit ServiceScanUpdateStatusText(cur_chan);
3271+    VERBOSE(VB_SIPARSER, LOC + tune_msg_str);
3272+
3273+    if (!Tune(transport))
3274+    {   // If we did not tune successfully, bail with message
3275+        UpdateScanPercentCompleted();
3276+        VERBOSE(VB_SIPARSER, LOC +
3277+                QString("Failed to tune %1 mplexid(%2) at offset %3")
3278+                .arg(item.FriendlyName).arg(item.mplexid)
3279+                .arg(transport.offset()));
3280+        return;
3281+    }
3282+
3283+    // If we have a DTV Signal Monitor, perform table scanner reset
3284+    if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
3285+    {
3286+        GetDTVSignalMonitor()->GetScanStreamData()->Reset();
3287+        GetDTVSignalMonitor()->SetChannel(-1,-1);
3288+    }
3289+
3290+    // Start signal monitor for this channel
3291+    signalMonitor->Start();
3292+
3293+    timer.start();
3294+    waitingForTables = true;
3295+}
3296+
3297+/** \fn SIScan::StopScanner(void)
3298+ *  \brief Stops the SIScan event loop and the signal monitor,
3299+ *         blocking until both exit.
3300+ */
3301+void SIScan::StopScanner(void)
3302+{
3303+    VERBOSE(VB_SIPARSER, LOC + "Stopping SIScanner");
3304+
3305+    threadExit = true;
3306+
3307+    if (scanner_thread_running)
3308+        pthread_join(scanner_thread, NULL);
3309+
3310+    if (signalMonitor)
3311+    {
3312+        signalMonitor->Stop();
3313+        delete signalMonitor;
3314+        signalMonitor = NULL;
3315+    }
3316+}
3317+
3318+/** \fn SIScan::ScanTransports(int,const QString,const QString,const QString)
3319+ *  \brief Generates a list of frequencies to scan and adds it to the
3320+ *   scanTransport list, and then sets the scanMode to TRANSPORT_LIST.
3321+ */
3322+bool SIScan::ScanTransports(int SourceID,
3323+                            const QString std,
3324+                            const QString modulation,
3325+                            const QString country)
3326+{
3327+    QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
3328+    QString name("");
3329+    if (scanMode == TRANSPORT_LIST)
3330+        return false;
3331+
3332+    scanTransports.clear();
3333+    nextIt = transport_scan_items_it_t( scanTransports.end());
3334+
3335+    freq_table_list_t tables =
3336+        get_matching_freq_tables(std, modulation, country);
3337+
3338+    VERBOSE(VB_SIPARSER, LOC +
3339+            QString("Looked up freq table (%1, %2, %3) w/%4 entries")
3340+            .arg(std).arg(modulation).arg(country).arg(tables.size()));
3341+
3342+    freq_table_list_t::iterator it = tables.begin();
3343+    for (; it != tables.end(); ++it)
3344+    {
3345+        const FrequencyTable &ft = **it;
3346+        int     name_num         = ft.name_offset;
3347+        QString strNameFormat    = ft.name_format;
3348+        uint    freq             = ft.frequencyStart;
3349+        while (freq <= ft.frequencyEnd)
3350+        {
3351+            name = strNameFormat;
3352+            if (strNameFormat.indexOf("%") >= 0)
3353+                name = strNameFormat.arg(name_num);
3354+
3355+            TransportScanItem item(SourceID, si_std, name, name_num,
3356+                                   freq, ft, signalTimeout);
3357+            scanTransports += item;
3358+
3359+            VERBOSE(VB_SIPARSER, LOC + item.toString());
3360+
3361+            name_num++;
3362+            freq += ft.frequencyStep;
3363+        }
3364+        delete *it;
3365+    }
3366+    tables.clear();
3367+
3368+    timer.start();
3369+    waitingForTables = false;
3370+
3371+    nextIt            = transport_scan_items_it_t( scanTransports.begin() );
3372+    transportsScanned = 0;
3373+    scanMode          = TRANSPORT_LIST;
3374+
3375+    return true;
3376+}
3377+
3378+bool SIScan::ScanForChannels(uint sourceid,
3379+                             const QString &std,
3380+                             const QString &cardtype,
3381+                             const DTVChannelList &channels)
3382+{
3383+    scanTransports.clear();
3384+    nextIt = transport_scan_items_it_t( scanTransports.end());
3385+
3386+    DTVTunerType tunertype;
3387+    tunertype.Parse(cardtype);
3388+
3389+    DTVChannelList::const_iterator it = channels.begin();
3390+    for (uint i = 0; it != channels.end(); ++it, i++)
3391+    {
3392+        DTVTransport tmp = *it;
3393+        tmp.sistandard = std;
3394+        TransportScanItem item(sourceid, QString::number(i),
3395+                               tunertype, tmp, signalTimeout);
3396+
3397+        scanTransports += item;
3398+
3399+        VERBOSE(VB_SIPARSER, LOC + item.toString());
3400+    }
3401+
3402+    if (scanTransports.empty())
3403+    {
3404+        VERBOSE(VB_IMPORTANT, LOC_ERR + "ScanForChannels() no transports");
3405+        return false;
3406+    }
3407+
3408+    timer.start();
3409+    waitingForTables = false;
3410+
3411+    nextIt            = transport_scan_items_it_t( scanTransports.begin());
3412+    transportsScanned = 0;
3413+    scanMode          = TRANSPORT_LIST;
3414+
3415+    return true;
3416+}
3417+
3418+/** \fn SIScan::ScanTransportsStartingOn(int,const QMap<QString,QString>&)
3419+ *  \brief Generates a list of frequencies to scan and adds it to the
3420+ *   scanTransport list, and then sets the scanMode to TRANSPORT_LIST.
3421+ */
3422+bool SIScan::ScanTransportsStartingOn(int sourceid,
3423+                                      const QMap<QString,QString> &startChan)
3424+{
3425+    QMap<QString,QString>::const_iterator it;
3426+
3427+    if (startChan.find("std")        == startChan.end() ||
3428+        startChan.find("modulation") == startChan.end())
3429+    {
3430+        return false;
3431+    }
3432+
3433+    QString std    = *startChan.find("std");
3434+    QString mod    = (*(startChan.find("modulation"))).toUpper();
3435+    QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";
3436+    QString name   = "";
3437+    bool    ok     = false;
3438+
3439+    if (scanMode == TRANSPORT_LIST)
3440+        return false;
3441+
3442+    scanTransports.clear();
3443+    nextIt = transport_scan_items_it_t( scanTransports.end() );
3444+
3445+    DTVMultiplex tuning;
3446+    DTVModulation modulation;
3447+    DTVModulationSystem msystem;
3448+    DTVTunerType type;
3449+
3450+    if (std == "dvb")
3451+    {
3452+        if (!modulation.Parse(*(startChan.find("modulation"))))
3453+        {
3454+            VERBOSE(VB_IMPORTANT, LOC + "Wrong modulation.");
3455+            return false;
3456+        }
3457+
3458+        if (modulation == DTVModulation::kModulationQPSK)
3459+        {
3460+            type = DTVTunerType::kTunerTypeQPSK;
3461+            ok = true;
3462+            if (startChan.find("msystem") != startChan.end())
3463+            {
3464+                if (!msystem.Parse(*(startChan.find("msystem"))))
3465+                {
3466+                    VERBOSE(VB_IMPORTANT, LOC + "Wrong modulation system.");
3467+                    return false;
3468+                }
3469+                if (msystem == DTVModulationSystem::kModulationSystemDVBS2)
3470+                    type = DTVTunerType::kTunerTypeDVB_S2;
3471+            }
3472+        }
3473+        else if (modulation == DTVModulation::kModulation8PSK)
3474+        {
3475+            type = DTVTunerType::kTunerTypeDVB_S2;
3476+            ok = true;
3477+        }
3478+        else
3479+            ok = type.Parse(mod);
3480+    }
3481+    else if (std == "atsc")
3482+    {
3483+        type = DTVTunerType::kTunerTypeATSC;
3484+        ok = true;
3485+    }
3486+
3487+    if (ok)
3488+    {
3489+        ok = tuning.ParseTuningParams(
3490+            type,
3491+            startChan["frequency"],      startChan["inversion"],
3492+            startChan["symbolrate"],     startChan["fec"],
3493+            startChan["polarity"],
3494+            startChan["coderate_hp"],    startChan["coderate_lp"],
3495+            startChan["constellation"],  startChan["trans_mode"],
3496+            startChan["guard_interval"], startChan["hierarchy"],
3497+            startChan["modulation"],     startChan["bandwidth"],
3498+            startChan["msystem"],        startChan["rolloff"]);
3499+    }
3500+
3501+    if (ok)
3502+    {
3503+        tuning.sistandard = si_std;
3504+        scanTransports += TransportScanItem(
3505+            sourceid, tr("Frequency %1").arg(startChan["frequency"]),
3506+            tuning, signalTimeout);
3507+    }
3508+
3509+    if (!ok)
3510+        return false;
3511+
3512+    timer.start();
3513+    waitingForTables = false;
3514+
3515+    nextIt            = transport_scan_items_it_t(scanTransports.begin());
3516+    transportsScanned = 0;
3517+    scanMode          = TRANSPORT_LIST;
3518+
3519+    return true;
3520+}
3521+
3522+bool SIScan::ScanTransport(int mplexid)
3523+{
3524+    scanTransports.clear();
3525+    nextIt = transport_scan_items_it_t(scanTransports.end());
3526+
3527+    MSqlQuery query(MSqlQuery::InitCon());
3528+    // Run DB query to get transports on sourceid SourceID
3529+    // connected to this card
3530+    QString theQuery = QString(
3531+        "SELECT sourceid, mplexid, sistandard, transportid "
3532+        "FROM dtv_multiplex WHERE mplexid = %2").arg(mplexid);
3533+    query.prepare(theQuery);
3534+
3535+    if (!query.exec() || !query.isActive())
3536+    {
3537+        MythDB::DBError("Get Transports for SourceID", query);
3538+        return false;
3539+    }
3540+
3541+    if (query.size() <= 0)
3542+    {
3543+        VERBOSE(VB_SIPARSER, LOC + "Unable to find transport to scan.");
3544+        return false;
3545+    }
3546+
3547+    while (query.next())
3548+    {
3549+        int sourceid = query.value(0).toInt();
3550+        int queriedMplexid  = query.value(1).toInt();
3551+        QString std  = query.value(2).toString();
3552+        int tsid     = query.value(3).toInt();
3553+
3554+        QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
3555+            QString("Multiplex #%1").arg(queriedMplexid);
3556+
3557+        VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);
3558+
3559+        TransportScanItem item(
3560+            sourceid, std, fn, queriedMplexid, signalTimeout);
3561+        scanTransports += item;
3562+    }
3563+
3564+    timer.start();
3565+    waitingForTables  = false;
3566+
3567+    transportsScanned = 0;
3568+    if (scanTransports.size())
3569+    {
3570+        nextIt        = transport_scan_items_it_t(scanTransports.begin());
3571+        scanMode      = TRANSPORT_LIST;
3572+        return true;
3573+    }
3574+
3575+    return false;
3576+}
3577+
3578+/** \fn SIScan::CheckImportedList(const DTVChannelInfoList&,uint,QString&,QString&,QString&)
3579+ *  \brief If we as scanning a dvb-utils import verify channel is in list..
3580+ */
3581+bool SIScan::CheckImportedList(const DTVChannelInfoList &channels,
3582+                               uint mpeg_program_num,
3583+                               QString &service_name,
3584+                               QString &callsign,
3585+                               QString &common_status_info)
3586+{
3587+    if (channels.empty())
3588+        return true;
3589+
3590+    bool found = false;
3591+    for (uint i = 0; i < channels.size(); i++)
3592+    {
3593+        VERBOSE(VB_IMPORTANT,
3594+                QString("comparing %1 %2 against %3 %4")
3595+                .arg(channels[i].serviceid).arg(channels[i].name)
3596+                .arg(mpeg_program_num).arg(common_status_info));
3597+
3598+        if (channels[i].serviceid == mpeg_program_num)
3599+        {
3600+            found = true;
3601+            if (!channels[i].name.isEmpty())
3602+            {
3603+                service_name = channels[i].name; service_name.detach();
3604+                callsign     = channels[i].name; callsign.detach();
3605+            }
3606+        }
3607+    }
3608+
3609+    if (found)
3610+    {
3611+        common_status_info += QString(" %1 %2")
3612+            .arg(tr("as")).arg(service_name);
3613+    }
3614+    else
3615+    {
3616+        emit ServiceScanUpdateText(
3617+            tr("Skipping %1, not in imported channel map")
3618+            .arg(common_status_info));
3619+    }
3620+
3621+    return found;
3622+}
3623+
3624+// ///////////////////// DB STUFF /////////////////////
3625+// ///////////////////// DB STUFF /////////////////////
3626+// ///////////////////// DB STUFF /////////////////////
3627+// ///////////////////// DB STUFF /////////////////////
3628+// ///////////////////// DB STUFF /////////////////////
3629+
3630+void SIScan::UpdatePMTinDB(
3631+    int db_source_id,
3632+    int db_mplexid, const QString &friendlyName, int freqid,
3633+    int pmt_indx, const ProgramMapTable *pmt,
3634+    const DTVChannelInfoList &channels, bool /*force_update*/)
3635+{
3636+    VERBOSE(VB_IMPORTANT, LOC + pmt->toString());
3637+
3638+    // See if service already in database based on program number
3639+    int chanid = ChannelUtil::GetChanID(
3640+        db_mplexid, -1, -1, -1, pmt->ProgramNumber());
3641+
3642+    QString chan_num = ChannelUtil::GetChanNum(chanid);
3643+    if (chan_num.isEmpty() || renameChannels)
3644+    {
3645+        chan_num = QString("%1#%2")
3646+            .arg((freqid) ? freqid : db_mplexid).arg(pmt_indx);
3647+    }
3648+
3649+    QString callsign = ChannelUtil::GetCallsign(chanid);
3650+    QString service_name = ChannelUtil::GetServiceName(chanid);
3651+
3652+    if (callsign.isEmpty())
3653+    {
3654+        callsign = QString("%1%2")
3655+            .arg(ChannelUtil::GetUnknownCallsign())
3656+            .arg(chan_num);
3657+    }
3658+    else if (service_name.isEmpty())
3659+        service_name = callsign; // only do this for real callsigns
3660+
3661+    QString common_status_info = tr("%1%2%3 on %4 (%5)")
3662+        .arg(service_name)
3663+        .arg(service_name.isEmpty() ? "" : QString(" %1 ").arg(tr("as")))
3664+        .arg(chan_num)
3665+        .arg(friendlyName).arg(freqid);
3666+
3667+    if (!CheckImportedList(channels, pmt->ProgramNumber(),
3668+                           service_name, chan_num, common_status_info))
3669+    {
3670+        return;
3671+    }
3672+
3673+    if (chanid < 0)
3674+    {   // The service is not in database, add it
3675+        emit ServiceScanUpdateText(
3676+            tr("Adding %1").arg(common_status_info));
3677+        chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
3678+        ChannelUtil::CreateChannel(
3679+            db_mplexid, db_source_id, chanid,
3680+            callsign,
3681+            service_name,
3682+            chan_num,
3683+            pmt->ProgramNumber(),
3684+            0, 0,
3685+            false, false, false, QString::number(freqid));
3686+    }
3687+    else
3688+    {   // The service is in database, update it
3689+        emit ServiceScanUpdateText(
3690+            tr("Updating %1").arg(common_status_info));
3691+
3692+        bool useeit = false;
3693+        bool hidden = false;
3694+
3695+        ChannelUtil::GetChannelSettings(chanid, useeit, hidden);
3696+
3697+        ChannelUtil::UpdateChannel(
3698+            db_mplexid, db_source_id, chanid,
3699+            callsign,
3700+            service_name,
3701+            chan_num,
3702+            pmt->ProgramNumber(),
3703+            0, 0,
3704+            useeit, hidden, false, QString::number(freqid));
3705+    }
3706+}
3707+
3708+void SIScan::IgnoreDataOnlyMsg(const QString &name, int aux_num)
3709+{
3710+    QString vmsg = QString("Ignoring Data Channel: %1").arg(name);
3711+    if (aux_num > 0)
3712+        vmsg += QString(" on %1").arg(aux_num);
3713+    VERBOSE(VB_SIPARSER, vmsg);
3714+
3715+    //
3716+
3717+    QString tmsg = tr("Skipping %1").arg(name);
3718+    if (aux_num > 0)
3719+        tmsg += " " + tr("on %1").arg(aux_num);
3720+    tmsg += " - " + tr("Data Only Channel (off-air?)");
3721+    emit ServiceScanUpdateText(tmsg);
3722+}
3723+
3724+void SIScan::IgnoreEmptyChanMsg(const QString &name, int aux_num)
3725+{
3726+    QString vmsg = QString("Ignoring Empty Channel: %1").arg(name);
3727+    if (aux_num > 0)
3728+        vmsg += QString(" on %1").arg(aux_num);
3729+    VERBOSE(VB_SIPARSER, vmsg);
3730+
3731+    //
3732+
3733+    QString tmsg = tr("Skipping %1").arg(name);
3734+    if (aux_num > 0)
3735+        tmsg += " " + tr("on %1").arg(aux_num);
3736+    tmsg += " - " + tr("Empty Channel (off-air?)");
3737+    emit ServiceScanUpdateText(tmsg);
3738+}
3739+
3740+void SIScan::IgnoreAudioOnlyMsg(const QString &name, int aux_num)
3741+{
3742+    QString vmsg = QString("Ignoring Audio Only Channel: %1").arg(name);
3743+    if (aux_num > 0)
3744+        vmsg += QString(" on %1").arg(aux_num);
3745+    VERBOSE(VB_SIPARSER, vmsg);
3746+
3747+    //
3748+
3749+    QString tmsg = tr("Skipping %1").arg(name);
3750+    if (aux_num > 0)
3751+        tmsg += " " + tr("on %1").arg(aux_num);
3752+    tmsg += " - " + tr("Audio Only Channel");
3753+    emit ServiceScanUpdateText(tmsg);
3754+}
3755+
3756+void SIScan::IgnoreEncryptedMsg(const QString &name, int aux_num)
3757+{
3758+    QString vmsg = QString("Ignoring Encrypted Channel: %1").arg(name);
3759+    if (aux_num > 0)
3760+        vmsg += QString(" on %1").arg(aux_num);
3761+    VERBOSE(VB_SIPARSER, vmsg);
3762+
3763+    //
3764+
3765+    QString tmsg = tr("Skipping %1").arg(name);
3766+    if (aux_num > 0)
3767+        tmsg += " " + tr("on %1").arg(aux_num);
3768+    tmsg += " - " + tr("Encrypted Channel");
3769+    emit ServiceScanUpdateText(tmsg);
3770+}
3771+
3772+void SIScan::UpdatePATinDB(
3773+    int db_mplexid, const QString &friendlyName, int freqid,
3774+    const ProgramAssociationTable *pat, const pmt_map_t &pmt_map,
3775+    const DTVChannelInfoList &channels, const QString &si_standard,
3776+    bool force_update)
3777+{
3778+    VERBOSE(VB_SIPARSER, LOC +
3779+            QString("UpdatePATinDB(): tsid: 0x%1  mplex: %2")
3780+            .arg(pat->TransportStreamID(),0,16).arg(db_mplexid));
3781+
3782+    VERBOSE(VB_IMPORTANT, LOC + pat->toString());
3783+
3784+    int db_source_id   = ChannelUtil::GetSourceID(db_mplexid);
3785+
3786+    for (uint i = 0; i < pat->ProgramCount(); i++)
3787+    {
3788+        pmt_map_t::const_iterator it = pmt_map.find(pat->ProgramNumber(i));
3789+        if (it == pmt_map.end())
3790+        {
3791+            VERBOSE(VB_SIPARSER,
3792+                   QString("UpdatePATinDB(): PMT for Program #%1 is missing")
3793+                   .arg(pat->ProgramNumber(i)));
3794+            continue;
3795+        }
3796+        pmt_vec_t::const_iterator vit = (*it).begin();
3797+        for (; vit != (*it).end(); ++vit)
3798+        {
3799+            VERBOSE(VB_SIPARSER,
3800+                    QString("UpdatePATinDB(): Prog %1 PID %2: PMT @")
3801+                    .arg(pat->ProgramNumber(i))
3802+                    .arg(pat->ProgramPID(i)) << *vit);
3803+
3804+            // ignore all services without PMT, and
3805+            // ignore services we have decided to ignore
3806+            if (!(*vit))
3807+                continue;
3808+            else if ((*vit)->StreamCount() <= 0)
3809+            {
3810+                IgnoreEmptyChanMsg(friendlyName, pat->ProgramNumber(i));
3811+                continue;
3812+            }
3813+            else if (ignoreAudioOnlyServices &&
3814+                     (*vit)->IsStillPicture(si_standard))
3815+            {
3816+                IgnoreAudioOnlyMsg(friendlyName, pat->ProgramNumber(i));
3817+                continue;
3818+            }
3819+            else if (ignoreEncryptedServices && (*vit)->IsEncrypted())
3820+            {
3821+                IgnoreEncryptedMsg(friendlyName, pat->ProgramNumber(i));
3822+                continue;
3823+            }
3824+
3825+            UpdatePMTinDB(db_source_id, db_mplexid, friendlyName, freqid,
3826+                          i, *vit, channels, force_update);
3827+        }
3828+    }
3829+}
3830+
3831+void SIScan::UpdateVCTinDB(int db_mplexid,
3832+                           const QString &friendlyName, int freqid,
3833+                           const VirtualChannelTable *vct,
3834+                           const DTVChannelInfoList &channels,
3835+                           bool force_update)
3836+{
3837+    (void) force_update;
3838+
3839+    VERBOSE(VB_SIPARSER, LOC +
3840+            QString("UpdateVCTinDB(): tsid: 0x%1  mplex: %2")
3841+            .arg(vct->TransportStreamID(),0,16).arg(db_mplexid));
3842+
3843+    int db_source_id   = ChannelUtil::GetSourceID(db_mplexid);
3844+
3845+    for (uint i = 0; i < vct->ChannelCount(); i++)
3846+    {
3847+        if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||
3848+            vct->ServiceType(i)    == 0x01 /* Analog TV */)
3849+        {
3850+            continue;
3851+        }
3852+
3853+        QString basic_status_info = QString("%1 %2-%3")
3854+            .arg(vct->ShortChannelName(i))
3855+            .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i));
3856+
3857+        if (vct->ServiceType(i) == 0x04 && ignoreDataServices)
3858+        {
3859+            IgnoreEmptyChanMsg(basic_status_info, vct->ProgramNumber(i));
3860+            continue;
3861+        }
3862+
3863+        if (vct->ServiceType(i) == 0x03 && ignoreAudioOnlyServices)
3864+        {
3865+            IgnoreAudioOnlyMsg(basic_status_info, vct->ProgramNumber(i));
3866+            continue;
3867+        }
3868+
3869+        if (vct->IsAccessControlled(i) && ignoreEncryptedServices)
3870+        {
3871+            IgnoreEncryptedMsg(basic_status_info, vct->ProgramNumber(i));
3872+            continue;
3873+        }
3874+
3875+        // See if service already in database
3876+        int chanid = ChannelUtil::GetChanID(
3877+            db_mplexid, vct->ChannelTransportStreamID(i),
3878+            vct->MajorChannel(i), vct->MinorChannel(i),
3879+            vct->ProgramNumber(i));
3880+
3881+        QString chan_num = ChannelUtil::GetChanNum(chanid);
3882+        if (chan_num.isEmpty() || renameChannels)
3883+        {
3884+            chan_num = channelFormat
3885+                .arg(vct->MajorChannel(i))
3886+                .arg(vct->MinorChannel(i));
3887+        }
3888+
3889+        QString callsign = ChannelUtil::GetCallsign(chanid);
3890+        if (callsign.isEmpty() || renameChannels)
3891+            callsign = vct->ShortChannelName(i);
3892+
3893+        // try to find an extended channel name, fallback to short name.
3894+        QString longName = vct->GetExtendedChannelName(i);
3895+        if (longName.isEmpty())
3896+            longName = vct->ShortChannelName(i);
3897+
3898+        QString common_status_info = tr("%1 %2-%3 as %4 on %5 (%6)")
3899+            .arg(vct->ShortChannelName(i))
3900+            .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i))
3901+            .arg(chan_num).arg(friendlyName).arg(freqid);
3902+
3903+        bool use_eit = !vct->IsHidden(i) ||
3904+            (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));
3905+
3906+
3907+        if (!CheckImportedList(channels, vct->ProgramNumber(i),
3908+                               longName, callsign, common_status_info))
3909+        {
3910+            continue;
3911+        }
3912+
3913+        QString msg = "";
3914+        if (chanid < 0)
3915+        {   // The service is not in database, add it
3916+            msg = tr("Adding %1").arg(common_status_info);
3917+            chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
3918+            if (chanid > 0)
3919+            {
3920+                bool use_eit = !vct->IsHidden(i) ||
3921+                    (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));
3922+
3923+                ChannelUtil::CreateChannel(
3924+                    db_mplexid,
3925+                    db_source_id,
3926+                    chanid,
3927+                    callsign,
3928+                    longName,
3929+                    chan_num,
3930+                    vct->ProgramNumber(i),
3931+                    vct->MajorChannel(i), vct->MinorChannel(i),
3932+                    use_eit,
3933+                    vct->IsHidden(i), vct->IsHiddenInGuide(i),
3934+                    QString::number(freqid));
3935+            }
3936+        }
3937+        else
3938+        {   // The service is in database, update it
3939+            msg = tr("Updating %1").arg(common_status_info);
3940+            ChannelUtil::UpdateChannel(
3941+                db_mplexid,
3942+                db_source_id,
3943+                chanid,
3944+                callsign,
3945+                longName,
3946+                chan_num,
3947+                vct->ProgramNumber(i),
3948+                vct->MajorChannel(i), vct->MinorChannel(i),
3949+                use_eit,
3950+                vct->IsHidden(i), vct->IsHiddenInGuide(i),
3951+                QString::number(freqid));
3952+        }
3953+        emit ServiceScanUpdateText(msg);
3954+        VERBOSE(VB_SIPARSER, msg);
3955+    }
3956+}
3957+
3958+/**
3959+ *  \brief Inserts channels from service description table.
3960+ */
3961+void SIScan::UpdateSDTinDB(int /*mplexid*/, const ServiceDescriptionTable *sdt,
3962+                           const DTVChannelInfoList &channels,
3963+                           bool force_update)
3964+{
3965+    if (!sdt->ServiceCount())
3966+        return;
3967+
3968+    int db_mplexid = ChannelUtil::GetMplexID(
3969+        sourceID, sdt->TSID(), sdt->OriginalNetworkID());
3970+
3971+    // HACK beg -- special exception for this network (dbver == "1067")
3972+    bool force_guide_present = (sdt->OriginalNetworkID() == 70);
3973+    // HACK end -- special exception for this network
3974+
3975+    if (db_mplexid == -1)
3976+    {
3977+        VERBOSE(VB_IMPORTANT, "SDT: Error determing what transport this "
3978+                "service table is associated with so failing");
3979+        emit ServiceScanUpdateText(
3980+            tr("Found channel, but it doesn't match existing tsid. You may "
3981+               "wish to delete existing channels and do a full scan."));
3982+        return;
3983+    }
3984+
3985+    int db_source_id = ChannelUtil::GetSourceID(db_mplexid);
3986+
3987+    /* This will be fixed post .17 to be more elegant */
3988+    bool upToDate = (ChannelUtil::GetServiceVersion(db_mplexid) ==
3989+                     (int)sdt->Version());
3990+    if (upToDate && !force_update)
3991+    {
3992+        emit ServiceScanUpdateText("Channels up to date");
3993+        return;
3994+    }
3995+    if (!upToDate)
3996+        ChannelUtil::SetServiceVersion(db_mplexid, sdt->Version());
3997+
3998+    for (uint i = 0; i < sdt->ServiceCount(); i++)
3999+    {
4000+        // Figure out best service name...
4001+        ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
4002+        QString service_name = "";
4003+        if (desc)
4004+            service_name = desc->ServiceName();
4005+
4006+        if (service_name.trimmed().isEmpty())
4007+            service_name = QString("%1 %2")
4008+                .arg(sdt->ServiceID(i)).arg(db_mplexid);
4009+
4010+        // Figure out best channel number
4011+        QString chan_num = QString::number(sdt->ServiceID(i));
4012+        bool have_uk_chan_num =
4013+            dvbChanNums.find(sdt->ServiceID(i)) != dvbChanNums.end();
4014+        if (have_uk_chan_num)
4015+            chan_num = QString::number(dvbChanNums[sdt->ServiceID(i)]);
4016+
4017+        // Skip to next if this is a service we don't care for
4018+        if (desc && desc->IsDigitalAudio() && ignoreAudioOnlyServices)
4019+        {
4020+            IgnoreAudioOnlyMsg(service_name, sdt->ServiceID(i));
4021+            delete desc;
4022+            continue;
4023+        }
4024+        else if (desc && !desc->IsDTV() && !desc->IsDigitalAudio() &&
4025+                 ignoreDataServices)
4026+        {
4027+            IgnoreDataOnlyMsg(service_name, sdt->ServiceID(i));
4028+            delete desc;
4029+            continue;
4030+        }
4031+        else if (ignoreEncryptedServices && sdt->IsEncrypted(i))
4032+        {
4033+            IgnoreEncryptedMsg(service_name, sdt->ServiceID(i));
4034+            if (desc)
4035+                delete desc;
4036+            continue;
4037+        }
4038+
4039+        // Default authority
4040+        QString default_authority = "";
4041+        desc_list_t parsed =
4042+            MPEGDescriptor::Parse(sdt->ServiceDescriptors(i),
4043+                                  sdt->ServiceDescriptorsLength(i));
4044+        const unsigned char *def_auth =
4045+            MPEGDescriptor::Find(parsed, DescriptorID::default_authority);
4046+        if (def_auth)
4047+            default_authority =
4048+                QString::fromAscii((const char*)def_auth+2, def_auth[1]);
4049+
4050+        QString common_status_info = service_name;
4051+
4052+        if (!CheckImportedList(channels, sdt->ServiceID(i),
4053+                               service_name, service_name, common_status_info))
4054+        {
4055+            if (desc)
4056+                delete desc;
4057+            continue;
4058+        }
4059+
4060+        // See if service already in database based on service ID
4061+        int chanid = ChannelUtil::GetChanID(db_mplexid, -1, -1, -1,
4062+                                            sdt->ServiceID(i));
4063+
4064+        if (chanid < 0)
4065+        {   // The service is not in database, add it
4066+            emit ServiceScanUpdateText(tr("Adding %1").arg(service_name));
4067+            chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
4068+            if (chanid > 0)
4069+            {
4070+                ChannelUtil::CreateChannel(
4071+                    db_mplexid, db_source_id, chanid,
4072+                    service_name,
4073+                    service_name,
4074+                    chan_num,
4075+                    sdt->ServiceID(i),
4076+                    0, 0,
4077+                    sdt->HasEITSchedule(i) ||
4078+                    sdt->HasEITPresentFollowing(i) ||
4079+                    force_guide_present,
4080+                    false, false, QString::null,
4081+                    QString::null, "Default", QString::null,
4082+                    default_authority);
4083+            }
4084+        }
4085+        else if (force_update || (desc && have_uk_chan_num))
4086+        {   // The service is in database & we have good info, update it
4087+            emit ServiceScanUpdateText(tr("Updating %1").arg(service_name));
4088+
4089+            bool useeit = false;
4090+            bool hidden = false;
4091+
4092+            ChannelUtil::GetChannelSettings(chanid, useeit, hidden);
4093+
4094+            if (!renameChannels)
4095+                chan_num = ChannelUtil::GetChanNum(chanid);
4096+            else
4097+                useeit = (sdt->HasEITSchedule(i) ||
4098+                            sdt->HasEITPresentFollowing(i) ||
4099+                            force_guide_present);
4100+
4101+            ChannelUtil::UpdateChannel(
4102+                db_mplexid,
4103+                db_source_id,
4104+                chanid,
4105+                service_name,
4106+                service_name,
4107+                chan_num,
4108+                sdt->ServiceID(i),
4109+                0, 0,
4110+                useeit,
4111+                hidden, false, QString::null,
4112+                QString::null, QString::null, QString::null,
4113+                default_authority);
4114+        }
4115+        else
4116+        {
4117+            emit ServiceScanUpdateText(
4118+                tr("Skipping %1 - already in DB, and "
4119+                   "we don't have better data.")
4120+                .arg(service_name));
4121+        }
4122+
4123+        if (desc)
4124+            delete desc;
4125+    }
4126+}
4127+
4128+// FindBestMplexFreq()
4129+//  - Examines the freq in the DB against the curent tuning frequency and
4130+//    it's offset frequencies. If the frequency in the DB is any of the
4131+//    tuning frequencies or offsets then use the DB frequency.
4132+uint64_t SIScan::FindBestMplexFreq(
4133+    const uint64_t tuning_freq,
4134+    const transport_scan_items_it_t transport, const uint sourceid,
4135+    const uint transportid, const uint networkid)
4136+{
4137+    uint64_t    db_freq;
4138+    QString     tmp_modulation, tmp_msystem, tmp_rolloff;
4139+    QString     tmp_si_std;
4140+    uint        tmp_transportid, tmp_networkid;
4141+    int         mplexid;
4142+
4143+    if (!transportid || !networkid)
4144+        return tuning_freq;
4145+
4146+    mplexid = ChannelUtil::GetMplexID(sourceid, transportid, networkid);
4147+    if (mplexid <= 0)
4148+        return tuning_freq;
4149+
4150+    if (!ChannelUtil::GetTuningParams(
4151+            (uint)mplexid, tmp_modulation,
4152+            db_freq, tmp_transportid, tmp_networkid, tmp_msystem, tmp_rolloff, tmp_si_std))
4153+    {
4154+        return tuning_freq;
4155+    }
4156+
4157+    for (uint i = 0; i < (*transport).offset_cnt(); i++)
4158+    {
4159+        if (db_freq == (*transport).freq_offset(i))
4160+            return db_freq;
4161+    }
4162+
4163+    return tuning_freq;
4164+}
4165+
4166+uint SIScan::InsertMultiplex(const transport_scan_items_it_t transport)
4167+{
4168+    DTVMultiplex tuning = (*transport).tuning;
4169+    uint tsid  = 0;
4170+    uint netid = 0;
4171+
4172+    tuning.frequency = (*transport).freq_offset(transport.offset());
4173+
4174+#ifdef USING_DVB
4175+    if (GetDVBSignalMonitor())
4176+    {
4177+        DVBSignalMonitor *sm = GetDVBSignalMonitor();
4178+
4179+        tsid  = sm->GetDetectedTransportID();
4180+        netid = sm->GetDetectedNetworkID();
4181+
4182+        // Try to read the actual values back from the card
4183+        if (GetDVBChannel()->IsTuningParamsProbeSupported())
4184+            GetDVBChannel()->ProbeTuningParams(tuning);
4185+
4186+        tuning.frequency = FindBestMplexFreq(
4187+            tuning.frequency, transport, (*transport).SourceID, tsid, netid);
4188+    }
4189+#endif // USING_DVB
4190+
4191+#ifdef USING_V4L
4192+    if (GetV4LChannel())
4193+    {
4194+        // convert to visual carrier
4195+        tuning.frequency = tuning.frequency - 1750000;
4196+    }
4197+#endif // USING_V4L
4198+
4199+    return ChannelUtil::CreateMultiplex(
4200+        (*transport).SourceID, tuning, tsid, netid);
4201+}