Ticket #2695: 2695-merge-v1.patch
| File 2695-merge-v1.patch, 172.8 KB (added by , 17 years ago) |
|---|
-
libs/libmythtv/libmythtv.pro
25 25 DEPENDPATH += ../libmyth ../libavcodec ../libavformat ../libavutil ../libswscale 26 26 DEPENDPATH += ../libmythmpeg2 ../libmythdb ../libmythhdhomerun 27 27 DEPENDPATH += ../libmythdvdnav/ 28 DEPENDPATH += ./dvbdev ./mpeg ./iptv 28 DEPENDPATH += ./dvbdev ./mpeg ./iptv ./channelscan 29 29 DEPENDPATH += ../libmythlivemedia/BasicUsageEnvironment/include 30 30 DEPENDPATH += ../libmythlivemedia/BasicUsageEnvironment 31 31 DEPENDPATH += ../libmythlivemedia/groupsock/include … … 247 247 SOURCES += dtvmultiplex.cpp 248 248 SOURCES += dtvconfparser.cpp dtvconfparserhelpers.cpp 249 249 250 HEADERS += channelscan/scaninfo.h channelscan/channelimporter.h 251 SOURCES += channelscan/scaninfo.cpp channelscan/channelimporter.cpp 252 250 253 using_frontend { 251 254 # Recording profile stuff 252 255 HEADERS += profilegroup.h … … 399 402 SOURCES += inputinfo.cpp inputgroupmap.cpp 400 403 401 404 # Channel scanner stuff 402 HEADERS += scanwizard.h scanwizardhelpers.h 403 HEADERS += siscan.h 404 HEADERS += scanwizardscanner.h 405 SOURCES += scanwizard.cpp scanwizardhelpers.cpp 406 SOURCES += siscan.cpp 407 SOURCES += scanwizardscanner.cpp 405 HEADERS += scanwizard.h 406 SOURCES += scanwizard.cpp 408 407 408 HEADERS += channelscan/channelscan_sm.h 409 HEADERS += channelscan/channelscanner.h 410 HEADERS += channelscan/channelscanner_gui.h 411 HEADERS += channelscan/channelscanner_cli.h 412 HEADERS += channelscan/frequencytablesetting.h 413 HEADERS += channelscan/inputselectorsetting.h 414 HEADERS += channelscan/loglist.h 415 HEADERS += channelscan/channelscanmiscsettings.h 416 HEADERS += channelscan/modulationsetting.h 417 HEADERS += channelscan/multiplexsetting.h 418 HEADERS += channelscan/paneanalog.h 419 HEADERS += channelscan/paneatsc.h 420 HEADERS += channelscan/panedvbc.h 421 HEADERS += channelscan/panedvbs.h 422 HEADERS += channelscan/panedvbs2.h 423 HEADERS += channelscan/panedvbt.h 424 HEADERS += channelscan/panedvbutilsimport.h 425 HEADERS += channelscan/panesingle.h 426 HEADERS += channelscan/scanmonitor.h 427 HEADERS += channelscan/scanprogresspopup.h 428 HEADERS += channelscan/scanwizardconfig.h 429 430 SOURCES += channelscan/channelscan_sm.cpp 431 SOURCES += channelscan/channelscanner.cpp 432 SOURCES += channelscan/channelscanner_gui.cpp 433 SOURCES += channelscan/channelscanner_cli.cpp 434 SOURCES += channelscan/frequencytablesetting.cpp 435 SOURCES += channelscan/inputselectorsetting.cpp 436 SOURCES += channelscan/loglist.cpp 437 SOURCES += channelscan/multiplexsetting.cpp 438 SOURCES += channelscan/paneanalog.cpp 439 SOURCES += channelscan/scanmonitor.cpp 440 SOURCES += channelscan/scanprogresspopup.cpp 441 SOURCES += channelscan/scanwizardconfig.cpp 442 409 443 # EIT stuff 410 444 HEADERS += eithelper.h eitscanner.h 411 445 HEADERS += eitfixup.h eitcache.h -
libs/libmythtv/scanwizardhelpers.h
1 /* -*- Mode: c++ -*-2 * $Id$3 * vim: set expandtab tabstop=4 shiftwidth=4:4 *5 * Original Project6 * MythTV http://www.mythtv.org7 *8 * Author(s):9 * John Pullan (john@pullan.org)10 *11 * Description:12 * Collection of classes to provide dvb channel scanning13 * functionality14 *15 *16 * This program is free software; you can redistribute it and/or17 * modify it under the terms of the GNU General Public License18 * as published by the Free Software Foundation; either version 219 * of the License, or (at your option) any later version.20 *21 * This program is distributed in the hope that it will be useful,22 * but WITHOUT ANY WARRANTY; without even the implied warranty of23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the24 * GNU General Public License for more details.25 *26 * You should have received a copy of the GNU General Public License27 * along with this program; if not, write to the Free Software28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.29 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html30 *31 */32 33 #ifndef SCANWIZARDHELPERS_H34 #define SCANWIZARDHELPERS_H35 36 #include "compat.h"37 #include "settings.h"38 39 #include <qwaitcondition.h>40 #include <qevent.h>41 42 class TransFreqTableSelector;43 class TransLabelSetting;44 class ScanWizardScanner;45 class ScanWizard;46 class OptionalTypeSetting;47 class VideoSourceSelector;48 class OFDMPane;49 class QPSKPane;50 class DVBS2Pane;51 class ATSCPane;52 class QAMPane;53 class AnalogPane;54 class STPane;55 class DVBUtilsImportPane;56 57 class ScanSignalMeter: public ProgressSetting, public TransientStorage58 {59 public:60 ScanSignalMeter(int steps): ProgressSetting(this, steps) {};61 };62 63 class ScanProgressPopup : public ConfigurationPopupDialog64 {65 Q_OBJECT66 67 friend class QObject; // quiet OSX gcc warning68 69 public:70 ScanProgressPopup(bool lock, bool strength, bool snr);71 virtual void deleteLater(void);72 73 void CreateDialog(void);74 virtual DialogCode exec(void);75 void DeleteDialog(void);76 77 void SetStatusSignalToNoise(int value);78 void SetStatusSignalStrength(int value);79 void SetStatusLock(int value);80 void SetScanProgress(double value);81 82 void SetStatusText(const QString &value);83 void SetStatusTitleText(const QString &value);84 85 private slots:86 void Done(void);87 88 private:89 ~ScanProgressPopup();90 91 bool done;92 QWaitCondition wait;93 94 ScanSignalMeter *ss;95 ScanSignalMeter *sn;96 ScanSignalMeter *progressBar;97 98 TransLabelSetting *sl;99 TransLabelSetting *sta;100 };101 102 class ScannerEvent : public QEvent103 {104 friend class QObject; // quiet OSX gcc warning105 106 public:107 enum TYPE108 {109 ScanComplete,110 ScanShutdown,111 AppendTextToLog,112 SetStatusText,113 SetStatusTitleText,114 SetPercentComplete,115 SetStatusRotorPosition,116 SetStatusSignalToNoise,117 SetStatusSignalStrength,118 SetStatusSignalLock,119 };120 121 ScannerEvent(TYPE t) :122 QEvent((QEvent::Type)(t + QEvent::User)),123 str(""), intvalue(0), spp_ptr(NULL) { ; }124 125 QString strValue() const { return str; }126 void strValue(const QString& _str) { str = _str; }127 128 int intValue() const { return intvalue; }129 void intValue(int _intvalue) { intvalue = _intvalue; }130 131 ScanProgressPopup *ScanProgressPopupValue() const { return spp_ptr; }132 void ScanProgressPopupValue(ScanProgressPopup *_spp_ptr)133 { spp_ptr = _spp_ptr; }134 135 TYPE eventType() const { return (TYPE)(type()-QEvent::User); }136 137 private:138 ~ScannerEvent() { }139 140 private:141 QString str;142 int intvalue;143 ScanProgressPopup *spp_ptr;144 };145 146 void post_event(QObject *dest, ScannerEvent::TYPE type, int val);147 void post_event(QObject *dest, ScannerEvent::TYPE type, const QString &val);148 void post_event(QObject *dest, ScannerEvent::TYPE type, int val,149 ScanProgressPopup *spp);150 151 // ///////////////////////////////152 // Settings Below Here153 // ///////////////////////////////154 155 class MultiplexSetting : public ComboBoxSetting, public TransientStorage156 {157 Q_OBJECT158 159 public:160 MultiplexSetting() : ComboBoxSetting(this), sourceid(0)161 { setLabel(tr("Transport")); }162 163 virtual void Load(void);164 165 void SetSourceID(uint _sourceid);166 167 protected:168 uint sourceid;169 };170 171 class IgnoreSignalTimeout : public CheckBoxSetting, public TransientStorage172 {173 public:174 IgnoreSignalTimeout() : CheckBoxSetting(this)175 {176 setLabel(QObject::tr("Ignore Signal Timeout"));177 setHelpText(178 QObject::tr("This option allows you to slow down the scan for "179 "broken drivers, such as the DVB drivers for the "180 "Leadtek LR6650 DVB card."));181 }182 };183 184 class InputSelector : public ComboBoxSetting, public TransientStorage185 {186 Q_OBJECT187 188 public:189 InputSelector(uint _default_cardid, const QString &_default_inputname);190 191 virtual void Load(void);192 193 uint GetCardID(void) const;194 195 QString GetInputName(void) const;196 197 static bool Parse(const QString &cardid_inputname,198 uint &cardid,199 QString &inputname);200 201 public slots:202 void SetSourceID(const QString &_sourceid);203 204 private:205 uint sourceid;206 uint default_cardid;207 QString default_inputname;208 };209 210 class ScanCountry : public ComboBoxSetting, public TransientStorage211 {212 Q_OBJECT213 214 public:215 enum Country216 {217 AU,218 FI,219 SE,220 UK,221 DE,222 ES,223 NZ,224 FR,225 };226 227 ScanCountry();228 };229 230 class ScanTypeSetting : public ComboBoxSetting, public TransientStorage231 {232 Q_OBJECT233 public:234 enum Type235 {236 Error_Open = 0,237 Error_Probe,238 // Scans that check each frequency in a predefined list239 FullScan_Analog,240 FullScan_ATSC,241 FullScan_OFDM,242 // Scans starting on one frequency that adds each transport243 // seen in the Network Information Tables to the scan.244 NITAddScan_OFDM,245 NITAddScan_QPSK,246 NITAddScan_QAM,247 // Scan of all transports already in the database248 FullTransportScan,249 // Scan of one transport already in the database250 TransportScan,251 // IPTV import of channels from M3U URL252 IPTVImport,253 // Imports lists from dvb-utils scanners254 DVBUtilsImport,255 };256 257 ScanTypeSetting() : ComboBoxSetting(this), hw_cardid(0)258 { setLabel(QObject::tr("Scan Type")); }259 260 protected slots:261 void SetInput(const QString &cardids_inputname);262 263 protected:264 uint hw_cardid;265 };266 267 class ScanOptionalConfig : public TriggeredConfigurationGroup268 {269 Q_OBJECT270 271 public:272 ScanOptionalConfig(ScanTypeSetting *_scan_type);273 274 QString GetATSCFormat(const QString&) const;275 QString GetFrequencyStandard(void) const;276 QString GetModulation(void) const;277 QString GetFrequencyTable(void) const;278 bool DoIgnoreSignalTimeout(void) const;279 QString GetFilename(void) const;280 uint GetMultiplex(void) const;281 bool DoDeleteChannels(void) const;282 bool DoRenameChannels(void) const;283 QMap<QString,QString> GetStartChan(void) const;284 285 void SetDefaultATSCFormat(const QString &atscFormat);286 287 public slots:288 void SetSourceID(const QString&);289 void triggerChanged(const QString&);290 291 private:292 ScanTypeSetting *scanType;293 ScanCountry *country;294 IgnoreSignalTimeout *ignoreSignalTimeoutAll;295 OFDMPane *paneOFDM;296 QPSKPane *paneQPSK;297 DVBS2Pane *paneDVBS2;298 ATSCPane *paneATSC;299 QAMPane *paneQAM;300 AnalogPane *paneAnalog;301 STPane *paneSingle;302 DVBUtilsImportPane *paneDVBUtilsImport;303 };304 305 class ScanWizardConfig: public VerticalConfigurationGroup306 {307 Q_OBJECT308 309 public:310 ScanWizardConfig(ScanWizard *_parent,311 uint default_sourceid,312 uint default_cardid,313 QString default_inputname);314 315 uint GetSourceID(void) const;316 QString GetATSCFormat(void) const;317 QString GetModulation(void) const { return scanConfig->GetModulation(); }318 int GetScanType(void) const { return scanType->getValue().toInt();}319 uint GetCardID(void) const { return input->GetCardID(); }320 QString GetInputName(void) const { return input->GetInputName(); }321 QString GetFilename(void) const { return scanConfig->GetFilename(); }322 uint GetMultiplex(void) const { return scanConfig->GetMultiplex(); }323 bool DoDeleteChannels(void) const { return scanConfig->DoDeleteChannels();}324 bool DoRenameChannels(void) const { return scanConfig->DoRenameChannels();}325 QString GetFrequencyStandard(void) const326 { return scanConfig->GetFrequencyStandard(); }327 QString GetFrequencyTable(void) const328 { return scanConfig->GetFrequencyTable(); }329 QMap<QString,QString> GetStartChan(void) const330 { return scanConfig->GetStartChan(); }331 bool DoIgnoreSignalTimeout(void) const332 { return scanConfig->DoIgnoreSignalTimeout(); }333 334 void SetDefaultATSCFormat(const QString &atscFormat)335 { scanConfig->SetDefaultATSCFormat(atscFormat); }336 337 protected:338 VideoSourceSelector *videoSource;339 InputSelector *input;340 ScanTypeSetting *scanType;341 ScanOptionalConfig *scanConfig;342 };343 344 class LogList: public ListBoxSetting, public TransientStorage345 {346 public:347 LogList();348 349 void updateText(const QString& status);350 protected:351 int n;352 };353 354 class ScanFrequencyTable: public ComboBoxSetting, public TransientStorage355 {356 public:357 ScanFrequencyTable() : ComboBoxSetting(this)358 {359 addSelection(QObject::tr("Broadcast"), "us", true);360 addSelection(QObject::tr("Cable") + " " +361 QObject::tr("High"), "uscablehigh", false);362 addSelection(QObject::tr("Cable HRC") + " " +363 QObject::tr("High"), "ushrchigh", false);364 addSelection(QObject::tr("Cable IRC") + " " +365 QObject::tr("High"), "usirchigh", false);366 addSelection(QObject::tr("Cable"), "uscable", false);367 addSelection(QObject::tr("Cable HRC"), "ushrc", false);368 addSelection(QObject::tr("Cable IRC"), "usirc", false);369 370 setLabel(QObject::tr("Frequency Table"));371 setHelpText(QObject::tr("Frequency table to use.") + " " +372 QObject::tr(373 "The option of scanning only \"High\" "374 "frequency channels is useful because most "375 "digital channels are on the higher frequencies."));376 }377 };378 379 class ScanATSCModulation: public ComboBoxSetting, public TransientStorage380 {381 public:382 ScanATSCModulation() : ComboBoxSetting(this)383 {384 addSelection(QObject::tr("Terrestrial")+" (8-VSB)","vsb8", true);385 addSelection(QObject::tr("Cable") + " (QAM-256)", "qam256", false);386 addSelection(QObject::tr("Cable") + " (QAM-128)", "qam128", false);387 addSelection(QObject::tr("Cable") + " (QAM-64)", "qam64", false);388 389 setLabel(QObject::tr("Modulation"));390 setHelpText(391 QObject::tr("Modulation, 8-VSB, QAM-256, etc.") + " " +392 QObject::tr("Most cable systems in the United States use "393 "QAM-256 or QAM-64, but some mixed systems "394 "may use 8-VSB for over-the-air channels."));395 }396 };397 398 class ScanATSCChannelFormat: public ComboBoxSetting, public TransientStorage399 {400 public:401 ScanATSCChannelFormat() : ComboBoxSetting(this)402 {403 addSelection(QObject::tr("(5_1) Underscore"), "%1_%2", true);404 addSelection(QObject::tr("(5-1) Minus"), "%1-%2", false);405 addSelection(QObject::tr("(5.1) Period"), "%1.%2", false);406 addSelection(QObject::tr("(501) Zero"), "%10%2", false);407 addSelection(QObject::tr("(51) None"), "%1%2", false);408 setLabel(QObject::tr("ATSC Channel Separator"));409 setHelpText(QObject::tr("What to use to separate ATSC major "410 "and minor channels."));411 }412 };413 414 class ScanOldChannelTreatment: public ComboBoxSetting, public TransientStorage415 {416 public:417 ScanOldChannelTreatment(bool rename = true) : ComboBoxSetting(this)418 {419 addSelection(QObject::tr("Minimal Updates"), "minimal");420 if (rename)421 addSelection(QObject::tr("Rename to Match"), "rename");422 addSelection(QObject::tr("Delete"), "delete");423 setLabel(QObject::tr("Existing Channel Treatment"));424 setHelpText(QObject::tr("How to treat existing channels."));425 }426 };427 428 class ScanFrequency: public LineEditSetting, public TransientStorage429 {430 public:431 ScanFrequency(bool in_kHz = false) : LineEditSetting(this)432 {433 QString units = (in_kHz) ? "kHz" : "Hz";434 setLabel(QObject::tr("Frequency (%1)").arg(units));435 setHelpText(436 QObject::tr(437 "Frequency (Option has no default).\n"438 "The frequency for this channel in %1.").arg(units));439 };440 };441 442 class ScanSymbolRate: public ComboBoxSetting, public TransientStorage443 {444 public:445 ScanSymbolRate() : ComboBoxSetting(this, true)446 {447 setLabel(QObject::tr("Symbol Rate"));448 setHelpText(449 QObject::tr(450 "Symbol Rate (symbols/second).\n"451 "Most dvb-s transponders transmit at 27.5 "452 "million symbols per second."));453 addSelection("3333000");454 addSelection("22000000");455 addSelection("27500000", "27500000", true);456 addSelection("28000000");457 addSelection("28500000");458 addSelection("29900000");459 };460 };461 462 class ScanPolarity: public ComboBoxSetting, public TransientStorage463 {464 public:465 ScanPolarity() : ComboBoxSetting(this)466 {467 setLabel(QObject::tr("Polarity"));468 setHelpText(QObject::tr("Polarity (Option has no default)"));469 addSelection(QObject::tr("Horizontal"), "h",true);470 addSelection(QObject::tr("Vertical"), "v");471 addSelection(QObject::tr("Right Circular"), "r");472 addSelection(QObject::tr("Left Circular"), "l");473 };474 };475 476 class ScanInversion: public ComboBoxSetting, public TransientStorage477 {478 public:479 ScanInversion() : ComboBoxSetting(this)480 {481 setLabel(QObject::tr("Inversion"));482 setHelpText(QObject::tr(483 "Inversion (Default: Auto):\n"484 "Most cards can autodetect this now, so "485 "leave it at Auto unless it won't work."));486 addSelection(QObject::tr("Auto"), "a",true);487 addSelection(QObject::tr("On"), "1");488 addSelection(QObject::tr("Off"), "0");489 };490 };491 492 class ScanBandwidth: public ComboBoxSetting, public TransientStorage493 {494 public:495 ScanBandwidth() : ComboBoxSetting(this)496 {497 setLabel(QObject::tr("Bandwidth"));498 setHelpText(QObject::tr("Bandwidth (Default: Auto)\n"));499 addSelection(QObject::tr("Auto"),"a",true);500 addSelection(QObject::tr("6 MHz"),"6");501 addSelection(QObject::tr("7 MHz"),"7");502 addSelection(QObject::tr("8 MHz"),"8");503 };504 };505 506 class ScanModulationSetting: public ComboBoxSetting507 {508 public:509 ScanModulationSetting(Storage *_storage) : ComboBoxSetting(_storage)510 {511 addSelection(QObject::tr("Auto"),"auto",true);512 addSelection("QPSK","qpsk");513 #ifdef FE_GET_EXTENDED_INFO514 addSelection("8PSK","8psk");515 #endif516 addSelection("QAM 16","qam_16");517 addSelection("QAM 32","qam_32");518 addSelection("QAM 64","qam_64");519 addSelection("QAM 128","qam_128");520 addSelection("QAM 256","qam_256");521 };522 };523 524 class ScanModulation: public ScanModulationSetting, public TransientStorage525 {526 public:527 ScanModulation() : ScanModulationSetting(this)528 {529 setLabel(QObject::tr("Modulation"));530 setHelpText(QObject::tr("Modulation (Default: Auto)"));531 };532 };533 534 class ScanConstellation: public ScanModulationSetting,535 public TransientStorage536 {537 public:538 ScanConstellation() : ScanModulationSetting(this)539 {540 setLabel(QObject::tr("Constellation"));541 setHelpText(QObject::tr("Constellation (Default: Auto)"));542 };543 };544 545 class ScanFecSetting: public ComboBoxSetting546 {547 public:548 ScanFecSetting(Storage *_storage) : ComboBoxSetting(_storage)549 {550 addSelection(QObject::tr("Auto"),"auto",true);551 addSelection(QObject::tr("None"),"none");552 addSelection("1/2");553 addSelection("2/3");554 addSelection("3/4");555 addSelection("4/5");556 addSelection("5/6");557 addSelection("6/7");558 addSelection("7/8");559 addSelection("8/9");560 }561 };562 563 class ScanFec: public ScanFecSetting, public TransientStorage564 {565 public:566 ScanFec() : ScanFecSetting(this)567 {568 setLabel(QObject::tr("FEC"));569 setHelpText(QObject::tr(570 "Forward Error Correction (Default: Auto)"));571 }572 };573 574 class ScanCodeRateLP: public ScanFecSetting, public TransientStorage575 {576 public:577 ScanCodeRateLP() : ScanFecSetting(this)578 {579 setLabel(QObject::tr("LP Coderate"));580 setHelpText(QObject::tr("Low Priority Code Rate (Default: Auto)"));581 }582 };583 584 class ScanCodeRateHP: public ScanFecSetting, public TransientStorage585 {586 public:587 ScanCodeRateHP() : ScanFecSetting(this)588 {589 setLabel(QObject::tr("HP Coderate"));590 setHelpText(QObject::tr("High Priority Code Rate (Default: Auto)"));591 };592 };593 594 class ScanGuardInterval: public ComboBoxSetting, public TransientStorage595 {596 public:597 ScanGuardInterval() : ComboBoxSetting(this)598 {599 setLabel(QObject::tr("Guard Interval"));600 setHelpText(QObject::tr("Guard Interval (Default: Auto)"));601 addSelection(QObject::tr("Auto"),"auto");602 addSelection("1/4");603 addSelection("1/8");604 addSelection("1/16");605 addSelection("1/32");606 };607 };608 609 class ScanTransmissionMode: public ComboBoxSetting, public TransientStorage610 {611 public:612 ScanTransmissionMode() : ComboBoxSetting(this)613 {614 setLabel(QObject::tr("Trans. Mode"));615 setHelpText(QObject::tr("Transmission Mode (Default: Auto)"));616 addSelection(QObject::tr("Auto"),"a");617 addSelection("2K","2");618 addSelection("8K","8");619 };620 };621 622 class ScanHierarchy: public ComboBoxSetting, public TransientStorage623 {624 public:625 ScanHierarchy() : ComboBoxSetting(this)626 {627 setLabel(QObject::tr("Hierarchy"));628 setHelpText(QObject::tr("Hierarchy (Default: Auto)"));629 addSelection(QObject::tr("Auto"),"a");630 addSelection(QObject::tr("None"), "n");631 addSelection("1");632 addSelection("2");633 addSelection("4");634 };635 };636 637 class OFDMPane : public HorizontalConfigurationGroup638 {639 public:640 OFDMPane() : HorizontalConfigurationGroup(false, false, true, true)641 {642 setUseFrame(false);643 VerticalConfigurationGroup *left =644 new VerticalConfigurationGroup(false,true,true,false);645 VerticalConfigurationGroup *right =646 new VerticalConfigurationGroup(false,true,true,false);647 left->addChild(pfrequency = new ScanFrequency());648 left->addChild(pbandwidth = new ScanBandwidth());649 left->addChild(pinversion = new ScanInversion());650 left->addChild(pconstellation = new ScanConstellation());651 right->addChild(pcoderate_lp = new ScanCodeRateLP());652 right->addChild(pcoderate_hp = new ScanCodeRateHP());653 right->addChild(ptrans_mode = new ScanTransmissionMode());654 right->addChild(pguard_interval = new ScanGuardInterval());655 right->addChild(phierarchy = new ScanHierarchy());656 addChild(left);657 addChild(right);658 }659 660 QString frequency(void) const { return pfrequency->getValue(); }661 QString bandwidth(void) const { return pbandwidth->getValue(); }662 QString inversion(void) const { return pinversion->getValue(); }663 QString constellation(void) const { return pconstellation->getValue(); }664 QString coderate_lp(void) const { return pcoderate_lp->getValue(); }665 QString coderate_hp(void) const { return pcoderate_hp->getValue(); }666 QString trans_mode(void) const { return ptrans_mode->getValue(); }667 QString guard_interval(void) const { return pguard_interval->getValue(); }668 QString hierarchy(void) const { return phierarchy->getValue(); }669 670 protected:671 ScanFrequency *pfrequency;672 ScanInversion *pinversion;673 ScanBandwidth *pbandwidth;674 ScanConstellation *pconstellation;675 ScanCodeRateLP *pcoderate_lp;676 ScanCodeRateHP *pcoderate_hp;677 ScanTransmissionMode *ptrans_mode;678 ScanGuardInterval *pguard_interval;679 ScanHierarchy *phierarchy;680 };681 682 class DVBS2Pane : public HorizontalConfigurationGroup683 {684 public:685 DVBS2Pane() : HorizontalConfigurationGroup(false,false,true,false)686 {687 setUseFrame(false);688 VerticalConfigurationGroup *left =689 new VerticalConfigurationGroup(false,true);690 VerticalConfigurationGroup *right =691 new VerticalConfigurationGroup(false,true);692 left->addChild( pfrequency = new ScanFrequency());693 left->addChild( ppolarity = new ScanPolarity());694 left->addChild( psymbolrate = new ScanSymbolRate());695 right->addChild(pfec = new ScanFec());696 right->addChild(pmodulation = new ScanModulation());697 right->addChild(pinversion = new ScanInversion());698 addChild(left);699 addChild(right);700 }701 702 QString frequency(void) const { return pfrequency->getValue(); }703 QString symbolrate(void) const { return psymbolrate->getValue(); }704 QString inversion(void) const { return pinversion->getValue(); }705 QString fec(void) const { return pfec->getValue(); }706 QString polarity(void) const { return ppolarity->getValue(); }707 QString modulation(void) const { return pmodulation->getValue(); }708 709 protected:710 ScanFrequency *pfrequency;711 ScanSymbolRate *psymbolrate;712 ScanInversion *pinversion;713 ScanFec *pfec;714 ScanPolarity *ppolarity;715 ScanModulation *pmodulation;716 };717 718 class QPSKPane : public HorizontalConfigurationGroup719 {720 public:721 QPSKPane() : HorizontalConfigurationGroup(false, false, true, false)722 {723 setUseFrame(false);724 VerticalConfigurationGroup *left =725 new VerticalConfigurationGroup(false,true);726 VerticalConfigurationGroup *right =727 new VerticalConfigurationGroup(false,true);728 left->addChild(pfrequency = new ScanFrequency(true));729 left->addChild(ppolarity = new ScanPolarity());730 left->addChild(psymbolrate = new ScanSymbolRate());731 right->addChild(pfec = new ScanFec());732 right->addChild(pinversion = new ScanInversion());733 addChild(left);734 addChild(right);735 }736 737 QString frequency(void) const { return pfrequency->getValue(); }738 QString symbolrate(void) const { return psymbolrate->getValue(); }739 QString inversion(void) const { return pinversion->getValue(); }740 QString fec(void) const { return pfec->getValue(); }741 QString polarity(void) const { return ppolarity->getValue(); }742 743 protected:744 ScanFrequency *pfrequency;745 ScanSymbolRate *psymbolrate;746 ScanInversion *pinversion;747 ScanFec *pfec;748 ScanPolarity *ppolarity;749 };750 751 class QAMPane : public HorizontalConfigurationGroup752 {753 public:754 QAMPane() : HorizontalConfigurationGroup(false, false, true, false)755 {756 setUseFrame(false);757 VerticalConfigurationGroup *left =758 new VerticalConfigurationGroup(false,true);759 VerticalConfigurationGroup *right =760 new VerticalConfigurationGroup(false,true);761 left->addChild(pfrequency = new ScanFrequency());762 left->addChild(psymbolrate = new ScanSymbolRate());763 left->addChild(pinversion = new ScanInversion());764 right->addChild(pmodulation = new ScanModulation());765 right->addChild(pfec = new ScanFec());766 addChild(left);767 addChild(right);768 }769 770 QString frequency(void) const { return pfrequency->getValue(); }771 QString symbolrate(void) const { return psymbolrate->getValue(); }772 QString inversion(void) const { return pinversion->getValue(); }773 QString fec(void) const { return pfec->getValue(); }774 QString modulation(void) const { return pmodulation->getValue(); }775 776 protected:777 ScanFrequency *pfrequency;778 ScanSymbolRate *psymbolrate;779 ScanInversion *pinversion;780 ScanModulation *pmodulation;781 ScanFec *pfec;782 };783 784 class ATSCPane : public VerticalConfigurationGroup785 {786 public:787 ATSCPane() : VerticalConfigurationGroup(false, false, true, false)788 {789 addChild(atsc_table = new ScanFrequencyTable());790 addChild(atsc_modulation = new ScanATSCModulation());791 addChild(atsc_format = new ScanATSCChannelFormat());792 addChild(old_channel_treatment = new ScanOldChannelTreatment());793 }794 795 QString atscFreqTable(void) const { return atsc_table->getValue(); }796 QString atscModulation(void) const { return atsc_modulation->getValue(); }797 QString GetATSCFormat(void) const { return atsc_format->getValue(); }798 bool DoDeleteChannels(void) const799 { return old_channel_treatment->getValue() == "delete"; }800 bool DoRenameChannels(void) const801 { return old_channel_treatment->getValue() == "rename"; }802 803 void SetDefaultATSCFormat(const QString &d)804 {805 int val = atsc_format->getValueIndex(d);806 atsc_format->setValue(val);807 }808 809 protected:810 ScanFrequencyTable *atsc_table;811 ScanATSCModulation *atsc_modulation;812 ScanATSCChannelFormat *atsc_format;813 ScanOldChannelTreatment *old_channel_treatment;814 };815 816 class AnalogPane : public VerticalConfigurationGroup817 {818 public:819 AnalogPane();820 821 void SetSourceID(uint sourceid);822 823 QString GetFrequencyTable(void) const;824 825 bool DoDeleteChannels(void) const826 { return old_channel_treatment->getValue() == "delete"; }827 bool DoRenameChannels(void) const828 { return old_channel_treatment->getValue() == "rename"; }829 830 protected:831 TransFreqTableSelector *freq_table;832 ScanOldChannelTreatment *old_channel_treatment;833 };834 835 class STPane : public VerticalConfigurationGroup836 {837 public:838 STPane() :839 VerticalConfigurationGroup(false, false, true, false),840 transport_setting(new MultiplexSetting()),841 atsc_format(new ScanATSCChannelFormat()),842 old_channel_treatment(new ScanOldChannelTreatment()),843 ignore_signal_timeout(new IgnoreSignalTimeout())844 {845 addChild(transport_setting);846 addChild(atsc_format);847 addChild(old_channel_treatment);848 addChild(ignore_signal_timeout);849 }850 851 QString GetATSCFormat(void) const { return atsc_format->getValue(); }852 bool DoDeleteChannels(void) const853 { return old_channel_treatment->getValue() == "delete"; }854 bool DoRenameChannels(void) const855 { return old_channel_treatment->getValue() == "rename"; }856 int GetMultiplex(void) const857 { return transport_setting->getValue().toInt(); }858 bool ignoreSignalTimeout(void) const859 { return ignore_signal_timeout->getValue().toInt(); }860 861 void SetDefaultATSCFormat(const QString &d)862 {863 int val = atsc_format->getValueIndex(d);864 atsc_format->setValue(val);865 }866 867 void SetSourceID(uint sourceid)868 { transport_setting->SetSourceID(sourceid); }869 870 protected:871 MultiplexSetting *transport_setting;872 ScanATSCChannelFormat *atsc_format;873 ScanOldChannelTreatment *old_channel_treatment;874 IgnoreSignalTimeout *ignore_signal_timeout;875 };876 877 class DVBUtilsImportPane : public VerticalConfigurationGroup878 {879 Q_OBJECT880 881 public:882 DVBUtilsImportPane() :883 VerticalConfigurationGroup(false,false,true,false),884 filename(new TransLineEditSetting()),885 atsc_format(new ScanATSCChannelFormat()),886 old_channel_treatment(new ScanOldChannelTreatment()),887 ignore_signal_timeout(new IgnoreSignalTimeout())888 {889 filename->setLabel(tr("File location"));890 filename->setHelpText(tr("Location of the channels.conf file."));891 addChild(filename);892 893 addChild(atsc_format);894 addChild(old_channel_treatment);895 addChild(ignore_signal_timeout);896 }897 898 QString GetFilename(void) const { return filename->getValue(); }899 QString GetATSCFormat(void) const { return atsc_format->getValue(); }900 901 bool DoDeleteChannels(void) const902 { return old_channel_treatment->getValue() == "delete"; }903 bool DoRenameChannels(void) const904 { return old_channel_treatment->getValue() == "rename"; }905 bool DoIgnoreSignalTimeout(void) const906 { return ignore_signal_timeout->getValue().toInt(); }907 908 void SetDefaultATSCFormat(const QString &d)909 {910 int val = atsc_format->getValueIndex(d);911 atsc_format->setValue(val);912 }913 914 private:915 TransLineEditSetting *filename;916 ScanATSCChannelFormat *atsc_format;917 ScanOldChannelTreatment *old_channel_treatment;918 IgnoreSignalTimeout *ignore_signal_timeout;919 };920 921 class ErrorPane : public HorizontalConfigurationGroup922 {923 public:924 ErrorPane(const QString &error) :925 HorizontalConfigurationGroup(false, false, true, false)926 {927 TransLabelSetting* label = new TransLabelSetting();928 label->setValue(error);929 addChild(label);930 }931 };932 933 class BlankSetting: public TransLabelSetting934 {935 public:936 BlankSetting() : TransLabelSetting()937 {938 setLabel("");939 }940 };941 942 #endif // SCANWIZARDHELPERS_H -
libs/libmythtv/scanwizardscanner.cpp
1 /* -*- Mode: c++ -*-2 * vim: set expandtab tabstop=4 shiftwidth=4:3 *4 * Original Project5 * MythTV http://www.mythtv.org6 *7 * Copyright (c) 2004, 2005 John Pullan <john@pullan.org>8 * Copyright (c) 2005 - 2007 Daniel Kristjansson9 *10 * Description:11 * Collection of classes to provide channel scanning functionallity12 *13 * This program is free software; you can redistribute it and/or14 * modify it under the terms of the GNU General Public License15 * as published by the Free Software Foundation; either version 216 * of the License, or (at your option) any later version.17 *18 * This program is distributed in the hope that it will be useful,19 * but WITHOUT ANY WARRANTY; without even the implied warranty of20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the21 * GNU General Public License for more details.22 *23 * You should have received a copy of the GNU General Public License24 * along with this program; if not, write to the Free Software25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html27 *28 */29 30 // System headers31 #include <unistd.h>32 33 // Qt headers34 #include <QApplication>35 #include <QEvent>36 37 // MythTV headers38 #include "mythcontext.h"39 #include "mythverbose.h"40 #include "scanwizard.h"41 #include "scanwizardhelpers.h"42 #include "scanwizardscanner.h"43 #include "channelbase.h"44 #include "dtvsignalmonitor.h"45 #include "siscan.h"46 #include "dtvconfparser.h"47 48 #ifdef USING_V4L49 #include "v4lchannel.h"50 #include "analogsignalmonitor.h"51 #endif52 53 #ifdef USING_DVB54 #include "dvbchannel.h"55 #include "dvbsignalmonitor.h"56 #endif57 58 #ifdef USING_HDHOMERUN59 #include "hdhrchannel.h"60 #include "hdhrsignalmonitor.h"61 #endif62 63 #ifdef USING_IPTV64 #include "iptvchannelfetcher.h"65 #endif66 67 #define LOC QString("SWizScan: ")68 #define LOC_ERR QString("SWizScan, Error: ")69 70 /// Percentage to set to after the transports have been scanned71 #define TRANSPORT_PCT 672 /// Percentage to set to after the first tune73 #define TUNED_PCT 374 75 QString ScanWizardScanner::kTitle = QString::null;76 77 // kTitel must be initialized after the Qt translation system is initialized...78 static void init_statics(void)79 {80 static QMutex lock;81 static bool do_init = true;82 QMutexLocker locker(&lock);83 if (do_init)84 {85 ScanWizardScanner::kTitle = ScanWizardScanner::tr("Scanning");86 do_init = false;87 }88 }89 90 ScanWizardScanner::ScanWizardScanner(void)91 : VerticalConfigurationGroup(false, true, false, false),92 log(new LogList()), channel(NULL), popupProgress(NULL),93 scanner(NULL), freeboxScanner(NULL), nVideoSource(0)94 {95 init_statics();96 97 setLabel(kTitle);98 addChild(log);99 }100 101 ScanWizardScanner::~ScanWizardScanner()102 {103 Teardown();104 105 QMutexLocker locker(&popupLock);106 StopPopup();107 }108 109 void ScanWizardScanner::Teardown()110 {111 // Join the thread and close the channel112 if (scanner)113 {114 scanner->deleteLater();115 scanner = NULL;116 }117 118 if (channel)119 {120 delete channel;121 channel = NULL;122 }123 124 #ifdef USING_IPTV125 if (freeboxScanner)126 {127 freeboxScanner->Stop();128 freeboxScanner->deleteLater();129 freeboxScanner = NULL;130 }131 #endif132 }133 134 void ScanWizardScanner::customEvent(QEvent *e)135 {136 ScannerEvent *scanEvent = (ScannerEvent*) e;137 138 switch (scanEvent->eventType())139 {140 case ScannerEvent::ScanComplete:141 {142 QMutexLocker locker(&popupLock);143 if (popupProgress)144 {145 popupProgress->SetScanProgress(1.0);146 popupProgress->accept();147 }148 }149 break;150 151 case ScannerEvent::ScanShutdown:152 {153 if (scanEvent->ScanProgressPopupValue())154 {155 ScanProgressPopup *spp = scanEvent->ScanProgressPopupValue();156 spp->DeleteDialog();157 spp->deleteLater();158 }159 160 Teardown();161 }162 break;163 164 case ScannerEvent::AppendTextToLog:165 {166 log->updateText(scanEvent->strValue());167 }168 break;169 170 default:171 break;172 }173 174 QMutexLocker locker(&popupLock);175 if (!popupProgress)176 return;177 178 switch (scanEvent->eventType())179 {180 case ScannerEvent::SetStatusText:181 popupProgress->SetStatusText(scanEvent->strValue());182 break;183 case ScannerEvent::SetStatusTitleText:184 popupProgress->SetStatusTitleText(scanEvent->strValue());185 break;186 case ScannerEvent::SetPercentComplete:187 popupProgress->SetScanProgress(scanEvent->intValue() * 0.01);188 break;189 case ScannerEvent::SetStatusSignalLock:190 popupProgress->SetStatusLock(scanEvent->intValue());191 break;192 case ScannerEvent::SetStatusSignalToNoise:193 popupProgress->SetStatusSignalToNoise(scanEvent->intValue());194 break;195 case ScannerEvent::SetStatusSignalStrength:196 popupProgress->SetStatusSignalStrength(scanEvent->intValue());197 break;198 default:199 break;200 }201 }202 203 void ScanWizardScanner::scanComplete()204 {205 ScannerEvent::TYPE se = ScannerEvent::ScanComplete;206 QApplication::postEvent(this, new ScannerEvent(se));207 }208 209 void ScanWizardScanner::transportScanComplete()210 {211 scanner->ScanServicesSourceID(nVideoSource);212 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);213 e->intValue(TRANSPORT_PCT);214 QApplication::postEvent(this, e);215 }216 217 void ScanWizardScanner::serviceScanPctComplete(int pct)218 {219 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetPercentComplete);220 int tmp = TRANSPORT_PCT + ((100 - TRANSPORT_PCT) * pct)/100;221 e->intValue(tmp);222 QApplication::postEvent(this, e);223 }224 225 void ScanWizardScanner::updateText(const QString &str)226 {227 if (str.isEmpty())228 return;229 ScannerEvent* e = new ScannerEvent(ScannerEvent::AppendTextToLog);230 e->strValue(str);231 QApplication::postEvent(this, e);232 }233 234 void ScanWizardScanner::updateStatusText(const QString &str)235 {236 QString msg = tr("Scanning");237 if (!str.isEmpty())238 msg = QString("%1 %2").arg(msg).arg(str);239 240 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusText);241 e->strValue(msg);242 QApplication::postEvent(this, e);243 }244 245 void ScanWizardScanner::StatusSignalLock(const SignalMonitorValue &val)246 {247 dvbLock(val.GetValue());248 }249 250 void ScanWizardScanner::StatusSignalToNoise(const SignalMonitorValue &val)251 {252 dvbSNR(val.GetNormalizedValue(0, 65535));253 }254 255 void ScanWizardScanner::StatusSignalStrength(const SignalMonitorValue &val)256 {257 dvbSignalStrength(val.GetNormalizedValue(0, 65535));258 }259 260 void ScanWizardScanner::dvbLock(int locked)261 {262 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalLock);263 e->intValue(locked);264 QApplication::postEvent(this, e);265 }266 267 void ScanWizardScanner::dvbSNR(int i)268 {269 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalToNoise);270 e->intValue(i);271 QApplication::postEvent(this, e);272 }273 274 void ScanWizardScanner::dvbSignalStrength(int i)275 {276 ScannerEvent* e = new ScannerEvent(ScannerEvent::SetStatusSignalStrength);277 e->intValue(i);278 QApplication::postEvent(this, e);279 }280 281 // full scan of existing transports broken282 // existing transport scan broken283 void ScanWizardScanner::Scan(284 int scantype,285 uint cardid,286 const QString &inputname,287 uint sourceid,288 bool do_delete_channels,289 bool do_rename_channels,290 bool do_ignore_signal_timeout,291 // stuff needed for particular scans292 uint mplexid /* TransportScan */,293 const QMap<QString,QString> &startChan /* NITAddScan */,294 const QString &freq_std /* FullScan */,295 const QString &mod /* FullScan */,296 const QString &tbl /* FullScan */,297 const QString &atsc_format /* any ATSC scan */)298 {299 nVideoSource = sourceid;300 PreScanCommon(scantype, cardid, inputname,301 sourceid, do_ignore_signal_timeout);302 303 VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete()");304 305 if (!scanner)306 {307 VERBOSE(VB_SIPARSER, LOC + "HandleTuneComplete(): "308 "scanner does not exist...");309 return;310 }311 312 scanner->StartScanner();313 updateStatusText("");314 315 bool ok = false;316 317 if (do_delete_channels && (ScanTypeSetting::TransportScan == scantype))318 {319 MSqlQuery query(MSqlQuery::InitCon());320 query.prepare("DELETE FROM channel "321 "WHERE sourceid = :SOURCEID AND "322 " mplexid = :MPLEXID");323 query.bindValue(":SOURCEID", sourceid);324 query.bindValue(":MPLEXID", mplexid);325 query.exec();326 }327 else if (do_delete_channels)328 {329 MSqlQuery query(MSqlQuery::InitCon());330 query.prepare("DELETE FROM channel "331 "WHERE sourceid = :SOURCEID");332 query.bindValue(":SOURCEID", sourceid);333 query.exec();334 335 if (ScanTypeSetting::TransportScan != scantype)336 {337 query.prepare("DELETE FROM dtv_multiplex "338 "WHERE sourceid = :SOURCEID");339 query.bindValue(":SOURCEID", sourceid);340 query.exec();341 }342 }343 344 scanner->SetChannelFormat(atsc_format);345 scanner->SetRenameChannels(do_rename_channels);346 347 if ((ScanTypeSetting::FullScan_ATSC == scantype) ||348 (ScanTypeSetting::FullScan_OFDM == scantype) ||349 (ScanTypeSetting::FullScan_Analog == scantype))350 {351 VERBOSE(VB_SIPARSER, LOC +352 "ScanTransports("<<freq_std<<", "<<mod<<", "<<tbl<<")");353 354 // HACK HACK HACK -- begin355 // if using QAM we may need additional time... (at least with HD-3000)356 if ((mod.left(3).toLower() == "qam") &&357 (scanner->GetSignalTimeout() < 1000))358 {359 scanner->SetSignalTimeout(1000);360 }361 // HACK HACK HACK -- end362 363 scanner->SetAnalog(ScanTypeSetting::FullScan_Analog == scantype);364 365 ok = scanner->ScanTransports(sourceid, freq_std, mod, tbl);366 }367 else if ((ScanTypeSetting::NITAddScan_OFDM == scantype) ||368 (ScanTypeSetting::NITAddScan_QPSK == scantype) ||369 (ScanTypeSetting::NITAddScan_QAM == scantype))370 {371 VERBOSE(VB_SIPARSER, LOC + "ScanTransports()");372 373 ok = scanner->ScanTransportsStartingOn(sourceid, startChan);374 }375 else if (ScanTypeSetting::FullTransportScan == scantype)376 {377 VERBOSE(VB_SIPARSER, LOC + "ScanServicesSourceID("<<sourceid<<")");378 379 ok = scanner->ScanServicesSourceID(sourceid);380 if (ok)381 {382 serviceScanPctComplete(0);383 }384 else385 {386 MythPopupBox::showOkPopup(gContext->GetMainWindow(),387 tr("ScanWizard"),388 tr("Error tuning to transport"));389 Teardown();390 }391 }392 else if ((ScanTypeSetting::DVBUtilsImport == scantype) && channels.size())393 {394 ok = true;395 396 VERBOSE(VB_SIPARSER, LOC + "ScanForChannels("<<sourceid<<")");397 398 QString card_type = CardUtil::GetRawCardType(cardid);399 QString sub_type = card_type;400 if (card_type == "DVB")401 {402 QString device = CardUtil::GetVideoDevice(cardid);403 404 ok = !device.isEmpty();405 if (ok)406 sub_type = CardUtil::ProbeDVBType(device).toUpper();407 }408 409 if (ok)410 {411 ok = scanner->ScanForChannels(sourceid, freq_std,412 sub_type, channels);413 }414 if (ok)415 {416 serviceScanPctComplete(0);417 }418 else419 {420 MythPopupBox::showOkPopup(gContext->GetMainWindow(),421 tr("ScanWizard"),422 tr("Error tuning to transport"));423 Teardown();424 }425 }426 else if (ScanTypeSetting::TransportScan == scantype)427 {428 VERBOSE(VB_SIPARSER, LOC + "ScanTransport("<<mplexid<<")");429 430 ok = scanner->ScanTransport(mplexid);431 }432 433 if (!ok)434 {435 VERBOSE(VB_IMPORTANT, "Failed to handle tune complete.");436 }437 }438 439 void ScanWizardScanner::ImportDVBUtils(uint sourceid, int cardtype,440 const QString &file)441 {442 channels.clear();443 444 DTVConfParser::cardtype_t type = DTVConfParser::UNKNOWN;445 type = (CardUtil::OFDM == cardtype) ? DTVConfParser::OFDM : type;446 type = (CardUtil::QPSK == cardtype) ? DTVConfParser::QPSK : type;447 type = (CardUtil::QAM == cardtype) ? DTVConfParser::QAM : type;448 type = ((CardUtil::ATSC == cardtype)||(CardUtil::HDHOMERUN == cardtype)) ?449 DTVConfParser::ATSC : type;450 451 if (type == DTVConfParser::UNKNOWN)452 return;453 454 DTVConfParser parser(type, sourceid, file);455 456 DTVConfParser::return_t ret = parser.Parse();457 if (DTVConfParser::OK != ret)458 {459 QString msg = (DTVConfParser::ERROR_PARSE == ret) ?460 tr("Failed to parse '%1'") : tr("Failed to open '%1'");461 462 MythPopupBox::showOkPopup(gContext->GetMainWindow(),463 tr("ScanWizard"), msg.arg(file));464 }465 else466 {467 channels = parser.GetChannels();468 }469 }470 471 void ScanWizardScanner::PreScanCommon(int scantype,472 uint cardid,473 const QString &inputname,474 uint sourceid,475 bool do_ignore_signal_timeout)476 {477 uint signal_timeout = 1000;478 uint channel_timeout = 40000;479 CardUtil::GetTimeouts(cardid, signal_timeout, channel_timeout);480 481 QString device = CardUtil::GetVideoDevice(cardid);482 if (device.isEmpty())483 {484 VERBOSE(VB_IMPORTANT, "No Device");485 return;486 }487 488 QString card_type = CardUtil::GetRawCardType(cardid);489 490 if ("DVB" == card_type)491 {492 QString sub_type = CardUtil::ProbeDVBType(device).toUpper();493 bool need_nit = (("QAM" == sub_type) ||494 ("QPSK" == sub_type) ||495 ("OFDM" == sub_type));496 497 // Ugh, Some DVB drivers don't fully support signal monitoring...498 if ((ScanTypeSetting::TransportScan == scantype) ||499 (ScanTypeSetting::FullTransportScan == scantype))500 {501 signal_timeout = (do_ignore_signal_timeout) ?502 channel_timeout * 10 : signal_timeout;503 }504 505 // Since we the NIT is only sent every 10 seconds, we add an506 // extra 20 + 2 seconds to the scan time for DVB countries.507 channel_timeout += (need_nit) ? 22 * 1000 : 0;508 }509 510 #ifdef USING_DVB511 if ("DVB" == card_type)512 channel = new DVBChannel(device);513 #endif514 515 #ifdef USING_V4L516 if (("V4L" == card_type) || ("MPEG" == card_type) ||517 ("HDPVR" == card_type))518 {519 channel = new V4LChannel(NULL, device);520 }521 #endif522 523 #ifdef USING_HDHOMERUN524 if ("HDHOMERUN" == card_type)525 {526 uint tuner = CardUtil::GetHDHRTuner(cardid);527 channel = new HDHRChannel(NULL, device, tuner);528 }529 #endif // USING_HDHOMERUN530 531 if (!channel)532 {533 VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel not created");534 return;535 }536 537 // explicitly set the cardid538 channel->SetCardID(cardid);539 540 // If the backend is running this may fail...541 if (!channel->Open())542 {543 VERBOSE(VB_IMPORTANT, LOC_ERR + "Channel could not be opened");544 return;545 }546 547 scanner = new SIScan(card_type, channel, sourceid, signal_timeout,548 channel_timeout, inputname);549 550 scanner->SetForceUpdate(true);551 552 bool ftao = CardUtil::IgnoreEncrypted(cardid, inputname);553 scanner->SetFTAOnly(ftao);554 555 bool tvo = CardUtil::TVOnly(cardid, inputname);556 scanner->SetTVOnly(tvo);557 558 connect(scanner, SIGNAL(ServiceScanComplete(void)),559 this, SLOT( scanComplete(void)));560 connect(scanner, SIGNAL(TransportScanComplete(void)),561 this, SLOT( transportScanComplete(void)));562 connect(scanner, SIGNAL(ServiceScanUpdateStatusText(const QString&)),563 this, SLOT( updateStatusText(const QString&)));564 connect(scanner, SIGNAL(ServiceScanUpdateText(const QString&)),565 this, SLOT( updateText(const QString&)));566 connect(scanner, SIGNAL(TransportScanUpdateText(const QString&)),567 this, SLOT( updateText(const QString&)));568 connect(scanner, SIGNAL(PctServiceScanComplete(int)),569 this, SLOT( serviceScanPctComplete(int)));570 571 // Signal Meters are connected here572 SignalMonitor *monitor = scanner->GetSignalMonitor();573 if (monitor)574 monitor->AddListener(this);575 576 DVBSignalMonitor *dvbm = NULL;577 #ifdef USING_DVB578 dvbm = scanner->GetDVBSignalMonitor();579 #endif // USING_DVB580 581 MonitorProgress(monitor, monitor, dvbm);582 }583 584 void ScanWizardScanner::ImportM3U(uint cardid, const QString &inputname,585 uint sourceid)586 {587 (void) cardid;588 (void) inputname;589 (void) sourceid;590 591 #ifdef USING_IPTV592 //Create an analog scan object593 freeboxScanner = new IPTVChannelFetcher(cardid, inputname, sourceid);594 595 connect(freeboxScanner, SIGNAL(ServiceScanComplete(void)),596 this, SLOT( scanComplete(void)));597 connect(freeboxScanner, SIGNAL(ServiceScanUpdateText(const QString&)),598 this, SLOT( updateText(const QString&)));599 connect(freeboxScanner, SIGNAL(ServiceScanPercentComplete(int)),600 this, SLOT( serviceScanPctComplete(int)));601 602 MonitorProgress(false, false, false);603 604 if (!freeboxScanner->Scan())605 {606 MythPopupBox::showOkPopup(gContext->GetMainWindow(),607 tr("ScanWizard"),608 tr("Error starting scan"));609 }610 #endif // USING_IPTV611 }612 613 void *spawn_popup(void *tmp)614 {615 ((ScanWizardScanner*)(tmp))->RunPopup();616 return NULL;617 }618 619 void ScanWizardScanner::RunPopup(void)620 {621 DialogCode ret = popupProgress->exec();622 623 post_event(this, ScannerEvent::ScanShutdown, ret, popupProgress);624 popupProgress = NULL;625 }626 627 void ScanWizardScanner::StopPopup(void)628 {629 if (popupProgress)630 {631 popupProgress->reject();632 popupLock.unlock();633 pthread_join(popup_thread, NULL);634 popupLock.lock();635 }636 }637 638 void ScanWizardScanner::MonitorProgress(bool lock, bool strength, bool snr)639 {640 QMutexLocker locker(&popupLock);641 StopPopup();642 popupProgress = new ScanProgressPopup(lock, strength, snr);643 popupProgress->CreateDialog();644 if (pthread_create(&popup_thread, NULL, spawn_popup, this) != 0)645 {646 VERBOSE(VB_IMPORTANT, "Failed to start MonitorProgress thread");647 popupProgress->DeleteDialog();648 popupProgress->deleteLater();649 popupProgress = NULL;650 }651 } -
libs/libmythtv/siscan.cpp
1 // -*- Mode: c++ -*-2 3 // C includes4 #include <cstdio>5 #include <pthread.h>6 #include <unistd.h>7 8 // Qt includes9 #include <qmutex.h>10 11 // MythTV includes - General12 #include "siscan.h"13 #include "scheduledrecording.h"14 #include "frequencies.h"15 #include "mythdb.h"16 #include "channelutil.h"17 #include "cardutil.h"18 19 // MythTV includes - DTV20 #include "dtvsignalmonitor.h"21 #include "scanstreamdata.h"22 23 // MythTV includes - ATSC24 #include "atsctables.h"25 26 // MythTV includes - DVB27 #include "dvbsignalmonitor.h"28 #include "dvbtables.h"29 30 #include "dvbchannel.h"31 #include "hdhrchannel.h"32 #include "v4lchannel.h"33 #include "compat.h"34 35 QString SIScan::loc(const SIScan *siscan)36 {37 if (siscan && siscan->channel)38 return QString("SIScan(%1)").arg(siscan->channel->GetDevice());39 return "SIScan(u)";40 }41 42 #define LOC (SIScan::loc(this) + ": ")43 #define LOC_ERR (SIScan::loc(this) + ", Error: ")44 45 /** \class SIScan46 * \brief Scanning class for cards that support a SignalMonitor class.47 *48 * Currently both SIParser and ScanStreamData are being used in49 * this class. The SIParser is being phased out, so that is not50 * described here.51 *52 * With ScanStreamData, we call ScanTransport() on each transport53 * and frequency offset in the list of transports. This list is54 * created from a FrequencyTable object.55 *56 * Each ScanTransport() call resets the ScanStreamData and the57 * SignalMonitor, then tunes to a new frequency and notes the tuning58 * time in the "timer" QTime object.59 *60 * HandleActiveScan is called every time through the event loop61 * and is what calls ScanTransport(), as well as checking when62 * the current time is "timeoutTune" or "channelTimeout" milliseconds63 * ahead of "timer". When the "timeoutTune" is exceeded we check64 * to see if we have a signal lock on the channel, if we don't we65 * check the next transport. When the larger "channelTimeout" is66 * exceeded we do nothing unless "waitingForTables" is still true,67 * if so we check if we at least got a PAT and if so we insert68 * a channel based on that by calling HandleMPEGDBInsertion().69 *70 * Meanwhile the ScanStreamData() emits several signals. For71 * the UI it emits signal quality signals. For SIScan it emits72 * UpdateMGT, UpdateVCT, UpdateNIT, and UpdateSDT signals. We73 * connect these to the HandleMGT, HandleVCT, etc. These in74 * turn just call HandleATSCDBInsertion() or75 * HandleDVBDBInsertion() depending on the type of table.76 *77 * HandleATSCDBInsertion() first checks if we have all the VCTs78 * described in the MGT. If we do we call UpdateVCTinDB() for each79 * TVCT and CVCT in the stream. UpdateVCTinDB() inserts the actual80 * channels. Then we set "waitingForTables" to false, set the81 * scanOffsetIt to 99 and updates the UI to reflect the added channel.82 * HandleDVBDBInsertion() and HandleMPEGDBInsertion() are similar.83 */84 85 SIScan::SIScan(const QString &_cardtype, ChannelBase *_channel, int _sourceID,86 uint signal_timeout, uint channel_timeout,87 const QString &_inputname)88 : // Set in constructor89 channel(_channel),90 signalMonitor(SignalMonitor::Init(_cardtype, -1, _channel)),91 sourceID(_sourceID),92 scanMode(IDLE),93 signalTimeout(signal_timeout),94 channelTimeout(channel_timeout),95 inputname(_inputname),96 // Settable97 isAnalog(false),98 ignoreAudioOnlyServices(false),99 ignoreDataServices(false),100 ignoreEncryptedServices(false),101 forceUpdate(false),102 renameChannels(false),103 channelFormat("%1_%2"),104 // State105 threadExit(false),106 waitingForTables(false),107 // Transports List108 transportsScanned(0),109 // Misc110 scanner_thread_running(false)111 {112 inputname.detach();113 114 // Initialize statics115 current = transport_scan_items_it_t( scanTransports.end());116 117 signalMonitor->AddListener(this);118 119 // Create a stream data for digital signal monitors120 DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();121 if (dtvSigMon)122 {123 VERBOSE(VB_SIPARSER, LOC + "Connecting up DTVSignalMonitor");124 ScanStreamData *data = new ScanStreamData();125 126 dtvSigMon->SetStreamData(data);127 dtvSigMon->AddFlags(SignalMonitor::kDTVSigMon_WaitForMGT |128 SignalMonitor::kDTVSigMon_WaitForVCT |129 SignalMonitor::kDTVSigMon_WaitForNIT |130 SignalMonitor::kDTVSigMon_WaitForSDT);131 132 data->AddMPEGListener(this);133 data->AddATSCMainListener(this);134 data->AddDVBMainListener(this);135 }136 }137 138 SIScan::~SIScan(void)139 {140 // Use deleteLater() instead141 StopScanner();142 VERBOSE(VB_SIPARSER, LOC + "SIScanner dtor");143 }144 145 void SIScan::deleteLater(void)146 {147 disconnect();148 StopScanner();149 VERBOSE(VB_SIPARSER, LOC + "SIScanner Stopped");150 channel = 0; // Deleted by caller151 teardown_frequency_tables();152 QObject::deleteLater();153 }154 155 void SIScan::AllGood(void)156 {157 if (!isAnalog)158 return;159 160 QString cur_chan = (*current).FriendlyName;161 QStringList list = cur_chan.split(" ", QString::SkipEmptyParts);162 QString freqid = (list.size() >= 2) ? list[1] : cur_chan;163 164 bool ok = false;165 166 QString msg = tr("Updated Channel %1").arg(cur_chan);167 168 if (!ChannelUtil::FindChannel(sourceID, freqid))169 {170 int chanid = ChannelUtil::CreateChanID(sourceID, freqid);171 172 QString callsign = QString("%1%2")173 .arg(ChannelUtil::GetUnknownCallsign()).arg(freqid);174 175 ok = ChannelUtil::CreateChannel(176 0 /* mplexid */,177 sourceID,178 chanid,179 callsign,180 "" /* service name */,181 freqid /* channum */,182 0 /* service id */,183 0 /* ATSC major channel */,184 0 /* ATSC minor channel */,185 false /* use on air guide */,186 false /* hidden */,187 false /* hidden in guide */,188 freqid);189 190 msg = (ok) ?191 tr("Added Channel %1").arg(cur_chan) :192 tr("Failed to add channel %1").arg(cur_chan);193 }194 else195 {196 // nothing to do here, XMLTV & DataDirect have better info197 }198 199 emit ServiceScanUpdateText(msg);200 201 // tell UI we are done with these channels202 if (scanMode == TRANSPORT_LIST)203 {204 UpdateScanPercentCompleted();205 waitingForTables = false;206 nextIt = current.nextTransport();207 }208 }209 210 /** \fn SIScan::ScanServicesSourceID(int)211 * \brief If we are not already scanning a frequency table, this creates212 * a new frequency table from database and begins scanning it.213 *214 * This is used by DVB to scan for channels we are told about from other215 * channels.216 *217 * Note: Something similar could be used with ATSC when EIT for other218 * channels is available on another ATSC channel, as encouraged by the219 * ATSC specification.220 */221 bool SIScan::ScanServicesSourceID(int SourceID)222 {223 if (scanMode == TRANSPORT_LIST)224 return false;225 226 nextIt = transport_scan_items_it_t( scanTransports.end() );227 228 MSqlQuery query(MSqlQuery::InitCon());229 // Run DB query to get transports on sourceid SourceID230 // connected to this card231 QString theQuery = QString(232 "SELECT sourceid, mplexid, sistandard, transportid "233 "FROM dtv_multiplex WHERE sourceid = %1").arg(SourceID);234 query.prepare(theQuery);235 236 if (!query.exec() || !query.isActive())237 {238 MythDB::DBError("Get Transports for SourceID", query);239 return false;240 }241 242 if (query.size() <= 0)243 {244 VERBOSE(VB_SIPARSER, LOC + "Unable to find any transports for " +245 QString("sourceid %1").arg(sourceID));246 247 return false;248 }249 250 while (query.next())251 {252 int sourceid = query.value(0).toInt();253 int mplexid = query.value(1).toInt();254 QString std = query.value(2).toString();255 int tsid = query.value(3).toInt();256 257 QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :258 QString("Multiplex #%1").arg(mplexid);259 260 VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);261 262 TransportScanItem item(sourceid, std, fn, mplexid, signalTimeout);263 scanTransports += item;264 }265 266 waitingForTables = false;267 transportsScanned = 0;268 if (scanTransports.size())269 {270 nextIt = transport_scan_items_it_t(scanTransports.begin());271 scanMode = TRANSPORT_LIST;272 return true;273 }274 275 return false;276 }277 278 void SIScan::HandlePAT(const ProgramAssociationTable *pat)279 {280 VERBOSE(VB_SIPARSER, LOC +281 QString("Got a Program Association Table for %1")282 .arg((*current).FriendlyName));283 284 // Add pmts to list, so we can do MPEG scan properly.285 ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();286 for (uint i = 0; i < pat->ProgramCount(); i++)287 {288 if (pat->ProgramPID(i)) // don't add NIT "program", MPEG/ATSC safe.289 sd->AddListeningPID(pat->ProgramPID(i));290 }291 }292 293 void SIScan::HandleVCT(uint, const VirtualChannelTable*)294 {295 VERBOSE(VB_SIPARSER, LOC + QString("Got a Virtual Channel Table for %1")296 .arg((*current).FriendlyName));297 298 HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);299 }300 301 void SIScan::HandleMGT(const MasterGuideTable*)302 {303 VERBOSE(VB_SIPARSER, LOC + QString("Got the Master Guide for %1")304 .arg((*current).FriendlyName));305 306 HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);307 }308 309 void SIScan::HandleSDT(uint, const ServiceDescriptionTable* sdt)310 {311 VERBOSE(VB_SIPARSER, LOC +312 QString("Got a Service Description Table for %1")313 .arg((*current).FriendlyName));314 VERBOSE(VB_SIPARSER, LOC + sdt->toString());315 316 HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);317 }318 319 void SIScan::HandleNIT(const NetworkInformationTable *nit)320 {321 VERBOSE(VB_SIPARSER, LOC +322 QString("Got a Network Information Table for %1")323 .arg((*current).FriendlyName));324 VERBOSE(VB_SIPARSER, LOC + nit->toString());325 326 if (nit->TransportStreamCount())327 {328 emit TransportScanUpdateText(329 tr("Network %1 Processing").arg(nit->NetworkName()));330 331 vector<uint> mp;332 mp = ChannelUtil::CreateMultiplexes(sourceID, nit);333 VERBOSE(VB_SIPARSER, QString("Created %1 multiplexes from NIT")334 .arg(mp.size()));335 336 // Get channel numbers from UK Frequency List Descriptors337 for (uint i = 0; i < nit->TransportStreamCount(); i++)338 {339 const desc_list_t& list =340 MPEGDescriptor::Parse(nit->TransportDescriptors(i),341 nit->TransportDescriptorsLength(i));342 343 const unsigned char* desc =344 MPEGDescriptor::Find(list, DescriptorID::dvb_uk_channel_list);345 346 if (desc)347 {348 UKChannelListDescriptor uklist(desc);349 for (uint j = 0; j < uklist.ChannelCount(); j++)350 dvbChanNums[uklist.ServiceID(j)] = uklist.ChannelNumber(j);351 }352 }353 }354 355 const ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();356 const DVBStreamData &dsd = *sd;357 if (dsd.HasAllNITSections())358 {359 emit TransportScanUpdateText(tr("Finished processing Transport List"));360 emit TransportScanComplete();361 }362 363 HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);364 }365 366 void SIScan::HandleMPEGDBInsertion(const ScanStreamData *sd, bool)367 {368 // Try to determine if this might be "OpenCable" transport.369 QString sistandard = sd->GetSIStandard((*current).tuning.sistandard);370 371 if (!(*current).mplexid)372 (*current).mplexid = InsertMultiplex(current);373 374 if (!(*current).mplexid)375 return;376 377 int mplexid = (*current).mplexid;378 int freqid = (*current).friendlyNum;379 QString fn = (*current).FriendlyName;380 381 pat_vec_t pats = sd->GetCachedPATs();382 pmt_map_t pmt_map = sd->GetCachedPMTMap();383 for (uint i = 0; i < pats.size(); i++)384 {385 UpdatePATinDB(mplexid, fn, freqid, pats[i], pmt_map,386 (*current).expectedChannels, sistandard, true);387 }388 sd->ReturnCachedPMTTables(pmt_map);389 sd->ReturnCachedPATTables(pats);390 391 // tell UI we are done with these channels392 if (scanMode == TRANSPORT_LIST)393 {394 UpdateScanPercentCompleted();395 waitingForTables = false;396 nextIt = current.nextTransport();397 }398 }399 400 void SIScan::HandleATSCDBInsertion(const ScanStreamData *sd,401 bool wait_until_complete)402 {403 if (wait_until_complete && !sd->HasCachedAllVCTs())404 return;405 406 if (!(*current).mplexid)407 (*current).mplexid = InsertMultiplex(current);408 409 if (!(*current).mplexid)410 return;411 412 int mplexid = (*current).mplexid;413 int freqid = (*current).friendlyNum;414 QString fn = (*current).FriendlyName;415 416 // Insert Terrestrial VCTs417 tvct_vec_t tvcts = sd->GetCachedTVCTs();418 for (uint i = 0; i < tvcts.size(); i++)419 {420 UpdateVCTinDB(mplexid, fn, freqid, tvcts[i],421 (*current).expectedChannels, true);422 }423 sd->ReturnCachedTVCTTables(tvcts);424 425 // Insert Cable VCTs426 cvct_vec_t cvcts = sd->GetCachedCVCTs();427 for (uint i = 0; i < cvcts.size(); i++)428 {429 UpdateVCTinDB(mplexid, fn, freqid, cvcts[i],430 (*current).expectedChannels, true);431 }432 sd->ReturnCachedCVCTTables(cvcts);433 434 // tell UI we are done with these channels435 if (scanMode == TRANSPORT_LIST)436 {437 UpdateScanPercentCompleted();438 waitingForTables = false;439 nextIt = current.nextTransport();440 }441 }442 443 void SIScan::HandleDVBDBInsertion(const ScanStreamData *sd,444 bool wait_until_complete)445 {446 const DVBStreamData &dsd = (const DVBStreamData &)(*sd);447 if (wait_until_complete && !(dsd.HasCachedSDT() && dsd.HasCachedAllNIT()))448 return;449 450 emit ServiceScanUpdateText(tr("Updating Services"));451 452 if (!(*current).mplexid)453 (*current).mplexid = InsertMultiplex(current);454 455 vector<const ServiceDescriptionTable*> sdts = sd->GetCachedSDTs();456 for (uint i = 0; i < sdts.size(); i++)457 {458 UpdateSDTinDB((*current).mplexid, sdts[i],459 (*current).expectedChannels, forceUpdate);460 }461 sd->ReturnCachedSDTTables(sdts);462 463 emit ServiceScanUpdateText(tr("Finished processing Services"));464 465 if (scanMode == TRANSPORT_LIST)466 {467 UpdateScanPercentCompleted();468 waitingForTables = false;469 nextIt = current.nextTransport();470 }471 else472 {473 emit PctServiceScanComplete(100);474 emit ServiceScanComplete();475 }476 }477 478 /** \fn SIScan::HandlePostInsertion(void)479 * \brief Insert channels based on any partial tables we do have.480 * \return true if we saw any tables481 */482 bool SIScan::HandlePostInsertion(void)483 {484 DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();485 if (!dtvSigMon)486 return false;487 488 const ScanStreamData *sd = dtvSigMon->GetScanStreamData();489 490 VERBOSE(VB_SIPARSER, LOC + "HandlePostInsertion() " +491 QString("pat(%1)").arg(sd->HasCachedAnyPAT()));492 493 const MasterGuideTable *mgt = sd->GetCachedMGT();494 if (mgt)495 {496 VERBOSE(VB_IMPORTANT, mgt->toString());497 HandleATSCDBInsertion(sd, false);498 sd->ReturnCachedTable(mgt);499 return true;500 }501 502 const NetworkInformationTable *nit = sd->GetCachedNIT(0, true);503 sdt_vec_t sdts = sd->GetCachedSDTs();504 if (nit || sdts.size())505 {506 if (nit)507 VERBOSE(VB_IMPORTANT, nit->toString());508 HandleDVBDBInsertion(sd, false);509 sd->ReturnCachedSDTTables(sdts);510 sd->ReturnCachedTable(nit);511 return true;512 }513 514 if (sd->HasCachedAnyPAT())515 {516 VERBOSE(VB_IMPORTANT, LOC + "Post insertion found PAT..");517 HandleMPEGDBInsertion(sd, false);518 return true;519 }520 return false;521 }522 523 DTVSignalMonitor* SIScan::GetDTVSignalMonitor(void)524 {525 return dynamic_cast<DTVSignalMonitor*>(signalMonitor);526 }527 528 DVBSignalMonitor* SIScan::GetDVBSignalMonitor(void)529 {530 #ifdef USING_DVB531 return dynamic_cast<DVBSignalMonitor*>(signalMonitor);532 #else533 return NULL;534 #endif535 }536 537 DTVChannel *SIScan::GetDTVChannel(void)538 {539 return dynamic_cast<DTVChannel*>(channel);540 }541 542 DVBChannel *SIScan::GetDVBChannel(void)543 {544 #ifdef USING_DVB545 return dynamic_cast<DVBChannel*>(channel);546 #else547 return NULL;548 #endif549 }550 551 V4LChannel *SIScan::GetV4LChannel(void)552 {553 #ifdef USING_V4L554 return dynamic_cast<V4LChannel*>(channel);555 #else556 return NULL;557 #endif558 }559 560 /** \fn SIScan::SpawnScanner(void*)561 * \brief Thunk that allows scanner_thread pthread to562 * call SIScan::RunScanner().563 */564 void *SIScan::SpawnScanner(void *param)565 {566 SIScan *scanner = (SIScan *)param;567 scanner->RunScanner();568 return NULL;569 }570 571 /** \fn SIScan::StartScanner(void)572 * \brief Starts the SIScan event loop.573 */574 void SIScan::StartScanner(void)575 {576 pthread_create(&scanner_thread, NULL, SpawnScanner, this);577 }578 579 /** \fn SIScan::RunScanner(void)580 * \brief This runs the event loop for SIScan until 'threadExit' is true.581 */582 void SIScan::RunScanner(void)583 {584 VERBOSE(VB_SIPARSER, LOC + "Starting SIScanner");585 586 scanner_thread_running = true;587 threadExit = false;588 589 while (!threadExit)590 {591 if (scanMode == TRANSPORT_LIST)592 HandleActiveScan();593 594 usleep(250);595 }596 scanner_thread_running = false;597 }598 599 // See if we have timed out600 bool SIScan::HasTimedOut(void)601 {602 if (!waitingForTables)603 return true;604 605 // have the tables have timed out?606 if (timer.elapsed() > (int)channelTimeout)607 {608 QString offset_str = current.offset() ?609 QObject::tr(" offset %2").arg(current.offset()) : "";610 QString cur_chan = QString("%1%2")611 .arg((*current).FriendlyName).arg(offset_str);612 QString time_out_table_str =613 QObject::tr("Timeout Scanning %1 -- no tables").arg(cur_chan);614 615 emit ServiceScanUpdateText(time_out_table_str);616 VERBOSE(VB_SIPARSER, LOC + time_out_table_str);617 618 return true;619 }620 621 // ok the tables haven't timed out, but have we hit the signal timeout?622 if (timer.elapsed() > (int)(*current).timeoutTune)623 {624 // If we don't have a signal in timeoutTune msec, continue..625 SignalMonitor *sm = GetSignalMonitor();626 if (NULL == sm || sm->HasSignalLock())627 return false;628 629 QString offset_str = current.offset() ?630 QObject::tr(" offset %2").arg(current.offset()) : "";631 QString cur_chan = QString("%1%2")632 .arg((*current).FriendlyName).arg(offset_str);633 QString time_out_sig_str =634 QObject::tr("Timeout Scanning %1 -- no signal").arg(cur_chan);635 636 emit ServiceScanUpdateText(time_out_sig_str);637 VERBOSE(VB_SIPARSER, LOC + time_out_sig_str);638 639 return true;640 }641 return false;642 }643 644 /** \fn SIScan::HandleActiveScan(void)645 * \brief Handles the TRANSPORT_LIST SIScan mode.646 */647 void SIScan::HandleActiveScan(void)648 {649 bool do_post_insertion = waitingForTables;650 651 if (!HasTimedOut())652 return;653 654 if (0 == nextIt.offset() && nextIt != transport_scan_items_it_t(scanTransports.begin()))655 {656 // Stop signal monitor for previous transport657 signalMonitor->Stop();658 659 if (do_post_insertion)660 HandlePostInsertion();661 662 transportsScanned++;663 UpdateScanPercentCompleted();664 }665 666 current = nextIt; // Increment current667 668 if (current != transport_scan_items_it_t(scanTransports.end()))669 {670 ScanTransport(current);671 672 // Increment nextIt673 nextIt = current;674 ++nextIt;675 }676 else677 {678 emit ServiceScanComplete();679 scanMode = IDLE;680 scanTransports.clear();681 current = nextIt = transport_scan_items_it_t(scanTransports.end());682 }683 }684 685 bool SIScan::Tune(const transport_scan_items_it_t transport)686 {687 const TransportScanItem &item = *transport;688 const uint64_t freq = item.freq_offset(transport.offset());689 690 #ifdef USING_DVB691 if (GetDVBSignalMonitor() && GetDVBChannel())692 {693 if (GetDVBChannel()->GetRotor())694 {695 GetDVBSignalMonitor()->AddFlags(SignalMonitor::kDVBSigMon_WaitForPos);696 GetDVBSignalMonitor()->SetRotorTarget(1.0f);697 }698 }699 #endif // USING_DVB700 701 if (!GetDTVChannel())702 return false;703 704 if (item.mplexid > 0)705 return GetDTVChannel()->TuneMultiplex(item.mplexid, inputname);706 707 DTVMultiplex tuning = item.tuning;708 tuning.frequency = freq;709 return GetDTVChannel()->Tune(tuning, inputname);710 }711 712 void SIScan::ScanTransport(const transport_scan_items_it_t transport)713 {714 QString offset_str = (transport.offset()) ?715 QObject::tr(" offset %2").arg(transport.offset()) : "";716 QString cur_chan = QString("%1%2")717 .arg((*current).FriendlyName).arg(offset_str);718 QString tune_msg_str =719 QObject::tr("Tuning to %1 mplexid(%2)")720 .arg(cur_chan).arg((*current).mplexid);721 722 const TransportScanItem &item = *transport;723 724 if (transport.offset() &&725 (item.freq_offset(transport.offset()) == item.freq_offset(0)))726 {727 waitingForTables = false;728 return; // nothing to do729 }730 731 emit ServiceScanUpdateStatusText(cur_chan);732 VERBOSE(VB_SIPARSER, LOC + tune_msg_str);733 734 if (!Tune(transport))735 { // If we did not tune successfully, bail with message736 UpdateScanPercentCompleted();737 VERBOSE(VB_SIPARSER, LOC +738 QString("Failed to tune %1 mplexid(%2) at offset %3")739 .arg(item.FriendlyName).arg(item.mplexid)740 .arg(transport.offset()));741 return;742 }743 744 // If we have a DTV Signal Monitor, perform table scanner reset745 if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())746 {747 GetDTVSignalMonitor()->GetScanStreamData()->Reset();748 GetDTVSignalMonitor()->SetChannel(-1,-1);749 }750 751 // Start signal monitor for this channel752 signalMonitor->Start();753 754 timer.start();755 waitingForTables = true;756 }757 758 /** \fn SIScan::StopScanner(void)759 * \brief Stops the SIScan event loop and the signal monitor,760 * blocking until both exit.761 */762 void SIScan::StopScanner(void)763 {764 VERBOSE(VB_SIPARSER, LOC + "Stopping SIScanner");765 766 threadExit = true;767 768 if (scanner_thread_running)769 pthread_join(scanner_thread, NULL);770 771 if (signalMonitor)772 {773 signalMonitor->Stop();774 delete signalMonitor;775 signalMonitor = NULL;776 }777 }778 779 /** \fn SIScan::ScanTransports(int,const QString,const QString,const QString)780 * \brief Generates a list of frequencies to scan and adds it to the781 * scanTransport list, and then sets the scanMode to TRANSPORT_LIST.782 */783 bool SIScan::ScanTransports(int SourceID,784 const QString std,785 const QString modulation,786 const QString country)787 {788 QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";789 QString name("");790 if (scanMode == TRANSPORT_LIST)791 return false;792 793 scanTransports.clear();794 nextIt = transport_scan_items_it_t( scanTransports.end());795 796 freq_table_list_t tables =797 get_matching_freq_tables(std, modulation, country);798 799 VERBOSE(VB_SIPARSER, LOC +800 QString("Looked up freq table (%1, %2, %3) w/%4 entries")801 .arg(std).arg(modulation).arg(country).arg(tables.size()));802 803 freq_table_list_t::iterator it = tables.begin();804 for (; it != tables.end(); ++it)805 {806 const FrequencyTable &ft = **it;807 int name_num = ft.name_offset;808 QString strNameFormat = ft.name_format;809 uint freq = ft.frequencyStart;810 while (freq <= ft.frequencyEnd)811 {812 name = strNameFormat;813 if (strNameFormat.indexOf("%") >= 0)814 name = strNameFormat.arg(name_num);815 816 TransportScanItem item(SourceID, si_std, name, name_num,817 freq, ft, signalTimeout);818 scanTransports += item;819 820 VERBOSE(VB_SIPARSER, LOC + item.toString());821 822 name_num++;823 freq += ft.frequencyStep;824 }825 delete *it;826 }827 tables.clear();828 829 timer.start();830 waitingForTables = false;831 832 nextIt = transport_scan_items_it_t( scanTransports.begin() );833 transportsScanned = 0;834 scanMode = TRANSPORT_LIST;835 836 return true;837 }838 839 bool SIScan::ScanForChannels(uint sourceid,840 const QString &std,841 const QString &cardtype,842 const DTVChannelList &channels)843 {844 scanTransports.clear();845 nextIt = transport_scan_items_it_t( scanTransports.end());846 847 DTVTunerType tunertype;848 tunertype.Parse(cardtype);849 850 DTVChannelList::const_iterator it = channels.begin();851 for (uint i = 0; it != channels.end(); ++it, i++)852 {853 DTVTransport tmp = *it;854 tmp.sistandard = std;855 TransportScanItem item(sourceid, QString::number(i),856 tunertype, tmp, signalTimeout);857 858 scanTransports += item;859 860 VERBOSE(VB_SIPARSER, LOC + item.toString());861 }862 863 if (scanTransports.empty())864 {865 VERBOSE(VB_IMPORTANT, LOC_ERR + "ScanForChannels() no transports");866 return false;867 }868 869 timer.start();870 waitingForTables = false;871 872 nextIt = transport_scan_items_it_t( scanTransports.begin());873 transportsScanned = 0;874 scanMode = TRANSPORT_LIST;875 876 return true;877 }878 879 /** \fn SIScan::ScanTransportsStartingOn(int,const QMap<QString,QString>&)880 * \brief Generates a list of frequencies to scan and adds it to the881 * scanTransport list, and then sets the scanMode to TRANSPORT_LIST.882 */883 bool SIScan::ScanTransportsStartingOn(int sourceid,884 const QMap<QString,QString> &startChan)885 {886 QMap<QString,QString>::const_iterator it;887 888 if (startChan.find("std") == startChan.end() ||889 startChan.find("modulation") == startChan.end())890 {891 return false;892 }893 894 QString std = *startChan.find("std");895 QString mod = (*(startChan.find("modulation"))).toUpper();896 QString si_std = (std.toLower() != "atsc") ? "dvb" : "atsc";897 QString name = "";898 bool ok = false;899 900 if (scanMode == TRANSPORT_LIST)901 return false;902 903 scanTransports.clear();904 nextIt = transport_scan_items_it_t( scanTransports.end() );905 906 DTVMultiplex tuning;907 908 DTVTunerType type;909 910 if (std == "dvb")911 {912 ok = type.Parse(mod);913 }914 else if (std == "atsc")915 {916 type = DTVTunerType::kTunerTypeATSC;917 ok = true;918 }919 920 if (ok)921 {922 ok = tuning.ParseTuningParams(923 type,924 startChan["frequency"], startChan["inversion"],925 startChan["symbolrate"], startChan["fec"],926 startChan["polarity"],927 startChan["coderate_hp"], startChan["coderate_lp"],928 startChan["constellation"], startChan["trans_mode"],929 startChan["guard_interval"], startChan["hierarchy"],930 startChan["modulation"], startChan["bandwidth"]);931 }932 933 if (ok)934 {935 tuning.sistandard = si_std;936 scanTransports += TransportScanItem(937 sourceid, tr("Frequency %1").arg(startChan["frequency"]),938 tuning, signalTimeout);939 }940 941 if (!ok)942 return false;943 944 timer.start();945 waitingForTables = false;946 947 nextIt = transport_scan_items_it_t(scanTransports.begin());948 transportsScanned = 0;949 scanMode = TRANSPORT_LIST;950 951 return true;952 }953 954 bool SIScan::ScanTransport(int mplexid)955 {956 scanTransports.clear();957 nextIt = transport_scan_items_it_t(scanTransports.end());958 959 MSqlQuery query(MSqlQuery::InitCon());960 // Run DB query to get transports on sourceid SourceID961 // connected to this card962 QString theQuery = QString(963 "SELECT sourceid, mplexid, sistandard, transportid "964 "FROM dtv_multiplex WHERE mplexid = %2").arg(mplexid);965 query.prepare(theQuery);966 967 if (!query.exec() || !query.isActive())968 {969 MythDB::DBError("Get Transports for SourceID", query);970 return false;971 }972 973 if (query.size() <= 0)974 {975 VERBOSE(VB_SIPARSER, LOC + "Unable to find transport to scan.");976 return false;977 }978 979 while (query.next())980 {981 int sourceid = query.value(0).toInt();982 int queriedMplexid = query.value(1).toInt();983 QString std = query.value(2).toString();984 int tsid = query.value(3).toInt();985 986 QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :987 QString("Multiplex #%1").arg(queriedMplexid);988 989 VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);990 991 TransportScanItem item(992 sourceid, std, fn, queriedMplexid, signalTimeout);993 scanTransports += item;994 }995 996 timer.start();997 waitingForTables = false;998 999 transportsScanned = 0;1000 if (scanTransports.size())1001 {1002 nextIt = transport_scan_items_it_t(scanTransports.begin());1003 scanMode = TRANSPORT_LIST;1004 return true;1005 }1006 1007 return false;1008 }1009 1010 /** \fn SIScan::CheckImportedList(const DTVChannelInfoList&,uint,QString&,QString&,QString&)1011 * \brief If we as scanning a dvb-utils import verify channel is in list..1012 */1013 bool SIScan::CheckImportedList(const DTVChannelInfoList &channels,1014 uint mpeg_program_num,1015 QString &service_name,1016 QString &callsign,1017 QString &common_status_info)1018 {1019 if (channels.empty())1020 return true;1021 1022 bool found = false;1023 for (uint i = 0; i < channels.size(); i++)1024 {1025 VERBOSE(VB_IMPORTANT,1026 QString("comparing %1 %2 against %3 %4")1027 .arg(channels[i].serviceid).arg(channels[i].name)1028 .arg(mpeg_program_num).arg(common_status_info));1029 1030 if (channels[i].serviceid == mpeg_program_num)1031 {1032 found = true;1033 if (!channels[i].name.isEmpty())1034 {1035 service_name = channels[i].name; service_name.detach();1036 callsign = channels[i].name; callsign.detach();1037 }1038 }1039 }1040 1041 if (found)1042 {1043 common_status_info += QString(" %1 %2")1044 .arg(tr("as")).arg(service_name);1045 }1046 else1047 {1048 emit ServiceScanUpdateText(1049 tr("Skipping %1, not in imported channel map")1050 .arg(common_status_info));1051 }1052 1053 return found;1054 }1055 1056 // ///////////////////// DB STUFF /////////////////////1057 // ///////////////////// DB STUFF /////////////////////1058 // ///////////////////// DB STUFF /////////////////////1059 // ///////////////////// DB STUFF /////////////////////1060 // ///////////////////// DB STUFF /////////////////////1061 1062 void SIScan::UpdatePMTinDB(1063 int db_source_id,1064 int db_mplexid, const QString &friendlyName, int freqid,1065 int pmt_indx, const ProgramMapTable *pmt,1066 const DTVChannelInfoList &channels, bool /*force_update*/)1067 {1068 VERBOSE(VB_IMPORTANT, LOC + pmt->toString());1069 1070 // See if service already in database based on program number1071 int chanid = ChannelUtil::GetChanID(1072 db_mplexid, -1, -1, -1, pmt->ProgramNumber());1073 1074 QString chan_num = ChannelUtil::GetChanNum(chanid);1075 if (chan_num.isEmpty() || renameChannels)1076 {1077 chan_num = QString("%1#%2")1078 .arg((freqid) ? freqid : db_mplexid).arg(pmt_indx);1079 }1080 1081 QString callsign = ChannelUtil::GetCallsign(chanid);1082 QString service_name = ChannelUtil::GetServiceName(chanid);1083 1084 if (callsign.isEmpty())1085 {1086 callsign = QString("%1%2")1087 .arg(ChannelUtil::GetUnknownCallsign())1088 .arg(chan_num);1089 }1090 else if (service_name.isEmpty())1091 service_name = callsign; // only do this for real callsigns1092 1093 QString common_status_info = tr("%1%2%3 on %4 (%5)")1094 .arg(service_name)1095 .arg(service_name.isEmpty() ? "" : QString(" %1 ").arg(tr("as")))1096 .arg(chan_num)1097 .arg(friendlyName).arg(freqid);1098 1099 if (!CheckImportedList(channels, pmt->ProgramNumber(),1100 service_name, chan_num, common_status_info))1101 {1102 return;1103 }1104 1105 if (chanid < 0)1106 { // The service is not in database, add it1107 emit ServiceScanUpdateText(1108 tr("Adding %1").arg(common_status_info));1109 chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);1110 ChannelUtil::CreateChannel(1111 db_mplexid, db_source_id, chanid,1112 callsign,1113 service_name,1114 chan_num,1115 pmt->ProgramNumber(),1116 0, 0,1117 false, false, false, QString::number(freqid));1118 }1119 else1120 { // The service is in database, update it1121 emit ServiceScanUpdateText(1122 tr("Updating %1").arg(common_status_info));1123 1124 bool useeit = false;1125 bool hidden = false;1126 1127 ChannelUtil::GetChannelSettings(chanid, useeit, hidden);1128 1129 ChannelUtil::UpdateChannel(1130 db_mplexid, db_source_id, chanid,1131 callsign,1132 service_name,1133 chan_num,1134 pmt->ProgramNumber(),1135 0, 0,1136 useeit, hidden, false, QString::number(freqid));1137 }1138 }1139 1140 void SIScan::IgnoreDataOnlyMsg(const QString &name, int aux_num)1141 {1142 QString vmsg = QString("Ignoring Data Channel: %1").arg(name);1143 if (aux_num > 0)1144 vmsg += QString(" on %1").arg(aux_num);1145 VERBOSE(VB_SIPARSER, vmsg);1146 1147 //1148 1149 QString tmsg = tr("Skipping %1").arg(name);1150 if (aux_num > 0)1151 tmsg += " " + tr("on %1").arg(aux_num);1152 tmsg += " - " + tr("Data Only Channel (off-air?)");1153 emit ServiceScanUpdateText(tmsg);1154 }1155 1156 void SIScan::IgnoreEmptyChanMsg(const QString &name, int aux_num)1157 {1158 QString vmsg = QString("Ignoring Empty Channel: %1").arg(name);1159 if (aux_num > 0)1160 vmsg += QString(" on %1").arg(aux_num);1161 VERBOSE(VB_SIPARSER, vmsg);1162 1163 //1164 1165 QString tmsg = tr("Skipping %1").arg(name);1166 if (aux_num > 0)1167 tmsg += " " + tr("on %1").arg(aux_num);1168 tmsg += " - " + tr("Empty Channel (off-air?)");1169 emit ServiceScanUpdateText(tmsg);1170 }1171 1172 void SIScan::IgnoreAudioOnlyMsg(const QString &name, int aux_num)1173 {1174 QString vmsg = QString("Ignoring Audio Only Channel: %1").arg(name);1175 if (aux_num > 0)1176 vmsg += QString(" on %1").arg(aux_num);1177 VERBOSE(VB_SIPARSER, vmsg);1178 1179 //1180 1181 QString tmsg = tr("Skipping %1").arg(name);1182 if (aux_num > 0)1183 tmsg += " " + tr("on %1").arg(aux_num);1184 tmsg += " - " + tr("Audio Only Channel");1185 emit ServiceScanUpdateText(tmsg);1186 }1187 1188 void SIScan::IgnoreEncryptedMsg(const QString &name, int aux_num)1189 {1190 QString vmsg = QString("Ignoring Encrypted Channel: %1").arg(name);1191 if (aux_num > 0)1192 vmsg += QString(" on %1").arg(aux_num);1193 VERBOSE(VB_SIPARSER, vmsg);1194 1195 //1196 1197 QString tmsg = tr("Skipping %1").arg(name);1198 if (aux_num > 0)1199 tmsg += " " + tr("on %1").arg(aux_num);1200 tmsg += " - " + tr("Encrypted Channel");1201 emit ServiceScanUpdateText(tmsg);1202 }1203 1204 void SIScan::UpdatePATinDB(1205 int db_mplexid, const QString &friendlyName, int freqid,1206 const ProgramAssociationTable *pat, const pmt_map_t &pmt_map,1207 const DTVChannelInfoList &channels, const QString &si_standard,1208 bool force_update)1209 {1210 VERBOSE(VB_SIPARSER, LOC +1211 QString("UpdatePATinDB(): tsid: 0x%1 mplex: %2")1212 .arg(pat->TransportStreamID(),0,16).arg(db_mplexid));1213 1214 VERBOSE(VB_IMPORTANT, LOC + pat->toString());1215 1216 int db_source_id = ChannelUtil::GetSourceID(db_mplexid);1217 1218 for (uint i = 0; i < pat->ProgramCount(); i++)1219 {1220 pmt_map_t::const_iterator it = pmt_map.find(pat->ProgramNumber(i));1221 if (it == pmt_map.end())1222 {1223 VERBOSE(VB_SIPARSER,1224 QString("UpdatePATinDB(): PMT for Program #%1 is missing")1225 .arg(pat->ProgramNumber(i)));1226 continue;1227 }1228 pmt_vec_t::const_iterator vit = (*it).begin();1229 for (; vit != (*it).end(); ++vit)1230 {1231 VERBOSE(VB_SIPARSER,1232 QString("UpdatePATinDB(): Prog %1 PID %2: PMT @")1233 .arg(pat->ProgramNumber(i))1234 .arg(pat->ProgramPID(i)) << *vit);1235 1236 // ignore all services without PMT, and1237 // ignore services we have decided to ignore1238 if (!(*vit))1239 continue;1240 else if ((*vit)->StreamCount() <= 0)1241 {1242 IgnoreEmptyChanMsg(friendlyName, pat->ProgramNumber(i));1243 continue;1244 }1245 else if (ignoreAudioOnlyServices &&1246 (*vit)->IsStillPicture(si_standard))1247 {1248 IgnoreAudioOnlyMsg(friendlyName, pat->ProgramNumber(i));1249 continue;1250 }1251 else if (ignoreEncryptedServices && (*vit)->IsEncrypted())1252 {1253 IgnoreEncryptedMsg(friendlyName, pat->ProgramNumber(i));1254 continue;1255 }1256 1257 UpdatePMTinDB(db_source_id, db_mplexid, friendlyName, freqid,1258 i, *vit, channels, force_update);1259 }1260 }1261 }1262 1263 void SIScan::UpdateVCTinDB(int db_mplexid,1264 const QString &friendlyName, int freqid,1265 const VirtualChannelTable *vct,1266 const DTVChannelInfoList &channels,1267 bool force_update)1268 {1269 (void) force_update;1270 1271 VERBOSE(VB_SIPARSER, LOC +1272 QString("UpdateVCTinDB(): tsid: 0x%1 mplex: %2")1273 .arg(vct->TransportStreamID(),0,16).arg(db_mplexid));1274 1275 int db_source_id = ChannelUtil::GetSourceID(db_mplexid);1276 1277 for (uint i = 0; i < vct->ChannelCount(); i++)1278 {1279 if (vct->ModulationMode(i) == 0x01 /* NTSC Modulation */ ||1280 vct->ServiceType(i) == 0x01 /* Analog TV */)1281 {1282 continue;1283 }1284 1285 QString basic_status_info = QString("%1 %2-%3")1286 .arg(vct->ShortChannelName(i))1287 .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i));1288 1289 if (vct->ServiceType(i) == 0x04 && ignoreDataServices)1290 {1291 IgnoreEmptyChanMsg(basic_status_info, vct->ProgramNumber(i));1292 continue;1293 }1294 1295 if (vct->ServiceType(i) == 0x03 && ignoreAudioOnlyServices)1296 {1297 IgnoreAudioOnlyMsg(basic_status_info, vct->ProgramNumber(i));1298 continue;1299 }1300 1301 if (vct->IsAccessControlled(i) && ignoreEncryptedServices)1302 {1303 IgnoreEncryptedMsg(basic_status_info, vct->ProgramNumber(i));1304 continue;1305 }1306 1307 // See if service already in database1308 int chanid = ChannelUtil::GetChanID(1309 db_mplexid, vct->ChannelTransportStreamID(i),1310 vct->MajorChannel(i), vct->MinorChannel(i),1311 vct->ProgramNumber(i));1312 1313 QString chan_num = ChannelUtil::GetChanNum(chanid);1314 if (chan_num.isEmpty() || renameChannels)1315 {1316 chan_num = channelFormat1317 .arg(vct->MajorChannel(i))1318 .arg(vct->MinorChannel(i));1319 }1320 1321 QString callsign = ChannelUtil::GetCallsign(chanid);1322 if (callsign.isEmpty() || renameChannels)1323 callsign = vct->ShortChannelName(i);1324 1325 // try to find an extended channel name, fallback to short name.1326 QString longName = vct->GetExtendedChannelName(i);1327 if (longName.isEmpty())1328 longName = vct->ShortChannelName(i);1329 1330 QString common_status_info = tr("%1 %2-%3 as %4 on %5 (%6)")1331 .arg(vct->ShortChannelName(i))1332 .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i))1333 .arg(chan_num).arg(friendlyName).arg(freqid);1334 1335 bool use_eit = !vct->IsHidden(i) ||1336 (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));1337 1338 1339 if (!CheckImportedList(channels, vct->ProgramNumber(i),1340 longName, callsign, common_status_info))1341 {1342 continue;1343 }1344 1345 QString msg = "";1346 if (chanid < 0)1347 { // The service is not in database, add it1348 msg = tr("Adding %1").arg(common_status_info);1349 chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);1350 if (chanid > 0)1351 {1352 bool use_eit = !vct->IsHidden(i) ||1353 (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));1354 1355 ChannelUtil::CreateChannel(1356 db_mplexid,1357 db_source_id,1358 chanid,1359 callsign,1360 longName,1361 chan_num,1362 vct->ProgramNumber(i),1363 vct->MajorChannel(i), vct->MinorChannel(i),1364 use_eit,1365 vct->IsHidden(i), vct->IsHiddenInGuide(i),1366 QString::number(freqid));1367 }1368 }1369 else1370 { // The service is in database, update it1371 msg = tr("Updating %1").arg(common_status_info);1372 ChannelUtil::UpdateChannel(1373 db_mplexid,1374 db_source_id,1375 chanid,1376 callsign,1377 longName,1378 chan_num,1379 vct->ProgramNumber(i),1380 vct->MajorChannel(i), vct->MinorChannel(i),1381 use_eit,1382 vct->IsHidden(i), vct->IsHiddenInGuide(i),1383 QString::number(freqid));1384 }1385 emit ServiceScanUpdateText(msg);1386 VERBOSE(VB_SIPARSER, msg);1387 }1388 }1389 1390 /**1391 * \brief Inserts channels from service description table.1392 */1393 void SIScan::UpdateSDTinDB(int /*mplexid*/, const ServiceDescriptionTable *sdt,1394 const DTVChannelInfoList &channels,1395 bool force_update)1396 {1397 if (!sdt->ServiceCount())1398 return;1399 1400 int db_mplexid = ChannelUtil::GetMplexID(1401 sourceID, sdt->TSID(), sdt->OriginalNetworkID());1402 1403 // HACK beg -- special exception for this network (dbver == "1067")1404 bool force_guide_present = (sdt->OriginalNetworkID() == 70);1405 // HACK end -- special exception for this network1406 1407 if (db_mplexid == -1)1408 {1409 VERBOSE(VB_IMPORTANT, "SDT: Error determing what transport this "1410 "service table is associated with so failing");1411 emit ServiceScanUpdateText(1412 tr("Found channel, but it doesn't match existing tsid. You may "1413 "wish to delete existing channels and do a full scan."));1414 return;1415 }1416 1417 int db_source_id = ChannelUtil::GetSourceID(db_mplexid);1418 1419 /* This will be fixed post .17 to be more elegant */1420 bool upToDate = (ChannelUtil::GetServiceVersion(db_mplexid) ==1421 (int)sdt->Version());1422 if (upToDate && !force_update)1423 {1424 emit ServiceScanUpdateText("Channels up to date");1425 return;1426 }1427 if (!upToDate)1428 ChannelUtil::SetServiceVersion(db_mplexid, sdt->Version());1429 1430 for (uint i = 0; i < sdt->ServiceCount(); i++)1431 {1432 // Figure out best service name...1433 ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);1434 QString service_name = "";1435 if (desc)1436 service_name = desc->ServiceName();1437 1438 if (service_name.trimmed().isEmpty())1439 service_name = QString("%1 %2")1440 .arg(sdt->ServiceID(i)).arg(db_mplexid);1441 1442 // Figure out best channel number1443 QString chan_num = QString::number(sdt->ServiceID(i));1444 bool have_uk_chan_num =1445 dvbChanNums.find(sdt->ServiceID(i)) != dvbChanNums.end();1446 if (have_uk_chan_num)1447 chan_num = QString::number(dvbChanNums[sdt->ServiceID(i)]);1448 1449 // Skip to next if this is a service we don't care for1450 if (desc && desc->IsDigitalAudio() && ignoreAudioOnlyServices)1451 {1452 IgnoreAudioOnlyMsg(service_name, sdt->ServiceID(i));1453 delete desc;1454 continue;1455 }1456 else if (desc && !desc->IsDTV() && !desc->IsDigitalAudio() &&1457 ignoreDataServices)1458 {1459 IgnoreDataOnlyMsg(service_name, sdt->ServiceID(i));1460 delete desc;1461 continue;1462 }1463 else if (ignoreEncryptedServices && sdt->IsEncrypted(i))1464 {1465 IgnoreEncryptedMsg(service_name, sdt->ServiceID(i));1466 if (desc)1467 delete desc;1468 continue;1469 }1470 1471 // Default authority1472 QString default_authority = "";1473 desc_list_t parsed =1474 MPEGDescriptor::Parse(sdt->ServiceDescriptors(i),1475 sdt->ServiceDescriptorsLength(i));1476 const unsigned char *def_auth =1477 MPEGDescriptor::Find(parsed, DescriptorID::default_authority);1478 if (def_auth)1479 default_authority =1480 QString::fromAscii((const char*)def_auth+2, def_auth[1]);1481 1482 QString common_status_info = service_name;1483 1484 if (!CheckImportedList(channels, sdt->ServiceID(i),1485 service_name, service_name, common_status_info))1486 {1487 if (desc)1488 delete desc;1489 continue;1490 }1491 1492 // See if service already in database based on service ID1493 int chanid = ChannelUtil::GetChanID(db_mplexid, -1, -1, -1,1494 sdt->ServiceID(i));1495 1496 if (chanid < 0)1497 { // The service is not in database, add it1498 emit ServiceScanUpdateText(tr("Adding %1").arg(service_name));1499 chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);1500 if (chanid > 0)1501 {1502 ChannelUtil::CreateChannel(1503 db_mplexid, db_source_id, chanid,1504 service_name,1505 service_name,1506 chan_num,1507 sdt->ServiceID(i),1508 0, 0,1509 sdt->HasEITSchedule(i) ||1510 sdt->HasEITPresentFollowing(i) ||1511 force_guide_present,1512 false, false, QString::null,1513 QString::null, "Default", QString::null,1514 default_authority);1515 }1516 }1517 else if (force_update || (desc && have_uk_chan_num))1518 { // The service is in database & we have good info, update it1519 emit ServiceScanUpdateText(tr("Updating %1").arg(service_name));1520 1521 bool useeit = false;1522 bool hidden = false;1523 1524 ChannelUtil::GetChannelSettings(chanid, useeit, hidden);1525 1526 if (!renameChannels)1527 chan_num = ChannelUtil::GetChanNum(chanid);1528 else1529 useeit = (sdt->HasEITSchedule(i) ||1530 sdt->HasEITPresentFollowing(i) ||1531 force_guide_present);1532 1533 ChannelUtil::UpdateChannel(1534 db_mplexid,1535 db_source_id,1536 chanid,1537 service_name,1538 service_name,1539 chan_num,1540 sdt->ServiceID(i),1541 0, 0,1542 useeit,1543 hidden, false, QString::null,1544 QString::null, QString::null, QString::null,1545 default_authority);1546 }1547 else1548 {1549 emit ServiceScanUpdateText(1550 tr("Skipping %1 - already in DB, and "1551 "we don't have better data.")1552 .arg(service_name));1553 }1554 1555 if (desc)1556 delete desc;1557 }1558 }1559 1560 // FindBestMplexFreq()1561 // - Examines the freq in the DB against the curent tuning frequency and1562 // it's offset frequencies. If the frequency in the DB is any of the1563 // tuning frequencies or offsets then use the DB frequency.1564 uint64_t SIScan::FindBestMplexFreq(1565 const uint64_t tuning_freq,1566 const transport_scan_items_it_t transport, const uint sourceid,1567 const uint transportid, const uint networkid)1568 {1569 uint64_t db_freq;1570 QString tmp_modulation;1571 QString tmp_si_std;1572 uint tmp_transportid, tmp_networkid;1573 int mplexid;1574 1575 if (!transportid || !networkid)1576 return tuning_freq;1577 1578 mplexid = ChannelUtil::GetMplexID(sourceid, transportid, networkid);1579 if (mplexid <= 0)1580 return tuning_freq;1581 1582 if (!ChannelUtil::GetTuningParams(1583 (uint)mplexid, tmp_modulation,1584 db_freq, tmp_transportid, tmp_networkid, tmp_si_std))1585 {1586 return tuning_freq;1587 }1588 1589 for (uint i = 0; i < (*transport).offset_cnt(); i++)1590 {1591 if (db_freq == (*transport).freq_offset(i))1592 return db_freq;1593 }1594 1595 return tuning_freq;1596 }1597 1598 uint SIScan::InsertMultiplex(const transport_scan_items_it_t transport)1599 {1600 DTVMultiplex tuning = (*transport).tuning;1601 uint tsid = 0;1602 uint netid = 0;1603 1604 tuning.frequency = (*transport).freq_offset(transport.offset());1605 1606 #ifdef USING_DVB1607 if (GetDVBSignalMonitor())1608 {1609 DVBSignalMonitor *sm = GetDVBSignalMonitor();1610 1611 tsid = sm->GetDetectedTransportID();1612 netid = sm->GetDetectedNetworkID();1613 1614 // Try to read the actual values back from the card1615 if (GetDVBChannel()->IsTuningParamsProbeSupported())1616 GetDVBChannel()->ProbeTuningParams(tuning);1617 1618 tuning.frequency = FindBestMplexFreq(1619 tuning.frequency, transport, (*transport).SourceID, tsid, netid);1620 }1621 #endif // USING_DVB1622 1623 #ifdef USING_V4L1624 if (GetV4LChannel())1625 {1626 // convert to visual carrier1627 tuning.frequency = tuning.frequency - 1750000;1628 }1629 #endif // USING_V4L1630 1631 return ChannelUtil::CreateMultiplex(1632 (*transport).SourceID, tuning, tsid, netid);1633 } -
libs/libmythtv/scanwizard.h
38 38 #include "settings.h" 39 39 40 40 class ScanWizardConfig; 41 class ScanWizardScanner;41 class ChannelScannerGUI; 42 42 43 43 class MPUBLIC ScanWizard : public QObject, public ConfigurationWizard 44 44 { … … 62 62 uint lastHWCardID; 63 63 uint lastHWCardType; 64 64 ScanWizardConfig *configPane; 65 ScanWizardScanner*scannerPane;65 ChannelScannerGUI *scannerPane; 66 66 }; 67 67 68 68 #endif // SCANWIZARD_H -
libs/libmythtv/frequencytables.h
76 76 constellation(_constellation), trans_mode(_trans_mode), 77 77 guard_interval(_guard_interval), hierarchy(_hierarchy) { ; } 78 78 79 FrequencyTable(uint64_t _frequencyStart, 80 uint64_t _frequencyEnd, 81 uint _frequencyStep, 82 QString _name_format, 83 int _name_offset, 84 DTVCodeRate _fec_inner, 85 DTVModulation _modulation, 86 uint _symbol_rate, 87 int _offset1, 88 int _offset2) 89 : name_format(_name_format), name_offset(_name_offset), 90 frequencyStart(_frequencyStart), frequencyEnd(_frequencyEnd), 91 frequencyStep(_frequencyStep), modulation(_modulation), 92 offset1(_offset1), offset2(_offset2), 93 symbol_rate(_symbol_rate), fec_inner(_fec_inner) { ; } 94 79 95 virtual ~FrequencyTable() { ; } 80 96 81 97 // Common Stuff … … 93 109 DTVBandwidth bandwidth; 94 110 DTVCodeRate coderate_hp; 95 111 DTVCodeRate coderate_lp; 96 DTVModulation constellation; 112 DTVModulation constellation; 97 113 DTVTransmitMode trans_mode; 98 114 DTVGuardInterval guard_interval; 99 115 DTVHierarchy hierarchy; 116 117 // DVB-C/DVB-S stuff 118 uint symbol_rate; 119 DTVCodeRate fec_inner; 100 120 }; 101 121 102 122 /** -
libs/libmythtv/siscan.h
1 // -*- Mode: c++ -*-2 3 #ifndef SISCAN_H4 #define SISCAN_H5 6 #include <pthread.h>7 8 // Qt includes9 #include <qobject.h>10 #include <qstring.h>11 #include <qmap.h>12 #include <qmutex.h>13 #include <qdatetime.h>14 15 // MythTV includes16 #include "frequencytables.h"17 #include "streamlisteners.h"18 #include "dtvconfparser.h"19 #include "signalmonitorlistener.h"20 21 class MSqlQuery;22 23 class ChannelBase;24 class DTVChannel;25 class V4LChannel;26 class DVBChannel;27 class HDHRChannel;28 29 class SignalMonitor;30 class DTVSignalMonitor;31 class DVBSignalMonitor;32 33 typedef enum34 {35 IDLE, ///< Don't do anything36 TRANSPORT_LIST, ///< Actively scan for channels37 } SCANMODE;38 39 typedef vector<const ProgramMapTable*> pmt_vec_t;40 typedef QMap<uint, pmt_vec_t> pmt_map_t;41 42 class SIScan : public QObject,43 public MPEGStreamListener,44 public ATSCMainStreamListener,45 public DVBMainStreamListener,46 public SignalMonitorListener47 {48 Q_OBJECT49 public:50 SIScan(const QString &_cardtype, ChannelBase* _channel, int _sourceID,51 uint signal_timeout, uint channel_timeout,52 const QString &_inputname);53 ~SIScan();54 55 void StartScanner(void);56 void StopScanner(void);57 58 bool ScanTransports(59 int src, const QString std, const QString mod, const QString country);60 bool ScanTransportsStartingOn(61 int sourceid, const QMap<QString,QString> &valueMap);62 bool ScanTransport(int mplexid);63 bool ScanForChannels(64 uint sourceid, const QString &std, const QString &cardtype,65 const DTVChannelList&);66 67 bool ScanServicesSourceID(int SourceID);68 69 void SetAnalog(bool is_analog) { isAnalog = is_analog; }70 void SetSourceID(int _SourceID) { sourceID = _SourceID; }71 void SetFTAOnly(bool _fFTAOnly) { ignoreEncryptedServices = _fFTAOnly; }72 void SetTVOnly(bool _tvOnly)73 { ignoreAudioOnlyServices = ignoreDataServices = _tvOnly; }74 void SetForceUpdate(bool _force) { forceUpdate = _force; }75 void SetRenameChannels(bool _r) { renameChannels = _r; }76 void SetChannelFormat(const QString _fmt) { channelFormat = _fmt; }77 void SetSignalTimeout(uint val) { signalTimeout = val; }78 void SetChannelTimeout(uint val) { channelTimeout = val; }79 80 uint GetSignalTimeout(void) const { return signalTimeout; }81 uint GetChannelTimeout(void) const { return channelTimeout; }82 83 SignalMonitor *GetSignalMonitor(void) { return signalMonitor; }84 DTVSignalMonitor *GetDTVSignalMonitor(void);85 DVBSignalMonitor *GetDVBSignalMonitor(void);86 87 // MPEG88 void HandlePAT(const ProgramAssociationTable*);89 void HandleCAT(const ConditionalAccessTable*) { }90 void HandlePMT(uint, const ProgramMapTable*) { }91 void HandleEncryptionStatus(uint /*pnum*/, bool /*encrypted*/) { }92 93 // ATSC Main94 void HandleSTT(const SystemTimeTable*) {}95 void HandleMGT(const MasterGuideTable*);96 void HandleVCT(uint tsid, const VirtualChannelTable*);97 98 // DVB Main99 void HandleNIT(const NetworkInformationTable*);100 void HandleSDT(uint tsid, const ServiceDescriptionTable*);101 void HandleTDT(const TimeDateTable*) {}102 103 // SignalMonitorListener104 virtual void AllGood(void);105 virtual void StatusSignalLock(const SignalMonitorValue&) { }106 virtual void StatusSignalStrength(const SignalMonitorValue&) { }107 108 public slots:109 void deleteLater(void);110 111 signals:112 // Values from 1-100 of scan completion113 void PctServiceScanComplete(int pct);114 void PctTransportScanComplete(int pct);115 void ServiceScanUpdateStatusText(const QString& status);116 void ServiceScanUpdateText(const QString& status);117 void TransportScanUpdateText(const QString& status);118 void ServiceScanComplete(void);119 void TransportScanComplete(void);120 121 private:122 // some useful gets123 DTVChannel *GetDTVChannel(void);124 V4LChannel *GetV4LChannel(void);125 DVBChannel *GetDVBChannel(void);126 127 /// \brief Called by SpawnScanner to run scanning thread128 void RunScanner(void);129 /// \brief Thunk to call RunScanner from pthread130 static void *SpawnScanner(void *param);131 132 bool HasTimedOut(void);133 void HandleActiveScan(void);134 bool Tune(const transport_scan_items_it_t transport);135 uint InsertMultiplex(const transport_scan_items_it_t transport);136 void ScanTransport(const transport_scan_items_it_t transport);137 138 /// \brief Updates Transport Scan progress bar139 inline void UpdateScanPercentCompleted(void);140 141 bool CheckImportedList(const DTVChannelInfoList&,142 uint mpeg_program_num,143 QString &service_name,144 QString &callsign,145 QString &common_status_info);146 147 void IgnoreDataOnlyMsg( const QString &name, int aux_num);148 void IgnoreEmptyChanMsg(const QString &name, int aux_num);149 void IgnoreAudioOnlyMsg(const QString &name, int aux_num);150 void IgnoreEncryptedMsg(const QString &name, int aux_num);151 152 void HandleMPEGDBInsertion(const ScanStreamData *sd, bool wait);153 void UpdatePATinDB(int mplexid, const QString &friendlyName, int freqid,154 const ProgramAssociationTable*, const pmt_map_t&,155 const DTVChannelInfoList&, const QString &si_standard,156 bool force_update);157 158 void UpdatePMTinDB(int sourceid,159 int mplexid, const QString &friendlyName, int freqid,160 int pmt_indx, const ProgramMapTable*,161 const DTVChannelInfoList&,162 bool force_update);163 164 void HandleATSCDBInsertion(const ScanStreamData *sd, bool wait);165 void UpdateVCTinDB(int mplexid, const QString &friendlyName, int freqid,166 const VirtualChannelTable*,167 const DTVChannelInfoList&,168 bool force_update);169 170 void HandleDVBDBInsertion(const ScanStreamData *sd, bool wait);171 void UpdateSDTinDB(int mplexid,172 const ServiceDescriptionTable*,173 const DTVChannelInfoList&,174 bool force_update);175 176 bool HandlePostInsertion(void);177 178 uint64_t FindBestMplexFreq(const uint64_t tuning_freq,179 const transport_scan_items_it_t transport,180 const uint sourceid, const uint transportid,181 const uint networkid);182 183 184 static QString loc(const SIScan*);185 186 private:187 // Set in constructor188 ChannelBase *channel;189 SignalMonitor *signalMonitor;190 int sourceID;191 SCANMODE scanMode;192 uint signalTimeout;193 uint channelTimeout;194 QString inputname;195 196 // Settable197 bool isAnalog;198 bool ignoreAudioOnlyServices;199 bool ignoreDataServices;200 bool ignoreEncryptedServices;201 bool forceUpdate;202 bool renameChannels;203 QString channelFormat;204 205 // State206 bool threadExit;207 bool waitingForTables;208 QTime timer;209 210 // Transports List211 int transportsScanned;212 transport_scan_items_t scanTransports;213 transport_scan_items_it_t current;214 transport_scan_items_it_t nextIt;215 QMap<uint, uint> dvbChanNums;216 217 /// Scanner thread, runs SIScan::StartScanner()218 pthread_t scanner_thread;219 bool scanner_thread_running;220 };221 222 inline void SIScan::UpdateScanPercentCompleted(void)223 {224 int tmp = (transportsScanned * 100) / scanTransports.size();225 emit PctServiceScanComplete(tmp);226 }227 228 #endif // SISCAN_H -
libs/libmythtv/frequencytables.cpp
92 92 93 93 // setup tuning params 94 94 tuning.frequency = freq; 95 tuning.sistandard = std; 95 tuning.sistandard = (std.toLower() != "atsc") ? "dvb" : "atsc"; 96 tuning.modulation = ft.modulation; 96 97 freq_offsets[1] = ft.offset1; 97 98 freq_offsets[2] = ft.offset2; 98 99 99 if (std == "dvb ")100 if (std == "dvbt") 100 101 { 101 102 tuning.inversion = ft.inversion; 102 103 tuning.bandwidth = ft.bandwidth; 103 104 tuning.hp_code_rate = ft.coderate_hp; 104 105 tuning.lp_code_rate = ft.coderate_lp; 105 tuning.modulation = ft.modulation;106 106 tuning.trans_mode = ft.trans_mode; 107 107 tuning.guard_interval = ft.guard_interval; 108 108 tuning.hierarchy = ft.hierarchy; 109 109 } 110 else 110 else if (std == "dvbc" || std == "dvbs") 111 111 { 112 tuning.modulation = ft.modulation; 112 tuning.symbolrate = ft.symbol_rate; 113 tuning.fec = ft.fec_inner; 113 114 } 114 115 115 116 mplexid = GetMultiplexIdFromDB(); … … 283 284 { 284 285 // United Kingdom 285 286 fmap["dvbt_ofdm_uk0"] = new FrequencyTable( 286 474000000, 850000000, 8000000, "" , 0, DTVInversion::kInversionOff, 287 474000000, 850000000, 8000000, "Channel %1", 21, 288 DTVInversion::kInversionOff, 287 289 DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto, 288 290 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 289 291 DTVTransmitMode::kTransmissionMode2K, … … 292 294 293 295 // Finland 294 296 fmap["dvbt_ofdm_fi0"] = new FrequencyTable( 295 474000000, 850000000, 8000000, "", 0, DTVInversion::kInversionOff, 297 474000000, 850000000, 8000000, "Channel %1", 21, 298 DTVInversion::kInversionOff, 296 299 DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto, 297 300 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64, 298 301 DTVTransmitMode::kTransmissionModeAuto, … … 301 304 302 305 // Sweden 303 306 fmap["dvbt_ofdm_se0"] = new FrequencyTable( 304 474000000, 850000000, 8000000, "", 0, DTVInversion::kInversionOff, 307 474000000, 850000000, 8000000, "Channel %1", 21, 308 DTVInversion::kInversionOff, 305 309 DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto, 306 310 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64, 307 311 DTVTransmitMode::kTransmissionModeAuto, … … 310 314 311 315 // Australia 312 316 fmap["dvbt_ofdm_au0"] = new FrequencyTable( 313 177500000, 226500000, 7000000, "", 0, DTVInversion::kInversionOff, 317 177500000, 226500000, 7000000, "Channel %1", 6, 318 DTVInversion::kInversionOff, 314 319 DTVBandwidth::kBandwidth7MHz, DTVCodeRate::kFECAuto, 315 320 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64, 316 DTVTransmitMode::kTransmissionMode8K, DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone, 321 DTVTransmitMode::kTransmissionMode8K, 322 DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone, 317 323 DTVModulation::kModulationQAMAuto, 125000, 0); // VHF 6-12 318 324 fmap["dvbt_ofdm_au1"] = new FrequencyTable( 319 529500000, 816500000, 7000000, "", 0, DTVInversion::kInversionOff, 325 529500000, 816500000, 7000000, "Channel %1", 28, 326 DTVInversion::kInversionOff, 320 327 DTVBandwidth::kBandwidth7MHz, DTVCodeRate::kFECAuto, 321 328 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAM64, 322 329 DTVTransmitMode::kTransmissionMode8K, … … 325 332 326 333 // Germany (Deuschland) 327 334 fmap["dvbt_ofdm_de0"] = new FrequencyTable( 328 177500000, 226500000, 7000000, "", 0, DTVInversion::kInversionOff, 335 177500000, 226500000, 7000000, "Channel %1", 6, 336 DTVInversion::kInversionOff, 329 337 DTVBandwidth::kBandwidth7MHz, DTVCodeRate::kFECAuto, 330 338 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 331 339 DTVTransmitMode::kTransmissionMode8K, 332 340 DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone, 333 DTVModulation::kModulationQAMAuto, 125000, 0); // VHF 6-12341 DTVModulation::kModulationQAMAuto, 0, 0); // VHF 6-12 334 342 fmap["dvbt_ofdm_de1"] = new FrequencyTable( 335 474000000, 826000000, 8000000, "", 0, DTVInversion::kInversionOff, 343 474000000, 826000000, 8000000, "Channel %1", 21, 344 DTVInversion::kInversionOff, 336 345 DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto, 337 346 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 338 347 DTVTransmitMode::kTransmissionModeAuto, 339 348 DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone, 340 DTVModulation::kModulationQAMAuto, 125000, 0); // UHF 21-65349 DTVModulation::kModulationQAMAuto, 0, 0); // UHF 21-65 341 350 342 351 // Spain 343 352 fmap["dvbt_ofdm_es0"] = new FrequencyTable( 344 474000000, 858000000, 8000000, "", 0, DTVInversion::kInversionOff, 353 474000000, 858000000, 8000000, "Channel %1", 21, 354 DTVInversion::kInversionOff, 345 355 DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto, 346 356 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 347 357 DTVTransmitMode::kTransmissionModeAuto, … … 350 360 351 361 // New Zealand 352 362 fmap["dvbt_ofdm_nz0"] = new FrequencyTable( 353 474000000, 858000000, 8000000, "", 0, DTVInversion::kInversionOff, 363 474000000, 858000000, 8000000, "Channel %1", 21, 364 DTVInversion::kInversionOff, 354 365 DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFEC_3_4, 355 366 DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAM64, 356 367 DTVTransmitMode::kTransmissionMode8K, … … 359 370 360 371 // france 361 372 fmap["dvbt_ofdm_fr0"] = new FrequencyTable( 362 474000000, 850000000, 8000000, "" , 0, DTVInversion::kInversionOff, 373 474000000, 850000000, 8000000, "Channel %1", 21, 374 DTVInversion::kInversionOff, 363 375 DTVBandwidth::kBandwidth8MHz, DTVCodeRate::kFECAuto, 364 376 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 365 377 DTVTransmitMode::kTransmissionMode8K, 366 378 DTVGuardInterval::kGuardIntervalAuto, DTVHierarchy::kHierarchyNone, 367 379 DTVModulation::kModulationQAMAuto, 167000, -166000); 368 380 381 // DVB-C Germany 382 fmap["dvbc_qam_de0"] = new FrequencyTable( 383 73000000, 73000000, 8000000, "Channel D%1", 73, 384 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 385 6900000, 0, 0); 386 fmap["dvbc_qam_de1"] = new FrequencyTable( 387 81000000, 81000000, 8000000, "Channel D%1", 81, 388 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 389 6900000, 0, 0); 390 fmap["dvbc_qam_de2"] = new FrequencyTable( 391 113000000, 121000000, 8000000, "Channel S0%1", 2, 392 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 393 6900000, 0, 0); 394 fmap["dvbc_qam_de3"] = new FrequencyTable( 395 306000000, 466000000, 8000000, "Channel S%1", 21, 396 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 397 6900000, 0, 0); 398 fmap["dvbc_qam_de4"] = new FrequencyTable( 399 474000000, 858000000, 8000000, "Channel %1", 21, 400 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 401 6900000, 0, 0); 402 403 fmap["dvbc_qam_uk0"] = new FrequencyTable( 404 12324000, 12324000+1, 10, "Channel %1", 1, 405 DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAMAuto, 406 29500000, 0, 0); 407 fmap["dvbc_qam_uk1"] = new FrequencyTable( 408 459000000, 459000000+1, 10, "Channel %1", 2, 409 DTVCodeRate::kFEC_3_4, DTVModulation::kModulationQAM64, 410 6952000, 0, 0); 411 412 fmap["dvbc_qam_bf0"] = new FrequencyTable( 413 203000000, 795000000, 100000, "BF Channel %1", 1, 414 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 415 6900000, 0, 0); 416 fmap["dvbc_qam_bf1"] = new FrequencyTable( 417 194750000, 794750000, 100000, "BF Channel %1", 1 + (795000-203000) / 100, 418 DTVCodeRate::kFECAuto, DTVModulation::kModulationQAMAuto, 419 6900000, 0, 0); 420 369 421 //#define DEBUG_DVB_OFFSETS 370 422 #ifdef DEBUG_DVB_OFFSETS 371 423 // UHF 14-69 -
libs/libmythtv/scanwizard.cpp
29 29 * 30 30 */ 31 31 32 #include "scanwizard helpers.h"33 #include " scanwizardscanner.h"32 #include "scanwizardconfig.h" 33 #include "channelscanner_gui.h" 34 34 #include "scanwizard.h" 35 35 #include "sourceutil.h" 36 36 #include "cardutil.h" 37 37 #include "videosource.h" 38 #include "scaninfo.h" 39 #include "channelimporter.h" 38 40 #include "mythverbose.h" 39 41 40 42 #define LOC QString("SWiz: ") … … 47 49 lastHWCardType(CardUtil::ERROR_PROBE), 48 50 configPane(new ScanWizardConfig( 49 51 this, default_sourceid, default_cardid, default_inputname)), 50 scannerPane(new ScanWizardScanner())52 scannerPane(new ChannelScannerGUI()) 51 53 { 52 54 addChild(configPane); 53 55 addChild(scannerPane); … … 66 68 67 69 void ScanWizard::SetPage(const QString &pageTitle) 68 70 { 69 VERBOSE(VB_ SIPARSER, QString("SetPage(%1)").arg(pageTitle));70 if (pageTitle != ScanWizardScanner::kTitle)71 VERBOSE(VB_CHANSCAN, QString("SetPage(%1)").arg(pageTitle)); 72 if (pageTitle != ChannelScannerGUI::kTitle) 71 73 return; 72 74 73 75 QMap<QString,QString> start_chan; … … 79 81 int scantype = configPane->GetScanType(); 80 82 bool do_scan = true; 81 83 82 VERBOSE(VB_ SIPARSER, LOC + "SetPage(): " +84 VERBOSE(VB_CHANSCAN, LOC + "SetPage(): " + 83 85 QString("type(%1) cardid(%2) inputname(%3)") 84 86 .arg(scantype).arg(cardid).arg(inputname)); 85 87 … … 88 90 scannerPane->ImportDVBUtils(sourceid, lastHWCardType, 89 91 configPane->GetFilename()); 90 92 } 91 else if (scantype == ScanTypeSetting::NITAddScan_ OFDM)93 else if (scantype == ScanTypeSetting::NITAddScan_DVBT) 92 94 { 93 95 start_chan = configPane->GetStartChan(); 94 96 parse_type = DTVTunerType::kTunerTypeOFDM; 95 97 } 96 else if (scantype == ScanTypeSetting::NITAddScan_ QPSK)98 else if (scantype == ScanTypeSetting::NITAddScan_DVBS) 97 99 { 98 100 start_chan = configPane->GetStartChan(); 99 101 parse_type = DTVTunerType::kTunerTypeQPSK; 100 102 } 101 else if (scantype == ScanTypeSetting::NITAddScan_ QAM)103 else if (scantype == ScanTypeSetting::NITAddScan_DVBC) 102 104 { 103 105 start_chan = configPane->GetStartChan(); 104 106 parse_type = DTVTunerType::kTunerTypeQAM; … … 111 113 else if ((scantype == ScanTypeSetting::FullScan_ATSC) || 112 114 (scantype == ScanTypeSetting::FullTransportScan) || 113 115 (scantype == ScanTypeSetting::TransportScan) || 114 (scantype == ScanTypeSetting::FullScan_ OFDM) ||116 (scantype == ScanTypeSetting::FullScan_DVBT) || 115 117 (scantype == ScanTypeSetting::FullScan_Analog)) 116 118 { 117 119 ; 118 120 } 121 else if (scantype == ScanTypeSetting::ExistingScanImport) 122 { 123 do_scan = false; 124 uint scanid = configPane->GetScanID(); 125 ScanDTVTransportList transports = LoadScan(scanid); 126 ChannelImporter ci(true, true, true, false); 127 ci.Process(transports); 128 } 119 129 else 120 130 { 121 131 do_scan = false; 122 VERBOSE(VB_ SIPARSER, LOC_ERR + "SetPage(): " +132 VERBOSE(VB_CHANSCAN, LOC_ERR + "SetPage(): " + 123 133 QString("type(%1) src(%2) cardid(%3) not handled") 124 134 .arg(scantype).arg(sourceid).arg(cardid)); 125 135 … … 150 160 151 161 if (do_scan) 152 162 { 163 QString table_start, table_end; 164 configPane->GetFrequencyTableRange(table_start, table_end); 165 153 166 scannerPane->Scan( 154 167 configPane->GetScanType(), configPane->GetCardID(), 155 168 configPane->GetInputName(), configPane->GetSourceID(), 156 configPane->DoDeleteChannels(), configPane->DoRenameChannels(),169 /*configPane->DoDeleteChannels(),configPane->DoRenameChannels(),*/ 157 170 configPane->DoIgnoreSignalTimeout(), configPane->GetMultiplex(), 158 171 start_chan, 159 172 configPane->GetFrequencyStandard(), configPane->GetModulation(), 160 configPane->GetFrequencyTable(), configPane->GetATSCFormat()); 173 configPane->GetFrequencyTable()/*,configPane->GetATSCFormat()*/, 174 table_start, table_end); 161 175 } 162 176 } 163 177 … … 177 191 lastHWCardID = cardid; 178 192 QString subtype = CardUtil::ProbeSubTypeName(cardid); 179 193 lastHWCardType = CardUtil::toCardType(subtype); 180 configPane->SetDefaultATSCFormat(181 SourceUtil::GetChannelFormat(configPane->GetSourceID()));182 194 } 183 195 } -
libs/libmythtv/scanwizardscanner.h
1 /* -*- Mode: c++ -*-2 * vim: set expandtab tabstop=4 shiftwidth=4:3 *4 * Original Project5 * MythTV http://www.mythtv.org6 *7 * Author(s):8 * John Pullan (john@pullan.org)9 *10 * Description:11 * Collection of classes to provide dvb channel scanning12 * functionallity13 *14 *15 * This program is free software; you can redistribute it and/or16 * modify it under the terms of the GNU General Public License17 * as published by the Free Software Foundation; either version 218 * of the License, or (at your option) any later version.19 *20 * This program is distributed in the hope that it will be useful,21 * but WITHOUT ANY WARRANTY; without even the implied warranty of22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the23 * GNU General Public License for more details.24 *25 * You should have received a copy of the GNU General Public License26 * along with this program; if not, write to the Free Software27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.28 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html29 *30 */31 32 #ifndef _SCANWIZARDSCANNER_H_33 #define _SCANWIZARDSCANNER_H_34 35 // Standard UNIX C headers36 #include <pthread.h>37 38 // Qt headers39 #include <qstring.h>40 #include <QEvent>41 42 // MythTV headers43 #include "settings.h"44 #include "dtvconfparser.h"45 #include "signalmonitorlistener.h"46 47 class ScanWizard;48 class AnalogScan;49 class IPTVChannelFetcher;50 class LogList;51 class SIScan;52 class ScanProgressPopup;53 54 class ChannelBase;55 class V4LChannel;56 class DVBChannel;57 class SignalMonitorValue;58 59 class ScanWizardScanner :60 public VerticalConfigurationGroup,61 public DVBSignalMonitorListener62 {63 Q_OBJECT64 65 friend void *spawn_popup(void*);66 67 public:68 ScanWizardScanner(void);69 virtual void deleteLater(void)70 { Teardown(); VerticalConfigurationGroup::deleteLater(); }71 72 void Scan(int scantype,73 uint cardid,74 const QString &inputname,75 uint sourceid,76 bool do_delete_channels,77 bool do_rename_channels,78 bool do_ignore_signal_timeout,79 // stuff needed for particular scans80 uint mplexid,81 const QMap<QString,QString> &startChan,82 const QString &freq_std,83 const QString &mod,84 const QString &tbl,85 const QString &atsc_format);86 87 void ImportDVBUtils(uint sourceid, int cardtype, const QString &file);88 void ImportM3U( uint cardid, const QString &inputname, uint sourceid);89 90 // SignalMonitorListener91 virtual void AllGood(void) { }92 virtual void StatusSignalLock(const SignalMonitorValue&);93 virtual void StatusSignalStrength(const SignalMonitorValue&);94 95 // DVBSignalMonitorListener96 virtual void StatusSignalToNoise(const SignalMonitorValue&);97 virtual void StatusBitErrorRate(const SignalMonitorValue&) { }98 virtual void StatusUncorrectedBlocks(const SignalMonitorValue&) { }99 virtual void StatusRotorPosition(const SignalMonitorValue&) { }100 101 protected slots:102 void CancelScan(void) { Teardown(); }103 void scanComplete(void);104 void transportScanComplete(void);105 void updateText(const QString& status);106 void updateStatusText(const QString& status);107 108 void serviceScanPctComplete(int pct);109 110 protected:111 ~ScanWizardScanner();112 void Teardown(void);113 114 void PreScanCommon(int scantype, uint cardid,115 const QString &inputname,116 uint sourceid, bool do_ignore_signal_timeout);117 118 void dvbLock(int);119 void dvbSNR(int);120 void dvbSignalStrength(int);121 void customEvent(QEvent *e);122 123 void MonitorProgress(bool lock, bool strength, bool snr);124 void RunPopup(void);125 void StopPopup(void);126 127 public:128 static QString kTitle;129 130 private:131 LogList *log;132 ChannelBase *channel;133 134 ScanProgressPopup *popupProgress;135 pthread_t popup_thread;136 mutable QMutex popupLock;137 138 SIScan *scanner;139 IPTVChannelFetcher *freeboxScanner;140 141 uint nVideoSource;142 143 // dvb-utils imported channels144 DTVChannelList channels;145 };146 147 #endif // _SCANWIZARDSCANNER_H_148 -
libs/libmythtv/iptv/iptvchannelfetcher.cpp
15 15 #include "cardutil.h" 16 16 #include "channelutil.h" 17 17 #include "iptvchannelfetcher.h" 18 #include "scanmonitor.h" 18 19 19 20 #define LOC QString("IPTVChanFetch: ") 20 21 #define LOC_ERR QString("IPTVChanFetch, Error: ") … … 38 39 } 39 40 40 41 IPTVChannelFetcher::IPTVChannelFetcher( 41 uint cardid, const QString &inputname, uint sourceid) : 42 uint cardid, const QString &inputname, uint sourceid, 43 ScanMonitor *monitor) : 44 _scan_monitor(monitor), 42 45 _cardid(cardid), _inputname(inputname), 43 46 _sourceid(sourceid), 44 47 _chan_cnt(1), _thread_running(false), … … 115 118 VERBOSE(VB_CHANNEL, QString("Playlist URL: %1").arg(url)); 116 119 117 120 // Step 2/4 : Download 118 emit ServiceScanPercentComplete(5); 119 emit ServiceScanUpdateText(tr("Downloading Playlist")); 121 if (_scan_monitor) 122 { 123 _scan_monitor->ScanPercentComplete(5); 124 _scan_monitor->ScanAppendTextToLog(QObject::tr("Downloading Playlist")); 125 } 120 126 121 127 QString playlist = DownloadPlaylist(url, true); 122 128 … … 127 133 } 128 134 129 135 // Step 3/4 : Process 130 emit ServiceScanPercentComplete(35); 131 emit ServiceScanUpdateText(tr("Processing Playlist")); 136 if (_scan_monitor) 137 { 138 _scan_monitor->ScanPercentComplete(35); 139 _scan_monitor->ScanAppendTextToLog(QObject::tr("Processing Playlist")); 140 } 132 141 133 142 const fbox_chan_map_t channels = ParsePlaylist(playlist, this); 134 143 135 144 // Step 4/4 : Finish up 136 emit ServiceScanUpdateText(tr("Adding Channels")); 145 if (_scan_monitor) 146 _scan_monitor->ScanAppendTextToLog(QObject::tr("Adding Channels")); 137 147 SetTotalNumChannels(channels.size()); 138 148 fbox_chan_map_t::const_iterator it = channels.begin(); 139 149 for (uint i = 1; it != channels.end(); ++it, ++i) … … 141 151 QString channum = it.key(); 142 152 QString name = (*it).m_name; 143 153 QString xmltvid = (*it).m_xmltvid.isEmpty() ? "" : (*it).m_xmltvid; 144 QString msg =tr("Channel #%1 : %2").arg(channum).arg(name);154 QString msg = QObject::tr("Channel #%1 : %2").arg(channum).arg(name); 145 155 146 156 int chanid = ChannelUtil::GetChanID(_sourceid, channum); 147 157 if (chanid <= 0) 148 158 { 149 emit ServiceScanUpdateText(tr("Adding %1").arg(msg)); 159 if (_scan_monitor) 160 { 161 _scan_monitor->ScanAppendTextToLog( 162 QObject::tr("Adding %1").arg(msg)); 163 } 150 164 chanid = ChannelUtil::CreateChanID(_sourceid, channum); 151 165 ChannelUtil::CreateChannel( 152 166 0, _sourceid, chanid, name, name, channum, … … 155 169 } 156 170 else 157 171 { 158 emit ServiceScanUpdateText(tr("Updating %1").arg(msg)); 172 if (_scan_monitor) 173 { 174 _scan_monitor->ScanAppendTextToLog( 175 QObject::tr("Updating %1").arg(msg)); 176 } 159 177 ChannelUtil::UpdateChannel( 160 178 0, _sourceid, chanid, name, name, channum, 161 179 0, 0, 0, false, false, false, QString::null, … … 165 183 SetNumChannelsInserted(i); 166 184 } 167 185 168 emit ServiceScanUpdateText(tr("Done")); 169 emit ServiceScanUpdateText(""); 170 emit ServiceScanPercentComplete(100); 171 emit ServiceScanComplete(); 186 if (_scan_monitor) 187 { 188 _scan_monitor->ScanAppendTextToLog(QObject::tr("Done")); 189 _scan_monitor->ScanAppendTextToLog(""); 190 _scan_monitor->ScanPercentComplete(100); 191 _scan_monitor->ScanComplete(); 192 } 172 193 173 194 _thread_running = false; 174 195 } … … 177 198 { 178 199 uint minval = 35, range = 70 - minval; 179 200 uint pct = minval + (uint) truncf((((float)val) / _chan_cnt) * range); 180 emit ServiceScanPercentComplete(pct); 201 if (_scan_monitor) 202 _scan_monitor->ScanPercentComplete(pct); 181 203 } 182 204 183 205 void IPTVChannelFetcher::SetNumChannelsInserted(uint val) 184 206 { 185 207 uint minval = 70, range = 100 - minval; 186 208 uint pct = minval + (uint) truncf((((float)val) / _chan_cnt) * range); 187 emit ServiceScanPercentComplete(pct); 209 if (_scan_monitor) 210 _scan_monitor->ScanPercentComplete(pct); 188 211 } 189 212 190 213 void IPTVChannelFetcher::SetMessage(const QString &status) 191 214 { 192 emit ServiceScanUpdateText(status); 215 if (_scan_monitor) 216 _scan_monitor->ScanAppendTextToLog(status); 193 217 } 194 218 195 219 QString IPTVChannelFetcher::DownloadPlaylist(const QString &url, … … 265 289 QString("Invalid channel list header (%1)").arg(header)); 266 290 267 291 if (fetcher) 268 fetcher->SetMessage(tr("ERROR: M3U channel list is malformed")); 292 { 293 fetcher->SetMessage( 294 QObject::tr("ERROR: M3U channel list is malformed")); 295 } 269 296 270 297 return chanmap; 271 298 } … … 290 317 if (!parse_chan_info(rawdata, info, channum, lineNum)) 291 318 break; 292 319 293 QString msg = tr("Encountered malformed channel");320 QString msg = QObject::tr("Encountered malformed channel"); 294 321 if (!channum.isEmpty()) 295 322 { 296 323 chanmap[channum] = info; 297 324 298 msg = tr("Parsing Channel #%1 : %2 : %3")325 msg = QObject::tr("Parsing Channel #%1 : %2 : %3") 299 326 .arg(channum).arg(info.m_name).arg(info.m_url); 300 327 VERBOSE(VB_CHANNEL, msg); 301 328 -
libs/libmythtv/iptv/iptvchannelfetcher.h
2 2 #define _IPTVCHANNELFETCHER_H_ 3 3 4 4 // Qt headers 5 #include < qobject.h>6 #include < qmutex.h>7 #include < qthread.h>5 #include <QObject> 6 #include <QMutex> 7 #include <QThread> 8 8 9 9 // MythTV headers 10 10 #include "iptvchannelinfo.h" 11 11 12 class ScanMonitor; 12 13 class IPTVChannelFetcher; 13 14 14 15 class IPTVChannelFetcherThread : public QThread … … 18 19 IPTVChannelFetcher *iptvfetcher; 19 20 }; 20 21 21 class IPTVChannelFetcher : public QObject22 class IPTVChannelFetcher 22 23 { 23 Q_OBJECT24 25 24 friend class IPTVChannelFetcherThread; 26 25 27 26 public: 28 IPTVChannelFetcher(uint cardid, const QString &inputname, uint sourceid); 27 IPTVChannelFetcher(uint cardid, const QString &inputname, uint sourceid, 28 ScanMonitor *monitor = NULL); 29 ~IPTVChannelFetcher(); 29 30 30 31 bool Scan(void); 31 32 void Stop(void); … … 34 35 static fbox_chan_map_t ParsePlaylist( 35 36 const QString &rawdata, IPTVChannelFetcher *fetcher = NULL); 36 37 37 signals:38 /** \brief Tells listener how far along we are from 0..100%39 * \param p percentage completion40 */41 void ServiceScanPercentComplete(int p);42 /// \brief Returns tatus message from the scanner43 void ServiceScanUpdateText(const QString &status);44 /// \brief Signals that the scan is complete45 void ServiceScanComplete(void);46 47 protected:48 void RunScan(void);49 50 38 private: 51 ~IPTVChannelFetcher();52 39 void SetTotalNumChannels(uint val) { _chan_cnt = (val) ? val : 1; } 53 40 void SetNumChannelsParsed(uint); 54 41 void SetNumChannelsInserted(uint); 55 42 void SetMessage(const QString &status); 56 43 44 protected: 45 void RunScan(void); 46 57 47 private: 48 ScanMonitor *_scan_monitor; 58 49 uint _cardid; 59 50 QString _inputname; 60 51 uint _sourceid; -
libs/libmythtv/scanwizardhelpers.cpp
1 /* -*- Mode: c++ -*-2 * $Id$3 * vim: set expandtab tabstop=4 shiftwidth=4:4 *5 * Original Project6 * MythTV http://www.mythtv.org7 *8 * Author(s):9 * John Pullan (john@pullan.org)10 *11 * Description:12 * Collection of classes to provide dvb channel scanning13 * functionallity14 *15 *16 * This program is free software; you can redistribute it and/or17 * modify it under the terms of the GNU General Public License18 * as published by the Free Software Foundation; either version 219 * of the License, or (at your option) any later version.20 *21 * This program is distributed in the hope that it will be useful,22 * but WITHOUT ANY WARRANTY; without even the implied warranty of23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the24 * GNU General Public License for more details.25 *26 * You should have received a copy of the GNU General Public License27 * along with this program; if not, write to the Free Software28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.29 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html30 *31 */32 33 // Qt headers34 #include <QApplication>35 #include <QLocale>36 37 // MythTV headers38 #include "mythcontext.h"39 #include "mythdb.h"40 #include "mythverbose.h"41 #include "frequencies.h"42 #include "videosource.h"43 #include "cardutil.h"44 #include "sourceutil.h"45 #include "scanwizardhelpers.h"46 #include "scanwizardscanner.h"47 #include "scanwizard.h"48 49 static QString card_types(void)50 {51 QString cardTypes = "";52 53 #ifdef USING_DVB54 cardTypes += "'DVB'";55 #endif // USING_DVB56 57 #ifdef USING_V4L58 if (!cardTypes.isEmpty())59 cardTypes += ",";60 cardTypes += "'V4L'";61 # ifdef USING_IVTV62 cardTypes += ",'MPEG'";63 # endif // USING_IVTV64 # ifdef USING_HDPVR65 cardTypes += ",'HDPVR'";66 # endif // USING_HDPVR67 #endif // USING_V4L68 69 #ifdef USING_IPTV70 if (!cardTypes.isEmpty())71 cardTypes += ",";72 cardTypes += "'FREEBOX'";73 #endif // USING_IPTV74 75 #ifdef USING_HDHOMERUN76 if (!cardTypes.isEmpty())77 cardTypes += ",";78 cardTypes += "'HDHOMERUN'";79 #endif // USING_HDHOMERUN80 81 if (cardTypes.isEmpty())82 cardTypes = "'DUMMY'";83 84 return QString("(%1)").arg(cardTypes);85 }86 87 ScanProgressPopup::ScanProgressPopup(bool lock, bool strength, bool snr) :88 ConfigurationPopupDialog(),89 done(false), ss(NULL), sn(NULL), progressBar(NULL), sl(NULL), sta(NULL)90 {91 setLabel(tr("Scan Progress"));92 93 addChild(sta = new TransLabelSetting());94 sta->setLabel(tr("Status"));95 sta->setValue(tr("Tuning"));96 97 if (lock)98 {99 addChild(sl = new TransLabelSetting());100 sl->setValue(" "101 " ");102 }103 104 if (strength)105 {106 addChild(ss = new ScanSignalMeter(65535));107 ss->setLabel(tr("Signal Strength"));108 }109 110 if (snr)111 {112 addChild(sn = new ScanSignalMeter(65535));113 sn->setLabel(tr("Signal/Noise"));114 }115 116 addChild(progressBar = new ScanSignalMeter(65535));117 progressBar->setValue(0);118 progressBar->setLabel(tr("Scan"));119 120 121 TransButtonSetting *cancel = new TransButtonSetting();122 cancel->setLabel(tr("Cancel"));123 addChild(cancel);124 125 connect(cancel, SIGNAL(pressed(void)),126 this, SLOT( reject(void)));127 128 //Seem to need to do this as the constructor doesn't seem enough129 setUseLabel(false);130 setUseFrame(false);131 }132 133 ScanProgressPopup::~ScanProgressPopup()134 {135 VERBOSE(VB_SIPARSER, "~ScanProgressPopup()");136 }137 138 void ScanProgressPopup::SetStatusSignalToNoise(int value)139 {140 if (sn)141 sn->setValue(value);142 }143 144 void ScanProgressPopup::SetStatusSignalStrength(int value)145 {146 if (ss)147 ss->setValue(value);148 }149 150 void ScanProgressPopup::SetStatusLock(int value)151 {152 if (sl)153 sl->setValue((value) ? tr("Locked") : tr("No Lock"));154 }155 156 void ScanProgressPopup::SetScanProgress(double value)157 {158 if (progressBar)159 progressBar->setValue((uint)(value * 65535));160 }161 162 void ScanProgressPopup::SetStatusText(const QString &value)163 {164 if (sta)165 sta->setValue(value);166 }167 168 void ScanProgressPopup::SetStatusTitleText(const QString &value)169 {170 QString msg = tr("Scan Progress") + QString(" %1").arg(value);171 setLabel(msg);172 }173 174 void ScanProgressPopup::deleteLater(void)175 {176 disconnect();177 if (dialog)178 {179 VERBOSE(VB_IMPORTANT, "Programmer Error: "180 "ScanProgressPopup::DeleteDialog() never called.");181 }182 ConfigurationPopupDialog::deleteLater();183 }184 185 void ScanProgressPopup::CreateDialog(void)186 {187 if (!dialog)188 {189 dialog = (ConfigPopupDialogWidget*)190 dialogWidget(gContext->GetMainWindow(),191 "ConfigurationPopupDialog");192 dialog->ShowPopup(this, SLOT(Done(void)));193 }194 }195 196 void ScanProgressPopup::DeleteDialog(void)197 {198 if (dialog)199 {200 dialog->deleteLater();201 dialog = NULL;202 }203 }204 205 DialogCode ScanProgressPopup::exec(void)206 {207 if (!dialog)208 {209 dialog = (ConfigPopupDialogWidget*)210 dialogWidget(gContext->GetMainWindow(),211 "ConfigurationPopupDialog");212 }213 214 dialog->setResult(kDialogCodeRejected);215 216 done = false;217 218 // Qt4 requires a QMutex as a parameter...219 // not sure if this is the best solution. Mutex Must be locked before wait.220 QMutex mutex;221 QMutexLocker locker(&mutex);222 223 while (!done)224 wait.wait(&mutex, 100);225 226 return dialog->result();227 }228 229 void ScanProgressPopup::Done(void)230 {231 done = true;232 wait.wakeAll();233 }234 235 void post_event(QObject *dest, ScannerEvent::TYPE type, int val)236 {237 ScannerEvent *e = new ScannerEvent(type);238 e->intValue(val);239 QApplication::postEvent(dest, e);240 }241 242 void post_event(QObject *dest, ScannerEvent::TYPE type, const QString &val)243 {244 ScannerEvent *e = new ScannerEvent(type);245 QString tmp = val; tmp.detach();246 e->strValue(tmp);247 QApplication::postEvent(dest, e);248 }249 250 void post_event(QObject *dest, ScannerEvent::TYPE type, int val,251 ScanProgressPopup *spp)252 {253 ScannerEvent *e = new ScannerEvent(type);254 e->intValue(val);255 e->ScanProgressPopupValue(spp);256 QApplication::postEvent(dest, e);257 }258 259 void MultiplexSetting::Load(void)260 {261 clearSelections();262 263 if (!sourceid)264 return;265 266 MSqlQuery query(MSqlQuery::InitCon());267 268 query.prepare(269 "SELECT mplexid, networkid, transportid, "270 " frequency, symbolrate, modulation "271 "FROM dtv_multiplex "272 "WHERE sourceid = :SOURCEID "273 "ORDER by frequency, networkid, transportid");274 query.bindValue(":SOURCEID", sourceid);275 276 if (!query.exec() || !query.isActive() || query.size() <= 0)277 return;278 279 while (query.next())280 {281 QString DisplayText;282 if (query.value(5).toString() == "8vsb")283 {284 QString ChannelNumber =285 QString("Freq %1").arg(query.value(3).toInt());286 struct CHANLIST* curList = chanlists[0].list;287 int totalChannels = chanlists[0].count;288 int findFrequency = (query.value(3).toInt() / 1000) - 1750;289 for (int x = 0 ; x < totalChannels ; x++)290 {291 if ((curList[x].freq <= findFrequency + 200) &&292 (curList[x].freq >= findFrequency - 200))293 {294 ChannelNumber = QString("%1").arg(curList[x].name);295 }296 }297 DisplayText = QObject::tr("ATSC Channel %1").arg(ChannelNumber);298 }299 else300 {301 DisplayText = QString("%1 Hz (%2) (%3) (%4)")302 .arg(query.value(3).toString())303 .arg(query.value(4).toString())304 .arg(query.value(1).toInt())305 .arg(query.value(2).toInt());306 }307 addSelection(DisplayText, query.value(0).toString());308 }309 }310 311 void MultiplexSetting::SetSourceID(uint _sourceid)312 {313 sourceid = _sourceid;314 Load();315 }316 317 InputSelector::InputSelector(318 uint _default_cardid, const QString &_default_inputname) :319 ComboBoxSetting(this), sourceid(0), default_cardid(_default_cardid),320 default_inputname(_default_inputname)321 {322 default_inputname.detach();323 setLabel(tr("Input"));324 }325 326 void InputSelector::Load(void)327 {328 clearSelections();329 330 if (!sourceid)331 return;332 333 MSqlQuery query(MSqlQuery::InitCon());334 query.prepare(335 "SELECT capturecard.cardid, cardtype, videodevice, inputname "336 "FROM capturecard, cardinput, videosource "337 "WHERE cardinput.sourceid = videosource.sourceid AND "338 " hostname = :HOSTNAME AND "339 " cardinput.sourceid = :SOURCEID AND "340 " cardinput.cardid = capturecard.cardid");341 342 query.bindValue(":HOSTNAME", gContext->GetHostName());343 query.bindValue(":SOURCEID", sourceid);344 345 if (!query.exec() || !query.isActive())346 {347 MythDB::DBError("InputSelector::Load()", query);348 return;349 }350 351 uint which = 0, cnt = 0;352 for (; query.next(); cnt++)353 {354 uint cardid = query.value(0).toUInt();355 QString inputname = query.value(3).toString();356 357 QString desc = CardUtil::GetDeviceLabel(358 cardid, query.value(1).toString(), query.value(2).toString());359 360 desc += QString(" (%1)").arg(inputname);361 362 QString key = QString("%1:%2").arg(cardid).arg(inputname);363 364 addSelection(desc, key);365 366 which = (default_cardid == cardid) ? cnt : which;367 }368 369 if (cnt)370 setValue(which);371 }372 373 void InputSelector::SetSourceID(const QString &_sourceid)374 {375 if (sourceid != _sourceid.toUInt())376 {377 sourceid = _sourceid.toUInt();378 Load();379 }380 }381 382 uint InputSelector::GetCardID(void) const383 {384 uint cardid = 0;385 QString inputname = QString::null;386 387 Parse(getValue(), cardid, inputname);388 389 return cardid;390 }391 392 QString InputSelector::GetInputName(void) const393 {394 uint cardid = 0;395 QString inputname = QString::null;396 397 Parse(getValue(), cardid, inputname);398 399 return inputname;400 }401 402 bool InputSelector::Parse(const QString &cardid_inputname,403 uint &cardid,404 QString &inputname)405 {406 cardid = 0;407 inputname = QString::null;408 409 int sep0 = cardid_inputname.indexOf(':');410 if (sep0 < 1)411 return false;412 413 cardid = cardid_inputname.left(sep0).toUInt();414 inputname = cardid_inputname.mid(sep0 + 1);415 416 return true;417 }418 419 void ScanTypeSetting::SetInput(const QString &cardids_inputname)420 {421 uint cardid = 0;422 QString inputname = QString::null;423 if (!InputSelector::Parse(cardids_inputname, cardid, inputname))424 return;425 426 // Only refresh if we really have to. If we do it too often427 // Then we end up fighting the scan routine when we want to428 // check the type of dvb card :/429 if (cardid == hw_cardid)430 return;431 432 hw_cardid = cardid;433 QString subtype = CardUtil::ProbeSubTypeName(hw_cardid);434 int nCardType = CardUtil::toCardType(subtype);435 clearSelections();436 437 bool importConf = false;438 439 switch (nCardType)440 {441 case CardUtil::V4L:442 case CardUtil::MPEG:443 addSelection(tr("Full Scan"),444 QString::number(FullScan_Analog), true);445 return;446 case CardUtil::OFDM:447 addSelection(tr("Full Scan"),448 QString::number(FullScan_OFDM), true);449 addSelection(tr("Full Scan (Tuned)"),450 QString::number(NITAddScan_OFDM));451 importConf = true;452 break;453 case CardUtil::QPSK:454 addSelection(tr("Full Scan (Tuned)"),455 QString::number(NITAddScan_QPSK));456 importConf = true;457 break;458 case CardUtil::QAM:459 addSelection(tr("Full Scan (Tuned)"),460 QString::number(NITAddScan_QAM));461 importConf = true;462 break;463 case CardUtil::ATSC:464 addSelection(tr("Full Scan"),465 QString::number(FullScan_ATSC), true);466 importConf = true;467 break;468 case CardUtil::HDHOMERUN:469 addSelection(tr("Full Scan (ATSC)"),470 QString::number(FullScan_ATSC), true);471 addSelection(tr("Full Scan (DVB)"),472 QString::number(FullScan_OFDM), true);473 addSelection(tr("Full Scan (DVB, tuned)"),474 QString::number(NITAddScan_OFDM));475 importConf = true;476 break;477 case CardUtil::FREEBOX:478 addSelection(tr("M3U Import"),479 QString::number(IPTVImport), true);480 return;481 case CardUtil::ERROR_PROBE:482 addSelection(QObject::tr("Failed to probe the card"),483 QString::number(Error_Probe), true);484 return;485 default:486 addSelection(QObject::tr("Failed to open the card"),487 QString::number(Error_Open), true);488 return;489 }490 491 if (importConf)492 addSelection(tr("Import channels.conf"),493 QString::number(DVBUtilsImport));494 495 addSelection(tr("Full Scan of Existing Transports"),496 QString::number(FullTransportScan));497 addSelection(tr("Existing Transport Scan"),498 QString::number(TransportScan));499 }500 501 ScanCountry::ScanCountry() : ComboBoxSetting(this)502 {503 Country country = AU;504 QLocale locale = QLocale::system();505 QLocale::Country qtcountry = locale.country();506 if (qtcountry == QLocale::Australia)507 country = AU;508 else if (qtcountry == QLocale::Germany)509 country = DE;510 else if (qtcountry == QLocale::Finland)511 country = FI;512 else if (qtcountry == QLocale::Sweden)513 country = SE;514 else if (qtcountry == QLocale::UnitedKingdom)515 country = UK;516 else if (qtcountry == QLocale::Spain)517 country = ES;518 else if (qtcountry == QLocale::NewZealand)519 country = NZ;520 else if (qtcountry == QLocale::France)521 country = FR;522 523 setLabel(tr("Country"));524 addSelection(QObject::tr("Australia"), "au", country == AU);525 addSelection(QObject::tr("Finland"), "fi", country == FI);526 addSelection(QObject::tr("Sweden"), "se", country == SE);527 addSelection(QObject::tr("United Kingdom"), "uk", country == UK);528 addSelection(QObject::tr("Germany"), "de", country == DE);529 addSelection(QObject::tr("Spain"), "es", country == ES);530 addSelection(QObject::tr("New Zealand"), "nz", country == NZ);531 addSelection(QObject::tr("France"), "fr", country == FR);532 }533 534 AnalogPane::AnalogPane() :535 VerticalConfigurationGroup(false, false, true, false),536 freq_table(new TransFreqTableSelector(0)),537 old_channel_treatment(new ScanOldChannelTreatment(false))538 {539 addChild(freq_table);540 addChild(old_channel_treatment);541 }542 543 void AnalogPane::SetSourceID(uint sourceid)544 {545 freq_table->SetSourceID(sourceid);546 }547 548 QString AnalogPane::GetFrequencyTable(void) const549 {550 return freq_table->getValue();551 }552 553 ScanOptionalConfig::ScanOptionalConfig(ScanTypeSetting *_scan_type) :554 TriggeredConfigurationGroup(false, false, true, true,555 false, false, true, true),556 scanType(_scan_type),557 country(new ScanCountry()),558 ignoreSignalTimeoutAll(new IgnoreSignalTimeout()),559 paneOFDM(new OFDMPane()), paneQPSK(new QPSKPane()),560 paneDVBS2(new DVBS2Pane()), paneATSC(new ATSCPane()),561 paneQAM(new QAMPane()), paneAnalog(new AnalogPane()),562 paneSingle(new STPane()),563 paneDVBUtilsImport(new DVBUtilsImportPane())564 {565 setTrigger(scanType);566 567 // only save settings for the selected pane568 setSaveAll(false);569 570 // There need to be two IgnoreSignalTimeout instances571 // because otherwise Qt will free the one instance twice..572 573 // There need to be two IgnoreSignalTimeout instances574 // because otherwise Qt will free the one instance twice..575 VerticalConfigurationGroup *scanAllTransports =576 new VerticalConfigurationGroup(false,false,true,true);577 scanAllTransports->addChild(ignoreSignalTimeoutAll);578 579 addTarget(QString::number(ScanTypeSetting::Error_Open),580 new ErrorPane(QObject::tr("Failed to open the card")));581 addTarget(QString::number(ScanTypeSetting::Error_Probe),582 new ErrorPane(QObject::tr("Failed to probe the card")));583 addTarget(QString::number(ScanTypeSetting::NITAddScan_QAM),584 paneQAM);585 addTarget(QString::number(ScanTypeSetting::NITAddScan_QPSK),586 paneQPSK);587 addTarget(QString::number(ScanTypeSetting::NITAddScan_OFDM),588 paneOFDM);589 addTarget(QString::number(ScanTypeSetting::FullScan_ATSC),590 paneATSC);591 addTarget(QString::number(ScanTypeSetting::FullScan_OFDM),592 country);593 addTarget(QString::number(ScanTypeSetting::FullScan_Analog),594 paneAnalog);595 addTarget(QString::number(ScanTypeSetting::TransportScan),596 paneSingle);597 addTarget(QString::number(ScanTypeSetting::FullTransportScan),598 scanAllTransports);599 addTarget(QString::number(ScanTypeSetting::IPTVImport),600 new BlankSetting());601 addTarget(QString::number(ScanTypeSetting::DVBUtilsImport),602 paneDVBUtilsImport);603 }604 605 void ScanOptionalConfig::triggerChanged(const QString& value)606 {607 TriggeredConfigurationGroup::triggerChanged(value);608 }609 610 void ScanOptionalConfig::SetSourceID(const QString &sourceid)611 {612 paneAnalog->SetSourceID(sourceid.toUInt());613 paneSingle->SetSourceID(sourceid.toUInt());614 }615 616 void ScanOptionalConfig::SetDefaultATSCFormat(const QString &atscFormat)617 {618 paneATSC->SetDefaultATSCFormat(atscFormat);619 paneSingle->SetDefaultATSCFormat(atscFormat);620 paneDVBUtilsImport->SetDefaultATSCFormat(atscFormat);621 }622 623 QString ScanOptionalConfig::GetATSCFormat(const QString &dfl) const624 {625 int st = scanType->getValue().toInt();626 627 bool ts0 = (ScanTypeSetting::FullScan_ATSC == st);628 QString vl0 = paneATSC->GetATSCFormat();629 630 bool ts1 = (ScanTypeSetting::TransportScan == st);631 QString vl1 = paneSingle->GetATSCFormat();632 633 bool ts2 = (ScanTypeSetting::DVBUtilsImport == st);634 QString vl2 = paneDVBUtilsImport->GetATSCFormat();635 636 return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : dfl);637 }638 639 QString ScanOptionalConfig::GetFrequencyStandard(void) const640 {641 int st = scanType->getValue().toInt();642 643 bool ts0 = (ScanTypeSetting::FullScan_ATSC == st);644 bool ts1 = (ScanTypeSetting::FullScan_Analog == st);645 646 return (ts0) ? "atsc" : ((ts1) ? "analog" : "dvbt");647 }648 649 QString ScanOptionalConfig::GetModulation(void) const650 {651 int st = scanType->getValue().toInt();652 653 bool ts0 = (ScanTypeSetting::FullScan_ATSC == st);654 QString vl0 = paneATSC->atscModulation();655 656 bool ts1 = (ScanTypeSetting::FullScan_OFDM == st);657 QString vl1 = "ofdm";658 659 bool ts2 = (ScanTypeSetting::FullScan_Analog == st);660 QString vl2 = "analog";661 662 return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : "unknown");663 }664 665 QString ScanOptionalConfig::GetFrequencyTable(void) const666 {667 int st = scanType->getValue().toInt();668 669 bool ts0 = (ScanTypeSetting::FullScan_ATSC == st);670 QString vl0 = paneATSC->atscFreqTable();671 672 bool ts1 = (ScanTypeSetting::FullScan_OFDM == st);673 QString vl1 = country->getValue();674 675 bool ts2 = (ScanTypeSetting::FullScan_Analog == st);676 QString vl2 = paneAnalog->GetFrequencyTable();677 678 return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : "unknown");679 }680 681 bool ScanOptionalConfig::DoIgnoreSignalTimeout(void) const682 {683 int st = scanType->getValue().toInt();684 685 bool ts0 = (ScanTypeSetting::TransportScan == st);686 bool vl0 = paneSingle->ignoreSignalTimeout();687 688 bool ts1 = (ScanTypeSetting::FullTransportScan == st);689 bool vl1 = (ignoreSignalTimeoutAll->getValue().toInt());690 691 bool ts2 = (ScanTypeSetting::DVBUtilsImport == st);692 bool vl2 = paneDVBUtilsImport->DoIgnoreSignalTimeout();693 694 return (ts0) ? vl0 : ((ts1) ? vl1 : (ts2) ? vl2 : false);695 }696 697 bool ScanOptionalConfig::DoDeleteChannels(void) const698 {699 int st = scanType->getValue().toInt();700 701 bool ts0 = (ScanTypeSetting::FullScan_ATSC == st);702 bool vl0 = paneATSC->DoDeleteChannels();703 704 bool ts1 = (ScanTypeSetting::TransportScan == st);705 bool vl1 = paneSingle->DoDeleteChannels();706 707 bool ts2 = (ScanTypeSetting::DVBUtilsImport == st);708 bool vl2 = paneDVBUtilsImport->DoDeleteChannels();709 710 bool ts3 = (ScanTypeSetting::FullScan_Analog == st);711 bool vl3 = paneAnalog->DoDeleteChannels();712 713 return (ts0) ? vl0 : (((ts1) ? vl1 : (ts2) ? vl2 : (ts3) ? vl3 : false));714 }715 716 bool ScanOptionalConfig::DoRenameChannels(void) const717 {718 int st = scanType->getValue().toInt();719 720 bool ts0 = (ScanTypeSetting::FullScan_ATSC == st);721 bool vl0 = paneATSC->DoRenameChannels();722 723 bool ts1 = (ScanTypeSetting::TransportScan == st);724 bool vl1 = paneSingle->DoRenameChannels();725 726 bool ts2 = (ScanTypeSetting::DVBUtilsImport == st);727 bool vl2 = paneDVBUtilsImport->DoRenameChannels();728 729 bool ts3 = (ScanTypeSetting::FullScan_Analog == st);730 bool vl3 = paneAnalog->DoRenameChannels();731 732 return (ts0) ? vl0 : (((ts1) ? vl1 : (ts2) ? vl2 : (ts3) ? vl3 : false));733 }734 735 QString ScanOptionalConfig::GetFilename(void) const736 {737 return paneDVBUtilsImport->GetFilename();738 }739 740 uint ScanOptionalConfig::GetMultiplex(void) const741 {742 int mplexid = paneSingle->GetMultiplex();743 return (mplexid <= 0) ? 0 : mplexid;744 }745 746 QMap<QString,QString> ScanOptionalConfig::GetStartChan(void) const747 {748 QMap<QString,QString> startChan;749 750 int st = scanType->getValue().toInt();751 if (ScanTypeSetting::NITAddScan_OFDM == st)752 {753 const OFDMPane *pane = paneOFDM;754 755 startChan["std"] = "dvb";756 startChan["frequency"] = pane->frequency();757 startChan["inversion"] = pane->inversion();758 startChan["bandwidth"] = pane->bandwidth();759 startChan["modulation"] = "ofdm";760 startChan["coderate_hp"] = pane->coderate_hp();761 startChan["coderate_lp"] = pane->coderate_lp();762 startChan["constellation"] = pane->constellation();763 startChan["trans_mode"] = pane->trans_mode();764 startChan["guard_interval"] = pane->guard_interval();765 startChan["hierarchy"] = pane->hierarchy();766 }767 else if (ScanTypeSetting::NITAddScan_QPSK == st)768 {769 const QPSKPane *pane = paneQPSK;770 771 startChan["std"] = "dvb";772 startChan["frequency"] = pane->frequency();773 startChan["inversion"] = pane->inversion();774 startChan["symbolrate"] = pane->symbolrate();775 startChan["fec"] = pane->fec();776 startChan["modulation"] = "qpsk";777 startChan["polarity"] = pane->polarity();778 }779 else if (ScanTypeSetting::NITAddScan_QAM == st)780 {781 const QAMPane *pane = paneQAM;782 783 startChan["std"] = "dvb";784 startChan["frequency"] = pane->frequency();785 startChan["inversion"] = pane->inversion();786 startChan["symbolrate"] = pane->symbolrate();787 startChan["fec"] = pane->fec();788 startChan["modulation"] = pane->modulation();789 }790 791 return startChan;792 }793 794 ScanWizardConfig::ScanWizardConfig(795 ScanWizard *_parent,796 uint default_sourceid, uint default_cardid,797 QString default_inputname) :798 VerticalConfigurationGroup(false, true, false, false),799 videoSource(new VideoSourceSelector(800 default_sourceid, card_types(), false)),801 input(new InputSelector(default_cardid, default_inputname)),802 scanType(new ScanTypeSetting()),803 scanConfig(new ScanOptionalConfig(scanType))804 {805 setLabel(tr("Scan Configuration"));806 807 addChild(videoSource);808 addChild(input);809 addChild(scanType);810 addChild(scanConfig);811 812 connect(videoSource, SIGNAL(valueChanged(const QString&)),813 scanConfig, SLOT( SetSourceID( const QString&)));814 815 connect(videoSource, SIGNAL(valueChanged(const QString&)),816 input, SLOT( SetSourceID( const QString&)));817 818 connect(input, SIGNAL(valueChanged(const QString&)),819 scanType, SLOT( SetInput( const QString&)));820 821 connect(input, SIGNAL(valueChanged(const QString&)),822 _parent, SLOT( SetInput( const QString&)));823 }824 825 uint ScanWizardConfig::GetSourceID(void) const826 {827 return videoSource->getValue().toUInt();828 }829 830 QString ScanWizardConfig::GetATSCFormat(void) const831 {832 QString dfl = SourceUtil::GetChannelFormat(GetSourceID());833 return scanConfig->GetATSCFormat(dfl);834 }835 836 LogList::LogList() : ListBoxSetting(this), n(0)837 {838 setSelectionMode(MythListBox::NoSelection);839 }840 841 void LogList::updateText(const QString& status)842 {843 addSelection(status,QString::number(n));844 setCurrentItem(n);845 n++;846 } -
programs/mythtv-setup/main.cpp
20 20 #include "mythuihelper.h" 21 21 #include "mythdirs.h" 22 22 23 #include "libmythtv/channelscan/channelscanner_cli.h" 24 #include "libmythtv/channelscan/scanwizardconfig.h" 25 #include "libmythtv/channelscan/scaninfo.h" 26 #include "libmythtv/channelscan/channelimporter.h" 27 #include "libmythtv/cardutil.h" 23 28 #include "libmythtv/dbcheck.h" 24 29 #include "libmythtv/videosource.h" 25 30 #include "channeleditor.h" … … 108 113 { 109 114 QString geometry = QString::null; 110 115 QString display = QString::null; 111 QString verboseString = QString(" important general"); 116 bool doScan = false; 117 bool doScanList = false; 118 bool doScanSaveOnly = false; 119 bool scanInteractive = true; 120 uint scanImport = 0; 121 uint scanCardId = 0; 122 QString scanTableName = "atsc-vsb8-us"; 123 QString scanInputName = ""; 124 bool use_display = true; 112 125 113 126 #ifdef USING_X11 114 127 // Remember any -display or -geometry argument … … 119 132 geometry = argv[argpos+1]; 120 133 else if (!strcmp(argv[argpos],"-display")) 121 134 display = argv[argpos+1]; 135 else if (QString(argv[argpos]).left(6) == "--scan") 136 { 137 use_display = false; 138 print_verbose_messages = 0; 139 verboseString = ""; 140 } 122 141 } 123 142 #endif 124 143 … … 127 146 // of the MythPushButton widgets, and they don't use the themed background. 128 147 QApplication::setDesktopSettingsAware(FALSE); 129 148 #endif 130 QApplication a(argc, argv );149 QApplication a(argc, argv, use_display); 131 150 132 151 QMap<QString, QString> settingsOverride; 133 152 … … 223 242 224 243 ++argpos; 225 244 } 245 else if (!strcmp(a.argv()[argpos],"--scan-list")) 246 { 247 doScanList = true; 248 } 249 else if (!strcmp(a.argv()[argpos],"--scan-import")) 250 { 251 if (a.argc()-1 > argpos) 252 { 253 QString tmpArg = a.argv()[argpos + 1]; 254 scanImport = tmpArg.toUInt(); 255 ++argpos; 256 } 257 else 258 { 259 cerr << "Missing scan number for import, please run " 260 << "--scan-list to list importable scans." << endl; 261 return BACKEND_EXIT_INVALID_CMDLINE; 262 } 263 } 264 else if (!strcmp(a.argv()[argpos],"--scan-save-only")) 265 { 266 doScanSaveOnly = true; 267 } 268 else if (!strcmp(a.argv()[argpos],"--scan-non-interactive")) 269 { 270 scanInteractive = false; 271 } 272 else if (!strcmp(a.argv()[argpos],"--scan")) 273 { 274 if (a.argc()-1 > argpos) 275 { 276 scanTableName = a.argv()[argpos + 1]; 277 ++argpos; 278 } 279 if (a.argc()-1 > argpos) 280 { 281 QString tmpArg = a.argv()[argpos + 1]; 282 scanCardId = tmpArg.toUInt(); 283 ++argpos; 284 } 285 if (a.argc()-1 > argpos) 286 { 287 scanInputName = a.argv()[argpos + 1]; 288 ++argpos; 289 } 290 doScan = true; 291 } 226 292 else 227 293 { 228 294 if (!(!strcmp(a.argv()[argpos],"-h") || … … 245 311 << "-v or --verbose debug-level " 246 312 "Use '-v help' for level info" << endl 247 313 << endl; 248 return -1;314 return BACKEND_EXIT_INVALID_CMDLINE; 249 315 } 250 316 } 251 317 … … 258 324 259 325 std::auto_ptr<MythContext> contextScopeDelete(gContext); 260 326 261 if (!gContext->Init( true))327 if (!gContext->Init(use_display)) 262 328 { 263 329 VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting."); 264 330 return GENERIC_EXIT_NO_MYTHCONTEXT; … … 293 359 return GENERIC_EXIT_DB_ERROR; 294 360 } 295 361 296 gContext->SetSetting("Theme", "G.A.N.T"); 297 GetMythUI()->LoadQtConfig(); 362 if (use_display) 363 { 364 gContext->SetSetting("Theme", "G.A.N.T"); 365 GetMythUI()->LoadQtConfig(); 298 366 299 QString fileprefix = GetConfDir();367 QString fileprefix = GetConfDir(); 300 368 301 QDir dir(fileprefix); 302 if (!dir.exists()) 303 dir.mkdir(fileprefix); 369 QDir dir(fileprefix); 370 if (!dir.exists()) 371 dir.mkdir(fileprefix); 372 } 304 373 374 if (doScan) 375 { 376 bool okCardID = scanCardId; 377 378 QStringList inputnames = CardUtil::GetInputNames(scanCardId); 379 okCardID &= !inputnames.empty(); 380 381 if (scanInputName.isEmpty()) 382 scanInputName = CardUtil::GetDefaultInput(scanCardId); 383 384 bool okInputName = inputnames.contains(scanInputName); 385 386 doScan = (okCardID && okInputName); 387 388 if (!okCardID) 389 { 390 cerr << "You must enter a valid cardid to scan." << endl; 391 vector<uint> cardids = CardUtil::GetCardIDs(); 392 if (cardids.empty()) 393 { 394 cerr << "But no cards have been defined on this host" 395 << endl; 396 return BACKEND_EXIT_INVALID_CMDLINE; 397 } 398 cerr << "Valid cards: " << endl; 399 for (uint i = 0; i < cardids.size(); i++) 400 { 401 fprintf(stderr, "%5i: %s %s\n", 402 cardids[i], 403 CardUtil::GetRawCardType(cardids[i]) 404 .toAscii().constData(), 405 CardUtil::GetVideoDevice(cardids[i]) 406 .toAscii().constData()); 407 } 408 return BACKEND_EXIT_INVALID_CMDLINE; 409 } 410 411 if (!okInputName) 412 { 413 cerr << "You must enter a valid input to scan this card." 414 << endl; 415 cerr << "Valid inputs: " << endl; 416 for (int i = 0; i < inputnames.size(); i++) 417 { 418 cerr << inputnames[i].toAscii().constData() << endl; 419 } 420 return BACKEND_EXIT_INVALID_CMDLINE; 421 } 422 } 423 424 if (doScan) 425 { 426 int ret = 0; 427 int firstBreak = scanTableName.indexOf("-"); 428 int secondBreak = scanTableName.lastIndexOf("-"); 429 QString freq_std = scanTableName.mid(0, firstBreak).toLower(); 430 QString mod = scanTableName.mid( 431 firstBreak+1, secondBreak-firstBreak-1).toLower(); 432 QString tbl = scanTableName.mid(secondBreak+1).toLower(); 433 uint inputid = CardUtil::GetInputID(scanCardId, scanInputName); 434 uint sourceid = ChannelUtil::GetSourceID(inputid); 435 QMap<QString,QString> startChan; 436 { 437 ChannelScannerCLI scanner(doScanSaveOnly, scanInteractive); 438 scanner.Scan( 439 (freq_std=="atsc") ? 440 ScanTypeSetting::FullScan_ATSC : 441 ((freq_std=="dvbt") ? 442 ScanTypeSetting::FullScan_DVBT : 443 ScanTypeSetting::FullScan_ATSC), 444 /* cardid */ scanCardId, 445 /* inputname */ scanInputName, 446 /* sourceid */ sourceid, 447 false, 448 // stuff needed for particular scans 449 /* mplexid */ 0, 450 startChan, freq_std, mod, tbl); 451 ret = a.exec(); 452 } 453 return (ret) ? GENERIC_EXIT_NOT_OK : BACKEND_EXIT_OK; 454 } 455 456 if (doScanList) 457 { 458 vector<ScanInfo> scans = LoadScanList(); 459 460 cout<<" scanid cardid sourceid processed date"<<endl; 461 for (uint i = 0; i < scans.size(); i++) 462 { 463 printf("%5i %6i %8i %8s %20s\n", 464 scans[i].scanid, scans[i].cardid, 465 scans[i].sourceid, (scans[i].processed) ? "yes" : "no", 466 scans[i].scandate.toString().toAscii().constData()); 467 } 468 cout<<endl; 469 470 return BACKEND_EXIT_OK; 471 } 472 473 if (scanImport) 474 { 475 cout<<"*** SCAN IMPORT START ***"<<endl; 476 { 477 ScanDTVTransportList list = LoadScan(scanImport); 478 ChannelImporter ci(false, true, true, false); 479 ci.Process(list); 480 } 481 cout<<"*** SCAN IMPORT END ***"<<endl; 482 return BACKEND_EXIT_OK; 483 } 484 305 485 MythMainWindow *mainWindow = GetMythMainWindow(); 306 486 mainWindow->Init(); 307 487 gContext->SetMainWindow(mainWindow);
