/* YUNTAI KYONG
Advanced Internet Service
term project
*/
#include "assert.h"
#include <malloc.h>
#include "elementaryStream.h"
#include "fileStream.h"
extern void error(char*);


elementaryStream::elementaryStream(fileStream *fs, CSocket *sock, 
									unsigned long initTimeStamp, unsigned short initSequence)
{
	assert(fs != NULL);
	this->sock = sock;
	this->fs = fs;
	
	fs->get_next_data();
	next_start_code();
	m_slice_start_code = 0x101;
	m_time_stamp = initTimeStamp;
	m_seq_num = initSequence;
}

/* searching start code */
int 
elementaryStream::next_start_code(void)
{	
	int size = 0;
	while(!fs->BYTEALIGNED())
	{
		if(fs->get_bit())		/* get 0s until byte aligned */
			error("Not an MPEG file.  Cannot find start code");
	}	
	/* Check if we are at the start code.  
	If not there is zero byte stuffing */
	
	/* check starting code or skip zero byte stuffing */
	while(!fs->next_bits(24, 0x000001)) 
	{
		if(fs->get_byte())
			error("Not an MPEG file.  Cannot find start code");
		size++; 
	}
	return size;
}

/* check how many bytes until next start code */
int 
elementaryStream::find_next_start_code(void)
{
	for(int bytes = 0; !fs->next_bits(24, 0x000001); bytes++)
	{
		if( fs->next_bits(24, 0x000001) == -2 )
		{
			printf("end of file!\n");
			return -2;
		}
		fs->get_bits(8);
	}
	return bytes;
}



int 
elementaryStream::get_gop_header(unsigned char *payload, int bytesToGo)
{
/* This procedure reads a Gop picture by picture.  */
	if( !fs->next_bits(32, GROUP_START_CODE) )
		return -2;

	fs->mark();
	fs->get_bits(32);						// skip group_start_code
	gop_i.time_code   = fs->get_bits(25);	// time_code
	gop_i.closed_gop  = fs->get_bit();		// closed_gop
	gop_i.broken_link = fs->get_bit();		// broken_link
	next_start_code();
	
	// check exention header
	
	if(fs->next_bits(32, EXTENSION_START_CODE))
    {
		fs->get_bits(32);		// skip extension_start_code
		for(gop_i.gop_ext_data_size = 0; !fs->next_bits(24, 0x000001); gop_i.gop_ext_data_size++)
			gop_i.gop_ext_data[gop_i.gop_ext_data_size] = fs->get_byte();
		gop_i.gop_size = 4 + gop_i.gop_ext_data_size;
		next_start_code();
    }
	else
		gop_i.gop_ext_data_size = 0;
	// check user data
	if(fs->next_bits(32, USER_DATA_START_CODE))
    {
		fs->get_bits(32);		// skip user_data_start_code
		for(gop_i.gop_user_data_size = 0; !fs->next_bits(24, 0x000001); gop_i.gop_user_data_size++)
			gop_i.gop_user_data[gop_i.gop_user_data_size] = fs->get_byte();
		gop_i.gop_size += 4 + gop_i.gop_user_data_size;
		next_start_code();
    }
	else
		gop_i.gop_user_data_size = 0;
	
	//find_next_start_code();
	next_start_code();
	//assert( fs->next_bits(32, PICTURE_START_CODE) );
	printf("get next start code()" );
	if( fs->getSizeFromMark() <= bytesToGo )
	{
		fs->load( payload );
		
		return fs->getSizeFromMark();
	}
	else
	{
		fs->rewind();	
		return -1;
	}
	
	
}

void 
elementaryStream::print_picture_header()
{
	printf("temporal reference: %d\n", picture_h.temporal_reference );
	printf("picture config type: %d\n",picture_h.picture_config_type );
	printf("vbv_delay: %d\n",picture_h.vbv_delay );
	

}

int 
elementaryStream::get_picture_header(unsigned char *payload, int bytesToGo)
{	
	
	if(!fs->next_bits(32, PICTURE_START_CODE))
	{
		printf("get_bits: %d\n",fs->get_bits(32));
		return -2;
	}

	fs->mark();
	fs->get_bits(32);		// skip picture strat code
	
	picture_h.temporal_reference	= fs->get_bits(10);	// temporal reference
	picture_h.picture_config_type	= fs->get_bits(3);	// type of picture		
	picture_h.vbv_delay				= fs->get_bits(16);	// 
	m_pic_type = picture_h.picture_config_type;
	if( picture_h.picture_config_type == 2 || picture_h.picture_config_type == 3 )
	{
		picture_h.full_pel_forward_vector  = fs->get_bit();
		picture_h.forward_f_code		   = fs->get_bits(3);
	}
	
	if( picture_h.picture_config_type == 3 )
	{
		picture_h.full_pel_backward_vector = fs->get_bit();
		picture_h.backward_f_code		   = fs->get_bits(3);
		
	}
		
	while( fs->get_bit() )
	{
		
		fs->get_bits(8);
		printf("get extra bits!\n");
	}
	
	
	next_start_code();
	
	if( fs->getSizeFromMark() <= bytesToGo )
	{
		fs->load( payload );
		
		return fs->getSizeFromMark();
	}
	else
	{
		fs->rewind();	
		return -1;
	}	
	
	
}

