Merge branch 'master' of /home/tmbinc/enigma2-git into tmbinc/FixTimingBugs
authorFelix Domke <tmbinc@elitedvb.net>
Fri, 13 Feb 2009 02:47:44 +0000 (03:47 +0100)
committerFelix Domke <tmbinc@elitedvb.net>
Fri, 13 Feb 2009 02:47:44 +0000 (03:47 +0100)
Conflicts:

lib/python/Screens/InfoBarGenerics.py

22 files changed:
lib/base/filepush.cpp
lib/dvb/decoder.cpp
lib/dvb/decoder.h
lib/dvb/demux.cpp
lib/dvb/demux.h
lib/dvb/dvb.cpp
lib/dvb/idemux.h
lib/dvb/idvb.h
lib/dvb/pvrparse.cpp
lib/dvb/pvrparse.h
lib/dvb/tstools.cpp
lib/dvb/tstools.h
lib/gui/epositiongauge.cpp
lib/python/Components/Converter/StringList.py
lib/python/Components/Network.py
lib/python/Components/Renderer/FrontpanelLed.py
lib/python/Components/Renderer/Listbox.py
lib/python/Screens/InfoBarGenerics.py
lib/service/iservice.h
lib/service/servicedvb.cpp
lib/service/servicedvb.h
lib/service/servicedvbrecord.cpp

index 1999707..e99e956 100644 (file)
@@ -260,12 +260,9 @@ void eFilePushThread::stop()
        // fixmee.. here we need a better solution to ensure
        // that the thread context take notice of the signal
        // even when no syscall is in progress
-       while(!sendSignal(SIGUSR1))
-       {
-               eDebug("send SIGUSR1 to thread context");
-               usleep(5000); // wait msek
-       }
-       kill();
+       eDebug("if enigma hangs here, the filepush thread is non-responsive. FIX THAT DAMN THREAD.");
+       sendSignal(SIGUSR1);
+       kill(0);
 }
 
 void eFilePushThread::pause()
index 065a49c..a4cffb7 100644 (file)
@@ -39,7 +39,7 @@
 DEFINE_REF(eDVBAudio);
 
 eDVBAudio::eDVBAudio(eDVBDemux *demux, int dev)
-       :m_demux(demux), m_dev(dev), m_is_freezed(0)
+       :m_demux(demux), m_dev(dev)
 {
        char filename[128];
 #if HAVE_DVB_API_VERSION < 3
@@ -198,7 +198,7 @@ int eDVBAudio::startPid(int pid, int type)
                break;
        }
 
-       eDebugNoNewLine("AUDIO_SET_BYPASS - ");
+       eDebugNoNewLine("AUDIO_SET_BYPASS(%d) - ", bypass);
        if (::ioctl(m_fd, AUDIO_SET_BYPASS_MODE, bypass) < 0)
                eDebug("failed (%m)");
        else
@@ -244,28 +244,20 @@ void eDVBAudio::flush()
 
 void eDVBAudio::freeze()
 {
-       if (!m_is_freezed)
-       {
-               eDebugNoNewLine("AUDIO_PAUSE - ");
-               if (::ioctl(m_fd, AUDIO_PAUSE) < 0)
-                       eDebug("failed (%m)");
-               else
-                       eDebug("ok");
-               m_is_freezed=1;
-       }
+       eDebugNoNewLine("AUDIO_PAUSE - ");
+       if (::ioctl(m_fd, AUDIO_PAUSE) < 0)
+               eDebug("failed (%m)");
+       else
+               eDebug("ok");
 }
 
 void eDVBAudio::unfreeze()
 {
-       if (m_is_freezed)
-       {
-               eDebugNoNewLine("AUDIO_CONTINUE - ");
-               if (::ioctl(m_fd, AUDIO_CONTINUE) < 0)
-                       eDebug("failed (%m)");
-               else
-                       eDebug("ok");
-               m_is_freezed=0;
-       }
+       eDebugNoNewLine("AUDIO_CONTINUE - ");
+       if (::ioctl(m_fd, AUDIO_CONTINUE) < 0)
+               eDebug("failed (%m)");
+       else
+               eDebug("ok");
 }
 
 void eDVBAudio::setChannel(int channel)
@@ -303,8 +295,8 @@ eDVBAudio::~eDVBAudio()
 DEFINE_REF(eDVBVideo);
 
 eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev)
