mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Reading 'epg.data' at startup
This commit is contained in:
parent
db7f6ee619
commit
430284a8a7
34
FORMATS
34
FORMATS
@ -180,3 +180,37 @@ Video Disk Recorder File Formats
|
|||||||
for audio 2 (if available). Dolby Digital data is stored in packets with
|
for audio 2 (if available). Dolby Digital data is stored in packets with
|
||||||
ids 0xBD.
|
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.
|
||||||
|
5
HISTORY
5
HISTORY
@ -997,7 +997,7 @@ Video Disk Recorder Revision History
|
|||||||
- If a recording has no episode title, the trailing '~' is no longer shown in
|
- If a recording has no episode title, the trailing '~' is no longer shown in
|
||||||
the progress display.
|
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
|
- Added scanning for EPG data for another 4 days on channels that support this
|
||||||
(thanks to Oleg Assovski).
|
(thanks to Oleg Assovski).
|
||||||
@ -1020,3 +1020,6 @@ Video Disk Recorder Revision History
|
|||||||
"instant" recording (see FORMATS for details).
|
"instant" recording (see FORMATS for details).
|
||||||
- Fixed the SVDRP GRAB command in case the video device can't be opened (thanks
|
- Fixed the SVDRP GRAB command in case the video device can't be opened (thanks
|
||||||
to Adrian Stabiszewski).
|
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).
|
||||||
|
125
eit.c
125
eit.c
@ -16,7 +16,7 @@
|
|||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
* (at your option) any later version. *
|
* (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"
|
#include "eit.h"
|
||||||
@ -341,7 +341,7 @@ unsigned short cEventInfo::GetServiceID() const
|
|||||||
void cEventInfo::Dump(FILE *f, const char *Prefix) const
|
void cEventInfo::Dump(FILE *f, const char *Prefix) const
|
||||||
{
|
{
|
||||||
if (tTime + lDuration >= time(NULL)) {
|
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))
|
if (!isempty(pTitle))
|
||||||
fprintf(f, "%sT %s\n", Prefix, pTitle);
|
fprintf(f, "%sT %s\n", Prefix, pTitle);
|
||||||
if (!isempty(pSubtitle))
|
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 MAXEPGBUGFIXSTATS 5
|
||||||
#define MAXEPGBUGFIXCHANS 50
|
#define MAXEPGBUGFIXCHANS 50
|
||||||
struct tEpgBugFixStats {
|
struct tEpgBugFixStats {
|
||||||
@ -545,6 +593,13 @@ cSchedule::cSchedule(unsigned short servid)
|
|||||||
cSchedule::~cSchedule()
|
cSchedule::~cSchedule()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cEventInfo *cSchedule::AddEvent(cEventInfo *EventInfo)
|
||||||
|
{
|
||||||
|
Events.Add(EventInfo);
|
||||||
|
return EventInfo;
|
||||||
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
const cEventInfo * cSchedule::GetPresentEvent() const
|
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::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);
|
pCurrentSchedule = GetSchedule(servid);
|
||||||
if (pCurrentSchedule == NULL)
|
if (pCurrentSchedule == NULL)
|
||||||
@ -709,12 +789,12 @@ bool cSchedules::SetCurrentServiceID(unsigned short servid)
|
|||||||
Add(new cSchedule(servid));
|
Add(new cSchedule(servid));
|
||||||
pCurrentSchedule = GetSchedule(servid);
|
pCurrentSchedule = GetSchedule(servid);
|
||||||
if (pCurrentSchedule == NULL)
|
if (pCurrentSchedule == NULL)
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uCurrentServiceID = servid;
|
uCurrentServiceID = servid;
|
||||||
|
|
||||||
return true;
|
return pCurrentSchedule;
|
||||||
}
|
}
|
||||||
/** */
|
/** */
|
||||||
const cSchedule * cSchedules::GetSchedule() const
|
const cSchedule * cSchedules::GetSchedule() const
|
||||||
@ -757,6 +837,13 @@ void cSchedules::Dump(FILE *f, const char *Prefix) const
|
|||||||
p->Dump(f, Prefix);
|
p->Dump(f, Prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
bool cSchedules::Read(FILE *f)
|
||||||
|
{
|
||||||
|
cMutexLock MutexLock;
|
||||||
|
return cSchedule::Read(f, (cSchedules *)cSIProcessor::Schedules(MutexLock));
|
||||||
|
}
|
||||||
|
|
||||||
// --- cEIT ------------------------------------------------------------------
|
// --- cEIT ------------------------------------------------------------------
|
||||||
|
|
||||||
class cEIT {
|
class cEIT {
|
||||||
@ -822,16 +909,19 @@ int cEIT::ProcessEIT(unsigned char *buffer)
|
|||||||
if (!pEvent) {
|
if (!pEvent) {
|
||||||
// If we don't have that event ID yet, we create a new one.
|
// 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.
|
// 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 = pSchedule->AddEvent(new cEventInfo(VdrProgramInfo->ServiceID, VdrProgramInfo->EventID));
|
||||||
pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID);
|
|
||||||
if (!pEvent)
|
if (!pEvent)
|
||||||
break;
|
break;
|
||||||
pEvent->SetTableID(tid);
|
pEvent->SetTableID(tid);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We have found an existing event, either through its event ID or its start time.
|
// 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
|
// 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))
|
if ((tid == 0x4F || tid == 0x60 || tid == 0x61) && (pEvent->GetTableID() == 0x4E || pEvent->GetTableID() == 0x50 || pEvent->GetTableID() == 0x51))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -920,6 +1010,25 @@ const cSchedules *cSIProcessor::Schedules(cMutexLock &MutexLock)
|
|||||||
return NULL;
|
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)
|
void cSIProcessor::SetEpgDataFileName(const char *FileName)
|
||||||
{
|
{
|
||||||
epgDataFileName = NULL;
|
epgDataFileName = NULL;
|
||||||
|
10
eit.h
10
eit.h
@ -16,7 +16,7 @@
|
|||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
* (at your option) any later version. *
|
* (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
|
#ifndef __EIT_H
|
||||||
@ -72,6 +72,7 @@ public:
|
|||||||
int GetChannelNumber(void) const { return nChannelNumber; }
|
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 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;
|
void Dump(FILE *f, const char *Prefix = "") const;
|
||||||
|
static bool Read(FILE *f, cSchedule *Schedule);
|
||||||
void FixEpgBugs(void);
|
void FixEpgBugs(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,6 +93,7 @@ protected:
|
|||||||
cSchedule(unsigned short servid = 0);
|
cSchedule(unsigned short servid = 0);
|
||||||
public:
|
public:
|
||||||
~cSchedule();
|
~cSchedule();
|
||||||
|
cEventInfo *AddEvent(cEventInfo *EventInfo);
|
||||||
const cEventInfo *GetPresentEvent(void) const;
|
const cEventInfo *GetPresentEvent(void) const;
|
||||||
const cEventInfo *GetFollowingEvent(void) const;
|
const cEventInfo *GetFollowingEvent(void) const;
|
||||||
unsigned short GetServiceID(void) const;
|
unsigned short GetServiceID(void) const;
|
||||||
@ -100,15 +102,17 @@ public:
|
|||||||
const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
|
const cEventInfo *GetEventNumber(int n) const { return Events.Get(n); }
|
||||||
int NumEvents(void) const { return Events.Count(); }
|
int NumEvents(void) const { return Events.Count(); }
|
||||||
void Dump(FILE *f, const char *Prefix = "") const;
|
void Dump(FILE *f, const char *Prefix = "") const;
|
||||||
|
static bool Read(FILE *f, cSchedules *Schedules);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cSchedules : public cList<cSchedule> {
|
class cSchedules : public cList<cSchedule> {
|
||||||
|
friend class cSchedule;
|
||||||
friend class cSIProcessor;
|
friend class cSIProcessor;
|
||||||
private:
|
private:
|
||||||
const cSchedule *pCurrentSchedule;
|
const cSchedule *pCurrentSchedule;
|
||||||
unsigned short uCurrentServiceID;
|
unsigned short uCurrentServiceID;
|
||||||
protected:
|
protected:
|
||||||
bool SetCurrentServiceID(unsigned short servid);
|
const cSchedule *SetCurrentServiceID(unsigned short servid);
|
||||||
void Cleanup();
|
void Cleanup();
|
||||||
public:
|
public:
|
||||||
cSchedules(void);
|
cSchedules(void);
|
||||||
@ -116,6 +120,7 @@ public:
|
|||||||
const cSchedule *GetSchedule(unsigned short servid) const;
|
const cSchedule *GetSchedule(unsigned short servid) const;
|
||||||
const cSchedule *GetSchedule(void) const;
|
const cSchedule *GetSchedule(void) const;
|
||||||
void Dump(FILE *f, const char *Prefix = "") const;
|
void Dump(FILE *f, const char *Prefix = "") const;
|
||||||
|
static bool Read(FILE *f);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct sip_filter {
|
typedef struct sip_filter {
|
||||||
@ -150,6 +155,7 @@ public:
|
|||||||
// Caller must provide a cMutexLock which has to survive the entire
|
// Caller must provide a cMutexLock which has to survive the entire
|
||||||
// time the returned cSchedules is accessed. Once the cSchedules is no
|
// time the returned cSchedules is accessed. Once the cSchedules is no
|
||||||
// longer used, the cMutexLock must be destroyed.
|
// longer used, the cMutexLock must be destroyed.
|
||||||
|
static bool Read(FILE *f = NULL);
|
||||||
void SetStatus(bool On);
|
void SetStatus(bool On);
|
||||||
bool SetUseTSTime(bool use);
|
bool SetUseTSTime(bool use);
|
||||||
bool SetCurrentServiceID(unsigned short servid);
|
bool SetCurrentServiceID(unsigned short servid);
|
||||||
|
5
vdr.c
5
vdr.c
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
* 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>
|
#include <getopt.h>
|
||||||
@ -35,6 +35,7 @@
|
|||||||
#ifdef DVDSUPPORT
|
#ifdef DVDSUPPORT
|
||||||
#include "dvd.h"
|
#include "dvd.h"
|
||||||
#endif //DVDSUPPORT
|
#endif //DVDSUPPORT
|
||||||
|
#include "eit.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -286,6 +287,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB);
|
cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB);
|
||||||
|
|
||||||
|
cSIProcessor::Read();
|
||||||
|
|
||||||
Channels.SwitchTo(Setup.CurrentChannel);
|
Channels.SwitchTo(Setup.CurrentChannel);
|
||||||
cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true);
|
cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user