int elementaryStream::get_user_data(unsigned char *payload, int bytesToGo)
{
	if(!fs->next_bits(32, USER_DATA_START_CODE))
		return -2;
	fs->mark();
	
	find_next_start_code();
	if( fs->getSizeFromMark() <= bytesToGo )
	{
		fs->load( payload  );
		
		return fs->getSizeFromMark();
	}
	else
	{
		fs->rewind();	
		return -1;
	}	
}

int 
elementaryStream::get_sequence_header(unsigned char *payload, int bytesToGo)
{
	if(!fs->next_bits(32, SEQUENCE_HEADER_CODE))
		return -2;
	
	fs->mark();
	fs->get_bits(32);			// skip sequence_header_code
	sequence_h.horizontal_size_value	= fs->get_bits(12);		// horizontal_size_value
	sequence_h.vertical_size_value		= fs->get_bits(12);		// vertical_size_value
	sequence_h.aspect_ratio_infomation	= fs->get_bits(4);		// aspect_ratio_infomation
	sequence_h.frame_rate_value			= fs->get_bits(4);		// grame_rate_value
	sequence_h.bit_rate_value			= fs->get_bits(18);		// bit_rate_value
	sequence_h.marker_bit				= fs->get_bit();		// marker_bit( should be '1' )

	if(!sequence_h.marker_bit)
		error("Marker bit in SEQUENCE HEADER not set.  MPEG file is corrupted");
	
	sequence_h.vbv_buffer_size_value		= fs->get_bits(10);		// vbv_buffer_size_value
	sequence_h.constrained_parameters_flag	= fs->get_bit();		// constrained_parameters_flag(=0)
	
	// check intra_quantiser_matrix and load
	sequence_h.load_intra_quantiser_matrix	= fs->get_bit();		// load_intra_quantiser_matrix
	if(sequence_h.load_intra_quantiser_matrix)
		for(int i = 0; i < 64; i++)
			sequence_h.intra_quantiser_matrix[i] = fs->get_bits(8);
	
	// check non_intra_quantiser_matrix and load
	sequence_h.load_non_intra_quantiser_matrix = fs->get_bit();
	if(sequence_h.load_non_intra_quantiser_matrix)
		for(int i = 0; i < 64; i++)
			sequence_h.non_intra_quantiser_matrix[i] = fs->get_bits(8);
	
	// seek to next start code
	next_start_code();
	
	// check extention_start_code
	// TODO: should be parsed to get profile_and_level_indication
	if(fs->next_bits(32, EXTENSION_START_CODE))
	{
		fs->get_bits(32);	// skip extension_start_code
		for(sequence_h.ext_data_size = 0; !fs->next_bits(24, 0x000001); sequence_h.ext_data_size++)
			sequence_h.ext_data[sequence_h.ext_data_size] = fs->get_byte();
		next_start_code();
	}
	else
		sequence_h.ext_data_size = 0;
	
	next_start_code();
	if(fs->next_bits(32, USER_DATA_START_CODE))
	{
		fs->get_bits(32);
		for(sequence_h.user_data_size = 0; !fs->next_bits(24, 0x000001); sequence_h.user_data_size++)
			sequence_h.user_data[sequence_h.user_data_size] = fs->get_byte();
		next_start_code();
	}
	else
		sequence_h.user_data_size = 0;
	
	sequence_h.sequence_header_size = 12 + (64 * sequence_h.load_intra_quantiser_matrix) 
						+ (64 * sequence_h.load_non_intra_quantiser_matrix);
	
	if(sequence_h.ext_data_size)
		sequence_h.sequence_header_size += 4 + sequence_h.ext_data_size;
	
	if(sequence_h.user_data)
		sequence_h.sequence_header_size += 4 + sequence_h.user_data_size;
	
	find_next_start_code();
	
	int loadSize = fs->getSizeFromMark();
	printf("loadSize: %d\n", loadSize);
	if( loadSize <= bytesToGo )
	{
		printf("load: %d\n", fs->load( payload  ) );
		return loadSize;
	}
	else
	{
		fs->rewind();	
		return -1;
	}
	
	return 1;
}
int 
elementaryStream::get_extension(unsigned char *payload, int bytesToGo)
{
	if(!fs->next_bits(32, EXTENSION_START_CODE))
		return -2;
	
	fs->mark();
	fs->get_bits(32);		// skip EXTENSION_START_CODE

	extension_h.extension_ID				= fs->get_bits(4);	// 4
	extension_h.f_code00					= fs->get_bits(4);	// 4
	extension_h.f_code01					= fs->get_bits(4);	// 4
	extension_h.f_code10					= fs->get_bits(4);	// 4
	extension_h.f_code11					= fs->get_bits(4);	// 4
	extension_h.intra_dc_precision			= fs->get_bits(2);	// 2
	extension_h.picture_structure			= fs->get_bits(2);	// 2
	extension_h.top_field_first				= fs->get_bit();	// 1
	extension_h.frame_pred_and_frame_dct	= fs->get_bit();	// 1
	extension_h.cpmcealment_motion_vectors	= fs->get_bit();	// 1
	extension_h.q_scale_type				= fs->get_bit();	// 1
	extension_h.intra_vic_format			= fs->get_bit();	// 1
	extension_h.alternate_scan				= fs->get_bit();	// 1
	extension_h.repeat_first_field			= fs->get_bit();	// 1	
	extension_h.chroma_420_type				= fs->get_bit();	// 1
	extension_h.progressive_frame			= fs->get_bit();	// 1
	extension_h.composite_display_flag		= fs->get_bit();	// 1
	
	if( extension_h.composite_display_flag )
	{
		extension_h.v_axis				= fs->get_bit();			// 1	
		extension_h.field_sequence		= fs->get_bits(3);			// 3
		extension_h.sub_carrier			= fs->get_bit();			// 1
		extension_h.burst_amplitude		= fs->get_bits(7);			// 7
		extension_h.sub_carrier_phase	= fs->get_bits(8);			// 8
	}

	next_start_code();
	
	if( fs->getSizeFromMark() <= bytesToGo )
	{
		fs->load( payload  );
		
		return fs->getSizeFromMark();
	}
	else
	{
		fs->rewind();	
		return -1;
	}	
}

