/* * dvbevents.cpp * * Copyright (C) 2003-2007 Christophe Thommeret * * This program is free software; you can redistribute it and/or modify * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include #include #include #include #include #include "dvbevents.h" DVBevents::DVBevents( TQString devType, int anum, int tnum, const TQString &charset, EventTable *table ) : KaffeineDVBsection( anum, tnum, charset ) { events = table; KaffeineEpgPlugin *plug; TQString plugName; int error; KTrader::OfferList offers = KTrader::self()->query("KaffeineEpgPlugin"); KTrader::OfferList::Iterator end( offers.end() ); for ( KTrader::OfferList::Iterator it=offers.begin(); it!=end; ++it ) { error = 0; KService::Ptr ptr = (*it); if ( !ptr->name().tqcontains(devType) ) continue; plug = KParts::ComponentFactory::createPartInstanceFromService(ptr, 0, ptr->name().ascii(), 0, 0, 0, &error ); plugName = ptr->desktopEntryName(); if (error > 0) { fprintf( stderr, "Loading of EPG plugin %s failed: %s\n", plugName.ascii(), KLibLoader::self()->lastErrorMessage().ascii() ); plug = NULL; } else { plugs.append( plug ); plug->setTable( table ); plug->initSection( anum, tnum, charset ); plugNames.append( plugName ); } } fprintf( stderr, "%d EPG plugins loaded for device %d:%d.\n", plugs.count(), anum, tnum ); } DVBevents::~DVBevents() { int i; isRunning = false; if ( !wait(2000) ) { terminate(); wait(); } for ( i=0; i<(int)plugs.count(); ++i ) { plugs.at(i)->stop(); KService::Ptr service = KService::serviceByDesktopName( plugNames[i] ); KLibLoader::self()->unloadLibrary( service->library().ascii() ); } } bool DVBevents::shortEventDesc( unsigned char *buf, EventDesc *desc ) { TQString 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; return true; } desc->shortEvents.append( new ShortEvent() ); ev = desc->shortEvents.getLast(); ev->name = name; ev->text = text; return true; } bool DVBevents::extEventDesc( unsigned char *buf, EventDesc *desc ) { int loop, len1, len2; unsigned char *b = buf; TQString 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 TQString( 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 TQString( s ) ); return true; } bool DVBevents::tableEIT( unsigned char* buffer ) { unsigned char* buf = buffer; unsigned int length, loop, sid, tid, eid, tsid, sn, lsn, nid; int i, sec; EventDesc *desc=0, *itdesc=0; EventSid *slist; TQPtrList *currentEvents; bool nodesc, parse; TQDateTime start, cur, dt; unsigned int cdt = TQDateTime::tqcurrentDateTime().toTime_t(); tid = getBits(buf,0,8); length = getBits(buf,12,12); sid = getBits(buf,24,16); sn = getBits(buf,48,8); lsn = getBits(buf,56,8); tsid = getBits(buf,64,16); nid = getBits(buf,80,16); length -=11; buf +=14; slist = currentSrc->getEventSid( nid, tsid, sid ); if ( !slist ) return false; slist->lock(); currentEvents = slist->getEvents(); TQPtrListIterator it( *currentEvents ); while ( length>4 ) { nodesc=parse=false; if ( !safeLen( buf+2 ) ) goto stop; eid = getBits(buf,0,16); if ( !safeLen( buf+2+5 ) ) goto stop; start = getDateTime( buf+2 ); nodesc=parse=true; it.toFirst(); while ( (desc=it.current())!=0 ) { if ( desc->sid==sid ) { if ( desc->startDateTime==start || desc->eid==eid ) { if ( desc->tid==0x4e && tid!=0x4e ) { parse = false; nodesc = false; break; } else { nodesc = false; if ( (cdt-desc->loop)<300 ) { // only reparse events every 300 seconds parse = false; } else { desc->extEvents.clear(); desc->shortEvents.clear(); desc->title=desc->subtitle=""; } break; } } } ++it; } if ( nodesc ) desc = new EventDesc(); if ( parse ) { if ( !safeLen( buf+10 ) ) goto stop; desc->duration = getTime( buf+7 ); if ( !safeLen( buf+11 ) ) goto stop; desc->running = getBits(buf,80,3); desc->sid = sid; desc->tid = tid; desc->tsid = tsid; desc->nid = nid; desc->lsn = lsn; desc->sn = sn; desc->eid = eid; desc->loop = cdt; } if ( desc->sn != sn ) { slist->unlock(); return false; } if ( !safeLen( buf+12 ) ) goto stop; loop = getBits(buf,84,12); buf +=12; length -=(12+loop); while ( loop>0 ) { if ( parse ) { if ( !safeLen( buf+1 ) ) goto stop; switch ( getBits(buf,0,8) ) { case 0x4D : if ( !shortEventDesc( buf, desc ) ) goto stop; break; case 0x4E : if ( !extEventDesc( buf, desc ) ) goto stop; break; default : break; } } if ( !safeLen( buf+2 ) ) goto stop; loop -=( getBits(buf,8,8)+2 ); buf +=( getBits(buf,8,8)+2 ); } //out: if ( parse ) { if ( !nodesc ) { if ( start==desc->startDateTime ) goto ifend; currentEvents->take( currentEvents->tqfind( desc ) ); } desc->startDateTime = start; for ( i=0; i<(int)currentEvents->count(); i++ ) { itdesc = currentEvents->at(i); if ( desc->startDateTimestartDateTime ) { currentEvents->insert( i, desc ); break; } itdesc = 0; } if ( !itdesc ) currentEvents->append( desc ); } ifend: if ( parse ) ++(desc->sn); if ( nodesc ) { cur = TQDateTime::tqcurrentDateTime(); dt = desc->startDateTime; sec = desc->duration.hour()*3600+desc->duration.minute()*60+desc->duration.second(); if ( dt.addSecs( sec )title.length()<3 ) { currentEvents->remove( desc ); } else desc->source = currentSrc->getSource(); } } slist->unlock(); return true; stop: slist->unlock(); fprintf( stderr, "Stop parsing EIT (%d:%d)\n", adapter, tuner ); if ( nodesc ) delete desc; return false; } bool DVBevents::safeLen( unsigned char* buf ) { if ( buf<(secbuf+readSize) ) return true; fprintf( stderr, "EIT (%d:%d) : buffer overflow! Rejected\n", adapter, tuner ); return false; } bool DVBevents::go( TQString src, int freqKHz, bool all ) { int tid, i; if ( isRunning ) return true; if ( all ) tid = 0; else tid = 0x4e; currentSrc = events->getEventSource( src ); if ( !setFilter( 0x12, tid, 1000 ) ) return false; isRunning = true; start(); fprintf(stderr,"dvbEvents %d:%d started\n", adapter, tuner); for ( i=0; i<(int)plugs.count(); ++i ) { plugs.at(i)->go( src, freqKHz ); } return true; } void DVBevents::stop() { int i; if ( !isRunning ) return; isRunning = false; if ( !wait(2000) ) { terminate(); wait(); fprintf(stderr,"dvbEvents %d:%d terminated\n", adapter, tuner); } else fprintf(stderr,"dvbEvents %d:%d ended\n", adapter, tuner); stopFilter(); for ( i=0; i<(int)plugs.count(); ++i ) { plugs.at(i)->stop(); } } void DVBevents::run() { int n=0, tid; int skip=0; setpriority(PRIO_PROCESS, 0, 19); // eit parsing is cpu eater on some astra multiplex. 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; tid = getBits(secbuf,0,8); if ( tid>0x4D && tid<0x70 ) { tableEIT( secbuf ); } } }