some service scan improovements
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Mon, 11 Aug 2008 22:02:24 +0000 (22:02 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Mon, 11 Aug 2008 22:02:24 +0000 (22:02 +0000)
- add a only free scan
- the scan now finds also services not listed in SDT
- add option "clear before scan" also for single transponder searches

For the only free scan a change in the main lamedb transponder format was
needed... i think this breaks some external settings editors

To detect the service format now the service database file starts with "eDVB
services /4/" .. the old format was "eDVB services /3/" .. e2 can read the
old and the new format.. but it writes always the new format!

lib/components/scan.h
lib/dvb/db.cpp
lib/dvb/db.h
lib/dvb/frontend.cpp
lib/dvb/frontend.h
lib/dvb/idvb.h
lib/dvb/scan.cpp
lib/dvb/scan.h
lib/python/Screens/ScanSetup.py

index 3d8984e..222158b 100644 (file)
@@ -44,7 +44,8 @@ public:
        void addInitial(const eDVBFrontendParametersTerrestrial &p);
        
                /* please keep the flags in sync with lib/dvb/scan.h ! */
-       enum { scanNetworkSearch=1, scanRemoveServices=4, scanDontRemoveFeeds=8, clearToScanOnFirstNIT = 16 };
+       enum { scanNetworkSearch=1, scanRemoveServices=4, scanDontRemoveFeeds=8, scanDontRemoveUnscanned=16, clearToScanOnFirstNIT = 32, scanOnlyFree = 64 };
+
        int start(int feid, int flags=0 );
        SWIG_VOID(RESULT) getFrontend(ePtr<iDVBFrontend> &SWIG_OUTPUT);
        SWIG_VOID(RESULT) getCurrentTransponder(ePtr<iDVBFrontendParameters> &SWIG_OUTPUT);
index 9035b8f..02ecc1d 100644 (file)
@@ -284,13 +284,14 @@ void eDVBDB::loadServicelist(const char *file)
                return;
        }
        char line[256];
-       if ((!fgets(line, 256, f)) || strncmp(line, "eDVB services", 13))
+       int version=3;
+       if ((!fgets(line, 256, f)) || sscanf(line, "eDVB services /%d/", &version) != 1)
        {
-               eDebug("not a servicefile");
+               eDebug("not a valid servicefile");
                fclose(f);
                return;
        }
