X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=lib%2Fdvb%2Fepgcache.cpp;h=0d2545fc7ef544397c474a990c05695e82ea6e50;hp=4d32474663941ec9c78322205f551a4ac8da2f36;hb=HEAD;hpb=e1cd84473da2da0d23f4cea1d4143f17a8fb5a2c diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp index 4d32474..0d2545f 100644 --- a/lib/dvb/epgcache.cpp +++ b/lib/dvb/epgcache.cpp @@ -1,26 +1,78 @@ #include #include +#include -#undef EPG_DEBUG +#undef EPG_DEBUG #ifdef EPG_DEBUG #include #endif +#include +#include #include #include // for usleep #include // for statfs -// #include #include +#include #include #include #include #include #include -int eventData::CacheSize=0; -descriptorMap eventData::descriptors; -__u8 eventData::data[4108]; +/* Interval between "garbage collect" cycles */ +#define CLEAN_INTERVAL 60000 // 1 min +/* Restart EPG data capture */ +#define UPDATE_INTERVAL 3600000 // 60 min +/* Time to wait after tuning in before EPG data capturing starts */ +#define ZAP_DELAY 2000 // 2 sec + +struct DescriptorPair +{ + int reference_count; + uint8_t* data; + + DescriptorPair() {} + DescriptorPair(int c, uint8_t* d): reference_count(c), data(d) {} +}; + +typedef std::tr1::unordered_map DescriptorMap; + +struct eventData +{ + uint8_t rawEITdata[10]; + uint8_t n_crc; + uint8_t type; + uint32_t *crc_list; + static DescriptorMap descriptors; + static uint8_t data[]; + static unsigned int CacheSize; + static bool isCacheCorrupt; + eventData(const eit_event_struct* e = NULL, int size = 0, int type = 0, int tsidonid = 0); + ~eventData(); + static void load(FILE *); + static void save(FILE *); + static void cacheCorrupt(const char* context); + const eit_event_struct* get() const; + int getEventID() const + { + return (rawEITdata[0] << 8) | rawEITdata[1]; + } + time_t getStartTime() const + { + return parseDVBtime(&rawEITdata[2]); + } + int getDuration() const + { + return fromBCD(rawEITdata[7])*3600+fromBCD(rawEITdata[8])*60+fromBCD(rawEITdata[9]); + } +}; + +unsigned int eventData::CacheSize = 0; +bool eventData::isCacheCorrupt = 0; +DescriptorMap eventData::descriptors; +uint8_t eventData::data[2 * 4096 + 12]; extern const uint32_t crc32_table[256]; const eServiceReference &handleGroup(const eServiceReference &ref) @@ -33,7 +85,7 @@ const eServiceReference &handleGroup(const eServiceReference &ref) ePtr db; if (!res->getChannelList(db)) { - eBouquet *bouquet=0; + eBouquet *bouquet = NULL; if (!db->getBouquet(ref, bouquet)) { std::list::iterator it(bouquet->m_services.begin()); @@ -46,22 +98,30 @@ const eServiceReference &handleGroup(const eServiceReference &ref) return ref; } -eventData::eventData(const eit_event_struct* e, int size, int type) - :ByteSize(size&0xFF), type(type&0xFF) +static uint32_t calculate_crc_hash(const uint8_t *data, int size) +{ + uint32_t crc = 0; + for (int i = 0; i < size; ++i) + crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[i]) & 0xFF]; + return crc; +} + +eventData::eventData(const eit_event_struct* e, int size, int _type, int tsidonid) + :n_crc(0), type(_type & 0xFF), crc_list(NULL) { if (!e) - return; + return; /* Used when loading from file */ - __u32 descr[65]; - __u32 *pdescr=descr; + uint32_t descr[65]; + uint32_t *pdescr=descr; - __u8 *data = (__u8*)e; + uint8_t *data = (uint8_t*)e; int ptr=12; size -= 12; while(size > 1) { - __u8 *descr = data+ptr; + uint8_t *descr = data + ptr; int descr_len = descr[1]; descr_len += 2; if (size >= descr_len) @@ -69,69 +129,158 @@ eventData::eventData(const eit_event_struct* e, int size, int type) switch (descr[0]) { case EXTENDED_EVENT_DESCRIPTOR: - case SHORT_EVENT_DESCRIPTOR: case LINKAGE_DESCRIPTOR: case COMPONENT_DESCRIPTOR: + case CONTENT_DESCRIPTOR: + case PARENTAL_RATING_DESCRIPTOR: + case PDC_DESCRIPTOR: { - __u32 crc = 0; - int cnt=0; - while(cnt++ < descr_len) - crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[ptr++]) & 0xFF]; - - descriptorMap::iterator it = - descriptors.find(crc); + uint32_t crc = calculate_crc_hash(descr, descr_len); + DescriptorMap::iterator it = descriptors.find(crc); if ( it == descriptors.end() ) { CacheSize+=descr_len; - __u8 *d = new __u8[descr_len]; + uint8_t *d = new uint8_t[descr_len]; memcpy(d, descr, descr_len); - descriptors[crc] = descriptorPair(1, d); + descriptors[crc] = DescriptorPair(1, d); } else - ++it->second.first; - *pdescr++=crc; + ++it->second.reference_count; + *pdescr++ = crc; + break; + } + case SHORT_EVENT_DESCRIPTOR: + { + //parse the data out from the short event descriptor + //get the country code, which will be used for converting to UTF8 + std::string cc( (const char*)&descr[2], 3); + std::transform(cc.begin(), cc.end(), cc.begin(), tolower); + int table = encodingHandler.getCountryCodeDefaultMapping(cc); + + int eventNameLen = descr[5]; + int eventTextLen = descr[6 + eventNameLen]; + + //convert our strings to UTF8 + std::string eventNameUTF8 = convertDVBUTF8((const unsigned char*)&descr[6], eventNameLen, table, tsidonid); + std::string textUTF8 = convertDVBUTF8((const unsigned char*)&descr[7 + eventNameLen], eventTextLen, table, tsidonid); + unsigned int eventNameUTF8len = eventNameUTF8.length(); + unsigned int textUTF8len = textUTF8.length(); + + //Rebuild the short event descriptor with UTF-8 strings + + //Save the title first + if( eventNameUTF8len > 0 ) //only store the data if there is something to store + { + /*this will actually cause us to save some memory + previously some descriptors didnt match because there text was different and titles the same. + Now that we store them seperatly we can save some space on title data some rough calculation show anywhere from 20 - 40% savings + */ + eventNameUTF8len = truncateUTF8(eventNameUTF8, 255 - 6); + int title_len = 6 + eventNameUTF8len; + uint8_t *title_data = new uint8_t[title_len + 2]; + title_data[0] = SHORT_EVENT_DESCRIPTOR; + title_data[1] = title_len; + title_data[2] = descr[2]; + title_data[3] = descr[3]; + title_data[4] = descr[4]; + title_data[5] = eventNameUTF8len + 1; + title_data[6] = 0x15; //identify event name as UTF-8 + memcpy(&title_data[7], eventNameUTF8.data(), eventNameUTF8len); + title_data[7 + eventNameUTF8len] = 0; + + //Calculate the CRC, based on our new data + title_len += 2; //add 2 the length to include the 2 bytes in the header + uint32_t title_crc = calculate_crc_hash(title_data, title_len); + + DescriptorMap::iterator it = descriptors.find(title_crc); + if ( it == descriptors.end() ) + { + CacheSize += title_len; + descriptors[title_crc] = DescriptorPair(1, title_data); + } + else + { + ++it->second.reference_count; + delete [] title_data; + } + *pdescr++ = title_crc; + } + + //save the text + if( textUTF8len > 0 ) //only store the data if there is something to store + { + textUTF8len = truncateUTF8(textUTF8, 255 - 6); + int text_len = 6 + textUTF8len; + uint8_t *text_data = new uint8_t[text_len + 2]; + text_data[0] = SHORT_EVENT_DESCRIPTOR; + text_data[1] = text_len; + text_data[2] = descr[2]; + text_data[3] = descr[3]; + text_data[4] = descr[4]; + text_data[5] = 0; + text_data[6] = textUTF8len + 1; //identify text as UTF-8 + text_data[7] = 0x15; //identify text as UTF-8 + memcpy(&text_data[8], textUTF8.data(), textUTF8len); + + text_len += 2; //add 2 the length to include the 2 bytes in the header + uint32_t text_crc = calculate_crc_hash(text_data, text_len); + + DescriptorMap::iterator it = descriptors.find(text_crc); + if ( it == descriptors.end() ) + { + CacheSize += text_len; + descriptors[text_crc] = DescriptorPair(1, text_data); + } + else + { + ++it->second.reference_count; + delete [] text_data; + } + *pdescr++ = text_crc; + } break; } default: // do not cache all other descriptors - ptr += descr_len; break; } + ptr += descr_len; size -= descr_len; } else break; } + memcpy(rawEITdata, (uint8_t*)e, 10); ASSERT(pdescr <= &descr[65]); - ByteSize = 10+((pdescr-descr)*4); - EITdata = new __u8[ByteSize]; - CacheSize+=ByteSize; - memcpy(EITdata, (__u8*) e, 10); - memcpy(EITdata+10, descr, ByteSize-10); + n_crc = pdescr - descr; + if (n_crc) + { + crc_list = new uint32_t[n_crc]; + memcpy(crc_list, descr, n_crc * sizeof(uint32_t)); + } + CacheSize += sizeof(*this) + n_crc * sizeof(uint32_t); } const eit_event_struct* eventData::get() const { - int pos = 12; - int tmp = ByteSize-10; - memcpy(data, EITdata, 10); - int descriptors_length=0; - __u32 *p = (__u32*)(EITdata+10); - while(tmp>3) + unsigned int pos = 12; + memcpy(data, rawEITdata, 10); + unsigned int descriptors_length = 0; + for (uint8_t i = 0; i < n_crc; ++i) { - descriptorMap::iterator it = - descriptors.find(*p++); - if ( it != descriptors.end() ) + DescriptorMap::iterator it = descriptors.find(crc_list[i]); + if (it != descriptors.end()) { - int b = it->second.second[1]+2; - memcpy(data+pos, it->second.second, b ); - pos += b; - descriptors_length += b; + unsigned int b = it->second.data[1] + 2; + if (pos + b < sizeof(data)) + { + memcpy(data + pos, it->second.data, b); + pos += b; + descriptors_length += b; + } } else - eFatal("LINE %d descriptor not found in descriptor cache %08x!!!!!!", __LINE__, *(p-1)); - tmp-=4; + cacheCorrupt("eventData::get"); } - ASSERT(pos <= 4108); data[10] = (descriptors_length >> 8) & 0x0F; data[11] = descriptors_length & 0xFF; return (eit_event_struct*)data; @@ -139,83 +288,95 @@ const eit_event_struct* eventData::get() const eventData::~eventData() { - if ( ByteSize ) + for ( uint8_t i = 0; i < n_crc; ++i ) { - CacheSize -= ByteSize; - __u32 *d = (__u32*)(EITdata+10); - ByteSize -= 10; - while(ByteSize>3) + DescriptorMap::iterator it = descriptors.find(crc_list[i]); + if ( it != descriptors.end() ) { - descriptorMap::iterator it = - descriptors.find(*d++); - if ( it != descriptors.end() ) + DescriptorPair &p = it->second; + if (!--p.reference_count) // no more used descriptor { - descriptorPair &p = it->second; - if (!--p.first) // no more used descriptor - { - CacheSize -= it->second.second[1]; - delete [] it->second.second; // free descriptor memory - descriptors.erase(it); // remove entry from descriptor map - } + CacheSize -= it->second.data[1]; + delete [] it->second.data; // free descriptor memory + descriptors.erase(it); // remove entry from descriptor map } - else - eFatal("LINE %d descriptor not found in descriptor cache %08x!!!!!!", __LINE__, *(d-1)); - ByteSize -= 4; } - delete [] EITdata; + else + { + cacheCorrupt("eventData::~eventData"); + } } + delete [] crc_list; + CacheSize -= sizeof(*this) + n_crc * sizeof(uint32_t); } void eventData::load(FILE *f) { - int size=0; + int size = 0; int id=0; - __u8 header[2]; - descriptorPair p; + DescriptorPair p; + uint8_t header[2]; fread(&size, sizeof(int), 1, f); + descriptors.rehash(size); while(size) { - fread(&id, sizeof(__u32), 1, f); - fread(&p.first, sizeof(int), 1, f); + fread(&id, sizeof(uint32_t), 1, f); + fread(&p.reference_count, sizeof(int), 1, f); fread(header, 2, 1, f); int bytes = header[1]+2; - p.second = new __u8[bytes]; - p.second[0] = header[0]; - p.second[1] = header[1]; - fread(p.second+2, bytes-2, 1, f); - descriptors[id]=p; + p.data = new uint8_t[bytes]; + p.data[0] = header[0]; + p.data[1] = header[1]; + fread(p.data+2, bytes-2, 1, f); + descriptors[id] = p; --size; - CacheSize+=bytes; } } void eventData::save(FILE *f) { + if (isCacheCorrupt) + return; int size=descriptors.size(); - descriptorMap::iterator it(descriptors.begin()); + DescriptorMap::iterator it(descriptors.begin()); fwrite(&size, sizeof(int), 1, f); while(size) { - fwrite(&it->first, sizeof(__u32), 1, f); - fwrite(&it->second.first, sizeof(int), 1, f); - fwrite(it->second.second, it->second.second[1]+2, 1, f); + fwrite(&it->first, sizeof(uint32_t), 1, f); + fwrite(&it->second.reference_count, sizeof(int), 1, f); + fwrite(it->second.data, it->second.data[1]+2, 1, f); ++it; --size; } } +void eventData::cacheCorrupt(const char* context) +{ + + eDebug("[eventData] EPG Cache is corrupt (%s), you should restart Enigma!", context); + if (!isCacheCorrupt) + { + isCacheCorrupt = true; + if (!eEPGCache::instance->m_filename.empty()) + unlink(eEPGCache::instance->m_filename.c_str()); // Remove corrupt EPG data + } +} + eEPGCache* eEPGCache::instance; -pthread_mutex_t eEPGCache::cache_lock= +static pthread_mutex_t cache_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; -pthread_mutex_t eEPGCache::channel_map_lock= +static pthread_mutex_t channel_map_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; DEFINE_REF(eEPGCache) eEPGCache::eEPGCache() - :messages(this,1), cleanTimer(eTimer::create(this)), m_running(0)//, paused(0) + :messages(this,1), cleanTimer(eTimer::create(this)), m_running(false) { - eDebug("[EPGC] Initialized EPGCache (wait for setCacheFile call now)"); + eDebug("[eEPGCache] Initialized EPGCache (wait for setCacheFile call now)"); + + enabledSources = 0; + historySeconds = 0; CONNECT(messages.recv_msg, eEPGCache::gotMessage); CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated); @@ -229,16 +390,15 @@ eEPGCache::eEPGCache() res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn); instance=this; - memset(m_filename, 0, sizeof(m_filename)); } void eEPGCache::setCacheFile(const char *path) { - bool inited = !!strlen(m_filename); - strncpy(m_filename, path, 1024); + bool inited = !m_filename.empty(); + m_filename = path; if (!inited) { - eDebug("[EPGC] setCacheFile read/write epg data from/to '%s'", m_filename); + eDebug("[eEPGCache] setCacheFile read/write epg data from/to '%s'", m_filename.c_str()); if (eDVBLocalTimeHandler::getInstance()->ready()) timeUpdated(); } @@ -246,15 +406,15 @@ void eEPGCache::setCacheFile(const char *path) void eEPGCache::timeUpdated() { - if (strlen(m_filename)) + if (!m_filename.empty()) { - if (!sync()) + if (!m_running) { - eDebug("[EPGC] time updated.. start EPG Mainloop"); + eDebug("[eEPGCache] time updated.. start EPG Mainloop"); run(); + m_running = true; singleLock s(channel_map_lock); - channelMapIterator it = m_knownChannels.begin(); - for (; it != m_knownChannels.end(); ++it) + for (ChannelMap::const_iterator it = m_knownChannels.begin(); it != m_knownChannels.end(); ++it) { if (it->second->state == -1) { it->second->state=0; @@ -265,7 +425,7 @@ void eEPGCache::timeUpdated() messages.send(Message(Message::timeChanged)); } else - eDebug("[EPGC] time updated.. but cache file not set yet.. dont start epg!!"); + eDebug("[eEPGCache] time updated.. but cache file not set yet.. dont start epg!!"); } void eEPGCache::DVBChannelAdded(eDVBChannel *chan) @@ -292,8 +452,7 @@ void eEPGCache::DVBChannelAdded(eDVBChannel *chan) void eEPGCache::DVBChannelRunning(iDVBChannel *chan) { - channelMapIterator it = - m_knownChannels.find(chan); + ChannelMap::const_iterator it = m_knownChannels.find(chan); if ( it == m_knownChannels.end() ) eDebug("[eEPGCache] will start non existing channel %p !!!", chan); else @@ -333,6 +492,36 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan) return; } +#ifdef ENABLE_VIRGIN + res = demux->createSectionReader( this, data.m_VirginNowNextReader ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize virgin nownext reader!!"); + return; + } + + res = demux->createSectionReader( this, data.m_VirginScheduleReader ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize virgin schedule reader!!"); + return; + } +#endif +#ifdef ENABLE_NETMED + res = demux->createSectionReader( this, data.m_NetmedScheduleReader ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize netmed schedule reader!!"); + return; + } + + res = demux->createSectionReader( this, data.m_NetmedScheduleOtherReader ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize netmed schedule other reader!!"); + return; + } +#endif res = demux->createSectionReader( this, data.m_ViasatReader ); if ( res ) { @@ -361,8 +550,23 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan) return; } #endif - if (m_running) { - data.state=0; +#if ENABLE_FREESAT + res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize FreeSat reader!!"); + return; + } + res = demux->createSectionReader( this, data.m_FreeSatScheduleOtherReader2 ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize FreeSat reader 2!!"); + return; + } +#endif + if (m_running) + { + data.state = 0; messages.send(Message(Message::startChannel, chan)); // -> gotMessage -> changedService } @@ -375,8 +579,7 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan) void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan) { - channelMapIterator it = - m_knownChannels.find(chan); + ChannelMap::iterator it = m_knownChannels.find(chan); if ( it != m_knownChannels.end() ) { int state=0; @@ -396,14 +599,16 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan) eDebug("[eEPGCache] remove channel %p", chan); if (it->second->state >= 0) messages.send(Message(Message::leaveChannel, chan)); - pthread_mutex_lock(&it->second->channel_active); - singleLock s(channel_map_lock); - m_knownChannels.erase(it); - pthread_mutex_unlock(&it->second->channel_active); - delete it->second; - it->second=0; + channel_data* cd = it->second; + pthread_mutex_lock(&cd->channel_active); + { + singleLock s(channel_map_lock); + m_knownChannels.erase(it); + } + pthread_mutex_unlock(&cd->channel_active); + delete cd; // -> gotMessage -> abortEPG - break; + return; } default: // ignore all other events return; @@ -414,46 +619,46 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan) } } -bool eEPGCache::FixOverlapping(std::pair &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service) +bool eEPGCache::FixOverlapping(EventCacheItem &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service) { bool ret = false; timeMap::iterator tmp = tm_it; - while ((tmp->first+tmp->second->getDuration()-300) > TM) + while ((tmp->first + tmp->second->getDuration() - 300) > TM) { - if(tmp->first != TM + if(tmp->first != TM #ifdef ENABLE_PRIVATE_EPG - && tmp->second->type != PRIVATE + && tmp->second->type != PRIVATE #endif -#ifdef ENABLE_MHW +#ifdef ENABLE_MHW_EPG && tmp->second->type != MHW #endif ) { - __u16 event_id = tmp->second->getEventID(); - servicemap.first.erase(event_id); + uint16_t event_id = tmp->second->getEventID(); + servicemap.byEvent.erase(event_id); #ifdef EPG_DEBUG Event evt((uint8_t*)tmp->second->get()); eServiceEvent event; event.parseFrom(&evt, service.sid<<16|service.onid); - eDebug("(1)erase no more used event %04x %d\n%s %s\n%s", + eDebug("[eEPGCache] (1)erase no more used event %04x %d\n%s %s\n%s", service.sid, event_id, event.getBeginTimeString().c_str(), event.getEventName().c_str(), event.getExtendedDescription().c_str()); #endif delete tmp->second; - if (tmp == servicemap.second.begin()) + if (tmp == servicemap.byTime.begin()) { - servicemap.second.erase(tmp); + servicemap.byTime.erase(tmp); break; } else - servicemap.second.erase(tmp--); + servicemap.byTime.erase(tmp--); ret = true; } else { - if (tmp == servicemap.second.begin()) + if (tmp == servicemap.byTime.begin()) break; --tmp; } @@ -464,97 +669,107 @@ bool eEPGCache::FixOverlapping(std::pair &servicemap, time_t T { if (tmp->first != TM && tmp->second->type != PRIVATE) { - __u16 event_id = tmp->second->getEventID(); - servicemap.first.erase(event_id); -#ifdef EPG_DEBUG + uint16_t event_id = tmp->second->getEventID(); + servicemap.byEvent.erase(event_id); +#ifdef EPG_DEBUG Event evt((uint8_t*)tmp->second->get()); eServiceEvent event; event.parseFrom(&evt, service.sid<<16|service.onid); - eDebug("(2)erase no more used event %04x %d\n%s %s\n%s", + eDebug("[eEPGCache] (2)erase no more used event %04x %d\n%s %s\n%s", service.sid, event_id, event.getBeginTimeString().c_str(), event.getEventName().c_str(), event.getExtendedDescription().c_str()); #endif delete tmp->second; - servicemap.second.erase(tmp++); + servicemap.byTime.erase(tmp++); ret = true; } else ++tmp; - if (tmp == servicemap.second.end()) + if (tmp == servicemap.byTime.end()) break; } return ret; } -void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) +void eEPGCache::sectionRead(const uint8_t *data, int source, channel_data *channel) { - eit_t *eit = (eit_t*) data; + const eit_t *eit = (const eit_t*) data; - int len=HILO(eit->section_length)-1;//+3-4; - int ptr=EIT_SIZE; + int len = eit->getSectionLength()-1;//+3-4; + int ptr = EIT_SIZE; if ( ptr >= len ) return; +#if 0 + /* + * disable for now, as this hack breaks EIT parsing for + * services with a low segment_last_table_id + * + * Multichoice should be the exception, not the rule... + */ + // This fixed the EPG on the Multichoice irdeto systems // the EIT packet is non-compliant.. their EIT packet stinks if ( data[ptr-1] < 0x40 ) --ptr; +#endif + + int onid = eit->getOriginalNetworkId(); + int tsid = eit->getTransportStreamId(); // Cablecom HACK .. tsid / onid in eit data are incorrect.. so we use // it from running channel (just for current transport stream eit data) - bool use_transponder_chid = source == SCHEDULE || (source == NOWNEXT && data[0] == 0x4E); - eDVBChannelID chid = channel->channel->getChannelID(); - uniqueEPGKey service( HILO(eit->service_id), - use_transponder_chid ? chid.original_network_id.get() : HILO(eit->original_network_id), - use_transponder_chid ? chid.transport_stream_id.get() : HILO(eit->transport_stream_id)); + /* + * Make an exception for BEV (onid 0x100, 0x101), which doesn't use + * SCHEDULE_OTHER. As a result SCHEDULE will contain data for different tsid's, + * so we should not replace it with the current tsid. + */ + bool use_transponder_chid = onid != 0x101 && onid != 0x100 && (source == SCHEDULE || (source == NOWNEXT && data[0] == 0x4E)); + + if (use_transponder_chid && channel) + { + eDVBChannelID chid = channel->channel->getChannelID(); + + onid = chid.original_network_id.get(); + tsid = chid.transport_stream_id.get(); + } + + uniqueEPGKey service( eit->getServiceID(), onid, tsid); eit_event_struct* eit_event = (eit_event_struct*) (data+ptr); int eit_event_size; int duration; - time_t TM = parseDVBtime( - eit_event->start_time_1, - eit_event->start_time_2, - eit_event->start_time_3, - eit_event->start_time_4, - eit_event->start_time_5); + time_t TM = parseDVBtime((const uint8_t*)eit_event + 2); time_t now = ::time(0); - if ( TM != 3599 && TM > -1) + if ( TM != 3599 && TM > -1 && channel) channel->haveData |= source; singleLock s(cache_lock); - // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene.. + // hier wird immer eine eventMap zurck gegeben.. entweder eine vorhandene.. // oder eine durch [] erzeugte - std::pair &servicemap = eventDB[service]; - eventMap::iterator prevEventIt = servicemap.first.end(); - timeMap::iterator prevTimeIt = servicemap.second.end(); + EventCacheItem &servicemap = eventDB[service]; + eventMap::iterator prevEventIt = servicemap.byEvent.end(); + timeMap::iterator prevTimeIt = servicemap.byTime.end(); while (ptrdescriptors_loop_length)+EIT_LOOP_SIZE; + uint16_t event_hash; + eit_event_size = eit_event->getDescriptorsLoopLength()+EIT_LOOP_SIZE; duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3); - TM = parseDVBtime( - eit_event->start_time_1, - eit_event->start_time_2, - eit_event->start_time_3, - eit_event->start_time_4, - eit_event->start_time_5, - &event_hash); - - if ( TM == 3599 ) - goto next; + TM = parseDVBtime((const uint8_t*)eit_event + 2, &event_hash); - if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) ) - goto next; - - if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ ) // old events should not be cached + if ( (TM != 3599) && // NVOD Service + (now <= (TM+duration)) && // skip old events + (TM < (now+28*24*60*60)) && // no more than 4 weeks in future + ( (onid != 1714) || (duration != (24*3600-1)) ) // PlatformaHD invalid event + ) { - __u16 event_id = HILO(eit_event->event_id); + uint16_t event_id = eit_event->getEventId(); eventData *evt = 0; int ev_erase_count = 0; int tm_erase_count = 0; @@ -569,32 +784,31 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) // search in eventmap eventMap::iterator ev_it = - servicemap.first.find(event_id); + servicemap.byEvent.find(event_id); -// eDebug("event_id is %d sid is %04x", event_id, service.sid); + //eDebug("[eEPGCache] event_id : %d, sid : %04x", event_id, service.sid); // entry with this event_id is already exist ? - if ( ev_it != servicemap.first.end() ) + if ( ev_it != servicemap.byEvent.end() ) { if ( source > ev_it->second->type ) // update needed ? goto next; // when not.. then skip this entry // search this event in timemap timeMap::iterator tm_it_tmp = - servicemap.second.find(ev_it->second->getStartTime()); + servicemap.byTime.find(ev_it->second->getStartTime()); - if ( tm_it_tmp != servicemap.second.end() ) + if ( tm_it_tmp != servicemap.byTime.end() ) { if ( tm_it_tmp->first == TM ) // just update eventdata { // exempt memory eventData *tmp = ev_it->second; - ev_it->second = tm_it_tmp->second = - new eventData(eit_event, eit_event_size, source); + ev_it->second = tm_it_tmp->second = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid); if (FixOverlapping(servicemap, TM, duration, tm_it_tmp, service)) { - prevEventIt = servicemap.first.end(); - prevTimeIt = servicemap.second.end(); + prevEventIt = servicemap.byEvent.end(); + prevTimeIt = servicemap.byTime.end(); } delete tmp; goto next; @@ -603,8 +817,8 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) { tm_erase_count++; // delete the found record from timemap - servicemap.second.erase(tm_it_tmp); - prevTimeIt=servicemap.second.end(); + servicemap.byTime.erase(tm_it_tmp); + prevTimeIt = servicemap.byTime.end(); } } } @@ -612,28 +826,27 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) // search in timemap, for check of a case if new time has coincided with time of other event // or event was is not found in eventmap timeMap::iterator tm_it = - servicemap.second.find(TM); + servicemap.byTime.find(TM); - if ( tm_it != servicemap.second.end() ) + if ( tm_it != servicemap.byTime.end() ) { // event with same start time but another event_id... if ( source > tm_it->second->type && - ev_it == servicemap.first.end() ) + ev_it == servicemap.byEvent.end() ) goto next; // when not.. then skip this entry // search this time in eventmap - eventMap::iterator ev_it_tmp = - servicemap.first.find(tm_it->second->getEventID()); + eventMap::iterator ev_it_tmp = servicemap.byEvent.find(tm_it->second->getEventID()); - if ( ev_it_tmp != servicemap.first.end() ) + if ( ev_it_tmp != servicemap.byEvent.end() ) { ev_erase_count++; // delete the found record from eventmap - servicemap.first.erase(ev_it_tmp); - prevEventIt=servicemap.first.end(); + servicemap.byEvent.erase(ev_it_tmp); + prevEventIt = servicemap.byEvent.end(); } } - evt = new eventData(eit_event, eit_event_size, source); + evt = new eventData(eit_event, eit_event_size, source, (tsid<<16)|onid); #ifdef EPG_DEBUG bool consistencyCheck=true; #endif @@ -649,90 +862,90 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) { // exempt memory delete ev_it->second; - tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair( TM, evt ) ); - ev_it->second=evt; + tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair( TM, evt ) ); + ev_it->second = evt; } else if (ev_erase_count > 0 && tm_erase_count == 0) { // exempt memory delete tm_it->second; - ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair( event_id, evt) ); - tm_it->second=evt; + ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair( event_id, evt) ); + tm_it->second = evt; } else // added new eventData { #ifdef EPG_DEBUG consistencyCheck=false; #endif - ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair( event_id, evt) ); - tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair( TM, evt ) ); + ev_it = prevEventIt = servicemap.byEvent.insert( prevEventIt, std::pair( event_id, evt) ); + tm_it = prevTimeIt = servicemap.byTime.insert( prevTimeIt, std::pair( TM, evt ) ); } #ifdef EPG_DEBUG if ( consistencyCheck ) { if ( tm_it->second != evt || ev_it->second != evt ) - eFatal("tm_it->second != ev_it->second"); + eFatal("[eEPGCache] tm_it->second != ev_it->second"); else if ( tm_it->second->getStartTime() != tm_it->first ) - eFatal("event start_time(%d) non equal timemap key(%d)", - tm_it->second->getStartTime(), tm_it->first ); + eFatal("[eEPGCache] event start_time(%d) non equal timemap key(%d)", + (int)tm_it->second->getStartTime(), (int)tm_it->first ); else if ( tm_it->first != TM ) - eFatal("timemap key(%d) non equal TM(%d)", - tm_it->first, TM); + eFatal("[eEPGCache] timemap key(%d) non equal TM(%d)", + (int)tm_it->first, (int)TM); else if ( ev_it->second->getEventID() != ev_it->first ) - eFatal("event_id (%d) non equal event_map key(%d)", - ev_it->second->getEventID(), ev_it->first); + eFatal("[eEPGCache] event_id (%d) non equal event_map key(%d)", + (int)ev_it->second->getEventID(), (int)ev_it->first); else if ( ev_it->first != event_id ) - eFatal("eventmap key(%d) non equal event_id(%d)", - ev_it->first, event_id ); + eFatal("[eEPGCache] eventmap key(%d) non equal event_id(%d)", + (int)ev_it->first, (int)event_id ); } #endif if (FixOverlapping(servicemap, TM, duration, tm_it, service)) { - prevEventIt = servicemap.first.end(); - prevTimeIt = servicemap.second.end(); + prevEventIt = servicemap.byEvent.end(); + prevTimeIt = servicemap.byTime.end(); } } next: #ifdef EPG_DEBUG - if ( servicemap.first.size() != servicemap.second.size() ) + if ( servicemap.byEvent.size() != servicemap.byTime.size() ) { FILE *f = fopen("/hdd/event_map.txt", "w+"); int i=0; - for (eventMap::iterator it(servicemap.first.begin()) - ; it != servicemap.first.end(); ++it ) + for (eventMap::iterator it(servicemap.byEvent.begin()) + ; it != servicemap.byEvent.end(); ++it ) fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second ); fclose(f); f = fopen("/hdd/time_map.txt", "w+"); i=0; - for (timeMap::iterator it(servicemap.second.begin()) - ; it != servicemap.second.end(); ++it ) + for (timeMap::iterator it(servicemap.byTime.begin()) + ; it != servicemap.byTime.end(); ++it ) fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second ); fclose(f); - eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", - service.sid, service.tsid, service.onid, - servicemap.first.size(), servicemap.second.size() ); + eFatal("[eEPGCache] (1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", + service.sid, service.tsid, service.onid, + servicemap.byEvent.size(), servicemap.byTime.size() ); } #endif ptr += eit_event_size; - eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size); + eit_event = (eit_event_struct*)(((uint8_t*)eit_event) + eit_event_size); } } void eEPGCache::flushEPG(const uniqueEPGKey & s) { - eDebug("[EPGC] flushEPG %d", (int)(bool)s); + eDebug("[eEPGCache] flushEPG %d", (int)(bool)s); singleLock l(cache_lock); if (s) // clear only this service { eventCache::iterator it = eventDB.find(s); if ( it != eventDB.end() ) { - eventMap &evMap = it->second.first; - timeMap &tmMap = it->second.second; + eventMap &evMap = it->second.byEvent; + timeMap &tmMap = it->second.byTime; tmMap.clear(); for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i) delete i->second; @@ -756,8 +969,8 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s) for (eventCache::iterator it(eventDB.begin()); it != eventDB.end(); ++it) { - eventMap &evMap = it->second.first; - timeMap &tmMap = it->second.second; + eventMap &evMap = it->second.byEvent; + timeMap &tmMap = it->second.byTime; for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i) delete i->second; evMap.clear(); @@ -769,42 +982,38 @@ void eEPGCache::flushEPG(const uniqueEPGKey & s) #endif channelLastUpdated.clear(); singleLock m(channel_map_lock); - for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) it->second->startEPG(); } - eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize); } void eEPGCache::cleanLoop() { - singleLock s(cache_lock); - if (!eventDB.empty()) - { - eDebug("[EPGC] start cleanloop"); - - time_t now = ::time(0); + { /* scope for cache lock */ + time_t now = ::time(0) - historySeconds; + singleLock s(cache_lock); for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++) { bool updated = false; - for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;) + for (timeMap::iterator It = DBIt->second.byTime.begin(); It != DBIt->second.byTime.end() && It->first < now;) { if ( now > (It->first+It->second->getDuration()) ) // outdated normal entry (nvod references to) { // remove entry from eventMap - eventMap::iterator b(DBIt->second.first.find(It->second->getEventID())); - if ( b != DBIt->second.first.end() ) + eventMap::iterator b(DBIt->second.byEvent.find(It->second->getEventID())); + if ( b != DBIt->second.byEvent.end() ) { // release Heap Memory for this entry (new ....) -// eDebug("[EPGC] delete old event (evmap)"); - DBIt->second.first.erase(b); + //eDebug("[eEPGCache] delete old event (evmap)"); + DBIt->second.byEvent.erase(b); } // remove entry from timeMap -// eDebug("[EPGC] release heap mem"); + //eDebug("[eEPGCache] release heap mem"); delete It->second; - DBIt->second.second.erase(It++); -// eDebug("[EPGC] delete old event (timeMap)"); + DBIt->second.byTime.erase(It++); + //eDebug("[eEPGCache] delete old event (timeMap)"); updated = true; } else @@ -817,7 +1026,7 @@ void eEPGCache::cleanLoop() content_time_tables.find( DBIt->first ); if ( x != content_time_tables.end() ) { - timeMap &tmMap = DBIt->second.second; + timeMap &tmMap = DBIt->second.byTime; for ( contentMap::iterator i = x->second.begin(); i != x->second.end(); ) { for ( contentTimeMap::iterator it(i->second.begin()); @@ -837,19 +1046,18 @@ void eEPGCache::cleanLoop() } #endif } - eDebug("[EPGC] stop cleanloop"); - eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize); - } + } /* release lock */ cleanTimer->start(CLEAN_INTERVAL,true); } eEPGCache::~eEPGCache() { + m_running = false; messages.send(Message::quit); kill(); // waiting for thread shutdown singleLock s(cache_lock); for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++) - for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++) + for (eventMap::iterator It = evIt->second.byEvent.begin(); It != evIt->second.byEvent.end(); It++) delete It->second; } @@ -863,8 +1071,7 @@ void eEPGCache::gotMessage( const Message &msg ) case Message::startChannel: { singleLock s(channel_map_lock); - channelMapIterator channel = - m_knownChannels.find(msg.channel); + ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel); if ( channel != m_knownChannels.end() ) channel->second->startChannel(); break; @@ -872,8 +1079,7 @@ void eEPGCache::gotMessage( const Message &msg ) case Message::leaveChannel: { singleLock s(channel_map_lock); - channelMapIterator channel = - m_knownChannels.find(msg.channel); + ChannelMap::const_iterator channel = m_knownChannels.find(msg.channel); if ( channel != m_knownChannels.end() ) channel->second->abortEPG(); break; @@ -885,7 +1091,7 @@ void eEPGCache::gotMessage( const Message &msg ) case Message::got_private_pid: { singleLock s(channel_map_lock); - for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) { eDVBChannel *channel = (eDVBChannel*) it->first; channel_data *data = it->second; @@ -906,9 +1112,9 @@ void eEPGCache::gotMessage( const Message &msg ) update = ZAP_DELAY; data->startPrivateTimer->start(update, 1); if (update >= 60000) - eDebug("[EPGC] next private update in %i min", update/60000); + eDebug("[eEPGCache] next private update in %i min", update/60000); else if (update >= 1000) - eDebug("[EPGC] next private update in %i sec", update/1000); + eDebug("[eEPGCache] next private update in %i sec", update/1000); break; } } @@ -919,7 +1125,7 @@ void eEPGCache::gotMessage( const Message &msg ) case Message::got_mhw2_channel_pid: { singleLock s(channel_map_lock); - for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) { eDVBChannel *channel = (eDVBChannel*) it->first; channel_data *data = it->second; @@ -928,7 +1134,7 @@ void eEPGCache::gotMessage( const Message &msg ) chid.original_network_id.get() == msg.service.onid ) { data->m_mhw2_channel_pid = msg.pid; - eDebug("[EPGC] got mhw2 channel pid %04x", msg.pid); + eDebug("[eEPGCache] got mhw2 channel pid %04x", msg.pid); break; } } @@ -937,7 +1143,7 @@ void eEPGCache::gotMessage( const Message &msg ) case Message::got_mhw2_title_pid: { singleLock s(channel_map_lock); - for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) { eDVBChannel *channel = (eDVBChannel*) it->first; channel_data *data = it->second; @@ -946,7 +1152,7 @@ void eEPGCache::gotMessage( const Message &msg ) chid.original_network_id.get() == msg.service.onid ) { data->m_mhw2_title_pid = msg.pid; - eDebug("[EPGC] got mhw2 title pid %04x", msg.pid); + eDebug("[eEPGCache] got mhw2 title pid %04x", msg.pid); break; } } @@ -955,7 +1161,7 @@ void eEPGCache::gotMessage( const Message &msg ) case Message::got_mhw2_summary_pid: { singleLock s(channel_map_lock); - for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + for (ChannelMap::const_iterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) { eDVBChannel *channel = (eDVBChannel*) it->first; channel_data *data = it->second; @@ -964,7 +1170,7 @@ void eEPGCache::gotMessage( const Message &msg ) chid.original_network_id.get() == msg.service.onid ) { data->m_mhw2_summary_pid = msg.pid; - eDebug("[EPGC] got mhw2 summary pid %04x", msg.pid); + eDebug("[eEPGCache] got mhw2 summary pid %04x", msg.pid); break; } } @@ -975,7 +1181,7 @@ void eEPGCache::gotMessage( const Message &msg ) cleanLoop(); break; default: - eDebug("unhandled EPGCache Message!!"); + eDebug("[eEPGCache] unhandled EPGCache Message!!"); break; } } @@ -983,137 +1189,177 @@ void eEPGCache::gotMessage( const Message &msg ) void eEPGCache::thread() { hasStarted(); - m_running=1; nice(4); load(); cleanLoop(); runLoop(); save(); - m_running=0; } +static const char* EPGDAT_IN_FLASH = "/epg.dat"; + void eEPGCache::load() { - FILE *f = fopen(m_filename, "r"); - if (f) + if (m_filename.empty()) + m_filename = "/hdd/epg.dat"; + const char* EPGDAT = m_filename.c_str(); + std::string filenamex = m_filename + ".loading"; + const char* EPGDATX = filenamex.c_str(); + FILE *f = fopen(EPGDAT, "rb"); + int renameResult; + if (f == NULL) + { + /* No EPG on harddisk, so try internal flash */ + eDebug("[eEPGCache] %s not found, try %s", EPGDAT, EPGDAT_IN_FLASH); + EPGDAT = EPGDAT_IN_FLASH; + f = fopen(EPGDAT, "rb"); + if (f == NULL) + return; + renameResult = -1; + } + else + { + unlink(EPGDATX); + renameResult = rename(EPGDAT, EPGDATX); + if (renameResult) eDebug("[eEPGCache] failed to rename %s", EPGDAT); + } { - unlink(m_filename); int size=0; int cnt=0; - + unsigned int magic=0; + unlink(EPGDAT_IN_FLASH);/* Don't keep it around when in flash */ + fread( &magic, sizeof(int), 1, f); + if (magic != 0x98765432) { - unsigned int magic=0; - fread( &magic, sizeof(int), 1, f); - if (magic != 0x98765432) - { - eDebug("[EPGC] epg file has incorrect byte order.. dont read it"); - fclose(f); - return; - } - char text1[13]; - fread( text1, 13, 1, f); - if ( !strncmp( text1, "ENIGMA_EPG_V7", 13) ) + eDebug("[eEPGCache] epg file has incorrect byte order.. dont read it"); + fclose(f); + return; + } + char text1[13]; + fread( text1, 13, 1, f); + if ( !memcmp( text1, "ENIGMA_EPG_V7", 13) ) + { + singleLock s(cache_lock); + fread( &size, sizeof(int), 1, f); + eventDB.rehash(size); /* Reserve buckets in advance */ + while(size--) { - singleLock s(cache_lock); + uniqueEPGKey key; + int size=0; + fread( &key, sizeof(uniqueEPGKey), 1, f); fread( &size, sizeof(int), 1, f); + EventCacheItem& item = eventDB[key]; /* Constructs new entry */ while(size--) { - uniqueEPGKey key; - eventMap evMap; - timeMap tmMap; - int size=0; - fread( &key, sizeof(uniqueEPGKey), 1, f); - fread( &size, sizeof(int), 1, f); - while(size--) + uint8_t len=0; + uint8_t type=0; + eventData *event=0; + fread( &type, sizeof(uint8_t), 1, f); + fread( &len, sizeof(uint8_t), 1, f); + event = new eventData(0, len, type); + event->n_crc = (len-10) / sizeof(uint32_t); + fread( event->rawEITdata, 10, 1, f); + if (event->n_crc) { - __u8 len=0; - __u8 type=0; - eventData *event=0; - fread( &type, sizeof(__u8), 1, f); - fread( &len, sizeof(__u8), 1, f); - event = new eventData(0, len, type); - event->EITdata = new __u8[len]; - eventData::CacheSize+=len; - fread( event->EITdata, len, 1, f); - evMap[ event->getEventID() ]=event; - tmMap[ event->getStartTime() ]=event; - ++cnt; + event->crc_list = new uint32_t[event->n_crc]; + fread( event->crc_list, sizeof(uint32_t), event->n_crc, f); } - eventDB[key]=std::pair(evMap,tmMap); + eventData::CacheSize += sizeof(eventData) + event->n_crc * sizeof(uint32_t); + item.byEvent[event->getEventID()] = event; + item.byTime[event->getStartTime()] = event; + ++cnt; } - eventData::load(f); - eDebug("[EPGC] %d events read from %s", cnt, m_filename); + } + eventData::load(f); + eDebug("[eEPGCache] %d events read from %s", cnt, EPGDAT); #ifdef ENABLE_PRIVATE_EPG - char text2[11]; - fread( text2, 11, 1, f); - if ( !strncmp( text2, "PRIVATE_EPG", 11) ) + char text2[11]; + fread( text2, 11, 1, f); + if ( !memcmp( text2, "PRIVATE_EPG", 11) ) + { + size=0; + fread( &size, sizeof(int), 1, f); + eventDB.rehash(size); /* Reserve buckets in advance */ + while(size--) { - size=0; + int size=0; + uniqueEPGKey key; + fread( &key, sizeof(uniqueEPGKey), 1, f); + eventMap &evMap = eventDB[key].byEvent; fread( &size, sizeof(int), 1, f); while(size--) { - int size=0; - uniqueEPGKey key; - fread( &key, sizeof(uniqueEPGKey), 1, f); - eventMap &evMap=eventDB[key].first; + int size; + int content_id; + fread( &content_id, sizeof(int), 1, f); fread( &size, sizeof(int), 1, f); while(size--) { - int size; - int content_id; - fread( &content_id, sizeof(int), 1, f); - fread( &size, sizeof(int), 1, f); - while(size--) - { - time_t time1, time2; - __u16 event_id; - fread( &time1, sizeof(time_t), 1, f); - fread( &time2, sizeof(time_t), 1, f); - fread( &event_id, sizeof(__u16), 1, f); - content_time_tables[key][content_id][time1]=std::pair(time2, event_id); - eventMap::iterator it = - evMap.find(event_id); - if (it != evMap.end()) - it->second->type = PRIVATE; - } + time_t time1, time2; + uint16_t event_id; + fread( &time1, sizeof(time_t), 1, f); + fread( &time2, sizeof(time_t), 1, f); + fread( &event_id, sizeof(uint16_t), 1, f); + content_time_tables[key][content_id][time1]=std::pair(time2, event_id); + eventMap::iterator it = + evMap.find(event_id); + if (it != evMap.end()) + it->second->type = PRIVATE; } } } -#endif // ENABLE_PRIVATE_EPG } - else - eDebug("[EPGC] don't read old epg database"); - fclose(f); +#endif // ENABLE_PRIVATE_EPG + } + else + eDebug("[eEPGCache] don't read old epg database"); + posix_fadvise(fileno(f), 0, 0, POSIX_FADV_DONTNEED); + fclose(f); + // We got this far, so the EPG file is okay. + if (renameResult == 0) + { + renameResult = rename(EPGDATX, EPGDAT); + if (renameResult) eDebug("[eEPGCache] failed to rename epg.dat back"); } } } void eEPGCache::save() { - /* create empty file */ - FILE *f = fopen(m_filename, "w"); + const char* EPGDAT = m_filename.c_str(); + if (eventData::isCacheCorrupt) + return; + // only save epg.dat if it's worth the trouble... + if (eventData::CacheSize < 10240) + return; + /* create empty file */ + FILE *f = fopen(EPGDAT, "wb"); if (!f) { - eDebug("[EPGC] couldn't save epg data to '%s'(%m)", m_filename); - return; + eDebug("[eEPGCache] couldn't save epg data to '%s'(%m)", EPGDAT); + EPGDAT = EPGDAT_IN_FLASH; + f = fopen(EPGDAT, "wb"); + if (!f) + return; } - char *buf = realpath(m_filename, NULL); + char *buf = realpath(EPGDAT, NULL); if (!buf) { - eDebug("[EPGC] realpath to '%s' failed in save (%m)", m_filename); + eDebug("[eEPGCache] realpath to '%s' failed in save (%m)", EPGDAT); fclose(f); return; } - eDebug("[EPGC] store epg to realpath '%s'", buf); + eDebug("[eEPGCache] store epg to realpath '%s'", buf); struct statfs s; off64_t tmp; if (statfs(buf, &s) < 0) { - eDebug("[EPGC] statfs '%s' failed in save (%m)", buf); + eDebug("[eEPGCache] statfs '%s' failed in save (%m)", buf); fclose(f); + free(buf); return; } @@ -1124,7 +1370,7 @@ void eEPGCache::save() tmp*=s.f_bsize; if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead { - eDebug("[EPGC] not enough free space at path '%s' %lld bytes availd but %d needed", buf, tmp, (eventData::CacheSize*12)/10); + eDebug("[eEPGCache] not enough free space at '%s' %lld bytes available but %u needed", buf, tmp, (eventData::CacheSize*12)/10); fclose(f); return; } @@ -1138,20 +1384,21 @@ void eEPGCache::save() fwrite( &size, sizeof(int), 1, f ); for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it) { - timeMap &timemap = service_it->second.second; + timeMap &timemap = service_it->second.byTime; fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f); size = timemap.size(); fwrite( &size, sizeof(int), 1, f); for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it) { - __u8 len = time_it->second->ByteSize; - fwrite( &time_it->second->type, sizeof(__u8), 1, f ); - fwrite( &len, sizeof(__u8), 1, f); - fwrite( time_it->second->EITdata, len, 1, f); + uint8_t len = time_it->second->n_crc * sizeof(uint32_t) + 10; + fwrite( &time_it->second->type, sizeof(uint8_t), 1, f ); + fwrite( &len, sizeof(uint8_t), 1, f); + fwrite( time_it->second->rawEITdata, 10, 1, f); + fwrite( time_it->second->crc_list, sizeof(uint32_t), time_it->second->n_crc, f); ++cnt; } } - eDebug("[EPGC] %d events written to %s", cnt, m_filename); + eDebug("[eEPGCache] %d events written to %s", cnt, EPGDAT); eventData::save(f); #ifdef ENABLE_PRIVATE_EPG const char* text3 = "PRIVATE_EPG"; @@ -1174,7 +1421,7 @@ void eEPGCache::save() { fwrite( &it->first, sizeof(time_t), 1, f); fwrite( &it->second.first, sizeof(time_t), 1, f); - fwrite( &it->second.second, sizeof(__u16), 1, f); + fwrite( &it->second.second, sizeof(uint16_t), 1, f); } } } @@ -1209,31 +1456,32 @@ eEPGCache::channel_data::channel_data(eEPGCache *ml) pthread_mutex_init(&channel_active, 0); } -bool eEPGCache::channel_data::finishEPG() +void eEPGCache::channel_data::finishEPG() { if (!isRunning) // epg ready { - eDebug("[EPGC] stop caching events(%ld)", ::time(0)); + eDebug("[eEPGCache] stop caching events(%ld)", ::time(0)); zapTimer->start(UPDATE_INTERVAL, 1); - eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000); + eDebug("[eEPGCache] next update in %i min", UPDATE_INTERVAL / 60000); for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i) { seenSections[i].clear(); calcedSections[i].clear(); } - singleLock l(cache->cache_lock); - cache->channelLastUpdated[channel->getChannelID()] = ::time(0); #ifdef ENABLE_MHW_EPG - cleanup(); + cleanupMHW(); #endif - return true; +#ifdef ENABLE_FREESAT + cleanupFreeSat(); +#endif + singleLock l(cache_lock); + cache->channelLastUpdated[channel->getChannelID()] = ::time(0); } - return false; } void eEPGCache::channel_data::startEPG() { - eDebug("[EPGC] start caching events(%ld)", ::time(0)); + eDebug("[eEPGCache] start caching events(%ld)", ::time(0)); state=0; haveData=0; for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i) @@ -1241,60 +1489,145 @@ void eEPGCache::channel_data::startEPG() seenSections[i].clear(); calcedSections[i].clear(); } +#ifdef ENABLE_MHW_EPG + cleanupMHW(); +#endif +#ifdef ENABLE_FREESAT + cleanupFreeSat(); +#endif eDVBSectionFilterMask mask; memset(&mask, 0, sizeof(mask)); #ifdef ENABLE_MHW_EPG - mask.pid = 0xD3; - mask.data[0] = 0x91; - mask.mask[0] = 0xFF; - m_MHWReader->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData), m_MHWConn); - m_MHWReader->start(mask); - isRunning |= MHW; - memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask)); - - mask.pid = m_mhw2_channel_pid; - mask.data[0] = 0xC8; - mask.mask[0] = 0xFF; - mask.data[1] = 0; - mask.mask[1] = 0xFF; - m_MHWReader2->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData2), m_MHWConn2); - m_MHWReader2->start(mask); - isRunning |= MHW; - memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask)); - mask.data[1] = 0; - mask.mask[1] = 0; - m_MHWTimeoutet=false; + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::MHW) + { + mask.pid = 0xD3; + mask.data[0] = 0x91; + mask.mask[0] = 0xFF; + m_MHWReader->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData), m_MHWConn); + m_MHWReader->start(mask); + isRunning |= MHW; + memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask)); + + mask.pid = m_mhw2_channel_pid; + mask.data[0] = 0xC8; + mask.mask[0] = 0xFF; + mask.data[1] = 0; + mask.mask[1] = 0xFF; + m_MHWReader2->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData2), m_MHWConn2); + m_MHWReader2->start(mask); + isRunning |= MHW; + memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask)); + mask.data[1] = 0; + mask.mask[1] = 0; + m_MHWTimeoutet=false; + } +#endif +#ifdef ENABLE_FREESAT + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::FREESAT_SCHEDULE_OTHER) + { + mask.pid = 3842; + mask.flags = eDVBSectionFilterMask::rfCRC; + mask.data[0] = 0x60; + mask.mask[0] = 0xFE; + m_FreeSatScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn); + m_FreeSatScheduleOtherReader->start(mask); + + /* + * faster pid, available on ITV HD transponder. + * We rely on the fact that we have either of the two, + * never both. (both readers share the same data callback + * and status maps) + */ + mask.pid = 3003; + m_FreeSatScheduleOtherReader2->connectRead(slot(*this, &eEPGCache::channel_data::readFreeSatScheduleOtherData), m_FreeSatScheduleOtherConn2); + m_FreeSatScheduleOtherReader2->start(mask); + isRunning |= FREESAT_SCHEDULE_OTHER; + } #endif - mask.pid = 0x12; mask.flags = eDVBSectionFilterMask::rfCRC; - mask.data[0] = 0x4E; - mask.mask[0] = 0xFE; - m_NowNextReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_NowNextConn); - m_NowNextReader->start(mask); - isRunning |= NOWNEXT; + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NOWNEXT) + { + mask.data[0] = 0x4E; + mask.mask[0] = 0xFE; + m_NowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NOWNEXT), m_NowNextConn); + m_NowNextReader->start(mask); + isRunning |= NOWNEXT; + } + + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE) + { + mask.data[0] = 0x50; + mask.mask[0] = 0xF0; + m_ScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE), m_ScheduleConn); + m_ScheduleReader->start(mask); + isRunning |= SCHEDULE; + } + + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::SCHEDULE_OTHER) + { + mask.data[0] = 0x60; + mask.mask[0] = 0xF0; + m_ScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::SCHEDULE_OTHER), m_ScheduleOtherConn); + m_ScheduleOtherReader->start(mask); + isRunning |= SCHEDULE_OTHER; + } - mask.data[0] = 0x50; - mask.mask[0] = 0xF0; - m_ScheduleReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleConn); - m_ScheduleReader->start(mask); - isRunning |= SCHEDULE; +#ifdef ENABLE_VIRGIN + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_NOWNEXT) + { + mask.pid = 0x2bc; + mask.data[0] = 0x4E; + mask.mask[0] = 0xFE; + m_VirginNowNextReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_NOWNEXT), m_VirginNowNextConn); + m_VirginNowNextReader->start(mask); + isRunning |= VIRGIN_NOWNEXT; + } - mask.data[0] = 0x60; - m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleOtherConn); - m_ScheduleOtherReader->start(mask); - isRunning |= SCHEDULE_OTHER; + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIRGIN_SCHEDULE) + { + mask.pid = 0x2bc; + mask.data[0] = 0x50; + mask.mask[0] = 0xFE; + m_VirginScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIRGIN_SCHEDULE), m_VirginScheduleConn); + m_VirginScheduleReader->start(mask); + isRunning |= VIRGIN_SCHEDULE; + } +#endif +#ifdef ENABLE_NETMED + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE) + { + mask.pid = 0x1388; + mask.data[0] = 0x50; + mask.mask[0] = 0xF0; + m_NetmedScheduleReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE), m_NetmedScheduleConn); + m_NetmedScheduleReader->start(mask); + isRunning |= NETMED_SCHEDULE; + } - mask.pid = 0x39; + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::NETMED_SCHEDULE_OTHER) + { + mask.pid = 0x1388; + mask.data[0] = 0x60; + mask.mask[0] = 0xF0; + m_NetmedScheduleOtherReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::NETMED_SCHEDULE_OTHER), m_NetmedScheduleOtherConn); + m_NetmedScheduleOtherReader->start(mask); + isRunning |= NETMED_SCHEDULE_OTHER; + } +#endif + if (eEPGCache::getInstance()->getEpgSources() & eEPGCache::VIASAT) + { + mask.pid = 0x39; - mask.data[0] = 0x40; - mask.mask[0] = 0x40; - m_ViasatReader->connectRead(slot(*this, &eEPGCache::channel_data::readDataViasat), m_ViasatConn); - m_ViasatReader->start(mask); - isRunning |= VIASAT; + mask.data[0] = 0x40; + mask.mask[0] = 0x40; + m_ViasatReader->connectRead(bind(slot(*this, &eEPGCache::channel_data::readData), (int)eEPGCache::VIASAT), m_ViasatConn); + m_ViasatReader->start(mask); + isRunning |= VIASAT; + } abortTimer->start(7000,true); } @@ -1305,28 +1638,72 @@ void eEPGCache::channel_data::abortNonAvail() { if ( !(haveData&NOWNEXT) && (isRunning&NOWNEXT) ) { - eDebug("[EPGC] abort non avail nownext reading"); + eDebug("[eEPGCache] abort non avail nownext reading"); isRunning &= ~NOWNEXT; m_NowNextReader->stop(); m_NowNextConn=0; } if ( !(haveData&SCHEDULE) && (isRunning&SCHEDULE) ) { - eDebug("[EPGC] abort non avail schedule reading"); + eDebug("[eEPGCache] abort non avail schedule reading"); isRunning &= ~SCHEDULE; m_ScheduleReader->stop(); m_ScheduleConn=0; } if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) ) { - eDebug("[EPGC] abort non avail schedule other reading"); + eDebug("[eEPGCache] abort non avail schedule other reading"); isRunning &= ~SCHEDULE_OTHER; m_ScheduleOtherReader->stop(); m_ScheduleOtherConn=0; } +#ifdef ENABLE_VIRGIN + if ( !(haveData&VIRGIN_NOWNEXT) && (isRunning&VIRGIN_NOWNEXT) ) + { + eDebug("[eEPGCache] abort non avail virgin nownext reading"); + isRunning &= ~VIRGIN_NOWNEXT; + m_VirginNowNextReader->stop(); + m_VirginNowNextConn=0; + } + if ( !(haveData&VIRGIN_SCHEDULE) && (isRunning&VIRGIN_SCHEDULE) ) + { + eDebug("[eEPGCache] abort non avail virgin schedule reading"); + isRunning &= ~VIRGIN_SCHEDULE; + m_VirginScheduleReader->stop(); + m_VirginScheduleConn=0; + } +#endif +#ifdef ENABLE_NETMED + if ( !(haveData&NETMED_SCHEDULE) && (isRunning&NETMED_SCHEDULE) ) + { + eDebug("[eEPGCache] abort non avail netmed schedule reading"); + isRunning &= ~NETMED_SCHEDULE; + m_NetmedScheduleReader->stop(); + m_NetmedScheduleConn=0; + } + if ( !(haveData&NETMED_SCHEDULE_OTHER) && (isRunning&NETMED_SCHEDULE_OTHER) ) + { + eDebug("[eEPGCache] abort non avail netmed schedule other reading"); + isRunning &= ~NETMED_SCHEDULE_OTHER; + m_NetmedScheduleOtherReader->stop(); + m_NetmedScheduleOtherConn=0; + } +#endif +#ifdef ENABLE_FREESAT + if ( !(haveData&FREESAT_SCHEDULE_OTHER) && (isRunning&FREESAT_SCHEDULE_OTHER) ) + { + eDebug("[eEPGCache] abort non avail FreeSat schedule_other reading"); + isRunning &= ~FREESAT_SCHEDULE_OTHER; + m_FreeSatScheduleOtherReader->stop(); + m_FreeSatScheduleOtherReader2->stop(); + m_FreeSatScheduleOtherConn=0; + m_FreeSatScheduleOtherConn2=0; + cleanupFreeSat(); + } +#endif if ( !(haveData&VIASAT) && (isRunning&VIASAT) ) { - eDebug("[EPGC] abort non avail viasat reading"); + eDebug("[eEPGCache] abort non avail viasat reading"); isRunning &= ~VIASAT; m_ViasatReader->stop(); m_ViasatConn=0; @@ -1334,7 +1711,7 @@ void eEPGCache::channel_data::abortNonAvail() #ifdef ENABLE_MHW_EPG if ( !(haveData&MHW) && (isRunning&MHW) ) { - eDebug("[EPGC] abort non avail mhw reading"); + eDebug("[eEPGCache] abort non avail mhw reading"); isRunning &= ~MHW; m_MHWReader->stop(); m_MHWConn=0; @@ -1354,6 +1731,12 @@ void eEPGCache::channel_data::abortNonAvail() seenSections[i].clear(); calcedSections[i].clear(); } +#ifdef ENABLE_MHW_EPG + cleanupMHW(); +#endif +#ifdef ENABLE_FREESAT + cleanupFreeSat(); +#endif } } ++state; @@ -1371,9 +1754,9 @@ void eEPGCache::channel_data::startChannel() zapTimer->start(update, 1); if (update >= 60000) - eDebug("[EPGC] next update in %i min", update/60000); + eDebug("[eEPGCache] next update in %i min", update/60000); else if (update >= 1000) - eDebug("[EPGC] next update in %i sec", update/1000); + eDebug("[eEPGCache] next update in %i sec", update/1000); } void eEPGCache::channel_data::abortEPG() @@ -1383,11 +1766,17 @@ void eEPGCache::channel_data::abortEPG() seenSections[i].clear(); calcedSections[i].clear(); } +#ifdef ENABLE_MHW_EPG + cleanupMHW(); +#endif +#ifdef ENABLE_FREESAT + cleanupFreeSat(); +#endif abortTimer->stop(); zapTimer->stop(); if (isRunning) { - eDebug("[EPGC] abort caching events !!"); + eDebug("[eEPGCache] abort caching events !!"); if (isRunning & SCHEDULE) { isRunning &= ~SCHEDULE; @@ -1406,6 +1795,44 @@ void eEPGCache::channel_data::abortEPG() m_ScheduleOtherReader->stop(); m_ScheduleOtherConn=0; } +#ifdef ENABLE_VIRGIN + if (isRunning & VIRGIN_NOWNEXT) + { + isRunning &= ~VIRGIN_NOWNEXT; + m_VirginNowNextReader->stop(); + m_VirginNowNextConn=0; + } + if (isRunning & VIRGIN_SCHEDULE) + { + isRunning &= ~VIRGIN_SCHEDULE; + m_VirginScheduleReader->stop(); + m_VirginScheduleConn=0; + } +#endif +#ifdef ENABLE_NETMED + if (isRunning & NETMED_SCHEDULE) + { + isRunning &= ~NETMED_SCHEDULE; + m_NetmedScheduleReader->stop(); + m_NetmedScheduleConn=0; + } + if (isRunning & NETMED_SCHEDULE_OTHER) + { + isRunning &= ~NETMED_SCHEDULE_OTHER; + m_NetmedScheduleOtherReader->stop(); + m_NetmedScheduleOtherConn=0; + } +#endif +#ifdef ENABLE_FREESAT + if (isRunning & FREESAT_SCHEDULE_OTHER) + { + isRunning &= ~FREESAT_SCHEDULE_OTHER; + m_FreeSatScheduleOtherReader->stop(); + m_FreeSatScheduleOtherReader2->stop(); + m_FreeSatScheduleOtherConn=0; + m_FreeSatScheduleOtherConn2=0; + } +#endif if (isRunning & VIASAT) { isRunning &= ~VIASAT; @@ -1432,52 +1859,57 @@ void eEPGCache::channel_data::abortEPG() pthread_mutex_unlock(&channel_active); } - -void eEPGCache::channel_data::readDataViasat( const __u8 *data) -{ - __u8 *d=0; - memcpy(&d, &data, sizeof(__u8*)); - d[0] |= 0x80; - readData(data); -} - -void eEPGCache::channel_data::readData( const __u8 *data) +void eEPGCache::channel_data::readData( const uint8_t *data, int source) { - int source; int map; - iDVBSectionReader *reader=NULL; - switch(data[0]) + iDVBSectionReader *reader = NULL; + switch (source) { - case 0x4E ... 0x4F: - reader=m_NowNextReader; - source=NOWNEXT; - map=0; + case NOWNEXT: + reader = m_NowNextReader; + map = 0; + break; + case SCHEDULE: + reader = m_ScheduleReader; + map = 1; + break; + case SCHEDULE_OTHER: + reader = m_ScheduleOtherReader; + map = 2; + break; + case VIASAT: + reader = m_ViasatReader; + map = 3; break; - case 0x50 ... 0x5F: - reader=m_ScheduleReader; - source=SCHEDULE; - map=1; +#ifdef ENABLE_NETMED + case NETMED_SCHEDULE: + reader = m_NetmedScheduleReader; + map = 1; break; - case 0x60 ... 0x6F: - reader=m_ScheduleOtherReader; - source=SCHEDULE_OTHER; - map=2; + case NETMED_SCHEDULE_OTHER: + reader = m_NetmedScheduleOtherReader; + map = 2; break; - case 0xD0 ... 0xDF: - case 0xE0 ... 0xEF: - reader=m_ViasatReader; - source=VIASAT; - map=3; +#endif +#ifdef ENABLE_VIRGIN + case VIRGIN_NOWNEXT: + reader = m_VirginNowNextReader; + map = 0; + break; + case VIRGIN_SCHEDULE: + reader = m_VirginScheduleReader; + map = 1; break; +#endif default: - eDebug("[EPGC] unknown table_id !!!"); + eDebug("[eEPGCache] unknown source"); return; } tidMap &seenSections = this->seenSections[map]; tidMap &calcedSections = this->calcedSections[map]; if ( (state == 1 && calcedSections == seenSections) || state > 1 ) { - eDebugNoNewLine("[EPGC] "); + eDebugNoNewLine("[eEPGCache] "); switch (source) { case NOWNEXT: @@ -1496,9 +1928,29 @@ void eEPGCache::channel_data::readData( const __u8 *data) m_ViasatConn=0; eDebugNoNewLine("viasat"); break; +#ifdef ENABLE_NETMED + case NETMED_SCHEDULE: + m_NetmedScheduleConn=0; + eDebugNoNewLine("netmed schedule"); + break; + case NETMED_SCHEDULE_OTHER: + m_NetmedScheduleOtherConn=0; + eDebugNoNewLine("netmed schedule other"); + break; +#endif +#ifdef ENABLE_VIRGIN + case VIRGIN_NOWNEXT: + m_VirginNowNextConn=0; + eDebugNoNewLine("virgin nownext"); + break; + case VIRGIN_SCHEDULE: + m_VirginScheduleConn=0; + eDebugNoNewLine("virgin schedule"); + break; +#endif default: eDebugNoNewLine("unknown");break; } - eDebug(" finished(%ld)", ::time(0)); + eDebugNoNewLine(" finished(%ld)\n", ::time(0)); if ( reader ) reader->stop(); isRunning &= ~source; @@ -1508,7 +1960,7 @@ void eEPGCache::channel_data::readData( const __u8 *data) else { eit_t *eit = (eit_t*) data; - __u32 sectionNo = data[0] << 24; + uint32_t sectionNo = data[0] << 24; sectionNo |= data[3] << 16; sectionNo |= data[4] << 8; sectionNo |= eit->section_number; @@ -1520,44 +1972,165 @@ void eEPGCache::channel_data::readData( const __u8 *data) { seenSections.insert(sectionNo); calcedSections.insert(sectionNo); - __u32 tmpval = sectionNo & 0xFFFFFF00; - __u8 incr = source == NOWNEXT ? 1 : 8; + uint32_t tmpval = sectionNo & 0xFFFFFF00; + uint8_t incr = source == NOWNEXT ? 1 : 8; for ( int i = 0; i <= eit->last_section_number; i+=incr ) { if ( i == eit->section_number ) { for (int x=i; x <= eit->segment_last_section_number; ++x) + { calcedSections.insert(tmpval|(x&0xFF)); + } } else + { calcedSections.insert(tmpval|(i&0xFF)); + } } cache->sectionRead(data, source, this); } } } -RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction) -// if t == -1 we search the current event... +#if ENABLE_FREESAT + +freesatEITSubtableStatus::freesatEITSubtableStatus(u_char version, uint8_t maxSection) : version(version) { - singleLock s(cache_lock); - uniqueEPGKey key(handleGroup(service)); + initMap(maxSection); +} - // check if EPG for this service is ready... +void freesatEITSubtableStatus::initMap(uint8_t maxSection) +{ + int i, maxSectionIdx = maxSection / 8; + for (i = 0; i < 32; i++) + { + sectionMap[i] = (i <= maxSectionIdx ? 0x0100 : 0x0000 ); + } +} + +bool freesatEITSubtableStatus::isSectionPresent(uint8_t sectionNo) +{ + uint8_t sectionIdx = sectionNo / 8; + uint8_t bitOffset = sectionNo % 8; + + return ((sectionMap[sectionIdx] & (1 << bitOffset)) != 0); +} + +bool freesatEITSubtableStatus::isCompleted() +{ + uint32_t i = 0; + uint8_t calc; + + while ( i < 32 ) + { + calc = sectionMap[i] >> 8; + if (! calc) return true; // Last segment passed + if (calc ^ ( sectionMap[i] & 0xFF ) ) // Segment not fully found + return false; + i++; + } + return true; // All segments ok +} + +void freesatEITSubtableStatus::seen(uint8_t sectionNo, uint8_t maxSegmentSection) +{ + uint8_t sectionIdx = sectionNo / 8; + uint8_t bitOffset = sectionNo % 8; + uint8_t maxBitOffset = maxSegmentSection % 8; + + sectionMap[sectionIdx] &= 0x00FF; // Clear calc map + sectionMap[sectionIdx] |= ((0x01FF << maxBitOffset) & 0xFF00); // Set calc map + sectionMap[sectionIdx] |= (1 << bitOffset); // Set seen map +} + +bool freesatEITSubtableStatus::isVersionChanged(u_char testVersion) +{ + return version != testVersion; +} + +void freesatEITSubtableStatus::updateVersion(u_char newVersion, uint8_t maxSection) +{ + version = newVersion; + initMap(maxSection); +} + +void eEPGCache::channel_data::cleanupFreeSat() +{ + m_FreeSatSubTableStatus.clear(); + m_FreesatTablesToComplete = 0; +} + +void eEPGCache::channel_data::readFreeSatScheduleOtherData( const uint8_t *data) +{ + eit_t *eit = (eit_t*) data; + uint32_t subtableNo = data[0] << 24; // Table ID + subtableNo |= data[3] << 16; // Service ID Hi + subtableNo |= data[4] << 8; // Service ID Lo + + // Check for sub-table version in map + std::map &freeSatSubTableStatus = this->m_FreeSatSubTableStatus; + std::map::iterator itmap = freeSatSubTableStatus.find(subtableNo); + + freesatEITSubtableStatus *fsstatus; + if ( itmap == freeSatSubTableStatus.end() ) + { + // New sub table. Store version. + //eDebug("[eEPGCache] New subtable (%x) version (%d) now/next (%d) tsid (%x/%x) onid (%x/%x)", subtableNo, eit->version_number, eit->current_next_indicator, eit->transport_stream_id_hi, eit->transport_stream_id_lo, eit->original_network_id_hi, eit->original_network_id_lo); + fsstatus = new freesatEITSubtableStatus(eit->version_number, eit->last_section_number); + m_FreesatTablesToComplete++; + freeSatSubTableStatus.insert(std::pair(subtableNo, *fsstatus)); + } + else + { + fsstatus = &itmap->second; + // Existing subtable. Check version. Should check current / next as well? Seems to always be current for Freesat + if ( fsstatus->isVersionChanged(eit->version_number) ) + { + eDebug("[eEPGCache] FS subtable (%x) version changed (%d) now/next (%d)", subtableNo, eit->version_number, eit->current_next_indicator); + m_FreesatTablesToComplete++; + fsstatus->updateVersion(eit->version_number, eit->last_section_number); + } + else + { + if ( fsstatus->isSectionPresent(eit->section_number) ) + { +// eDebug("[eEPGCache] DUP FS sub/sec/ver (%x/%d/%d)", subtableNo, eit->section_number, eit->version_number); + return; + } + } + } + +// eDebug("[eEPGCache] New FS sub/sec/ls/lss/ver (%x/%d/%d/%d/%d)", subtableNo, eit->section_number, eit->last_section_number, eit->segment_last_section_number, eit->version_number); + fsstatus->seen(eit->section_number, eit->segment_last_section_number); + if (fsstatus->isCompleted()) + { + m_FreesatTablesToComplete--; + } + cache->sectionRead(data, FREESAT_SCHEDULE_OTHER, this); +} +#endif + +RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction) +// if t == -1 we search the current event... +{ + uniqueEPGKey key(handleGroup(service)); + + // check if EPG for this service is ready... eventCache::iterator It = eventDB.find( key ); - if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ? + if ( It != eventDB.end() && !It->second.byEvent.empty() ) // entrys cached ? { if (t==-1) t = ::time(0); - timeMap::iterator i = direction <= 0 ? It->second.second.lower_bound(t) : // find > or equal - It->second.second.upper_bound(t); // just > - if ( i != It->second.second.end() ) + timeMap::iterator i = direction <= 0 ? It->second.byTime.lower_bound(t) : // find > or equal + It->second.byTime.upper_bound(t); // just > + if ( i != It->second.byTime.end() ) { if ( direction < 0 || (direction == 0 && i->first > t) ) { timeMap::iterator x = i; --x; - if ( x != It->second.second.end() ) + if ( x != It->second.byTime.end() ) { time_t start_time = x->first; if (direction >= 0) @@ -1579,16 +2152,6 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co return -1; } -RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result, int direction) -{ - singleLock s(cache_lock); - const eventData *data=0; - RESULT ret = lookupEventTime(service, t, data, direction); - if ( !ret && data ) - result = data->get(); - return ret; -} - RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction) { singleLock s(cache_lock); @@ -1604,6 +2167,7 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, eP singleLock s(cache_lock); const eventData *data=0; RESULT ret = lookupEventTime(service, t, data, direction); + result = NULL; if ( !ret && data ) { Event ev((uint8_t*)data->get()); @@ -1616,14 +2180,13 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, eP RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result ) { - singleLock s(cache_lock); uniqueEPGKey key(handleGroup(service)); - eventCache::iterator It = eventDB.find( key ); - if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached? + eventCache::iterator It = eventDB.find(key); + if (It != eventDB.end()) { - eventMap::iterator i( It->second.first.find( event_id )); - if ( i != It->second.first.end() ) + eventMap::iterator i = It->second.byEvent.find(event_id); + if ( i != It->second.byEvent.end() ) { result = i->second; return 0; @@ -1631,19 +2194,48 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, else { result = 0; - eDebug("[EPGC] event %04x not found in epgcache", event_id); + eDebug("[eEPGCache] event %04x not found in epgcache", event_id); } } return -1; } -RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eit_event_struct *&result) +RESULT eEPGCache::saveEventToFile(const char* filename, const eServiceReference &service, int eit_event_id, time_t begTime, time_t endTime) { + RESULT ret = -1; singleLock s(cache_lock); - const eventData *data=0; - RESULT ret = lookupEventId(service, event_id, data); - if ( !ret && data ) - result = data->get(); + const eventData *data = NULL; + if ( eit_event_id != -1 ) + { + eDebug("[eEPGCache] %s epg event id %x", __func__, eit_event_id); + ret = lookupEventId(service, eit_event_id, data); + } + if ( (ret != 0) && (begTime != -1) ) + { + time_t queryTime = begTime; + if (endTime != -1) + queryTime += (endTime - begTime) / 2; + ret = lookupEventTime(service, queryTime, data); + } + if (ret == 0) + { + int fd = open(filename, O_CREAT|O_WRONLY, 0666); + if (fd < 0) + { + eDebug("[eEPGCache] Failed to create file: %s", filename); + return fd; + } + const eit_event_struct *event = data->get(); + int evLen = event->getDescriptorsLoopLength() + 12/*EIT_LOOP_SIZE*/; + int wr = ::write( fd, event, evLen ); + ::close(fd); + if ( wr != evLen ) + { + ::unlink(filename); /* Remove faulty file */ + eDebug("[eEPGCache] eit write error on %s: %m", filename); + ret = (wr < 0) ? wr : -1; + } + } return ret; } @@ -1662,6 +2254,7 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, singleLock s(cache_lock); const eventData *data=0; RESULT ret = lookupEventId(service, event_id, data); + result = NULL; if ( !ret && data ) { Event ev((uint8_t*)data->get()); @@ -1679,16 +2272,16 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, if (begin == -1) begin = ::time(0); eventCache::iterator It = eventDB.find(ref); - if ( It != eventDB.end() && It->second.second.size() ) + if ( It != eventDB.end() && !It->second.byTime.empty() ) { - m_timemap_cursor = It->second.second.lower_bound(begin); - if ( m_timemap_cursor != It->second.second.end() ) + m_timemap_cursor = It->second.byTime.lower_bound(begin); + if ( m_timemap_cursor != It->second.byTime.end() ) { if ( m_timemap_cursor->first != begin ) { timeMap::iterator x = m_timemap_cursor; --x; - if ( x != It->second.second.end() ) + if ( x != It->second.byTime.end() ) { time_t start_time = x->first; if ( begin > start_time && begin < (start_time+x->second->getDuration())) @@ -1698,9 +2291,9 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, } if (minutes != -1) - m_timemap_end = It->second.second.lower_bound(begin+minutes*60); + m_timemap_end = It->second.byTime.lower_bound(begin+minutes*60); else - m_timemap_end = It->second.second.end(); + m_timemap_end = It->second.byTime.end(); currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get(); return m_timemap_cursor == m_timemap_end ? -1 : 0; @@ -1708,26 +2301,6 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, return -1; } -RESULT eEPGCache::getNextTimeEntry(const eventData *& result) -{ - if ( m_timemap_cursor != m_timemap_end ) - { - result = m_timemap_cursor++->second; - return 0; - } - return -1; -} - -RESULT eEPGCache::getNextTimeEntry(const eit_event_struct *&result) -{ - if ( m_timemap_cursor != m_timemap_end ) - { - result = m_timemap_cursor++->second->get(); - return 0; - } - return -1; -} - RESULT eEPGCache::getNextTimeEntry(Event *&result) { if ( m_timemap_cursor != m_timemap_end ) @@ -1749,8 +2322,9 @@ RESULT eEPGCache::getNextTimeEntry(ePtr &result) return -1; } -void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service, eServiceEvent *ptr, ePyObject nowTime, ePyObject service_name ) +void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service_reference, eServiceEvent *ptr, ePyObject service_name, ePyObject nowTime, eventData *evData ) { + //eDebug("[eEPGCache] fillTuple arg=%s argcnt=%d, ptr=%d evData=%d", argstring, argcount, ptr ? 1 : 0, evData ? 1 : 0); ePyObject tmp; int spos=0, tpos=0; char c; @@ -1763,13 +2337,13 @@ void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject s tmp = PyLong_FromLong(0); break; case 'I': // Event Id - tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject(); + tmp = evData ? PyLong_FromLong(evData->getEventID()) : (ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject()); break; case 'B': // Event Begin Time - tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject(); + tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : (evData ? PyLong_FromLong(evData->getStartTime()) : ePyObject()); break; case 'D': // Event Duration - tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject(); + tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : (evData ? PyLong_FromLong(evData->getDuration()) : ePyObject()); break; case 'T': // Event Title tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject(); @@ -1780,12 +2354,18 @@ void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject s case 'E': // Event Extended Description tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject(); break; + case 'P': // Event Parental Rating + tmp = ptr ? ePyObject(ptr->getParentalData()) : ePyObject(); + break; + case 'W': // Event Content Description + tmp = ptr ? ePyObject(ptr->getGenreData()) : ePyObject(); + break; case 'C': // Current Time tmp = nowTime; inc_refcount = true; break; case 'R': // service reference string - tmp = service; + tmp = service_reference; inc_refcount = true; break; case 'n': // short service name @@ -1798,7 +2378,7 @@ void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject s continue; default: // ignore unknown tmp = ePyObject(); - eDebug("fillTuple unknown '%c'... insert 'None' in result", c); + eDebug("[eEPGCache] fillTuple unknown '%c'... insert 'None' in result", c); } if (!tmp) { @@ -1815,7 +2395,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, { if (convertFunc) { - fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name); + fillTuple(convertFuncArgs, argstring, argcount, service, ptr, service_name, nowTime, 0); ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs); if (!result) { @@ -1827,7 +2407,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, Py_DECREF(dest_list); PyErr_SetString(PyExc_StandardError, "error in convertFunc execute"); - eDebug("error in convertFunc execute"); + eDebug("[eEPGCache] handleEvent: error in convertFunc execute"); return -1; } PyList_Append(dest_list, result); @@ -1836,7 +2416,7 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, else { ePyObject tuple = PyTuple_New(argcount); - fillTuple(tuple, argstring, argcount, service, ptr, nowTime, service_name); + fillTuple(tuple, argstring, argcount, service, ptr, service_name, nowTime, 0); PyList_Append(dest_list, tuple); Py_DECREF(tuple); } @@ -1852,6 +2432,8 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, // T = Event Title // S = Event Short Description // E = Event Extended Description +// P = Event Parental Rating +// W = Event Content Description ('W'hat) // C = Current Time // R = Service Reference // N = Service Name @@ -1880,7 +2462,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("no list"); + eDebug("[eEPGCache] no list"); return NULL; } int listIt=0; @@ -1888,11 +2470,11 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) if (!listSize) { PyErr_SetString(PyExc_StandardError, - "not params given"); - eDebug("not params given"); + "no params given"); + eDebug("[eEPGCache] no params given"); return NULL; } - else + else { ePyObject argv=PyList_GET_ITEM(list, 0); // borrowed reference! if (PyString_Check(argv)) @@ -1903,7 +2485,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) else argstring = "I"; // just event id as default argcount = strlen(argstring); -// eDebug("have %d args('%s')", argcount, argstring); +// eDebug("[eEPGCache] have %d args('%s')", argcount, argstring); } bool forceReturnOne = strchr(argstring, 'X') ? true : false; @@ -1916,7 +2498,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) { PyErr_SetString(PyExc_StandardError, "convertFunc must be callable"); - eDebug("convertFunc is not callable"); + eDebug("[eEPGCache] convertFunc is not callable"); return NULL; } convertFuncArgs = PyTuple_New(argcount); @@ -1952,7 +2534,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) { if (!PyString_Check(entry)) { - eDebug("tuple entry 0 is no a string"); + eDebug("[eEPGCache] tuple entry 0 is no a string"); goto skip_entry; } service = entry; @@ -1962,7 +2544,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) type=PyInt_AsLong(entry); if (type < -1 || type > 2) { - eDebug("unknown type %d", type); + eDebug("[eEPGCache] unknown type %d", type); goto skip_entry; } break; @@ -1973,7 +2555,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) minutes=PyInt_AsLong(entry); break; default: - eDebug("unneeded extra argument"); + eDebug("[eEPGCache] unneeded extra argument"); break; } } @@ -1982,12 +2564,6 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) stime = ::time(0); eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service)))); - if (ref.type != eServiceReference::idDVB) - { - eDebug("service reference for epg query is not valid"); - continue; - } - // redirect subservice querys to parent service eServiceReferenceDVB &dvb_ref = (eServiceReferenceDVB&)ref; if (dvb_ref.getParentTransportStreamID().get()) // linkage subservice @@ -2096,63 +2672,302 @@ skip_entry: return dest_list; } -void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, eServiceEvent *ptr, ePyObject service_name, ePyObject service_reference) +static void fill_eit_start(eit_event_struct *evt, time_t t) { - ePyObject tmp; - int pos=0; - while(pos < argcount) + tm *time = gmtime(&t); + + int l = 0; + int month = time->tm_mon + 1; + if (month == 1 || month == 2) + l = 1; + int mjd = 14956 + time->tm_mday + (int)((time->tm_year - l) * 365.25) + (int)((month + 1 + l*12) * 30.6001); + evt->start_time_1 = mjd >> 8; + evt->start_time_2 = mjd & 0xFF; + + evt->start_time_3 = toBCD(time->tm_hour); + evt->start_time_4 = toBCD(time->tm_min); + evt->start_time_5 = toBCD(time->tm_sec); + +} + +static void fill_eit_duration(eit_event_struct *evt, int time) +{ + //time is given in second + //convert to hour, minutes, seconds + evt->duration_1 = toBCD(time / 3600); + evt->duration_2 = toBCD((time % 3600) / 60); + evt->duration_3 = toBCD((time % 3600) % 60); +} + +// convert from set of strings to DVB format (EIT) +void eEPGCache::submitEventData(const std::vector& serviceRefs, long start, + long duration, const char* title, const char* short_summary, + const char* long_description, char event_type) +{ + std::vector sids; + std::vector chids; + for (std::vector::const_iterator serviceRef = serviceRefs.begin(); + serviceRef != serviceRefs.end(); + ++serviceRef) { - bool inc_refcount=false; - switch(argstring[pos]) + eDVBChannelID chid; + serviceRef->getChannelID(chid); + chids.push_back(chid); + sids.push_back(serviceRef->getServiceID().get()); + } + submitEventData(sids, chids, start, duration, title, short_summary, long_description, event_type, EPG_IMPORT); +} + +void eEPGCache::submitEventData(const std::vector& sids, const std::vector& chids, long start, + long duration, const char* title, const char* short_summary, + const char* long_description, char event_type, int source) +{ + if (!title) + return; + if (sids.size() != chids.size()) + return; + static const int EIT_LENGTH = 4108; + static const uint8_t codePage = 0x15; // UTF-8 encoding + uint8_t data[EIT_LENGTH]; + + eit_t *packet = (eit_t *) data; + packet->table_id = 0x50; + packet->section_syntax_indicator = 1; + + packet->version_number = 0; // eEPGCache::sectionRead() will dig this for the moment + packet->current_next_indicator = 0; + packet->section_number = 0; // eEPGCache::sectionRead() will dig this for the moment + packet->last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment + + packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment + packet->segment_last_table_id = 0x50; + + eit_event_t *evt_struct = (eit_event_t*) (data + EIT_SIZE); + + uint16_t eventId = start & 0xFFFF; + evt_struct->setEventId(eventId); + + //6 bytes start time, 3 bytes duration + fill_eit_start(evt_struct, start); + fill_eit_duration(evt_struct, duration); + + evt_struct->running_status = 0; + evt_struct->free_CA_mode = 0; + + //no support for different code pages, only DVB's latin1 character set + //TODO: convert text to correct character set (data is probably passed in as UTF-8) + uint8_t *x = (uint8_t *) evt_struct; + x += EIT_LOOP_SIZE; + int nameLength = strnlen(title, 246); + int descLength = short_summary ? strnlen(short_summary, 246 - nameLength) : 0; + + eit_short_event_descriptor_struct *short_evt = (eit_short_event_descriptor_struct*) x; + short_evt->descriptor_tag = SHORT_EVENT_DESCRIPTOR; + short_evt->descriptor_length = EIT_SHORT_EVENT_DESCRIPTOR_SIZE + nameLength + descLength + 1 - 2; //+1 for length of short description, -2 for tag and length + if (nameLength) ++short_evt->descriptor_length; // +1 for codepage byte + if (descLength) ++short_evt->descriptor_length; + short_evt->language_code_1 = 'e'; + short_evt->language_code_2 = 'n'; + short_evt->language_code_3 = 'g'; + short_evt->event_name_length = nameLength ? nameLength + 1 : 0; + x = (uint8_t *) short_evt; + x += EIT_SHORT_EVENT_DESCRIPTOR_SIZE; + *x = codePage; + ++x; + memcpy(x, title, nameLength); + x += nameLength; + if (descLength) + { + *x = descLength + 1; + ++x; + *x = codePage; + ++x; + memcpy(x, short_summary, descLength); + x += descLength; + } + else + { + *x = 0; + ++x; + } + + //Content type + if (event_type != 0) + { + x[0] = 0x54; + x[1] = 2; + x[2] = event_type; + x[3] = 0; + x += 4; + } + + //Long description + int currentLoopLength = x - (uint8_t*)short_evt; + static const int overheadPerDescriptor = 9; //increase if codepages are added!!! + static const int MAX_LEN = 256 - overheadPerDescriptor; + + int textLength = long_description ? strnlen(long_description, EIT_LENGTH) : 0;//EIT_LENGTH is a bit too much, but it's only here as a reasonable end point + int lastDescriptorNumber = (textLength + MAX_LEN-1) / MAX_LEN - 1; + int remainingTextLength = textLength - lastDescriptorNumber * MAX_LEN; + + //if long description is too long, just try to fill as many descriptors as possible + while ( (lastDescriptorNumber+1) * 256 + currentLoopLength > EIT_LENGTH - EIT_LOOP_SIZE) + { + lastDescriptorNumber--; + remainingTextLength = MAX_LEN; + } + + for (int descrIndex = 0; descrIndex <= lastDescriptorNumber; ++descrIndex) + { + eit_extended_descriptor_struct *ext_evt = (eit_extended_descriptor_struct*) x; + ext_evt->descriptor_tag = EIT_EXTENDED_EVENT_DESCRIPOR; + //descriptor header length is 6, including the 2 tag and length bytes + //so the length field must be: stringlength + 1 (2 4-bits numbers) + 3 (lang code) + 2 bytes for item info length field and text length field + int currentTextLength = descrIndex < lastDescriptorNumber ? MAX_LEN : remainingTextLength; + ext_evt->descriptor_length = 6 + currentTextLength + 1; + + ext_evt->descriptor_number = descrIndex; + ext_evt->last_descriptor_number = lastDescriptorNumber; + ext_evt->iso_639_2_language_code_1 = 'e'; + ext_evt->iso_639_2_language_code_2 = 'n'; + ext_evt->iso_639_2_language_code_3 = 'g'; + + x[6] = 0; //item information (car, year, director, etc. Unsupported for now) + x[7] = currentTextLength + 1; //length of description string (part in this message) + x[8] = codePage; + memcpy(x + 9, &long_description[descrIndex*MAX_LEN], currentTextLength); + + x += 2 + ext_evt->descriptor_length; + } + + //TODO: add age and more + int desc_loop_length = x - ((uint8_t*)evt_struct + EIT_LOOP_SIZE); + evt_struct->setDescriptorsLoopLength(desc_loop_length); + + int packet_length = (x - data) - 3; //should add 1 for crc.... + packet->setSectionLength(packet_length); + // Add channelrefs and submit data. + for (unsigned int i = 0; i < chids.size(); i++) + { + packet->setServiceId(sids[i]); + packet->setTransportStreamId(chids[i].transport_stream_id.get()); + packet->setOriginalNetworkId(chids[i].original_network_id.get()); + sectionRead(data, source, 0); + } +} + +void eEPGCache::setEpgHistorySeconds(time_t seconds) +{ + historySeconds = seconds; +} + +void eEPGCache::setEpgSources(unsigned int mask) +{ + enabledSources = mask; +} + +unsigned int eEPGCache::getEpgSources() +{ + return enabledSources; +} + +static const char* getStringFromPython(ePyObject obj) +{ + char *result = 0; + if (PyString_Check(obj)) + { + result = PyString_AS_STRING(obj); + } + return result; +} + +void eEPGCache::importEvent(ePyObject serviceReference, ePyObject list) +{ + importEvents(serviceReference, list); +} + +//here we get a python tuple of tuples ;) +// consider it an array of objects with the following data +// 1. start time (long) +// 2. duration (int) +// 3. event title (string) +// 4. short description (string) +// 5. extended description (string) +// 6. event type (byte) +void eEPGCache::importEvents(ePyObject serviceReferences, ePyObject list) +{ + std::vector refs; + + if (PyString_Check(serviceReferences)) + { + char *refstr; + refstr = PyString_AS_STRING(serviceReferences); + if (!refstr) { - case '0': // PyLong 0 - tmp = PyLong_FromLong(0); - break; - case 'I': // Event Id - tmp = PyLong_FromLong(evData->getEventID()); - break; - case 'B': // Event Begin Time - if (ptr) - tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject(); - else - tmp = PyLong_FromLong(evData->getStartTime()); - break; - case 'D': // Event Duration - if (ptr) - tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject(); - else - tmp = PyLong_FromLong(evData->getDuration()); - break; - case 'T': // Event Title - tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject(); - break; - case 'S': // Event Short Description - tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject(); - break; - case 'E': // Event Extended Description - tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject(); - break; - case 'R': // service reference string - tmp = service_reference; - inc_refcount = true; - break; - case 'n': // short service name - case 'N': // service name - tmp = service_name; - inc_refcount = true; - break; - default: // ignore unknown - tmp = ePyObject(); - eDebug("fillTuple2 unknown '%c'... insert None in Result", argstring[pos]); + eDebug("[eEPGCache:import] serviceReference string is 0, aborting"); + return; } - if (!tmp) + refs.push_back(eServiceReferenceDVB(refstr)); + } + else if (PyList_Check(serviceReferences)) + { + int nRefs = PyList_Size(serviceReferences); + for (int i = 0; i < nRefs; ++i) { - tmp = Py_None; - inc_refcount = true; + PyObject* item = PyList_GET_ITEM(serviceReferences, i); + char *refstr; + refstr = PyString_AS_STRING(item); + if (!refstr) + { + eDebug("[eEPGCache:import] a serviceref item is not a string"); + } + else + { + refs.push_back(eServiceReferenceDVB(refstr)); + } } - if (inc_refcount) - Py_INCREF(tmp); - PyTuple_SET_ITEM(tuple, pos++, tmp); + } + else + { + eDebug("[eEPGCache:import] serviceReference string is neither string nor list, aborting"); + return; + } + + bool isTuple = PyTuple_Check(list); + if (!isTuple && !PyList_Check(list)) + { + + eDebug("[eEPGCache:import] argument 'list' is neither list nor tuple."); + return; + } + + int numberOfEvents = isTuple ? PyTuple_Size(list) : PyList_Size(list); + + for (int i = 0; i < numberOfEvents; ++i) + { + ePyObject singleEvent = isTuple ? PyTuple_GET_ITEM(list, i) : PyList_GET_ITEM(list, i); + if (!PyTuple_Check(singleEvent)) + { + eDebug("[eEPGCache:import] eventdata tuple does not pass PyTuple_Check, aborting"); + return; + } + int tupleSize = PyTuple_Size(singleEvent); + if (tupleSize < 5) + { + eDebug("[eEPGCache:import] eventdata tuple does not contain enough fields, aborting"); + return; + } + + long start = PyLong_AsLong(PyTuple_GET_ITEM(singleEvent, 0)); + long duration = PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 1)); + const char *title = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 2)); + const char *short_summary = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 3)); + const char *long_description = getStringFromPython(PyTuple_GET_ITEM(singleEvent, 4)); + char event_type = (char) PyInt_AsLong(PyTuple_GET_ITEM(singleEvent, 5)); + + Py_BEGIN_ALLOW_THREADS; + submitEventData(refs, start, duration, title, short_summary, long_description, event_type); + Py_END_ALLOW_THREADS; } } @@ -2163,6 +2978,8 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData // D = Event Duration // T = Event Title // S = Event Short Description +// P = Event Parental Rating +// W = Event Content Description // E = Event Extended Description // R = Service Reference // N = Service Name @@ -2170,12 +2987,13 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData // the second tuple entry is the MAX matches value // the third tuple entry is the type of query // 0 = search for similar broadcastings (SIMILAR_BROADCASTINGS_SEARCH) -// 1 = search events with exactly title name (EXAKT_TITLE_SEARCH) +// 1 = search events with exactly title name (EXACT_TITLE_SEARCH) // 2 = search events with text in title name (PARTIAL_TITLE_SEARCH) +// 3 = search events starting with title name (START_TITLE_SEARCH) // when type is 0 (SIMILAR_BROADCASTINGS_SEARCH) // the fourth is the servicereference string // the fifth is the eventid -// when type is 1 or 2 (EXAKT_TITLE_SEARCH or PARTIAL_TITLE_SEARCH) +// when type > 0 (*_TITLE_SEARCH) // the fourth is the search text // the fifth is // 0 = case sensitive (CASE_CHECK) @@ -2184,8 +3002,7 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData PyObject *eEPGCache::search(ePyObject arg) { ePyObject ret; - int descridx = -1; - __u32 descr[512]; + std::deque descr; int eventid = -1; const char *argstring=0; char *refstr=0; @@ -2211,11 +3028,14 @@ PyObject *eEPGCache::search(ePyObject arg) #endif argstring = PyString_AS_STRING(obj); for (int i=0; i < argcount; ++i) + { switch(argstring[i]) { case 'S': case 'E': case 'T': + case 'P': + case 'W': needServiceEvent=true; break; case 'N': @@ -2230,20 +3050,24 @@ PyObject *eEPGCache::search(ePyObject arg) default: break; } + } } else { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("tuple arg 0 is not a string"); + eDebug("[eEPGCache] tuple arg 0 is not a string"); return NULL; } } if (tuplesize > 1) + { maxmatches = PyLong_AsLong(PyTuple_GET_ITEM(arg, 1)); + } if (tuplesize > 2) { querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2)); + if (tuplesize > 4 && querytype == 0) { ePyObject obj = PyTuple_GET_ITEM(arg, 3); @@ -2259,47 +3083,44 @@ PyObject *eEPGCache::search(ePyObject arg) lookupEventId(ref, eventid, evData); if (evData) { - __u8 *data = evData->EITdata; - int tmp = evData->ByteSize-10; - __u32 *p = (__u32*)(data+10); - // search short and extended event descriptors - while(tmp>3) + // search short and extended event descriptors + for (uint8_t i = 0; i < evData->n_crc; ++i) { - __u32 crc = *p++; - descriptorMap::iterator it = + uint32_t crc = evData->crc_list[i]; + DescriptorMap::iterator it = eventData::descriptors.find(crc); if (it != eventData::descriptors.end()) { - __u8 *descr_data = it->second.second; + uint8_t *descr_data = it->second.data; switch(descr_data[0]) { case 0x4D ... 0x4E: - descr[++descridx]=crc; + descr.push_back(crc); + break; default: break; } } - tmp-=4; } } - if (descridx<0) - eDebug("event not found"); + if (descr.empty()) + eDebug("[eEPGCache] event not found"); } else { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("tuple arg 4 is not a valid service reference string"); + eDebug("[eEPGCache] tuple arg 4 is not a valid service reference string"); return NULL; } } else { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("tuple arg 4 is not a string"); + eDebug("[eEPGCache] tuple arg 4 is not a string"); return NULL; } } - else if (tuplesize > 4 && (querytype == 1 || querytype == 2) ) + else if (tuplesize > 4 && (querytype > 0) ) { ePyObject obj = PyTuple_GET_ITEM(arg, 3); if (PyString_Check(obj)) @@ -2311,83 +3132,85 @@ PyObject *eEPGCache::search(ePyObject arg) #else int textlen = PyString_Size(obj); #endif - if (querytype == 1) - eDebug("lookup for events with '%s' as title(%s)", str, casetype?"ignore case":"case sensitive"); - else - eDebug("lookup for events with '%s' in title(%s)", str, casetype?"ignore case":"case sensitive"); + switch (querytype) + { + case 1: + eDebug("[eEPGCache] lookup events with '%s' as title (%s)", str, casetype?"ignore case":"case sensitive"); + break; + case 2: + eDebug("[eEPGCache] lookup events with '%s' in title (%s)", str, casetype?"ignore case":"case sensitive"); + break; + case 3: + eDebug("[eEPGCache] lookup events, title starting with '%s' (%s)", str, casetype?"ignore case":"case sensitive"); + break; + } + Py_BEGIN_ALLOW_THREADS; /* No Python code in this section, so other threads can run */ singleLock s(cache_lock); - for (descriptorMap::iterator it(eventData::descriptors.begin()); - it != eventData::descriptors.end() && descridx < 511; ++it) + std::string title; + for (DescriptorMap::iterator it(eventData::descriptors.begin()); + it != eventData::descriptors.end(); ++it) { - __u8 *data = it->second.second; - if ( data[0] == 0x4D ) // short event descriptor + uint8_t *data = it->second.data; + if ( data[0] == SHORT_EVENT_DESCRIPTOR ) { + const char *titleptr = (const char*)&data[6]; int title_len = data[5]; - if ( querytype == 1 ) + if (data[6] < 0x20) { - int offs = 6; - // skip DVB-Text Encoding! - if (data[6] == 0x10) - { - offs+=3; - title_len-=3; - } - else if(data[6] > 0 && data[6] < 0x20) - { - offs+=1; - title_len-=1; - } + /* custom encoding */ + title = convertDVBUTF8((unsigned char*)titleptr, title_len, 0x40, 0); + titleptr = title.data(); + title_len = title.length(); + } + if (title_len < textlen) + /*Doesn't fit, so cannot match anything */ + continue; + if (querytype == 1) + { + /* require exact title match */ if (title_len != textlen) continue; - if ( casetype ) + } + else if (querytype == 3) + { + /* Do a "startswith" match by pretending the text isn't that long */ + title_len = textlen; + } + if (casetype) + { + while (title_len >= textlen) { - if ( !strncasecmp((const char*)data+offs, str, title_len) ) + if (!strncasecmp(titleptr, str, textlen)) { -// std::string s((const char*)data+offs, title_len); -// eDebug("match1 %s %s", str, s.c_str() ); - descr[++descridx] = it->first; + descr.push_back(it->first); + break; } - } - else if ( !strncmp((const char*)data+offs, str, title_len) ) - { -// std::string s((const char*)data+offs, title_len); -// eDebug("match2 %s %s", str, s.c_str() ); - descr[++descridx] = it->first; + title_len--; + titleptr++; } } else { - int idx=0; - while((title_len-idx) >= textlen) + while (title_len >= textlen) { - if (casetype) - { - if (!strncasecmp((const char*)data+6+idx, str, textlen) ) - { - descr[++descridx] = it->first; -// std::string s((const char*)data+6, title_len); -// eDebug("match 3 %s %s", str, s.c_str() ); - break; - } - } - else if (!strncmp((const char*)data+6+idx, str, textlen) ) + if (!memcmp(titleptr, str, textlen)) { - descr[++descridx] = it->first; -// std::string s((const char*)data+6, title_len); -// eDebug("match 4 %s %s", str, s.c_str() ); + descr.push_back(it->first); break; } - ++idx; + title_len--; + titleptr++; } } } } + Py_END_ALLOW_THREADS; } else { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("tuple arg 4 is not a string"); + eDebug("[eEPGCache] tuple arg 4 is not a string"); return NULL; } } @@ -2395,7 +3218,7 @@ PyObject *eEPGCache::search(ePyObject arg) { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("tuple arg 3(%d) is not a known querytype(0, 1, 2)", querytype); + eDebug("[eEPGCache] tuple arg 3(%d) is not a known querytype(0..3)", querytype); return NULL; } } @@ -2403,7 +3226,7 @@ PyObject *eEPGCache::search(ePyObject arg) { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("not enough args in tuple"); + eDebug("[eEPGCache] not enough args in tuple"); return NULL; } } @@ -2411,11 +3234,11 @@ PyObject *eEPGCache::search(ePyObject arg) { PyErr_SetString(PyExc_StandardError, "type error"); - eDebug("arg 0 is not a tuple"); + eDebug("[eEPGCache] arg 0 is not a tuple"); return NULL; } - if (descridx > -1) + if (!descr.empty()) { int maxcount=maxmatches; eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB("")); @@ -2432,105 +3255,118 @@ PyObject *eEPGCache::search(ePyObject arg) ++cit; continue; } - ePyObject service_name; - ePyObject service_reference; - timeMap &evmap = cit->second.second; + timeMap &evmap = cit->second.byTime; // check all events for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit) { - int evid = evit->second->getEventID(); - if ( evid == eventid) - continue; - __u8 *data = evit->second->EITdata; - int tmp = evit->second->ByteSize-10; - __u32 *p = (__u32*)(data+10); + if (querytype == 0) + { + /* ignore the current event, when looking for similar events */ + if (evit->second->getEventID() == eventid) + continue; + } // check if any of our descriptor used by this event - int cnt=-1; - while(tmp>3) + unsigned int cnt = 0; + for (uint8_t i = 0; i < evit->second->n_crc; ++i) { - __u32 crc32 = *p++; - for ( int i=0; i <= descridx; ++i) + uint32_t crc32 = evit->second->crc_list[i]; + for (std::deque::const_iterator it = descr.begin(); + it != descr.end(); ++it) { - if (descr[i] == crc32) // found... + if (*it == crc32) // found... + { ++cnt; + if (querytype) + { + /* we need only one match, when we're not looking for similar broadcasting events */ + i = evit->second->n_crc; + break; + } + } } - tmp-=4; } - if ( (querytype == 0 && cnt == descridx) || - ((querytype == 1 || querytype == 2) && cnt != -1) ) + if ( (querytype == 0 && cnt == descr.size()) || + ((querytype > 0) && cnt != 0) ) { const uniqueEPGKey &service = cit->first; - eServiceReference ref = - eDVBDB::getInstance()->searchReference(service.tsid, service.onid, service.sid); - if (ref.valid()) + std::vector refs; + eDVBDB::getInstance()->searchAllReferences(refs, service.tsid, service.onid, service.sid); + for (unsigned int i = 0; i < refs.size(); i++) { - // create servive event - eServiceEvent ptr; - const eventData *ev_data=0; - if (needServiceEvent) + eServiceReference ref = refs[i]; + if (ref.valid()) { - if (lookupEventId(ref, evid, ev_data)) - eDebug("event not found !!!!!!!!!!!"); - else + ePyObject service_name; + ePyObject service_reference; + // create servive event + eServiceEvent ptr; + const eventData *ev_data=0; + if (needServiceEvent) { - const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref; - Event ev((uint8_t*)ev_data->get()); - ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get()); + if (lookupEventId(ref, evit->second->getEventID(), ev_data)) + eDebug("[eEPGCache] event not found !!!!!!!!!!!"); + else + { + const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref; + Event ev((uint8_t*)ev_data->get()); + ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get()); + } } - } - // create service name - if (must_get_service_name && !service_name) - { - ePtr sptr; - eServiceCenterPtr service_center; - eServiceCenter::getPrivInstance(service_center); - if (service_center) + // create service name + if (must_get_service_name && !service_name) { - service_center->info(ref, sptr); - if (sptr) + ePtr sptr; + eServiceCenterPtr service_center; + eServiceCenter::getPrivInstance(service_center); + if (service_center) { - std::string name; - sptr->getName(ref, name); - - if (must_get_service_name == 1) + service_center->info(ref, sptr); + if (sptr) { - size_t pos; - // filter short name brakets - while((pos = name.find("\xc2\x86")) != std::string::npos) - name.erase(pos,2); - while((pos = name.find("\xc2\x87")) != std::string::npos) - name.erase(pos,2); - } - else - name = buildShortName(name); + std::string name; + sptr->getName(ref, name); - if (name.length()) - service_name = PyString_FromString(name.c_str()); + if (must_get_service_name == 1) + { + size_t pos; + // filter short name brakets + while((pos = name.find("\xc2\x86")) != std::string::npos) + name.erase(pos,2); + while((pos = name.find("\xc2\x87")) != std::string::npos) + name.erase(pos,2); + } + else + name = buildShortName(name); + + if (name.length()) + service_name = PyString_FromString(name.c_str()); + } } + if (!service_name) + service_name = PyString_FromString(""); } - if (!service_name) - service_name = PyString_FromString(""); + // create servicereference string + if (must_get_service_reference && !service_reference) + service_reference = PyString_FromString(ref.toString().c_str()); + // create list + if (!ret) + ret = PyList_New(0); + // create tuple + ePyObject tuple = PyTuple_New(argcount); + // fill tuple + ePyObject tmp = ePyObject(); + fillTuple(tuple, argstring, argcount, service_reference, ev_data ? &ptr : 0, service_name, tmp, evit->second); + PyList_Append(ret, tuple); + Py_DECREF(tuple); + if (service_name) + Py_DECREF(service_name); + if (service_reference) + Py_DECREF(service_reference); + --maxcount; } - // create servicereference string - if (must_get_service_reference && !service_reference) - service_reference = PyString_FromString(ref.toString().c_str()); - // create list - if (!ret) - ret = PyList_New(0); - // create tuple - ePyObject tuple = PyTuple_New(argcount); - // fill tuple - fillTuple2(tuple, argstring, argcount, evit->second, ev_data ? &ptr : 0, service_name, service_reference); - PyList_Append(ret, tuple); - Py_DECREF(tuple); - --maxcount; } } } - if (service_name) - Py_DECREF(service_name); - if (service_reference) - Py_DECREF(service_reference); if (first) { // now start at first service in epgcache database ( only in SIMILAR BROADCASTING SEARCH ) @@ -2576,11 +3412,11 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler) switch ((*desc)->getTag()) { case 0xC2: // user defined - if ((*desc)->getLength() == 8) + if ((*desc)->getLength() == 8) { - __u8 buffer[10]; + uint8_t buffer[10]; (*desc)->writeToBuffer(buffer); - if (!strncmp((const char *)buffer+2, "EPGDATA", 7)) + if (!memcmp((const char *)buffer+2, "EPGDATA", 7)) { eServiceReferenceDVB ref; if (!pmthandler->getServiceReference(ref)) @@ -2589,7 +3425,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler) messages.send(Message(Message::got_mhw2_channel_pid, ref, pid)); } } - else if(!strncmp((const char *)buffer+2, "FICHAS", 6)) + else if(!memcmp((const char *)buffer+2, "FICHAS", 6)) { eServiceReferenceDVB ref; if (!pmthandler->getServiceReference(ref)) @@ -2598,7 +3434,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler) messages.send(Message(Message::got_mhw2_summary_pid, ref, pid)); } } - else if(!strncmp((const char *)buffer+2, "GENEROS", 7)) + else if(!memcmp((const char *)buffer+2, "GENEROS", 7)) { eServiceReferenceDVB ref; if (!pmthandler->getServiceReference(ref)) @@ -2625,7 +3461,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler) break; case 0x90: { - UnknownDescriptor *descr = (UnknownDescriptor*)*desc; + Descriptor *descr = (Descriptor*)*desc; int descr_len = descr->getLength(); if (descr_len == 4) { @@ -2657,27 +3493,27 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler) } } else - eDebug("PMTready but no pmt!!"); + eDebug("[eEPGCache] PMTready but no pmt!!"); } struct date_time { - __u8 data[5]; + uint8_t data[5]; time_t tm; date_time( const date_time &a ) { memcpy(data, a.data, 5); tm = a.tm; } - date_time( const __u8 data[5]) + date_time( const uint8_t data[5]) { memcpy(this->data, data, 5); - tm = parseDVBtime(data[0], data[1], data[2], data[3], data[4]); + tm = parseDVBtime(data); } date_time() { } - const __u8& operator[](int pos) const + const uint8_t& operator[](int pos) const { return data[pos]; } @@ -2691,42 +3527,44 @@ struct less_datetime } }; -void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __u8 *data) +void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const uint8_t *data) { contentMap &content_time_table = content_time_tables[current_service]; singleLock s(cache_lock); std::map< date_time, std::list, less_datetime > start_times; - eventMap &evMap = eventDB[current_service].first; - timeMap &tmMap = eventDB[current_service].second; - int ptr=8; + EventCacheItem &eventDBitem = eventDB[current_service]; + eventMap &evMap = eventDBitem.byEvent; + timeMap &tmMap = eventDBitem.byTime; + int ptr = 8; int content_id = data[ptr++] << 24; content_id |= data[ptr++] << 16; content_id |= data[ptr++] << 8; content_id |= data[ptr++]; - contentTimeMap &time_event_map = - content_time_table[content_id]; + contentTimeMap &time_event_map = content_time_table[content_id]; for ( contentTimeMap::iterator it( time_event_map.begin() ); it != time_event_map.end(); ++it ) { eventMap::iterator evIt( evMap.find(it->second.second) ); if ( evIt != evMap.end() ) { + // time_event_map can have other timestamp -> get timestamp from eventData + time_t ev_time = evIt->second->getStartTime(); delete evIt->second; evMap.erase(evIt); + tmMap.erase(ev_time); } - tmMap.erase(it->second.first); } time_event_map.clear(); - __u8 duration[3]; + uint8_t duration[3]; memcpy(duration, data+ptr, 3); ptr+=3; int duration_sec = fromBCD(duration[0])*3600+fromBCD(duration[1])*60+fromBCD(duration[2]); - const __u8 *descriptors[65]; - const __u8 **pdescr = descriptors; + const uint8_t *descriptors[65]; + const uint8_t **pdescr = descriptors; int descriptors_length = (data[ptr++]&0x0F) << 8; descriptors_length |= data[ptr++]; @@ -2768,7 +3606,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ descr_len -= 6; while( descr_len > 2 ) { - __u8 datetime[5]; + uint8_t datetime[5]; datetime[0] = data[ptr++]; datetime[1] = data[ptr++]; int tmp_len = data[ptr++]; @@ -2795,13 +3633,13 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ } } ASSERT(pdescr <= &descriptors[65]); - __u8 event[4098]; + uint8_t event[4098]; eit_event_struct *ev_struct = (eit_event_struct*) event; ev_struct->running_status = 0; ev_struct->free_CA_mode = 1; memcpy(event+7, duration, 3); ptr = 12; - const __u8 **d=descriptors; + const uint8_t **d=descriptors; while ( d < pdescr ) { memcpy(event+ptr, *d, ((*d)[1])+2); @@ -2820,7 +3658,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ for (std::list::iterator i(it->second.begin()); i != it->second.end(); ++i) { event[bptr++] = 0x4A; - __u8 *len = event+(bptr++); + uint8_t *len = event+(bptr++); event[bptr++] = (i->tsid & 0xFF00) >> 8; event[bptr++] = (i->tsid & 0xFF); event[bptr++] = (i->onid & 0xFF00) >> 8; @@ -2839,12 +3677,12 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ while( tmMap.find(stime) != tmMap.end() ) ++stime; event[6] += (stime - it->first.tm); - __u16 event_id = 0; + uint16_t event_id = 0; while( evMap.find(event_id) != evMap.end() ) ++event_id; event[0] = (event_id & 0xFF00) >> 8; event[1] = (event_id & 0xFF); - time_event_map[it->first.tm]=std::pair(stime, event_id); + time_event_map[it->first.tm]=std::pair(stime, event_id); eventData *d = new eventData( ev_struct, bptr, PRIVATE ); evMap[event_id] = d; tmMap[stime] = d; @@ -2860,7 +3698,7 @@ void eEPGCache::channel_data::startPrivateReader() mask.flags = eDVBSectionFilterMask::rfCRC; mask.data[0] = 0xA0; mask.mask[0] = 0xFF; - eDebug("[EPGC] start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion); + eDebug("[eEPGCache] start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion); if (m_PrevVersion != -1) { mask.data[3] = m_PrevVersion << 1; @@ -2873,7 +3711,7 @@ void eEPGCache::channel_data::startPrivateReader() m_PrivateReader->start(mask); } -void eEPGCache::channel_data::readPrivateData( const __u8 *data) +void eEPGCache::channel_data::readPrivateData( const uint8_t *data) { if ( seenPrivateSections.find(data[6]) == seenPrivateSections.end() ) { @@ -2882,7 +3720,7 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data) } if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) ) { - eDebug("[EPGC] private finished"); + eDebug("[eEPGCache] private finished"); eDVBChannelID chid = channel->getChannelID(); int tmp = chid.original_network_id.get(); tmp |= 0x80000000; // we use highest bit as private epg indicator @@ -2896,15 +3734,16 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data) #endif // ENABLE_PRIVATE_EPG #ifdef ENABLE_MHW_EPG -void eEPGCache::channel_data::cleanup() +void eEPGCache::channel_data::cleanupMHW() { + m_MHWTimeoutTimer->stop(); m_channels.clear(); m_themes.clear(); m_titles.clear(); m_program_ids.clear(); } -__u8 *eEPGCache::channel_data::delimitName( __u8 *in, __u8 *out, int len_in ) +uint8_t *eEPGCache::channel_data::delimitName( uint8_t *in, uint8_t *out, int len_in ) { // Names in mhw structs are not strings as they are not '\0' terminated. // This function converts the mhw name into a string. @@ -2939,7 +3778,7 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu { char tz_saved[1024]; // Remove offset in mhw time. - __u8 local_hours = hours; + uint8_t local_hours = hours; if ( hours >= 16 ) local_hours -= 4; else if ( hours >= 8 ) @@ -2952,7 +3791,7 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu char *old_tz = getenv( "TZ" ); if (old_tz) strcpy(tz_saved, old_tz); - putenv("TZ=CET-1CEST,M3.5.0/2,M10.5.0/3"); + putenv((char*)"TZ=CET-1CEST,M3.5.0/2,M10.5.0/3"); tzset(); tm localnow; @@ -2990,10 +3829,10 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu timeMHW2DVB( recdate.tm_hour, minutes, return_time+2 ); } -void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, std::string sumText, const __u8 *data) +void eEPGCache::channel_data::storeMHWTitle(std::map::iterator itTitle, std::string sumText, const uint8_t *data) // data is borrowed from calling proc to save memory space. { - __u8 name[34]; + uint8_t name[34]; // For each title a separate EIT packet will be sent to eEPGCache::sectionRead() bool isMHW2 = itTitle->second.mhw2_mjd_hi || itTitle->second.mhw2_mjd_lo || @@ -3016,7 +3855,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment packet->segment_last_table_id = 0x50; - __u8 *title = isMHW2 ? ((__u8*)(itTitle->second.title))-4 : (__u8*)itTitle->second.title; + uint8_t *title = isMHW2 ? ((uint8_t*)(itTitle->second.title))-4 : (uint8_t*)itTitle->second.title; std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 35 : 23 ); int prog_title_length = prog_title.length(); @@ -3035,13 +3874,13 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator data[4] = itTitle->second.mhw2_hours; data[5] = itTitle->second.mhw2_minutes; data[6] = itTitle->second.mhw2_seconds; - timeMHW2DVB( HILO(itTitle->second.mhw2_duration), data+7 ); + timeMHW2DVB( itTitle->second.getMhw2Duration(), data+7 ); } else { timeMHW2DVB( itTitle->second.dh.day, itTitle->second.dh.hours, itTitle->second.ms.minutes, (u_char *) event_data + 2 ); - timeMHW2DVB( HILO(itTitle->second.duration), (u_char *) event_data+7 ); + timeMHW2DVB( itTitle->second.getDuration(), (u_char *) event_data+7 ); } event_data->running_status = 0; @@ -3136,21 +3975,21 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator cache->sectionRead( data, MHW, this ); } -void eEPGCache::channel_data::startTimeout(int msec) +void eEPGCache::channel_data::startMHWTimeout(int msec) { m_MHWTimeoutTimer->start(msec,true); m_MHWTimeoutet=false; } -void eEPGCache::channel_data::startMHWReader(__u16 pid, __u8 tid) +void eEPGCache::channel_data::startMHWReader(uint16_t pid, uint8_t tid) { m_MHWFilterMask.pid = pid; m_MHWFilterMask.data[0] = tid; m_MHWReader->start(m_MHWFilterMask); -// eDebug("start 0x%02x 0x%02x", pid, tid); +// eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid); } -void eEPGCache::channel_data::startMHWReader2(__u16 pid, __u8 tid, int ext) +void eEPGCache::channel_data::startMHWReader2(uint16_t pid, uint8_t tid, int ext) { m_MHWFilterMask2.pid = pid; m_MHWFilterMask2.data[0] = tid; @@ -3158,18 +3997,18 @@ void eEPGCache::channel_data::startMHWReader2(__u16 pid, __u8 tid, int ext) { m_MHWFilterMask2.data[1] = ext; m_MHWFilterMask2.mask[1] = 0xFF; -// eDebug("start 0x%03x 0x%02x 0x%02x", pid, tid, ext); +// eDebug("[eEPGCache] start 0x%03x 0x%02x 0x%02x", pid, tid, ext); } else { m_MHWFilterMask2.data[1] = 0; m_MHWFilterMask2.mask[1] = 0; -// eDebug("start 0x%02x 0x%02x", pid, tid); +// eDebug("[eEPGCache] start 0x%02x 0x%02x", pid, tid); } m_MHWReader2->start(m_MHWFilterMask2); } -void eEPGCache::channel_data::readMHWData(const __u8 *data) +void eEPGCache::channel_data::readMHWData(const uint8_t *data) { if ( m_MHWReader2 ) m_MHWReader2->stop(); @@ -3178,7 +4017,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) // have si data.. so we dont read mhw data (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) ) { - eDebug("[EPGC] mhw aborted %d", state); + eDebug("[eEPGCache] mhw aborted %d", state); } else if (m_MHWFilterMask.pid == 0xD3 && m_MHWFilterMask.data[0] == 0x91) // Channels table @@ -3195,7 +4034,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) } haveData |= MHW; - eDebug("[EPGC] mhw %d channels found", m_channels.size()); + eDebug("[eEPGCache] mhw %d channels found", m_channels.size()); // Channels table has been read, start reading the themes table. startMHWReader(0xD3, 0x92); @@ -3208,9 +4047,9 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) int record_size = sizeof( mhw_theme_name_t ); int nbr_records = int (len/record_size); int idx_ptr = 0; - __u8 next_idx = (__u8) *(data + 3 + idx_ptr); - __u8 idx = 0; - __u8 sub_idx = 0; + uint8_t next_idx = (uint8_t) *(data + 3 + idx_ptr); + uint8_t idx = 0; + uint8_t sub_idx = 0; for ( int i = 0; i < nbr_records; i++ ) { mhw_theme_name_t *theme = (mhw_theme_name_t*) &data[19 + i*record_size]; @@ -3218,7 +4057,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) { idx = (idx_ptr<<4); idx_ptr++; - next_idx = (__u8) *(data + 3 + idx_ptr); + next_idx = (uint8_t) *(data + 3 + idx_ptr); sub_idx = 0; } else @@ -3226,30 +4065,32 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) m_themes[idx+sub_idx] = *theme; } - eDebug("[EPGC] mhw %d themes found", m_themes.size()); + eDebug("[eEPGCache] mhw %d themes found", m_themes.size()); // Themes table has been read, start reading the titles table. startMHWReader(0xD2, 0x90); - startTimeout(4000); + startMHWTimeout(4000); return; } else if (m_MHWFilterMask.pid == 0xD2 && m_MHWFilterMask.data[0] == 0x90) // Titles table { mhw_title_t *title = (mhw_title_t*) data; + uint8_t name[24]; + std::string prog_title = (char *) delimitName( title->title, name, 23 ); - if ( title->channel_id == 0xFF ) // Separator + if ( title->channel_id == 0xFF || prog_title.substr(0,7) == "BIENTOT" ) // Separator or BIENTOT record return; // Continue reading of the current table. else { // Create unique key per title - __u32 title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)| + uint32_t title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)| (title->ms.minutes); - __u32 program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)| + uint32_t program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)| ((title->program_id_ml)<<8)|(title->program_id_lo); if ( m_titles.find( title_id ) == m_titles.end() ) { - startTimeout(4000); + startMHWTimeout(4000); title->mhw2_mjd_hi = 0; title->mhw2_mjd_lo = 0; title->mhw2_duration_hi = 0; @@ -3257,10 +4098,10 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) m_titles[ title_id ] = *title; if ( (title->ms.summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) ) // program_ids will be used to gather summaries. - m_program_ids.insert(std::pair<__u32,__u32>(program_id,title_id)); + m_program_ids.insert(std::pair(program_id,title_id)); return; // Continue reading of the current table. } - else if (!checkTimeout()) + else if (!checkMHWTimeout()) return; } if ( !m_program_ids.empty()) @@ -3268,10 +4109,10 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) // Titles table has been read, there are summaries to read. // Start reading summaries, store corresponding titles on the fly. startMHWReader(0xD3, 0x90); - eDebug("[EPGC] mhw %d titles(%d with summary) found", + eDebug("[eEPGCache] mhw %d titles(%d with summary) found", m_titles.size(), m_program_ids.size()); - startTimeout(4000); + startMHWTimeout(4000); return; } } @@ -3281,20 +4122,20 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) mhw_summary_t *summary = (mhw_summary_t*) data; // Create unique key per record - __u32 program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)| + uint32_t program_id = ((summary->program_id_hi)<<24)|((summary->program_id_mh)<<16)| ((summary->program_id_ml)<<8)|(summary->program_id_lo); int len = ((data[1]&0xf)<<8) + data[2]; - // ugly workaround to convert const __u8* to char* + // ugly workaround to convert const uint8_t* to char* char *tmp=0; memcpy(&tmp, &data, sizeof(void*)); tmp[len+3] = 0; // Terminate as a string. - std::multimap<__u32, __u32>::iterator itProgid( m_program_ids.find( program_id ) ); + std::multimap::iterator itProgid( m_program_ids.find( program_id ) ); if ( itProgid == m_program_ids.end() ) { /* This part is to prevent to looping forever if some summaries are not received yet. There is a timeout of 4 sec. after the last successfully read summary. */ - if (!m_program_ids.empty() && !checkTimeout()) + if (!m_program_ids.empty() && !checkMHWTimeout()) return; // Continue reading of the current table. } else @@ -3306,11 +4147,11 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) the_text.replace(pos, 2, " "); // Find corresponding title, store title and summary in epgcache. - std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgid->second ) ); + std::map::iterator itTitle( m_titles.find( itProgid->second ) ); if ( itTitle != m_titles.end() ) { - startTimeout(4000); - storeTitle( itTitle, the_text, data ); + startMHWTimeout(4000); + storeMHWTitle( itTitle, the_text, data ); m_titles.erase( itTitle ); } m_program_ids.erase( itProgid ); @@ -3318,13 +4159,13 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) return; // Continue reading of the current table. } } - eDebug("[EPGC] mhw finished(%ld) %d summaries not found", + eDebug("[eEPGCache] mhw finished(%ld) %d summaries not found", ::time(0), m_program_ids.size()); // Summaries have been read, titles that have summaries have been stored. // Now store titles that do not have summaries. - for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++) - storeTitle( itTitle, "", data ); + for (std::map::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++) + storeMHWTitle( itTitle, "", data ); isRunning &= ~MHW; m_MHWConn=0; if ( m_MHWReader ) @@ -3333,7 +4174,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) finishEPG(); } -void eEPGCache::channel_data::readMHWData2(const __u8 *data) +void eEPGCache::channel_data::readMHWData2(const uint8_t *data) { int dataLen = (((data[1]&0xf) << 8) | data[2]) + 3; @@ -3344,7 +4185,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) // have si data.. so we dont read mhw data (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) ) { - eDebug("[EPGC] mhw2 aborted %d", state); + eDebug("[eEPGCache] mhw2 aborted %d", state); } else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0) // Channels table @@ -3369,7 +4210,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) else goto abort; // data seems consistent... - const __u8 *tmp = data+121; + const uint8_t *tmp = data+121; for (int i=0; i < num_channels; ++i) { mhw_channel_name_t channel; @@ -3380,7 +4221,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) channel.channel_id_hi = *(tmp++); channel.channel_id_lo = *(tmp++); m_channels[i]=channel; -// eDebug("%d(%02x) %04x: %02x %02x", i, i, (channel.channel_id_hi << 8) | channel.channel_id_lo, *tmp, *(tmp+1)); +// eDebug("[eEPGCache] %d(%02x) %04x: %02x %02x", i, i, (channel.channel_id_hi << 8) | channel.channel_id_lo, *tmp, *(tmp+1)); tmp+=2; } for (int i=0; i < num_channels; ++i) @@ -3391,15 +4232,15 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) for (; x < channel_name_len; ++x) channel.name[x]=*(tmp++); channel.name[x+1]=0; -// eDebug("%d(%02x) %s", i, i, channel.name); +// eDebug("[eEPGCache] %d(%02x) %s", i, i, channel.name); } haveData |= MHW; - eDebug("[EPGC] mhw2 %d channels found", m_channels.size()); + eDebug("[eEPGCache] mhw2 %d channels found", m_channels.size()); } else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1) { // Themes table - eDebug("[EPGC] mhw2 themes nyi"); + eDebug("[eEPGCache] mhw2 themes nyi"); } else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6) // Titles table @@ -3408,7 +4249,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) bool valid=false; bool finish=false; -// eDebug("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", +// eDebug("[eEPGCache] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", // data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], // data[11], data[12], data[13], data[14], data[15], data[16], data[17] ); @@ -3423,11 +4264,11 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) if (!valid) { if (dataLen > 18) - eDebug("mhw2 title table invalid!!"); - if (checkTimeout()) + eDebug("[eEPGCache] mhw2 title table invalid!!"); + if (checkMHWTimeout()) goto abort; if (!m_MHWTimeoutTimer->isActive()) - startTimeout(5000); + startMHWTimeout(5000); return; // continue reading } @@ -3436,7 +4277,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) pos = 18; while (pos < dataLen) { -// eDebugNoNewLine(" [%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x [%02x %02x %02x %02x %02x %02x %02x] LL - DESCR - ", +// eDebugNoNewLine("[eEPGCache] [%02x] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x [%02x %02x %02x %02x %02x %02x %02x] LL - DESCR - ", // data[pos], data[pos+1], data[pos+2], data[pos+3], data[pos+4], data[pos+5], data[pos+6], data[pos+7], // data[pos+8], data[pos+9], data[pos+10], data[pos+11], data[pos+12], data[pos+13], data[pos+14], data[pos+15], data[pos+16], data[pos+17]); title.channel_id = data[pos]+1; @@ -3450,37 +4291,37 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) title.mhw2_duration_lo = duration&0xFF; // Create unique key per title - __u32 title_id = (data[pos+7] << 24) | (data[pos+8] << 16) | (data[pos+9] << 8) | data[pos+10]; + uint32_t title_id = (data[pos+7] << 24) | (data[pos+8] << 16) | (data[pos+9] << 8) | data[pos+10]; - __u8 slen = data[pos+18] & 0x3f; - __u8 *dest = ((__u8*)title.title)-4; + uint8_t slen = data[pos+18] & 0x3f; + uint8_t *dest = ((uint8_t*)title.title)-4; memcpy(dest, &data[pos+19], slen>35 ? 35 : slen); memset(dest+slen, 0, 35-slen); pos += 19 + slen; // eDebug("%02x [%02x %02x]: %s", data[pos], data[pos+1], data[pos+2], dest); // not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f); - __u32 summary_id = (data[pos+1] << 8) | data[pos+2]; + uint32_t summary_id = (data[pos+1] << 8) | data[pos+2]; // if (title.channel_id > m_channels.size()) -// eDebug("channel_id(%d %02x) to big!!", title.channel_id); +// eDebug("[eEPGCache] channel_id(%d %02x) to big!!", title.channel_id); -// eDebug("pos %d prog_id %02x %02x chid %02x summary_id %04x dest %p len %d\n", +// eDebug("[eEPGCache] pos %d prog_id %02x %02x chid %02x summary_id %04x dest %p len %d\n", // pos, title.program_id_ml, title.program_id_lo, title.channel_id, summary_id, dest, slen); -// eDebug("title_id %08x -> summary_id %04x\n", title_id, summary_id); +// eDebug("[eEPGCache] title_id %08x -> summary_id %04x\n", title_id, summary_id); pos += 3; - std::map<__u32, mhw_title_t>::iterator it = m_titles.find( title_id ); + std::map::iterator it = m_titles.find( title_id ); if ( it == m_titles.end() ) { - startTimeout(5000); + startMHWTimeout(5000); m_titles[ title_id ] = title; if (summary_id != 0xFFFF) { bool add=true; - std::multimap<__u32, __u32>::iterator it(m_program_ids.lower_bound(summary_id)); + std::multimap::iterator it(m_program_ids.lower_bound(summary_id)); while (it != m_program_ids.end() && it->first == summary_id) { if (it->second == title_id) { @@ -3490,27 +4331,26 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) ++it; } if (add) - m_program_ids.insert(std::pair<__u32,__u32>(summary_id,title_id)); + m_program_ids.insert(std::pair(summary_id,title_id)); } } else { - if ( !checkTimeout() ) + if ( !checkMHWTimeout() ) continue; // Continue reading of the current table. finish=true; break; } } -start_summary: if (finish) { - eDebug("[EPGC] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size()); + eDebug("[eEPGCache] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size()); if (!m_program_ids.empty()) { // Titles table has been read, there are summaries to read. // Start reading summaries, store corresponding titles on the fly. startMHWReader2(m_mhw2_summary_pid, 0x96); - startTimeout(15000); + startMHWTimeout(15000); return; } } @@ -3520,7 +4360,7 @@ start_summary: else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96) // Summaries table { - if (!checkTimeout()) + if (!checkMHWTimeout()) { int len, loop, pos, lenline; bool valid; @@ -3555,11 +4395,11 @@ start_summary: if (valid) { // data seems consistent... - __u32 summary_id = (data[3]<<8)|data[4]; -// eDebug ("summary id %04x\n", summary_id); -// eDebug("[%02x %02x] %02x %02x %02x %02x %02x %02x %02x %02x XX\n", data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13] ); + uint32_t summary_id = (data[3]<<8)|data[4]; +// eDebug ("[eEPGCache] summary id %04x\n", summary_id); +// eDebug("[eEPGCache] [%02x %02x] %02x %02x %02x %02x %02x %02x %02x %02x XX\n", data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13] ); - // ugly workaround to convert const __u8* to char* + // ugly workaround to convert const uint8_t* to char* char *tmp=0; memcpy(&tmp, &data, sizeof(void*)); @@ -3579,7 +4419,7 @@ start_summary: else tmp[pos+1] = 0; - std::multimap<__u32, __u32>::iterator itProgId( m_program_ids.lower_bound(summary_id) ); + std::multimap::iterator itProgId( m_program_ids.lower_bound(summary_id) ); if ( itProgId == m_program_ids.end() || itProgId->first != summary_id) { /* This part is to prevent to looping forever if some summaries are not received yet. There is a timeout of 4 sec. after the last successfully read summary. */ @@ -3588,19 +4428,19 @@ start_summary: } else { - startTimeout(15000); + startMHWTimeout(15000); std::string the_text = (char *) (data + pos + 1); -// eDebug ("summary id %04x : %s\n", summary_id, data+pos+1); +// eDebug ("[eEPGCache] summary id %04x : %s\n", summary_id, data+pos+1); while( itProgId != m_program_ids.end() && itProgId->first == summary_id ) { -// eDebug("."); +// eDebug("[eEPGCache] ."); // Find corresponding title, store title and summary in epgcache. - std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) ); + std::map::iterator itTitle( m_titles.find( itProgId->second ) ); if ( itTitle != m_titles.end() ) { - storeTitle( itTitle, the_text, data ); + storeMHWTitle( itTitle, the_text, data ); m_titles.erase( itTitle ); } m_program_ids.erase( itProgId++ ); @@ -3631,9 +4471,9 @@ start_summary: { // Summaries have been read, titles that have summaries have been stored. // Now store titles that do not have summaries. - for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++) - storeTitle( itTitle, "", data ); - eDebug("[EPGC] mhw2 finished(%ld) %d summaries not found", + for (std::map::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++) + storeMHWTitle( itTitle, "", data ); + eDebug("[eEPGCache] mhw2 finished(%ld) %d summaries not found", ::time(0), m_program_ids.size()); }