vdr 2.8.1
eit.c
Go to the documentation of this file.
1/*
2 * eit.c: EIT section filter
3 *
4 * See the main source file 'vdr.c' for copyright information and
5 * how to reach the author.
6 *
7 * Original version (as used in VDR before 1.3.0) written by
8 * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
9 * Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
10 *
11 * $Id: eit.c 5.7 2026/02/04 10:06:06 kls Exp $
12 */
13
14// The various ways in which broadcasters handle (or screw up) their EPG:
15// - Some use the same version for all tables, and use unique event ids, which are the same in
16// both the 0x5X and the 0x6X tables. And once an event has an id, it keeps it until it is
17// no longer in the tables. Those are the good guys!
18// - Some use separate versions for each table (0x50, 0x51, ...).
19// - Some broadcast tables 0x5X and 0x6X, but use different event ids for the same event in both
20// sets of tables, and sometimes even use different titles, short texts or descriptions.
21// - Some broadcast the full EPG only on one transponder (tables 0x6X), and on the actual transponder
22// they provide only the present/following information.
23// - Some have overlapping events, especially when they mess up daylight saving time.
24// - Some use all new event ids every time they update their tables.
25// So, to bring order to chaos, VDR does as follows:
26// - Completely ignore table 0x4F.
27// - Once a schedule has seen events from 0x5X, tables 0x6X are ignored for that schedule.
28// - When looking up an event in its schedule, the start time is used for tables 0x6X, and the
29// event id for tables 0x4E and 0x5X.
30
31#include "eit.h"
32#include <sys/time.h>
33#include "epg.h"
34#include "i18n.h"
35#include "libsi/section.h"
36#include "libsi/descriptor.h"
37
38#define VALID_TIME (31536000 * 2) // two years
39
40#define DBGEIT 0
41
42// --- cEitTables ------------------------------------------------------------
43
45{
46 complete = false;
47 tableStart = 0;
48 tableEnd = 0;
49}
50
51bool cEitTables::Check(uchar TableId, uchar Version, int SectionNumber)
52{
53 int ti = Index(TableId);
54 return sectionSyncer[ti].Check(Version, SectionNumber);
55}
56
57bool cEitTables::Processed(uchar TableId, uchar LastTableId, int SectionNumber, int LastSectionNumber, int SegmentLastSectionNumber)
58{
59 bool Result = false;
60 int ti = Index(TableId);
61 int LastIndex = Index(LastTableId);
62 complete = false;
63 if (sectionSyncer[ti].Processed(SectionNumber, LastSectionNumber, SegmentLastSectionNumber)) {
64 Result = true; // the table with TableId is complete
65 for (int i = 0; i <= LastIndex; i++) {
66 if (!sectionSyncer[i].Complete())
67 return Result;
68 }
69 complete = true; // all tables have been processed
70 }
71 return Result;
72}
73
74// --- cEIT ------------------------------------------------------------------
75
76class cEIT : public SI::EIT {
77public:
78 cEIT(cEitTablesHash &EitTablesHash, int Source, u_char Tid, const u_char *Data);
79 };
80
81cEIT::cEIT(cEitTablesHash &EitTablesHash, int Source, u_char Tid, const u_char *Data)
82:SI::EIT(Data, false)
83{
84 if (!CheckCRCAndParse())
85 return;
86 int HashId = getServiceId();
87 cEitTables *EitTables = EitTablesHash.Get(HashId);
88 if (!EitTables) {
89 EitTables = new cEitTables;
90 EitTablesHash.Add(EitTables, HashId);
91 }
92 bool Process = EitTables->Check(Tid, getVersionNumber(), getSectionNumber());
93 if (Tid != 0x4E && !Process) // we need to set the 'seen' tag to watch the running status of the present/following event
94 return;
95
96 time_t Now = time(NULL);
97 if (Now < VALID_TIME)
98 return; // we need the current time for handling PDC descriptors
99
100 cStateKey ChannelsStateKey;
101 cChannels *Channels = cChannels::GetChannelsWrite(ChannelsStateKey, 10);
102 if (!Channels)
103 return;
105 cChannel *Channel = Channels->GetByChannelID(channelID, true);
106 if (!Channel || EpgHandlers.IgnoreChannel(Channel)) {
107 ChannelsStateKey.Remove(false);
108 return;
109 }
110
111 cStateKey SchedulesStateKey;
112 cSchedules *Schedules = cSchedules::GetSchedulesWrite(SchedulesStateKey, 10);
113 if (!Schedules) {
114 ChannelsStateKey.Remove(false);
115 return;
116 }
117
118 cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(Channel, true);
119
120 if (pSchedule->OnActualTp(Tid) && (Tid & 0xF0) == 0x60) {
121 SchedulesStateKey.Remove(false);
122 ChannelsStateKey.Remove(false);
123 return;
124 }
125
126 if (!EpgHandlers.BeginSegmentTransfer(Channel)) {
127 SchedulesStateKey.Remove(false);
128 ChannelsStateKey.Remove(false);
129 return;
130 }
131
132 bool ChannelsModified = false;
133 bool handledExternally = EpgHandlers.HandledExternally(Channel);
134
135 bool Empty = true;
136 bool Modified = false;
137 time_t LingerLimit = Now - EPG_LINGER_TIME;
138 time_t SegmentStart = 0; // these are actually "section" start/end times
139 time_t SegmentEnd = 0;
140 struct tm t = { 0 };
141 localtime_r(&Now, &t); // this initializes the time zone in 't'
142
143 SI::EIT::Event SiEitEvent;
144 for (SI::Loop::Iterator it; eventLoop.getNext(SiEitEvent, it); ) {
145 if (EpgHandlers.HandleEitEvent(pSchedule, &SiEitEvent, Tid, getVersionNumber()))
146 continue; // an EPG handler has done all of the processing
147 time_t StartTime = SiEitEvent.getStartTime();
148 int Duration = SiEitEvent.getDuration();
149 // Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
150 if (StartTime == 0 || StartTime > 0 && Duration == 0)
151 continue;
152 Empty = false;
153 // Ignore events that ended before the "EPG linger time":
154 if (StartTime + Duration < LingerLimit)
155 continue;
156 if (!SegmentStart)
157 SegmentStart = StartTime;
158 SegmentEnd = StartTime + Duration;
159 if (Tid == 0x4E) {
160 if (getSectionNumber() == 0)
161 EitTables->SetTableStart(SegmentStart);
162 else
163 EitTables->SetTableEnd(SegmentEnd);
164 }
165 cEvent *newEvent = NULL;
166 cEvent *rEvent = NULL;
167 cEvent *pEvent = NULL;
168 if (Tid == 0x4E || (Tid & 0xF0) == 0x50)
169 pEvent = const_cast<cEvent *>(pSchedule->GetEventById(SiEitEvent.getEventId()));
170 else
171 pEvent = const_cast<cEvent *>(pSchedule->GetEventByTime(StartTime));
172 if (!pEvent || handledExternally) {
173 if (handledExternally && !EpgHandlers.IsUpdate(SiEitEvent.getEventId(), StartTime, Tid, getVersionNumber()))
174 continue;
175 // If we don't have that event yet, we create a new one.
176 // Otherwise we copy the information into the existing event anyway, because the data might have changed.
177 pEvent = newEvent = new cEvent(SiEitEvent.getEventId());
178 newEvent->SetStartTime(StartTime);
179 newEvent->SetDuration(Duration);
180 if (!handledExternally)
181 pSchedule->AddEvent(newEvent);
182 }
183 else {
184 // We have found an existing event, either through its event ID or its start time.
185 pEvent->SetSeen();
186 uchar TableID = max(pEvent->TableID(), uchar(0x4E)); // for backwards compatibility, table ids less than 0x4E are treated as if they were "present"
187 // We never overwrite present/following with events from other tables:
188 if (TableID == 0x4E && Tid != 0x4E)
189 continue;
190 if (pEvent->HasTimer()) {
191 if (pEvent->StartTime() != StartTime || pEvent->Duration() != Duration)
192 dsyslog("channel %d (%s) event %s times changed to %s-%s", Channel->Number(), Channel->Name(), *pEvent->ToDescr(), *TimeString(StartTime), *TimeString(StartTime + Duration));
193 }
194 EpgHandlers.SetEventID(pEvent, SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-(
195 EpgHandlers.SetStartTime(pEvent, StartTime);
196 EpgHandlers.SetDuration(pEvent, Duration);
197 }
198 if (pEvent->TableID() > 0x4E) // for backwards compatibility, table ids less than 0x4E are never overwritten
199 pEvent->SetTableID(Tid);
200 if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
201 int RunningStatus = SiEitEvent.getRunningStatus();
202#if DBGEIT
203 if (Process)
204 dsyslog("channel %d (%s) event %s status %d (raw data from '%s' section)", Channel->Number(), Channel->Name(), *pEvent->ToDescr(), RunningStatus, getSectionNumber() ? "following" : "present");
205#endif
206 if (RunningStatus >= SI::RunningStatusNotRunning) {
207 // Workaround for broadcasters who set an event to status "not running" where
208 // this is inappropriate:
209 if (RunningStatus != pEvent->RunningStatus()) { // if the running status of the event has changed...
210 if (RunningStatus == SI::RunningStatusNotRunning) { // ...and the new status is "not running"...
211 int OverrideStatus = -1;
212 if (getSectionNumber() == 0) { // ...and if this the "present" event...
213 if (pEvent->RunningStatus() == SI::RunningStatusPausing) // ...and if the event has already been set to "pausing"...
214 OverrideStatus = SI::RunningStatusPausing; // ...then we ignore the faulty new status and stay with "pausing"
215 }
216 else // ...and if this is the "following" event...
217 OverrideStatus = SI::RunningStatusUndefined; // ...then we ignore the faulty new status and fall back to "undefined"
218 if (OverrideStatus >= 0) {
219#if DBGEIT
220 if (Process)
221 dsyslog("channel %d (%s) event %s status %d (ignored status %d from '%s' section)", Channel->Number(), Channel->Name(), *pEvent->ToDescr(), OverrideStatus, RunningStatus, getSectionNumber() ? "following" : "present");
222#endif
223 RunningStatus = OverrideStatus;
224 }
225 }
226 }
227 pSchedule->SetRunningStatus(pEvent, RunningStatus, Channel);
228 }
229 if (!Process)
230 continue;
231 }
232 pEvent->SetVersion(getVersionNumber());
233
234 int LanguagePreferenceShort = -1;
235 int LanguagePreferenceExt = -1;
236 bool UseExtendedEventDescriptor = false;
238 SI::ExtendedEventDescriptors *ExtendedEventDescriptors = NULL;
239 SI::ShortEventDescriptor *ShortEventDescriptor = NULL;
240 cLinkChannels *LinkChannels = NULL;
241 cComponents *Components = NULL;
242 for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) {
243 switch (d->getDescriptorTag()) {
246 if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt) || !ExtendedEventDescriptors) {
247 delete ExtendedEventDescriptors;
248 ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
249 UseExtendedEventDescriptor = true;
250 }
251 if (UseExtendedEventDescriptor) {
252 if (ExtendedEventDescriptors->Add(eed))
253 d = NULL; // so that it is not deleted
254 }
255 if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
256 UseExtendedEventDescriptor = false;
257 }
258 break;
261 if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort) || !ShortEventDescriptor) {
262 delete ShortEventDescriptor;
263 ShortEventDescriptor = sed;
264 d = NULL; // so that it is not deleted
265 }
266 }
267 break;
271 int NumContents = 0;
272 uchar Contents[MaxEventContents] = { 0 };
273 for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) {
274 if (NumContents < MaxEventContents) {
275 Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF);
276 NumContents++;
277 }
278 }
279 EpgHandlers.SetContents(pEvent, Contents);
280 }
281 break;
283 int LanguagePreferenceRating = -1;
286 for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) {
287 if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) {
288 int ParentalRating = (Rating.getRating() & 0xFF);
289 switch (ParentalRating) {
290 // values defined by the DVB standard (minimum age = rating + 3 years):
291 case 0x01 ... 0x0F: ParentalRating += 3; break;
292 // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?):
293 case 0x11: ParentalRating = 10; break;
294 case 0x12: ParentalRating = 12; break;
295 case 0x13: ParentalRating = 16; break;
296 default: ParentalRating = 0;
297 }
298 EpgHandlers.SetParentalRating(pEvent, ParentalRating);
299 }
300 }
301 }
302 break;
305 t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
306 int month = t.tm_mon;
307 t.tm_mon = pd->getMonth() - 1;
308 t.tm_mday = pd->getDay();
309 t.tm_hour = pd->getHour();
310 t.tm_min = pd->getMinute();
311 t.tm_sec = 0;
312 if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
313 t.tm_year++;
314 else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
315 t.tm_year--;
316 time_t vps = mktime(&t);
317 EpgHandlers.SetVps(pEvent, vps);
318 }
319 break;
322 cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, Channel->Nid(), Channel->Tid(), tsed->getReferenceServiceId()));
323 if (!rSchedule)
324 break;
325 rEvent = (cEvent *)rSchedule->GetEventById(tsed->getReferenceEventId());
326 if (!rEvent)
327 break;
328 EpgHandlers.SetTitle(pEvent, rEvent->Title());
329 EpgHandlers.SetShortText(pEvent, rEvent->ShortText());
330 EpgHandlers.SetDescription(pEvent, rEvent->Description());
331 }
332 break;
335 tChannelID linkID(Source, ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
336 if (ld->getLinkageType() == SI::LinkageTypePremiere) { // Premiere World
337 bool hit = StartTime <= Now && Now < StartTime + Duration;
338 if (hit) {
339 char linkName[ld->privateData.getLength() + 1];
340 strn0cpy(linkName, (const char *)ld->privateData.getData(), sizeof(linkName));
341 // TODO is there a standard way to determine the character set of this string?
342 cChannel *link = Channels->GetByChannelID(linkID);
343 if (link != Channel) { // only link to other channels, not the same one
344 if (link) {
345 if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
346 ChannelsModified |= link->SetName(linkName, "", "");
347 }
348 else if (Setup.UpdateChannels >= 4) {
349 cChannel *Transponder = Channel;
350 if (Channel->Tid() != ld->getTransportStreamId())
351 Transponder = Channels->GetByTransponderID(linkID);
352 link = Channels->NewChannel(Transponder, linkName, "", "", ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId());
353 ChannelsModified = true;
354 //XXX patFilter->Trigger();
355 }
356 if (link) {
357 if (!LinkChannels)
358 LinkChannels = new cLinkChannels;
359 LinkChannels->Add(new cLinkChannel(link));
360 }
361 }
362 else
363 ChannelsModified |= Channel->SetPortalName(linkName);
364 }
365 }
366 }
367 break;
370 uchar Stream = cd->getStreamContent();
371 uchar Ext = cd->getStreamContentExt();
372 uchar Type = cd->getComponentType();
373 if ((1 <= Stream && Stream <= 6 && Type != 0) // 1=MPEG2-video, 2=MPEG1-audio, 3=subtitles, 4=AC3-audio, 5=H.264-video, 6=HEAAC-audio
374 || (Stream == 9 && Ext < 2)) { // 0x09=HEVC-video, 0x19=AC-4-audio
375 if (!Components)
376 Components = new cComponents;
377 char buffer[Utf8BufSize(256)];
378 if (Stream == 9)
379 Stream |= Ext << 4;
380 Components->SetComponent(Components->NumComponents(), Stream, Type, I18nNormalizeLanguageCode(cd->languageCode), cd->description.getText(buffer, sizeof(buffer)));
381 }
382 }
383 break;
384 default: ;
385 }
386 delete d;
387 }
388
389 if (!rEvent) {
390 if (ShortEventDescriptor) {
391 char buffer[Utf8BufSize(256)];
392 EpgHandlers.SetTitle(pEvent, ShortEventDescriptor->name.getText(buffer, sizeof(buffer)));
393 EpgHandlers.SetShortText(pEvent, ShortEventDescriptor->text.getText(buffer, sizeof(buffer)));
394 EpgHandlers.SetLanguage(pEvent, I18nNormalizeLanguageCode(ShortEventDescriptor->languageCode));
395 }
396 else {
397 EpgHandlers.SetTitle(pEvent, NULL);
398 EpgHandlers.SetShortText(pEvent, NULL);
399 }
400 if (ExtendedEventDescriptors) {
401 char buffer[Utf8BufSize(ExtendedEventDescriptors->getMaximumTextLength(": ")) + 1];
402 EpgHandlers.SetDescription(pEvent, ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": "));
403 }
404 else
405 EpgHandlers.SetDescription(pEvent, NULL);
406 }
407 delete ExtendedEventDescriptors;
408 delete ShortEventDescriptor;
409
410 EpgHandlers.SetComponents(pEvent, Components);
411
412 EpgHandlers.FixEpgBugs(pEvent);
413 if (LinkChannels)
414 ChannelsModified |= Channel->SetLinkChannels(LinkChannels);
415 Modified = true;
416 EpgHandlers.HandleEvent(pEvent);
417 if (handledExternally)
418 delete pEvent;
419 }
420 if (Tid == 0x4E) {
421 if (Empty && getSectionNumber() == 0)
422 // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
423 pSchedule->ClrRunningStatus(Channel);
424 pSchedule->SetPresentSeen();
425 }
426 if (Process) {
428 if (Modified && (Tid >= 0x50 || Complete)) { // we process the 0x5X tables segment by segment, but 0x4E only if we have received ALL its segments (0 and 1, i.e. "present" and "following")
429 if (Tid == 0x4E && getLastSectionNumber() == 1) {
430 SegmentStart = EitTables->TableStart();
431 SegmentEnd = EitTables->TableEnd();
432 }
433 EpgHandlers.SortSchedule(pSchedule);
434 EpgHandlers.DropOutdated(pSchedule, SegmentStart, SegmentEnd, Tid, getVersionNumber());
435 }
436 }
437 EpgHandlers.EndSegmentTransfer(Modified);
438 SchedulesStateKey.Remove(Modified);
439 ChannelsStateKey.Remove(ChannelsModified);
440}
441
442// --- cTDT ------------------------------------------------------------------
443
444#define MAX_TIME_DIFF 1 // number of seconds the local time may differ from dvb time before making any corrections
445#define MAX_ADJ_DIFF 10 // number of seconds the local time may differ from dvb time to allow smooth adjustment
446#define ADJ_DELTA 300 // number of seconds between calls for smooth time adjustment
447
448class cTDT : public SI::TDT {
449private:
450 static cMutex mutex;
451 static time_t lastAdj;
452public:
453 cTDT(const u_char *Data);
454 };
455
457time_t cTDT::lastAdj = 0;
458
459cTDT::cTDT(const u_char *Data)
460:SI::TDT(Data, false)
461{
462 CheckParse();
463
464 time_t dvbtim = getTime();
465 time_t loctim = time(NULL);
466
467 int diff = dvbtim - loctim;
468 if (abs(diff) > MAX_TIME_DIFF) {
469 mutex.Lock();
470 if (abs(diff) > MAX_ADJ_DIFF) {
471 timespec ts = {};
472 ts.tv_sec = dvbtim;
473 if (clock_settime(CLOCK_REALTIME, &ts) == 0)
474 isyslog("system time changed from %s (%jd) to %s (%jd)", *TimeToString(loctim), intmax_t(loctim), *TimeToString(dvbtim), intmax_t(dvbtim));
475 else
476 esyslog("ERROR while setting system time: %m");
477 }
478 else if (time(NULL) - lastAdj > ADJ_DELTA) {
479 lastAdj = time(NULL);
480 timeval delta;
481 delta.tv_sec = diff;
482 delta.tv_usec = 0;
483 if (adjtime(&delta, NULL) == 0)
484 isyslog("system time adjustment initiated from %s (%jd) to %s (%jd)", *TimeToString(loctim), intmax_t(loctim), *TimeToString(dvbtim), intmax_t(dvbtim));
485 else
486 esyslog("ERROR while adjusting system time: %m");
487 }
488 mutex.Unlock();
489 }
490}
491
492// --- cEitFilter ------------------------------------------------------------
493
494time_t cEitFilter::disableUntil = 0;
495
497{
498 Set(0x12, 0x40, 0xC0); // event info present&following actual/other TS (0x4E/0x4F), future actual/other TS (0x5X/0x6X)
499 Set(0x14, 0x70); // TDT
500}
501
503{
504 cMutexLock MutexLock(&mutex);
506 eitTablesHash.Clear();
507}
508
510{
511 disableUntil = Time;
512}
513
514void cEitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
515{
516 cMutexLock MutexLock(&mutex);
517 if (disableUntil) {
518 if (time(NULL) > disableUntil)
519 disableUntil = 0;
520 else
521 return;
522 }
523 switch (Pid) {
524 case 0x12: {
525 if (Tid == 0x4E || Tid >= 0x50 && Tid <= 0x6F) // we ignore 0x4F, which only causes trouble
526 cEIT EIT(eitTablesHash, Source(), Tid, Data);
527 }
528 break;
529 case 0x14: {
530 if (Setup.SetSystemTime && Setup.TimeSource == Source() && Setup.TimeTransponder && ISTRANSPONDER(Transponder(), Setup.TimeTransponder))
531 cTDT TDT(Data);
532 }
533 break;
534 default: ;
535 }
536}
#define ISTRANSPONDER(f1, f2)
Definition channels.h:18
bool CheckCRCAndParse()
Definition si.c:65
int getLength() const
Definition util.h:58
const unsigned char * getData() const
Definition util.h:51
int getComponentType() const
Definition descriptor.c:575
int getStreamContentExt() const
Definition descriptor.c:571
int getStreamContent() const
Definition descriptor.c:567
StructureLoop< Nibble > nibbleLoop
Definition descriptor.h:102
bool Add(GroupDescriptor *d)
Definition si.c:201
Descriptor * getNext(Iterator &it)
Definition si.c:112
DescriptorTag getDescriptorTag() const
Definition si.c:100
DescriptorLoop eventDescriptors
Definition section.h:170
time_t getDuration() const
Definition section.c:201
time_t getStartTime() const
Definition section.c:197
int getEventId() const
Definition section.c:205
RunningStatus getRunningStatus() const
Definition section.c:237
int getOriginalNetworkId() const
Definition section.c:168
int getSegmentLastSectionNumber() const
Definition section.c:172
StructureLoop< Event > eventLoop
Definition section.h:182
int getServiceId() const
Definition section.c:160
int getTransportStreamId() const
Definition section.c:164
int getLastTableId() const
Definition section.c:176
EIT(const unsigned char *data, bool doCopy=true)
Definition section.h:152
char * getText(const char *separation1="\t", const char *separation2="\n")
Definition descriptor.c:86
int getMaximumTextLength(const char *separation1="\t", const char *separation2="\n")
Definition descriptor.c:81
int getOriginalNetworkId() const
Definition descriptor.c:772
int getTransportStreamId() const
Definition descriptor.c:768
int getServiceId() const
Definition descriptor.c:776
LinkageType getLinkageType() const
Definition descriptor.c:780
int getSectionNumber() const
Definition si.c:88
int getLastSectionNumber() const
Definition si.c:92
int getVersionNumber() const
Definition si.c:84
int getDay() const
Definition descriptor.c:828
int getMinute() const
Definition descriptor.c:840
int getHour() const
Definition descriptor.c:836
int getMonth() const
Definition descriptor.c:832
StructureLoop< Rating > ratingLoop
Definition descriptor.h:119
void CheckParse()
Definition util.c:182
char * getText()
Definition si.c:222
TDT(const unsigned char *data, bool doCopy=true)
Definition section.h:196
time_t getTime() const
Definition section.c:254
int Nid(void) const
Definition channels.h:174
bool SetName(const char *Name, const char *ShortName, const char *Provider)
Definition channels.c:268
int Tid(void) const
Definition channels.h:175
bool SetPortalName(const char *PortalName)
Definition channels.c:293
bool SetLinkChannels(cLinkChannels *LinkChannels)
Definition channels.c:494
int Number(void) const
Definition channels.h:179
const char * Name(void) const
Definition channels.c:121
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition channels.c:861
cChannel * NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid=0)
Definition channels.c:1106
const cChannel * GetByTransponderID(tChannelID ChannelID) const
Definition channels.c:1041
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition channels.c:1011
int NumComponents(void) const
Definition epg.h:62
void SetComponent(int Index, const char *s)
Definition epg.c:77
Definition eit.c:76
cEIT(cEitTablesHash &EitTablesHash, int Source, u_char Tid, const u_char *Data)
Definition eit.c:81
cMutex mutex
Definition eit.h:50
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length) override
Processes the data delivered to this filter.
Definition eit.c:514
static void SetDisableUntil(time_t Time)
Definition eit.c:509
cEitTablesHash eitTablesHash
Definition eit.h:51
cEitFilter(void)
Definition eit.c:496
static time_t disableUntil
Definition eit.h:52
virtual void SetStatus(bool On) override
Turns this filter on or off, depending on the value of On.
Definition eit.c:502
bool complete
Definition eit.h:28
time_t tableStart
Definition eit.h:26
void SetTableStart(time_t t)
Definition eit.h:32
bool Processed(uchar TableId, uchar LastTableId, int SectionNumber, int LastSectionNumber, int SegmentLastSectionNumber=-1)
Returns true if all sections of the table with the given TableId have been processed.
Definition eit.c:57
cEitTables(void)
Definition eit.c:44
cSectionSyncerRandom sectionSyncer[NUM_EIT_TABLES]
Definition eit.h:25
bool Complete(void)
Returns true if all sections of all tables have been processed.
Definition eit.h:39
void SetTableEnd(time_t t)
Definition eit.h:33
time_t TableEnd(void)
Definition eit.h:35
time_t tableEnd
Definition eit.h:27
bool Check(uchar TableId, uchar Version, int SectionNumber)
Definition eit.c:51
time_t TableStart(void)
Definition eit.h:34
Definition epg.h:74
const char * ShortText(void) const
Definition epg.h:109
cString ToDescr(void) const
Definition epg.c:257
void SetSeen(void)
Definition epg.c:246
uchar TableID(void) const
Definition epg.h:104
int RunningStatus(void) const
Definition epg.h:106
const char * Description(void) const
Definition epg.h:110
time_t StartTime(void) const
Definition epg.h:114
const char * Title(void) const
Definition epg.h:108
void SetStartTime(time_t StartTime)
Definition epg.c:225
bool HasTimer(void) const
Definition epg.h:123
int Duration(void) const
Definition epg.h:116
void SetVersion(uchar Version)
Definition epg.c:176
void SetDuration(int Duration)
Definition epg.c:236
void SetTableID(uchar TableID)
Definition epg.c:171
void Set(u_short Pid, u_char Tid, u_char Mask=0xFF)
Sets the given filter data by calling Add() with Sticky = true.
Definition filter.c:182
int Transponder(void)
Returns the transponder of the data delivered to this filter.
Definition filter.c:139
virtual void SetStatus(bool On)
Turns this filter on or off, depending on the value of On.
Definition filter.c:149
int Source(void)
Returns the source of the data delivered to this filter.
Definition filter.c:134
void Add(cListObject *Object, unsigned int Id)
Definition tools.c:2393
T * Get(unsigned int Id) const
Definition tools.h:935
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2194
int Index(void) const
Definition tools.c:2114
void SetRunningStatus(cEvent *Event, int RunningStatus, const cChannel *Channel=NULL)
Definition epg.c:1074
const cEvent * GetEventByTime(time_t StartTime) const
Definition epg.c:1053
bool OnActualTp(uchar TableId)
Definition epg.c:968
void SetPresentSeen(void)
Definition epg.h:175
void ClrRunningStatus(cChannel *Channel=NULL)
Definition epg.c:1089
const cEvent * GetEventById(tEventID EventID) const
Definition epg.c:1048
cEvent * AddEvent(cEvent *Event)
Definition epg.c:975
static cSchedules * GetSchedulesWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for write access.
Definition epg.c:1296
const cSchedule * GetSchedule(tChannelID ChannelID) const
Definition epg.c:1396
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition thread.c:870
Definition eit.c:448
static cMutex mutex
Definition eit.c:450
cTDT(const u_char *Data)
Definition eit.c:459
static time_t lastAdj
Definition eit.c:451
cSetup Setup
Definition config.c:372
#define MAX_ADJ_DIFF
Definition eit.c:445
#define MAX_TIME_DIFF
Definition eit.c:444
#define VALID_TIME
Definition eit.c:38
#define ADJ_DELTA
Definition eit.c:446
cEpgHandlers EpgHandlers
Definition epg.c:1457
@ MaxEventContents
Definition epg.h:26
#define EPG_LINGER_TIME
Definition epg.h:24
bool I18nIsPreferredLanguage(int *PreferredLanguages, const char *LanguageCode, int &OldPreference, int *Position)
Checks the given LanguageCode (which may be something like "eng" or "eng+deu") against the PreferredL...
Definition i18n.c:331
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition i18n.c:300
@ RunningStatusUndefined
Definition si.h:196
@ RunningStatusPausing
Definition si.h:199
@ RunningStatusNotRunning
Definition si.h:197
@ ExtendedEventDescriptorTag
Definition si.h:91
@ ShortEventDescriptorTag
Definition si.h:90
@ ComponentDescriptorTag
Definition si.h:93
@ ParentalRatingDescriptorTag
Definition si.h:98
@ PDCDescriptorTag
Definition si.h:118
@ ContentDescriptorTag
Definition si.h:97
@ TimeShiftedEventDescriptorTag
Definition si.h:92
@ LinkageDescriptorTag
Definition si.h:87
@ LinkageTypePremiere
Definition si.h:213
cString TimeString(time_t t)
Converts the given time to a string of the form "hh:mm".
Definition tools.c:1318
cString TimeToString(time_t t)
Converts the given time to a string of the form "www mmm dd hh:mm:ss yyyy".
Definition tools.c:1288
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:131
unsigned char uchar
Definition tools.h:31
#define dsyslog(a...)
Definition tools.h:37
T max(T a, T b)
Definition tools.h:64
#define esyslog(a...)
Definition tools.h:35
#define Utf8BufSize(s)
Definition tools.h:143
#define isyslog(a...)
Definition tools.h:36