Logo Search packages:      
Sourcecode: kaffeine version File versions

dvbout.cpp

/***************************************************************************
                          dvbout.cpp  -  description
                             -------------------
    begin                : Sat Mar 6 2004
    copyright            : (C) 2004-2005 by Christophe Thommeret
    email                : hftom@free.fr
    last modified        : $Date: 2005/02/02 10:08:24 $ 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 "dvbout.h"
#include "ts2rtp.h"
#include "ts2pes.h"



DVBout::DVBout( ChannelDesc chan, int card )
{
      bool bok;
      bok = true;
      unsigned int i=card, j, k;

      for( i = 0 ; i < 256 ; i++ ) {
            k = 0;
            for (j = (i << 24) | 0x800000 ; j != 0x80000000 ; j <<= 1) {
                  k = (k << 1) ^ (((k ^ j) & 0x80000000) ? 0x04c11db7 : 0);
            }
            CRC32[i] = k;
      }

      fdPipe=0;
      outType = 0;
      channel = chan;
      thWrite = 0;
      tp = 0;
      tpShift = 0;
      rtp = 0;
      activeApid = 0;
      timeShifting = beginLive = false;
      haveRec = haveLive = instantRec = false;
      connect( &stopRecTimer, SIGNAL(timeout()), this, SLOT(stopRec()) );
      connect( &timerPatPmt, SIGNAL(timeout()), this, SLOT(setPatPmt()) );
}



void DVBout::calculateCRC( unsigned char *p_begin, unsigned char *p_end )
{
      unsigned int i_crc = 0xffffffff;

      /* Calculate the CRC */
      while( p_begin < p_end ) {
            i_crc = (i_crc<<8) ^ CRC32[ (i_crc>>24) ^ ((unsigned int)*p_begin) ];
            p_begin++;
      }

      /* Store it after the data */
      p_end[0] = (i_crc >> 24) & 0xff;
      p_end[1] = (i_crc >> 16) & 0xff;
      p_end[2] = (i_crc >>  8) & 0xff;
      p_end[3] = (i_crc >>  0) & 0xff;
}



void DVBout::writePat()
{
      int i;

      tspat[0x00] = 0x47; /* sync_byte */
      tspat[0x01] = 0x40;
      tspat[0x02] = 0x00; /* PID = 0x0000 */
      tspat[0x03] = 0x10; // | (ps->pat_counter & 0x0f);
      tspat[0x04] = 0x00; /* CRC calculation begins here */
      tspat[0x05] = 0x00; /* 0x00: Program association section */
      tspat[0x06] = 0xb0; /* */
      tspat[0x07] = 0x11; /* section_length = 0x011 */
      tspat[0x08] = 0x00;
      tspat[0x09] = 0xbb; /* TS id = 0x00b0 (what the vlc calls "Stream ID") */
      tspat[0x0a] = 0xc1;
      /* section # and last section # */
      tspat[0x0b] = tspat[0x0c] = 0x00;
      /* Network PID (useless) */
      tspat[0x0d] = tspat[0x0e] = 0x00; tspat[0x0f] = 0xe0; tspat[0x10] = 0x10;
      /* Program Map PID */
      pmtpid = 0x64;
      while ( pmtpid==channel.vpid || pmtpid==channel.apid[activeApid].pid || pmtpid==channel.subpid.pid ) pmtpid--;
      tspat[0x11] = 0x03; tspat[0x12] = 0xe8; tspat[0x13] = 0xe0; tspat[0x14] = pmtpid;
      /* Put CRC in ts[0x15...0x18] */
      calculateCRC( tspat + 0x05, tspat + 0x15 );
      /* needed stuffing bytes */
      for (i=0x19 ; i < 188 ; i++) tspat[i]=0xff;
}



