servicemp3.cpp: dont apply ac3/pcm delay when no video is running
[enigma2.git] / lib / service / servicedvb.cpp
index 4141236a7df521abde818014e08a5e7ff703890c..6d9cad09fbe8e9d10d409dad946ac3f8fc2e7590 100644 (file)
@@ -96,218 +96,10 @@ int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const
        return false;
 }
 
        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.rolloff)
-                       {
-                               default:
-                               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;
-                       }
-                       PutToDict(dict, "roll off", tmp);
-                       switch(feparm.pilot)
-                       {
-                               case eDVBFrontendParametersSatellite::Pilot::On: tmp="ON"; break;
-                               case eDVBFrontendParametersSatellite::Pilot::Off: tmp="OFF"; break;
-                               default:
-                               case eDVBFrontendParametersSatellite::Pilot::Unknown: tmp="AUTO"; break;
-                       }
-                       PutToDict(dict, "pilot", 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);
-}
+extern void PutToDict(ePyObject &dict, const char*key, long value);  // defined in dvb/frontend.cpp
+extern void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm); // defined in dvb/frontend.cpp
+extern void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm); // defined in dvb/frontend.cpp
+extern void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm); // defined in dvb/frontend.cpp
 
 PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
 {
 
 PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
 {
@@ -503,6 +295,7 @@ public:
        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);
        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);
+       PyObject *getInfoObject(const eServiceReference &r, int what);
 };
 
 DEFINE_REF(eStaticServiceDVBPVRInformation);
 };
 
 DEFINE_REF(eStaticServiceDVBPVRInformation);
@@ -534,14 +327,29 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
        
        eDVBTSTools tstools;
        
        
        eDVBTSTools tstools;
        
+       struct stat s;
+       stat(ref.path.c_str(), &s);
+
+       if (tstools.openFile(ref.path.c_str(), 1))
+               return 0;
+
+                       /* check if cached data is still valid */
+       if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
+               return m_parser.m_length / 90000;
+
+                       /* open again, this time with stream info */
        if (tstools.openFile(ref.path.c_str()))
                return 0;
 
        if (tstools.openFile(ref.path.c_str()))
                return 0;
 
+                       /* otherwise, re-calc length and update meta file */
        pts_t len;
        if (tstools.calcLen(len))
                return 0;
 
        pts_t len;
        if (tstools.calcLen(len))
                return 0;
 
-       return len / 90000;
+       m_parser.m_length = len;
+       m_parser.m_filesize = s.st_size;
+       m_parser.updateMeta(ref.path);
+       return m_parser.m_length / 90000;
 }
 
 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
 }
 
 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
@@ -552,6 +360,8 @@ int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w
                return iServiceInformation::resIsString;
        case iServiceInformation::sServiceref:
                return iServiceInformation::resIsString;
                return iServiceInformation::resIsString;
        case iServiceInformation::sServiceref:
                return iServiceInformation::resIsString;
+       case iServiceInformation::sFileSize:
+               return m_parser.m_filesize;
        case iServiceInformation::sTimeCreate:
                if (m_parser.m_time_create)
                        return m_parser.m_time_create;
        case iServiceInformation::sTimeCreate:
                if (m_parser.m_time_create)
                        return m_parser.m_time_create;
@@ -577,6 +387,17 @@ std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReferen
        }
 }
 
        }
 }
 
+PyObject *eStaticServiceDVBPVRInformation::getInfoObject(const eServiceReference &r, int what)
+{
+       switch (what)
+       {
+       case iServiceInformation::sFileSize:
+               return PyLong_FromLongLong(m_parser.m_filesize);
+       default:
+               Py_RETURN_NONE;
+       }
+}
+
 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
 {
        if (!ref.path.empty())
 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
 {
        if (!ref.path.empty())
@@ -604,6 +425,7 @@ public:
        
        RESULT deleteFromDisk(int simulate);
        RESULT getListOfFilenames(std::list<std::string> &);
        
        RESULT deleteFromDisk(int simulate);
        RESULT getListOfFilenames(std::list<std::string> &);
+       RESULT reindex();
 };
 
 DEFINE_REF(eDVBPVRServiceOfflineOperations);
 };
 
 DEFINE_REF(eDVBPVRServiceOfflineOperations);
@@ -658,6 +480,7 @@ RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string
 
        res.push_back(m_ref.path + ".meta");
        res.push_back(m_ref.path + ".ap");
 
        res.push_back(m_ref.path + ".meta");
        res.push_back(m_ref.path + ".ap");
