/*******************************************************************
                     macroblock layer interface
 *******************************************************************/

#define MACROBLOCK_C
#include "macroblock.h"

typedef struct {
	int value;
	int length;
} BASIC_VLC_ELEMENT;

int get_macroblock_address_increment(MPEG_IO *in);
int read_macroblock(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt);
int macroblock_to_read_block_option(MACROBLOCK *in, READ_BLOCK_OPTION *opt);
int macroblock_to_mc_parameter(MACROBLOCK *in, MC_PARAMETER *out);	
int reset_motion_vector_predictor(MACROBLOCK *p);

static void read_macroblock_mode(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt);
static void read_macroblock_type_snr_scalability(MPEG_IO *in, MACROBLOCK *out);
static void read_macroblock_type_b_spatial_scalability(MPEG_IO *in, MACROBLOCK *out);
static void read_macroblock_type_p_spatial_scalability(MPEG_IO *in, MACROBLOCK *out);
static void read_macroblock_type_i_spatial_scalability(MPEG_IO *in, MACROBLOCK *out);
static void read_macroblock_type_b(MPEG_IO *in, MACROBLOCK *out);
static void read_macroblock_type_p(MPEG_IO *in, MACROBLOCK *out);
static void read_macroblock_type_i(MPEG_IO *in, MACROBLOCK *out);
static void read_macroblock_type_d(MPEG_IO *in, MACROBLOCK *out);
static int get_motion_code(MPEG_IO *in);
static int get_dmvector(MPEG_IO *in);
static void read_dual_prime_motion_vector(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt);
static void read_motion_vector(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt, int s);
static void read_dmv(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt, int s, int t);
static int get_motion_vector_predictor(MPEG_IO *in, int predictor, int f_code, int half);
static void read_coded_block(MPEG_IO *in, MACROBLOCK *out, int chroma_format);
static int get_coded_block_pattern(MPEG_IO *in);

int read_macroblock(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt)
{
	read_macroblock_mode(in, out, opt);

	if(out->macroblock_quant){
		out->quantizer_scale_code = get_bits(in, 5);
	}

	if(out->macroblock_motion_forward || (out->macroblock_intra && opt->concealment_motion_vectors)){
		read_motion_vector(in, out, opt, 0);
	}

	if(out->macroblock_motion_backward){
		read_motion_vector(in, out, opt, 1);
	}

	if( (out->macroblock_intra && ! opt->concealment_motion_vectors) || ( (opt->picture_coding_type == 2) && ! out->macroblock_motion_forward) ){
		reset_motion_vector_predictor(out);
	}

	if(out->macroblock_intra && opt->concealment_motion_vectors){
		get_bits(in, 1); /* marker bit */
	}

	read_coded_block(in, out, opt->chroma_format);

	return 1;
}

int macroblock_to_read_block_option(MACROBLOCK *in, READ_BLOCK_OPTION *out)
{
	out->macroblock_intra = in->macroblock_intra;
	out->dct_type = in->dct_type;

	if(in->macroblock_quant){
		out->quantizer_scale_code = in->quantizer_scale_code;
	}

	if(! in->macroblock_intra){
		reset_dc_dct_predictor(out);
	}
	
	return 1;
}

int get_macroblock_address_increment(MPEG_IO *in)
{
	int r;
	int code;

	static const BASIC_VLC_ELEMENT table_a[] = {
		{ 5, 4}, { 4, 4},
		{ 3, 3}, { 3, 3}, { 2, 3}, { 2, 3},
		{ 1, 1}, { 1, 1}, { 1, 1}, { 1, 1},
		{ 1, 1}, { 1, 1}, { 1, 1}, { 1, 1}, 
	};
	
	static const BASIC_VLC_ELEMENT table_b[] = {
		{15, 8}, {14, 8}, {13, 8}, {12, 8}, {11, 8}, {10, 8},
		{ 9, 7}, { 9, 7}, { 8, 7}, { 8, 7},
		{ 7, 5}, { 7, 5}, { 7, 5}, { 7, 5},
		{ 7, 5}, { 7, 5}, { 7, 5}, { 7, 5},
		{ 6, 5}, { 6, 5}, { 6, 5}, { 6, 5},
		{ 6, 5}, { 6, 5}, { 6, 5}, { 6, 5},
	};

	static const BASIC_VLC_ELEMENT table_c[] = {
		{33,11}, {32,11}, {31,11}, {30,11},
		{29,11}, {28,11}, {27,11}, {26,11},
		{25,11}, {24,11}, {23,11}, {22,11},
		{21,10}, {21,10}, {20,10}, {20,10},
		{19,10}, {19,10}, {18,10}, {18,10},
		{17,10}, {17,10}, {16,10}, {16,10},
	};

	r = 0;
	
	while((code = read_bits(in, 11)) > 0){
		if(code == 8){
			r += 33;
			erase_bits(in, 11);
		}else{
			break;
		}
	}

	if(code > 255){
		code = (code >> 7) - 2;
		r += table_a[code].value;
		erase_bits(in, table_a[code].length);
	}else if(code > 47){
		code = (code >> 3) - 6;
		r += table_b[code].value;
		erase_bits(in, table_b[code].length);
	}else if(code > 23){
		code = code - 24;
		r += table_c[code].value;
		erase_bits(in, table_c[code].length);
	}

	return r;
}

