X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/df8830e6f19c5557fd52b1a9ac4fbf23c1afcdf2..f96990d7d97115a2cdc070dedd88629c11a17f39:/lib/dvb/epgcache.cpp diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp index b5f519e9..974e9f7b 100644 --- a/lib/dvb/epgcache.cpp +++ b/lib/dvb/epgcache.cpp @@ -3,12 +3,17 @@ #undef EPG_DEBUG +#ifdef EPG_DEBUG +#include +#endif + #include #include // for usleep #include // for statfs // #include #include #include +#include #include int eventData::CacheSize=0; @@ -65,7 +70,6 @@ const eit_event_struct* eventData::get() const { int pos = 12; int tmp = ByteSize-12; - memcpy(data, EITdata, 12); __u32 *p = (__u32*)(EITdata+12); while(tmp>0) @@ -177,12 +181,11 @@ eEPGCache::eEPGCache() void eEPGCache::timeUpdated() { - if ( !thread_running() ) + if (!sync()) { eDebug("[EPGC] time updated.. start EPG Mainloop"); run(); - } - else + } else messages.send(Message(Message::timeChanged)); } @@ -298,6 +301,69 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan) } } +void eEPGCache::FixOverlapping(std::pair &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service) +{ + timeMap::iterator tmp = tm_it; + while ((tmp->first+tmp->second->getDuration()-300) > TM) + { + if(tmp->first != TM && tmp->second->type != PRIVATE) + { + __u16 event_id = tmp->second->getEventID(); + servicemap.first.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", + 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()) + { + servicemap.second.erase(tmp); + break; + } + else + servicemap.second.erase(tmp--); + } + else + { + if (tmp == servicemap.second.begin()) + break; + --tmp; + } + } + + tmp = tm_it; + while(tmp->first < (TM+duration-300)) + { + if (tmp->first != TM && tmp->second->type != PRIVATE) + { + __u16 event_id = tmp->second->getEventID(); + servicemap.first.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", + service.sid, event_id, + event.getBeginTimeString().c_str(), + event.getEventName().c_str(), + event.getExtendedDescription().c_str()); +#endif + delete tmp->second; + servicemap.second.erase(tmp++); + } + else + ++tmp; + if (tmp == servicemap.second.end()) + break; + } +} + void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) { eit_t *eit = (eit_t*) data; @@ -318,7 +384,7 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) 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 = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); + time_t now = eDVBLocalTimeHandler::getInstance()->nowTime(); if ( TM != 3599 && TM > -1) channel->haveData |= source; @@ -365,24 +431,24 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) if ( ev_it != servicemap.first.end() ) { if ( source > ev_it->second->type ) // update needed ? - goto next; // when not.. the skip this entry + goto next; // when not.. then skip this entry // search this event in timemap - timeMap::iterator tm_it_tmp = + timeMap::iterator tm_it_tmp = servicemap.second.find(ev_it->second->getStartTime()); if ( tm_it_tmp != servicemap.second.end() ) { - if ( tm_it_tmp->first == TM ) // correct eventData + if ( tm_it_tmp->first == TM ) // just update eventdata { // exempt memory delete ev_it->second; - evt = new eventData(eit_event, eit_event_size, source); - ev_it->second=evt; - tm_it_tmp->second=evt; + ev_it->second = tm_it_tmp->second = + new eventData(eit_event, eit_event_size, source); + FixOverlapping(servicemap, TM, duration, tm_it_tmp, service); goto next; } - else + else // event has new event begin time { tm_erase_count++; // delete the found record from timemap @@ -392,45 +458,44 @@ 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 + // 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); if ( tm_it != servicemap.second.end() ) { - // i think, if event is not found on eventmap, but found on timemap updating nevertheless demands -#if 0 - if ( source > tm_it->second->type && tm_erase_count == 0 ) // update needed ? - goto next; // when not.. the skip this entry -#endif + // event with same start time but another event_id... + if ( source > tm_it->second->type && + ev_it == servicemap.first.end() ) + goto next; // when not.. then skip this entry // search this time in eventmap - eventMap::iterator ev_it_tmp = + eventMap::iterator ev_it_tmp = servicemap.first.find(tm_it->second->getEventID()); if ( ev_it_tmp != servicemap.first.end() ) { - ev_erase_count++; + ev_erase_count++; // delete the found record from eventmap servicemap.first.erase(ev_it_tmp); prevEventIt=servicemap.first.end(); } } - + evt = new eventData(eit_event, eit_event_size, source); -#if EPG_DEBUG +#ifdef EPG_DEBUG bool consistencyCheck=true; #endif if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed { // exempt memory - delete ev_it->second; + delete ev_it->second; delete tm_it->second; ev_it->second=evt; tm_it->second=evt; } - else if (ev_erase_count == 0 && tm_erase_count > 0) + else if (ev_erase_count == 0 && tm_erase_count > 0) { // exempt memory delete ev_it->second; @@ -446,34 +511,37 @@ void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel) } else // added new eventData { -#if EPG_DEBUG +#ifdef EPG_DEBUG consistencyCheck=false; #endif - prevEventIt=servicemap.first.insert( prevEventIt, std::pair( event_id, evt) ); - prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair( TM, evt ) ); + ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair( event_id, evt) ); + tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair( TM, evt ) ); } -#if EPG_DEBUG + + FixOverlapping(servicemap, TM, duration, tm_it, service); + +#ifdef EPG_DEBUG if ( consistencyCheck ) { if ( tm_it->second != evt || ev_it->second != evt ) eFatal("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)", + eFatal("event start_time(%d) non equal timemap key(%d)", tm_it->second->getStartTime(), tm_it->first ); else if ( tm_it->first != TM ) - eFatal("timemap key(%d) non equal TM(%d)", + eFatal("timemap key(%d) non equal TM(%d)", tm_it->first, 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); else if ( ev_it->first != event_id ) - eFatal("eventmap key(%d) non equal event_id(%d)", + eFatal("eventmap key(%d) non equal event_id(%d)", ev_it->first, event_id ); } #endif } next: -#if EPG_DEBUG +#ifdef EPG_DEBUG if ( servicemap.first.size() != servicemap.second.size() ) { FILE *f = fopen("/hdd/event_map.txt", "w+"); @@ -561,7 +629,7 @@ void eEPGCache::cleanLoop() { eDebug("[EPGC] start cleanloop"); - time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); + time_t now = eDVBLocalTimeHandler::getInstance()->nowTime(); for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++) { @@ -672,9 +740,18 @@ void eEPGCache::gotMessage( const Message &msg ) chid.original_network_id.get() == msg.service.onid && data->m_PrivatePid == -1 ) { + data->m_PrevVersion = -1; data->m_PrivatePid = msg.pid; data->m_PrivateService = msg.service; - data->startPrivateReader(msg.pid, -1); + updateMap::iterator It = channelLastUpdated.find( channel->getChannelID() ); + int update = ( It != channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY ); + if (update < ZAP_DELAY) + update = ZAP_DELAY; + data->startPrivateTimer.start(update, 1); + if (update >= 60000) + eDebug("[EPGC] next private update in %i min", update/60000); + else if (update >= 1000) + eDebug("[EPGC] next private update in %i sec", update/1000); break; } } @@ -692,6 +769,7 @@ void eEPGCache::gotMessage( const Message &msg ) void eEPGCache::thread() { + hasStarted(); nice(4); load(); cleanLoop(); @@ -778,6 +856,7 @@ void eEPGCache::load() int size=0; uniqueEPGKey key; fread( &key, sizeof(uniqueEPGKey), 1, f); + eventMap &evMap=eventDB[key].first; fread( &size, sizeof(int), 1, f); while(size--) { @@ -793,6 +872,10 @@ void eEPGCache::load() 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; } } } @@ -899,18 +982,20 @@ void eEPGCache::save() eEPGCache::channel_data::channel_data(eEPGCache *ml) :cache(ml) - ,abortTimer(ml), zapTimer(ml) - ,state(0), isRunning(0), haveData(0), can_delete(1) + ,abortTimer(ml), zapTimer(ml),state(0) + ,isRunning(0), haveData(0), can_delete(1) + ,startPrivateTimer(ml) { CONNECT(zapTimer.timeout, eEPGCache::channel_data::startEPG); CONNECT(abortTimer.timeout, eEPGCache::channel_data::abortNonAvail); + CONNECT(startPrivateTimer.timeout, eEPGCache::channel_data::startPrivateReader); } bool eEPGCache::channel_data::finishEPG() { if (!isRunning) // epg ready { - eDebug("[EPGC] stop caching events(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference()); + eDebug("[EPGC] stop caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); zapTimer.start(UPDATE_INTERVAL, 1); eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000); for (int i=0; i < 3; ++i) @@ -919,7 +1004,7 @@ bool eEPGCache::channel_data::finishEPG() calcedSections[i].clear(); } singleLock l(cache->cache_lock); - cache->channelLastUpdated[channel->getChannelID()] = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); + cache->channelLastUpdated[channel->getChannelID()] = eDVBLocalTimeHandler::getInstance()->nowTime(); #ifdef ENABLE_PRIVATE_EPG if (seenPrivateSections.empty()) #endif @@ -931,7 +1016,7 @@ bool eEPGCache::channel_data::finishEPG() void eEPGCache::channel_data::startEPG() { - eDebug("[EPGC] start caching events(%d)", eDVBLocalTimeHandler::getInstance()->difference()+time(0)); + eDebug("[EPGC] start caching events(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); state=0; haveData=0; can_delete=0; @@ -1015,7 +1100,7 @@ void eEPGCache::channel_data::startChannel() { updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() ); - int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY ); + int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (eDVBLocalTimeHandler::getInstance()->nowTime()-It->second) * 1000 ) ) : ZAP_DELAY ); if (update < ZAP_DELAY) update = ZAP_DELAY; @@ -1118,7 +1203,7 @@ void eEPGCache::channel_data::readData( const __u8 *data) break; default: eDebugNoNewLine("unknown");break; } - eDebug(" finished(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference()); + eDebug(" finished(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); if ( reader ) reader->stop(); isRunning &= ~source; @@ -1169,7 +1254,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 = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); + t = eDVBLocalTimeHandler::getInstance()->nowTime(); 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() ) @@ -1520,7 +1605,7 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) } PyObject *nowTime = strchr(argstring, 'C') ? - PyLong_FromLong(time(0)+eDVBLocalTimeHandler::getInstance()->difference()) : + PyLong_FromLong(eDVBLocalTimeHandler::getInstance()->nowTime()) : NULL; bool must_get_service_name = strchr(argstring, 'N') ? true : false; @@ -1532,6 +1617,7 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) PyObject *item=PyList_GET_ITEM(list, listIt++); // borrowed reference! if (PyTuple_Check(item)) { + bool service_changed=false; int type=0; long event_id=-1; time_t stime=-1; @@ -1579,6 +1665,24 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) 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 + { + eServiceCenterPtr service_center; + if (!eServiceCenter::getPrivInstance(service_center)) + { + dvb_ref.setTransportStreamID( dvb_ref.getParentTransportStreamID() ); + dvb_ref.setServiceID( dvb_ref.getParentServiceID() ); + dvb_ref.setParentTransportStreamID(eTransportStreamID(0)); + dvb_ref.setParentServiceID(eServiceID(0)); + dvb_ref.name=""; + service = PyString_FromString(dvb_ref.toString().c_str()); + service_changed = true; + } + } + PyObject *service_name=NULL; if (must_get_service_name) { @@ -1628,6 +1732,8 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) if (ret) return ret; } + if (service_changed) + Py_DECREF(service); if (service_name) Py_DECREF(service_name); } @@ -1641,6 +1747,408 @@ skip_entry: return dest_list; } +void fillTuple2(PyObject *tuple, const char *argstring, int argcount, eventData *evData, ePtr &ptr, PyObject *service_name, PyObject *service_reference) +{ + PyObject *tmp=NULL; + int pos=0; + while(pos < argcount) + { + bool inc_refcount=false; + switch(argstring[pos]) + { + 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()) : NULL; + else + tmp = PyLong_FromLong(evData->getStartTime()); + break; + case 'D': // Event Duration + if (ptr) + tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL; + else + tmp = PyLong_FromLong(evData->getDuration()); + break; + case 'T': // Event Title + tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL; + break; + case 'S': // Event Short Description + tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL; + break; + case 'E': // Event Extended Description + tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL; + break; + case 'R': // service reference string + tmp = service_reference; + inc_refcount = true; + break; + case 'N': // service name + tmp = service_name; + inc_refcount = true; + break; + } + if (!tmp) + { + tmp = Py_None; + inc_refcount = true; + } + if (inc_refcount) + Py_INCREF(tmp); + PyTuple_SET_ITEM(tuple, pos++, tmp); + } +} + +// here we get a python tuple +// the first entry in the tuple is a python string to specify the format of the returned tuples (in a list) +// I = Event Id +// B = Event Begin Time +// D = Event Duration +// T = Event Title +// S = Event Short Description +// E = Event Extended Description +// R = Service Reference +// N = 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) +// 1 = search events with exactly title name (EXAKT_TITLE_SEARCH) +// 2 = search events with text in title name (PARTIAL_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) +// the fourth is the search text +// the fifth is +// 0 = case sensitive (CASE_CHECK) +// 1 = case insensitive (NO_CASECHECK) + +PyObject *eEPGCache::search(PyObject *arg) +{ + PyObject *ret = 0; + int descridx = -1; + __u32 descr[512]; + int eventid = -1; + const char *argstring=0; + char *refstr=0; + int argcount=0; + int querytype=-1; + bool needServiceEvent=false; + int maxmatches=0; + + if (PyTuple_Check(arg)) + { + int tuplesize=PyTuple_Size(arg); + if (tuplesize > 0) + { + PyObject *obj = PyTuple_GET_ITEM(arg,0); + if (PyString_Check(obj)) + { + argcount = PyString_GET_SIZE(obj); + argstring = PyString_AS_STRING(obj); + for (int i=0; i < argcount; ++i) + switch(argstring[i]) + { + case 'S': + case 'E': + case 'T': + needServiceEvent=true; + default: + break; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("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) + { + PyObject *obj = PyTuple_GET_ITEM(arg, 3); + if (PyString_Check(obj)) + { + refstr = PyString_AS_STRING(obj); + eServiceReferenceDVB ref(refstr); + if (ref.valid()) + { + eventid = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4)); + singleLock s(cache_lock); + const eventData *evData = 0; + lookupEventId(ref, eventid, evData); + if (evData) + { + __u8 *data = evData->EITdata; + int tmp = evData->ByteSize-12; + __u32 *p = (__u32*)(data+12); + // search short and extended event descriptors + while(tmp>0) + { + __u32 crc = *p++; + descriptorMap::iterator it = + eventData::descriptors.find(crc); + if (it != eventData::descriptors.end()) + { + __u8 *descr_data = it->second.second; + switch(descr_data[0]) + { + case 0x4D ... 0x4E: + descr[++descridx]=crc; + default: + break; + } + } + tmp-=4; + } + } + if (descridx<0) + eDebug("event not found"); + } + else + { + 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"); + eDebug("tuple arg 4 is not a string"); + return NULL; + } + } + else if (tuplesize > 4 && (querytype == 1 || querytype == 2) ) + { + PyObject *obj = PyTuple_GET_ITEM(arg, 3); + if (PyString_Check(obj)) + { + int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4)); + const char *str = PyString_AS_STRING(obj); + int textlen = PyString_GET_SIZE(obj); + 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"); + singleLock s(cache_lock); + for (descriptorMap::iterator it(eventData::descriptors.begin()); + it != eventData::descriptors.end() && descridx < 511; ++it) + { + __u8 *data = it->second.second; + if ( data[0] == 0x4D ) // short event descriptor + { + int title_len = data[5]; + if ( querytype == 1 ) + { + if (title_len > textlen) + continue; + else if (title_len < textlen) + continue; + if ( casetype ) + { + if ( !strncasecmp((const char*)data+6, str, title_len) ) + { +// std::string s((const char*)data+6, title_len); +// eDebug("match1 %s %s", str, s.c_str() ); + descr[++descridx] = it->first; + } + } + else if ( !strncmp((const char*)data+6, str, title_len) ) + { +// std::string s((const char*)data+6, title_len); +// eDebug("match2 %s %s", str, s.c_str() ); + descr[++descridx] = it->first; + } + } + else + { + int idx=0; + while((title_len-idx) >= 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) ) + { + descr[++descridx] = it->first; +// std::string s((const char*)data+6, title_len); +// eDebug("match 4 %s %s", str, s.c_str() ); + break; + } + } + ++idx; + } + } + } + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("tuple arg 4 is not a string"); + return NULL; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("tuple arg 3(%d) is not a known querytype(0, 1, 2)", querytype); + return NULL; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("not enough args in tuple"); + return NULL; + } + } + else + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("arg 0 is not a tuple"); + return NULL; + } + + if (descridx > -1) + { + int maxcount=maxmatches; + eServiceReferenceDVB ref(refstr?refstr:""); + // ref is only valid in SIMILAR_BROADCASTING_SEARCH + // in this case we start searching with the base service + bool first = ref.valid() ? true : false; + singleLock s(cache_lock); + eventCache::iterator cit(ref.valid() ? eventDB.find(ref) : eventDB.begin()); + while(cit != eventDB.end() && maxcount) + { + if ( ref.valid() && !first && cit->first == ref ) + { + // do not scan base service twice ( only in SIMILAR BROADCASTING SEARCH ) + ++cit; + continue; + } + PyObject *service_name=0; + PyObject *service_reference=0; + timeMap &evmap = cit->second.second; + // check all events + for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit) + { + if (evit->second->getEventID() == eventid) + continue; + __u8 *data = evit->second->EITdata; + int tmp = evit->second->ByteSize-12; + __u32 *p = (__u32*)(data+12); + // check if any of our descriptor used by this event + int cnt=-1; + while(tmp>0) + { + __u32 crc32 = *p++; + for ( int i=0; i <= descridx; ++i) + { + if (descr[i] == crc32) // found... + ++cnt; + } + tmp-=4; + } + if ( (querytype == 0 && cnt == descridx) || + ((querytype == 1 || querytype == 2) && cnt != -1) ) + { + const uniqueEPGKey &service = cit->first; + eServiceReference ref = + eDVBDB::getInstance()->searchReference(service.tsid, service.onid, service.sid); + if (ref.valid()) + { + // create servive event + ePtr ptr; + if (needServiceEvent) + { + lookupEventId(ref, evit->first, ptr); + if (!ptr) + eDebug("event not found !!!!!!!!!!!"); + } + // create service name + if (!service_name && strchr(argstring,'N')) + { + ePtr sptr; + eServiceCenterPtr service_center; + eServiceCenter::getPrivInstance(service_center); + if (service_center) + { + service_center->info(ref, sptr); + if (sptr) + { + std::string name; + sptr->getName(ref, name); + if (name.length()) + service_name = PyString_FromString(name.c_str()); + } + } + if (!service_name) + service_name = PyString_FromString(""); + } + // create servicereference string + if (!service_reference && strchr(argstring,'R')) + service_reference = PyString_FromString(ref.toString().c_str()); + // create list + if (!ret) + ret = PyList_New(0); + // create tuple + PyObject *tuple = PyTuple_New(argcount); + // fill tuple + fillTuple2(tuple, argstring, argcount, evit->second, ptr, 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 ) + first=false; + cit=eventDB.begin(); + } + else + ++cit; + } + } + + if (!ret) + { + Py_INCREF(Py_None); + ret=Py_None; + } + + return ret; +} + #ifdef ENABLE_PRIVATE_EPG #include #include @@ -1695,7 +2203,7 @@ void eEPGCache::PMTready(eDVBServicePMTHandler *pmthandler) if (tmp==3) { eServiceReferenceDVB ref; - if (!pmthandler->getService(ref)) + if (!pmthandler->getServiceReference(ref)) { int pid = (*es)->getPid(); messages.send(Message(Message::got_private_pid, ref, pid)); @@ -1793,6 +2301,14 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ onid |= data[ptr++]; int sid = data[ptr++] << 8; sid |= data[ptr++]; + +// WORKAROUND for wrong transmitted epg data + if ( onid == 0x85 && tsid == 0x11 && sid == 0xd3 ) // premiere sends wrong tsid here + tsid = 0x1; + else if ( onid == 0x85 && tsid == 0x3 && sid == 0xf5 ) // premiere sends wrong sid here + sid = 0xdc; +//////////////////////////////////////////// + uniqueEPGKey service( sid, onid, tsid ); descr_len -= 6; while( descr_len > 0 ) @@ -1868,33 +2384,30 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ event[0] = (event_id & 0xFF00) >> 8; event[1] = (event_id & 0xFF); time_event_map[it->first.tm]=std::pair(stime, event_id); - eventData *d = new eventData( ev_struct, bptr, eEPGCache::SCHEDULE ); + eventData *d = new eventData( ev_struct, bptr, eEPGCache::PRIVATE ); evMap[event_id] = d; tmMap[stime] = d; } } -void eEPGCache::channel_data::startPrivateReader(int pid, int version) +void eEPGCache::channel_data::startPrivateReader() { eDVBSectionFilterMask mask; memset(&mask, 0, sizeof(mask)); - mask.pid = pid; + mask.pid = m_PrivatePid; mask.flags = eDVBSectionFilterMask::rfCRC; mask.data[0] = 0xA0; mask.mask[0] = 0xFF; - eDebug("start privatefilter for pid %04x and version %d", pid, version); - if (version != -1) + eDebug("start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion); + if (m_PrevVersion != -1) { - mask.data[3] = version << 1; + mask.data[3] = m_PrevVersion << 1; mask.mask[3] = 0x3E; mask.mode[3] = 0x3E; } seenPrivateSections.clear(); m_PrivateReader->connectRead(slot(*this, &eEPGCache::channel_data::readPrivateData), m_PrivateConn); m_PrivateReader->start(mask); -#ifdef NEED_DEMUX_WORKAROUND - m_PrevVersion=version; -#endif } void eEPGCache::channel_data::readPrivateData( const __u8 *data) @@ -1927,9 +2440,8 @@ void eEPGCache::channel_data::readPrivateData( const __u8 *data) eDebug("[EPGC] private finished"); if (!isRunning) can_delete = 1; - int version = data[5]; - version = ((version & 0x3E) >> 1); - startPrivateReader(m_PrivatePid, version); + m_PrevVersion = (data[5] & 0x3E) >> 1; + startPrivateReader(); } } }