scan.cpp: more robust streamtype detection for pat scan.. use libdvbsi++ to parse...
[enigma2.git] / lib / dvb / scan.cpp
index 3c4f407bfe576a0cfaac3f31cfd29d1de4531c53..19c10868b1db07e12e3b0baae2df004ad7c8f336 100644 (file)
@@ -5,6 +5,7 @@
 #include <dvbsi++/terrestrial_delivery_system_descriptor.h>
 #include <dvbsi++/cable_delivery_system_descriptor.h>
 #include <dvbsi++/ca_identifier_descriptor.h>
+#include <dvbsi++/registration_descriptor.h>
 #include <lib/dvb/specs.h>
 #include <lib/dvb/esection.h>
 #include <lib/dvb/scan.h>
 #include <lib/base/estring.h>
 #include <errno.h>
 
-static bool scan_debug;
-#define SCAN_eDebug(x...) do { if (scan_debug) eDebug(x); } while(0)
-#define SCAN_eDebugNoNewLine(x...) do { if (scan_debug) eDebugNoNewLine(x); } while(0)
+#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_pmt_running(false), m_abort_current_pmt(false), m_flags(0)
+       ,m_usePAT(usePAT), m_scan_debug(debug)
 {
-       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);
@@ -41,10 +41,14 @@ int eDVBScan::isValidONIDTSID(int orbital_position, eOriginalNetworkID onid, eTr
        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 0x00eb:
+               return tsid != 0x4321;
        case 0x0002:
                return abs(orbital_position-282) < 6;
        default:
@@ -136,23 +140,33 @@ RESULT eDVBScan::nextChannel()
 RESULT eDVBScan::startFilter()
 {
        bool startSDT=true;
-       assert(m_demux);
+       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<ServiceDescriptionSection>();
+               m_SDT = new eTable<ServiceDescriptionSection>(m_scan_debug);
                int tsid=-1;
                if (m_ready & readyPAT && m_ready & validPAT)
                {
                        std::vector<ProgramAssociationSection*>::const_iterator i =
                                m_PAT->getSections().begin();
-                       assert(i != m_PAT->getSections().end());
+                       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)
@@ -162,11 +176,11 @@ RESULT eDVBScan::startFilter()
                                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>();
+                       m_PMT = new eTable<ProgramMapSection>(m_scan_debug);
                        CONNECT(m_PMT->tableReady, eDVBScan::PMTready);
-                       PMTready(-1);
-
+                       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);
@@ -195,8 +209,8 @@ RESULT eDVBScan::startFilter()
                m_PAT = 0;
                if (m_ready_all & readyPAT)
                {
-                       m_PAT = new eTable<ProgramAssociationSection>();
-                       if (m_PAT->start(m_demux, eDVBPATSpec()))
+                       m_PAT = new eTable<ProgramAssociationSection>(m_scan_debug);
+                       if (m_PAT->start(m_demux, eDVBPATSpec(4000)))
                                return -1;
                        CONNECT(m_PAT->tableReady, eDVBScan::PATready);
                }
@@ -204,7 +218,7 @@ RESULT eDVBScan::startFilter()
                m_NIT = 0;
                if (m_ready_all & readyNIT)
                {
-                       m_NIT = new eTable<NetworkInformationSection>();
+                       m_NIT = new eTable<NetworkInformationSection>(m_scan_debug);
                        if (m_NIT->start(m_demux, eDVBNITSpec()))
                                return -1;
                        CONNECT(m_NIT->tableReady, eDVBScan::NITready);
@@ -213,13 +227,12 @@ RESULT eDVBScan::startFilter()
                m_BAT = 0;
                if (m_ready_all & readyBAT)
                {
-                       m_BAT = new eTable<BouquetAssociationSection>();
+                       m_BAT = new eTable<BouquetAssociationSection>(m_scan_debug);
                        if (m_BAT->start(m_demux, eDVBBATSpec()))
                                return -1;
                        CONNECT(m_BAT->tableReady, eDVBScan::BATready);
                }
        }
-
        return 0;
 }
 
@@ -269,72 +282,93 @@ void eDVBScan::PMTready(int err)
                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());
+                               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;
+                               int isaudio = 0, isvideo = 0, is_scrambled = 0, forced_audio = 0, forced_video = 0;
                                switch ((*es)->getType())
                                {
                                case 0x1b: // AVC Video Stream (MPEG4 H264)
+                               case 0x10: // MPEG 4 Part 2
                                case 0x01: // MPEG 1 video
                                case 0x02: // MPEG 2 video
                                        isvideo = 1;
+                                       forced_video = 1;
                                        //break; fall through !!!
                                case 0x03: // MPEG 1 audio
-                               case 0x04: // MPEG 2 audio:
-                                       if (!isvideo)
+                               case 0x04: // MPEG 2 audio
+                               case 0x0f: // MPEG 2 AAC
+                               case 0x11: // MPEG 4 AAC
+                                       if (!isvideo) 
+                                       {
+                                               forced_audio = 1;
                                                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. */
+                               case 0xEA: // TS_PSI_ST_SMPTE_VC1
                                        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 */
+                                               uint8_t tag = (*desc)->getTag();
+                                               /* PES private can contain AC-3, DTS or lots of other stuff.
+                                                  check descriptors to get the exakt type. */
+                                               if (!forced_video && !forced_audio)
                                                {
-                                                               /* 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)
+                                                       switch (tag)
                                                        {
-                                                       case 0x41432d33:
+                                                       case 0x1C: // TS_PSI_DT_MPEG4_Audio
+                                                       case 0x2B: // TS_PSI_DT_MPEG2_AAC
+                                                       case AAC_DESCRIPTOR:
+                                                       case AC3_DESCRIPTOR:
+                                                       case DTS_DESCRIPTOR:
+                                                       case AUDIO_STREAM_DESCRIPTOR:
                                                                isaudio = 1;
+                                                               break;
+                                                       case 0x28: // TS_PSI_DT_AVC
+                                                       case 0x1B: // TS_PSI_DT_MPEG4_Video
+                                                       case VIDEO_STREAM_DESCRIPTOR:
+                                                               isvideo = 1;
+                                                               break;
+                                                       case REGISTRATION_DESCRIPTOR: /* some services don't have a separate AC3 descriptor */
+                                                       {
+                                                               RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
+                                                               switch (d->getFormatIdentifier())
+                                                               {
+                                                               case 0x44545331 ... 0x44545333: // DTS1/DTS2/DTS3
+                                                               case 0x41432d33: // == 'AC-3'
+                                                               case 0x42535344: // == 'BSSD' (LPCM)
+                                                                       isaudio = 1;
+                                                                       break;
+                                                               case 0x56432d31: // == 'VC-1'
+                                                                       isvideo = 1;
+                                                                       break;
+                                                               default:
+                                                                       break;
+                                                               }
+                                                       }
                                                        default:
                                                                break;
                                                        }
-                                                       break;
-                                               }
                                                }
+                                               if (tag == CA_DESCRIPTOR)
+                                                       is_scrambled = 1;
                                        }
+                               default:
                                        break;
                                }
-                               if (isaudio)
-                                       have_audio = true;
-                               else if (isvideo)
+                               if (isvideo)
                                        have_video = true;
+                               else if (isaudio)
+                                       have_audio = true;
                                else
                                        continue;
                                if (is_scrambled)
@@ -355,7 +389,7 @@ void eDVBScan::PMTready(int err)
                else
                        m_pmt_in_progress->second.serviceType = 100;
        }
-       if (err == -2) // aborted in sdt progress
+       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;
@@ -366,9 +400,10 @@ void eDVBScan::PMTready(int err)
        }
 
        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));
+               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();
        }