+       res.push_back(m_ref.path + ".sc");
        res.push_back(m_ref.path + ".cuts");
        std::string tmp = m_ref.path;
        tmp.erase(m_ref.path.length()-3);
        res.push_back(m_ref.path + ".cuts");
        std::string tmp = m_ref.path;
        tmp.erase(m_ref.path.length()-3);
@@ -665,6 +488,42 @@ RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string
        return 0;
 }
 
        return 0;
 }
 
+RESULT eDVBPVRServiceOfflineOperations::reindex()
+{
+       const char *filename = m_ref.path.c_str();
+       eDebug("reindexing %s...", filename);
+
+       eMPEGStreamInformation info;
+       eMPEGStreamParserTS parser(info);
+       
+       info.startSave(filename);
+       
+       eRawFile f;
+       
+       int err = f.open(m_ref.path.c_str(), 0);
+       if (err < 0)
+               return -1;
+       
+       off_t length = f.length();
+       unsigned char buffer[188*256*4];
+       while (1)
+       {
+               off_t offset = f.lseek(0, SEEK_CUR);
+               eDebug("at %08llx / %08llx (%d %%)", offset, length, (int)(offset * 100 / length));
+               int r = f.read(buffer, sizeof(buffer));
+               if (!r)
+                       break;
+               if (r < 0)
+                       return r;
+               parser.parseData(offset, buffer, r);
+       }
+       
+       info.stopSave();
+       f.close();
+       
+       return 0;
+}
+
 DEFINE_REF(eServiceFactoryDVB)
 
 eServiceFactoryDVB::eServiceFactoryDVB()
 DEFINE_REF(eServiceFactoryDVB)
 
 eServiceFactoryDVB::eServiceFactoryDVB()
@@ -676,6 +535,7 @@ eServiceFactoryDVB::eServiceFactoryDVB()
        {
                std::list<std::string> extensions;
                extensions.push_back("ts");
        {
                std::list<std::string> extensions;
                extensions.push_back("ts");
+               extensions.push_back("trp");
                sc->addServiceFactory(eServiceFactoryDVB::id, this, extensions);
        }
 
                sc->addServiceFactory(eServiceFactoryDVB::id, this, extensions);
        }
 
