/*******************************************************************
                     macroblock layer interface
 *******************************************************************/

#define MACROBLOCK_C
#include "macroblock.h"

typedef struct {
	int value;
	int length;
} BASIC_VLC_ELEMENT;

int get_macroblock_address_increment(VIDEO_STREAM *in);
int read_macroblock(VIDEO_STREAM *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(VIDEO_STREAM *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt);
static void read_macroblock_type_snr_scalability(VIDEO_STREAM *in, MACROBLOCK *out);
static void read_macroblock_type_b_spatial_scalability(VIDEO_STREAM *in, MACROBLOCK *out);
static void read_macroblock_type_p_spatial_scalability(VIDEO_STREAM *in, MACROBLOCK *out);
static void read_macroblock_type_i_spatial_scalability(VIDEO_STREAM *in, MACROBLOCK *out);
static void read_macroblock_type_b(VIDEO_STREAM *in, MACROBLOCK *out);
static void read_macroblock_type_p(VIDEO_STREAM *in, MACROBLOCK *out);
static void read_macroblock_type_i(VIDEO_STREAM *in, MACROBLOCK *out);
static void read_macroblock_type_d(VIDEO_STREAM *in, MACROBLOCK *out);
static int get_motion_code(VIDEO_STREAM *in);
static int get_dmvector(VIDEO_STREAM *in);
static void read_dual_prime_motion_vector(VIDEO_STREAM *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt);
static void read_motion_vector(VIDEO_STREAM *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt, int s);
static void read_dmv(VIDEO_STREAM *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt, int s, int t);
static int get_motion_vector_predictor(VIDEO_STREAM *in, int predictor, int f_code, int half);
static void read_coded_block(VIDEO_STREAM *in, MACROBLOCK *out, int chroma_format);
static int get_coded_block_pattern(VIDEO_STREAM *in);
static void read_spatial_temporal_weight(VIDEO_STREAM *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt);

int read_macroblock(VIDEO_STREAM *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(VIDEO_STREAM *in)
{
	int r;
	int code;

    static const BASIC_VLC_ELEMENT table_a[] = {
    	{9,7},{8,7},
	    {7,5},{7,5},{7,5},{7,5},{6,5},{6,5},{6,5},{6,5},
    	{5,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4},{5,4},
	    {4,4},{4,4},{4,4},{4,4},{4,4},{4,4},{4,4},{4,4},
    	{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},
	    {3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},{3,3},
       	{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},
    	{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},{2,3},
	    {1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
    	{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
	    {1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
    	{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
	    {1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
    	{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
	    {1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
    	{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},{1,1},
    };

    static const BASIC_VLC_ELEMENT table_b[] = {
    	{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},
   	    {15,8},{15,8},{15,8},{15,8},{15,8},{15,8},{15,8},{15,8},
    	{14,8},{14,8},{14,8},{14,8},{14,8},{14,8},{14,8},{14,8},
    	{13,8},{13,8},{13,8},{13,8},{13,8},{13,8},{13,8},{13,8},
    	{12,8},{12,8},{12,8},{12,8},{12,8},{12,8},{12,8},{12,8},
	    {11,8},{11,8},{11,8},{11,8},{11,8},{11,8},{11,8},{11,8},
    	{10,8},{10,8},{10,8},{10,8},{10,8},{10,8},{10,8},{10,8},
    };

	r = 0;

    code = read_bits(in, 11);

	while( (code = read_bits(in, 11)) == 8 ){
        r += 33;
        erase_bits(in, 11);
	}

	if(code > 95){
		code = (code >> 4) - 6;
		r += table_a[code].value;
		erase_bits(in, table_a[code].length);
	}else if(code > 23){
		code -= 24;
		r += table_b[code].value;
		erase_bits(in, table_b[code].length);
	}else{
        r = 0;
    }

	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(VIDEO_STREAM *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){
		read_spatial_temporal_weight(in, out, opt);
	}

	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_class == 0) || (out->spatial_temporal_weight_class == 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;
			}
		}
	}else if(out->macroblock_intra && opt->concealment_motion_vectors){
		if(opt->picture_structure == 3){
			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{
			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;
		}
	}

	if(opt->frame_predictive_frame_dct){
		out->dct_type = 0;
	}else if( opt->picture_structure == 3 && (out->macroblock_intra || out->macroblock_pattern) ){
		out->dct_type = get_bits(in, 1);
	}
}

static void read_macroblock_type_snr_scalability(VIDEO_STREAM *in, MACROBLOCK *out)
{
	int code;
	
	code = read_bits(in, 3);
	if( (code >> 2) == 1 ){
		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_class = 0;
		erase_bits(in, 1);
	}else if( (code >> 1) == 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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}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_class = 0;
		erase_bits(in, 3);
	}
}

static void read_macroblock_type_b_spatial_scalability(VIDEO_STREAM *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 9);
	
	if( (code >> 7) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}else if( (code >> 7) == 3 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}else if( (code >> 6) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 3);
	}else if( (code >> 6) == 3 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 3);
	}else if( (code >> 5) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 4);
	}else if( (code >> 5) == 3 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 4);
	}else if( (code >> 3) == 6 ){
		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 >> 3) == 7 ){
		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 >> 3) == 4 ){
		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, 6);
	}else if( (code >> 3) == 5 ){
		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 >> 2) == 6 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 7);
	}else if( (code >> 2) == 7 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 7);
	}else if( (code >> 2) == 4 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 7);
	}else if( (code >> 2) == 5 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 7);
	}else if( (code >> 1) == 4 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 8);
	}else if( (code >> 1) == 5 ){
		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 == 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 == 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_class = 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_class = 4;
		erase_bits(in, 9);
	}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_class = 4;
		erase_bits(in, 9);
	}
}

