/* video.c */

#include "mphead.h"

void *malloc();

extern short mb_addr_inc[2048];
extern unsigned char macro_block_table_p[64],macro_block_table_b[64];
extern short coded_block_pattern_table[512];
extern gray;

int scaled_intra_quant_matrix[64];
int scaled_non_intra_quant_matrix[64];

short block[64];
int dc_y_past,dc_cr_past,dc_cb_past;
int pict_type;
int full_pel_forw,pict_forw_r_size,pict_forw_f;
int full_pel_back,pict_back_r_size,pict_back_f;

int mb_address,mb_past_mb_addr;
int motion_h_forw_code,motion_h_forw_r;
int motion_v_forw_code,motion_v_forw_r;
int motion_h_back_code,motion_h_back_r;
int motion_v_back_code,motion_v_back_r;
int coded_block_pattern,intra,past_intra_addr;
int past_forw,past_back;
int right_for_prev,down_for_prev;
int right_back_prev,down_back_prev;

int width,height;
int mb_height,mb_width;
int mod_y,mod_c;
struct pict_image *past,*future,*current;

unsigned char zigzag[64] = {
	 0, 1, 8,16, 9, 2, 3,10,
	17,24,32,25,18,11, 4, 5,
	12,19,26,33,40,48,41,34,
	27,20,13, 6, 7,14,21,28,
	35,42,49,56,57,50,43,36,
	29,22,15,23,30,37,44,51,
	58,59,52,45,38,31,39,46,
	53,60,61,54,47,55,62,63,
};

static quant_scale;
static unsigned char intra_quant_matrix[64];
static unsigned char non_intra_quant_matrix[64];
static struct pict_image *ring[RING_BUF_SIZE];

static unsigned char default_intra_matrix[64] = {
	 8,16,19,22,26,27,29,34,
	16,16,22,24,27,29,34,37,
	19,22,26,27,29,34,34,38,
	22,22,26,27,29,34,37,40,
	22,26,27,29,32,35,40,48,
	26,27,29,32,35,40,48,58,
	26,27,29,34,38,46,56,69,
	27,29,35,38,46,56,69,83,
};

init_video()
{
	int i,j;

	for (i=0; i<64; i++)
		intra_quant_matrix[i] = default_intra_matrix[zigzag[i]];
	for (i=0; i<64; i++)
		non_intra_quant_matrix[i] = 16;
}

static struct pict_image *
new_pict_image()
{
	int w = mb_width*mb_height*64;
	struct pict_image *new;

	new = malloc(sizeof(struct pict_image)+w*6);
	memset(new,0,sizeof(struct pict_image));
	new->cr = (unsigned char *)(new+1);
	new->cb = new->cr+w;
	new->lum = new->cb+w;
	new->o[0] = new->lum;
	new->o[1] = new->lum+8;
	new->o[2] = new->lum+mod_y*8;
	new->o[3] = new->lum+mod_y*8+8;
	new->o[4] = new->cb;
	new->o[5] = new->cr;
	return new;
}

static inline int
decode_motion_vector()
{
	int i;
	extern short motion_vector_table[2048];

	fill_bitsn(11);
	i = motion_vector_table[show_bitsn(11)];
	flush_bitsn(i&15);
	return i>>4;
}

static
compute_vector(recon_ptr,recon_prev,f,full_pel_vector,motion_code,motion_r)
int *recon_ptr,*recon_prev;
{
	int i,little,big;

	little = motion_code*f;
	if (little == 0)
		big = 0;
	else if (little > 0) {
		if (f != 1)
			little -= f-1-motion_r;
		big = little-32*f;
	}
	else {
		if (f != 1)
			little += f-1-motion_r;
		big = little+32*f;
	}
	i = *recon_prev+little;
	if (i>=-16*f && i<16*f)
		*recon_ptr = *recon_prev+little;
	else
		*recon_ptr = *recon_prev+big;
	*recon_prev = *recon_ptr;
	if (full_pel_vector)
		*recon_ptr <<= 1;
}

static
fix_scaled_matrixes()
{
	int i;
	static old_qscale = -1;

	if (quant_scale != old_qscale) {
		old_qscale = quant_scale;
		for (i=0; i<64; i++) {
			scaled_intra_quant_matrix[i] = old_qscale*intra_quant_matrix[i];
			scaled_non_intra_quant_matrix[i] = old_qscale*non_intra_quant_matrix[i];
		}
	}
}