@@ -1010,30 +870,41 @@ RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<
 
 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
 {
 
 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
 {
-                       // TODO: handle the listing itself
-       // if (ref.... == -1) .. return "... bouquets ...";
-       // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
-                       // TODO: cache
-       ePtr<iDVBChannelList> db;
-       ePtr<eDVBResourceManager> res;
-       
-       int err;
-       if ((err = eDVBResourceManager::getInstance(res)) != 0)
+       if (!ref.path.empty()) // playback
        {
        {
-               eDebug("no resource manager");
-               return err;
+               eDVBMetaParser parser;
+               int ret=parser.parseFile(ref.path);
+               service = new eDVBService;
+               if (!ret)
+                       eDVBDB::getInstance()->parseServiceData(service, parser.m_service_data);
        }
        }
-       if ((err = res->getChannelList(db)) != 0)
+       else
        {
        {
-               eDebug("no channel list");
-               return err;
-       }
+                       // TODO: handle the listing itself
+               // if (ref.... == -1) .. return "... bouquets ...";
+               // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
+                       // TODO: cache
+               ePtr<iDVBChannelList> db;
+               ePtr<eDVBResourceManager> res;
+       
+               int err;
+               if ((err = eDVBResourceManager::getInstance(res)) != 0)
+               {
+                       eDebug("no resource manager");
+                       return err;
+               }
+               if ((err = res->getChannelList(db)) != 0)
+               {
+                       eDebug("no channel list");
+                       return err;
+               }
        
                /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
        
                /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
-       if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
-       {
-               eDebug("getService failed!");
-               return err;
+               if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
+               {
+                       eDebug("getService failed!");
+                       return err;
+               }
        }
 
        return 0;
        }
 
        return 0;
@@ -1042,11 +913,10 @@ 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)
 {
 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();
        
        m_is_primary = 1;
        m_is_pvr = !m_reference.path.empty();
        
-       m_timeshift_enabled = m_timeshift_active = 0;
+       m_timeshift_enabled = m_timeshift_active = 0, m_timeshift_changed = 0;
        m_skipmode = 0;
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
        m_skipmode = 0;
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
@@ -1067,6 +937,29 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
 
 eDVBServicePlay::~eDVBServicePlay()
 {
 
 eDVBServicePlay::~eDVBServicePlay()
 {
+       if (m_is_pvr)
+       {
+               eDVBMetaParser meta;
+               int ret=meta.parseFile(m_reference.path);
+               if (!ret)
+               {
+                       char tmp[255];
+                       meta.m_service_data="";
+                       sprintf(tmp, "f:%x", m_dvb_service->m_flags);
+                       meta.m_service_data += tmp;
+                       // cached pids
+                       for (int x=0; x < eDVBService::cacheMax; ++x)
+                       {
+                               int entry = m_dvb_service->getCacheEntry((eDVBService::cacheID)x);
+                               if (entry != -1)
+                               {
+                                       sprintf(tmp, ",c:%02d%04x", x, entry);
+                                       meta.m_service_data += tmp;
+                               }
+                       }
+                       meta.updateMeta(m_reference.path);
+               }
+       }
        delete m_subtitle_widget;
 }
 
        delete m_subtitle_widget;
 }
 
@@ -1158,29 +1051,40 @@ void eDVBServicePlay::serviceEventTimeshift(int event)
                break;
        case eDVBServicePMTHandler::eventEOF:
                if ((!m_is_paused) && (m_skipmode >= 0))
                break;
        case eDVBServicePMTHandler::eventEOF:
                if ((!m_is_paused) && (m_skipmode >= 0))
+               {
+                       eDebug("timeshift EOF, so let's go live");
                        switchToLive();
                        switchToLive();
+               }
                break;
        }
 }
 
 RESULT eDVBServicePlay::start()
 {
                break;
        }
 }
 
 RESULT eDVBServicePlay::start()
 {
-       int r;
+       eServiceReferenceDVB service = (eServiceReferenceDVB&)m_reference;
+
                /* in pvr mode, we only want to use one demux. in tv mode, we're using 
                   two (one for decoding, one for data source), as we must be prepared
                   to start recording from the data demux. */
        if (m_is_pvr)
                /* in pvr mode, we only want to use one demux. in tv mode, we're using 
                   two (one for decoding, one for data source), as we must be prepared
                   to start recording from the data demux. */
        if (m_is_pvr)
+       {
+               eDVBMetaParser meta;
+               if (!meta.parseFile(m_reference.path))
+               {
+                       service = meta.m_ref;
+                       service.path = m_reference.path;
+               }
                m_cue = new eCueSheet();
                m_cue = new eCueSheet();
+       }
        else
                m_event(this, evStart);
 
        m_first_program_info = 1;
        else
                m_event(this, evStart);
 
        m_first_program_info = 1;
-       eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
-       r = m_service_handler.tune(service, m_is_pvr, m_cue);
+       m_service_handler.tune(service, m_is_pvr, m_cue, false, m_dvb_service);
 
 
-               /* inject EIT if there is a stored one */
        if (m_is_pvr)
        {
        if (m_is_pvr)
        {
+               /* inject EIT if there is a stored one */
                std::string filename = service.path;
                filename.erase(filename.length()-2, 2);
                filename+="eit";
                std::string filename = service.path;
                filename.erase(filename.length()-2, 2);
                filename+="eit";
@@ -1191,10 +1095,6 @@ RESULT eDVBServicePlay::start()
                        m_event_handler.inject(event, 0);
                        m_event_handler.inject(empty, 1);
                }
                        m_event_handler.inject(event, 0);
                        m_event_handler.inject(empty, 1);
                }
-       }
-
-       if (m_is_pvr)
-       {
                loadCuesheet();
                m_event(this, evStart);
        }
                loadCuesheet();
                m_event(this, evStart);
        }
@@ -1281,6 +1181,9 @@ RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
 
 RESULT eDVBServicePlay::setSlowMotion(int ratio)
 {
 
 RESULT eDVBServicePlay::setSlowMotion(int ratio)
 {
+       ASSERT(ratio); /* The API changed: instead of calling setSlowMotion(0), call play! */
+       eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
+       setFastForward_internal(0);
        if (m_decoder)
                return m_decoder->setSlowMotion(ratio);
        else
        if (m_decoder)
                return m_decoder->setSlowMotion(ratio);
        else
@@ -1288,6 +1191,13 @@ RESULT eDVBServicePlay::setSlowMotion(int ratio)
 }
 
 RESULT eDVBServicePlay::setFastForward(int ratio)
 }
 
 RESULT eDVBServicePlay::setFastForward(int ratio)
