--- /home/wendel/vdr-1.7.27.plain//eit.c 2012-03-14 11:11:15.000000000 +0100 +++ eit.c 2012-10-01 09:38:51.526839349 +0200 @@ -45,6 +45,7 @@ return; } + bool handledExternally = EpgHandlers.HandledExternally(channel); cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channel, true); bool Empty = true; @@ -70,14 +71,18 @@ cEvent *newEvent = NULL; cEvent *rEvent = NULL; cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), StartTime); - if (!pEvent) { + if (!pEvent || handledExternally) { if (OnlyRunningStatus) continue; + if (handledExternally) + if (!EpgHandlers.IsUpdate(SiEitEvent.getEventId(), StartTime, Tid, getVersionNumber())) + continue; // If we don't have that event yet, we create a new one. // Otherwise we copy the information into the existing event anyway, because the data might have changed. pEvent = newEvent = new cEvent(SiEitEvent.getEventId()); newEvent->SetStartTime(StartTime); newEvent->SetDuration(Duration); + if (!handledExternally) pSchedule->AddEvent(newEvent); } else { @@ -290,6 +295,9 @@ channel->SetLinkChannels(LinkChannels); Modified = true; EpgHandlers.HandleEvent(pEvent); + + if (handledExternally) + delete pEvent; } if (Tid == 0x4E) { if (Empty && getSectionNumber() == 0) --- /home/wendel/vdr-1.7.27.plain//epg.c 2012-03-10 14:14:27.000000000 +0100 +++ epg.c 2012-10-01 09:41:35.010845128 +0200 @@ -18,6 +18,7 @@ #include "timers.h" #define RUNNINGSTATUSTIMEOUT 30 // seconds before the running status is considered unknown +#define EPGDATAWRITEDELTA 600 // seconds between writing the epg.data file // --- tComponent ------------------------------------------------------------ @@ -1109,6 +1110,47 @@ return false; } +// --- cEpgDataWriter --------------------------------------------------------- + +class cEpgDataWriter : public cThread { +private: + cMutex mutex; +protected: + virtual void Action(void); +public: + cEpgDataWriter(void); + void Perform(void); + }; + +cEpgDataWriter::cEpgDataWriter(void) +:cThread("epg data writer") +{ +} + +void cEpgDataWriter::Action(void) +{ + SetPriority(19); + SetIOPriority(7); + Perform(); +} + +void cEpgDataWriter::Perform(void) +{ + cMutexLock MutexLock(&mutex); // to make sure fore- and background calls don't cause parellel dumps! + { + cSchedulesLock SchedulesLock(true, 1000); + cSchedules *s = (cSchedules *)cSchedules::Schedules(SchedulesLock); + if (s) { + time_t now = time(NULL); + for (cSchedule *p = s->First(); p; p = s->Next(p)) + p->Cleanup(now); + } + } + cSchedules::Dump(); +} + +static cEpgDataWriter EpgDataWriter; + // --- cSchedulesLock -------------------------------------------------------- cSchedulesLock::cSchedulesLock(bool WriteLock, int TimeoutMs) @@ -1152,28 +1194,13 @@ if (Force) lastDump = 0; time_t now = time(NULL); - struct tm tm_r; - struct tm *ptm = localtime_r(&now, &tm_r); - if (now - lastCleanup > 3600) { - isyslog("cleaning up schedules data"); - cSchedulesLock SchedulesLock(true, 1000); - cSchedules *s = (cSchedules *)Schedules(SchedulesLock); - if (s) { - for (cSchedule *p = s->First(); p; p = s->Next(p)) - p->Cleanup(now); - } - lastCleanup = now; - if (ptm->tm_hour == 5) - ReportEpgBugFixStats(true); - } - if (epgDataFileName && now - lastDump > 600) { - cSafeFile f(epgDataFileName); - if (f.Open()) { - Dump(f); - f.Close(); + if (now - lastDump > EPGDATAWRITEDELTA) { + if (epgDataFileName) { + if (Force) + EpgDataWriter.Perform(); + else if (!EpgDataWriter.Active()) + EpgDataWriter.Start(); } - else - LOG_ERROR; lastDump = now; } } @@ -1207,8 +1234,23 @@ cSchedulesLock SchedulesLock; cSchedules *s = (cSchedules *)Schedules(SchedulesLock); if (s) { + cSafeFile *sf = NULL; + if (!f) { + sf = new cSafeFile(epgDataFileName); + if (sf->Open()) + f = *sf; + else { + LOG_ERROR; + delete sf; + return false; + } + } for (cSchedule *p = s->First(); p; p = s->Next(p)) p->Dump(f, Prefix, DumpMode, AtTime); + if (sf) { + sf->Close(); + delete sf; + } return true; } return false; @@ -1329,6 +1371,24 @@ return true; } return false; +} + +bool cEpgHandlers::HandledExternally(const cChannel *Channel) +{ + for (cEpgHandler *eh = First(); eh; eh = Next(eh)) { + if (eh->HandledExternally(Channel)) + return true; + } + return false; +} + +bool cEpgHandlers::IsUpdate(tEventID EventID, time_t StartTime, uchar TableID, uchar Version) +{ + for (cEpgHandler *eh = First(); eh; eh = Next(eh)) { + if (eh->IsUpdate(EventID, StartTime, TableID, Version)) + return true; + } + return false; } void cEpgHandlers::SetEventID(cEvent *Event, tEventID EventID) --- /home/wendel/vdr-1.7.27.plain//epg.h 2012-03-10 14:50:10.000000000 +0100 +++ epg.h 2012-10-01 09:43:28.162849134 +0200 @@ -207,7 +207,7 @@ static void Cleanup(bool Force = false); static void ResetVersions(void); static bool ClearAll(void); - static bool Dump(FILE *f, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0); + static bool Dump(FILE *f = NULL, const char *Prefix = "", eDumpMode DumpMode = dmAll, time_t AtTime = 0); static bool Read(FILE *f = NULL); cSchedule *AddSchedule(tChannelID ChannelID); const cSchedule *GetSchedule(tChannelID ChannelID) const; @@ -244,6 +244,16 @@ ///< EPG handlers are queried to see if any of them would like to do the ///< complete processing by itself. TableID and Version are from the ///< incoming section data. + virtual bool HandledExternally(const cChannel *Channel) { return false; } + ///< If any EPG handler returns true in this function, it is assumed that + ///< the EPG for the given Channel is handled completely from some external + ///< source. Incoming EIT data is processed as usual, but any new EPG event + ///< will not be added to the respective schedule. It's up to the EPG + ///< handler to take care of this. + virtual bool IsUpdate(tEventID EventID, time_t StartTime, uchar TableID, uchar Version) { return false; } + ///< VDR can't perform the update check (version, tid) for external handled events + ///< therefore the handle have to take care. Otherwise the parsing of 'non' updates will + ///< take a lot of resources virtual bool SetEventID(cEvent *Event, tEventID EventID) { return false; } virtual bool SetTitle(cEvent *Event, const char *Title) { return false; } virtual bool SetShortText(cEvent *Event, const char *ShortText) { return false; } @@ -269,6 +279,8 @@ public: bool IgnoreChannel(const cChannel *Channel); bool HandleEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version); + bool HandledExternally(const cChannel *Channel); + bool IsUpdate(tEventID EventID, time_t StartTime, uchar TableID, uchar Version); void SetEventID(cEvent *Event, tEventID EventID); void SetTitle(cEvent *Event, const char *Title); void SetShortText(cEvent *Event, const char *ShortText);