00001
00002
00003
00004 #include <cstdio>
00005 #include <pthread.h>
00006 #include <unistd.h>
00007
00008
00009 #include <qmutex.h>
00010
00011
00012 #include "siscan.h"
00013 #include "scheduledrecording.h"
00014 #include "frequencies.h"
00015 #include "mythdbcon.h"
00016 #include "channelutil.h"
00017 #include "cardutil.h"
00018
00019
00020 #include "dtvsignalmonitor.h"
00021 #include "scanstreamdata.h"
00022
00023
00024 #include "atsctables.h"
00025
00026
00027 #include "dvbsignalmonitor.h"
00028 #include "dvbtables.h"
00029
00030 #include "dvbchannel.h"
00031 #include "hdhrchannel.h"
00032 #include "channel.h"
00033 #include "compat.h"
00034
00035 QString SIScan::loc(const SIScan *siscan)
00036 {
00037 if (siscan && siscan->channel)
00038 return QString("SIScan(%1)").arg(siscan->channel->GetDevice());
00039 return "SIScan(u)";
00040 }
00041
00042 #define LOC (SIScan::loc(this) + ": ")
00043 #define LOC_ERR (SIScan::loc(this) + ", Error: ")
00044
00085 SIScan::SIScan(const QString &_cardtype, ChannelBase *_channel, int _sourceID,
00086 uint signal_timeout, uint channel_timeout,
00087 const QString &_inputname)
00088 :
00089 channel(_channel),
00090 signalMonitor(SignalMonitor::Init(_cardtype, -1, _channel)),
00091 sourceID(_sourceID),
00092 scanMode(IDLE),
00093 signalTimeout(signal_timeout),
00094 channelTimeout(channel_timeout),
00095 inputname(QDeepCopy<QString>(_inputname)),
00096
00097 ignoreAudioOnlyServices(false),
00098 ignoreDataServices(false),
00099 ignoreEncryptedServices(false),
00100 forceUpdate(false),
00101 renameChannels(false),
00102 channelFormat("%1_%2"),
00103
00104 threadExit(false),
00105 waitingForTables(false),
00106
00107 transportsScanned(0),
00108
00109 scanner_thread_running(false)
00110 {
00111
00112 init_freq_tables();
00113 current = scanTransports.end();
00114
00115
00116 DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
00117 if (dtvSigMon)
00118 {
00119 VERBOSE(VB_SIPARSER, LOC + "Connecting up DTVSignalMonitor");
00120 ScanStreamData *data = new ScanStreamData();
00121
00122 dtvSigMon->SetStreamData(data);
00123 dtvSigMon->AddFlags(SignalMonitor::kDTVSigMon_WaitForMGT |
00124 SignalMonitor::kDTVSigMon_WaitForVCT |
00125 SignalMonitor::kDTVSigMon_WaitForNIT |
00126 SignalMonitor::kDTVSigMon_WaitForSDT);
00127
00128 data->AddMPEGListener(this);
00129 data->AddATSCMainListener(this);
00130 data->AddDVBMainListener(this);
00131 }
00132 }
00133
00134 SIScan::~SIScan(void)
00135 {
00136
00137 StopScanner();
00138 VERBOSE(VB_SIPARSER, LOC + "SIScanner dtor");
00139 }
00140
00141 void SIScan::deleteLater(void)
00142 {
00143 disconnect();
00144 StopScanner();
00145 VERBOSE(VB_SIPARSER, LOC + "SIScanner Stopped");
00146 QObject::deleteLater();
00147 }
00148
00149 void SIScan::SetAnalog(bool is_analog)
00150 {
00151 if (is_analog)
00152 {
00153 connect(signalMonitor, SIGNAL(AllGood( void)),
00154 this, SLOT( HandleAllGood(void)));
00155 }
00156 else
00157 {
00158 disconnect(signalMonitor, SIGNAL(AllGood( void)),
00159 this, SLOT( HandleAllGood(void)));
00160 }
00161 }
00162
00163 void SIScan::HandleAllGood(void)
00164 {
00165 QString cur_chan = (*current).FriendlyName;
00166 QStringList list = QStringList::split(" ", cur_chan);
00167 QString freqid = (list.size() >= 2) ? list[1] : cur_chan;
00168
00169 bool ok = false;
00170
00171 QString msg = tr("Updated Channel %1").arg(cur_chan);
00172
00173 if (!ChannelUtil::FindChannel(sourceID, freqid))
00174 {
00175 int chanid = ChannelUtil::CreateChanID(sourceID, freqid);
00176
00177 QString callsign = QString("%1%2")
00178 .arg(ChannelUtil::GetUnknownCallsign()).arg(freqid);
00179
00180 ok = ChannelUtil::CreateChannel(
00181 0 ,
00182 sourceID,
00183 chanid,
00184 callsign,
00185 "" ,
00186 freqid ,
00187 0 ,
00188 0 ,
00189 0 ,
00190 false ,
00191 false ,
00192 false ,
00193 freqid);
00194
00195 msg = (ok) ?
00196 tr("Added Channel %1").arg(cur_chan) :
00197 tr("Failed to add channel %1").arg(cur_chan);
00198 }
00199 else
00200 {
00201
00202 }
00203
00204 emit ServiceScanUpdateText(msg);
00205
00206
00207 if (scanMode == TRANSPORT_LIST)
00208 {
00209 UpdateScanPercentCompleted();
00210 waitingForTables = false;
00211 nextIt = current.nextTransport();
00212 }
00213 }
00214
00226 bool SIScan::ScanServicesSourceID(int SourceID)
00227 {
00228 if (scanMode == TRANSPORT_LIST)
00229 return false;
00230
00231 nextIt = scanTransports.end();
00232
00233 MSqlQuery query(MSqlQuery::InitCon());
00234
00235
00236 QString theQuery = QString(
00237 "SELECT sourceid, mplexid, sistandard, transportid "
00238 "FROM dtv_multiplex WHERE sourceid = %1").arg(SourceID);
00239 query.prepare(theQuery);
00240
00241 if (!query.exec() || !query.isActive())
00242 {
00243 MythContext::DBError("Get Transports for SourceID", query);
00244 return false;
00245 }
00246
00247 if (query.size() <= 0)
00248 {
00249 VERBOSE(VB_SIPARSER, LOC + "Unable to find any transports for " +
00250 QString("sourceid %1").arg(sourceID));
00251
00252 return false;
00253 }
00254
00255 while (query.next())
00256 {
00257 int sourceid = query.value(0).toInt();
00258 int mplexid = query.value(1).toInt();
00259 QString std = query.value(2).toString();
00260 int tsid = query.value(3).toInt();
00261
00262 QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
00263 QString("Multiplex #%1").arg(mplexid);
00264
00265 VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);
00266
00267 TransportScanItem item(sourceid, std, fn, mplexid, signalTimeout);
00268 scanTransports += item;
00269 }
00270
00271 waitingForTables = false;
00272 transportsScanned = 0;
00273 if (scanTransports.size())
00274 {
00275 nextIt = scanTransports.begin();
00276 scanMode = TRANSPORT_LIST;
00277 return true;
00278 }
00279
00280 return false;
00281 }
00282
00283 void SIScan::HandlePAT(const ProgramAssociationTable *pat)
00284 {
00285 VERBOSE(VB_SIPARSER, LOC +
00286 QString("Got a Program Association Table for %1")
00287 .arg((*current).FriendlyName));
00288
00289
00290 ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();
00291 for (uint i = 0; i < pat->ProgramCount(); i++)
00292 {
00293 if (pat->ProgramPID(i))
00294 sd->AddListeningPID(pat->ProgramPID(i));
00295 }
00296 }
00297
00298 void SIScan::HandleVCT(uint, const VirtualChannelTable*)
00299 {
00300 VERBOSE(VB_SIPARSER, LOC + QString("Got a Virtual Channel Table for %1")
00301 .arg((*current).FriendlyName));
00302
00303 HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
00304 }
00305
00306 void SIScan::HandleMGT(const MasterGuideTable*)
00307 {
00308 VERBOSE(VB_SIPARSER, LOC + QString("Got the Master Guide for %1")
00309 .arg((*current).FriendlyName));
00310
00311 HandleATSCDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
00312 }
00313
00314 void SIScan::HandleSDT(uint, const ServiceDescriptionTable* sdt)
00315 {
00316 VERBOSE(VB_SIPARSER, LOC +
00317 QString("Got a Service Description Table for %1")
00318 .arg((*current).FriendlyName));
00319 VERBOSE(VB_SIPARSER, LOC + sdt->toString());
00320
00321 HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
00322 }
00323
00324 void SIScan::HandleNIT(const NetworkInformationTable *nit)
00325 {
00326 VERBOSE(VB_SIPARSER, LOC +
00327 QString("Got a Network Information Table for %1")
00328 .arg((*current).FriendlyName));
00329 VERBOSE(VB_SIPARSER, LOC + nit->toString());
00330
00331 if (nit->TransportStreamCount())
00332 {
00333 emit TransportScanUpdateText(
00334 tr("Network %1 Processing").arg(nit->NetworkName()));
00335
00336 vector<uint> mp;
00337 mp = ChannelUtil::CreateMultiplexes(sourceID, nit);
00338 VERBOSE(VB_SIPARSER, QString("Created %1 multiplexes from NIT")
00339 .arg(mp.size()));
00340
00341
00342 for (uint i = 0; i < nit->TransportStreamCount(); i++)
00343 {
00344 const desc_list_t& list =
00345 MPEGDescriptor::Parse(nit->TransportDescriptors(i),
00346 nit->TransportDescriptorsLength(i));
00347
00348 const unsigned char* desc =
00349 MPEGDescriptor::Find(list, DescriptorID::dvb_uk_channel_list);
00350
00351 if (desc)
00352 {
00353 UKChannelListDescriptor uklist(desc);
00354 for (uint j = 0; j < uklist.ChannelCount(); j++)
00355 dvbChanNums[uklist.ServiceID(j)] = uklist.ChannelNumber(j);
00356 }
00357 }
00358 }
00359
00360 const ScanStreamData *sd = GetDTVSignalMonitor()->GetScanStreamData();
00361 const DVBStreamData &dsd = *sd;
00362 if (dsd.HasAllNITSections())
00363 {
00364 emit TransportScanUpdateText(tr("Finished processing Transport List"));
00365 emit TransportScanComplete();
00366 }
00367
00368 HandleDVBDBInsertion(GetDTVSignalMonitor()->GetScanStreamData(), true);
00369 }
00370
00371 void SIScan::HandleMPEGDBInsertion(const ScanStreamData *sd, bool)
00372 {
00373
00374 QString sistandard = sd->GetSIStandard((*current).tuning.sistandard);
00375
00376 if (!(*current).mplexid)
00377 (*current).mplexid = InsertMultiplex(current);
00378
00379 if (!(*current).mplexid)
00380 return;
00381
00382 int mplexid = (*current).mplexid;
00383 int freqid = (*current).friendlyNum;
00384 QString fn = (*current).FriendlyName;
00385
00386 pat_vec_t pats = sd->GetCachedPATs();
00387 pmt_map_t pmt_map = sd->GetCachedPMTMap();
00388 for (uint i = 0; i < pats.size(); i++)
00389 {
00390 UpdatePATinDB(mplexid, fn, freqid, pats[i], pmt_map,
00391 (*current).expectedChannels, sistandard, true);
00392 }
00393 sd->ReturnCachedPMTTables(pmt_map);
00394 sd->ReturnCachedPATTables(pats);
00395
00396
00397 if (scanMode == TRANSPORT_LIST)
00398 {
00399 UpdateScanPercentCompleted();
00400 waitingForTables = false;
00401 nextIt = current.nextTransport();
00402 }
00403 }
00404
00405 void SIScan::HandleATSCDBInsertion(const ScanStreamData *sd,
00406 bool wait_until_complete)
00407 {
00408 if (wait_until_complete && !sd->HasCachedAllVCTs())
00409 return;
00410
00411 if (!(*current).mplexid)
00412 (*current).mplexid = InsertMultiplex(current);
00413
00414 if (!(*current).mplexid)
00415 return;
00416
00417 int mplexid = (*current).mplexid;
00418 int freqid = (*current).friendlyNum;
00419 QString fn = (*current).FriendlyName;
00420
00421
00422 tvct_vec_t tvcts = sd->GetAllCachedTVCTs();
00423 for (uint i = 0; i < tvcts.size(); i++)
00424 {
00425 UpdateVCTinDB(mplexid, fn, freqid, tvcts[i],
00426 (*current).expectedChannels, true);
00427 }
00428 sd->ReturnCachedTVCTTables(tvcts);
00429
00430
00431 cvct_vec_t cvcts = sd->GetAllCachedCVCTs();
00432 for (uint i = 0; i < cvcts.size(); i++)
00433 {
00434 UpdateVCTinDB(mplexid, fn, freqid, cvcts[i],
00435 (*current).expectedChannels, true);
00436 }
00437 sd->ReturnCachedCVCTTables(cvcts);
00438
00439
00440 if (scanMode == TRANSPORT_LIST)
00441 {
00442 UpdateScanPercentCompleted();
00443 waitingForTables = false;
00444 nextIt = current.nextTransport();
00445 }
00446 }
00447
00448 void SIScan::HandleDVBDBInsertion(const ScanStreamData *sd,
00449 bool wait_until_complete)
00450 {
00451 const DVBStreamData &dsd = (const DVBStreamData &)(*sd);
00452 if (wait_until_complete && !(dsd.HasCachedSDT() && dsd.HasCachedAllNIT()))
00453 return;
00454
00455 emit ServiceScanUpdateText(tr("Updating Services"));
00456
00457 if (!(*current).mplexid)
00458 (*current).mplexid = InsertMultiplex(current);
00459
00460 vector<const ServiceDescriptionTable*> sdts = sd->GetAllCachedSDTs();
00461 for (uint i = 0; i < sdts.size(); i++)
00462 {
00463 UpdateSDTinDB((*current).mplexid, sdts[i],
00464 (*current).expectedChannels, forceUpdate);
00465 }
00466 sd->ReturnCachedSDTTables(sdts);
00467
00468 emit ServiceScanUpdateText(tr("Finished processing Services"));
00469
00470 if (scanMode == TRANSPORT_LIST)
00471 {
00472 UpdateScanPercentCompleted();
00473 waitingForTables = false;
00474 nextIt = current.nextTransport();
00475 }
00476 else
00477 {
00478 emit PctServiceScanComplete(100);
00479 emit ServiceScanComplete();
00480 }
00481 }
00482
00487 bool SIScan::HandlePostInsertion(void)
00488 {
00489 DTVSignalMonitor* dtvSigMon = GetDTVSignalMonitor();
00490 if (!dtvSigMon)
00491 return false;
00492
00493 const ScanStreamData *sd = dtvSigMon->GetScanStreamData();
00494
00495 VERBOSE(VB_SIPARSER, LOC + "HandlePostInsertion() " +
00496 QString("pat(%1)").arg(sd->HasCachedAnyPAT()));
00497
00498 const MasterGuideTable *mgt = sd->GetCachedMGT();
00499 if (mgt)
00500 {
00501 VERBOSE(VB_IMPORTANT, mgt->toString());
00502 HandleATSCDBInsertion(sd, false);
00503 sd->ReturnCachedTable(mgt);
00504 return true;
00505 }
00506
00507 const NetworkInformationTable *nit = sd->GetCachedNIT(0);
00508 sdt_vec_t sdts = sd->GetAllCachedSDTs();
00509 if (nit || sdts.size())
00510 {
00511 if (nit)
00512 VERBOSE(VB_IMPORTANT, nit->toString());
00513 HandleDVBDBInsertion(sd, false);
00514 sd->ReturnCachedSDTTables(sdts);
00515 sd->ReturnCachedTable(nit);
00516 return true;
00517 }
00518
00519 if (sd->HasCachedAnyPAT())
00520 {
00521 VERBOSE(VB_IMPORTANT, LOC + "Post insertion found PAT..");
00522 HandleMPEGDBInsertion(sd, false);
00523 return true;
00524 }
00525 return false;
00526 }
00527
00528 DTVSignalMonitor* SIScan::GetDTVSignalMonitor(void)
00529 {
00530 return dynamic_cast<DTVSignalMonitor*>(signalMonitor);
00531 }
00532
00533 DVBSignalMonitor* SIScan::GetDVBSignalMonitor(void)
00534 {
00535 #ifdef USING_DVB
00536 return dynamic_cast<DVBSignalMonitor*>(signalMonitor);
00537 #else
00538 return NULL;
00539 #endif
00540 }
00541
00542 DTVChannel *SIScan::GetDTVChannel(void)
00543 {
00544 return dynamic_cast<DTVChannel*>(channel);
00545 }
00546
00547 DVBChannel *SIScan::GetDVBChannel(void)
00548 {
00549 #ifdef USING_DVB
00550 return dynamic_cast<DVBChannel*>(channel);
00551 #else
00552 return NULL;
00553 #endif
00554 }
00555
00556 Channel *SIScan::GetChannel(void)
00557 {
00558 #ifdef USING_V4L
00559 return dynamic_cast<Channel*>(channel);
00560 #else
00561 return NULL;
00562 #endif
00563 }
00564
00569 void *SIScan::SpawnScanner(void *param)
00570 {
00571 SIScan *scanner = (SIScan *)param;
00572 scanner->RunScanner();
00573 return NULL;
00574 }
00575
00579 void SIScan::StartScanner(void)
00580 {
00581 pthread_create(&scanner_thread, NULL, SpawnScanner, this);
00582 }
00583
00587 void SIScan::RunScanner(void)
00588 {
00589 VERBOSE(VB_SIPARSER, LOC + "Starting SIScanner");
00590
00591 scanner_thread_running = true;
00592 threadExit = false;
00593
00594 while (!threadExit)
00595 {
00596 if (scanMode == TRANSPORT_LIST)
00597 HandleActiveScan();
00598
00599 usleep(250);
00600 }
00601 scanner_thread_running = false;
00602 }
00603
00604
00605 bool SIScan::HasTimedOut(void)
00606 {
00607 if (!waitingForTables)
00608 return true;
00609
00610
00611 if (timer.elapsed() > (int)channelTimeout)
00612 {
00613 QString offset_str = current.offset() ?
00614 QObject::tr(" offset %2").arg(current.offset()) : "";
00615 QString cur_chan = QString("%1%2")
00616 .arg((*current).FriendlyName).arg(offset_str);
00617 QString time_out_table_str =
00618 QObject::tr("Timeout Scanning %1 -- no tables").arg(cur_chan);
00619
00620 emit ServiceScanUpdateText(time_out_table_str);
00621 VERBOSE(VB_SIPARSER, LOC + time_out_table_str);
00622
00623 return true;
00624 }
00625
00626
00627 if (timer.elapsed() > (int)(*current).timeoutTune)
00628 {
00629
00630 SignalMonitor *sm = GetSignalMonitor();
00631 if (NULL == sm || sm->HasSignalLock())
00632 return false;
00633
00634 QString offset_str = current.offset() ?
00635 QObject::tr(" offset %2").arg(current.offset()) : "";
00636 QString cur_chan = QString("%1%2")
00637 .arg((*current).FriendlyName).arg(offset_str);
00638 QString time_out_sig_str =
00639 QObject::tr("Timeout Scanning %1 -- no signal").arg(cur_chan);
00640
00641 emit ServiceScanUpdateText(time_out_sig_str);
00642 VERBOSE(VB_SIPARSER, LOC + time_out_sig_str);
00643
00644 return true;
00645 }
00646 return false;
00647 }
00648
00652 void SIScan::HandleActiveScan(void)
00653 {
00654 bool do_post_insertion = waitingForTables;
00655
00656 if (!HasTimedOut())
00657 return;
00658
00659 if (0 == nextIt.offset() && nextIt != scanTransports.begin())
00660 {
00661
00662 signalMonitor->Stop();
00663
00664 if (do_post_insertion)
00665 HandlePostInsertion();
00666
00667 transportsScanned++;
00668 UpdateScanPercentCompleted();
00669 }
00670
00671 current = nextIt;
00672
00673 if (current != scanTransports.end())
00674 {
00675 ScanTransport(current);
00676
00677
00678 nextIt = current;
00679 ++nextIt;
00680 }
00681 else
00682 {
00683 emit ServiceScanComplete();
00684 scanMode = IDLE;
00685 scanTransports.clear();
00686 current = nextIt = scanTransports.end();
00687 }
00688 }
00689
00690 bool SIScan::Tune(const transport_scan_items_it_t transport)
00691 {
00692 const TransportScanItem &item = *transport;
00693 const uint64_t freq = item.freq_offset(transport.offset());
00694
00695 #ifdef USING_DVB
00696 if (GetDVBSignalMonitor() && GetDVBChannel())
00697 {
00698 if (GetDVBChannel()->GetRotor())
00699 {
00700 GetDVBSignalMonitor()->AddFlags(SignalMonitor::kDVBSigMon_WaitForPos);
00701 GetDVBSignalMonitor()->SetRotorTarget(1.0f);
00702 }
00703 }
00704 #endif // USING_DVB
00705
00706 if (!GetDTVChannel())
00707 return false;
00708
00709 if (item.mplexid > 0)
00710 return GetDTVChannel()->TuneMultiplex(item.mplexid, inputname);
00711
00712 DTVMultiplex tuning = item.tuning;
00713 tuning.frequency = freq;
00714 return GetDTVChannel()->Tune(tuning, inputname);
00715 }
00716
00717 void SIScan::ScanTransport(const transport_scan_items_it_t transport)
00718 {
00719 QString offset_str = (transport.offset()) ?
00720 QObject::tr(" offset %2").arg(transport.offset()) : "";
00721 QString cur_chan = QString("%1%2")
00722 .arg((*current).FriendlyName).arg(offset_str);
00723 QString tune_msg_str =
00724 QObject::tr("Tuning to %1 mplexid(%2)")
00725 .arg(cur_chan).arg((*current).mplexid);
00726
00727 const TransportScanItem &item = *transport;
00728
00729 if (transport.offset() &&
00730 (item.freq_offset(transport.offset()) == item.freq_offset(0)))
00731 {
00732 waitingForTables = false;
00733 return;
00734 }
00735
00736 emit ServiceScanUpdateStatusText(cur_chan);
00737 VERBOSE(VB_SIPARSER, LOC + tune_msg_str);
00738
00739 if (!Tune(transport))
00740 {
00741 UpdateScanPercentCompleted();
00742 VERBOSE(VB_SIPARSER, LOC +
00743 QString("Failed to tune %1 mplexid(%2) at offset %3")
00744 .arg(item.FriendlyName).arg(item.mplexid)
00745 .arg(transport.offset()));
00746 return;
00747 }
00748
00749
00750 if (GetDTVSignalMonitor() && GetDTVSignalMonitor()->GetScanStreamData())
00751 {
00752 GetDTVSignalMonitor()->GetScanStreamData()->Reset();
00753 GetDTVSignalMonitor()->SetChannel(-1,-1);
00754 }
00755
00756
00757 signalMonitor->Start();
00758
00759 timer.start();
00760 waitingForTables = true;
00761 }
00762
00767 void SIScan::StopScanner(void)
00768 {
00769 VERBOSE(VB_SIPARSER, LOC + "Stopping SIScanner");
00770
00771 threadExit = true;
00772
00773 if (scanner_thread_running)
00774 pthread_join(scanner_thread, NULL);
00775
00776 if (signalMonitor)
00777 {
00778 signalMonitor->Stop();
00779 signalMonitor->deleteLater();
00780 signalMonitor = NULL;
00781 }
00782 }
00783
00788 bool SIScan::ScanTransports(int SourceID,
00789 const QString std,
00790 const QString modulation,
00791 const QString country)
00792 {
00793 QString si_std = (std.lower() != "atsc") ? "dvb" : "atsc";
00794 QString name("");
00795 if (scanMode == TRANSPORT_LIST)
00796 return false;
00797
00798 scanTransports.clear();
00799 nextIt = scanTransports.end();
00800
00801 freq_table_list_t tables =
00802 get_matching_freq_tables(std, modulation, country);
00803
00804 VERBOSE(VB_SIPARSER, LOC +
00805 QString("Looked up freq table (%1, %2, %3) w/%4 entries")
00806 .arg(std).arg(modulation).arg(country).arg(tables.size()));
00807
00808 freq_table_list_t::iterator it = tables.begin();
00809 for (; it != tables.end(); ++it)
00810 {
00811 const FrequencyTable &ft = **it;
00812 int name_num = ft.name_offset;
00813 QString strNameFormat = ft.name_format;
00814 uint freq = ft.frequencyStart;
00815 while (freq <= ft.frequencyEnd)
00816 {
00817 name = strNameFormat;
00818 if (strNameFormat.find("%") >= 0)
00819 name = strNameFormat.arg(name_num);
00820
00821 TransportScanItem item(SourceID, si_std, name, name_num,
00822 freq, ft, signalTimeout);
00823 scanTransports += item;
00824
00825 VERBOSE(VB_SIPARSER, LOC + item.toString());
00826
00827 name_num++;
00828 freq += ft.frequencyStep;
00829 }
00830 }
00831
00832 timer.start();
00833 waitingForTables = false;
00834
00835 nextIt = scanTransports.begin();
00836 transportsScanned = 0;
00837 scanMode = TRANSPORT_LIST;
00838
00839 return true;
00840 }
00841
00842 bool SIScan::ScanForChannels(uint sourceid,
00843 const QString &std,
00844 const QString &cardtype,
00845 const DTVChannelList &channels)
00846 {
00847 scanTransports.clear();
00848 nextIt = scanTransports.end();
00849
00850 DTVTunerType tunertype;
00851 tunertype.Parse(cardtype);
00852
00853 DTVChannelList::const_iterator it = channels.begin();
00854 for (uint i = 0; it != channels.end(); ++it, i++)
00855 {
00856 DTVTransport tmp = *it;
00857 tmp.sistandard = std;
00858 TransportScanItem item(sourceid, QString::number(i),
00859 tunertype, tmp, signalTimeout);
00860
00861 scanTransports += item;
00862
00863 VERBOSE(VB_SIPARSER, LOC + item.toString());
00864 }
00865
00866 if (scanTransports.empty())
00867 {
00868 VERBOSE(VB_IMPORTANT, LOC_ERR + "ScanForChannels() no transports");
00869 return false;
00870 }
00871
00872 timer.start();
00873 waitingForTables = false;
00874
00875 nextIt = scanTransports.begin();
00876 transportsScanned = 0;
00877 scanMode = TRANSPORT_LIST;
00878
00879 return true;
00880 }
00881
00886 bool SIScan::ScanTransportsStartingOn(int sourceid,
00887 const QMap<QString,QString> &startChan)
00888 {
00889 QMap<QString,QString>::const_iterator it;
00890
00891 if (startChan.find("std") == startChan.end() ||
00892 startChan.find("modulation") == startChan.end())
00893 {
00894 return false;
00895 }
00896
00897 QString std = *startChan.find("std");
00898 QString mod = (*(startChan.find("modulation"))).upper();
00899 QString si_std = (std.lower() != "atsc") ? "dvb" : "atsc";
00900 QString name = "";
00901 bool ok = false;
00902
00903 if (scanMode == TRANSPORT_LIST)
00904 return false;
00905
00906 scanTransports.clear();
00907 nextIt = scanTransports.end();
00908
00909 DTVMultiplex tuning;
00910
00911 DTVTunerType type;
00912
00913 if (std == "dvb")
00914 {
00915 ok = type.Parse(mod);
00916 }
00917 else if (std == "atsc")
00918 {
00919 type = DTVTunerType::kTunerTypeATSC;
00920 ok = true;
00921 }
00922
00923 if (ok)
00924 {
00925 ok = tuning.ParseTuningParams(
00926 type,
00927 startChan["frequency"], startChan["inversion"],
00928 startChan["symbolrate"], startChan["fec"],
00929 startChan["polarity"],
00930 startChan["coderate_hp"], startChan["coderate_lp"],
00931 startChan["constellation"], startChan["trans_mode"],
00932 startChan["guard_interval"], startChan["hierarchy"],
00933 startChan["modulation"], startChan["bandwidth"]);
00934 }
00935
00936 if (ok)
00937 {
00938 tuning.sistandard = si_std;
00939 scanTransports += TransportScanItem(
00940 sourceid, tr("Frequency %1").arg(startChan["frequency"]),
00941 tuning, signalTimeout);
00942 }
00943
00944 if (!ok)
00945 return false;
00946
00947 timer.start();
00948 waitingForTables = false;
00949
00950 nextIt = scanTransports.begin();
00951 transportsScanned = 0;
00952 scanMode = TRANSPORT_LIST;
00953
00954 return true;
00955 }
00956
00957 bool SIScan::ScanTransport(int mplexid)
00958 {
00959 scanTransports.clear();
00960 nextIt = scanTransports.end();
00961
00962 MSqlQuery query(MSqlQuery::InitCon());
00963
00964
00965 QString theQuery = QString(
00966 "SELECT sourceid, mplexid, sistandard, transportid "
00967 "FROM dtv_multiplex WHERE mplexid = %2").arg(mplexid);
00968 query.prepare(theQuery);
00969
00970 if (!query.exec() || !query.isActive())
00971 {
00972 MythContext::DBError("Get Transports for SourceID", query);
00973 return false;
00974 }
00975
00976 if (query.size() <= 0)
00977 {
00978 VERBOSE(VB_SIPARSER, LOC + "Unable to find transport to scan.");
00979 return false;
00980 }
00981
00982 while (query.next())
00983 {
00984 int sourceid = query.value(0).toInt();
00985 int mplexid = query.value(1).toInt();
00986 QString std = query.value(2).toString();
00987 int tsid = query.value(3).toInt();
00988
00989 QString fn = (tsid) ? QString("Transport ID %1").arg(tsid) :
00990 QString("Multiplex #%1").arg(mplexid);
00991
00992 VERBOSE(VB_SIPARSER, LOC + "Adding " + fn);
00993
00994 TransportScanItem item(sourceid, std, fn, mplexid, signalTimeout);
00995 scanTransports += item;
00996 }
00997
00998 timer.start();
00999 waitingForTables = false;
01000
01001 transportsScanned = 0;
01002 if (scanTransports.size())
01003 {
01004 nextIt = scanTransports.begin();
01005 scanMode = TRANSPORT_LIST;
01006 return true;
01007 }
01008
01009 return false;
01010 }
01011
01015 bool SIScan::CheckImportedList(const DTVChannelInfoList &channels,
01016 uint mpeg_program_num,
01017 QString &service_name,
01018 QString &callsign,
01019 QString &common_status_info)
01020 {
01021 if (channels.empty())
01022 return true;
01023
01024 bool found = false;
01025 for (uint i = 0; i < channels.size(); i++)
01026 {
01027 VERBOSE(VB_IMPORTANT,
01028 QString("comparing %1 %2 against %3 %4")
01029 .arg(channels[i].serviceid).arg(channels[i].name)
01030 .arg(mpeg_program_num).arg(common_status_info));
01031
01032 if (channels[i].serviceid == mpeg_program_num)
01033 {
01034 found = true;
01035 if (!channels[i].name.isEmpty())
01036 {
01037 service_name = QDeepCopy<QString>(channels[i].name);
01038 callsign = QDeepCopy<QString>(channels[i].name);
01039 }
01040 }
01041 }
01042
01043 if (found)
01044 {
01045 common_status_info += QString(" %1 %2")
01046 .arg(tr("as")).arg(service_name);
01047 }
01048 else
01049 {
01050 emit ServiceScanUpdateText(
01051 tr("Skipping %1, not in imported channel map")
01052 .arg(common_status_info));
01053 }
01054
01055 return found;
01056 }
01057
01058
01059
01060
01061
01062
01063
01064 void SIScan::UpdatePMTinDB(
01065 int db_source_id,
01066 int db_mplexid, const QString &friendlyName, int freqid,
01067 int pmt_indx, const ProgramMapTable *pmt,
01068 const DTVChannelInfoList &channels, bool )
01069 {
01070 VERBOSE(VB_IMPORTANT, LOC + pmt->toString());
01071
01072
01073 int chanid = ChannelUtil::GetChanID(
01074 db_mplexid, -1, -1, -1, pmt->ProgramNumber());
01075
01076 QString chan_num = ChannelUtil::GetChanNum(chanid);
01077 if (chan_num.isEmpty() || renameChannels)
01078 {
01079 chan_num = QString("%1#%2")
01080 .arg((freqid) ? freqid : db_mplexid).arg(pmt_indx);
01081 }
01082
01083 QString callsign = ChannelUtil::GetCallsign(chanid);
01084 QString service_name = ChannelUtil::GetServiceName(chanid);
01085
01086 if (callsign.isEmpty())
01087 {
01088 callsign = QString("%1%2")
01089 .arg(ChannelUtil::GetUnknownCallsign())
01090 .arg(chan_num);
01091 }
01092 else if (service_name.isEmpty())
01093 service_name = callsign;
01094
01095 QString common_status_info = tr("%1%2%3 on %4 (%5)")
01096 .arg(service_name)
01097 .arg(service_name.isEmpty() ? "" : QString(" %1 ").arg(tr("as")))
01098 .arg(chan_num)
01099 .arg(friendlyName).arg(freqid);
01100
01101 if (!CheckImportedList(channels, pmt->ProgramNumber(),
01102 service_name, chan_num, common_status_info))
01103 {
01104 return;
01105 }
01106
01107 if (chanid < 0)
01108 {
01109 emit ServiceScanUpdateText(
01110 tr("Adding %1").arg(common_status_info));
01111 chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
01112 ChannelUtil::CreateChannel(
01113 db_mplexid, db_source_id, chanid,
01114 callsign,
01115 service_name,
01116 chan_num,
01117 pmt->ProgramNumber(),
01118 0, 0,
01119 false, false, false, QString::number(freqid));
01120 }
01121 else
01122 {
01123 emit ServiceScanUpdateText(
01124 tr("Updating %1").arg(common_status_info));
01125
01126 bool useeit = false;
01127 bool hidden = false;
01128
01129 ChannelUtil::GetChannelSettings(chanid, useeit, hidden);
01130
01131 ChannelUtil::UpdateChannel(
01132 db_mplexid, db_source_id, chanid,
01133 callsign,
01134 service_name,
01135 chan_num,
01136 pmt->ProgramNumber(),
01137 0, 0,
01138 useeit, hidden, false, QString::number(freqid));
01139 }
01140 }
01141
01142 void SIScan::IgnoreDataOnlyMsg(const QString &name, int aux_num)
01143 {
01144 QString vmsg = QString("Ignoring Data Channel: %1").arg(name);
01145 if (aux_num > 0)
01146 vmsg += QString(" on %1").arg(aux_num);
01147 VERBOSE(VB_SIPARSER, vmsg);
01148
01149
01150
01151 QString tmsg = tr("Skipping %1").arg(name);
01152 if (aux_num > 0)
01153 tmsg += " " + tr("on %1").arg(aux_num);
01154 tmsg += " - " + tr("Data Only Channel (off-air?)");
01155 emit ServiceScanUpdateText(tmsg);
01156 }
01157
01158 void SIScan::IgnoreEmptyChanMsg(const QString &name, int aux_num)
01159 {
01160 QString vmsg = QString("Ignoring Empty Channel: %1").arg(name);
01161 if (aux_num > 0)
01162 vmsg += QString(" on %1").arg(aux_num);
01163 VERBOSE(VB_SIPARSER, vmsg);
01164
01165
01166
01167 QString tmsg = tr("Skipping %1").arg(name);
01168 if (aux_num > 0)
01169 tmsg += " " + tr("on %1").arg(aux_num);
01170 tmsg += " - " + tr("Empty Channel (off-air?)");
01171 emit ServiceScanUpdateText(tmsg);
01172 }
01173
01174 void SIScan::IgnoreAudioOnlyMsg(const QString &name, int aux_num)
01175 {
01176 QString vmsg = QString("Ignoring Audio Only Channel: %1").arg(name);
01177 if (aux_num > 0)
01178 vmsg += QString(" on %1").arg(aux_num);
01179 VERBOSE(VB_SIPARSER, vmsg);
01180
01181
01182
01183 QString tmsg = tr("Skipping %1").arg(name);
01184 if (aux_num > 0)
01185 tmsg += " " + tr("on %1").arg(aux_num);
01186 tmsg += " - " + tr("Audio Only Channel");
01187 emit ServiceScanUpdateText(tmsg);
01188 }
01189
01190 void SIScan::IgnoreEncryptedMsg(const QString &name, int aux_num)
01191 {
01192 QString vmsg = QString("Ignoring Encrypted Channel: %1").arg(name);
01193 if (aux_num > 0)
01194 vmsg += QString(" on %1").arg(aux_num);
01195 VERBOSE(VB_SIPARSER, vmsg);
01196
01197
01198
01199 QString tmsg = tr("Skipping %1").arg(name);
01200 if (aux_num > 0)
01201 tmsg += " " + tr("on %1").arg(aux_num);
01202 tmsg += " - " + tr("Encrypted Channel");
01203 emit ServiceScanUpdateText(tmsg);
01204 }
01205
01206 void SIScan::UpdatePATinDB(
01207 int db_mplexid, const QString &friendlyName, int freqid,
01208 const ProgramAssociationTable *pat, const pmt_map_t &pmt_map,
01209 const DTVChannelInfoList &channels, const QString &si_standard,
01210 bool force_update)
01211 {
01212 VERBOSE(VB_SIPARSER, LOC +
01213 QString("UpdatePATinDB(): tsid: 0x%1 mplex: %2")
01214 .arg(pat->TransportStreamID(),0,16).arg(db_mplexid));
01215
01216 VERBOSE(VB_IMPORTANT, LOC + pat->toString());
01217
01218 int db_source_id = ChannelUtil::GetSourceID(db_mplexid);
01219
01220 for (uint i = 0; i < pat->ProgramCount(); i++)
01221 {
01222 pmt_map_t::const_iterator it = pmt_map.find(pat->ProgramNumber(i));
01223 if (it == pmt_map.end())
01224 {
01225 VERBOSE(VB_SIPARSER,
01226 QString("UpdatePATinDB(): PMT for Program #%1 is missing")
01227 .arg(pat->ProgramNumber(i)));
01228 continue;
01229 }
01230 pmt_vec_t::const_iterator vit = (*it).begin();
01231 for (; vit != (*it).end(); ++vit)
01232 {
01233 VERBOSE(VB_SIPARSER,
01234 QString("UpdatePATinDB(): Prog %1 PID %2: PMT @")
01235 .arg(pat->ProgramNumber(i))
01236 .arg(pat->ProgramPID(i)) << *vit);
01237
01238
01239
01240 if (!(*vit))
01241 continue;
01242 else if ((*vit)->StreamCount() <= 0)
01243 {
01244 IgnoreEmptyChanMsg(friendlyName, pat->ProgramNumber(i));
01245 continue;
01246 }
01247 else if (ignoreAudioOnlyServices &&
01248 (*vit)->IsStillPicture(si_standard))
01249 {
01250 IgnoreAudioOnlyMsg(friendlyName, pat->ProgramNumber(i));
01251 continue;
01252 }
01253 else if (ignoreEncryptedServices && (*vit)->IsEncrypted())
01254 {
01255 IgnoreEncryptedMsg(friendlyName, pat->ProgramNumber(i));
01256 continue;
01257 }
01258
01259 UpdatePMTinDB(db_source_id, db_mplexid, friendlyName, freqid,
01260 i, *vit, channels, force_update);
01261 }
01262 }
01263 }
01264
01265 void SIScan::UpdateVCTinDB(int db_mplexid,
01266 const QString &friendlyName, int freqid,
01267 const VirtualChannelTable *vct,
01268 const DTVChannelInfoList &channels,
01269 bool force_update)
01270 {
01271 (void) force_update;
01272
01273 VERBOSE(VB_SIPARSER, LOC +
01274 QString("UpdateVCTinDB(): tsid: 0x%1 mplex: %1")
01275 .arg(vct->TransportStreamID(),0,16).arg(db_mplexid));
01276
01277 int db_source_id = ChannelUtil::GetSourceID(db_mplexid);
01278
01279 for (uint i = 0; i < vct->ChannelCount(); i++)
01280 {
01281 if (vct->ModulationMode(i) == 0x01 ||
01282 vct->ServiceType(i) == 0x01 )
01283 {
01284 continue;
01285 }
01286
01287 QString basic_status_info = QString("%1 %2-%3")
01288 .arg(vct->ShortChannelName(i))
01289 .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i));
01290
01291 if (vct->ServiceType(i) == 0x04 && ignoreDataServices)
01292 {
01293 IgnoreEmptyChanMsg(basic_status_info, vct->ProgramNumber(i));
01294 continue;
01295 }
01296
01297 if (vct->ServiceType(i) == 0x03 && ignoreAudioOnlyServices)
01298 {
01299 IgnoreAudioOnlyMsg(basic_status_info, vct->ProgramNumber(i));
01300 continue;
01301 }
01302
01303 if (vct->IsAccessControlled(i) && ignoreEncryptedServices)
01304 {
01305 IgnoreEncryptedMsg(basic_status_info, vct->ProgramNumber(i));
01306 continue;
01307 }
01308
01309
01310 int chanid = ChannelUtil::GetChanID(
01311 db_mplexid, vct->ChannelTransportStreamID(i),
01312 vct->MajorChannel(i), vct->MinorChannel(i),
01313 vct->ProgramNumber(i));
01314
01315 QString chan_num = ChannelUtil::GetChanNum(chanid);
01316 if (chan_num.isEmpty() || renameChannels)
01317 {
01318 chan_num = channelFormat
01319 .arg(vct->MajorChannel(i))
01320 .arg(vct->MinorChannel(i));
01321 }
01322
01323 QString callsign = ChannelUtil::GetCallsign(chanid);
01324 if (callsign.isEmpty() || renameChannels)
01325 callsign = vct->ShortChannelName(i);
01326
01327
01328 QString longName = vct->GetExtendedChannelName(i);
01329 if (longName.isEmpty())
01330 longName = vct->ShortChannelName(i);
01331
01332 QString common_status_info = tr("%1 %2-%3 as %4 on %5 (%6)")
01333 .arg(vct->ShortChannelName(i))
01334 .arg(vct->MajorChannel(i)).arg(vct->MinorChannel(i))
01335 .arg(chan_num).arg(friendlyName).arg(freqid);
01336
01337 bool use_eit = !vct->IsHidden(i) ||
01338 (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));
01339
01340
01341 if (!CheckImportedList(channels, vct->ProgramNumber(i),
01342 longName, callsign, common_status_info))
01343 {
01344 continue;
01345 }
01346
01347 QString msg = "";
01348 if (chanid < 0)
01349 {
01350 msg = tr("Adding %1").arg(common_status_info);
01351 chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
01352 if (chanid > 0)
01353 {
01354 bool use_eit = !vct->IsHidden(i) ||
01355 (vct->IsHidden(i) && !vct->IsHiddenInGuide(i));
01356
01357 ChannelUtil::CreateChannel(
01358 db_mplexid,
01359 db_source_id,
01360 chanid,
01361 callsign,
01362 longName,
01363 chan_num,
01364 vct->ProgramNumber(i),
01365 vct->MajorChannel(i), vct->MinorChannel(i),
01366 use_eit,
01367 vct->IsHidden(i), vct->IsHiddenInGuide(i),
01368 QString::number(freqid));
01369 }
01370 }
01371 else
01372 {
01373 msg = tr("Updating %1").arg(common_status_info);
01374 ChannelUtil::UpdateChannel(
01375 db_mplexid,
01376 db_source_id,
01377 chanid,
01378 callsign,
01379 longName,
01380 chan_num,
01381 vct->ProgramNumber(i),
01382 vct->MajorChannel(i), vct->MinorChannel(i),
01383 use_eit,
01384 vct->IsHidden(i), vct->IsHiddenInGuide(i),
01385 QString::number(freqid));
01386 }
01387 emit ServiceScanUpdateText(msg);
01388 VERBOSE(VB_SIPARSER, msg);
01389 }
01390 }
01391
01395 void SIScan::UpdateSDTinDB(int , const ServiceDescriptionTable *sdt,
01396 const DTVChannelInfoList &channels,
01397 bool force_update)
01398 {
01399 if (!sdt->ServiceCount())
01400 return;
01401
01402 int db_mplexid = ChannelUtil::GetMplexID(
01403 sourceID, sdt->TSID(), sdt->OriginalNetworkID());
01404
01405
01406 bool force_guide_present = (sdt->OriginalNetworkID() == 70);
01407
01408
01409 if (db_mplexid == -1)
01410 {
01411 VERBOSE(VB_IMPORTANT, "SDT: Error determing what transport this "
01412 "service table is associated with so failing");
01413 emit ServiceScanUpdateText(
01414 tr("Found channel, but it doesn't match existing tsid. You may "
01415 "wish to delete existing channels and do a full scan."));
01416 return;
01417 }
01418
01419 int db_source_id = ChannelUtil::GetSourceID(db_mplexid);
01420
01421
01422 bool upToDate = (ChannelUtil::GetServiceVersion(db_mplexid) ==
01423 (int)sdt->Version());
01424 if (upToDate && !force_update)
01425 {
01426 emit ServiceScanUpdateText("Channels up to date");
01427 return;
01428 }
01429 if (!upToDate)
01430 ChannelUtil::SetServiceVersion(db_mplexid, sdt->Version());
01431
01432 for (uint i = 0; i < sdt->ServiceCount(); i++)
01433 {
01434
01435 ServiceDescriptor *desc = sdt->GetServiceDescriptor(i);
01436 QString service_name = "";
01437 if (desc)
01438 service_name = desc->ServiceName();
01439
01440 if (service_name.stripWhiteSpace().isEmpty())
01441 service_name = QString("%1 %2")
01442 .arg(sdt->ServiceID(i)).arg(db_mplexid);
01443
01444
01445 QString chan_num = QString::number(sdt->ServiceID(i));
01446 bool have_uk_chan_num =
01447 dvbChanNums.find(sdt->ServiceID(i)) != dvbChanNums.end();
01448 if (have_uk_chan_num)
01449 chan_num = QString::number(dvbChanNums[sdt->ServiceID(i)]);
01450
01451
01452 if (desc && desc->IsDigitalAudio() && ignoreAudioOnlyServices)
01453 {
01454 IgnoreAudioOnlyMsg(service_name, sdt->ServiceID(i));
01455 continue;
01456 }
01457 else if (desc && !desc->IsDTV() && !desc->IsDigitalAudio() &&
01458 ignoreDataServices)
01459 {
01460 IgnoreDataOnlyMsg(service_name, sdt->ServiceID(i));
01461 continue;
01462 }
01463 else if (ignoreEncryptedServices && sdt->IsEncrypted(i))
01464 {
01465 IgnoreEncryptedMsg(service_name, sdt->ServiceID(i));
01466 continue;
01467 }
01468
01469
01470 QString default_authority = "";
01471 desc_list_t parsed =
01472 MPEGDescriptor::Parse(sdt->ServiceDescriptors(i),
01473 sdt->ServiceDescriptorsLength(i));
01474 const unsigned char *def_auth =
01475 MPEGDescriptor::Find(parsed, DescriptorID::default_authority);
01476 if (def_auth)
01477 default_authority =
01478 QString::fromAscii((const char*)def_auth+2, def_auth[1]);
01479
01480 QString common_status_info = service_name;
01481
01482 if (!CheckImportedList(channels, sdt->ServiceID(i),
01483 service_name, service_name, common_status_info))
01484 {
01485 continue;
01486 }
01487
01488
01489 int chanid = ChannelUtil::GetChanID(db_mplexid, -1, -1, -1,
01490 sdt->ServiceID(i));
01491
01492 if (chanid < 0)
01493 {
01494 emit ServiceScanUpdateText(tr("Adding %1").arg(service_name));
01495 chanid = ChannelUtil::CreateChanID(db_source_id, chan_num);
01496 if (chanid > 0)
01497 {
01498 ChannelUtil::CreateChannel(
01499 db_mplexid, db_source_id, chanid,
01500 service_name,
01501 service_name,
01502 chan_num,
01503 sdt->ServiceID(i),
01504 0, 0,
01505 sdt->HasEITSchedule(i) ||
01506 sdt->HasEITPresentFollowing(i) ||
01507 force_guide_present,
01508 false, false, QString::null,
01509 QString::null, "Default", QString::null,
01510 default_authority);
01511 }
01512 }
01513 else if (force_update || (desc && have_uk_chan_num))
01514 {
01515 emit ServiceScanUpdateText(tr("Updating %1").arg(service_name));
01516
01517 bool useeit = false;
01518 bool hidden = false;
01519
01520 ChannelUtil::GetChannelSettings(chanid, useeit, hidden);
01521
01522 if (!renameChannels)
01523 chan_num = ChannelUtil::GetChanNum(chanid);
01524 else
01525 useeit = (sdt->HasEITSchedule(i) ||
01526 sdt->HasEITPresentFollowing(i) ||
01527 force_guide_present);
01528
01529 ChannelUtil::UpdateChannel(
01530 db_mplexid,
01531 db_source_id,
01532 chanid,
01533 service_name,
01534 service_name,
01535 chan_num,
01536 sdt->ServiceID(i),
01537 0, 0,
01538 useeit,
01539 hidden, false, QString::null,
01540 QString::null, QString::null, QString::null,
01541 default_authority);
01542 }
01543 else
01544 {
01545 emit ServiceScanUpdateText(
01546 tr("Skipping %1 - already in DB, and "
01547 "we don't have better data.")
01548 .arg(service_name));
01549 }
01550
01551 if (desc)
01552 delete desc;
01553 }
01554 }
01555
01556
01557
01558
01559
01560 uint64_t SIScan::FindBestMplexFreq(
01561 const uint64_t tuning_freq,
01562 const transport_scan_items_it_t transport, const uint sourceid,
01563 const uint transportid, const uint networkid)
01564 {
01565 uint64_t db_freq;
01566 QString tmp_modulation;
01567 QString tmp_si_std;
01568 uint tmp_transportid, tmp_networkid;
01569 int mplexid;
01570
01571 if (!transportid || !networkid)
01572 return tuning_freq;
01573
01574 mplexid = ChannelUtil::GetMplexID(sourceid, transportid, networkid);
01575 if (mplexid <= 0)
01576 return tuning_freq;
01577
01578 if (!ChannelUtil::GetTuningParams(
01579 (uint)mplexid, tmp_modulation,
01580 db_freq, tmp_transportid, tmp_networkid, tmp_si_std))
01581 {
01582 return tuning_freq;
01583 }
01584
01585 for (uint i = 0; i < (*transport).offset_cnt(); i++)
01586 {
01587 if (db_freq == (*transport).freq_offset(i))
01588 return db_freq;
01589 }
01590
01591 return tuning_freq;
01592 }
01593
01594 uint SIScan::InsertMultiplex(const transport_scan_items_it_t transport)
01595 {
01596 DTVMultiplex tuning = (*transport).tuning;
01597 uint tsid = 0;
01598 uint netid = 0;
01599
01600 tuning.frequency = (*transport).freq_offset(transport.offset());
01601
01602 if (GetDTVSignalMonitor())
01603 {
01604 DTVSignalMonitor *sm = GetDTVSignalMonitor();
01605
01606 tsid = sm->GetDetectedTransportID();
01607 netid = sm->GetDetectedNetworkID();
01608
01609 #ifdef USING_DVB
01610
01611 if (GetDVBSignalMonitor() && GetDVBChannel()->IsTuningParamsProbeSupported())
01612 GetDVBChannel()->ProbeTuningParams(tuning);
01613 #endif // USING_DVB
01614
01615 tuning.frequency = FindBestMplexFreq(
01616 tuning.frequency, transport, (*transport).SourceID, tsid, netid);
01617 }
01618
01619 #ifdef USING_V4L
01620 if (GetChannel())
01621 {
01622
01623 tuning.frequency = tuning.frequency - 1750000;
01624 }
01625 #endif // USING_V4L
01626
01627 return ChannelUtil::CreateMultiplex(
01628 (*transport).SourceID, tuning, tsid, netid);
01629 }