+{
+       eDebug("eDVBServicePlay::setFastForward(%d)", ratio);
+       ASSERT(ratio);
+       return setFastForward_internal(ratio);
+}
+
+RESULT eDVBServicePlay::setFastForward_internal(int ratio)
 {
        int skipmode, ffratio;
        
 {
        int skipmode, ffratio;
        
@@ -1320,8 +1230,14 @@ RESULT eDVBServicePlay::setFastForward(int ratio)
        
        if (!m_decoder)
                return -1;
        
        if (!m_decoder)
                return -1;
-
-       return m_decoder->setFastForward(ffratio);
+               
+       if (ffratio == 0)
+               ; /* return m_decoder->play(); is done in caller*/
+       else if (ffratio != 1)
+               return m_decoder->setFastForward(ffratio);
+       else
+               return m_decoder->setTrickmode();
+       return 0;
 }
 
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
 }
 
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
@@ -1349,20 +1265,24 @@ RESULT eDVBServicePlay::getLength(pts_t &len)
 
 RESULT eDVBServicePlay::pause()
 {
 
 RESULT eDVBServicePlay::pause()
 {
-       if (!m_is_paused && m_decoder)
+       eDebug("eDVBServicePlay::pause");
+       setFastForward_internal(0);
+       if (m_decoder)
        {
                m_is_paused = 1;
        {
                m_is_paused = 1;
-               return m_decoder->freeze(0);
+               return m_decoder->pause();
        } else
                return -1;
 }
 
 RESULT eDVBServicePlay::unpause()
 {
        } else
                return -1;
 }
 
 RESULT eDVBServicePlay::unpause()
 {
-       if (m_is_paused && m_decoder)
+       eDebug("eDVBServicePlay::unpause");
+       setFastForward_internal(0);
+       if (m_decoder)
        {
                m_is_paused = 0;
        {
                m_is_paused = 0;
-               return m_decoder->unfreeze();
+               return m_decoder->play();
        } else
                return -1;
 }
        } else
                return -1;
 }
@@ -1444,9 +1364,8 @@ RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
 
 RESULT eDVBServicePlay::setTrickmode(int trick)
 {
 
 RESULT eDVBServicePlay::setTrickmode(int trick)
 {
-       if (m_decoder)
-               m_decoder->setTrickmode(trick);
-       return 0;
+               /* currently unimplemented */
+       return -1;
 }
 
 RESULT eDVBServicePlay::isCurrentlySeekable()
 }
 
 RESULT eDVBServicePlay::isCurrentlySeekable()
@@ -1555,7 +1474,7 @@ RESULT eDVBServicePlay::getName(std::string &name)
                ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
                return i->getName(m_reference, name);
        }
                ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
                return i->getName(m_reference, name);
        }
-       if (m_dvb_service)
+       else if (m_dvb_service)
        {
                m_dvb_service->getName(m_reference, name);
                if (name.empty())
        {
                m_dvb_service->getName(m_reference, name);
                if (name.empty())
@@ -1573,20 +1492,6 @@ RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
        return m_event_handler.getEvent(evt, nownext);
 }
 
        return m_event_handler.getEvent(evt, nownext);
 }
 
-static int readMpegProc(char *str, int decoder)
-{
-       int val = -1;
-       char tmp[64];
-       sprintf(tmp, "/proc/stb/vmpeg/%d/%s", decoder, str);
-       FILE *f = fopen(tmp, "r");
-       if (f)
-       {
-               fscanf(f, "%x", &val);
-               fclose(f);
-       }
-       return val;
-}
-
 int eDVBServicePlay::getInfo(int w)
 {
        eDVBServicePMTHandler::program program;
 int eDVBServicePlay::getInfo(int w)
 {
        eDVBServicePMTHandler::program program;
@@ -1603,44 +1508,30 @@ int eDVBServicePlay::getInfo(int w)
 
        switch (w)
        {
 
        switch (w)
        {
-#if HAVE_DVB_API_VERSION >= 3
        case sVideoHeight:
        case sVideoHeight:
-               if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventSizeChanged)
-                       return m_videoEventData.height;
-               else
-                       return readMpegProc("yres", !m_is_primary);
+               if (m_decoder)
+                       return m_decoder->getVideoHeight();
+               break;
        case sVideoWidth:
        case sVideoWidth:
-               if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventSizeChanged)
-                       return m_videoEventData.width;
-               else
-                       return readMpegProc("xres", !m_is_primary);
+               if (m_decoder)
+                       return m_decoder->getVideoWidth();
+               break;
        case sFrameRate:
        case sFrameRate:
-               if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventFrameRateChanged)
-                       return m_videoEventData.framerate;
-               else
-                       return readMpegProc("framerate", !m_is_primary);
+               if (m_decoder)
+                       return m_decoder->getVideoFrameRate();
+               break;
        case sProgressive:
        case sProgressive:
-               if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventProgressiveChanged)
-                       return m_videoEventData.progressive;
-               return readMpegProc("progressive", !m_is_primary);
-#else
-#warning "FIXMEE implement sFrameRate, sProgressive, sVideoHeight, sVideoWidth for old DVB API"
-#endif
+               if (m_decoder)
+                       return m_decoder->getVideoProgressive();
+               break;
        case sAspect:
        {
        case sAspect:
        {
-               int val;
-#if HAVE_DVB_API_VERSION >= 3
-               if (m_videoEventData.type == iTSMPEGDecoder::videoEvent::eventSizeChanged)
-                       return m_videoEventData.aspect == VIDEO_FORMAT_4_3 ? 1 : 3;
-               else if ((val=readMpegProc("aspect", !m_is_primary)) != -1)
-                       return val;
-               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)
+               int aspect = -1;
+               if (m_decoder)
+                       aspect = m_decoder->getVideoAspect();
+               if (aspect == -1 && no_program_info)
+                       break;
+               else if (aspect == -1 && !program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
                {
                        ePtr<eServiceEvent> evt;
                        if (!m_event_handler.getEvent(evt, 0))
                {
                        ePtr<eServiceEvent> evt;
                        if (!m_event_handler.getEvent(evt, 0))
@@ -1677,13 +1568,39 @@ int eDVBServicePlay::getInfo(int w)
                                }
                        }
                }
                                }
                        }
                }
