Merge branch 'bug_352_fix_some_cutlist_bugs'
authorghost <andreas.monzner@multimedia-labs.de>
Wed, 23 Dec 2009 15:21:59 +0000 (16:21 +0100)
committerghost <andreas.monzner@multimedia-labs.de>
Wed, 23 Dec 2009 15:21:59 +0000 (16:21 +0100)
1  2 
lib/dvb/dvb.cpp
lib/python/Plugins/Extensions/CutListEditor/plugin.py
lib/service/servicedvb.cpp

diff --combined lib/dvb/dvb.cpp
@@@ -1462,7 -1462,12 +1462,7 @@@ void eDVBChannel::getNextSourceSpan(off
                        continue;
                }
                
 -              size_t iframe_len;
 -                      /* try to align to iframe */
 -              int direction = pts < 0 ? -1 : 1;
 -              m_tstools.findFrame(offset, iframe_len, direction);
 -
 -              eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx (skipped additional %d frames due to iframe re-align)", relative, pts, offset, direction);
 +              eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
                current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
        }
  
@@@ -1766,6 -1771,8 +1766,8 @@@ RESULT eDVBChannel::playFile(const cha
        m_pvr_thread->setStreamMode(1);
        m_pvr_thread->setScatterGather(this);
  
+       m_event(this, evtPreStart);
        if (m_pvr_thread->start(file, m_pvr_fd_dst))
        {
                delete m_pvr_thread;
@@@ -7,7 -7,6 +7,7 @@@ from Components.ActionMap import Helpab
  from Components.MultiContent import MultiContentEntryText
  from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
  from Components.VideoWindow import VideoWindow
 +from Components.Label import Label
  from Screens.InfoBarGenerics import InfoBarSeek, InfoBarCueSheetSupport
  from Components.GUIComponent import GUIComponent
  from enigma import eListboxPythonMultiContent, eListbox, gFont, iPlayableService, RT_HALIGN_RIGHT
@@@ -120,13 -119,12 +120,13 @@@ class CutListEditor(Screen, InfoBarBase
                <widget source="session.CurrentService" render="Label" position="135,405" size="450,50" font="Regular;22" halign="center" valign="center">
                        <convert type="ServiceName">Name</convert>
                </widget>
 -              <widget source="session.CurrentService" render="Label" position="50,450" zPosition="1" size="620,25" font="Regular;20" halign="center" valign="center">
 +              <widget source="session.CurrentService" render="Label" position="320,450" zPosition="1" size="420,25" font="Regular;20" halign="left" valign="center">
                        <convert type="ServicePosition">Position,Detailed</convert>
                </widget>
 -              <eLabel position="62,98" size="179,274" backgroundColor="#505555" />
 -              <eLabel position="64,100" size="175,270" backgroundColor="#000000" />
 -              <widget source="cutlist" position="64,100" zPosition="1" size="175,270" scrollbarMode="showOnDemand" transparent="1" render="Listbox" >
 +              <widget name="SeekState" position="210,450" zPosition="1" size="100,25" halign="right" font="Regular;20" valign="center" />
 +              <eLabel position="48,98" size="204,274" backgroundColor="#505555" />
 +              <eLabel position="50,100" size="200,270" backgroundColor="#000000" />
 +              <widget source="cutlist" position="50,100" zPosition="1" size="200,270" scrollbarMode="showOnDemand" transparent="1" render="Listbox" >
                        <convert type="TemplatedMultiContent">
                                {"template": [
                                                MultiContentEntryText(size=(125, 20), text = 1, backcolor = MultiContentTemplateColor(3)),
                self["Timeline"] = ServicePositionGauge(self.session.nav)
                self["cutlist"] = List(self.getCutlist())
                self["cutlist"].onSelectionChanged.append(self.selectionChanged)
 +              self["SeekState"] = Label()
 +              self.onPlayStateChanged.append(self.updateStateLabel)
 +              self.updateStateLabel(self.seekstate)
  
                self["Video"] = VideoWindow(decoder = 0)
  
                        })
  
                # to track new entries we save the last version of the cutlist
 -              self.last_cuts = [ ]
 +              self.last_cuts = self.getCutlist()
                self.cut_start = None
 +              self.inhibit_seek = False
                self.onClose.append(self.__onClose)
  
        def __onClose(self):
-               self.session.nav.playService(self.old_service)
+               self.session.nav.playService(self.old_service, forceRestart=True)
  
 +      def updateStateLabel(self, state):
 +              self["SeekState"].setText(state[3].strip())
 +
        def showTutorial(self):
                if not self.tutorial_seen:
                        self.tutorial_seen = True
                return r
  
        def selectionChanged(self):
 -              where = self["cutlist"].getCurrent()
 -              if where is None:
 -                      print "no selection"
 -                      return
 -              pts = where[0][0]
 -              seek = self.getSeek()
 -              if seek is None:
 -                      print "no seek"
 -                      return
 -              seek.seekTo(pts)
 +              if not self.inhibit_seek:
 +                      where = self["cutlist"].getCurrent()
 +                      if where is None:
 +                              print "no selection"
 +                              return
 +                      pts = where[0][0]
 +                      seek = self.getSeek()
 +                      if seek is None:
 +                              print "no seek"
 +                              return
 +                      seek.seekTo(pts)
  
        def refillList(self):
                print "cue sheet changed, refilling"
                self.downloadCuesheet()
  
 -              # get the first changed entry, and select it
 +              # get the first changed entry, counted from the end, and select it
                new_list = self.getCutlist()
                self["cutlist"].list = new_list
  
 -              for i in range(min(len(new_list), len(self.last_cuts))):
 -                      if new_list[i] != self.last_cuts[i]:
 -                              self["cutlist"].setIndex(i)
 +              l1 = len(new_list)
 +              l2 = len(self.last_cuts)
 +              for i in range(min(l1, l2)):
 +                      if new_list[l1-i-1] != self.last_cuts[l2-i-1]:
 +                              self["cutlist"].setIndex(l1-i-1)
                                break
                self.last_cuts = new_list
  
        def getStateForPosition(self, pos):
 -              state = 0 # in
 -
 -              # when first point is "in", the beginning is "out"
 -              if len(self.cut_list) and self.cut_list[0][1] == 0:
 -                      state = 1
 -
 +              state = -1
                for (where, what) in self.cut_list:
 -                      if where < pos:
 -                              if what == 0: # in
 -                                      state = 0
 -                              elif what == 1: # out
 +                      if what in [0, 1]:
 +                              if where < pos:
 +                                      state = what
 +                              elif where == pos:
                                        state = 1
 +                              elif state == -1:
 +                                      state = 1 - what
 +              if state == -1:
 +                      state = 0
                return state
  
        def showMenu(self):
                        in_after = None
  
                        for (where, what) in self.cut_list:
 -                              if what == 1 and where < self.context_position: # out
 +                              if what == 1 and where <= self.context_position: # out
                                        out_before = (where, what)
                                elif what == 0 and where < self.context_position: # in, before out
                                        out_before = None
 -                              elif what == 0 and where > self.context_position and in_after is None:
 +                              elif what == 0 and where >= self.context_position and in_after is None:
                                        in_after = (where, what)
  
                        if out_before is not None:
  
                        if in_after is not None:
                                self.cut_list.remove(in_after)
 +                      self.inhibit_seek = True
                        self.uploadCuesheet()
 +                      self.inhibit_seek = False
                elif result == CutListContextMenu.RET_MARK:
                        self.__addMark()
                elif result == CutListContextMenu.RET_DELETEMARK:
                        self.cut_list.remove(self.context_nearest_mark)
 +                      self.inhibit_seek = True
                        self.uploadCuesheet()
 +                      self.inhibit_seek = False
                elif result == CutListContextMenu.RET_REMOVEBEFORE:
                        # remove in/out marks before current position
                        for (where, what) in self.cut_list[:]:
                                        self.cut_list.remove((where, what))
                        # add 'in' point
                        bisect.insort(self.cut_list, (self.context_position, 0))
 +                      self.inhibit_seek = True
                        self.uploadCuesheet()
 +                      self.inhibit_seek = False
                elif result == CutListContextMenu.RET_REMOVEAFTER:
                        # remove in/out marks after current position
                        for (where, what) in self.cut_list[:]:
                                        self.cut_list.remove((where, what))
                        # add 'out' point
                        bisect.insort(self.cut_list, (self.context_position, 1))
 +                      self.inhibit_seek = True
                        self.uploadCuesheet()
 +                      self.inhibit_seek = False
                elif result == CutListContextMenu.RET_GRABFRAME:
                        self.grabFrame()
  
@@@ -917,7 -917,7 +917,7 @@@ eDVBServicePlay::eDVBServicePlay(const 
        m_is_pvr = !m_reference.path.empty();
        
        m_timeshift_enabled = m_timeshift_active = 0, m_timeshift_changed = 0;
 -      m_skipmode = 0;
 +      m_skipmode = m_fastforward = m_slowmotion = 0;
        
        CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
        CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
@@@ -1029,6 -1029,9 +1029,9 @@@ void eDVBServicePlay::serviceEvent(int 
                m_event((iPlayableService*)this, evUpdatedInfo);
                break;
        }
+       case eDVBServicePMTHandler::eventPreStart:
+               loadCuesheet();
+               break;
        case eDVBServicePMTHandler::eventEOF:
                m_event((iPlayableService*)this, evEOF);
                break;
@@@ -1095,7 -1098,6 +1098,6 @@@ RESULT eDVBServicePlay::start(
                        m_event_handler.inject(event, 0);
                        m_event_handler.inject(empty, 1);
                }
-               loadCuesheet();
                m_event(this, evStart);
        }
        return 0;
@@@ -1185,10 -1187,7 +1187,10 @@@ RESULT eDVBServicePlay::setSlowMotion(i
        eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
        setFastForward_internal(0);
        if (m_decoder)
 +      {
 +              m_slowmotion = ratio;
                return m_decoder->setSlowMotion(ratio);
 +      }
        else
                return -1;
  }
@@@ -1200,11 -1199,10 +1202,11 @@@ RESULT eDVBServicePlay::setFastForward(
        return setFastForward_internal(ratio);
  }
  
 -RESULT eDVBServicePlay::setFastForward_internal(int ratio)
 +RESULT eDVBServicePlay::setFastForward_internal(int ratio, bool final_seek)
  {
 -      int skipmode, ffratio;
 -      
 +      int skipmode, ffratio, ret = 0;
 +      pts_t pos=0;
 +
        if (ratio > 8)
        {
                skipmode = ratio;
                if (m_cue)
                        m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
        }
 -      
 +
        m_skipmode = skipmode;
 -      
 +
 +      if (final_seek)
 +              eDebug("trickplay stopped .. ret %d, pos %lld", getPlayPosition(pos), pos);
 +
 +      m_fastforward = ffratio;
 +
        if (!m_decoder)
                return -1;
 -              
 +
        if (ffratio == 0)
                ; /* return m_decoder->play(); is done in caller*/
        else if (ffratio != 1)
 -              return m_decoder->setFastForward(ffratio);
 +              ret = m_decoder->setFastForward(ffratio);
        else
 -              return m_decoder->setTrickmode();
 -      return 0;
 +              ret = m_decoder->setTrickmode();
 +
 +      if (pos)
 +              eDebug("final seek after trickplay ret %d", seekTo(pos));
 +
 +      return ret;
  }
  
  RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
@@@ -1279,10 -1268,9 +1281,10 @@@ RESULT eDVBServicePlay::getLength(pts_
  RESULT eDVBServicePlay::pause()
  {
        eDebug("eDVBServicePlay::pause");
 -      setFastForward_internal(0);
 +      setFastForward_internal(0, m_slowmotion || m_fastforward > 1);
        if (m_decoder)
        {
 +              m_slowmotion = 0;
                m_is_paused = 1;
                return m_decoder->pause();
        } else
  RESULT eDVBServicePlay::unpause()
  {
        eDebug("eDVBServicePlay::unpause");
 -      setFastForward_internal(0);
 +      setFastForward_internal(0, m_slowmotion || m_fastforward > 1);
        if (m_decoder)
        {
 +              m_slowmotion = 0;
                m_is_paused = 0;
                return m_decoder->play();
        } else
@@@ -1743,7 -1730,6 +1745,7 @@@ int eDVBServicePlay::selectAudioStream(
  {
        eDVBServicePMTHandler::program program;
        eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
 +      pts_t position = -1;
  
        if (h.getProgramInfo(program))
                return -1;
                apidtype = program.audioStreams[stream].type;
        }
  
 +      if (i != -1 && apid != m_current_audio_pid && (m_is_pvr || m_timeshift_active))
 +              eDebug("getPlayPosition ret %d, pos %lld in selectAudioStream", getPlayPosition(position), position);
 +
        m_current_audio_pid = apid;
  
        if (m_is_primary && m_decoder->setAudioPID(apid, apidtype))
                return -4;
        }
  
 +      if (position != -1)
 +              eDebug("seekTo ret %d", seekTo(position));
 +
        int rdsPid = apid;
  
                /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */
@@@ -2251,7 -2231,7 +2253,7 @@@ void eDVBServicePlay::switchToLive(
        m_new_subtitle_page_connection = 0;
        m_rds_decoder_event_connection = 0;
        m_video_event_connection = 0;
 -      m_is_paused = m_skipmode = 0; /* not supported in live mode */
 +      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();
@@@ -2285,13 -2265,12 +2287,13 @@@ void eDVBServicePlay::switchToTimeshift
        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 */
  
        eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
        pause();
        updateDecoder(); /* mainly to switch off PCR, and to set pause */
 -      
 +
        m_event((iPlayableService*)this, evSeekableStatusChanged);
  }
  
@@@ -2421,8 -2400,17 +2423,8 @@@ void eDVBServicePlay::updateDecoder(
                        }
                }
  
 -              std::string config_delay;
 -              int config_delay_int = 0;
 -              if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
 -                      config_delay_int = atoi(config_delay.c_str());
 -              m_decoder->setAC3Delay(ac3_delay == -1 ? config_delay_int : ac3_delay + config_delay_int);
 -
 -              if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
 -                      config_delay_int = atoi(config_delay.c_str());
 -              else
 -                      config_delay_int = 0;
 -              m_decoder->setPCMDelay(pcm_delay == -1 ? config_delay_int : pcm_delay + config_delay_int);
 +              setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
 +              setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
  
                m_decoder->setVideoPID(vpid, vpidtype);
                selectAudioStream();
@@@ -2946,28 -2934,16 +2948,28 @@@ void eDVBServicePlay::setAC3Delay(int d
  {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
 -      if (m_decoder)
 -              m_decoder->setAC3Delay(delay);
 +      if (m_decoder) {
 +              std::string config_delay;
 +              int config_delay_int = 0;
 +              if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
 +                      config_delay_int = atoi(config_delay.c_str());
 +              m_decoder->setAC3Delay(delay + config_delay_int);
 +      }
  }
  
  void eDVBServicePlay::setPCMDelay(int delay)
  {
        if (m_dvb_service)
                m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
 -      if (m_decoder)
 -              m_decoder->setPCMDelay(delay);
 +      if (m_decoder) {
 +              std::string config_delay;
 +              int config_delay_int = 0;
 +              if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
 +                      config_delay_int = atoi(config_delay.c_str());
 +              else
 +                      config_delay_int = 0;
 +              m_decoder->setPCMDelay(delay + config_delay_int);
 +      }
  }
  
  void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)