-       :m_demux(demux), m_dev(dev), m_is_slow_motion(0), m_is_fast_forward(0), m_is_freezed(0)
-       ,m_width(-1), m_height(-1), m_framerate(-1), m_aspect(-1), m_progressive(-1)
+       : m_demux(demux), m_dev(dev),
+       m_width(-1), m_height(-1), m_framerate(-1), m_aspect(-1), m_progressive(-1)
 {
        char filename[128];
 #if HAVE_DVB_API_VERSION < 3
@@ -493,34 +485,25 @@ void eDVBVideo::flush()
 
 void eDVBVideo::freeze()
 {
-       if (!m_is_freezed)
-       {
-               eDebugNoNewLine("VIDEO_FREEZE - ");
-               if (::ioctl(m_fd, VIDEO_FREEZE) < 0)
-                       eDebug("failed (%m)");
-               else
-                       eDebug("ok");
-               m_is_freezed=1;
-       }
+       eDebugNoNewLine("VIDEO_FREEZE - ");
+       if (::ioctl(m_fd, VIDEO_FREEZE) < 0)
+               eDebug("failed (%m)");
+       else
+               eDebug("ok");
 }
 
 void eDVBVideo::unfreeze()
 {
-       if (m_is_freezed)
-       {
-               eDebugNoNewLine("VIDEO_CONTINUE - ");
-               if (::ioctl(m_fd, VIDEO_CONTINUE) < 0)
-                       eDebug("failed (%m)");
-               else
-                       eDebug("ok");
-               m_is_freezed=0;
-       }
+       eDebugNoNewLine("VIDEO_CONTINUE - ");
+       if (::ioctl(m_fd, VIDEO_CONTINUE) < 0)
+               eDebug("failed (%m)");
+       else
+               eDebug("ok");
 }
 
 int eDVBVideo::setSlowMotion(int repeat)
 {
-       eDebugNoNewLine("VIDEO_SLOWMOTION - ");
-       m_is_slow_motion = repeat;
+       eDebugNoNewLine("VIDEO_SLOWMOTION(%d) - ", repeat);
        int ret = ::ioctl(m_fd, VIDEO_SLOWMOTION, repeat);
        if (ret < 0)
                eDebug("failed(%m)");
@@ -531,8 +514,7 @@ int eDVBVideo::setSlowMotion(int repeat)
 
 int eDVBVideo::setFastForward(int skip)
 {
-       eDebugNoNewLine("VIDEO_FAST_FORWARD - ");
-       m_is_fast_forward = skip;
+       eDebugNoNewLine("VIDEO_FAST_FORWARD(%d) - ", skip);
        int ret = ::ioctl(m_fd, VIDEO_FAST_FORWARD, skip);
        if (ret < 0)
                eDebug("failed(%m)");
@@ -559,11 +541,6 @@ int eDVBVideo::getPTS(pts_t &now)
 
 eDVBVideo::~eDVBVideo()
 {
-       if (m_is_slow_motion)
-               setSlowMotion(0);
-       if (m_is_fast_forward)
-               setFastForward(0);
-       unfreeze();
        if (m_fd >= 0)
                ::close(m_fd);
        if (m_fd_demux >= 0)
@@ -869,14 +846,14 @@ int eTSMPEGDecoder::setState()
 {
        int res = 0;
 
-       int noaudio = m_is_sm || m_is_ff || m_is_trickmode;
+       int noaudio = (m_state != statePlay) && (m_state != statePause);
        int nott = noaudio; /* actually same conditions */
 
        if ((noaudio && m_audio) || (!m_audio && !noaudio))
-               m_changed |= changeAudio;
+               m_changed |= changeAudio | changeState;
 
        if ((nott && m_text) || (!m_text && !nott))
-               m_changed |= changeText;
+               m_changed |= changeText | changeState;
 
        bool changed = !!m_changed;
 #if HAVE_DVB_API_VERSION < 3
@@ -1019,6 +996,39 @@ int eTSMPEGDecoder::setState()
                m_changed &= ~changeText;
        }
 #endif
+
+       if (m_changed & changeState)
+       {
+                                       /* play, slowmotion, fast-forward */
+               int state_table[6][4] = 
+                       {
+                               /* [stateStop] =                 */ {0, 0, 0},
+                               /* [statePause] =                */ {0, 0, 0},
+                               /* [statePlay] =                 */ {1, 0, 0},
+                               /* [stateDecoderFastForward] =   */ {1, 0, m_ff_sm_ratio},
+                               /* [stateHighspeedFastForward] = */ {1, 0, 1},
+                               /* [stateSlowMotion] =           */ {1, m_ff_sm_ratio, 0}
+                       };
+               int *s = state_table[m_state];
+               if (m_video)
+               {
+                       m_video->setSlowMotion(s[1]);
+                       m_video->setFastForward(s[2]);
+                       if (s[0])
+                               m_video->unfreeze();
+                       else
+                               m_video->freeze();
+               }
+               if (m_audio)
+               {
+                       if (s[0])
+                               m_audio->unfreeze();
+                       else
+                               m_audio->freeze();
+               }
+               m_changed &= ~changeState;
+       }
+
        if (changed && !m_video && m_audio && m_radio_pic.length())
                showSinglePic(m_radio_pic.c_str());
 
@@ -1061,11 +1071,13 @@ RESULT eTSMPEGDecoder::setAC3Delay(int delay)
 }
 
 eTSMPEGDecoder::eTSMPEGDecoder(eDVBDemux *demux, int decoder)
-       :m_demux(demux), m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp))
+       : m_demux(demux), 
+               m_vpid(-1), m_vtype(-1), m_apid(-1), m_atype(-1), m_pcrpid(-1), m_textpid(-1),
+               m_changed(0), m_decoder(decoder), m_video_clip_fd(-1), m_showSinglePicTimer(eTimer::create(eApp))
 {
        demux->connectEvent(slot(*this, &eTSMPEGDecoder::demux_event), m_demux_event_conn);
        CONNECT(m_showSinglePicTimer->timeout, eTSMPEGDecoder::finishShowSinglePic);
-       m_is_ff = m_is_sm = m_is_trickmode = 0;
+       m_state = stateStop;
 }
 
 eTSMPEGDecoder::~eTSMPEGDecoder()
@@ -1147,82 +1159,61 @@ RESULT eTSMPEGDecoder::setSyncMaster(int who)
        return -1;
 }
 
-RESULT eTSMPEGDecoder::start()
-{
-       RESULT r;
-       r = setState();
-       if (r)
-               return r;
-       return unfreeze();
-}
-
-       /* preroll is start in freezed mode. */
-RESULT eTSMPEGDecoder::preroll()
+RESULT eTSMPEGDecoder::set()
 {
        return setState();
 }
 
-RESULT eTSMPEGDecoder::freeze(int cont)
-{
-       if (m_video)
-               m_video->freeze();
-
-       if (m_audio)
-               m_audio->freeze();
-
-       return 0;
-}
-
-RESULT eTSMPEGDecoder::unfreeze()
+RESULT eTSMPEGDecoder::play()
 {
-       if (m_video)
-               m_video->unfreeze();
-
-       if (m_audio)
-               m_audio->unfreeze();
-
-       return 0;
-}
-
-RESULT eTSMPEGDecoder::setSinglePictureMode(int when)
-{
-       return -1;
+       if (m_state == statePlay)
+               return 0;
+       m_state = statePlay;
+       m_changed |= changeState;
+       return setState();
 }
 
-RESULT eTSMPEGDecoder::setPictureSkipMode(int what)
+RESULT eTSMPEGDecoder::pause()
 {
-       return -1;
+       if (m_state == statePause)
+               return 0;
+       m_state = statePause;
+       m_changed |= changeState;
+       return setState();
 }
 
 RESULT eTSMPEGDecoder::setFastForward(int frames_to_skip)
 {
-       m_is_ff = frames_to_skip != 0;
+       if ((m_state == stateDecoderFastForward) && (m_ff_sm_ratio == frames_to_skip))
+               return 0;
 
-       setState();
-       unfreeze(); // audio might be restarted and still in preroll (freezed) state.
+       m_state = stateDecoderFastForward;
+       m_ff_sm_ratio = frames_to_skip;
+       m_changed |= changeState;
+       return setState();
 
-       if (m_video)
-               return m_video->setFastForward(frames_to_skip);
-       else
-               return -1;
+//             return m_video->setFastForward(frames_to_skip);
 }
 
 RESULT eTSMPEGDecoder::setSlowMotion(int repeat)
 {
-       m_is_sm = repeat != 0;
-
-       setState();
-       unfreeze(); // audio might be restarted and still in preroll (freezed) state.
+       if ((m_state == stateSlowMotion) && (m_ff_sm_ratio == repeat))
+               return 0;
 
-       if (m_video)
-               return m_video->setSlowMotion(repeat);
-       else
-               return -1;
+       m_state = stateSlowMotion;
+       m_ff_sm_ratio = repeat;
+       m_changed |= changeState;
+       return setState();
 }
 
-RESULT eTSMPEGDecoder::setZoom(int what)
+RESULT eTSMPEGDecoder::setTrickmode()
 {
-       return -1;
+       if (m_state == stateTrickmode)
+               return 0;
+
+       m_state = stateTrickmode;
+       m_changed |= changeState;
+       return setState();
 }
 
 RESULT eTSMPEGDecoder::flush()
@@ -1246,13 +1237,6 @@ void eTSMPEGDecoder::demux_event(int event)
        }
 }
 
-RESULT eTSMPEGDecoder::setTrickmode(int what)
-{
-       m_is_trickmode = what;
-       setState();
-       return 0;
-}
-
 RESULT eTSMPEGDecoder::getPTS(int what, pts_t &pts)
 {
        if (what == 0) /* auto */
index f2e10bb..51be514 100644 (file)
@@ -125,10 +125,12 @@ private:
                changeVideo = 1, 
                changeAudio = 2, 
                changePCR   = 4,
-               changeText  = 8
+               changeText  = 8,
+               changeState = 16,
        };
        int m_changed, m_decoder;
-       int m_is_ff, m_is_sm, m_is_trickmode;
+       int m_state;
+       int m_ff_sm_ratio;
        int setState();
        ePtr<eConnection> m_demux_event_conn;
        ePtr<eConnection> m_video_event_conn;
