/*******************************************************************
   MPEG Video sequence header reading routine
 *******************************************************************/

#include "scan.h"

#define SEQUENCE_HEADER_C
#include "sequence_header.h"

int read_sequence_header(MPEG_IO *in, SEQUENCE_HEADER *out);
int sequence_header_to_bgr_conversion_parameter(SEQUENCE_HEADER *in, BGR_CONVERSION_PARAMETER *out, int remap);
int sequence_header_to_read_picture_header_option(SEQUENCE_HEADER *in, READ_PICTURE_HEADER_OPTION *out);
int sequence_header_to_read_slice_header_option(SEQUENCE_HEADER *in, READ_SLICE_HEADER_OPTION *out);
int sequence_header_to_read_macroblock_option(SEQUENCE_HEADER *in, READ_MACROBLOCK_OPTION *out);
int sequence_header_to_read_block_option(SEQUENCE_HEADER *in, READ_BLOCK_OPTION *out);
int sequence_header_to_mc_parameter(SEQUENCE_HEADER *in, MC_PARAMETER *out);

static int identify_frame_per_scale(int picture_rate, FRAME_PER_SCALE *out);

int read_sequence_header(MPEG_IO *in, SEQUENCE_HEADER *out)
{
	int i;
	int code;
	
	out->h_size = get_bits(in, 12);
	out->v_size = get_bits(in, 12);
	out->aspect_ratio = get_bits(in, 4);
	out->picture_rate = get_bits(in, 4);
	
	identify_frame_per_scale(out->picture_rate, &(out->fps));
	
	out->bit_rate = get_bits(in, 18);
	get_bits(in, 1); /* marker bit */
	out->vbv_buffer_size = get_bits(in, 10);
	out->mpeg1 = get_bits(in, 1);
	out->has_intra_quantizer_matrix = get_bits(in, 1);
	if(out->has_intra_quantizer_matrix){
		for(i=0;i<64;i++){
			out->iqm[i] = get_bits(in, 8);
		}
	}
	out->has_nonintra_quantizer_matrix = get_bits(in, 1);
	if(out->has_nonintra_quantizer_matrix){
		for(i=0;i<64;i++){
			out->nqm[i] = get_bits(in, 8);
		}
	}

	while(next_start_code(in)){
		code = read_bits(in, 32);
		if(code != 0x1b5){
			break;
		}
		erase_bits(in, 32);

		code = get_bits(in, 4);
		switch(code){
		case 1:
			out->has_sequence_extension = 1;
			out->se.profile_and_level = get_bits(in, 8);
			out->se.progressive = get_bits(in, 1);
			out->se.chroma_format = get_bits(in, 2);
			out->h_size += get_bits(in, 2) << 12;
			out->v_size += get_bits(in, 2) << 12;
			out->bit_rate += get_bits(in, 12) << 18;
			out->vbv_buffer_size += get_bits(in, 8) << 10;
			out->se.low_delay = get_bits(in, 1);
			out->se.frame_rate_ext_n = get_bits(in, 2);			
			out->se.frame_rate_ext_d = get_bits(in, 2);

			out->fps.frame *= (out->se.frame_rate_ext_n + 1);
			out->fps.scale *= (out->se.frame_rate_ext_d + 1);
			
			break;
		case 2:
			out->has_sequence_display_extension = 1;
			out->sd.video_format = get_bits(in, 3);
			out->sd.has_color_description = get_bits(in, 1);
			if(out->sd.has_color_description){
				out->sd.color_primaries = get_bits(in, 8);
				out->sd.transfer_characteristics = get_bits(in, 8);
				out->sd.matrix_coefficients = get_bits(in, 8);
			}
			out->sd.display_h_size = get_bits(in, 14);
			out->sd.display_v_size = get_bits(in, 14);
			break;
		case 5:
			out->has_sequence_scalable_extension = 1;
			out->ss.scalable_mode = get_bits(in, 2);
			out->ss.layer = get_bits(in, 4);
			if(out->ss.scalable_mode == 1){
				out->ss.lower_layer_prediction_h_size = get_bits(in, 14);
				out->ss.lower_layer_prediction_v_size = get_bits(in, 14);
				out->ss.h_subsampling_facter_m = get_bits(in, 5);
				out->ss.h_subsampling_facter_n = get_bits(in, 5);
				out->ss.v_subsampling_facter_m = get_bits(in, 5);	
				out->ss.v_subsampling_facter_n = get_bits(in, 5);
			}else if(out->ss.scalable_mode == 3){
				out->ss.picture_mux_enable = get_bits(in, 1);
				out->ss.mux_to_progressive_sequence = get_bits(in, 1);
				out->ss.pixture_mux_order = get_bits(in, 3);
				out->ss.pixture_mux_facter = get_bits(in, 3);
			}
			break;
		default:
			return 0;
		}
	}

	return 1;
}

