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

/* Encoder class implementation */

#include "Encoder.H"
#include "SectionProducers.H"
#include "PESProducer.H"
#include "TSProducer.H"
#include "Utilities.H"

Encoder::Encoder (EventManager* m)
{
  manager = m;
  tsprod = new TSProducer(this);
  head_prec = NULL;
  packet_number = 0;
  sys_time = 0;
  sys_const = 20000000;
  // set producer list to null
  head_prec = NULL;
}

void Encoder::set_bitrate (int r)
{
  bitrate = r;
  packet_time = (1504 * 27000) / bitrate;  
}

void Encoder::install_dir (Directory* d)
{
  dir = d;

  // build null packet TS and add producer
  TS* nullts = new TS();
  nullts->config_basic('0', '0', 'L', '0', '0', '0');
  nullts->pid = 8191;
  (void) add_prod(nullts, new Producer(this), NULLPROD, NULL);

  // build PAT packet TS and add producer
  TS* patts = new TS();
  patts->config_basic('0', 'A', 'H', '0', '0', 'P');  
  patts->pid = 0;
  (void) add_prod(patts, new PATProducer(this, new PATSection()), PSI, NULL);

  // FIX - set up conditional access producer as well
  
  // now setup prec's based on new directory
  build_records();
}

void Encoder::build_records ()
{
  // loop through programs in directory
  ProgramRecord* prec = dir->head_prec;
  while (prec)
    {
      // check pid for MapTable
      if (prec->program->pid == UNASSIGNED)
 	{
 	  prec->program->pid = new_pid();
	  if (prec->program->active == ACTIVE)
 	    {
 	      TS* mapts = new TS();
 	      mapts->pid = prec->program->pid;
	      mapts->config_basic('0', 'A', 'H', '0', '0', 'P');
	      (void) add_prod(mapts,
 		       new MapProducer(this, new MapSection(prec->program)),
 		       PSI, NULL);
 	    }
 	}
      else
 	{
	  // FIX - check to see if program is active before sending Map table
 	}
      // loop through programs estreams check estreams
      EStreamRecord* erec = prec->program->head_erec;
      while (erec)
 	{
 	  if (erec->estream->pid == UNASSIGNED)
 	    {
 	      erec->estream->pid = new_pid();
 	      if (prec->program->active == ACTIVE)
 		{
 		  TS* ts = new TS();
 	          ts->pid = erec->estream->pid;
 		  ts->config_basic('0', 'A', 'H', '0', 0, 'P');  	      
 		  ProducerRecord* prodrec = add_prod(ts,
 			   new PESProducer(this, new PES()), ELEM,
 			   erec->estream->bandwidth);
		  if (erec->estream == prec->program->pcr_estream)
		    {
		      prodrec->pcr_flag = 1;
		      prodrec->next_pcr = 0;
		    }
 		}
 	    }
 	  else
 	    {
 	      // FIX - further work on Encoder::build_records
 	    }
 	  erec = erec->next_erec;
 	}
      prec = prec->next_prec;
    }
}

void Encoder::connect (OutputPort* op)
{
  oport = op;
  // connect tsport
  tsprod->connect(op);
  // payload Producers connect just before they are used
}

void Encoder::send_packet (int pid)
{
  // get prec
  ProducerRecord* prec = find_prec(pid);
  send_packet(prec);
}

void Encoder::send_scheduled_packet ()
{
  ProducerRecord* min_prec = NULL;
  double min_cur_gap = 100.0;
  ProducerRecord* prec = head_prec;  
  while (prec)
    {
      if (prec->cur_gap < min_cur_gap)
 	{
 	  min_cur_gap = prec->cur_gap;
 	  min_prec = prec;
 	}
      prec = prec->next_prec;
    }
  send_packet(min_prec);
}