@@ -154,17 +156,33 @@ public:
        RESULT setSyncPCR(int pcrpid);
        RESULT setTextPID(int textpid);
        RESULT setSyncMaster(int who);
-       RESULT start();
-       RESULT preroll();
-       RESULT freeze(int cont);
-       RESULT unfreeze();
-       RESULT setSinglePictureMode(int when);
-       RESULT setPictureSkipMode(int what);
-       RESULT setFastForward(int frames_to_skip);
-       RESULT setSlowMotion(int repeat);
-       RESULT setZoom(int what);
+       
+               /*
+               The following states exist:
+               
+                - stop: data source closed, no playback
+                - pause: data source active, decoder paused
+                - play: data source active, decoder consuming
+                - decoder fast forward: data source linear, decoder drops frames
+                - trickmode, highspeed reverse: data source fast forwards / reverses, decoder just displays frames as fast as it can
+                - slow motion: decoder displays frames multiple times
+               */
+       enum {
+               stateStop,
+               statePause,
+               statePlay,
+               stateDecoderFastForward,
+               stateTrickmode,
+               stateSlowMotion
+       };
+       RESULT set(); /* just apply settings, keep state */
+       RESULT play(); /* -> play */
+       RESULT pause(); /* -> pause */
+       RESULT setFastForward(int frames_to_skip); /* -> decoder fast forward */
+       RESULT setSlowMotion(int repeat); /* -> slow motion **/
+       RESULT setTrickmode(); /* -> highspeed fast forward */
+
        RESULT flush();
-       RESULT setTrickmode(int what);
        RESULT showSinglePic(const char *filename);
        RESULT setRadioPic(const std::string &filename);
                /* what 0=auto, 1=video, 2=audio. */
index 810b10a..918ecec 100644 (file)
@@ -402,9 +402,10 @@ class eDVBRecordFileThread: public eFilePushThread
 {
 public:
        eDVBRecordFileThread();
-       void setTimingPID(int pid);
+       void setTimingPID(int pid, int type);
        
-       void saveTimingInformation(const std::string &filename);
+       void startSaveMetaInformation(const std::string &filename);
+       void stopSaveMetaInformation();
        int getLastPTS(pts_t &pts);
 protected:
        int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
@@ -422,14 +423,19 @@ eDVBRecordFileThread::eDVBRecordFileThread()
        m_current_offset = 0;
 }
 
-void eDVBRecordFileThread::setTimingPID(int pid)
+void eDVBRecordFileThread::setTimingPID(int pid, int type)
 {
-       m_ts_parser.setPid(pid);
+       m_ts_parser.setPid(pid, type);
 }
 
-void eDVBRecordFileThread::saveTimingInformation(const std::string &filename)
+void eDVBRecordFileThread::startSaveMetaInformation(const std::string &filename)
 {
-       m_stream_info.save(filename.c_str());
+       m_stream_info.startSave(filename.c_str());
+}
+
+void eDVBRecordFileThread::stopSaveMetaInformation()
+{
+       m_stream_info.stopSave();
 }
 
 int eDVBRecordFileThread::getLastPTS(pts_t &pts)
@@ -520,6 +526,9 @@ RESULT eDVBTSRecorder::start()
        ::ioctl(m_source_fd, DMX_START);
        
 #endif
+
+       if (m_target_filename != "")
+               m_thread->startSaveMetaInformation(m_target_filename);
        
        m_thread->start(m_source_fd, m_target_fd);
        m_running = 1;
@@ -553,11 +562,11 @@ RESULT eDVBTSRecorder::removePID(int pid)
        return 0;
 }
 
-RESULT eDVBTSRecorder::setTimingPID(int pid)
+RESULT eDVBTSRecorder::setTimingPID(int pid, int type)
 {
        if (m_running)
                return -1;
-       m_thread->setTimingPID(pid);
+       m_thread->setTimingPID(pid, type);
        return 0;
 }
 
@@ -590,8 +599,7 @@ RESULT eDVBTSRecorder::stop()
        close(m_source_fd);
        m_source_fd = -1;
        
-       if (m_target_filename != "")
-               m_thread->saveTimingInformation(m_target_filename + ".ap");
+       m_thread->stopSaveMetaInformation();
        
        return 0;
 }
index 14501b9..7a697d4 100644 (file)
@@ -94,7 +94,7 @@ public:
        RESULT addPID(int pid);
        RESULT removePID(int pid);
        
-       RESULT setTimingPID(int pid);
+       RESULT setTimingPID(int pid, int type);
        
        RESULT setTargetFD(int fd);
        RESULT setTargetFilename(const char *filename);
index 2460943..4bbed51 100644 (file)
@@ -974,7 +974,7 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
        }
 #endif
 
-#if 1 /* not yet */
+#if 0
        if (!m_iframe_search)
                return len;
 
@@ -990,9 +990,9 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
                unsigned char *ts = data + ts_offset;
                int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
 
-               if ((d[3] == 0) && (m_pid == pid))  /* picture start */
+               if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid))  /* picture start */
                {
-                       int picture_type = (d[5] >> 3) & 7;
+                       int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
                        d += 4;
 
 //                     eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
@@ -1036,16 +1036,25 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
                        }
                } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
                {
-                       if (m_pid != pid)
+                               /* verify that this is actually a PES header, not just some ES data */
+                       if (ts[1] & 0x40) /* PUSI set */
                        {
-                               eDebug("now locked to pid %04x", pid);
-                               m_pid = pid;
+                               int payload_start = 4;
+                               if (ts[3] & 0x20) /* adaptation field present */
+                                       payload_start += ts[4] + 1; /* skip AF */
+                               if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
+                               {
+                                       if (m_pid != pid)
+                                       {
+                                               eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
+                                               m_pid = pid;
+                                       }
+                               }
                        }
 //                     m_pid = 0x6e;
                        d += 4;
                } else
                        d += 4; /* ignore */
-
        }
 
        if (m_iframe_state == 1)
@@ -1200,7 +1209,7 @@ void eDVBChannel::cueSheetEvent(int event)
                {
                        off_t offset_in, offset_out;
                        pts_t pts_in = i->first, pts_out = i->second;
-                       if (m_tstools.getOffset(offset_in, pts_in) || m_tstools.getOffset(offset_out, pts_out))
+                       if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
                        {
                                eDebug("span translation failed.\n");
                                continue;
@@ -1263,6 +1272,21 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
        eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
 
        current_offset += align(m_skipmode_m, blocksize);
+       
+       if (m_skipmode_m)
+       {
+               eDebug("we are at %llx, and we try to find the iframe here:", current_offset);
+               size_t iframe_len;
+               off_t iframe_start = current_offset;
+               
+               if (m_tstools.findIFrame(iframe_start, iframe_len, (m_skipmode_m < 0) ? -1 : +1))
+                       eDebug("failed");
+               else
+               {
+                       current_offset = align(iframe_start, blocksize);
+                       max = align(iframe_len, blocksize);
+               }
+       }
 
        while (!m_cue->m_seek_requests.empty())
        {
@@ -1328,17 +1352,21 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                eDebug("AP relative seeking failed!");
                        } else
                        {
-                               eDebug("next ap is %llx\n", pts);
                                pts = nextap;
+                               eDebug("next ap is %llx\n", pts);
                        }
                }
 
                off_t offset = 0;
-               if (m_tstools.getOffset(offset, pts))
+               if (m_tstools.getOffset(offset, pts, -1))
                {
                        eDebug("get offset for pts=%lld failed!", pts);
                        continue;
                }
+               
+               size_t iframe_len;
+                       /* try to align to iframe */
+               m_tstools.findIFrame(offset, iframe_len, pts < 0 ? -1 : 1);
 
                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 */
@@ -1415,10 +1443,16 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                m_pvr_thread->sendEvent(eFilePushThread::evtUser);
        }
 
