/* 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 "Utilities.H"
#include "PESConsumer.H"
#include "IPortFromRam.H"
#include "Decoder.H"
#include "OPortToFile.H"
extern "C"
{
#include <stdio.h>
#include <fcntl.h>
#include <malloc.h>
int write (int, char*, int);
}
PESConsumer::PESConsumer (Decoder* d, PES* p) : Consumer(d)
{
pes = p;
cstate = CSTART;
pes_out_flag = TRUE;
esport = NULL;
}
// transfer c from binary to decimal
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. */
// 分析PES的信息
int PESConsumer::read_partial (int n)
{
int i = 0;
while (i < n)
{
switch (cstate)
{
case CSTART:
buf = (char*) malloc (512);
buf_index = 0;
cstate = PCHEAD1;
break;
case PCHEAD1:
if (buf_index < 9)
{
buf[buf_index] = iport->read_byte();
buf_index++;
i++;
}
if (buf_index == 9)
{
header_length = char2int(buf[8]) + 9; // (buf[8])= PES_header_data_length
cstate = PCHEAD2;
}
break;
case PCHEAD2:
if(buf_index < header_length)
{
buf[buf_index] = iport->read_byte();
buf_index++;
i++;
}
if (buf_index == header_length)
{
InputPort* save_port = iport;
iport = new IPortFromRam(buf, header_length);
read_pes_header();
delete iport;
iport = save_port;
if (pes_out_flag)
write_elementary_stream_chunk(buf, header_length);
delete buf;
buf_index = 0; // done with buf
cstate = PCPAYLOAD;
}
break;
case PCPAYLOAD:
// dispense with remaining n-i payload bytes
{ // 20080107
int plen = n - i;
char* pbuf = (char*) malloc(plen);
for (int j = 0; j < plen; j++)
{
pbuf[j] = iport->read_byte();
i++;
}
write_elementary_stream_chunk(pbuf, plen);
delete pbuf;
assert(i == n);
// stay in PCPAYLOAD state;
// state changes when payload_unit_start_indicator is seen
}
break;
default:
sys_error("unknown PESConsumer state");
}
}
return n;
}
void PESConsumer::flush ()
{
esport->flush();
}
void PESConsumer::write_elementary_stream_chunk (char* pbuf, int plen)
{
// prepare esport
if (!esport)
{
// use decoder->get_ts()->pid or pes->stream_id?
int cur_pid = decoder->get_ts()->pid;
// FIX - provide access function to current pid from decoder?
char fileName[32];
sprintf(fileName, "stream%d", cur_pid);
esport = new OPortToFile(fileName, 0);
}
// output loop
for (int i = 0; i < plen; i++)
{
esport->write_byte(pbuf[i]);
}
}
void PESConsumer::read_pes_header ()
{
int result = iport->read_pattern("000000000000000000000001");
pes->stream_id = iport->read_uimsbf(8, "reading stream_id");
pes->PES_packet_length = iport->read_uimsbf(16, "reading PES_packet_length");
if ((pes->stream_id != id_private_stream_2) && (pes->stream_id != id_padding_stream))
{
// read "01"
int result = iport->read_pattern("10");
// read PES_scrambling_control; currently uses only "00" or "11"
char scramble1 = iport->read_bit();
char scramble2 = iport->read_bit();
if ((scramble1 == ZERO) && (scramble2 == ZERO))
pes->scrambling_code = '0';
else
pes->scrambling_code = 'S';
// read PES_priority
char priority = iport->read_bit();
if (priority == ONE)
pes->priority_code = 'H';
else
pes->priority_code = 'L';
// read data_alignment_indicator
char align = iport->read_bit();
if (align == ONE)
pes->alignment_indicator_code = 'A';
else
pes->alignment_indicator_code = '0';
// read copyright
char copyright = iport->read_bit();
if (copyright == ONE)
pes->copyright_code = 'C';
else
pes->copyright_code = '0';
// read copy_or_original
char original = iport->read_bit();
if (original == ONE)
pes->original_code = 'C';
else
pes->original_code = '0';
// read 8 flags
char pts_flag = iport->read_bit();
char dts_flag = iport->read_bit();
char escr_flag = iport->read_bit();
char esrate_flag = iport->read_bit();
char dsm_trick_flag = iport->read_bit();
char additional_copy_flag = iport->read_bit();
char crc_flag = iport->read_bit();
char extension_flag = iport->read_bit();
// read PES_header_data_length
int PES_header_length =
iport->read_uimsbf(8, "reading PES_header_length");
// read optional fields
// read pts,dts
if ((pts_flag == ONE) && (dts_flag == ZERO))
{
iport->read_pattern("0010");
pes->PTS = iport->read_timestamp90();
pes->DTS = NULL;
decoder->get_manager()->Trigger(PTSDTSEvent, pes);
}
else if ((pts_flag == ONE) && (dts_flag == ONE))
{
iport->read_pattern("0011");
pes->PTS = iport->read_timestamp90();
iport->read_pattern("0001");
pes->DTS = iport->read_timestamp90();
decoder->get_manager()->Trigger(PTSDTSEvent, pes);
}
else
{
pes->PTS = NULL;
pes->DTS = NULL;
}
// read escr
if (escr_flag == ONE)
{
iport->read_reserved_bits(2);
pes->ESCR = iport->read_timestamp27_pes_format();
}
// read es_rate
if (esrate_flag == ONE)
{
iport->read_markerbit();
pes->ES_rate = iport->read_uimsbf(22, "reading ES_rate");
iport->read_markerbit();
}
// read DSM_trick_mode
if (dsm_trick_flag == ONE)
{
read_trick_mode();
}
// read additional_copy_info
if (additional_copy_flag == ONE)
{
iport->read_markerbit();
pes->additional_copy_info = NULL;
char c;
for (int i = 0; i < 7; i++)
{
c = iport->read_bit();
if (c == '1')
{
pes->additional_copy_info |= (1 << i);
}
}
}
// read previous_PES_packet_CRC
if (crc_flag == ONE)
{
pes->previous_CRC = iport->read_uimsbf(16, "reading previous_CRC");
}
// read PES extension fields
if (extension_flag == ONE)
{
read_extension();
}
// skip the stuffing bytes. N.B. the "9" added to PES_header_length
pes->number_stuffing_bytes =
PES_header_length + 9 - pes->get_header_data_length();
for (int i = 0; i < pes->number_stuffing_bytes; i++)
iport->read_byte();
}
// call PESParsed callback
decoder->get_manager()->Trigger(PESHeaderParsed, pes);
}
void PESConsumer::read_trick_mode ()
{
char intra;
pes->trick_mode = new TrickMode();
int code = iport->read_uimsbf(3, "reading trick_control_code");
switch (code)
{
case 0:
pes->trick_mode->trick_mode_control_code = 'F';
read_field_id();
intra = iport->read_bit();
if (intra == ONE)
{
pes->trick_mode->intra_slice_refresh_code = 'I';
}
else
{
pes->trick_mode->intra_slice_refresh_code = '0';
}
read_frequency_truncation();
break;
case 1:
pes->trick_mode->trick_mode_control_code = 'S';
pes->trick_mode->field_rep_control =
iport->read_uimsbf(5, "reading field rep_control");
break;
case 2: