The only msmpeg4 code that is ever executed by the VC-1 based decoders is ff_msmpeg4_decode_init() and what is directly reachable from it. This is: a) A call to av_image_check_size(), then ff_h263_decode_init(), b) followed by setting [yc]_dc_scale_table and initializing scantable/permutations. c) Afterwards, some static tables are initialized. d) Finally, slice_height is set. The replacement for ff_msmpeg4_decode_init() performs a) just like now; it also sets [yc]_dc_scale_table, but it only initializes inter_scantable and intra_scantable and not permutated_intra_[hv]_scantable: The latter are only used inside decode_mb callbacks which are only called in ff_h263_decode_frame() which is unused for VC-1.* The static tables initialized in c) are not used at all by VC-1 (the ones that are used have been factored out in previous commits); this avoids touching 327KiB of .bss. slice_height is also not used by the VC-1 decoder (setting it in ff_msmpeg4_decode_init() is probably redundant after b34397b4cd780b5692548e7d021ec884c7217dba). *: It follows from this that the VC-1 decoder is not really based upon the H.263 decoder either; changing this will be done in a future commit. Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
		
			
				
	
	
		
			339 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			339 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
}
 | 
						|
 |