change iFrontendInformation api
[enigma2.git] / lib / service / servicedvb.cpp
index fe9398cbb86ca9b470576f99a34bb62f967a7f84..9d9f2d1f385597716afff8ddf58e7ea88666dbd6 100644 (file)
@@ -3,6 +3,7 @@
 #include <string>
 #include <lib/service/servicedvb.h>
 #include <lib/service/service.h>
+#include <lib/base/estring.h>
 #include <lib/base/init_num.h>
 #include <lib/base/init.h>
 #include <lib/base/nconfig.h> // access to python config
@@ -26,8 +27,6 @@
 #include <byteswap.h>
 #include <netinet/in.h>
 
-#define INTERNAL_TELETEXT
-
 #ifndef BYTE_ORDER
 #error no byte order defined!
 #endif
@@ -40,6 +39,8 @@ class eStaticServiceDVBInformation: public iStaticServiceInformation
 public:
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
+       int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
+       PyObject *getInfoObject(const eServiceReference &ref, int);
 };
 
 DEFINE_REF(eStaticServiceDVBInformation);
@@ -64,16 +65,7 @@ RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::
                                if (!service_center->info(parent, service_info))
                                {
                                        if (!service_info->getName(parent, name))
-                                       {
-                                               // just show short name
-                                               unsigned int pos = name.find("\xc2\x86");
-                                               if ( pos != std::string::npos )
-                                                       name.erase(0, pos+2);
-                                               pos = name.find("\xc2\x87");
-                                               if ( pos != std::string::npos )
-                                                       name.erase(pos);
-                                               name+=" - ";
-                                       }
+                                               name=buildShortName(name) + " - ";
                                }
                        }
                }
@@ -91,13 +83,289 @@ int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
        return -1;
 }
 