-       eDebug("reading services");
+       eDebug("reading services (version %d)", version);
        if ((!fgets(line, 256, f)) || strcmp(line, "transponders\n"))
        {
                eDebug("services invalid, no transponders");
@@ -325,11 +326,15 @@ void eDVBDB::loadServicelist(const char *file)
                        {
                                eDVBFrontendParametersSatellite sat;
                                int frequency, symbol_rate, polarisation, fec, orbital_position, inversion,
+                                       flags=0,
                                        system=eDVBFrontendParametersSatellite::System::DVB_S,
                                        modulation=eDVBFrontendParametersSatellite::Modulation::QPSK,
                                        rolloff=eDVBFrontendParametersSatellite::RollOff::alpha_0_35,
                                        pilot=eDVBFrontendParametersSatellite::Pilot::Unknown;
-                               sscanf(line+3, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", &frequency, &symbol_rate, &polarisation, &fec, &orbital_position, &inversion, &system, &modulation, &rolloff, &pilot);
+                               if (version == 3)
+                                       sscanf(line+3, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", &frequency, &symbol_rate, &polarisation, &fec, &orbital_position, &inversion, &system, &modulation, &rolloff, &pilot);
+                               else
+                                       sscanf(line+3, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", &frequency, &symbol_rate, &polarisation, &fec, &orbital_position, &inversion, &flags, &system, &modulation, &rolloff, &pilot);
                                sat.frequency = frequency;
                                sat.symbol_rate = symbol_rate;
                                sat.polarisation = polarisation;
@@ -342,11 +347,12 @@ void eDVBDB::loadServicelist(const char *file)
                                sat.rolloff = rolloff;
                                sat.pilot = pilot;
                                feparm->setDVBS(sat);
+                               feparm->setFlags(flags);
                        } else if (line[1]=='t')
                        {
                                eDVBFrontendParametersTerrestrial ter;
-                               int frequency, bandwidth, code_rate_HP, code_rate_LP, modulation, transmission_mode, guard_interval, hierarchy, inversion;
-                               sscanf(line+3, "%d:%d:%d:%d:%d:%d:%d:%d:%d", &frequency, &bandwidth, &code_rate_HP, &code_rate_LP, &modulation, &transmission_mode, &guard_interval, &hierarchy, &inversion);
+                               int frequency, bandwidth, code_rate_HP, code_rate_LP, modulation, transmission_mode, guard_interval, hierarchy, inversion, flags=0;
+                               sscanf(line+3, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d", &frequency, &bandwidth, &code_rate_HP, &code_rate_LP, &modulation, &transmission_mode, &guard_interval, &hierarchy, &inversion, &flags);
                                ter.frequency = frequency;
                                ter.bandwidth = bandwidth;
                                ter.code_rate_HP = code_rate_HP;
@@ -357,20 +363,23 @@ void eDVBDB::loadServicelist(const char *file)
                                ter.hierarchy = hierarchy;
                                ter.inversion = inversion;
                                feparm->setDVBT(ter);
+                               feparm->setFlags(flags);
                        } else if (line[1]=='c')
                        {
                                eDVBFrontendParametersCable cab;
                                int frequency, symbol_rate,
                                        inversion=eDVBFrontendParametersCable::Inversion::Unknown,
                                        modulation=eDVBFrontendParametersCable::Modulation::Auto,
-                                       fec_inner=eDVBFrontendParametersCable::FEC::fAuto;
-                               sscanf(line+3, "%d:%d:%d:%d:%d", &frequency, &symbol_rate, &inversion, &modulation, &fec_inner);
+                                       fec_inner=eDVBFrontendParametersCable::FEC::fAuto,
+                                       flags=0;
+                               sscanf(line+3, "%d:%d:%d:%d:%d:%d", &frequency, &symbol_rate, &inversion, &modulation, &fec_inner, &flags);
                                cab.frequency = frequency;
                                cab.fec_inner = fec_inner;
                                cab.inversion = inversion;
                                cab.symbol_rate = symbol_rate;
                                cab.modulation = modulation;
                                feparm->setDVBC(cab);
+                               feparm->setFlags(flags);
                        }
                }
                addChannelToList(channelid, feparm);
@@ -469,7 +478,7 @@ void eDVBDB::saveServicelist(const char *file)
        int channels=0, services=0;
        if (!f)
                eFatal("couldn't save lame channel db!");
-       fprintf(f, "eDVB services /3/\n");
+       fprintf(f, "eDVB services /4/\n");
        fprintf(f, "transponders\n");
        for (std::map<eDVBChannelID, channel>::const_iterator i(m_channels.begin());
                        i != m_channels.end(); ++i)
@@ -482,15 +491,18 @@ void eDVBDB::saveServicelist(const char *file)
                eDVBFrontendParametersSatellite sat;
                eDVBFrontendParametersTerrestrial ter;
                eDVBFrontendParametersCable cab;
+               unsigned int flags;  // flagOnlyFree yet..
+               ch.m_frontendParameters->getFlags(flags);
                if (!ch.m_frontendParameters->getDVBS(sat))
                {
                        if (sat.system == eDVBFrontendParametersSatellite::System::DVB_S2)
                        {
-                               fprintf(f, "\ts %d:%d:%d:%d:%d:%d:%d:%d:%d",
+                               fprintf(f, "\ts %d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
                                        sat.frequency, sat.symbol_rate,
                                        sat.polarisation, sat.fec,
                                        sat.orbital_position > 1800 ? sat.orbital_position - 3600 : sat.orbital_position,
                                        sat.inversion,
+                                       flags,
                                        sat.system,
                                        sat.modulation,
                                        sat.rolloff);
@@ -501,24 +513,24 @@ void eDVBDB::saveServicelist(const char *file)
                        }
                        else
                        {
-                               fprintf(f, "\ts %d:%d:%d:%d:%d:%d\n",
+                               fprintf(f, "\ts %d:%d:%d:%d:%d:%d:%d\n",
                                        sat.frequency, sat.symbol_rate,
                                        sat.polarisation, sat.fec,
                                        sat.orbital_position > 1800 ? sat.orbital_position - 3600 : sat.orbital_position,
-                                       sat.inversion);
+                                       sat.inversion, flags);
                        }
                }
                else if (!ch.m_frontendParameters->getDVBT(ter))
                {
-                       fprintf(f, "\tt %d:%d:%d:%d:%d:%d:%d:%d:%d\n",
+                       fprintf(f, "\tt %d:%d:%d:%d:%d:%d:%d:%d:%d:%d\n",
                                ter.frequency, ter.bandwidth, ter.code_rate_HP,
                                ter.code_rate_LP, ter.modulation, ter.transmission_mode,
-                               ter.guard_interval, ter.hierarchy, ter.inversion);
+                               ter.guard_interval, ter.hierarchy, ter.inversion, flags);
                }
                else if (!ch.m_frontendParameters->getDVBC(cab))
                {
-                       fprintf(f, "\tc %d:%d:%d:%d:%d\n",
-                               cab.frequency, cab.symbol_rate, cab.inversion, cab.modulation, cab.fec_inner);
+                       fprintf(f, "\tc %d:%d:%d:%d:%d:%d\n",
+                               cab.frequency, cab.symbol_rate, cab.inversion, cab.modulation, cab.fec_inner, flags);
                }
                fprintf(f, "/\n");
                channels++;
@@ -1228,6 +1240,45 @@ RESULT eDVBDB::removeServices(eDVBChannelID chid, unsigned int orbpos)
        return ret;
 }
 
+RESULT eDVBDB::removeServices(iDVBFrontendParameters *feparm)
+{
+       int ret = -1;
+       std::set<eDVBChannelID> removed_chids;
+       std::map<eDVBChannelID, channel>::iterator it(m_channels.begin());
+       while (it != m_channels.end())
+       {
+               int diff;
+               if (!feparm->calculateDifference(&(*it->second.m_frontendParameters), diff, false))
+               {
+                       if (diff < 4000)
+                       {
+                               removed_chids.insert(it->first);
+                               m_channels.erase(it++);
+                       }
+                       else
+                               ++it;
+               }
+               else
+                       ++it;
+       }
+       if (!removed_chids.empty())
+       {
+               std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator service(m_services.begin());
+               while(service != m_services.end())
+               {
+                       eDVBChannelID chid;
+                       service->first.getChannelID(chid);
+                       std::set<eDVBChannelID>::iterator it(removed_chids.find(chid));
+                       if (it != removed_chids.end())
+                               m_services.erase(service++);
+                       else
+                               ++service;
+               }
+               ret = 0;
+       }
+       return ret;
+}
+
 RESULT eDVBDB::addFlag(const eServiceReference &ref, unsigned int flagmask)
 {
        if (ref.type == eServiceReference::idDVB)
@@ -1315,9 +1366,13 @@ RESULT eDVBDB::removeFlags(unsigned int flagmask, eDVBChannelID chid, unsigned i
 RESULT eDVBDB::addChannelToList(const eDVBChannelID &id, iDVBFrontendParameters *feparm)
 {
        channel ch;
+       std::map<eDVBChannelID, channel>::iterator it = m_channels.find(id);
        assert(feparm);
        ch.m_frontendParameters = feparm;
-       m_channels.insert(std::pair<eDVBChannelID, channel>(id, ch));
+       if (it != m_channels.end())
+               it->second = ch;
+       else
+               m_channels.insert(std::pair<eDVBChannelID, channel>(id, ch));
        return 0;
 }
 
index 512f81e..55e008f 100644 (file)
@@ -44,6 +44,7 @@ public:
 #ifndef SWIG
        RESULT removeFlags(unsigned int flagmask, eDVBChannelID chid, unsigned int orb_pos);
        RESULT removeServices(eDVBChannelID chid, unsigned int orb_pos);
+       RESULT removeServices(iDVBFrontendParameters *feparm);
 
        RESULT addChannelToList(const eDVBChannelID &id, iDVBFrontendParameters *feparm);
        RESULT removeChannel(const eDVBChannelID &id);
index 2d38dc2..d7bc673 100644 (file)
@@ -204,7 +204,8 @@ void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescr
                guard_interval, hierarchy, modulation);
 }
 
-eDVBFrontendParameters::eDVBFrontendParameters(): m_type(-1)
+eDVBFrontendParameters::eDVBFrontendParameters()
+       :m_type(-1), m_flags(0)
 {
 }
 
index 49e2da8..cbe3dfc 100644 (file)
@@ -13,6 +13,7 @@ class eDVBFrontendParameters: public iDVBFrontendParameters
                eDVBFrontendParametersTerrestrial terrestrial;
        };
        int m_type;
+       int m_flags;
 public:
        eDVBFrontendParameters();
        ~eDVBFrontendParameters()
@@ -32,6 +33,9 @@ public:
 
        RESULT getHash(unsigned long &) const;
        RESULT calcLockTimeout(unsigned int &) const;
+
+       RESULT getFlags(unsigned int &flags) const { flags = m_flags; return 0; }
+       RESULT setFlags(unsigned int flags) { m_flags = flags; return 0; }
 };
 
 #ifndef SWIG
index cd3e0ec..ebf2237 100644 (file)
@@ -375,6 +375,7 @@ public:
        virtual RESULT removeService(const eServiceReference &service)=0;
        virtual RESULT removeServices(eDVBChannelID chid=eDVBChannelID(), unsigned int orb_pos=0xFFFFFFFF)=0;
        virtual RESULT removeServices(int dvb_namespace=-1, int tsid=-1, int onid=-1, unsigned int orb_pos=0xFFFFFFFF)=0;
+       virtual RESULT removeServices(iDVBFrontendParameters *feparm)=0;
        virtual RESULT addFlag(const eServiceReference &service, unsigned int flagmask=0xFFFFFFFF)=0;
        virtual RESULT removeFlag(const eServiceReference &service, unsigned int flagmask=0xFFFFFFFF)=0;
        virtual RESULT removeFlags(unsigned int flagmask, eDVBChannelID chid=eDVBChannelID(), unsigned int orb_pos=0xFFFFFFFF)=0;
@@ -402,6 +403,7 @@ class iDVBFrontendParameters: public iObject
        ~iDVBFrontendParameters();
 #endif
 public:
+       enum { flagOnlyFree = 1 };
        virtual RESULT getSystem(int &SWIG_OUTPUT) const = 0;
        virtual RESULT getDVBS(eDVBFrontendParametersSatellite &SWIG_OUTPUT) const = 0;
        virtual RESULT getDVBC(eDVBFrontendParametersCable &SWIG_OUTPUT) const = 0;
@@ -410,6 +412,7 @@ public:
        virtual RESULT calculateDifference(const iDVBFrontendParameters *parm, int &SWIG_OUTPUT, bool exact) const = 0;
        virtual RESULT getHash(unsigned long &SWIG_OUTPUT) const = 0;
        virtual RESULT calcLockTimeout(unsigned int &) const = 0;
+       virtual RESULT getFlags(unsigned int &) const = 0;
 };
 SWIG_TEMPLATE_TYPEDEF(ePtr<iDVBFrontendParameters>, iDVBFrontendParametersPtr);
 
index 8d412ce..3c4f407 100644 (file)
@@ -22,7 +22,7 @@ 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_flags(0), m_usePAT(usePAT)
+       ,m_pmt_running(false), m_abort_current_pmt(false), m_flags(0), m_usePAT(usePAT)
 {
        scan_debug=debug;
        if (m_channel->getDemux(m_demux))
@@ -84,10 +84,12 @@ RESULT eDVBScan::nextChannel()
 {
        ePtr<iDVBFrontend> fe;
 
-       m_SDT = 0; m_PAT = 0; m_BAT = 0; m_NIT = 0;
+       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;
        
@@ -152,6 +154,17 @@ RESULT eDVBScan::startFilter()
                                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<unsigned short, service>((*program)->getProgramNumber(), service((*program)->getProgramMapPid())));
+                       }
+                       m_PMT = new eTable<ProgramMapSection>();
+                       CONNECT(m_PMT->tableReady, eDVBScan::PMTready);
+                       PMTready(-1);
 
                        // KabelBW HACK ... on 618Mhz and 626Mhz the transport stream id in PAT and SDT is different
                        {
@@ -212,7 +225,7 @@ RESULT eDVBScan::startFilter()
 
 void eDVBScan::SDTready(int err)
 {
-       SCAN_eDebug("got sdt");
+       SCAN_eDebug("got sdt %d", err);
        m_ready |= readySDT;
        if (!err)
                m_ready |= validSDT;
@@ -246,6 +259,122 @@ void eDVBScan::PATready(int err)
        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<ProgramMapSection*>::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
+                               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)
+                                       {
+                                               switch ((*desc)->getTag())
+                                               {
+                                               case DTS_DESCRIPTOR:
+                                               case AAC_DESCRIPTOR:
+                                                       isaudio = 1;
+                                               case AC3_DESCRIPTOR:
+                                                       isaudio = 1;
+                                                       break;
+                                               case CA_DESCRIPTOR:
+                                                       is_scrambled = 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;
+                                               }
+                                               }
+                                       }
+                                       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 == -2) // aborted in sdt progress
+               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));
+       else
+       {
+               m_pmt_running = false;
+               channelDone();
+       }
+}
+
+
 void eDVBScan::addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
 {
                /* add it to the list of known channels. */
@@ -357,13 +486,19 @@ int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *c
 
 void eDVBScan::channelDone()
 {
-       if (m_ready & validSDT)
+       if (m_ready & validSDT && (!(m_flags & scanOnlyFree) || !m_pmt_running))
        {
                unsigned long hash = 0;
 
                // 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_ch_current->getHash(hash);
                
@@ -381,6 +516,7 @@ void eDVBScan::channelDone()
        
        if (m_ready & validNIT)
        {
+               eDebug("validNIT");
                int system;
                std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
                m_ch_current->getSystem(system);
@@ -512,9 +648,17 @@ void eDVBScan::channelDone()
                }
                m_ready &= ~validNIT;
        }
-       
-       if ((m_ready  & m_ready_all) != m_ready_all)
+
+       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
@@ -537,7 +681,106 @@ void eDVBScan::channelDone()
                   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<eDVBService> service = new eDVBService;
+
+               if (!m_chid_current)
+               {
+                       unsigned long hash = 0;
+
+                       // 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_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 = pname;
+               }
+
+               std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
+
+               if (i.second)
+               {
+                       m_last_service = i.first;
+                       m_event(evtNewService);
+               }
+               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
@@ -598,52 +841,64 @@ void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
                std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
                for (;it != m_ch_scanned.end(); ++it)
                {
-                       int system;
-                       (*it)->getSystem(system);
-                       switch(system)
+                       if (m_flags & scanDontRemoveUnscanned) {
+                               eDebug("scanDontRemoveUnscanned!");
+                               db->removeServices(&(*(*it)));
+                       }
+                       else
                        {
-                               case iDVBFrontend::feSatellite:
-                               {
-                                       eDVBFrontendParametersSatellite sat_parm;
-                                       (*it)->getDVBS(sat_parm);
-                                       scanned_sat_positions.insert(sat_parm.orbital_position);
-                                       break;
-                               }
-                               case iDVBFrontend::feTerrestrial:
+                               int system;
+                               (*it)->getSystem(system);
+                               switch(system)
                                {
-                                       clearTerrestrial=true;
-                                       break;
-                               }
-                               case iDVBFrontend::feCable:
-                               {
-                                       clearCable=true;
-                                       break;
+                                       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)
                {
-                       int system;
-                       (*it)->getSystem(system);
-                       switch(system)
+                       if (m_flags & scanDontRemoveUnscanned)
+                               db->removeServices(&(*(*it)));
+                       else
                        {
-                               case iDVBFrontend::feSatellite:
-                               {
-                                       eDVBFrontendParametersSatellite sat_parm;
-                                       (*it)->getDVBS(sat_parm);
-                                       scanned_sat_positions.insert(sat_parm.orbital_position);
-                                       break;
-                               }
-                               case iDVBFrontend::feTerrestrial:
+                               int system;
+                               (*it)->getSystem(system);
+                               switch(system)
                                {
-                                       clearTerrestrial=true;
-                                       break;
-                               }
-                               case iDVBFrontend::feCable:
-                               {
-                                       clearCable=true;
-                                       break;
+                                       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;
+                                       }
                                }
                        }
                }
@@ -672,7 +927,15 @@ void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
 
        for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::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<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
                service(m_new_services.begin()); service != m_new_services.end(); ++service)
        {
@@ -712,61 +975,83 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
 
        for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
        {
-               SCAN_eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
+               unsigned short service_id = (*s)->getServiceId();
+               SCAN_eDebugNoNewLine("SID %04x: ", service_id);
+               bool add = true;
 
-               eServiceReferenceDVB ref;
-               ePtr<eDVBService> service = new eDVBService;
-               
-               ref.set(chid);
-               ref.setServiceID((*s)->getServiceId());
-
-               for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
-                               desc != (*s)->getDescriptors()->end(); ++desc)
-                       if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
-                               ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
-               
-               for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
-                               desc != (*s)->getDescriptors()->end(); ++desc)
+               if (m_flags & scanOnlyFree)
                {
-                       switch ((*desc)->getTag())
-                       {
-                       case SERVICE_DESCRIPTOR:
+                       std::map<unsigned short, service>::iterator it =
+                               m_pmts_to_read.find(service_id);
+                       if (it != m_pmts_to_read.end())
                        {
-                               ServiceDescriptor &d = (ServiceDescriptor&)**desc;
-                               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;
+                               if (it->second.scrambled)
+                               {
+                                       SCAN_eDebug("is scrambled!");
+                                       add = false;
+                               }
                        }
-                       case CA_IDENTIFIER_DESCRIPTOR:
+                       else
+                               SCAN_eDebug("not found in PAT.. so we assume it is scrambled!!");
+               }
+
+               if (add)
+               {
+                       eServiceReferenceDVB ref;
+                       ePtr<eDVBService> service = new eDVBService;
+
+                       ref.set(chid);
+                       ref.setServiceID(service_id);
+
+                       for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
+                                       desc != (*s)->getDescriptors()->end(); ++desc)
                        {
-                               CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
-                               const CaSystemIdList &caids = *d.getCaSystemIds();
-                               SCAN_eDebugNoNewLine("CA ");
-                               for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
+                               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:
                                {
-                                       SCAN_eDebugNoNewLine("%04x ", *i);
-                                       service->m_ca.push_front(*i);
+                                       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;
                                }
-                               SCAN_eDebug("");
-                               break;
                        }
-                       default:
-                               SCAN_eDebug("descr<%x>", (*desc)->getTag());
-                               break;
+
+                       std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
+
+                       if (i.second)
+                       {
+                               m_last_service = i.first;
+                               m_event(evtNewService);
                        }
                }
-               
-               std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(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;
 }
 
index 68e21a5..50de21d 100644 (file)
@@ -5,10 +5,23 @@
 #include <dvbsi++/network_information_section.h>
 #include <dvbsi++/bouquet_association_section.h>
 #include <dvbsi++/program_association_section.h>
+#include <dvbsi++/program_map_section.h>
+
 #include <lib/dvb/idemux.h>
 #include <lib/dvb/esection.h>
 #include <lib/dvb/db.h>
 
+struct service
+{
+       service(unsigned short pmtPid)
+               :pmtPid(pmtPid), serviceType(0xFF), scrambled(false)
+       {
+       }
+       unsigned short pmtPid;
+       unsigned char serviceType;
+       bool scrambled;
+};
+
 class eDVBScan: public Object, public iObject
 {
        DECLARE_REF(eDVBScan);
@@ -41,21 +54,29 @@ class eDVBScan: public Object, public iObject
        std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> > m_new_channels;
        std::map<eServiceReferenceDVB, ePtr<eDVBService> > m_new_services;
        std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator m_last_service;
-       
+
+       std::map<unsigned short, service> m_pmts_to_read;
+       std::map<unsigned short, service>::iterator m_pmt_in_progress;
+       bool m_pmt_running;
+       bool m_abort_current_pmt;
+
        std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan, m_ch_scanned, m_ch_unavailable;
        ePtr<iDVBFrontendParameters> m_ch_current;
        eDVBChannelID m_chid_current;
-       
+       eTransportStreamID m_pat_tsid;
+
        ePtr<eTable<ServiceDescriptionSection> > m_SDT;
        ePtr<eTable<NetworkInformationSection> > m_NIT;
        ePtr<eTable<BouquetAssociationSection> > m_BAT;
        ePtr<eTable<ProgramAssociationSection> > m_PAT;
-               
+       ePtr<eTable<ProgramMapSection> > m_PMT;
+
        void SDTready(int err);
        void NITready(int err);
        void BATready(int err);
        void PATready(int err);
-               
+       void PMTready(int err);
+
        void addKnownGoodChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm);
        void addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameters *feparm);
 
@@ -75,7 +96,8 @@ public:
        enum {
                scanNetworkSearch = 1, scanSearchBAT = 2,
                scanRemoveServices = 4, scanDontRemoveFeeds = 8,
-               clearToScanOnFirstNIT = 16 };
+               scanDontRemoveUnscanned = 16,
+               clearToScanOnFirstNIT = 32, scanOnlyFree = 64 };
 
        void start(const eSmartPtrList<iDVBFrontendParameters> &known_transponders, int flags);
 
