Merge remote branch 'origin/acid-burn/bug_687_fix_wrong_polish_encodings'
authoracid-burn <acid-burn@opendreambox.org>
Mon, 21 Feb 2011 08:48:02 +0000 (09:48 +0100)
committeracid-burn <acid-burn@opendreambox.org>
Mon, 21 Feb 2011 08:48:02 +0000 (09:48 +0100)
26 files changed:
lib/dvb/decoder.cpp
lib/dvb/decoder.h
lib/dvb/demux.cpp
lib/dvb/demux.h
lib/dvb/dvb.cpp
lib/dvb/esection.h
lib/dvb/idvb.h
lib/dvb/pmt.cpp
lib/dvb/pmt.h
lib/dvb/tstools.cpp
lib/gui/elistboxcontent.cpp
lib/gui/esubtitle.h
lib/python/Components/FileList.py
lib/python/Components/PluginComponent.py
lib/python/Components/Sources/ServiceEvent.py
lib/python/Plugins/Extensions/DVDPlayer/src/servicedvd.cpp
lib/python/Plugins/Extensions/MediaPlayer/plugin.py
lib/python/Screens/AudioSelection.py
lib/python/Screens/SleepTimerEdit.py
lib/service/Makefile.am
lib/service/servicedvb.cpp
lib/service/servicem2ts.cpp [new file with mode: 0644]
lib/service/servicem2ts.h [new file with mode: 0644]
lib/service/servicemp3.cpp
lib/service/servicemp3.h
tools/enigma2.sh.in

index 88cd3ee1e91a27a927b4d1922ef497b8ae845901..a89f72bbb69b021f890edabaf0ab1a03b3820bf6 100644 (file)
@@ -203,6 +203,9 @@ int eDVBAudio::startPid(int pid, int type)
        case aLPCM:
                bypass = 6;
                break;
+       case aDTSHD:
+               bypass = 0x10;
+               break;
        }
 
        eDebugNoNewLine("AUDIO_SET_BYPASS(%d) - ", bypass);
@@ -1299,9 +1302,10 @@ RESULT eTSMPEGDecoder::showSinglePic(const char *filename)
                if (f >= 0)
                {
                        struct stat s;
+                       size_t written=0;
                        fstat(f, &s);
                        if (m_video_clip_fd == -1)
-                               m_video_clip_fd = open("/dev/dvb/adapter0/video0", O_WRONLY|O_NONBLOCK);
+                               m_video_clip_fd = open("/dev/dvb/adapter0/video0", O_WRONLY);
                        if (m_video_clip_fd >= 0)
                        {
                                bool seq_end_avail = false;
index 3a0fbac1e58f27c303a7d28202884a6c9de7bc53..7610b654b761c05bc77ab43649ec6972208e740c 100644 (file)
@@ -13,7 +13,7 @@ private:
        ePtr<eDVBDemux> m_demux;
        int m_fd, m_fd_demux, m_dev, m_is_freezed;
 public:
-       enum { aMPEG, aAC3, aDTS, aAAC, aAACHE, aLPCM };
+       enum { aMPEG, aAC3, aDTS, aAAC, aAACHE, aLPCM, aDTSHD };
        eDVBAudio(eDVBDemux *demux, int dev);
        enum { aMonoLeft, aStereo, aMonoRight };
        void setChannel(int channel);
index 0c736c55c23e1cfc55de9e1f0a2c5a793b01a22b..f4d86185b508a03461075f17bd119cd911005e60 100644 (file)
@@ -85,6 +85,13 @@ int eDVBDemux::openDemux(void)
        return ::open(filename, O_RDWR);
 }
 
+int eDVBDemux::openDVR(int flags)
+{
+       char filename[128];
+       snprintf(filename, 128, "/dev/dvb/adapter%d/dvr%d", adapter, demux);
+       return ::open(filename, flags);
+}
+
 DEFINE_REF(eDVBDemux)
 
 RESULT eDVBDemux::setSourceFrontend(int fenum)
index d43c41bb6733cee2760cef8fc7992f12363b2755..e73982ec1507913c9943050bad11266590e4a692 100644 (file)
@@ -26,7 +26,8 @@ public:
        RESULT getCADemuxID(uint8_t &id) { id = demux; return 0; }
        RESULT flush();
        RESULT connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn);
-       
+       int openDVR(int flags);
+
        int getRefCount() { return ref; }
 private:
        int adapter, demux, source;
index c2ddb4099f35de7d73aa093f4b588a4ee9029b17..6f9a67fbd092002b4b6818805a6a75eb6c29b2b5 100644 (file)
@@ -466,7 +466,7 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
 
        ePtr<eDVBRegisteredDemux> unused;
 
-       if (m_boxtype == DM800 || m_boxtype == DM500HD || m_boxtype == DM800SE) // dm800 / 500hd
+       if (m_boxtype == DM800) // dm800
        {
                cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
                for (; i != m_demux.end(); ++i, ++n)
@@ -522,7 +522,7 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
                        }
                }
        }
-       else if (m_boxtype == DM8000 || m_boxtype == DM7020HD)
+       else if (m_boxtype == DM8000 || m_boxtype == DM500HD || m_boxtype == DM800SE || m_boxtype == DM7020HD)
        {
                cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
                for (; i != m_demux.end(); ++i, ++n)
@@ -1792,14 +1792,28 @@ RESULT eDVBChannel::playSource(ePtr<iTsSource> &source, const char *streaminfo_f
                /* (this codepath needs to be improved anyway.) */
 #if HAVE_DVB_API_VERSION < 3
                m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
-#else
-               m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
-#endif
                if (m_pvr_fd_dst < 0)
                {
-                       eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
+                       eDebug("can't open /dev/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
+                       return -ENODEV;
+               }
+#else
+               ePtr<eDVBAllocatedDemux> &demux = m_demux ? m_demux : m_decoder_demux;
+               if (demux)
+               {
+                       m_pvr_fd_dst = demux->get().openDVR(O_WRONLY);
+                       if (m_pvr_fd_dst < 0)
+                       {
+                               eDebug("can't open /dev/dvb/adapterX/dvrX - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
+                               return -ENODEV;
+                       }
+               }
+               else
+               {
+                       eDebug("no demux allocated yet.. so its not possible to open the dvr device!!");
                        return -ENODEV;
                }
+#endif
        }
 
        m_pvr_thread = new eDVBChannelFilePush();
index 833cc93b2ded9216b264350ddccd9e4895038d3a..3e097ccc142c5e12338559760a454f540aebda9c 100644 (file)
@@ -100,6 +100,10 @@ class eAUTable: public eAUGTable
        int first;
        ePtr<iDVBDemux> m_demux;
        eMainloop *ml;
+
+       /* needed to detect broken table version handling (seen on some m2ts files) */
+       struct timespec m_prev_table_update;
+       int m_table_cnt;
 public:
 
        eAUTable()
@@ -119,6 +123,7 @@ public:
        
        int begin(eMainloop *m, const eDVBTableSpec &spec, ePtr<iDVBDemux> demux)
        {
+               m_table_cnt = 0;
                ml = m;
                m_demux = demux;
                first= 1;
@@ -197,6 +202,24 @@ public:
 
                if (current && (!current->getSpec(spec)))
                {
+                       /* detect broken table version handling (seen on some m2ts files) */
+                       if (m_table_cnt)
+                       {
+                               if (abs(timeout_usec(m_prev_table_update)) > 500000)
+                                       m_table_cnt = -1;
+                               else if (m_table_cnt > 1) // two pmt update within one second
+                               {
+                                       eDebug("Seen two consecutive table version changes within 500ms. "
+                                           "This seems broken, so auto update for pid %04x, table %02x is now disabled!!",
+                                           spec.pid, spec.tid);
+                                       m_table_cnt = 0;
+                                       return;
+                               }
+                       }
+
+                       ++m_table_cnt;
+                       clock_gettime(CLOCK_MONOTONIC, &m_prev_table_update);
+
                        next = new Table();
                        CONNECT(next->tableReady, eAUTable::slotTableReady);
                        spec.flags &= ~(eDVBTableSpec::tfAnyVersion|eDVBTableSpec::tfThisVersion|eDVBTableSpec::tfHaveTimeout);
index f15cd04e529622906b18f4729f675f88aadfe22e..86936f8dc36900b199f19fa1a690ac2f4b597afb 100644 (file)
@@ -636,6 +636,7 @@ public:
        virtual RESULT getSTC(pts_t &pts, int num=0)=0;
        virtual RESULT getCADemuxID(uint8_t &id)=0;
        virtual RESULT flush()=0;
+       virtual int openDVR(int flags)=0;
 };
 
 #if HAVE_DVB_API_VERSION < 3 && !defined(VIDEO_EVENT_SIZE_CHANGED)
@@ -650,7 +651,7 @@ public:
                /** Set Displayed Video PID and type */
        virtual RESULT setVideoPID(int vpid, int type)=0;
 
-       enum { af_MPEG, af_AC3, af_DTS, af_AAC };
+       enum { af_MPEG, af_AC3, af_DTS, af_AAC, af_DTSHD };
                /** Set Displayed Audio PID and type */
        virtual RESULT setAudioPID(int apid, int type)=0;
 
index ca56141bc89115c4ba32bdc15f27a1bf4f465503..e5e633160c82458480b0e10d3b5f718359a43ad1 100644 (file)
 #include <dvbsi++/registration_descriptor.h>
 
 eDVBServicePMTHandler::eDVBServicePMTHandler()
-       :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF)
+       :m_ca_servicePtr(0), m_dvb_scan(0), m_decode_demux_num(0xFF), m_no_pat_entry_delay(eTimer::create())
 {
        m_use_decode_demux = 0;
        m_pmt_pid = -1;
        eDVBResourceManager::getInstance(m_resourceManager);
        CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready);
        CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready);
+       CONNECT(m_no_pat_entry_delay->timeout, eDVBServicePMTHandler::sendEventNoPatEntry);
 }
 
 eDVBServicePMTHandler::~eDVBServicePMTHandler()
@@ -43,8 +44,15 @@ void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel)
                && (state == iDVBChannel::state_ok) && (!m_demux))
        {
                if (m_channel)
-                       if (m_channel->getDemux(m_demux, (!m_use_decode_demux) ? 0 : iDVBChannel::capDecode))
+               {
+                       if (m_pvr_demux_tmp)
+                       {
+                               m_demux = m_pvr_demux_tmp;
+                               m_pvr_demux_tmp = NULL;
+                       }
+                       else if (m_channel->getDemux(m_demux, (!m_use_decode_demux) ? 0 : iDVBChannel::capDecode))
                                eDebug("Allocating %s-decoding a demux for now tuned-in channel failed.", m_use_decode_demux ? "" : "non-");
+               }
                
                serviceEvent(eventTuned);
                
@@ -126,25 +134,55 @@ void eDVBServicePMTHandler::PMTready(int error)
        }
 }
 