static
parse_macro_block()
{
	int i;
	int recon_right_for,recon_down_for,recon_right_back,recon_down_back;
	int motion_forw,motion_back;
	int mb_quant,mb_pattern;
	int zero_block_flag;
	static unsigned char quant_table[4] = {0, 1, 0, 0};

	do {
		fill_bitsn(11);
		i = mb_addr_inc[show_bitsn(11)];
		flush_bitsn(i & 15);
		i >>= 4;
		if (i == MB_ESCAPE) {
			mb_address += 33;
			i = MB_STUFFING;
		}
	} while (i == MB_STUFFING);
	mb_address += i;
	if (mb_address >= mb_height*mb_width)
		return;
	if (mb_address-mb_past_mb_addr > 1)
		if (pict_type == P_TYPE)
			process_skipped_p_mblocks();
		else if (pict_type == B_TYPE)
			process_skipped_b_mblocks();
	mb_past_mb_addr = mb_address;
	switch (pict_type) {
		case I_TYPE:
			fill_bitsn(2);
			i = show_bitsn(2);
			motion_forw = 0;
			motion_back = 0;
			mb_pattern = 0;
			intra = 1;
			mb_quant = quant_table[i];
			flush_bitsn(1 + mb_quant);
			break;
		case P_TYPE:
			fill_bitsn(6);
			i = macro_block_table_p[show_bitsn(6)];
			goto label;
		case B_TYPE:
			fill_bitsn(6);
			i = macro_block_table_b[show_bitsn(6)];
label:
			mb_quant = i&128;
			motion_forw = i&64;
			motion_back = i&32;
			mb_pattern = i&16;
			intra = i&8;
			flush_bitsn(i&7);
			break;
	}
	if (mb_quant) {
		fill_bitsn(5);
		quant_scale = get_bitsn(5);
		fix_scaled_matrixes();
	}
	if (motion_forw) {
		motion_h_forw_code = decode_motion_vector();
		if (pict_forw_f!=1 && motion_h_forw_code) {
			fill_bitsn(6);
			motion_h_forw_r = get_bitsn(pict_forw_r_size);
		}
		motion_v_forw_code = decode_motion_vector();
		if (pict_forw_f!=1 && motion_v_forw_code) {
			fill_bitsn(6);
			motion_v_forw_r = get_bitsn(pict_forw_r_size);
		}
	}
	if (motion_back) {
		motion_h_back_code = decode_motion_vector();
		if (pict_back_f!=1 && motion_h_back_code) {
			fill_bitsn(6);
			motion_h_back_r = get_bitsn(pict_back_r_size);
		}
		motion_v_back_code = decode_motion_vector();
		if (pict_back_f!=1 && motion_v_back_code) {
			fill_bitsn(6);
			motion_v_back_r = get_bitsn(pict_back_r_size);
		}
	}
	if (mb_pattern) {
		fill_bitsn(9);
		i = coded_block_pattern_table[show_bitsn(9)];
		flush_bitsn(i&15);
		coded_block_pattern = i>>4;
	}
	else
		coded_block_pattern = 0;
	if (pict_type == P_TYPE) {
		if (!motion_forw) {
			recon_right_for = 0;
			recon_down_for = 0;
			right_for_prev = 0;
			down_for_prev = 0;
		}
		else {
			compute_vector(&recon_right_for,&right_for_prev,pict_forw_f,full_pel_forw,motion_h_forw_code,motion_h_forw_r);
			compute_vector(&recon_down_for,&down_for_prev,pict_forw_f,full_pel_forw,motion_v_forw_code,motion_v_forw_r);
		}
	}
	if (pict_type == B_TYPE) {
		if (intra) {
			right_for_prev = 0;
			down_for_prev = 0;
			right_back_prev = 0;
			down_back_prev = 0;
		}
		else {
			if (motion_forw) {
				compute_vector(&recon_right_for,&right_for_prev,pict_forw_f,full_pel_forw,motion_h_forw_code,motion_h_forw_r);
				compute_vector(&recon_down_for,&down_for_prev,pict_forw_f,full_pel_forw,motion_v_forw_code,motion_v_forw_r);
			}
			if (motion_back) {
				compute_vector(&recon_right_back,&right_back_prev,pict_back_f,full_pel_back,motion_h_back_code,motion_h_back_r);
				compute_vector(&recon_down_back,&down_back_prev,pict_back_f,full_pel_back,motion_v_back_code,motion_v_back_r);
			}
			past_forw = motion_forw;
			past_back = motion_back;
		}
	}
	for (i=0; i<6; i++) {
		if (gray && i>=4) {
			if (intra || coded_block_pattern&32>>i)
				skip_block(i);
			continue;
		}
		zero_block_flag = 1;
		if (intra || coded_block_pattern&32>>i) {
			parse_recon_block(i);
			zero_block_flag = 0;
		}
		if (intra)
			recon_i_mblock(i,zero_block_flag);
		else if (motion_forw && motion_back)
			recon_bi_mblock(i,recon_right_for,recon_down_for,recon_right_back,recon_down_back,zero_block_flag);
		else if (pict_type == P_TYPE)
			recon_p_or_b_mblock(i,recon_right_for,recon_down_for,future,zero_block_flag);
		else if (motion_forw)
			recon_p_or_b_mblock(i,recon_right_for,recon_down_for,past,zero_block_flag);
		else if (motion_back)
			recon_p_or_b_mblock(i,recon_right_back,recon_down_back,future,zero_block_flag);
		else
			recon_i_mblock(i,zero_block_flag);
	}
	if (pict_type == 4)
		flush_bitsn(1);
	if (intra)
		past_intra_addr = mb_address;
}

