www.pudn.com > MPEG4Codec.zip > mp4_block.c


/************************************************************************** 
 *                                                                        * 
 * This code has been developed by Andrea Graziani. This software is an   * 
 * implementation of a part of one or more MPEG-4 Video tools as          * 
 * specified in ISO/IEC 14496-2 standard.  Those intending to use this    * 
 * software module in hardware or software products are advised that its  * 
 * use may infringe existing patents or copyrights, and any such use      * 
 * would be at such party's own risk.  The original developer of this     * 
 * software module and his/her company, and subsequent editors and their  * 
 * companies (including Project Mayo), will have no liability for use of  * 
 * this software or modifications or derivatives thereof.                 * 
 *                                                                        * 
 * Project Mayo gives users of the Codec a license to this software       * 
 * module or modifications thereof for use in hardware or software        * 
 * products claiming conformance to the MPEG-4 Video Standard as          * 
 * described in the Open DivX license.                                    * 
 *                                                                        * 
 * The complete Open DivX license can be found at                         * 
 * http://www.projectmayo.com/opendivx/license.php                        * 
 *                                                                        * 
 **************************************************************************/ 
/** 
*  Copyright (C) 2001 - Project Mayo 
 * 
 * Andrea Graziani (Ag) 
 * 
 * DivX Advanced Research Center  
* 
**/ 
/// mp4_block.c // 
 
#include  
#include  
#include  
 
#include "mp4_vars.h" 
 
#include "getbits.h" 
#include "clearblock.h" 
#include "mp4_iquant.h" 
#include "mp4_predict.h" 
#include "mp4_vld.h" 
#include "debug.h" 
#include "mp4_block.h" 
 
/** 
 * 
**/ 
 
static int getDCsizeLum(); 
static int getDCsizeChr(); 
static int getDCdiff(); 
static void setDCscaler(int block_num); 
 
static int getACdir(); 
 
/***/ 
 
// Purpose: texture decoding of block_num 
int block(int block_num, int coded) 
{ 
	int i; 
	int dct_dc_size, dct_dc_diff; 
	int intraFlag = ((mp4_state->hdr.derived_mb_type == INTRA) ||  
		(mp4_state->hdr.derived_mb_type == INTRA_Q)) ? 1 : 0; 
	event_t event; 
 
	clearblock(ld->block); // clearblock 
 
	if (intraFlag) 
	{ 
		setDCscaler(block_num); // calculate DC scaler 
 
		if (block_num < 4) { 
			dct_dc_size = getDCsizeLum(); 
			if (dct_dc_size != 0)  
				dct_dc_diff = getDCdiff(dct_dc_size); 
			else  
				dct_dc_diff = 0; 
			if (dct_dc_size > 8) 
				getbits1(); // marker bit 
		} 
		else { 
			dct_dc_size = getDCsizeChr(); 
			if (dct_dc_size != 0) 
				dct_dc_diff = getDCdiff(dct_dc_size); 
			else  
				dct_dc_diff = 0; 
			if (dct_dc_size > 8) 
				getbits1(); // marker bit 
		} 
 
		ld->block[0] = (short) dct_dc_diff; 
//		_Print("DC diff: %d\n", dct_dc_diff); 
	} 
	if (intraFlag) 
	{ 
		// dc reconstruction, prediction direction 
		dc_recon(block_num, &ld->block[0]); 
	} 
 
	if (coded)  
	{ 
		unsigned int * zigzag; // zigzag scan dir 
 
		if ((intraFlag) && (mp4_state->hdr.ac_pred_flag == 1)) { 
 
			if (mp4_state->coeff_pred.predict_dir == TOP) 
				zigzag = mp4_tables->alternate_horizontal_scan; 
			else 
				zigzag = mp4_tables->alternate_vertical_scan; 
		} 
		else { 
			zigzag = mp4_tables->zig_zag_scan; 
		} 
 
		i = intraFlag ? 1 : 0; 
		do // event vld 
		{ 
			event = vld_event(intraFlag); 
/*** 
			if (event.run == -1) 
			{ 
				printf("Error: invalid vld code\n"); 
				exit(201); 
			} 
***/			 
			i+= event.run; 
			ld->block[zigzag[i]] = (short) event.level; 
 
//			_Print("Vld Event: Run Level Last %d %d %d\n", event.run, event.level, event.last); 
 
			i++; 
		} while (! event.last); 
	} 
 
	if (intraFlag) 
	{ 
		// ac reconstruction 
		// ac_rescaling(...) 
		ac_recon(block_num, &ld->block[0]); 
	} 
 
#ifdef _DEBUG_B_ACDC 
	if (intraFlag) 
	{ 
		int i; 
		_Print("After AcDcRecon:\n"); 
		_Print("   x "); 
		for (i = 1; i < 64; i++) { 
			if ((i != 0) && ((i % 8) == 0)) 
				_Print("\n"); 
			_Print("%4d ", ld->block[i]); 
		} 
		_Print("\n"); 
	} 
#endif // _DEBUG_ACDC 
 
	if (mp4_state->hdr.quant_type == 0) 
	{ 
		// inverse quantization 
		iquant(ld->block, intraFlag); 
	} 
	else  
	{ 
		_Error("Error: MPEG-2 inverse quantization NOT implemented\n"); 
		exit(110); 
	} 
 
#ifdef _DEBUG_B_QUANT 
	{ 
		int i; 
		_Print("After IQuant:\n"); 
		_Print("   x "); 
		for (i = 1; i < 64; i++) { 
			if ((i != 0) && ((i % 8) == 0)) 
				_Print("\n"); 
			_Print("%4d ", ld->block[i]); 
		} 
		_Print("\n"); 
	} 
#endif // _DEBUG_B_QUANT 
 
	// inverse dct 
	idct(ld->block); 
 
	return 1; 
} 
 