void 
elementaryStream::print_gop()
{
	
	printf("Time code %x\n", gop_i.time_code);
	printf("closed_gop %s\n", gop_i.closed_gop ? "true" : "false");
	printf("broken_link %s\n", gop_i.broken_link ? "true" : "false");
	
	if(gop_i.gop_ext_data_size)
		printf("Extension data exists\n");
	
	if(gop_i.gop_user_data_size)
		printf("User data exists\n");
	
	printf("Size of gop %d\n", gop_i.gop_size);
}

int 
elementaryStream::get_slices(unsigned char *payload, int bytesToGo)
{
	
	fs->mark();
	fs->get_bits(32);			// skip slice header
	if( find_next_start_code() == -2 )
	{
		while( fs->get_byte() != -2 );
		fs->load(payload);
		printf("end of file!\n");
		return -2;
	}
	
	while( !(fs->next_bits(32, GROUP_START_CODE) || fs->next_bits(32, SEQUENCE_HEADER_CODE) ||
		fs->next_bits(32, SEQUENCE_END_CODE)|| fs->next_bits(32, PICTURE_START_CODE)) )
	{
		fs->get_bits(32);
		if( find_next_start_code() == -2 )
		{
			while( fs->get_byte() != -2 );
			fs->load(payload);
			printf("end of file!\n");
			return -2;
		}
	}
	return fs->load(payload);
	
	//printf("before find_next_start_code()\n" );
	//printf("next start code: %u\n", next_start  );
	//printf("after find_next_start_code()\n" );
	//next_start_code();
	/*
	if( fs->getSizeFromMark() <= bytesToGo )
	{
		
	}
	else
	{
		printf(" **************** insufficient...  *************** \n");
		fs->rewind();
		return -1;
	}
	*/
	
}

void
elementaryStream::print_sequence_header()
{
	printf("Got MPEG sequence header\n");
	printf("Sequence header size %d\n", sequence_h.sequence_header_size);
	printf("Frame width %d\n", sequence_h.horizontal_size_value);
	printf("Frame height %d\n", sequence_h.vertical_size_value);
	printf("Pel aspect ratio (height to width) %d\n",(sequence_h.aspect_ratio_infomation > 16) ? 
		0 : sequence_h.aspect_ratio_infomation);
	printf("Picture rate %d\n", (sequence_h.frame_rate_value > 8) ?
		9 : sequence_h.frame_rate_value);
	printf("Bit rate ");
	if(sequence_h.bit_rate_value == 0x3ffff)
		printf("variable\n");
	else
		printf("%d bits/s (%5.2f Kbytes/s)\n", sequence_h.bit_rate_value * 400,
        (sequence_h.bit_rate_value * 400.0) / 8192);
	printf("Vbv buffer size %d\n", sequence_h.vbv_buffer_size_value);
	if(sequence_h.load_intra_quantiser_matrix)
		printf("Intra quantizer matrix exists\n");
	else
		printf("Uses default intra quantizer matrix\n");
	if(sequence_h.load_non_intra_quantiser_matrix)
		printf("Non intra quantizer matrix exists\n");
	else
		printf("Uses default non intra quantizer matrix\n");
	if(sequence_h.ext_data_size)
		printf("Extension data exists\n");
	if(sequence_h.user_data_size)
		printf("User data exists\n");
}