-class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
+int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
 {
-       DECLARE_REF(eStaticServiceDVBBouquetInformation);
-public:
-       RESULT getName(const eServiceReference &ref, std::string &name);
-       int getLength(const eServiceReference &ref);
-};
+       ePtr<eDVBResourceManager> res_mgr;
+       if ( eDVBResourceManager::getInstance( res_mgr ) )
+               eDebug("isPlayable... no res manager!!");
+       else
+       {
+               eDVBChannelID chid, chid_ignore;
+               ((const eServiceReferenceDVB&)ref).getChannelID(chid);
+               ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
+               return res_mgr->canAllocateChannel(chid, chid_ignore);
+       }
+       return false;
+}
+
+static void PutToDict(ePyObject &dict, const char*key, long value)
+{
+       ePyObject item = PyString_FromFormat("%d", value);
+       if (item)
+       {
+               if (PyDict_SetItemString(dict, key, item))
+                       eDebug("put %s to dict failed", key);
+               Py_DECREF(item);
+       }
+       else
+               eDebug("could not create PyObject for %s", key);
+}
+
+extern void PutToDict(ePyObject &dict, const char*key, const char *value);
+
+void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm)
+{
+       const char *tmp=0;
+       PutToDict(dict, "type", "Satellite");
+       PutToDict(dict, "frequency", feparm.frequency);
+       PutToDict(dict, "symbolrate", feparm.symbol_rate);
+       PutToDict(dict, "orbital position", feparm.orbital_position);
+       switch (feparm.inversion)
+       {
+               case eDVBFrontendParametersSatellite::Inversion::On: tmp="ON"; break;
+               case eDVBFrontendParametersSatellite::Inversion::Off: tmp="OFF"; break;
+               default:
+               case eDVBFrontendParametersSatellite::Inversion::Unknown: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "inversion", tmp);
+       switch (feparm.fec)
+       {
+               case eDVBFrontendParametersSatellite::FEC::fNone: tmp="NONE"; break;
+               case eDVBFrontendParametersSatellite::FEC::f1_2: tmp="1/2"; break;
+               case eDVBFrontendParametersSatellite::FEC::f2_3: tmp="2/3"; break;
+               case eDVBFrontendParametersSatellite::FEC::f3_4: tmp="3/4"; break;
+               case eDVBFrontendParametersSatellite::FEC::f5_6: tmp="5/6"; break;
+               case eDVBFrontendParametersSatellite::FEC::f7_8: tmp="7/8"; break;
+               case eDVBFrontendParametersSatellite::FEC::f3_5: tmp="3/5"; break;
+               case eDVBFrontendParametersSatellite::FEC::f4_5: tmp="4/5"; break;
+               case eDVBFrontendParametersSatellite::FEC::f8_9: tmp="8/9"; break;
+               case eDVBFrontendParametersSatellite::FEC::f9_10: tmp="9/10"; break;
+               default:
+               case eDVBFrontendParametersSatellite::FEC::fAuto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "fec inner", tmp);
+       switch (feparm.modulation)
+       {
+               case eDVBFrontendParametersSatellite::Modulation::Auto: tmp="AUTO"; break;
+               case eDVBFrontendParametersSatellite::Modulation::QPSK: tmp="QPSK"; break;
+               case eDVBFrontendParametersSatellite::Modulation::M8PSK: tmp="8PSK"; break;
+               case eDVBFrontendParametersSatellite::Modulation::QAM_16: tmp="QAM16"; break;
+       }
+       PutToDict(dict, "modulation", tmp);
+       switch(feparm.polarisation)
+       {
+               case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
+               case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
+               case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR LEFT"; break;
+               default:
+               case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR RIGHT"; break;
+       }
+       PutToDict(dict, "polarization", tmp);
+       switch(feparm.system)
+       {
+               default:
+               case eDVBFrontendParametersSatellite::System::DVB_S: tmp="DVB-S"; break;
+               case eDVBFrontendParametersSatellite::System::DVB_S2:
+                       switch(feparm.roll_off)
+                       {
+                               case eDVBFrontendParametersSatellite::RollOff::alpha_0_35: tmp="0.35"; break;
+                               case eDVBFrontendParametersSatellite::RollOff::alpha_0_25: tmp="0.25"; break;
+                               case eDVBFrontendParametersSatellite::RollOff::alpha_0_20: tmp="0.20"; break;
+                               default:
+                               case eDVBFrontendParametersSatellite::RollOff::alpha_auto: tmp="AUTO"; break;
+                       }
+                       PutToDict(dict, "roll off", tmp);
+                       tmp="DVB-S2";
+                       break;
+       }
+       PutToDict(dict, "system", tmp);
+}
+
+void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm)
+{
+       PutToDict(dict, "type", "Terrestrial");
+       PutToDict(dict, "frequency", feparm.frequency);
+       const char *tmp=0;
+       switch (feparm.bandwidth)
+       {
+       case eDVBFrontendParametersTerrestrial::Bandwidth::Bw8MHz: tmp="8 MHz"; break;
+       case eDVBFrontendParametersTerrestrial::Bandwidth::Bw7MHz: tmp="7 MHz"; break;
+       case eDVBFrontendParametersTerrestrial::Bandwidth::Bw6MHz: tmp="6 MHz"; break;
+       default:
+       case eDVBFrontendParametersTerrestrial::Bandwidth::BwAuto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "bandwidth", tmp);
+       switch (feparm.code_rate_LP)
+       {
+       case eDVBFrontendParametersTerrestrial::FEC::f1_2: tmp="1/2"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f2_3: tmp="2/3"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f3_4: tmp="3/4"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f5_6: tmp="5/6"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f7_8: tmp="7/8"; break;
+       default:
+       case eDVBFrontendParametersTerrestrial::FEC::fAuto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "code rate lp", tmp);
+       switch (feparm.code_rate_HP)
+       {
+       case eDVBFrontendParametersTerrestrial::FEC::f1_2: tmp="1/2"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f2_3: tmp="2/3"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f3_4: tmp="3/4"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f5_6: tmp="5/6"; break;
+       case eDVBFrontendParametersTerrestrial::FEC::f7_8: tmp="7/8"; break;
+       default:
+       case eDVBFrontendParametersTerrestrial::FEC::fAuto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "code rate hp", tmp);
+       switch (feparm.modulation)
+       {
+       case eDVBFrontendParametersTerrestrial::Modulation::QPSK: tmp="QPSK"; break;
+       case eDVBFrontendParametersTerrestrial::Modulation::QAM16: tmp="QAM16"; break;
+       case eDVBFrontendParametersTerrestrial::Modulation::QAM64: tmp="QAM64"; break;
+       default:
+       case eDVBFrontendParametersTerrestrial::Modulation::Auto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "constellation", tmp);
+       switch (feparm.transmission_mode)
+       {
+       case eDVBFrontendParametersTerrestrial::TransmissionMode::TM2k: tmp="2k"; break;
+       case eDVBFrontendParametersTerrestrial::TransmissionMode::TM8k: tmp="8k"; break;
+       default:
+       case eDVBFrontendParametersTerrestrial::TransmissionMode::TMAuto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "transmission mode", tmp);
+       switch (feparm.guard_interval)
+       {
+               case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_32: tmp="1/32"; break;
+               case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_16: tmp="1/16"; break;
+               case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_8: tmp="1/8"; break;
+               case eDVBFrontendParametersTerrestrial::GuardInterval::GI_1_4: tmp="1/4"; break;
+               default:
+               case eDVBFrontendParametersTerrestrial::GuardInterval::GI_Auto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "guard interval", tmp);
+       switch (feparm.hierarchy)
+       {
+               case eDVBFrontendParametersTerrestrial::Hierarchy::HNone: tmp="NONE"; break;
+               case eDVBFrontendParametersTerrestrial::Hierarchy::H1: tmp="1"; break;
+               case eDVBFrontendParametersTerrestrial::Hierarchy::H2: tmp="2"; break;
+               case eDVBFrontendParametersTerrestrial::Hierarchy::H4: tmp="4"; break;
+               default:
+               case eDVBFrontendParametersTerrestrial::Hierarchy::HAuto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "hierarchy", tmp);
+       switch (feparm.inversion)
+       {
+               case eDVBFrontendParametersSatellite::Inversion::On: tmp="ON"; break;
+               case eDVBFrontendParametersSatellite::Inversion::Off: tmp="OFF"; break;
+               default:
+               case eDVBFrontendParametersSatellite::Inversion::Unknown: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "inversion", tmp);
+}
+
+void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm)
+{
+       const char *tmp=0;
+       PutToDict(dict, "type", "Cable");
+       PutToDict(dict, "frequency", feparm.frequency);
+       PutToDict(dict, "symbolrate", feparm.symbol_rate);
+       switch (feparm.modulation)
+       {
+       case eDVBFrontendParametersCable::Modulation::QAM16: tmp="QAM16"; break;
+       case eDVBFrontendParametersCable::Modulation::QAM32: tmp="QAM32"; break;
+       case eDVBFrontendParametersCable::Modulation::QAM64: tmp="QAM64"; break;
+       case eDVBFrontendParametersCable::Modulation::QAM128: tmp="QAM128"; break;
+       case eDVBFrontendParametersCable::Modulation::QAM256: tmp="QAM256"; break;
+       default:
+       case eDVBFrontendParametersCable::Modulation::Auto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "modulation", tmp);
+       switch (feparm.inversion)
+       {
+       case eDVBFrontendParametersCable::Inversion::On: tmp="ON"; break;
+       case eDVBFrontendParametersCable::Inversion::Off: tmp="OFF"; break;
+       default:
+       case eDVBFrontendParametersCable::Inversion::Unknown: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "inversion", tmp);
+       switch (feparm.fec_inner)
+       {
+       case eDVBFrontendParametersCable::FEC::fNone: tmp="NONE"; break;
+       case eDVBFrontendParametersCable::FEC::f1_2: tmp="1/2"; break;
+       case eDVBFrontendParametersCable::FEC::f2_3: tmp="2/3"; break;
+       case eDVBFrontendParametersCable::FEC::f3_4: tmp="3/4"; break;
+       case eDVBFrontendParametersCable::FEC::f5_6: tmp="5/6"; break;
+       case eDVBFrontendParametersCable::FEC::f7_8: tmp="7/8"; break;
+       case eDVBFrontendParametersCable::FEC::f8_9: tmp="8/9"; break;
+       default:
+       case eDVBFrontendParametersCable::FEC::fAuto: tmp="AUTO"; break;
+       }
+       PutToDict(dict, "fec inner", tmp);
+}
+
+PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
+{
+       if (r.type == eServiceReference::idDVB)
+       {
+               const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)r;
+               switch(what)
+               {
+                       case iServiceInformation::sTransponderData:
+                       {
+                               ePtr<eDVBResourceManager> res;
+                               if (!eDVBResourceManager::getInstance(res))
+                               {
+                                       ePtr<iDVBChannelList> db;
+                                       if (!res->getChannelList(db))
+                                       {
+                                               eDVBChannelID chid;
+                                               ref.getChannelID(chid);
+                                               ePtr<iDVBFrontendParameters> feparm;
+                                               if (!db->getChannelFrontendData(chid, feparm))
+                                               {
+                                                       int system;
+                                                       if (!feparm->getSystem(system))
+                                                       {
+                                                               ePyObject dict = PyDict_New();
+                                                               switch(system)
+                                                               {
+                                                                       case iDVBFrontend::feSatellite:
+                                                                       {
+                                                                               eDVBFrontendParametersSatellite s;
+                                                                               feparm->getDVBS(s);
+                                                                               PutSatelliteDataToDict(dict, s);
+                                                                               break;
+                                                                       }
+                                                                       case iDVBFrontend::feTerrestrial:
+                                                                       {
+                                                                               eDVBFrontendParametersTerrestrial t;
+                                                                               feparm->getDVBT(t);
+                                                                               PutTerrestrialDataToDict(dict, t);
+                                                                               break;
+                                                                       }
+                                                                       case iDVBFrontend::feCable:
+                                                                       {
+                                                                               eDVBFrontendParametersCable c;
+                                                                               feparm->getDVBC(c);
+                                                                               PutCableDataToDict(dict, c);
+                                                                               break;
+                                                                       }
+                                                                       default:
+                                                                               eDebug("unknown frontend type %d", system);
+                                                                               Py_DECREF(dict);
+                                                                               break;
+                                                               }
+                                                               return dict;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       Py_RETURN_NONE;
+}
 
 DEFINE_REF(eStaticServiceDVBBouquetInformation);
 
@@ -134,11 +402,64 @@ RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref
                return -1;
 }
 
+int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
+{
+       if (ref.flags & eServiceReference::isGroup)
+       {
+               ePtr<iDVBChannelList> db;
+               ePtr<eDVBResourceManager> res;
+
+               if (eDVBResourceManager::getInstance(res))
+               {
+                       eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no resource manager!");
+                       return 0;
+               }
+
+               if (res->getChannelList(db))
+               {
+                       eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no channel list!");
+                       return 0;
+               }
+
+               eBouquet *bouquet=0;
+               if (db->getBouquet(ref, bouquet))
+               {
+                       eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. getBouquet failed!");
+                       return 0;
+               }
+
+               int cur=0;
+               eDVBChannelID chid, chid_ignore;
+               ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
+               for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
+               {
+                       ((const eServiceReferenceDVB&)*it).getChannelID(chid);
+                       int tmp=res->canAllocateChannel(chid, chid_ignore);
+                       if (tmp > cur)
+                       {
+                               m_playable_service = *it;
+                               cur = tmp;
+                       }
+               }
+               if (cur)
+                       return cur;
+       }
+       m_playable_service = eServiceReference();
+       return 0;
+}
+
 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
 {
        return -1;
 }
 
+#include <lib/dvb/epgcache.h>
+
+RESULT eStaticServiceDVBBouquetInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
+{
+       return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
+}
+
 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
 {
        DECLARE_REF(eStaticServiceDVBPVRInformation);
@@ -149,7 +470,7 @@ public:
        RESULT getName(const eServiceReference &ref, std::string &name);
        int getLength(const eServiceReference &ref);
        RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
-
+       int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
        int getInfo(const eServiceReference &ref, int w);
        std::string getInfoString(const eServiceReference &ref,int w);
 };
@@ -211,6 +532,8 @@ std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReferen
                return m_parser.m_description;
        case iServiceInformation::sServiceref:
                return m_parser.m_ref.toString();
+       case iServiceInformation::sTags:
+               return m_parser.m_tags;
        default:
                return "";
        }
@@ -381,7 +704,7 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sort
        
        if (!m_query)
                return -1;
-       
+
        while (!m_query->getNextResult(ref))
                list.push_back(ref);
 
@@ -398,6 +721,7 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sort
 //   S = Service Reference (as python string object .. same as ref.toString())
 //   C = Service Reference (as python string object .. same as ref.toCompareString())
 //   N = Service Name (as python string object)
+//   n = Short Service Name (short name brakets used) (as python string object)
 //   when exactly one return value per service is selected in the format string,
 //   then each value is directly a list entry
 //   when more than one value is returned per service, then the list is a list of
@@ -405,7 +729,7 @@ RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sort
 //   unknown format string chars are returned as python None values !
 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
 {
-       PyObject *ret=0;
+       ePyObject ret;
        std::list<eServiceReference> tmplist;
        int retcount=1;
 
@@ -418,7 +742,7 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                ePtr<iStaticServiceInformation> sptr;
                eServiceCenterPtr service_center;
 
-               if (strchr(format, 'N'))
+               if (strchr(format, 'N') || strchr(format, 'n'))
                        eServiceCenter::getPrivInstance(service_center);
 
                ret = PyList_New(services);
@@ -427,14 +751,14 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                for (int cnt=0; cnt < services; ++cnt)
                {
                        eServiceReference &ref=*it++;
-                       PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
+                       ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
                        for (int i=0; i < retcount; ++i)
                        {
-                               PyObject *tmp=0;
+                               ePyObject tmp;
                                switch(format[i])
                                {
                                case 'R':  // service reference (swig)object
-                                       tmp = New_eServiceReference(ref);
+                                       tmp = NEW_eServiceReference(ref);
                                        break;
                                case 'C':  // service reference compare string
                                        tmp = PyString_FromString(ref.toCompareString().c_str());
@@ -450,6 +774,30 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                                                {
                                                        std::string name;
                                                        sptr->getName(ref, name);
+
+                                                       // filter short name brakets
+                                                       unsigned int pos;
+                                                       while((pos = name.find("\xc2\x86")) != std::string::npos)
+                                                               name.erase(pos,2);
+                                                       while((pos = name.find("\xc2\x87")) != std::string::npos)
+                                                               name.erase(pos,2);
+
+                                                       if (name.length())
+                                                               tmp = PyString_FromString(name.c_str());
+                                               }
+                                       }
+                                       if (!tmp)
+                                               tmp = PyString_FromString("<n/a>");
+                                       break;
+                               case 'n':  // short service name
+                                       if (service_center)
+                                       {
+                                               service_center->info(ref, sptr);
+                                               if (sptr)
+                                               {
+                                                       std::string name;
+                                                       sptr->getName(ref, name);
+                                                       name = buildShortName(name);
                                                        if (name.length())
                                                                tmp = PyString_FromString(name.c_str());
                                                }
@@ -477,7 +825,7 @@ PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
                                PyList_SET_ITEM(ret, cnt, tuple);
                }
        }
-       return ret ? ret : PyList_New(0);
+       return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
 }
 
 RESULT eDVBServiceList::getNext(eServiceReference &ref)
@@ -488,14 +836,9 @@ RESULT eDVBServiceList::getNext(eServiceReference &ref)
        return m_query->getNextResult((eServiceReferenceDVB&)ref);
 }
 
-int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
-{
-       return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
-}
-
 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
 {
-       if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
+       if (m_parent.flags & eServiceReference::canDescent) // bouquet
        {
                ePtr<iDVBChannelList> db;
                ePtr<eDVBResourceManager> resm;
@@ -589,7 +932,7 @@ RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableServ
 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
 {
        /* is a listable service? */
-       if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
+       if (ref.flags & eServiceReference::canDescent) // bouquet
        {
                if ( !ref.name.empty() )  // satellites or providers list
                        ptr = m_StaticServiceDVBInfo;
@@ -657,6 +1000,7 @@ RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServ
 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
        m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
 {
+       memset(&m_videoEventData, 0, sizeof(struct iTSMPEGDecoder::videoEvent));
        m_is_primary = 1;
        m_is_pvr = !m_reference.path.empty();
        
@@ -672,6 +1016,8 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
        
        m_subtitle_widget = 0;
        
+       m_tune_state = -1;
+       
        CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
 }
 
@@ -698,6 +1044,8 @@ void eDVBServicePlay::gotNewEvent()
 
 void eDVBServicePlay::serviceEvent(int event)
 {
+       m_tune_state = event;
+
        switch (event)
        {
        case eDVBServicePMTHandler::eventTuned:
@@ -717,9 +1065,13 @@ void eDVBServicePlay::serviceEvent(int event)
                }
                break;
        }
+       case eDVBServicePMTHandler::eventNoResources:
+       case eDVBServicePMTHandler::eventNoPAT:
+       case eDVBServicePMTHandler::eventNoPATEntry:
+       case eDVBServicePMTHandler::eventNoPMT:
        case eDVBServicePMTHandler::eventTuneFailed:
        {
-               eDebug("DVB service failed to tune");
+               eDebug("DVB service failed to tune - error %d", event);
                m_event((iPlayableService*)this, evTuneFailed);
                break;
        }
@@ -772,6 +1124,8 @@ RESULT eDVBServicePlay::start()
                   to start recording from the data demux. */
        if (m_is_pvr)
                m_cue = new eCueSheet();
+       else
+               m_event(this, evStart);
 
        m_first_program_info = 1;
        eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
@@ -793,9 +1147,11 @@ RESULT eDVBServicePlay::start()
        }
 
        if (m_is_pvr)
+       {
                loadCuesheet();
+               m_event(this, evStart);
+       }
 
-       m_event(this, evStart);
        m_event((iPlayableService*)this, evSeekableStatusChanged);
        return 0;
 }
@@ -837,7 +1193,7 @@ RESULT eDVBServicePlay::stop()
                if (!::stat(m_reference.path.c_str(), &s))
                        saveCuesheet();
        }
-       
+       m_event((iPlayableService*)this, evStopped);
        return 0;
 }
 
@@ -1153,19 +1509,42 @@ RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
 int eDVBServicePlay::getInfo(int w)
 {
        eDVBServicePMTHandler::program program;
-
+       
        if (w == sCAIDs)
                return resIsPyObject;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
        
+       int no_program_info = 0;
+       
        if (h.getProgramInfo(program))
-               return -1;
+               no_program_info = 1;
        
        switch (w)
        {
+#if HAVE_DVB_API_VERSION >= 3
+       case sVideoHeight:
+               if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
+                       return m_videoEventData.height;
+               return -1;
+       case sVideoWidth:
+               if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
+                       return m_videoEventData.width;
+               return -1;
+#else
+#warning "FIXMEE implement sVideoHeight, sVideoWidth for old DVB API"
+#endif
        case sAspect:
-               if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
+#if HAVE_DVB_API_VERSION >= 3
+               if (m_videoEventData.type != iTSMPEGDecoder::videoEvent::eventUnknown)
+                       return m_videoEventData.aspect == VIDEO_FORMAT_4_3 ? 1 : 3;
+               else
+#else
+#warning "FIXMEE implement sAspect for old DVB API"
+#endif
+               if (no_program_info)
+                       return -1; 
+               else if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
                {
                        ePtr<eServiceEvent> evt;
                        if (!m_event_handler.getEvent(evt, 0))
@@ -1203,18 +1582,20 @@ int eDVBServicePlay::getInfo(int w)
                        }
                }
                return -1;
-       case sIsCrypted: return program.isCrypted();
-       case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
-       case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
-       case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
-       case sPCRPID: return program.pcrPid;
-       case sPMTPID: return program.pmtPid;
-       case sTXTPID: return program.textPid;
+       case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
+       case sVideoPID: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
+       case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
+       case sAudioPID: if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
+       case sPCRPID: if (no_program_info) return -1; return program.pcrPid;
+       case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
+       case sTXTPID: if (no_program_info) return -1; return program.textPid;
        case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
        case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
        case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
        case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
        case sProvider: if (!m_dvb_service) return -1; return -2;
+       case sServiceref: return resIsString;
+       case sDVBState: return m_tune_state;
        default:
                return -1;
        }
@@ -1227,6 +1608,8 @@ std::string eDVBServicePlay::getInfoString(int w)
        case sProvider:
                if (!m_dvb_service) return "";
                return m_dvb_service->m_provider_name;
+       case sServiceref:
+               return m_reference.toString();
        default:
                break;
        }
@@ -1239,6 +1622,8 @@ PyObject *eDVBServicePlay::getInfoObject(int w)
        {
        case sCAIDs:
                return m_service_handler.getCaIds();
+       case sTransponderData:
+               return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
        default:
                break;
        }
@@ -1364,7 +1749,7 @@ std::string eDVBServicePlay::getRadioText(int x)
                switch(x)
                {
                        case 0:
-                               return m_radiotext_parser->getCurrentText();
+                               return convertLatin1UTF8(m_radiotext_parser->getCurrentText());
                }
        return "";
 }
@@ -1385,19 +1770,54 @@ int eDVBServiceBase::getFrontendInfo(int w)
        return fe->readFrontendData(w);
 }
 
-PyObject *eDVBServiceBase::getFrontendData(bool original)
+PyObject *eDVBServiceBase::getFrontendData()
 {
-       PyObject *ret=0;
+       ePyObject ret = PyDict_New();
+       if (ret)
+       {
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
+               {
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                               fe->getFrontendData(ret);
+               }
+       }
+       else
+               Py_RETURN_NONE;
+       return ret;
+}
 
-       eUsePtr<iDVBChannel> channel;
-       if(!m_service_handler.getChannel(channel))
+PyObject *eDVBServiceBase::getFrontendStatus()
+{
+       ePyObject ret = PyDict_New();
+       if (ret)
+       {
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
+               {
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                               fe->getFrontendStatus(ret);
+               }
+       }
+       else
+               Py_RETURN_NONE;
+       return ret;
+}
+
+PyObject *eDVBServiceBase::getTransponderData(bool original)
+{
+       ePyObject ret = PyDict_New();
+       if (ret)
        {
-               ePtr<iDVBFrontend> fe;
-               if(!channel->getFrontend(fe))
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
                {
-                       ret = fe->readTransponderData(original);
-                       if (ret)
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
                        {
+                               fe->getTransponderData(ret, original);
                                ePtr<iDVBFrontendParameters> feparm;
                                channel->getCurrentFrontendParameters(feparm);
                                if (feparm)
@@ -1405,8 +1825,8 @@ PyObject *eDVBServiceBase::getFrontendData(bool original)
                                        eDVBFrontendParametersSatellite osat;
                                        if (!feparm->getDVBS(osat))
                                        {
-                                               void PutToDict(PyObject *, const char*, long);
-                                               void PutToDict(PyObject *, const char*, const char*);
+                                               void PutToDict(ePyObject &, const char*, long);
+                                               void PutToDict(ePyObject &, const char*, const char*);
                                                PutToDict(ret, "orbital_position", osat.orbital_position);
                                                const char *tmp = "UNKNOWN";
                                                switch(osat.polarisation)
@@ -1423,10 +1843,26 @@ PyObject *eDVBServiceBase::getFrontendData(bool original)
                        }
                }
        }
-       if (!ret)
+       else
+               Py_RETURN_NONE;
+       return ret;
+}
+
+PyObject *eDVBServiceBase::getAll(bool original)
+{
+       ePyObject ret = getTransponderData(original);
+       if (ret != Py_None)
        {
-               ret = Py_None;
-               Py_INCREF(ret);
+               eUsePtr<iDVBChannel> channel;
+               if(!m_service_handler.getChannel(channel))
+               {
+                       ePtr<iDVBFrontend> fe;
+                       if(!channel->getFrontend(fe))
+                       {
+                               fe->getFrontendData(ret);
+                               fe->getFrontendStatus(ret);
+                       }
+               }
        }
        return ret;
 }
@@ -1504,7 +1940,7 @@ RESULT eDVBServicePlay::stopTimeshift()
        
        close(m_timeshift_fd);
        eDebug("remove timeshift file");
-       remove(m_timeshift_file.c_str());
+       eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
        
        return 0;
 }
@@ -1530,11 +1966,11 @@ RESULT eDVBServicePlay::activateTimeshift()
 
 PyObject *eDVBServicePlay::getCutList()
 {
-       PyObject *list = PyList_New(0);
+       ePyObject list = PyList_New(0);
        
        for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
        {
-               PyObject *tuple = PyTuple_New(2);
+               ePyObject tuple = PyTuple_New(2);
                PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
                PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
                PyList_Append(list, tuple);
@@ -1544,7 +1980,7 @@ PyObject *eDVBServicePlay::getCutList()
        return list;
 }
 
-void eDVBServicePlay::setCutList(PyObject *list)
+void eDVBServicePlay::setCutList(ePyObject list)
 {
        if (!PyList_Check(list))
                return;
@@ -1555,7 +1991,7 @@ void eDVBServicePlay::setCutList(PyObject *list)
        
        for (i=0; i<size; ++i)
        {
-               PyObject *tuple = PyList_GetItem(list, i);
+               ePyObject tuple = PyList_GET_ITEM(list, i);
                if (!PyTuple_Check(tuple))
                {
                        eDebug("non-tuple in cutlist");
@@ -1566,7 +2002,7 @@ void eDVBServicePlay::setCutList(PyObject *list)
                        eDebug("cutlist entries need to be a 2-tuple");
                        continue;
                }
-               PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
+               ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
                if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
                {
                        eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
@@ -1619,6 +2055,11 @@ void eDVBServicePlay::updateTimeshiftPids()
                        i != program.audioStreams.end(); ++i)
                                pids_to_record.insert(i->pid);
 
+               for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
+                       i(program.subtitleStreams.begin());
+                       i != program.subtitleStreams.end(); ++i)
+                               pids_to_record.insert(i->pid);
+
                std::set<int> new_pids, obsolete_pids;
                
                std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
@@ -1653,6 +2094,7 @@ void eDVBServicePlay::switchToLive()
        m_new_dvb_subtitle_page_connection = 0;
        m_new_subtitle_page_connection = 0;
        m_radiotext_updated_connection = 0;
+       m_video_event_connection = 0;
 
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
@@ -1676,17 +2118,18 @@ void eDVBServicePlay::switchToTimeshift()
        m_new_subtitle_page_connection = 0;
        m_new_dvb_subtitle_page_connection = 0;
        m_radiotext_updated_connection = 0;
+       m_video_event_connection = 0;
 
        m_timeshift_active = 1;
 
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
-
        eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
        r.path = m_timeshift_file;
 
        m_cue = new eCueSheet();
        m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
        updateDecoder(); /* mainly to switch off PCR */
+
+       m_event((iPlayableService*)this, evSeekableStatusChanged);
 }
 
 void eDVBServicePlay::updateDecoder()
@@ -1757,13 +2200,15 @@ void eDVBServicePlay::updateDecoder()
        {
                h.getDecodeDemux(m_decode_demux);
                if (m_decode_demux)
+               {
                        m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
+                       if (m_decoder)
+                               m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
+               }
                if (m_cue)
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
-#ifdef INTERNAL_TELETEXT
                m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
                m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
-#endif
                m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
                m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
        }
@@ -1865,7 +2310,7 @@ void eDVBServicePlay::updateDecoder()
                        m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
                        m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
                }
-       }
+       }       
        m_have_video_pid = (vpid > 0 && vpid < 0x2000);
 }
 
