summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FORMATS34
-rw-r--r--HISTORY5
-rw-r--r--eit.c125
-rw-r--r--eit.h10
-rw-r--r--vdr.c5
5 files changed, 167 insertions, 12 deletions
diff --git a/FORMATS b/FORMATS
index 9f1a7d99..0da29397 100644
--- a/FORMATS
+++ b/FORMATS
@@ -180,3 +180,37 @@ Video Disk Recorder File Formats
for audio 2 (if available). Dolby Digital data is stored in packets with
ids 0xBD.
+* epg.data
+
+ This file contains the EPG data in an easily parsable format. The first
+ character of each line defines what kind of data this line contains.
+
+ The following tag characters are defined:
+
+ C <service id> <channel name>
+ E <event id> <start time> <duration> <table id>
+ T <title>
+ S <subtitle>
+ D <description>
+ e
+ c
+
+ Lowercase characters mark the end of a sequence that was started by the
+ corresponding uppercase character. The outer frame consists of a sequence
+ of one or more 'C'...'c' (Channel) entries. Inside these any number of
+ 'E'...'e' (Event) entries are allowed. The 'T', 'S' and 'D' entries are
+ optional (although every event should at least have a 'T' entry).
+
+ <service id> is the "program number" as defined in 'channels.conf'
+ <channel name> is the "name" as in 'channels.conf' (for information only)
+ <start time> is the time (as a time_t integer) in UTC when this event starts
+ <duration> is the time (in seconds) that this event will take
+ <table id> is a hex number that indicates the table this event is contained
+ in (if this is left empty or 0 this event will not be overwritten
+ or modified by data that comes from the DVB stream)
+ <title> is the title of the event
+ <subtitle> is the subtitle (typically the name of the episode etc.)
+ <description> is the description of the event
+
+ This file will be read at program startup in order to restore the results of
+ previous EPG scans.
diff --git a/HISTORY b/HISTORY
index 1e133b2a..58ab9cc5 100644
--- a/HISTORY
+++ b/HISTORY
@@ -997,7 +997,7 @@ Video Disk Recorder Revision History
- If a recording has no episode title, the trailing '~' is no longer shown in
the progress display.
-2002-02-17: Version 1.0.0pre1
+2002-02-23: Version 1.0.0pre1
- Added scanning for EPG data for another 4 days on channels that support this
(thanks to Oleg Assovski).
@@ -1020,3 +1020,6 @@ Video Disk Recorder Revision History
"instant" recording (see FORMATS for details).
- Fixed the SVDRP GRAB command in case the video device can't be opened (thanks
to Adrian Stabiszewski).
+- At startup the data written into 'epg.data' is now read into the EPG data
+ structures. In order for this to work, the 'E' record has been extended to
+ (optionally) contain the 'table ID' (see FORMATS for details).
diff --git a/eit.c b/eit.c
index afb1ed4f..bd43fe92 100644
--- a/eit.c
+++ b/eit.c
@@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.c 1.36 2002/02/23 13:53:53 kls Exp $
+ * $Id: eit.c 1.37 2002/02/23 17:11:19 kls Exp $
***************************************************************************/
#include "eit.h"
@@ -341,7 +341,7 @@ unsigned short cEventInfo::GetServiceID() const
void cEventInfo::Dump(FILE *f, const char *Prefix) const
{
if (tTime + lDuration >= time(NULL)) {
- fprintf(f, "%sE %u %ld %ld\n", Prefix, uEventID, tTime, lDuration);
+ fprintf(f, "%sE %u %ld %ld %X\n", Prefix, uEventID, tTime, lDuration, uTableID);
if (!isempty(pTitle))
fprintf(f, "%sT %s\n", Prefix, pTitle);
if (!isempty(pSubtitle))
@@ -352,6 +352,54 @@ void cEventInfo::Dump(FILE *f, const char *Prefix) const
}
}
+bool cEventInfo::Read(FILE *f, cSchedule *Schedule)
+{
+ if (Schedule) {
+ cEventInfo *pEvent = NULL;
+ char *s;
+ while ((s = readline(f)) != NULL) {
+ char *t = skipspace(s + 1);
+ switch (*s) {
+ case 'E': if (!pEvent) {
+ unsigned int uEventID;
+ time_t tTime;
+ long lDuration;
+ unsigned int uTableID = 0;
+ int n = sscanf(t, "%u %ld %ld %X", &uEventID, &tTime, &lDuration, &uTableID);
+ if (n == 3 || n == 4) {
+ pEvent = (cEventInfo *)Schedule->GetEvent(uEventID, tTime);
+ if (!pEvent)
+ pEvent = Schedule->AddEvent(new cEventInfo(Schedule->GetServiceID(), uEventID));
+ if (pEvent) {
+ pEvent->SetTableID(uTableID);
+ pEvent->SetTime(tTime);
+ pEvent->SetDuration(lDuration);
+ }
+ }
+ }
+ break;
+ case 'T': if (pEvent)
+ pEvent->SetTitle(t);
+ break;
+ case 'S': if (pEvent)
+ pEvent->SetSubtitle(t);
+ break;
+ case 'D': if (pEvent)
+ pEvent->SetExtendedDescription(t);
+ break;
+ case 'e': pEvent = NULL;
+ break;
+ case 'c': // to keep things simple we react on 'c' here
+ return false;
+ default: esyslog(LOG_ERR, "ERROR: unexpected tag while reading EPG data: %s", s);
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
#define MAXEPGBUGFIXSTATS 5
#define MAXEPGBUGFIXCHANS 50
struct tEpgBugFixStats {
@@ -545,6 +593,13 @@ cSchedule::cSchedule(unsigned short servid)
cSchedule::~cSchedule()
{
}
+
+cEventInfo *cSchedule::AddEvent(cEventInfo *EventInfo)
+{
+ Events.Add(EventInfo);
+ return EventInfo;
+}
+
/** */
const cEventInfo * cSchedule::GetPresentEvent() const
{
@@ -689,6 +744,31 @@ void cSchedule::Dump(FILE *f, const char *Prefix) const
}
}
+bool cSchedule::Read(FILE *f, cSchedules *Schedules)
+{
+ if (Schedules) {
+ char *s;
+ while ((s = readline(f)) != NULL) {
+ if (*s == 'C') {
+ unsigned int uServiceID;
+ if (1 == sscanf(s + 1, "%u", &uServiceID)) {
+ cSchedule *p = (cSchedule *)Schedules->SetCurrentServiceID(uServiceID);
+ if (p) {
+ while (cEventInfo::Read(f, p))
+ ; // loop stops after having read the closing 'c'
+ }
+ }
+ }
+ else {
+ esyslog(LOG_ERR, "ERROR: unexpected tag while reading EPG data: %s", s);
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
// --- cSchedules ------------------------------------------------------------
cSchedules::cSchedules()
@@ -701,7 +781,7 @@ cSchedules::~cSchedules()
{
}
/** */
-bool cSchedules::SetCurrentServiceID(unsigned short servid)
+const cSchedule *cSchedules::SetCurrentServiceID(unsigned short servid)
{
pCurrentSchedule = GetSchedule(servid);
if (pCurrentSchedule == NULL)
@@ -709,12 +789,12 @@ bool cSchedules::SetCurrentServiceID(unsigned short servid)
Add(new cSchedule(servid));
pCurrentSchedule = GetSchedule(servid);
if (pCurrentSchedule == NULL)
- return false;
+ return NULL;
}
uCurrentServiceID = servid;
- return true;
+ return pCurrentSchedule;
}
/** */
const cSchedule * cSchedules::GetSchedule() const
@@ -757,6 +837,13 @@ void cSchedules::Dump(FILE *f, const char *Prefix) const
p->Dump(f, Prefix);
}
+/** */
+bool cSchedules::Read(FILE *f)
+{
+ cMutexLock MutexLock;
+ return cSchedule::Read(f, (cSchedules *)cSIProcessor::Schedules(MutexLock));
+}
+
// --- cEIT ------------------------------------------------------------------
class cEIT {
@@ -822,16 +909,19 @@ int cEIT::ProcessEIT(unsigned char *buffer)
if (!pEvent) {
// If we don't have that event ID yet, we create a new one.
// Otherwise we copy the information into the existing event anyway, because the data might have changed.
- pSchedule->Events.Add(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID));
- pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID);
+ pEvent = pSchedule->AddEvent(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID));
if (!pEvent)
break;
pEvent->SetTableID(tid);
}
else {
// We have found an existing event, either through its event ID or its start time.
+ // If the existing event has a zero table ID it was defined externally and shall
+ // not be overwritten.
+ if (pEvent->GetTableID() == 0x00)
+ continue;
// If the new event comes from a table that belongs to an "other TS" and the existing
- // one comes from a "actual TS" table, lets skip it.
+ // one comes from an "actual TS" table, lets skip it.
if ((tid == 0x4F || tid == 0x60 || tid == 0x61) && (pEvent->GetTableID() == 0x4E || pEvent->GetTableID() == 0x50 || pEvent->GetTableID() == 0x51))
continue;
}
@@ -920,6 +1010,25 @@ const cSchedules *cSIProcessor::Schedules(cMutexLock &MutexLock)
return NULL;
}
+bool cSIProcessor::Read(FILE *f)
+{
+ bool OwnFile = f == NULL;
+ if (OwnFile) {
+ const char *FileName = GetEpgDataFileName();
+ if (access(FileName, R_OK) == 0) {
+ dsyslog(LOG_INFO, "reading EPG data from %s", FileName);
+ if ((f = fopen(FileName, "r")) == NULL) {
+ LOG_ERROR;
+ return false;
+ }
+ }
+ }
+ bool result = cSchedules::Read(f);
+ if (OwnFile)
+ fclose(f);
+ return result;
+}
+
void cSIProcessor::SetEpgDataFileName(const char *FileName)
{
epgDataFileName = NULL;
diff --git a/eit.h b/eit.h
index 16f21017..55c0f4e0 100644
--- a/eit.h
+++ b/eit.h
@@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.h 1.14 2002/02/23 13:51:31 kls Exp $
+ * $Id: eit.h 1.15 2002/02/23 15:30:25 kls Exp $
***************************************************************************/
#ifndef __EIT_H
@@ -72,6 +72,7 @@ public:
int GetChannelNumber(void) const { return nChannelNumber; }
void SetChannelNumber(int ChannelNumber) const { ((cEventInfo *)this)->nChannelNumber = ChannelNumber; } // doesn't modify the EIT data, so it's ok to make it 'const'
void Dump(FILE *f, const char *Prefix = "") const;
+ static bool Read(FILE *f, cSchedule *Schedule);
void FixEpgBugs(void);
};
@@ -92,6 +93,7 @@ protected:
cSchedule(unsigned short servid = 0);
public:
~cSchedule();
+ cEventInfo *AddEvent(cEventInfo *EventInfo);
const cEventInfo *GetPresentEvent(void) const;
const cEventInfo *GetFollowingEvent(void) const;
unsigned short GetServiceID(void) const;
@@ -100,15 +102,17 @@ public:
const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
int NumEvents(void) const { return Events.Count(); }
void Dump(FILE *f, const char *Prefix = "") const;
+ static bool Read(FILE *f, cSchedules *Schedules);
};
class cSchedules : public cList<cSchedule> {
+ friend class cSchedule;
friend class cSIProcessor;
private:
const cSchedule *pCurrentSchedule;
unsigned short uCurrentServiceID;
protected:
- bool SetCurrentServiceID(unsigned short servid);
+ const cSchedule *SetCurrentServiceID(unsigned short servid);
void Cleanup();
public:
cSchedules(void);
@@ -116,6 +120,7 @@ public:
const cSchedule *GetSchedule(unsigned short servid) const;
const cSchedule *GetSchedule(void) const;
void Dump(FILE *f, const char *Prefix = "") const;
+ static bool Read(FILE *f);
};
typedef struct sip_filter {
@@ -150,6 +155,7 @@ public:
// Caller must provide a cMutexLock which has to survive the entire
// time the returned cSchedules is accessed. Once the cSchedules is no
// longer used, the cMutexLock must be destroyed.
+ static bool Read(FILE *f = NULL);
void SetStatus(bool On);
bool SetUseTSTime(bool use);
bool SetCurrentServiceID(unsigned short servid);
diff --git a/vdr.c b/vdr.c
index 9d5167b4..296478fa 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
- * $Id: vdr.c 1.95 2002/02/10 15:12:43 kls Exp $
+ * $Id: vdr.c 1.96 2002/02/23 16:35:36 kls Exp $
*/
#include <getopt.h>
@@ -35,6 +35,7 @@
#ifdef DVDSUPPORT
#include "dvd.h"
#endif //DVDSUPPORT
+#include "eit.h"
#include "i18n.h"
#include "interface.h"
#include "menu.h"
@@ -286,6 +287,8 @@ int main(int argc, char *argv[])
cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB);
+ cSIProcessor::Read();
+
Channels.SwitchTo(Setup.CurrentChannel);
cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true);