static
parse_seq_head()
{
	int i;

	fill_bitsn(24);
	width = get_bitsn(12);
	height = get_bitsn(12);
	width = (width+1) & ~1;
	height = (height+1) & ~1;
	mb_width = (width+15)/16;
	mb_height = (height+15)/16;
	mod_c = mb_width*8;
	mod_y = mod_c*2;
	for (i = 0; i < RING_BUF_SIZE; i++)
		ring[i] = new_pict_image();
	fill_bitsn(8);
	flush_bitsn(4);
	flush_bitsn(4);
	fill_bitsn(19);
	flush_bitsn(18);
	flush_bitsn(1);
	fill_bitsn(12);
	flush_bitsn(10);
	flush_bitsn(1);
	if (get_bitsn(1))
		for (i = 0; i < 64; i++) {
			fill_bitsn(8);
			intra_quant_matrix[i] = get_bitsn(8);
		}
	fill_bitsn(1);
	if (get_bitsn(1))
		for (i = 0; i < 64; i++) {
			fill_bitsn(8);
			non_intra_quant_matrix[i] = get_bitsn(8);
		}
	next_start_code();
	init_output();
}

static
parse_gop()
{
	next_start_code();
}

empty_ring()
{
	int i;

	for (i=0; i<RING_BUF_SIZE; i++)
		ring[i]->lock = 0;
	current = future = past = NULL;
}

static
parse_picture()
{
	int i;

	fill_bitsn(13);
	flush_bitsn(10);
	pict_type = get_bitsn(3);
	if (pict_type == B_TYPE)
		if (!future || !past)
			return 1;
	if (pict_type == P_TYPE)
		if (!future)
			return 1;
	fill_bitsn(16);
	flush_bitsn(16);
	if (pict_type==P_TYPE || pict_type==B_TYPE) {
		fill_bitsn(4);
		full_pel_forw = get_bitsn(1);
		pict_forw_r_size = get_bitsn(3)-1;
		pict_forw_f = 1 << pict_forw_r_size;
	}
	if (pict_type == B_TYPE) {
		fill_bitsn(4);
		full_pel_back = get_bitsn(1);
		pict_back_r_size = get_bitsn(3)-1;
		pict_back_f = 1 << pict_back_r_size;
	}
	get_extra_bit_info();
	next_start_code();
	i = 0;
	while (ring[i]->lock)
		if (++i >= RING_BUF_SIZE)
			eexit();
	current = ring[i];
	mb_past_mb_addr = -1;
	return 0;
}

static
parse_slice(d)
{
	fill_bitsn(5);
	quant_scale = get_bitsn(5);
	fix_scaled_matrixes();
	get_extra_bit_info();
	past_intra_addr = -2;
	right_for_prev = 0;
	down_for_prev = 0;
	right_back_prev = 0;
	down_back_prev = 0;
	mb_address = ((d&255)-1)*mb_width - 1;
	dc_y_past = 1024;
	dc_cr_past = 1024;
	dc_cb_past = 1024;
}

static
display_picture()
{
	if (pict_type==I_TYPE || pict_type==P_TYPE) {
		if (future == NULL) {
			future = current;
			future->lock |= FUTURE_LOCK;
		}
		else {
			if (past)
				past->lock &= ~PAST_LOCK;
			past = future;
			past->lock &= ~FUTURE_LOCK;
			past->lock |= PAST_LOCK;
			future = current;
			future->lock |= FUTURE_LOCK;
			current = past;
			output_frame();
		}
	} else
		output_frame();
}

parse_stream()
{
	unsigned start_code;

	fill_bitsn(24);
	if (show_bitsn(24) == 1) {
		start_code = next_start_code();
		fill_bitsn(32);
		flush_bitsn(32);
		switch (start_code) {
			case EXT_START_CODE:
			case USER_START_CODE:
				get_ext_data();
				break;
			case SEQ_END_CODE:
				if (future) {
					current = future;
					output_frame();
				}
				end_output();
				return 1;
			case SEQ_START_CODE:
				parse_seq_head();
				break;
			case GOP_START_CODE:
				parse_gop();
				break;
			case PICTURE_START_CODE:
				if (parse_picture()) {
					start_code = next_start_code();
					while (start_code!=PICTURE_START_CODE && start_code!=GOP_START_CODE && start_code!=SEQ_END_CODE) {
						fill_bitsn(32);
						flush_bitsn(32);
						start_code = next_start_code();
					}
				}
				break;
			default:
				if (start_code>=SLICE_MIN_START_CODE && start_code<=SLICE_MAX_START_CODE)
					parse_slice(start_code);
				break;
		}
	}
	else {
		while (fill_bitsn(23),show_bitsn(23))
			parse_macro_block();
		start_code = next_start_code();
		if (start_code<SLICE_MIN_START_CODE || start_code>SLICE_MAX_START_CODE)
			display_picture();
	}
	return 0;
}
