diff options
-rw-r--r-- | dish.c | 248 | ||||
-rw-r--r-- | dish.h | 56 | ||||
-rw-r--r-- | eepg.c | 96 |
3 files changed, 247 insertions, 153 deletions
@@ -20,82 +20,92 @@ namespace SI { // returns the value of a sequence of bits in the byte array - static unsigned int getBits(int bitIndex, int bitCount, const unsigned char *byteptr, int length) - { - union { - unsigned char b[4]; - unsigned long val; - } chunk; + static unsigned int getBits(int bitIndex, int bitCount, const unsigned char *byteptr, + int length) { + union + { + unsigned char b[4]; + unsigned long val; + } chunk; - int offset = bitIndex >> 3; - int bitnum = bitIndex - (offset << 3); - int rightend = 32 - bitnum - bitCount; + int offset = bitIndex >> 3; + int bitnum = bitIndex - (offset << 3); + int rightend = 32 - bitnum - bitCount; - chunk.b[3] = byteptr[offset]; - chunk.b[2] = (offset+1 < length) ? byteptr[offset+1] : 0; - chunk.b[1] = (offset+2 < length) ? byteptr[offset+2] : 0; - chunk.b[0] = 0; // Never need to look this far ahead. + chunk.b[3] = byteptr[offset]; + chunk.b[2] = (offset + 1 < length) ? byteptr[offset + 1] : 0; + chunk.b[1] = (offset + 2 < length) ? byteptr[offset + 2] : 0; + chunk.b[0] = 0; // Never need to look this far ahead. - return (unsigned int)(((chunk.val & (0xFFFFFFFF >> bitnum)) >> rightend)); + return (unsigned int) ((((((chunk.val & (0xFFFFFFFF >> bitnum)) >> rightend))))); } - DishDescriptor::DishDescriptor(UnimplementedDescriptor *unimplementedDesc) + DishDescriptor::DishDescriptor() { - text = NULL; + name = NULL; shortText = NULL; + description = NULL; decompressed = NULL; - this->unimplementedDesc = unimplementedDesc; + DishTheme = 0; + DishCategory = 0; + mpaaRating = 0; + starRating = 0; } DishDescriptor::~DishDescriptor() { delete [] decompressed; decompressed = NULL; - delete unimplementedDesc; + delete name; + name = NULL; + delete shortText; + shortText = NULL; + delete description; + description = NULL; } - const char *DishDescriptor::getTheme(int contentNibleLvl2) + const char *DishDescriptor::getTheme() { - const char* theme; - using namespace DISH_THEMES; + const char *theme; + using namespace DISH_THEMES; - switch (contentNibleLvl2) { - case Movie: - theme = "Movie"; - break; - case Sports: - theme = "Sports"; - break; - case News_Business: - theme = "News/Business"; - break; - case Family_Children: - theme = "Family/Children"; - break; - case Education: - theme = "Education"; - break; - case Series_Special: - theme = "Series/Special"; - break; - case Music_Art: - theme = "Music/Art"; - break; - case Religious: - theme = "Religious"; - break; - default: - theme = ""; - break; - } - return theme; + switch (DishTheme){ + case Movie: + theme = "Movie"; + break; + case Sports: + theme = "Sports"; + break; + case News_Business: + theme = "News/Business"; + break; + case Family_Children: + theme = "Family/Children"; + break; + case Education: + theme = "Education"; + break; + case Series_Special: + theme = "Series/Special"; + break; + case Music_Art: + theme = "Music/Art"; + break; + case Religious: + theme = "Religious"; + break; + default: + theme = ""; + break; + } + return theme; } - const char *DishDescriptor::getCategory(int userNible) + const char *DishDescriptor::getCategory() { - using namespace DISH_CATEGORIES; + using namespace DISH_CATEGORIES; - switch (userNible) { + switch (DishCategory) { case Action: return "Action"; case ActionSports: return "Action Sports"; case Adults_only: return "Adults only"; @@ -253,13 +263,108 @@ namespace SI case Yoga: return "Yoga"; default: return ""; } + } + void DishDescriptor::setExtendedtData(unsigned char Tid, CharArray data) + { + Decompress(Tid, data); + if (decompressed) { + char *split = strchr((char*)((decompressed)), 0x0D); // Look for carriage return + //LogD(2, prep("dLength:%d, length:%d, count:%d, decompressed: %s"), dLength, length, count, decompressed); + if(split){ + *split = 0; + shortText = new string((char*)decompressed); + description = new string((split[1] == 0x20) ? split + 2 : split + 1); + }else{ + description = new string((char*)decompressed); + } + delete[] decompressed; + decompressed = NULL; + } else { + shortText = new string(); + description = new string(); + } } - void DishDescriptor::Decompress(unsigned char Tid) + const char *DishDescriptor::getShortText(void) { - const unsigned char *str = unimplementedDesc->getData().getData(); - const unsigned char *cmp = NULL; // Compressed data + string tmp = ""; + if (shortText != NULL) tmp += *shortText; + if(DishTheme > 0){ + if(tmp != "") tmp += " - "; + + tmp += getTheme(); + } + if(DishCategory > 0){ + if(tmp != "") tmp += " - "; + + tmp += getCategory(); + } + return tmp.c_str(); + } + + const char *DishDescriptor::getDescription(void) { + string tmp = ""; + if (description != NULL) tmp += *description; + char* rating = getRating(); + if (rating && rating != "") { + if(tmp != "") tmp += "|"; + tmp += rating; + } + if (starRating > 0) { + if(tmp != "") tmp += "|"; + tmp += getStarRating(); + } + return tmp.c_str(); + } + + void DishDescriptor::setContent(ContentDescriptor::Nibble Nibble) + { + DishTheme = Nibble.getContentNibbleLevel2() & 0xF; + DishCategory = ((Nibble.getUserNibble1() & 0xF) << 4) | (Nibble.getUserNibble2() & 0xF); + } + + void DishDescriptor::setRating(uint16_t rating) + { + uint16_t newRating = (rating >> 10) & 0x07; + if (newRating == 0) newRating = 5; + if (newRating == 6) newRating = 0; + mpaaRating = (newRating << 10) | (rating & 0x3FF); + starRating = (rating >> 13) & 0x07; + } + + const char* DishDescriptor::getRating(){ + static const char *const ratings[8] = { "", "G", "PG", "PG-13", "R", "NR/AO", "", "NC-17" }; + char buffer[19]; + buffer[0] = 0; + strcpy(buffer, ratings[(mpaaRating >> 10) & 0x07]); + if (mpaaRating & 0x3A7F) { + strcat(buffer, " ["); + if (mpaaRating & 0x0230) + strcat(buffer, "V,"); + if (mpaaRating & 0x000A) + strcat(buffer, "L,"); + if (mpaaRating & 0x0044) + strcat(buffer, "N,"); + if (mpaaRating & 0x0101) + strcat(buffer, "SC,"); + if (char *s = strrchr(buffer, ',')) + s[0] = ']'; + } + + return isempty(buffer) ? NULL : buffer; + } + + const char* DishDescriptor::getStarRating(){ + static const char *const critiques[8] = { "", "*", "*+", "**", "**+", "***", "***+", "****" }; + return critiques[starRating & 0x07]; + } + + + void DishDescriptor::Decompress(unsigned char Tid, CharArray data) + { + const unsigned char *str = data.getData(); + const unsigned char *cmp = NULL; int length = 0; // Length of compressed data unsigned int dLength = 0; // Length of decompressed data if((str[3] & 0xFC) == 0x80){ @@ -278,15 +383,14 @@ namespace SI HuffmanTable *table; unsigned int tableSize, numBits; if (Tid > 0x80) { - table = Table255; - tableSize = SIZE_TABLE_255; - numBits = 13; - } - else { - table = Table128; - tableSize = SIZE_TABLE_128; - numBits = 11; - } + table = Table255; + tableSize = SIZE_TABLE_255; + numBits = 13; + } else { + table = Table128; + tableSize = SIZE_TABLE_128; + numBits = 11; + } unsigned int bLength = length << 3; // number of bits unsigned int currentBit = 0, count = 0; while(currentBit < bLength - 1 && count < dLength){ @@ -305,18 +409,8 @@ namespace SI } decompressed[count] = 0; - char *split = strchr((char*)(decompressed), 0x0D); // Look for carriage return - //LogD(2, prep("dLength:%d, length:%d, count:%d, decompressed: %s"), dLength, length, count, decompressed); - if(split){ - *split = 0; - shortText = (char*)(decompressed); - text = (split[1] == 0x20) ? split + 2 : split + 1; - }else{ - text = (char*)(decompressed); - } } - struct DishDescriptor::HuffmanTable DishDescriptor::Table128[SIZE_TABLE_128] = { { 0x0000, 0x20, 0x03 }, { 0x0100, 0x65, 0x04 }, { 0x0180, 0x74, 0x04 }, { 0x0200, 0x61, 0x04 }, { 0x0280, 0x6F, 0x04 }, { 0x0300, 0x73, 0x04 }, @@ -451,4 +545,4 @@ struct DishDescriptor::HuffmanTable DishDescriptor::Table255[SIZE_TABLE_255] = { { 0x1FFD, 0x02, 0x0D }, { 0x1FFE, 0x01, 0x0D }, { 0x1FFF, 0x00, 0x0D } }; -} //end of namespace +} //end of namespace @@ -239,33 +239,47 @@ namespace SI #define SIZE_TABLE_128 128 #define SIZE_TABLE_255 255 -class UnimplementedDescriptor; +using namespace std; class DishDescriptor { public: - DishDescriptor(UnimplementedDescriptor*); - virtual ~DishDescriptor(); - const char* getText(void) const { return text; } + DishDescriptor(); + virtual ~DishDescriptor(); + const char* getName(void) const { return name?name->c_str():""; } + const char* getShortText(void); + const char *getDescription(void); + // const char* getShortText(void) const { return shortText?shortText->c_str():""; } + // const char* getDescription(void) const { return description?description->c_str():""; } + const char *getTheme(); + const char *getCategory(); + const char *getRating(); + const char *getStarRating(); + void setShortData(unsigned char Tid, CharArray data); + void setExtendedtData(unsigned char Tid, CharArray data); + void setRating(uint16_t value); + void setContent(ContentDescriptor::Nibble Nibble); - const char* getShortText(void) const { return shortText; } - const char* getTheme(int contentNibleLvl2); - const char* getCategory(int userNible); - // Decompress the byte arrary and stores the result to a text string - void Decompress(unsigned char Tid); -protected: - const char* text; // name or description of the event - const char* shortText; // usually the episode name - unsigned char* decompressed; - UnimplementedDescriptor* unimplementedDesc; - struct HuffmanTable { - unsigned int startingAddress; - unsigned char character; - unsigned char numberOfBits; - }; - static HuffmanTable Table128[SIZE_TABLE_128]; - static HuffmanTable Table255[SIZE_TABLE_255]; +protected: + // Decompress the byte array and stores the result to a text string + void Decompress(unsigned char Tid, CharArray data); + string *name; // name of the event + string *shortText; // usually the episode name + string *description; // description of the event + unsigned char *decompressed; + uchar DishTheme; + uchar DishCategory; + uint16_t mpaaRating; + uint16_t starRating; + struct HuffmanTable + { + unsigned int startingAddress; + unsigned char character; + unsigned char numberOfBits; + }; + static HuffmanTable Table128[SIZE_TABLE_128]; + static HuffmanTable Table255[SIZE_TABLE_255]; }; } /* namespace SI */ @@ -10,6 +10,7 @@ * -Freesat patch written by dom /at/ suborbital.org.uk * * + * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. @@ -344,6 +345,7 @@ public: cFilterEEPG (void); virtual void SetStatus (bool On); void Trigger (void); + static const int EIT_PID = 0x12; }; cFilterEEPG::cFilterEEPG (void) @@ -2823,15 +2825,13 @@ extern bool SystemCharacterTableIsSingleByte;*/ class cEIT2:public SI::EIT { public: - cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool OnlyRunningStatus = false); + cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool isEITPid = false, bool OnlyRunningStatus = false); }; -cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Data, bool OnlyRunningStatus) +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) Tid--; - if (!CheckCRCAndParse ()) { LogD(2, prep("!CheckCRCAndParse ()")); return; @@ -2846,7 +2846,7 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat return; // only collect data for known channels } - LogD(4, prep("channelID: %s format:%d"), *channel->GetChannelID().ToString(), Format); + //LogD(4, prep("channelID: %s format:%d"), *channel->GetChannelID().ToString(), Format); #ifdef USE_NOEPG // only use epg from channels not blocked by noEPG-patch @@ -2874,6 +2874,11 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat if (!SegmentStart) SegmentStart = SiEitEvent.getStartTime (); SegmentEnd = SiEitEvent.getStartTime () + SiEitEvent.getDuration (); + int versionNumber = getVersionNumber(); + // increase version number for DISH_BEV EIT so it does not get overwriten by VDR. + // TODO check the same for other providers. + if (Format == DISH_BEV && isEITPid) versionNumber++; + cEvent *newEvent = NULL; cEvent *rEvent = NULL; cEvent *pEvent = (cEvent *) pSchedule->GetEvent (SiEitEvent.getEventId (), SiEitEvent.getStartTime ()); @@ -2962,7 +2967,7 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat continue; } #else - if (pEvent->Version () == getVersionNumber ()) + if (pEvent->Version () == versionNumber) continue; #endif /* DDEPGENTRY */ HasExternalData = ExternalData = true; @@ -2977,7 +2982,7 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat // 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() == getVersionNumber()) + else if (Tid == pEvent->TableID() && pEvent->Version() == versionNumber) continue; } if (!ExternalData) { @@ -2998,7 +3003,7 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat } if (OnlyRunningStatus) continue; // do this before setting the version, so that the full update can be done later - pEvent->SetVersion (getVersionNumber()); + pEvent->SetVersion (versionNumber); int LanguagePreferenceShort = -1; int LanguagePreferenceExt = -1; @@ -3006,9 +3011,9 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat SI::Descriptor * d; SI::ExtendedEventDescriptors * ExtendedEventDescriptors = NULL; SI::ShortEventDescriptor * ShortEventDescriptor = NULL; - SI::DishDescriptor *DishExtendedEventDescriptor = NULL; - SI::DishDescriptor *DishShortEventDescriptor = NULL; - uchar DishTheme = 0, DishCategory = 0; + //SI::DishDescriptor *DishExtendedEventDescriptor = NULL; + SI::DishDescriptor *DishEventDescriptor = NULL; + //uchar DishTheme = 0, DishCategory = 0; cLinkChannels *LinkChannels = NULL; @@ -3060,13 +3065,11 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat Contents[NumContents] = ((Nibble.getContentNibbleLevel1() & 0xF) << 4) | (Nibble.getContentNibbleLevel2() & 0xF); NumContents++; } - if (Format == DISH_BEV && NumContents == 1) { - DishTheme = Nibble.getContentNibbleLevel2() & 0xF; - DishCategory = ((Nibble.getUserNibble1() & 0xF) << 4) | (Nibble.getUserNibble2() & 0xF); - //LogD(2, prep("EEPGDEBUG:DishTheme:%x-DishCategory:%x)"), DishTheme, DishCategory); + if (DishEventDescriptor && NumContents == 1) { + DishEventDescriptor->setContent(Nibble); } - //LogD(2, prep("EEPGDEBUG:Nibble:%x-%x-%x-%x)"), Nibble.getContentNibbleLevel1(),Nibble.getContentNibbleLevel2() - // , Nibble.getUserNibble1(), Nibble.getUserNibble2()); +// LogD(2, prep("EEPGDEBUG:Nibble:%x-%x-%x-%x)"), Nibble.getContentNibbleLevel1(),Nibble.getContentNibbleLevel2() +// , Nibble.getUserNibble1(), Nibble.getUserNibble2()); } pEvent->SetContents(Contents); @@ -3190,33 +3193,27 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat } break; case SI::DishExtendedEventDescriptorTag: { - SI::DishDescriptor *deed = new SI::DishDescriptor((SI::UnimplementedDescriptor *)d); - deed->Decompress(Tid); - if (!DishExtendedEventDescriptor) { - DishExtendedEventDescriptor = deed; - d = NULL; // so that it is not deleted + SI::UnimplementedDescriptor *deed = (SI::UnimplementedDescriptor *)d; + if (!DishEventDescriptor) { + DishEventDescriptor = new SI::DishDescriptor(); } + DishEventDescriptor->setExtendedtData(Tid, deed->getData()); HasExternalData = true; } break; case SI::DishShortEventDescriptorTag: { - SI::DishDescriptor *dsed = new SI::DishDescriptor((SI::UnimplementedDescriptor *)d); - dsed->Decompress(Tid); - if (!DishShortEventDescriptor) { - DishShortEventDescriptor = dsed; - d = NULL; // so that it is not deleted + SI::UnimplementedDescriptor *dsed = (SI::UnimplementedDescriptor *)d; + if (!DishEventDescriptor) { + DishEventDescriptor = new SI::DishDescriptor(); } + DishEventDescriptor->setShortData(Tid, dsed->getData()); HasExternalData = true; } break; case SI::DishRatingDescriptorTag: { - if (d->getLength() == 4) { + if (d->getLength() == 4 && DishEventDescriptor) { uint16_t rating = d->getData().TwoBytes(2); - uint16_t newRating = (rating >> 10) & 0x07; - if (newRating == 0) newRating = 5; - if (newRating == 6) newRating = 0; - pEvent->SetParentalRating((newRating << 10) | (rating & 0x3FF)); -// pEvent->SetStarRating((rating >> 13) & 0x07); + DishEventDescriptor->setRating(rating); } } break; @@ -3250,30 +3247,19 @@ cEIT2::cEIT2 (cSchedules * Schedules, int Source, u_char Tid, const u_char * Dat } else if (!HasExternalData) pEvent->SetDescription (NULL); - if (DishShortEventDescriptor) { - pEvent->SetTitle(DishShortEventDescriptor->getText()); - //LogD(2, prep("channelID: %s DishTitle: %s"), *channel->GetChannelID().ToString(), DishShortEventDescriptor->getText()); - } - if (DishExtendedEventDescriptor) { - pEvent->SetDescription(DishExtendedEventDescriptor->getText()); - char *tmp; - if (DishTheme >= 0) { - Asprintf (&tmp, "%s - %s ~ %s", DishExtendedEventDescriptor->getShortText() - , DishExtendedEventDescriptor->getTheme(DishTheme) - , DishExtendedEventDescriptor->getCategory(DishCategory)); - pEvent->SetShortText(tmp); - //LogD(2, prep("EEPGDEBUG:DishTheme:%x-DishCategory:%x)"), DishTheme, DishCategory); - free(tmp); - } else - pEvent->SetShortText(DishExtendedEventDescriptor->getShortText()); + if (DishEventDescriptor) { + pEvent->SetTitle(DishEventDescriptor->getName()); + pEvent->SetDescription(DishEventDescriptor->getDescription()); + pEvent->SetShortText(DishEventDescriptor->getShortText()); + //LogD(2, prep("channelID: %s DishTitle: %s"), *channel->GetChannelID().ToString(), DishEventDescriptor->getName()); //LogD(2, prep("DishDescription: %s"), DishExtendedEventDescriptor->getText()); //LogD(2, prep("DishShortText: %s"), DishExtendedEventDescriptor->getShortText()); } + } delete ExtendedEventDescriptors; delete ShortEventDescriptor; - delete DishExtendedEventDescriptor; - delete DishShortEventDescriptor; + delete DishEventDescriptor; pEvent->SetComponents (Components); @@ -3471,7 +3457,7 @@ void cFilterEEPG::ProcessNextFormat (bool FirstTime = false) AddFilter (pid, 0xb0); //perhaps TID is equal to first data byte? break; case DISH_BEV: - AddFilter (0x12, 0, 0); // event info, actual(0x4e)/other(0x4f) TS, present/following + AddFilter (EIT_PID, 0, 0); // event info, actual(0x4e)/other(0x4f) TS, present/following AddFilter (0x0300, 0, 0); // Dish Network EEPG event info, actual(0x4e)/other(0x4f) TS, present/following AddFilter (0x0441, 0, 0); // Dish Network EEPG event info, actual(0x4e)/other(0x4f) TS, present/following // AddFilter (0x0441, 0x50, 0xf0); // Bell ExpressVU EEPG @@ -3490,7 +3476,7 @@ void cFilterEEPG::ProccessContinuous(u_short Pid, u_char Tid, int Length, const cSchedules *Schedules = (cSchedules*)(cSchedules::Schedules(SchedulesLock)); //Look for other satelite positions only if Dish/Bell ExpressVU for the moment hardcoded pid check if(Schedules) - SI::cEIT2 EIT(Schedules, Source(), Tid, Data); + SI::cEIT2 EIT(Schedules, Source(), Tid, Data, Pid == EIT_PID); else//cEIT EIT (Schedules, Source (), Tid, Data); { @@ -3501,7 +3487,7 @@ void cFilterEEPG::ProccessContinuous(u_short Pid, u_char Tid, int Length, const cSchedulesLock SchedulesLock; cSchedules *Schedules = (cSchedules*)(cSchedules::Schedules(SchedulesLock)); if(Schedules) - SI::cEIT2 EIT(Schedules, Source(), Tid, Data, true); + SI::cEIT2 EIT(Schedules, Source(), Tid, Data, Pid == EIT_PID, true); //cEIT EIT (Schedules, Source (), Tid, Data, true); } @@ -3665,7 +3651,7 @@ void cFilterEEPG::Process (u_short Pid, u_char Tid, const u_char * Data, int Len } //if pmtpid else if (Source ()) { - if ( Pid == 0x12 || Pid == 0x0300 || Pid == 0x0441 ) { + if ( Pid == EIT_PID || Pid == 0x0300 || Pid == 0x0441 ) { if (Tid >= 0x4E) ProccessContinuous(Pid, Tid, Length, Data); return; |