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

/* PES class implementation */

#include "PESProducer.H"
#include "OPortToRam.H"
#include "Encoder.H"
#include "IPortFromFile.H"

extern "C"
{
#include 
}

PESProducer::PESProducer (Encoder* e, PES* p) : Producer(e)
{
  pes = p;
  timestamp_lock = FALSE;
  esport = NULL;    // defer initialization of esport until first usage
}

int PESProducer::fill_buffer ()
{
  if (buf) delete buf;
  length_stored = pes->PES_packet_length + 6;
  buf = (char*) malloc (length_stored);
  OutputPort* save_port = oport;
  oport = new OPortToRam(buf, length_stored, NULL);
  send_pes_packet();
  delete oport;
  oport = save_port;
  buf_index = 0;
  return length_stored;
}

void PESProducer::send_pes_packet ()
{
  oport->write_pattern("000000000000000000000001");

  oport->write_uimsbf(pes->stream_id, 8);

  oport->write_uimsbf(pes->PES_packet_length, 16);

  if ((pes->stream_id != id_private_stream_2) &&
      (pes->stream_id != id_padding_stream))
    {
      oport->write_pattern("10");
      
      // write PES_scrambling_control; currently uses only "00" or "11"
      if (pes->scrambling_code == 'S') oport->write_pattern("11");
      else oport->write_pattern("00");
      
      // write PES_priority
      if (pes->priority_code == 'H') oport->write_bit('1');
      else oport->write_bit('0');
      
      // write data_alignment_indicator
      if (pes->alignment_indicator_code == 'A') oport->write_bit('1');
      else oport->write_bit('0');
      
      // write copyright
      if (pes->copyright_code == 'C') oport->write_bit('1');
      else oport->write_bit('0');
      
      // write copy_or_original
      if (pes->original_code == 'O') oport->write_bit('1');
      else oport->write_bit('0');
      
      // write PTS_DTS_flags
      if (pes->PTS) oport->write_bit('1'); else oport->write_bit('0');
      if (pes->DTS) oport->write_bit('1'); else oport->write_bit('0');
      
      // write ESCR_flag
      if (pes->ESCR) oport->write_bit('1'); else oport->write_bit('0');
      
      // write ES_rate_flag
      if (pes->ES_rate) oport->write_bit('1'); else oport->write_bit('0');
      
      // write DSM_trick_mode_flag
      if (pes->trick_mode) oport->write_bit('1'); else oport->write_bit('0');
      
      // write additional_copy_info_flag
      if (pes->additional_copy_info) oport->write_bit('1'); else oport->write_bit('0');
      
      // write PES_CRC_flag
      if (pes->previous_CRC) oport->write_bit('1'); else oport->write_bit('0');
      
      // write PES_extension_flag 
      if (pes->extension) oport->write_bit('1'); else oport->write_bit('0');

      // write PES_header_data_length
      oport->write_uimsbf(pes->get_header_length() - 9, 8);

      // output all optional fields
      // output PTS, DTS
      if (pes->PTS)
	{
          if (timestamp_lock == FALSE)
	    {
	      TimeStamp90 PTS = encoder->sys_time + encoder->sys_const;
	      pes->PTS = &PTS;
  	      // FIX -- distinguish between PTS and DTS semantics
	      if (pes->DTS) pes->DTS = pes->PTS;
	    }
	  if (pes->PTS && !pes->DTS)
	    {
	      oport->write_pattern("0010");
	      oport->write_timestamp90(pes->PTS);
	    }
	  if (pes->PTS && pes->DTS)
	    {
	      oport->write_pattern("0011");
	      oport->write_timestamp90(pes->PTS);
	      oport->write_pattern("0001");
	      oport->write_timestamp90(pes->DTS);
	    }
	}
      // output ESCR
      if (pes->ESCR)
	{
	  oport->write_reserved_bits(2);
	  oport->write_timestamp27_pes_format(pes->ESCR);
	}

      // output ES_rate
      if (pes->ES_rate)
	{
	  oport->write_markerbit();
	  oport->write_uimsbf(pes->ES_rate, 22);
	  oport->write_markerbit();
	}

      // output DSM_trick_mode field
      if (pes->trick_mode)
        send_trick_mode();

      // output additional_copy_info
      if (pes->additional_copy_info)
	{
	  oport->write_markerbit();
	  char mask = (char) 1;
	  for (int i = 0; i < 7; i++)
	    {
	      if (pes->additional_copy_info & mask)
		oport->write_bit('1'); else oport->write_bit('0');
	      mask = mask << 1;
	    }
	}

      // output previous_PES_packet_CRC
      if (pes->previous_CRC)
	oport->write_uimsbf(pes->previous_CRC, 16);

      // output PES extension fields
      if (pes->extension)
	send_extension();

      // output stuffing bytes
      for (int i = 0; i < pes->number_stuffing_bytes; i++)
	oport->write_byte(0xff);

      // output payload
      send_payload();
    }
}