+void eDVBServicePMTHandler::sendEventNoPatEntry()
+{
+       serviceEvent(eventNoPATEntry);
+}
+
 void eDVBServicePMTHandler::PATready(int)
 {
+       eDebug("PATready");
        ePtr<eTable<ProgramAssociationSection> > ptr;
        if (!m_PAT.getCurrent(ptr))
        {
+               int service_id_single = -1;
+               int pmtpid_single = -1;
                int pmtpid = -1;
+               int cnt=0;
                std::vector<ProgramAssociationSection*>::const_iterator i;
                for (i = ptr->getSections().begin(); pmtpid == -1 && i != ptr->getSections().end(); ++i)
                {
                        const ProgramAssociationSection &pat = **i;
                        ProgramAssociationConstIterator program;
                        for (program = pat.getPrograms()->begin(); pmtpid == -1 && program != pat.getPrograms()->end(); ++program)
+                       {
+                               ++cnt;
                                if (eServiceID((*program)->getProgramNumber()) == m_reference.getServiceID())
                                        pmtpid = (*program)->getProgramMapPid();
+                               if (++cnt == 1 && pmtpid_single == -1 && pmtpid == -1)
+                               {
+                                       pmtpid_single = (*program)->getProgramMapPid();
+                                       service_id_single = (*program)->getProgramNumber();
+                               }
+                               else
+                                       pmtpid_single = service_id_single = -1;
+                       }
                }
-               if (pmtpid == -1)
-                       serviceEvent(eventNoPATEntry);
-               else
+               if (pmtpid_single != -1) // only one PAT entry .. and not valid pmtpid found
+               {
+                       eDebug("use single pat entry!");
+                       m_reference.setServiceID(eServiceID(service_id_single));
+                       pmtpid = pmtpid_single;
+               }
+               if (pmtpid == -1) {
+                       eDebug("no PAT entry found.. start delay");
+                       m_no_pat_entry_delay->start(1000, true);
+               }
+               else {
+                       eDebug("use pmtpid %04x for service_id %04x", pmtpid, m_reference.getServiceID().get());
+                       m_no_pat_entry_delay->stop();
                        m_PMT.begin(eApp, eDVBPMTSpec(pmtpid, m_reference.getServiceID().get()), m_demux);
+               }
        } else
                serviceEvent(eventNoPAT);
 }
@@ -230,8 +268,29 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                        for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
                        {
                                const ProgramMapSection &pmt = **i;
+                               int is_hdmv = 0;
+
                                program.pcrPid = pmt.getPcrPid();
 
+                               for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
+                                       desc != pmt.getDescriptors()->end(); ++desc)
+                               {
+                                       if ((*desc)->getTag() == CA_DESCRIPTOR)
+                                       {
+                                               CaDescriptor *descr = (CaDescriptor*)(*desc);
+                                               program::capid_pair pair;
+                                               pair.caid = descr->getCaSystemId();
+                                               pair.capid = descr->getCaPid();
+                                               program.caids.push_back(pair);
+                                       }
+                                       else if ((*desc)->getTag() == REGISTRATION_DESCRIPTOR)
+                                       {
+                                               RegistrationDescriptor *d = (RegistrationDescriptor*)(*desc);
+                                               if (d->getFormatIdentifier() == 0x48444d56) // HDMV
+                                                       is_hdmv = 1;
+                                       }
+                               }
+
                                ElementaryStreamInfoConstIterator es;
                                for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
                                {
@@ -287,25 +346,34 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                                        audio.type = audioStream::atAACHE;
                                                        forced_audio = 1;
                                                }
-                                       case 0x80: // user private ... but blueray LPCM
-                                               if (!isvideo && !isaudio)
+                                       case 0x80: // user private ... but bluray LPCM
+                                       case 0xA0: // bluray secondary LPCM
+                                               if (!isvideo && !isaudio && is_hdmv)
                                                {
                                                        isaudio = 1;
                                                        audio.type = audioStream::atLPCM;
                                                }
-                                       case 0x81: // user private ... but blueray AC3
-                                               if (!isvideo && !isaudio)
+                                       case 0x81: // user private ... but bluray AC3
+                                       case 0xA1: // bluray secondary AC3
+                                               if (!isvideo && !isaudio && is_hdmv)
                                                {
                                                        isaudio = 1;
                                                        audio.type = audioStream::atAC3;
                                                }
-                                       case 0x82: // Blueray DTS (dvb user private...)
-                                       case 0xA2: // Blueray secondary DTS
-                                               if (!isvideo && !isaudio)
+                                       case 0x82: // bluray DTS (dvb user private...)
+                                       case 0xA2: // bluray secondary DTS
+                                               if (!isvideo && !isaudio && is_hdmv)
                                                {
                                                        isaudio = 1;
                                                        audio.type = audioStream::atDTS;
                                                }
+                                       case 0x86: // bluray DTS-HD (dvb user private...)
+                                       case 0xA6: // bluray secondary DTS-HD
+                                               if (!isvideo && !isaudio && is_hdmv)
+                                               {
+                                                       isaudio = 1;
+                                                       audio.type = audioStream::atDTSHD;
+                                               }
                                        case 0x06: // PES Private
                                        case 0xEA: // TS_PSI_ST_SMPTE_VC1
                                        {
@@ -497,9 +565,9 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                        default:
                                                break;
                                        }
-                                       if (isteletext && (isaudio || isvideo)) 
+                                       if (isteletext && (isaudio || isvideo))
                                        {
-                                               eDebug("ambiguous streamtype for PID %04x detected.. forced as teletext!", (*es)->getPid());                                    
+                                               eDebug("ambiguous streamtype for PID %04x detected.. forced as teletext!", (*es)->getPid());
                                                continue; // continue with next PID
                                        }
                                        else if (issubtitle && (isaudio || isvideo))
@@ -537,18 +605,6 @@ int eDVBServicePMTHandler::getProgramInfo(program &program)
                                        else
                                                continue;
                                }
-                               for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
-                                       desc != pmt.getDescriptors()->end(); ++desc)
-                               {
-                                       if ((*desc)->getTag() == CA_DESCRIPTOR)
-                                       {
-                                               CaDescriptor *descr = (CaDescriptor*)(*desc);
-                                               program::capid_pair pair;
-                                               pair.caid = descr->getCaSystemId();
-                                               pair.capid = descr->getCaPid();
-                                               program.caids.push_back(pair);
-                                       }
-                               }
                        }
                        ret = 0;
 
@@ -710,8 +766,8 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
 {
        RESULT res=0;
        m_reference = ref;
-       
        m_use_decode_demux = use_decode_demux;
+       m_no_pat_entry_delay->stop();
 
                /* use given service as backup. This is used for timeshift where we want to clone the live stream using the cache, but in fact have a PVR channel */
        m_service = service;
@@ -735,13 +791,12 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
        {
                if (!ref.getServiceID().get() /* incorrect sid in meta file or recordings.epl*/ )
                {
-                       eWarning("no .meta file found, trying to find PMT pid");
                        eDVBTSTools tstools;
+                       bool b = source || !tstools.openFile(ref.path.c_str(), 1);
+                       eWarning("no .meta file found, trying to find PMT pid");
                        if (source)
-                               tstools.setSource(source, streaminfo_file ? streaminfo_file : ref.path.c_str());
-                       else if (tstools.openFile(ref.path.c_str()))
-                               eWarning("failed to open file");
-                       else
+                               tstools.setSource(source, NULL);
+                       if (b)
                        {
                                int service_id, pmt_pid;
                                if (!tstools.findPMT(pmt_pid, service_id))
@@ -751,6 +806,8 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
                                        m_pmt_pid = pmt_pid;
                                }
                        }
+                       else
+                               eWarning("no valid source to find PMT pid!");
                }
                eDebug("alloc PVR");
                        /* allocate PVR */
@@ -792,7 +849,10 @@ int eDVBServicePMTHandler::tuneExt(eServiceReferenceDVB &ref, int use_decode_dem
                if (m_pvr_channel)
                {
                        m_pvr_channel->setCueSheet(cue);
-                       if (source)
+
+                       if (m_pvr_channel->getDemux(m_pvr_demux_tmp, (!m_use_decode_demux) ? 0 : iDVBChannel::capDecode))
+                               eDebug("Allocating %s-decoding a demux for PVR channel failed.", m_use_decode_demux ? "" : "non-");
+                       else if (source)
                                m_pvr_channel->playSource(source, streaminfo_file);
                        else
                                m_pvr_channel->playFile(ref.path.c_str());
index 86b634fc459a1b9206ca9d5ac34dfe835c3995c6..0c44f35a7ea682549ed18c4970febaf36943bcf1 100644 (file)
@@ -86,8 +86,8 @@ class eDVBServicePMTHandler: public Object
        eUsePtr<iDVBChannel> m_channel;
        eUsePtr<iDVBPVRChannel> m_pvr_channel;
        ePtr<eDVBResourceManager> m_resourceManager;
-       ePtr<iDVBDemux> m_demux;
-       
+       ePtr<iDVBDemux> m_demux, m_pvr_demux_tmp;
+
        void channelStateChanged(iDVBChannel *);
        ePtr<eConnection> m_channelStateChanged_connection;
        void channelEvent(iDVBChannel *, int event);
@@ -102,6 +102,7 @@ class eDVBServicePMTHandler: public Object
        
        int m_use_decode_demux;
        uint8_t m_decode_demux_num;
+       ePtr<eTimer> m_no_pat_entry_delay;
 public:
        eDVBServicePMTHandler();
        ~eDVBServicePMTHandler();
@@ -144,7 +145,7 @@ public:
        {
                int pid,
                    rdsPid; // hack for some radio services which transmit radiotext on different pid (i.e. harmony fm, HIT RADIO FFH, ...)
-               enum { atMPEG, atAC3, atDTS, atAAC, atAACHE, atLPCM };
+               enum { atMPEG, atAC3, atDTS, atAAC, atAACHE, atLPCM, atDTSHD };
                int type; // mpeg2, ac3, dts, ...
                
                int component_tag;
@@ -210,6 +211,7 @@ public:
        int getPMT(ePtr<eTable<ProgramMapSection> > &ptr) { return m_PMT.getCurrent(ptr); }
        int getChannel(eUsePtr<iDVBChannel> &channel);
        void resetCachedProgram() { m_have_cached_program = false; }
+       void sendEventNoPatEntry();
 
        /* deprecated interface */
        int tune(eServiceReferenceDVB &ref, int use_decode_demux, eCueSheet *sg=0, bool simulate=false, eDVBService *service = 0);
index 9b47f9b890f21147429af6a23b43e9ac29d271ef..6cd855ccd3045a0c556d34fba439073096680917 100644 (file)
@@ -212,6 +212,8 @@ int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
                                                        break;
                                                case 0x71: // AC3 / DTS
                                                        break;
+                                               case 0x72: // DTS - HD
+                                                       break;
                                                default:
                                                        eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]);
                                                        continue;
index a19e11a34f7e69cd17a8af9ec9a1d6875143b9d9..ba0794e73ccb416fe85b22aab90e06e99f705ed1 100644 (file)
@@ -641,7 +641,8 @@ static ePyObject lookupColor(ePyObject color, ePyObject data)
        if ((icolor & 0xFF000000) == 0xFF000000)
        {
                int index = icolor & 0xFFFFFF;
-               eDebug("[eListboxPythonMultiContent] template color index: %d", index);
+               if (PyTuple_GetItem(data, index) == Py_None)
+                       return ePyObject();
                return PyTuple_GetItem(data, index);
        }
 
index 45345db1d89d2857c86c5865b0475eb3ed4d60e9..cdad7286cab7cd8e7ce3b7e29a4b4361b272440a 100644 (file)
@@ -23,15 +23,21 @@ struct ePangoSubtitlePageElement
 
 struct ePangoSubtitlePage
 {
-       pts_t show_pts;
+       pts_t m_show_pts;
        int m_timeout; /* in milliseconds */
        std::vector<ePangoSubtitlePageElement> m_elements;
        void clear() { m_elements.clear(); }
 };
 
+struct eVobSubtitlePage
+{
+       pts_t m_show_pts;
+       int m_timeout; /* in milliseconds */
+       ePtr<gPixmap> m_pixmap;
+};
+
 class eDVBTeletextSubtitlePage;
-class eDVBPangoSubtitlePage;
-class ePangoSubtitlePage;
+class eDVBSubtitlePage;
 
 class eSubtitleWidget: public eWidget, public Object
 {
index 1d71514b9d105ab6dbb2efbed7ba3118ef96b06d..1b7e81f5c382d8bee684e8d285d76e4e7e261f5c 100755 (executable)
@@ -28,7 +28,8 @@ EXTENSIONS = {
                "mpeg": "movie",
                "mkv": "movie",
                "mp4": "movie",
-               "mov": "movie"
+               "mov": "movie",
+               "m2ts": "movie",
        }
 
 def FileEntryComponent(name, absolute = None, isDir = False):
index 0e178fff0790050f3338e4638106992339c9f628..e5194b28c9922fd9d3711da69dd6dc67bd4c3959 100755 (executable)
@@ -124,6 +124,8 @@ class PluginComponent:
        def clearPluginList(self):
                self.pluginList = []
                self.plugins = {}
+               self.firstRun = True
+               self.restartRequired = False
 
        def shutdown(self):
                for p in self.pluginList[:]:
index 93c733bd1c5bc044acbf069f2a86b50da6908bc1..8a0a66a16426a3527cca4d6700e7ec42d389904e 100644 (file)
@@ -25,7 +25,7 @@ class ServiceEvent(Source, object):
        def newService(self, ref):
                if not self.service or not ref or self.service != ref:
                        self.service = ref
-                       if not ref or (ref.flags & Ref.flagDirectory) == Ref.flagDirectory or ref.flags & Ref.isMarker:
+                       if not ref:
                                self.changed((self.CHANGED_CLEAR,))
                        else:
                                self.changed((self.CHANGED_ALL,))
index ccacf3c062fac10bed2a730245e44d532360749a..6d1397da4d5e538741c62554ac5fa46cc7b5503d 100644 (file)
@@ -749,7 +749,7 @@ PyObject *eServiceDVD::getSubtitleList()
                ePyObject tuple = PyTuple_New(5);
                PyTuple_SetItem(tuple, 0, PyInt_FromLong(2));
                PyTuple_SetItem(tuple, 1, PyInt_FromLong(spu_id+1));
-               PyTuple_SetItem(tuple, 2, PyInt_FromLong(3));
+               PyTuple_SetItem(tuple, 2, PyInt_FromLong(5));
                PyTuple_SetItem(tuple, 3, PyInt_FromLong(0));
                PyTuple_SetItem(tuple, 4, PyString_FromString(spu_string));
                PyList_Append(l, tuple);
index b44a2470944788d3e299acae821039763230a566..6ff1c5a50ac9a9e8a4ceb0968b86dfae406a4968 100644 (file)
@@ -110,7 +110,7 @@ class MediaPlayer(Screen, InfoBarBase, InfoBarSeek, InfoBarAudioSelection, InfoB
 
                # 'None' is magic to start at the list of mountpoints
                defaultDir = config.mediaplayer.defaultDir.getValue()
-               self.filelist = FileList(defaultDir, matchingPattern = "(?i)^.*\.(mp2|mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|divx|m4v|mkv|mp4|m4a|dat|flac|mov)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls")
+               self.filelist = FileList(defaultDir, matchingPattern = "(?i)^.*\.(mp2|mp3|ogg|ts|wav|wave|m3u|pls|e2pls|mpg|vob|avi|divx|m4v|mkv|mp4|m4a|dat|flac|mov|m2ts)", useServiceRef = True, additionalExtensions = "4098:m3u 4098:e2pls 4098:pls")
                self["filelist"] = self.filelist
 
                self.playlist = MyPlayList()
index b3b82b46d0fed8d6477bff4f304649bfaf305ec4..4c6896201d5e04aeb6d4b456761c1b10db7788e2 100644 (file)
@@ -46,7 +46,7 @@ class AudioSelection(Screen, ConfigListScreen):
                        "cancel": self.cancel,
                        "up": self.keyUp,
                        "down": self.keyDown,
-               }, -3)
+               }, -2)
 
                self.settings = ConfigSubsection()
                choicelist = [(PAGE_AUDIO,_("audio tracks")), (PAGE_SUBTITLES,_("Subtitles"))]
@@ -62,13 +62,12 @@ class AudioSelection(Screen, ConfigListScreen):
                streams = []
                conflist = []
                selectedidx = 0
-               
-               service = self.session.nav.getCurrentService()
-               self.audioTracks = audio = service and service.audioTracks()
-               n = audio and audio.getNumberOfTracks() or 0
-               
+
                if self.settings.menupage.getValue() == PAGE_AUDIO:
                        self.setTitle(_("Select audio track"))
+                       service = self.session.nav.getCurrentService()
+                       self.audioTracks = audio = service and service.audioTracks()
+                       n = audio and audio.getNumberOfTracks() or 0
                        if SystemInfo["CanDownmixAC3"]:
                                self.settings.downmix = ConfigOnOff(default=config.av.downmix_ac3.value)
                                self.settings.downmix.addNotifier(self.changeAC3Downmix, initial_call = False)
@@ -160,7 +159,7 @@ class AudioSelection(Screen, ConfigListScreen):
                                                number = "%x%02x" % (x[3],x[2])
 
                                        elif x[0] == 2:
-                                               types = ("UTF-8 text","SSA / AAS",".SRT file","VOB")
+                                               types = (_("<unknown>"), "UTF-8 text", "SSA", "AAS", ".SRT file", "VOB", "PGS (unsupported)")
                                                description = types[x[2]]
 
                                        streams.append((x, "", number, description, language, selected))
@@ -189,7 +188,7 @@ class AudioSelection(Screen, ConfigListScreen):
                                conflist.append(getConfigListEntry(Plugins[0][0], ConfigNothing()))
                                self.plugincallfunc = Plugins[0][1]
                        if len(Plugins) > 1:
-                               print "these plugins are installed but not displayed in the dialog box:", Plugins[1:]
+                               print "plugin(s) installed but not displayed in the dialog box:", Plugins[1:]
 
                self["config"].list = conflist
                self["config"].l.setList(conflist)
index e5e7af4e3e522fc2102c8fa250394011c069390b..61440d416002ad8e72ede67d7d70564c608e1633 100644 (file)
@@ -103,6 +103,7 @@ class SleepTimerEdit(Screen):
                        config.SleepTimer.defaulttime.setValue(time)
                        config.SleepTimer.defaulttime.save()
                        config.SleepTimer.action.save()
+                       config.SleepTimer.ask.save()
                        self.session.nav.SleepTimer.setSleepTime(time)
                        self.session.openWithCallback(self.close, MessageBox, _("The sleep timer has been activated."), MessageBox.TYPE_INFO)
                else:
index edafd1a2ac2a540940c87beb68cbd1f26c4b2306..9f956b66c078734c4975c48d3ecd6c71d0682f42 100644 (file)
@@ -16,7 +16,8 @@ libenigma_service_a_SOURCES = \
        servicedvb.cpp \
        servicedvbrecord.cpp \
        servicefs.cpp \
-       servicemp3.cpp
+       servicemp3.cpp \
+       servicem2ts.cpp
 
 serviceincludedir = $(pkgincludedir)/lib/service
 serviceinclude_HEADERS = \
@@ -27,7 +28,8 @@ serviceinclude_HEADERS = \
        servicedvb.h \
        servicedvbrecord.h \
        servicefs.h \
-       servicemp3.h
+       servicemp3.h \
+       servicem2ts.h
 
 if HAVE_LIBXINE
 libenigma_service_a_SOURCES += \
index 914d6bf1b2555239919ca2b944aba986e05b57a9..8650989a49c501b9b514df9434e6eca326cc845c 100644 (file)
@@ -1801,6 +1801,8 @@ RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int
                info.m_description = "AAC-HE";
        else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
                info.m_description = "DTS";
+       else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTSHD)
+               info.m_description = "DTS-HD";
        else
                info.m_description = "???";
 