int macroblock_to_mc_parameter(MACROBLOCK *in, MC_PARAMETER *out)
{
	int r,s,t;

	out->macroblock_motion_forward = in->macroblock_motion_forward;
	out->macroblock_motion_backward = in->macroblock_motion_backward;

	out->prediction_type = in->prediction_type;

	for(r=0;r<2;r++){
		for(s=0;s<2;s++){
			for(t=0;t<2;t++){
				out->PMV[r][s][t] = in->PMV[r][s][t];
			}
			out->DMV[r][s] = in->DMV[r][s];
			out->motion_vertical_field_select[r][s] = in->motion_vertical_field_select[r][s];
		}
	}

	return 1;
}

int reset_motion_vector_predictor(MACROBLOCK *p)
{
	int r,s,t;

	for(r=0;r<2;r++){
		for(s=0;s<2;s++){
			for(t=0;t<2;t++){
				p->PMV[r][s][t] = 0;
			}
		}
	}

	return 1;
}

static void read_macroblock_mode(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt)
{
	int code;

	if(opt->scalable_mode == 2){
		read_macroblock_type_snr_scalability(in, out);
	}else if(opt->scalable_mode == 1 && opt->picture_coding_type == 3){
		read_macroblock_type_b_spatial_scalability(in, out);
	}else if(opt->scalable_mode == 1 && opt->picture_coding_type == 2){
		read_macroblock_type_p_spatial_scalability(in, out);
	}else if(opt->scalable_mode == 1 && opt->picture_coding_type == 1){
		read_macroblock_type_i_spatial_scalability(in, out);
	}else if(opt->picture_coding_type == 3){
		read_macroblock_type_b(in, out);
	}else if(opt->picture_coding_type == 2){
		read_macroblock_type_p(in, out);
	}else if(opt->picture_coding_type == 1){
		read_macroblock_type_i(in, out);
	}else if(opt->picture_coding_type == 4){
		read_macroblock_type_d(in, out);
	}

	if(out->spatial_temporal_weight_code_flag){
		if(opt->spatial_temporal_weight_code_table_index){
			out->spatial_temporal_weight_code = get_bits(in, 2);
		}
	}

	if(out->macroblock_motion_forward || out->macroblock_motion_backward){
		if(opt->picture_structure == 3){
			if(! opt->frame_predictive_frame_dct){
				code = get_bits(in, 2);
				switch(code){
				case 0:
					break;
				case 1:
					out->prediction_type = PREDICTION_TYPE_FIELD_BASED;
					if(out->spatial_temporal_weight_code > 1){
						out->motion_vector_count = 2;
					}else{
						out->motion_vector_count = 1;
					}
					out->motion_vector_format = MOTION_VECTOR_FORMAT_FIELD;
					out->dual_prime_motion_vector = 0;
					break;
				case 2:
					out->prediction_type = PREDICTION_TYPE_FRAME_BASED;
					out->motion_vector_count = 1;
					out->motion_vector_format = MOTION_VECTOR_FORMAT_FRAME;
					out->dual_prime_motion_vector = 0;
					break;
				case 3:
					out->prediction_type = PREDICTION_TYPE_DUAL_PRIME;
					out->motion_vector_count = 1;
					out->motion_vector_format = MOTION_VECTOR_FORMAT_FIELD;
					out->dual_prime_motion_vector = 1;
					break;
				default:
					break;
				}
			}else{
				out->prediction_type = PREDICTION_TYPE_FRAME_BASED;
				out->motion_vector_count = 1;
				out->motion_vector_format = MOTION_VECTOR_FORMAT_FRAME;
				out->dual_prime_motion_vector = 0;
			}
		}else{
			code = get_bits(in, 2);
			switch(code){
			case 0:
				break;
			case 1:
				out->prediction_type = PREDICTION_TYPE_FIELD_BASED;
				out->motion_vector_count = 1;
				out->motion_vector_format = MOTION_VECTOR_FORMAT_FIELD;
				out->dual_prime_motion_vector = 0;
				break;
			case 2:
				out->prediction_type = PREDICTION_TYPE_16x8_MC;
				out->motion_vector_count = 2;
				out->motion_vector_format = MOTION_VECTOR_FORMAT_FIELD;
				out->dual_prime_motion_vector = 0;
				break;
			case 3:
				out->prediction_type = PREDICTION_TYPE_DUAL_PRIME;
				out->motion_vector_count = 1;
				out->motion_vector_format = MOTION_VECTOR_FORMAT_FIELD;
				out->dual_prime_motion_vector = 1;
				break;
			default:
				break;
			}
		}
	}

	if(opt->frame_predictive_frame_dct){
		out->dct_type = 0;
	}else if( (opt->picture_structure == 1 || opt->picture_structure == 2) && (out->macroblock_intra || out->macroblock_pattern) ){
		out->dct_type = get_bits(in, 1);
	}
}