-               return -1;
+               else
+                       return aspect;
+               break;
        }
        case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
        }
        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 sVideoPID:
+               if (m_dvb_service)
+               {
+                       int vpid = m_dvb_service->getCacheEntry(eDVBService::cVPID);
+                       if (vpid != -1)
+                               return vpid;
+               }
+               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 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 sAudioPID:
+               if (m_dvb_service)
+               {
+                       int apid = m_dvb_service->getCacheEntry(eDVBService::cAPID);
+                       if (apid != -1)
+                               return apid;
+                       apid = m_dvb_service->getCacheEntry(eDVBService::cAC3PID);
+                       if (apid != -1)
+                               return apid;
+               }
+               if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
+       case sPCRPID:
+               if (m_dvb_service)
+               {
+                       int pcrpid = m_dvb_service->getCacheEntry(eDVBService::cPCRPID);
+                       if (pcrpid != -1)
+                               return pcrpid;
+               }
+               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 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();
@@ -1694,8 +1611,9 @@ int eDVBServicePlay::getInfo(int w)
        case sServiceref: return resIsString;
        case sDVBState: return m_tune_state;
        default:
        case sServiceref: return resIsString;
        case sDVBState: return m_tune_state;
        default:
-               return -1;
+               break;
        }
        }
+       return -1;
 }
 
 std::string eDVBServicePlay::getInfoString(int w)
 }
 
 std::string eDVBServicePlay::getInfoString(int w)