diff --git a/lib/service/servicem2ts.cpp b/lib/service/servicem2ts.cpp
new file mode 100644 (file)
index 0000000..e79907d
--- /dev/null
@@ -0,0 +1,380 @@
+#include <lib/base/init_num.h>
+#include <lib/base/init.h>
+#include <lib/dvb/metaparser.h>
+#include <lib/service/servicem2ts.h>
+
+DEFINE_REF(eServiceFactoryM2TS)
+
+class eM2TSFile: public iTsSource
+{
+       DECLARE_REF(eM2TSFile);
+       eSingleLock m_lock;
+public:
+       eM2TSFile(const char *filename, bool cached=false);
+       ~eM2TSFile();
+
+       // iTsSource
+       off_t lseek(off_t offset, int whence);
+       ssize_t read(off_t offset, void *buf, size_t count);
+       off_t length();
+       int valid();
+private:
+       int m_sync_offset;
+       int m_fd;     /* for uncached */
+       FILE *m_file; /* for cached */
+       off_t m_current_offset, m_length;
+       bool m_cached;
+       off_t lseek_internal(off_t offset, int whence);
+};
+
+class eStaticServiceM2TSInformation: public iStaticServiceInformation
+{
+       DECLARE_REF(eStaticServiceM2TSInformation);
+       eServiceReference m_ref;
+       eDVBMetaParser m_parser;
+public:
+       eStaticServiceM2TSInformation(const eServiceReference &ref);
+       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);
+       PyObject *getInfoObject(const eServiceReference &r, int what);
+};
+
+DEFINE_REF(eStaticServiceM2TSInformation);
+
+eStaticServiceM2TSInformation::eStaticServiceM2TSInformation(const eServiceReference &ref)
+{
+       m_ref = ref;
+       m_parser.parseFile(ref.path);
+}
+
+RESULT eStaticServiceM2TSInformation::getName(const eServiceReference &ref, std::string &name)
+{
+       ASSERT(ref == m_ref);
+       if (m_parser.m_name.size())
+               name = m_parser.m_name;
+       else
+       {
+               name = ref.path;
+               size_t n = name.rfind('/');
+               if (n != std::string::npos)
+                       name = name.substr(n + 1);
+       }
+       return 0;
+}
+
+int eStaticServiceM2TSInformation::getLength(const eServiceReference &ref)
+{
+       ASSERT(ref == m_ref);
+       
+       eDVBTSTools tstools;
+       
+       struct stat s;
+       stat(ref.path.c_str(), &s);
+
+       eM2TSFile *file = new eM2TSFile(ref.path.c_str());
+       ePtr<iTsSource> source = file;
+
+       if (!source->valid())
+               return 0;
+
+       tstools.setSource(source);
+
+                       /* 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 */
+       tstools.setSource(source, ref.path.c_str());
+
+                       /* otherwise, re-calc length and update meta file */
+       pts_t len;
+       if (tstools.calcLen(len))
+               return 0;
+
+       m_parser.m_length = len;
+       m_parser.m_filesize = s.st_size;
+       m_parser.updateMeta(ref.path);
+       return m_parser.m_length / 90000;
+}
+
+int eStaticServiceM2TSInformation::getInfo(const eServiceReference &ref, int w)
+{
+       switch (w)
+       {
+       case iServiceInformation::sDescription:
+               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;
+               else
+                       return iServiceInformation::resNA;
+       default:
+               return iServiceInformation::resNA;
+       }
+}
+
+std::string eStaticServiceM2TSInformation::getInfoString(const eServiceReference &ref,int w)
+{
+       switch (w)
+       {
+       case iServiceInformation::sDescription:
+               return m_parser.m_description;
+       case iServiceInformation::sServiceref:
+               return m_parser.m_ref.toString();
+       case iServiceInformation::sTags:
+               return m_parser.m_tags;
+       default:
+               return "";
+       }
+}
+
+PyObject *eStaticServiceM2TSInformation::getInfoObject(const eServiceReference &r, int what)
+{
+       switch (what)
+       {
+       case iServiceInformation::sFileSize:
+               return PyLong_FromLongLong(m_parser.m_filesize);
+       default:
+               Py_RETURN_NONE;
+       }
+}
+
+RESULT eStaticServiceM2TSInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
+{
+       if (!ref.path.empty())
+       {
+               ePtr<eServiceEvent> event = new eServiceEvent;
+               std::string filename = ref.path;
+               filename.erase(filename.length()-4, 2);
+               filename+="eit";
+               if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
+               {
+                       evt = event;
+                       return 0;
+               }
+       }
+       evt = 0;
+       return -1;
+}
+
+DEFINE_REF(eM2TSFile);
+
+eM2TSFile::eM2TSFile(const char *filename, bool cached)
+       :m_lock(false), m_sync_offset(0), m_fd(-1), m_file(NULL), m_current_offset(0), m_length(0), m_cached(cached)
+{
+       if (!m_cached)
+               m_fd = ::open(filename, O_RDONLY | O_LARGEFILE);
+       else
+               m_file = ::fopen64(filename, "rb");
+       if (valid())
+               m_current_offset = m_length = lseek_internal(0, SEEK_END);
+}
+
+eM2TSFile::~eM2TSFile()
+{
+       if (m_cached)
+       {
+               if (m_file)
+               {
+                       ::fclose(m_file);
+                       m_file = 0;
+               }
+       }
+       else
+       {
+               if (m_fd >= 0)
+                       ::close(m_fd);
+               m_fd = -1;
+       }
+}
+
+off_t eM2TSFile::lseek(off_t offset, int whence)
+{
+       eSingleLocker l(m_lock);
+
+       offset = (offset % 188) + (offset * 192) / 188;
+
+       if (offset != m_current_offset)
+               m_current_offset = lseek_internal(offset, whence);
+
+       return m_current_offset;
+}
+
+off_t eM2TSFile::lseek_internal(off_t offset, int whence)
+{
+       off_t ret;
+
+       if (!m_cached)
+               ret = ::lseek(m_fd, offset, whence);
+       else
+       {
+               if (::fseeko(m_file, offset, whence) < 0)
+                       perror("fseeko");
+               ret = ::ftello(m_file);
+       }
+       return ret <= 0 ? ret : (ret % 192) + (ret*188) / 192;
+}
+
+ssize_t eM2TSFile::read(off_t offset, void *b, size_t count)
+{
+       eSingleLocker l(m_lock);
+       unsigned char tmp[192*3];
+       unsigned char *buf = (unsigned char*)b;
+
+       size_t rd=0;
+       offset = (offset % 188) + (offset * 192) / 188;
+
+sync:
+       if ((offset+m_sync_offset) != m_current_offset)
+       {
+//             eDebug("seekTo %lld", offset+m_sync_offset);
+               m_current_offset = lseek_internal(offset+m_sync_offset, SEEK_SET);
+               if (m_current_offset < 0)
+                       return m_current_offset;
+       }
+
+       while (rd < count) {
+               size_t ret;
+               if (!m_cached)
+                       ret = ::read(m_fd, tmp, 192);
+               else
+                       ret = ::fread(tmp, 1, 192, m_file);
+               if (ret < 0 || ret < 192)
+                       return rd ? rd : ret;
+
+               if (tmp[4] != 0x47)
+               {
+                       if (rd > 0) {
+                               eDebug("short read at pos %lld async!!", m_current_offset);
+                               return rd;
+                       }
+                       else {
+                               int x=0;
+                               if (!m_cached)
+                                       ret = ::read(m_fd, tmp+192, 384);
+                               else
+                                       ret = ::fread(tmp+192, 1, 384, m_file);
+
+#if 0
+                               eDebugNoNewLine("m2ts out of sync at pos %lld, real %lld:", offset + m_sync_offset, m_current_offset);
+                               for (; x < 192; ++x)
+                                       eDebugNoNewLine(" %02x", tmp[x]);
+                               eDebug("");
+                               x=0;
+#else
+                               eDebug("m2ts out of sync at pos %lld, real %lld", offset + m_sync_offset, m_current_offset);
+#endif
+                               for (; x < 192; ++x)
+                               {
+                                       if (tmp[x] == 0x47 && tmp[x+192] == 0x47)
+                                       {
+                                               int add_offs = (x - 4);
+                                               eDebug("sync found at pos %d, sync_offset is now %d, old was %d", x, add_offs + m_sync_offset, m_sync_offset);
+                                               m_sync_offset += add_offs;
+                                               goto sync;
+                                       }
+                               }
+                       }
+               }
+
+               memcpy(buf+rd, tmp+4, 188);
+
+               rd += 188;
+               m_current_offset += 188;
+       }
+
+       m_sync_offset %= 188;
+
+       return rd;
+}
+
+int eM2TSFile::valid()
+{
+       if (!m_cached)
+               return m_fd != -1;
+       else
+               return !!m_file;
+}
+
+off_t eM2TSFile::length()
+{
+       return m_length;
+}
+
+eServiceFactoryM2TS::eServiceFactoryM2TS()
+{
+       ePtr<eServiceCenter> sc;
+       eServiceCenter::getPrivInstance(sc);
+       if (sc)
+       {
+               std::list<std::string> extensions;
+               extensions.push_back("m2ts");
+               extensions.push_back("mts");
+               sc->addServiceFactory(eServiceFactoryM2TS::id, this, extensions);
+       }
+}
+
+eServiceFactoryM2TS::~eServiceFactoryM2TS()
+{
+       ePtr<eServiceCenter> sc;
+       
+       eServiceCenter::getPrivInstance(sc);
+       if (sc)
+               sc->removeServiceFactory(eServiceFactoryM2TS::id);
+}
+
+RESULT eServiceFactoryM2TS::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
+{
+       ptr = new eServiceM2TS(ref);
+       return 0;
+}
+
+RESULT eServiceFactoryM2TS::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
+{
+       ptr=0;
+       return -1;
+}
+
+RESULT eServiceFactoryM2TS::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
+{
+       ptr=0;
+       return -1;
+}
+
+RESULT eServiceFactoryM2TS::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
+{
+       ptr=new eStaticServiceM2TSInformation(ref);
+       return 0;
+}
+
+RESULT eServiceFactoryM2TS::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
+{
+       ptr = 0;
+       return -1;
+}
+
+eServiceM2TS::eServiceM2TS(const eServiceReference &ref)
+       :eDVBServicePlay(ref, NULL)
+{
+}
+
+ePtr<iTsSource> eServiceM2TS::createTsSource(eServiceReferenceDVB &ref)
+{
+       ePtr<iTsSource> source = new eM2TSFile(ref.path.c_str());
+       return source;
+}
+
+RESULT eServiceM2TS::isCurrentlySeekable()
+{
+       return 1; // for fast winding we need index files... so only skip forward/backward yet
+}
+
+eAutoInitPtr<eServiceFactoryM2TS> init_eServiceFactoryM2TS(eAutoInitNumbers::service+1, "eServiceFactoryM2TS");
diff --git a/lib/service/servicem2ts.h b/lib/service/servicem2ts.h
new file mode 100644 (file)
index 0000000..bfa4f7d
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef __servicem2ts_h
+#define __servicem2ts_h
+
+#include <lib/service/servicedvb.h>
+
+class eServiceFactoryM2TS: public iServiceHandler
+{
+       DECLARE_REF(eServiceFactoryM2TS);
+public:
+       eServiceFactoryM2TS();
+       virtual ~eServiceFactoryM2TS();
+       enum { id = 0x3 };
+
+               // iServiceHandler
+       RESULT play(const eServiceReference &, ePtr<iPlayableService> &ptr);
+       RESULT record(const eServiceReference &, ePtr<iRecordableService> &ptr);
+       RESULT list(const eServiceReference &, ePtr<iListableService> &ptr);
+       RESULT info(const eServiceReference &, ePtr<iStaticServiceInformation> &ptr);
+       RESULT offlineOperations(const eServiceReference &, ePtr<iServiceOfflineOperations> &ptr);
+};
+
+class eServiceM2TS: public eDVBServicePlay
+{
+       friend class eServiceFactoryM2TS;
+protected:
+       eServiceM2TS(const eServiceReference &ref);
+       ePtr<iTsSource> createTsSource(eServiceReferenceDVB &ref);
+
+       // iSeekableService
+       RESULT isCurrentlySeekable();
+};
+
+#endif
index e453a2b3c896a6cef1be80a9236d7d08386de658..b05b1030bec8bf1cad8afd07ac82232ac02d67c6 100644 (file)
@@ -11,6 +11,7 @@
 #include <lib/gui/esubtitle.h>
 #include <lib/service/servicemp3.h>
 #include <lib/service/service.h>
+#include <lib/gdi/gpixmap.h>
 
 #include <string>
 
@@ -225,6 +226,9 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
        m_currentTrickRatio = 0;
        m_subs_to_pull = 0;
        m_buffer_size = 1*1024*1024;
+       m_prev_decoder_time = -1;
+       m_decoder_time_valid_state = 0;
+
        CONNECT(m_seekTimeout->timeout, eServiceMP3::seekTimeoutCB);
        CONNECT(m_subtitle_sync_timer->timeout, eServiceMP3::pushSubtitles);
        CONNECT(m_pump.recv_msg, eServiceMP3::gstPoll);
@@ -327,7 +331,7 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
 
        g_object_set (G_OBJECT (m_gst_playbin), "uri", uri, NULL);
 
-       int flags = 0x47; // ( == GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_TEXT )
+       int flags = 0x47; // ( GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_NATIVE_VIDEO | GST_PLAY_FLAG_TEXT );
        g_object_set (G_OBJECT (m_gst_playbin), "flags", flags, NULL);
 
        g_free(uri);
@@ -338,8 +342,9 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
        else
        {
                m_subs_to_pull_handler_id = g_signal_connect (subsink, "new-buffer", G_CALLBACK (gstCBsubtitleAvail), this);
-               g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-pango-markup"), NULL);
+               g_object_set (G_OBJECT (subsink), "caps", gst_caps_from_string("text/plain; text/x-plain; text/x-pango-markup; video/x-dvd-subpicture; subpicture/x-pgs"), NULL);
                g_object_set (G_OBJECT (m_gst_playbin), "text-sink", subsink, NULL);
+               
        }
 
        if ( m_gst_playbin )