static void read_macroblock_type_snr_scalability(MPEG_IO *in, MACROBLOCK *out)
{
	int code;
	
	code = read_bits(in, 3);
	if(code > 3){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 1);
	}else if(code > 1){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}else{
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 3);
	}
}

static void read_macroblock_type_b_spatial_scalability(MPEG_IO *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 9);
	
	if(code > 383){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}else if(code > 255){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}else if(code > 191){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 3);
	}else if(code > 127){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 3);
	}else if(code > 95){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 4);
	}else if(code > 63){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 4);
	}else if(code > 55){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 6);
	}else if(code > 47){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 6);
	}else if(code > 39){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 6);
	}else if(code > 31){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 6);
	}else if(code > 27){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code > 23){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code > 19){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code > 15){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code > 19){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code == 15){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 9);
	}else if(code == 14){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 9);
	}else if(code == 13){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 9);
	}else if(code == 12){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 9);
	}else if(code > 9){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 8);
	}else if(code > 7){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 8);
	}
}

static void read_macroblock_type_p_spatial_scalability(MPEG_IO *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 7);

	if(code > 95){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 2);
	}else if(code > 63){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}else if(code > 47){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 3);
	}else if(code > 31){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 3);
	}else if(code > 23){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 4);
	}else if(code > 15){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 4);
	}else if(code > 13){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 6);
	}else if(code > 11){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 6);
	}else if(code > 9){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 1;
		erase_bits(in, 6);
	}else if(code > 7){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 6);
	}else if(code == 7){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code == 6){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code == 5){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 7);
	}else if(code == 4){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 7);
	}else if(code == 3){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 7);
	}else if(code == 2){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 7);
	}		
}

static void read_macroblock_type_i_spatial_scalability(MPEG_IO *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 4);

	if(code > 7){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 1);
	}else if(code > 3){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 2);
	}else if(code == 3){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 4);
	}else if(code == 2){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 4);
	}else if(code == 1){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		out->spatial_temporal_weight_classes = 4;
		erase_bits(in, 4);
	}
}

static void read_macroblock_type_b(MPEG_IO *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 6);
	if(code > 47){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}else if(code > 31){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}else if(code > 23){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 3);
	}else if(code > 15){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 3);
	}else if(code > 11){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 4);
	}else if(code > 7){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 4);
	}else if(code > 5){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 5);
	}else if(code > 3){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 5);
	}else if(code == 3){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 6);
	}else if(code == 2){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 1;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 6);
	}else if(code == 1){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 6);
	}
}

static void read_macroblock_type_p(MPEG_IO *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 6);

	if(code > 31){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 1);
	}else if(code > 15){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}else if(code > 7){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 3);
	}else if(code > 5){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 5);
	}else if(code > 3){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 1;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 5);
	}else if(code > 1){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 1;
		out->macroblock_intra = 0;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 5);
	}else if(code == 1){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 6);
	}
}

static void read_macroblock_type_i(MPEG_IO *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 2);

	if(code > 1){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 1);
	}else if(code == 1){
		out->macroblock_quant = 1;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}
}

static void read_macroblock_type_d(MPEG_IO *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 2);

	if(code == 3){
		out->macroblock_quant = 0;
		out->macroblock_motion_forward = 0;
		out->macroblock_motion_backward = 0;
		out->macroblock_pattern = 0;
		out->macroblock_intra = 1;
		out->spatial_temporal_weight_code_flag = 0;
		erase_bits(in, 2);
	}
}

