summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitar Petrovski <dimeptr@gmail.com>2012-10-16 17:40:59 (GMT)
committerDimitar Petrovski <dimeptr@gmail.com>2012-10-16 17:40:59 (GMT)
commit7de1003a14fb4b41920896c550db4e58f53aea8d (patch)
treedc70fa663dba793f25a1a14b9577ce8972d2ba70
parentd207fd0a5873a4a60488a8dc2eb0cf62c172069b (diff)
downloadvdr-plugin-eepg-7de1003a14fb4b41920896c550db4e58f53aea8d.tar.gz
vdr-plugin-eepg-7de1003a14fb4b41920896c550db4e58f53aea8d.tar.bz2
Drop unmanaged Disable Double EPG entry. EEPG tries to handle this anyway
Drop unmanaged NOEPG support, there is a separate plugin for that Move cEIT2 in a separate file and try to use it in epghandler also
-rw-r--r--Makefile2
-rw-r--r--eepg.c645
-rw-r--r--eit2.c640
-rw-r--r--eit2.h49
-rw-r--r--epghandler.c7
-rw-r--r--epghandler.h2
-rw-r--r--util.h3
7 files changed, 702 insertions, 646 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..1174681 100644
--- a/eepg.c
+++ b/eepg.c
@@ -150,7 +150,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 +173,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:
@@ -2662,628 +2641,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/eit2.c b/eit2.c
new file mode 100644
index 0000000..5bd7cc4
--- /dev/null
+++ b/eit2.c
@@ -0,0 +1,640 @@
+/*
+ * 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"
+
+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;
+
+
+
+ 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:
+ {
+ 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 || (SetupPE->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)
+: OnlyRunningStatus(false)
+, Empty(true)
+, Modified(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..5d2e4bb
--- /dev/null
+++ b/eit2.h
@@ -0,0 +1,49 @@
+#ifndef CEIT2_H_
+#define CEIT2_H_
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+#include <libsi/si.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;
+ time_t SegmentStart;
+ time_t SegmentEnd;
+ cSchedules* Schedules;
+ cChannel* channel;
+
+ bool OnlyRunningStatus;
+ };
+} //end namespace SI
+
+#endif /* CEIT2_H_ */
diff --git a/epghandler.c b/epghandler.c
index f8a6636..3aaec2e 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) {
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/util.h b/util.h
index 230f44c..f15bce6 100644
--- a/util.h
+++ b/util.h
@@ -28,5 +28,8 @@ time_t LocalTime2UTC (time_t t);
time_t UTC2LocalTime (time_t t);
void GetLocalTimeOffset (void);
void CleanString (unsigned char *String);
+
+#define Asprintf(a, b, c...) void( asprintf(a, b, c) < 0 ? esyslog("memory allocation error - %s", b) : void() )
+
}
#endif /* UTIL_H_ */