#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SCAN_eDebug(x...) do { if (m_scan_debug) eDebug(x); } while(0) #define SCAN_eDebugNoNewLine(x...) do { if (m_scan_debug) eDebugNoNewLine(x); } while(0) DEFINE_REF(eDVBScan); eDVBScan::eDVBScan(iDVBChannel *channel, bool usePAT, bool debug) :m_channel(channel), m_channel_state(iDVBChannel::state_idle) ,m_ready(0), m_ready_all(usePAT ? (readySDT|readyPAT) : readySDT) ,m_pmt_running(false), m_abort_current_pmt(false), m_flags(0) ,m_usePAT(usePAT), m_scan_debug(debug) { if (m_channel->getDemux(m_demux)) SCAN_eDebug("scan: failed to allocate demux!"); m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection); } eDVBScan::~eDVBScan() { } int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTransportStreamID tsid) { switch (onid.get()) { case 0: case 0x1111: return 0; case 0x13E: // workaround for 11258H and 11470V on hotbird with same ONID/TSID (0x13E/0x578) return orbital_position != 130 || tsid != 0x578; case 1: return orbital_position == 192; case 0x00B1: return tsid != 0x00B0; case 0x0002: return abs(orbital_position-282) < 6; default: return onid.get() < 0xFF00; } } eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash) { // on valid ONIDs, ignore frequency ("sub network") part if (isValidONIDTSID((hash >> 16) & 0xFFFF, onid, tsid)) hash &= ~0xFFFF; return eDVBNamespace(hash); } void eDVBScan::stateChange(iDVBChannel *ch) { int state; if (ch->getState(state)) return; if (m_channel_state == state) return; if (state == iDVBChannel::state_ok) { startFilter(); m_channel_state = state; } else if (state == iDVBChannel::state_failed) { m_ch_unavailable.push_back(m_ch_current); nextChannel(); } /* unavailable will timeout, anyway. */ } RESULT eDVBScan::nextChannel() { ePtr fe; m_SDT = 0; m_PAT = 0; m_BAT = 0; m_NIT = 0, m_PMT = 0; m_ready = 0; m_pat_tsid = eTransportStreamID(); /* check what we need */ m_ready_all = readySDT; if (m_flags & scanNetworkSearch) m_ready_all |= readyNIT; if (m_flags & scanSearchBAT) m_ready_all |= readyBAT; if (m_usePAT) m_ready_all |= readyPAT; if (m_ch_toScan.empty()) { SCAN_eDebug("no channels left to scan."); SCAN_eDebug("%d channels scanned, %d were unavailable.", m_ch_scanned.size(), m_ch_unavailable.size()); SCAN_eDebug("%d channels in database.", m_new_channels.size()); m_event(evtFinish); return -ENOENT; } m_ch_current = m_ch_toScan.front(); m_ch_toScan.pop_front(); if (m_channel->getFrontend(fe)) { m_event(evtFail); return -ENOTSUP; } m_chid_current = eDVBChannelID(); m_channel_state = iDVBChannel::state_idle; if (fe->tune(*m_ch_current)) return nextChannel(); m_event(evtUpdate); return 0; } RESULT eDVBScan::startFilter() { bool startSDT=true; assert(m_demux); /* only start required filters filter */ if (m_ready_all & readyPAT) startSDT = m_ready & readyPAT; // m_ch_current is not set, when eDVBScan is just used for a SDT update if (!m_ch_current) { unsigned int channelFlags; m_channel->getCurrentFrontendParameters(m_ch_current); m_ch_current->getFlags(channelFlags); if (channelFlags & iDVBFrontendParameters::flagOnlyFree) m_flags |= scanOnlyFree; } m_SDT = 0; if (startSDT && (m_ready_all & readySDT)) { m_SDT = new eTable(m_scan_debug); int tsid=-1; if (m_ready & readyPAT && m_ready & validPAT) { std::vector::const_iterator i = m_PAT->getSections().begin(); assert(i != m_PAT->getSections().end()); tsid = (*i)->getTableIdExtension(); // in PAT this is the transport stream id m_pat_tsid = eTransportStreamID(tsid); for (; i != m_PAT->getSections().end(); ++i) { const ProgramAssociationSection &pat = **i; ProgramAssociationConstIterator program = pat.getPrograms()->begin(); for (; program != pat.getPrograms()->end(); ++program) m_pmts_to_read.insert(std::pair((*program)->getProgramNumber(), service((*program)->getProgramMapPid()))); } m_PMT = new eTable(m_scan_debug); CONNECT(m_PMT->tableReady, eDVBScan::PMTready); PMTready(-2); // KabelBW HACK ... on 618Mhz and 626Mhz the transport stream id in PAT and SDT is different { int type; m_ch_current->getSystem(type); if (type == iDVBFrontend::feCable) { eDVBFrontendParametersCable parm; m_ch_current->getDVBC(parm); if ((tsid == 0x00d7 && abs(parm.frequency-618000) < 2000) || (tsid == 0x00d8 && abs(parm.frequency-626000) < 2000)) tsid = -1; } } } if (tsid == -1) { if (m_SDT->start(m_demux, eDVBSDTSpec())) return -1; } else if (m_SDT->start(m_demux, eDVBSDTSpec(tsid, true))) return -1; CONNECT(m_SDT->tableReady, eDVBScan::SDTready); } if (!(m_ready & readyPAT)) { m_PAT = 0; if (m_ready_all & readyPAT) { m_PAT = new eTable(m_scan_debug); if (m_PAT->start(m_demux, eDVBPATSpec(4000))) return -1; CONNECT(m_PAT->tableReady, eDVBScan::PATready); } m_NIT = 0; if (m_ready_all & readyNIT) { m_NIT = new eTable(m_scan_debug); if (m_NIT->start(m_demux, eDVBNITSpec())) return -1; CONNECT(m_NIT->tableReady, eDVBScan::NITready); } m_BAT = 0; if (m_ready_all & readyBAT) { m_BAT = new eTable(m_scan_debug); if (m_BAT->start(m_demux, eDVBBATSpec())) return -1; CONNECT(m_BAT->tableReady, eDVBScan::BATready); } } return 0; } void eDVBScan::SDTready(int err) { SCAN_eDebug("got sdt %d", err); m_ready |= readySDT; if (!err) m_ready |= validSDT; channelDone(); } void eDVBScan::NITready(int err) { SCAN_eDebug("got nit, err %d", err); m_ready |= readyNIT; if (!err) m_ready |= validNIT; channelDone(); } void eDVBScan::BATready(int err) { SCAN_eDebug("got bat"); m_ready |= readyBAT; if (!err) m_ready |= validBAT; channelDone(); } void eDVBScan::PATready(int err) { SCAN_eDebug("got pat"); m_ready |= readyPAT; if (!err) m_ready |= validPAT; startFilter(); // for starting the SDT filter } void eDVBScan::PMTready(int err) { SCAN_eDebug("got pmt %d", err); if (!err) { bool scrambled = false; bool have_audio = false; bool have_video = false; unsigned short pcrpid = 0xFFFF; std::vector::const_iterator i; for (i = m_PMT->getSections().begin(); i != m_PMT->getSections().end(); ++i) { const ProgramMapSection &pmt = **i; if (pcrpid == 0xFFFF) pcrpid = pmt.getPcrPid(); else SCAN_eDebug("already have a pcrpid %04x %04x", pcrpid, pmt.getPcrPid()); ElementaryStreamInfoConstIterator es; for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es) { int isaudio = 0, isvideo = 0, is_scrambled = 0; switch ((*es)->getType()) { case 0x1b: // AVC Video Stream (MPEG4 H264) case 0x01: // MPEG 1 video case 0x02: // MPEG 2 video isvideo = 1; //break; fall through !!! case 0x03: // MPEG 1 audio case 0x04: // MPEG 2 audio: if (!isvideo) isaudio = 1; //break; fall through !!! case 0x06: // PES Private case 0x81: // user private /* PES private can contain AC-3, DTS or lots of other stuff. check descriptors to get the exact type. */ for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin(); desc != (*es)->getDescriptors()->end(); ++desc) { uint8_t tag = (*desc)->getTag(); if (!isaudio && !isvideo) { switch (tag) { case DTS_DESCRIPTOR: case AAC_DESCRIPTOR: case AC3_DESCRIPTOR: isaudio = 1; break; case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */ { /* libdvbsi++ doesn't yet support this descriptor type, so work around. */ if ((*desc)->getLength() != 4) break; unsigned char descr[6]; (*desc)->writeToBuffer(descr); int format_identifier = (descr[2] << 24) | (descr[3] << 16) | (descr[4] << 8) | (descr[5]); switch (format_identifier) { case 0x41432d33: isaudio = 1; default: break; } break; } } } if (tag == CA_DESCRIPTOR) is_scrambled = 1; } break; } if (isaudio) have_audio = true; else if (isvideo) have_video = true; else continue; if (is_scrambled) scrambled = true; } for (DescriptorConstIterator desc = pmt.getDescriptors()->begin(); desc != pmt.getDescriptors()->end(); ++desc) { if ((*desc)->getTag() == CA_DESCRIPTOR) scrambled = true; } } m_pmt_in_progress->second.scrambled = scrambled; if ( have_video ) m_pmt_in_progress->second.serviceType = 1; else if ( have_audio ) m_pmt_in_progress->second.serviceType = 2; else m_pmt_in_progress->second.serviceType = 100; } if (err == -1) // timeout or removed by sdt m_pmts_to_read.erase(m_pmt_in_progress++); else if (m_pmt_running) ++m_pmt_in_progress; else { m_pmt_in_progress = m_pmts_to_read.begin(); m_pmt_running = true; } if (m_pmt_in_progress != m_pmts_to_read.end()) m_PMT->start(m_demux, eDVBPMTSpec(m_pmt_in_progress->second.pmtPid, m_pmt_in_progress->first, 4000)); else { m_PMT = 0; m_pmt_running = false; channelDone(); } } void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm) { /* add it to the list of known channels. */ if (chid) m_new_channels.insert(std::pair >(chid, feparm)); } void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm) { /* check if we don't already have that channel ... */ int type; feparm->getSystem(type); switch(type) { case iDVBFrontend::feSatellite: { eDVBFrontendParametersSatellite parm; feparm->getDVBS(parm); SCAN_eDebug("try to add %d %d %d %d %d %d", parm.orbital_position, parm.frequency, parm.symbol_rate, parm.polarisation, parm.fec, parm.modulation); break; } case iDVBFrontend::feCable: { eDVBFrontendParametersCable parm; feparm->getDVBC(parm); SCAN_eDebug("try to add %d %d %d %d", parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner); break; } case iDVBFrontend::feTerrestrial: { eDVBFrontendParametersTerrestrial parm; feparm->getDVBT(parm); SCAN_eDebug("try to add %d %d %d %d %d %d %d %d", parm.frequency, parm.modulation, parm.transmission_mode, parm.hierarchy, parm.guard_interval, parm.code_rate_LP, parm.code_rate_HP, parm.bandwidth); break; } } int found_count=0; /* ... in the list of channels to scan */ for (std::list >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();) { if (sameChannel(*i, feparm)) { if (!found_count) { *i = feparm; // update SCAN_eDebug("update"); } else { SCAN_eDebug("remove dupe"); m_ch_toScan.erase(i++); continue; } ++found_count; } ++i; } if (found_count > 0) { SCAN_eDebug("already in todo list"); return; } /* ... in the list of successfully scanned channels */ for (std::list >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i) if (sameChannel(*i, feparm)) { SCAN_eDebug("successfully scanned"); return; } /* ... in the list of unavailable channels */ for (std::list >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i) if (sameChannel(*i, feparm, true)) { SCAN_eDebug("scanned but not available"); return; } /* ... on the current channel */ if (sameChannel(m_ch_current, feparm)) { SCAN_eDebug("is current"); return; } SCAN_eDebug("really add"); /* otherwise, add it to the todo list. */ m_ch_toScan.push_front(feparm); // better.. then the rotor not turning wild from east to west :) } int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2, bool exact) const { int diff; if (ch1->calculateDifference(ch2, diff, exact)) return 0; if (diff < 4000) // more than 4mhz difference? return 1; return 0; } void eDVBScan::channelDone() { if (m_ready & validSDT && (!(m_flags & scanOnlyFree) || !m_pmt_running)) { unsigned long hash = 0; m_ch_current->getHash(hash); eDVBNamespace dvbnamespace = buildNamespace( (**m_SDT->getSections().begin()).getOriginalNetworkId(), (**m_SDT->getSections().begin()).getTransportStreamId(), hash); SCAN_eDebug("SDT: "); std::vector::const_iterator i; for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i) processSDT(dvbnamespace, **i); m_ready &= ~validSDT; } if (m_ready & validNIT) { int system; std::list > m_ch_toScan_backup; m_ch_current->getSystem(system); SCAN_eDebug("dumping NIT"); if (m_flags & clearToScanOnFirstNIT) { m_ch_toScan_backup = m_ch_toScan; m_ch_toScan.clear(); } std::vector::const_iterator i; for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i) { const TransportStreamInfoList &tsinfovec = *(*i)->getTsInfo(); for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin()); tsinfo != tsinfovec.end(); ++tsinfo) { SCAN_eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(), (*tsinfo)->getOriginalNetworkId()); eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId(); eTransportStreamID tsid = (*tsinfo)->getTransportStreamId(); for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin(); desc != (*tsinfo)->getDescriptors()->end(); ++desc) { switch ((*desc)->getTag()) { case CABLE_DELIVERY_SYSTEM_DESCRIPTOR: { if (system != iDVBFrontend::feCable) break; // when current locked transponder is no cable transponder ignore this descriptor CableDeliverySystemDescriptor &d = (CableDeliverySystemDescriptor&)**desc; ePtr feparm = new eDVBFrontendParameters; eDVBFrontendParametersCable cable; cable.set(d); feparm->setDVBC(cable); unsigned long hash=0; feparm->getHash(hash); eDVBNamespace ns = buildNamespace(onid, tsid, hash); addChannelToScan( eDVBChannelID(ns, tsid, onid), feparm); break; } case TERRESTRIAL_DELIVERY_SYSTEM_DESCRIPTOR: { if (system != iDVBFrontend::feTerrestrial) break; // when current locked transponder is no terrestrial transponder ignore this descriptor TerrestrialDeliverySystemDescriptor &d = (TerrestrialDeliverySystemDescriptor&)**desc; ePtr feparm = new eDVBFrontendParameters; eDVBFrontendParametersTerrestrial terr; terr.set(d); feparm->setDVBT(terr); unsigned long hash=0; feparm->getHash(hash); eDVBNamespace ns = buildNamespace(onid, tsid, hash); addChannelToScan( eDVBChannelID(ns, tsid, onid), feparm); break; } case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR: { if (system != iDVBFrontend::feSatellite) break; // when current locked transponder is no satellite transponder ignore this descriptor SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc; if (d.getFrequency() < 10000) break; ePtr feparm = new eDVBFrontendParameters; eDVBFrontendParametersSatellite sat; sat.set(d); eDVBFrontendParametersSatellite p; m_ch_current->getDVBS(p); if ( abs(p.orbital_position - sat.orbital_position) < 5 ) sat.orbital_position = p.orbital_position; if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 ) { SCAN_eDebug("found transponder with incorrect west/east flag ... correct this"); sat.orbital_position = p.orbital_position; } feparm->setDVBS(sat); if ( p.orbital_position != sat.orbital_position) SCAN_eDebug("dropping this transponder, it's on another satellite."); else { unsigned long hash=0; feparm->getHash(hash); addChannelToScan( eDVBChannelID(buildNamespace(onid, tsid, hash), tsid, onid), feparm); } break; } default: SCAN_eDebug("descr<%x>", (*desc)->getTag()); break; } } } } /* a pitfall is to have the clearToScanOnFirstNIT-flag set, and having channels which have no or invalid NIT. this code will not erase the toScan list unless at least one valid entry has been found. This is not a perfect solution, as the channel could contain a partial NIT. Life's bad. */ if (m_flags & clearToScanOnFirstNIT) { if (m_ch_toScan.empty()) { eWarning("clearToScanOnFirstNIT was set, but NIT is invalid. Refusing to stop scan."); m_ch_toScan = m_ch_toScan_backup; } else m_flags &= ~clearToScanOnFirstNIT; } m_ready &= ~validNIT; } if (m_pmt_running || (m_ready & m_ready_all) != m_ready_all) { if (m_abort_current_pmt) { m_abort_current_pmt = false; PMTready(-1); } return; } SCAN_eDebug("channel done!"); /* if we had services on this channel, we declare this channels as "known good". add it. (TODO: not yet implemented) a NIT entry could have possible overridden our frontend data with more exact data. (TODO: not yet implemented) the tuning process could have lead to more exact data than the user entered. The channel id was probably corrected by the data written in the SDT. this is important, as "initial transponder lists" usually don't have valid CHIDs (and that's good). These are the reasons for adding the transponder here, and not before. */ for (m_pmt_in_progress = m_pmts_to_read.begin(); m_pmt_in_progress != m_pmts_to_read.end();) { int type; eServiceReferenceDVB ref; ePtr service = new eDVBService; if (!m_chid_current) { unsigned long hash = 0; m_ch_current->getHash(hash); m_chid_current = eDVBChannelID( buildNamespace(eOriginalNetworkID(0), m_pat_tsid, hash), m_pat_tsid, eOriginalNetworkID(0)); } if (m_pmt_in_progress->second.serviceType == 1) SCAN_eDebug("SID %04x is VIDEO", m_pmt_in_progress->first); else if (m_pmt_in_progress->second.serviceType == 2) SCAN_eDebug("SID %04x is AUDIO", m_pmt_in_progress->first); else SCAN_eDebug("SID %04x is DATA", m_pmt_in_progress->first); ref.set(m_chid_current); ref.setServiceID(m_pmt_in_progress->first); ref.setServiceType(m_pmt_in_progress->second.serviceType); if (!m_ch_current->getSystem(type)) { char sname[255]; char pname[255]; memset(pname, 0, sizeof(pname)); memset(sname, 0, sizeof(sname)); switch(type) { case iDVBFrontend::feSatellite: { eDVBFrontendParametersSatellite parm; m_ch_current->getDVBS(parm); snprintf(sname, 255, "%d%c SID 0x%02x", parm.frequency/1000, parm.polarisation ? 'V' : 'H', m_pmt_in_progress->first); snprintf(pname, 255, "%s %s %d%c %d.%d°%c", parm.system ? "DVB-S2" : "DVB-S", parm.modulation == 1 ? "QPSK" : "8PSK", parm.frequency/1000, parm.polarisation ? 'V' : 'H', parm.orbital_position/10, parm.orbital_position%10, parm.orbital_position > 0 ? 'E' : 'W'); break; } case iDVBFrontend::feTerrestrial: { eDVBFrontendParametersTerrestrial parm; m_ch_current->getDVBT(parm); snprintf(sname, 255, "%d SID 0x%02x", parm.frequency/1000, m_pmt_in_progress->first); break; } case iDVBFrontend::feCable: { eDVBFrontendParametersCable parm; m_ch_current->getDVBC(parm); snprintf(sname, 255, "%d SID 0x%02x", parm.frequency/1000, m_pmt_in_progress->first); break; } } SCAN_eDebug("name '%s', provider_name '%s'", sname, pname); service->m_service_name = convertDVBUTF8(sname); service->genSortName(); service->m_provider_name = convertDVBUTF8(pname); } if (!(m_flags & scanOnlyFree) || !m_pmt_in_progress->second.scrambled) { SCAN_eDebug("add not scrambled!"); std::pair >::iterator, bool> i = m_new_services.insert(std::pair >(ref, service)); if (i.second) { m_last_service = i.first; m_event(evtNewService); } } else SCAN_eDebug("dont add... is scrambled!"); m_pmts_to_read.erase(m_pmt_in_progress++); } if (!m_chid_current) eWarning("SCAN: the current channel's ID was not corrected - not adding channel."); else addKnownGoodChannel(m_chid_current, m_ch_current); m_ch_scanned.push_back(m_ch_current); for (std::list >::iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end();) { if (sameChannel(*i, m_ch_current)) { SCAN_eDebug("remove dupe 2"); m_ch_toScan.erase(i++); continue; } ++i; } nextChannel(); } void eDVBScan::start(const eSmartPtrList &known_transponders, int flags) { m_flags = flags; m_ch_toScan.clear(); m_ch_scanned.clear(); m_ch_unavailable.clear(); m_new_channels.clear(); m_new_services.clear(); m_last_service = m_new_services.end(); for (eSmartPtrList::const_iterator i(known_transponders.begin()); i != known_transponders.end(); ++i) { bool exist=false; for (std::list >::const_iterator ii(m_ch_toScan.begin()); ii != m_ch_toScan.end(); ++ii) { if (sameChannel(*i, *ii, true)) { exist=true; break; } } if (!exist) m_ch_toScan.push_back(*i); } nextChannel(); } void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags) { if (m_flags & scanRemoveServices) { bool clearTerrestrial=false; bool clearCable=false; std::set scanned_sat_positions; std::list >::iterator it(m_ch_scanned.begin()); for (;it != m_ch_scanned.end(); ++it) { if (m_flags & scanDontRemoveUnscanned) db->removeServices(&(*(*it))); else { int system; (*it)->getSystem(system); switch(system) { case iDVBFrontend::feSatellite: { eDVBFrontendParametersSatellite sat_parm; (*it)->getDVBS(sat_parm); scanned_sat_positions.insert(sat_parm.orbital_position); break; } case iDVBFrontend::feTerrestrial: { clearTerrestrial=true; break; } case iDVBFrontend::feCable: { clearCable=true; break; } } } } for (it=m_ch_unavailable.begin();it != m_ch_unavailable.end(); ++it) { if (m_flags & scanDontRemoveUnscanned) db->removeServices(&(*(*it))); else { int system; (*it)->getSystem(system); switch(system) { case iDVBFrontend::feSatellite: { eDVBFrontendParametersSatellite sat_parm; (*it)->getDVBS(sat_parm); scanned_sat_positions.insert(sat_parm.orbital_position); break; } case iDVBFrontend::feTerrestrial: { clearTerrestrial=true; break; } case iDVBFrontend::feCable: { clearCable=true; break; } } } } if (clearTerrestrial) { eDVBChannelID chid; chid.dvbnamespace=0xEEEE0000; db->removeServices(chid); } if (clearCable) { eDVBChannelID chid; chid.dvbnamespace=0xFFFF0000; db->removeServices(chid); } for (std::set::iterator x(scanned_sat_positions.begin()); x != scanned_sat_positions.end(); ++x) { eDVBChannelID chid; if (m_flags & scanDontRemoveFeeds) chid.dvbnamespace = eDVBNamespace((*x)<<16); // eDebug("remove %d %08x", *x, chid.dvbnamespace.get()); db->removeServices(chid, *x); } } for (std::map >::const_iterator ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch) { if (m_flags & scanOnlyFree) { eDVBFrontendParameters *ptr = (eDVBFrontendParameters*)&(*ch->second); ptr->setFlags(iDVBFrontendParameters::flagOnlyFree); } db->addChannelToList(ch->first, ch->second); } for (std::map >::const_iterator service(m_new_services.begin()); service != m_new_services.end(); ++service) { ePtr dvb_service; if (!db->getService(service->first, dvb_service)) { if (dvb_service->m_flags & eDVBService::dxNoSDT) continue; if (!(dvb_service->m_flags & eDVBService::dxHoldName)) { dvb_service->m_service_name = service->second->m_service_name; dvb_service->m_service_name_sort = service->second->m_service_name_sort; } dvb_service->m_provider_name = service->second->m_provider_name; if (service->second->m_ca.size()) dvb_service->m_ca = service->second->m_ca; if (!dontRemoveOldFlags) // do not remove new found flags when not wished dvb_service->m_flags &= ~eDVBService::dxNewFound; } else { db->addService(service->first, service->second); if (!(m_flags & scanRemoveServices)) service->second->m_flags |= eDVBService::dxNewFound; } } } RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionSection &sdt) { const ServiceDescriptionList &services = *sdt.getDescriptions(); SCAN_eDebug("ONID: %04x", sdt.getOriginalNetworkId()); eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId()); /* save correct CHID for this channel */ m_chid_current = chid; for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s) { unsigned short service_id = (*s)->getServiceId(); SCAN_eDebugNoNewLine("SID %04x: ", service_id); bool add = true; if (m_flags & scanOnlyFree) { std::map::iterator it = m_pmts_to_read.find(service_id); if (it != m_pmts_to_read.end()) { if (it->second.scrambled) { SCAN_eDebug("is scrambled!"); add = false; } else SCAN_eDebug("is free"); } else { SCAN_eDebug("not found in PAT.. so we assume it is scrambled!!"); add = false; } } if (add) { eServiceReferenceDVB ref; ePtr service = new eDVBService; ref.set(chid); ref.setServiceID(service_id); for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin(); desc != (*s)->getDescriptors()->end(); ++desc) { switch ((*desc)->getTag()) { case SERVICE_DESCRIPTOR: { ServiceDescriptor &d = (ServiceDescriptor&)**desc; ref.setServiceType(d.getServiceType()); service->m_service_name = convertDVBUTF8(d.getServiceName()); service->genSortName(); service->m_provider_name = convertDVBUTF8(d.getServiceProviderName()); SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str()); break; } case CA_IDENTIFIER_DESCRIPTOR: { CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc; const CaSystemIdList &caids = *d.getCaSystemIds(); SCAN_eDebugNoNewLine("CA "); for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i) { SCAN_eDebugNoNewLine("%04x ", *i); service->m_ca.push_front(*i); } SCAN_eDebug(""); break; } default: SCAN_eDebug("descr<%x>", (*desc)->getTag()); break; } } std::pair >::iterator, bool> i = m_new_services.insert(std::pair >(ref, service)); if (i.second) { m_last_service = i.first; m_event(evtNewService); } } if (m_pmt_running && m_pmt_in_progress->first == service_id) m_abort_current_pmt = true; else m_pmts_to_read.erase(service_id); } return 0; } RESULT eDVBScan::connectEvent(const Slot1 &event, ePtr &connection) { connection = new eConnection(this, m_event.connect(event)); return 0; } void eDVBScan::getStats(int &transponders_done, int &transponders_total, int &services) { transponders_done = m_ch_scanned.size() + m_ch_unavailable.size(); transponders_total = m_ch_toScan.size() + transponders_done; services = m_new_services.size(); } void eDVBScan::getLastServiceName(std::string &last_service_name) { if (m_last_service == m_new_services.end()) last_service_name = ""; else last_service_name = m_last_service->second->m_service_name; } RESULT eDVBScan::getFrontend(ePtr &fe) { if (m_channel) return m_channel->getFrontend(fe); fe = 0; return -1; } RESULT eDVBScan::getCurrentTransponder(ePtr &tp) { if (m_ch_current) { tp = m_ch_current; return 0; } tp = 0; return -1; }