static int get_motion_code(MPEG_IO *in)
{
	int r;
	int code;
	
	static const BASIC_VLC_ELEMENT table_a[] = {
		{ 2, 4}, {-2, 4},
		{ 1, 3}, { 1, 3}, {-1,3}, {-1, 3},
		{ 0, 1}, { 0, 1}, { 0,1}, { 0, 1},
		{ 0, 1}, { 0, 1}, { 0,1}, { 0, 1},
	};
	
	static const BASIC_VLC_ELEMENT table_b[] = {
		{ 7, 8}, {-7, 8}, { 6, 8}, {-6, 8}, { 5, 8}, {-5, 8},
		{ 4, 7}, { 4, 7}, {-4, 7}, {-4, 7},
		{ 3, 5}, { 3, 5}, { 3, 5}, { 3, 5},
		{ 3, 5}, { 3, 5}, { 3, 5}, { 3, 5},
		{-3, 5}, {-3, 5}, {-3, 5}, {-3, 5},
		{-3, 5}, {-3, 5}, {-3, 5}, {-3, 5},
	};
	
	static const BASIC_VLC_ELEMENT table_c[] = {
		{16,11}, {-16,11}, {15,11}, {-15,11},
		{14,11}, {-14,11}, {13,11}, {-13,11},
		{12,11}, {-12,11}, {11,11}, {-11,11},
		{10,10}, {10,10}, {-10,10}, {-10,10},
		{ 9,10}, { 9,10}, { -9,10}, { -9,10},
		{ 8,10}, { 8,10}, { -8,10}, { -8,10},
	};

	code = read_bits(in, 11);

	if(code > 511){
		code = (code >> 7) - 2;
		r = table_a[code].value;
		erase_bits(in, table_a[code].length);
	}else if(code > 95){
		code = (code >> 3) - 6;
		r = table_b[code].value;
		erase_bits(in, table_b[code].length);
	}else{
		code -= 24;
		r = table_c[code].value;
		erase_bits(in, table_c[code].length);
	}

	return r;
}

static int get_dmvector(MPEG_IO *in)
{
	int code;
	
	static const BASIC_VLC_ELEMENT table[] = {
		{ 0, 1}, { 0, 1}, { 1, 2}, {-1, 2}
	};

	code = read_bits(in, 2);

	erase_bits(in, table[code].length);

	return table[code].value;
}

static void read_motion_vector(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt, int s)
{
	int r,t;
	int half;

	if( (out->motion_vector_format == MOTION_VECTOR_FORMAT_FIELD) && (opt->picture_structure == 3) ){
		half = 1;
	}else{
		half = 0;
	}
	
	if(out->motion_vector_count == 1){
		if( (out->motion_vector_format == MOTION_VECTOR_FORMAT_FIELD) && (out->dual_prime_motion_vector != 1) ){
			out->motion_vertical_field_select[0][s] = get_bits(in, 1);
		}
		for(t=0;t<2;t++){
			out->PMV[0][s][t] = get_motion_vector_predictor(in, out->PMV[0][s][t], opt->f_code[s][t], (half && t));
			if(out->dual_prime_motion_vector == 1){
				read_dmv(in, out, opt, s, t);
			}
			out->PMV[1][s][t] = out->PMV[0][s][t];
		}
	}else{
		for(r=0;r<2;r++){
			out->motion_vertical_field_select[r][s] = get_bits(in, 1);
			for(t=0;t<2;t++){
				out->PMV[r][s][t] = get_motion_vector_predictor(in, out->PMV[r][s][t], opt->f_code[s][t], (half && t));
			}
		}
	}
}

static void read_dmv(MPEG_IO *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt, int s, int t)
{
	int v;
	int dmvector;

	dmvector = get_dmvector(in);
	
	if(opt->picture_structure == 3){
		v = out->PMV[0][s][t] >> 1;
		if(opt->top_field_first){
			out->DMV[0][t] = ( ( v   + (v>0) )>>1 ) + dmvector - t;
			out->DMV[1][t] = ( ( v*3 + (v>0) )>>1 ) + dmvector + t;
		}else{
			out->DMV[0][t] = ( ( v*3 + (v>0) )>>1 ) + dmvector - t;
			out->DMV[1][t] = ( ( v   + (v>0) )>>1 ) + dmvector + t;
		}
	}else{
		v = out->PMV[0][s][t];
		out->DMV[0][t] = ( ( v + (v>0) )>>1) + dmvector;
		if(opt->picture_structure == 1){
			out->DMV[0][t] -= t;
		}else{
			out->DMV[0][t] += t;
		}
	}
}

