- While recording, collect startcodes and save them into ".sc"-files
authorFelix Domke <tmbinc@elitedvb.net>
Fri, 13 Feb 2009 02:41:57 +0000 (03:41 +0100)
committerFelix Domke <tmbinc@elitedvb.net>
Fri, 13 Feb 2009 02:41:57 +0000 (03:41 +0100)
 - this allows finding iframes for fast forward/reverse more easily
 - when in fast forward, strictly just output good (=complete iframes) data (this might break dm7025, we will fix this later)

 - draw smaller, fixed-size bar in position gauge

14 files changed:
lib/dvb/decoder.cpp
lib/dvb/demux.cpp
lib/dvb/demux.h
lib/dvb/dvb.cpp
lib/dvb/idemux.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/Renderer/Listbox.py
lib/service/servicedvb.cpp
lib/service/servicedvbrecord.cpp

index 6f0ead653c720cddd63b7d29b0d67ccfc9b33a0d..a4cffb77cc77e3c6629ae0597ca100c8b8faaa75 100644 (file)
@@ -1071,7 +1071,9 @@ 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);
index 810b10a5983604b65f6c4940546666ba43d34d0f..918ecec6bf6dca4c0a1b9ef33541e7ff97d437eb 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 14501b9859b2d2a9a02c41a33d96c2f0dff0e30b..7a697d49db27b5473db29b4d07b77bf800a5202f 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 c320fc7871199e6decf11733ee0409a2e54db1e1..4bbed519326b36d4c72376fab41ef0bd5b5902f8 100644 (file)
@@ -974,7 +974,7 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
        }
 #endif
 
-#if 1 /* This codepath is required on Broadcom-based Dreamboxes (DM800, DM8000) and strips away non-I-frames. */
+#if 0
        if (!m_iframe_search)
                return len;
 
@@ -1272,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())
        {
@@ -1348,6 +1363,10 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                        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 */
@@ -1417,30 +1436,23 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                }
        }
 
-       if (m_source_span.empty()) {
-               if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
-               {
-                       eDebug("reached SOF");
-                       m_skipmode_m = 0;
-                       m_pvr_thread->sendEvent(eFilePushThread::evtUser);
-               }
+       if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
+       {
+               eDebug("reached SOF");
+               m_skipmode_m = 0;
+               m_pvr_thread->sendEvent(eFilePushThread::evtUser);
+       }
+
+       if (m_source_span.empty())
+       {
                start = current_offset;
                size = max;
-       } else {
-               off_t tmp2, tmp = align(m_source_span.rbegin()->second, blocksize);
-               pts_t len;
-               getLength(len);
-               m_tstools.getOffset(tmp2, len, 1);
-               if (current_offset == tmp || current_offset == tmp2) {
-                       start = tmp2;
-                       size = max;
-               } else {
-                       start = tmp - align(512*1024, blocksize);
-                       size = align(512*1024, blocksize);
-               }
+               eDebug("NO CUESHEET. (%08llx, %d)", start, size);
+       } else
+       {
+               start = current_offset;
+               size = 0;
        }
-
-       eDebug("END OF CUESHEET. (%08llx, %d)", start, size);
        return;
 }
 
index 9432afb6002491c328d6b63016d8c297c575356b..e92b1e75c6df7e89442a7cfc25b10d006774992f 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 71cbd602f06187bb7fced1640eb5f6c29ce8031a..1393bf77847a6ec384bba54b0bf31cd4fc8cd25a 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,7 +58,11 @@ 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();
@@ -284,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)
 {
 }
@@ -293,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 */
 
@@ -311,78 +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 */
-                        (pkt[4] >> 5) == 0) /* and I-frame */
-               {
-                       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;
 }
@@ -405,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)
@@ -520,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 20d334709f0f5ff8257ce0631f0b59d529069014..28c0314a3082265bf6006499860a34f12597ff14 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 */
@@ -46,6 +49,23 @@ public:
        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 bd7ebce2843be12e4bef4d6a1f12262b47555215..7ac86f08acff7fa86694fcf63554440eb29baca5 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;
@@ -562,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 4bc04729c42056c3ab645ce46cb5a56249f0cb2f..a8e0751ec1e7668d0420089c3dcb42a3353f335f 100644 (file)
@@ -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 b3ee5111348c04787ca864d834c6a2f166a41756..ff98c080835532c4565558bb35254616b2673839 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 c9488db02216b7ca7df30f3d60e8ac3f5ac80e22..08794b343a8fda60d2e62c06f774f8cf47e973fe 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 8e510b4c09aae51490f2fa1b24586b5cc5ab5cc8..7a895330aa2381f8cc03d5c6348e346096cdabee 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 33cd865e9ea7c648893a6f37fa9a6e20a802b65a..e3d960d45a387ab29db0c82a6d3e492d77e24c0c 100644 (file)
@@ -370,13 +370,17 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
        struct stat s;
        stat(ref.path.c_str(), &s);
 
-       if (tstools.openFile(ref.path.c_str()))
+       if (tstools.openFile(ref.path.c_str(), 1))
                return 0;
 
                        /* check if cached data is still valid */
        if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
                return m_parser.m_length / 90000;
 
+                       /* open again, this time with stream info */
+       if (tstools.openFile(ref.path.c_str()))
+               return 0;
+
                        /* otherwise, re-calc length and update meta file */
        pts_t len;
        if (tstools.calcLen(len))
@@ -502,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);
@@ -1001,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;
        }
 }
@@ -1173,9 +1181,9 @@ RESULT eDVBServicePlay::setFastForward_internal(int ratio)
        
        if (!m_decoder)
                return -1;
-
+               
        if (ffratio == 0)
-               return 0;
+               return m_decoder->play();
        else if (ffratio != 1)
                return m_decoder->setFastForward(ffratio);
        else
@@ -1211,6 +1219,7 @@ RESULT eDVBServicePlay::pause()
        setFastForward_internal(0);
        if (m_decoder)
        {
+               m_is_paused = 1;
                return m_decoder->pause();
        } else
                return -1;
@@ -1222,6 +1231,7 @@ RESULT eDVBServicePlay::unpause()
        setFastForward_internal(0);
        if (m_decoder)
        {
+               m_is_paused = 0;
                return m_decoder->play();
        } else
                return -1;
@@ -2136,6 +2146,8 @@ void eDVBServicePlay::switchToLive()
        if (!m_timeshift_active)
                return;
        
+       eDebug("SwitchToLive");
+       
        m_cue = 0;
        m_decoder = 0;
        m_decode_demux = 0;
index c2767e8d42b0b29cd8435365b9791535a3ccf1bf..5b7b5d8ca7f7d37e27730b5dbe24d28dda7b2276 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;