www.pudn.com > MPEG2systemsrc.rar > SectionConsumers.C


/* Copyright (C) 1995, Tektronix Inc. All Rights Reserved.
 *
 *   Usage Restrictions
 *
 * License is granted to copy, to use, and to make and to use derivative
 * works for research and evaluation purposes only.
 *
 *   Disclaimer of Warranty
 *
 * These software programs are available to the user without any license
 * fee or royalty on an "as is" basis.  Tektronix Inc. disclaims any and
 * all warranties, whether express, implied, or statuary, including any
 * implied warranties or merchantability or of fitness for a particular
 * purpose.  In no event shall the copyright-holder be liable for any 
 * incidental, punitive, or consequential damages of any kind whatsoever
 * arising from the use of these programs.
 *
 * This disclaimer of warranty extends to the user of these programs and
 * user's customers, employees, agents, transferees, successors, and
 * assigns.
 *
 * The Tektronix Inc. does not represent or warrant that the programs
 * furnished hereunder are free of infringement of any third-party
 * patents.
*/

/* SectionConsumer class implementation */

#include "Utilities.H"
#include "IPortFromRam.H"
#include "SectionConsumers.H"
#include "Decoder.H"
#include "Events.H"
#include "PES.H"
#include "PESConsumer.H"

extern "C"
{
#include 
}

SectionConsumer::SectionConsumer (Decoder* d, Section* s) : Consumer(d)
{
  sec = s;
  buf_index = -1;
  length_expected = -1;
}

static int char2int (char c)
{
  int result = 0;
  for (int i = 7; i >= 0; i--)
    {
      if ((c & (1 << i)) == 0) result = result * 2;
      else result = result * 2 + 1;
    }
  return result;
}

/* This function is called to read TP payloads. */
int SectionConsumer::read_partial (int n)
{
  int i = 0;
  while (i < n)
    {
      switch (cstate)
	{
	case CSTART:
	  buf = (char*) malloc (1024); // FIX -- private sections can be 4096
	  buf_index = 0;
	  cstate = SCHEAD1;
	  break;
	case SCHEAD1:
	  if (buf_index < 4)
	    {
	      buf[buf_index] = iport->read_byte();
    	      buf_index++; i++;
	    }
	  if (buf_index == 4)
	    {
	      // FIX -- this case assumes ptr == 0
	      if (buf[0] != 0)
		{
		  sys_error("non zero pointer offset in SectionConsumer");
		}
              length_expected = (char2int(buf[2]) & 0xF) << 8; 
              length_expected += char2int(buf[3]) + 4;
	      cstate = SCHEAD2;
	    }
	  break;
	case SCHEAD2:
	  if (buf_index < length_expected)
	    {
	      buf[buf_index] = iport->read_byte();
	      buf_index++; i++;
	    }
          if (buf_index == length_expected)
	    {
	      InputPort* save_port = iport;
	      iport = new IPortFromRam(buf, length_expected);
	      read_section();
	      delete iport;
	      iport = save_port;
	      delete buf;  buf_index = 0;  // done with buf
	      cstate = SCFLUSH;
	    }
	  break;
	case SCFLUSH:
	  char c = iport->read_byte();
	  assert(c == (char) 0xff);
	  i++;
	  break;
	default:
	  sys_error("unknown SectionConsumer state");
	}
    }
  return n;
}

void SectionConsumer::read_header_a ()
{
  // read pointer field
  // FIX -- this assumes that there is always a pointer field
  sec->pointer = iport->read_uimsbf(8, "reading pointer field");

  // skip to start of section
  for (int k = 0; k < sec->pointer; k++)
    (void) iport->read_byte();

  // start CRC
  iport->start_crc();

  // read table_id (should be 0)
  sec->table_id = iport->read_uimsbf(8, "reading table_id");
  
  // read section_syntax_code
  char syntax = iport->read_bit();
  if (syntax == ONE)
    sec->section_syntax_code = 'S';
  else
    sec->section_syntax_code = 'L';
  
  // read '0' and reserved bits
  iport->read_bit();
  iport->read_reserved_bits(2);
  
  // read section_length
  sec->section_length = iport->read_uimsbf(12, "reading section_length");
}

void SectionConsumer::read_header_b ()
{
  // read reserved bits
  iport->read_reserved_bits(2);
  
  // read version_number
  sec->version_number = iport->read_uimsbf(5, "reading version_number");
  
  // read current_next_indicator
  char cur_next = iport->read_bit();
  if (cur_next == ONE)
    sec->current_next_code = 'C';
  else
    sec->current_next_code = 'N';
  
  // read section_number
  sec->section_number = iport->read_uimsbf(8, "reading section_number");
  
  // read last_section_number
  sec->last_section_number = iport->read_uimsbf(8, "reading last_section_number");
}

void SectionConsumer::read_CRC ()
{
  // read CRC
  iport->stop_crc();
  if (!iport->check_crc())
    decoder->get_manager()->Trigger(BadCRC, sec);
}

PATConsumer::PATConsumer (Decoder* d, PATSection* s)
    : SectionConsumer(d, s)
{
  patsec = s;
}

