/*******************************************************************
            MPEG Video picture header reading routine
 *******************************************************************/
#include <stdlib.h>

#include "scan.h"

#define PICTURE_HEADER_C
#include "picture_header.h"

int read_picture_header(MPEG_IO *in, PICTURE_HEADER *out, READ_PICTURE_HEADER_OPTION *opt);
int picture_header_to_read_macroblock_option(PICTURE_HEADER *in, READ_MACROBLOCK_OPTION *out);
int picture_header_to_read_block_option(PICTURE_HEADER *in, READ_BLOCK_OPTION *out);
int picture_header_to_mc_parameter(PICTURE_HEADER *in, MC_PARAMETER *out);

static int read_picture_coding_extension(MPEG_IO *in, PICTURE_CODING_EXTENSION *out);
static int read_quant_matrix_extension(MPEG_IO *in, QUANT_MATRIX_EXTENSION *out);
static int read_picture_display_extension(MPEG_IO *in, PICTURE_DISPLAY_EXTENSION *out, int progressive_sequence, int picture_structure, int repeat_first_field);
static int read_picture_spatial_scalable_extension(MPEG_IO *in, PICTURE_SPATIAL_SCALABLE_EXTENSION *out);
static int read_temporal_scalable_extension(MPEG_IO *in, PICTURE_TEMPORAL_SCALABLE_EXTENSION *out);


int read_picture_header(MPEG_IO *in, PICTURE_HEADER *out, READ_PICTURE_HEADER_OPTION *opt)
{
	int code;
	
	out->temporal_reference = get_bits(in, 10);
	out->picture_coding_type = get_bits(in, 3);
	out->vbv_delay = get_bits(in, 16);
	if(out->picture_coding_type == 2 || out->picture_coding_type == 3){
		out->full_pel_forward_vector = get_bits(in, 1);
		out->forward_f_code = get_bits(in, 3);
	}
	if(out->picture_coding_type == 3){
		out->full_pel_backward_vector = get_bits(in, 1);
		out->backward_f_code = get_bits(in, 3);
	}

	while((code = get_bits(in, 1)) == 1){
		get_bits(in, 8);  /* read skip EBP & EIP */
	}

	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 8:
			out->has_picture_coding_extension = 1;
			read_picture_coding_extension(in, &(out->pc));
			break;
		case 3:
			out->has_quant_matrix_extension = 1;
			read_quant_matrix_extension(in, &(out->qm));
			break;
		case 7:
			out->has_picture_display_extension = 1;
			read_picture_display_extension(in, &(out->pd), opt->progressive_sequence, out->pc.picture_structure, out->pc.repeat_first_field);
			break;
		case 9:
			out->has_picture_spatial_scalable_extension = 1;
			read_picture_spatial_scalable_extension(in, &(out->pss));
			break;
		case 10:
			out->has_temporal_scalable_extension = 1;
			read_temporal_scalable_extension(in, &(out->pts));
			break;
		default:
			break;
		}
	}

	return 1;
}

int picture_header_to_read_macroblock_option(PICTURE_HEADER *in, READ_MACROBLOCK_OPTION *out)
{
	int i,j;
	
	out->picture_coding_type = in->picture_coding_type;

	if(in->has_picture_coding_extension){
		out->picture_structure = in->pc.picture_structure;
		out->top_field_first = in->pc.top_field_first;
		out->frame_predictive_frame_dct = in->pc.frame_predictive_frame_dct;
		out->concealment_motion_vectors = in->pc.concealment_motion_vectors;
		
		for(i=0;i<2;i++){
			for(j=0;j<2;j++){
				out->f_code[i][j] = in->pc.f_code[i][j];
			}
		}
	}else{
		out->picture_structure = 0;
		out->top_field_first = 0;
		out->frame_predictive_frame_dct = 0;
		out->concealment_motion_vectors = 0;

		out->f_code[0][0] = in->forward_f_code;
		out->f_code[0][1] = in->forward_f_code;
		out->f_code[1][0] = in->backward_f_code;
		out->f_code[1][1] = in->backward_f_code;
	}

	if(in->has_picture_spatial_scalable_extension){
		out->spatial_temporal_weight_code_table_index = in->pss.spatial_temporal_weight_code_table_index;
	}else{
		out->spatial_temporal_weight_code_table_index = 0;
	}

	return 1;
}