void DVBout::writePmt()
{
      int i, ac3=0, sub=0;

      tspmt[0x00] = 0x47; /* sync_byte */
      tspmt[0x01] = 0x40;
      tspmt[0x02] = pmtpid;
      tspmt[0x03] = 0x10; // | (ps->pmt_counter & 0x0f);
      tspmt[0x04] = 0x00; /* CRC calculation begins here */
      tspmt[0x05] = 0x02; /* 0x02: Program map section */
      tspmt[0x06] = 0xb0; /* */
      tspmt[0x07] = 0x20; /* section_length = 0x025 */
      tspmt[0x08] = 0x03;
      tspmt[0x09] = 0xe8; /* prog number */
      tspmt[0x0a] = 0xc1;
      /* section # and last section # */
      tspmt[0x0b] = tspmt[0x0c] = 0x00;
      /* PCR PID */
      tspmt[0x0d] = channel.vpid>>8;
      tspmt[0x0e] = (channel.vpid<<8)>>8;
      /* program_info_length == 0 */
      tspmt[0x0f] = 0xf0; tspmt[0x10] = 0x00;
      /* Program Map / Video PID */
      tspmt[0x11] = 0x02; /* stream type = video */
      tspmt[0x12] = channel.vpid>>8;
      tspmt[0x13] = (channel.vpid<<8)>>8;
      tspmt[0x14] = 0xf0; tspmt[0x15] = 0x09; /* es info length */
      /* useless info */
      tspmt[0x16] = 0x07; tspmt[0x17] = 0x04; tspmt[0x18] = 0x08; tspmt[0x19] = 0x80;
      tspmt[0x1a] = 0x24; tspmt[0x1b] = 0x02; tspmt[0x1c] = 0x11; tspmt[0x1d] = 0x01;
      tspmt[0x1e] = 0xfe;
      if ( channel.apid[activeApid].ac3 ) {
            // ac3
            //tspmt[0x1f] = 0x06; /* stream type = ISO_13818_PES_PRIVATE */
            //tspmt[0x20] = channel.apid[activeApid].pid>>8; tspmt[0x21] = (channel.apid[activeApid].pid<<8)>>8;
            //tspmt[0x22] = 0xf0; tspmt[0x23] = 0x03; /* es info length */
            //tspmt[0x24] = 0x6A; /*ac3 tag*/
            //tspmt[0x25] = 0x01; /*descriptor length*/
            //tspmt[0x26] = 0x00; /*stuff*/
            //ac3 = 3;
            //tspmt[0x07] = 0x20+ac3; /* update section_length */
            tspmt[0x1f] = 0x81; // stream type = audio
            tspmt[0x20] = channel.apid[activeApid].pid>>8; tspmt[0x21] = (channel.apid[activeApid].pid<<8)>>8;
            tspmt[0x22] = 0xf0; tspmt[0x23] = 0x06; // es info length
            tspmt[0x24] = 0x05; tspmt[0x25] = 0x04; tspmt[0x26] = 0x41;
            tspmt[0x27] = 0x43; tspmt[0x28] = 0x2d; tspmt[0x29] = 0x33;
            ac3 = 6;
            tspmt[0x07] = 0x20+ac3; // update section_length
      }
      else {
            // mpeg
            tspmt[0x1f] = 0x04; // stream type = audio
            tspmt[0x20] = channel.apid[activeApid].pid>>8; tspmt[0x21] = (channel.apid[activeApid].pid<<8)>>8;
            tspmt[0x22] = 0xf0; tspmt[0x23] = 0x00; // es info length
      }
      // Subtitles
      if( channel.subpid.pid ) {
            tspmt[0x24+ac3] = 0x06; // stream type = ISO_13818_PES_PRIVATE
            tspmt[0x25+ac3] = channel.subpid.pid>>8; tspmt[0x26+ac3] = (channel.subpid.pid<<8)>>8;
            tspmt[0x27+ac3] = 0xf0; tspmt[0x28+ac3] = 0x0a; // es info length
            tspmt[0x29+ac3] = 0x59; //DVB sub tag
            tspmt[0x2a+ac3] = 0x08; // descriptor length
            tspmt[0x2b+ac3] = channel.subpid.lang.constref(0); tspmt[0x2c+ac3] = channel.subpid.lang.constref(1); tspmt[0x2d+ac3] = channel.subpid.lang.constref(2);
            tspmt[0x2d+1+ac3] = 0x00;
            tspmt[0x2f+ac3] = channel.subpid.page>>8; tspmt[0x30+ac3] = (channel.subpid.page<<8)>>8; // comp_page_id
            tspmt[0x31+ac3] = channel.subpid.id>>8; tspmt[0x32+ac3] = (channel.subpid.id<<8)>>8; // anc_page_id
            sub = 15;
            tspmt[0x07] = 0x20+ac3+sub; // update section_length
      }
      // Put CRC in ts[0x29...0x2c]
      calculateCRC( tspmt+0x05, tspmt+0x24+ac3+sub );
      // needed stuffing bytes
      for (i=0x28+ac3+sub ; i < 188 ; i++) tspmt[i]=0xff;
}



int DVBout::currentAudioPid()
{
      return activeApid;
}



bool DVBout::hasInstantRec()
{
      return instantRec;
}



bool DVBout::hasRec()
{
      return haveRec;
}



bool DVBout::hasLive()
{
      return haveLive;
}



bool DVBout::doPause( QString name ) // called from dvbstream::run()
{
      if ( !haveLive ) return false;

      if ( !timeShifting ) {
            liveFile.setName( name );
            liveFile.open( IO_WriteOnly|IO_Truncate );
            liveFile.writeBlock( (char*)tspat, TS_SIZE );
            liveFile.writeBlock( (char*)tspmt, TS_SIZE );
            timeShifting = true;
            if ( close( fdPipe )<0 ) perror("close out pipe : ");
            else {
                  fprintf(stderr,"out pipe closed\n");
                  fdPipe = 0;
            }
            //emit shifting( timeShifting );
      }
      return true;
}



