add iCueSheet interface and null implementation
[enigma2.git] / lib / service / servicedvb.cpp
index 827b7f362702ec89f734852ded841dd453c0ad4b..76abbd3805120669c331898da1420e9ff533d08d 100644 (file)
 #include <lib/dvb/tstools.h>
 #include <lib/python/python.h>
 
+#include <sys/vfs.h>
+
+#define TSPATH "/media/hdd"
+
 class eStaticServiceDVBInformation: public iStaticServiceInformation
 {
        DECLARE_REF(eStaticServiceDVBInformation);
@@ -526,6 +530,7 @@ eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *serv
 {
        m_is_pvr = !ref.path.empty();
        m_timeshift_enabled = m_timeshift_active = 0;
+       m_skipmode = 0;
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
        CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
@@ -590,10 +595,11 @@ void eDVBServicePlay::serviceEvent(int event)
                break;
        }
        case eDVBServicePMTHandler::eventEOF:
-       {
-               m_event((iPlayableService*)this, evEnd);
+               m_event((iPlayableService*)this, evEOF);
+               break;
+       case eDVBServicePMTHandler::eventSOF:
+               m_event((iPlayableService*)this, evSOF);
                break;
-       }
        }
 }
 
@@ -617,7 +623,8 @@ RESULT eDVBServicePlay::start()
                /* in pvr mode, we only want to use one demux. in tv mode, we're using 
                   two (one for decoding, one for data source), as we must be prepared
                   to start recording from the data demux. */
-       r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr);
+       m_cue = new eCueSheet();
+       r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr, m_cue);
        m_event(this, evStart);
        m_event((iPlayableService*)this, evSeekableStatusChanged);
        return 0;
@@ -625,6 +632,15 @@ RESULT eDVBServicePlay::start()
 
 RESULT eDVBServicePlay::stop()
 {
+       eDebug("stop timeshift");
+       stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
+       
+       eDebug("free ts handler");
+       m_service_handler_timeshift.free();
+       eDebug("stop service handler");
+       m_service_handler.free();
+       eDebug("ok");
+       
        return 0;
 }
 
@@ -659,15 +675,44 @@ RESULT eDVBServicePlay::setSlowMotion(int ratio)
 
 RESULT eDVBServicePlay::setFastForward(int ratio)
 {
-       if (m_decoder)
-               return m_decoder->setFastForward(ratio);
-       else
+       int skipmode, ffratio;
+       
+       if (ratio > 8)
+       {
+               skipmode = ratio;
+               ffratio = 1;
+       } else if (ratio > 0)
+       {
+               skipmode = 0;
+               ffratio = ratio;
+       } else if (!ratio)
+       {
+               skipmode = 0;
+               ffratio = 0;
+       } else // if (ratio < 0)
+       {
+               skipmode = ratio;
+               ffratio = 1;
+       }
+
+       if (m_skipmode != skipmode)
+       {
+               eDebug("setting cue skipmode to %d", skipmode);
+               if (m_cue)
+                       m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
+       }
+       
+       m_skipmode = skipmode;
+       
+       if (!m_decoder)
                return -1;
+
+       return m_decoder->setFastForward(ffratio);
 }
     
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
 {
-       if (m_is_pvr || m_timeshift_active)
+       if (m_is_pvr || m_timeshift_enabled)
        {
                ptr = this;
                return 0;
@@ -677,15 +722,13 @@ RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
        return -1;
 }
 
+       /* TODO: when timeshift is enabled but not active, this doesn't work. */
 RESULT eDVBServicePlay::getLength(pts_t &len)
 {
        ePtr<iDVBPVRChannel> pvr_channel;
        
-       if (m_service_handler.getPVRChannel(pvr_channel))
-       {
-               eDebug("getPVRChannel failed!");
+       if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
                return -1;
-       }
        
        return pvr_channel->getLength(len);
 }
@@ -722,7 +765,11 @@ RESULT eDVBServicePlay::seekTo(pts_t to)
        if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
                return -1;
        
-       return pvr_channel->seekTo(m_decode_demux, 0, to);
+       if (!m_cue)
+               return -1;
+       
+       m_cue->seekTo(0, to);
+       return 0;
 }
 
 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
@@ -739,7 +786,11 @@ RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
        
        to *= direction;
        
-       return pvr_channel->seekTo(m_decode_demux, 1, to);
+       if (!m_cue)
+               return 0;
+       
+       m_cue->seekTo(1, to);
+       return 0;
 }
 
 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
@@ -762,6 +813,11 @@ RESULT eDVBServicePlay::setTrickmode(int trick)
        return 0;
 }
 
+RESULT eDVBServicePlay::isCurrentlySeekable()
+{
+       return m_is_pvr || m_timeshift_active;
+}
+
 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
 {
        ptr = this;
@@ -788,7 +844,34 @@ RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
 
 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
 {
+       ptr = 0;
        if (m_timeshift_enabled || !m_is_pvr)
+       {
+               if (!m_timeshift_enabled)
+               {
+                               /* we need enough diskspace */
+                       struct statfs fs;
+                       if (statfs(TSPATH "/.", &fs) < 0)
+                       {
+                               eDebug("statfs failed!");
+                               return -2;
+                       }
+               
+                       if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
+                       {
+                               eDebug("not enough diskspace for timeshift! (less than 1GB)");
+                               return -3;
+                       }
+               }
+               ptr = this;
+               return 0;
+       }
+       return -1;
+}
+
+RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
+{
+       if (m_is_pvr)
        {
                ptr = this;
                return 0;
@@ -1036,7 +1119,7 @@ RESULT eDVBServicePlay::startTimeshift()
        if (!m_record)
                return -3;
 
-       char templ[]="/media/hdd/timeshift.XXXXXX";
+       char templ[]=TSPATH "/timeshift.XXXXXX";
        m_timeshift_fd = mkstemp(templ);
        m_timeshift_file = templ;
        
@@ -1071,6 +1154,7 @@ RESULT eDVBServicePlay::stopTimeshift()
        m_record = 0;
        
        close(m_timeshift_fd);
+       eDebug("remove timeshift file");
        remove(m_timeshift_file.c_str());
        
        return 0;
@@ -1095,6 +1179,23 @@ RESULT eDVBServicePlay::activateTimeshift()
        return -2;
 }
 
+PyObject *eDVBServicePlay::getCutList()
+{
+       PyObject *list = PyList_New(0);
+       
+       return list;
+}
+
+RESULT eDVBServicePlay::addCut(const pts_t &when, int what)
+{
+       return -1;
+}
+
+RESULT eDVBServicePlay::removeCut(const pts_t &when, int what)
+{
+       return -1;
+}
+
 void eDVBServicePlay::updateTimeshiftPids()
 {
        if (!m_record)
@@ -1174,7 +1275,7 @@ void eDVBServicePlay::switchToTimeshift()
        eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
        r.path = m_timeshift_file;
        
-       m_service_handler_timeshift.tune(r, 1); /* use the decoder demux for everything */
+       m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
 }
 
 void eDVBServicePlay::updateDecoder()
@@ -1233,6 +1334,8 @@ void eDVBServicePlay::updateDecoder()
                h.getDecodeDemux(m_decode_demux);
                if (m_decode_demux)
                        m_decode_demux->getMPEGDecoder(m_decoder);
+               if (m_cue)
+                       m_cue->setDecodingDemux(m_decode_demux);
        }
 
        if (m_decoder)