/***/ 
 
int blockIntra(int block_num, int coded) 
{ 
	int i; 
	int dct_dc_size, dct_dc_diff; 
	event_t event; 
 
	clearblock(ld->block); // clearblock 
 
	// dc coeff 
	setDCscaler(block_num); // calculate DC scaler 
 
	if (block_num < 4) { 
		dct_dc_size = getDCsizeLum(); 
		if (dct_dc_size != 0)  
			dct_dc_diff = getDCdiff(dct_dc_size); 
		else  
			dct_dc_diff = 0; 
		if (dct_dc_size > 8) 
			getbits1(); // marker bit 
	} 
	else { 
		dct_dc_size = getDCsizeChr(); 
		if (dct_dc_size != 0) 
			dct_dc_diff = getDCdiff(dct_dc_size); 
		else  
			dct_dc_diff = 0; 
		if (dct_dc_size > 8) 
			getbits1(); // marker bit 
	} 
 
	ld->block[0] = (short) dct_dc_diff; 
 
	// dc reconstruction, prediction direction 
	dc_recon(block_num, &ld->block[0]); 
 
	if (coded)  
	{ 
		unsigned int * zigzag; // zigzag scan dir 
 
		if (mp4_state->hdr.ac_pred_flag == 1) { 
 
			if (mp4_state->coeff_pred.predict_dir == TOP) 
				zigzag = mp4_tables->alternate_horizontal_scan; 
			else 
				zigzag = mp4_tables->alternate_vertical_scan; 
		} 
		else { 
			zigzag = mp4_tables->zig_zag_scan; 
		} 
 
		i = 1; 
		do // event vld 
		{ 
			event = vld_intra_dct(); 
/*** 
			if (event.run == -1) 
			{ 
				printf("Error: invalid vld code\n"); 
				exit(201); 
			} 
***/			 
			i+= event.run; 
			ld->block[zigzag[i]] = (short) event.level; 
 
//			_Print("Vld Event: Run Level Last %d %d %d\n", event.run, event.level, event.last); 
 
			i++; 
		} while (! event.last); 
	} 
 
	// ac reconstruction 
	mp4_state->hdr.intrablock_rescaled = ac_rescaling(block_num, &ld->block[0]); 
	if (! mp4_state->hdr.intrablock_rescaled) 
	{ 
		ac_recon(block_num, &ld->block[0]); 
	} 
	ac_store(block_num, &ld->block[0]); 
 
	if (mp4_state->hdr.quant_type == 0) 
	{ 
		iquant(ld->block, 1); 
	} 
	else  
	{ 
		iquant_typefirst(ld->block); 
	} 
 
	// inverse dct 
	idct(ld->block); 
 
	return 1; 
} 
 
/***/ 
 
int blockInter(int block_num, int coded) 
{ 
	event_t event; 
	unsigned int * zigzag = mp4_tables->zig_zag_scan; // zigzag scan dir 
	int i; 
	 
	clearblock(ld->block); // clearblock 
 
	// inverse quant type 
	if (mp4_state->hdr.quant_type == 0)  
	{ 
		int q_scale = mp4_state->hdr.quantizer; 
		int q_2scale = q_scale << 1; 
		int q_add = (q_scale & 1) ? q_scale : (q_scale - 1); 
			 
		i = 0; 
		do // event vld 
		{ 
			event = vld_inter_dct(); 
 
			/*** 
			if (event.run == -1) 
			{ 
			printf("Error: invalid vld code\n"); 
			exit(201); 
			} 
			***/			 
			i+= event.run; 
			if (event.level > 0) { 
				ld->block[zigzag[i]] = (q_2scale * event.level) + q_add; 
			} 
			else { 
				ld->block[zigzag[i]] = (q_2scale * event.level) - q_add; 
			} 
			 
			// _Print("Vld Event: Run Level Last %d %d %d\n", event.run, event.level, event.last); 
			 
			i++; 
		} while (! event.last); 
	} 
	else  
	{ 
		int k, m = 0; 
		i = 0; 
 
		// event vld 
		do  
		{ 
			event = vld_inter_dct(); 
 
			i+= event.run; 
	 
			k = (event.level > 0) ? 1 : -1; 
 
			assert(ld->block[zigzag[i]] < 2047); 
			assert(ld->block[zigzag[i]] > -2048); 
 
			ld->block[zigzag[i]] = ((2 * event.level + k) * mp4_state->hdr.quantizer *  
				mp4_tables->nonintra_quant_matrix[zigzag[i]]) >> 4; 
 
			assert(ld->block[zigzag[i]] < 2047); 
			assert(ld->block[zigzag[i]] > -2048); 
 
			m ^= ld->block[zigzag[i]]; 
			 
			// _Print("Vld Event: Run Level Last %d %d %d\n", event.run, event.level, event.last); 
			 
			i++; 
		} while (! event.last); 
 
		if (!(m%2)) ld->block[63] ^= 1; 
	} 
 
	// inverse dct 
	idct(ld->block); 
		 
	return 1; 
} 
 
