Logo Search packages:      
Sourcecode: kaffeine version File versions

dvbsi.cpp

/***************************************************************************
                          dvbsi.cpp  -  description
                             -------------------
    begin                : 2004
    copyright            : (C) 2003-2005 by Christophe Thommeret
    email                : hftom@free.fr
    last modified        : $Date: 2005/02/02 10:08:25 $ by $Author: juergenk $
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include <stdio.h>
#include <unistd.h>
#include <sys/poll.h>

#include <qdir.h>

#include <kmessagebox.h>
#include <klocale.h>
#include <kprocess.h>
#include <kapplication.h>
 
#include "dvbsi.h"

#define TIMER_EVENT_SCAN_END 100



DVBsi::DVBsi( bool *ok, int card, DvbStream *d ) : DVBsection( ok, card )
{
      channels.setAutoDelete( true );
      transponders.setAutoDelete( true );
      isRunning = false;
      dvb = d;
}



DVBsi::~DVBsi()
{
      isRunning = false;
      wait();
      channels.clear();
      transponders.clear();
}



void DVBsi::serviceDesc( unsigned char* buf, ChannelDesc *desc )
{
      unsigned int i, j;

      desc->type = getBits(buf,16,8);
      i = getBits(buf,24,8);
      desc->provider = getText( buf+4, i ).stripWhiteSpace();
      j = getBits(buf+i,32,8);
      desc->name = getText( buf+5+i, j ).stripWhiteSpace();
      if ( desc->name=="" ) desc->name = "Unknown";
      fprintf(stderr,"%s\n", desc->name.latin1() );
}



void DVBsi::satelliteDesc( unsigned char* buf, Transponder *trans )
{
      QString s, t;

      trans->type = FE_QPSK;
      s = t.setNum( getBits(buf,16,32), 16 );
      trans->freq = s.toInt();
      trans->freq /=100;
      if ( getBits(buf,65,2) ) trans->pol = 'v';
      else trans->pol = 'h';
      s = t.setNum( getBits(buf,72,28), 16 );
      trans->sr = s.toInt();
      trans->sr /=10;
      switch ( getBits(buf,100,4) ) {
            case 1 : trans->coderateH = FEC_1_2; break;
            case 2 : trans->coderateH = FEC_2_3; break;
            case 3 : trans->coderateH = FEC_3_4; break;
            case 4 : trans->coderateH = FEC_5_6; break;
            case 5 : trans->coderateH = FEC_7_8; break;
            case 6 : trans->coderateH = FEC_8_9; break;
            case 7 : trans->coderateH = FEC_NONE; break;
      }
}



void DVBsi::cableDesc( unsigned char* buf, Transponder *trans )
{
      QString s, t;

      trans->type = FE_QAM;
      s = t.setNum( getBits(buf,16,32), 16 );
      trans->freq = s.toInt();
      trans->freq /=10;
      switch ( getBits(buf,64,8) ) {
            case 1 : trans->modulation = QAM_16; break;
            case 2 : trans->modulation = QAM_32; break;
            case 3 : trans->modulation = QAM_64; break;
            case 4 : trans->modulation = QAM_128; break;
            case 5 : trans->modulation = QAM_256; break;
      }
      s = t.setNum( getBits(buf,72,28), 16 );
      trans->sr = s.toInt();
      trans->sr /=10;
      switch ( getBits(buf,100,4) ) {
            case 1 : trans->coderateH = FEC_1_2; break;
            case 2 : trans->coderateH = FEC_2_3; break;
            case 3 : trans->coderateH = FEC_3_4; break;
            case 4 : trans->coderateH = FEC_5_6; break;
            case 5 : trans->coderateH = FEC_7_8; break;
            case 6 : trans->coderateH = FEC_8_9; break;
            case 7 : trans->coderateH = FEC_NONE; break;
      }
}



void DVBsi::terrestrialDesc( unsigned char* buf, Transponder *trans )
{
      trans->type = FE_OFDM;
      trans->freq = getBits(buf,16,32)/100;
      trans->bandwidth = (fe_bandwidth_t)(BANDWIDTH_8_MHZ + getBits(buf,48,3));
      switch ( getBits(buf,56,2) ) {
            case 0 : trans->modulation = QPSK; break;
            case 1 : trans->modulation = QAM_16; break;
            case 2 : trans->modulation = QAM_64; break;
      }
      trans->hierarchy = (fe_hierarchy_t)(HIERARCHY_NONE + getBits(buf,58,3));
      switch ( getBits(buf,61,3) ) {
            case 0 : trans->coderateH = FEC_1_2; break;
            case 1 : trans->coderateH = FEC_2_3; break;
            case 2 : trans->coderateH = FEC_3_4; break;
            case 3 : trans->coderateH = FEC_5_6; break;
            case 4 : trans->coderateH = FEC_7_8; break;
      }
      switch ( getBits(buf,64,3) ) {
            case 0 : trans->coderateL = FEC_1_2; break;
            case 1 : trans->coderateL = FEC_2_3; break;
            case 2 : trans->coderateL = FEC_3_4; break;
            case 3 : trans->coderateL = FEC_5_6; break;
            case 4 : trans->coderateL = FEC_7_8; break;
      }
      trans->guard = (fe_guard_interval_t)(GUARD_INTERVAL_1_32 + getBits(buf,67,2));
      switch ( getBits(buf,69,2) ) {
            case 0 : trans->transmission = TRANSMISSION_MODE_2K; break;
            case 1 : trans->transmission = TRANSMISSION_MODE_8K; break;
      }
}



void DVBsi::freqListDesc( unsigned char* buf, Transponder *trans )
{
      unsigned char len, type;
      unsigned char *b=buf;
      QString s, t;
      unsigned long freq;

      len = getBits(b,8,8);
      type = getBits(b,22,2);
      len-= 1;
      b+= 3;
      while ( len>0 ) {
            switch ( type ) {
                  case 1: // satellite
                        s = t.setNum( getBits(b,0,32), 16 );
                        freq = s.toInt();
                        freq /=100;
                        fprintf( stderr, "          %d\n", freq );
                        trans->freqlist.append( freq );
                        break;
                  case 2: // cable
                        s = t.setNum( getBits(b,0,32), 16 );
                        freq = s.toInt();
                        freq /=10;
                        fprintf( stderr, "          %d\n", freq );
                        trans->freqlist.append( freq );
                        break;
                  case 3: // terrestrial
                        freq = getBits(b,0,32)/100;
                        fprintf( stderr, "          %d\n", freq );
                        trans->freqlist.append( freq );
                        break;
            }
            len-= 4;
            b+= 4;
      }
}



bool DVBsi::tableSDT( unsigned char* buf )
{
      int length, loop;
      ChannelDesc *desc;
      QString s;
      unsigned short tsid;

      tsid = getBits(buf,24,16);
      length = getBits(buf,12,12);
      length -=8;
      buf +=11;

      while ( length>4 ) {
            desc = new ChannelDesc();
            channels.append( desc );
            desc->tp.tsid = tsid;
            desc->sid = getBits(buf,0,16);
            desc->fta = getBits(buf,27,1 );
            loop = getBits(buf,28,12);
            buf +=5;
            length -=(5+loop);
            while ( loop>0 ) {
                  switch ( getBits(buf,0,8) ) {
                        case 0x48 :
                              serviceDesc( buf, desc );
                              break;
                        default :
                              break;
                  }
                  loop -=( getBits(buf,8,8)+2 );
                  buf +=( getBits(buf,8,8)+2 );
            }
      }
      return true;
}



bool DVBsi::tablePMT( unsigned char* buf )
{
      int length, loop;
      int type;
      int sid;
      int i;
      int nlang=0;
      int pid=0;
      ChannelDesc *desc=0;
      QString lang;

      sid = getBits(buf+3,0,16);
      for ( i=indexChannels; i<(int)channels.count(); i++ ) {
            if ( channels.at( i )->sid==sid ) {
                  desc = channels.at( i );
                  break;
            }
      }

      if ( !desc ) return false;

      length = getBits(buf,12,12);
      loop = getBits(buf+10,4,12);
      length -=(9+loop);
      buf +=12+loop;

      while ( length>4 ) {
            type = getBits(buf,0,8);
            pid = getBits(buf,11,13);
            if ( type==1 || type==2 ) {
                  desc->type=1;
                  desc->vpid = pid;
            }
            if ( type==3 || type==4 ) {
                  if ( !desc->vpid ) desc->type=2;
                  nlang++;
                  if ( desc->napid<desc->maxapid ) {
                        desc->apid[(int)desc->napid].pid = pid;
                        desc->napid++;
                  }
            }
            loop = getBits(buf,28,12);
            buf +=5;
            length -=(5+loop);
            while ( loop>0 ) {
                  switch ( getBits(buf,0,8) ) {
                        case 0x0A :
                              lang = langDesc( buf );
                              if ( (type==3 || type==4) && nlang<=desc->maxapid ) {
                                    desc->apid[desc->napid-1].lang = lang;
                              }
                              break;
                        case 0x56 :
                              if ( type==6 ) desc->ttpid = pid;
                               break;
                        case 0x59 :
                              if ( type==6 && desc->subpid.pid==0 ) {
                                    unsigned int st = getBits(buf+5,0,8);
                                    if ( st>=0x10 && st<=0x23 ) {
                                          desc->subpid.pid=pid; // DVB subtitle descriptor
                                          desc->subpid.page = getBits(buf+6,0,16);
                                          desc->subpid.id = getBits(buf+8,0,16);
                                          desc->subpid.lang = langDesc(buf);
                                          fprintf( stderr, "\nDVB SUB on %s page_id : %d anc_id : %d lang : %s\n\n", desc->name.latin1(),
                                                desc->subpid.page, desc->subpid.id, desc->subpid.lang.latin1() );
                                    }
                              }
                              break;
                        case 0x6a :
                              if ( type==6 && desc->napid<desc->maxapid ) {
                                    desc->apid[(int)desc->napid].pid = pid;
                                    desc->apid[(int)desc->napid].ac3 = 1;
                                    desc->napid++;
                                    nlang++;
                              }
                              break;
                        default :
                              break;
                  }
                  loop -=( getBits(buf,8,8)+2 );
                  buf +=( getBits(buf,8,8)+2 );
            }
      }

      return true;
}



bool DVBsi::tableNIT( unsigned char* buf )
{
      int length, loop, i, j;
      Transponder *trans, *curtrans;

      loop = getBits(buf,68,12);
      buf +=10+loop;
      length = getBits(buf,4,12);
      buf +=2;

      while ( length>0 ) {
            trans = new Transponder();
            trans->source = transponders.at(0)->source;
            trans->tsid = getBits(buf,0,16);
            loop = getBits(buf,36,12);
            buf +=6;
            length -=(6+loop);
            while ( loop>0 ) {
                  switch ( getBits(buf,0,8) ) {
                        case 0x43 :
                              satelliteDesc( buf, trans );
                              break;
                        case 0x44 :
                              cableDesc( buf, trans );
                              break;
                        case 0x5a :
                              terrestrialDesc( buf, trans );
                              break;
                        case 0x62 :
                              fprintf(stderr,"     Found frequency list.\n");
                              freqListDesc( buf, trans );
                              break;
                        default :
                              break;
                  }
                  loop -=( getBits(buf,8,8)+2 );
                  buf +=( getBits(buf,8,8)+2 );
            }
            if ( trans->freq==0 ) {
                  delete trans;
                  continue;
            }
            curtrans = 0;
            for ( i=0; i<(int)transponders.count(); i++ ) {
                  if ( trans->tsid==transponders.at(i)->tsid || trans->sameAs( transponders.at(i) ) ) {
                        curtrans = transponders.at(i);
                        break;
                  }
            }
            if ( !curtrans ) transponders.append( trans );
            else {
                  for ( i=0; i<(int)trans->freqlist.count(); i++ ) {
                        for ( j=0; j<(int)curtrans->freqlist.count(); j++ ) {
                              if ( curtrans->freqlist[j]==trans->freqlist[i] ) {
                                    j = -1;     
                                    break;
                              }
                        }
                        if ( j!=-1 ) {
                              fprintf(stderr,"          Appending freq %d to %d\n", trans->freqlist[i], curtrans->freq );
                              curtrans->freqlist.append( trans->freqlist[i] );
                        }
                  }
                  delete trans;
            }
      }

      return true;
}



bool DVBsi::tablePAT( unsigned char *buf )
{
      int length, i;
      int sid;
      int pmt;

      length = getBits(buf,12,12);
      length -=5;
      buf +=8;

      while ( length>4 ) {
            sid = getBits(buf,0,16);
            pmt = getBits(buf,19,13);     
            buf +=4;
            length -=4;
            for ( i=indexChannels; i<(int)channels.count(); i++ ) {
                  if ( channels.at( i )->sid==sid ) {
                        channels.at( i )->pmtpid = pmt;
                        break;
                  }
            }
      }

      return true;
}



bool DVBsi::getSection( int pid, int tid, int timeout )
{
      unsigned char buf[4096];
      int i, n=0;
      int last=1, current=0, loop=0;
      QValueList<int> list;

      if ( !setFilter( pid, tid, timeout ) ) return false;

      do {
            n = read( fdDemux, buf, 4096 );
            if ( n<4 ) {
                  fprintf(stderr,"\nInvalid section length or timeout : pid=%d\n\n", pid);
                  stopFilter();
                  return false;
            }
            
            last = getBits(buf,56,8);
            current = getBits(buf,48,8);
            for ( i=0; i<(int)list.count(); i++ ) {
                  if ( current==list[i] ) {
                        i = -1;
                        break;
                  }
            }
            if ( i>-1 ) list.append( current );
            else {
                  loop++; // missing section ?
                  continue;
            }
            switch ( getBits(buf,0,8) ) {
                  case 0x42 :
                        fprintf(stderr,"Reading SDT : pid=%d\n", pid);
                        tableSDT( buf );
                        break;
                  case 0x00 :
                        fprintf(stderr,"Reading PAT : pid=%d\n", pid);
                        tablePAT( buf );
                        break;
                  case 0x02 :
                        fprintf(stderr,"Reading PMT : pid=%d\n", pid);
                        tablePMT( buf );
                        break;
                  case 0x40 :
                        fprintf(stderr,"Reading NIT : pid=%d\n", pid);
                        tableNIT( buf );
                        break;
                  default:
                        break;
            }
            loop = 0;
      } while ( (int)list.count()<=last && loop<=last );

      stopFilter();
      return true;
}



void DVBsi::stop()
{
      if ( !isRunning ) return;

      isRunning = false;
      if ( !wait(2000) ) {
            terminate();
            if ( scanMode<2 ) dvb->stopScan();
      }
}



void DVBsi::out( bool stopscan )
{
      if ( stopscan ) dvb->stopScan();
      KApplication::kApplication()->postEvent( this, new QTimerEvent( TIMER_EVENT_SCAN_END ) );
}



void DVBsi::go( QPtrList<Transponder> trans, int mode )
{
      int i;
      
      if ( isRunning ) return;
      
      scanMode = mode;
      transponders.clear();
      for ( i=0; i<(int)trans.count(); i++ ) transponders.append( new Transponder( *trans.at(i) ) );
      channels.clear();
      isRunning = true;
      start();
}



void DVBsi::timerEvent( QTimerEvent *e )
{
      switch ( e->timerId() ) {
            case TIMER_EVENT_SCAN_END :
                  emit end( true );
                  break;
      }
}



void DVBsi::run()
{
      int i, j=0, k=0;
      ChannelDesc chan;
      Transponder trans;
      unsigned short tsid;

      progressTransponder = 0;

      if ( scanMode<2 ) {
            dvb->stopScan();
            for ( i=0; i<(int)transponders.count(); i++ ) {
                  if ( !isRunning ) { out(); return; }
                  chan.tp = *transponders.at(i);
                  usleep(100000);
                  if ( !dvb->tuneDvb( &chan, false ) ) {
                        for ( k=0; k<(int)chan.tp.freqlist.count(); k++ ) {
                              chan.tp.freq = chan.tp.freqlist[k];
                              fprintf(stderr,"Trying alternate frequency\n");
                              if ( dvb->tuneDvb( &chan, false ) ) {
                                    k = -1;
                                    transponders.at(i)->freq = chan.tp.freq;
                                    break;
                              }
                        }
                        if ( k>-1 ) {
                              fprintf(stderr,"dvbsi : Cant tune DVB\n");
                              progressTransponder++;
                              sleep(1);
                              continue;
                        }
                  }
                        
                  indexChannels = j;
                  fprintf(stderr,"Transponders : %d/%d\n", i+1, transponders.count() );
                  getSection( 0x10, 0x40, 60000 );         //NIT
                  if ( !isRunning )  { out(); return; }
                  getSection( 0x11, 0x42 );         //SDT
                  if ( !isRunning )  { out(); return; }
                  getSection( 0x00, 0x00 );         //PAT
                  for ( ; j<(int)channels.count(); j++ ) {
                        if ( channels.at( j )->pmtpid==0 ) {
                              channels.at(j)->completed = 1;
                              continue;
                        }
                        if ( !isRunning )  { out(); return; }
                        getSection( channels.at( j )->pmtpid, 0x02 );    //PMTs
                        tsid = channels.at(j)->tp.tsid;
                        channels.at(j)->tp = *transponders.at(i);
                        if ( channels.at(j)->tp.tsid==0 ) channels.at(j)->tp.tsid = tsid;
                        channels.at(j)->completed = 1;
                  }
                  dvb->stopScan();
                  progressTransponder++;
            }
            fprintf(stderr,"Transponders : %d\n", transponders.count());
      }
      else if ( scanMode==2 ) {
            indexChannels = 0;
            trans = dvb->getCurrentTransponder();
            getSection( 0x11, 0x42 );         //SDT
            getSection( 0x00, 0x00 );         //PAT
            for ( j=0; j<(int)channels.count(); j++ ) {
                  if ( channels.at( j )->pmtpid==0 ) {
                        channels.at(j)->completed = 1;
                        continue;
                  }
                  if ( !isRunning )  { out(false); return; }
                  getSection( channels.at( j )->pmtpid, 0x02 );    //PMTs
                  tsid = channels.at(j)->tp.tsid;
                  channels.at(j)->tp = trans;
                  channels.at(j)->tp.tsid = tsid;
                  channels.at(j)->completed = 1;
            }
      }
      //listChannels();
      fprintf(stderr,"dvbsi : The end :)\n");
      isRunning = false;
      //listChannels();
      KApplication::kApplication()->postEvent( this, new QTimerEvent( TIMER_EVENT_SCAN_END ) );
}



bool DVBsi::listChannels()
{
      QString s,t;
      int i, valid=0;
      
      for ( i=0; i<(int)channels.count(); i++ ) {
            if ( channels.at( i )->pmtpid==0 ) continue;
            if ( channels.at(i)->name =="" ) continue;
            if ( channels.at( i )->type<1 ) continue;
            if ( channels.at( i )->type>2 ) continue;
            if ( channels.at( i )->type==1 && channels.at(i)->vpid==0 ) continue;
            if ( channels.at( i )->type==1 && channels.at(i)->napid==0 ) continue;
            if ( channels.at( i )->type==2 && channels.at(i)->napid==0 ) continue;
            if ( channels.at( i )->type==2 && channels.at(i)->vpid!=0 ) continue;

            s = "|"+channels.at(i)->name;
            s = s+"|"+t.setNum(channels.at(i)->tp.freq);
            s = s+"|"+channels.at(i)->tp.pol;
            s = s+"|"+t.setNum(channels.at(i)->tp.sr);
            fprintf(stderr, "%s\n", s.latin1() );
            valid++;
      }
      fprintf(stderr, "Channels found : %d\n", valid );
      return true;
}
      

Generated by  Doxygen 1.6.0   Back to index