int sequence_header_to_bgr_conversion_parameter(SEQUENCE_HEADER *in, BGR_CONVERSION_PARAMETER *out, int remap)
{
	static const int table[8][2][3][3] = {
		{
			{	/*   Y       U       V        */     
				{65536,      0, 103219}, /* R */
				{65536, -12257, -30659}, /* G */
				{65536, 121621,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 117504}, /* R */
				{76309, -13954, -34903}, /* G */
				{76309, 138453,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* no sequence_display_extension */

		{
			{	/*   Y       U       V        */     
				{65536,      0, 103219}, /* R */
				{65536, -12257, -30659}, /* G */
				{65536, 121621,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 117504}, /* R */
				{76309, -13954, -34903}, /* G */
				{76309, 138453,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* ITU-R Rec. 709 */

		{
			{	/*   Y       U       V        */     
				{65536,      0,  91881}, /* R */
				{65536, -22553, -46801}, /* G */
				{65536, 116129,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 104597}, /* R */
				{76309, -25675, -53279}, /* G */
				{76309, 132201,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* unspecified video */

		{
			{	/*   Y       U       V        */     
				{65536,      0,  91881}, /* R */
				{65536, -22553, -46801}, /* G */
				{65536, 116129,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 104597}, /* R */
				{76309, -25675, -53279}, /* G */
				{76309, 132201,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* reserved */

		{
			{	/*   Y       U       V        */     
				{65536,      0,  91750}, /* R */
				{65536, -21749, -46652}, /* G */
				{65536, 116654,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 104448}, /* R */
				{76309, -24759, -53109}, /* G */
				{76309, 132798,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* FCC */

		{
			{	/*   Y       U       V        */     
				{65536,      0,  91881}, /* R */
				{65536, -22553, -46801}, /* G */
				{65536, 116129,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 104597}, /* R */
				{76309, -25675, -53279}, /* G */
				{76309, 132201,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* ITU-R Rec. 624-4 System B, G */

		{
			{	/*   Y       U       V        */     
				{65536,      0,  91881}, /* R */
				{65536, -22553, -46801}, /* G */
				{65536, 116129,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 104597}, /* R */
				{76309, -25675, -53279}, /* G */
				{76309, 132201,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* SMPTE 170M */

		{
			{	/*   Y       U       V        */     
				{65536,      0, 103284}, /* R */
				{65536, -22680, -47127}, /* G */
				{65536, 119668,      0}, /* B */
			}, /* straight conversion */
	
			{	/*   Y       U       V        */     
				{76309,      0, 117579}, /* R */
				{76309, -16907, -35559}, /* G */
				{76309, 136230,      0}, /* B */
			}, /* re-map conversion */
		
		}, /* SMPTE 240 */
	};

	if(in->has_sequence_extension){
		out->chroma_format = in->se.chroma_format;
		out->progressive = in->se.progressive;
	}else{
		out->chroma_format = 1;
		out->progressive = 1;
	}

	if(in->has_sequence_display_extension){
		out->ry = table[in->sd.matrix_coefficients][remap][0][0];
		out->ru = table[in->sd.matrix_coefficients][remap][0][1];
		out->rv = table[in->sd.matrix_coefficients][remap][0][2];

		out->gy = table[in->sd.matrix_coefficients][remap][1][0];
		out->gu = table[in->sd.matrix_coefficients][remap][1][1];
		out->gv = table[in->sd.matrix_coefficients][remap][1][2];

		out->by = table[in->sd.matrix_coefficients][remap][2][0];
		out->bu = table[in->sd.matrix_coefficients][remap][2][1];
		out->bv = table[in->sd.matrix_coefficients][remap][2][2];
	}else{
		out->ry = table[0][remap][0][0];
		out->ru = table[0][remap][0][1];
		out->rv = table[0][remap][0][2];

		out->gy = table[0][remap][1][0];
		out->gu = table[0][remap][1][1];
		out->gv = table[0][remap][1][2];

		out->by = table[0][remap][2][0];
		out->bu = table[0][remap][2][1];
		out->bv = table[0][remap][2][2];
	}

    return 1;		
}
int sequence_header_to_read_picture_header_option(SEQUENCE_HEADER *in, READ_PICTURE_HEADER_OPTION *out)
{
	if(in->has_sequence_extension){
		out->progressive_sequence = in->se.progressive;
	}else{
		out->progressive_sequence = 1;
	}
	
	return 1;
}

int sequence_header_to_read_slice_header_option(SEQUENCE_HEADER *in, READ_SLICE_HEADER_OPTION *out)
{
	out->v_size = in->v_size;

	if(in->has_sequence_scalable_extension){
		out->scalable_mode = in->ss.scalable_mode;
	}else{
		out->scalable_mode = -1;
	}

	return 1;
}

int sequence_header_to_read_macroblock_option(SEQUENCE_HEADER *in, READ_MACROBLOCK_OPTION *out)
{
	if(in->has_sequence_extension){
		out->chroma_format = in->se.chroma_format;
	}else{
		out->chroma_format = 1;
	}
	
	if(in->has_sequence_scalable_extension){
		out->scalable_mode = in->ss.scalable_mode;
	}else{
		out->scalable_mode = -1;
	}

	return 1;
}

int sequence_header_to_read_block_option(SEQUENCE_HEADER *in, READ_BLOCK_OPTION *out)
{
	int i;

	if(in->has_sequence_extension){
		out->chroma_format = in->se.chroma_format;
	}else{
		out->chroma_format = 1;
	}
		
	if(in->has_intra_quantizer_matrix){
		for(i=0;i<64;i++){
			out->quantizer_weight[0][scan_table[0][i]] = in->iqm[i];
			out->quantizer_weight[2][scan_table[0][i]] = in->iqm[i];
		}
	}else{
		memcpy(out->quantizer_weight[0], default_intra_quantizer_matrix, 64);
		memcpy(out->quantizer_weight[2], default_intra_quantizer_matrix, 64);
	}

	if(in->has_nonintra_quantizer_matrix){
		for(i=0;i<64;i++){
			out->quantizer_weight[1][scan_table[0][i]] = in->nqm[i];
			out->quantizer_weight[3][scan_table[0][i]] = in->nqm[i];
		}
	}else{
		memset(out->quantizer_weight[1], 16, 64);
		memset(out->quantizer_weight[3], 16, 64);
	}

	return 1;
}

int sequence_header_to_mc_parameter(SEQUENCE_HEADER *in, MC_PARAMETER *out)
{
	if(in->has_sequence_extension){
		out->chroma_format = in->se.chroma_format;
	}else{
		out->chroma_format = 1;
	}
	
	return 1;
}
static int identify_frame_per_scale(int picture_rate, FRAME_PER_SCALE *out)
{
	static const int frame[16] = {
		 0, 23976, 24, 25, 2997, 30, 50, 5994,
		60,     0,  0,  0,    0,  0,  0,    0,
	};

	static const int scale[16] = {
		 1,  1000,  1,  1,  100,  1,  1,  100,
		 1,     1,  1,  1,    1,  1,  1,    1,
	};

	if(picture_rate < 0 || picture_rate > 16){
		return 0;
	}
	
	out->frame = frame[picture_rate];
	out->scale = scale[picture_rate];

	return 1;
}