/***/ 
 
static int getDCsizeLum() 
{ 
	int code; 
 
	// [Ag][note] bad code 
 
	if (showbits(11) == 1) { 
		flushbits(11); 
		return 12; 
	} 
  if (showbits(10) == 1) { 
    flushbits(10); 
    return 11; 
  } 
  if (showbits(9) == 1) { 
    flushbits(9); 
    return 10; 
	} 
	if (showbits(8) == 1) { 
		flushbits(8); 
		return 9; 
	} 
	if (showbits(7) == 1) { 
		flushbits(7); 
		return 8; 
	} 
	if (showbits(6) == 1) { 
		flushbits(6); 
		return 7; 
	}   
	if (showbits(5) == 1) { 
		flushbits(5); 
		return 6; 
	} 
	if (showbits(4) == 1) { 
		flushbits(4); 
		return 5; 
	} 
 
	code = showbits(3); 
 
	if (code == 1) { 
		flushbits(3); 
		return 4; 
	} else if (code == 2) { 
		flushbits(3); 
		return 3; 
	} else if (code == 3) { 
		flushbits(3); 
		return 0; 
	} 
 
  code = showbits(2); 
 
  if (code == 2) { 
		flushbits(2); 
		return 2; 
	} else if (code == 3) { 
		flushbits(2); 
		return 1; 
	}      
 
	return 0; 
} 
 
static int getDCsizeChr() 
{ 
	// [Ag][note] bad code 
 
	if (showbits(12) == 1) { 
		flushbits(12); 
		return 12; 
	} 
	if (showbits(11) == 1) { 
		flushbits(11); 
		return 11; 
	} 
	if (showbits(10) == 1) { 
		flushbits(10); 
		return 10; 
	} 
	if (showbits(9) == 1) { 
		flushbits(9); 
		return 9; 
	} 
	if (showbits(8) == 1) { 
		flushbits(8); 
		return 8; 
	} 
	if (showbits(7) == 1) { 
		flushbits(7); 
		return 7; 
	} 
	if (showbits(6) == 1) { 
		flushbits(6); 
		return 6; 
	} 
	if (showbits(5) == 1) { 
		flushbits(5); 
		return 5; 
	} 
	if (showbits(4) == 1) { 
		flushbits(4); 
		return 4; 
	}  
	if (showbits(3) == 1) { 
		flushbits(3); 
		return 3; 
	}  
 
	return (3 - getbits(2)); 
} 
 
/***/ 
 
static int getDCdiff(int dct_dc_size) 
{ 
	int code = getbits(dct_dc_size); 
	int msb = code >> (dct_dc_size - 1); 
 
	if (msb == 0) { 
		return (-1 * (code^((int) pow(2.0,(double) dct_dc_size) - 1))); 
	} 
  else {  
		return code; 
	} 
} 
 
/***/ 
 
static void setDCscaler(int block_num)  
{ 
	int type = (block_num < 4) ? 0 : 1; 
	int quant = mp4_state->hdr.quantizer; 
 
	if (type == 0) { 
		if (quant > 0 && quant < 5)  
			mp4_state->hdr.dc_scaler = 8; 
		else if (quant > 4 && quant < 9)  
			mp4_state->hdr.dc_scaler = (2 * quant); 
		else if (quant > 8 && quant < 25)  
			mp4_state->hdr.dc_scaler = (quant + 8); 
		else  
			mp4_state->hdr.dc_scaler = (2 * quant - 16); 
	} 
  else { 
		if (quant > 0 && quant < 5)  
			mp4_state->hdr.dc_scaler = 8; 
		else if (quant > 4 && quant < 25)  
			mp4_state->hdr.dc_scaler = ((quant + 13) / 2); 
		else  
			mp4_state->hdr.dc_scaler = (quant - 6); 
	} 
} 
 
/***/