static void read_macroblock_type_p_spatial_scalability(VIDEO_STREAM *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 7);

	if( (code >> 5) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}else if( (code >> 4) == 3 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 3);
	}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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 7);
	}else if( (code >> 1) == 7 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 6);
	}else if( (code >> 3) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 4);
	}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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 7);
	}else if( (code >> 3) == 3 ){
		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 >> 4) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 3);
	}else if( (code >> 1) == 4 ){
		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_class = 0;
		erase_bits(in, 6);
	}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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 7);
	}else if( (code >> 5) == 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 = 1;
		erase_bits(in, 2);
	}else if( (code >> 1) == 5 ){
		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 >> 1) == 6){
		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 == 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_class = 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_class = 4;
		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_class = 4;
		erase_bits(in, 7);
	}		
}

static void read_macroblock_type_i_spatial_scalability(VIDEO_STREAM *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 4);

	if( (code >> 3) == 1){
		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_class = 4;
		erase_bits(in, 1);
	}else if( (code >> 2) == 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;
		out->spatial_temporal_weight_class = 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;
		out->spatial_temporal_weight_class = 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;
		out->spatial_temporal_weight_class = 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_class = 4;
		erase_bits(in, 4);
	}
}

static void read_macroblock_type_b(VIDEO_STREAM *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 6);
	if( (code >> 4) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}else if( (code >> 4) == 3 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}else if( (code >> 3) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 3);
	}else if( (code >> 3) == 3 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 3);
	}else if( (code >> 2) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 4);
	}else if( (code >> 2) == 3 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 4);
	}else if( (code >> 1) == 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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 5);
	}else if( (code >> 1) == 2 ){
		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;
		out->spatial_temporal_weight_class = 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;
		out->spatial_temporal_weight_class = 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;
		out->spatial_temporal_weight_class = 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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 6);
	}
}

static void read_macroblock_type_p(VIDEO_STREAM *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 6);

	if( (code >> 5) == 1 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 1);
	}else if( (code >> 4) == 1 ){
		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_class = 0;
		erase_bits(in, 2);
	}else if( (code >> 3) == 1 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 3);
	}else if( (code >> 1) == 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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 5);
	}else if( (code >> 1) == 2 ){
		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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 5);
	}else if( (code >> 1) == 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;
		out->spatial_temporal_weight_class = 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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 6);
	}
}

static void read_macroblock_type_i(VIDEO_STREAM *in, MACROBLOCK *out)
{
	int code;

	code = read_bits(in, 2);

	if( (code >> 1) == 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;
		out->spatial_temporal_weight_class = 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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}
}

static void read_macroblock_type_d(VIDEO_STREAM *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;
		out->spatial_temporal_weight_class = 0;
		erase_bits(in, 2);
	}
}

static int get_motion_code(VIDEO_STREAM *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 > 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{
		code -= 24;
		r = table_c[code].value;
		erase_bits(in, table_c[code].length);
	}

	return r;
}

static int get_dmvector(VIDEO_STREAM *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(VIDEO_STREAM *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 = 2;
	}else if( opt->full_pel_vector[s] ){
		half = 3;
	}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+1)) );
			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(VIDEO_STREAM *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(VIDEO_STREAM *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( (!r_size) || (motion_code == 0) ){
		delta = motion_code;
	}else{
		motion_residual = get_bits(in, r_size);
		delta = (abs(motion_code) - 1) * f + motion_residual + 1;
		if(motion_code < 0){
			delta = 0 - delta;
		}
	}

	if(half){
		prediction >>= 1;
	}

	r = prediction + delta;

	if(r < low){
		r += range;
	}else if(r > high){
		r -= range;
	}

	if(half){
		r <<= 1;
	}

	return r;
}

static void read_coded_block(VIDEO_STREAM *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(VIDEO_STREAM *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},
		{43,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) - 12;
		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;
}

typedef struct {
	int weight_top;
	int weight_bottom;
	int class;
	int integer_weight;
} SPATIAL_TEMPORAL_WEIGHT_TABLE_ELEMENT;

static void read_spatial_temporal_weight(VIDEO_STREAM *in, MACROBLOCK *out, READ_MACROBLOCK_OPTION *opt)
{
	int code;
	
	static const SPATIAL_TEMPORAL_WEIGHT_TABLE_ELEMENT table[4][4] = {
		{
			{1, 1, 1, 0},
			{1, 1, 1, 0},
			{1, 1, 1, 0},
			{1, 1, 1, 0},
		}, /* table_index_0 */

		{
			{0, 2, 3, 1},
			{0, 1, 1, 0},
			{1, 2, 3, 0},
			{1, 1, 1, 0},
		}, /* table_index_1 */

		{
			{2, 0, 2, 1},
			{1, 0, 1, 0},
			{2, 1, 2, 0},
			{1, 1, 1, 0},
		}, /* table_index_2 */

		{
			{2, 0, 2, 1},
			{2, 1, 2, 0},
			{1, 2, 3, 0},
			{1, 1, 1, 0},
		}, /* table_index_4 */
	};
	
	if(opt->spatial_temporal_weight_code_table_index){
		code = get_bits(in, 2);
		out->spatial_temporal_weight[0] = table[opt->spatial_temporal_weight_code_table_index][code].weight_top;
		out->spatial_temporal_weight[1] = table[opt->spatial_temporal_weight_code_table_index][code].weight_bottom;
		out->spatial_temporal_weight_class = table[opt->spatial_temporal_weight_code_table_index][code].class;
		out->spatial_temporal_integer_weight = table[opt->spatial_temporal_weight_code_table_index][code].integer_weight;
	}else{
		out->spatial_temporal_weight[0] = 1;
		out->spatial_temporal_weight[1] = 1;
		out->spatial_temporal_weight_class = 1;
		out->spatial_temporal_integer_weight = 0;
	}
}