summaryrefslogtreecommitdiff
path: root/eit.c
diff options
context:
space:
mode:
Diffstat (limited to 'eit.c')
-rw-r--r--eit.c1596
1 files changed, 157 insertions, 1439 deletions
diff --git a/eit.c b/eit.c
index 8e0ade7..45a4d80 100644
--- a/eit.c
+++ b/eit.c
@@ -1,1483 +1,201 @@
-/***************************************************************************
- eit.c - description
- -------------------
- begin : Fri Aug 25 2000
- copyright : (C) 2000 by Robert Schneider
- email : Robert.Schneider@web.de
-
- 2001-08-15: Adapted to 'libdtv' by Rolf Hakenes <hakenes@hippomi.de>
-
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * $Id: eit.c 1.80 2003/10/12 11:05:42 kls Exp $
- ***************************************************************************/
+/*
+ * eit.c: EIT section filter
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * Original version (as used in VDR before 1.3.0) written by
+ * Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
+ * Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
+ *
+ * $Id: eit.c 1.84 2004/01/02 22:27:29 kls Exp $
+ */
#include "eit.h"
-#include <ctype.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <linux/dvb/dmx.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include "channels.h"
-#include "config.h"
-#include "libdtv/libdtv.h"
-#include "videodir.h"
-
-// --- cMJD ------------------------------------------------------------------
-
-class cMJD {
-public:
- cMJD();
- cMJD(u_char date_hi, u_char date_lo);
- cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese);
- ~cMJD();
- /** */
- void ConvertToTime();
- /** */
- bool SetSystemTime();
- /** */
- time_t GetTime_t();
-protected: // Protected attributes
- /** */
- time_t mjdtime;
-protected: // Protected attributes
- /** */
- u_char time_second;
-protected: // Protected attributes
- /** */
- u_char time_minute;
-protected: // Protected attributes
- /** */
- u_char time_hour;
-protected: // Protected attributes
- /** */
- u_short mjd;
-};
-
-cMJD::cMJD()
-{
-}
-
-cMJD::cMJD(u_char date_hi, u_char date_lo)
-{
- mjd = date_hi << 8 | date_lo;
- time_hour = time_minute = time_second = 0;
- ConvertToTime();
-}
-
-cMJD::cMJD(u_char date_hi, u_char date_lo, u_char timehr, u_char timemi, u_char timese)
-{
- mjd = date_hi << 8 | date_lo;
- time_hour = timehr;
- time_minute = timemi;
- time_second = timese;
- ConvertToTime();
-}
-
-cMJD::~cMJD()
-{
-}
-
-/** */
-void cMJD::ConvertToTime()
-{
- struct tm t;
-
- t.tm_sec = time_second;
- t.tm_min = time_minute;
- t.tm_hour = time_hour;
- int k;
+#include "epg.h"
+#include "libsi/section.h"
+#include "libsi/descriptor.h"
- t.tm_year = (int) ((mjd - 15078.2) / 365.25);
- t.tm_mon = (int) ((mjd - 14956.1 - (int)(t.tm_year * 365.25)) / 30.6001);
- t.tm_mday = (int) (mjd - 14956 - (int)(t.tm_year * 365.25) - (int)(t.tm_mon * 30.6001));
- k = (t.tm_mon == 14 || t.tm_mon == 15) ? 1 : 0;
- t.tm_year = t.tm_year + k;
- t.tm_mon = t.tm_mon - 1 - k * 12;
- t.tm_mon--;
-
- t.tm_isdst = -1;
- t.tm_gmtoff = 0;
-
- mjdtime = timegm(&t);
-
- //isyslog("Time parsed = %s\n", ctime(&mjdtime));
-}
-
-/** */
-bool cMJD::SetSystemTime()
-{
- struct tm *ptm;
- time_t loctim;
-
- struct tm tm_r;
- ptm = localtime_r(&mjdtime, &tm_r);
- loctim = time(NULL);
-
- if (abs(mjdtime - loctim) > 2)
- {
- isyslog("System Time = %s (%ld)\n", ctime(&loctim), loctim);
- isyslog("Local Time = %s (%ld)\n", ctime(&mjdtime), mjdtime);
- if (stime(&mjdtime) < 0)
- esyslog("ERROR while setting system time: %m");
- return true;
- }
-
- return false;
-}
-/** */
-time_t cMJD::GetTime_t()
-{
- return mjdtime;
-}
-
-// --- cTDT ------------------------------------------------------------------
+// --- cEIT ------------------------------------------------------------------
-class cTDT {
+class cEIT : public SI::EIT {
public:
- cTDT(tdt_t *ptdt);
- ~cTDT();
- /** */
- bool SetSystemTime();
-protected: // Protected attributes
- /** */
- tdt_t tdt;
- /** */
- cMJD mjd; // kls 2001-03-02: made this a member instead of a pointer (it wasn't deleted in the destructor!)
-};
-
-#define BCD2DEC(b) (((b >> 4) & 0x0F) * 10 + (b & 0x0F))
-
-cTDT::cTDT(tdt_t *ptdt)
-:tdt(*ptdt)
-,mjd(tdt.utc_mjd_hi, tdt.utc_mjd_lo, BCD2DEC(tdt.utc_time_h), BCD2DEC(tdt.utc_time_m), BCD2DEC(tdt.utc_time_s))
-{
-}
-
-cTDT::~cTDT()
-{
-}
-/** */
-bool cTDT::SetSystemTime()
-{
- return mjd.SetSystemTime();
-}
-
-// --- cEventInfo ------------------------------------------------------------
-
-cEventInfo::cEventInfo(tChannelID channelid, unsigned short eventid)
-{
- pTitle = NULL;
- pSubtitle = NULL;
- pExtendedDescription = NULL;
- bIsPresent = bIsFollowing = false;
- lDuration = 0;
- tTime = 0;
- uTableID = 0;
- uEventID = eventid;
- channelID = channelid;
- nChannelNumber = 0;
-}
-
-cEventInfo::~cEventInfo()
-{
- free(pTitle);
- free(pSubtitle);
- free(pExtendedDescription);
-}
-
-/** */
-const char * cEventInfo::GetTitle() const
-{
- return pTitle;
-}
-/** */
-const char * cEventInfo::GetSubtitle() const
-{
- return pSubtitle;
-}
-/** */
-const char * cEventInfo::GetExtendedDescription() const
-{
- return pExtendedDescription;
-}
-/** */
-bool cEventInfo::IsPresent() const
-{
- return bIsPresent;
-}
-/** */
-void cEventInfo::SetPresent(bool pres)
-{
- bIsPresent = pres;
-}
-/** */
-bool cEventInfo::IsFollowing() const
-{
- return bIsFollowing;
-}
-
-void cEventInfo::SetTableID(unsigned char tableid)
-{
- uTableID = tableid;
-}
-
-/** */
-void cEventInfo::SetFollowing(bool foll)
-{
- bIsFollowing = foll;
-}
-/** */
-const char * cEventInfo::GetDate() const
-{
- static char szDate[25];
-
- struct tm tm_r;
- strftime(szDate, sizeof(szDate), "%d.%m.%Y", localtime_r(&tTime, &tm_r));
-
- return szDate;
-}
-
-const unsigned char cEventInfo::GetTableID(void) const
-{
- return uTableID;
-}
-
-/** */
-const char * cEventInfo::GetTimeString() const
-{
- static char szTime[25];
-
- struct tm tm_r;
- strftime(szTime, sizeof(szTime), "%R", localtime_r(&tTime, &tm_r));
-
- return szTime;
-}
-/** */
-const char * cEventInfo::GetEndTimeString() const
-{
- static char szEndTime[25];
- time_t tEndTime = tTime + lDuration;
-
- struct tm tm_r;
- strftime(szEndTime, sizeof(szEndTime), "%R", localtime_r(&tEndTime, &tm_r));
+ cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data);
+ };
- return szEndTime;
-}
-/** */
-time_t cEventInfo::GetTime() const
-{
- return tTime;
-}
-/** */
-long cEventInfo::GetDuration() const
-{
- return lDuration;
-}
-/** */
-unsigned short cEventInfo::GetEventID() const
-{
- return uEventID;
-}
-/** */
-void cEventInfo::SetTitle(const char *string)
-{
- pTitle = strcpyrealloc(pTitle, string);
-}
-/** */
-void cEventInfo::SetSubtitle(const char *string)
-{
- pSubtitle = strcpyrealloc(pSubtitle, string);
-}
-/** */
-void cEventInfo::SetExtendedDescription(const char *string)
-{
- pExtendedDescription = strcpyrealloc(pExtendedDescription, string);
-}
-/** */
-void cEventInfo::SetTime(time_t t)
-{
- tTime = t;
-}
-/** */
-void cEventInfo::SetDuration(long l)
-{
- lDuration = l;
-}
-/** */
-void cEventInfo::SetEventID(unsigned short evid)
+cEIT::cEIT(cSchedules *Schedules, int Source, u_char Tid, const u_char *Data)
+:SI::EIT(Data, false)
{
- uEventID = evid;
-}
-/** */
-void cEventInfo::SetChannelID(tChannelID channelid)
-{
- channelID = channelid;
-}
+ if (!CheckCRCAndParse())
+ return;
-/** */
-tChannelID cEventInfo::GetChannelID() const
-{
- return channelID;
-}
+ tChannelID channelID(Source, getOriginalNetworkId(), getTransportStreamId(), getServiceId());
+ cChannel *channel = Channels.GetByChannelID(channelID, true);
+ if (!channel)
+ return; // only collect data for known channels
-/** */
-void cEventInfo::Dump(FILE *f, const char *Prefix) const
-{
- if (tTime + lDuration >= time(NULL)) {
- fprintf(f, "%sE %u %ld %ld %X\n", Prefix, uEventID, tTime, lDuration, uTableID);
- if (!isempty(pTitle))
- fprintf(f, "%sT %s\n", Prefix, pTitle);
- if (!isempty(pSubtitle))
- fprintf(f, "%sS %s\n", Prefix, pSubtitle);
- if (!isempty(pExtendedDescription))
- fprintf(f, "%sD %s\n", Prefix, pExtendedDescription);
- fprintf(f, "%se\n", Prefix);
- }
-}
+ cEvent *rEvent = NULL;
-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->GetChannelID(), 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 true;
- default: esyslog("ERROR: unexpected tag while reading EPG data: %s", s);
- return false;
- }
- }
- esyslog("ERROR: unexpected end of file while reading EPG data");
+ cSchedule *pSchedule = (cSchedule *)Schedules->GetSchedule(channelID);
+ if (!pSchedule) {
+ pSchedule = new cSchedule(channelID);
+ Schedules->Add(pSchedule);
}
- return false;
-}
-
-#define MAXEPGBUGFIXSTATS 7
-#define MAXEPGBUGFIXCHANS 100
-struct tEpgBugFixStats {
- int hits;
- int n;
- tChannelID channelIDs[MAXEPGBUGFIXCHANS];
- tEpgBugFixStats(void) { hits = n = 0; }
- };
-tEpgBugFixStats EpgBugFixStats[MAXEPGBUGFIXSTATS];
-
-static void EpgBugFixStat(int Number, tChannelID ChannelID)
-{
- if (0 <= Number && Number < MAXEPGBUGFIXSTATS) {
- tEpgBugFixStats *p = &EpgBugFixStats[Number];
- p->hits++;
- int i = 0;
- for (; i < p->n; i++) {
- if (p->channelIDs[i] == ChannelID)
- break;
+ SI::EIT::Event SiEitEvent;
+ for (SI::Loop::Iterator it; eventLoop.hasNext(it); ) {
+ SiEitEvent = eventLoop.getNext(it);
+
+ cEvent *pEvent = (cEvent *)pSchedule->GetEvent(SiEitEvent.getEventId(), SiEitEvent.getStartTime());
+ if (!pEvent) {
+ // 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.
+ pEvent = pSchedule->AddEvent(new cEvent(channelID, SiEitEvent.getEventId()));
+ if (!pEvent)
+ continue;
+ pEvent->SetTableID(Tid);
}
- if (i == p->n && p->n < MAXEPGBUGFIXCHANS)
- p->channelIDs[p->n++] = ChannelID;
- }
-}
-
-static void ReportEpgBugFixStats(bool Reset = false)
-{
- if (Setup.EPGBugfixLevel > 0) {
- bool GotHits = false;
- char buffer[1024];
- for (int i = 0; i < MAXEPGBUGFIXSTATS; i++) {
- const char *delim = "\t";
- tEpgBugFixStats *p = &EpgBugFixStats[i];
- if (p->hits) {
- bool PrintedStats = false;
- char *q = buffer;
- *buffer = 0;
- for (int c = 0; c < p->n; c++) {
- cChannel *channel = Channels.GetByChannelID(p->channelIDs[c], true);
- if (channel) {
- if (!GotHits) {
- dsyslog("=====================");
- dsyslog("EPG bugfix statistics");
- dsyslog("=====================");
- dsyslog("IF SOMEBODY WHO IS IN CHARGE OF THE EPG DATA FOR ONE OF THE LISTED");
- dsyslog("CHANNELS READS THIS: PLEASE TAKE A LOOK AT THE FUNCTION cEventInfo::FixEpgBugs()");
- dsyslog("IN VDR/eit.c TO LEARN WHAT'S WRONG WITH YOUR DATA, AND FIX IT!");
- dsyslog("=====================");
- dsyslog("Fix\tHits\tChannels");
- GotHits = true;
- }
- if (!PrintedStats) {
- q += snprintf(q, sizeof(buffer) - (q - buffer), "%d\t%d", i, p->hits);
- PrintedStats = true;
- }
- q += snprintf(q, sizeof(buffer) - (q - buffer), "%s%s", delim, channel->Name());
- delim = ", ";
- }
- }
- if (*buffer)
- dsyslog("%s", buffer);
- }
- if (Reset)
- p->hits = p->n = 0;
+ else {
+ // 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->TableID() == 0x00)
+ continue;
+ // If the new event comes from a table that belongs to an "other TS" and the existing
+ // one comes from an "actual TS" table, let's skip it.
+ #define ISACTUALTS(tid) (tid == 0x4E || (tid & 0x50) == 0x50)
+ if (!ISACTUALTS(Tid) && ISACTUALTS(pEvent->TableID()))
+ continue;
+ // If the new event comes from a "schedule" table and the existing one comes from
+ // a "present/following" table, let's skip it (the p/f table usually contains more
+ // information, like e.g. a description).
+ if ((Tid & 0x50) == 0x50 && pEvent->TableID() == 0x4E || (Tid & 0x60) == 0x60 && pEvent->TableID() == 0x4F)
+ continue;
+ // If both events come from the same "schedule" table and the new event's table id is larger than the
+ // existing one's, let's skip it (higher tids mean "farther in the future" and usually have less information).
+ if (((Tid & 0x50) == 0x50 || (Tid & 0x60) == 0x60) && (pEvent->TableID() & 0xF0) == (Tid & 0xF0) && (Tid > pEvent->TableID()))
+ continue;
+ // If the new event comes from the same table and has the same version number
+ // as the existing one, let's skip it to avoid unnecessary work.
+ // Unfortunately some stations (like, e.g. "Premiere") broadcast their EPG data on several transponders (like
+ // the actual Premiere transponder and the Sat.1/Pro7 transponder), but use different version numbers on
+ // each of them :-( So if one DVB card is tuned to the Premiere transponder, while an other one is tuned
+ // to the Sat.1/Pro7 transponder, events will keep toggling because of the bogus version numbers.
+ if (Tid == pEvent->TableID() && pEvent->Version() == getVersionNumber())
+ continue;
}
- if (GotHits)
- dsyslog("=====================");
- }
-}
-
-void cEventInfo::FixEpgBugs(void)
-{
- // VDR can't usefully handle newline characters in the EPG data, so let's
- // always convert them to blanks (independent of the setting of EPGBugfixLevel):
- strreplace(pTitle, '\n', ' ');
- strreplace(pSubtitle, '\n', ' ');
- strreplace(pExtendedDescription, '\n', ' ');
-
- if (Setup.EPGBugfixLevel == 0)
- return;
-
- // Some TV stations apparently have their own idea about how to fill in the
- // EPG data. Let's fix their bugs as good as we can:
- if (pTitle) {
-
- // VOX puts too much information into the Subtitle and leaves the Extended
- // Description empty:
- //
- // Title
- // (NAT, Year Min')[ ["Subtitle". ]Extended Description]
- //
- if (pSubtitle && !pExtendedDescription) {
- if (*pSubtitle == '(') {
- char *e = strchr(pSubtitle + 1, ')');
- if (e) {
- if (*(e + 1)) {
- if (*++e == ' ')
- if (*(e + 1) == '"')
- e++;
+ pEvent->SetVersion(getVersionNumber());
+ pEvent->SetTableID(Tid);
+ pEvent->SetEventID(SiEitEvent.getEventId()); // unfortunately some stations use different event ids for the same event in different tables :-(
+
+ SI::Descriptor *d;
+ SI::ExtendedEventDescriptors exGroup;
+ char text[256];
+ for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext(it2)); ) {
+ switch (d->getDescriptorTag()) {
+ case SI::ExtendedEventDescriptorTag:
+ exGroup.Add((SI::ExtendedEventDescriptor *)d);
+ d = NULL; //so that it is not deleted
+ break;
+ case SI::ShortEventDescriptorTag: {
+ SI::ShortEventDescriptor *sed = (SI::ShortEventDescriptor *)d;
+ pEvent->SetTitle(sed->name.getText(text));
+ pEvent->SetShortText(sed->text.getText(text));
}
- else
- e = NULL;
- char *s = e ? strdup(e) : NULL;
- free(pSubtitle);
- pSubtitle = s;
- EpgBugFixStat(0, GetChannelID());
- // now the fixes #1 and #2 below will handle the rest
- }
- }
- }
-
- // VOX and VIVA put the Subtitle in quotes and use either the Subtitle
- // or the Extended Description field, depending on how long the string is:
- //
- // Title
- // "Subtitle". Extended Description
- //
- if ((pSubtitle == NULL) != (pExtendedDescription == NULL)) {
- char *p = pSubtitle ? pSubtitle : pExtendedDescription;
- if (*p == '"') {
- const char *delim = "\".";
- char *e = strstr(p + 1, delim);
- if (e) {
- *e = 0;
- char *s = strdup(p + 1);
- char *d = strdup(e + strlen(delim));
- free(pSubtitle);
- free(pExtendedDescription);
- pSubtitle = s;
- pExtendedDescription = d;
- EpgBugFixStat(1, GetChannelID());
- }
- }
- }
-
- // VOX and VIVA put the Extended Description into the Subtitle (preceeded
- // by a blank) if there is no actual Subtitle and the Extended Description
- // is short enough:
- //
- // Title
- // Extended Description
- //
- if (pSubtitle && !pExtendedDescription) {
- if (*pSubtitle == ' ') {
- memmove(pSubtitle, pSubtitle + 1, strlen(pSubtitle));
- pExtendedDescription = pSubtitle;
- pSubtitle = NULL;
- EpgBugFixStat(2, GetChannelID());
- }
- }
-
- // Pro7 sometimes repeats the Title in the Subtitle:
- //
- // Title
- // Title
- //
- if (pSubtitle && strcmp(pTitle, pSubtitle) == 0) {
- free(pSubtitle);
- pSubtitle = NULL;
- EpgBugFixStat(3, GetChannelID());
- }
-
- // ZDF.info puts the Subtitle between double quotes, which is nothing
- // but annoying (some even put a '.' after the closing '"'):
- //
- // Title
- // "Subtitle"[.]
- //
- if (pSubtitle && *pSubtitle == '"') {
- int l = strlen(pSubtitle);
- if (l > 2 && (pSubtitle[l - 1] == '"' || (pSubtitle[l - 1] == '.' && pSubtitle[l - 2] == '"'))) {
- memmove(pSubtitle, pSubtitle + 1, l);
- char *p = strrchr(pSubtitle, '"');
- if (p)
- *p = 0;
- EpgBugFixStat(4, GetChannelID());
- }
- }
-
- if (Setup.EPGBugfixLevel <= 1)
- return;
-
- // Some channels apparently try to do some formatting in the texts,
- // which is a bad idea because they have no way of knowing the width
- // of the window that will actually display the text.
- // Remove excess whitespace:
- pTitle = compactspace(pTitle);
- pSubtitle = compactspace(pSubtitle);
- pExtendedDescription = compactspace(pExtendedDescription);
- // Remove superfluous hyphens:
- if (pExtendedDescription) {
- char *p = pExtendedDescription;
- while (*p && *(p + 1) && *(p + 2)) {
- if (*p == '-' && *(p + 1) == ' ' && *(p + 2) && islower(*(p - 1)) && islower(*(p + 2))) {
- if (!startswith(p + 2, "und ")) { // special case in German, as in "Lach- und Sachgeschichten"
- memmove(p, p + 2, strlen(p + 2) + 1);
- EpgBugFixStat(5, GetChannelID());
- }
+ break;
+ case SI::ContentDescriptorTag:
+ break;
+ case SI::ParentalRatingDescriptorTag:
+ break;
+ case SI::TimeShiftedEventDescriptorTag: {
+ SI::TimeShiftedEventDescriptor *tsed = (SI::TimeShiftedEventDescriptor *)d;
+ cSchedule *rSchedule = (cSchedule *)Schedules->GetSchedule(tChannelID(Source, 0, 0, tsed->getReferenceServiceId()));
+ if (!rSchedule)
+ break;
+ rEvent = (cEvent *)rSchedule->GetEvent(tsed->getReferenceEventId());
+ if (!rEvent)
+ break;
+ pEvent->SetTitle(rEvent->Title());
+ pEvent->SetShortText(rEvent->ShortText());
+ pEvent->SetDescription(rEvent->Description());
}
- p++;
- }
- }
-
-#define MAX_USEFUL_SUBTITLE_LENGTH 40
- // Some channels put a whole lot of information in the Subtitle and leave
- // the Extended Description totally empty. So if the Subtitle length exceeds
- // MAX_USEFUL_SUBTITLE_LENGTH, let's put this into the Extended Description
- // instead:
- if (!isempty(pSubtitle) && isempty(pExtendedDescription)) {
- if (strlen(pSubtitle) > MAX_USEFUL_SUBTITLE_LENGTH) {
- free(pExtendedDescription);
- pExtendedDescription = pSubtitle;
- pSubtitle = NULL;
- EpgBugFixStat(6, GetChannelID());
- }
- }
-
- // Some channels use the ` ("backtick") character, where a ' (single quote)
- // would be normally used. Actually, "backticks" in normal text don't make
- // much sense, so let's replace them:
- strreplace(pTitle, '`', '\'');
- strreplace(pSubtitle, '`', '\'');
- strreplace(pExtendedDescription, '`', '\'');
- }
-}
-
-// --- cSchedule -------------------------------------------------------------
-
-cSchedule::cSchedule(tChannelID channelid)
-{
- pPresent = pFollowing = NULL;
- channelID = channelid;
-}
-
-
-cSchedule::~cSchedule()
-{
-}
-
-cEventInfo *cSchedule::AddEvent(cEventInfo *EventInfo)
-{
- Events.Add(EventInfo);
- return EventInfo;
-}
-
-const cEventInfo *cSchedule::GetPresentEvent(void) const
-{
- return GetEventAround(time(NULL));
-}
+ break;
+ default: ;
+ }
+ delete d;
+ }
-const cEventInfo *cSchedule::GetFollowingEvent(void) const
-{
- const cEventInfo *pe = NULL;
- time_t now = time(NULL);
- time_t delta = INT_MAX;
- for (cEventInfo *p = Events.First(); p; p = Events.Next(p)) {
- time_t dt = p->GetTime() - now;
- if (dt > 0 && dt < delta) {
- delta = dt;
- pe = p;
+ if (!rEvent) {
+ char buffer[exGroup.getMaximumTextLength()];
+ pEvent->SetDescription(exGroup.getText(buffer));
}
- }
- return pe;
-}
-
-void cSchedule::SetChannelID(tChannelID channelid)
-{
- channelID = channelid;
-}
-/** */
-tChannelID cSchedule::GetChannelID() const
-{
- return channelID;
-}
-/** */
-const cEventInfo * cSchedule::GetEvent(unsigned short uEventID, time_t tTime) const
-{
- // Returns either the event info with the given uEventID or, if that one can't
- // be found, the one with the given tTime (or NULL if neither can be found)
- cEventInfo *pe = Events.First();
- cEventInfo *pt = NULL;
- while (pe != NULL)
- {
- if (pe->GetEventID() == uEventID)
- return pe;
- if (tTime > 0 && pe->GetTime() == tTime) // 'tTime < 0' is apparently used with NVOD channels
- pt = pe;
-
- pe = Events.Next(pe);
- }
- return pt;
-}
+ pEvent->SetStartTime(SiEitEvent.getStartTime());
+ pEvent->SetDuration(SiEitEvent.getDuration());
+ pEvent->FixEpgBugs();
-const cEventInfo *cSchedule::GetEventAround(time_t Time) const
-{
- const cEventInfo *pe = NULL;
- time_t delta = INT_MAX;
- for (cEventInfo *p = Events.First(); p; p = Events.Next(p)) {
- time_t dt = Time - p->GetTime();
- if (dt >= 0 && dt < delta && p->GetTime() + p->GetDuration() >= Time) {
- delta = dt;
- pe = p;
+ if (isPresentFollowing()) {
+ if (SiEitEvent.getRunningStatus() == SI::RunningStatusPausing || SiEitEvent.getRunningStatus() == SI::RunningStatusRunning)
+ pSchedule->SetPresentEvent(pEvent);
+ else if (SiEitEvent.getRunningStatus() == SI::RunningStatusStartsInAFewSeconds)
+ pSchedule->SetFollowingEvent(pEvent);
}
}
- return pe;
-}
-
-bool cSchedule::SetPresentEvent(cEventInfo *pEvent)
-{
- if (pPresent != NULL)
- pPresent->SetPresent(false);
- pPresent = pEvent;
- pPresent->SetPresent(true);
-
- return true;
-}
-
-/** */
-bool cSchedule::SetFollowingEvent(cEventInfo *pEvent)
-{
- if (pFollowing != NULL)
- pFollowing->SetFollowing(false);
- pFollowing = pEvent;
- pFollowing->SetFollowing(true);
-
- return true;
-}
-
-/** */
-void cSchedule::Cleanup()
-{
- Cleanup(time(NULL));
-}
-
-/** */
-void cSchedule::Cleanup(time_t tTime)
-{
- cEventInfo *pEvent;
- for (int a = 0; true ; a++)
- {
- pEvent = Events.Get(a);
- if (pEvent == NULL)
- break;
- if (pEvent->GetTime() + pEvent->GetDuration() + 3600 < tTime) // adding one hour for safety
- {
- Events.Del(pEvent);
- a--;
- }
- }
-}
-
-/** */
-void cSchedule::Dump(FILE *f, const char *Prefix) const
-{
- cChannel *channel = Channels.GetByChannelID(channelID, true);
- if (channel)
- {
- fprintf(f, "%sC %s %s\n", Prefix, channel->GetChannelID().ToString(), channel->Name());
- for (cEventInfo *p = Events.First(); p; p = Events.Next(p))
- p->Dump(f, Prefix);
- fprintf(f, "%sc\n", Prefix);
- }
-}
-
-bool cSchedule::Read(FILE *f, cSchedules *Schedules)
-{
- if (Schedules) {
- char *s;
- while ((s = readline(f)) != NULL) {
- if (*s == 'C') {
- s = skipspace(s + 1);
- char *p = strchr(s, ' ');
- if (p)
- *p = 0; // strips optional channel name
- if (*s) {
- tChannelID channelID = tChannelID::FromString(s);
- if (channelID.Valid()) {
- cSchedule *p = (cSchedule *)Schedules->AddChannelID(channelID);
- if (p) {
- if (!cEventInfo::Read(f, p))
- return false;
- }
- }
- else {
- esyslog("ERROR: illegal channel ID: %s", s);
- return false;
- }
- }
- }
- else {
- esyslog("ERROR: unexpected tag while reading EPG data: %s", s);
- return false;
- }
- }
- return true;
- }
- return false;
-}
-
-// --- cSchedules ------------------------------------------------------------
-
-cSchedules::cSchedules()
-{
- pCurrentSchedule = NULL;
-}
-
-cSchedules::~cSchedules()
-{
-}
-/** */
-const cSchedule *cSchedules::AddChannelID(tChannelID channelid)
-{
- channelid.ClrRid();
- const cSchedule *p = GetSchedule(channelid);
- if (!p) {
- Add(new cSchedule(channelid));
- p = GetSchedule(channelid);
- }
- return p;
-}
-/** */
-const cSchedule *cSchedules::SetCurrentChannelID(tChannelID channelid)
-{
- channelid.ClrRid();
- pCurrentSchedule = AddChannelID(channelid);
- if (pCurrentSchedule)
- currentChannelID = channelid;
- return pCurrentSchedule;
-}
-/** */
-const cSchedule * cSchedules::GetSchedule() const
-{
- return pCurrentSchedule;
-}
-/** */
-const cSchedule * cSchedules::GetSchedule(tChannelID channelid) const
-{
- cSchedule *p;
-
- channelid.ClrRid();
- p = First();
- while (p != NULL)
- {
- if (p->GetChannelID() == channelid)
- return p;
- p = Next(p);
- }
-
- return NULL;
-}
-
-/** */
-void cSchedules::Cleanup()
-{
- cSchedule *p;
-
- p = First();
- while (p != NULL)
- {
- p->Cleanup(time(NULL));
- p = Next(p);
- }
-}
-
-/** */
-void cSchedules::Dump(FILE *f, const char *Prefix) const
-{
- for (cSchedule *p = First(); p; p = Next(p))
- p->Dump(f, Prefix);
-}
-
-/** */
-bool cSchedules::Read(FILE *f)
-{
- cMutexLock MutexLock;
- return cSchedule::Read(f, (cSchedules *)cSIProcessor::Schedules(MutexLock));
-}
-
-// --- cEIT ------------------------------------------------------------------
-
-class cEIT {
-private:
- cSchedules *schedules;
-public:
- cEIT(unsigned char *buf, int length, cSchedules *Schedules);
- ~cEIT();
- /** */
- int ProcessEIT(unsigned char *buffer, int CurrentSource);
-
-protected: // Protected methods
- /** returns true if this EIT covers a
-present/following information, false if it's
-schedule information */
- bool IsPresentFollowing();
-protected: // Protected attributes
- /** Table ID of this EIT struct */
- u_char tid;
-};
-
-cEIT::cEIT(unsigned char * buf, int length, cSchedules *Schedules)
-{
- tid = buf[0];
- schedules = Schedules;
-}
-
-cEIT::~cEIT()
-{
-}
-
-/** */
-int cEIT::ProcessEIT(unsigned char *buffer, int CurrentSource)
-{
- cEventInfo *pEvent, *rEvent = NULL;
- cSchedule *pSchedule, *rSchedule = NULL;
- struct LIST *VdrProgramInfos;
- struct VdrProgramInfo *VdrProgramInfo;
-
- if (!buffer)
- return -1;
-
- VdrProgramInfos = createVdrProgramInfos(buffer);
-
- if (VdrProgramInfos) {
- for (VdrProgramInfo = (struct VdrProgramInfo *) VdrProgramInfos->Head; VdrProgramInfo; VdrProgramInfo = (struct VdrProgramInfo *) xSucc (VdrProgramInfo)) {
- //XXX TODO use complete channel ID
- cChannel *channel = Channels.GetByServiceID(CurrentSource, VdrProgramInfo->ServiceID);
- tChannelID channelID = channel ? channel->GetChannelID() : tChannelID(CurrentSource, 0, 0, VdrProgramInfo->ServiceID);
- channelID.ClrRid();
- //XXX
- pSchedule = (cSchedule *)schedules->GetSchedule(channelID);
- if (!pSchedule) {
- schedules->Add(new cSchedule(channelID));
- pSchedule = (cSchedule *)schedules->GetSchedule(channelID);
- if (!pSchedule)
- break;
- }
- if (VdrProgramInfo->ReferenceServiceID) {
- rSchedule = (cSchedule *)schedules->GetSchedule(tChannelID(CurrentSource, 0, 0, VdrProgramInfo->ReferenceServiceID));
- if (!rSchedule)
- break;
- rEvent = (cEventInfo *)rSchedule->GetEvent((unsigned short)VdrProgramInfo->ReferenceEventID);
- if (!rEvent)
- break;
- }
- pEvent = (cEventInfo *)pSchedule->GetEvent((unsigned short)VdrProgramInfo->EventID, VdrProgramInfo->StartTime);
- if (!pEvent) {
- // 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.
- pEvent = pSchedule->AddEvent(new cEventInfo(channelID, VdrProgramInfo->EventID));
- if (!pEvent)
- break;
- pEvent->SetTableID(tid);
- }
- else {
- // 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
- // 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))
- continue;
- }
- if (rEvent) {
- pEvent->SetTitle(rEvent->GetTitle());
- pEvent->SetSubtitle(rEvent->GetSubtitle());
- pEvent->SetExtendedDescription(rEvent->GetExtendedDescription());
- }
- else {
- pEvent->SetTableID(tid);
- pEvent->SetTitle(VdrProgramInfo->ShortName);
- pEvent->SetSubtitle(VdrProgramInfo->ShortText);
- pEvent->SetExtendedDescription(VdrProgramInfo->ExtendedName);
- //XXX kls 2001-09-22:
- //XXX apparently this never occurred, so I have simpified ExtendedDescription handling
- //XXX pEvent->AddExtendedDescription(VdrProgramInfo->ExtendedText);
- }
- pEvent->SetTime(VdrProgramInfo->StartTime);
- pEvent->SetDuration(VdrProgramInfo->Duration);
- pEvent->FixEpgBugs();
- if (IsPresentFollowing()) {
- if ((GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_PAUSING) || (GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_RUNNING))
- pSchedule->SetPresentEvent(pEvent);
- else if (GetRunningStatus(VdrProgramInfo->Status) == RUNNING_STATUS_AWAITING)
- pSchedule->SetFollowingEvent(pEvent);
- }
- }
- }
-
- xMemFreeAll(NULL);
- return 0;
-}
-
-/** returns true if this EIT covers a
-present/following information, false if it's
-schedule information */
-bool cEIT::IsPresentFollowing()
-{
- if (tid == 0x4e || tid == 0x4f)
- return true;
-
- return false;
}
-// --- cCaDescriptor ---------------------------------------------------------
+// --- cTDT ------------------------------------------------------------------
-class cCaDescriptor : public cListObject {
- friend class cSIProcessor;
+class cTDT : public SI::TDT {
private:
- int source;
- int transponder;
- int serviceId;
- int caSystem;
- unsigned int providerId;
- int caPid;
- int length;
- uchar *data;
+ static cMutex mutex;
public:
- cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, unsigned int ProviderId, int CaPid, int Length, uchar *Data);
- virtual ~cCaDescriptor();
- int Length(void) const { return length; }
- const uchar *Data(void) const { return data; }
+ cTDT(const u_char *Data);
};
-cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, unsigned int ProviderId, int CaPid, int Length, uchar *Data)
-{
- source = Source;
- transponder = Transponder;
- serviceId = ServiceId;
- caSystem = CaSystem;
- providerId = ProviderId;
- caPid = CaPid;
- length = Length + 6;
- data = MALLOC(uchar, length);
- data[0] = DESCR_CA;
- data[1] = length - 2;
- data[2] = (caSystem >> 8) & 0xFF;
- data[3] = caSystem & 0xFF;
- data[4] = ((CaPid >> 8) & 0x1F) | 0xE0;
- data[5] = CaPid & 0xFF;
- if (Length)
- memcpy(&data[6], Data, Length);
-//#define DEBUG_CA_DESCRIPTORS 1
-#ifdef DEBUG_CA_DESCRIPTORS
- char buffer[1024];
- char *q = buffer;
- q += sprintf(q, "CAM: %04X %5d %5d %04X %6X %04X -", source, transponder, serviceId, caSystem, providerId, caPid);
- for (int i = 0; i < length; i++)
- q += sprintf(q, " %02X", data[i]);
- dsyslog(buffer);
-#endif
-}
+cMutex cTDT::mutex;
-cCaDescriptor::~cCaDescriptor()
+cTDT::cTDT(const u_char *Data)
+:SI::TDT(Data, false)
{
- free(data);
-}
-
-// --- cSIProcessor ----------------------------------------------------------
-
-#define MAX_FILTERS 20
-#define EPGDATAFILENAME "epg.data"
+ CheckParse();
-int cSIProcessor::numSIProcessors = 0;
-cSchedules *cSIProcessor::schedules = NULL;
-cMutex cSIProcessor::schedulesMutex;
-cList<cCaDescriptor> cSIProcessor::caDescriptors;
-cMutex cSIProcessor::caDescriptorsMutex;
-const char *cSIProcessor::epgDataFileName = EPGDATAFILENAME;
-time_t cSIProcessor::lastDump = time(NULL);
+ time_t sattim = getTime();
+ time_t loctim = time(NULL);
-/** */
-cSIProcessor::cSIProcessor(const char *FileName)
-{
- fileName = strdup(FileName);
- masterSIProcessor = numSIProcessors == 0; // the first one becomes the 'master'
- currentSource = 0;
- currentTransponder = 0;
- statusCount = 0;
- pmtIndex = 0;
- pmtPid = 0;
- filters = NULL;
- if (!numSIProcessors++) { // the first one creates them
- schedules = new cSchedules;
- }
- filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER));
- SetStatus(true);
- Start();
-}
-
-cSIProcessor::~cSIProcessor()
-{
- if (masterSIProcessor)
- ReportEpgBugFixStats();
- active = false;
- Cancel(3);
- ShutDownFilters();
- free(filters);
- if (!--numSIProcessors) { // the last one deletes them
- delete schedules;
- }
- free(fileName);
-}
-
-const cSchedules *cSIProcessor::Schedules(cMutexLock &MutexLock)
-{
- if (MutexLock.Lock(&schedulesMutex))
- return schedules;
- return NULL;
-}
-
-bool cSIProcessor::Read(FILE *f)
-{
- bool OwnFile = f == NULL;
- if (OwnFile) {
- const char *FileName = GetEpgDataFileName();
- if (access(FileName, R_OK) == 0) {
- dsyslog("reading EPG data from %s", FileName);
- if ((f = fopen(FileName, "r")) == NULL) {
- LOG_ERROR;
- return false;
- }
- }
- else
- return false;
+ if (abs(sattim - loctim) > 2) {
+ mutex.Lock();
+ isyslog("System Time = %s (%ld)\n", ctime(&loctim), loctim);
+ isyslog("Local Time = %s (%ld)\n", ctime(&sattim), sattim);
+ if (stime(&sattim) < 0)
+ esyslog("ERROR while setting system time: %m");
+ mutex.Unlock();
}
- bool result = cSchedules::Read(f);
- if (OwnFile)
- fclose(f);
- return result;
-}
-
-void cSIProcessor::Clear(void)
-{
- cMutexLock MutexLock(&schedulesMutex);
- delete schedules;
- schedules = new cSchedules;
-}
-
-void cSIProcessor::SetEpgDataFileName(const char *FileName)
-{
- epgDataFileName = NULL;
- if (FileName)
- epgDataFileName = strdup(DirectoryOk(FileName) ? AddDirectory(FileName, EPGDATAFILENAME) : FileName);
-}
-
-const char *cSIProcessor::GetEpgDataFileName(void)
-{
- if (epgDataFileName)
- return *epgDataFileName == '/' ? epgDataFileName : AddDirectory(VideoDirectory, epgDataFileName);
- return NULL;
-}
-
-void cSIProcessor::SetStatus(bool On)
-{
- LOCK_THREAD;
- statusCount++;
- ShutDownFilters();
- pmtIndex = 0;
- pmtPid = 0;
- if (On)
- {
- AddFilter(0x00, 0x00); // PAT
- AddFilter(0x14, 0x70); // TDT
- AddFilter(0x12, 0x4e, 0xfe); // event info, actual(0x4e)/other(0x4f) TS, present/following
- AddFilter(0x12, 0x50, 0xfe); // event info, actual TS, schedule(0x50)/schedule for another 4 days(0x51)
- AddFilter(0x12, 0x60, 0xfe); // event info, other TS, schedule(0x60)/schedule for another 4 days(0x61)
- }
-}
-
-#define PMT_SCAN_TIMEOUT 10 // seconds
-
-/** use the vbi device to parse all relevant SI
-information and let the classes corresponding
-to the tables write their information to the disk */
-void cSIProcessor::Action()
-{
- dsyslog("EIT processing thread started (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : "");
-
- time_t lastCleanup = time(NULL);
- time_t lastPmtScan = time(NULL);
-
- int oldStatusCount = 0;
- active = true;
-
- while(active)
- {
- if (masterSIProcessor)
- {
- time_t now = time(NULL);
- struct tm tm_r;
- struct tm *ptm = localtime_r(&now, &tm_r);
- if (now - lastCleanup > 3600 && ptm->tm_hour == 5)
- {
- cMutexLock MutexLock(&schedulesMutex);
- isyslog("cleaning up schedules data");
- schedules->Cleanup();
- lastCleanup = now;
- ReportEpgBugFixStats(true);
- }
- if (epgDataFileName && now - lastDump > 600)
- {
- cMutexLock MutexLock(&schedulesMutex);
- cSafeFile f(GetEpgDataFileName());
- if (f.Open()) {
- schedules->Dump(f);
- f.Close();
- }
- else
- LOG_ERROR;
- lastDump = now;
- }
- }
-
- // set up pfd structures for all active filter
- Lock();
- pollfd pfd[MAX_FILTERS];
- int NumUsedFilters = 0;
- for (int a = 0; a < MAX_FILTERS ; a++)
- {
- if (filters[a].inuse)
- {
- pfd[NumUsedFilters].fd = filters[a].handle;
- pfd[NumUsedFilters].events = POLLIN;
- NumUsedFilters++;
- }
- }
- oldStatusCount = statusCount;
- Unlock();
-
- // wait until data becomes ready from the bitfilter
- if (poll(pfd, NumUsedFilters, 1000) != 0)
- {
- for (int aa = 0; aa < NumUsedFilters; aa++)
- {
- if (pfd[aa].revents & POLLIN)
- {
- int a;
- for (a = 0; a < MAX_FILTERS; a++) {
- if (pfd[aa].fd == filters[a].handle)
- break;
- }
- if (a >= MAX_FILTERS || !filters[a].inuse) // filter no longer available
- continue;
- // read section
- unsigned char buf[4096]; // max. allowed size for any EIT section
- int r = safe_read(filters[a].handle, buf, sizeof(buf));
- if (r > 3) // minimum number of bytes necessary to get section length
- {
- int seclen = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
- int pid = filters[a].pid;
- if (seclen == r)
- {
- //dsyslog("Received pid 0x%04X with table ID 0x%02X and length of %4d\n", pid, buf[0], seclen);
- cMutexLock MutexLock(&schedulesMutex); // since the xMem... stuff is not thread safe, we need to use a "global" mutex
- LOCK_THREAD;
- if (statusCount != oldStatusCount)
- break;
- switch (pid)
- {
- case 0x00:
- if (buf[0] == 0x00)
- {
- if (pmtPid && time(NULL) - lastPmtScan > PMT_SCAN_TIMEOUT) {
- DelFilter(pmtPid, 0x02);
- pmtPid = 0;
- pmtIndex++;
- lastPmtScan = time(NULL);
- }
- if (!pmtPid) {
- struct LIST *pat = siParsePAT(buf);
- if (pat) {
- int Index = 0;
- for (struct Program *prg = (struct Program *)pat->Head; prg; prg = (struct Program *)xSucc(prg)) {
- if (prg->ProgramID) {
- if (Index++ == pmtIndex) {
- pmtPid = prg->NetworkPID;
- AddFilter(pmtPid, 0x02);
- break;
- }
- }
- }
- if (!pmtPid)
- pmtIndex = 0;
- }
- xMemFreeAll(NULL);
- }
- }
- break;
- case 0x14:
- if (buf[0] == 0x70)
- {
- if (Setup.SetSystemTime && Setup.TimeTransponder && ISTRANSPONDER(currentTransponder, Setup.TimeTransponder))
- {
- cTDT ctdt((tdt_t *)buf);
- ctdt.SetSystemTime();
- }
- }
- break;
-
- case 0x12:
- if (buf[0] != 0x72)
- {
- cEIT ceit(buf, seclen, schedules);
- ceit.ProcessEIT(buf, currentSource);
- }
- /*else
- dsyslog("Received stuffing section in EIT\n");
- */
- break;
-
- default: {
- if (pid == pmtPid && buf[0] == 0x02 && currentSource && currentTransponder) {
- struct Pid *pi = siParsePMT(buf);
- if (pi) {
- struct Descriptor *d;
- for (d = (struct Descriptor *)pi->Descriptors->Head; d; d = (struct Descriptor *)xSucc(d))
- NewCaDescriptor(d, pi->ProgramID);
- // Also scan the PidInfo list for descriptors - some broadcasts send them only here.
- for (struct PidInfo *p = (struct PidInfo *)pi->InfoList->Head; p; p = (struct PidInfo *)xSucc(p)) {
- for (d = (struct Descriptor *)p->Descriptors->Head; d; d = (struct Descriptor *)xSucc(d))
- NewCaDescriptor(d, pi->ProgramID);
- }
- }
- xMemFreeAll(NULL);
- lastPmtScan = 0; // this triggers the next scan
- }
- }
- break;
- }
- }
- /*
- else
- dsyslog("read incomplete section - seclen = %d, r = %d", seclen, r);
- */
- }
- }
- }
- }
- }
-
- dsyslog("EIT processing thread ended (pid=%d)%s", getpid(), masterSIProcessor ? " - master" : "");
}
-/** Add a filter with packet identifier pid and
-table identifer tid */
-bool cSIProcessor::AddFilter(unsigned short pid, u_char tid, u_char mask)
-{
- dmx_sct_filter_params sctFilterParams;
- memset(&sctFilterParams, 0, sizeof(sctFilterParams));
- sctFilterParams.pid = pid;
- sctFilterParams.timeout = 0;
- sctFilterParams.flags = DMX_IMMEDIATE_START;
- sctFilterParams.filter.filter[0] = tid;
- sctFilterParams.filter.mask[0] = mask;
+// --- cEitFilter ------------------------------------------------------------
- for (int a = 0; a < MAX_FILTERS; a++)
- {
- if (!filters[a].inuse)
- {
- filters[a].pid = pid;
- filters[a].tid = tid;
- if ((filters[a].handle = open(fileName, O_RDWR | O_NONBLOCK)) >= 0)
- {
- if (ioctl(filters[a].handle, DMX_SET_FILTER, &sctFilterParams) >= 0)
- filters[a].inuse = true;
- else
- {
- esyslog("ERROR: can't set filter (pid=%d, tid=%02X)", pid, tid);
- close(filters[a].handle);
- return false;
- }
- // dsyslog("Registered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid);
- }
- else
- {
- esyslog("ERROR: can't open filter handle");
- return false;
- }
- return true;
- }
- }
- esyslog("ERROR: too many filters");
-
- return false;
-}
-
-bool cSIProcessor::DelFilter(unsigned short pid, u_char tid)
+cEitFilter::cEitFilter(void)
{
- for (int a = 0; a < MAX_FILTERS; a++)
- {
- if (filters[a].inuse && filters[a].pid == pid && filters[a].tid == tid)
- {
- close(filters[a].handle);
- // dsyslog("Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid);
- filters[a].inuse = false;
- return true;
- }
- }
- return false;
+ Set(0x12, 0x4E, 0xFE); // event info, actual(0x4E)/other(0x4F) TS, present/following
+ Set(0x12, 0x50, 0xF0); // event info, actual TS, schedule(0x50)/schedule for future days(0x5X)
+ Set(0x12, 0x60, 0xF0); // event info, other TS, schedule(0x60)/schedule for future days(0x6X)
+ Set(0x14, 0x70); // TDT
}
-/** */
-bool cSIProcessor::ShutDownFilters(void)
+void cEitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
- for (int a = 0; a < MAX_FILTERS; a++)
- {
- if (filters[a].inuse)
- {
- close(filters[a].handle);
- // dsyslog("Deregistered filter handle %04x, pid = %02d, tid = %02d", filters[a].handle, filters[a].pid, filters[a].tid);
- filters[a].inuse = false;
- }
- }
-
- return true; // there's no real 'boolean' to return here...
-}
-
-/** */
-void cSIProcessor::SetCurrentTransponder(int CurrentSource, int CurrentTransponder)
-{
- currentSource = CurrentSource;
- currentTransponder = CurrentTransponder;
-}
-
-/** */
-bool cSIProcessor::SetCurrentChannelID(tChannelID channelid)
-{
- cMutexLock MutexLock(&schedulesMutex);
- return schedules ? schedules->SetCurrentChannelID(channelid) : false;
-}
-
-void cSIProcessor::TriggerDump(void)
-{
- cMutexLock MutexLock(&schedulesMutex);
- lastDump = 0;
-}
-
-void cSIProcessor::NewCaDescriptor(struct Descriptor *d, int ServiceId)
-{
- if (DescriptorTag(d) == DESCR_CA) {
- struct CaDescriptor *cd = (struct CaDescriptor *)d;
- cMutexLock MutexLock(&caDescriptorsMutex);
-
- for (cCaDescriptor *ca = caDescriptors.First(); ca; ca = caDescriptors.Next(ca)) {
- if (ca->source == currentSource && ca->transponder == currentTransponder && ca->serviceId == ServiceId && ca->caSystem == cd->CA_type && ca->providerId == cd->ProviderID && ca->caPid == cd->CA_PID)
- return;
+ switch (Pid) {
+ case 0x12: {
+ cSchedulesLock SchedulesLock(true, 10);
+ cSchedules *Schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock);
+ if (Schedules)
+ cEIT EIT(Schedules, Source(), Tid, Data);
}
- caDescriptors.Add(new cCaDescriptor(currentSource, currentTransponder, ServiceId, cd->CA_type, cd->ProviderID, cd->CA_PID, cd->DataLength, cd->Data));
- //XXX update???
- }
-}
-
-int cSIProcessor::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data)
-{
- if (!CaSystemIds || !*CaSystemIds)
- return 0;
- if (BufSize > 0 && Data) {
- cMutexLock MutexLock(&caDescriptorsMutex);
- int length = 0;
- for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
- if (d->source == Source && d->transponder == Transponder && d->serviceId == ServiceId) {
- const unsigned short *caids = CaSystemIds;
- do {
- if (d->caSystem == *caids) {
- if (length + d->Length() <= BufSize) {
- memcpy(Data + length, d->Data(), d->Length());
- length += d->Length();
- }
- else
- return -1;
- }
- } while (*++caids);
- }
+ break;
+ case 0x14: {
+ if (Setup.SetSystemTime && Setup.TimeTransponder && ISTRANSPONDER(Transponder(), Setup.TimeTransponder))
+ cTDT TDT(Data);
}
- return length;
- }
- return -1;
+ break;
+ }
}