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