@@ -1757,7 +1675,7 @@ RESULT eDVBServicePlay::selectTrack(unsigned int i)
 {
        int ret = selectAudioStream(i);
 
 {
        int ret = selectAudioStream(i);
 
-       if (m_decoder->start())
+       if (m_decoder->set())
                return -5;
 
        return ret;
                return -5;
 
        return ret;
@@ -1782,6 +1700,8 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int
                info.m_description = "AC3";
        else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
                info.m_description = "AAC";
                info.m_description = "AC3";
        else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
                info.m_description = "AAC";
+       else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
+               info.m_description = "AAC-HE";
        else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
                info.m_description = "DTS";
        else
        else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
                info.m_description = "DTS";
        else
@@ -1832,27 +1752,32 @@ int eDVBServicePlay::selectAudioStream(int i)
 
        m_current_audio_pid = apid;
 
 
        m_current_audio_pid = apid;
 
-       if (m_decoder->setAudioPID(apid, apidtype))
+       if (m_is_primary && m_decoder->setAudioPID(apid, apidtype))
        {
                eDebug("set audio pid failed");
                return -4;
        }
 
        {
                eDebug("set audio pid failed");
                return -4;
        }
 
+       int rdsPid = apid;
+
                /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */
        if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
                /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */
        if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
-               if (!m_rds_decoder)
+       {
+               int different_pid = program.videoStreams.empty() && program.audioStreams.size() == 1 && program.audioStreams[stream].rdsPid != -1;
+               if (different_pid)
+                       rdsPid = program.audioStreams[stream].rdsPid;
+               if (!m_rds_decoder || m_rds_decoder->getPid() != rdsPid)
                {
                {
+                       m_rds_decoder = 0;
                        ePtr<iDVBDemux> data_demux;
                        if (!h.getDataDemux(data_demux))
                        {
                        ePtr<iDVBDemux> data_demux;
                        if (!h.getDataDemux(data_demux))
                        {
-                               m_rds_decoder = new eDVBRdsDecoder(data_demux);
+                               m_rds_decoder = new eDVBRdsDecoder(data_demux, different_pid);
                                m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
                                m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
+                               m_rds_decoder->start(rdsPid);
                        }
                }
                        }
                }
-
-               /* if we decided that we need one, update the pid */
-       if (m_rds_decoder)
-               m_rds_decoder->start(apid);
+       }
 
                        /* store new pid as default only when:
                                a.) we have an entry in the service db for the current service,
 
                        /* store new pid as default only when:
                                a.) we have an entry in the service db for the current service,
@@ -1861,7 +1786,7 @@ int eDVBServicePlay::selectAudioStream(int i)
                                    anything in the best case, or destroy the default setting in
                                    case the real default is not yet available.)
                        */
                                    anything in the best case, or destroy the default setting in
                                    case the real default is not yet available.)
                        */
-       if (m_dvb_service && !m_is_pvr && ((i != -1)
+       if (m_dvb_service && ((i != -1)
                || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
        {
                if (apidtype == eDVBAudio::aMPEG)
                || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
        {
                if (apidtype == eDVBAudio::aMPEG)
@@ -1869,11 +1794,16 @@ int eDVBServicePlay::selectAudioStream(int i)
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
                }
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
                }
-               else
+               else if (apidtype == eDVBAudio::aAC3)
                {
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
                }
                {
                        m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
                        m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
                }
+               else
+               {
+                       m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
+                       m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
+               }
        }
 
        h.resetCachedProgram();
        }
 
        h.resetCachedProgram();
@@ -2031,31 +1961,7 @@ PyObject *eDVBServiceBase::getTransponderData(bool original)
                {
                        ePtr<iDVBFrontend> fe;
                        if(!channel->getFrontend(fe))
                {
                        ePtr<iDVBFrontend> fe;
                        if(!channel->getFrontend(fe))
-                       {
                                fe->getTransponderData(ret, original);
                                fe->getTransponderData(ret, original);
-                               ePtr<iDVBFrontendParameters> feparm;
-                               channel->getCurrentFrontendParameters(feparm);
-                               if (feparm)
-                               {
-                                       eDVBFrontendParametersSatellite osat;
-                                       if (!feparm->getDVBS(osat))
-                                       {
-                                               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)
-                                               {
-                                                       case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
-                                                       case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
-                                                       case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
-                                                       case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
-                                                       default:break;
-                                               }
-                                               PutToDict(ret, "polarization", tmp);
-                                       }
-                               }
-                       }
                }
        }
        else
                }
        }
        else
@@ -2197,8 +2103,8 @@ PyObject *eDVBServicePlay::getCutList()
        for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
        {
                ePyObject tuple = PyTuple_New(2);
        for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
        {
                ePyObject tuple = PyTuple_New(2);
-               PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
-               PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
+               PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
+               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
                PyList_Append(list, tuple);
                Py_DECREF(tuple);
        }
                PyList_Append(list, tuple);
                Py_DECREF(tuple);
        }
@@ -2311,6 +2217,8 @@ void eDVBServicePlay::switchToLive()
        if (!m_timeshift_active)
                return;
        
        if (!m_timeshift_active)
                return;
        
+       eDebug("SwitchToLive");
+       
        m_cue = 0;
        m_decoder = 0;
        m_decode_demux = 0;
        m_cue = 0;
        m_decoder = 0;
        m_decode_demux = 0;
@@ -2321,10 +2229,12 @@ void eDVBServicePlay::switchToLive()
        m_new_subtitle_page_connection = 0;
        m_rds_decoder_event_connection = 0;
        m_video_event_connection = 0;
        m_new_subtitle_page_connection = 0;
        m_rds_decoder_event_connection = 0;
        m_video_event_connection = 0;
+       m_is_paused = m_skipmode = 0; /* not supported in live mode */
 
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
        m_timeshift_active = 0;
 
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
        m_timeshift_active = 0;
+       m_timeshift_changed = 1;
 
        m_event((iPlayableService*)this, evSeekableStatusChanged);
 
 
        m_event((iPlayableService*)this, evSeekableStatusChanged);
 
@@ -2347,12 +2257,13 @@ void eDVBServicePlay::switchToTimeshift()
        m_video_event_connection = 0;
 
        m_timeshift_active = 1;
        m_video_event_connection = 0;
 
        m_timeshift_active = 1;
+       m_timeshift_changed = 1;
 
        eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
        r.path = m_timeshift_file;
 
        m_cue = new eCueSheet();
 
        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 */