static int get_motion_vector_predictor(MPEG_IO *in, int prediction, int f_code, int half)
{
	int r;
	
	int f;
	int r_size;
	int high;
	int low;
	int range;

	int delta;
	
	int motion_code;
	int motion_residual;

	r_size = f_code - 1;
	f = 1 << r_size;

	high = 16 * f - 1;
	low = -16 * f;
	range = 32 * f;

	motion_code = get_motion_code(in);
	if( (f == 1) || (motion_code == 0) ){
		delta = motion_code;
	}else{
		motion_residual = get_bits(in, f);
		delta = (abs(motion_code) - 1) * f + motion_residual + 1;
		if(motion_code < 0){
			delta = 0 - delta;
		}
	}

	if(half){
		prediction /= 2;
	}

	r = prediction + delta;

	if(r < low){
		r += range;
	}else if(r > high){
		r -= range;
	}

	if(half){
		r *= 2;
	}

	return r;
}

static void read_coded_block(MPEG_IO *in, MACROBLOCK *out, int chroma_format)
{
	int i;
	int coded_block_pattern;

	switch(chroma_format){
	case 0:
		break;
	case 1:
		out->block_count = 6;
		break;
	case 2:
		out->block_count = 8;
		break;
	case 3:
		out->block_count = 12;
		break;
	default:
		break;
	}
	
	if(out->macroblock_pattern){
		coded_block_pattern = get_coded_block_pattern(in);
		if(chroma_format == 2){
			coded_block_pattern <<= 2;
			coded_block_pattern += get_bits(in, 2);
		}else if(chroma_format == 3){
			coded_block_pattern <<= 6;
			coded_block_pattern += get_bits(in, 6);
		}
	}else{
        coded_block_pattern = 0;
    }
	
	if(out->macroblock_intra){
		for(i=0;i<out->block_count;i++){
			out->pattern_code[i] = 1;
		}
	}else{
		for(i=0;i<out->block_count;i++){
			out->pattern_code[i] = (coded_block_pattern >> (out->block_count - 1 - i)) & 1;
		}
	}
}

static int get_coded_block_pattern(MPEG_IO *in)
{
	int r;
	int code;
	
	static const BASIC_VLC_ELEMENT table_a[] = {
		{63,6},{ 3,6},{36,6},{24,6},{62,5},{62,5},{ 2,5},{ 2,5},
		{61,5},{61,5},{ 1,5},{ 1,5},{56,5},{56,5},{52,5},{52,5},
		{44,5},{44,5},{28,5},{28,5},{40,5},{40,5},{20,5},{20,5},
		{48,5},{48,5},{12,5},{12,5},{32,4},{32,4},{32,4},{32,4},
		{16,4},{16,4},{16,4},{16,4},{ 8,4},{ 8,4},{ 8,4},{ 8,4},
		{ 4,4},{ 4,4},{ 4,4},{ 4,4},{60,3},{60,3},{60,3},{60,3},
		{60,3},{60,3},{60,3},{60,3},
	};
	
	static const BASIC_VLC_ELEMENT table_b[] = {
		{ 0,0},{ 0,9},{39,9},{27,9},{59,9},{55,9},{47,9},{31,9},
		{58,8},{58,8},{54,8},{54,8},{46,8},{46,8},{30,8},{30,8},
		{57,8},{57,8},{53,8},{53,8},{45,8},{45,8},{29,8},{29,8},
		{38,8},{38,8},{26,8},{26,8},{37,8},{37,8},{25,8},{25,8},
		{48,8},{43,8},{23,8},{23,8},{51,8},{51,8},{15,8},{15,8},
		{42,8},{42,8},{22,8},{22,8},{50,8},{50,8},{14,8},{14,8},
		{41,8},{41,8},{21,8},{21,8},{49,8},{49,8},{13,8},{13,8},
		{35,8},{35,8},{19,8},{19,8},{11,8},{11,8},{ 7,8},{ 7,8},
		{34,7},{34,7},{34,7},{34,7},{18,7},{18,7},{18,7},{18,7},
		{10,7},{10,7},{10,7},{10,7},{ 6,7},{ 6,7},{ 6,7},{ 6,7},
		{33,7},{33,7},{33,7},{33,7},{17,7},{17,7},{17,7},{17,7},
		{ 9,7},{ 9,7},{ 9,7},{ 9,7},{ 5,7},{ 5,7},{ 5,7},{ 5,7},
	};

	code = read_bits(in, 9);

	if(code > 95){
		code = (code >> 3) - 24;
		r = table_a[code].value;
		erase_bits(in, table_a[code].length);
	}else{
		r = table_b[code].value;
		erase_bits(in, table_b[code].length);
	}

	return r;
}