void DVBout::setPatPmt()
{
      countpatpmt++;
      if ( countpatpmt>5 ) timerPatPmt.stop();
      else patpmt = true;
}



bool DVBout::goLive( QString name, int napid )
{
      if ( fdPipe ) return false;

      haveLive = true;
      pipeName = name;
      beginLive = true;
      activeApid = napid;
      writePat();
      writePmt();
      patpmt = true;
      countpatpmt = 0;
      timerPatPmt.start( 500 );
      start();
      return true;
}



void DVBout::stopLive()
{
      haveLive = false;
      timerPatPmt.stop();
      usleep( 10000 );
      if ( timeShifting ) {
            liveFile.close();
            timeShifting = false;
            emit shifting( timeShifting );
      }
      if ( fdPipe ) {
            close( fdPipe );
            fprintf( stderr, "pipe closed\n" );
            fdPipe = 0;
      }
}



bool DVBout::goRec( int type, QString name, RecTimer *t )
{
      int ps = 0;
      bool ok;

      recTimer = t;
      
      if ( outType ) return false;
      if ( tp ) return false;

      if ( channel.apid[activeApid].ac3 ) type = OutTS;

      switch ( type ) {
            case OutPS : ps = 1;
            case OutPES : {
                  tp = new Ts2Pes( name, channel.apid[activeApid].pid, channel.vpid, ps, &ok );
                  if ( !ok ) {
                        delete tp;
                        tp = 0;
                        return false;
                  }
                  tp->go();
                  break;
            }
            case OutTS : {
                  writePat();
                  writePmt();
                  outFile.setName( name+".ts" );
                  if ( !outFile.open( IO_WriteOnly | IO_Truncate ) ) return false;
                  outFile.writeBlock( (char*)tspat, TS_SIZE );
                  outFile.writeBlock( (char*)tspmt, TS_SIZE );
                  break;
            }
      }
      outType = type;
      haveRec = true;
      if ( recTimer ) stopRecTimer.start( (recTimer->duration.hour()*3600+recTimer->duration.minute()*60)*1000, true );
      else instantRec = true;
      fprintf( stderr, "Recording started : %s\n", channel.name.latin1() );
      return true;
}



void DVBout::changeTimer( int ms )
{
      if ( stopRecTimer.isActive() ) stopRecTimer.changeInterval( ms );
}



void DVBout::stopRec()
{
      if ( !(outType) ) return;

      if ( stopRecTimer.isActive() ) stopRecTimer.stop();
      int type = outType;
      outType=0;
      usleep( 10000 );
      switch ( type ) {
            case OutPES :
            case OutPS : {
                  delete tp;
                  tp = 0;
                  break;
            }
            case OutTS : outFile.close();
      }
      haveRec = instantRec = false;
      fprintf( stderr, "Recording stopped : %s\n", channel.name.latin1() );
      if ( !haveLive ) emit endRecord( this, recTimer, true );
      else emit endRecord( this, recTimer, false );
}
      


void DVBout::process( unsigned char *buf, int size )
{
      int i, pid;
      unsigned char *buffer=buf;
      int NTS=64;

      for ( i=0; i<size; i+=TS_SIZE ) {
            pid = (((buffer[1] & 0x1f) << 8) | buffer[2]);
            /*if ( pid==channel.subpid ) {
                  if ( buffer[3]&0xc0 ) fprintf(stderr,"DVBSUB ENCRYPTED!!!!!\n");
                  else fprintf(stderr,"DVBSUB CLEAR!!!!!\n");
            }*/
            if (channel.vpid==pid || channel.apid[activeApid].pid==pid || channel.subpid.pid==pid) {
                  memcpy( thBuf+thWrite, buffer, TS_SIZE );
                  thWrite+=TS_SIZE;
                  if ( thWrite==(TS_SIZE*NTS ) ) {
                        if ( haveLive && fdPipe ) {
                              if ( beginLive ) {
                                    //emit playDvb();
                                    beginLive = !beginLive;
                              }
                              if ( patpmt ) {
                                    write( fdPipe, tspat, TS_SIZE );
                                    write( fdPipe, tspmt, TS_SIZE );
                                    patpmt = false;
                              }
                              write( fdPipe, thBuf, TS_SIZE*NTS );
                        }
                        else if ( timeShifting ) liveFile.writeBlock( (char*)thBuf, TS_SIZE*NTS );
                        if ( outType > OutTS ) tp->run( thBuf, TS_SIZE*NTS );
                        else if ( outType==OutTS ) outFile.writeBlock( (char*)thBuf, TS_SIZE*NTS );
                        thWrite = 0;
                  }
            }
            buffer+=TS_SIZE;
      }
}



void DVBout::run()
{
      if ( (fdPipe=open( pipeName, O_WRONLY))<0 ) {
            perror("PIPE FILE: ");
            return;
      }
      fprintf(stderr,"pipe opened\n");
}



DVBout::~DVBout()
{
}

Generated by  Doxygen 1.6.0   Back to index