+       m_service_handler_timeshift.tune(r, 1, m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
 
        eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
        pause();
 
        eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
        pause();
@@ -2414,25 +2325,45 @@ void eDVBServicePlay::updateDecoder()
        if (!m_decoder)
        {
                h.getDecodeDemux(m_decode_demux);
        if (!m_decoder)
        {
                h.getDecodeDemux(m_decode_demux);
+               if (m_timeshift_changed)
+                       m_decoder = 0;
                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_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);
-                       m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
-                       m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
-                       m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
-                       m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
-               } else
-               {
-                       m_teletext_parser = 0;
-                       m_subtitle_parser = 0;
+                       if (m_is_primary)
+                       {
+                               m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
+                               m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
+                               m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
+                               m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
+                               if (m_timeshift_changed)
+                               {
+                                       ePyObject subs = getCachedSubtitle();
+                                       if (subs != Py_None)
+                                       {
+                                               int type = PyInt_AsLong(PyTuple_GET_ITEM(subs, 0)),
+                                                   pid = PyInt_AsLong(PyTuple_GET_ITEM(subs, 1)),
+                                                   comp_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 2)), // ttx page
+                                                   anc_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 3)); // ttx magazine
+                                               if (type == 0) // dvb
+                                                       m_subtitle_parser->start(pid, comp_page, anc_page);
+                                               else if (type == 1) // ttx
+                                                       m_teletext_parser->setPageAndMagazine(comp_page, anc_page);
+                                       }
+                                       Py_DECREF(subs);
+                               }
+                       }
+                       m_decoder->play(); /* pids will be set later */
                }
                }
-
                if (m_cue)
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
                if (m_cue)
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
+               m_decoder->play(); /* pids will be set later. */
        }
 
        }
 
+       m_timeshift_changed = 0;
+
        if (m_decoder)
        {
                if (m_dvb_service)
        if (m_decoder)
        {
                if (m_dvb_service)
@@ -2441,7 +2372,7 @@ void eDVBServicePlay::updateDecoder()
                        ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
                        pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
                }
                        ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
                        pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
                }
-               else // subservice or recording
+               else // subservice
                {
                        eServiceReferenceDVB ref;
                        m_service_handler.getServiceReference(ref);
                {
                        eServiceReferenceDVB ref;
                        m_service_handler.getServiceReference(ref);
@@ -2466,8 +2397,9 @@ void eDVBServicePlay::updateDecoder()
                                }
                        }
                }
                                }
                        }
                }
-               m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
-               m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
+
+               setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
+               setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
 
                m_decoder->setVideoPID(vpid, vpidtype);
                selectAudioStream();
 
                m_decoder->setVideoPID(vpid, vpidtype);
                selectAudioStream();
@@ -2477,17 +2409,11 @@ void eDVBServicePlay::updateDecoder()
                else
                        m_decoder->setSyncPCR(-1);
 
                else
                        m_decoder->setSyncPCR(-1);
 
-               m_decoder->setTextPID(tpid);
-
-               m_teletext_parser->start(program.textPid);
-
-               if (!m_is_primary)
-                       m_decoder->setTrickmode(1);
-
-               if (m_is_paused)
-                       m_decoder->preroll();
-               else
-                       m_decoder->start();
+               if (m_is_primary)
+               {
+                       m_decoder->setTextPID(tpid);
+                       m_teletext_parser->start(program.textPid);
+               }
 
                if (vpid > 0 && vpid < 0x2000)
                        ;
 
                if (vpid > 0 && vpid < 0x2000)
                        ;
@@ -2498,10 +2424,11 @@ void eDVBServicePlay::updateDecoder()
                                m_decoder->setRadioPic(radio_pic);
                }
 
                                m_decoder->setRadioPic(radio_pic);
                }
 
+               m_decoder->set();
                m_decoder->setAudioChannel(achannel);
 
                /* don't worry about non-existing services, nor pvr services */
                m_decoder->setAudioChannel(achannel);
 
                /* don't worry about non-existing services, nor pvr services */
-               if (m_dvb_service && !m_is_pvr)
+               if (m_dvb_service)
                {
                                /* (audio pid will be set in selectAudioTrack */
                        m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
                {
                                /* (audio pid will be set in selectAudioTrack */
                        m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
@@ -2509,7 +2436,7 @@ void eDVBServicePlay::updateDecoder()
                        m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
                        m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
                }
                        m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
                        m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
                }
-       }       
+       }
        m_have_video_pid = (vpid > 0 && vpid < 0x2000);
 }
 
        m_have_video_pid = (vpid > 0 && vpid < 0x2000);
 }
 
@@ -2605,11 +2532,16 @@ void eDVBServicePlay::cutlistToCuesheet()
                
        std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
        
                
        std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
        
