summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dvb/decoder.cpp4
-rw-r--r--lib/dvb/demux.cpp28
-rw-r--r--lib/dvb/demux.h2
-rw-r--r--lib/dvb/dvb.cpp56
-rw-r--r--lib/dvb/idemux.h2
-rw-r--r--lib/dvb/pvrparse.cpp302
-rw-r--r--lib/dvb/pvrparse.h26
-rw-r--r--lib/dvb/tstools.cpp70
-rw-r--r--lib/dvb/tstools.h2
-rw-r--r--lib/gui/epositiongauge.cpp2
-rw-r--r--lib/python/Components/Converter/StringList.py6
-rw-r--r--lib/python/Components/Renderer/Listbox.py4
-rw-r--r--lib/service/servicedvb.cpp18
-rw-r--r--lib/service/servicedvbrecord.cpp10
14 files changed, 416 insertions, 116 deletions
diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp
index 6f0ead6..a4cffb7 100644
--- a/lib/dvb/decoder.cpp
+++ b/lib/dvb/decoder.cpp
@@ -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);
diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp
index 810b10a..918ecec 100644
--- a/lib/dvb/demux.cpp
+++ b/lib/dvb/demux.cpp
@@ -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;
}
diff --git a/lib/dvb/demux.h b/lib/dvb/demux.h
index 14501b9..7a697d4 100644
--- a/lib/dvb/demux.h
+++ b/lib/dvb/demux.h
@@ -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);
diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp
index c320fc7..4bbed51 100644
--- a/lib/dvb/dvb.cpp
+++ b/lib/dvb/dvb.cpp
@@ -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;
}
diff --git a/lib/dvb/idemux.h b/lib/dvb/idemux.h
index 9432afb..e92b1e7 100644
--- a/lib/dvb/idemux.h
+++ b/lib/dvb/idemux.h
@@ -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. */
diff --git a/lib/dvb/pvrparse.cpp b/lib/dvb/pvrparse.cpp
index 71cbd60..1393bf7 100644
--- a/lib/dvb/pvrparse.cpp
+++ b/lib/dvb/pvrparse.cpp
@@ -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)
diff --git a/lib/dvb/pvrparse.h b/lib/dvb/pvrparse.h
index 20d3347..28c0314 100644
--- a/lib/dvb/pvrparse.h
+++ b/lib/dvb/pvrparse.h
@@ -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;
diff --git a/lib/dvb/tstools.cpp b/lib/dvb/tstools.cpp
index bd7ebce..7ac86f0 100644
--- a/lib/dvb/tstools.cpp
+++ b/lib/dvb/tstools.cpp
@@ -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;
+}
diff --git a/lib/dvb/tstools.h b/lib/dvb/tstools.h
index 4bc0472..a8e0751 100644
--- a/lib/dvb/tstools.h
+++ b/lib/dvb/tstools.h
@@ -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;
diff --git a/lib/gui/epositiongauge.cpp b/lib/gui/epositiongauge.cpp
index b3ee511..ff98c08 100644
--- a/lib/gui/epositiongauge.cpp
+++ b/lib/gui/epositiongauge.cpp
@@ -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;
diff --git a/lib/python/Components/Converter/StringList.py b/lib/python/Components/Converter/StringList.py
index c9488db..08794b3 100644
--- a/lib/python/Components/Converter/StringList.py
+++ b/lib/python/Components/Converter/StringList.py
@@ -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
diff --git a/lib/python/Components/Renderer/Listbox.py b/lib/python/Components/Renderer/Listbox.py
index 8e510b4..7a89533 100644
--- a/lib/python/Components/Renderer/Listbox.py
+++ b/lib/python/Components/Renderer/Listbox.py
@@ -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)
diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp
index 33cd865..e3d960d 100644
--- a/lib/service/servicedvb.cpp
+++ b/lib/service/servicedvb.cpp
@@ -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;
diff --git a/lib/service/servicedvbrecord.cpp b/lib/service/servicedvbrecord.cpp
index c2767e8..5b7b5d8 100644
--- a/lib/service/servicedvbrecord.cpp
+++ b/lib/service/servicedvbrecord.cpp
@@ -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;