-       start = current_offset;
-       size = max;
-
-       eDebug("END OF CUESHEET. (%08llx, %d)", start, size);
+       if (m_source_span.empty())
+       {
+               start = current_offset;
+               size = max;
+               eDebug("NO CUESHEET. (%08llx, %d)", start, size);
+       } else
+       {
+               start = current_offset;
+               size = 0;
+       }
        return;
 }
 
index 9432afb..e92b1e7 100644 (file)
@@ -30,7 +30,7 @@ public:
        virtual RESULT addPID(int pid) = 0;
        virtual RESULT removePID(int pid) = 0;
        
-       virtual RESULT setTimingPID(int pid) = 0;
+       virtual RESULT setTimingPID(int pid, int type) = 0;
        
        virtual RESULT setTargetFD(int fd) = 0;
                /* for saving additional meta data. */
index ec016d6..cfa98ec 100644 (file)
@@ -664,37 +664,24 @@ public:
                /** Set Sync mode to either audio or video master */
        virtual RESULT setSyncMaster(int who)=0;
 
-               /** Apply settings with starting video */
-       virtual RESULT start()=0;
-               /** Apply settings but don't start yet */
-       virtual RESULT preroll()=0;
+               /** Apply settings but don't change state */
+       virtual RESULT set()=0;
+               /* all those apply settings, then transition to the given state */
 
-               /** Freeze frame. Either continue decoding (without display) or halt. */
-       virtual RESULT freeze(int cont)=0;
-               /** Continue after freeze. */
-       virtual RESULT unfreeze()=0;
+               /** play */
+       virtual RESULT play()=0;
+               /** Freeze frame. */
+       virtual RESULT pause()=0;
 
                /** fast forward by skipping frames. 0 is disabled, 2 is twice-the-speed, ... */
        virtual RESULT setFastForward(int skip=0)=0;
 
-               // stop on .. Picture
-       enum { spm_I, spm_Ref, spm_Any };
-               /** Stop on specific decoded picture. For I-Frame display. */
-       virtual RESULT setSinglePictureMode(int when)=0;
-
-       enum { pkm_B, pkm_PB };
-               /** Fast forward by skipping either B or P/B pictures */
-       virtual RESULT setPictureSkipMode(int what)=0;
-
                /** Slow Motion by repeating pictures */
        virtual RESULT setSlowMotion(int repeat)=0;
-       
-       enum { zoom_Normal, zoom_PanScan, zoom_Letterbox, zoom_Fullscreen };
-               /** Set Zoom. mode *must* be fitting. */
-       virtual RESULT setZoom(int what)=0;
-
-       virtual RESULT setTrickmode(int what) = 0;
 
+               /** Display any complete data as fast as possible */
+       virtual RESULT setTrickmode()=0;
+       
        virtual RESULT getPTS(int what, pts_t &pts) = 0;
 
        virtual RESULT showSinglePic(const char *filename) = 0;
index 5931366..1393bf7 100644 (file)
@@ -6,9 +6,36 @@
 #error no byte order defined!
 #endif
 
-int eMPEGStreamInformation::save(const char *filename)
+eMPEGStreamInformation::eMPEGStreamInformation()
+       : m_structure_cache_valid(0), m_structure_read(0), m_structure_write(0)
 {
-       FILE *f = fopen(filename, "wb");
+}
+
+eMPEGStreamInformation::~eMPEGStreamInformation()
+{
+       if (m_structure_read)
+               fclose(m_structure_read);
+       if (m_structure_write)
+               fclose(m_structure_write);
+}
+
+int eMPEGStreamInformation::startSave(const char *filename)
+{
+       m_filename = filename;
+       m_structure_write = fopen((m_filename + ".sc").c_str(), "wb");
+       return 0;
+}
+
+int eMPEGStreamInformation::stopSave(void)
+{
+       if (m_structure_write)
+       {
+               fclose(m_structure_write);
+               m_structure_write = 0;
+       }
+       if (m_filename == "")
+               return -1;
+       FILE *f = fopen((m_filename + ".ap").c_str(), "wb");
        if (!f)
                return -1;
        
@@ -31,13 +58,15 @@ int eMPEGStreamInformation::save(const char *filename)
 
 int eMPEGStreamInformation::load(const char *filename)
 {
-       FILE *f = fopen(filename, "rb");
+       m_filename = filename;
+       if (m_structure_read)
+               fclose(m_structure_read);
+       m_structure_read = fopen((std::string(m_filename) + ".sc").c_str(), "rb");
+       FILE *f = fopen((std::string(m_filename) + ".ap").c_str(), "rb");
        if (!f)
                return -1;
        m_access_points.clear();
        m_pts_to_offset.clear();
-       pts_t last = -(1LL<<62);
-       int loaded = 0, skipped = 0;
        while (1)
        {
                unsigned long long d[2];
@@ -48,16 +77,9 @@ int eMPEGStreamInformation::load(const char *filename)
                d[0] = bswap_64(d[0]);
                d[1] = bswap_64(d[1]);
 #endif
-               if ((d[1] - last) > 90000/2)
-               {
-                       m_access_points[d[0]] = d[1];
-                       m_pts_to_offset.insert(std::pair<pts_t,off_t>(d[1], d[0]));
-                       last = d[1];
-                       loaded++;
-               } else
-                       skipped++;
+               m_access_points[d[0]] = d[1];
+               m_pts_to_offset.insert(std::pair<pts_t,off_t>(d[1], d[0]));
        }
-       eDebug("loaded %d, skipped %d", loaded, skipped);
        fclose(f);
        fixupDiscontinuties();
        return 0;
@@ -216,30 +238,45 @@ pts_t eMPEGStreamInformation::getInterpolated(off_t offset)
        return before_ts + diff;
 }
  
-off_t eMPEGStreamInformation::getAccessPoint(pts_t ts)
+off_t eMPEGStreamInformation::getAccessPoint(pts_t ts, int marg)
 {
                /* FIXME: more efficient implementation */
        off_t last = 0;
+       off_t last2 = 0;
+       pts_t lastc = 0;
        for (std::map<off_t, pts_t>::const_iterator i(m_access_points.begin()); i != m_access_points.end(); ++i)
        {
                pts_t delta = getDelta(i->first);
                pts_t c = i->second - delta;
-               if (c > ts)
-                       break;
+               if (c > ts) {
+                       if (marg > 0)
+                               return (last + i->first)/376*188;
+                       else if (marg < 0)
+                               return (last + last2)/376*188;
+                       else
+                               return last;
+               }
+               lastc = c;
+               last2 = last;
                last = i->first;
        }
-       return last;
+       if (marg < 0)
+               return (last + last2)/376*188;
+       else
+               return last;
 }
 
 int eMPEGStreamInformation::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction)
 {
        off_t offset = getAccessPoint(start);
+       pts_t c1, c2;
        std::map<off_t, pts_t>::const_iterator i = m_access_points.find(offset);
        if (i == m_access_points.end())
        {
                eDebug("getNextAccessPoint: initial AP not found");
                return -1;
        }
+       c1 = i->second - getDelta(i->first);
        while (direction)
        {
                if (direction > 0)
@@ -247,6 +284,12 @@ int eMPEGStreamInformation::getNextAccessPoint(pts_t &ts, const pts_t &start, in
                        if (i == m_access_points.end())
                                return -1;
                        ++i;
+                       c2 = i->second - getDelta(i->first);
+                       if (c1 == c2) { // Discontinuity
+                               ++i;
+                               c2 = i->second - getDelta(i->first);
+                       }
+                       c1 = c2;
                        direction--;
                }
                if (direction < 0)
@@ -257,6 +300,12 @@ int eMPEGStreamInformation::getNextAccessPoint(pts_t &ts, const pts_t &start, in
                                return -1;
                        }
                        --i;
+                       c2 = i->second - getDelta(i->first);
+                       if (c1 == c2) { // Discontinuity
+                               --i;
+                               c2 = i->second - getDelta(i->first);
+                       }
+                       c1 = c2;
                        direction++;
                }
        }