@@ -1990,44 +2435,101 @@ void eDVBServicePlay::cutlistToCuesheet()
        m_cue->commitSpans();
 }
 
-RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
+RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
 {
        if (m_subtitle_widget)
                disableSubtitles(parent);
-       
-       if (!PyInt_Check(entry))
-               return -1;
 
-       int page = PyInt_AsLong(entry);
+       ePyObject entry;
+       int tuplesize = PyTuple_Size(tuple);
+       int type = 0;
 
-       if (page > 0 && !m_teletext_parser)
-               return -1;
-       if (page < 0 && !m_subtitle_parser)
-               return -1;
+       if (!PyTuple_Check(tuple))
+               goto error_out;
+
+       if (tuplesize < 1)
+               goto error_out;
+
+       entry = PyTuple_GET_ITEM(tuple, 0);
+
+       if (!PyInt_Check(entry))
+               goto error_out;
 
-       m_subtitle_widget = new eSubtitleWidget(parent);
-       m_subtitle_widget->resize(parent->size()); /* full size */
+       type = PyInt_AsLong(entry);
 
-       if (page > 0)
+       if (type == 1)  // teletext subtitles
        {
-/*             eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
-               eDVBServicePMTHandler::program program;
-               if (h.getProgramInfo(program))
-                       eDebug("getting program info failed.");
-               else
+               int page, magazine, pid;
+               if (tuplesize < 4)
+                       goto error_out;
+
+               if (!m_teletext_parser)
                {
-                       eDebug("start teletext on pid %04x, page %d", program.textPid, page);
-                       m_teletext_parser->start(program.textPid);*/
-                       m_teletext_parser->setPage(page);
-//             }
+                       eDebug("enable teletext subtitles.. no parser !!!");
+                       return -1;
+               }
+
+               entry = PyTuple_GET_ITEM(tuple, 1);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               pid = PyInt_AsLong(entry);
+
+               entry = PyTuple_GET_ITEM(tuple, 2);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               page = PyInt_AsLong(entry);
+
+               entry = PyTuple_GET_ITEM(tuple, 3);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               magazine = PyInt_AsLong(entry);
+
+               m_subtitle_widget = new eSubtitleWidget(parent);
+               m_subtitle_widget->resize(parent->size()); /* full size */
+               m_teletext_parser->setPageAndMagazine(page, magazine);
+               if (m_dvb_service)
+                       m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
        }
