#include #include #include #include #include #include #include #include #include "kaffeinepremiereepg.h" #include "kaffeinepremiereepg.moc" #define STARTTIME_BIAS (20*60) #define POLY 0xA001 // CRC16 K_EXPORT_COMPONENT_FACTORY (libkaffeinepremiereepg, KParts::GenericFactory) KaffeinePremiereEpg::KaffeinePremiereEpg( QWidget*, const char*, QObject* parent, const char* name, const QStringList& ) : KaffeineEpgPlugin(parent,name) { setInstance(KParts::GenericFactory::instance()); } KaffeinePremiereEpg::~KaffeinePremiereEpg() { isRunning = false; if ( !wait(2000) ) { terminate(); wait(); } } KAboutData *KaffeinePremiereEpg::createAboutData() { KAboutData* aboutData = new KAboutData( "kaffeinepremiereepg", I18N_NOOP("KaffeinePremiereEpg"), "0.1", I18N_NOOP("A EPG plugin for Kaffeine."), KAboutData::License_GPL, "(c) 2007, The Author.", 0, "", ""); aboutData->addAuthor("The Author.",0, "somewhere@someland.org"); return aboutData; } bool KaffeinePremiereEpg::go( QString src, int freqKHz ) { fprintf(stderr,"premiereEPG go()\n"); if ( !src.upper().contains("ASTRA") || !src.upper().contains("19.2") ) { fprintf(stderr,"premiereEPG not on Astra-19.2\n"); return true; // don't start if not on astra-19.2 } if ( freqKHz>11716 && freqKHz<11721 ) pid = 2834; else { fprintf(stderr,"premiereEPG wrong freq = %d\n", freqKHz); return false; // don't start if not on right transponder } if ( !setFilter( pid, 0, 1000) ) { fprintf(stderr,"premiereEPG can't set filter\n"); return false; } currentSrc = events->getEventSource( src ); isRunning = true; start(); fprintf(stderr,"premiereEPG %d:%d:%d started\n", adapter, tuner, pid); return true; } void KaffeinePremiereEpg::stop() { if ( !isRunning ) return; isRunning = false; if ( !wait(2000) ) { terminate(); wait(); fprintf(stderr,"premiereEPG %d:%d:%d terminated\n", adapter, tuner, pid); } else fprintf(stderr,"premiereEPG %d:%d:%d ended\n", adapter, tuner, pid); stopFilter(); } void KaffeinePremiereEpg::run() { int n=0, tid; int skip=0; setpriority(PRIO_PROCESS, 0, 19); while ( isRunning ) { if ( !isRunning ) break; if ( poll(pf,1,1000)>0 ){ if ( pf[0].revents & POLLIN ){ n = read( fdDemux, secbuf, 4096 ); skip = 0; } else skip++; } else skip++; if (skip) continue; if ( n<16 ) continue; else readSize = n; if ( !isRunning ) break; if ( getBits(secbuf,0,8) == 0xa0 ) { tableCIT( secbuf ); } } } bool KaffeinePremiereEpg::extEventForCID(unsigned char *buf, EventDesc *desc ) { int loop, len1, len2; unsigned char *b = buf; QString s; if ( !safeLen( b+7 ) ) return false; loop = getBits(b+6,0,8); b +=7; while ( loop>0 ) { if ( !safeLen( b+1 ) ) return false; len1 = getBits(b,0,8); if ( !safeLen( b+1+len1 ) ) return false; s = getText(b+1,len1); if ( !safeLen( b+1+len1+1 ) ) return false; len2 = getBits(b+1+len1,0,8); if ( !safeLen( buf+2+len1+len2 ) ) return false; if ( !s.isEmpty() ) s = s+" : "; s = s+getText(b+2+len1,len2); desc->extEvents.append( new QString( s ) ); b +=(2+len1+len2); loop -=(2+len1+len2); } if ( !safeLen( b+1 ) ) return false; len1 = getBits(b,0,8); if ( !safeLen( b+1+len1 ) ) return false; s = getText(b+1,len1); desc->extEvents.append( new QString( s ) ); return true; } bool KaffeinePremiereEpg::shortEventForCID(unsigned char* buf, EventDesc *desc) { QString name, text; int len, len2; ShortEvent *ev; if ( !safeLen( buf+6 ) ) return false; len = getBits(buf,40,8); if ( !safeLen( buf+6+len ) ) return false; name = getText( buf+6, len ); if ( !safeLen( buf+6+len+1 ) ) return false; len2 = getBits(buf+6+len,0,8); if ( !safeLen( buf+7+len+len2 ) ) return false; text = getText( buf+7+len, len2); if ( desc->title.isEmpty() ) { desc->title=name; desc->subtitle=text; //qDebug("%d: %s", pid, desc->title.latin1()); return true; } desc->shortEvents.append( new ShortEvent() ); ev = desc->shortEvents.getLast(); ev->name = name; ev->text = text; return true; } unsigned int KaffeinePremiereEpg::crc16(unsigned int crc, unsigned char const *p, int len) { while(len--) { crc^=*p++; for(int i=0; i<8; i++) crc=(crc&1) ? (crc>>1)^POLY : (crc>>1); } return crc&0xFFFF; } bool KaffeinePremiereEpg::contentTransmissionTable( unsigned char* buffer, EventDesc *desc ) { // every 0xf2 table has multiple dates and times for one SID // for every time we need an event_id and a seperate EventDesc unsigned char *buf = buffer; int len = buf[1]; int start_tm_loop; int tsid, nid, sid; int content_id; unsigned short event_id; QDateTime start, cur, dt; QDate start_dt; QTime start_tm; EventSid *slist; QPtrList *currentEvents; bool dontadd = false; EventDesc *newDesc = 0, *itdesc = 0; tsid = getBits(buf, 16, 16); nid = getBits(buf, 32, 16); sid = getBits(buf, 48, 16); buf += 8; len -= 6; slist = currentSrc->getEventSid(nid, tsid, sid); if(!slist) return false; slist->lock(); currentEvents = slist->getEvents(); QPtrListIterator it( *currentEvents ); unsigned int cdt = QDateTime::currentDateTime().toTime_t(); bool parse = true; int optCount = 0; while(len > 0) { start_dt = getDate(buf); start_tm_loop = getBits(buf, 16, 8); buf += 3; len -= 3; optCount++; int index = 0; for(; start_tm_loop > 0; start_tm_loop -= 3) { int h, m, s; s = ((getBits(buf,16,4)*10)+getBits(buf,20,4))%60; m = ((getBits(buf,8,4)*10)+getBits(buf,12,4))%60; h = ((getBits(buf,0,4)*10)+getBits(buf,4,4))%24; start_tm = QTime(h, m, s); QTime local = QTime::currentTime(Qt::LocalTime); QTime loc_utc = QTime::currentTime(Qt::UTC); int diff = loc_utc.secsTo(local); /*printf("local: %s, loc_utc: %s, diff: %d, time: %s", local.toString("hh:mm:ss").latin1(), loc_utc.toString("hh:mm:ss").latin1(), diff, start_tm.toString("hh:mm:ss").latin1());*/ start_tm = start_tm.addSecs(diff); //printf(", conv: %s\n", start_tm.toString("hh:mm:ss").latin1()); start = QDateTime( start_dt, start_tm ); content_id = desc->eid; // event_id calculation by Stefan Huelswitt, vdr-premiereepg unsigned int crc[3]; bool isOpt = false; if(index++==0) isOpt = true; crc[0] = content_id; crc[1] = isOpt ? optCount : 0; crc[2] = start.toTime_t() / STARTTIME_BIAS; event_id = ((('P'<<8)|'W')<<16) | crc16(0,(unsigned char *)crc,sizeof(crc)); //event_id = content_id ^ (start.toTime_t() & 0xFFFFF800); newDesc = new EventDesc(*desc); // epg fix by Stefan Huelswitt, vdr-premiereepg if(nid==133) { if (tsid==0x03 && sid==0xf0) { tsid=0x02; sid=0xe0; } else if(tsid==0x03 && sid==0xf1) { tsid=0x02; sid=0xe1; } else if(tsid==0x03 && sid==0xf5) { tsid=0x03; sid=0xdc; } else if(tsid==0x04 && sid==0xd2) { tsid=0x11; sid=0xe2; } else if(tsid==0x11 && sid==0xd3) { tsid=0x11; sid=0xe3; } else if(tsid==0x01 && sid==0xd4) { tsid=0x04; sid=0xe4; } // new shift due to deactivated SID 212 //if(sid==0xd4) sid=0xe4; //as 0xd4 is no longer in service, we can map this directly (tsid 0x01 seems to be wrong) } newDesc->eid = event_id; newDesc->tsid = tsid; newDesc->nid = nid; newDesc->sid = sid; newDesc->startDateTime = start; parse = true; it.toFirst(); while ( (itdesc = it.current()) != 0 ) { if( itdesc->sid == sid) { if( itdesc->startDateTime == start || itdesc->eid == event_id ) { parse = false; break; } /*else { if ( (cdt - itdesc->loop) < 300 ) { // only reparse events every 300 seconds parse = false; } else parse = true; break; }*/ } ++it; } if(parse) { for( int i=0; i < (int)currentEvents->count(); i++) { itdesc = currentEvents->at(i); /*if( itdesc->startDateTime == start || itdesc->eid == event_id ) { dontadd = true; break; } else {*/ if( start < itdesc->startDateTime){ currentEvents->insert(i, newDesc); break; } itdesc = 0; //dontadd = false; //} } if(!itdesc)// && dontadd == false) currentEvents->append(newDesc); } cur = QDateTime::currentDateTime(); dt = start; int sec = newDesc->duration.hour()*3600+newDesc->duration.minute()*60+newDesc->duration.second(); if ( dt.addSecs( sec ) < cur) currentEvents->remove( newDesc ); else newDesc->source = currentSrc->getSource(); buf += 3; len -= 3; } } slist->unlock(); return true; } bool KaffeinePremiereEpg::tableCIT( unsigned char* buffer ) { unsigned char* buf = buffer; int sec_length, sec_num, sec_last; int content_id, discr_sec_length; QTime dur; sec_length = getBits(buf, 12, 12); sec_num = getBits(buf, 48, 8); sec_last = getBits(buf, 56, 8); buf += 8; sec_length -= 5; content_id = getBits(buf, 0, 32); //duration = getBits(buf, 32, 24); dur = getTime(buf+4); discr_sec_length = getBits(buf, 60, 12); buf += 9; sec_length -= 9; EventDesc *desc = 0; desc = new EventDesc(); int event_id = 0; int sanity_count = 0; while (sec_length > 4) // traverse all descriptors, remember, there might be multiple sub-tables { int descr_id = (int)buf[0]; int descr_length = ((int)buf[1]) + 2; unsigned int cdt = QDateTime::currentDateTime().toTime_t(); switch(buf[0]) { case 0x4d: //short_event { shortEventForCID(buf,desc); } break; case 0x4e: //extended_event { extEventForCID(buf,desc); } break; case 0xf2: //privat_content_transmission { desc->eid = content_id; //pass temporary content_id desc->duration = dur; //desc->running = 1; desc->tid = buf[0]; desc->lsn = sec_last; desc->sn = sec_num; desc->loop = cdt; contentTransmissionTable(buf,desc); } break; } if(sec_length < descr_length) break; buf += descr_length; sec_length -= descr_length; } return true; }