@@ -266,6 +315,117 @@ int eMPEGStreamInformation::getNextAccessPoint(pts_t &ts, const pts_t &start, in
        return 0;
 }
 
+void eMPEGStreamInformation::writeStructureEntry(off_t offset, structure_data data)
+{
+       unsigned long long d[2];
+#if BYTE_ORDER == BIG_ENDIAN
+       d[0] = offset;
+       d[1] = data;
+#else
+       d[0] = bswap_64(offset);
+       d[1] = bswap_64(data);
+#endif
+       if (m_structure_write)
+               fwrite(d, sizeof(d), 1, m_structure_write);
+}
+
+int eMPEGStreamInformation::getStructureEntry(off_t &offset, unsigned long long &data, int get_next)
+{
+       if (!m_structure_read)
+       {
+               eDebug("getStructureEntry failed because of no m_structure_read");
+               return -1;
+       }
+
+       const int struture_cache_entries = sizeof(m_structure_cache) / 16;
+       if ((!m_structure_cache_valid) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(struture_cache_entries - (get_next ? 2 : 1)) * 2] <= offset))
+       {
+               fseek(m_structure_read, 0, SEEK_END);
+               int l = ftell(m_structure_read);
+               unsigned long long d[2];
+               const int entry_size = sizeof d;
+
+                       /* do a binary search */
+               int count = l / entry_size;
+               int i = 0;
+               
+               while (count)
+               {
+                       int step = count >> 1;
+                       
+                       fseek(m_structure_read, (i + step) * entry_size, SEEK_SET);
+                       if (!fread(d, 1, entry_size, m_structure_read))
+                       {
+                               eDebug("read error at entry %d", i);
+                               return -1;
+                       }
+                       
+#if BYTE_ORDER != BIG_ENDIAN
+                       d[0] = bswap_64(d[0]);
+                       d[1] = bswap_64(d[1]);
+#endif
+//                     eDebug("%d: %08llx > %llx", i, d[0], d[1]);
+                       
+                       if (d[0] < (unsigned long long)offset)
+                       {
+                               i += step + 1;
+                               count -= step + 1;
+                       } else
+                               count = step;
+               }
+               
+               eDebug("found %d", i);
+               
+                       /* put that in the middle */
+               i -= struture_cache_entries / 2;
+               if (i < 0)
+                       i = 0;
+               eDebug("cache starts at %d", i);
+               fseek(m_structure_read, i * entry_size, SEEK_SET);
+               int num = fread(m_structure_cache, entry_size, struture_cache_entries, m_structure_read);
+               eDebug("%d entries", num);
+               for (i = 0; i < struture_cache_entries; ++i)
+               {
+                       if (i < num)
+                       {
+#if BYTE_ORDER != BIG_ENDIAN
+                               m_structure_cache[i * 2] = bswap_64(m_structure_cache[i * 2]);
+                               m_structure_cache[i * 2 + 1] = bswap_64(m_structure_cache[i * 2 + 1]);
+#endif
+                       } else
+                       {
+                               m_structure_cache[i * 2] = 0x7fffffffffffffffULL; /* fill with harmless content */
+                               m_structure_cache[i * 2 + 1] = 0;
+                       }
+               }
+               m_structure_cache_valid = 1;
+       }
+       
+       int i = 0;
+       while ((off_t)m_structure_cache[i * 2] <= offset)
+       {
+               ++i;
+               if (i == struture_cache_entries)
+               {
+                       eDebug("structure data consistency fail!, we are looking for %llx, but last entry is %llx", offset, m_structure_cache[i*2-2]);
+                       return -1;
+               }
+       }
+       if (!i)
+       {
+               eDebug("structure data (first entry) consistency fail!");
+               return -1;
+       }
+       
+       if (!get_next)
+               --i;
+
+//     eDebug("[%d] looked for %llx, found %llx=%llx", sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]);
+       offset = m_structure_cache[i * 2];
+       data = m_structure_cache[i * 2 + 1];
+       return 0;
+}
+
 eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo): m_streaminfo(streaminfo), m_pktptr(0), m_pid(-1), m_need_next_packet(0), m_skip(0), m_last_pts_valid(0)
 {
 }
@@ -275,16 +435,15 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
        if (!wantPacket(pkt))
                eWarning("something's wrong.");
 
-       const unsigned char *end = pkt + 188;
+       const unsigned char *end = pkt + 188, *begin = pkt;
        
-       if (!(pkt[3] & 0x10))
-       {
-               eWarning("[TSPARSE] PUSI set but no payload.");
-               return 0;
-       }
+       int pusi = !!(pkt[1] & 0x40);
        
-       if (pkt[3] & 0x20) // adaption field present?
-               pkt += pkt[4] + 4 + 1;  /* skip adaption field and header */
+       if (!(pkt[3] & 0x10)) /* no payload? */
+               return 0;
+
+       if (pkt[3] & 0x20) // adaptation field present?
+               pkt += pkt[4] + 4 + 1;  /* skip adaptation field and header */
        else
                pkt += 4; /* skip header */
 
@@ -293,77 +452,96 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
                eWarning("[TSPARSE] dropping huge adaption field");
                return 0;
        }
-       
-               // ok, we now have the start of the payload, aligned with the PES packet start.
-       if (pkt[0] || pkt[1] || (pkt[2] != 1))
-       {
-               eWarning("broken startcode");
-               return 0;
-       }
-       
-       
+
        pts_t pts = 0;
        int ptsvalid = 0;
        