void PESProducer::send_trick_mode ()
{
  if (pes->trick_mode == NULL) return;
  switch (pes->trick_mode->trick_mode_control_code)
    {
    case 'F':
      oport->write_pattern("000");
      send_field_id();
      if (pes->trick_mode->intra_slice_refresh_code == 'I')
	oport->write_bit('1');
      else
	oport->write_bit('0');
      send_frequency_truncation();
      break;
    case 'S':
      oport->write_pattern("001");
      oport->write_uimsbf(pes->trick_mode->field_rep_control, 5);
      break;
    case 'Z':
      oport->write_pattern("010");
      send_field_id();
      oport->write_reserved_bits(3);
      break;
    case 'R':
      oport->write_pattern("011");
      send_field_id();
      if (pes->trick_mode->intra_slice_refresh_code == 'I')
	oport->write_bit('1');
      else
	oport->write_bit('0');
      send_frequency_truncation();
      break;
    }
}

void PESProducer::send_field_id ()
{
  if (pes->trick_mode == NULL) return;
  switch (pes->trick_mode->field_id_code)
    {
    case '1':
      oport->write_pattern("00");
      break;
    case '2':
      oport->write_pattern("01");
      break;
    case 'B':
      oport->write_pattern("10");	  
      break;
    }
}

void PESProducer::send_frequency_truncation ()
{
  if (pes->trick_mode == NULL) return;
  switch (pes->trick_mode->frequency_truncation_code)
    {
    case 'D':
      oport->write_pattern("00");
      break;
    case '3':
      oport->write_pattern("01");
      break;
    case '6':
      oport->write_pattern("10");
      break;
    case 'A':
      oport->write_pattern("11");
      break;
    }
}

void PESProducer::send_extension ()
{
  if (pes->extension == NULL) return;

  // output flags
  if (pes->extension->PES_private_data) oport->write_bit('1');
  else oport->write_bit('0');
  
  if (pes->extension->pack_header) oport->write_bit('1');
  else oport->write_bit('0');
  
  if (pes->extension->pp_seq_counter_code == '1') oport->write_bit('1');
  else oport->write_bit('0');
  
  if (pes->extension->P_STD_buffer_code == '1') oport->write_bit('1');
  else oport->write_bit('0');
  
  oport->write_reserved_bits(3);
  
  if (pes->extension->PES_extension_field_length) oport->write_bit('1');
  else oport->write_bit('0');
  
  // output PES_private_data
  if (pes->extension->PES_private_data)
    {
      for (int i = 0; i < 16; i++)
	{
	  oport->write_byte(pes->extension->PES_private_data[i]);
	}
    }
  
  // output pack_header
  if (pes->extension->pack_header)
    {
      oport->write_uimsbf(pes->extension->pack_field_length, 8);
      for (int j = 0; j < pes->extension->pack_field_length; j++)
	{
	  oport->write_byte(pes->extension->pack_header[j]);
	}
    }
  
  // output pp_seq_counter
  if (pes->extension->pp_seq_counter_code == ONE)
    {
      oport->write_markerbit();
      oport->write_uimsbf(pes->extension->pp_seq_counter, 7);
      oport->write_markerbit();
      oport->write_uimsbf(pes->extension->original_stuff_length, 7);      
    }
  
  // output P_STD_buffer
  if (pes->extension->P_STD_buffer_code == ONE)
    {
      oport->write_pattern("01");
      oport->write_bit(pes->extension->P_STD_buffer_scale);
      oport->write_uimsbf(pes->extension->P_STD_buffer_size, 13);
    }
  
  // output PES_extension_field
  if (pes->extension->PES_extension_field_length)
    {
      oport->write_markerbit();
      oport->write_uimsbf(pes->extension->PES_extension_field_length, 7);
      for (int k = 0; k < pes->extension->PES_extension_field_length; k++)
	{
	  oport->write_byte(0xff);
	}
    }
}

void PESProducer::send_payload ()
{
  // calculate payload length
  int payload_length = pes->get_length() - pes->get_header_length();
  if (payload_length <= 0) return;

  // prepare esport
  if (!esport)
    {
      esport = new IPortFromFile(pes->file_name, CYCLE);
    }
  
  // read/write loop
  char byte;
  for (int i = 0; i < payload_length; i++)
    {
      byte = esport->read_byte();
      oport->write_byte(byte);
    }
}