vdr  2.6.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.4 2021/12/11 20:58:51 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 
51 bool cEitTables::Check(uchar TableId, uchar Version, int SectionNumber)
52 {
53  int ti = Index(TableId);
54  return sectionSyncer[ti].Check(Version, SectionNumber);
55 }
56 
57 bool 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 
76 class cEIT : public SI::EIT {
77 public:
78  cEIT(cEitTablesHash &EitTablesHash, int Source, u_char Tid, const u_char *Data);
79  };
80 
81 cEIT::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
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;
237  SI::Descriptor *d;
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;
303  case SI::PDCDescriptorTag: {
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  }
395  else {
396  EpgHandlers.SetTitle(pEvent, NULL);
397  EpgHandlers.SetShortText(pEvent, NULL);
398  }
399  if (ExtendedEventDescriptors) {
400  char buffer[Utf8BufSize(ExtendedEventDescriptors->getMaximumTextLength(": ")) + 1];
401  EpgHandlers.SetDescription(pEvent, ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": "));
402  }
403  else
404  EpgHandlers.SetDescription(pEvent, NULL);
405  }
406  delete ExtendedEventDescriptors;
407  delete ShortEventDescriptor;
408 
409  EpgHandlers.SetComponents(pEvent, Components);
410 
411  EpgHandlers.FixEpgBugs(pEvent);
412  if (LinkChannels)
413  ChannelsModified |= Channel->SetLinkChannels(LinkChannels);
414  Modified = true;
415  EpgHandlers.HandleEvent(pEvent);
416  if (handledExternally)
417  delete pEvent;
418  }
419  if (Tid == 0x4E) {
420  if (Empty && getSectionNumber() == 0)
421  // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
422  pSchedule->ClrRunningStatus(Channel);
423  pSchedule->SetPresentSeen();
424  }
425  if (Process) {
427  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")
428  if (Tid == 0x4E && getLastSectionNumber() == 1) {
429  SegmentStart = EitTables->TableStart();
430  SegmentEnd = EitTables->TableEnd();
431  }
432  EpgHandlers.SortSchedule(pSchedule);
433  EpgHandlers.DropOutdated(pSchedule, SegmentStart, SegmentEnd, Tid, getVersionNumber());
434  }
435  }
437  SchedulesStateKey.Remove(Modified);
438  ChannelsStateKey.Remove(ChannelsModified);
439 }
440 
441 // --- cTDT ------------------------------------------------------------------
442 
443 #define MAX_TIME_DIFF 1 // number of seconds the local time may differ from dvb time before making any corrections
444 #define MAX_ADJ_DIFF 10 // number of seconds the local time may differ from dvb time to allow smooth adjustment
445 #define ADJ_DELTA 300 // number of seconds between calls for smooth time adjustment
446 
447 class cTDT : public SI::TDT {
448 private:
449  static cMutex mutex;
450  static time_t lastAdj;
451 public:
452  cTDT(const u_char *Data);
453  };
454 
456 time_t cTDT::lastAdj = 0;
457 
458 cTDT::cTDT(const u_char *Data)
459 :SI::TDT(Data, false)
460 {
461  CheckParse();
462 
463  time_t dvbtim = getTime();
464  time_t loctim = time(NULL);
465 
466  int diff = dvbtim - loctim;
467  if (abs(diff) > MAX_TIME_DIFF) {
468  mutex.Lock();
469  if (abs(diff) > MAX_ADJ_DIFF) {
470  timespec ts = {};
471  ts.tv_sec = dvbtim;
472  if (clock_settime(CLOCK_REALTIME, &ts) == 0)
473  isyslog("system time changed from %s (%ld) to %s (%ld)", *TimeToString(loctim), loctim, *TimeToString(dvbtim), dvbtim);
474  else
475  esyslog("ERROR while setting system time: %m");
476  }
477  else if (time(NULL) - lastAdj > ADJ_DELTA) {
478  lastAdj = time(NULL);
479  timeval delta;
480  delta.tv_sec = diff;
481  delta.tv_usec = 0;
482  if (adjtime(&delta, NULL) == 0)
483  isyslog("system time adjustment initiated from %s (%ld) to %s (%ld)", *TimeToString(loctim), loctim, *TimeToString(dvbtim), dvbtim);
484  else
485  esyslog("ERROR while adjusting system time: %m");
486  }
487  mutex.Unlock();
488  }
489 }
490 
491 // --- cEitFilter ------------------------------------------------------------
492 
493 time_t cEitFilter::disableUntil = 0;
494 
496 {
497  Set(0x12, 0x40, 0xC0); // event info present&following actual/other TS (0x4E/0x4F), future actual/other TS (0x5X/0x6X)
498  Set(0x14, 0x70); // TDT
499 }
500 
502 {
503  cMutexLock MutexLock(&mutex);
504  cFilter::SetStatus(On);
506 }
507 
509 {
510  disableUntil = Time;
511 }
512 
513 void cEitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
514 {
515  cMutexLock MutexLock(&mutex);
516  if (disableUntil) {
517  if (time(NULL) > disableUntil)
518  disableUntil = 0;
519  else
520  return;
521  }
522  switch (Pid) {
523  case 0x12: {
524  if (Tid == 0x4E || Tid >= 0x50 && Tid <= 0x6F) // we ignore 0x4F, which only causes trouble
525  cEIT EIT(eitTablesHash, Source(), Tid, Data);
526  }
527  break;
528  case 0x14: {
530  cTDT TDT(Data);
531  }
532  break;
533  default: ;
534  }
535 }
#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
int getContentNibbleLevel1() const
Definition: descriptor.c:289
int getContentNibbleLevel2() const
Definition: descriptor.c:293
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
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
time_t getTime() const
Definition: section.c:254
int Nid(void) const
Definition: channels.h:173
bool SetName(const char *Name, const char *ShortName, const char *Provider)
Definition: channels.c:262
int Tid(void) const
Definition: channels.h:174
bool SetPortalName(const char *PortalName)
Definition: channels.c:290
bool SetLinkChannels(cLinkChannels *LinkChannels)
Definition: channels.c:491
int Number(void) const
Definition: channels.h:178
const char * Name(void) const
Definition: channels.c:107
static cChannels * GetChannelsWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of channels for write access.
Definition: channels.c:860
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:1105
const cChannel * GetByTransponderID(tChannelID ChannelID) const
Definition: channels.c:1040
const cChannel * GetByChannelID(tChannelID ChannelID, bool TryWithoutRid=false, bool TryWithoutPolarization=false) const
Definition: channels.c:1010
int NumComponents(void) const
Definition: epg.h:61
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)
Processes the data delivered to this filter.
Definition: eit.c:513
static void SetDisableUntil(time_t Time)
Definition: eit.c:508
cEitTablesHash eitTablesHash
Definition: eit.h:51
virtual void SetStatus(bool On)
Turns this filter on or off, depending on the value of On.
Definition: eit.c:501
cEitFilter(void)
Definition: eit.c:495
static time_t disableUntil
Definition: eit.h:52
Definition: eit.h:23
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
void SortSchedule(cSchedule *Schedule)
Definition: epg.c:1574
void EndSegmentTransfer(bool Modified)
Definition: epg.c:1601
bool IgnoreChannel(const cChannel *Channel)
Definition: epg.c:1431
bool HandleEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version)
Definition: epg.c:1440
void SetStartTime(cEvent *Event, time_t StartTime)
Definition: epg.c:1521
void SetTitle(cEvent *Event, const char *Title)
Definition: epg.c:1476
void DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version)
Definition: epg.c:1583
bool IsUpdate(tEventID EventID, time_t StartTime, uchar TableID, uchar Version)
Definition: epg.c:1458
void FixEpgBugs(cEvent *Event)
Definition: epg.c:1557
void HandleEvent(cEvent *Event)
Definition: epg.c:1566
void SetComponents(cEvent *Event, cComponents *Components)
Definition: epg.c:1548
void SetVps(cEvent *Event, time_t Vps)
Definition: epg.c:1539
void SetParentalRating(cEvent *Event, int ParentalRating)
Definition: epg.c:1512
bool BeginSegmentTransfer(const cChannel *Channel)
Definition: epg.c:1592
bool HandledExternally(const cChannel *Channel)
Definition: epg.c:1449
void SetContents(cEvent *Event, uchar *Contents)
Definition: epg.c:1503
void SetShortText(cEvent *Event, const char *ShortText)
Definition: epg.c:1485
void SetDuration(cEvent *Event, int Duration)
Definition: epg.c:1530
void SetDescription(cEvent *Event, const char *Description)
Definition: epg.c:1494
void SetEventID(cEvent *Event, tEventID EventID)
Definition: epg.c:1467
Definition: epg.h:73
cString ToDescr(void) const
Definition: epg.c:248
void SetSeen(void)
Definition: epg.c:237
uchar TableID(void) const
Definition: epg.h:102
int RunningStatus(void) const
Definition: epg.h:104
time_t StartTime(void) const
Definition: epg.h:111
void SetStartTime(time_t StartTime)
Definition: epg.c:216
bool HasTimer(void) const
Definition: epg.h:120
const char * Title(void) const
Definition: epg.h:105
int Duration(void) const
Definition: epg.h:113
void SetVersion(uchar Version)
Definition: epg.c:172
void SetDuration(int Duration)
Definition: epg.c:227
const char * ShortText(void) const
Definition: epg.h:106
void SetTableID(uchar TableID)
Definition: epg.c:167
const char * Description(void) const
Definition: epg.h:107
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:211
int Transponder(void)
Returns the transponder of the data delivered to this filter.
Definition: filter.c:168
virtual void SetStatus(bool On)
Turns this filter on or off, depending on the value of On.
Definition: filter.c:178
int Source(void)
Returns the source of the data delivered to this filter.
Definition: filter.c:163
void Clear(void)
Definition: tools.c:2404
void Add(cListObject *Object, unsigned int Id)
Definition: tools.c:2383
T * Get(unsigned int Id) const
Definition: tools.h:929
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2184
int Index(void) const
Definition: tools.c:2104
Definition: thread.h:67
void Lock(void)
Definition: thread.c:222
void Unlock(void)
Definition: thread.c:228
Definition: epg.h:152
void SetRunningStatus(cEvent *Event, int RunningStatus, const cChannel *Channel=NULL)
Definition: epg.c:1052
const cEvent * GetEventByTime(time_t StartTime) const
Definition: epg.c:1031
bool OnActualTp(uchar TableId)
Definition: epg.c:934
void SetPresentSeen(void)
Definition: epg.h:172
void ClrRunningStatus(cChannel *Channel=NULL)
Definition: epg.c:1070
const cEvent * GetEventById(tEventID EventID) const
Definition: epg.c:1026
cEvent * AddEvent(cEvent *Event)
Definition: epg.c:941
static cSchedules * GetSchedulesWrite(cStateKey &StateKey, int TimeoutMs=0)
Gets the list of schedules for write access.
Definition: epg.c:1274
const cSchedule * GetSchedule(tChannelID ChannelID) const
Definition: epg.c:1374
bool Check(uchar Version, int SectionNumber)
Returns true if Version is not the current version, or the given SectionNumber has not been marked as...
Definition: filter.c:31
int EPGLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:297
int UpdateChannels
Definition: config.h:325
int TimeTransponder
Definition: config.h:289
int SetSystemTime
Definition: config.h:287
int TimeSource
Definition: config.h:288
void Remove(bool IncState=true)
Removes this key from the lock it was previously used with.
Definition: thread.c:859
Definition: eit.c:447
static cMutex mutex
Definition: eit.c:449
cTDT(const u_char *Data)
Definition: eit.c:458
static time_t lastAdj
Definition: eit.c:450
cSetup Setup
Definition: config.c:372
#define MAX_ADJ_DIFF
Definition: eit.c:444
#define MAX_TIME_DIFF
Definition: eit.c:443
#define VALID_TIME
Definition: eit.c:38
#define ADJ_DELTA
Definition: eit.c:445
cEpgHandlers EpgHandlers
Definition: epg.c:1429
@ MaxEventContents
Definition: epg.h:25
#define EPG_LINGER_TIME
Definition: epg.h:23
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:316
const char * I18nNormalizeLanguageCode(const char *Code)
Returns a 3 letter language code that may not be zero terminated.
Definition: i18n.c:285
Definition: descriptor.c:16
RunningStatus
Definition: si.h:197
@ RunningStatusUndefined
Definition: si.h:197
@ RunningStatusPausing
Definition: si.h:200
@ RunningStatusNotRunning
Definition: si.h:198
TableId
Definition: si.h:23
@ ExtendedEventDescriptorTag
Definition: si.h:92
@ ShortEventDescriptorTag
Definition: si.h:91
@ ComponentDescriptorTag
Definition: si.h:94
@ ParentalRatingDescriptorTag
Definition: si.h:99
@ PDCDescriptorTag
Definition: si.h:119
@ ContentDescriptorTag
Definition: si.h:98
@ TimeShiftedEventDescriptorTag
Definition: si.h:93
@ LinkageDescriptorTag
Definition: si.h:88
@ LinkageTypePremiere
Definition: si.h:214
unsigned char u_char
Definition: headers.h:24
cString TimeString(time_t t)
Converts the given time to a string of the form "hh:mm".
Definition: tools.c:1255
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:1225
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