aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorFraxinas <andreas.frisch@multimedia-labs.de>2009-01-15 13:22:06 +0100
committerFraxinas <andreas.frisch@multimedia-labs.de>2009-01-15 13:22:06 +0100
commitb3135c06dd527e0ed65b6ffa921f830132f7d8b9 (patch)
tree53c06d38680d21f366cbb1fc42d17e94b36a109a /lib
parent2c9a0e18d4ad0b5a73abb5466ea2f70b61daf7fa (diff)
parent97909d42012ca026c51d2e7b882ce55eb0acffab (diff)
downloadenigma2-b3135c06dd527e0ed65b6ffa921f830132f7d8b9.tar.gz
enigma2-b3135c06dd527e0ed65b6ffa921f830132f7d8b9.zip
Merge branch 'master' of fraxinas@git.opendreambox.org:/git/enigma2
Diffstat (limited to 'lib')
-rw-r--r--lib/dvb/demux.cpp19
-rw-r--r--lib/dvb/demux.h4
-rw-r--r--lib/dvb/idemux.h2
-rw-r--r--lib/dvb/metaparser.cpp23
-rw-r--r--lib/dvb/metaparser.h3
-rw-r--r--lib/dvb/pvrparse.cpp17
-rw-r--r--lib/dvb/pvrparse.h3
-rw-r--r--lib/python/Components/EpgList.py6
-rw-r--r--lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py143
-rw-r--r--lib/python/Screens/EpgSelection.py40
-rw-r--r--lib/python/Screens/EventView.py46
-rw-r--r--lib/python/Screens/TimerEdit.py5
-rw-r--r--lib/service/servicedvb.cpp13
-rw-r--r--lib/service/servicedvbrecord.cpp103
-rw-r--r--lib/service/servicedvbrecord.h9
15 files changed, 397 insertions, 39 deletions
diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp
index a0f1c326..810b10a5 100644
--- a/lib/dvb/demux.cpp
+++ b/lib/dvb/demux.cpp
@@ -405,12 +405,14 @@ public:
void setTimingPID(int pid);
void saveTimingInformation(const std::string &filename);
+ int getLastPTS(pts_t &pts);
protected:
int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
private:
eMPEGStreamParserTS m_ts_parser;
eMPEGStreamInformation m_stream_info;
off_t m_current_offset;
+ pts_t m_last_pcr; /* very approximate.. */
int m_pid;
};
@@ -430,6 +432,11 @@ void eDVBRecordFileThread::saveTimingInformation(const std::string &filename)
m_stream_info.save(filename.c_str());
}
+int eDVBRecordFileThread::getLastPTS(pts_t &pts)
+{
+ return m_ts_parser.getLastPTS(pts);
+}
+
int eDVBRecordFileThread::filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining)
{
m_ts_parser.parseData(m_current_offset, data, len);
@@ -589,6 +596,18 @@ RESULT eDVBTSRecorder::stop()
return 0;
}
+RESULT eDVBTSRecorder::getCurrentPCR(pts_t &pcr)
+{
+ if (!m_running)
+ return 0;
+ if (!m_thread)
+ return 0;
+ /* XXX: we need a lock here */
+
+ /* we don't filter PCR data, so just use the last received PTS, which is not accurate, but better than nothing */
+ return m_thread->getLastPTS(pcr);
+}
+
RESULT eDVBTSRecorder::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
{
conn = new eConnection(this, m_event.connect(event));
diff --git a/lib/dvb/demux.h b/lib/dvb/demux.h
index 1a7db979..14501b98 100644
--- a/lib/dvb/demux.h
+++ b/lib/dvb/demux.h
@@ -101,7 +101,9 @@ public:
RESULT setBoundary(off_t max);
RESULT stop();
-
+
+ RESULT getCurrentPCR(pts_t &pcr);
+
RESULT connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn);
private:
RESULT startPID(int pid);
diff --git a/lib/dvb/idemux.h b/lib/dvb/idemux.h
index 2b750882..9432afb6 100644
--- a/lib/dvb/idemux.h
+++ b/lib/dvb/idemux.h
@@ -38,6 +38,8 @@ public:
virtual RESULT setBoundary(off_t max) = 0;
virtual RESULT stop() = 0;
+
+ virtual RESULT getCurrentPCR(pts_t &pcr) = 0;
enum {
eventWriteError,
diff --git a/lib/dvb/metaparser.cpp b/lib/dvb/metaparser.cpp
index 3e3f9a79..175c7cdb 100644
--- a/lib/dvb/metaparser.cpp
+++ b/lib/dvb/metaparser.cpp
@@ -6,6 +6,8 @@ eDVBMetaParser::eDVBMetaParser()
{
m_time_create = 0;
m_data_ok = 0;
+ m_length = 0;
+ m_filesize = 0;
}
int eDVBMetaParser::parseFile(const std::string &basename)
@@ -59,6 +61,12 @@ int eDVBMetaParser::parseMeta(const std::string &tsname)
case 4:
m_tags = line;
break;
+ case 5:
+ m_length = atoi(line); //movielength in pts
+ break;
+ case 6:
+ m_filesize = atoll(line);
+ break;
default:
break;
}
@@ -105,17 +113,19 @@ int eDVBMetaParser::parseRecordings(const std::string &filename)
ref = eServiceReferenceDVB(line + 10);
if (!strncmp(line, "#DESCRIPTION: ", 14))
description = line + 14;
-
- if ((line[0] == '/') && (ref.path == filename))
+ if ((line[0] == '/') && (ref.path.substr(ref.path.find_last_of('/')) == filename.substr(filename.find_last_of('/'))))
{
// eDebug("hit! ref %s descr %s", m_ref.toString().c_str(), m_name.c_str());
m_ref = ref;
m_name = description;
m_description = "";
m_time_create = 0;
-
+ m_length = 0;
+ m_filesize = 0;
+
m_data_ok = 1;
fclose(f);
+ updateMeta(filename.c_str());
return 0;
}
}
@@ -125,14 +135,17 @@ int eDVBMetaParser::parseRecordings(const std::string &filename)
int eDVBMetaParser::updateMeta(const std::string &tsname)
{
- if (!m_data_ok)
+ /* write meta file only if we have valid data. Note that we might convert recordings.epl data to .meta, which is fine. */
+ if (!m_data_ok)
return -1;
std::string filename = tsname + ".meta";
+ eServiceReference ref = m_ref;
+ ref.path = "";
FILE *f = fopen(filename.c_str(), "w");
if (!f)
return -ENOENT;
- fprintf(f, "%s\n%s\n%s\n%d\n%s\n", m_ref.toString().c_str(), m_name.c_str(), m_description.c_str(), m_time_create, m_tags.c_str());
+ fprintf(f, "%s\n%s\n%s\n%d\n%s\n%d\n%lld\n", ref.toString().c_str(), m_name.c_str(), m_description.c_str(), m_time_create, m_tags.c_str(), m_length, m_filesize );
fclose(f);
return 0;
}
diff --git a/lib/dvb/metaparser.h b/lib/dvb/metaparser.h
index 01fabde8..2ca94d6d 100644
--- a/lib/dvb/metaparser.h
+++ b/lib/dvb/metaparser.h
@@ -18,7 +18,8 @@ public:
eServiceReferenceDVB m_ref;
std::string m_name, m_description;
- int m_time_create;
+ int m_time_create, m_length;
+ long long m_filesize;
std::string m_tags;
};
diff --git a/lib/dvb/pvrparse.cpp b/lib/dvb/pvrparse.cpp
index 1b6cb467..59313669 100644
--- a/lib/dvb/pvrparse.cpp
+++ b/lib/dvb/pvrparse.cpp
@@ -266,7 +266,7 @@ int eMPEGStreamInformation::getNextAccessPoint(pts_t &ts, const pts_t &start, in
return 0;
}
-eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo): m_streaminfo(streaminfo), m_pktptr(0), m_pid(-1), m_need_next_packet(0), m_skip(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)
{
}
@@ -313,6 +313,9 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
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;
@@ -503,3 +506,15 @@ void eMPEGStreamParserTS::setPid(int _pid)
m_pktptr = 0;
m_pid = _pid;
}
+
+int eMPEGStreamParserTS::getLastPTS(pts_t &last_pts)
+{
+ if (!m_last_pts_valid)
+ {
+ last_pts = 0;
+ return -1;
+ }
+ last_pts = m_last_pts;
+ return 0;
+}
+
diff --git a/lib/dvb/pvrparse.h b/lib/dvb/pvrparse.h
index 69bb9924..94f9f67f 100644
--- a/lib/dvb/pvrparse.h
+++ b/lib/dvb/pvrparse.h
@@ -55,6 +55,7 @@ public:
eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo);
void parseData(off_t offset, const void *data, unsigned int len);
void setPid(int pid);
+ int getLastPTS(pts_t &last_pts);
private:
eMPEGStreamInformation &m_streaminfo;
unsigned char m_pkt[188];
@@ -64,6 +65,8 @@ private:
int m_pid;
int m_need_next_packet;
int m_skip;
+ int m_last_pts_valid;
+ pts_t m_last_pts;
};
#endif
diff --git a/lib/python/Components/EpgList.py b/lib/python/Components/EpgList.py
index 30f566fd..8a7c8d45 100644
--- a/lib/python/Components/EpgList.py
+++ b/lib/python/Components/EpgList.py
@@ -284,6 +284,12 @@ class EPGList(HTMLComponent, GUIComponent):
x = self.l.getCurrentSelection()
return x and x[1]
+ def moveToService(self,serviceref):
+ for x in range(len(self.list)):
+ if self.list[x][1] == serviceref.toString():
+ self.instance.moveSelectionTo(x)
+ break
+
def moveToEventId(self, eventId):
index = 0
for x in self.list:
diff --git a/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py b/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py
index afae6b3a..b2e07e10 100644
--- a/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py
+++ b/lib/python/Plugins/Extensions/GraphMultiEPG/GraphMultiEpg.py
@@ -15,8 +15,9 @@ from Screens.TimeDateInput import TimeDateInput
from Screens.TimerEntry import TimerEntry
from Screens.EpgSelection import EPGSelection
from Screens.TimerEdit import TimerSanityConflict
+from Screens.MessageBox import MessageBox
from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE
-from RecordTimer import RecordTimerEntry, parseEvent
+from RecordTimer import RecordTimerEntry, parseEvent, AFTEREVENT
from ServiceReference import ServiceReference
from Tools.LoadPixmap import LoadPixmap
from enigma import eEPGCache, eListbox, gFont, eListboxPythonMultiContent, \
@@ -41,6 +42,10 @@ class EPGList(HTMLComponent, GUIComponent):
self.l.setSelectableFunc(self.isSelectable)
self.epgcache = eEPGCache.getInstance()
self.clock_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock.png'))
+ self.clock_add_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_add.png'))
+ self.clock_pre_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_pre.png'))
+ self.clock_post_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_post.png'))
+ self.clock_prepost_pixmap = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/epgclock_prepost.png'))
self.time_base = None
self.time_epoch = time_epoch
self.list = None
@@ -92,6 +97,22 @@ class EPGList(HTMLComponent, GUIComponent):
event = self.epgcache.lookupEventId(service.ref, eventid)
return event
+ def moveToService(self,serviceref):
+ for x in range(len(self.list)):
+ if self.list[x][0] == serviceref.toString():
+ self.instance.moveSelectionTo(x)
+ break
+
+ def getIndexFromService(self, serviceref):
+ for x in range(len(self.list)):
+ if self.list[x][0] == serviceref.toString():
+ return x
+ return 0
+
+ def setCurrentIndex(self, index):
+ if self.instance is not None:
+ self.instance.moveSelectionTo(index)
+
def getCurrent(self):
if self.cur_service is None:
return ( None, None )
@@ -227,7 +248,7 @@ class EPGList(HTMLComponent, GUIComponent):
borderColor = self.borderColor
for ev in events: #(event_id, event_title, begin_time, duration)
- rec=ev[2] and self.timer.isInTimer(ev[0], ev[2], ev[3], service) > ((ev[3]/10)*8)
+ rec=ev[2] and self.timer.isInTimer(ev[0], ev[2], ev[3], service)
xpos, ewidth = self.calcEntryPosAndWidthHelper(ev[2], ev[3], start, end, width)
res.append(MultiContentEntryText(
pos = (left+xpos, top), size = (ewidth, height),
@@ -237,7 +258,8 @@ class EPGList(HTMLComponent, GUIComponent):
if rec and ewidth > 23:
res.append(MultiContentEntryPixmapAlphaTest(
pos = (left+xpos+ewidth-22, top+height-22), size = (21, 21),
- png = self.clock_pixmap, backcolor = backColor,
+ png = self.getClockPixmap(service, ev[2], ev[3], ev[0]),
+ backcolor = backColor,
backcolor_sel = backColorSelected))
return res
@@ -329,6 +351,30 @@ class EPGList(HTMLComponent, GUIComponent):
def resetOffset(self):
self.offs = 0
+
+ def getClockPixmap(self, refstr, beginTime, duration, eventId):
+ pre_clock = 1
+ post_clock = 2
+ clock_type = 0
+ endTime = beginTime + duration
+ for x in self.timer.timer_list:
+ if x.service_ref.ref.toString() == refstr:
+ if x.eit == eventId:
+ return self.clock_pixmap
+ beg = x.begin
+ end = x.end
+ if beginTime > beg and beginTime < end and endTime > end:
+ clock_type |= pre_clock
+ elif beginTime < beg and endTime > beg and endTime < end:
+ clock_type |= post_clock
+ if clock_type == 0:
+ return self.clock_add_pixmap
+ elif clock_type == pre_clock:
+ return self.clock_pre_pixmap
+ elif clock_type == post_clock:
+ return self.clock_post_pixmap
+ else:
+ return self.clock_prepost_pixmap
class TimelineText(HTMLComponent, GUIComponent):
def __init__(self):
@@ -356,6 +402,12 @@ config.misc.graph_mepg_prev_time=ConfigClock(default = time())
config.misc.graph_mepg_prev_time_period=ConfigInteger(default=120, limits=(60,300))
class GraphMultiEPG(Screen):
+ EMPTY = 0
+ ADD_TIMER = 1
+ REMOVE_TIMER = 2
+
+ ZAP = 1
+
def __init__(self, session, services, zapFunc=None, bouquetChangeCB=None):
Screen.__init__(self, session)
self.bouquetChangeCB = bouquetChangeCB
@@ -364,7 +416,9 @@ class GraphMultiEPG(Screen):
self.ask_time = now - tmp
self.closeRecursive = False
self["key_red"] = Button("")
- self["key_green"] = Button(_("Add timer"))
+ self["key_green"] = Button("")
+ self.key_green_choice = self.EMPTY
+ self.key_red_choice = self.EMPTY
self["timeline_text"] = TimelineText()
self["Event"] = Event()
self.time_lines = [ ]
@@ -488,6 +542,7 @@ class GraphMultiEPG(Screen):
#just used in multipeg
def onCreate(self):
self["list"].fillMultiEPG(self.services, self.ask_time)
+ self["list"].moveToService(self.session.nav.getCurrentlyPlayingServiceReference())
self.moveTimeLines()
def eventViewCallback(self, setEvent, setService, val):
@@ -505,7 +560,7 @@ class GraphMultiEPG(Screen):
setEvent(cur[0])
def zapTo(self):
- if self.zapFunc and self["key_red"].getText() == "Zap":
+ if self.zapFunc and self.key_red_choice == self.ZAP:
self.closeRecursive = True
ref = self["list"].getCurrent()[1]
if ref:
@@ -514,14 +569,28 @@ class GraphMultiEPG(Screen):
def eventSelected(self):
self.infoKeyPressed()
+ def removeTimer(self, timer):
+ timer.afterEvent = AFTEREVENT.NONE
+ self.session.nav.RecordTimer.removeEntry(timer)
+ self["key_green"].setText(_("Add timer"))
+ self.key_green_choice = self.ADD_TIMER
+
def timerAdd(self):
cur = self["list"].getCurrent()
event = cur[0]
serviceref = cur[1]
if event is None:
return
- newEntry = RecordTimerEntry(serviceref, checkOldTimers = True, *parseEvent(event))
- self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry)
+ eventid = event.getEventId()
+ refstr = serviceref.ref.toString()
+ for timer in self.session.nav.RecordTimer.timer_list:
+ if timer.eit == eventid and timer.service_ref.ref.toString() == refstr:
+ cb_func = lambda ret : not ret or self.removeTimer(timer)
+ self.session.openWithCallback(cb_func, MessageBox, _("Do you really want to delete %s?") % event.getEventName())
+ break
+ else:
+ newEntry = RecordTimerEntry(serviceref, checkOldTimers = True, *parseEvent(event))
+ self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry)
def finishedAdd(self, answer):
print "finished add"
@@ -535,25 +604,63 @@ class GraphMultiEPG(Screen):
self.session.nav.RecordTimer.record(entry)
else:
self.session.openWithCallback(self.finishSanityCorrection, TimerSanityConflict, simulTimerList)
+ self["key_green"].setText(_("Remove timer"))
+ self.key_green_choice = self.REMOVE_TIMER
else:
+ self["key_green"].setText(_("Add timer"))
+ self.key_green_choice = self.ADD_TIMER
print "Timeredit aborted"
def finishSanityCorrection(self, answer):
self.finishedAdd(answer)
def onSelectionChanged(self):
- evt = self["list"].getCurrent()
- self["Event"].newEvent(evt and evt[0])
- if evt and evt[0]:
- evt = evt[0]
- now = time()
- start = evt.getBeginTime()
- end = start + evt.getDuration()
- if now >= start and now <= end:
- self["key_red"].setText("Zap")
- else:
+ cur = self["list"].getCurrent()
+ if cur is None:
+ if self.key_green_choice != self.EMPTY:
+ self["key_green"].setText("")
+ self.key_green_choice = self.EMPTY
+ if self.key_red_choice != self.EMPTY:
self["key_red"].setText("")
-
+ self.key_red_choice = self.EMPTY
+ return
+
+ event = cur[0]
+ self["Event"].newEvent(event)
+
+ if cur[1] is None or cur[1].getServiceName() == "":
+ if self.key_green_choice != self.EMPTY:
+ self["key_green"].setText("")
+ self.key_green_choice = self.EMPTY
+ if self.key_red_choice != self.EMPTY:
+ self["key_red"].setText("")
+ self.key_red_choice = self.EMPTY
+ return
+ elif self.key_red_choice != self.ZAP:
+ self["key_red"].setText("Zap")
+ self.key_red_choice = self.ZAP
+
+ if not event:
+ if self.key_green_choice != self.EMPTY:
+ self["key_green"].setText("")
+ self.key_green_choice = self.EMPTY
+ return
+
+ serviceref = cur[1]
+ eventid = event.getEventId()
+ refstr = serviceref.ref.toString()
+ isRecordEvent = False
+ for timer in self.session.nav.RecordTimer.timer_list:
+ if timer.eit == eventid and timer.service_ref.ref.toString() == refstr:
+ isRecordEvent = True
+ break
+ if isRecordEvent and self.key_green_choice != self.REMOVE_TIMER:
+ self["key_green"].setText(_("Remove timer"))
+ self.key_green_choice = self.REMOVE_TIMER
+ elif not isRecordEvent and self.key_green_choice != self.ADD_TIMER:
+ self["key_green"].setText(_("Add timer"))
+ self.key_green_choice = self.ADD_TIMER
+
def moveTimeLines(self, force=False):
l = self["list"]
event_rect = l.getEventRect()
diff --git a/lib/python/Screens/EpgSelection.py b/lib/python/Screens/EpgSelection.py
index f6793269..526576e1 100644
--- a/lib/python/Screens/EpgSelection.py
+++ b/lib/python/Screens/EpgSelection.py
@@ -19,8 +19,11 @@ from time import localtime, time
mepg_config_initialized = False
class EPGSelection(Screen):
- ADD_TIMER = 0
- REMOVE_TIMER = 1
+ EMPTY = 0
+ ADD_TIMER = 1
+ REMOVE_TIMER = 2
+
+ ZAP = 1
def __init__(self, session, service, zapFunc=None, eventid=None, bouquetChangeCB=None):
Screen.__init__(self, session)
@@ -64,6 +67,7 @@ class EPGSelection(Screen):
self["key_green"] = Button(_("Add timer"))
self.key_green_choice = self.ADD_TIMER
+ self.key_red_choice = self.EMPTY
self["list"] = EPGList(type = self.type, selChangedCB = self.onSelectionChanged, timer = self.session.nav.RecordTimer)
self["actions"] = ActionMap(["EPGSelectActions", "OkCancelActions"],
@@ -131,6 +135,7 @@ class EPGSelection(Screen):
l.recalcEntrySize()
if self.type == EPG_TYPE_MULTI:
l.fillMultiEPG(self.services, self.ask_time)
+ l.moveToService(self.session.nav.getCurrentlyPlayingServiceReference())
elif self.type == EPG_TYPE_SINGLE:
l.fillSingleEPG(self.currentService)
else:
@@ -151,7 +156,7 @@ class EPGSelection(Screen):
setEvent(cur[0])
def zapTo(self): # just used in multiepg
- if self.zapFunc and self["key_red"].getText() == "Zap":
+ if self.zapFunc and self.key_red_choice == self.ZAP:
lst = self["list"]
count = lst.getCurrentChangeCount()
if count == 0:
@@ -250,13 +255,11 @@ class EPGSelection(Screen):
self["key_red"].setText("")
else:
if state == 1:
- self["key_red"].setText("Zap")
self["now_button_sel"].show()
self["now_button"].hide()
else:
self["now_button"].show()
self["now_button_sel"].hide()
- self["key_red"].setText("")
if state == 2:
self["next_button_sel"].show()
@@ -274,6 +277,15 @@ class EPGSelection(Screen):
def onSelectionChanged(self):
cur = self["list"].getCurrent()
+ if cur is None:
+ if self.key_green_choice != self.EMPTY:
+ self["key_green"].setText("")
+ self.key_green_choice = self.EMPTY
+ if self.key_red_choice != self.EMPTY:
+ self["key_red"].setText("")
+ self.key_red_choice = self.EMPTY
+ return
+ event = cur[0]
if self.type == EPG_TYPE_MULTI:
count = self["list"].getCurrentChangeCount()
if self.ask_time != -1:
@@ -286,7 +298,6 @@ class EPGSelection(Screen):
self.applyButtonState(1)
days = [ _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat"), _("Sun") ]
datestr = ""
- event = cur[0]
if event is not None:
now = time()
beg = event.getBeginTime()
@@ -297,10 +308,23 @@ class EPGSelection(Screen):
else:
datestr = '%s %d.%d.'%(_("Today"), begTime[2], begTime[1])
self["date"].setText(datestr)
- else:
- event = cur[0]
+
+ if cur[1] is None or cur[1].getServiceName() == "":
+ if self.key_green_choice != self.EMPTY:
+ self["key_green"].setText("")
+ self.key_green_choice = self.EMPTY
+ if self.key_red_choice != self.EMPTY:
+ self["key_red"].setText("")
+ self.key_red_choice = self.EMPTY
+ return
+ elif self.key_red_choice != self.ZAP and self.type == EPG_TYPE_MULTI:
+ self["key_red"].setText("Zap")
+ self.key_red_choice = self.ZAP
if event is None:
+ if self.key_green_choice != self.EMPTY:
+ self["key_green"].setText("")
+ self.key_green_choice = self.EMPTY
return
serviceref = cur[1]
diff --git a/lib/python/Screens/EventView.py b/lib/python/Screens/EventView.py
index 5d50d9bc..5d3786fb 100644
--- a/lib/python/Screens/EventView.py
+++ b/lib/python/Screens/EventView.py
@@ -1,17 +1,21 @@
from Screen import Screen
from Screens.TimerEdit import TimerSanityConflict
+from Screens.MessageBox import MessageBox
from Components.ActionMap import ActionMap
from Components.Button import Button
from Components.Label import Label
from Components.ScrollLabel import ScrollLabel
from Components.TimerList import TimerList
from enigma import eEPGCache, eTimer, eServiceReference
-from RecordTimer import RecordTimerEntry, parseEvent
+from RecordTimer import RecordTimerEntry, parseEvent, AFTEREVENT
from TimerEntry import TimerEntry
from time import localtime
from Components.config import config
class EventViewBase:
+ ADD_TIMER = 0
+ REMOVE_TIMER = 1
+
def __init__(self, Event, Ref, callback=None, similarEPGCB=None):
self.similarEPGCB = similarEPGCB
self.cbFunc = callback
@@ -28,6 +32,7 @@ class EventViewBase:
self.SimilarBroadcastTimer.callback.append(self.getSimilarEvents)
else:
self.SimilarBroadcastTimer = None
+ self.key_green_choice = self.ADD_TIMER
if self.isRecording:
self["key_green"] = Button("")
else:
@@ -59,8 +64,25 @@ class EventViewBase:
if self.cbFunc is not None:
self.cbFunc(self.setEvent, self.setService, +1)
+ def removeTimer(self, timer):
+ timer.afterEvent = AFTEREVENT.NONE
+ self.session.nav.RecordTimer.removeEntry(timer)
+ self["key_green"].setText(_("Add timer"))
+ self.key_green_choice = self.ADD_TIMER
+
def timerAdd(self):
- if not self.isRecording:
+ event = self.event
+ serviceref = self.currentService
+ if event is None:
+ return
+ eventid = event.getEventId()
+ refstr = serviceref.ref.toString()
+ for timer in self.session.nav.RecordTimer.timer_list:
+ if timer.eit == eventid and timer.service_ref.ref.toString() == refstr:
+ cb_func = lambda ret : not ret or self.removeTimer(timer)
+ self.session.openWithCallback(cb_func, MessageBox, _("Do you really want to delete %s?") % event.getEventName())
+ break
+ else:
newEntry = RecordTimerEntry(self.currentService, checkOldTimers = True, *parseEvent(self.event))
self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry)
@@ -76,7 +98,11 @@ class EventViewBase:
self.session.nav.RecordTimer.record(entry)
else:
self.session.openWithCallback(self.finishSanityCorrection, TimerSanityConflict, simulTimerList)
+ self["key_green"].setText(_("Remove timer"))
+ self.key_green_choice = self.REMOVE_TIMER
else:
+ self["key_green"].setText(_("Add timer"))
+ self.key_green_choice = self.ADD_TIMER
print "Timeredit aborted"
def finishSanityCorrection(self, answer):
@@ -123,6 +149,22 @@ class EventViewBase:
if self.SimilarBroadcastTimer is not None:
self.SimilarBroadcastTimer.start(400,True)
+ serviceref = self.currentService
+ eventid = self.event.getEventId()
+ refstr = serviceref.ref.toString()
+ isRecordEvent = False
+ for timer in self.session.nav.RecordTimer.timer_list:
+ if timer.eit == eventid and timer.service_ref.ref.toString() == refstr:
+ isRecordEvent = True
+ break
+ if isRecordEvent and self.key_green_choice != self.REMOVE_TIMER:
+ self["key_green"].setText(_("Remove timer"))
+ self.key_green_choice = self.REMOVE_TIMER
+ elif not isRecordEvent and self.key_green_choice != self.ADD_TIMER:
+ self["key_green"].setText(_("Add timer"))
+ self.key_green_choice = self.ADD_TIMER
+
+
def pageUp(self):
self["epg_description"].pageUp()
diff --git a/lib/python/Screens/TimerEdit.py b/lib/python/Screens/TimerEdit.py
index 59e2bd03..8cda8ca4 100644
--- a/lib/python/Screens/TimerEdit.py
+++ b/lib/python/Screens/TimerEdit.py
@@ -269,8 +269,9 @@ class TimerEditList(Screen):
self.session.openWithCallback(self.finishedEdit, TimerSanityConflict, timersanitycheck.getSimulTimerList())
else:
print "Sanity check passed"
- if not timersanitycheck.doubleCheck():
- self.session.nav.RecordTimer.timeChanged(entry)
+# if not timersanitycheck.doubleCheck():
+ self.session.nav.RecordTimer.timeChanged(entry)
+
self.fillTimerList()
self.updateState()
else:
diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp
index 90195d9b..dcd7017c 100644
--- a/lib/service/servicedvb.cpp
+++ b/lib/service/servicedvb.cpp
@@ -536,14 +536,25 @@ int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
eDVBTSTools tstools;
+ struct stat s;
+ stat(ref.path.c_str(), &s);
+
if (tstools.openFile(ref.path.c_str()))
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;
+
+ /* otherwise, re-calc length and update meta file */
pts_t len;
if (tstools.calcLen(len))
return 0;
- return len / 90000;
+ m_parser.m_length = len;
+ m_parser.m_filesize = s.st_size;
+ m_parser.updateMeta(ref.path);
+ return m_parser.m_length / 90000;
}
int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
diff --git a/lib/service/servicedvbrecord.cpp b/lib/service/servicedvbrecord.cpp
index b92ee257..c2767e8d 100644
--- a/lib/service/servicedvbrecord.cpp
+++ b/lib/service/servicedvbrecord.cpp
@@ -3,11 +3,20 @@
#include <lib/dvb/epgcache.h>
#include <fcntl.h>
+ /* for cutlist */
+#include <byteswap.h>
+#include <netinet/in.h>
+
+#ifndef BYTE_ORDER
+#error no byte order defined!
+#endif
+
DEFINE_REF(eDVBServiceRecord);
eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref): m_ref(ref)
{
CONNECT(m_service_handler.serviceEvent, eDVBServiceRecord::serviceEvent);
+ CONNECT(m_event_handler.m_eit_changed, eDVBServiceRecord::gotNewEvent);
m_state = stateIdle;
m_want_record = 0;
m_tuned = 0;
@@ -15,6 +24,7 @@ eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref): m_ref(ref
m_error = 0;
m_streaming = 0;
m_simulate = false;
+ m_last_event_id = -1;
}
void eDVBServiceRecord::serviceEvent(int event)
@@ -26,6 +36,22 @@ void eDVBServiceRecord::serviceEvent(int event)
{
eDebug("tuned..");
m_tuned = 1;
+
+ /* start feeding EIT updates */
+ ePtr<iDVBDemux> m_demux;
+ if (!m_service_handler.getDataDemux(m_demux))
+ {
+ eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_ref;
+ int sid = ref.getParentServiceID().get();
+ if (!sid)
+ sid = ref.getServiceID().get();
+ if ( ref.getParentTransportStreamID().get() &&
+ ref.getParentTransportStreamID() != ref.getTransportStreamID() )
+ m_event_handler.startOther(m_demux, sid);
+ else
+ m_event_handler.start(m_demux, sid);
+ }
+
if (m_state == stateRecording && m_want_record)
doRecord();
m_event((iRecordableService*)this, evTunedIn);
@@ -145,6 +171,9 @@ RESULT eDVBServiceRecord::stop()
::close(m_target_fd);
m_target_fd = -1;
}
+
+ saveCutlist();
+
m_state = statePrepared;
} else if (!m_simulate)
eDebug("(was not recording)");
@@ -398,3 +427,77 @@ void eDVBServiceRecord::recordEvent(int event)
eDebug("unhandled record event %d", event);
}
}
+
+void eDVBServiceRecord::gotNewEvent()
+{
+ ePtr<eServiceEvent> event_now;
+ m_event_handler.getEvent(event_now, 0);
+
+ if (!event_now)
+ return;
+
+ int event_id = event_now->getEventId();
+
+ pts_t p;
+
+ if (m_record)
+ {
+ if (m_record->getCurrentPCR(p))
+ eDebug("getting PCR failed!");
+ else
+ {
+ static int i;
+ m_event_timestamps[/* event_id*/ ++i] = p;
+ eDebug("pcr of eit change: %llx", p);
+ }
+ }
+
+ if (event_id != m_last_event_id)
+ eDebug("[eDVBServiceRecord] now running: %s (%d seconds)", event_now->getEventName().c_str(), event_now->getDuration());
+
+ m_last_event_id = event_id;
+}
+
+void eDVBServiceRecord::saveCutlist()
+{
+ /* XXX: dupe of eDVBServicePlay::saveCuesheet, refactor plz */
+ std::string filename = m_filename + ".cuts";
+
+ eDVBTSTools tstools;
+
+ if (tstools.openFile(m_filename.c_str()))
+ {
+ eDebug("[eDVBServiceRecord] saving cutlist failed because tstools failed");
+ return;
+ }
+
+ FILE *f = fopen(filename.c_str(), "wb");
+
+ if (f)
+ {
+ unsigned long long where;
+ int what;
+
+ for (std::map<int,pts_t>::iterator i(m_event_timestamps.begin()); i != m_event_timestamps.end(); ++i)
+ {
+ pts_t p = i->second;
+ off_t offset = 0; // fixme, we need to note down both
+ if (tstools.fixupPTS(offset, p))
+ {
+ eDebug("[eDVBServiceRecord] fixing up PTS failed, not saving");
+ continue;
+ }
+ eDebug("fixed up %llx to %llx (offset %llx)", i->second, p, offset);
+#if BYTE_ORDER == BIG_ENDIAN
+ where = p;
+#else
+ where = bswap_64(p);
+#endif
+ what = htonl(2); /* mark */
+ fwrite(&where, sizeof(where), 1, f);
+ fwrite(&what, sizeof(what), 1, f);
+ }
+ fclose(f);
+ }
+
+}
diff --git a/lib/service/servicedvbrecord.h b/lib/service/servicedvbrecord.h
index 17de033e..856f92b3 100644
--- a/lib/service/servicedvbrecord.h
+++ b/lib/service/servicedvbrecord.h
@@ -36,6 +36,8 @@ private:
friend class eServiceFactoryDVB;
eDVBServiceRecord(const eServiceReferenceDVB &ref);
+ eDVBServiceEITHandler m_event_handler;
+
eServiceReferenceDVB m_ref;
ePtr<iDVBTSRecorder> m_record;
@@ -44,8 +46,11 @@ private:
int m_recording, m_tuned, m_error;
std::set<int> m_pids_active;
std::string m_filename;
+
+ std::map<int,pts_t> m_event_timestamps;
int m_target_fd;
int m_streaming;
+ int m_last_event_id;
int doPrepare();
int doRecord();
@@ -56,6 +61,10 @@ private:
/* recorder events */
void recordEvent(int event);
+
+ /* eit updates */
+ void gotNewEvent();
+ void saveCutlist();
};
#endif