@@ -395,7 +430,7 @@ void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameter
        {
                eDVBFrontendParametersSatellite parm;
                feparm->getDVBS(parm);
-               eDebug("try to add %d %d %d %d %d %d",
+               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;
        }
@@ -403,7 +438,7 @@ void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameter
        {
                eDVBFrontendParametersCable parm;
                feparm->getDVBC(parm);
-               eDebug("try to add %d %d %d %d",
+               SCAN_eDebug("try to add %d %d %d %d",
                        parm.frequency, parm.symbol_rate, parm.modulation, parm.fec_inner);
                break;
        }
@@ -411,7 +446,7 @@ void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameter
        {
                eDVBFrontendParametersTerrestrial parm;
                feparm->getDVBT(parm);
-               eDebug("try to add %d %d %d %d %d %d %d %d",
+               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;
@@ -427,11 +462,11 @@ void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameter
                        if (!found_count)
                        {
                                *i = feparm;  // update
-                               eDebug("update");
+                               SCAN_eDebug("update");
                        }
                        else
                        {
-                               eDebug("remove dupe");
+                               SCAN_eDebug("remove dupe");
                                m_ch_toScan.erase(i++);
                                continue;
                        }
@@ -442,7 +477,7 @@ void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameter
 
        if (found_count > 0)
        {
-               eDebug("already in todo list");
+               SCAN_eDebug("already in todo list");
                return;
        }
 
@@ -450,7 +485,7 @@ void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameter
        for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
                if (sameChannel(*i, feparm))
                {
-                       eDebug("successfully scanned");
+                       SCAN_eDebug("successfully scanned");
                        return;
                }
 
@@ -458,18 +493,18 @@ void eDVBScan::addChannelToScan(const eDVBChannelID &chid, iDVBFrontendParameter
        for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
                if (sameChannel(*i, feparm, true))
                {
-                       eDebug("scanned but not available");
+                       SCAN_eDebug("scanned but not available");
                        return;
                }
 
                /* ... on the current channel */
        if (sameChannel(m_ch_current, feparm))
        {
-               eDebug("is current");
+               SCAN_eDebug("is current");
                return;
        }
 
-       eDebug("really add");
+       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 :)
 }
@@ -490,16 +525,6 @@ void eDVBScan::channelDone()
        {
                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);
                
                eDVBNamespace dvbnamespace = buildNamespace(
@@ -516,7 +541,6 @@ void eDVBScan::channelDone()
        
        if (m_ready & validNIT)
        {
-               eDebug("validNIT");
                int system;
                std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan_backup;
                m_ch_current->getSystem(system);
@@ -604,7 +628,7 @@ void eDVBScan::channelDone()
 
                                                if ( abs(abs(3600 - p.orbital_position) - sat.orbital_position) < 5 )
                                                {
-                                                       eDebug("found transponder with incorrect west/east flag ... correct this");
+                                                       SCAN_eDebug("found transponder with incorrect west/east flag ... correct this");
                                                        sat.orbital_position = p.orbital_position;
                                                }
 
@@ -692,16 +716,6 @@ void eDVBScan::channelDone()
                {
                        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(
@@ -748,11 +762,20 @@ void eDVBScan::channelDone()
                                }
                                case iDVBFrontend::feTerrestrial:
                                {
+                                       ePtr<iDVBFrontend> fe;
                                        eDVBFrontendParametersTerrestrial parm;
                                        m_ch_current->getDVBT(parm);
                                        snprintf(sname, 255, "%d SID 0x%02x",
                                                parm.frequency/1000,
                                                m_pmt_in_progress->first);
+                                       if (!m_channel->getFrontend(fe))
+                                       {
+                                               ePyObject tp_dict = PyDict_New();
+                                               fe->getTransponderData(tp_dict, false);
+                                               m_corrected_frequencys[m_chid_current] =
+                                                       PyInt_AsLong(PyDict_GetItemString(tp_dict, "frequency"));
+                                               Py_DECREF(tp_dict);
+                                       }
                                        break;
                                }
                                case iDVBFrontend::feCable:
@@ -768,16 +791,21 @@ void eDVBScan::channelDone()
                        SCAN_eDebug("name '%s', provider_name '%s'", sname, pname);
                        service->m_service_name = convertDVBUTF8(sname);
                        service->genSortName();
-                       service->m_provider_name = pname;
+                       service->m_provider_name = convertDVBUTF8(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);
+               if (!(m_flags & scanOnlyFree) || !m_pmt_in_progress->second.scrambled) {
+                       SCAN_eDebug("add not scrambled!");
+                       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);
+                       }
                }
+               else
+                       SCAN_eDebug("dont add... is scrambled!");
                m_pmts_to_read.erase(m_pmt_in_progress++);
        }
 
@@ -792,7 +820,7 @@ void eDVBScan::channelDone()
        {
                if (sameChannel(*i, m_ch_current))
                {
-                       eDebug("remove dupe 2");
+                       SCAN_eDebug("remove dupe 2");
                        m_ch_toScan.erase(i++);
                        continue;
                }
@@ -841,10 +869,8 @@ void eDVBScan::insertInto(iDVBChannelList *db, bool dontRemoveOldFlags)
                std::list<ePtr<iDVBFrontendParameters> >::iterator it(m_ch_scanned.begin());
                for (;it != m_ch_scanned.end(); ++it)
                {
-                       if (m_flags & scanDontRemoveUnscanned) {
-                               eDebug("scanDontRemoveUnscanned!");
+                       if (m_flags & scanDontRemoveUnscanned)
                                db->removeServices(&(*(*it)));
-                       }
                        else
                        {
                                int system;
@@ -928,6 +954,24 @@ 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)
        {
+               int system;
+               ch->second->getSystem(system);
+               if (system == iDVBFrontend::feTerrestrial)
+               {
+                       std::map<eDVBChannelID, unsigned int>::iterator it = m_corrected_frequencys.find(ch->first);
+                       if (it != m_corrected_frequencys.end())
+                       {
+                               eDVBFrontendParameters *p = (eDVBFrontendParameters*)&(*ch->second);
+                               eDVBFrontendParametersTerrestrial parm;
+                               p->getDVBT(parm);
+                               eDebug("corrected freq for tsid %04x, onid %04x, ns %08x is %d, old was %d",
+                                       ch->first.transport_stream_id.get(), ch->first.original_network_id.get(),
+                                       ch->first.dvbnamespace.get(), it->second, parm.frequency);
+                               parm.frequency = it->second;
+                               p->setDVBT(parm);
+                               m_corrected_frequencys.erase(it);
+                       }
+               }
                if (m_flags & scanOnlyFree)
                {
                        eDVBFrontendParameters *ptr = (eDVBFrontendParameters*)&(*ch->second);
@@ -990,9 +1034,13 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
                                        SCAN_eDebug("is scrambled!");
                                        add = false;
                                }
+                               else
+                                       SCAN_eDebug("is free");
                        }
-                       else
+                       else {
                                SCAN_eDebug("not found in PAT.. so we assume it is scrambled!!");
+                               add = false;
+                       }
                }
 
                if (add)
@@ -1038,7 +1086,8 @@ RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescription
                                }
                        }
 
-                       std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i = m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
+                       std::pair<std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator, bool> i =
+                               m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
 
                        if (i.second)
                        {