-       if (pkt[7] & 0x80) // PTS present?
+       if (pusi)
        {
-               pts  = ((unsigned long long)(pkt[ 9]&0xE))  << 29;
-               pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
-               pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
-               pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
-               pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
-               ptsvalid = 1;
-               
-               m_last_pts = pts;
-               m_last_pts_valid = 1;
-
-#if 0          
-               int sec = pts / 90000;
-               int frm = pts % 90000;
-               int min = sec / 60;
-               sec %= 60;
-               int hr = min / 60;
-               min %= 60;
-               int d = hr / 24;
-               hr %= 24;
+                       // ok, we now have the start of the payload, aligned with the PES packet start.
+               if (pkt[0] || pkt[1] || (pkt[2] != 1))
+               {
+                       eWarning("broken startcode");
+                       return 0;
+               }
+
+               if (pkt[7] & 0x80) // PTS present?
+               {
+                       pts  = ((unsigned long long)(pkt[ 9]&0xE))  << 29;
+                       pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
+                       pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
+                       pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
+                       pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
+                       ptsvalid = 1;
+                       
+                       m_last_pts = pts;
+                       m_last_pts_valid = 1;
+
+       #if 0           
+                       int sec = pts / 90000;
+                       int frm = pts % 90000;
+                       int min = sec / 60;
+                       sec %= 60;
+                       int hr = min / 60;
+                       min %= 60;
+                       int d = hr / 24;
+                       hr %= 24;
+                       
+                       eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
+       #endif
+               }
                
-               eDebug("pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
-#endif
+                       /* advance to payload */
+               pkt += pkt[8] + 9;
        }
-       
-               /* advance to payload */
-       pkt += pkt[8] + 9;
 
-               /* sometimes, there are zeros before the startcode. */
        while (pkt < (end-4))
-               if (pkt[0] || pkt[1] || pkt[2])
-                       break;
-               else
-                       pkt++;
-
-               /* if startcode found */
-//     eDebug("%02x %02x %02x %02x", pkt[0], pkt[1], pkt[2], pkt[3]);
-       if (!(pkt[0] || pkt[1] || (pkt[2] != 1)))
        {
-               if (pkt[3] == 0xb3) /* sequence header */
+               int pkt_offset = pkt - begin;
+               if (!(pkt[0] || pkt[1] || (pkt[2] != 1)))
                {
-                       if (ptsvalid)
+//                     eDebug("SC %02x %02x %02x %02x, %02x", pkt[0], pkt[1], pkt[2], pkt[3], pkt[4]);
+                       int sc = pkt[3];
+                       
+                       if (m_streamtype == 0) /* mpeg2 */
                        {
-                               m_streaminfo.m_access_points[offset] = pts;
-//                             eDebug("Sequence header at %llx, pts %llx", offset, pts);
-                       } else
-                               /*eDebug("Sequence header but no valid PTS value.")*/;
-               }
+                               if ((sc == 0x00) || (sc == 0xb3) || (sc == 0xb8)) /* picture, sequence, group start code */
+                               {
+                                       unsigned long long data = sc | (pkt[4] << 8) | (pkt[5] << 16) | (pkt[6] << 24);
+                                       m_streaminfo.writeStructureEntry(offset + pkt_offset, data  & 0xFFFFFFFFULL);
+                               }
+                               if (pkt[3] == 0xb3) /* sequence header */
+                               {
+                                       if (ptsvalid)
+                                       {
+                                               m_streaminfo.m_access_points[offset] = pts;
+       //                                      eDebug("Sequence header at %llx, pts %llx", offset, pts);
+                                       } else
+                                               /*eDebug("Sequence header but no valid PTS value.")*/;
+                               }
+                       }
 
-               if (pkt[3] == 0x09) /* MPEG4 AVC unit access delimiter */
-               {
-                       if (ptsvalid)
+                       if (m_streamtype == 1) /* H.264 */
                        {
-                               m_streaminfo.m_access_points[offset] = pts;
-//                             eDebug("MPEG4 AVC UAD at %llx, pts %llx", offset, pts);
-                       } else
-                               /*eDebug("MPEG4 AVC UAD but no valid PTS value.")*/;
+                               if (sc == 0x09)
+                               {
+                                               /* store image type */
+                                       unsigned long long data = sc | (pkt[4] << 8);
+                                       m_streaminfo.writeStructureEntry(offset + pkt_offset, data);
+                               }
+                               if (pkt[3] == 0x09 &&   /* MPEG4 AVC NAL unit access delimiter */
+                                        (pkt[4] >> 5) == 0) /* and I-frame */
+                               {
+                                       if (ptsvalid)
+                                       {
+                                               m_streaminfo.m_access_points[offset] = pts;
+       //                              eDebug("MPEG4 AVC UAD at %llx, pts %llx", offset, pts);
+                                       } else
+                                               /*eDebug("MPEG4 AVC UAD but no valid PTS value.")*/;
+                               }
+                       }
                }
+               ++pkt;
        }
        return 0;
 }
@@ -386,7 +564,7 @@ inline int eMPEGStreamParserTS::wantPacket(const unsigned char *hdr) const
        if (hdr[1] & 0x40)       /* pusi set: yes. */
                return 1;
 
-       return 0;
+       return m_streamtype == 0; /* we need all packets for MPEG2, but only PUSI packets for H.264 */
 }
 
 void eMPEGStreamParserTS::parseData(off_t offset, const void *data, unsigned int len)
@@ -501,10 +679,11 @@ void eMPEGStreamParserTS::parseData(off_t offset, const void *data, unsigned int
        }
 }
 
-void eMPEGStreamParserTS::setPid(int _pid)
+void eMPEGStreamParserTS::setPid(int _pid, int type)
 {
        m_pktptr = 0;
        m_pid = _pid;
+       m_streamtype = type;
 }
 
 int eMPEGStreamParserTS::getLastPTS(pts_t &last_pts)
index 94f9f67..28c0314 100644 (file)
@@ -12,6 +12,8 @@
 class eMPEGStreamInformation
 {
 public:
+       eMPEGStreamInformation();
+       ~eMPEGStreamInformation();
                /* we order by off_t here, since the timestamp may */
                /* wrap around. */
                /* we only record sequence start's pts values here. */
@@ -23,7 +25,8 @@ public:
                /* these are non-fixed up pts value (like m_access_points), just used to accelerate stuff. */
        std::multimap<pts_t, off_t> m_pts_to_offset; 
 
-       int save(const char *filename);
+       int startSave(const char *filename);
+       int stopSave(void);
        int load(const char *filename);
        
                /* recalculates timestampDeltas */
@@ -41,11 +44,28 @@ public:
                /* inter/extrapolate timestamp from offset */
        pts_t getInterpolated(off_t offset);
        
-       off_t getAccessPoint(pts_t ts);
+       off_t getAccessPoint(pts_t ts, int marg=0);
        
        int getNextAccessPoint(pts_t &ts, const pts_t &start, int direction);
        
        bool empty();
+       
+       typedef unsigned long long structure_data;
+               /* this is usually:
+                       sc | (other_information << 8)
+                       but is really specific to the used video encoder.
+               */
+       void writeStructureEntry(off_t offset, structure_data data);
+
+               /* get a structure entry at given offset (or previous one, if no exact match was found).
+                  optionall, return next element. Offset will be returned. this allows you to easily 
+                  get previous and next structure elements. */
+       int getStructureEntry(off_t &offset, unsigned long long &data, int get_next);
+
+       std::string m_filename;
+       int m_structure_cache_valid;
+       unsigned long long m_structure_cache[1024];
+       FILE *m_structure_read, *m_structure_write;
 };
 
        /* Now we define the parser's state: */
@@ -54,7 +74,7 @@ class eMPEGStreamParserTS
 public:
        eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo);
        void parseData(off_t offset, const void *data, unsigned int len);
-       void setPid(int pid);
+       void setPid(int pid, int streamtype);
        int getLastPTS(pts_t &last_pts);
 private:
        eMPEGStreamInformation &m_streaminfo;
@@ -62,7 +82,7 @@ private:
        int m_pktptr;
        int processPacket(const unsigned char *pkt, off_t offset);
        inline int wantPacket(const unsigned char *hdr) const;
-       int m_pid;
+       int m_pid, m_streamtype;
        int m_need_next_packet;
        int m_skip;
        int m_last_pts_valid;
index 5157ef2..7ac86f0 100644 (file)
@@ -32,7 +32,10 @@ int eDVBTSTools::openFile(const char *filename, int nostreaminfo)
        closeFile();
        
        if (!nostreaminfo)
-               m_streaminfo.load((std::string(filename) + ".ap").c_str());
+       {
+               eDebug("loading streaminfo for %s", filename);
+               m_streaminfo.load(filename);
+       }
        
        if (!m_streaminfo.empty())
                m_use_streaminfo = 1;
@@ -209,11 +212,14 @@ int eDVBTSTools::fixupPTS(const off_t &offset, pts_t &now)
        }
 }
 
-int eDVBTSTools::getOffset(off_t &offset, pts_t &pts)
+int eDVBTSTools::getOffset(off_t &offset, pts_t &pts, int marg)
 {
        if (m_use_streaminfo)
        {
-               offset = m_streaminfo.getAccessPoint(pts);
+               if (pts >= m_pts_end && marg > 0 && m_end_valid)
+                       offset = m_offset_end;
+               else
+                       offset = m_streaminfo.getAccessPoint(pts, marg);
                return 0;
        } else
        {
@@ -559,3 +565,68 @@ int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
        
        return -1;
 }
+
+int eDVBTSTools::findIFrame(off_t &_offset, size_t &len, int direction)
+{
+       off_t offset = _offset;
+//     eDebug("trying to find iFrame at %llx", offset);
+
+       if (!m_use_streaminfo)
+       {
+               eDebug("can't get next iframe without streaminfo");
+               return -1;
+       }
+
+                               /* let's find the iframe before the given offset */
+       unsigned long long data;
+       while (1)
+       {
+               if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0))
+               {
+                       eDebug("getting structure info for origin offset failed.");
+                       return -1;
+               }
+               if (offset == 0x7fffffffffffffffLL) /* eof */
+               {
+                       eDebug("reached eof");
+                       return -1;
+               }
+                       /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */
+                       /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */
+               int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/
+               is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */
+//             eDebug("%08llx@%llx -> %d", data, offset, is_start);
+               if (is_start)
+                       break;
+
+               if (direction == -1)
+                       --offset; /* move to previous entry */
+               else if (direction == +1)
+                       direction = 0;
+       }
+                       /* let's find the next frame after the given offset */
+       off_t start = offset;
+
+       do {
+               if (m_streaminfo.getStructureEntry(offset, data, 1))
+               {
+                       eDebug("get next failed");
+                       return -1;
+               }
+               if (offset == 0x7fffffffffffffffLL) /* eof */
+               {
+                       eDebug("reached eof (while looking for end of iframe)");
+                       return -1;
+               }
+//             eDebug("%08llx@%llx", data, offset);
+       } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
+
+                       /* align to TS pkt start */
+       start = start - (start % 188);
+       offset = offset - (offset % 188);
+
+       len = offset - start;
+       _offset = start;
+//     eDebug("result: offset=%llx, len: %ld", offset, (int)len);
+       return 0;
+}
index 1316825..a8e0751 100644 (file)
@@ -40,7 +40,7 @@ public:
        int fixupPTS(const off_t &offset, pts_t &pts);
        
                /* get (approximate) offset corresponding to PTS */
-       int getOffset(off_t &offset, pts_t &pts);
+       int getOffset(off_t &offset, pts_t &pts, int marg=0);
        
        int getNextAccessPoint(pts_t &ts, const pts_t &start, int direction);
        
@@ -55,6 +55,8 @@ public:
        int takeSample(off_t off, pts_t &p);
        
        int findPMT(int &pmt_pid, int &service_id);
+       
+       int findIFrame(off_t &offset, size_t &len, int direction);
 private:
        int m_pid;
        int m_maxrange;
index b3ee511..ff98c08 100644 (file)
@@ -144,7 +144,7 @@ int ePositionGauge::event(int event, void *data, void *data2)
                        {
                                painter.setForegroundColor(gRGB(m_foreground_color));
                                int xi = scale(in), xo = scale(out);
-                               painter.fill(eRect(xi, 10, xo-xi, s.height()-14));
+                               painter.fill(eRect(xi, (s.height()-4) / 2, xo-xi, 4));
                        }
                        
                        in = m_length;
index c9488db..08794b3 100644 (file)
@@ -19,8 +19,11 @@ class StringList(Converter):
        def selectionChanged(self, index):
                self.source.selectionChanged(index)
                # update all non-master targets
+               print "changed selection in listbox!"
                for x in self.downstream_elements:
+                       print "downstream element", x
                        if x is not self.master:
+                               print "is not master, so update to index", index
                                x.index = index
 
        @cached
@@ -43,3 +46,6 @@ class StringList(Converter):
                        self.master.index = index
 
        index = property(getIndex, setIndex)
+
+       def entry_changed(self, index):
+               self.downstream_elements.entry_changed(index)
\ No newline at end of file
index f32a648..64b3aa6 100755 (executable)
@@ -203,7 +203,7 @@ class Network:
                                        ifaces[currif]["gateway"] = map(int, split[1].split('.'))
                                        if self.ifaces[currif].has_key("gateway"):
                                                if self.ifaces[currif]["gateway"] != ifaces[currif]["gateway"] and ifaces[currif]["dhcp"] == False:
-                                                       self.ifaces[currif]["gateway"] = map(int, split[1].split('.'))                                  
+                                                       self.ifaces[currif]["gateway"] = map(int, split[1].split('.'))
                                if (split[0] == "pre-up"):
                                        if self.ifaces[currif].has_key("preup"):
                                                self.ifaces[currif]["preup"] = i
index 7bb584e..cd329b5 100644 (file)
@@ -6,15 +6,24 @@ class FrontpanelLed(Element):
                Element.__init__(self)
 
        def changed(self, *args, **kwargs):
-               if self.source.value:
+               if self.source.value or 1:
                        pattern = 0x55555555
+                       pattern_4bit = 0x84fc8c04
                        speed = 20
                else:
                        pattern = 0
+                       pattern_4bit = 0xffffffff
                        speed = 1
 
                try:
                        open("/proc/stb/fp/led0_pattern", "w").write("%08x" % pattern)
+               except IOError:
+                       pass
+               try:
+                       open("/proc/stb/fp/led_pattern", "w").write("%08x" % pattern_4bit)
+               except IOError:
+                       pass
+               try:
                        open("/proc/stb/fp/led_pattern_speed", "w").write("%d" % speed)
                except IOError:
                        pass
index 8e510b4..7a89533 100644 (file)
@@ -78,3 +78,7 @@ class Listbox(Renderer, object):
 
        def changed(self, what):
                self.content = self.source.content
+
+       def entry_changed(self, index):
+               if self.instance is not None:
+                       self.instance.entryChanged(index)
index 3f9fe21..a50c10b 100644 (file)
@@ -781,12 +781,21 @@ class InfoBarSeek:
                        print "not pauseable."
                        state = self.SEEK_STATE_PLAY
 
-               oldstate = self.seekstate
                self.seekstate = state
 