void 
elementaryStream::getVideoSpecficeHeader( unsigned char* vs_header, 
										  int end_of_slice,
										  int beginning_of_slce,
										  int seq_header_present,
										  int new_pic_header,	
										  int active_N_bit	)
{
	VIDEO_SPECIFIC_HEADER *vh = (VIDEO_SPECIFIC_HEADER*)vs_header;
	vh->TR		= picture_h.temporal_reference;
	vh->T		= 1;
	vh->MBZ		= 0;

	vh->FFC		= picture_h.forward_f_code;
	vh->FFV		= picture_h.full_pel_forward_vector;
	vh->BFC		= picture_h.backward_f_code;
	vh->FBV		= picture_h.full_pel_backward_vector;
    vh->P		= picture_h.picture_config_type;
    vh->E		= end_of_slice;
	vh->B		= beginning_of_slce;
    vh->S		= seq_header_present;
    vh->N		= new_pic_header;
	vh->AN		= active_N_bit;
}


void elementaryStream::getMPEG2ExtensionHeader( unsigned char* e_h)
{
	MPEG2_VIDEO_SPECIFIC_HEADER_EXTENSION *h = (MPEG2_VIDEO_SPECIFIC_HEADER_EXTENSION*)e_h;
		/* byte 0,1 */
	h->backward_vertical_f_code		= extension_h.f_code11;
	h->backward_horizontal_f_code	= extension_h.f_code10;
	h->forward_vertical_f_code		= extension_h.f_code01;	
	h->forward_horizontal_f_code	= extension_h.f_code00;		
	h->E = 0;								/* Extensions present */
	h->X = 0;								/* Unused	*/
	/* byte 2,3 */
	h->DC = extension_h.intra_dc_precision;				/* Intra_DC_precision  */
	h->PS = extension_h.picture_structure;								/* picture_structure  */
	h->T = extension_h.top_field_first;								/* top_field_first  */
	h->P = extension_h.frame_pred_and_frame_dct;								/* frame_predicted_frame_dct   */
	h->C = extension_h.cpmcealment_motion_vectors;								/* concealment_motion_vectors   */
	h->Q = extension_h.q_scale_type;								/* q_scale type   */
	h->V = extension_h.intra_vic_format;								/* intra_vlc_format   */
	h->A = extension_h.alternate_scan;								/* alternate scan   */
	h->R = extension_h.repeat_first_field;								/* repeat_first_field   */
	h->H = extension_h.chroma_420_type;								/* chroma_420_type   */
	h->G = extension_h.progressive_frame;								/* progressive frame   */
	h->D = extension_h.composite_display_flag;								/* composite_display_flag   */
/*	
	extension_h.v_axis;					// 1	
	extension_h.field_sequence;			// 3
	extension_h.sub_carrier;				// 1
	extension_h.burst_amplitude;			// 7
	extension_h.sub_carrier_phase;			// 8
*/	
}

int
elementaryStream::sendRTPpacket(unsigned char* payload,int increment, int marker,int payloadSize)
{
	static unsigned char    buffer[16384];
	static unsigned char    RTP_pkt[sizeof(RTP_HEADER)+sizeof(buffer)];
	static RTP_HEADER *rtp_header;
	m_stream_num = 10;

	rtp_header = (RTP_HEADER *)RTP_pkt;
	
	rtp_header->csrc_len		= 0;				/* expect 0 */
	rtp_header->extension	= 0;				
	rtp_header->padding		= 0;				/* expect 0 */
	rtp_header->version		= RTP_VERSION;		/* expect 2 */
	
	/* byte 1 */
	rtp_header->payload		= MPV_PAYLOAD;		
	rtp_header->marker		= marker;			
	/* bytes 2, 3 */
	rtp_header->seq_no		= htons(m_seq_num++);			
	/* bytes 4-7 */
	if( marker )
		Sleep( 33 ); // sleep 33 msec
	
	if( increment )
	{
		m_time_stamp += (29700*hold);		
		hold = 0;
	}

	rtp_header->timestamp	= htonl(m_time_stamp);
	/* bytes 8-11 */
    rtp_header->ssrc		= htonl(m_stream_num);			/* stream number is used here. */
	
	memcpy( RTP_pkt + sizeof(RTP_HEADER), payload, payloadSize );
	return sock->write( (void*)&RTP_pkt, sizeof(RTP_HEADER)+payloadSize );
}