@@ -354,14 +359,6 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
                {
                        eDebug("eServiceMP3::subtitle uri: %s", g_filename_to_uri(srt_filename, NULL, NULL));
                        g_object_set (G_OBJECT (m_gst_playbin), "suburi", g_filename_to_uri(srt_filename, NULL, NULL), NULL);
-                       subtitleStream subs;
-                       subs.type = stSRT;
-                       subs.language_code = std::string("und");
-                       m_subtitleStreams.push_back(subs);
-               }
-               if ( m_sourceinfo.is_streaming )
-               {
-                       g_signal_connect (G_OBJECT (m_gst_playbin), "notify::source", G_CALLBACK (gstHTTPSourceSetAgent), this);
                }
        } else
        {
@@ -380,12 +377,12 @@ eServiceMP3::eServiceMP3(eServiceReference ref)
 eServiceMP3::~eServiceMP3()
 {
        // disconnect subtitle callback
-       GstElement *sink;
-       g_object_get (G_OBJECT (m_gst_playbin), "text-sink", &sink, NULL);
-       if (sink)
+       GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
+
+       if (appsink)
        {
-               g_signal_handler_disconnect (sink, m_subs_to_pull_handler_id);
-               gst_object_unref(sink);
+               g_signal_handler_disconnect (appsink, m_subs_to_pull_handler_id);
+               gst_object_unref(appsink);
        }
 
        delete m_subtitle_widget;
@@ -442,6 +439,8 @@ RESULT eServiceMP3::stop()
 
        if (m_state == stStopped)
                return -1;
+       
+       //GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(m_gst_playbin),GST_DEBUG_GRAPH_SHOW_ALL,"e2-playbin");
 
        eDebug("eServiceMP3::stop %s", m_ref.path.c_str());
        gst_element_set_state(m_gst_playbin, GST_STATE_NULL);
@@ -568,6 +567,8 @@ RESULT eServiceMP3::seekTo(pts_t to)
                if (!(ret = seekToImpl(to)))
                {
                        m_subtitle_pages.clear();
+                       m_prev_decoder_time = -1;
+                       m_decoder_time_valid_state = 0;
                        m_subs_to_pull = 0;
                }
        }
@@ -669,6 +670,7 @@ RESULT eServiceMP3::getPlayPosition(pts_t &pts)
 
        /* pos is in nanoseconds. we have 90 000 pts per second. */
        pts = pos / 11111;
+//     eDebug("gst_element_query_position %lld pts (%lld ms)", pts, pos/1000000);
        return 0;
 }
 
@@ -1111,6 +1113,48 @@ RESULT eServiceMP3::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
        return 0;
 }
 
+subtype_t getSubtitleType(GstPad* pad, gchar *g_codec=NULL)
+{
+       subtype_t type = stUnknown;
+       GstCaps* caps = gst_pad_get_negotiated_caps(pad);
+
+       if ( caps )
+       {
+               GstStructure* str = gst_caps_get_structure(caps, 0);
+               const gchar *g_type = gst_structure_get_name(str);
+               eDebug("getSubtitleType::subtitle probe caps type=%s", g_type);
+
+               if ( !strcmp(g_type, "video/x-dvd-subpicture") )
+                       type = stVOB;
+               else if ( !strcmp(g_type, "text/x-pango-markup") )
+                       type = stSSA;
+               else if ( !strcmp(g_type, "text/plain") )
+                       type = stPlainText;
+               else if ( !strcmp(g_type, "subpicture/x-pgs") )
+                       type = stPGS;
+               else
+                       eDebug("getSubtitleType::unsupported subtitle caps %s (%s)", g_type, g_codec);
+       }
+       else if ( g_codec )
+       {
+               eDebug("getSubtitleType::subtitle probe codec tag=%s", g_codec);
+               if ( !strcmp(g_codec, "VOB") )
+                       type = stVOB;
+               else if ( !strcmp(g_codec, "SubStation Alpha") || !strcmp(g_codec, "SSA") )
+                       type = stSSA;
+               else if ( !strcmp(g_codec, "ASS") )
+                       type = stASS;
+               else if ( !strcmp(g_codec, "UTF-8 plain text") )
+                       type = stPlainText;
+               else
+                       eDebug("getSubtitleType::unsupported subtitle codec %s", g_codec);
+       }
+       else
+               eDebug("getSubtitleType::unidentifiable subtitle stream!");
+
+       return type;
+}
+
 void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
 {
        if (!msg)
@@ -1157,16 +1201,15 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                                }       break;
                                case GST_STATE_CHANGE_READY_TO_PAUSED:
                                {
-                                       GstElement *sink;
-                                       g_object_get (G_OBJECT (m_gst_playbin), "text-sink", &sink, NULL);
-                                       if (sink)
-                                       {
-                                               g_object_set (G_OBJECT (sink), "max-buffers", 2, NULL);
-                                               g_object_set (G_OBJECT (sink), "sync", FALSE, NULL);
-                                               g_object_set (G_OBJECT (sink), "async", FALSE, NULL);
-                                               g_object_set (G_OBJECT (sink), "emit-signals", TRUE, NULL);
-                                               gst_object_unref(sink);
-                                       }
+                                       GstElement *appsink = gst_bin_get_by_name(GST_BIN(m_gst_playbin), "subtitle_sink");
+                                       if (appsink)
+                                       {
+                                               g_object_set (G_OBJECT (appsink), "max-buffers", 2, NULL);
+                                               g_object_set (G_OBJECT (appsink), "sync", FALSE, NULL);
+                                               g_object_set (G_OBJECT (appsink), "emit-signals", TRUE, NULL);
+                                               eDebug("eServiceMP3::appsink properties set!");
+                                               gst_object_unref(appsink);
+                                       }
                                        setAC3Delay(ac3_delay);
                                        setPCMDelay(pcm_delay);
                                }       break;
@@ -1283,7 +1326,6 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                                        continue;
                                GstStructure* str = gst_caps_get_structure(caps, 0);
                                const gchar *g_type = gst_structure_get_name(str);
-                               eDebug("AUDIO STRUCT=%s", g_type);
                                audio.type = gstCheckAudioPad(str);
                                g_codec = g_strdup(g_type);
                                g_lang = g_strdup_printf ("und");
@@ -1304,25 +1346,31 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
                        }
 
                        for (i = 0; i < n_text; i++)
-                       {       
-                               gchar *g_lang;
-//                             gchar *g_type;
-//                             GstPad* pad = 0;
-//                             g_signal_emit_by_name (m_gst_playbin, "get-text-pad", i, &pad);
-//                             GstCaps* caps = gst_pad_get_negotiated_caps(pad);
-//                             GstStructure* str = gst_caps_get_structure(caps, 0);
-//                             g_type = gst_structure_get_name(str);
-//                             g_signal_emit_by_name (m_gst_playbin, "get-text-tags", i, &tags);
+                       {
+                               gchar *g_codec = NULL, *g_lang = NULL;
+                               g_signal_emit_by_name (m_gst_playbin, "get-text-tags", i, &tags);
                                subtitleStream subs;
-                               subs.type = stPlainText;
+//                             int ret;
+
                                g_lang = g_strdup_printf ("und");
                                if ( tags && gst_is_tag_list(tags) )
+                               {
                                        gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
+                                       gst_tag_list_get_string(tags, GST_TAG_SUBTITLE_CODEC, &g_codec);
+                                       gst_tag_list_free(tags);
+                               }
+
                                subs.language_code = std::string(g_lang);
-                               eDebug("eServiceMP3::subtitle stream=%i language=%s"/* type=%s*/, i, g_lang/*, g_type*/);
+                               eDebug("eServiceMP3::subtitle stream=%i language=%s codec=%s", i, g_lang, g_codec);
+                               
+                               GstPad* pad = 0;
+                               g_signal_emit_by_name (m_gst_playbin, "get-text-pad", i, &pad);
+                               if ( pad )
+                                       g_signal_connect (G_OBJECT (pad), "notify::caps", G_CALLBACK (gstTextpadHasCAPS), this);
+                               subs.type = getSubtitleType(pad, g_codec);
+
                                m_subtitleStreams.push_back(subs);
                                g_free (g_lang);
-//                             g_free (g_type);
                        }
                        m_event((iPlayableService*)this, evUpdatedEventInfo);
                        break;
@@ -1415,7 +1463,7 @@ void eServiceMP3::gstBusCall(GstBus *bus, GstMessage *msg)
 GstBusSyncReply eServiceMP3::gstBusSyncHandler(GstBus *bus, GstMessage *message, gpointer user_data)
 {
        eServiceMP3 *_this = (eServiceMP3*)user_data;
-       _this->m_pump.send(1);
+       _this->m_pump.send(Message(1));
                /* wake */
        return GST_BUS_PASS;
 }
@@ -1469,43 +1517,103 @@ audiotype_t eServiceMP3::gstCheckAudioPad(GstStructure* structure)
        return atUnknown;
 }
 
-void eServiceMP3::gstPoll(const int &msg)
+void eServiceMP3::gstPoll(const Message &msg)
 {
-               /* ok, we have a serious problem here. gstBusSyncHandler sends 
-                  us the wakup signal, but likely before it was posted.
-                  the usleep, an EVIL HACK (DON'T DO THAT!!!) works around this.
-                  
-                  I need to understand the API a bit more to make this work 
-                  proplerly. */
-       if (msg == 1)
+       if (msg.type == 1)
        {
                GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE (m_gst_playbin));
                GstMessage *message;
-               usleep(1);
-               while ((message = gst_bus_pop (bus)))
+               while ((message = gst_bus_pop(bus)))
                {
                        gstBusCall(bus, message);
                        gst_message_unref (message);
                }
        }
-       else
+       else if (msg.type == 2)
                pullSubtitle();
