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;
}