add possibility to view eventinfo in recorded movielist (move cursor to
[enigma2.git] / lib / service / servicedvb.cpp
index 9cfe7073055a2aecf1191e4778c436b960914a38..616c7007e5ceeb9a6707d4520e152917c0ddedf5 100644 (file)
 #include <lib/dvb/tstools.h>
 #include <lib/python/python.h>
 
+               /* for subtitles */
+#include <lib/gui/esubtitle.h>
+
 #include <sys/vfs.h>
 
 #include <byteswap.h>
 #include <netinet/in.h>
 
-#include <dvbsi++/event_information_section.h>
+#define INTERNAL_TELETEXT
 
 #ifndef BYTE_ORDER
 #error no byte order defined!
@@ -144,7 +147,8 @@ public:
        eStaticServiceDVBPVRInformation(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 getInfo(const eServiceReference &ref, int w);
        std::string getInfoString(const eServiceReference &ref,int w);
 };
@@ -211,6 +215,24 @@ std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReferen
        }
 }
 
+RESULT eStaticServiceDVBPVRInformation::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()-2, 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;
+}
+
 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
 {
        DECLARE_REF(eDVBPVRServiceOfflineOperations);
@@ -625,7 +647,7 @@ RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServ
 }
 
 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
-       m_reference(ref), m_dvb_service(service), m_is_paused(0)
+       m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
 {
        m_is_primary = 1;
        m_is_pvr = !m_reference.path.empty();
@@ -639,10 +661,15 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
 
        m_cuesheet_changed = 0;
        m_cutlist_enabled = 1;
+       
+       m_subtitle_widget = 0;
+       
+       CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
 }
 
 eDVBServicePlay::~eDVBServicePlay()
 {
+       delete m_subtitle_widget;
 }
 
 void eDVBServicePlay::gotNewEvent()
@@ -741,32 +768,22 @@ RESULT eDVBServicePlay::start()
        m_first_program_info = 1;
        eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
        r = m_service_handler.tune(service, m_is_pvr, m_cue);
-       
+
                /* inject EIT if there is a stored one */
        if (m_is_pvr)
        {
                std::string filename = service.path;
                filename.erase(filename.length()-2, 2);
                filename+="eit";
-               int fd = ::open( filename.c_str(), O_RDONLY );
-               if ( fd > -1 )
+               ePtr<eServiceEvent> event = new eServiceEvent;
+               if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
                {
-                       __u8 buf[4096];
-                       int rd = ::read(fd, buf, 4096);
-                       ::close(fd);
-                       if ( rd > 12 /*EIT_LOOP_SIZE*/ )
-                       {
-                               Event ev(buf);
-                               ePtr<eServiceEvent> event = new eServiceEvent;
-                               ePtr<eServiceEvent> empty;
-                               event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
-                               m_event_handler.inject(event, 0);
-                               m_event_handler.inject(empty, 1);
-                               eDebug("injected");
-                       }
+                       ePtr<eServiceEvent> empty;
+                       m_event_handler.inject(event, 0);
+                       m_event_handler.inject(empty, 1);
                }
        }
-       
+
        if (m_is_pvr)
                loadCuesheet();
 
