yading@10: /* yading@10: * MSMPEG4 backend for encoder and decoder yading@10: * Copyright (c) 2001 Fabrice Bellard yading@10: * Copyright (c) 2002-2004 Michael Niedermayer yading@10: * yading@10: * msmpeg4v1 & v2 stuff by Michael Niedermayer yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * MSMPEG4 backend for encoder and decoder yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: #include "dsputil.h" yading@10: #include "mpegvideo.h" yading@10: #include "msmpeg4.h" yading@10: #include "libavutil/x86/asm.h" yading@10: #include "h263.h" yading@10: #include "mpeg4video.h" yading@10: #include "msmpeg4data.h" yading@10: #include "vc1data.h" yading@10: #include "libavutil/imgutils.h" yading@10: yading@10: /* yading@10: * You can also call this codec : MPEG4 with a twist ! yading@10: * yading@10: * TODO: yading@10: * - (encoding) select best mv table (two choices) yading@10: * - (encoding) select best vlc/dc table yading@10: */ yading@10: //#define DEBUG yading@10: yading@10: /* This table is practically identical to the one from h263 yading@10: * except that it is inverted. */ yading@10: static av_cold void init_h263_dc_for_msmpeg4(void) yading@10: { yading@10: int level, uni_code, uni_len; yading@10: yading@10: if(ff_v2_dc_chroma_table[255 + 256][1]) yading@10: return; yading@10: yading@10: for(level=-256; level<256; level++){ yading@10: int size, v, l; yading@10: /* find number of bits */ yading@10: size = 0; yading@10: v = abs(level); yading@10: while (v) { yading@10: v >>= 1; yading@10: size++; yading@10: } yading@10: yading@10: if (level < 0) yading@10: l= (-level) ^ ((1 << size) - 1); yading@10: else yading@10: l= level; yading@10: yading@10: /* luminance h263 */ yading@10: uni_code= ff_mpeg4_DCtab_lum[size][0]; yading@10: uni_len = ff_mpeg4_DCtab_lum[size][1]; yading@10: uni_code ^= (1< 0) { yading@10: uni_code<<=size; uni_code|=l; yading@10: uni_len+=size; yading@10: if (size > 8){ yading@10: uni_code<<=1; uni_code|=1; yading@10: uni_len++; yading@10: } yading@10: } yading@10: ff_v2_dc_lum_table[level + 256][0] = uni_code; yading@10: ff_v2_dc_lum_table[level + 256][1] = uni_len; yading@10: yading@10: /* chrominance h263 */ yading@10: uni_code= ff_mpeg4_DCtab_chrom[size][0]; yading@10: uni_len = ff_mpeg4_DCtab_chrom[size][1]; yading@10: uni_code ^= (1< 0) { yading@10: uni_code<<=size; uni_code|=l; yading@10: uni_len+=size; yading@10: if (size > 8){ yading@10: uni_code<<=1; uni_code|=1; yading@10: uni_len++; yading@10: } yading@10: } yading@10: ff_v2_dc_chroma_table[level + 256][0] = uni_code; yading@10: ff_v2_dc_chroma_table[level + 256][1] = uni_len; yading@10: yading@10: } yading@10: } yading@10: yading@10: av_cold void ff_msmpeg4_common_init(MpegEncContext *s) yading@10: { yading@10: switch(s->msmpeg4_version){ yading@10: case 1: yading@10: case 2: yading@10: s->y_dc_scale_table= yading@10: s->c_dc_scale_table= ff_mpeg1_dc_scale_table; yading@10: break; yading@10: case 3: yading@10: if(s->workaround_bugs){ yading@10: s->y_dc_scale_table= ff_old_ff_y_dc_scale_table; yading@10: s->c_dc_scale_table= ff_wmv1_c_dc_scale_table; yading@10: } else{ yading@10: s->y_dc_scale_table= ff_mpeg4_y_dc_scale_table; yading@10: s->c_dc_scale_table= ff_mpeg4_c_dc_scale_table; yading@10: } yading@10: break; yading@10: case 4: yading@10: case 5: yading@10: s->y_dc_scale_table= ff_wmv1_y_dc_scale_table; yading@10: s->c_dc_scale_table= ff_wmv1_c_dc_scale_table; yading@10: break; yading@10: #if CONFIG_VC1_DECODER yading@10: case 6: yading@10: s->y_dc_scale_table= ff_wmv3_dc_scale_table; yading@10: s->c_dc_scale_table= ff_wmv3_dc_scale_table; yading@10: break; yading@10: #endif yading@10: yading@10: } yading@10: yading@10: yading@10: if(s->msmpeg4_version>=4){ yading@10: ff_init_scantable(s->dsp.idct_permutation, &s->intra_scantable , ff_wmv1_scantable[1]); yading@10: ff_init_scantable(s->dsp.idct_permutation, &s->intra_h_scantable, ff_wmv1_scantable[2]); yading@10: ff_init_scantable(s->dsp.idct_permutation, &s->intra_v_scantable, ff_wmv1_scantable[3]); yading@10: ff_init_scantable(s->dsp.idct_permutation, &s->inter_scantable , ff_wmv1_scantable[0]); yading@10: } yading@10: //Note the default tables are set in common_init in mpegvideo.c yading@10: yading@10: init_h263_dc_for_msmpeg4(); yading@10: } yading@10: yading@10: /* predict coded block */ yading@10: int ff_msmpeg4_coded_block_pred(MpegEncContext * s, int n, uint8_t **coded_block_ptr) yading@10: { yading@10: int xy, wrap, pred, a, b, c; yading@10: yading@10: xy = s->block_index[n]; yading@10: wrap = s->b8_stride; yading@10: yading@10: /* B C yading@10: * A X yading@10: */ yading@10: a = s->coded_block[xy - 1 ]; yading@10: b = s->coded_block[xy - 1 - wrap]; yading@10: c = s->coded_block[xy - wrap]; yading@10: yading@10: if (b == c) { yading@10: pred = a; yading@10: } else { yading@10: pred = c; yading@10: } yading@10: yading@10: /* store value */ yading@10: *coded_block_ptr = &s->coded_block[xy]; yading@10: yading@10: return pred; yading@10: } yading@10: yading@10: static int get_dc(uint8_t *src, int stride, int scale) yading@10: { yading@10: int y; yading@10: int sum=0; yading@10: for(y=0; y<8; y++){ yading@10: int x; yading@10: for(x=0; x<8; x++){ yading@10: sum+=src[x + y*stride]; yading@10: } yading@10: } yading@10: return FASTDIV((sum + (scale>>1)), scale); yading@10: } yading@10: yading@10: /* dir = 0: left, dir = 1: top prediction */ yading@10: int ff_msmpeg4_pred_dc(MpegEncContext *s, int n, yading@10: int16_t **dc_val_ptr, int *dir_ptr) yading@10: { yading@10: int a, b, c, wrap, pred, scale; yading@10: int16_t *dc_val; yading@10: yading@10: /* find prediction */ yading@10: if (n < 4) { yading@10: scale = s->y_dc_scale; yading@10: } else { yading@10: scale = s->c_dc_scale; yading@10: } yading@10: yading@10: wrap = s->block_wrap[n]; yading@10: dc_val= s->dc_val[0] + s->block_index[n]; yading@10: yading@10: /* B C yading@10: * A X yading@10: */ yading@10: a = dc_val[ - 1]; yading@10: b = dc_val[ - 1 - wrap]; yading@10: c = dc_val[ - wrap]; yading@10: yading@10: if(s->first_slice_line && (n&2)==0 && s->msmpeg4_version<4){ yading@10: b=c=1024; yading@10: } yading@10: yading@10: /* XXX: the following solution consumes divisions, but it does not yading@10: necessitate to modify mpegvideo.c. The problem comes from the yading@10: fact they decided to store the quantized DC (which would lead yading@10: to problems if Q could vary !) */ yading@10: #if ARCH_X86 && HAVE_7REGS && HAVE_EBX_AVAILABLE yading@10: __asm__ volatile( yading@10: "movl %3, %%eax \n\t" yading@10: "shrl $1, %%eax \n\t" yading@10: "addl %%eax, %2 \n\t" yading@10: "addl %%eax, %1 \n\t" yading@10: "addl %0, %%eax \n\t" yading@10: "imull %4 \n\t" yading@10: "movl %%edx, %0 \n\t" yading@10: "movl %1, %%eax \n\t" yading@10: "imull %4 \n\t" yading@10: "movl %%edx, %1 \n\t" yading@10: "movl %2, %%eax \n\t" yading@10: "imull %4 \n\t" yading@10: "movl %%edx, %2 \n\t" yading@10: : "+b" (a), "+c" (b), "+D" (c) yading@10: : "g" (scale), "S" (ff_inverse[scale]) yading@10: : "%eax", "%edx" yading@10: ); yading@10: #else yading@10: /* #elif ARCH_ALPHA */ yading@10: /* Divisions are extremely costly on Alpha; optimize the most yading@10: common case. But they are costly everywhere... yading@10: */ yading@10: if (scale == 8) { yading@10: a = (a + (8 >> 1)) / 8; yading@10: b = (b + (8 >> 1)) / 8; yading@10: c = (c + (8 >> 1)) / 8; yading@10: } else { yading@10: a = FASTDIV((a + (scale >> 1)), scale); yading@10: b = FASTDIV((b + (scale >> 1)), scale); yading@10: c = FASTDIV((c + (scale >> 1)), scale); yading@10: } yading@10: #endif yading@10: /* XXX: WARNING: they did not choose the same test as MPEG4. This yading@10: is very important ! */ yading@10: if(s->msmpeg4_version>3){ yading@10: if(s->inter_intra_pred){ yading@10: uint8_t *dest; yading@10: int wrap; yading@10: yading@10: if(n==1){ yading@10: pred=a; yading@10: *dir_ptr = 0; yading@10: }else if(n==2){ yading@10: pred=c; yading@10: *dir_ptr = 1; yading@10: }else if(n==3){ yading@10: if (abs(a - b) < abs(b - c)) { yading@10: pred = c; yading@10: *dir_ptr = 1; yading@10: } else { yading@10: pred = a; yading@10: *dir_ptr = 0; yading@10: } yading@10: }else{ yading@10: if(n<4){ yading@10: wrap= s->linesize; yading@10: dest= s->current_picture.f.data[0] + (((n >> 1) + 2*s->mb_y) * 8* wrap ) + ((n & 1) + 2*s->mb_x) * 8; yading@10: }else{ yading@10: wrap= s->uvlinesize; yading@10: dest= s->current_picture.f.data[n - 3] + (s->mb_y * 8 * wrap) + s->mb_x * 8; yading@10: } yading@10: if(s->mb_x==0) a= (1024 + (scale>>1))/scale; yading@10: else a= get_dc(dest-8, wrap, scale*8); yading@10: if(s->mb_y==0) c= (1024 + (scale>>1))/scale; yading@10: else c= get_dc(dest-8*wrap, wrap, scale*8); yading@10: yading@10: if (s->h263_aic_dir==0) { yading@10: pred= a; yading@10: *dir_ptr = 0; yading@10: }else if (s->h263_aic_dir==1) { yading@10: if(n==0){ yading@10: pred= c; yading@10: *dir_ptr = 1; yading@10: }else{ yading@10: pred= a; yading@10: *dir_ptr = 0; yading@10: } yading@10: }else if (s->h263_aic_dir==2) { yading@10: if(n==0){ yading@10: pred= a; yading@10: *dir_ptr = 0; yading@10: }else{ yading@10: pred= c; yading@10: *dir_ptr = 1; yading@10: } yading@10: } else { yading@10: pred= c; yading@10: *dir_ptr = 1; yading@10: } yading@10: } yading@10: }else{ yading@10: if (abs(a - b) < abs(b - c)) { yading@10: pred = c; yading@10: *dir_ptr = 1; yading@10: } else { yading@10: pred = a; yading@10: *dir_ptr = 0; yading@10: } yading@10: } yading@10: }else{ yading@10: if (abs(a - b) <= abs(b - c)) { yading@10: pred = c; yading@10: *dir_ptr = 1; yading@10: } else { yading@10: pred = a; yading@10: *dir_ptr = 0; yading@10: } yading@10: } yading@10: yading@10: /* update predictor */ yading@10: *dc_val_ptr = &dc_val[0]; yading@10: return pred; yading@10: } yading@10: