X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/8cada4eb31be58a3fa3efa09afbf431b3b62ca08..2b557e7ef4b0518736c5162a501cd9bc743930b3:/lib/dvb/epgcache.cpp diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp index 6a00b6be..47da4101 100644 --- a/lib/dvb/epgcache.cpp +++ b/lib/dvb/epgcache.cpp @@ -14,13 +14,37 @@ #include #include #include -#include +#include int eventData::CacheSize=0; descriptorMap eventData::descriptors; __u8 eventData::data[4108]; extern const uint32_t crc32_table[256]; +const eServiceReference &handleGroup(const eServiceReference &ref) +{ + if (ref.flags & eServiceReference::isGroup) + { + ePtr res; + if (!eDVBResourceManager::getInstance(res)) + { + ePtr db; + if (!res->getChannelList(db)) + { + eBouquet *bouquet=0; + if (!db->getBouquet(ref, bouquet)) + { + std::list::iterator it(bouquet->m_services.begin()); + if (it != bouquet->m_services.end()) + return *it; + } + } + } + } + return ref; +} + + eventData::eventData(const eit_event_struct* e, int size, int type) :ByteSize(size&0xFF), type(type&0xFF) { @@ -263,6 +287,12 @@ void eEPGCache::DVBChannelRunning(iDVBChannel *chan) eDebug("[eEPGCache] couldnt initialize mhw reader!!"); return; } + res = demux->createSectionReader( this, data.m_MHWReader2 ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize mhw reader!!"); + return; + } #endif messages.send(Message(Message::startChannel, chan)); // -> gotMessage -> changedService @@ -316,7 +346,14 @@ void eEPGCache::FixOverlapping(std::pair &servicemap, time_t T timeMap::iterator tmp = tm_it; while ((tmp->first+tmp->second->getDuration()-300) > TM) { - if(tmp->first != TM && tmp->second->type != PRIVATE) + if(tmp->first != TM +#ifdef ENABLE_PRIVATE_EPG + && tmp->second->type != PRIVATE +#endif +#ifdef ENABLE_MHW + && tmp->second->type != MHW +#endif + ) { __u16 event_id = tmp->second->getEventID(); servicemap.first.erase(event_id); @@ -753,7 +790,10 @@ void eEPGCache::gotMessage( const Message &msg ) data->m_PrevVersion = -1; data->m_PrivatePid = msg.pid; data->m_PrivateService = msg.service; - updateMap::iterator It = channelLastUpdated.find( channel->getChannelID() ); + int onid = chid.original_network_id.get(); + 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 ); if (update < ZAP_DELAY) update = ZAP_DELAY; @@ -818,7 +858,7 @@ void eEPGCache::load() fread( &magic, sizeof(int), 1, f); if (magic != 0x98765432) { - eDebug("epg file has incorrect byte order.. dont read it"); + eDebug("[EPGC] epg file has incorrect byte order.. dont read it"); fclose(f); return; } @@ -853,7 +893,7 @@ void eEPGCache::load() eventDB[key]=std::pair(evMap,tmMap); } eventData::load(f); - eDebug("%d events read from /hdd/epg.dat", cnt); + eDebug("[EPGC] %d events read from /hdd/epg.dat", cnt); #ifdef ENABLE_PRIVATE_EPG char text2[11]; fread( text2, 11, 1, f); @@ -946,7 +986,7 @@ void eEPGCache::save() ++cnt; } } - eDebug("%d events written to /hdd/epg.dat", cnt); + eDebug("[EPGC] %d events written to /hdd/epg.dat", cnt); eventData::save(f); #ifdef ENABLE_PRIVATE_EPG const char* text3 = "PRIVATE_EPG"; @@ -1056,6 +1096,18 @@ void eEPGCache::channel_data::startEPG() m_MHWReader->start(mask); isRunning |= MHW; memcpy(&m_MHWFilterMask, &mask, sizeof(eDVBSectionFilterMask)); + + mask.pid = 0x231; + mask.data[0] = 0xC8; + mask.mask[0] = 0xFF; + mask.data[1] = 0; + mask.mask[1] = 0xFF; + m_MHWReader2->connectRead(slot(*this, &eEPGCache::channel_data::readMHWData2), m_MHWConn2); + m_MHWReader2->start(mask); + isRunning |= MHW; + memcpy(&m_MHWFilterMask2, &mask, sizeof(eDVBSectionFilterMask)); + mask.data[1] = 0; + mask.mask[1] = 0; #endif mask.pid = 0x12; @@ -1074,7 +1126,6 @@ void eEPGCache::channel_data::startEPG() isRunning |= SCHEDULE; mask.data[0] = 0x60; - mask.mask[0] = 0xF0; m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleOtherConn); m_ScheduleOtherReader->start(mask); isRunning |= SCHEDULE_OTHER; @@ -1114,6 +1165,8 @@ void eEPGCache::channel_data::abortNonAvail() isRunning &= ~MHW; m_MHWReader->stop(); m_MHWConn=0; + m_MHWReader2->stop(); + m_MHWConn2=0; } #endif if ( isRunning ) @@ -1184,6 +1237,8 @@ void eEPGCache::channel_data::abortEPG() isRunning &= ~MHW; m_MHWReader->stop(); m_MHWConn=0; + m_MHWReader2->stop(); + m_MHWConn2=0; } #endif } @@ -1198,91 +1253,86 @@ void eEPGCache::channel_data::abortEPG() void eEPGCache::channel_data::readData( const __u8 *data) { - if (!data) - eDebug("get Null pointer from section reader !!"); - else + int source; + int map; + iDVBSectionReader *reader=NULL; + switch(data[0]) + { + case 0x4E ... 0x4F: + reader=m_NowNextReader; + source=NOWNEXT; + map=0; + break; + case 0x50 ... 0x5F: + reader=m_ScheduleReader; + source=SCHEDULE; + map=1; + break; + case 0x60 ... 0x6F: + reader=m_ScheduleOtherReader; + source=SCHEDULE_OTHER; + map=2; + 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 ) { - int source; - int map; - iDVBSectionReader *reader=NULL; - switch(data[0]) + eDebugNoNewLine("[EPGC] "); + switch (source) { - case 0x4E ... 0x4F: - reader=m_NowNextReader; - source=NOWNEXT; - map=0; + case NOWNEXT: + m_NowNextConn=0; + eDebugNoNewLine("nownext"); break; - case 0x50 ... 0x5F: - reader=m_ScheduleReader; - source=SCHEDULE; - map=1; + case SCHEDULE: + m_ScheduleConn=0; + eDebugNoNewLine("schedule"); break; - case 0x60 ... 0x6F: - reader=m_ScheduleOtherReader; - source=SCHEDULE_OTHER; - map=2; + case SCHEDULE_OTHER: + m_ScheduleOtherConn=0; + eDebugNoNewLine("schedule other"); break; - default: - eDebug("[EPGC] unknown table_id !!!"); - return; + default: eDebugNoNewLine("unknown");break; } - tidMap &seenSections = this->seenSections[map]; - tidMap &calcedSections = this->calcedSections[map]; - if ( state == 1 && calcedSections == seenSections || state > 1 ) - { - eDebugNoNewLine("[EPGC] "); - switch (source) - { - case NOWNEXT: - m_NowNextConn=0; - eDebugNoNewLine("nownext"); - break; - case SCHEDULE: - m_ScheduleConn=0; - eDebugNoNewLine("schedule"); - break; - case SCHEDULE_OTHER: - m_ScheduleOtherConn=0; - eDebugNoNewLine("schedule other"); - break; - default: eDebugNoNewLine("unknown");break; - } - eDebug(" finished(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); - if ( reader ) - reader->stop(); - isRunning &= ~source; - if (!isRunning) - finishEPG(); - } - else - { - eit_t *eit = (eit_t*) data; - __u32 sectionNo = data[0] << 24; - sectionNo |= data[3] << 16; - sectionNo |= data[4] << 8; - sectionNo |= eit->section_number; + eDebug(" finished(%ld)", eDVBLocalTimeHandler::getInstance()->nowTime()); + if ( reader ) + reader->stop(); + isRunning &= ~source; + if (!isRunning) + finishEPG(); + } + else + { + eit_t *eit = (eit_t*) data; + __u32 sectionNo = data[0] << 24; + sectionNo |= data[3] << 16; + sectionNo |= data[4] << 8; + sectionNo |= eit->section_number; - tidMap::iterator it = - seenSections.find(sectionNo); + tidMap::iterator it = + seenSections.find(sectionNo); - if ( it == seenSections.end() ) + if ( it == seenSections.end() ) + { + seenSections.insert(sectionNo); + calcedSections.insert(sectionNo); + __u32 tmpval = sectionNo & 0xFFFFFF00; + __u8 incr = source == NOWNEXT ? 1 : 8; + for ( int i = 0; i <= eit->last_section_number; i+=incr ) { - seenSections.insert(sectionNo); - calcedSections.insert(sectionNo); - __u32 tmpval = sectionNo & 0xFFFFFF00; - __u8 incr = source == NOWNEXT ? 1 : 8; - for ( int i = 0; i <= eit->last_section_number; i+=incr ) + if ( i == eit->section_number ) { - if ( i == eit->section_number ) - { - for (int x=i; x <= eit->segment_last_section_number; ++x) - calcedSections.insert(tmpval|(x&0xFF)); - } - else - calcedSections.insert(tmpval|(i&0xFF)); + for (int x=i; x <= eit->segment_last_section_number; ++x) + calcedSections.insert(tmpval|(x&0xFF)); } - cache->sectionRead(data, source, this); + else + calcedSections.insert(tmpval|(i&0xFF)); } + cache->sectionRead(data, source, this); } } } @@ -1291,7 +1341,7 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co // if t == -1 we search the current event... { singleLock s(cache_lock); - uniqueEPGKey key(service); + uniqueEPGKey key(handleGroup(service)); // check if EPG for this service is ready... eventCache::iterator It = eventDB.find( key ); @@ -1367,7 +1417,7 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, eP RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result ) { singleLock s(cache_lock); - uniqueEPGKey key( service ); + uniqueEPGKey key(handleGroup(service)); eventCache::iterator It = eventDB.find( key ); if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached? @@ -1381,7 +1431,7 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, else { result = 0; - eDebug("event %04x not found in epgcache", event_id); + eDebug("[EPGC] event %04x not found in epgcache", event_id); } } return -1; @@ -1424,7 +1474,7 @@ RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes) { - eventCache::iterator It = eventDB.find( service ); + eventCache::iterator It = eventDB.find(handleGroup(service)); 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(); @@ -1448,7 +1498,7 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, } else m_timemap_cursor = It->second.second.begin(); - const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service; + const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)handleGroup(service); currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get(); return 0; } @@ -1496,9 +1546,9 @@ RESULT eEPGCache::getNextTimeEntry(ePtr &result) return -1; } -void fillTuple(PyObject *tuple, char *argstring, int argcount, PyObject *service, ePtr &ptr, PyObject *nowTime, PyObject *service_name ) +void fillTuple(ePyObject tuple, char *argstring, int argcount, ePyObject service, ePtr &ptr, ePyObject nowTime, ePyObject service_name ) { - PyObject *tmp=NULL; + ePyObject tmp; int pos=0; while(pos < argcount) { @@ -1509,22 +1559,22 @@ void fillTuple(PyObject *tuple, char *argstring, int argcount, PyObject *service tmp = PyLong_FromLong(0); break; case 'I': // Event Id - tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : NULL; + tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : ePyObject(); break; case 'B': // Event Begin Time - tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : NULL; + tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject(); break; case 'D': // Event Duration - tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL; + tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject(); break; case 'T': // Event Title - tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL; + tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject(); break; case 'S': // Event Short Description - tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL; + tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject(); break; case 'E': // Event Extended Description - tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL; + tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject(); break; case 'C': // Current Time tmp = nowTime; @@ -1549,13 +1599,13 @@ void fillTuple(PyObject *tuple, char *argstring, int argcount, PyObject *service } } -PyObject *handleEvent(ePtr &ptr, PyObject *dest_list, char* argstring, int argcount, PyObject *service, PyObject *nowTime, PyObject *service_name, PyObject *convertFunc, PyObject *convertFuncArgs) +int handleEvent(ePtr &ptr, ePyObject dest_list, 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); - PyObject *result = PyObject_CallObject(convertFunc, convertFuncArgs); - if (result == NULL) + ePyObject result = PyObject_CallObject(convertFunc, convertFuncArgs); + if (result) { if (service_name) Py_DECREF(service_name); @@ -1563,14 +1613,17 @@ PyObject *handleEvent(ePtr &ptr, PyObject *dest_list, char* argst Py_DECREF(nowTime); Py_DECREF(convertFuncArgs); Py_DECREF(dest_list); - return result; + PyErr_SetString(PyExc_StandardError, + "error in convertFunc execute"); + eDebug("error in convertFunc execute"); + return -1; } PyList_Append(dest_list, result); Py_DECREF(result); } else { - PyObject *tuple = PyTuple_New(argcount); + ePyObject tuple = PyTuple_New(argcount); fillTuple(tuple, argstring, argcount, service, ptr, nowTime, service_name); PyList_Append(dest_list, tuple); Py_DECREF(tuple); @@ -1602,9 +1655,9 @@ PyObject *handleEvent(ePtr &ptr, PyObject *dest_list, char* argst // when type is time then it is the start_time ( 0 for now_time ) // the fourth is the end_time .. ( optional .. for query all events in time range) -PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) +PyObject *eEPGCache::lookupEvent(ePyObject list, ePyObject convertFunc) { - PyObject *convertFuncArgs=NULL; + ePyObject convertFuncArgs; int argcount=0; char *argstring=NULL; if (!PyList_Check(list)) @@ -1625,7 +1678,7 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) } else { - PyObject *argv=PyList_GET_ITEM(list, 0); // borrowed reference! + ePyObject argv=PyList_GET_ITEM(list, 0); // borrowed reference! if (PyString_Check(argv)) { argstring = PyString_AS_STRING(argv); @@ -1648,17 +1701,17 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) convertFuncArgs = PyTuple_New(argcount); } - PyObject *nowTime = strchr(argstring, 'C') ? + ePyObject nowTime = strchr(argstring, 'C') ? PyLong_FromLong(eDVBLocalTimeHandler::getInstance()->nowTime()) : - NULL; + ePyObject(); bool must_get_service_name = strchr(argstring, 'N') ? true : false; // create dest list - PyObject *dest_list=PyList_New(0); + ePyObject dest_list=PyList_New(0); while(listSize > listIt) { - PyObject *item=PyList_GET_ITEM(list, listIt++); // borrowed reference! + ePyObject item=PyList_GET_ITEM(list, listIt++); // borrowed reference! if (PyTuple_Check(item)) { bool service_changed=false; @@ -1668,10 +1721,10 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) int minutes=0; int tupleSize=PyTuple_Size(item); int tupleIt=0; - PyObject *service=NULL; + ePyObject service; while(tupleSize > tupleIt) // parse query args { - PyObject *entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference! + ePyObject entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference! switch(tupleIt++) { case 0: @@ -1703,7 +1756,7 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) break; } } - eServiceReference ref(PyString_AS_STRING(service)); + eServiceReference ref(handleGroup(eServiceReference(PyString_AS_STRING(service)))); if (ref.type != eServiceReference::idDVB) { eDebug("service reference for epg query is not valid"); @@ -1727,7 +1780,7 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) } } - PyObject *service_name=NULL; + ePyObject service_name; if (must_get_service_name) { ePtr sptr; @@ -1755,9 +1808,11 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) ePtr ptr; while (!getNextTimeEntry(ptr)) { - PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs); - if (ret) - return ret; + if (handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) + { + Unlock(); + return 0; // error + } } } Unlock(); @@ -1772,9 +1827,8 @@ PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) else lookupEventTime(ref, stime, ptr, type); } - PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs); - if (ret) - return ret; + if (handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs)) + return 0; // error } if (service_changed) Py_DECREF(service); @@ -1791,9 +1845,9 @@ skip_entry: return dest_list; } -void fillTuple2(PyObject *tuple, const char *argstring, int argcount, eventData *evData, ePtr &ptr, PyObject *service_name, PyObject *service_reference) +void fillTuple2(ePyObject tuple, const char *argstring, int argcount, eventData *evData, ePtr &ptr, ePyObject service_name, ePyObject service_reference) { - PyObject *tmp=NULL; + ePyObject tmp; int pos=0; while(pos < argcount) { @@ -1808,24 +1862,24 @@ void fillTuple2(PyObject *tuple, const char *argstring, int argcount, eventData break; case 'B': // Event Begin Time if (ptr) - tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : NULL; + tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : ePyObject(); else tmp = PyLong_FromLong(evData->getStartTime()); break; case 'D': // Event Duration if (ptr) - tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL; + tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : ePyObject(); else tmp = PyLong_FromLong(evData->getDuration()); break; case 'T': // Event Title - tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL; + tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : ePyObject(); break; case 'S': // Event Short Description - tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL; + tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : ePyObject(); break; case 'E': // Event Extended Description - tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL; + tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : ePyObject(); break; case 'R': // service reference string tmp = service_reference; @@ -1871,9 +1925,9 @@ void fillTuple2(PyObject *tuple, const char *argstring, int argcount, eventData // 0 = case sensitive (CASE_CHECK) // 1 = case insensitive (NO_CASECHECK) -PyObject *eEPGCache::search(PyObject *arg) +PyObject *eEPGCache::search(ePyObject arg) { - PyObject *ret = 0; + ePyObject ret; int descridx = -1; __u32 descr[512]; int eventid = -1; @@ -1889,7 +1943,7 @@ PyObject *eEPGCache::search(PyObject *arg) int tuplesize=PyTuple_Size(arg); if (tuplesize > 0) { - PyObject *obj = PyTuple_GET_ITEM(arg,0); + ePyObject obj = PyTuple_GET_ITEM(arg,0); if (PyString_Check(obj)) { argcount = PyString_GET_SIZE(obj); @@ -1920,7 +1974,7 @@ PyObject *eEPGCache::search(PyObject *arg) querytype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 2)); if (tuplesize > 4 && querytype == 0) { - PyObject *obj = PyTuple_GET_ITEM(arg, 3); + ePyObject obj = PyTuple_GET_ITEM(arg, 3); if (PyString_Check(obj)) { refstr = PyString_AS_STRING(obj); @@ -1977,7 +2031,7 @@ PyObject *eEPGCache::search(PyObject *arg) } else if (tuplesize > 4 && (querytype == 1 || querytype == 2) ) { - PyObject *obj = PyTuple_GET_ITEM(arg, 3); + ePyObject obj = PyTuple_GET_ITEM(arg, 3); if (PyString_Check(obj)) { int casetype = PyLong_AsLong(PyTuple_GET_ITEM(arg, 4)); @@ -2080,7 +2134,7 @@ PyObject *eEPGCache::search(PyObject *arg) if (descridx > -1) { int maxcount=maxmatches; - eServiceReferenceDVB ref(refstr?refstr:""); + eServiceReferenceDVB ref(refstr?(const eServiceReferenceDVB&)handleGroup(eServiceReference(refstr)):eServiceReferenceDVB("")); // ref is only valid in SIMILAR_BROADCASTING_SEARCH // in this case we start searching with the base service bool first = ref.valid() ? true : false; @@ -2094,13 +2148,14 @@ PyObject *eEPGCache::search(PyObject *arg) ++cit; continue; } - PyObject *service_name=0; - PyObject *service_reference=0; + ePyObject service_name; + ePyObject service_reference; timeMap &evmap = cit->second.second; // check all events for (timeMap::iterator evit(evmap.begin()); evit != evmap.end() && maxcount; ++evit) { - if (evit->second->getEventID() == eventid) + int evid = evit->second->getEventID(); + if ( evid == eventid) continue; __u8 *data = evit->second->EITdata; int tmp = evit->second->ByteSize-12; @@ -2129,7 +2184,7 @@ PyObject *eEPGCache::search(PyObject *arg) ePtr ptr; if (needServiceEvent) { - lookupEventId(ref, evit->first, ptr); + lookupEventId(ref, evid, ptr); if (!ptr) eDebug("event not found !!!!!!!!!!!"); } @@ -2160,7 +2215,7 @@ PyObject *eEPGCache::search(PyObject *arg) if (!ret) ret = PyList_New(0); // create tuple - PyObject *tuple = PyTuple_New(argcount); + ePyObject tuple = PyTuple_New(argcount); // fill tuple fillTuple2(tuple, argstring, argcount, evit->second, ptr, service_name, service_reference); PyList_Append(ret, tuple); @@ -2346,13 +2401,21 @@ void eEPGCache::privateSectionRead(const uniqueEPGKey ¤t_service, const __ 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; +// WORKAROUND for wrong transmitted epg data (01.08.2006) + if ( onid == 0x85 ) + { + switch( (tsid << 16) | sid ) + { + case 0x01030b: sid = 0x1b; tsid = 4; break; // Premiere Win + case 0x0300f0: sid = 0xe0; tsid = 2; break; + case 0x0300f1: sid = 0xe1; tsid = 2; break; + case 0x0300f5: sid = 0xdc; break; + case 0x0400d2: sid = 0xe2; tsid = 0x11; break; + case 0x1100d3: sid = 0xe3; break; + } + } //////////////////////////////////////////// - + uniqueEPGKey service( sid, onid, tsid ); descr_len -= 6; while( descr_len > 0 ) @@ -2442,7 +2505,7 @@ void eEPGCache::channel_data::startPrivateReader() mask.flags = eDVBSectionFilterMask::rfCRC; mask.data[0] = 0xA0; mask.mask[0] = 0xFF; - eDebug("start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion); + eDebug("[EPGC] start privatefilter for pid %04x and version %d", m_PrivatePid, m_PrevVersion); if (m_PrevVersion != -1) { mask.data[3] = m_PrevVersion << 1; @@ -2457,21 +2520,21 @@ void eEPGCache::channel_data::startPrivateReader() void eEPGCache::channel_data::readPrivateData( const __u8 *data) { - if (!data) - eDebug("get Null pointer from section reader !!"); - else + if ( seenPrivateSections.find( data[6] ) == seenPrivateSections.end() ) { - if ( seenPrivateSections.find( data[6] ) == seenPrivateSections.end() ) - { - cache->privateSectionRead(m_PrivateService, data); - seenPrivateSections.insert(data[6]); - } - if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) ) - { - eDebug("[EPGC] private finished"); - m_PrevVersion = (data[5] & 0x3E) >> 1; - startPrivateReader(); - } + cache->privateSectionRead(m_PrivateService, data); + seenPrivateSections.insert(data[6]); + } + if ( seenPrivateSections.size() == (unsigned int)(data[7] + 1) ) + { + eDebug("[EPGC] private finished"); + eDVBChannelID chid = channel->getChannelID(); + 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(); + m_PrevVersion = (data[5] & 0x3E) >> 1; + startPrivateReader(); } } @@ -2570,8 +2633,10 @@ void eEPGCache::channel_data::timeMHW2DVB( u_char day, u_char hours, u_char minu void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, std::string sumText, const __u8 *data) // 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() - __u8 name[24]; + bool isMHW2 = itTitle->second.mhw2_mjd_hi || itTitle->second.mhw2_mjd_lo || + itTitle->second.mhw2_duration_hi || itTitle->second.mhw2_duration_lo; eit_t *packet = (eit_t *) data; packet->table_id = 0x50; @@ -2589,7 +2654,8 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator packet->segment_last_section_number = 0; // eEPGCache::sectionRead() will dig this for the moment packet->segment_last_table_id = 0x50; - std::string prog_title = (char *) delimitName( itTitle->second.title, name, 23 ); + __u8 *title = isMHW2 ? ((__u8*)(itTitle->second.title))-4 : (__u8*)itTitle->second.title; + std::string prog_title = (char *) delimitName( title, name, isMHW2 ? 33 : 23 ); int prog_title_length = prog_title.length(); int packet_length = EIT_SIZE + EIT_LOOP_SIZE + EIT_SHORT_EVENT_DESCRIPTOR_SIZE + @@ -2599,9 +2665,22 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator event_data->event_id_hi = (( itTitle->first ) >> 8 ) & 0xFF; event_data->event_id_lo = ( itTitle->first ) & 0xFF; - timeMHW2DVB( itTitle->second.day, itTitle->second.hours, itTitle->second.minutes, + if (isMHW2) + { + u_char *data = (u_char*) event_data; + data[2] = itTitle->second.mhw2_mjd_hi; + data[3] = itTitle->second.mhw2_mjd_lo; + data[4] = itTitle->second.mhw2_hours; + data[5] = itTitle->second.mhw2_minutes; + data[6] = itTitle->second.mhw2_seconds; + timeMHW2DVB( HILO(itTitle->second.mhw2_duration), data+7 ); + } + else + { + timeMHW2DVB( itTitle->second.dh.day, itTitle->second.dh.hours, itTitle->second.ms.minutes, (u_char *) event_data + 2 ); - timeMHW2DVB( HILO(itTitle->second.duration), (u_char *) event_data+7 ); + timeMHW2DVB( HILO(itTitle->second.duration), (u_char *) event_data+7 ); + } event_data->running_status = 0; event_data->free_CA_mode = 0; @@ -2616,9 +2695,8 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator short_event_descriptor->language_code_2 = 'n'; short_event_descriptor->language_code_3 = 'g'; short_event_descriptor->event_name_length = prog_title_length; - delimitName( itTitle->second.title, name, 23 ); u_char *event_name = (u_char *) short_event_descriptor + EIT_SHORT_EVENT_DESCRIPTOR_SIZE; - memcpy(event_name, name, prog_title_length); + memcpy(event_name, prog_title.c_str(), prog_title_length); // Set text length event_name[prog_title_length] = 0; @@ -2665,22 +2743,26 @@ void eEPGCache::channel_data::storeTitle(std::map<__u32, mhw_title_t>::iterator } } } - // Add content descriptor - u_char *descriptor = (u_char *) data + packet_length; - packet_length += 4; - descr_ll += 4; - int content_id = 0; - std::string content_descr = (char *) delimitName( m_themes[itTitle->second.theme_id].name, name, 15 ); - if ( content_descr.find( "FILM" ) != std::string::npos ) - content_id = 0x10; - else if ( content_descr.find( "SPORT" ) != std::string::npos ) - content_id = 0x40; + if (!isMHW2) + { + // Add content descriptor + u_char *descriptor = (u_char *) data + packet_length; + packet_length += 4; + descr_ll += 4; + + int content_id = 0; + std::string content_descr = (char *) delimitName( m_themes[itTitle->second.theme_id].name, name, 15 ); + if ( content_descr.find( "FILM" ) != std::string::npos ) + content_id = 0x10; + else if ( content_descr.find( "SPORT" ) != std::string::npos ) + content_id = 0x40; - descriptor[0] = 0x54; - descriptor[1] = 2; - descriptor[2] = content_id; - descriptor[3] = 0; + descriptor[0] = 0x54; + descriptor[1] = 2; + descriptor[2] = content_id; + descriptor[3] = 0; + } event_data->descriptors_loop_length_hi = (descr_ll & 0xf00)>>8; event_data->descriptors_loop_length_lo = (descr_ll & 0xff); @@ -2706,11 +2788,33 @@ void eEPGCache::channel_data::startMHWReader(__u16 pid, __u8 tid) // eDebug("start 0x%02x 0x%02x", pid, tid); } +void eEPGCache::channel_data::startMHWReader2(__u16 pid, __u8 tid, int ext) +{ + m_MHWFilterMask2.pid = pid; + m_MHWFilterMask2.data[0] = tid; + if (ext != -1) + { + m_MHWFilterMask2.data[1] = ext; + m_MHWFilterMask2.mask[1] = 0xFF; +// eDebug("start 0x%03x 0x%02x 0x%02x", pid, tid, ext); + } + else + { + m_MHWFilterMask2.data[1] = 0; + m_MHWFilterMask2.mask[1] = 0; +// eDebug("start 0x%02x 0x%02x", pid, tid); + } + m_MHWReader2->start(m_MHWFilterMask2); +} + void eEPGCache::channel_data::readMHWData(const __u8 *data) { + if ( m_MHWReader2 ) + m_MHWReader2->stop(); + if ( state > 1 || // aborted // have si data.. so we dont read mhw data - (haveData & (SCHEDULE|SCHEDULE_OTHER)) ) + (haveData & (SCHEDULE|SCHEDULE_OTHER)) ) { eDebug("[EPGC] mhw aborted %d", state); } @@ -2728,7 +2832,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) } haveData |= MHW; - eDebug("channels finished %d found", m_channels.size()); + eDebug("[EPGC] mhw %d channels found", m_channels.size()); // Channels table has been read, start reading the themes table. startMHWReader(0xD3, 0x92); @@ -2759,7 +2863,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) m_themes[idx+sub_idx] = *theme; } - eDebug("themes finished %d found", m_themes.size()); + eDebug("[EPGC] mhw %d themes found", m_themes.size()); // Themes table has been read, start reading the titles table. startMHWReader(0xD2, 0x90); startTimeout(4000); @@ -2775,16 +2879,20 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) else { // Create unique key per title - __u32 title_id = ((title->channel_id)<<16)|((title->day)<<13)|((title->hours)<<8)| - (title->minutes); + __u32 title_id = ((title->channel_id)<<16)|((title->dh.day)<<13)|((title->dh.hours)<<8)| + (title->ms.minutes); __u32 program_id = ((title->program_id_hi)<<24)|((title->program_id_mh)<<16)| ((title->program_id_ml)<<8)|(title->program_id_lo); if ( m_titles.find( title_id ) == m_titles.end() ) { startTimeout(4000); + title->mhw2_mjd_hi = 0; + title->mhw2_mjd_lo = 0; + title->mhw2_duration_hi = 0; + title->mhw2_duration_lo = 0; m_titles[ title_id ] = *title; - if ( (title->summary_available) && (m_program_ids.find(program_id) == m_program_ids.end()) ) + 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; return; // Continue reading of the current table. @@ -2797,7 +2905,7 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) // Titles table has been read, there are summaries to read. // Start reading summaries, store corresponding titles on the fly. startMHWReader(0xD3, 0x90); - eDebug("titles finished %d titles, %d with summary", + eDebug("[EPGC] mhw %d titles(%d with summary) found", m_titles.size(), m_program_ids.size()); startTimeout(4000); @@ -2847,13 +2955,13 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) return; // Continue reading of the current table. } } + eDebug("[EPGC] mhw finished(%ld) %d summaries not found", + eDVBLocalTimeHandler::getInstance()->nowTime(), + m_program_ids.size()); // Summaries have been read, titles that have summaries have been stored. // Now store titles that do not have summaries. for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++) storeTitle( itTitle, "", data ); - eDebug("[EPGC] mhw finished(%ld) %d summaries left", - eDVBLocalTimeHandler::getInstance()->nowTime(), - m_program_ids.size()); isRunning &= ~MHW; m_MHWConn=0; if ( m_MHWReader ) @@ -2862,4 +2970,292 @@ void eEPGCache::channel_data::readMHWData(const __u8 *data) finishEPG(); } +void eEPGCache::channel_data::readMHWData2(const __u8 *data) +{ + int dataLen = (((data[1]&0xf) << 8) | data[2]) + 3; + + if ( m_MHWReader ) + m_MHWReader->stop(); + + if ( state > 1 || // aborted + // have si data.. so we dont read mhw data + (haveData & (eEPGCache::SCHEDULE|eEPGCache::SCHEDULE_OTHER)) ) + { + eDebug("[EPGC] mhw2 aborted %d", state); + } + 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 ptr = 121 + 6 * num_channels; + if( dataLen > ptr ) + { + for( int chid = 0; chid < num_channels; ++chid ) + { + ptr += ( data[ptr] & 0x0f ) + 1; + if( dataLen < ptr ) + goto abort; + } + } + else + goto abort; + } + else + goto abort; + // data seems consistent... + const __u8 *tmp = data+121; + for (int i=0; i < num_channels; ++i) + { + mhw_channel_name_t channel; + 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); + tmp+=2; + } + for (int i=0; i < num_channels; ++i) + { + mhw_channel_name_t &channel = m_channels[i]; + int channel_name_len=*(tmp++)&0x0f; + int x=0; + for (; x < channel_name_len; ++x) + channel.name[x]=*(tmp++); + channel.name[x+1]=0; + } + 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) + { + // Themes table + eDebug("[EPGC] mhw2 themes nyi"); + } + else if (m_MHWFilterMask2.pid == 0x234 && m_MHWFilterMask2.data[0] == 0xe6) + // Titles table + { + int pos=18; + bool valid=true; + int len = ((data[1]&0xf)<<8) + data[2] - 16; + bool finish=false; + if(data[dataLen-1] != 0xff) + return; + while( pos < dataLen ) + { + 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; + } + } + // data seems consistent... + mhw_title_t title; + pos = 18; + while (pos < len) + { + 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_duration_hi = (duration&0xFF00) >> 8; + title.mhw2_duration_lo = duration&0xFF; + __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); + pos += 11 + slen; +// 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; + +// 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() ) + { + startTimeout(4000); + m_titles[ title_id ] = title; + if (summary_id != 0xFFFF && // no summary avail + m_program_ids.find(summary_id) == m_program_ids.end()) + { + m_program_ids[ summary_id ] = title_id; + } + } + else + { + if ( !checkTimeout() ) + continue; // Continue reading of the current table. + finish=true; + break; + } + } +start_summary: + if (finish) + { + eDebug("[EPGC] mhw2 %d titles(%d with summary) found", m_titles.size(), m_program_ids.size()); + if (!m_program_ids.empty()) + { + // Titles table has been read, there are summaries to read. + // Start reading summaries, store corresponding titles on the fly. + startMHWReader2(0x236, 0x96); + startTimeout(4000); + return; + } + } + else + return; + } + 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 ) + { + loop = data[12]; + pos = 13 + loop; + if( dataLen > pos ) + { + loop = data[pos] & 0x0f; + pos += 1; + if( dataLen > pos ) + { + len = 0; + for( ; loop > 0; --loop ) + { + if( dataLen > (pos+len) ) + { + lenline = data[pos+len]; + len += lenline + 1; + } + 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 + { + startTimeout(4000); + std::string the_text = (char *) (data + pos + 1); + + // 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. + } + } + } + if (isRunning & eEPGCache::MHW) + { + if ( m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 0) + { + // Channels table has been read, start reading the themes table. + startMHWReader2(0x231, 0xC8, 1); + return; + } + else if ( m_MHWFilterMask2.pid == 0x231 && m_MHWFilterMask2.data[0] == 0xC8 && m_MHWFilterMask2.data[1] == 1) + { + // Themes table has been read, start reading the titles table. + startMHWReader2(0x234, 0xe6); + return; + } + else + { + // Summaries have been read, titles that have summaries have been stored. + // Now store titles that do not have summaries. + for (std::map<__u32, mhw_title_t>::iterator itTitle(m_titles.begin()); itTitle != m_titles.end(); itTitle++) + storeTitle( itTitle, "", data ); + eDebug("[EPGC] mhw2 finished(%ld) %d summaries not found", + eDVBLocalTimeHandler::getInstance()->nowTime(), + m_program_ids.size()); + } + } +abort: + isRunning &= ~MHW; + m_MHWConn2=0; + if ( m_MHWReader2 ) + m_MHWReader2->stop(); + if (haveData) + finishEPG(); +} #endif