index b14c7e7..35f482b 100644 (file)
@@ -400,12 +400,10 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                                self.updateSatList()
                                print self.scan_satselection[index_to_scan]
                                self.list.append(getConfigListEntry(_("Satellite"), self.scan_satselection[index_to_scan]))
-                               self.list.append(getConfigListEntry(_("Clear before scan"), self.scan_clearallservices))
+                               self.list.append(getConfigListEntry(_("Network scan"), self.scan_networkScan))
                        elif self.scan_type.value == "multisat":
-                               # if (norotor)
                                tlist = []
                                SatList = nimmanager.getSatListForNim(index_to_scan)
-                               self.list.append(getConfigListEntry(_("Clear before scan"), self.scan_clearallservices))
                                for x in SatList:
                                        if self.Satexists(tlist, x[0]) == 0:
                                                tlist.append(x[0])
@@ -413,9 +411,6 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                                                configEntry = getConfigListEntry(nimmanager.getSatDescription(x[0]), sat)
                                                self.list.append(configEntry)
                                                self.multiscanlist.append((x[0], sat))
-                               # if (rotor):
-                          # for sat in nimmanager.satList:
-                               #       self.list.append(getConfigListEntry(sat[1], self.scan_scansat[sat[0]]))
                elif nim.isCompatible("DVB-C"):
                        if self.scan_typecable.value == "single_transponder":
                                self.list.append(getConfigListEntry(_("Frequency"), self.scan_cab.frequency))
@@ -424,8 +419,6 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                                self.list.append(getConfigListEntry(_("Modulation"), self.scan_cab.modulation))
                                self.list.append(getConfigListEntry(_("FEC"), self.scan_cab.fec))
                                self.list.append(getConfigListEntry(_("Network scan"), self.scan_networkScan))
-                       elif self.scan_typecable.value == "complete":
-                               self.list.append(getConfigListEntry(_("Clear before scan"), self.scan_clearallservices))
                elif nim.isCompatible("DVB-T"):
                        if self.scan_typeterrestrial.value == "single_transponder":
                                self.list.append(getConfigListEntry(_("Frequency"), self.scan_ter.frequency))
@@ -438,22 +431,8 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                                self.list.append(getConfigListEntry(_("Guard interval mode"), self.scan_ter.guard))
                                self.list.append(getConfigListEntry(_("Hierarchy mode"), self.scan_ter.hierarchy))
                                self.list.append(getConfigListEntry(_("Network scan"), self.scan_networkScan))
-                       elif self.scan_typeterrestrial.value == "complete":
-                               self.list.append(getConfigListEntry(_("Clear before scan"), self.scan_clearallservices))
-
-#              if (nim.isCompatible("DVB-S") and self.scan_type.type == "single_transponder") or \
-#                      (nim.isCompatbile("DVB-C") and self.scan_typecable.type == "single_transponder") or \
-#                      (nim.isCompatible("DVB-T") and self.scan_typeterrestrial.type == "single_transponder"):
-#                              self.configElementSNR = getConfigListEntry(_("SNR"), self.scan_snr)
-#                              self.list.append(self.configElementSNR)
-#                              self.configElementACG = getConfigListEntry(_("AGC"), self.scan_agc)
-#                              self.list.append(self.configElementACG)
-#                              self.configElementBER = getConfigListEntry(_("BER"), self.scan_ber)
-#                              self.list.append(self.configElementBER)
-#                              self.statusTimer.start(500, False)
-#              else:
-#                      self.statusTimer.stop()
-
+               self.list.append(getConfigListEntry(_("Clear before scan"), self.scan_clearallservices))
+               self.list.append(getConfigListEntry(_("Only Free scan"), self.scan_onlyfree))
                self["config"].list = self.list
                self["config"].l.setList(self.list)
 