void Encoder::send_packet (ProducerRecord* prec_togo)
{
  if (prec_togo == NULL)
    {
      prec_togo = find_prec(8191);
      if (prec_togo == NULL)
	{
	  sys_message("can't find pid 8191 in Encoder table");
	  return;
	}    
    }

  // set up environment
  packet_number++;
  if (packet_number > 1) sys_time = sys_time + packet_time;

  // prepare and bind ts structure
  prec_togo->ts->inc_cc();
  if ((prec_togo->pcr_flag == 1) && (sys_time > prec_togo->next_pcr))
    {
      prec_togo->ts->add_pcr(sys_time);
      prec_togo->next_pcr = sys_time + TimeStamp27(270000);
    }
  else
    {
      prec_togo->ts->delete_pcr();
    }
  tsprod->ts = prec_togo->ts;
  
  // send packet
  tsprod->send_ts_packet(prec_togo->prod);

  // adjust gaps
  ProducerRecord* prec = head_prec;  
  while (prec)
    {
      if (prec == prec_togo)
	prec->cur_gap = prec->cur_gap + prec->gap;
      else
	prec->cur_gap = prec->cur_gap - 1;
      prec = prec->next_prec;
    }
}

Directory* Encoder::get_dir ()
{
  return dir;
}

TS* Encoder::get_ts (int pid)
{
  ProducerRecord* prec = find_prec(pid);
  if (prec)
    {
      return prec->ts;
    }
  return NULL;
}

PES* Encoder::get_pes (int pid)
{
  ProducerRecord* prec = find_prec(pid);
  if (prec)
    {
      PESProducer* pesprod = (PESProducer*) prec->prod;
      return pesprod->pes;
    }
  return NULL;
}

ProducerRecord* Encoder::add_prod (TS* ts, Producer* prod, ProdType t, int b)
{
  ProducerRecord* prec = new ProducerRecord(ts, prod, t);
  prec->next_prec = head_prec;
  prec->stream_band = b;
  head_prec = prec;
  recalc_mux();
  return prec;
}

void Encoder::delete_prod (int pid)
{
  ProducerRecord* cur_prec = head_prec;
  ProducerRecord* prev_prec;
  while (cur_prec)
    {
      if (cur_prec->ts->pid == pid)
	{
	  if (cur_prec == head_prec)
	    {
	      head_prec = head_prec->next_prec;
	    }
	  else
	    {
	      prev_prec->next_prec = cur_prec->next_prec;
	    }
	  delete cur_prec;
	  return;
	}
      prev_prec = cur_prec;
      cur_prec = cur_prec->next_prec;
    }
  recalc_mux();
}

ProducerRecord* Encoder::find_prec (int pid)
{
  ProducerRecord* prec = head_prec;
  while (prec)
    {
      if (prec == NULL)
	{
	  sys_error("unexpected NULL prec");
	}
      if (prec->ts->pid == pid)
	{
	  return prec;
	}
      prec = prec->next_prec;
    }
  return NULL;
}

Producer* Encoder::get_prod (int pid)
{
  ProducerRecord* prec = find_prec(pid);
  if (prec == NULL) return NULL;
  return prec->prod;
}

int Encoder::new_pid ()
{
  static int counter = 16;
  return counter++;
}

int max (int a, int b)
{
  return (a < b) ? b : a;
}

int Encoder::recalc_mux ()
{
  // sum non-psi and non-null bandwidths
  int elem_total = 0;
  int npsi = 0;
  ProducerRecord* prec = head_prec;
  while (prec)
    {
      if (prec->type == ELEM) elem_total = elem_total + prec->stream_band;
      if (prec->type == PSI) npsi++;
      prec = prec->next_prec;
    }

  // calculate total psi and set psi bandwidths
  psi_rate = max(80, int(double(bitrate) / 300.0));
  prec = head_prec;
  while (prec)
    {
      if (prec->type == PSI) prec->stream_band = psi_rate / npsi;
      prec->gap =
	(1.0 / (double(prec->stream_band) / double(bitrate))) - 1.0;
      prec = prec->next_prec;
    }
    
  // calculate null bandwidth
  if (elem_total + psi_rate > bitrate)
    {
      sys_error("stream bandwidth's is greater than total available");
    }
  prec = find_prec(8191);
  prec->stream_band = bitrate - (elem_total + psi_rate);
  prec->gap = (1.0 / (double(prec->stream_band) / double(bitrate))) - 1.0;
  
  return 1;
}

ProducerRecord::ProducerRecord (TS* t1, Producer* p, ProdType t2)
{
  ts = t1;
  type = t2;
  prod = p;
  pcr_flag = 0;
  next_prec = NULL;
}