int picture_header_to_read_block_option(PICTURE_HEADER *in, READ_BLOCK_OPTION *out)
{
	int i, j;
	
	if(in->has_picture_coding_extension){
		out->picture_structure = in->pc.picture_structure;
		out->intra_dc_precision = in->pc.intra_dc_precision;
		out->intra_vlc_format = in->pc.intra_vlc_format;
		out->alternate_scan = in->pc.alternate_scan;
		out->q_scale_type = in->pc.q_scale_type;
	}else{
		out->picture_structure = 3;
		out->intra_dc_precision = 0;
		out->intra_vlc_format = 0;
		out->alternate_scan = 0;
		out->q_scale_type = 0;
	}

	if(in->has_quant_matrix_extension){
		for(i=0;i<4;i++){
			if(in->qm.load_quantizer_matrix[i]){
				for(j=0;j<64;j++){
					out->quantizer_weight[j][scan_table[0][j]] = in->qm.quantizer_matrix[i][j];
				}
			}else if(i>1){
				memcpy(out->quantizer_weight[i], out->quantizer_weight[i-2], 64);
			}
		}
	}

	return 1;
}

static int read_picture_coding_extension(MPEG_IO *in, PICTURE_CODING_EXTENSION *out)
{
	out->f_code[0][0] = get_bits(in, 4);
	out->f_code[0][1] = get_bits(in, 4); 
	out->f_code[1][0] = get_bits(in, 4);
	out->f_code[1][1] = get_bits(in, 4);
	out->intra_dc_precision = get_bits(in, 2);
	out->picture_structure = get_bits(in, 2);
	out->top_field_first = get_bits(in, 1);
	out->frame_predictive_frame_dct = get_bits(in, 1);
	out->concealment_motion_vectors = get_bits(in, 1);
	out->q_scale_type = get_bits(in, 1);
	out->intra_vlc_format = get_bits(in, 1);
	out->alternate_scan = get_bits(in, 1);
	out->repeat_first_field = get_bits(in, 1);
	out->chroma_420_type = get_bits(in, 1);
	out->progressive_frame = get_bits(in, 1);
	out->composit_display_flag = get_bits(in, 1);
	if(out->composit_display_flag){
		out->v_axis = get_bits(in, 1);
		out->field_sequence = get_bits(in, 3);
		out->sub_carrier = get_bits(in, 1);
		out->burst_amplitude = get_bits(in, 7);
		out->sub_carrier_phase = get_bits(in, 8);
	}

	return 1;
}

int picture_header_to_mc_parameter(PICTURE_HEADER *in, MC_PARAMETER *out)
{
	out->picture_coding_type = in->picture_coding_type;
	
	if(in->has_picture_coding_extension){
		if(in->pc.picture_structure != 3){
			out->second_field = !out->second_field;
		}

		out->picture_structure = in->pc.picture_structure;
		out->top_field_first = in->pc.top_field_first;
	}else{
		out->second_field = 0;
		out->picture_structure = 3;
		out->top_field_first = 0;
	}

	return 1;
}

static int read_quant_matrix_extension(MPEG_IO *in, QUANT_MATRIX_EXTENSION *out)
{
	int i,j;

	for(i=0;i<4;i++){
		out->load_quantizer_matrix[i] = get_bits(in, 1);
		if(out->load_quantizer_matrix[i]){
			for(j=0;j<64;j++){
				out->quantizer_matrix[i][j] = get_bits(in,8);
			}
		}
	}

	return 1;
}

static int read_picture_display_extension(MPEG_IO *in, PICTURE_DISPLAY_EXTENSION *out, int progressive_sequence, int picture_structure, int repeat_first_field)
{
	int i;
	if(progressive_sequence || picture_structure == 1 || picture_structure == 2){
		out->number_of_frame_center_offset = 1;
	}else{
		if(repeat_first_field){
			out->number_of_frame_center_offset = 3;
		}else{
			out->number_of_frame_center_offset = 2;
		}
	}
	
	for(i=0;i<out->number_of_frame_center_offset;i++){
		out->frame_center_horizontal_offset[i] = get_bits(in, 16);
		get_bits(in, 1);
		out->frame_center_vertical_offset[i] = get_bits(in, 16);
		get_bits(in, 1);
	}
	return 1;
}

static int read_picture_spatial_scalable_extension(MPEG_IO *in, PICTURE_SPATIAL_SCALABLE_EXTENSION *out)
{
	out->low_layer_temporal_reference = get_bits(in, 10);
	out->lower_layer_horizontal_offset = get_bits(in, 15);
	out->lower_layer_vertical_offset = get_bits(in, 15);
	out->spatial_temporal_weight_code_table_index = get_bits(in, 2);
	out->lower_layer_progressive_frame = get_bits(in, 1);
	out->lower_layer_deinterlaced_field_select = get_bits(in, 1);

	return 1;
}

static int read_temporal_scalable_extension(MPEG_IO *in, PICTURE_TEMPORAL_SCALABLE_EXTENSION *out)
{
	out->reference_select_code = get_bits(in, 2);
	out->forward_temporal_reference = get_bits(in, 10);
	out->backward_temporal_reference = get_bits(in, 10);

	return 1;
}

