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); } } /***/