@@ -540,6 +519,7 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                        self.scan_typecable = ConfigSelection(default = "single_transponder", choices = [("single_transponder", _("Single transponder")), ("complete", _("Complete"))])
                        self.scan_typeterrestrial = ConfigSelection(default = "single_transponder", choices = [("single_transponder", _("Single transponder")), ("complete", _("Complete"))])
                        self.scan_clearallservices = ConfigSelection(default = "no", choices = [("no", _("no")), ("yes", _("yes")), ("yes_hold_feeds", _("yes (keep feeds)"))])
+                       self.scan_onlyfree = ConfigYesNo(default = False)
                        self.scan_networkScan = ConfigYesNo(default = False)
 
                        nim_list = []
@@ -663,9 +643,8 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
        def keyGo(self):
                tlist = []
                flags = None
-               extFlags = True
-               
                startScan = True
+               removeAll = True
                index_to_scan = int(self.scan_nims.value)
                
                if self.scan_nims == [ ]:
@@ -703,10 +682,11 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                                                                self.scan_sat.rolloff.index,
                                                                self.scan_sat.pilot.index)
                                flags = self.scan_networkScan.value and eComponentScan.scanNetworkSearch or 0
-                               extFlags = False
+                               removeAll = False
                        elif self.scan_type.value == "single_satellite":
                                sat = self.satList[index_to_scan][self.scan_satselection[index_to_scan].index]
                                getInitialTransponderList(tlist, sat[0])
