Skip to content
Snippets Groups Projects
vc1.c 144 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * VC-1 and WMV3 decoder
    
     * Copyright (c) 2006-2007 Konstantin Shishkov
    
     * Partly based on vc9.c (c) 2005 Anonymous, Alex Beregszaszi, Michael Niedermayer
    
     * 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 vc1.c
     * VC-1 and WMV3 decoder
    
     *
     */
    #include "dsputil.h"
    #include "avcodec.h"
    #include "mpegvideo.h"
    
    #include "vc1.h"
    
    #include "msmpeg4data.h"
    
    anonymous's avatar
    anonymous committed
    
    
    anonymous's avatar
    anonymous committed
    #define MB_INTRA_VLC_BITS 9
    #define DC_VLC_BITS 9
    
    anonymous's avatar
    anonymous committed
    static const uint16_t table_mb_intra[64][2];
    
    /**
     * Get unary code of limited length
     * @fixme FIXME Slow and ugly
     * @param gb GetBitContext
     * @param[in] stop The bitstop value (unary code of 1's or 0's)
     * @param[in] len Maximum length
     * @return Unary length/index
     */
    
    static int get_prefix(GetBitContext *gb, int stop, int len)
    {
    
    anonymous's avatar
    anonymous committed
    #if 1
    
        int i;
    
        for(i = 0; i < len && get_bits1(gb) != stop; i++);
        return i;
    /*  int i = 0, tmp = !stop;
    
      if (i == len && tmp != stop) return len+1;
    
    anonymous's avatar
    anonymous committed
    #else
      unsigned int buf;
      int log;
    
      OPEN_READER(re, gb);
      UPDATE_CACHE(re, gb);
      buf=GET_CACHE(re, gb); //Still not sure
      if (stop) buf = ~buf;
    
    anonymous's avatar
    anonymous committed
      log= av_log2(-buf); //FIXME: -?
      if (log < limit){
        LAST_SKIP_BITS(re, gb, log+1);
        CLOSE_READER(re, gb);
        return log;
      }
    
    anonymous's avatar
    anonymous committed
      LAST_SKIP_BITS(re, gb, limit);
      CLOSE_READER(re, gb);
      return limit;
    #endif
    }
    
    
    static inline int decode210(GetBitContext *gb){
    
        if (get_bits1(gb))
    
     * Init VC-1 specific tables and VC1Context members
     * @param v The VC1Context to initialize
    
     * @return Status
     */
    
    static int vc1_init_common(VC1Context *v)
    
    anonymous's avatar
    anonymous committed
    
        /* VLC tables */
    
            init_vlc(&ff_vc1_bfraction_vlc, VC1_BFRACTION_VLC_BITS, 23,
                     ff_vc1_bfraction_bits, 1, 1,
                     ff_vc1_bfraction_codes, 1, 1, 1);
            init_vlc(&ff_vc1_norm2_vlc, VC1_NORM2_VLC_BITS, 4,
                     ff_vc1_norm2_bits, 1, 1,
                     ff_vc1_norm2_codes, 1, 1, 1);
            init_vlc(&ff_vc1_norm6_vlc, VC1_NORM6_VLC_BITS, 64,
                     ff_vc1_norm6_bits, 1, 1,
                     ff_vc1_norm6_codes, 2, 2, 1);
            init_vlc(&ff_vc1_imode_vlc, VC1_IMODE_VLC_BITS, 7,
                     ff_vc1_imode_bits, 1, 1,
                     ff_vc1_imode_codes, 1, 1, 1);
    
    anonymous's avatar
    anonymous committed
            for (i=0; i<3; i++)
            {
    
                init_vlc(&ff_vc1_ttmb_vlc[i], VC1_TTMB_VLC_BITS, 16,
                         ff_vc1_ttmb_bits[i], 1, 1,
                         ff_vc1_ttmb_codes[i], 2, 2, 1);
                init_vlc(&ff_vc1_ttblk_vlc[i], VC1_TTBLK_VLC_BITS, 8,
                         ff_vc1_ttblk_bits[i], 1, 1,
                         ff_vc1_ttblk_codes[i], 1, 1, 1);
                init_vlc(&ff_vc1_subblkpat_vlc[i], VC1_SUBBLKPAT_VLC_BITS, 15,
                         ff_vc1_subblkpat_bits[i], 1, 1,
                         ff_vc1_subblkpat_codes[i], 1, 1, 1);
    
    anonymous's avatar
    anonymous committed
            }
            for(i=0; i<4; i++)
    
                init_vlc(&ff_vc1_4mv_block_pattern_vlc[i], VC1_4MV_BLOCK_PATTERN_VLC_BITS, 16,
                         ff_vc1_4mv_block_pattern_bits[i], 1, 1,
                         ff_vc1_4mv_block_pattern_codes[i], 1, 1, 1);
                init_vlc(&ff_vc1_cbpcy_p_vlc[i], VC1_CBPCY_P_VLC_BITS, 64,
                         ff_vc1_cbpcy_p_bits[i], 1, 1,
                         ff_vc1_cbpcy_p_codes[i], 2, 2, 1);
                init_vlc(&ff_vc1_mv_diff_vlc[i], VC1_MV_DIFF_VLC_BITS, 73,
                         ff_vc1_mv_diff_bits[i], 1, 1,
                         ff_vc1_mv_diff_codes[i], 2, 2, 1);
    
                init_vlc(&ff_vc1_ac_coeff_table[i], AC_VLC_BITS, vc1_ac_sizes[i],
    
                         &vc1_ac_tables[i][0][1], 8, 4,
                         &vc1_ac_tables[i][0][0], 8, 4, 1);
            init_vlc(&ff_msmp4_mb_i_vlc, MB_INTRA_VLC_BITS, 64,
                     &ff_msmp4_mb_i_table[0][1], 4, 2,
                     &ff_msmp4_mb_i_table[0][0], 4, 2, 1);
    
    anonymous's avatar
    anonymous committed
        /* Other defaults */
        v->pq = -1;
        v->mvrange = 0; /* 7.1.1.18, p80 */
    
    
    /***********************************************************************/
    
     * @defgroup bitplane VC9 Bitplane decoding
     * @see 8.7, p56
     * @{
     */
    
    /** @addtogroup bitplane
     * Imode types
     * @{
     */
    enum Imode {
        IMODE_RAW,
        IMODE_NORM2,
        IMODE_DIFF2,
        IMODE_NORM6,
        IMODE_DIFF6,
        IMODE_ROWSKIP,
        IMODE_COLSKIP
    };
    /** @} */ //imode defines
    
    /** Decode rows by checking if they are skipped
     * @param plane Buffer to store decoded bits
     * @param[in] width Width of this buffer
     * @param[in] height Height of this buffer
     * @param[in] stride of this buffer
     */
    static void decode_rowskip(uint8_t* plane, int width, int height, int stride, GetBitContext *gb){
        int x, y;
    
        for (y=0; y<height; y++){
            if (!get_bits(gb, 1)) //rowskip
                memset(plane, 0, width);
            else
                for (x=0; x<width; x++)
                    plane[x] = get_bits(gb, 1);
            plane += stride;
    
    /** Decode columns by checking if they are skipped
     * @param plane Buffer to store decoded bits
     * @param[in] width Width of this buffer
     * @param[in] height Height of this buffer
     * @param[in] stride of this buffer
     * @fixme FIXME: Optimize
     */
    static void decode_colskip(uint8_t* plane, int width, int height, int stride, GetBitContext *gb){
        int x, y;
    
        for (x=0; x<width; x++){
            if (!get_bits(gb, 1)) //colskip
                for (y=0; y<height; y++)
                    plane[y*stride] = 0;
            else
                for (y=0; y<height; y++)
                    plane[y*stride] = get_bits(gb, 1);
            plane ++;
    
    /** Decode a bitplane's bits
     * @param bp Bitplane where to store the decode bits
     * @param v VC-1 context for bit reading and logging
    
     * @return Status
    
    static int bitplane_decoding(uint8_t* data, int *raw_flag, VC1Context *v)
    
        uint8_t invert, *planep = data;
        int width, height, stride;
    
        width = v->s.mb_width;
        height = v->s.mb_height;
        stride = v->s.mb_stride;
    
        imode = get_vlc2(gb, ff_vc1_imode_vlc.table, VC1_IMODE_VLC_BITS, 1);
    
        case IMODE_RAW:
            //Data is actually read in the MB layer (same for all tests == "raw")
    
            *raw_flag = 1; //invert ignored
    
            return invert;
        case IMODE_DIFF2:
        case IMODE_NORM2:
    
                *planep++ = get_bits(gb, 1);
                offset = 1;
    
            else offset = 0;
            // decode bitplane as one long line
    
            for (y = offset; y < height * width; y += 2) {
    
                code = get_vlc2(gb, ff_vc1_norm2_vlc.table, VC1_NORM2_VLC_BITS, 1);
    
            }
            break;
        case IMODE_DIFF6:
        case IMODE_NORM6:
    
            if(!(height % 3) && (width % 3)) { // use 2x3 decoding
                for(y = 0; y < height; y+= 3) {
                    for(x = width & 1; x < width; x += 2) {
    
                        code = get_vlc2(gb, ff_vc1_norm6_vlc.table, VC1_NORM6_VLC_BITS, 2);
    
                        if(code < 0){
                            av_log(v->s.avctx, AV_LOG_DEBUG, "invalid NORM-6 VLC\n");
                            return -1;
                        }
                        planep[x + 0] = (code >> 0) & 1;
                        planep[x + 1] = (code >> 1) & 1;
    
                        planep[x + 0 + stride] = (code >> 2) & 1;
                        planep[x + 1 + stride] = (code >> 3) & 1;
                        planep[x + 0 + stride * 2] = (code >> 4) & 1;
                        planep[x + 1 + stride * 2] = (code >> 5) & 1;
    
                if(width & 1) decode_colskip(data, 1, height, stride, &v->s.gb);
    
                for(y = height & 1; y < height; y += 2) {
                    for(x = width % 3; x < width; x += 3) {
    
                        code = get_vlc2(gb, ff_vc1_norm6_vlc.table, VC1_NORM6_VLC_BITS, 2);
    
                        if(code < 0){
                            av_log(v->s.avctx, AV_LOG_DEBUG, "invalid NORM-6 VLC\n");
                            return -1;
                        }
                        planep[x + 0] = (code >> 0) & 1;
                        planep[x + 1] = (code >> 1) & 1;
                        planep[x + 2] = (code >> 2) & 1;
    
                        planep[x + 0 + stride] = (code >> 3) & 1;
                        planep[x + 1 + stride] = (code >> 4) & 1;
                        planep[x + 2 + stride] = (code >> 5) & 1;
    
                x = width % 3;
                if(x) decode_colskip(data  ,             x, height    , stride, &v->s.gb);
                if(height & 1) decode_rowskip(data+x, width - x, 1, stride, &v->s.gb);
    
            decode_rowskip(data, width, height, stride, &v->s.gb);
    
            decode_colskip(data, width, height, stride, &v->s.gb);
    
            break;
        default: break;
        }
    
        /* Applying diff operator */
        if (imode == IMODE_DIFF2 || imode == IMODE_DIFF6)
        {
    
                planep += stride;
                planep[0] ^= planep[-stride];
                for (x=1; x<width; x++)
    
                    if (planep[x-1] != planep[x-stride]) planep[x] ^= invert;
                    else                                 planep[x] ^= planep[x-1];
    
            planep = data;
            for (x=0; x<stride*height; x++) planep[x] = !planep[x]; //FIXME stride
    
    /***********************************************************************/
    /** VOP Dquant decoding
     * @param v VC-1 Context
     */
    static int vop_dquant_decoding(VC1Context *v)
    {
        GetBitContext *gb = &v->s.gb;
        int pqdiff;
    
        //variable size
        if (v->dquant == 2)
        {
            pqdiff = get_bits(gb, 3);
            if (pqdiff == 7) v->altpq = get_bits(gb, 5);
            else v->altpq = v->pq + pqdiff + 1;
        }
        else
    
            v->dquantfrm = get_bits(gb, 1);
            if ( v->dquantfrm )
    
                v->dqprofile = get_bits(gb, 2);
                switch (v->dqprofile)
    
                case DQPROFILE_SINGLE_EDGE:
                case DQPROFILE_DOUBLE_EDGES:
                    v->dqsbedge = get_bits(gb, 2);
                    break;
                case DQPROFILE_ALL_MBS:
                    v->dqbilevel = get_bits(gb, 1);
                default: break; //Forbidden ?
    
    Ivan Kalvachev's avatar
    Ivan Kalvachev committed
                }
    
                if (v->dqbilevel || v->dqprofile != DQPROFILE_ALL_MBS)
    
                    pqdiff = get_bits(gb, 3);
                    if (pqdiff == 7) v->altpq = get_bits(gb, 5);
                    else v->altpq = v->pq + pqdiff + 1;
    
    /** Put block onto picture
     */
    static void vc1_put_block(VC1Context *v, DCTELEM block[6][64])
    {
        uint8_t *Y;
        int ys, us, vs;
        DSPContext *dsp = &v->s.dsp;
    
    
        if(v->rangeredfrm) {
            int i, j, k;
            for(k = 0; k < 6; k++)
                for(j = 0; j < 8; j++)
                    for(i = 0; i < 8; i++)
                        block[k][i + j*8] = ((block[k][i + j*8] - 128) << 1) + 128;
    
        }
    
        ys = v->s.current_picture.linesize[0];
        us = v->s.current_picture.linesize[1];
        vs = v->s.current_picture.linesize[2];
        Y = v->s.dest[0];
    
        dsp->put_pixels_clamped(block[0], Y, ys);
        dsp->put_pixels_clamped(block[1], Y + 8, ys);
        Y += ys * 8;
        dsp->put_pixels_clamped(block[2], Y, ys);
        dsp->put_pixels_clamped(block[3], Y + 8, ys);
    
    
        if(!(v->s.flags & CODEC_FLAG_GRAY)) {
            dsp->put_pixels_clamped(block[4], v->s.dest[1], us);
            dsp->put_pixels_clamped(block[5], v->s.dest[2], vs);
        }
    
    }
    
    /** Do motion compensation over 1 macroblock
     * Mostly adapted hpel_motion and qpel_motion from mpegvideo.c
     */
    
    static void vc1_mc_1mv(VC1Context *v, int dir)
    
    {
        MpegEncContext *s = &v->s;
        DSPContext *dsp = &v->s.dsp;
        uint8_t *srcY, *srcU, *srcV;
    
        int dxy, uvdxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y;
    
        mx = s->mv[dir][0][0];
        my = s->mv[dir][0][1];
    
        // store motion vectors for further use in B frames
        if(s->pict_type == P_TYPE) {
            s->current_picture.motion_val[1][s->block_index[0]][0] = mx;
            s->current_picture.motion_val[1][s->block_index[0]][1] = my;
        }
    
        uvmx = (mx + ((mx & 3) == 3)) >> 1;
        uvmy = (my + ((my & 3) == 3)) >> 1;
    
        if(v->fastuvmc) {
            uvmx = uvmx + ((uvmx<0)?(uvmx&1):-(uvmx&1));
            uvmy = uvmy + ((uvmy<0)?(uvmy&1):-(uvmy&1));
        }
    
        if(!dir) {
            srcY = s->last_picture.data[0];
            srcU = s->last_picture.data[1];
            srcV = s->last_picture.data[2];
        } else {
            srcY = s->next_picture.data[0];
            srcU = s->next_picture.data[1];
            srcV = s->next_picture.data[2];
        }
    
        src_x = s->mb_x * 16 + (mx >> 2);
        src_y = s->mb_y * 16 + (my >> 2);
        uvsrc_x = s->mb_x * 8 + (uvmx >> 2);
        uvsrc_y = s->mb_y * 8 + (uvmy >> 2);
    
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        if(v->profile != PROFILE_ADVANCED){
            src_x   = av_clip(  src_x, -16, s->mb_width  * 16);
            src_y   = av_clip(  src_y, -16, s->mb_height * 16);
            uvsrc_x = av_clip(uvsrc_x,  -8, s->mb_width  *  8);
            uvsrc_y = av_clip(uvsrc_y,  -8, s->mb_height *  8);
        }else{
            src_x   = av_clip(  src_x, -17, s->avctx->coded_width);
            src_y   = av_clip(  src_y, -18, s->avctx->coded_height + 1);
            uvsrc_x = av_clip(uvsrc_x,  -8, s->avctx->coded_width  >> 1);
            uvsrc_y = av_clip(uvsrc_y,  -8, s->avctx->coded_height >> 1);
        }
    
    
        srcY += src_y * s->linesize + src_x;
        srcU += uvsrc_y * s->uvlinesize + uvsrc_x;
        srcV += uvsrc_y * s->uvlinesize + uvsrc_x;
    
    
        /* for grayscale we should not try to read from unknown area */
        if(s->flags & CODEC_FLAG_GRAY) {
            srcU = s->edge_emu_buffer + 18 * s->linesize;
            srcV = s->edge_emu_buffer + 18 * s->linesize;
        }
    
    
        if(v->rangeredfrm || (v->mv_mode == MV_PMODE_INTENSITY_COMP)
    
           || (unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx&3) - 16 - s->mspel*3
           || (unsigned)(src_y - s->mspel) > s->v_edge_pos - (my&3) - 16 - s->mspel*3){
            uint8_t *uvbuf= s->edge_emu_buffer + 19 * s->linesize;
    
            srcY -= s->mspel * (1 + s->linesize);
            ff_emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize, 17+s->mspel*2, 17+s->mspel*2,
                                src_x - s->mspel, src_y - s->mspel, s->h_edge_pos, s->v_edge_pos);
    
            srcY = s->edge_emu_buffer;
            ff_emulated_edge_mc(uvbuf     , srcU, s->uvlinesize, 8+1, 8+1,
                                uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
            ff_emulated_edge_mc(uvbuf + 16, srcV, s->uvlinesize, 8+1, 8+1,
                                uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
            srcU = uvbuf;
            srcV = uvbuf + 16;
    
            /* if we deal with range reduction we need to scale source blocks */
            if(v->rangeredfrm) {
                int i, j;
                uint8_t *src, *src2;
    
                src = srcY;
    
                for(j = 0; j < 17 + s->mspel*2; j++) {
                    for(i = 0; i < 17 + s->mspel*2; i++) src[i] = ((src[i] - 128) >> 1) + 128;
    
                    src += s->linesize;
                }
                src = srcU; src2 = srcV;
                for(j = 0; j < 9; j++) {
                    for(i = 0; i < 9; i++) {
                        src[i] = ((src[i] - 128) >> 1) + 128;
                        src2[i] = ((src2[i] - 128) >> 1) + 128;
                    }
                    src += s->uvlinesize;
                    src2 += s->uvlinesize;
                }
            }
    
            /* if we deal with intensity compensation we need to scale source blocks */
            if(v->mv_mode == MV_PMODE_INTENSITY_COMP) {
                int i, j;
                uint8_t *src, *src2;
    
                src = srcY;
    
                for(j = 0; j < 17 + s->mspel*2; j++) {
                    for(i = 0; i < 17 + s->mspel*2; i++) src[i] = v->luty[src[i]];
    
                    src += s->linesize;
                }
                src = srcU; src2 = srcV;
                for(j = 0; j < 9; j++) {
                    for(i = 0; i < 9; i++) {
                        src[i] = v->lutuv[src[i]];
                        src2[i] = v->lutuv[src2[i]];
                    }
                    src += s->uvlinesize;
                    src2 += s->uvlinesize;
                }
            }
    
            srcY += s->mspel * (1 + s->linesize);
    
        if(s->mspel) {
            dxy = ((my & 3) << 2) | (mx & 3);
            dsp->put_vc1_mspel_pixels_tab[dxy](s->dest[0]    , srcY    , s->linesize, v->rnd);
            dsp->put_vc1_mspel_pixels_tab[dxy](s->dest[0] + 8, srcY + 8, s->linesize, v->rnd);
            srcY += s->linesize * 8;
            dsp->put_vc1_mspel_pixels_tab[dxy](s->dest[0] + 8 * s->linesize    , srcY    , s->linesize, v->rnd);
            dsp->put_vc1_mspel_pixels_tab[dxy](s->dest[0] + 8 * s->linesize + 8, srcY + 8, s->linesize, v->rnd);
    
        } else { // hpel mc - always used for luma
            dxy = (my & 2) | ((mx & 2) >> 1);
    
            if(!v->rnd)
                dsp->put_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, 16);
            else
                dsp->put_no_rnd_pixels_tab[0][dxy](s->dest[0], srcY, s->linesize, 16);
        }
    
    
        if(s->flags & CODEC_FLAG_GRAY) return;
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        /* Chroma MC always uses qpel bilinear */
    
        uvdxy = ((uvmy & 3) << 2) | (uvmx & 3);
    
        uvmx = (uvmx&3)<<1;
        uvmy = (uvmy&3)<<1;
        if(!v->rnd){
            dsp->put_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
            dsp->put_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
        }else{
            dsp->put_no_rnd_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
            dsp->put_no_rnd_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
        }
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
    /** Do motion compensation for 4-MV macroblock - luminance block
     */
    static void vc1_mc_4mv_luma(VC1Context *v, int n)
    {
        MpegEncContext *s = &v->s;
        DSPContext *dsp = &v->s.dsp;
        uint8_t *srcY;
        int dxy, mx, my, src_x, src_y;
        int off;
    
        if(!v->s.last_picture.data[0])return;
        mx = s->mv[0][n][0];
        my = s->mv[0][n][1];
        srcY = s->last_picture.data[0];
    
        off = s->linesize * 4 * (n&2) + (n&1) * 8;
    
        src_x = s->mb_x * 16 + (n&1) * 8 + (mx >> 2);
        src_y = s->mb_y * 16 + (n&2) * 4 + (my >> 2);
    
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        if(v->profile != PROFILE_ADVANCED){
            src_x   = av_clip(  src_x, -16, s->mb_width  * 16);
            src_y   = av_clip(  src_y, -16, s->mb_height * 16);
        }else{
            src_x   = av_clip(  src_x, -17, s->avctx->coded_width);
            src_y   = av_clip(  src_y, -18, s->avctx->coded_height + 1);
        }
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
    
        srcY += src_y * s->linesize + src_x;
    
    
        if(v->rangeredfrm || (v->mv_mode == MV_PMODE_INTENSITY_COMP)
    
           || (unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx&3) - 8 - s->mspel*2
           || (unsigned)(src_y - s->mspel) > s->v_edge_pos - (my&3) - 8 - s->mspel*2){
    
            srcY -= s->mspel * (1 + s->linesize);
            ff_emulated_edge_mc(s->edge_emu_buffer, srcY, s->linesize, 9+s->mspel*2, 9+s->mspel*2,
                                src_x - s->mspel, src_y - s->mspel, s->h_edge_pos, s->v_edge_pos);
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
            srcY = s->edge_emu_buffer;
    
            /* if we deal with range reduction we need to scale source blocks */
            if(v->rangeredfrm) {
                int i, j;
                uint8_t *src;
    
                src = srcY;
    
                for(j = 0; j < 9 + s->mspel*2; j++) {
                    for(i = 0; i < 9 + s->mspel*2; i++) src[i] = ((src[i] - 128) >> 1) + 128;
    
                    src += s->linesize;
                }
            }
    
            /* if we deal with intensity compensation we need to scale source blocks */
            if(v->mv_mode == MV_PMODE_INTENSITY_COMP) {
                int i, j;
                uint8_t *src;
    
                src = srcY;
                for(j = 0; j < 9 + s->mspel*2; j++) {
                    for(i = 0; i < 9 + s->mspel*2; i++) src[i] = v->luty[src[i]];
                    src += s->linesize;
                }
            }
    
            srcY += s->mspel * (1 + s->linesize);
    
        if(s->mspel) {
            dxy = ((my & 3) << 2) | (mx & 3);
            dsp->put_vc1_mspel_pixels_tab[dxy](s->dest[0] + off, srcY, s->linesize, v->rnd);
    
        } else { // hpel mc - always used for luma
            dxy = (my & 2) | ((mx & 2) >> 1);
    
            if(!v->rnd)
                dsp->put_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize, 8);
            else
                dsp->put_no_rnd_pixels_tab[1][dxy](s->dest[0] + off, srcY, s->linesize, 8);
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        }
    }
    
    static inline int median4(int a, int b, int c, int d)
    {
    
            if(c < d) return (FFMIN(b, d) + FFMAX(a, c)) / 2;
            else      return (FFMIN(b, c) + FFMAX(a, d)) / 2;
    
            if(c < d) return (FFMIN(a, d) + FFMAX(b, c)) / 2;
            else      return (FFMIN(a, c) + FFMAX(b, d)) / 2;
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
    }
    
    
    /** Do motion compensation for 4-MV macroblock - both chroma blocks
     */
    static void vc1_mc_4mv_chroma(VC1Context *v)
    {
        MpegEncContext *s = &v->s;
        DSPContext *dsp = &v->s.dsp;
        uint8_t *srcU, *srcV;
        int uvdxy, uvmx, uvmy, uvsrc_x, uvsrc_y;
        int i, idx, tx = 0, ty = 0;
        int mvx[4], mvy[4], intra[4];
        static const int count[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
    
        if(!v->s.last_picture.data[0])return;
    
        if(s->flags & CODEC_FLAG_GRAY) return;
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
    
        for(i = 0; i < 4; i++) {
            mvx[i] = s->mv[0][i][0];
            mvy[i] = s->mv[0][i][1];
            intra[i] = v->mb_type[0][s->block_index[i]];
        }
    
        /* calculate chroma MV vector from four luma MVs */
    
        idx = (intra[3] << 3) | (intra[2] << 2) | (intra[1] << 1) | intra[0];
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        if(!idx) { // all blocks are inter
            tx = median4(mvx[0], mvx[1], mvx[2], mvx[3]);
            ty = median4(mvy[0], mvy[1], mvy[2], mvy[3]);
        } else if(count[idx] == 1) { // 3 inter blocks
            switch(idx) {
            case 0x1:
                tx = mid_pred(mvx[1], mvx[2], mvx[3]);
    
                ty = mid_pred(mvy[1], mvy[2], mvy[3]);
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
                break;
            case 0x2:
                tx = mid_pred(mvx[0], mvx[2], mvx[3]);
    
                ty = mid_pred(mvy[0], mvy[2], mvy[3]);
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
                break;
            case 0x4:
                tx = mid_pred(mvx[0], mvx[1], mvx[3]);
    
                ty = mid_pred(mvy[0], mvy[1], mvy[3]);
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
                break;
            case 0x8:
                tx = mid_pred(mvx[0], mvx[1], mvx[2]);
    
                ty = mid_pred(mvy[0], mvy[1], mvy[2]);
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
                break;
            }
        } else if(count[idx] == 2) {
            int t1 = 0, t2 = 0;
            for(i=0; i<3;i++) if(!intra[i]) {t1 = i; break;}
            for(i= t1+1; i<4; i++)if(!intra[i]) {t2 = i; break;}
    
            tx = (mvx[t1] + mvx[t2]) / 2;
            ty = (mvy[t1] + mvy[t2]) / 2;
    
        } else {
            s->current_picture.motion_val[1][s->block_index[0]][0] = 0;
            s->current_picture.motion_val[1][s->block_index[0]][1] = 0;
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
            return; //no need to do MC for inter blocks
    
        s->current_picture.motion_val[1][s->block_index[0]][0] = tx;
        s->current_picture.motion_val[1][s->block_index[0]][1] = ty;
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        uvmx = (tx + ((tx&3) == 3)) >> 1;
        uvmy = (ty + ((ty&3) == 3)) >> 1;
    
        if(v->fastuvmc) {
            uvmx = uvmx + ((uvmx<0)?(uvmx&1):-(uvmx&1));
            uvmy = uvmy + ((uvmy<0)?(uvmy&1):-(uvmy&1));
        }
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
    
        uvsrc_x = s->mb_x * 8 + (uvmx >> 2);
        uvsrc_y = s->mb_y * 8 + (uvmy >> 2);
    
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        if(v->profile != PROFILE_ADVANCED){
            uvsrc_x = av_clip(uvsrc_x,  -8, s->mb_width  *  8);
            uvsrc_y = av_clip(uvsrc_y,  -8, s->mb_height *  8);
        }else{
            uvsrc_x = av_clip(uvsrc_x,  -8, s->avctx->coded_width  >> 1);
            uvsrc_y = av_clip(uvsrc_y,  -8, s->avctx->coded_height >> 1);
        }
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        srcU = s->last_picture.data[1] + uvsrc_y * s->uvlinesize + uvsrc_x;
        srcV = s->last_picture.data[2] + uvsrc_y * s->uvlinesize + uvsrc_x;
    
        if(v->rangeredfrm || (v->mv_mode == MV_PMODE_INTENSITY_COMP)
           || (unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 9
    
           || (unsigned)uvsrc_y > (s->v_edge_pos >> 1) - 9){
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
            ff_emulated_edge_mc(s->edge_emu_buffer     , srcU, s->uvlinesize, 8+1, 8+1,
                                uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
            ff_emulated_edge_mc(s->edge_emu_buffer + 16, srcV, s->uvlinesize, 8+1, 8+1,
                                uvsrc_x, uvsrc_y, s->h_edge_pos >> 1, s->v_edge_pos >> 1);
            srcU = s->edge_emu_buffer;
            srcV = s->edge_emu_buffer + 16;
    
    
            /* if we deal with range reduction we need to scale source blocks */
            if(v->rangeredfrm) {
                int i, j;
                uint8_t *src, *src2;
    
                src = srcU; src2 = srcV;
                for(j = 0; j < 9; j++) {
                    for(i = 0; i < 9; i++) {
                        src[i] = ((src[i] - 128) >> 1) + 128;
                        src2[i] = ((src2[i] - 128) >> 1) + 128;
                    }
                    src += s->uvlinesize;
                    src2 += s->uvlinesize;
                }
            }
    
            /* if we deal with intensity compensation we need to scale source blocks */
            if(v->mv_mode == MV_PMODE_INTENSITY_COMP) {
                int i, j;
                uint8_t *src, *src2;
    
                src = srcU; src2 = srcV;
                for(j = 0; j < 9; j++) {
                    for(i = 0; i < 9; i++) {
                        src[i] = v->lutuv[src[i]];
                        src2[i] = v->lutuv[src2[i]];
                    }
                    src += s->uvlinesize;
                    src2 += s->uvlinesize;
                }
            }
    
    Kostya Shishkov's avatar
    Kostya Shishkov committed
        /* Chroma MC always uses qpel bilinear */
    
        uvdxy = ((uvmy & 3) << 2) | (uvmx & 3);
    
        uvmx = (uvmx&3)<<1;
        uvmy = (uvmy&3)<<1;
        if(!v->rnd){
            dsp->put_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
            dsp->put_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
        }else{
            dsp->put_no_rnd_h264_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy);
            dsp->put_no_rnd_h264_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy);
        }
    
    static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb);
    
    
     * Decode Simple/Main Profiles sequence header
     * @see Figure 7-8, p16-17
     * @param avctx Codec context
     * @param gb GetBit context initialized from Codec context extra_data
     * @return Status
     */
    
    static int decode_sequence_header(AVCodecContext *avctx, GetBitContext *gb)
    {
    
        VC1Context *v = avctx->priv_data;
    
        av_log(avctx, AV_LOG_DEBUG, "Header: %0X\n", show_bits(gb, 32));
    
        if (v->profile == PROFILE_COMPLEX)
    
            av_log(avctx, AV_LOG_ERROR, "WMV3 Complex Profile is not fully supported\n");
    
        if (v->profile == PROFILE_ADVANCED)
    
            return decode_sequence_header_adv(v, gb);
    
        }
        else
        {
            v->res_sm = get_bits(gb, 2); //reserved
            if (v->res_sm)
            {
                av_log(avctx, AV_LOG_ERROR,
                       "Reserved RES_SM=%i is forbidden\n", v->res_sm);
    
            }
        }
    
        // (fps-2)/4 (->30)
        v->frmrtq_postproc = get_bits(gb, 3); //common
        // (bitrate-32kbps)/64kbps
        v->bitrtq_postproc = get_bits(gb, 5); //common
    
        v->s.loop_filter = get_bits(gb, 1); //common
    
        if(v->s.loop_filter == 1 && v->profile == PROFILE_SIMPLE)
        {
            av_log(avctx, AV_LOG_ERROR,
                   "LOOPFILTER shell not be enabled in simple profile\n");
        }
    
        v->res_x8 = get_bits(gb, 1); //reserved
        if (v->res_x8)
    
            av_log(avctx, AV_LOG_ERROR,
                   "1 for reserved RES_X8 is forbidden\n");
            //return -1;
        }
        v->multires = get_bits(gb, 1);
        v->res_fasttx = get_bits(gb, 1);
        if (!v->res_fasttx)
        {
            av_log(avctx, AV_LOG_ERROR,
                   "0 for reserved RES_FASTTX is forbidden\n");
            //return -1;
    
        }
    
        v->fastuvmc =  get_bits(gb, 1); //common
        if (!v->profile && !v->fastuvmc)
        {
            av_log(avctx, AV_LOG_ERROR,
                   "FASTUVMC unavailable in Simple Profile\n");
            return -1;
        }
        v->extended_mv =  get_bits(gb, 1); //common
        if (!v->profile && v->extended_mv)
        {
            av_log(avctx, AV_LOG_ERROR,
                   "Extended MVs unavailable in Simple Profile\n");
            return -1;
        }
        v->dquant =  get_bits(gb, 2); //common
        v->vstransform =  get_bits(gb, 1); //common
    
        v->res_transtab = get_bits(gb, 1);
        if (v->res_transtab)
    
            av_log(avctx, AV_LOG_ERROR,
                   "1 for reserved RES_TRANSTAB is forbidden\n");
            return -1;
    
        v->s.resync_marker = get_bits(gb, 1);
        v->rangered = get_bits(gb, 1);
        if (v->rangered && v->profile == PROFILE_SIMPLE)
    
            av_log(avctx, AV_LOG_INFO,
                   "RANGERED should be set to 0 in simple profile\n");
    
    anonymous's avatar
    anonymous committed
        v->s.max_b_frames = avctx->max_b_frames = get_bits(gb, 3); //common
    
        v->finterpflag = get_bits(gb, 1); //common
        v->res_rtm_flag = get_bits(gb, 1); //reserved
        if (!v->res_rtm_flag)
    
    //            av_log(avctx, AV_LOG_ERROR,
    //                   "0 for reserved RES_RTM_FLAG is forbidden\n");
    
            av_log(avctx, AV_LOG_ERROR,
                   "Old WMV3 version detected, only I-frames will be decoded\n");
            //return -1;
        }
    
        //TODO: figure out what they mean (always 0x402F)
        if(!v->res_fasttx) skip_bits(gb, 16);
    
                   "Profile %i:\nfrmrtq_postproc=%i, bitrtq_postproc=%i\n"
    
                   "LoopFilter=%i, MultiRes=%i, FastUVMC=%i, Extended MV=%i\n"
    
                   "Rangered=%i, VSTransform=%i, Overlap=%i, SyncMarker=%i\n"
                   "DQuant=%i, Quantizer mode=%i, Max B frames=%i\n",
                   v->profile, v->frmrtq_postproc, v->bitrtq_postproc,
    
                   v->s.loop_filter, v->multires, v->fastuvmc, v->extended_mv,
    
    anonymous's avatar
    anonymous committed
                   v->rangered, v->vstransform, v->overlap, v->s.resync_marker,
    
                   v->dquant, v->quantizer_mode, avctx->max_b_frames
                   );
    
    static int decode_sequence_header_adv(VC1Context *v, GetBitContext *gb)
    {
        v->res_rtm_flag = 1;
        v->level = get_bits(gb, 3);
        if(v->level >= 5)
        {
            av_log(v->s.avctx, AV_LOG_ERROR, "Reserved LEVEL %i\n",v->level);
        }
        v->chromaformat = get_bits(gb, 2);
        if (v->chromaformat != 1)
        {
            av_log(v->s.avctx, AV_LOG_ERROR,
                   "Only 4:2:0 chroma format supported\n");
            return -1;
        }
    
        // (fps-2)/4 (->30)
        v->frmrtq_postproc = get_bits(gb, 3); //common
        // (bitrate-32kbps)/64kbps
        v->bitrtq_postproc = get_bits(gb, 5); //common
        v->postprocflag = get_bits(gb, 1); //common
    
        v->s.avctx->coded_width = (get_bits(gb, 12) + 1) << 1;
        v->s.avctx->coded_height = (get_bits(gb, 12) + 1) << 1;
    
        v->s.avctx->width = v->s.avctx->coded_width;
        v->s.avctx->height = v->s.avctx->coded_height;
    
        v->broadcast = get_bits1(gb);
        v->interlace = get_bits1(gb);
        v->tfcntrflag = get_bits1(gb);
        v->finterpflag = get_bits1(gb);
        get_bits1(gb); // reserved
    
        v->s.h_edge_pos = v->s.avctx->coded_width;
        v->s.v_edge_pos = v->s.avctx->coded_height;
    
    
        av_log(v->s.avctx, AV_LOG_DEBUG,
                   "Advanced Profile level %i:\nfrmrtq_postproc=%i, bitrtq_postproc=%i\n"
                   "LoopFilter=%i, ChromaFormat=%i, Pulldown=%i, Interlace: %i\n"
                   "TFCTRflag=%i, FINTERPflag=%i\n",
                   v->level, v->frmrtq_postproc, v->bitrtq_postproc,
                   v->s.loop_filter, v->chromaformat, v->broadcast, v->interlace,
                   v->tfcntrflag, v->finterpflag
                   );
    
    
        v->psf = get_bits1(gb);
        if(v->psf) { //PsF, 6.1.13
            av_log(v->s.avctx, AV_LOG_ERROR, "Progressive Segmented Frame mode: not supported (yet)\n");
            return -1;
        }
    
        v->s.max_b_frames = v->s.avctx->max_b_frames = 7;
    
        if(get_bits1(gb)) { //Display Info - decoding is not affected by it
            int w, h, ar = 0;
    
            av_log(v->s.avctx, AV_LOG_DEBUG, "Display extended info:\n");
    
            v->s.avctx->width  = v->s.width  = w = get_bits(gb, 14) + 1;
            v->s.avctx->height = v->s.height = h = get_bits(gb, 14) + 1;
    
            av_log(v->s.avctx, AV_LOG_DEBUG, "Display dimensions: %ix%i\n", w, h);
    
            if(ar && ar < 14){
    
                v->s.avctx->sample_aspect_ratio = ff_vc1_pixel_aspect[ar];
    
            }else if(ar == 15){
    
                w = get_bits(gb, 8);
                h = get_bits(gb, 8);
    
                v->s.avctx->sample_aspect_ratio = (AVRational){w, h};
    
            }
    
            if(get_bits1(gb)){ //framerate stuff
                if(get_bits1(gb)) {
    
                    v->s.avctx->time_base.num = 32;