/******************************************************************* picture decoding (reconstract) module *******************************************************************/ #define PICTURE_C #include "picture.h" /* in block_mmx.asm */ extern void __stdcall copy_i_block_to_frame_mmx(short *in, unsigned char *out, int step); extern void __stdcall add_diff_to_frame_mmx(short *in, unsigned char *out, int step); int decode_picture(VIDEO_STREAM *in, MC_BUFFER *out, DECODE_PICTURE_PARAMETER *prm); void add_block_data_to_frame(short *in, FRAME *out, READ_BLOCK_OPTION *opt, int x, int y, int block_number); void add_block_data_to_frame_mmx(short *in, FRAME *out, READ_BLOCK_OPTION *opt, int x, int y, int block_number); static void check_motion_vector(MC_PARAMETER *prm, int x, int y, int width, int height); int decode_picture(VIDEO_STREAM *in, MC_BUFFER *out, DECODE_PICTURE_PARAMETER *prm) { int i; SLICE_HEADER sh; MACROBLOCK mb; short block[64]; int x, y, address, inc, width, height, max; address = 0; width = out->current->width; height = out->current->height; max = width * height / 16; if(prm->mc_parameter.picture_structure != 3){ max /= 2; } while(vs_next_start_code(in)){ if(!read_slice_header(in, &sh, &(prm->slice_option))){ return 0; } slice_header_to_read_block_option(&sh, &(prm->block_option)); reset_motion_vector_predictor(&mb); inc = get_macroblock_address_increment(in); if( ((inc-1)*16) == (address % width) ){ inc = 1; }else{ return 0; } do{ read_macroblock(in, &mb, &(prm->macroblock_option)); macroblock_to_mc_parameter(&mb, &(prm->mc_parameter)); macroblock_to_read_block_option(&mb, &(prm->block_option)); x = address % width; y = address / width * 16; if(prm->mc_parameter.picture_structure != 3){ y *= 2; } check_motion_vector(&(prm->mc_parameter), x, y, width, height); mc(out, &(prm->mc_parameter), x, y); for(i=0;iblock_option))){ return 0; } prm->idct_func(block); prm->add_block_func(block, out->current, &(prm->block_option), x, y, i); } } address += 16; if(address >= max){ /* all macroblocks have decoded */ return 1; } inc = get_macroblock_address_increment(in); if(inc == 0){ /* goto next slice */ break; } if(inc != 1){ /* skipped macroblock */ reset_dc_dct_predictor(&(prm->block_option)); if(prm->macroblock_option.picture_coding_type == 2){ reset_motion_vector_predictor(&mb); macroblock_to_mc_parameter(&mb, &(prm->mc_parameter)); } if(prm->mc_parameter.picture_structure == 3){ prm->mc_parameter.prediction_type = PREDICTION_TYPE_FRAME_BASED; }else{ prm->mc_parameter.prediction_type = PREDICTION_TYPE_FIELD_BASED; prm->mc_parameter.motion_vertical_field_select[0][1] = (prm->mc_parameter.picture_structure == 2); prm->mc_parameter.motion_vertical_field_select[0][1] = (prm->mc_parameter.picture_structure == 2); } } for(i=0;imc_parameter.picture_structure != 3){ y *= 2; } mc(out, &(prm->mc_parameter), x, y); address += 16; } }while(1); } return 1; } static const int cc_table[] = { 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, }; static const int x_offset[12] = { 0, 8, 0, 8, 0, 0, 0, 0, 8, 8, 8, 8, }; static const int y_offset[12][4][2] = { {/* block_number - 0 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 0, 0, }, {/* picture_structure - 2 */ 1, 1, }, {/* picture_structure - 3 */ 0, 0, }, }, {/* block_number - 1 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 0, 0, }, {/* picture_structure - 2 */ 1, 1, }, {/* picture_structure - 3 */ 0, 0, }, }, {/* block_number - 2 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 16, 16, }, {/* picture_structure - 2 */ 17, 17, }, {/* picture_structure - 3 */ 8, 1, }, }, {/* block_number - 3 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 16, 16, }, {/* picture_structure - 2 */ 17, 17, }, {/* picture_structure - 3 */ 8, 1, }, }, {/* block_number - 4 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 0, 0, }, {/* picture_structure - 2 */ 1, 1, }, {/* picture_structure - 3 */ 0, 0, }, }, {/* block_number - 5 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 0, 0, }, {/* picture_structure - 2 */ 1, 1, }, {/* picture_structure - 3 */ 0, 0, }, }, {/* block_number - 6 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 16, 16, }, {/* picture_structure - 2 */ 17, 17, }, {/* picture_structure - 3 */ 8, 1, }, }, {/* block_number - 7 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 16, 16, }, {/* picture_structure - 2 */ 17, 17, }, {/* picture_structure - 3 */ 8, 1, }, }, {/* block_number - 8 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 0, 0, }, {/* picture_structure - 2 */ 1, 1, }, {/* picture_structure - 3 */ 0, 0, }, }, {/* block_number - 9 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 0, 0, }, {/* picture_structure - 2 */ 1, 1, }, {/* picture_structure - 3 */ 0, 0, }, }, {/* block_number - 10 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 16, 16, }, {/* picture_structure - 2 */ 17, 17, }, {/* picture_structure - 3 */ 8, 1, }, }, {/* block_number - 11 */ {/* dummy */ 0, 0, }, {/* picture_structure - 1 */ 16, 16, }, {/* picture_structure - 2 */ 17, 17, }, {/* picture_structure - 3 */ 8, 1, }, }, }; static const int y_shift[3][4] = { {/* cc == 0, y */ 0, 0, 0, 0, }, {/* cc == 1, u */ 0, 1, 0, 0, }, {/* cc == 2, v */ 0, 1, 0, 0, }, }; static const int x_shift[3][4] = { {/* cc == 0, y */ 0, 0, 0, 0, }, {/* cc == 1, u */ 0, 1, 1, 0, }, {/* cc == 2, v */ 0, 1, 1, 0, } }; static const int step_shift[3][4][4][2] = { {/* cc == 0 */ {/* dummy */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 0, 0, }, {/* chroma_format == 2 */ 0, 0, }, {/* chroma_format == 3 */ 0, 0, }, }, {/* picture_structure == 1 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 1, 1, }, {/* chroma_format == 2 */ 1, 1, }, {/* chroma_format == 3 */ 1, 1, }, }, {/* picture_structure == 2 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 1, 1, }, {/* chroma_format == 2 */ 1, 1, }, {/* chroma_format == 3 */ 1, 1, }, }, {/* picture_structure == 3 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 0, 1, }, {/* chroma_format == 2 */ 0, 1, }, {/* chroma_format == 3 */ 0, 1, }, }, }, {/* cc == 1 */ {/* dummy */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 0, 0, }, {/* chroma_format == 2 */ 0, 0, }, {/* chroma_format == 3 */ 0, 0, }, }, {/* picture_structure == 1 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 1, 1, }, {/* chroma_format == 2 */ 1, 1, }, {/* chroma_format == 3 */ 1, 1, }, }, {/* picture_structure == 2 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 1, 1, }, {/* chroma_format == 2 */ 1, 1, }, {/* chroma_format == 3 */ 1, 1, }, }, {/* picture_structure == 3 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 0, 0, }, {/* chroma_format == 2 */ 0, 1, }, {/* chroma_format == 3 */ 0, 1, }, }, }, {/* cc == 2 */ {/* dummy */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 0, 0, }, {/* chroma_format == 2 */ 0, 0, }, {/* chroma_format == 3 */ 0, 0, }, }, {/* picture_structure == 1 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 1, 1, }, {/* chroma_format == 2 */ 1, 1, }, {/* chroma_format == 3 */ 1, 1, }, }, {/* picture_structure == 2 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 1, 1, }, {/* chroma_format == 2 */ 1, 1, }, {/* chroma_format == 3 */ 1, 1, }, }, {/* picture_structure == 3 */ {/* dummy */ 0, 0, }, {/* chroma_format == 1 */ 0, 0, }, {/* chroma_format == 2 */ 0, 1, }, {/* chroma_format == 3 */ 0, 1, }, }, }, }; void add_block_data_to_frame(short *in, FRAME *out, READ_BLOCK_OPTION *opt, int x, int y, int block_number) { int i,j; int step, cc; unsigned char *p; cc = cc_table[block_number]; switch(cc){ case 0: p = out->y; break; case 1: p = out->u; break; case 2: p = out->v; break; default: return; }; x >>= x_shift[cc][opt->chroma_format]; y >>= y_shift[cc][opt->chroma_format]; step = out->width << step_shift[cc][opt->picture_structure][opt->chroma_format][opt->dct_type]; p += (y + y_offset[block_number][opt->picture_structure][opt->dct_type]) * out->width; p += x + x_offset[block_number]; if(opt->macroblock_intra){ for(i=0;i<8;i++){ for(j=0;j<8;j++){ p[j] = uchar_clip_table[UCHAR_CLIP_TABLE_OFFSET+in[j]]; } p += step; in += 8; } }else{ for(i=0;i<8;i++){ for(j=0;j<8;j++){ p[j] = uchar_clip_table[UCHAR_CLIP_TABLE_OFFSET+p[j]+in[j]]; } p += step; in += 8; } } } typedef void ( __stdcall *ADD_BLOCK_CORE)(short *, unsigned char *, int); void add_block_data_to_frame_mmx(short *in, FRAME *out, READ_BLOCK_OPTION *opt, int x, int y, int block_number) { int step, cc; unsigned char *p; static const ADD_BLOCK_CORE table[2] = { add_diff_to_frame_mmx, copy_i_block_to_frame_mmx, }; cc = cc_table[block_number]; switch(cc){ case 0: p = out->y; break; case 1: p = out->u; break; case 2: p = out->v; break; default: return; }; x >>= x_shift[cc][opt->chroma_format]; y >>= y_shift[cc][opt->chroma_format]; step = out->width << step_shift[cc][opt->picture_structure][opt->chroma_format][opt->dct_type]; p += (y + y_offset[block_number][opt->picture_structure][opt->dct_type]) * out->width; p += x + x_offset[block_number]; table[opt->macroblock_intra](in, p, step); } static void check_motion_vector(MC_PARAMETER *prm, int x, int y, int width, int height) { int r,s; for(r=0;r<2;r++){ for(s=0;s<2;s++){ if(prm->PMV[r][s][0] < -2 * x){ prm->PMV[r][s][0] = -2 * x; }else if(prm->PMV[r][s][0] > (width-x-16)*2){ prm->PMV[r][s][0] = (width-x-16)*2; } if(prm->PMV[r][s][1] < -2 * y){ prm->PMV[r][s][1] = - 2 * y; }else if(prm->PMV[r][s][1] > (height-y-16)*2){ prm->PMV[r][s][1] = (height-y-16)*2; } } } }