X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/a9fc8426e77d7e07cbbfdc4fc5a9aec211134d7c..7709c1d61e799fa06a257f1d6b9c23ae205fe0c9:/lib/dvb/epgcache.cpp diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp index 8cdfa0c9..2b688c29 100644 --- a/lib/dvb/epgcache.cpp +++ b/lib/dvb/epgcache.cpp @@ -213,13 +213,13 @@ pthread_mutex_t eEPGCache::channel_map_lock= DEFINE_REF(eEPGCache) eEPGCache::eEPGCache() - :messages(this,1), cleanTimer(this)//, paused(0) + :messages(this,1), cleanTimer(eTimer::create(this))//, paused(0) { eDebug("[EPGC] Initialized EPGCache"); CONNECT(messages.recv_msg, eEPGCache::gotMessage); CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated); - CONNECT(cleanTimer.timeout, eEPGCache::cleanLoop); + CONNECT(cleanTimer->timeout, eEPGCache::cleanLoop); ePtr res_mgr; eDVBResourceManager::getInstance(res_mgr); @@ -232,6 +232,30 @@ eEPGCache::eEPGCache() timeUpdated(); } instance=this; + + memset(m_filename, 0, sizeof(m_filename)); + + FILE *f = fopen("/etc/enigma2/epg.dat.src", "r"); + if (f) + { + int rd = fread(m_filename, 1, 255, f); + if (rd > 0) + { + m_filename[rd] = 0; + char *p=strchr(m_filename, '\n'); + if (p) + m_filename[p-m_filename] = 0; + p=strchr(m_filename, '\t'); + if (p) + m_filename[p-m_filename] = 0; + } + fclose(f); + } + + if (!strlen(m_filename)) + strcpy(m_filename, "/hdd/epg.dat"); + + eDebug("[EPGC] read/write epg data from/to '%s'", m_filename); } void eEPGCache::timeUpdated() @@ -254,6 +278,11 @@ void eEPGCache::DVBChannelAdded(eDVBChannel *chan) data->prevChannelState = -1; #ifdef ENABLE_PRIVATE_EPG data->m_PrivatePid = -1; +#endif +#ifdef ENABLE_MHW_EPG + data->m_mhw2_channel_pid = 0x231; // defaults for astra 19.2 D+ + data->m_mhw2_title_pid = 0x234; // defaults for astra 19.2 D+ + data->m_mhw2_summary_pid = 0x236; // defaults for astra 19.2 D+ #endif singleLock s(channel_map_lock); m_knownChannels.insert( std::pair(chan, data) ); @@ -303,6 +332,13 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan) eDebug("[eEPGCache] couldnt initialize schedule other reader!!"); return; } + + res = demux->createSectionReader( this, data.m_ViasatReader ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize viasat reader!!"); + return; + } #ifdef ENABLE_PRIVATE_EPG res = demux->createSectionReader( this, data.m_PrivateReader ); if ( res ) @@ -372,8 +408,9 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan) } } -void eEPGCache::FixOverlapping(std::pair &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service) +bool eEPGCache::FixOverlapping(std::pair &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) { @@ -406,6 +443,7 @@ void eEPGCache::FixOverlapping(std::pair &servicemap, time_t T } else servicemap.second.erase(tmp--); + ret = true; } else { @@ -434,12 +472,14 @@ void eEPGCache::FixOverlapping(std::pair &servicemap, time_t T #endif delete tmp->second; servicemap.second.erase(tmp++); + ret = true; } else ++tmp; if (tmp == servicemap.second.end()) break; } + return ret; } void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) @@ -456,13 +496,25 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) if ( data[ptr-1] < 0x40 ) --ptr; - uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) ); + // 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)); + 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 now = eDVBLocalTimeHandler::getInstance()->nowTime(); + 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 now = ::time(0); if ( TM != 3599 && TM > -1) channel->haveData |= source; @@ -476,6 +528,7 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) while (ptrdescriptors_loop_length)+EIT_LOOP_SIZE; duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3); @@ -484,7 +537,8 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) eit_event->start_time_2, eit_event->start_time_3, eit_event->start_time_4, - eit_event->start_time_5); + eit_event->start_time_5, + &event_hash); if ( TM == 3599 ) goto next; @@ -495,16 +549,24 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ ) // old events should not be cached { __u16 event_id = HILO(eit_event->event_id); -// eDebug("event_id is %d sid is %04x", event_id, service.sid); - eventData *evt = 0; int ev_erase_count = 0; int tm_erase_count = 0; + if (event_id == 0) { + // hack for some polsat services on 13.0E..... but this also replaces other valid event_ids with value 0.. + // but we dont care about it... + event_id = event_hash; + eit_event->event_id_hi = event_hash >> 8; + eit_event->event_id_lo = event_hash & 0xFF; + } + // search in eventmap eventMap::iterator ev_it = servicemap.first.find(event_id); +// eDebug("event_id is %d sid is %04x", event_id, service.sid); + // entry with this event_id is already exist ? if ( ev_it != servicemap.first.end() ) { @@ -523,7 +585,11 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) eventData *tmp = ev_it->second; ev_it->second = tm_it_tmp->second = new eventData(eit_event, eit_event_size, source); - FixOverlapping(servicemap, TM, duration, tm_it_tmp, service); + if (FixOverlapping(servicemap, TM, duration, tm_it_tmp, service)) + { + prevEventIt = servicemap.first.end(); + prevTimeIt = servicemap.second.end(); + } delete tmp; goto next; } @@ -596,8 +662,6 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair( TM, evt ) ); } - FixOverlapping(servicemap, TM, duration, tm_it, service); - #ifdef EPG_DEBUG if ( consistencyCheck ) { @@ -617,6 +681,11 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) ev_it->first, event_id ); } #endif + if (FixOverlapping(servicemap, TM, duration, tm_it, service)) + { + prevEventIt = servicemap.first.end(); + prevTimeIt = servicemap.second.end(); + } } next: #ifdef EPG_DEBUG @@ -707,7 +776,7 @@ void eEPGCache::cleanLoop() { eDebug("[EPGC] start cleanloop"); - time_t now = eDVBLocalTimeHandler::getInstance()->nowTime(); + time_t now = ::time(0); for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++) { @@ -765,7 +834,7 @@ void eEPGCache::cleanLoop() eDebug("[EPGC] stop cleanloop"); eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize); } - cleanTimer.start(CLEAN_INTERVAL,true); + cleanTimer->start(CLEAN_INTERVAL,true); } eEPGCache::~eEPGCache() @@ -826,10 +895,10 @@ void eEPGCache::gotMessage( const Message &msg ) onid |= 0x80000000; // we use highest bit as private epg indicator chid.original_network_id = onid; updateMap::iterator It = channelLastUpdated.find( chid ); - int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY ); + int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY ); if (update < ZAP_DELAY) update = ZAP_DELAY; - data->startPrivateTimer.start(update, 1); + data->startPrivateTimer->start(update, 1); if (update >= 60000) eDebug("[EPGC] next private update in %i min", update/60000); else if (update >= 1000) @@ -839,6 +908,62 @@ void eEPGCache::gotMessage( const Message &msg ) } break; } +#endif +#ifdef ENABLE_MHW_EPG + case Message::got_mhw2_channel_pid: + { + singleLock s(channel_map_lock); + for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + { + eDVBChannel *channel = (eDVBChannel*) it->first; + channel_data *data = it->second; + eDVBChannelID chid = channel->getChannelID(); + if ( chid.transport_stream_id.get() == msg.service.tsid && + chid.original_network_id.get() == msg.service.onid ) + { + data->m_mhw2_channel_pid = msg.pid; + eDebug("[EPGC] got mhw2 channel pid %04x", msg.pid); + break; + } + } + break; + } + case Message::got_mhw2_title_pid: + { + singleLock s(channel_map_lock); + for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + { + eDVBChannel *channel = (eDVBChannel*) it->first; + channel_data *data = it->second; + eDVBChannelID chid = channel->getChannelID(); + if ( chid.transport_stream_id.get() == msg.service.tsid && + chid.original_network_id.get() == msg.service.onid ) + { + data->m_mhw2_title_pid = msg.pid; + eDebug("[EPGC] got mhw2 title pid %04x", msg.pid); + break; + } + } + break; + } + case Message::got_mhw2_summary_pid: + { + singleLock s(channel_map_lock); + for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it) + { + eDVBChannel *channel = (eDVBChannel*) it->first; + channel_data *data = it->second; + eDVBChannelID chid = channel->getChannelID(); + if ( chid.transport_stream_id.get() == msg.service.tsid && + chid.original_network_id.get() == msg.service.onid ) + { + data->m_mhw2_summary_pid = msg.pid; + eDebug("[EPGC] got mhw2 summary pid %04x", msg.pid); + break; + } + } + break; + } #endif case Message::timeChanged: cleanLoop(); @@ -861,30 +986,13 @@ void eEPGCache::thread() void eEPGCache::load() { - FILE *f = fopen("/hdd/epg.dat", "r"); + FILE *f = fopen(m_filename, "r"); if (f) { - unlink("/hdd/epg.dat"); + unlink(m_filename); int size=0; int cnt=0; -#if 0 - unsigned char md5_saved[16]; - unsigned char md5[16]; - bool md5ok=false; - if (!md5_file("/hdd/epg.dat", 1, md5)) - { - FILE *f = fopen("/hdd/epg.dat.md5", "r"); - if (f) - { - fread( md5_saved, 16, 1, f); - fclose(f); - if ( !memcmp(md5_saved, md5, 16) ) - md5ok=true; - } - } - if ( md5ok ) -#endif { unsigned int magic=0; fread( &magic, sizeof(int), 1, f); @@ -926,7 +1034,7 @@ void eEPGCache::load() eventDB[key]=std::pair(evMap,tmMap); } eventData::load(f); - eDebug("[EPGC] %d events read from /hdd/epg.dat", cnt); + eDebug("[EPGC] %d events read from %s", cnt, m_filename); #ifdef ENABLE_PRIVATE_EPG char text2[11]; fread( text2, 11, 1, f); @@ -974,9 +1082,15 @@ void eEPGCache::load() void eEPGCache::save() { + char *buf = realpath(m_filename, NULL); + if (!buf) + return; + + eDebug("[EPGC] store epg to '%s'", buf); + struct statfs s; off64_t tmp; - if (statfs("/hdd", &s)<0) + if (statfs(buf, &s)<0) tmp=0; else { @@ -984,6 +1098,8 @@ void eEPGCache::save() tmp*=s.f_bsize; } + free(buf); + // prevent writes to builtin flash if ( tmp < 1024*1024*50 ) // storage size < 50MB return; @@ -994,13 +1110,13 @@ void eEPGCache::save() if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead return; - FILE *f = fopen("/hdd/epg.dat", "w"); + FILE *f = fopen(m_filename, "w"); int cnt=0; if ( f ) { unsigned int magic = 0x98765432; fwrite( &magic, sizeof(int), 1, f); - const char *text = "ENIGMA_EPG_V7"; + const char *text = "UNFINISHED_V7"; fwrite( text, 13, 1, f ); int size = eventDB.size(); fwrite( &size, sizeof(int), 1, f ); @@ -1019,7 +1135,7 @@ void eEPGCache::save() ++cnt; } } - eDebug("[EPGC] %d events written to /hdd/epg.dat", cnt); + eDebug("[EPGC] %d events written to %s", cnt, m_filename); eventData::save(f); #ifdef ENABLE_PRIVATE_EPG const char* text3 = "PRIVATE_EPG"; @@ -1047,40 +1163,33 @@ void eEPGCache::save() } } #endif + // write version string after binary data + // has been written to disk. + fsync(fileno(f)); + fseek(f, sizeof(int), SEEK_SET); + fwrite("ENIGMA_EPG_V7", 13, 1, f); fclose(f); -#if 0 - unsigned char md5[16]; - if (!md5_file("/hdd/epg.dat", 1, md5)) - { - FILE *f = fopen("/hdd/epg.dat.md5", "w"); - if (f) - { - fwrite( md5, 16, 1, f); - fclose(f); - } - } -#endif } } eEPGCache::channel_data::channel_data(eEPGCache *ml) :cache(ml) - ,abortTimer(ml), zapTimer(ml), state(0) + ,abortTimer(eTimer::create(ml)), zapTimer(eTimer::create(ml)), state(0) ,isRunning(0), haveData(0) #ifdef ENABLE_PRIVATE_EPG - ,startPrivateTimer(ml) + ,startPrivateTimer(eTimer::create(ml)) #endif #ifdef ENABLE_MHW_EPG - ,m_MHWTimeoutTimer(ml) + ,m_MHWTimeoutTimer(eTimer::create(ml)) #endif { #ifdef ENABLE_MHW_EPG - CONNECT(m_MHWTimeoutTimer.timeout, eEPGCache::channel_data::MHWTimeout); + CONNECT(m_MHWTimeoutTimer->timeout, eEPGCache::channel_data::MHWTimeout); #endif - CONNECT(zapTimer.timeout, eEPGCache::channel_data::startEPG); - CONNECT(abortTimer.timeout, eEPGCache::channel_data::abortNonAvail); + CONNECT(zapTimer->timeout, eEPGCache::channel_data::startEPG); + CONNECT(abortTimer->timeout, eEPGCache::channel_data::abortNonAvail); #ifdef ENABLE_PRIVATE_EPG - CONNECT(startPrivateTimer.timeout, eEPGCache::channel_data::startPrivateReader); + CONNECT(startPrivateTimer->timeout, eEPGCache::channel_data::startPrivateReader); #endif pthread_mutex_init(&channel_active, 0); } @@ -1089,16 +1198,16 @@ bool eEPGCache::channel_data::finishEPG() { if (!isRunning) // epg ready { - eDebug("[EPGC] stop caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); - zapTimer.start(UPDATE_INTERVAL, 1); + eDebug("[EPGC] stop caching events(%ld)", ::time(0)); + zapTimer->start(UPDATE_INTERVAL, 1); eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000); - for (int i=0; i < 3; ++i) + 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()] = eDVBLocalTimeHandler::getInstance()->nowTime(); + cache->channelLastUpdated[channel->getChannelID()] = ::time(0); #ifdef ENABLE_MHW_EPG cleanup(); #endif @@ -1109,10 +1218,10 @@ bool eEPGCache::channel_data::finishEPG() void eEPGCache::channel_data::startEPG() { - eDebug("[EPGC] start caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); + eDebug("[EPGC] start caching events(%ld)", ::time(0)); state=0; haveData=0; - for (int i=0; i < 3; ++i) + for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i) { seenSections[i].clear(); calcedSections[i].clear(); @@ -1130,7 +1239,7 @@ void eEPGCache::channel_data::startEPG() isRunning |= MHW; memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask)); - mask.pid = 0x231; + mask.pid = m_mhw2_channel_pid; mask.data[0] = 0xC8; mask.mask[0] = 0xFF; mask.data[1] = 0; @@ -1141,6 +1250,7 @@ void eEPGCache::channel_data::startEPG() memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask)); mask.data[1] = 0; mask.mask[1] = 0; + m_MHWTimeoutet=false; #endif mask.pid = 0x12; @@ -1163,7 +1273,15 @@ void eEPGCache::channel_data::startEPG() m_ScheduleOtherReader->start(mask); isRunning |= SCHEDULE_OTHER; - abortTimer.start(7000,true); + 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; + + abortTimer->start(7000,true); } void eEPGCache::channel_data::abortNonAvail() @@ -1186,11 +1304,18 @@ void eEPGCache::channel_data::abortNonAvail() } if ( !(haveData&SCHEDULE_OTHER) && (isRunning&SCHEDULE_OTHER) ) { - eDebug("[EPGC] abort non avail schedule_other reading"); + eDebug("[EPGC] abort non avail schedule other reading"); isRunning &= ~SCHEDULE_OTHER; m_ScheduleOtherReader->stop(); m_ScheduleOtherConn=0; } + if ( !(haveData&VIASAT) && (isRunning&VIASAT) ) + { + eDebug("[EPGC] abort non avail viasat reading"); + isRunning &= ~VIASAT; + m_ViasatReader->stop(); + m_ViasatConn=0; + } #ifdef ENABLE_MHW_EPG if ( !(haveData&MHW) && (isRunning&MHW) ) { @@ -1202,12 +1327,14 @@ void eEPGCache::channel_data::abortNonAvail() m_MHWConn2=0; } #endif - if ( isRunning ) - abortTimer.start(90000, true); + if ( isRunning & VIASAT ) + abortTimer->start(300000, true); + else if ( isRunning ) + abortTimer->start(90000, true); else { ++state; - for (int i=0; i < 3; ++i) + for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i) { seenSections[i].clear(); calcedSections[i].clear(); @@ -1222,12 +1349,12 @@ void eEPGCache::channel_data::startChannel() pthread_mutex_lock(&channel_active); updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() ); - int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY ); + int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (::time(0)-It->second) * 1000 ) ) : ZAP_DELAY ); if (update < ZAP_DELAY) update = ZAP_DELAY; - zapTimer.start(update, 1); + zapTimer->start(update, 1); if (update >= 60000) eDebug("[EPGC] next update in %i min", update/60000); else if (update >= 1000) @@ -1236,13 +1363,13 @@ void eEPGCache::channel_data::startChannel() void eEPGCache::channel_data::abortEPG() { - for (int i=0; i < 3; ++i) + for (unsigned int i=0; i < sizeof(seenSections)/sizeof(tidMap); ++i) { seenSections[i].clear(); calcedSections[i].clear(); } - abortTimer.stop(); - zapTimer.stop(); + abortTimer->stop(); + zapTimer->stop(); if (isRunning) { eDebug("[EPGC] abort caching events !!"); @@ -1264,6 +1391,12 @@ void eEPGCache::channel_data::abortEPG() m_ScheduleOtherReader->stop(); m_ScheduleOtherConn=0; } + if (isRunning & VIASAT) + { + isRunning &= ~VIASAT; + m_ViasatReader->stop(); + m_ViasatConn=0; + } #ifdef ENABLE_MHW_EPG if (isRunning & MHW) { @@ -1284,6 +1417,15 @@ 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) { int source; @@ -1306,13 +1448,19 @@ void eEPGCache::channel_data::readData( const __u8 *data) source=SCHEDULE_OTHER; map=2; break; + case 0xD0 ... 0xDF: + case 0xE0 ... 0xEF: + reader=m_ViasatReader; + source=VIASAT; + map=3; + break; default: eDebug("[EPGC] unknown table_id !!!"); return; } tidMap &seenSections = this->seenSections[map]; tidMap &calcedSections = this->calcedSections[map]; - if ( state == 1 && calcedSections == seenSections || state > 1 ) + if ( (state == 1 && calcedSections == seenSections) || state > 1 ) { eDebugNoNewLine("[EPGC] "); switch (source) @@ -1329,9 +1477,13 @@ void eEPGCache::channel_data::readData( const __u8 *data) m_ScheduleOtherConn=0; eDebugNoNewLine("schedule other"); break; + case VIASAT: + m_ViasatConn=0; + eDebugNoNewLine("viasat"); + break; default: eDebugNoNewLine("unknown");break; } - eDebug(" finished(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); + eDebug(" finished(%ld)", ::time(0)); if ( reader ) reader->stop(); isRunning &= ~source; @@ -1381,7 +1533,7 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ? { if (t==-1) - t = eDVBLocalTimeHandler::getInstance()->nowTime(); + 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() ) @@ -1507,10 +1659,10 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes) { + singleLock s(cache_lock); const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service); if (begin == -1) - begin = eDVBLocalTimeHandler::getInstance()->nowTime(); - Lock(); + begin = ::time(0); eventCache::iterator It = eventDB.find(ref); if ( It != eventDB.end() && It->second.second.size() ) { @@ -1531,15 +1683,13 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, } if (minutes != -1) - m_timemap_end = It->second.second.upper_bound(begin+minutes*60); + m_timemap_end = It->second.second.lower_bound(begin+minutes*60); else m_timemap_end = It->second.second.end(); currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get(); - Unlock(); - return 0; + return m_timemap_cursor == m_timemap_end ? -1 : 0; } - Unlock(); return -1; } @@ -1584,14 +1734,15 @@ RESULT eEPGCache::getNextTimeEntry(ePtr &result) return -1; } -void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service, eServiceEvent *ptr, ePyObject nowTime, ePyObject service_name ) +void fillTuple(ePyObject tuple, const char *argstring, int argcount, ePyObject service, eServiceEvent *ptr, ePyObject nowTime, ePyObject service_name ) { ePyObject tmp; - int pos=0; - while(pos < argcount) + int spos=0, tpos=0; + char c; + while(spos < argcount) { bool inc_refcount=false; - switch(argstring[pos]) + switch((c=argstring[spos++])) { case '0': // PyLong 0 tmp = PyLong_FromLong(0); @@ -1626,6 +1777,13 @@ void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service case 'N': // service name tmp = service_name; inc_refcount = true; + break; + case 'X': + ++argcount; + continue; + default: // ignore unknown + tmp = ePyObject(); + eDebug("fillTuple unknown '%c'... insert 'None' in result", c); } if (!tmp) { @@ -1634,17 +1792,17 @@ void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service } if (inc_refcount) Py_INCREF(tmp); - PyTuple_SET_ITEM(tuple, pos++, tmp); + PyTuple_SET_ITEM(tuple, tpos++, tmp); } } -int handleEvent(eServiceEvent *ptr, ePyObject dest_list, char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs) +int handleEvent(eServiceEvent *ptr, ePyObject dest_list, const char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs) { if (convertFunc) { fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name); ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs); - if (result) + if (!result) { if (service_name) Py_DECREF(service_name); @@ -1683,6 +1841,9 @@ int handleEvent(eServiceEvent *ptr, ePyObject dest_list, char* argstring, int ar // R = Service Reference // N = Service Name // n = Short Service Name +// X = Return a minimum of one tuple per service in the result list... even when no event was found. +// The returned tuple is filled with all available infos... non avail is filled as None +// The position and existence of 'X' in the format string has no influence on the result tuple... its completely ignored.. // then for each service follows a tuple // first tuple entry is the servicereference (as string... use the ref.toString() function) // the second is the type of query @@ -1699,7 +1860,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) { ePyObject convertFuncArgs; int argcount=0; - char *argstring=NULL; + const char *argstring=NULL; if (!PyList_Check(list)) { PyErr_SetString(PyExc_StandardError, @@ -1729,6 +1890,11 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) argcount = strlen(argstring); // eDebug("have %d args('%s')", argcount, argstring); } + + bool forceReturnOne = strchr(argstring, 'X') ? true : false; + if (forceReturnOne) + --argcount; + if (convertFunc) { if (!PyCallable_Check(convertFunc)) @@ -1742,7 +1908,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) } ePyObject nowTime = strchr(argstring, 'C') ? - PyLong_FromLong(eDVBLocalTimeHandler::getInstance()->nowTime()) : + PyLong_FromLong(::time(0)) : ePyObject(); int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0; @@ -1798,7 +1964,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) } if (minutes && stime == -1) - stime = eDVBLocalTimeHandler::getInstance()->nowTime(); + stime = ::time(0); eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service)))); if (ref.type != eServiceReference::idDVB) @@ -1840,7 +2006,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) if (must_get_service_name == 1) { - unsigned int pos; + size_t pos; // filter short name brakets while((pos = name.find("\xc2\x86")) != std::string::npos) name.erase(pos,2); @@ -1859,7 +2025,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) } if (minutes) { - Lock(); + singleLock s(cache_lock); if (!startTimeQuery(ref, stime, minutes)) { while ( m_timemap_cursor != m_timemap_end ) @@ -1868,33 +2034,36 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) eServiceEvent evt; evt.parseFrom(&ev, currentQueryTsidOnid); if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) - { - Unlock(); return 0; // error - } } } - else - handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs); - Unlock(); + else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) + return 0; // error } else { eServiceEvent evt; - Event *ev=0; + const eventData *ev_data=0; if (stime) { + singleLock s(cache_lock); if (type == 2) - lookupEventId(ref, event_id, ev); + lookupEventId(ref, event_id, ev_data); else - lookupEventTime(ref, stime, ev, type); - if (ev) + lookupEventTime(ref, stime, ev_data, type); + if (ev_data) { const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref; - evt.parseFrom(ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get()); + Event ev((uint8_t*)ev_data->get()); + evt.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get()); } } - if (handleEvent(ev ? &evt : 0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) + if (ev_data) + { + if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) + return 0; // error + } + else if (forceReturnOne && handleEvent(0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) return 0; // error } if (service_changed) @@ -1957,6 +2126,9 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData tmp = service_name; inc_refcount = true; break; + default: // ignore unknown + tmp = ePyObject(); + eDebug("fillTuple2 unknown '%c'... insert None in Result", argstring[pos]); } if (!tmp) { @@ -2006,6 +2178,8 @@ PyObject *eEPGCache::search(ePyObject arg) int querytype=-1; bool needServiceEvent=false; int maxmatches=0; + int must_get_service_name = 0; + bool must_get_service_reference = false; if (PyTuple_Check(arg)) { @@ -2015,7 +2189,11 @@ PyObject *eEPGCache::search(ePyObject arg) ePyObject obj = PyTuple_GET_ITEM(arg,0); if (PyString_Check(obj)) { +#if PY_VERSION_HEX < 0x02060000 argcount = PyString_GET_SIZE(obj); +#else + argcount = PyString_Size(obj); +#endif argstring = PyString_AS_STRING(obj); for (int i=0; i < argcount; ++i) switch(argstring[i]) @@ -2024,6 +2202,16 @@ PyObject *eEPGCache::search(ePyObject arg) case 'E': case 'T': needServiceEvent=true; + break; + case 'N': + must_get_service_name = 1; + break; + case 'n': + must_get_service_name = 2; + break; + case 'R': + must_get_service_reference = true; + break; default: break; } @@ -2084,16 +2272,14 @@ PyObject *eEPGCache::search(ePyObject arg) } else { - PyErr_SetString(PyExc_StandardError, - "type error"); + PyErr_SetString(PyExc_StandardError, "type error"); eDebug("tuple arg 4 is not a valid service reference string"); return NULL; } } else { - PyErr_SetString(PyExc_StandardError, - "type error"); + PyErr_SetString(PyExc_StandardError, "type error"); eDebug("tuple arg 4 is not a string"); return NULL; } @@ -2105,7 +2291,11 @@ PyObject *eEPGCache::search(ePyObject arg) { int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4)); const char *str = PyString_AS_STRING(obj); +#if PY_VERSION_HEX < 0x02060000 int textlen = PyString_GET_SIZE(obj); +#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 @@ -2120,22 +2310,32 @@ PyObject *eEPGCache::search(ePyObject arg) int title_len = data[5]; if ( querytype == 1 ) { - if (title_len > textlen) - continue; - else if (title_len < textlen) + 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; + } + if (title_len != textlen) continue; if ( casetype ) { - if ( !strncasecmp((const char*)data+6, str, title_len) ) + if ( !strncasecmp((const char*)data+offs, str, title_len) ) { -// std::string s((const char*)data+6, title_len); +// std::string s((const char*)data+offs, title_len); // eDebug("match1 %s %s", str, s.c_str() ); descr[++descridx] = it->first; } } - else if ( !strncmp((const char*)data+6, str, title_len) ) + else if ( !strncmp((const char*)data+offs, str, title_len) ) { -// std::string s((const char*)data+6, title_len); +// std::string s((const char*)data+offs, title_len); // eDebug("match2 %s %s", str, s.c_str() ); descr[++descridx] = it->first; } @@ -2154,13 +2354,13 @@ PyObject *eEPGCache::search(ePyObject arg) // eDebug("match 3 %s %s", str, s.c_str() ); break; } - else if (!strncmp((const char*)data+6+idx, str, textlen) ) - { - descr[++descridx] = it->first; -// std::string s((const char*)data+6, title_len); -// eDebug("match 4 %s %s", str, s.c_str() ); - break; - } + } + else if (!strncmp((const char*)data+6+idx, str, textlen) ) + { + descr[++descridx] = it->first; +// std::string s((const char*)data+6, title_len); +// eDebug("match 4 %s %s", str, s.c_str() ); + break; } ++idx; } @@ -2251,56 +2451,53 @@ PyObject *eEPGCache::search(ePyObject arg) { // create servive event eServiceEvent ptr; - Event *ev=0; + const eventData *ev_data=0; if (needServiceEvent) { - if (lookupEventId(ref, evid, ev)) + if (lookupEventId(ref, evid, ev_data)) eDebug("event not found !!!!!!!!!!!"); else { const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref; - ptr.parseFrom(ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get()); + Event ev((uint8_t*)ev_data->get()); + ptr.parseFrom(&ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get()); } } // create service name - if (!service_name) + if (must_get_service_name && !service_name) { - int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0; - if (must_get_service_name) + ePtr sptr; + eServiceCenterPtr service_center; + eServiceCenter::getPrivInstance(service_center); + if (service_center) { - ePtr sptr; - eServiceCenterPtr service_center; - eServiceCenter::getPrivInstance(service_center); - if (service_center) + service_center->info(ref, sptr); + if (sptr) { - service_center->info(ref, sptr); - if (sptr) - { - std::string name; - sptr->getName(ref, name); + std::string name; + sptr->getName(ref, name); - if (must_get_service_name == 1) - { - unsigned int 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 (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 (!service_reference && strchr(argstring,'R')) + if (must_get_service_reference && !service_reference) service_reference = PyString_FromString(ref.toString().c_str()); // create list if (!ret) @@ -2308,7 +2505,7 @@ PyObject *eEPGCache::search(ePyObject arg) // create tuple ePyObject tuple = PyTuple_New(argcount); // fill tuple - fillTuple2(tuple, argstring, argcount, evit->second, ev ? &ptr : 0, service_name, service_reference); + fillTuple2(tuple, argstring, argcount, evit->second, ev_data ? &ptr : 0, service_name, service_reference); PyList_Append(ret, tuple); Py_DECREF(tuple); --maxcount; @@ -2357,6 +2554,50 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler) int tmp=0; switch ((*es)->getType()) { + case 0xC1: // user private + for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin(); + desc != (*es)->getDescriptors()->end(); ++desc) + { + switch ((*desc)->getTag()) + { + case 0xC2: // user defined + if ((*desc)->getLength() == 8) + { + __u8 buffer[10]; + (*desc)->writeToBuffer(buffer); + if (!strncmp((const char *)buffer+2, "EPGDATA", 7)) + { + eServiceReferenceDVB ref; + if (!pmthandler->getServiceReference(ref)) + { + int pid = (*es)->getPid(); + messages.send(Message(Message::got_mhw2_channel_pid, ref, pid)); + } + } + else if(!strncmp((const char *)buffer+2, "FICHAS", 6)) + { + eServiceReferenceDVB ref; + if (!pmthandler->getServiceReference(ref)) + { + int pid = (*es)->getPid(); + messages.send(Message(Message::got_mhw2_summary_pid, ref, pid)); + } + } + else if(!strncmp((const char *)buffer+2, "GENEROS", 7)) + { + eServiceReferenceDVB ref; + if (!pmthandler->getServiceReference(ref)) + { + int pid = (*es)->getPid(); + messages.send(Message(Message::got_mhw2_title_pid, ref, pid)); + } + } + } + break; + default: + break; + } + } case 0x05: // private for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin(); desc != (*es)->getDescriptors()->end(); ++desc) @@ -2492,7 +2733,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ int sid = data[ptr++] << 8; sid |= data[ptr++]; -// WORKAROUND for wrong transmitted epg data (01.08.2006) +// WORKAROUND for wrong transmitted epg data (01.10.2007) if ( onid == 0x85 ) { switch( (tsid << 16) | sid ) @@ -2503,6 +2744,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ case 0x0300f5: sid = 0xdc; break; case 0x0400d2: sid = 0xe2; tsid = 0x11; break; case 0x1100d3: sid = 0xe3; break; + case 0x0100d4: sid = 0xe4; tsid = 4; break; } } //////////////////////////////////////////// @@ -2537,7 +2779,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ } } } - ASSERT(pdescr <= &descriptors[65]) + ASSERT(pdescr <= &descriptors[65]); __u8 event[4098]; eit_event_struct *ev_struct = (eit_event_struct*) event; ev_struct->running_status = 0; @@ -2554,7 +2796,7 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ ASSERT(ptr <= 4098); for ( std::map< date_time, std::list >::iterator it(start_times.begin()); it != start_times.end(); ++it ) { - time_t now = eDVBLocalTimeHandler::getInstance()->nowTime(); + time_t now = ::time(0); if ( (it->first.tm + duration_sec) < now ) continue; memcpy(event+2, it->first.data, 5); @@ -2630,7 +2872,7 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data) int tmp = chid.original_network_id.get(); tmp |= 0x80000000; // we use highest bit as private epg indicator chid.original_network_id = tmp; - cache->channelLastUpdated[chid] = eDVBLocalTimeHandler::getInstance()->nowTime(); + cache->channelLastUpdated[chid] = ::time(0); m_PrevVersion = (data[5] & 0x3E) >> 1; startPrivateReader(); } @@ -2680,6 +2922,7 @@ void eEPGCache::channel_data::timeMHW2DVB( int minutes, u_char *return_time) void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time) // For date plus time of day { + char tz_saved[1024]; // Remove offset in mhw time. __u8 local_hours = hours; if ( hours >= 16 ) @@ -2689,9 +2932,11 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu // As far as we know all mhw time data is sent in central Europe time zone. // So, temporarily set timezone to western europe - time_t dt = eDVBLocalTimeHandler::getInstance()->nowTime(); + time_t dt = ::time(0); 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"); tzset(); @@ -2714,7 +2959,7 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu if ( old_tz == NULL ) unsetenv( "TZ" ); else - putenv( old_tz ); + setenv("TZ", tz_saved, 1); tzset(); // Calculate MJD according to annex in ETSI EN 300 468 @@ -2757,7 +3002,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator packet->segment_last_table_id = 0x50; __u8 *title = isMHW2 ? ((__u8*)(itTitle->second.title))-4 : (__u8*)itTitle->second.title; - std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 33 : 23 ); + std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 35 : 23 ); int prog_title_length = prog_title.length(); int packet_length = EIT_SIZE + EIT_LOOP_SIZE + EIT_SHORT_EVENT_DESCRIPTOR_SIZE + @@ -2878,7 +3123,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator void eEPGCache::channel_data::startTimeout(int msec) { - m_MHWTimeoutTimer.start(msec,true); + m_MHWTimeoutTimer->start(msec,true); m_MHWTimeoutet=false; } @@ -2916,7 +3161,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) if ( state > 1 || // aborted // have si data.. so we dont read mhw data - (haveData & (SCHEDULE|SCHEDULE_OTHER)) ) + (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) ) { eDebug("[EPGC] mhw aborted %d", state); } @@ -3059,7 +3304,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) } } eDebug("[EPGC] mhw finished(%ld) %d summaries not found", - eDVBLocalTimeHandler::getInstance()->nowTime(), + ::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. @@ -3082,18 +3327,18 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) if ( state > 1 || // aborted // have si data.. so we dont read mhw data - (haveData & (eEPGCache::SCHEDULE|eEPGCache::SCHEDULE_OTHER)) ) + (haveData & (SCHEDULE|SCHEDULE_OTHER|VIASAT)) ) { eDebug("[EPGC] mhw2 aborted %d", state); } - else if (m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0) + else if (m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0) // Channels table { - int num_channels = data[119]; + int num_channels = data[120]; m_channels.resize(num_channels); - if(dataLen > 119) + if(dataLen > 120) { - int ptr = 120 + 8 * num_channels; + int ptr = 121 + 8 * num_channels; if( dataLen > ptr ) { for( int chid = 0; chid < num_channels; ++chid ) @@ -3109,7 +3354,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) else goto abort; // data seems consistent... - const __u8 *tmp = data+120; + const __u8 *tmp = data+121; for (int i=0; i < num_channels; ++i) { mhw_channel_name_t channel; @@ -3120,6 +3365,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)); tmp+=2; } for (int i=0; i < num_channels; ++i) @@ -3130,83 +3376,86 @@ 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); } haveData |= MHW; eDebug("[EPGC] mhw2 %d channels found", m_channels.size()); } - else if (m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1) + 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"); } - else if (m_MHWFilterMask2.pid == 0x234 && m_MHWFilterMask2.data[0] == 0xe6) + else if (m_MHWFilterMask2.pid == m_mhw2_title_pid && m_MHWFilterMask2.data[0] == 0xe6) // Titles table { int pos=18; - bool valid=true; - int len = ((data[1]&0xf)<<8) + data[2] - 16; + bool valid=false; bool finish=false; - if(data[dataLen-1] != 0xff) - return; - while( pos < dataLen ) + +// eDebug("%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] ); + + while( pos < dataLen && !valid) { - valid = false; - pos += 7; - if( pos < dataLen ) - { - pos += 3; - if( pos < dataLen ) - { - if( data[pos] > 0xc0 ) - { - pos += ( data[pos] - 0xc0 ); - pos += 4; - if( pos < dataLen ) - { - if( data[pos] == 0xff ) - { - ++pos; - valid = true; - } - } - } - } - } - if( !valid ) - { - if (checkTimeout()) - goto start_summary; - return; - } + pos += 18; + pos += (data[pos] & 0x3F) + 4; + if( pos == dataLen ) + valid = true; + } + + if (!valid) + { + if (dataLen > 18) + eDebug("mhw2 title table invalid!!"); + if (checkTimeout()) + goto abort; + if (!m_MHWTimeoutTimer->isActive()) + startTimeout(5000); + return; // continue reading } + // data seems consistent... mhw_title_t title; pos = 18; - while (pos < len) + while (pos < dataLen) { +// eDebugNoNewLine(" [%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; - title.program_id_ml = data[pos+1]; - title.program_id_lo = data[pos+2]; - title.mhw2_mjd_hi = data[pos+3]; - title.mhw2_mjd_lo = data[pos+4]; - title.mhw2_hours = data[pos+5]; - title.mhw2_minutes = data[pos+6]; - title.mhw2_seconds = data[pos+7]; - int duration = ((data[pos+8] << 8)|data[pos+9]) >> 4; + title.mhw2_mjd_hi = data[pos+11]; + title.mhw2_mjd_lo = data[pos+12]; + title.mhw2_hours = data[pos+13]; + title.mhw2_minutes = data[pos+14]; + title.mhw2_seconds = data[pos+15]; + int duration = ((data[pos+16] << 8)|data[pos+17]) >> 4; title.mhw2_duration_hi = (duration&0xFF00) >> 8; title.mhw2_duration_lo = duration&0xFF; - __u8 slen = data[pos+10] & 0x3f; + + // Create unique key per title + __u32 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; - memcpy(dest, &data[pos+11], slen>33 ? 33 : slen); - memset(dest+slen, 0, 33-slen); - pos += 11 + slen; + 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]; - // Create unique key per title - __u32 title_id = (title.channel_id<<16) | (title.program_id_ml<<8) | title.program_id_lo; +// if (title.channel_id > m_channels.size()) +// eDebug("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", +// pos, title.program_id_ml, title.program_id_lo, title.channel_id, summary_id, dest, slen); - pos += 4; +// eDebug("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 ); if ( it == m_titles.end() ) @@ -3245,7 +3494,7 @@ start_summary: { // Titles table has been read, there are summaries to read. // Start reading summaries, store corresponding titles on the fly. - startMHWReader2(0x236, 0x96); + startMHWReader2(m_mhw2_summary_pid, 0x96); startTimeout(15000); return; } @@ -3253,7 +3502,7 @@ start_summary: else return; } - else if (m_MHWFilterMask2.pid == 0x236 && m_MHWFilterMask2.data[0] == 0x96) + else if (m_MHWFilterMask2.pid == m_mhw2_summary_pid && m_MHWFilterMask2.data[0] == 0x96) // Summaries table { if (!checkTimeout()) @@ -3287,10 +3536,13 @@ start_summary: } else return; // continue reading + 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] ); // ugly workaround to convert const __u8* to char* char *tmp=0; @@ -3308,7 +3560,7 @@ start_summary: len += lenline + 1; } if( len > 0 ) - tmp[pos+len] = 0; + tmp[pos+len] = 0; else tmp[pos+1] = 0; @@ -3324,8 +3576,11 @@ start_summary: startTimeout(15000); std::string the_text = (char *) (data + pos + 1); +// eDebug ("summary id %04x : %s\n", summary_id, data+pos+1); + while( itProgId != m_program_ids.end() && itProgId->first == summary_id ) { +// eDebug("."); // Find corresponding title, store title and summary in epgcache. std::map<__u32, mhw_title_t>::iterator itTitle( m_titles.find( itProgId->second ) ); if ( itTitle != m_titles.end() ) @@ -3345,16 +3600,16 @@ start_summary: } if (isRunning & eEPGCache::MHW) { - if ( m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0) + if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0) { // Channels table has been read, start reading the themes table. - startMHWReader2(0x231, 0xC8, 1); + startMHWReader2(m_mhw2_channel_pid, 0xC8, 1); return; } - else if ( m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1) + else if ( m_MHWFilterMask2.pid == m_mhw2_channel_pid && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1) { // Themes table has been read, start reading the titles table. - startMHWReader2(0x234, 0xe6); + startMHWReader2(m_mhw2_title_pid, 0xe6); return; } else @@ -3364,7 +3619,7 @@ start_summary: 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", - eDVBLocalTimeHandler::getInstance()->nowTime(), + ::time(0), m_program_ids.size()); } }