-               for i in (0, 1, 2):
-                       if oldstate[i] != self.seekstate[i]:
-                               (self.session.nav.pause, pauseable.setFastForward, pauseable.setSlowMotion)[i](self.seekstate[i])
+               if pauseable is not None:
+                       if self.seekstate[0]:
+                               print "resolved to PAUSE"
+                               pauseable.pause()
+                       elif self.seekstate[1]:
+                               print "resolved to FAST FORWARD"
+                               pauseable.setFastForward(self.seekstate[1])
+                       elif self.seekstate[2]:
+                               print "resolved to SLOW MOTION"
+                               pauseable.setSlowMotion(self.seekstate[2])
+                       else:
+                               print "resolved to PLAY"
+                               pauseable.unpause()
 
                for c in self.onPlayStateChanged:
                        c(self.seekstate)
index 02fc450..e27752a 100644 (file)
@@ -392,6 +392,8 @@ class iPauseableService: public iObject
        ~iPausableService();
 #endif
 public:
+
+               /* this will set the *state* directly. So just call a SINGLE function of those at a time. */
        virtual RESULT pause()=0;
        virtual RESULT unpause()=0;
 
index 0f01b83..e3d960d 100644 (file)
@@ -506,6 +506,7 @@ RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string
 
        res.push_back(m_ref.path + ".meta");
        res.push_back(m_ref.path + ".ap");
+       res.push_back(m_ref.path + ".sc");
        res.push_back(m_ref.path + ".cuts");
        std::string tmp = m_ref.path;
        tmp.erase(m_ref.path.length()-3);
@@ -1005,7 +1006,10 @@ void eDVBServicePlay::serviceEventTimeshift(int event)
                break;
        case eDVBServicePMTHandler::eventEOF:
                if ((!m_is_paused) && (m_skipmode >= 0))
+               {
+                       eDebug("timeshift EOF, so let's go live");
                        switchToLive();
+               }
                break;
        }
 }
@@ -1128,6 +1132,9 @@ RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
 
 RESULT eDVBServicePlay::setSlowMotion(int ratio)
 {
+       assert(ratio); /* The API changed: instead of calling setSlowMotion(0), call play! */
+       eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
+       setFastForward_internal(0);
        if (m_decoder)
                return m_decoder->setSlowMotion(ratio);
        else
@@ -1136,6 +1143,13 @@ RESULT eDVBServicePlay::setSlowMotion(int ratio)
 
 RESULT eDVBServicePlay::setFastForward(int ratio)
 {
+       eDebug("eDVBServicePlay::setFastForward(%d)", ratio);
+       assert(ratio);
+       return setFastForward_internal(ratio);
+}
+
+RESULT eDVBServicePlay::setFastForward_internal(int ratio)
+{
        int skipmode, ffratio;
        
        if (ratio > 8)
@@ -1167,8 +1181,13 @@ RESULT eDVBServicePlay::setFastForward(int ratio)
        
        if (!m_decoder)
                return -1;
-
-       return m_decoder->setFastForward(ffratio);
+               
+       if (ffratio == 0)
+               return m_decoder->play();
+       else if (ffratio != 1)
+               return m_decoder->setFastForward(ffratio);
+       else
+               return m_decoder->setTrickmode();
 }
 
 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
@@ -1196,20 +1215,24 @@ RESULT eDVBServicePlay::getLength(pts_t &len)
 
 RESULT eDVBServicePlay::pause()
 {
-       if (!m_is_paused && m_decoder)
+       eDebug("eDVBServicePlay::pause");
+       setFastForward_internal(0);
+       if (m_decoder)
        {
                m_is_paused = 1;
-               return m_decoder->freeze(0);
+               return m_decoder->pause();
        } else
                return -1;
 }
 
 RESULT eDVBServicePlay::unpause()
 {
-       if (m_is_paused && m_decoder)
+       eDebug("eDVBServicePlay::unpause");
+       setFastForward_internal(0);
+       if (m_decoder)
        {
                m_is_paused = 0;
-               return m_decoder->unfreeze();
+               return m_decoder->play();
        } else
                return -1;
 }
@@ -1291,9 +1314,8 @@ RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
 
 RESULT eDVBServicePlay::setTrickmode(int trick)
 {
-       if (m_decoder)
-               m_decoder->setTrickmode(trick);
-       return 0;
+               /* currently unimplemented */
+       return -1;
 }
 
 RESULT eDVBServicePlay::isCurrentlySeekable()
@@ -1579,7 +1601,7 @@ RESULT eDVBServicePlay::selectTrack(unsigned int i)
 {
        int ret = selectAudioStream(i);
 
-       if (m_decoder->start())
+       if (m_decoder->play())
                return -5;
 
        return ret;
@@ -2124,6 +2146,8 @@ void eDVBServicePlay::switchToLive()
        if (!m_timeshift_active)
                return;
        
+       eDebug("SwitchToLive");
+       
        m_cue = 0;
        m_decoder = 0;
        m_decode_demux = 0;
@@ -2295,12 +2319,12 @@ void eDVBServicePlay::updateDecoder()
                m_teletext_parser->start(program.textPid);
 
                if (!m_is_primary)
-                       m_decoder->setTrickmode(1);
+                       m_decoder->setTrickmode();
 
                if (m_is_paused)
-                       m_decoder->preroll();
+                       m_decoder->pause();
                else
-                       m_decoder->start();
+                       m_decoder->play();
 
                if (vpid > 0 && vpid < 0x2000)
                        ;
index 56ec89e..43e4690 100644 (file)
@@ -218,6 +218,7 @@ private:
 
        int m_current_audio_stream;
        int selectAudioStream(int n = -1);
+       RESULT setFastForward_internal(int ratio);
        
                /* timeshift */
        ePtr<iDVBTSRecorder> m_record;
index c2767e8..5b7b5d8 100644 (file)
@@ -270,7 +270,7 @@ int eDVBServiceRecord::doRecord()
                        if (program.pmtPid != -1)
                                pids_to_record.insert(program.pmtPid); // PMT
 
-                       int timing_pid = -1;
+                       int timing_pid = -1, timing_pid_type = -1;
 
                        eDebugNoNewLine("RECORD: have %d video stream(s)", program.videoStreams.size());
                        if (!program.videoStreams.empty())
@@ -283,7 +283,10 @@ int eDVBServiceRecord::doRecord()
                                        pids_to_record.insert(i->pid);
                                        
                                        if (timing_pid == -1)
+                                       {
                                                timing_pid = i->pid;
+                                               timing_pid_type = i->type;
+                                       }
                                        
                                        if (i != program.videoStreams.begin())
                                                        eDebugNoNewLine(", ");
@@ -302,7 +305,10 @@ int eDVBServiceRecord::doRecord()
                                        pids_to_record.insert(i->pid);
        
                                        if (timing_pid == -1)
+                                       {
                                                timing_pid = i->pid;
+                                               timing_pid_type = -1;
+                                       }
                                
                                        if (i != program.audioStreams.begin())
                                                eDebugNoNewLine(", ");
@@ -358,7 +364,7 @@ int eDVBServiceRecord::doRecord()
                        }
 
                        if (timing_pid != -1)
-                               m_record->setTimingPID(timing_pid);
+                               m_record->setTimingPID(timing_pid, timing_pid_type);
 
                        m_pids_active = pids_to_record;