-       else
+       else if (type == 0)
        {
-               int pid = -page;
-               m_subtitle_parser->start(pid);
+               int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
+               if (!m_subtitle_parser)
+               {
+                       eDebug("enable dvb subtitles.. no parser !!!");
+                       return -1;
+               }
+               if (tuplesize < 4)
+                       goto error_out;
+
+               entry = PyTuple_GET_ITEM(tuple, 1);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               pid = PyInt_AsLong(entry);
+
+               entry = PyTuple_GET_ITEM(tuple, 2);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               composition_page_id = PyInt_AsLong(entry);
+
+               entry = PyTuple_GET_ITEM(tuple, 3);
+               if (!PyInt_Check(entry))
+                       goto error_out;
+               ancillary_page_id = PyInt_AsLong(entry);
+
+               m_subtitle_widget = new eSubtitleWidget(parent);
+               m_subtitle_widget->resize(parent->size()); /* full size */
+               m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
+               if (m_dvb_service)
+                       m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
        }
-
+       else
+               goto error_out;
        return 0;
+error_out:
+       eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
+               "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
+               "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
+       return -1;
 }
 
 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
@@ -2041,32 +2543,52 @@ RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
        }
        if (m_teletext_parser)
        {
-               m_teletext_parser->setPage(-1);
+               m_teletext_parser->setPageAndMagazine(-1, -1);
                m_subtitle_pages.clear();
        }