+       else if (msg.type == 3)
+               gstTextpadHasCAPS_synced(msg.d.pad);
+       else
+               eDebug("gstPoll unhandled Message %d\n", msg.type);
 }
 
 eAutoInitPtr<eServiceFactoryMP3> init_eServiceFactoryMP3(eAutoInitNumbers::service+1, "eServiceFactoryMP3");
 
 void eServiceMP3::gstCBsubtitleAvail(GstElement *appsink, gpointer user_data)
 {
-       eServiceMP3 *_this = (eServiceMP3*)user_data;
+       eServiceMP3 *_this = (eServiceMP3*)user_data;   
        eSingleLocker l(_this->m_subs_to_pull_lock);
        ++_this->m_subs_to_pull;
-       _this->m_pump.send(2);
+       _this->m_pump.send(Message(2));
+}
+
+void eServiceMP3::gstTextpadHasCAPS(GstPad *pad, GParamSpec * unused, gpointer user_data)
+{
+       eServiceMP3 *_this = (eServiceMP3*)user_data;
+
+       gst_object_ref (pad);
+
+       _this->m_pump.send(Message(3, pad));
+}
+
+// after messagepump
+void eServiceMP3::gstTextpadHasCAPS_synced(GstPad *pad)
+{
+       GstCaps *caps;
+
+       g_object_get (G_OBJECT (pad), "caps", &caps, NULL);
+
+       eDebug("gstTextpadHasCAPS:: signal::caps = %s", gst_caps_to_string(caps));
+
+       if (caps)
+       {
+               subtitleStream subs;
+
+//             eDebug("gstGhostpadHasCAPS_synced %p %d", pad, m_subtitleStreams.size());
+
+               if (!m_subtitleStreams.empty())
+                       subs = m_subtitleStreams[m_currentSubtitleStream];
+               else {
+                       subs.type = stUnknown;
+                       subs.pad = pad;
+               }
+
+               if ( subs.type == stUnknown )
+               {
+                       GstTagList *tags;
+//                     eDebug("gstGhostpadHasCAPS::m_subtitleStreams[%i].type == stUnknown...", m_currentSubtitleStream);
+
+                       gchar *g_lang;
+                       g_signal_emit_by_name (m_gst_playbin, "get-text-tags", m_currentSubtitleStream, &tags);
+
+                       g_lang = g_strdup_printf ("und");
+                       if ( tags && gst_is_tag_list(tags) )
+                               gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &g_lang);
+
+                       subs.language_code = std::string(g_lang);
+                       subs.type = getSubtitleType(pad);
+
+                       if (!m_subtitleStreams.empty())
+                               m_subtitleStreams[m_currentSubtitleStream] = subs;
+                       else
+                               m_subtitleStreams.push_back(subs);
+
+                       g_free (g_lang);
+               }
+
+//             eDebug("gstGhostpadHasCAPS:: m_gst_prev_subtitle_caps=%s equal=%i",gst_caps_to_string(m_gst_prev_subtitle_caps),gst_caps_is_equal(m_gst_prev_subtitle_caps, caps));
+
+               gst_caps_unref (caps);
+       }
+
+       gst_object_unref (pad);
 }
 
 void eServiceMP3::pullSubtitle()
 {
        GstElement *sink;
        g_object_get (G_OBJECT (m_gst_playbin), "text-sink", &sink, NULL);
+       
        if (sink)
        {
                while (m_subs_to_pull && m_subtitle_pages.size() < 2)
@@ -1521,17 +1629,31 @@ void eServiceMP3::pullSubtitle()
                                gint64 buf_pos = GST_BUFFER_TIMESTAMP(buffer);
                                gint64 duration_ns = GST_BUFFER_DURATION(buffer);
                                size_t len = GST_BUFFER_SIZE(buffer);
-                               unsigned char line[len+1];
-                               memcpy(line, GST_BUFFER_DATA(buffer), len);
-                               line[len] = 0;
-                               eDebug("got new subtitle @ buf_pos = %lld ns (in pts=%lld): '%s' ", buf_pos, buf_pos/11111, line);
-                               ePangoSubtitlePage page;
-                               gRGB rgbcol(0xD0,0xD0,0xD0);
-                               page.m_elements.push_back(ePangoSubtitlePageElement(rgbcol, (const char*)line));
-                               page.show_pts = buf_pos / 11111L;
-                               page.m_timeout = duration_ns / 1000000;
-                               m_subtitle_pages.push_back(page);
-                               pushSubtitles();
+                               eDebug("pullSubtitle m_subtitleStreams[m_currentSubtitleStream].type=%i",m_subtitleStreams[m_currentSubtitleStream].type);
+                               
+                               if ( m_subtitleStreams[m_currentSubtitleStream].type )
+                               {
+                                       if ( m_subtitleStreams[m_currentSubtitleStream].type < stVOB )
+                                       {
+                                               unsigned char line[len+1];
+                                               SubtitlePage page;
+                                               memcpy(line, GST_BUFFER_DATA(buffer), len);
+                                               line[len] = 0;
+                                               eDebug("got new text subtitle @ buf_pos = %lld ns (in pts=%lld): '%s' ", buf_pos, buf_pos/11111, line);
+                                               gRGB rgbcol(0xD0,0xD0,0xD0);
+                                               page.type = SubtitlePage::Pango;
+                                               page.pango_page.m_elements.push_back(ePangoSubtitlePageElement(rgbcol, (const char*)line));
+                                               page.pango_page.m_show_pts = buf_pos / 11111L;
+                                               page.pango_page.m_timeout = duration_ns / 1000000;
+                                               m_subtitle_pages.push_back(page);
+                                               if (m_subtitle_pages.size()==1)
+                                                       pushSubtitles();
+                                       }
+                                       else
+                                       {
+                                               eDebug("unsupported subpicture... ignoring");
+                                       }
+                               }
                                gst_buffer_unref(buffer);
                        }
                }
