www.pudn.com > MPEG2systemsrc.rar > TSConsumer.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.
*/

/* TSConsumer class implementation */

#include "Utilities.H"
#include "TSConsumer.H"
#include "PESConsumer.H"
#include "Section.H"
#include "SectionConsumers.H"

extern "C"
{
#include 
}

TSConsumer::TSConsumer (Decoder* d, TS* t) : Consumer(d)
{
  ts = t;
}

void TSConsumer::read_sync ()
{
  char bits = 0;
  char bit;
  char sync = (char) 0x47;
  int found = FALSE;

  int k = 0;

  while (!found)
    {
      if (bits == sync)
	found = TRUE;
      else
	{
	  bit = iport->read_bit();
	  bits = bits << 1;
	  if (bit == '1') bits++;
	}
      if (k++ > 1000)
	{
	  sys_error("can't find sync - exiting");
	}
    }
   if (k > 9)
     {
       sys_message("trouble finding sync on TP");
     }
}

void TSConsumer::read_ts_packet ()
{
  // read sync_byte
  read_sync();

  // read transport_error_indicator
  char transport_error_indicator = iport->read_bit();

  // read payload_unit_start_indicator
  char payload_unit_start_indicator = iport->read_bit();

  // read transport_priority
  char priority = iport->read_bit();

  // read pid
  int pid = iport->read_uimsbf(13, "reading pid");
  if (pid == 8191)
    {
      for (int i = 0; i < 185; i++)
	(void) iport->read_byte();
      return;
    }
  ts = decoder->get_ts(pid);
  if (ts == NULL)
    {
      decoder->get_manager()->Trigger(UnexpectedPid, new Wrapper(pid));
      for (int i = 0; i < 185; i++)
	(void) iport->read_byte();
      return;
    }

  // now adjust ts structure with fields read so far
  if (transport_error_indicator == ONE)
    ts->transport_error_code = 'E';
  else
    ts->transport_error_code = '0';
  if (payload_unit_start_indicator == ONE)
    ts->payload_unit_start_code = 'A';
  else
    ts->payload_unit_start_code = '0';
  if (priority == ONE)
    ts->priority_code = 'H';
  else
    ts->priority_code = 'L';
      
  // read transport_scrambling_control; currently uses only "00" or "11"
  char scramble1 = iport->read_bit();
  char scramble2 = iport->read_bit();
  if ((scramble1 == ZERO) && (scramble2 == ZERO))
    ts->scrambling_code = '0';
  else
    ts->scrambling_code = 'S';	
      
  // read adaptation field control
  char afc1 = iport->read_bit();
  char afc2 = iport->read_bit();

  // read continuity_counter
  int oldcc = ts->continuity_counter;
  ts->continuity_counter = iport->read_uimsbf(4, "reading continuity_counter");
  if (oldcc != NOCC)
    {
      int expectedcc = (oldcc >= 15) ? 0 : oldcc+1;
      if (expectedcc != ts->continuity_counter)
	{
          decoder->get_manager()->Trigger(Discontinuity, ts);
	}
    }

  // read adaptation_field
  if (afc1 == '1')
    read_adaptation();
  else
    {
      delete ts->adaptation;
      ts->adaptation = NULL;
    }

  // call TSParsed callback
  decoder->get_manager()->Trigger(TSParsed, ts);
  
  // read the payload or flush out rest of packet
  if (afc2 == '1')
    read_payload();
  else
    {
      int header_length = ts->get_header_length();
      int nbytes = 188 - header_length;
      for (int i = 0; i < nbytes; i++)
	(void) iport->read_byte();
    }
}

void TSConsumer::read_adaptation ()
{
  // get clean adaptation structure
  if (ts->adaptation) delete ts->adaptation;
  ts->adaptation = new AdaptationField();
  
  // read adaptation_field_length
  ts->adaptation->adaptation_field_length =
    iport->read_uimsbf(8, "reading adaptation_field_length");
  if (ts->adaptation->adaptation_field_length == 0) return;
  
  // read discontinuity_indicator
  char discontinuity = iport->read_bit();
  if (discontinuity == ONE)
    {
      ts->adaptation->discontinuity_code = 'D';
      decoder->get_manager()->Trigger(Discontinuity, ts);
    }
  else
    ts->adaptation->discontinuity_code = 'O';

  // read random_access_indicator
  char random = iport->read_bit();
  if (random == ONE)
    {
      ts->adaptation->random_access_code = 'R';
      decoder->get_manager()->Trigger(RandomAccess, ts);
    }
  else
    ts->adaptation->random_access_code = 'O';

  // read elementary_stream_priority_indicator
  char priority = iport->read_bit();
  if (priority == ONE)
    ts->adaptation->elem_stream_priority_code = 'H';
  else
    ts->adaptation->elem_stream_priority_code = 'L';

  // read optional field flags
  char PCR_flag = iport->read_bit();
  char OPCR_flag = iport->read_bit();  
  char splicing_point_flag = iport->read_bit();
  char transport_private_data_flag = iport->read_bit();
  char adaptation_field_extension_flag = iport->read_bit();

  // read PCR
  if (PCR_flag == ONE)
    {
      ts->adaptation->PCR = iport->read_timestamp27_ts_format();
      decoder->get_manager()->Trigger(PCREvent, ts);      
    }

  // read OPCR
  if (OPCR_flag == ONE)
    {
      ts->adaptation->OPCR = iport->read_timestamp27_ts_format();
    }
  
  // read splice_countdown
  if (splicing_point_flag == ONE)
    {
      ts->adaptation->splice_countdown =
	iport->read_tcimsbf(8, "reading spice_countdown");
    }
  else
    ts->adaptation->splice_countdown = NOSPLICE;

  // read private_data
  if (transport_private_data_flag == ONE)
    {
      ts->adaptation->transport_private_data_length =
	iport->read_uimsbf(8, "reading transport_private_data_length");
      for (int i = 0; i < ts->adaptation->transport_private_data_length; i++)
	(void) iport->read_byte();
    }
  
  // read extension
  if (adaptation_field_extension_flag == ONE)
    {
      ts->adaptation->adaptation_extension_length =
	iport->read_uimsbf(8, "reading adaptation_extension_length");
      for (int j = 0; j < ts->adaptation->adaptation_extension_length; j++)
	(void) iport->read_byte();
    }

  // read stuffing bytes
  int current_length = ts->adaptation->get_length();
  int fields_length = ts->adaptation->get_fields_length();
  ts->adaptation->number_stuffing_bytes =
    ts->adaptation->adaptation_field_length - (fields_length + 1);
  if (ts->adaptation->number_stuffing_bytes > 0)
    {
      for (int k = 0; k < ts->adaptation->number_stuffing_bytes; k++)
	(void) iport->read_byte();
    }
}

void TSConsumer::read_payload ()
{
  int header_length = ts->get_header_length();
  int nbytes = 188 - header_length;
  Consumer* cons = decoder->get_cons(ts->pid);
  if (cons == NULL)
    {
      sys_error("can't find consumer in TSConsumer::read_payload");
    }
  else
    {
      if (ts->payload_unit_start_code == 'A') cons->set_cstate(CSTART);
      cons->connect(iport);
      cons->read_partial(nbytes);
    }
}