void PATConsumer::read_section ()
{
  // read header_a
  read_header_a();

  // read transport_stream_id
  patsec->transport_stream_id = iport->read_uimsbf(16,
						   "reading trans_strm_id");
  
  // read header_b
  read_header_b();

  // create new directory; get old one
  Directory* newdir = new Directory();
  Directory* olddir = decoder->get_dir();

  int network_pid = decoder->get_networkpid();
  
  // read loop
  for (int i = 0; i < patsec->section_length - 9; i += 4)
    {
      int prog_number = iport->read_uimsbf(16, "reading program number");
      iport->read_reserved_bits(3);
      if (prog_number == 0)
	{
          network_pid = iport->read_uimsbf(13, "reading network_pid");
	}
      else
	{
          int pid = iport->read_uimsbf(13, "reading pid");
	  // update Directory
	  Program* program = olddir->get_program(prog_number);
          if (program)
	    {
	      // not a new program
	      newdir->add_program(program);
	    }
	  else
	    {
	      // a new program
	      newdir->add_program(new Program(prog_number, pid));
	    }
        }
    }

  // setup decoder using new directory
  decoder->install_netpid(network_pid);
  decoder->install_dir(newdir);

  // read CRC
  read_CRC();

  // call PATParsed callback
  decoder->get_manager()->Trigger(PATParsed, patsec);
}

MapConsumer::MapConsumer (Decoder* d, MapSection* s)
    : SectionConsumer(d, s)
{
  mapsec = s;
}

void MapConsumer::read_section ()
{
  // read header_a
  read_header_a();
  
  // read program_number
  mapsec->program_number = iport->read_uimsbf(16, "reading program_number");
  
  // read header_b
  read_header_b();

  // read reserved bits
  iport->read_reserved_bits(3);
  
  // read pcr_pid
  mapsec->pcr_pid = iport->read_uimsbf(13, "reading pcr_pid");

  // read reserved bits
  iport->read_reserved_bits(4);

  // create new program with same program number
  Program* newprog = new Program(mapsec->program_number,
				 decoder->get_ts()->pid);

  // read program_info_length and info into newprog
  mapsec->program_info_length =
    iport->read_uimsbf(12, "reading program_info_length");
  // FIX - implement descriptors for program info
  for (int i = 0; i < mapsec->program_info_length; i++)
    {
      (void) iport->read_byte();
    }
  
  // read loop
  int bytes_in_loop =
    mapsec->section_length - mapsec->program_info_length - 13;
  for (int j = 0; j < bytes_in_loop; )
    {
      // read fields
      int stream_type = iport->read_uimsbf(8, "reading stream_type");
      iport->read_reserved_bits(3);
      int elem_pid = iport->read_uimsbf(13, "reading elem_pid");

      EStream* estream = new EStream((StreamType) stream_type, elem_pid, NULL);
      newprog->add_estream(estream);

      // read estream info
      iport->read_reserved_bits(4);
      int info_length = iport->read_uimsbf(12, "reading es_info_length");
      // FIX - implement descriptors for estream info
      for (int k = 0; k < info_length; k++)
	(void) iport->read_byte();

      j += 5 + info_length;
    }

  // get dir and install new program
  decoder->install_prog(newprog);
  
  // read CRC
  read_CRC();

  // call MapParsed callback
  decoder->get_manager()->Trigger(MapParsed, mapsec);
}

CAConsumer::CAConsumer (Decoder* d, CASection* s)
    : SectionConsumer(d, s)
{
  casec = s;
}

void CAConsumer::read_section ()
{
  // read header_a
  read_header_a();

  // read 16/18 reservered bits, read_header_b() will read 2 more bits.
  iport->read_reserved_bits(16); 
  
  // read header_b
  read_header_b();
  
  // read loop
  int bytes_in_loop = casec->section_length - 9;
   for (int j = 0; j < bytes_in_loop; )
    {
      // read descriptor
      int descriptor_tag = iport->read_uimsbf(8, "reading des_tag");
      if (descriptor_tag != 9)
	sys_message("bad descriptor in CASection");
      
      int descriptor_length = iport->read_uimsbf(8, "reading des_length");
      
      int CA_system_id = iport->read_uimsbf(16, "reading CA_system_id");
      
      iport->read_reserved_bits(3);
      
      int ca_pid = iport->read_uimsbf(13, "reading des_tag");
      // FIX -- eventually add a CAConsumer to consume ca_pid; ignore for now

      for (int k = 0; k < descriptor_length - 4; k++)
	(void) iport->read_byte();
      
      j += descriptor_length + 2;
    }

  // read CRC
  read_CRC();

  // call CAParsed callback
  decoder->get_manager()->Trigger(CAParsed, casec);
}

PriConsumer::PriConsumer (Decoder* d, PriSection* s)
    : SectionConsumer(d, s)
{
  prisec = s;
}

void PriConsumer::read_section ()
{
  // read header_a
  read_header_a();

  // check syntax indicator
  if (prisec->section_syntax_code == 'S')
    {
      for (int i = 0; i < prisec->section_length; i++)
	(void) iport->read_byte();
    }
  else
    {
      // read table_id_extension
      prisec->table_id_extension =
	iport->read_uimsbf(16, "reading table_id_ext");
      
      // read header_b
      read_header_b();
      
      // read loop
      int bytes_in_loop = prisec->section_length - 9;
      for (int j = 0; j < bytes_in_loop; j++)
	{
	  (void) iport->read_byte();
	}
      
      // read CRC
      read_CRC();
    }
}