1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
--- /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);
|