+       int have_any_span = 0;
+       
        while (1)
        {
                if (i == m_cue_entries.end())
        while (1)
        {
                if (i == m_cue_entries.end())
+               {
+                       if (!have_any_span)
+                               break;
                        out = length;
                        out = length;
-               else {
+               else {
                        if (i->what == 0) /* in */
                        {
                                in = i++->where;
                        if (i->what == 0) /* in */
                        {
                                in = i++->where;
@@ -2633,7 +2565,10 @@ void eDVBServicePlay::cutlistToCuesheet()
                        out = length;
                
                if (in < out)
                        out = length;
                
                if (in < out)
+               {
+                       have_any_span = 1;
                        m_cue->addSourceSpan(in, out);
                        m_cue->addSourceSpan(in, out);
+               }
                
                in = length;
                
                
                in = length;
                
@@ -2777,7 +2712,7 @@ PyObject *eDVBServicePlay::getCachedSubtitle()
                                        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, 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, 1, PyInt_FromLong(pid)); // 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;
                                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;
@@ -2912,18 +2847,22 @@ void eDVBServicePlay::checkSubtitleTiming()
                        m_decoder->getPTS(0, pos);
 
                eDebug("%lld %lld", pos, show_time);
                        m_decoder->getPTS(0, pos);
 
                eDebug("%lld %lld", pos, show_time);
-               int diff =  show_time - pos;
+               int diff = show_time - pos;
+               if (type == TELETEXT && !page.m_have_pts)
+               {
+                       eDebug("ttx subtitle page without pts... immediate show");
+                       diff = 0;
+               }
                if (diff < 0)
                {
                        eDebug("[late (%d ms)]", -diff / 90);
                        diff = 0;
                }
                if (diff < 0)
                {
                        eDebug("[late (%d ms)]", -diff / 90);
                        diff = 0;
                }
-//             if (diff > 900000)
-//             {
-//                     eDebug("[invalid]");
-//                     diff = 0;
-//             }
-       
+               if (abs(diff) > 1800000)
+               {
+                       eDebug("[invalid]... immediate show!");
+                       diff = 0;
+               }
                if ((diff/90)<20)
                {
                        if (type == TELETEXT)
                if ((diff/90)<20)
                {
                        if (type == TELETEXT)
@@ -2984,21 +2923,32 @@ void eDVBServicePlay::setAC3Delay(int delay)
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
-       if (m_decoder)
-               m_decoder->setAC3Delay(delay);
+       if (m_decoder) {
+               std::string config_delay;
+               int config_delay_int = 0;
+               if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
+                       config_delay_int = atoi(config_delay.c_str());
+               m_decoder->setAC3Delay(delay + config_delay_int);
+       }
 }
 
 void eDVBServicePlay::setPCMDelay(int delay)
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
 }
 
 void eDVBServicePlay::setPCMDelay(int delay)
 {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
-       if (m_decoder)
-               m_decoder->setPCMDelay(delay);
+       if (m_decoder) {
+               std::string config_delay;
+               int config_delay_int = 0;
+               if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
+                       config_delay_int = atoi(config_delay.c_str());
+               else
+                       config_delay_int = 0;
+               m_decoder->setPCMDelay(delay + config_delay_int);
+       }
 }
 
 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
 {
 }
 
 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
 {
-       memcpy(&m_videoEventData, &event, sizeof(event));
        switch(event.type) {
                case iTSMPEGDecoder::videoEvent::eventSizeChanged:
                        m_event((iPlayableService*)this, evVideoSizeChanged);
        switch(event.type) {
                case iTSMPEGDecoder::videoEvent::eventSizeChanged:
                        m_event((iPlayableService*)this, evVideoSizeChanged);
@@ -3025,18 +2975,16 @@ PyObject *eDVBServicePlay::getStreamingData()
        eDVBServicePMTHandler::program program;
        if (m_service_handler.getProgramInfo(program))
        {
        eDVBServicePMTHandler::program program;
        if (m_service_handler.getProgramInfo(program))
        {
-               Py_INCREF(Py_None);
-               return Py_None;
+               Py_RETURN_NONE;
        }
 
        }
 
-       PyObject *r = program.createPythonObject();
+       ePyObject r = program.createPythonObject();
        ePtr<iDVBDemux> demux;
        if (!m_service_handler.getDataDemux(demux))
        {
                uint8_t demux_id;
        ePtr<iDVBDemux> demux;
        if (!m_service_handler.getDataDemux(demux))
        {
                uint8_t demux_id;
-               demux->getCADemuxID(demux_id);
-               
-               PyDict_SetItemString(r, "demux", PyInt_FromLong(demux_id));
+               if (!demux->getCADemuxID(demux_id))
+                       PutToDict(r, "demux", demux_id);
        }
 
        return r;
        }
 
        return r;