summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--eepg.c743
-rw-r--r--eepg.h15
-rw-r--r--eit2.c643
-rw-r--r--eit2.h50
-rw-r--r--epghandler.c27
-rw-r--r--epghandler.h2
-rw-r--r--equivhandler.c2
-rw-r--r--log.h3
-rw-r--r--setupeepg.c1
-rw-r--r--util.c169
-rw-r--r--util.h67
12 files changed, 989 insertions, 735 deletions
diff --git a/Makefile b/Makefile
index b63221f..49e8770 100644
--- a/Makefile
+++ b/Makefile
@@ -65,7 +65,7 @@ DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
### The object files (add further files here):
-OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o equivhandler.o util.o
+OBJS = $(PLUGIN).o dish.o epghandler.o setupeepg.o equivhandler.o util.o eit2.o
ifdef DBG
CXXFLAGS += -g
diff --git a/eepg.c b/eepg.c
index 1361b72..2ba6008 100644
--- a/eepg.c
+++ b/eepg.c
@@ -45,6 +45,7 @@
#include "setupeepg.h"
#include "equivhandler.h"
#include "util.h"
+#include "eit2.h"
#include <map>
#include <string>
@@ -64,14 +65,6 @@
static const char *VERSION = "0.0.6pre";
static const char *DESCRIPTION = trNOOP ("Parses Extended EPG data");
-template <class T> T REALLOC(T Var, size_t Size)
-{
- T p = (T)realloc(Var, Size);
- if (!p)
- free(Var);
- return p;
-}
-
using namespace std;
using namespace util;
@@ -100,7 +93,6 @@ char *cs_hexdump (int m, const uchar * buf, int n)
}
cSetupEEPG* SetupPE = cSetupEEPG::getInstance();
-cEquivHandler* EquivHandler;
// --- cMenuSetupPremiereEpg ------------------------------------------------------------
@@ -150,7 +142,7 @@ void cMenuSetupPremiereEpg::Store (void)
#endif
}
-#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() )
+//#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() )
// --- CRC16 -------------------------------------------------------------------
@@ -173,27 +165,6 @@ unsigned int crc16 (unsigned int crc, unsigned char const *p, int len)
static int LastVersionNagra = -1; //currently only used for Nagra, should be stored per transponder, per system
-
-#ifdef USE_NOEPG
-bool allowedEPG (tChannelID kanalID)
-{
- bool rc;
-
- if (Setup.noEPGMode == 1) {
- rc = false;
- if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL)
- rc = true;
- } else {
- rc = true;
- if (strstr (::Setup.noEPGList, kanalID.ToString ()) != NULL)
- rc = false;
- }
-
- return rc;
-}
-#endif /* NOEPG */
-
-
class cFilterEEPG:public cFilter
{
private:
@@ -267,6 +238,8 @@ public:
cFilterEEPG::cFilterEEPG (void)
{
+ nSummaries = 0;
+ nTitles = 0;
Trigger ();
//Set (0x00, 0x00);
}
@@ -333,21 +306,21 @@ void syslog_with_tid (int priority, const char *format, ...) __attribute__ ((for
-struct hufftab {
- unsigned int value;
- short bits;
- char next;
-};
+//struct hufftab {
+// unsigned int value;
+// short bits;
+// char next;
+//};
+//
+//#define START '\0'
+//#define STOP '\0'
+//#define ESCAPE '\1'
-#define START '\0'
-#define STOP '\0'
-#define ESCAPE '\1'
+//int freesat_decode_error = 0; /* If set an error has occurred during decoding */
-int freesat_decode_error = 0; /* If set an error has occurred during decoding */
-
-static struct hufftab *tables[2][128];
-static int table_size[2][128];
+//static struct hufftab *tables[2][128];
+//static int table_size[2][128];
static sNodeH* sky_tables[2];
/** \brief Convert a textual character description into a value
@@ -589,7 +562,7 @@ static bool load_sky_file (const char *filename)
char *freesat_huffman_decode (const unsigned char *src, size_t size)
{
int tableid;
- freesat_decode_error = 0;
+// freesat_decode_error = 0;
if (src[0] == 0x1f && (src[1] == 1 || src[1] == 2)) {
int uncompressed_len = 30;
@@ -859,44 +832,28 @@ bool cFilterEEPG::InitDictionary (void)
return true;
}
-void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize)
-{
- if (from[0] == 0x1f) {
- char *temp = freesat_huffman_decode (from, len);
- if (temp) {
- len = strlen (temp);
- len = len < buffsize - 1 ? len : buffsize - 1;
- strncpy (buffer, temp, len);
- buffer[len] = 0;
- free (temp);
- return;
- }
- }
-
- SI::String convStr;
- SI::CharArray charArray;
- charArray.assign(from, len);
- convStr.setData(charArray, len);
- //LogE(5, prep("decodeText2 from %s - length %d"), from, len);
- convStr.getText(buffer, buffsize);
- //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize);
-}
-
-void sortSchedules(cSchedules * Schedules, tChannelID channelID){
-
- LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString());
-
- cChannel *pChannel = GetChannelByID (channelID, false);
- cSchedule *pSchedule;
- if (pChannel) {
- pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true));
- pSchedule->Sort();
- Schedules->SetModified(pSchedule);
- }
- if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0)
- EquivHandler->sortEquivalents(channelID, Schedules);
-}
-
+//void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize)
+//{
+// if (from[0] == 0x1f) {
+// char *temp = freesat_huffman_decode (from, len);
+// if (temp) {
+// len = strlen (temp);
+// len = len < buffsize - 1 ? len : buffsize - 1;
+// strncpy (buffer, temp, len);
+// buffer[len] = 0;
+// free (temp);
+// return;
+// }
+// }
+//
+// SI::String convStr;
+// SI::CharArray charArray;
+// charArray.assign(from, len);
+// convStr.setData(charArray, len);
+// //LogE(5, prep("decodeText2 from %s - length %d"), from, len);
+// convStr.getText(buffer, buffsize);
+// //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize);
+//}
/**
* \brief Get MHW channels
@@ -2662,628 +2619,6 @@ void cFilterEEPG::AddFilter (u_short Pid, u_char Tid, unsigned char Mask)
}
}
-namespace SI
-{
- enum DescriptorTagExt {
- DishRatingDescriptorTag = 0x89,
- DishShortEventDescriptorTag = 0x91,
- DishExtendedEventDescriptorTag = 0x92,
- DishSeriesDescriptorTag = 0x96,
- };
-
-// typedef InheritEnum< DescriptorTagExt, SI::DescriptorTag > ExtendedDescriptorTag;
-
-/*extern const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte = NULL);
-extern bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode);
-extern bool SystemCharacterTableIsSingleByte;*/
-class cEIT2:public SI::EIT
-{
-public:
- cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid = false, bool OnlyRunningStatus = false);
-//protected:
-// void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent);
-};
-
-
-cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid, bool OnlyRunningStatus)
-: SI::EIT (Data, false)
-{
- //LogD(2, prep("cEIT2::cEIT2"));
- if (Tid > 0 && (Format == DISH_BEV || (SetupPE->ProcessEIT && isEITPid))) Tid--;
-
- if (!CheckCRCAndParse ()) {
- LogD(2, prep("!CheckCRCAndParse ()"));
- return;
- }
-
- bool searchOtherSatPositions = Format == DISH_BEV;
-
- tChannelID channelID (Source, getOriginalNetworkId (), getTransportStreamId (), getServiceId ());
- cChannel *channel = GetChannelByID (channelID, searchOtherSatPositions);
- if (!channel) {
- LogD(3, prep("!channel channelID: %s"), *channelID.ToString());
- return; // only collect data for known channels
- }
-
- //LogD(5, prep("channelID: %s format:%d"), *channel->GetChannelID().ToString(), Format);
-
-#ifdef USE_NOEPG
- // only use epg from channels not blocked by noEPG-patch
- tChannelID kanalID;
- kanalID = channel->GetChannelID ();
- if (!allowedEPG (kanalID))
- return;
-#endif /* NOEPG */
-
- cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (channel, true);
-
- bool Empty = true;
- bool Modified = false;
- bool HasExternalData = false;
- time_t SegmentStart = 0;
- time_t SegmentEnd = 0;
-
- SI::EIT::Event SiEitEvent;
- for (SI::Loop::Iterator it; eventLoop.getNext (SiEitEvent, it);) {
- bool ExternalData = false;
- // 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.
- if (SiEitEvent.getStartTime () == 0 || (SiEitEvent.getStartTime () > 0 && SiEitEvent.getDuration () == 0))
- continue;
- Empty = false;
- if (!SegmentStart)
- SegmentStart = SiEitEvent.getStartTime ();
- SegmentEnd = SiEitEvent.getStartTime () + SiEitEvent.getDuration ();
- int versionNumber = getVersionNumber();
-
- cEvent *newEvent = NULL;
- cEvent *rEvent = NULL;
- cEvent *pEvent = (cEvent *) pSchedule->GetEvent (SiEitEvent.getEventId (), SiEitEvent.getStartTime ());
- if (!pEvent) {
- if (OnlyRunningStatus)
- continue;
- // If we don't have that event yet, we create a new one.
- // Otherwise we copy the information into the existing event anyway, because the data might have changed.
- pEvent = newEvent = new cEvent (SiEitEvent.getEventId ());
- if (!pEvent)
- continue;
- } else {
- //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber);
- // We have found an existing event, either through its event ID or its start time.
- pEvent->SetSeen ();
-
- // If the existing event has a zero table ID it was defined externally and shall
- // not be overwritten.
- if (pEvent->TableID () == 0x00) {
-#ifdef USE_DDEPGENTRY
- if (pEvent->Version () == getVersionNumber ()) {
- if (Setup.MixEpgAction == 0)
- continue;
- //printf("in");
- //printf("%s", pEvent->GetTimeString());
- // to use the info of the original epg, update the extern one,
- // if it has less info
- SI::Descriptor * d;
- SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL;
- //SI::ExtendedEventDescriptor *eed = NULL;
- SI::ShortEventDescriptor * ShortEventDescriptor = NULL;
- //SI::ShortEventDescriptor *sed = NULL;
- //SI::TimeShiftedEventDescriptor *tsed = NULL;
- //cLinkChannels *LinkChannels = NULL;
- for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext (it2));) {
- if (d->getDescriptorTag () == SI::ShortEventDescriptorTag) {
- int LanguagePreferenceShort = -1;
- SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d;
- if (I18nIsPreferredLanguage (Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort)
- || !ShortEventDescriptor) {
- delete ShortEventDescriptor;
- ShortEventDescriptor = sed;
- d = NULL; // so that it is not deleted
- }
- } else if (d->getDescriptorTag () == SI::ExtendedEventDescriptorTag) {
- int LanguagePreferenceExt = -1;
- bool UseExtendedEventDescriptor = false;
- SI::ExtendedEventDescriptor * eed = (SI::ExtendedEventDescriptor *) d;
- if (I18nIsPreferredLanguage (Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt)
- || !ExtendedEventDescriptors) {
- delete ExtendedEventDescriptors;
- ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
- UseExtendedEventDescriptor = true;
- }
- if (UseExtendedEventDescriptor) {
- ExtendedEventDescriptors->Add (eed);
- d = NULL; // so that it is not deleted
- }
- if (eed->getDescriptorNumber () == eed->getLastDescriptorNumber ())
- UseExtendedEventDescriptor = false;
- }
- delete d;
- }
- if (pEvent) {
- if (ShortEventDescriptor) {
- char buffer[256];
- if (ShortEventDescriptor->text.getText (buffer, sizeof (buffer)) && pEvent->ShortText ()
- && (strlen (ShortEventDescriptor->text.getText (buffer, sizeof (buffer))) >
- strlen (pEvent->ShortText ()))) {
- pEvent->SetShortText (ShortEventDescriptor->text.getText (buffer, sizeof (buffer)));
- pEvent->FixEpgBugs ();
- }
- }
- if (ExtendedEventDescriptors) {
- char buffer[ExtendedEventDescriptors->getMaximumTextLength (": ") + 1];
- //pEvent->SetDescription(ExtendedEventDescriptors->getText(buffer, sizeof(buffer), ": "));
- if (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")
- && pEvent->Description ()
- && (strlen (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": ")) >
- strlen (pEvent->Description ()))) {
- pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": "));
- pEvent->FixEpgBugs ();
- }
- }
- }
- delete ExtendedEventDescriptors;
- delete ShortEventDescriptor;
- continue;
- }
-#else
- if (pEvent->Version () == versionNumber)
- continue;
-#endif /* DDEPGENTRY */
- HasExternalData = ExternalData = true;
- }
- // If the new event has a higher table ID, let's skip it.
- // The lower the table ID, the more "current" the information.
- else if (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.
- else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber)
- continue;
- }
- if (!ExternalData) {
- pEvent->SetEventID (SiEitEvent.getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-(
- pEvent->SetTableID (Tid);
- pEvent->SetStartTime (SiEitEvent.getStartTime ());
- pEvent->SetDuration (SiEitEvent.getDuration ());
- }
- if (newEvent)
- pSchedule->AddEvent (newEvent);
- if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
-#ifdef USE_DDEPGENTRY
- if (Setup.DisableVPS == 0 && SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning)
-#else
- if (SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning)
-#endif /* DDEPGENTRY */
- pSchedule->SetRunningStatus (pEvent, SiEitEvent.getRunningStatus (), channel);
- }
- if (OnlyRunningStatus)
- continue; // do this before setting the version, so that the full update can be done later
- pEvent->SetVersion (versionNumber);
-
- int LanguagePreferenceShort = -1;
- int LanguagePreferenceExt = -1;
- unsigned char nDescriptorTag;
- bool UseExtendedEventDescriptor = false;
- SI::Descriptor * d;
- SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL;
- SI::ShortEventDescriptor * ShortEventDescriptor = NULL;
- //SI::DishDescriptor *DishExtendedEventDescriptor = NULL;
- SI::DishDescriptor *DishEventDescriptor = NULL;
- //uchar DishTheme = 0, DishCategory = 0;
-
-
- cLinkChannels *LinkChannels = NULL;
- cComponents *Components = NULL;
- for (SI::Loop::Iterator it2; (d = SiEitEvent.eventDescriptors.getNext (it2));) {
- if (ExternalData && d->getDescriptorTag () != SI::ComponentDescriptorTag) {
- delete d;
- LogD(2, prep("continue:d->getDescriptorTAG():%x)"), d->getDescriptorTag ());
- continue;
- }
-
- //LogD(2, prep("EEPGDEBUG:d->getDescriptorTAG():%x)"), d->getDescriptorTag ());
- nDescriptorTag = d->getDescriptorTag ();
- switch (nDescriptorTag) {
- case SI::ExtendedEventDescriptorTag: {
- SI::ExtendedEventDescriptor * eed = (SI::ExtendedEventDescriptor *) d;
- if (I18nIsPreferredLanguage (Setup.EPGLanguages, eed->languageCode, LanguagePreferenceExt)
- || !ExtendedEventDescriptors) {
- delete ExtendedEventDescriptors;
- ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
- UseExtendedEventDescriptor = true;
- }
- if (UseExtendedEventDescriptor) {
- ExtendedEventDescriptors->Add (eed);
- d = NULL; // so that it is not deleted
- }
- if (eed->getDescriptorNumber () == eed->getLastDescriptorNumber ())
- UseExtendedEventDescriptor = false;
- }
- break;
- case SI::ShortEventDescriptorTag: {
- SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d;
- if (I18nIsPreferredLanguage (Setup.EPGLanguages, sed->languageCode, LanguagePreferenceShort)
- || !ShortEventDescriptor) {
- delete ShortEventDescriptor;
- ShortEventDescriptor = sed;
- d = NULL; // so that it is not deleted
- }
- }
- break;
-#if APIVERSNUM > 10711
- case SI::ContentDescriptorTag: {
- SI::ContentDescriptor *cd = (SI::ContentDescriptor *)d;
- SI::ContentDescriptor::Nibble Nibble;
- int NumContents = 0;
- uchar Contents[MaxEventContents] = { 0 };
- for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3); ) {
- if (NumContents < MaxEventContents) {
- Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF);
- NumContents++;
- }
- if (DishEventDescriptor && NumContents == 1) {
- DishEventDescriptor->setContent(Nibble);
- }
-// LogD(2, prep("EEPGDEBUG:Nibble:%x-%x-%x-%x)"), Nibble.getContentNibbleLevel1(),Nibble.getContentNibbleLevel2()
-// , Nibble.getUserNibble1(), Nibble.getUserNibble2());
-
- }
- pEvent->SetContents(Contents);
- }
- break;
-#endif
- case SI::ParentalRatingDescriptorTag: {
- int LanguagePreferenceRating = -1;
- SI::ParentalRatingDescriptor *prd = (SI::ParentalRatingDescriptor *)d;
- SI::ParentalRatingDescriptor::Rating Rating;
- for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3); ) {
- if (I18nIsPreferredLanguage(Setup.EPGLanguages, Rating.languageCode, LanguagePreferenceRating)) {
- int ParentalRating = (Rating.getRating() & 0xFF);
- switch (ParentalRating) {
- // values defined by the DVB standard (minimum age = rating + 3 years):
- case 0x01 ... 0x0F:
- ParentalRating += 3;
- break;
- // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?):
- case 0x11:
- ParentalRating = 10;
- break;
- case 0x12:
- ParentalRating = 12;
- break;
- case 0x13:
- ParentalRating = 16;
- break;
- default:
- ParentalRating = 0;
- }
- pEvent->SetParentalRating(ParentalRating);
- }
- }
- }
- break;
- case SI::PDCDescriptorTag: {
- SI::PDCDescriptor * pd = (SI::PDCDescriptor *) d;
- time_t now = time (NULL);
- struct tm tm_r;
- struct tm t = *localtime_r (&now, &tm_r); // this initializes the time zone in 't'
- t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
- int month = t.tm_mon;
- t.tm_mon = pd->getMonth () - 1;
- t.tm_mday = pd->getDay ();
- t.tm_hour = pd->getHour ();
- t.tm_min = pd->getMinute ();
- t.tm_sec = 0;
- if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
- t.tm_year++;
- else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
- t.tm_year--;
- time_t vps = mktime (&t);
- pEvent->SetVps (vps);
- }
- break;
- case SI::TimeShiftedEventDescriptorTag: {
- SI::TimeShiftedEventDescriptor * tsed = (SI::TimeShiftedEventDescriptor *) d;
- cSchedule *rSchedule =
- (cSchedule *) Schedules->
- GetSchedule (tChannelID (Source, channel->Nid (), channel->Tid (), 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 ());
- }
- break;
- case SI::LinkageDescriptorTag: {
- SI::LinkageDescriptor * ld = (SI::LinkageDescriptor *) d;
- tChannelID linkID (Source, ld->getOriginalNetworkId (), ld->getTransportStreamId (), ld->getServiceId ());
- if (ld->getLinkageType () == 0xB0) { // Premiere World
- time_t now = time (NULL);
- bool hit = SiEitEvent.getStartTime () <= now
- && now < SiEitEvent.getStartTime () + SiEitEvent.getDuration ();
- if (hit) {
- char linkName[ld->privateData.getLength () + 1];
- strn0cpy (linkName, (const char *) ld->privateData.getData (), sizeof (linkName));
- // TODO is there a standard way to determine the character set of this string?
- cChannel *link = Channels.GetByChannelID (linkID);
- if (link != channel) { // only link to other channels, not the same one
- //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
- if (link) {
- if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
- link->SetName (linkName, "", "");
- } else if (Setup.UpdateChannels >= 4) {
- cChannel *transponder = channel;
- if (channel->Tid () != ld->getTransportStreamId ())
- transponder = Channels.GetByTransponderID (linkID);
- link =
- Channels.NewChannel (transponder, linkName, "", "", ld->getOriginalNetworkId (),
- ld->getTransportStreamId (), ld->getServiceId ());
- }
- if (link) {
- if (!LinkChannels)
- LinkChannels = new cLinkChannels;
- LinkChannels->Add (new cLinkChannel (link));
- }
- } else
- channel->SetPortalName (linkName);
- }
- }
- }
- break;
- case SI::ComponentDescriptorTag: {
- SI::ComponentDescriptor * cd = (SI::ComponentDescriptor *) d;
- uchar Stream = cd->getStreamContent ();
- uchar Type = cd->getComponentType ();
- //if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles
- 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
- if (!Components)
- Components = new cComponents;
- char buffer[Utf8BufSize (256)];
- Components->SetComponent (Components->NumComponents (), Stream, Type,
- I18nNormalizeLanguageCode (cd->languageCode),
- cd->description.getText (buffer, sizeof (buffer)));
- }
- }
- break;
- case SI::DishExtendedEventDescriptorTag: {
- SI::UnimplementedDescriptor *deed = (SI::UnimplementedDescriptor *)d;
- if (!DishEventDescriptor) {
- DishEventDescriptor = new SI::DishDescriptor();
- }
- DishEventDescriptor->setExtendedtData(Tid+1, deed->getData());
- HasExternalData = true;
- }
- break;
- case SI::DishShortEventDescriptorTag: {
- SI::UnimplementedDescriptor *dsed = (SI::UnimplementedDescriptor *)d;
- if (!DishEventDescriptor) {
- DishEventDescriptor = new SI::DishDescriptor();
- }
- DishEventDescriptor->setShortData(Tid+1, dsed->getData());
- HasExternalData = true;
- }
- break;
- case SI::DishRatingDescriptorTag: {
- if (d->getLength() == 4) {
- if (!DishEventDescriptor) {
- DishEventDescriptor = new SI::DishDescriptor();
- }
- uint16_t rating = d->getData().TwoBytes(2);
- DishEventDescriptor->setRating(rating);
- }
- }
- break;
- case SI::DishSeriesDescriptorTag: {
- if (d->getLength() == 10) {
- //LogD(2, prep("DishSeriesDescriptorTag: %s)"), (const char*) d->getData().getData());
- if (!DishEventDescriptor) {
- DishEventDescriptor = new SI::DishDescriptor();
- }
- DishEventDescriptor->setEpisodeInfo(d->getData());
- }
-// else {
-// LogD(2, prep("DishSeriesDescriptorTag length: %d)"), d->getLength());
-// }
- }
- break;
- default:
- break;
- }
- delete d;
- }
-
- if (!rEvent) {
- if (ShortEventDescriptor) {
- char buffer[Utf8BufSize (256)];
- unsigned char *f;
- int l = ShortEventDescriptor->name.getLength();
- f = (unsigned char *) ShortEventDescriptor->name.getData().getData();
- decodeText2 (f, l, buffer, sizeof (buffer));
- //ShortEventDescriptor->name.getText(buffer, sizeof(buffer));
- LogD(2, prep("Title: %s Decoded: %s"), f, buffer);
- pEvent->SetTitle (buffer);
- LogD(3, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title());
- l = ShortEventDescriptor->text.getLength();
- if (l > 0) { //Set the Short Text only if there is data so that we do not overwrite valid data
- f = (unsigned char *) ShortEventDescriptor->text.getData().getData();
- decodeText2 (f, l, buffer, sizeof (buffer));
- //ShortEventDescriptor->text.getText(buffer, sizeof(buffer));
- pEvent->SetShortText (buffer);
- }
- LogD(3, prep("ShortText: %s"), pEvent->ShortText());
- LogD(2, prep("ShortText: %s Decoded: %s"), f, buffer);
- } else if (!HasExternalData) {
- pEvent->SetTitle (NULL);
- pEvent->SetShortText (NULL);
- LogD(3, prep("SetTitle (NULL)"));
- }
- if (ExtendedEventDescriptors) {
- char buffer[Utf8BufSize (ExtendedEventDescriptors->getMaximumTextLength (": ")) + 1];
- pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": "));
- LogD(3, prep("Description: %s"), pEvent->Description());
- } else if (!HasExternalData)
- pEvent->SetDescription (NULL);
-
- if (DishEventDescriptor) {
- if (DishEventDescriptor->getName())
- pEvent->SetTitle(DishEventDescriptor->getName());
- //LogD(2, prep("channelID: %s DishTitle: %s"), *channel->GetChannelID().ToString(), DishEventDescriptor->getName());
- pEvent->SetShortText(DishEventDescriptor->getShortText());
- char *tmp;
- string fmt;
-
- const char * description = DishEventDescriptor->getDescription();
- //BEV sets the description previously with ExtendedEventDescriptor
- if (0 == strcmp(DishEventDescriptor->getDescription(),"") && pEvent->Description())
- description = pEvent->Description();
-
-
- fmt = "%s";
- if (DishEventDescriptor->hasTheme()) {
- fmt += "\nTheme: ";
- }
- fmt += "%s";
- if (DishEventDescriptor->hasCategory()) {
- fmt += "\nCategory: ";
- }
- fmt += "%s";
-
- if ((0 != strcmp(DishEventDescriptor->getRating(),"")
- || 0 != strcmp(DishEventDescriptor->getStarRating(),""))) {
- fmt += "\n\nRating: ";
- }
- fmt += "%s %s";
- if (0 != strcmp(DishEventDescriptor->getProgramId(),"")) {
- fmt += "\n\nProgram ID: ";
- }
- fmt += "%s %s%s";
- time_t orgAirDate = DishEventDescriptor->getOriginalAirDate();
- char datestr [80];
- bool dateok = false;
- if (orgAirDate == 0) {
- dateok = strftime (datestr,80," Original Air Date: %a %b %d %Y",gmtime(&orgAirDate)) > 0;
- }
-
- Asprintf (&tmp, fmt.c_str(), description
- , DishEventDescriptor->getTheme(), DishEventDescriptor->getCategory()
- , DishEventDescriptor->getRating(), DishEventDescriptor->getStarRating()
- , DishEventDescriptor->getProgramId(), DishEventDescriptor->getSeriesId()
- , orgAirDate == 0 || !dateok ? "" : datestr);
- pEvent->SetDescription(tmp);
- free(tmp);
-
-
- //LogD(2, prep("DishDescription: %s"), DishEventDescriptor->getDescription());
- //LogD(2, prep("DishShortText: %s"), DishEventDescriptor->getShortText());
- }
-
- }
- delete ExtendedEventDescriptors;
- delete ShortEventDescriptor;
- delete DishEventDescriptor;
-
- pEvent->SetComponents (Components);
-
-// LogD(2, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title());
-
-// if (pEvent->ChannelID() == tChannelID::FromString("S119.0W-4100-6-110-110")) {
-// LogD(2, prep("ID: %d Title: %s Time: %d Tid: 0x%x"), pEvent->EventID(), pEvent->Title(), pEvent->StartTime(), pEvent->TableID());
-// }
-
- if (!HasExternalData)
- pEvent->FixEpgBugs ();
- if (LinkChannels)
- channel->SetLinkChannels (LinkChannels);
- Modified = true;
-#ifdef USE_DDEPGENTRY
- //to avoid double epg-entrys from ext and int epg sources :EW
- if (pEvent && pEvent->TableID () != 0x00) {
- cEvent *pPreviousEvent = (cEvent *) pSchedule->GetPreviousEvent (pEvent);
- if (pPreviousEvent) {
- if (Setup.DoubleEpgAction == 0) {
- pPreviousEvent->SetStartTime (pEvent->StartTime ());
- pPreviousEvent->SetDuration (pEvent->Duration ());
- if (Setup.DisableVPS == 0) {
- if (channel)
- pPreviousEvent->SetRunningStatus (pEvent->RunningStatus (), channel);
- else
- pPreviousEvent->SetRunningStatus (pEvent->RunningStatus ());
- }
- // to use the info of the original epg, update the extern one,
- // if it has less info
- char buffer_short_intern[256];
- char buffer_short_extern[256];
- int len_short_intern = 0;
- int len_short_extern = 0;
- if (pEvent->ShortText ())
- len_short_intern =
- snprintf (buffer_short_intern, sizeof (buffer_short_intern) - 1, "%s", pEvent->ShortText ());
- if (pPreviousEvent->ShortText ())
- len_short_extern =
- snprintf (buffer_short_extern, sizeof (buffer_short_extern) - 1, "%s", pPreviousEvent->ShortText ());
- if (len_short_intern > 0) {
- if (len_short_extern < 1)
- pPreviousEvent->SetShortText (buffer_short_intern);
- else if (len_short_intern > len_short_extern)
- pPreviousEvent->SetShortText (buffer_short_intern);
- }
- if (pEvent->Description ()) {
- char buffer_title_intern[4096];
- char buffer_title_extern[4096];
- int len_title_intern = 0;
- int len_title_extern = 0;
- if (pEvent->Description ())
- len_title_intern =
- snprintf (buffer_title_intern, sizeof (buffer_title_intern) - 1, "%s", pEvent->Description ());
- if (pPreviousEvent->Description ())
- len_title_extern =
- snprintf (buffer_title_extern, sizeof (buffer_title_extern) - 1, "%s",
- pPreviousEvent->Description ());
- if (len_title_intern > 0) {
- if (len_title_extern < 1)
- pPreviousEvent->SetDescription (buffer_title_intern);
- else if (len_title_intern > len_title_extern)
- pPreviousEvent->SetDescription (buffer_title_intern);
- }
- }
- if (pPreviousEvent->Vps () == 0 && pEvent->Vps () != 0)
- pPreviousEvent->SetVps (pEvent->Vps ());
- pSchedule->DelEvent (pEvent);
- pPreviousEvent->FixEpgBugs ();
- } else
- pSchedule->DelEvent (pPreviousEvent);
- }
- }
-#endif /* DDEPGENTRY */
- EquivHandler->updateEquivalent(Schedules, channel->GetChannelID(), pEvent);
- }
- if (Empty && Tid == 0x4E && getSectionNumber () == 0)
- // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
- pSchedule->ClrRunningStatus (channel);
- if (Tid == 0x4E)
- pSchedule->SetPresentSeen ();
- if (OnlyRunningStatus) {
- LogD(4, prep("OnlyRunningStatus"));
- return;
- }
- if (Modified) {
- if (!HasExternalData)
- pSchedule->DropOutdated (SegmentStart, SegmentEnd, Tid, getVersionNumber ());
- sortSchedules(Schedules, channel->GetChannelID());
- }
- LogD(4, prep("end of cEIT2"));
-
-}
-//end of cEIT2
-
-} //end namespace SI
-
void cFilterEEPG::ProcessNextFormat (bool FirstTime = false)
{
/* for (int i = 0; i <= HIGHEST_FORMAT; i++)
diff --git a/eepg.h b/eepg.h
index 18690de..7e1cc74 100644
--- a/eepg.h
+++ b/eepg.h
@@ -17,21 +17,6 @@
//#define NAGRA 6
//#define HIGHEST_FORMAT 6
-enum EFormat {
-//First all batchmode, load ONCE protocols:
- MHW1 = 0,
- MHW2 ,
- SKY_IT ,
- SKY_UK ,
- NAGRA ,
-//Than all CONTinuous protocols, so they will be processed LAST:
- PREMIERE ,
- FREEVIEW ,
- DISH_BEV ,
- EIT ,
-//the highest number of EPG-formats that is supported by this plugin
- HIGHEST_FORMAT = EIT
-} Format;
#define NAGRA_TABLE_ID 0x55 //the lower the table Id, the more "current" it is; table_id 0x00 never gets overwritten, now/next are at 0x4e or 0x4f!
#define DEFAULT_TABLE_ID 0x30
diff --git a/eit2.c b/eit2.c
new file mode 100644
index 0000000..12a7a95
--- /dev/null
+++ b/eit2.c
@@ -0,0 +1,643 @@
+/*
+ * eit2.c
+ *
+ * Created on: Oct 16, 2012
+ * Author: d.petrovski
+ */
+#include "eit2.h"
+
+#include <string>
+#include <vdr/config.h>
+#include "log.h"
+#include "util.h"
+#include "dish.h"
+#include "equivhandler.h"
+
+using namespace std;
+using namespace util;
+
+namespace SI
+{
+
+cEvent* cEIT2::ProcessEitEvent(cSchedule* pSchedule,const SI::EIT::Event* EitEvent,
+ uchar Tid, uchar versionNumber)
+{
+ bool ExternalData = false;
+ // 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.
+ if (EitEvent->getStartTime () == 0 || (EitEvent->getStartTime () > 0 && EitEvent->getDuration () == 0))
+ return NULL;
+ Empty = false;
+ if (!SegmentStart)
+ SegmentStart = EitEvent->getStartTime ();
+ SegmentEnd = EitEvent->getStartTime () + EitEvent->getDuration ();
+ // int versionNumber = getVersionNumber();
+
+ cEvent *newEvent = NULL;
+ cEvent *pEvent = (cEvent *) pSchedule->GetEvent (EitEvent->getEventId (), EitEvent->getStartTime ());
+ if (!pEvent) {
+ if (OnlyRunningStatus)
+ return NULL;
+ // If we don't have that event yet, we create a new one.
+ // Otherwise we copy the information into the existing event anyway, because the data might have changed.
+ pEvent = newEvent = new cEvent (EitEvent->getEventId ());
+ if (!pEvent)
+ return NULL;
+ } else {
+ //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber);
+ // We have found an existing event, either through its event ID or its start time.
+ pEvent->SetSeen ();
+
+ // If the existing event has a zero table ID it was defined externally and shall
+ // not be overwritten.
+ if (pEvent->TableID () == 0x00) {
+ if (pEvent->Version () == versionNumber)
+ return NULL;
+ /*HasExternalData = */ExternalData = true;
+ }
+ // If the new event has a higher table ID, let's skip it.
+ // The lower the table ID, the more "current" the information.
+ else if (Tid > pEvent->TableID())
+ return NULL;
+ // 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.
+ else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber)
+ return NULL;
+ }
+ if (!ExternalData) {
+ pEvent->SetEventID (EitEvent->getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-(
+ pEvent->SetTableID (Tid);
+ pEvent->SetStartTime (EitEvent->getStartTime ());
+ pEvent->SetDuration (EitEvent->getDuration ());
+ }
+ if (newEvent)
+ pSchedule->AddEvent (newEvent);
+ if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
+ if (EitEvent->getRunningStatus () >= SI::RunningStatusNotRunning)
+ pSchedule->SetRunningStatus (pEvent, EitEvent->getRunningStatus (), channel);
+ }
+ if (OnlyRunningStatus)
+ return NULL; // do this before setting the version, so that the full update can be done later
+ pEvent->SetVersion (versionNumber);
+
+ ProcessEventDescriptors(ExternalData, channel->Source(), Tid, EitEvent,
+ pEvent, Schedules, channel);
+
+ Modified = true;
+ return pEvent;
+}
+
+void cEIT2::ProcessEventDescriptors(bool ExternalData, int Source,
+ u_char Tid, const SI::EIT::Event* SiEitEvent, cEvent* pEvent,
+ cSchedules* Schedules, cChannel* channel)
+{
+
+ cEvent *rEvent = NULL;
+ int LanguagePreferenceShort = -1;
+ int LanguagePreferenceExt = -1;
+ unsigned char nDescriptorTag;
+ bool UseExtendedEventDescriptor = false;
+ SI::Descriptor * d;
+ SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL;
+ SI::ShortEventDescriptor * ShortEventDescriptor = NULL;
+ //SI::DishDescriptor *DishExtendedEventDescriptor = NULL;
+ SI::DishDescriptor *DishEventDescriptor = NULL;
+ //uchar DishTheme = 0, DishCategory = 0;
+
+
+ cLinkChannels *LinkChannels = NULL;
+ cComponents *Components = NULL;
+
+
+ DescriptorLoop dl = SiEitEvent->eventDescriptors;
+ for (SI::Loop::Iterator it2; (d = dl.getNext(it2)); )
+ {
+ if (ExternalData && d->getDescriptorTag() != SI::ComponentDescriptorTag)
+ {
+ delete d;
+ LogD(2, prep("continue:d->getDescriptorTAG():%x)"), d->getDescriptorTag ());
+ continue;
+ }
+
+ //LogD(2, prep("EEPGDEBUG:d->getDescriptorTAG():%x)"), d->getDescriptorTag ());
+ nDescriptorTag = d->getDescriptorTag();
+ switch (nDescriptorTag)
+ {
+ case SI::ExtendedEventDescriptorTag:
+ {
+ SI::ExtendedEventDescriptor * eed =
+ (SI::ExtendedEventDescriptor *) d;
+ if (I18nIsPreferredLanguage(Setup.EPGLanguages, eed->languageCode,
+ LanguagePreferenceExt) || !ExtendedEventDescriptors)
+ {
+ delete ExtendedEventDescriptors;
+ ExtendedEventDescriptors = new SI::ExtendedEventDescriptors;
+ UseExtendedEventDescriptor = true;
+ }
+ if (UseExtendedEventDescriptor)
+ {
+ ExtendedEventDescriptors->Add(eed);
+ d = NULL; // so that it is not deleted
+ }
+ if (eed->getDescriptorNumber() == eed->getLastDescriptorNumber())
+ UseExtendedEventDescriptor = false;
+ }
+ break;
+ case SI::ShortEventDescriptorTag:
+ {
+ SI::ShortEventDescriptor * sed = (SI::ShortEventDescriptor *) d;
+ if (I18nIsPreferredLanguage(Setup.EPGLanguages, sed->languageCode,
+ LanguagePreferenceShort) || !ShortEventDescriptor)
+ {
+ delete ShortEventDescriptor;
+ ShortEventDescriptor = sed;
+ d = NULL; // so that it is not deleted
+ }
+ }
+ break;
+#if APIVERSNUM > 10711
+ case SI::ContentDescriptorTag:
+ {
+ SI::ContentDescriptor *cd = (SI::ContentDescriptor *) d;
+ SI::ContentDescriptor::Nibble Nibble;
+ int NumContents = 0;
+ uchar Contents[MaxEventContents] =
+ { 0 };
+ for (SI::Loop::Iterator it3; cd->nibbleLoop.getNext(Nibble, it3);)
+ {
+ if (NumContents < MaxEventContents)
+ {
+ Contents[NumContents] = ((Nibble.getContentNibbleLevel1()
+ & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF);
+ NumContents++;
+ }
+ if (DishEventDescriptor && NumContents == 1)
+ {
+ DishEventDescriptor->setContent(Nibble);
+ }
+ // LogD(2, prep("EEPGDEBUG:Nibble:%x-%x-%x-%x)"), Nibble.getContentNibbleLevel1(),Nibble.getContentNibbleLevel2()
+ // , Nibble.getUserNibble1(), Nibble.getUserNibble2());
+
+ }
+ pEvent->SetContents(Contents);
+ }
+ break;
+#endif
+ case SI::ParentalRatingDescriptorTag:
+ {
+ int LanguagePreferenceRating = -1;
+ SI::ParentalRatingDescriptor *prd =
+ (SI::ParentalRatingDescriptor *) d;
+ SI::ParentalRatingDescriptor::Rating Rating;
+ for (SI::Loop::Iterator it3; prd->ratingLoop.getNext(Rating, it3);)
+ {
+ if (I18nIsPreferredLanguage(Setup.EPGLanguages,
+ Rating.languageCode, LanguagePreferenceRating))
+ {
+ int ParentalRating = (Rating.getRating() & 0xFF);
+ switch (ParentalRating)
+ {
+ // values defined by the DVB standard (minimum age = rating + 3 years):
+ case 0x01 ... 0x0F:
+ ParentalRating += 3;
+ break;
+ // values defined by broadcaster CSAT (now why didn't they just use 0x07, 0x09 and 0x0D?):
+ case 0x11:
+ ParentalRating = 10;
+ break;
+ case 0x12:
+ ParentalRating = 12;
+ break;
+ case 0x13:
+ ParentalRating = 16;
+ break;
+ default:
+ ParentalRating = 0;
+ }
+ pEvent->SetParentalRating(ParentalRating);
+ }
+ }
+ }
+ break;
+ case SI::PDCDescriptorTag:
+ {
+ SI::PDCDescriptor * pd = (SI::PDCDescriptor *) d;
+ time_t now = time(NULL);
+ struct tm tm_r;
+ struct tm t = *localtime_r(&now, &tm_r); // this initializes the time zone in 't'
+ t.tm_isdst = -1; // makes sure mktime() will determine the correct DST setting
+ int month = t.tm_mon;
+ t.tm_mon = pd->getMonth() - 1;
+ t.tm_mday = pd->getDay();
+ t.tm_hour = pd->getHour();
+ t.tm_min = pd->getMinute();
+ t.tm_sec = 0;
+ if (month == 11 && t.tm_mon == 0) // current month is dec, but event is in jan
+ t.tm_year++;
+ else if (month == 0 && t.tm_mon == 11) // current month is jan, but event is in dec
+ t.tm_year--;
+ time_t vps = mktime(&t);
+ pEvent->SetVps(vps);
+ }
+ break;
+ case SI::TimeShiftedEventDescriptorTag:
+ {
+ if (Schedules) {
+ SI::TimeShiftedEventDescriptor * tsed =
+ (SI::TimeShiftedEventDescriptor *) d;
+ cSchedule *rSchedule = (cSchedule *) Schedules->GetSchedule(
+ tChannelID(Source, channel->Nid(), channel->Tid(),
+ 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());
+ }
+ }
+ break;
+ case SI::LinkageDescriptorTag:
+ {
+ SI::LinkageDescriptor * ld = (SI::LinkageDescriptor *) d;
+ tChannelID linkID(Source, ld->getOriginalNetworkId(),
+ ld->getTransportStreamId(), ld->getServiceId());
+ if (ld->getLinkageType() == 0xB0)
+ { // Premiere World
+ time_t now = time(NULL);
+ bool hit = SiEitEvent->getStartTime() <= now
+ && now
+ < SiEitEvent->getStartTime() + SiEitEvent->getDuration();
+ if (hit)
+ {
+ char linkName[ld->privateData.getLength() + 1];
+ strn0cpy(linkName, (const char *) ld->privateData.getData(),
+ sizeof(linkName));
+ // TODO is there a standard way to determine the character set of this string?
+ cChannel *link = Channels.GetByChannelID(linkID);
+ if (link != channel)
+ { // only link to other channels, not the same one
+ //fprintf(stderr, "Linkage %s %4d %4d %5d %5d %5d %5d %02X '%s'\n", hit ? "*" : "", channel->Number(), link ? link->Number() : -1, SiEitEvent.getEventId(), ld->getOriginalNetworkId(), ld->getTransportStreamId(), ld->getServiceId(), ld->getLinkageType(), linkName);//XXX
+ if (link)
+ {
+ if (Setup.UpdateChannels == 1
+ || Setup.UpdateChannels >= 3)
+ link->SetName(linkName, "", "");
+ }
+ else if (Setup.UpdateChannels >= 4)
+ {
+ cChannel *transponder = channel;
+ if (channel->Tid() != ld->getTransportStreamId())
+ transponder = Channels.GetByTransponderID(linkID);
+ link = Channels.NewChannel(transponder, linkName,
+ "", "", ld->getOriginalNetworkId(),
+ ld->getTransportStreamId(), ld->getServiceId());
+ }
+ if (link)
+ {
+ if (!LinkChannels)
+ LinkChannels = new cLinkChannels;
+ LinkChannels->Add(new cLinkChannel(link));
+ }
+ }
+ else
+ channel->SetPortalName(linkName);
+ }
+ }
+ }
+ break;
+ case SI::ComponentDescriptorTag:
+ {
+ SI::ComponentDescriptor * cd = (SI::ComponentDescriptor *) d;
+ uchar Stream = cd->getStreamContent();
+ uchar Type = cd->getComponentType();
+ //if (1 <= Stream && Stream <= 3 && Type != 0) { // 1=video, 2=audio, 3=subtitles
+ 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
+ if (!Components)
+ Components = new cComponents;
+ char buffer[Utf8BufSize (256)];
+ Components->SetComponent(Components->NumComponents(), Stream,
+ Type, I18nNormalizeLanguageCode(cd->languageCode),
+ cd->description.getText(buffer, sizeof(buffer)));
+ }
+ }
+ break;
+ case SI::DishExtendedEventDescriptorTag:
+ {
+ SI::UnimplementedDescriptor *deed =
+ (SI::UnimplementedDescriptor *) d;
+ if (!DishEventDescriptor)
+ {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ DishEventDescriptor->setExtendedtData(Tid + 1, deed->getData());
+ // HasExternalData = true;
+ }
+ break;
+ case SI::DishShortEventDescriptorTag:
+ {
+ SI::UnimplementedDescriptor *dsed =
+ (SI::UnimplementedDescriptor *) d;
+ if (!DishEventDescriptor)
+ {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ DishEventDescriptor->setShortData(Tid + 1, dsed->getData());
+ // HasExternalData = true;
+ }
+ break;
+ case SI::DishRatingDescriptorTag:
+ {
+ if (d->getLength() == 4)
+ {
+ if (!DishEventDescriptor)
+ {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ uint16_t rating = d->getData().TwoBytes(2);
+ DishEventDescriptor->setRating(rating);
+ }
+ }
+ break;
+ case SI::DishSeriesDescriptorTag:
+ {
+ if (d->getLength() == 10)
+ {
+ //LogD(2, prep("DishSeriesDescriptorTag: %s)"), (const char*) d->getData().getData());
+ if (!DishEventDescriptor)
+ {
+ DishEventDescriptor = new SI::DishDescriptor();
+ }
+ DishEventDescriptor->setEpisodeInfo(d->getData());
+ }
+ // else {
+ // LogD(2, prep("DishSeriesDescriptorTag length: %d)"), d->getLength());
+ // }
+ }
+ break;
+ default:
+ break;
+ }
+ delete d;
+ }
+ if (!rEvent) {
+ if (ShortEventDescriptor) {
+ char buffer[Utf8BufSize (256)];
+ unsigned char *f;
+ int l = ShortEventDescriptor->name.getLength();
+ f = (unsigned char *) ShortEventDescriptor->name.getData().getData();
+ decodeText2 (f, l, buffer, sizeof (buffer));
+ //ShortEventDescriptor->name.getText(buffer, sizeof(buffer));
+ LogD(2, prep("Title: %s Decoded: %s"), f, buffer);
+ pEvent->SetTitle (buffer);
+ LogD(3, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title());
+ l = ShortEventDescriptor->text.getLength();
+ if (l > 0) { //Set the Short Text only if there is data so that we do not overwrite valid data
+ f = (unsigned char *) ShortEventDescriptor->text.getData().getData();
+ decodeText2 (f, l, buffer, sizeof (buffer));
+ //ShortEventDescriptor->text.getText(buffer, sizeof(buffer));
+ pEvent->SetShortText (buffer);
+ }
+ LogD(3, prep("ShortText: %s"), pEvent->ShortText());
+ LogD(2, prep("ShortText: %s Decoded: %s"), f, buffer);
+ } else if (/*!HasExternalData*/!DishEventDescriptor) {
+ pEvent->SetTitle (NULL);
+ pEvent->SetShortText (NULL);
+ LogD(3, prep("SetTitle (NULL)"));
+ }
+ if (ExtendedEventDescriptors) {
+ char buffer[Utf8BufSize (ExtendedEventDescriptors->getMaximumTextLength (": ")) + 1];
+ pEvent->SetDescription (ExtendedEventDescriptors->getText (buffer, sizeof (buffer), ": "));
+ LogD(3, prep("Description: %s"), pEvent->Description());
+ } else if (!/*HasExternalData*/DishEventDescriptor)
+ pEvent->SetDescription (NULL);
+
+ if (DishEventDescriptor) {
+ if (DishEventDescriptor->getName())
+ pEvent->SetTitle(DishEventDescriptor->getName());
+ //LogD(2, prep("channelID: %s DishTitle: %s"), *channel->GetChannelID().ToString(), DishEventDescriptor->getName());
+ pEvent->SetShortText(DishEventDescriptor->getShortText());
+ char *tmp;
+ string fmt;
+
+ const char * description = DishEventDescriptor->getDescription();
+ //BEV sets the description previously with ExtendedEventDescriptor
+ if (0 == strcmp(DishEventDescriptor->getDescription(),"") && pEvent->Description())
+ description = pEvent->Description();
+
+
+ fmt = "%s";
+ if (DishEventDescriptor->hasTheme()) {
+ fmt += "\nTheme: ";
+ }
+ fmt += "%s";
+ if (DishEventDescriptor->hasCategory()) {
+ fmt += "\nCategory: ";
+ }
+ fmt += "%s";
+
+ if ((0 != strcmp(DishEventDescriptor->getRating(),"")
+ || 0 != strcmp(DishEventDescriptor->getStarRating(),""))) {
+ fmt += "\n\nRating: ";
+ }
+ fmt += "%s %s";
+ if (0 != strcmp(DishEventDescriptor->getProgramId(),"")) {
+ fmt += "\n\nProgram ID: ";
+ }
+ fmt += "%s %s%s";
+ time_t orgAirDate = DishEventDescriptor->getOriginalAirDate();
+ char datestr [80];
+ bool dateok = false;
+ if (orgAirDate == 0) {
+ dateok = strftime (datestr,80," Original Air Date: %a %b %d %Y",gmtime(&orgAirDate)) > 0;
+ }
+
+ Asprintf (&tmp, fmt.c_str(), description
+ , DishEventDescriptor->getTheme(), DishEventDescriptor->getCategory()
+ , DishEventDescriptor->getRating(), DishEventDescriptor->getStarRating()
+ , DishEventDescriptor->getProgramId(), DishEventDescriptor->getSeriesId()
+ , orgAirDate == 0 || !dateok ? "" : datestr);
+ pEvent->SetDescription(tmp);
+ free(tmp);
+
+
+ //LogD(2, prep("DishDescription: %s"), DishEventDescriptor->getDescription());
+ //LogD(2, prep("DishShortText: %s"), DishEventDescriptor->getShortText());
+ }
+
+ }
+ delete ExtendedEventDescriptors;
+ delete ShortEventDescriptor;
+ delete DishEventDescriptor;
+
+ pEvent->SetComponents (Components);
+
+ // LogD(2, prep("channelID: %s Title: %s"), *channel->GetChannelID().ToString(), pEvent->Title());
+
+ // if (pEvent->ChannelID() == tChannelID::FromString("S119.0W-4100-6-110-110")) {
+ // LogD(2, prep("ID: %d Title: %s Time: %d Tid: 0x%x"), pEvent->EventID(), pEvent->Title(), pEvent->StartTime(), pEvent->TableID());
+ // }
+
+ // if (!HasExternalData)
+ pEvent->FixEpgBugs ();
+ if (LinkChannels)
+ channel->SetLinkChannels (LinkChannels);
+}
+
+cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid, bool OnlyRunningStatus)
+: SI::EIT (Data, false)
+, OnlyRunningStatus(OnlyRunningStatus)
+, Schedules(Schedules)
+{
+
+ //LogD(2, prep("cEIT2::cEIT2"));
+ if (Tid > 0 && (Format == DISH_BEV || (cSetupEEPG::getInstance()->ProcessEIT && isEITPid))) Tid--;
+
+ if (!CheckCRCAndParse ()) {
+ LogD(2, prep("!CheckCRCAndParse ()"));
+ return;
+ }
+
+ bool searchOtherSatPositions = Format == DISH_BEV;
+
+ tChannelID channelID (Source, getOriginalNetworkId (), getTransportStreamId (), getServiceId ());
+ channel = GetChannelByID (channelID, searchOtherSatPositions);
+ if (!channel) {
+ LogD(3, prep("!channel channelID: %s"), *channelID.ToString());
+ return; // only collect data for known channels
+ }
+
+ //LogD(5, prep("channelID: %s format:%d"), *channel->GetChannelID().ToString(), Format);
+
+ cSchedule *pSchedule = (cSchedule *) Schedules->GetSchedule (channel, true);
+
+ Empty = true;
+ Modified = false;
+ // bool HasExternalData = false;
+ SegmentStart = 0;
+ SegmentEnd = 0;
+
+ SI::EIT::Event SiEitEvent;
+ for (SI::Loop::Iterator it; eventLoop.getNext (SiEitEvent, it);) {
+ int versionNumber = getVersionNumber();
+ // bool ExternalData = false;
+ // // 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.
+ // if (SiEitEvent.getStartTime () == 0 || (SiEitEvent.getStartTime () > 0 && SiEitEvent.getDuration () == 0))
+ // continue;
+ // Empty = false;
+ // if (!SegmentStart)
+ // SegmentStart = SiEitEvent.getStartTime ();
+ // SegmentEnd = SiEitEvent.getStartTime () + SiEitEvent.getDuration ();
+ // int versionNumber = getVersionNumber();
+ //
+ // cEvent *newEvent = NULL;
+ // cEvent *pEvent = (cEvent *) pSchedule->GetEvent (SiEitEvent.getEventId (), SiEitEvent.getStartTime ());
+ // if (!pEvent) {
+ // if (OnlyRunningStatus)
+ // continue;
+ // // If we don't have that event yet, we create a new one.
+ // // Otherwise we copy the information into the existing event anyway, because the data might have changed.
+ // pEvent = newEvent = new cEvent (SiEitEvent.getEventId ());
+ // if (!pEvent)
+ // continue;
+ // } else {
+ // //LogD(3, prep("existing event channelID: %s Title: %s TableID 0x%02X new TID 0x%02X Version %i, new version %i"), *channel->GetChannelID().ToString(), pEvent->Title(), pEvent->TableID(), Tid, pEvent->Version(), versionNumber);
+ // // We have found an existing event, either through its event ID or its start time.
+ // pEvent->SetSeen ();
+ //
+ // // If the existing event has a zero table ID it was defined externally and shall
+ // // not be overwritten.
+ // if (pEvent->TableID () == 0x00) {
+ // if (pEvent->Version () == versionNumber)
+ // continue;
+ // /*HasExternalData = */ExternalData = true;
+ // }
+ // // If the new event has a higher table ID, let's skip it.
+ // // The lower the table ID, the more "current" the information.
+ // else if (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.
+ // else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber)
+ // continue;
+ // }
+ // if (!ExternalData) {
+ // pEvent->SetEventID (SiEitEvent.getEventId ()); // unfortunately some stations use different event ids for the same event in different tables :-(
+ // pEvent->SetTableID (Tid);
+ // pEvent->SetStartTime (SiEitEvent.getStartTime ());
+ // pEvent->SetDuration (SiEitEvent.getDuration ());
+ // }
+ // if (newEvent)
+ // pSchedule->AddEvent (newEvent);
+ // if (Tid == 0x4E) { // we trust only the present/following info on the actual TS
+ // if (SiEitEvent.getRunningStatus () >= SI::RunningStatusNotRunning)
+ // pSchedule->SetRunningStatus (pEvent, SiEitEvent.getRunningStatus (), channel);
+ // }
+ // if (OnlyRunningStatus)
+ // continue; // do this before setting the version, so that the full update can be done later
+ // pEvent->SetVersion (versionNumber);
+ //
+ // ProcessEventDescriptors(ExternalData, Source, Tid, SiEitEvent,
+ // pEvent, Schedules, channel);
+ //
+ // Modified = true;
+ cEvent *pEvent = ProcessEitEvent(pSchedule, &SiEitEvent,
+ Tid, versionNumber);
+ if (pEvent)
+ EquivHandler->updateEquivalent(Schedules, channel->GetChannelID(), pEvent);
+ }
+
+ ////
+
+ if (Empty && Tid == 0x4E && getSectionNumber () == 0)
+ // ETR 211: an empty entry in section 0 of table 0x4E means there is currently no event running
+ pSchedule->ClrRunningStatus (channel);
+ if (Tid == 0x4E)
+ pSchedule->SetPresentSeen ();
+ if (OnlyRunningStatus) {
+ LogD(4, prep("OnlyRunningStatus"));
+ return;
+ }
+ if (Modified) {
+ // if (!HasExternalData)
+ pSchedule->DropOutdated (SegmentStart, SegmentEnd, Tid, getVersionNumber ());
+ sortSchedules(Schedules, channel->GetChannelID());
+ }
+ LogD(4, prep("end of cEIT2"));
+
+}
+//end of cEIT2
+
+cEIT2::cEIT2 (cSchedule * Schedule)
+: Empty(true)
+, Modified(false)
+, OnlyRunningStatus(false)
+, SegmentStart(0)
+, SegmentEnd(0)
+, Schedules(NULL)
+{
+ //LogD(2, prep("cEIT2::cEIT2"));
+ // if (Tid > 0 && (Format == DISH_BEV || (SetupPE->ProcessEIT && isEITPid))) Tid--;
+
+ bool searchOtherSatPositions = Format == DISH_BEV;
+
+ tChannelID channelID (Schedule->ChannelID().Source(), getOriginalNetworkId (), getTransportStreamId (), getServiceId ());
+ channel = GetChannelByID (channelID, searchOtherSatPositions);
+ if (!channel) {
+ LogD(3, prep("!channel channelID: %s"), *channelID.ToString());
+ return; // only collect data for known channels
+ }
+}
+} //end namespace SI
+
diff --git a/eit2.h b/eit2.h
new file mode 100644
index 0000000..7686672
--- /dev/null
+++ b/eit2.h
@@ -0,0 +1,50 @@
+#ifndef CEIT2_H_
+#define CEIT2_H_
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+#include <libsi/si.h>
+#include <vdr/epg.h>
+
+namespace SI
+{
+enum DescriptorTagExt {
+ DishRatingDescriptorTag = 0x89,
+ DishShortEventDescriptorTag = 0x91,
+ DishExtendedEventDescriptorTag = 0x92,
+ DishSeriesDescriptorTag = 0x96,
+};
+
+// typedef InheritEnum< DescriptorTagExt, SI::DescriptorTag > ExtendedDescriptorTag;
+
+/*extern const char *getCharacterTable(const unsigned char *&buffer, int &length, bool *isSingleByte = NULL);
+extern bool convertCharacterTable(const char *from, size_t fromLength, char *to, size_t toLength, const char *fromCode);
+extern bool SystemCharacterTableIsSingleByte;*/
+class cEIT2:public SI::EIT
+{
+public:
+ cEIT2(cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid = false,
+ bool OnlyRunningStatus = false);
+ cEIT2 (cSchedule * Schedule);
+ //protected:
+ // void updateEquivalent(cSchedules * Schedules, tChannelID channelID, cEvent *pEvent);
+ cEvent* ProcessEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version);
+
+private:
+ void ProcessEventDescriptors(bool ExternalData, int Source, u_char Tid,
+ const SI::EIT::Event* SiEitEvent, cEvent* pEvent,
+ cSchedules* Schedules, cChannel* channel);
+
+private:
+ bool Empty;
+ bool Modified;
+ // bool HasExternalData = false;
+ bool OnlyRunningStatus;
+ time_t SegmentStart;
+ time_t SegmentEnd;
+ cSchedules* Schedules;
+ cChannel* channel;
+
+};
+} //end namespace SI
+
+#endif /* CEIT2_H_ */
diff --git a/epghandler.c b/epghandler.c
index 44ee909..0262d75 100644
--- a/epghandler.c
+++ b/epghandler.c
@@ -9,7 +9,9 @@
#if APIVERSNUM > 10725
#include "log.h"
#include "equivhandler.h"
+#include "eit2.h"
#include <vdr/sources.h>
+#include <libsi/si.h>
cEEpgHandler::cEEpgHandler() {
LogD(4, prep("cEEpgHandler()"));
@@ -27,8 +29,11 @@ bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule,
//DISH NID 0x1001 to 0x100B BEV 0x100 and 0x101
//TODO move the eit handling code at least for NA providers here instead of discarding.
int nid = Schedule->ChannelID().Nid();
- if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100)
+ if ((nid >= 0x1001 && nid <= 0x100B) || nid == 0x101 || nid == 0x100) {
+ SI::cEIT2 eit2(Schedule);
+ eit2.ProcessEitEvent(Schedule, EitEvent, TableID, Version);
return true;
+ }
//TODO Should it be added in setup?
if (EitEvent->getDurationHour() > _LONG_EVENT_HOURS) {
@@ -43,6 +48,25 @@ bool cEEpgHandler::HandleEitEvent(cSchedule* Schedule,
}
}
+ //VDR creates new event if the EitEvent StartTime is different than EEPG time so
+ //the EEPG event has to be deleted but the data should be kept
+ const cEvent* ev = Schedule->GetEvent(EitEvent->getEventId(),EitEvent->getStartTime());
+ if (!ev){
+ ev = Schedule->GetEvent(EitEvent->getEventId());
+ if (ev && ((ev->StartTime()>EitEvent->getStartTime() && ev->StartTime()<=EitEvent->getStartTime()+EitEvent->getDuration())
+ || (EitEvent->getStartTime() > ev->StartTime() && EitEvent->getStartTime() <= ev->EndTime()))) {
+ LogD(0, prep("!!!Deleting Event id:%d title:%s start_time:%d new_start_time:%d duration:%d new_duration:%d"), ev->EventID(), ev->Title(), ev->StartTime(), EitEvent->getStartTime(), ev->Duration(), EitEvent->getDuration());
+
+ if (ev->Description() && strcmp(ev->Description(),"") != 0)
+ origDescription = ev->Description();
+ if (ev->ShortText() && strcmp(ev->ShortText(),"") != 0)
+ origShortText = ev->ShortText();
+ Schedule->DropOutdated(ev->StartTime()-1,ev->EndTime()+1,ev->TableID()-1,ev->Version());
+ LogD(0, prep("!!!End Deleting Event"));
+ }
+ }
+
+
return false;
// return true;
@@ -148,6 +172,7 @@ bool cEEpgHandler::HandleEvent(cEvent* Event) {
return true;
}
+
bool cEEpgHandler::SortSchedule(cSchedule* Schedule) {
Schedule->Sort();
diff --git a/epghandler.h b/epghandler.h
index 3219f58..4e60e57 100644
--- a/epghandler.h
+++ b/epghandler.h
@@ -34,6 +34,8 @@ public:
virtual bool SortSchedule(cSchedule *Schedule);
virtual bool DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version);
+// bool ParseEitEvent(cSchedule *Schedule, const SI::EIT::Event *EitEvent, uchar TableID, uchar Version);
+
private:
std::string origShortText;
std::string origDescription;
diff --git a/equivhandler.c b/equivhandler.c
index a742150..281d2f3 100644
--- a/equivhandler.c
+++ b/equivhandler.c
@@ -170,8 +170,8 @@ void cEquivHandler::updateEquivalent(tChannelID channelID, cEvent *pEvent){
ret = equiChanMap.equal_range(*channelID.ToString());
for (it=ret.first; it!=ret.second; ++it) {
- LogD(3, prep("equivalent channel exists"));
tChannelID equChannelID (tChannelID::FromString((*it).second.c_str()));
+ LogD(3, prep("equivalent channel '%s' exists"), *equChannelID.ToString());
cEvent* newEvent = new cEvent (pEvent->EventID());
cloneEvent(pEvent, newEvent);
diff --git a/log.h b/log.h
index 35942d3..b743763 100644
--- a/log.h
+++ b/log.h
@@ -9,7 +9,8 @@
#define LOG_H_
#include <string>
-#include <stdarg.h>
+#include <vdr/tools.h>
+#include <vdr/thread.h>
#include "setupeepg.h"
#define VERBOSE 1
diff --git a/setupeepg.c b/setupeepg.c
index 54f8243..ee2565e 100644
--- a/setupeepg.c
+++ b/setupeepg.c
@@ -14,6 +14,7 @@ cSetupEEPG* cSetupEEPG::_setupEEPG = NULL;
cSetupEEPG::cSetupEEPG (void)
{
+ ConfDir = NULL;
OptPat = 1;
OrderInfo = 1;
RatingInfo = 1;
diff --git a/util.c b/util.c
index 6df6137..bf5455a 100644
--- a/util.c
+++ b/util.c
@@ -5,6 +5,8 @@
* Author: d.petrovski
*/
#include "util.h"
+#include "log.h"
+#include "equivhandler.h"
#include <vdr/channels.h>
#include <vdr/thread.h>
#include <vdr/epg.h>
@@ -21,6 +23,12 @@ int Yesterday;
int YesterdayEpoch;
int YesterdayEpochUTC;
+struct hufftab *tables[2][128];
+int table_size[2][128];
+
+EFormat Format;
+cEquivHandler* EquivHandler;
+
cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos)
{
cChannel *VC = Channels.GetByChannelID(channelID, true);
@@ -155,7 +163,7 @@ class cAddEventThread : public cThread
private:
cTimeMs LastHandleEvent;
// cList<cAddEventListItem> *list;
- std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare> *map_list;
+ std::map<tChannelID,cList<cEvent>*,tChannelIDCompare> *map_list;
enum { INSERT_TIMEOUT_IN_MS = 10000 };
protected:
virtual void Action(void);
@@ -169,14 +177,14 @@ cAddEventThread::cAddEventThread(void)
:cThread("cAddEventThread"), LastHandleEvent()
{
// list = new cList<cAddEventListItem>;
- map_list = new std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare>;
+ map_list = new std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>;
}
cAddEventThread::~cAddEventThread(void)
{
LOCK_THREAD;
// list->cList::Clear();
- std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare>::iterator it;
+ std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>::iterator it;
for ( it=map_list->begin() ; it != map_list->end(); it++ )
(*it).second->cList::Clear();
Cancel(3);
@@ -197,21 +205,28 @@ void cAddEventThread::Action(void)
// EpgHandlers.DropOutdated(schedule, e->GetEvent()->StartTime(), e->GetEvent()->EndTime(), e->GetEvent()->TableID(), e->GetEvent()->Version());
// list->Del(e);
// }
- std::map<tChannelID,cList<cEvent *>*,tChannelIDCompare>::iterator it;
+ std::map<tChannelID,cList<cEvent>*,tChannelIDCompare>::iterator it;
it=map_list->begin();
while (schedules && it != map_list->end()) {
cSchedule *schedule = (cSchedule *)schedules->GetSchedule(Channels.GetByChannelID((*it).first), true);
while (((*it).second->First()) != NULL) {
- cEvent* event = *(*it).second->First();
+ cEvent* event = (*it).second->First();
cEvent *pEqvEvent = (cEvent *) schedule->GetEvent (event->EventID(), event->StartTime());
- if (pEqvEvent)
+ if (pEqvEvent){
+ LogD (0, prep("schedule->DelEvent(event)"));
schedule->DelEvent(pEqvEvent);
+ }
- schedule->AddEvent(event);
+ LogD (0, prep("schedule->AddEvent(event)"));
+ //cCondWait::SleepMs(10);
+ if (event)
+ schedule->AddEvent(event);
(*it).second->Del(event);
}
EpgHandlers.SortSchedule(schedule);
+ //sortSchedules(schedules, (*it).first);
+ //schedule->Sort();
delete (*it).second;
map_list->erase(it);
it=map_list->begin();
@@ -224,16 +239,21 @@ void cAddEventThread::Action(void)
void cAddEventThread::AddEvent(cEvent *Event, tChannelID ChannelID)
{
+ LogD (0, prep("AddEventT start"));
LOCK_THREAD;
+ LogD (0, prep("AddEventT lock "));
if (map_list->empty() || map_list->count(ChannelID) == 0) {
- cList<cEvent *>* list = new cList<cEvent *>;
+ LogD (0, prep("AddEventT if"));
+ cList<cEvent>* list = new cList<cEvent>;
list->Add(Event);
map_list->insert(std::make_pair(ChannelID, list));
} else {
+ LogD (0, prep("AddEventT else"));
(*map_list->find(ChannelID)).second->Add(Event);
}
// list->Add(new cAddEventListItem(Event, ChannelID));
LastHandleEvent.Set(INSERT_TIMEOUT_IN_MS);
+ LogD (0, prep("AddEventT end"));
}
static cAddEventThread AddEventThread;
@@ -242,11 +262,144 @@ static cAddEventThread AddEventThread;
void AddEvent(cEvent *Event, tChannelID ChannelID)
{
+ LogD (0, prep("AddEvent"));
AddEventThread.AddEvent(Event, ChannelID);
if (!AddEventThread.Active())
AddEventThread.Start();
}
+/** \brief Decode an EPG string as necessary
+ *
+ * \param src - Possibly encoded string
+ * \param size - Size of the buffer
+ *
+ * \retval NULL - Can't decode
+ * \return A decoded string
+ */
+char *freesat_huffman_decode (const unsigned char *src, size_t size)
+{
+ int tableid;
+// freesat_decode_error = 0;
+
+ if (src[0] == 0x1f && (src[1] == 1 || src[1] == 2)) {
+ int uncompressed_len = 30;
+ char *uncompressed = (char *) calloc (1, uncompressed_len + 1);
+ unsigned value = 0, byte = 2, bit = 0;
+ int p = 0;
+ unsigned char lastch = START;
+
+ tableid = src[1] - 1;
+ while (byte < 6 && byte < size) {
+ value |= src[byte] << ((5 - byte) * 8);
+ byte++;
+ }
+ //freesat_table_load (); /**< Load the tables as necessary */
+
+ do {
+ bool found = false;
+ unsigned bitShift = 0;
+ if (lastch == ESCAPE) {
+ char nextCh = (value >> 24) & 0xff;
+ found = true;
+ // Encoded in the next 8 bits.
+ // Terminated by the first ASCII character.
+ bitShift = 8;
+ if ((nextCh & 0x80) == 0)
+ lastch = nextCh;
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ } else {
+ int j;
+ for (j = 0; j < table_size[tableid][lastch]; j++) {
+ unsigned mask = 0, maskbit = 0x80000000;
+ short kk;
+ for (kk = 0; kk < tables[tableid][lastch][j].bits; kk++) {
+ mask |= maskbit;
+ maskbit >>= 1;
+ }
+ if ((value & mask) == tables[tableid][lastch][j].value) {
+ char nextCh = tables[tableid][lastch][j].next;
+ bitShift = tables[tableid][lastch][j].bits;
+ if (nextCh != STOP && nextCh != ESCAPE) {
+ if (p >= uncompressed_len) {
+ uncompressed_len += 10;
+ uncompressed = (char *) REALLOC (uncompressed, uncompressed_len + 1);
+ }
+ uncompressed[p++] = nextCh;
+ uncompressed[p] = 0;
+ }
+ found = true;
+ lastch = nextCh;
+ break;
+ }
+ }
+ }
+ if (found) {
+ // Shift up by the number of bits.
+ unsigned b;
+ for (b = 0; b < bitShift; b++) {
+ value = (value << 1) & 0xfffffffe;
+ if (byte < size)
+ value |= (src[byte] >> (7 - bit)) & 1;
+ if (bit == 7) {
+ bit = 0;
+ byte++;
+ } else
+ bit++;
+ }
+ } else {
+ LogE (0, prep("Missing table %d entry: <%s>"), tableid + 1, uncompressed);
+ // Entry missing in table.
+ return uncompressed;
+ }
+ } while (lastch != STOP && value != 0);
+
+ return uncompressed;
+ }
+ return NULL;
+}
+
+void decodeText2 (const unsigned char *from, int len, char *buffer, int buffsize)
+{
+ if (from[0] == 0x1f) {
+ char *temp = freesat_huffman_decode (from, len);
+ if (temp) {
+ len = strlen (temp);
+ len = len < buffsize - 1 ? len : buffsize - 1;
+ strncpy (buffer, temp, len);
+ buffer[len] = 0;
+ free (temp);
+ return;
+ }
+ }
+
+ SI::String convStr;
+ SI::CharArray charArray;
+ charArray.assign(from, len);
+ convStr.setData(charArray, len);
+ //LogE(5, prep("decodeText2 from %s - length %d"), from, len);
+ convStr.getText(buffer, buffsize);
+ //LogE(5, prep("decodeText2 buffer %s - buffsize %d"), buffer, buffsize);
+}
+
+void sortSchedules(cSchedules * Schedules, tChannelID channelID){
+
+ LogD(3, prep("Start sortEquivalent %s"), *channelID.ToString());
+
+ cChannel *pChannel = GetChannelByID (channelID, false);
+ cSchedule *pSchedule;
+ if (pChannel) {
+ pSchedule = (cSchedule *) (Schedules->GetSchedule(pChannel, true));
+ pSchedule->Sort();
+ Schedules->SetModified(pSchedule);
+ }
+ if (EquivHandler->getEquiChanMap().count(*channelID.ToString()) > 0)
+ EquivHandler->sortEquivalents(channelID, Schedules);
+}
}
diff --git a/util.h b/util.h
index 230f44c..69c0717 100644
--- a/util.h
+++ b/util.h
@@ -11,9 +11,18 @@
class cChannel;
struct tChannelID;
class cEvent;
+class cEquivHandler;
+class cSchedules;
+
+#define START '\0'
+#define STOP '\0'
+#define ESCAPE '\1'
+
+#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() )
namespace util
{
+
extern int AvailableSources[32];
extern int NumberOfAvailableSources;
@@ -21,12 +30,62 @@ extern int Yesterday;
extern int YesterdayEpoch;
extern int YesterdayEpochUTC;
+extern enum EFormat
+{
+//First all batchmode, load ONCE protocols:
+ MHW1 = 0,
+ MHW2,
+ SKY_IT,
+ SKY_UK,
+ NAGRA,
+//Than all CONTinuous protocols, so they will be processed LAST:
+ PREMIERE,
+ FREEVIEW,
+ DISH_BEV,
+ EIT,
+//the highest number of EPG-formats that is supported by this plugin
+ HIGHEST_FORMAT = EIT
+} Format;
+
+extern cEquivHandler* EquivHandler;
+
void AddEvent(cEvent *event, tChannelID ChannelID);
cChannel *GetChannelByID(tChannelID & channelID, bool searchOtherPos);
-time_t LocalTime2UTC (time_t t);
-time_t UTC2LocalTime (time_t t);
-void GetLocalTimeOffset (void);
-void CleanString (unsigned char *String);
+time_t LocalTime2UTC(time_t t);
+time_t UTC2LocalTime(time_t t);
+void GetLocalTimeOffset(void);
+void CleanString(unsigned char *String);
+void decodeText2(const unsigned char *from, int len, char *buffer, int buffsize);
+char *freesat_huffman_decode(const unsigned char *src, size_t size);
+void sortSchedules(cSchedules * Schedules, tChannelID channelID);
+
+//struct sNode
+//{
+// char *Value;
+// struct sNode *P0;
+// struct sNode *P1;
+//};
+//
+//typedef struct sNode sNodeH;
+
+template<class T> T REALLOC(T Var, size_t Size)
+{
+ T p = (T) realloc(Var, Size);
+ if (!p) free(Var);
+ return p;
+}
+
+struct hufftab
+{
+ unsigned int value;
+ short bits;
+ char next;
+};
+
+extern struct hufftab *tables[2][128];
+extern int table_size[2][128];
+//static sNodeH* sky_tables[2];
+
}
#endif /* UTIL_H_ */