X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/527b292c4f846302522430695fcbfa1f8dadb8d8..761cde6e77261e8ee7680510705b6283a734c2af:/lib/dvb/epgcache.cpp diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp index 63331061..81b96a82 100644 --- a/lib/dvb/epgcache.cpp +++ b/lib/dvb/epgcache.cpp @@ -12,6 +12,7 @@ #include // for statfs // #include #include +#include #include #include #include @@ -45,7 +46,6 @@ 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) { @@ -226,7 +226,11 @@ eEPGCache::eEPGCache() if (!res_mgr) eDebug("[eEPGCache] no resource manager !!!!!!!"); else + { res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn); + if (eDVBLocalTimeHandler::getInstance()->ready()) + timeUpdated(); + } instance=this; } @@ -563,29 +567,25 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) #endif if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed { - eventData *tmp1 = ev_it->second, - *tmp2 = tm_it->second; + // exempt memory + delete ev_it->second; + delete tm_it->second; ev_it->second=evt; tm_it->second=evt; - // exempt memory - delete tmp1; - delete tmp2; } else if (ev_erase_count == 0 && tm_erase_count > 0) { - eventData *tmp = ev_it->second; + // exempt memory + delete ev_it->second; tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair( TM, evt ) ); ev_it->second=evt; - // exempt memory - delete tmp; } else if (ev_erase_count > 0 && tm_erase_count == 0) { - eventData *tmp = tm_it->second; + // exempt memory + delete tm_it->second; ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair( event_id, evt) ); tm_it->second=evt; - // exempt memory - delete tmp; } else // added new eventData { @@ -861,10 +861,10 @@ void eEPGCache::thread() void eEPGCache::load() { - singleLock s(cache_lock); FILE *f = fopen("/hdd/epg.dat", "r"); if (f) { + unlink("/hdd/epg.dat"); int size=0; int cnt=0; #if 0 @@ -898,6 +898,7 @@ void eEPGCache::load() fread( text1, 13, 1, f); if ( !strncmp( text1, "ENIGMA_EPG_V7", 13) ) { + singleLock s(cache_lock); fread( &size, sizeof(int), 1, f); while(size--) { @@ -1162,7 +1163,7 @@ void eEPGCache::channel_data::startEPG() m_ScheduleOtherReader->start(mask); isRunning |= SCHEDULE_OTHER; -// abortTimer.start(7000,true); + abortTimer.start(7000,true); } void eEPGCache::channel_data::abortNonAvail() @@ -1285,7 +1286,6 @@ void eEPGCache::channel_data::abortEPG() void eEPGCache::channel_data::readData( const __u8 *data) { -#if 0 int source; int map; iDVBSectionReader *reader=NULL; @@ -1368,7 +1368,6 @@ void eEPGCache::channel_data::readData( const __u8 *data) cache->sectionRead(data, source, this); } } -#endif } RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction) @@ -1387,13 +1386,13 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co It->second.second.upper_bound(t); // just > if ( i != It->second.second.end() ) { - if ( direction < 0 || (direction == 0 && i->second->getStartTime() > t) ) + if ( direction < 0 || (direction == 0 && i->first > t) ) { timeMap::iterator x = i; --x; if ( x != It->second.second.end() ) { - time_t start_time = x->second->getStartTime(); + time_t start_time = x->first; if (direction >= 0) { if (t < start_time) @@ -1508,23 +1507,23 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes) { + const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service); Lock(); - eventCache::iterator It = eventDB.find(handleGroup(service)); + eventCache::iterator It = eventDB.find(ref); if ( It != eventDB.end() && It->second.second.size() ) { - m_timemap_end = minutes != -1 ? It->second.second.upper_bound(begin+minutes*60) : It->second.second.end(); if ( begin != -1 ) { m_timemap_cursor = It->second.second.lower_bound(begin); if ( m_timemap_cursor != It->second.second.end() ) { - if ( m_timemap_cursor->second->getStartTime() != begin ) + if ( m_timemap_cursor->first != begin ) { timeMap::iterator x = m_timemap_cursor; --x; if ( x != It->second.second.end() ) { - time_t start_time = x->second->getStartTime(); + time_t start_time = x->first; if ( begin > start_time && begin < (start_time+x->second->getDuration())) m_timemap_cursor = x; } @@ -1533,7 +1532,12 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, } else m_timemap_cursor = It->second.second.begin(); - const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service); + + if (minutes != -1 && m_timemap_cursor != It->second.second.end()) + m_timemap_end = It->second.second.upper_bound(m_timemap_cursor->first+minutes*60); + else + m_timemap_end = It->second.second.end(); + currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get(); Unlock(); return 0; @@ -1583,7 +1587,7 @@ RESULT eEPGCache::getNextTimeEntry(ePtr &result) return -1; } -void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service, ePtr &ptr, ePyObject nowTime, ePyObject service_name ) +void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service, eServiceEvent *ptr, ePyObject nowTime, ePyObject service_name ) { ePyObject tmp; int pos=0; @@ -1621,6 +1625,7 @@ void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service tmp = service; inc_refcount = true; break; + case 'n': // short service name case 'N': // service name tmp = service_name; inc_refcount = true; @@ -1636,7 +1641,7 @@ void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service } } -int handleEvent(ePtr &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, char* argstring, int argcount, ePyObject service, ePyObject nowTime, ePyObject service_name, ePyObject convertFunc, ePyObject convertFuncArgs) { if (convertFunc) { @@ -1680,6 +1685,7 @@ int handleEvent(ePtr &ptr, ePyObject dest_list, char* argstring, // C = Current Time // R = Service Reference // N = Service Name +// n = Short Service Name // 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 @@ -1689,7 +1695,7 @@ int handleEvent(ePtr &ptr, ePyObject dest_list, char* argstring, // +1 = event after given start_time // the third // when type is eventid it is the event_id -// when type is time then it is the start_time ( 0 for now_time ) +// when type is time then it is the start_time ( -1 for now_time ) // the fourth is the end_time .. ( optional .. for query all events in time range) PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) @@ -1742,7 +1748,7 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) PyLong_FromLong(eDVBLocalTimeHandler::getInstance()->nowTime()) : ePyObject(); - bool must_get_service_name = strchr(argstring, 'N') ? true : false; + int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0; // create dest list ePyObject dest_list=PyList_New(0); @@ -1830,6 +1836,19 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) { 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()); } @@ -1842,10 +1861,12 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) Lock(); if (!startTimeQuery(ref, stime, minutes)) { - ePtr ptr; - while (!getNextTimeEntry(ptr)) + while ( m_timemap_cursor != m_timemap_end ) { - if (handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) + Event ev((uint8_t*)m_timemap_cursor++->second->get()); + eServiceEvent evt; + evt.parseFrom(&ev, currentQueryTsidOnid); + if (handleEvent(&evt, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) { Unlock(); return 0; // error @@ -1856,15 +1877,21 @@ PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) } else { - ePtr ptr; + eServiceEvent evt; + Event *ev=0; if (stime) { if (type == 2) - lookupEventId(ref, event_id, ptr); + lookupEventId(ref, event_id, ev); else - lookupEventTime(ref, stime, ptr, type); + lookupEventTime(ref, stime, ev, type); + if (ev) + { + const eServiceReferenceDVB &dref = (const eServiceReferenceDVB&)ref; + evt.parseFrom(ev, (dref.getTransportStreamID().get()<<16)|dref.getOriginalNetworkID().get()); + } } - if (handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) + if (handleEvent(ev ? &evt : 0, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) return 0; // error } if (service_changed) @@ -1882,7 +1909,7 @@ skip_entry: return dest_list; } -void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, ePtr &ptr, ePyObject service_name, ePyObject service_reference) +void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, eServiceEvent *ptr, ePyObject service_name, ePyObject service_reference) { ePyObject tmp; int pos=0; @@ -1922,6 +1949,7 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData tmp = service_reference; inc_refcount = true; break; + case 'n': // short service name case 'N': // service name tmp = service_name; inc_refcount = true; @@ -1948,6 +1976,7 @@ void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData // E = Event Extended Description // R = Service Reference // N = Service Name +// n = Short Service Name // 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) @@ -2218,32 +2247,49 @@ PyObject *eEPGCache::search(ePyObject arg) if (ref.valid()) { // create servive event - ePtr ptr; + eServiceEvent ptr; + Event *ev=0; if (needServiceEvent) { - lookupEventId(ref, evid, ptr); - if (!ptr) + if (lookupEventId(ref, evid, ev)) eDebug("event not found !!!!!!!!!!!"); } // create service name - if (!service_name && strchr(argstring,'N')) + if (!service_name) { - ePtr sptr; - eServiceCenterPtr service_center; - eServiceCenter::getPrivInstance(service_center); - if (service_center) + int must_get_service_name = strchr(argstring, 'N') ? 1 : strchr(argstring, 'n') ? 2 : 0; + if (must_get_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 (name.length()) - service_name = PyString_FromString(name.c_str()); + service_center->info(ref, sptr); + if (sptr) + { + 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 (!service_name) + service_name = PyString_FromString(""); } - if (!service_name) - service_name = PyString_FromString(""); } // create servicereference string if (!service_reference && strchr(argstring,'R')) @@ -2254,7 +2300,7 @@ PyObject *eEPGCache::search(ePyObject arg) // create tuple ePyObject tuple = PyTuple_New(argcount); // fill tuple - fillTuple2(tuple, argstring, argcount, evit->second, ptr, service_name, service_reference); + fillTuple2(tuple, argstring, argcount, evit->second, ev ? &ptr : 0, service_name, service_reference); PyList_Append(ret, tuple); Py_DECREF(tuple); --maxcount; @@ -2680,6 +2726,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator // data is borrowed from calling proc to save memory space. { __u8 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 || itTitle->second.mhw2_duration_hi || itTitle->second.mhw2_duration_lo; @@ -2687,6 +2734,7 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator eit_t *packet = (eit_t *) data; packet->table_id = 0x50; packet->section_syntax_indicator = 1; + packet->service_id_hi = m_channels[ itTitle->second.channel_id - 1 ].channel_id_hi; packet->service_id_lo = m_channels[ itTitle->second.channel_id - 1 ].channel_id_lo; packet->version_number = 0; // eEPGCache::sectionRead() will dig this for the moment @@ -2871,10 +2919,11 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) int record_size = sizeof( mhw_channel_name_t ); int nbr_records = int (len/record_size); + m_channels.resize(nbr_records); for ( int i = 0; i < nbr_records; i++ ) { mhw_channel_name_t *channel = (mhw_channel_name_t*) &data[4 + i*record_size]; - m_channels.push_back( *channel ); + m_channels[i]=*channel; } haveData |= MHW; @@ -2940,7 +2989,7 @@ 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[ program_id ] = title_id; + m_program_ids.insert(std::pair<__u32,__u32>(program_id,title_id)); return; // Continue reading of the current table. } else if (!checkTimeout()) @@ -2973,7 +3022,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) memcpy(&tmp, &data, sizeof(void*)); tmp[len+3] = 0; // Terminate as a string. - std::map<__u32, __u32>::iterator itProgid( m_program_ids.find( program_id ) ); + std::multimap<__u32, __u32>::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. */ @@ -3032,10 +3081,11 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) else if (m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0) // Channels table { - int num_channels = data[120]; - if(dataLen > 120) + int num_channels = data[119]; + m_channels.resize(num_channels); + if(dataLen > 119) { - int ptr = 121 + 6 * num_channels; + int ptr = 120 + 8 * num_channels; if( dataLen > ptr ) { for( int chid = 0; chid < num_channels; ++chid ) @@ -3051,18 +3101,17 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) else goto abort; // data seems consistent... - const __u8 *tmp = data+121; + const __u8 *tmp = data+120; for (int i=0; i < num_channels; ++i) { mhw_channel_name_t channel; + channel.network_id_hi = *(tmp++); + channel.network_id_lo = *(tmp++); channel.transport_stream_id_hi = *(tmp++); channel.transport_stream_id_lo = *(tmp++); channel.channel_id_hi = *(tmp++); channel.channel_id_lo = *(tmp++); -#warning FIXME hardcoded network_id in mhw2 epg - channel.network_id_hi = 0; // hardcoded astra 19.2 - channel.network_id_lo = 1; - m_channels.push_back(channel); + m_channels[i]=channel; tmp+=2; } for (int i=0; i < num_channels; ++i) @@ -3141,7 +3190,7 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) __u8 slen = data[pos+10] & 0x3f; __u8 *dest = ((__u8*)title.title)-4; memcpy(dest, &data[pos+11], slen>33 ? 33 : slen); - memset(dest+slen, 0x20, 33-slen); + memset(dest+slen, 0, 33-slen); pos += 11 + slen; // not used theme id (data[7] & 0x3f) + (data[pos] & 0x3f); __u32 summary_id = (data[pos+1] << 8) | data[pos+2]; @@ -3149,19 +3198,27 @@ void eEPGCache::channel_data::readMHWData2(const __u8 *data) // Create unique key per title __u32 title_id = (title.channel_id<<16) | (title.program_id_ml<<8) | title.program_id_lo; -// eDebug("program_id: %08x, %s", program_id, -// std::string((const char *)title.title, (int)(slen > 23 ? 23 : slen)).c_str()); - pos += 4; - if ( m_titles.find( title_id ) == m_titles.end() ) + std::map<__u32, mhw_title_t>::iterator it = m_titles.find( title_id ); + if ( it == m_titles.end() ) { - startTimeout(4000); + startTimeout(5000); m_titles[ title_id ] = title; - if (summary_id != 0xFFFF && // no summary avail - m_program_ids.find(summary_id) == m_program_ids.end()) + if (summary_id != 0xFFFF) { - m_program_ids[ summary_id ] = title_id; + bool add=true; + std::multimap<__u32, __u32>::iterator it(m_program_ids.lower_bound(summary_id)); + while (it != m_program_ids.end() && it->first == summary_id) + { + if (it->second == title_id) { + add=false; + break; + } + ++it; + } + if (add) + m_program_ids.insert(std::pair<__u32,__u32>(summary_id,title_id)); } } else @@ -3181,7 +3238,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); - startTimeout(4000); + startTimeout(15000); return; } } @@ -3191,84 +3248,91 @@ start_summary: else if (m_MHWFilterMask2.pid == 0x236 && m_MHWFilterMask2.data[0] == 0x96) // Summaries table { - int len, loop, pos, lenline; - bool valid; - valid = true; - if( dataLen > 18 ) + if (!checkTimeout()) { - loop = data[12]; - pos = 13 + loop; - if( dataLen > pos ) + int len, loop, pos, lenline; + bool valid; + valid = true; + if( dataLen > 15 ) { - loop = data[pos] & 0x0f; - pos += 1; + loop = data[14]; + pos = 15 + loop; if( dataLen > pos ) { - len = 0; - for( ; loop > 0; --loop ) + loop = data[pos] & 0x0f; + pos += 1; + if( dataLen > pos ) { - if( dataLen > (pos+len) ) + len = 0; + for( ; loop > 0; --loop ) { - lenline = data[pos+len]; - len += lenline + 1; + if( dataLen > (pos+len) ) + { + lenline = data[pos+len]; + len += lenline + 1; + } + else + valid=false; } - else - valid=false; } } } - } - else if (!checkTimeout()) - return; // continue reading - if (valid && !checkTimeout()) - { - // data seems consistent... - __u32 summary_id = (data[3]<<8)|data[4]; - - // ugly workaround to convert const __u8* to char* - char *tmp=0; - memcpy(&tmp, &data, sizeof(void*)); - - len = 0; - loop = data[12]; - pos = 13 + loop; - loop = tmp[pos] & 0x0f; - pos += 1; - for( ; loop > 0; loop -- ) - { - lenline = tmp[pos+len]; - tmp[pos+len] = ' '; - len += lenline + 1; - } - if( len > 0 ) - tmp[pos+len] = 0; - else - tmp[pos+1] = 0; - - std::map<__u32, __u32>::iterator itProgid( m_program_ids.find( summary_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() ) - return; // Continue reading of the current table. - } else + return; // continue reading + if (valid) { - startTimeout(4000); - std::string the_text = (char *) (data + pos + 1); + // data seems consistent... + __u32 summary_id = (data[3]<<8)|data[4]; + + // ugly workaround to convert const __u8* to char* + char *tmp=0; + memcpy(&tmp, &data, sizeof(void*)); - // 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() ) + len = 0; + loop = data[14]; + pos = 15 + loop; + loop = tmp[pos] & 0x0f; + pos += 1; + for( ; loop > 0; loop -- ) + { + lenline = tmp[pos+len]; + tmp[pos+len] = ' '; + len += lenline + 1; + } + if( len > 0 ) + tmp[pos+len] = 0; + else + tmp[pos+1] = 0; + + std::multimap<__u32, __u32>::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. */ + if ( !m_program_ids.empty() ) + return; // Continue reading of the current table. + } + else { - storeTitle( itTitle, the_text, data ); - m_titles.erase( itTitle ); + startTimeout(15000); + std::string the_text = (char *) (data + pos + 1); + + while( itProgId != m_program_ids.end() && itProgId->first == summary_id ) + { + // 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() ) + { + storeTitle( itTitle, the_text, data ); + m_titles.erase( itTitle ); + } + m_program_ids.erase( itProgId++ ); + } + if ( !m_program_ids.empty() ) + return; // Continue reading of the current table. } - m_program_ids.erase( itProgid ); - if ( !m_program_ids.empty() ) - return; // Continue reading of the current table. } + else + return; // continue reading } } if (isRunning & eEPGCache::MHW)