+                               flags = self.scan_networkScan.value and eComponentScan.scanNetworkSearch or 0
                        elif self.scan_type.value == "multisat":
                                SatList = nimmanager.getSatListForNim(index_to_scan)
                                for x in self.multiscanlist:
@@ -723,7 +703,7 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                                                                                          fec,
                                                                                          self.scan_cab.inversion.index)
                                flags = self.scan_networkScan.value and eComponentScan.scanNetworkSearch or 0
-                               extFlags = False
+                               removeAll = False
                        elif self.scan_typecable.value == "complete":
                                if config.Nims[index_to_scan].cable.scan_type.value == "provider":
                                        getInitialCableTransponderList(tlist, index_to_scan)
@@ -743,20 +723,25 @@ class ScanSetup(ConfigListScreen, Screen, CableTransponderSearchSupport):
                                                guard = self.scan_ter.guard.index,
                                                hierarchy = self.scan_ter.hierarchy.index)
                                flags = self.scan_networkScan.value and eComponentScan.scanNetworkSearch or 0
-                               extFlags = False
+                               removeAll = False
                        elif self.scan_typeterrestrial.value == "complete":
                                getInitialTerrestrialTransponderList(tlist, nimmanager.getTerrestrialDescription(index_to_scan))
 
                if flags is None:
                        flags = eComponentScan.scanNetworkSearch
 
-               if extFlags:
-                       tmp = self.scan_clearallservices.value
-                       if tmp == "yes":
-                               flags |= eComponentScan.scanRemoveServices
-                       elif tmp == "yes_hold_feeds":
-                               flags |= eComponentScan.scanRemoveServices
-                               flags |= eComponentScan.scanDontRemoveFeeds
+               tmp = self.scan_clearallservices.value
+               if tmp == "yes":
+                       flags |= eComponentScan.scanRemoveServices
+               elif tmp == "yes_hold_feeds":
+                       flags |= eComponentScan.scanRemoveServices
+                       flags |= eComponentScan.scanDontRemoveFeeds
+
+               if tmp != "no" and not removeAll:
+                       flags |= eComponentScan.scanDontRemoveUnscanned
+
+               if self.scan_onlyfree.value:
+                       flags |= eComponentScan.scanOnlyFree
 
                for x in self["config"].list:
                        x[1].save()