@@ -1018,7 +1035,8 @@ RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
 {
        ptr = 0;
-       if (m_timeshift_enabled || !m_is_pvr)
+       if (m_have_video_pid &&  // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
+               (m_timeshift_enabled || !m_is_pvr))
        {
                if (!m_timeshift_enabled)
                {
@@ -1053,6 +1071,18 @@ RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
        return -1;
 }
 
+RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
+{
+       ptr = this;
+       return 0;
+}
+
+RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
+{
+       ptr = this;
+       return 0;
+}
+
 RESULT eDVBServicePlay::getName(std::string &name)
 {
        if (m_is_pvr)
@@ -1263,20 +1293,18 @@ int eDVBServicePlay::selectAudioStream(int i)
 
 int eDVBServicePlay::getCurrentChannel()
 {
-       int curChannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
-       return curChannel == -1 ? STEREO : curChannel;
+       return m_decoder ? m_decoder->getAudioChannel() : STEREO;
 }
 
 RESULT eDVBServicePlay::selectChannel(int i)
 {
-       if (i < iAudioChannelSelection::LEFT || i > iAudioChannelSelection::RIGHT)
+       if (i < LEFT || i > RIGHT || i == STEREO)
                i = -1;  // Stereo
-       if (m_dvb_service->getCacheEntry(eDVBService::cACHANNEL) != i)
-       {
+       if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
-               if (m_decoder)
-                       m_decoder->setAudioChannel(i);
-       }
+       if (m_decoder)
+               m_decoder->setAudioChannel(i);
+       return 0;
 }
 
 int eDVBServiceBase::getFrontendInfo(int w)
@@ -1551,6 +1579,7 @@ void eDVBServicePlay::switchToLive()
        m_decoder = 0;
        m_decode_demux = 0;
        m_teletext_parser = 0;
+       m_new_subtitle_page_connection = 0;
        
                /* free the timeshift service handler, we need the resources */
        m_service_handler_timeshift.free();
@@ -1569,6 +1598,7 @@ void eDVBServicePlay::switchToTimeshift()
        m_decode_demux = 0;
        m_decoder = 0;
        m_teletext_parser = 0;
+       m_new_subtitle_page_connection = 0;
        
        m_timeshift_active = 1;
 
@@ -1584,7 +1614,8 @@ void eDVBServicePlay::switchToTimeshift()
 
 void eDVBServicePlay::updateDecoder()
 {
-       int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1;
+       int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
+
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 
        bool defaultac3=false;
@@ -1643,7 +1674,6 @@ void eDVBServicePlay::updateDecoder()
                pcrpid = program.pcrPid;
                eDebug(", and the text pid is %04x", program.textPid);
                tpid = program.textPid;
-               achannel = program.audioChannel;
        }
 
        if (!m_decoder)
@@ -1655,11 +1685,46 @@ void eDVBServicePlay::updateDecoder()
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
 #ifdef INTERNAL_TELETEXT
                m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
+               m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
 #endif
        }
 
        if (m_decoder)
        {
+               if (m_dvb_service)
+               {
+                       achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
+                       ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
+                       pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
+               }
+               else // subservice or recording
+               {
+                       eServiceReferenceDVB ref;
+                       m_service_handler.getServiceReference(ref);
+                       eServiceReferenceDVB parent = ref.getParentServiceReference();
+                       if (!parent)
+                               parent = ref;
+                       if (parent)
+                       {
+                               ePtr<eDVBResourceManager> res_mgr;
+                               if (!eDVBResourceManager::getInstance(res_mgr))
+                               {
+                                       ePtr<iDVBChannelList> db;
+                                       if (!res_mgr->getChannelList(db))
+                                       {
+                                               ePtr<eDVBService> origService;
+                                               if (!db->getService(parent, origService))
+                                               {
+                                                       ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
+                                                       pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
+               m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
+
                m_decoder->setVideoPID(vpid, vpidtype);
                m_current_audio_stream = 0;
                m_decoder->setAudioPID(apid, apidtype);
@@ -1667,18 +1732,26 @@ void eDVBServicePlay::updateDecoder()
                        m_decoder->setSyncPCR(pcrpid);
                else
                        m_decoder->setSyncPCR(-1);
-#ifndef INTERNAL_TELETEXT
+
                m_decoder->setTextPID(tpid);
-#else
+
                if (m_teletext_parser)
                        m_teletext_parser->start(tpid);
-#endif
 
                if (!m_is_primary)
                        m_decoder->setTrickmode(1);
 
                m_decoder->start();
 
+               if (vpid > 0 && vpid < 0x2000)
+                       ;
+               else
+               {
+                       std::string radio_pic;
+                       if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
+                               m_decoder->setRadioPic(radio_pic);
+               }
+
                m_decoder->setAudioChannel(achannel);
 
 // how we can do this better?
@@ -1704,6 +1777,7 @@ void eDVBServicePlay::updateDecoder()
                        m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
                }
        }
+       m_have_video_pid = (vpid > 0 && vpid < 0x2000);
 }
 
 void eDVBServicePlay::loadCuesheet()
@@ -1827,6 +1901,141 @@ void eDVBServicePlay::cutlistToCuesheet()
        m_cue->commitSpans();
 }
 
+RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
+{
+       if (m_subtitle_widget)
+               disableSubtitles(parent);
+       
+       if (!m_teletext_parser)
+               return -1;
+       
+       if (!PyInt_Check(entry))
+               return -1;
+       
+       m_subtitle_widget = new eSubtitleWidget(parent);
+       m_subtitle_widget->resize(parent->size()); /* full size */
+       
+       int page = PyInt_AsLong(entry);
+       
+       m_teletext_parser->setPage(page);
+
+       return 0;
+}
+
+RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
+{
+       delete m_subtitle_widget;
+       m_subtitle_widget = 0;
+       return 0;
+}
+
+PyObject *eDVBServicePlay::getSubtitleList()
+{
+       if (!m_teletext_parser)
+       {
+               Py_INCREF(Py_None);
+               return Py_None;
+       }
+       
+       PyObject *l = PyList_New(0);
+       
+       for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
+       {
+               PyObject *tuple = PyTuple_New(2);
+               char desc[20];
+               sprintf(desc, "Page %x", *i);
+               PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
+               PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
+               PyList_Append(l, tuple);
+       }
+       
+       return l;
+}
+
+void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
+{
+       if (m_subtitle_widget)
+       {
+               m_subtitle_pages.push_back(page);
+               
+               checkSubtitleTiming();
+       }
+}
+
+void eDVBServicePlay::checkSubtitleTiming()
+{
+       while (1)
+       {
+               if (m_subtitle_pages.empty())
+                       return;
+       
+               eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
+       
+               pts_t pos = 0;
+       
+               if (m_decoder)
+                       m_decoder->getPTS(0, pos);
+       
+               int diff = p.m_pts - pos;
+               if (diff < 0)
+               {
+                       eDebug("[late (%d ms)]", -diff / 90);
+                       diff = 0;
+               }
+               if (diff > 900000)
+               {
+                       eDebug("[invalid]");
+                       diff = 0;
+               }
+       
+               if (!diff)
+               {
+                       m_subtitle_widget->setPage(p);
+                       m_subtitle_pages.pop_front();
+               } else
+               {
+                       m_subtitle_sync_timer.start(diff / 90, 1);
+                       break;
+               }
+       }
+}
+
+int eDVBServicePlay::getAC3Delay()
+{
+       if (m_dvb_service)
+               return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
+       else if (m_decoder)
+               return m_decoder->getAC3Delay();
+       else
+               return 0;
+}
+
+int eDVBServicePlay::getPCMDelay()
+{
+       if (m_dvb_service)
+               return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
+       else if (m_decoder)
+               return m_decoder->getPCMDelay();
+       else
+               return 0;
+}
+
+void eDVBServicePlay::setAC3Delay(int delay)
+{
+       if (m_dvb_service)
+               m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
+       if (m_decoder)
+               m_decoder->setAC3Delay(delay);
+}
+
+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);
+}
+
 DEFINE_REF(eDVBServicePlay)
 
 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");