Merge branch 'bug_672_removed_pvr_device'
[enigma2.git] / lib / service / servicedvb.cpp
index 69329ce07c6cb626ce4438bcced5c0f34f92cf73..8650989a49c501b9b514df9434e6eca326cc845c 100644 (file)
@@ -309,7 +309,9 @@ eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceR
 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
 {
        ASSERT(ref == m_ref);
-       if (m_parser.m_name.size())
+       if (!ref.name.empty())
+               name = ref.name;
+       else if (!m_parser.m_name.empty())
                name = m_parser.m_name;
        else
        {
@@ -503,18 +505,19 @@ RESULT eDVBPVRServiceOfflineOperations::reindex()
        int err = f.open(m_ref.path.c_str(), 0);
        if (err < 0)
                return -1;
-       
+
+       off_t offset = 0;
        off_t length = f.length();
        unsigned char buffer[188*256*4];
        while (1)
        {
-               off_t offset = f.lseek(0, SEEK_CUR);
                eDebug("at %08llx / %08llx (%d %%)", offset, length, (int)(offset * 100 / length));
-               int r = f.read(buffer, sizeof(buffer));
+               int r = f.read(offset, buffer, sizeof(buffer));
                if (!r)
                        break;
                if (r < 0)
                        return r;
+               offset += r;
                parser.parseData(offset, buffer, r);
        }
        
@@ -902,7 +905,7 @@ RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServ
                /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
                if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
                {
-                       eDebug("getService failed!");
+//                     eDebug("getService failed!");
                        return err;
                }
        }
@@ -910,7 +913,7 @@ RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServ
        return 0;
 }
 
-eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
+eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
        m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
 {
        m_is_primary = 1;
@@ -1021,12 +1024,13 @@ void eDVBServicePlay::serviceEvent(int event)
                        updateTimeshiftPids();
                if (!m_timeshift_active)
                        updateDecoder();
-               if (m_first_program_info && m_is_pvr)
+               if (m_first_program_info & 1 && m_is_pvr)
                {
-                       m_first_program_info = 0;
+                       m_first_program_info &= ~1;
                        seekTo(0);
                }
-               m_event((iPlayableService*)this, evUpdatedInfo);
+               if (!m_timeshift_active)
+                       m_event((iPlayableService*)this, evUpdatedInfo);
                break;
        }
        case eDVBServicePMTHandler::eventPreStart:
@@ -1046,17 +1050,87 @@ void eDVBServicePlay::serviceEventTimeshift(int event)
        switch (event)
        {
        case eDVBServicePMTHandler::eventNewProgramInfo:
+               eDebug("eventNewProgramInfo TS");
                if (m_timeshift_active)
+               {
                        updateDecoder();
+                       if (m_first_program_info & 2)
+                       {
+                               if (m_slowmotion)
+                               {
+                                       eDebug("re-apply slowmotion after timeshift file change");
+                                       m_decoder->setSlowMotion(m_slowmotion);
+                               }
+                               if (m_fastforward)
+                               {
+                                       eDebug("re-apply skip %d, ratio %d after timeshift file change", m_skipmode, m_fastforward);
+                                       if (m_skipmode)
+                                               m_cue->setSkipmode(m_skipmode * 90000); /* convert to 90000 per second */
+                                       if (m_fastforward != 1)
+                                               m_decoder->setFastForward(m_fastforward);
+                                       else
+                                               m_decoder->setTrickmode();
+                               }
+                               else
+                                       seekTo(0);
+                               m_first_program_info &= ~2;
+                       }
+                       m_event((iPlayableService*)this, evUpdatedInfo);
+               }
                break;
        case eDVBServicePMTHandler::eventSOF:
-               m_event((iPlayableService*)this, evSOF);
+#if 0
+               if (!m_timeshift_file_next.empty())
+               {
+                       eDebug("timeshift SOF, switch to next file");
+                       m_decoder->pause();
+
+                       m_first_program_info |= 2;
+
+                       eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
+                       r.path = m_timeshift_file_next;
+
+                       /* free the timeshift service handler, we need the resources */
+                       m_service_handler_timeshift.free();
+                       resetTimeshift(1);
+
+                       if (m_skipmode < 0)
+                               m_cue->seekTo(0, -1000);
+                       ePtr<iTsSource> source = createTsSource(r);
+                       m_service_handler_timeshift.tuneExt(r, 1, source, r.path.c_str(), m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+                       m_event((iPlayableService*)this, evUser+1);
+               }
+               else
+#endif
+                       m_event((iPlayableService*)this, evSOF);
                break;
        case eDVBServicePMTHandler::eventEOF:
                if ((!m_is_paused) && (m_skipmode >= 0))
                {
-                       eDebug("timeshift EOF, so let's go live");
-                       switchToLive();
+                       if (m_timeshift_file_next.empty())
+                       {
+                               eDebug("timeshift EOF, so let's go live");
+                               switchToLive();
+                       }
+                       else
+                       {
+                               eDebug("timeshift EOF, switch to next file");
+
+                               m_first_program_info |= 2;
+
+                               eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
+                               r.path = m_timeshift_file_next;
+
+                               /* free the timeshift service handler, we need the resources */
+                               m_service_handler_timeshift.free();
+                               resetTimeshift(1);
+
+                               ePtr<iTsSource> source = createTsSource(r);
+                               m_service_handler_timeshift.tuneExt(r, 1, source, m_timeshift_file_next.c_str(), m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+                               m_event((iPlayableService*)this, evUser+1);
+                       }
                }
                break;
        }
@@ -1083,7 +1157,8 @@ RESULT eDVBServicePlay::start()
                m_event(this, evStart);
 
        m_first_program_info = 1;
-       m_service_handler.tune(service, m_is_pvr, m_cue, false, m_dvb_service);
+       ePtr<iTsSource> source = createTsSource(service);
+       m_service_handler.tuneExt(service, m_is_pvr, source, service.path.c_str(), m_cue, false, m_dvb_service);
 
        if (m_is_pvr)
        {
@@ -1128,11 +1203,7 @@ RESULT eDVBServicePlay::stop()
                        
                        if (length)
                        {
-                               int perc = play_position * 100LL / length;
-                       
-                                       /* only store last play position when between 1% and 99% */
-                               if ((1 < perc) && (perc < 99))
-                                       m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+                               m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
                        }
                        m_cuesheet_changed = 1;
                }
@@ -1391,7 +1462,7 @@ RESULT eDVBServicePlay::isCurrentlySeekable()
        if (m_decoder)
        {
                ret = (m_is_pvr || m_timeshift_active) ? 3 : 0; // fast forward/backward possible and seeking possible
-               if (m_decoder->getVideoWidth() == -1)
+               if (m_decoder->getVideoProgressive() == -1)
                        ret &= ~2;
        }
        return ret;
@@ -1520,7 +1591,7 @@ int eDVBServicePlay::getInfo(int w)
 {
        eDVBServicePMTHandler::program program;
 
-       if (w == sCAIDs)
+       if (w == sCAIDs || w == sCAIDPIDs)
                return resIsPyObject;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
@@ -1661,6 +1732,8 @@ PyObject *eDVBServicePlay::getInfoObject(int w)
        {
        case sCAIDs:
                return m_service_handler.getCaIds();
+       case sCAIDPIDs:
+               return m_service_handler.getCaIds(true);
        case sTransponderData:
                return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
        default:
@@ -1728,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 = "???";
 
@@ -2089,12 +2164,13 @@ RESULT eDVBServicePlay::startTimeshift()
        return 0;
 }
 
-RESULT eDVBServicePlay::stopTimeshift()
+RESULT eDVBServicePlay::stopTimeshift(bool swToLive)
 {
        if (!m_timeshift_enabled)
                return -1;
        
-       switchToLive();
+       if (swToLive)
+               switchToLive();
        
        m_timeshift_enabled = 0;
        
@@ -2243,33 +2319,58 @@ void eDVBServicePlay::updateTimeshiftPids()
        }
 }
 
+RESULT eDVBServicePlay::setNextPlaybackFile(const char *f)
+{
+       m_timeshift_file_next = f;
+       return 0;
+}
+
 void eDVBServicePlay::switchToLive()
 {
        if (!m_timeshift_active)
                return;
-       
+
        eDebug("SwitchToLive");
-       
+
+       resetTimeshift(0);
+
+       m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
+
+       /* free the timeshift service handler, we need the resources */
+       m_service_handler_timeshift.free();
+
+       updateDecoder(true);
+}
+
+void eDVBServicePlay::resetTimeshift(int start)
+{
        m_cue = 0;
-       m_decoder = 0;
        m_decode_demux = 0;
+       m_decoder = 0;
        m_teletext_parser = 0;
        m_rds_decoder = 0;
        m_subtitle_parser = 0;
-       m_new_dvb_subtitle_page_connection = 0;
        m_new_subtitle_page_connection = 0;
+       m_new_dvb_subtitle_page_connection = 0;
        m_rds_decoder_event_connection = 0;
        m_video_event_connection = 0;
-       m_is_paused = m_skipmode = m_fastforward = m_slowmotion = 0; /* not supported in live mode */
-
-               /* free the timeshift service handler, we need the resources */
-       m_service_handler_timeshift.free();
-       m_timeshift_active = 0;
        m_timeshift_changed = 1;
+       m_timeshift_file_next.clear();
 
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
+       if (start)
+       {
+               m_cue = new eCueSheet();
+               m_timeshift_active = 1;
+       }
+       else
+               m_timeshift_active = 0;
+}
 
-       updateDecoder();
+ePtr<iTsSource> eDVBServicePlay::createTsSource(eServiceReferenceDVB &ref)
+{
+       eRawFile *f = new eRawFile();
+       f->open(ref.path.c_str());
+       return ePtr<iTsSource>(f);
 }
 
 void eDVBServicePlay::switchToTimeshift()
@@ -2277,36 +2378,25 @@ void eDVBServicePlay::switchToTimeshift()
        if (m_timeshift_active)
                return;
 
-       m_decode_demux = 0;
-       m_decoder = 0;
-       m_teletext_parser = 0;
-       m_rds_decoder = 0;
-       m_subtitle_parser = 0;
-       m_new_subtitle_page_connection = 0;
-       m_new_dvb_subtitle_page_connection = 0;
-       m_rds_decoder_event_connection = 0;
-       m_video_event_connection = 0;
-
-       m_timeshift_active = 1;
-       m_timeshift_changed = 1;
+       resetTimeshift(1);
 
        eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
        r.path = m_timeshift_file;
 
-       m_cue = new eCueSheet();
        m_cue->seekTo(0, -1000);
-       m_service_handler_timeshift.tune(r, 1, m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+       ePtr<iTsSource> source = createTsSource(r);
+       m_service_handler_timeshift.tuneExt(r, 1, source, m_timeshift_file.c_str(), m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
 
        eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
        pause();
-       updateDecoder(); /* mainly to switch off PCR, and to set pause */
-
-       m_event((iPlayableService*)this, evSeekableStatusChanged);
+       updateDecoder(true); /* mainly to switch off PCR, and to set pause */
 }
 
-void eDVBServicePlay::updateDecoder()
+void eDVBServicePlay::updateDecoder(bool sendSeekableStateChanged)
 {
        int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
+       bool mustPlay = false;
 
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 
@@ -2315,7 +2405,7 @@ void eDVBServicePlay::updateDecoder()
                eDebug("getting program info failed.");
        else
        {
-               eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
+               eDebugNoNewLine("have %zd video stream(s)", program.videoStreams.size());
                if (!program.videoStreams.empty())
                {
                        eDebugNoNewLine(" (");
@@ -2334,7 +2424,7 @@ void eDVBServicePlay::updateDecoder()
                        }
                        eDebugNoNewLine(")");
                }
-               eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
+               eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size());
                if (!program.audioStreams.empty())
                {
                        eDebugNoNewLine(" (");
@@ -2357,8 +2447,6 @@ void eDVBServicePlay::updateDecoder()
        if (!m_decoder)
        {
                h.getDecodeDemux(m_decode_demux);
-               if (m_timeshift_changed)
-                       m_decoder = 0;
                if (m_decode_demux)
                {
                        m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
@@ -2387,17 +2475,17 @@ void eDVBServicePlay::updateDecoder()
                                        Py_DECREF(subs);
                                }
                        }
-                       m_decoder->play(); /* pids will be set later */
                }
                if (m_cue)
                        m_cue->setDecodingDemux(m_decode_demux, m_decoder);
-               m_decoder->play(); /* pids will be set later. */
+               mustPlay = true;
        }
 
        m_timeshift_changed = 0;
 
        if (m_decoder)
        {
+               bool wasSeekable = m_decoder->getVideoProgressive() != -1;
                if (m_dvb_service)
                {
                        achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
@@ -2456,7 +2544,11 @@ void eDVBServicePlay::updateDecoder()
                                m_decoder->setRadioPic(radio_pic);
                }
 
-               m_decoder->set();
+               if (mustPlay)
+                       m_decoder->play();
+               else
+                       m_decoder->set();
+
                m_decoder->setAudioChannel(achannel);
 
                /* don't worry about non-existing services, nor pvr services */
@@ -2468,8 +2560,13 @@ void eDVBServicePlay::updateDecoder()
                        m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
                        m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
                }
+               if (!sendSeekableStateChanged && (m_decoder->getVideoProgressive() != -1) != wasSeekable)
+                       sendSeekableStateChanged = true;
        }
        m_have_video_pid = (vpid > 0 && vpid < 0x2000);
+
+       if (sendSeekableStateChanged)
+               m_event((iPlayableService*)this, evSeekableStatusChanged);
 }
 
 void eDVBServicePlay::loadCuesheet()
@@ -2504,7 +2601,7 @@ void eDVBServicePlay::loadCuesheet()
                        m_cue_entries.insert(cueEntry(where, what));
                }
                fclose(f);
-               eDebug("%d entries", m_cue_entries.size());
+               eDebug("%zd entries", m_cue_entries.size());
        } else
                eDebug("cutfile not found!");
        
@@ -2570,7 +2667,7 @@ void eDVBServicePlay::cutlistToCuesheet()
        {
                if (i == m_cue_entries.end())
                {
-                       if (!have_any_span)
+                       if (!have_any_span && !in)
                                break;
                        out = length;
                } else {
@@ -2600,6 +2697,7 @@ void eDVBServicePlay::cutlistToCuesheet()
                {
                        have_any_span = 1;
                        m_cue->addSourceSpan(in, out);
+                       in = out = 0;
                }
                
                in = length;