+       if (m_dvb_service)
+               m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
        return 0;
 }
 
-PyObject *eDVBServicePlay::getSubtitleList()
+PyObject *eDVBServicePlay::getCachedSubtitle()
 {
-       if (!m_teletext_parser)
+       if (m_dvb_service)
        {
-               Py_INCREF(Py_None);
-               return Py_None;
+               int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
+               if (tmp != -1)
+               {
+                       unsigned int data = (unsigned int)tmp;
+                       int pid = (data&0xFFFF0000)>>16;
+                       ePyObject tuple = PyTuple_New(4);
+                       eDVBServicePMTHandler::program program;
+                       eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+                       if (!h.getProgramInfo(program))
+                       {
+                               if (program.textPid==pid) // teletext
+                                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
+                               else
+                                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
+                               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
+                               PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
+                               PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
+                               return tuple;
+                       }
+               }
        }
+       Py_RETURN_NONE;
+}
+
+PyObject *eDVBServicePlay::getSubtitleList()
+{
+       if (!m_teletext_parser)
+               Py_RETURN_NONE;
        
-       PyObject *l = PyList_New(0);
-       
-       for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
-       {
-               PyObject *tuple = PyTuple_New(2);
-               char desc[20];
-               sprintf(desc, "Page %x", *i);
-               PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
-               PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
-               PyList_Append(l, tuple);
-               Py_DECREF(tuple);
-       }
+       ePyObject l = PyList_New(0);
+       std::set<int> added_ttx_pages;
+
+       std::set<eDVBServicePMTHandler::subtitleStream> &subs =
+               m_teletext_parser->m_found_subtitle_pages;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
        eDVBServicePMTHandler::program program;
@@ -2077,11 +2599,58 @@ PyObject *eDVBServicePlay::getSubtitleList()
                for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
                        it != program.subtitleStreams.end(); ++it)
                {
-                       PyObject *tuple = PyTuple_New(2);
-                       char desc[20];
-                       sprintf(desc, "DVB %s", it->language_code.c_str());
-                       PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
-                       PyTuple_SetItem(tuple, 1, PyInt_FromLong(-it->pid));
+                       switch(it->subtitling_type)
+                       {
+                               case 0x01: // ebu teletext subtitles
+                               {
+                                       int page_number = it->teletext_page_number & 0xFF;
+                                       int magazine_number = it->teletext_magazine_number & 7;
+                                       int hash = magazine_number << 8 | page_number;
+                                       if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+                                       {
+                                               ePyObject tuple = PyTuple_New(5);
+                                               PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+                                               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+                                               PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+                                               PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+                                               PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+                                               PyList_Append(l, tuple);
+                                               Py_DECREF(tuple);
+                                               added_ttx_pages.insert(hash);
+                                       }
+                                       break;
+                               }
+                               case 0x10 ... 0x13:
+                               case 0x20 ... 0x23: // dvb subtitles
+                               {
+                                       ePyObject tuple = PyTuple_New(5);
+                                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
+                                       PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+                                       PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
+                                       PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
+                                       PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+                                       PyList_Insert(l, 0, tuple);
+                                       Py_DECREF(tuple);
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
+               it != subs.end(); ++it)
+       {
+               int page_number = it->teletext_page_number & 0xFF;
+               int magazine_number = it->teletext_magazine_number & 7;
+               int hash = magazine_number << 8 | page_number;
+               if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+               {
+                       ePyObject tuple = PyTuple_New(5);
+                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+                       PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+                       PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+                       PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+                       PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
                        PyList_Append(l, tuple);
                        Py_DECREF(tuple);
                }
@@ -2159,7 +2728,7 @@ void eDVBServicePlay::checkSubtitleTiming()
                        }
                } else
                {
-                       eDebug("start subtitle delay %d", diff / 90);
+//                     eDebug("start subtitle delay %d", diff / 90);
                        m_subtitle_sync_timer.start(diff / 90, 1);
                        break;
                }
@@ -2211,6 +2780,24 @@ void eDVBServicePlay::setPCMDelay(int delay)
                m_decoder->setPCMDelay(delay);
 }
 
+void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
+{
+       memcpy(&m_videoEventData, &event, sizeof(iTSMPEGDecoder::videoEvent));
+       m_event((iPlayableService*)this, evVideoSizeChanged);
+}
+
 DEFINE_REF(eDVBServicePlay)
 
+PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
+{
+       switch (w)
+       {
+       case iServiceInformation::sTransponderData:
+               return eStaticServiceDVBInformation().getInfoObject(ref, w);
+       default:
+               break;
+       }
+       return iStaticServiceInformation::getInfoObject(ref, w);
+}
+
 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");