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