@@ -1543,45 +1665,56 @@ void eServiceMP3::pullSubtitle()
 
 void eServiceMP3::pushSubtitles()
 {
-       ePangoSubtitlePage page;
-       pts_t running_pts;
        while ( !m_subtitle_pages.empty() )
        {
+               SubtitlePage &frontpage = m_subtitle_pages.front();
+               pts_t running_pts;
+               gint64 diff_ms = 0;
+               gint64 show_pts = 0;
+
                getPlayPosition(running_pts);
-               page = m_subtitle_pages.front();
-               gint64 diff_ms = ( page.show_pts - running_pts ) / 90;
-               eDebug("eServiceMP3::pushSubtitles show_pts = %lld  running_pts = %lld  diff = %lld", page.show_pts, running_pts, diff_ms);
-               if (diff_ms < -100)
-               {
-                       GstFormat fmt = GST_FORMAT_TIME;
-                       gint64 now;
-                       if (gst_element_query_position(m_gst_playbin, &fmt, &now) != -1)
-                       {
-                               now /= 11111;
-                               diff_ms = abs((now - running_pts) / 90);
-                               eDebug("diff < -100ms check decoder/pipeline diff: decoder: %lld, pipeline: %lld, diff: %lld", running_pts, now, diff_ms);
-                               if (diff_ms > 100000)
-                               {
-                                       eDebug("high decoder/pipeline difference.. assume decoder has now started yet.. check again in 1sec");
-                                       m_subtitle_sync_timer->start(1000, true);
-                                       break;
-                               }
+
+               if (m_decoder_time_valid_state < 4) {
+                       ++m_decoder_time_valid_state;
+                       if (m_prev_decoder_time == running_pts)
+                               m_decoder_time_valid_state = 0;
+                       if (m_decoder_time_valid_state < 4) {
+//                             if (m_decoder_time_valid_state)
+//                                     eDebug("%d: decoder time not valid! prev %lld, now %lld\n", m_decoder_time_valid_state, m_prev_decoder_time/90, running_pts/90);
+//                             else
+//                                     eDebug("%d: decoder time not valid! now %lld\n", m_decoder_time_valid_state, running_pts/90);
+                               m_subtitle_sync_timer->start(25, true);
+                               m_prev_decoder_time = running_pts;
+                               break;
                        }
-                       else
-                               eDebug("query position for decoder/pipeline check failed!");
-                       eDebug("subtitle to late... drop");
+               }
+
+               if (frontpage.type == SubtitlePage::Pango)
+                       show_pts = frontpage.pango_page.m_show_pts;
+
+               diff_ms = ( show_pts - running_pts ) / 90;
+               eDebug("check subtitle: decoder: %lld, show_pts: %lld, diff: %lld ms", running_pts/90, show_pts/90, diff_ms);
+
+               if ( diff_ms < -100 )
+               {
+                       eDebug("subtitle too late... drop");
                        m_subtitle_pages.pop_front();
                }
                else if ( diff_ms > 20 )
                {
-//                     eDebug("start recheck timer");
-                       m_subtitle_sync_timer->start(diff_ms > 1000 ? 1000 : diff_ms, true);
+                       eDebug("start timer");
+                       m_subtitle_sync_timer->start(diff_ms, true);
                        break;
                }
                else // immediate show
                {
-                       if (m_subtitle_widget)
-                               m_subtitle_widget->setPage(page);
+                       if ( m_subtitle_widget )
+                       {
+                               eDebug("show!\n");
+                               if ( frontpage.type == SubtitlePage::Pango)
+                                       m_subtitle_widget->setPage(frontpage.pango_page);
+                               m_subtitle_widget->show();
+                       }
                        m_subtitle_pages.pop_front();
                }
        }
@@ -1589,12 +1722,20 @@ void eServiceMP3::pushSubtitles()
                pullSubtitle();
 }
 
+
 RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple)
 {
+       eDebug ("eServiceMP3::enableSubtitles m_currentSubtitleStream=%i this=%p",m_currentSubtitleStream, this);
        ePyObject entry;
        int tuplesize = PyTuple_Size(tuple);
        int pid, type;
        gint text_pid = 0;
+       eSingleLocker l(m_subs_to_pull_lock);
+
+//     GstPad *pad = 0;
+//     g_signal_emit_by_name (m_gst_playbin, "get-text-pad", m_currentSubtitleStream, &pad);
+//     gst_element_get_static_pad(m_gst_subtitlebin, "sink");
+//     gulong subprobe_handler_id = gst_pad_add_buffer_probe (pad, G_CALLBACK (gstCBsubtitleDrop), NULL);
 
        if (!PyTuple_Check(tuple))
                goto error_out;
@@ -1611,10 +1752,11 @@ RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple)
 
        if (m_currentSubtitleStream != pid)
        {
-               eSingleLocker l(m_subs_to_pull_lock);
                g_object_set (G_OBJECT (m_gst_playbin), "current-text", pid, NULL);
+               eDebug ("eServiceMP3::enableSubtitles g_object_set current-text = %i", pid);
                m_currentSubtitleStream = pid;
                m_subs_to_pull = 0;
+               m_prev_decoder_time = -1;
                m_subtitle_pages.clear();
        }
 
@@ -1625,6 +1767,9 @@ RESULT eServiceMP3::enableSubtitles(eWidget *parent, ePyObject tuple)
        g_object_get (G_OBJECT (m_gst_playbin), "current-text", &text_pid, NULL);
 
        eDebug ("eServiceMP3::switched to subtitle stream %i", text_pid);
+//     gst_pad_remove_buffer_probe (pad, subprobe_handler_id);
+
+       m_event((iPlayableService*)this, evUpdatedInfo);
 
        return 0;
 
@@ -1651,26 +1796,35 @@ PyObject *eServiceMP3::getCachedSubtitle()
 
 PyObject *eServiceMP3::getSubtitleList()
 {
-       eDebug("eServiceMP3::getSubtitleList");
-
+//     eDebug("eServiceMP3::getSubtitleList");
        ePyObject l = PyList_New(0);
-       int stream_count[sizeof(subtype_t)];
-       for ( unsigned int i = 0; i < sizeof(subtype_t); i++ )
-               stream_count[i] = 0;
-
+       int stream_idx = 0;
+       
        for (std::vector<subtitleStream>::iterator IterSubtitleStream(m_subtitleStreams.begin()); IterSubtitleStream != m_subtitleStreams.end(); ++IterSubtitleStream)
        {
                subtype_t type = IterSubtitleStream->type;
-               ePyObject tuple = PyTuple_New(5);
-               PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(2));
-               PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(stream_count[type]));
-               PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(int(type)));
-               PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(0));
-               PyTuple_SET_ITEM(tuple, 4, PyString_FromString((IterSubtitleStream->language_code).c_str()));
-               PyList_Append(l, tuple);
-               Py_DECREF(tuple);
-               stream_count[type]++;
+               switch(type)
+               {
+               case stUnknown:
+               case stVOB:
+               case stPGS:
+                       break;
+               default:
+               {
+                       ePyObject tuple = PyTuple_New(5);
+//                     eDebug("eServiceMP3::getSubtitleList idx=%i type=%i, code=%s", stream_idx, int(type), (IterSubtitleStream->language_code).c_str());
+                       PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(2));
+                       PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(stream_idx));
+                       PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(int(type)));
+                       PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(0));
+                       PyTuple_SET_ITEM(tuple, 4, PyString_FromString((IterSubtitleStream->language_code).c_str()));
+                       PyList_Append(l, tuple);
+                       Py_DECREF(tuple);
+               }
+               }
+               stream_idx++;
        }
+       eDebug("eServiceMP3::getSubtitleList finished");
        return l;
 }
 
index d54997a604f5f12f9da50fafdd7b7440944d764f..a92a4cf78b95ec8b3a92d1051b97c53bac6d6011 100644 (file)
@@ -46,7 +46,7 @@ public:
 typedef struct _GstElement GstElement;
 
 typedef enum { atUnknown, atMPEG, atMP3, atAC3, atDTS, atAAC, atPCM, atOGG, atFLAC } audiotype_t;
-typedef enum { stPlainText, stSSA, stSRT } subtype_t;
+typedef enum { stUnknown, stPlainText, stSSA, stASS, stSRT, stVOB, stPGS } subtype_t;
 typedef enum { ctNone, ctMPEGTS, ctMPEGPS, ctMKV, ctAVI, ctMP4, ctVCD, ctCDA } containertype_t;
 
 class eServiceMP3: public iPlayableService, public iPauseableService,
@@ -194,30 +194,63 @@ private:
        enum
        {
                stIdle, stRunning, stStopped,
+        };
+        int m_state;
+        GstElement *m_gst_playbin;
+        GstTagList *m_stream_tags;
+
+        struct Message
+        {
+                Message()
+                        :type(-1)
+                {}
+                Message(int type)
+                        :type(type)
+                {}
+                Message(int type, GstPad *pad)
+                        :type(type)
+                {
+                        d.pad=pad;
+                }
+
+                int type;
+                union {
+                        GstPad *pad; // for msg type 3
+                } d;
+        };
+
+        eFixedMessagePump<Message> m_pump;
+        std::string m_error_message;
+
+        audiotype_t gstCheckAudioPad(GstStructure* structure);
+        void gstBusCall(GstBus *bus, GstMessage *msg);
+        static GstBusSyncReply gstBusSyncHandler(GstBus *bus, GstMessage *message, gpointer user_data);
+       static void gstTextpadHasCAPS(GstPad *pad, GParamSpec * unused, gpointer user_data);
+       void gstTextpadHasCAPS_synced(GstPad *pad);
+        static void gstCBsubtitleAvail(GstElement *element, gpointer user_data);
+        GstPad* gstCreateSubtitleSink(eServiceMP3* _this, subtype_t type);
+       void gstPoll(const Message&);
+        static void gstHTTPSourceSetAgent(GObject *source, GParamSpec *unused, gpointer user_data);
+
+       struct SubtitlePage
+       {
+               enum { Unknown, Pango, Vob } type;
+               ePangoSubtitlePage pango_page;
+               eVobSubtitlePage vob_page;
        };
-       int m_state;
-       GstElement *m_gst_playbin;
-       GstTagList *m_stream_tags;
-       eFixedMessagePump<int> m_pump;
-       std::string m_error_message;
-
-       audiotype_t gstCheckAudioPad(GstStructure* structure);
-       void gstBusCall(GstBus *bus, GstMessage *msg);
-       static GstBusSyncReply gstBusSyncHandler(GstBus *bus, GstMessage *message, gpointer user_data);
-       static void gstCBsubtitleAvail(GstElement *element, gpointer user_data);
-       GstPad* gstCreateSubtitleSink(eServiceMP3* _this, subtype_t type);
-       void gstPoll(const int&);
-       static void gstHTTPSourceSetAgent(GObject *source, GParamSpec *unused, gpointer user_data);
-
-       std::list<ePangoSubtitlePage> m_subtitle_pages;
-       ePtr<eTimer> m_subtitle_sync_timer;
-       
-       ePtr<eTimer> m_streamingsrc_timeout;
-       void pushSubtitles();
-       void pullSubtitle();
-       void sourceTimeout();
-       int m_subs_to_pull;
-       sourceStream m_sourceinfo;
+
+        std::list<SubtitlePage> m_subtitle_pages;
+        ePtr<eTimer> m_subtitle_sync_timer;
+        
+        ePtr<eTimer> m_streamingsrc_timeout;
+        pts_t m_prev_decoder_time;
+        int m_decoder_time_valid_state;
+
+        void pushSubtitles();
+        void pullSubtitle();
+        void sourceTimeout();
+        int m_subs_to_pull;
+        sourceStream m_sourceinfo;
        eSingleLock m_subs_to_pull_lock;
        gulong m_subs_to_pull_handler_id;
 
index a19e6733558e06b289aed539fa2954eeb38c92d7..5914c3f87036e7cffceb8153332c4977427bec0a 100755 (executable)
@@ -7,11 +7,23 @@ if [ -x @bindir@/showiframe -a -f /boot/backdrop.mvi ]; then
        @bindir@/showiframe /boot/backdrop.mvi
 fi
 
+# hook to execute scripts always before enigma2 start
+if [ -x @bindir@/enigma2_pre_start.sh ]; then
+       @bindir@/enigma2_pre_start.sh
+fi
+
 if [ -d /home/root ]; then
        cd /home/root
 fi
 
-LD_PRELOAD=@libdir@/libopen.so.0.0.0 @bindir@/enigma2
+LIBS=@libdir@/libopen.so.0.0.0
+
+#check for dreambox specific passthrough helper lib
+if [ -e @libdir@/libpassthrough.so ]; then
+       LIBS="$LIBS @libdir@/libpassthrough.so"
+fi
+
+LD_PRELOAD=$LIBS @bindir@/enigma2
 
 # enigma2 exit codes:
 #